Cung cấp EKS Cluster và Tự động hóa Deployment
Tạo Cấu hình EKS Cluster
Chúng ta sẽ sử dụng eksctl
để build cluster. Thực tiễn tốt nhất là định nghĩa cluster trong một file cấu hình, sau đó bạn có thể commit vào Git repository để kiểm soát phiên bản và tái tạo.
Trong root directory của dự án, tạo thư mục mới có tên
k8s
.mkdir k8s cd k8s
Tạo file mới có tên
cluster.yaml
Dán nội dung sau vào
cluster.yaml
. Đọc các comment để hiểu từng dòng làm gì# k8s/cluster.yaml apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: # Tên cluster của bạn name: workshop-cluster # AWS region nơi cluster sẽ được tạo region: us-east-2 # Phiên bản Kubernetes của cluster version: "1.33" # Section này định nghĩa các Kubernetes worker node nodeGroups: - name: ng-1-workers # Tên cho node group instanceType: t3.medium # Instance type general-purpose mặc định. desiredCapacity: 2 # Bắt đầu với 2 node cho high availability minSize: 1 # Để tiết kiệm chi phí, bạn có thể scale down xuống 1 node khi không test tích cực maxSize: 3 # Giới hạn max size để ngăn chi phí vượt quá do tai nạn # Khuyến nghị: Sử dụng AWS Bottlerocket OS để bảo mật tốt hơn và footprint nhỏ hơn amiFamily: Bottlerocket # Khuyến nghị: Launch nodegroup trong private subnet privateNetworking: true accessConfig: authenticationMode: API_AND_CONFIG_MAP # Tạo EKS access entry để giúp GitHub Actions workflow có thể deploy vào cluster accessEntries: # QUAN TRỌNG: Thay thế <<AWS Account ID>> bằng AWS Account ID của bạn - principalARN: arn:aws:iam::<<AWS Account ID>>:role/WorkshopGitHubActionsRole accessPolicies: - policyARN: arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy accessScope: type: cluster
Khởi chạy EKS Cluster
Bây giờ, thực thi lệnh để build cluster.
Mở terminal trong thư mục
secure-container-pipeline
.Chạy lệnh tạo:
eksctl create cluster -f k8s/cluster.yaml
Hãy kiên nhẫn. Quá trình này sẽ mất 15-20 phút.
eksctl
sẽ in ra rất nhiều thông tin khi nó cung cấp các tài nguyên trong AWS CloudFormation. Hãy đi uống cà phê.Xác nhận: Khi hoàn tất,
eksctl
sẽ tự động cập nhật filekubeconfig
local của bạn (~/.kube/config
). Điều này có nghĩakubectl
bây giờ sẽ trỏ đến EKS cluster mới của bạn.
Xác minh Quyền truy cập Cluster
Hãy đảm bảo bạn có thể giao tiếp với cluster mới.
Chạy lệnh
kubectl
này:kubectl get nodes
Bạn sẽ thấy output liệt kê hai worker node, tương tự như thế này:
NAME STATUS ROLES AGE VERSION ip-192-168-158-45.us-east-2.compute.internal Ready <none> 6m16s v1.33.1-eks-b9364f6 ip-192-168-173-179.us-east-2.compute.internal Ready <none> 6m21s v1.33.1-eks-b9364f6
Tạo Kubernetes Deployment Manifest
Chúng ta cần nói với Kubernetes cách chạy ứng dụng của chúng ta. Chúng ta sẽ làm điều này với hai file tài nguyên Kubernetes tiêu chuẩn: một Deployment (để quản lý các Pod ứng dụng) và một Service (để expose ứng dụng ra traffic).
Trong root directory của dự án, tạo thư mục mới có tên
k8s
.mkdir k8s cd k8s
Tạo file
deployment.yaml
:# Trong thư mục 'k8s' touch deployment.yaml
Dán nội dung này vào k8s/deployment.yaml. Chú ý đặc biệt đến dòng ##IMAGE_TAG_PLACEHOLDER##; chúng ta sẽ thay thế điều này một cách động trong pipeline của chúng ta.
# k8s/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: workshop-app labels: app: workshop-app spec: replicas: 2 # Chạy hai instance cho availability selector: matchLabels: app: workshop-app template: metadata: labels: app: workshop-app spec: containers: - name: workshop-app # QUAN TRỌNG: Đây là placeholder. Pipeline của chúng ta sẽ thay thế nó. image: "IMAGE_PLACEHOLDER" ports: - containerPort: 8080 # --- Security Context --- # Điều này thực thi các thực tiễn bảo mật tốt nhất ở cấp độ container. securityContext: # Ngăn container có được nhiều quyền hơn parent process. allowPrivilegeEscalation: false # Chạy container với read-only root filesystem. readOnlyRootFilesystem: true # Củng cố non-root user của Dockerfile. runAsNonRoot: true # Chỉ định user và group ID để chạy, khớp với Dockerfile. runAsUser: 1001 runAsGroup: 1001 # Drop tất cả Linux capability và chỉ thêm lại những gì cần thiết (không có trong trường hợp này). capabilities: drop: - "ALL" # Vị trí cho file tạm thời, vì root filesystem là read-only. volumes: - name: tmp emptyDir: {}
Tạo file
service.yaml
:# Trong thư mục 'k8s' touch service.yaml
Dán nội dung này vào
k8s/service.yaml
. Điều này sẽ tạo một serviceLoadBalancer
, tự động cung cấp AWS Network Load Balancer để expose ứng dụng của bạn ra internet.# k8s/service.yaml apiVersion: v1 kind: Service metadata: name: workshop-app-service spec: selector: app: workshop-app # Type này tạo external AWS Load Balancer type: LoadBalancer ports: - protocol: TCP port: 80 # Port mà load balancer lắng nghe targetPort: 8080 # Port mà container lắng nghe
Quay lại root directory của dự án:
cd ..
Cập nhật IAM Role cho Quyền Deployment
WorkshopGitHubActionsRole
của chúng ta có thể push vào ECR, nhưng nó chưa thể giao tiếp với EKS cluster. Chúng ta cần cấp quyền cho nó.
Trong AWS Console, đi đến IAM → Roles →.
Chọn role
WorkshopGitHubActionsRole
.Trong tab Permissions, section Permissions policies, chọn Add permissions → Create inline policy.
Với Policy editor, chọn JSON, dán policy sau và thay thế AWS account ID:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "Statement1", "Effect": "Allow", "Action": "eks:DescribeCluster", "Resource": "arn:aws:eks:us-east-2:<<AWS Account ID>>:cluster/workshop-cluster" } ] }
Click Next.
Đặt tên cho policy, như
DescribeWorkshopEKSCluster
.Tạo policy.
Cập nhật GitHub Actions Workflow để Deploy
Bây giờ, chúng ta sẽ thêm job deploy
mới vào file ci.yml
.
Mở
.github/workflows/ci.yml
.Thêm job
deploy
mới vào cuối file. File hoàn chỉnh, cập nhật sẽ giống như thế này:# .github/workflows/ci.yml # ... (các tham số khác được bỏ qua) ... jobs: build-scan-push: # ... (job build-scan-push vẫn giữ nguyên như trước) ... # ---- JOB DEPLOY MỚI ---- deploy: # Job này chỉ chạy nếu job 'build-scan-push' thành công name: Deploy to EKS needs: build-scan-push runs-on: ubuntu-latest permissions: # Bắt buộc cho kết nối OIDC đến AWS id-token: write contents: read steps: - name: Checkout repository uses: actions/checkout@v5 - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: arn:aws:iam::<<AWS Account ID>>:role/WorkshopGitHubActionsRole # <-- DÁN ROLE ARN CỦA BẠN VÀO ĐÂY aws-region: ${{ env.AWS_REGION }} - name: Set up Kubeconfig for EKS run: aws eks update-kubeconfig --name ${{ env.EKS_CLUSTER_NAME }} --region ${{ env.AWS_REGION }} - name: Substitute image tag in Kubernetes manifest run: | sed -i 's|IMAGE_PLACEHOLDER|${{ needs.build-scan-push.outputs.image }}|' k8s/deployment.yaml - name: Deploy to EKS cluster run: | echo "--- Applying deployment.yaml ---" cat k8s/deployment.yaml kubectl apply -f k8s/deployment.yaml echo "--- Applying service.yaml ---" kubectl apply -f k8s/service.yaml
Thay đổi Chính:
- Job
deploy
mới được thêm vào. needs: build-scan-push
đảm bảo deployment chỉ xảy ra sau khi build và scan thành công.- Lệnh
sed
là bước quan trọng tìmIMAGE_PLACEHOLDER
và thay thế nó bằng image URI thực tế, unique từ bước build. kubectl apply
gửi cấu hình của chúng ta đến EKS cluster.
- Job
Commit, push và xác minh deployment:
Commit thay đổi của bạn:
git add . git commit -m "feat: Add k8s manifests and deploy job to CI workflow" git push origin main
Theo dõi pipeline: Đi đến tab Actions trong GitHub. Bạn sẽ thấy pipeline đầy đủ chạy. Lần này, sau khi “Build, Scan & Push” hoàn tất, job “Deploy to EKS” sẽ bắt đầu.
Xác minh trong terminal: Khi pipeline thành công, kiểm tra trạng thái deployment của bạn.
Kiểm tra pod:
kubectl get pods -l app=workshop-app
Bạn sẽ thấy hai pod với trạng thái
Running
.Kiểm tra service và lấy Load Balancer URL:
kubectl get service workshop-app-service
Sẽ mất một hoặc hai phút để AWS cung cấp load balancer.
EXTERNAL-IP
sẽ thay đổi từ<pending>
thành một DNS name dài.
Test ứng dụng! Copy DNS name
EXTERNAL-IP
và dán vào trình duyệt web. Bạn sẽ thấy thông báo:Hello, FCJ-ers!