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.