0

🚀 Chapter 5 — Platform: Phần J — Triển khai Google Online Boutique từ Amazon ECR qua GitOps lên Amazon EKS

Ở Chapter 5F, chúng ta đã sử dụng Helm và Argo CD để quản lý ba môi trường:

GitHub GitOps Repository
          ↓
        Argo CD
          ↓
      Amazon EKS
          ↓
   Dev / Staging / Production

Tuy nhiên, image của các service vẫn chưa được kết nối hoàn chỉnh với quy trình CI/CD.

Trong phần này, chúng ta sẽ xây dựng flow:

Developer
    ↓
GitHub Application Repository
    ↓
GitHub Actions
    ↓
Docker Build
    ↓
Amazon ECR
    ↓
Update image tag trong GitOps Repository
    ↓
Argo CD
    ↓
Amazon EKS
    ↓
Google Online Boutique

Mục tiêu của phần này là:

  • Build Docker image bằng GitHub Actions.
  • Push image lên Amazon ECR.
  • Sử dụng Git commit SHA làm image tag.
  • Cập nhật image tag trong GitOps repository.
  • Để Argo CD tự động triển khai image mới lên EKS.
  • Không sử dụng kubectl apply trực tiếp từ CI/CD.
  • Giữ GitOps repository là nguồn dữ liệu chính của deployment.

1. Kiến trúc triển khai

Sau khi hoàn thành Chapter 5J, flow sẽ như sau:

                 Application Repository
                         GitHub
                           │
                           ▼
                    GitHub Actions
                           │
                 ┌─────────┴─────────┐
                 ▼                   ▼
              Test              Docker Build
                                       │
                                       ▼
                                Amazon ECR
                                       │
                                       ▼
                         Update GitOps Repository
                                       │
                                       ▼
                              Git commit image tag
                                       │
                                       ▼
                              Argo CD detects change
                                       │
                                       ▼
                                  Amazon EKS
                                       │
                ┌──────────────────────┼──────────────────────┐
                ▼                      ▼                      ▼
              Dev                  Staging               Production

Trong phần này:

  • GitHub Actions chịu trách nhiệm build và push image.
  • GitOps repository chịu trách nhiệm lưu image version cần deploy.
  • Argo CD chịu trách nhiệm đồng bộ deployment vào EKS.
  • EKS chỉ triển khai image version được khai báo trong GitOps repository.

2. Chuẩn bị repository

Chúng ta sử dụng hai repository:

Application repository

Repository chứa source code của Online Boutique:

microservices-demo/

Ví dụ service:

src/
├── frontend/
├── cartservice/
├── paymentservice/
├── checkoutservice/
└── ...

GitOps repository

Repository đã tạo ở Chapter 5F:

online-boutique-gitops/

Cấu trúc hiện tại có thể tương tự:

online-boutique-gitops/
├── helm-chart/
│   ├── Chart.yaml
│   ├── values.yaml
│   ├── values-dev.yaml
│   ├── values-staging.yaml
│   ├── values-production.yaml
│   └── templates/
│       ├── frontend.yaml
│       ├── cartservice.yaml
│       ├── paymentservice.yaml
│       └── ...
│
└── argocd/
    ├── online-boutique-dev.yaml
    ├── online-boutique-staging.yaml
    └── online-boutique-production.yaml

3. Kiểm tra Amazon ECR

Đặt region sử dụng trong lab:

export AWS_REGION=ap-northeast-1

Kiểm tra AWS Identity:

aws sts get-caller-identity

Kiểm tra danh sách ECR repository:

aws ecr describe-repositories \
  --region "$AWS_REGION" \
  --query 'repositories[].repositoryName' \
  --output table

Kết quả có thể tương tự:

--------------------------------
|       DescribeRepositories   |
+------------------------------+
|  online-boutique/frontend    |
|  online-boutique/cartservice |
|  online-boutique/paymentservice |
+------------------------------+

Nếu chưa có repository cho frontend, tạo repository:

aws ecr create-repository \
  --repository-name online-boutique/frontend \
  --region "$AWS_REGION"

Kiểm tra lại:

aws ecr describe-repositories \
  --repository-names online-boutique/frontend \
  --region "$AWS_REGION"

Lấy AWS Account ID:

export AWS_ACCOUNT_ID=$(aws sts get-caller-identity \
  --query Account \
  --output text)

Tạo biến ECR registry:

export ECR_REGISTRY="${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com"

Kiểm tra:

echo "$ECR_REGISTRY"

Ví dụ:

123456789012.dkr.ecr.ap-northeast-1.amazonaws.com

4. Kiểm tra Docker image của frontend

Di chuyển đến Application repository:

cd microservices-demo

Kiểm tra thư mục frontend:

ls src/frontend

Kiểm tra Dockerfile:

find src/frontend -maxdepth 2 -name 'Dockerfile' -print

Kết quả mong đợi:

src/frontend/Dockerfile

Build thử image local:

docker build \
  -t online-boutique-frontend:test \
  ./src/frontend

Kiểm tra image:

docker images | grep online-boutique-frontend

Nếu build thành công, tiếp tục bước tiếp theo.


5. Kiểm tra image repository trong Helm chart

Di chuyển đến GitOps repository:

cd ../online-boutique-gitops

Tìm cấu hình image hiện tại:

grep -Rni "image:" helm-chart

Hoặc:

grep -Rni "repository:" helm-chart

Mở file values của Dev:

nano helm-chart/values-dev.yaml

Thêm hoặc điều chỉnh cấu hình frontend:

frontend:
  image:
    repository: 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/online-boutique/frontend
    tag: test
  replicaCount: 1

Thay:

123456789012

bằng AWS Account ID của bạn.

Tên field image.repositoryimage.tag phải khớp với template Helm hiện tại. Nếu chart đang sử dụng tên field khác, cần sửa theo cấu trúc chart của bạn.

Kiểm tra template frontend:

grep -Rni "Values.frontend" helm-chart/templates

Ví dụ template cần có logic tương tự:

image: "{{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag }}"

Render Helm chart:

helm template online-boutique-dev \
  ./helm-chart \
  --namespace online-boutique-dev \
  -f ./helm-chart/values.yaml \
  -f ./helm-chart/values-dev.yaml

Nếu không có lỗi, tiếp tục.


6. Tạo cấu hình image cho ba môi trường

Mở file Dev:

nano helm-chart/values-dev.yaml

Ví dụ:

frontend:
  replicaCount: 1
  image:
    repository: 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/online-boutique/frontend
    tag: test

Mở file Staging:

nano helm-chart/values-staging.yaml

Ví dụ:

frontend:
  replicaCount: 2
  image:
    repository: 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/online-boutique/frontend
    tag: test

Mở file Production:

nano helm-chart/values-production.yaml

Ví dụ:

frontend:
  replicaCount: 3
  image:
    repository: 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/online-boutique/frontend
    tag: test

Ở bước đầu, cả ba môi trường dùng tag test.

Sau này GitHub Actions sẽ thay test bằng commit SHA:

a81c92f

7. Kiểm tra Helm chart

Chạy:

helm lint ./helm-chart

Render môi trường Dev:

helm template online-boutique-dev \
  ./helm-chart \
  --namespace online-boutique-dev \
  -f ./helm-chart/values.yaml \
  -f ./helm-chart/values-dev.yaml \
  > /tmp/online-boutique-dev.yaml

Kiểm tra image:

grep -n "image:" /tmp/online-boutique-dev.yaml

Render Staging:

helm template online-boutique-staging \
  ./helm-chart \
  --namespace online-boutique-staging \
  -f ./helm-chart/values.yaml \
  -f ./helm-chart/values-staging.yaml \
  > /tmp/online-boutique-staging.yaml

Render Production:

helm template online-boutique-production \
  ./helm-chart \
  --namespace online-boutique-production \
  -f ./helm-chart/values.yaml \
  -f ./helm-chart/values-production.yaml \
  > /tmp/online-boutique-production.yaml

Kiểm tra image repository:

grep -n "online-boutique/frontend" \
  /tmp/online-boutique-dev.yaml

8. Commit cấu hình ECR ban đầu

Kiểm tra thay đổi:

git status

Commit:

git add helm-chart
git commit -m "configure ECR image repository for frontend"

Push:

git push origin chapter-5f-multi-environment

Argo CD sẽ phát hiện thay đổi trong GitOps repository và đồng bộ lại cấu hình.

Kiểm tra Application:

argocd app get online-boutique-dev

Kiểm tra Deployment:

kubectl get deployment frontend \
  -n online-boutique-dev

9. Tạo IAM policy cho GitHub Actions

GitHub Actions cần quyền:

  • Đăng nhập vào Amazon ECR.
  • Push Docker image.
  • Ghi các layer của image.
  • Kiểm tra image tồn tại.

Tạo file policy:

nano github-actions-ecr-policy.json

Thêm:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ECRAuthentication",
      "Effect": "Allow",
      "Action": [
        "ecr:GetAuthorizationToken"
      ],
      "Resource": "*"
    },
    {
      "Sid": "ECRPush",
      "Effect": "Allow",
      "Action": [
        "ecr:BatchCheckLayerAvailability",
        "ecr:CompleteLayerUpload",
        "ecr:InitiateLayerUpload",
        "ecr:PutImage",
        "ecr:UploadLayerPart",
        "ecr:BatchGetImage",
        "ecr:DescribeRepositories"
      ],
      "Resource": "arn:aws:ecr:ap-northeast-1:123456789012:repository/online-boutique/frontend"
    }
  ]
}

Thay:

123456789012

bằng AWS Account ID của bạn.

Tạo IAM policy:

aws iam create-policy \
  --policy-name GitHubActionsOnlineBoutiqueECRPush \
  --policy-document file://github-actions-ecr-policy.json

Trong production, nên sử dụng GitHub OIDC thay vì lưu AWS Access Key dài hạn trong GitHub Secrets. Phần này có thể được triển khai thành một bài nâng cao riêng.


10. Tạo GitHub Secrets

Trong Application repository, mở:

GitHub
→ Repository
→ Settings
→ Secrets and variables
→ Actions
→ New repository secret

Tạo các secret sau:

AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
AWS_REGION
AWS_ACCOUNT_ID
GITOPS_REPO
GH_PAT

Ví dụ:

AWS_REGION=ap-northeast-1
AWS_ACCOUNT_ID=123456789012
GITOPS_REPO=Juu-dev/online-boutique-gitops

GH_PAT là GitHub Personal Access Token có quyền ghi vào GitOps repository.

Token cần có quyền phù hợp để:

  • Clone GitOps repository.
  • Sửa file values.
  • Commit.
  • Push branch.

Không đưa token trực tiếp vào file workflow.


11. Tạo GitHub Actions workflow

Trong Application repository:

mkdir -p .github/workflows

Tạo file:

nano .github/workflows/build-push-update-gitops.yml

Thêm nội dung:

name: Build, Push to ECR and Update GitOps

on:
  push:
    branches:
      - main
    paths:
      - "src/frontend/**"
      - ".github/workflows/build-push-update-gitops.yml"

permissions:
  contents: read

env:
  AWS_REGION: ${{ secrets.AWS_REGION }}
  AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }}
  ECR_REPOSITORY: online-boutique/frontend
  SERVICE_NAME: frontend
  GITOPS_REPOSITORY: ${{ secrets.GITOPS_REPO }}
  GITOPS_BRANCH: chapter-5f-multi-environment

jobs:
  build-push-update:
    name: Build, Push and Update GitOps
    runs-on: ubuntu-latest

    steps:
      - name: Checkout application repository
        uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ env.AWS_REGION }}

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2

      - name: Set image variables
        id: image
        shell: bash
        run: |
          IMAGE_TAG="${GITHUB_SHA::7}"
          ECR_REGISTRY="${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com"
          IMAGE_URI="${ECR_REGISTRY}/${ECR_REPOSITORY}:${IMAGE_TAG}"

          echo "IMAGE_TAG=${IMAGE_TAG}" >> "$GITHUB_OUTPUT"
          echo "IMAGE_URI=${IMAGE_URI}" >> "$GITHUB_OUTPUT"

      - name: Run frontend tests
        working-directory: src/frontend
        run: |
          echo "Run frontend tests here"
          # Thay bằng lệnh test thực tế của frontend nếu có

      - name: Build Docker image
        run: |
          docker build \
            -t "${{ steps.image.outputs.IMAGE_URI }}" \
            ./src/frontend

      - name: Push Docker image to ECR
        run: |
          docker push "${{ steps.image.outputs.IMAGE_URI }}"

      - name: Checkout GitOps repository
        uses: actions/checkout@v4
        with:
          repository: ${{ env.GITOPS_REPOSITORY }}
          ref: ${{ env.GITOPS_BRANCH }}
          token: ${{ secrets.GH_PAT }}
          path: gitops

      - name: Update Dev image tag
        working-directory: gitops
        run: |
          python3 - <<'PY'
          from pathlib import Path

          file_path = Path("helm-chart/values-dev.yaml")
          content = file_path.read_text()

          old_tag = "tag: test"
          new_tag = "tag: ${{ steps.image.outputs.IMAGE_TAG }}"

          if old_tag not in content:
              raise SystemExit("Could not find the expected image tag in values-dev.yaml")

          file_path.write_text(content.replace(old_tag, new_tag, 1))
          PY

      - name: Commit and push GitOps change
        working-directory: gitops
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

          git add helm-chart/values-dev.yaml

          git diff --cached --quiet && {
            echo "No GitOps changes detected"
            exit 0
          }

          git commit -m "deploy frontend ${{ steps.image.outputs.IMAGE_TAG }} to dev"
          git push origin "${{ env.GITOPS_BRANCH }}"

Lưu ý:

  • Workflow trên chỉ cập nhật môi trường dev.
  • stagingproduction sẽ được cập nhật ở các bước promotion tiếp theo.
  • Phần thay thế tag: test cần được điều chỉnh nếu file values của bạn đang dùng tag khác.

12. Kiểm tra workflow

Kiểm tra file:

cat .github/workflows/build-push-update-gitops.yml

Commit workflow:

git add .github/workflows/build-push-update-gitops.yml
git commit -m "add ECR build and GitOps update workflow"

Push lên branch main:

git push origin main

Mở GitHub:

Repository
→ Actions
→ Build, Push to ECR and Update GitOps

Theo dõi các bước:

Checkout application repository
        ↓
Configure AWS credentials
        ↓
Login to Amazon ECR
        ↓
Run frontend tests
        ↓
Build Docker image
        ↓
Push Docker image to ECR
        ↓
Checkout GitOps repository
        ↓
Update Dev image tag
        ↓
Commit and push GitOps change

13. Kiểm tra image trên ECR

Sau khi workflow thành công, chạy:

aws ecr list-images \
  --repository-name online-boutique/frontend \
  --region "$AWS_REGION"

Hoặc hiển thị image tag:

aws ecr describe-images \
  --repository-name online-boutique/frontend \
  --region "$AWS_REGION" \
  --query 'imageDetails[].imageTags' \
  --output table

Kết quả có thể tương tự:

----------------
| imageTags    |
+--------------+
| a81c92f       |
| test          |
+--------------+

Lấy image digest:

aws ecr describe-images \
  --repository-name online-boutique/frontend \
  --region "$AWS_REGION" \
  --query 'imageDetails[].{Tags:imageTags,Digest:imageDigest}' \
  --output table

14. Kiểm tra GitOps repository

Clone hoặc cập nhật GitOps repository:

cd ../online-boutique-gitops
git pull origin chapter-5f-multi-environment

Mở file:

cat helm-chart/values-dev.yaml

Kiểm tra tag:

frontend:
  image:
    repository: 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/online-boutique/frontend
    tag: a81c92f

Tag a81c92f chính là 7 ký tự đầu của Git commit SHA.

Kiểm tra lịch sử commit:

git log --oneline -5

Kết quả có thể tương tự:

a123456 deploy frontend a81c92f to dev

15. Kiểm tra Argo CD

Xem trạng thái Application:

argocd app get online-boutique-dev

Theo dõi quá trình đồng bộ:

argocd app wait online-boutique-dev \
  --sync \
  --health

Kiểm tra Deployment:

kubectl get deployment frontend \
  -n online-boutique-dev

Kiểm tra Pod:

kubectl get pods \
  -n online-boutique-dev \
  -l app=frontend

Kiểm tra image thực tế đang chạy:

kubectl get deployment frontend \
  -n online-boutique-dev \
  -o jsonpath='{.spec.template.spec.containers[*].image}'

Kết quả mong đợi:

123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/online-boutique/frontend:a81c92f

Kiểm tra image của Pod:

kubectl get pod \
  -n online-boutique-dev \
  -l app=frontend \
  -o jsonpath='{.items[0].status.containerStatuses[*].imageID}'

16. Kiểm tra toàn bộ flow

Thực hiện một thay đổi nhỏ trong frontend:

cd ../microservices-demo

Ví dụ chỉnh sửa một file frontend:

nano src/frontend/some-file

Commit:

git add src/frontend
git commit -m "update frontend"

Push:

git push origin main

Kiểm tra flow:

Git push
   ↓
GitHub Actions
   ↓
Docker Build
   ↓
Push image lên ECR
   ↓
Cập nhật values-dev.yaml
   ↓
GitOps commit
   ↓
Argo CD sync
   ↓
EKS rollout

Theo dõi rollout:

kubectl rollout status deployment/frontend \
  -n online-boutique-dev

Kiểm tra ReplicaSet:

kubectl get replicasets \
  -n online-boutique-dev

Kiểm tra thời gian deploy:

kubectl rollout history deployment/frontend \
  -n online-boutique-dev

17. Kiểm tra GitOps drift

Thử thay đổi image trực tiếp trong cluster:

kubectl set image deployment/frontend \
  frontend=nginx:latest \
  -n online-boutique-dev

Kiểm tra image:

kubectl get deployment frontend \
  -n online-boutique-dev \
  -o jsonpath='{.spec.template.spec.containers[*].image}'

Argo CD sẽ phát hiện trạng thái thực tế khác với Git.

Kiểm tra:

argocd app get online-boutique-dev

Nếu selfHeal: true đang bật, Argo CD sẽ đưa Deployment về image được khai báo trong GitOps repository.

Kiểm tra lại:

kubectl get deployment frontend \
  -n online-boutique-dev \
  -o jsonpath='{.spec.template.spec.containers[*].image}'

Kết quả cần quay về:

123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/online-boutique/frontend:a81c92f

18. Tách promotion Dev → Staging → Production

Ở bước trước, GitHub Actions chỉ cập nhật Dev.

Flow hiện tại:

Build image
    ↓
Push ECR
    ↓
Update Dev
    ↓
Argo CD deploy Dev

Sau khi Dev được kiểm tra thành công, chúng ta có thể promote cùng image tag sang Staging.

Ví dụ mở file:

nano helm-chart/values-staging.yaml

Thay:

frontend:
  image:
    tag: test

thành:

frontend:
  image:
    tag: a81c92f

Commit:

git add helm-chart/values-staging.yaml
git commit -m "promote frontend a81c92f to staging"
git push origin chapter-5f-multi-environment

Kiểm tra:

argocd app get online-boutique-staging

Sau khi Staging được kiểm tra, promote cùng tag sang Production:

nano helm-chart/values-production.yaml

Thay:

frontend:
  image:
    tag: test

thành:

frontend:
  image:
    tag: a81c92f

Commit:

git add helm-chart/values-production.yaml
git commit -m "promote frontend a81c92f to production"
git push origin chapter-5f-multi-environment

Điểm quan trọng:

Không build lại image cho từng môi trường.

Chúng ta sử dụng cùng một image:

frontend:a81c92f

cho:

Dev
 ↓
Staging
 ↓
Production

19. Kiểm tra rollback bằng Git

Giả sử image mới gây lỗi:

frontend:a81c92f

Tìm commit trước đó:

git log --oneline -- helm-chart/values-production.yaml

Rollback bằng Git revert:

git revert <COMMIT_ID>

Push:

git push origin chapter-5f-multi-environment

Argo CD sẽ phát hiện commit mới và triển khai lại image version cũ.

Kiểm tra:

argocd app get online-boutique-production

Kiểm tra image:

kubectl get deployment frontend \
  -n online-boutique-production \
  -o jsonpath='{.spec.template.spec.containers[*].image}'

20. Kiểm tra cuối cùng

Kiểm tra ECR

aws ecr describe-images \
  --repository-name online-boutique/frontend \
  --region "$AWS_REGION"

Kiểm tra GitOps

git log --oneline -5

Kiểm tra Argo CD

argocd app list

Kiểm tra EKS

kubectl get pods -n online-boutique-dev
kubectl get pods -n online-boutique-staging
kubectl get pods -n online-boutique-production

Kiểm tra image của từng môi trường

kubectl get deployment frontend \
  -n online-boutique-dev \
  -o jsonpath='{.spec.template.spec.containers[*].image}'
kubectl get deployment frontend \
  -n online-boutique-staging \
  -o jsonpath='{.spec.template.spec.containers[*].image}'
kubectl get deployment frontend \
  -n online-boutique-production \
  -o jsonpath='{.spec.template.spec.containers[*].image}'

Kết quả mong đợi:

Dev        → frontend:a81c92f
Staging    → frontend:a81c92f
Production → frontend:a81c92f

21. Kiến trúc cuối Chapter 5J

                    Developer
                        │
                        ▼
                GitHub Application Repo
                        │
                        ▼
                 GitHub Actions
                        │
             ┌──────────┴──────────┐
             ▼                     ▼
          Test                Docker Build
                                    │
                                    ▼
                              Amazon ECR
                                    │
                                    ▼
                         Image tag từ Git SHA
                                    │
                                    ▼
                         GitOps Repository
                                    │
                                    ▼
                                Argo CD
                                    │
                                    ▼
                              Amazon EKS
                                    │
              ┌─────────────────────┼─────────────────────┐
              ▼                     ▼                     ▼
             Dev                 Staging              Production

Kết quả đạt được

Sau Chapter 5J:

  • GitHub Actions build Docker image.
  • Docker image được lưu trong Amazon ECR.
  • Image tag được tạo từ Git commit SHA.
  • GitOps repository lưu image version cần triển khai.
  • Argo CD tự động đồng bộ thay đổi từ Git.
  • EKS triển khai image từ ECR.
  • Dev, Staging và Production sử dụng cùng một artifact.
  • Có thể rollback bằng git revert.
  • Không cần chạy kubectl apply trực tiếp từ GitHub Actions.

Đây là flow:

Build once
    ↓
Store in ECR
    ↓
Promote through Git
    ↓
Deploy with Argo CD

Lưu ý: Trong production thực tế, nên thay AWS Access Key bằng GitHub OIDC, sử dụng image digest thay vì chỉ image tag, bật ECR image scanning, và thiết lập approval trước khi promote Production.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí