Gitlab-CI auto deploy with AWS EKS and ECR
Bài đăng này đã không được cập nhật trong 4 năm
Đặt vấn đề
Gần đây rất nhiều người hay nói đến Docker, Kubernetes (K8s) làm cho một thằng chỉ code backend như mình để ý. Sau một thời gian tìm hiểu và mất tiền cho AWS, cuối cùng cũng cho ra được bài viết dưới đây.
Trong bài viết này mình sẽ nói về việc tự động deploy một ứng dụng lên AWS EKS (Elastic Kubernetes Service) sử dụng Gitlab-CI, docker images sẽ lưu trữ tại ECR( Amazon Elastic Container Registry ).
Nội dung gồm các phần:
- Setup Kubernetes cluster
- Dockerize
- Push image to ECR
- Kubernetes deployments
- Auto deploy via Gitlab-CI
- Clean up
Các bước mình triển khai: tạo k8s cluster => dockerize => push image lên ECR => deploy app bằng EKS => Gitlab auto deploy.
Setup Kubernetes cluster
Có nhiều cách để tạo một K8s cluster, bạn có thể vào AWS console để tạo thông qua giao diện trực quan. Còn với mình, mình sẽ tạo thông qua eksctl
, đây là một CLI do AWS cung cấp.
Lưu ý một chút là do mình dùng macOS nên các câu lệnh dưới đây là cho macOS. Các bạn có thể truy cập AWS guide để cài đặt cho hệ điều hành mình đang dùng.
Install the AWS CLI
curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg" sudo installer -pkg AWSCLIV2.pkg -target /
Configure your AWS CLI credentials
Để sử dụng được CLI này bạn cần Access keys của AWS bao gồm access key ID và secret access key. Truy cập IAM của AWS để generate nhé. Tiếp đó dùng lệnh:
aws configure
sau đó nhập thông tin Access keys đã lấy từ AWS.
Ví dụ:
$ aws configure
AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Default region name [None]: ap-southeast-1
Default output format [None]: json
Install eksctl
Mình cài bằng brew
brew install weaveworks/tap/eksctl
Kiểm tra xem cài đặt thành công chưa bằng lệnh:
eksctl version
# 0.25.0
Create Kubernetes cluster
Câu lệnh tạo một cluster như sau:
eksctl create cluster --name=app-demo
Trên đây mình tạo một cluster tên là app-demo
. Nếu không có flag --node-type thì eksctl sẽ mặc định là m5.large
với chi phí là $0.12 một giờ.
Nghe thì tưởng chừng ít nhưng bạn thử để vài ngày xem, nó sẽ là:
Thời gian tạo cluster thường mất từ 15–20 phút. Bạn muốn theo dõi xem khi chạy lệnh eksctl create cluster
thì AWS sẽ tạo những resource nào thì có thể truy cập vào http://console.aws.amazon.com/, tìm kiếm service tên là CloudFormation.
Bạn đợi khi status chuyển sang CREATE_COMPLETE hoặc ở terminal hiển thị như sau có nghĩa là quá trình tạo đã xong.
[✔] EKS cluster "app-demo" in "ap-southeast-1" region is ready
Sau khi xong, chạy lệnh:
kubectl get nodes
Kết quả:
là thành công.
Nếu có vấn đề gì về credentials, bạn nên kiểm tra lại config aws bằng lệnh bên trên aws configure
.
Dockerize
Bước tiếp theo, ta cần dockerize ứng dụng. Tuỳ ứng dụng của bạn mà bạn viết Dockerfile cho phù hợp. Nếu bạn nào chưa có thì dùng app của mình. App viết bằng Vuejs, clone tại link.
# Dockerfile
FROM node:lts-alpine
# install simple http server for serving static content
RUN npm install -g http-server
# make the 'app' folder the current working directory
WORKDIR /app
# copy both 'package.json' and 'package-lock.json' (if available)
COPY package*.json ./
# install project dependencies
RUN npm install
# copy project files and folders to the current working directory (i.e. 'app' folder)
COPY . .
# build app for production with minification
RUN npm run build
EXPOSE 8080
CMD [ "http-server", "dist" ]
Build docker images bằng lệnh:
docker build -t demo-app .
Output của việc dockerize là bạn phải chạy được app qua docker. Ta chạy app bằng lệnh:
docker run -p 8080:8080 demo-app
Truy cập localhost:8080
nếu app hiển thị bình thường là ta đã thành công.
Push image to ECR
Bước tiếp theo ta sẽ push images lên ECR Đầu tiên cần login:
aws ecr get-login-password --region <region> | docker login --username AWS --password-stdin <aws_account_id>.dkr.ecr.<region>.amazonaws.com
Thay thế region, aws_account_id bằng thông tin tài khoản AWS của bạn.
Tiếp đến tạo một responsitory
aws ecr create-repository \
--repository-name demo-app \
--image-scanning-configuration scanOnPush=true \
--region <region>
Bạn cũng có thể tạo responsitory qua giao diện tại ECR responsitory
Cuối cùng ta add tag và push image lên ECR via:
docker tag demo-app aws_account_id.dkr.ecr.<region>.amazonaws.com/demo-app:latest
docker push aws_account_id.dkr.ecr.<region>.amazonaws.com/demo-app:latest
Lưu ý rằng gói Free Tier sẽ free cho bạn 500Mb khi lưu trên ECR. Nếu tổng dung lượng các file images của bạn > 500Mb thì nên cân nhắc xoá bớt đi.
Kubernetes deployments
Giờ là thời điểm để deploy app vào cluster ta đã tạo trước đó.
Tạo một file tên là deployment.yaml
có nội dung như sau:
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-app
spec:
replicas: 3
selector:
matchLabels:
app: demo-app
template:
metadata:
labels:
app: demo-app
spec:
containers:
- name: demo-app
image: <aws_account_id>.dkr.ecr.<region>.amazonaws.com/demo-app:latest
ports:
- containerPort: 8080
Ta chỉ cần chú ý đến các mục chính:
- Kind là Deployment
- Tên của deployments này là demo-app
- Số lượng replicas là 3.
- Image được lấy từ `<aws_account_id>.dkr.ecr.<region>.amazonaws.com/demo-app
Tiếp đến chạy lệnh:
kubectl apply -f deployment.yaml
Kiểm tra bằng lệnh:
kubectl get deployments
Kết quả là như này là thành công:
Lúc này code đã được deploy lên các node, tuy vậy ta vẫn chưa truy cập được từ internet. Tiếp đến ta cần expose một External IP để truy cập vào app từ internet. Sử dụng một ELB( Elastic Load Balancer). Tạo mới file service.yml
như sau:
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: elb
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 8080
selector:
app: demo-app
Lưu ý phần selector, điền vào đúng tên của app, chạy lệnh để tạo:
kubectl apply -f service.yaml
Kiểm tra thông tin ELB bằng lệnh:
kubectl get services elb
Kiểm tra tại EXTERNAL-IP
ta sẽ có một domain
. Truy cập domain
để kiểm tra xem app đã được deploy chưa.
Auto deploy via Gitlab-CI
Tạo file .gitlab-ci.yml
Sau tất cả ta đã deploy được một ứng dụng lên EKS. Bước tiếp theo là cần tự động deploy khi có commit mới, việc này ta đã quen ở bài trước. Đó là sử dụng Gitlab-CI. Ngoài Gitlab-CI thì có rất nhiều tool phục vụ việc này như Jenkins, Github actions.
Tạo mới file .gitlab-ci.yml
variables:
REPOSITORY_URL: <aws_account_id>.dkr.ecr.<region>.amazonaws.com
REGION: <region>
stages:
- build
- deploy
build:
stage: build
script:
- docker build -t demo-app -f ./Dockerfile .
- docker tag demo-app $REPOSITORY_URL/demo-app:${CI_COMMIT_SHORT_SHA}
- docker push $REPOSITORY_URL/demo-app:${CI_COMMIT_SHORT_SHA}
only:
- master
deploy:
stage: deploy
environment: production
script:
- kubectl set image deployment/demo-app demo-app=$REPOSITORY_URL/demo-app:${CI_COMMIT_SHORT_SHA} --record
Giải thích:
- Trong file này mình định nghĩa ra 2 stage: build và deploy. Stage build có nhiệm vụ dockerize và push image lên ECR, còn stage deploy có nhiệm vụ cập nhật lại image đó lên các node của k8s
- Để chạy được các dòng lệnh này, Gitlab dùng Runner để thực hiện. Mình sẽ nói kỹ hơn về Runner ở phần dưới đây.
Gitlab-runner
Hiểu nôm na là khi bạn commit code lên gitlab mà trong thư mục gốc có file .gitlab-ci.yml, thì Gitlab-CI sẽ được trigger. Gitlab-CI sẽ sử dụng Runner (được cài đặt trong mục Setting => CI-CD => Runner) để chạy các dòng lệnh trong file .gitlab-ci.yml.
Có 2 loại Runner là: Share Runners và Specifics Runner
Share Runners
Là runner đã cài đặt sẵn các chương trình ví dụ docker, shell, kubernetes ... mà mọi người đều có thể dùng được. Chỉ cần chọn Enable shared Runners như hình bên trên.
Ưu điểm: Không cần cài đặt gì thêm, plug and play.
Nhược điểm: Mình không thể custom cho Runner này, ví dụ muốn cài thêm biến môi trường chẳng hạn.
Specifics Runner
Có 2 cách để setup Specifics Runner là cài tự động và thủ công. Cách cài tự động là cài trên k8s mình sẽ nói sau, trong bài này mình sẽ chỉ các bạn cách cài đặt thủ công trên máy local.
Output của bước này là khi Gitlab-CI chạy nó sẽ chạy con runner lên chính con máy của các bạn ( các bạn cũng có thể cài gitlab-runner lên một con server bất kỳ). Do các biến môi trường đã cài sẵn trên máy các bạn rồi nên nhìn file .gitlab-ci.yml rất gọn.
Các bước cài đặt:
- Tuỳ theo hệ điều hành, bạn chọn cách cài đặt phù hợp tại link
- Khi cài xong bạn cần register với gitlab bằng lệnh
gitlab-runner register
- Làm theo hướng dẫn. Lưu ý rằng gitlab-runner có nhiều loại executor (docker, k8s, shell, ssh ..) nhưng theo cách mình đang làm thì bạn chọn là
shell
. Sau đó chạy gitlab-runner lên:
gitlab-runner run
Bạn vào Setting => CI-CD => Runners để kiểm tra, nếu có chấm màu xanh là thành công
Lưu ý quan trọng: bạn ấn vào hình cái bút để edit runner và tick vào Run untagged jobs. Nếu không tick chọn vào đây, thì executor chỉ chạy với các stage có cùng tag với nó. Mà ở trên file .gitlab-ci.yml mình không định nghĩa cho các stage, nên kết quả là executor này sẽ không chạy.
Khi có một commit mới, gitlab-CI sẽ trigger đến gitlab-runner trên máy bạn và chạy các script trong file .gitlab-ci.yml
Trong file gitlab-ci.yml bạn để ý sẽ thấy có biến {CI_COMMIT_SHORT_SHA}. Đây là ID của một commit, ta dùng short ID của commit để đánh tag cho image ( thay vì image nào cũng là latest). Một commit đươc push lên sẽ tương ứng có 1 file docker image được sinh ra. Việc này sẽ phục vụ cho việc rollback nếu có lỗi xảy ra.
Sửa code một chút rồi commit lại để tận hưởng thành quả nhé.
Cleaning Up
Sau khi đạt được thành quả, bạn có thể ngắm nhìn một lúc, take a screenshot nhưng đừng quên xoá nó đi nếu không có ý định sử dụng lâu dài.
eksctl delete cluster --name=demo-app
Kết luận
Bài viết trên đây là một hành trình đến Docker, k8s, AWS với học phí 21.53$ của mình. Các bạn có thắc mắc gì thì comment nhé. Tài liệu tham khảo:
All rights reserved