Deployment obrazu z prywatnego repozytorium ECR na klaster AWS EKS

W tym artykule, pokaże jak zbudować obraz przykładowej aplikacji napisanej we Flask, zbudować oraz spushować obraz do AWS ECR oraz jak zrobić deploy na AWS EKS, aby mieć dostęp do aplikacji z poziomu load balancera za który posłuży nam AWS ELB. Do zadania będziemy potrzebowali skonfigurowany klaster kubernetes przy pomocy serwisu AWS EKS. Jeden ze sposobów na utworzenia klastra, opisywałem we wcześniejszych postach na moim blogu https://cloud-devops.pl/tworzenie-klastra-kubernetes-przy-pomocy-aws-eks/

W pierwszej kolejności musimy sobie utworzyć repozytorium ECR, robimy to przy pomocy polecenia

aws ecr create-repository --repository-name flask-app-repo

Następnie musimy zbudować sobie obraz, który wyślemy do repozytorium, poniżej obraz, który użyłem ja

from flask import Flask
import os

app = Flask(__name__)

@app.route('/')
def index():
    return "Your username is " + os.environ["USER"] + " your password is " + os.environ["PASSWORD"]

app.run(debug=False, host="0.0.0.0", port=8080)

Jest to prosta aplikacja napisana w Python przy użyciu Flaska, wyświelta nam ona prosty tekst, do którego potrzebujemy 2 zmienne środowiskowe, USER oraz PASSWORD, zostanę one ustawione w deploymencie. Aplikację mamy gotową, teraz czas na Dockerfile, na podstawie którego zbudujemy obraz

FROM python:3.9-alpine

COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt

COPY . .

CMD [ "python", "app.py"]

Równie prosty jak cała aplikacja. Do zbudowania obrazu używamy python 3.9-alpine, kopiujemy plik requirements.txt do niego, uruchamiany pip3 który zainstaluje nam zależności. Następnie kopiowana jest cala aplikacja i odpalana przy pomocy CMD. Mamy aplikację, mamy przygotowany Dockerfile, czas zbudować obraz i wysłać do repozytorium. Aby zbudować obraz używamy poniższego polecenia

docker build -t 111111111111.dkr.ecr.eu-central-1.amazonaws.com/flask-app-repo:latest .

Następnie, aby móc wysłać obraz do prywatnego repozytorium, musimy się zalogować, robimy to przy pomocy polecenia

aws ecr get-login-password --region eu-central-1 | docker login --username AWS --password-stdin 111111111111.dkr.ecr.eu-central-1.amazonaws.com

Jak już zalogowaliśmy się poprawnie, to czas spushować obraz do repozytorium, robimy to przy pomocy polecenia

docker push 111111111111.dkr.ecr.eu-central-1.amazonaws.com/flask-app-repo:latest

Od strony obrazu mamy wszystko gotowe, teraz czas na kilka zadań do wykonania w kubernetesie. W pierwszej kolejności tworzymy namespace, aby nie pracować na default, tworzy go przy pomocy polecenia

kubectl create namespace flask-app

Następnie, zmieniamy domyślny namespace dla contextu, aby się nie pogubić

kubectl config set-context --current --namespace=flask-app

Teraz, aby pobrać obraz z prywatnego repozytorium, musimy dodać secret, który przeznaczony jest dla docker-registry. Wykonujemy więc, poniższe polecenie

kubectl create secret docker-registry reg-cred
  --docker-server=111111111111.dkr.ecr.eu-central-1.amazonaws.com
  --docker-username=AWS
  --docker-password=$(aws ecr get-login-password)
  --namespace=flask-app

Dzięki czemu, w deploymencie, wystarczy, że wskażemy przy pomocy imagePullSecrets, z którego secretu ma korzystać K8s przy pullowaniu obrazu. Tworzymy sobie plik flask-deployment.yml z poniższym kodem

apiVersion: apps/v1
kind: Deployment
metadata:
  name: flask-app
  namespace: flask-app
  labels:
    app: flask-app
spec:
  replicas: 2
  template:
    metadata:
      name: flask-app
      labels:
        app: flask-app
    spec:
      containers:
        - name: flask-app
          image: 111111111111.dkr.ecr.eu-central-1.amazonaws.com/flask-app-repo:latest
          imagePullPolicy: Always
          ports:
            - containerPort: 8080
              hostPort: 80
              protocol: TCP
          env:
            - name: USER
              value: "test_user"
            - name: PASSWORD
              value: "test_password"
      restartPolicy: Always
      imagePullSecrets:
        - name: reg-cred
  selector:
    matchLabels:
      app: flask-app

W image podajemy URI do naszego obrazu, natomiast w imagePullSecrets nazwę naszego secret, który utworzyliśmy chwilę wcześniej. Zmienne środowiskowe USER oraz PASSWORD, dodałem tylko dla przykładu, aby faktycznie coś aplikacja robiła, poza prostym hello world 🙂 Teraz musimy utworzyć nasz deployment, przy pomocy polecenia

kubectl apply -f flask-deployment.yml

Teraz przy pomocy poniższego polecenia, sprawdźmy czy wszystko działa, jeżeli mamy 2 pody ze statusem Ready 1/1, tzn, że wszystko działa prawidłowo i obraz został pobrany 🙂

kubectl get po

W tym momencie, mógłbym zakończyć post, ale nie byłbym sobą, pod nam niby działa, ale czy aplikacja też? Sprawdźmy to dodając serwis oraz wykorzystując AWE Elastic Load Balancer. Tworzymy plik flask-service.yml, a nim dajemy poniższy kod

apiVersion: v1
kind: Service
metadata:
  name: flask-app-service
  namespace: flask-app
spec:
  selector:
    app: flask-app
  ports:
    - port: 80
      targetPort: 8080
      protocol: TCP
  type: LoadBalancer

Obowiązkowo musi mieć typ LoadBalancer, aby był dostępny z zewnątrz. Uruchamiany plik poleceniem

kubectl apply -f flask-service.yml

Teraz przy pomocy poniższego polecenia, sprawdźmy czy serwis został dodany oraz czy działa.

kubectl get svc | grep "flask-app-service" 

Skopiujmy więc EXTERAL-IP i sprawdźmy czy na stronie pokaże się napis

Your username is test_user your password is test_password

Jeżeli tak, to jest to najlepszy dowód na to, że nasza aplikacja działa w 100% 🙂 Mam nadzieję, że artykuł wszystko wyjaśnił, i nie będziecie mieli więcej problemów, z deployem obrazów z ECR na EKS.

Related Posts