0

🚀 Chapter 4 — Production: Phần B — Quản lý Docker Image với Amazon ECR Lifecycle Policy

Chapter 4A, chúng ta đã thay đổi kiến trúc:

GitHub
   ↓
GitHub Actions
   ↓
Matrix
   ↓
Reusable Workflow
   ↓
Docker Build
   ↓
Amazon ECR
   ↓
SSH
   ↓
EC2
   ↓
docker pull
   ↓
Docker Compose

EC2 không còn phải build Docker image nữa.

Nhưng khi CI/CD chạy nhiều lần, ECR sẽ bắt đầu có rất nhiều image:

frontend
├── image-001
├── image-002
├── image-003
├── image-004
├── image-005
├── ...
└── image-100

Nếu mỗi lần git push đều tạo một image mới, số lượng image sẽ tăng liên tục.

Vì vậy ở Chapter 4B, chúng ta sẽ giải quyết vấn đề:

Image nào cần giữ lại? Image nào có thể tự động xóa?

AWS ECR cung cấp Lifecycle Policy để tự động expire hoặc archive các image không còn cần thiết. Policy có thể dựa trên số lượng image hoặc thời gian kể từ khi image được push.


1. Mục tiêu

Sau Chapter 4B, kiến trúc sẽ trở thành:

Developer
    ↓
git push
    ↓
GitHub
    ↓
GitHub Actions
    ↓
Matrix
    ↓
Reusable Workflow
    ↓
Docker Build
    ↓
Amazon ECR
    ↓
Lifecycle Policy
    ↓
Old Images → Expire

Mục tiêu của chúng ta:

✅ Image mới vẫn được push vào ECR

✅ Image đang sử dụng vẫn được giữ

✅ Image cũ tự động được cleanup

✅ Không cần SSH vào EC2 để xóa image

✅ Không cần xóa image thủ công

2. Kiểm tra trạng thái từ Chapter 4A

Trên local:

cd online-boutique-cicd

Kiểm tra Git:

git status

Kiểm tra workflow:

find .github/workflows -type f

Bạn sẽ thấy:

.github/workflows/
├── reusable-ci-cd.yml
└── scale-ci-cd.yml

Kiểm tra AWS region:

aws configure get region

Kết quả:

ap-northeast-1

Nếu chưa có:

aws configure set region ap-northeast-1

3. Kiểm tra các ECR Repository

Chạy:

aws ecr describe-repositories \
  --query 'repositories[].repositoryName' \
  --output table

Bạn sẽ thấy các repository đã tạo ở Chapter 4A:

------------------------------------------------
|              DescribeRepositories             |
+----------------------------------------------+
| online-boutique-frontend                     |
| online-boutique-cartservice                  |
| online-boutique-productcatalogservice        |
| online-boutique-checkoutservice              |
+----------------------------------------------+

Nếu chỉ muốn kiểm tra riêng Online Boutique:

aws ecr describe-repositories \
  --query 'repositories[?starts_with(repositoryName, `online-boutique-`)].repositoryName' \
  --output table

4. Kiểm tra Docker Images trong ECR

Kiểm tra frontend:

aws ecr list-images \
  --repository-name online-boutique-frontend \
  --output table

Nếu workflow Chapter 4A đã chạy nhiều lần, bạn sẽ thấy:

IMAGE TAG
--------
abc123
def456
ghi789
...

Kiểm tra thời gian push:

aws ecr describe-images \
  --repository-name online-boutique-frontend \
  --query 'imageDetails[].{Tag:imageTags[0],Pushed:imagePushedAt}' \
  --output table

Ví dụ:

--------------------------------
|       DescribeImages         |
+----------+-------------------+
| Tag      | Pushed            |
+----------+-------------------+
| abc123   | 2026-09-11...     |
| def456   | 2026-09-10...     |
| ghi789   | 2026-09-09...     |
+----------+-------------------+

5. Tạo Lifecycle Policy đầu tiên

Chúng ta sẽ bắt đầu bằng một policy đơn giản:

Giữ lại 5 image được push gần nhất, các image cũ hơn sẽ được expire.

Tạo file:

mkdir -p ecr
nano ecr/lifecycle-policy.json

Thêm:

{
  "rules": [
    {
      "rulePriority": 1,
      "description": "Keep only the latest 5 images",
      "selection": {
        "tagStatus": "any",
        "countType": "imageCountMoreThan",
        "countNumber": 5
      },
      "action": {
        "type": "expire"
      }
    }
  ]
}

Lưu file.


6. Kiểm tra JSON

Chạy:

cat ecr/lifecycle-policy.json

Bạn phải thấy:

{
  "rules": [
    {
      "rulePriority": 1,
      "description": "Keep only the latest 5 images",
      "selection": {
        "tagStatus": "any",
        "countType": "imageCountMoreThan",
        "countNumber": 5
      },
      "action": {
        "type": "expire"
      }
    }
  ]
}

Nếu máy có jq:

jq . ecr/lifecycle-policy.json

Nếu chưa có:

sudo apt install -y jq

7. Preview Lifecycle Policy

Không áp dụng policy ngay.

Trước tiên chúng ta preview để xem image nào sẽ bị expire.

AWS cũng khuyến nghị sử dụng lifecycle policy preview trước khi áp dụng policy thực tế.

Chạy:

aws ecr start-lifecycle-policy-preview \
  --repository-name online-boutique-frontend \
  --lifecycle-policy-text file://ecr/lifecycle-policy.json

Kết quả sẽ trả về:

previewId
repositoryName
status

Ví dụ:

{
    "registryId": "123456789012",
    "repositoryName": "online-boutique-frontend",
    "lifecyclePolicyText": "...",
    "status": "IN_PROGRESS",
    "previewId": "..."
}

8. Kiểm tra Preview

Chạy:

aws ecr get-lifecycle-policy-preview \
  --repository-name online-boutique-frontend

Ban đầu có thể:

IN_PROGRESS

Chờ vài giây rồi chạy lại:

aws ecr get-lifecycle-policy-preview \
  --repository-name online-boutique-frontend

Khi hoàn tất:

COMPLETE

9. Xem Image nào sẽ bị xóa

Chạy:

aws ecr get-lifecycle-policy-preview \
  --repository-name online-boutique-frontend \
  --query 'previewResults[].{Tag:imageTags[0],Action:action,ImageDigest:imageDigest}' \
  --output table

Ví dụ:

------------------------------------------------
|              GetLifecyclePolicyPreview       |
+----------+----------+------------------------+
| Tag      | Action   | ImageDigest            |
+----------+----------+------------------------+
| abc123   | EXPIRE   | sha256:...             |
| def456   | EXPIRE   | sha256:...             |
| ghi789   | KEEP     | sha256:...             |
| jkl012   | KEEP     | sha256:...             |
| mno345   | KEEP     | sha256:...             |
+----------+----------+------------------------+

Đây là bước rất quan trọng.

Chúng ta kiểm tra policy trước khi cho phép ECR thực sự expire image.


10. Áp dụng Lifecycle Policy

Sau khi preview đúng với mong muốn:

aws ecr put-lifecycle-policy \
  --repository-name online-boutique-frontend \
  --lifecycle-policy-text file://ecr/lifecycle-policy.json

Kết quả:

{
    "registryId": "123456789012",
    "repositoryName": "online-boutique-frontend",
    "lifecyclePolicyText": "..."
}

AWS hỗ trợ tạo hoặc cập nhật lifecycle policy bằng put-lifecycle-policy.


11. Kiểm tra Lifecycle Policy

Chạy:

aws ecr get-lifecycle-policy \
  --repository-name online-boutique-frontend

Hoặc chỉ lấy policy:

aws ecr get-lifecycle-policy \
  --repository-name online-boutique-frontend \
  --query 'lifecyclePolicyText' \
  --output text

Kết quả:

{
  "rules": [
    {
      "rulePriority": 1,
      "description": "Keep only the latest 5 images",
      "selection": {
        "tagStatus": "any",
        "countType": "imageCountMoreThan",
        "countNumber": 5
      },
      "action": {
        "type": "expire"
      }
    }
  ]
}

12. Áp dụng cho các service còn lại

Hiện tại Online Boutique có:

online-boutique-frontend
online-boutique-cartservice
online-boutique-productcatalogservice
online-boutique-checkoutservice

Không nên chỉ quản lý frontend.

Chúng ta áp dụng cùng policy cho tất cả repository.

Chạy:

for repo in \
  online-boutique-frontend \
  online-boutique-cartservice \
  online-boutique-productcatalogservice \
  online-boutique-checkoutservice
do
  aws ecr put-lifecycle-policy \
    --repository-name "$repo" \
    --lifecycle-policy-text file://ecr/lifecycle-policy.json
done

Kiểm tra:

for repo in \
  online-boutique-frontend \
  online-boutique-cartservice \
  online-boutique-productcatalogservice \
  online-boutique-checkoutservice
do
  echo "===== $repo ====="

  aws ecr get-lifecycle-policy \
    --repository-name "$repo" \
    --query 'repositoryName' \
    --output text
done

Kết quả:

===== online-boutique-frontend =====
online-boutique-frontend

===== online-boutique-cartservice =====
online-boutique-cartservice

===== online-boutique-productcatalogservice =====
online-boutique-productcatalogservice

===== online-boutique-checkoutservice =====
online-boutique-checkoutservice

13. Kiểm tra số lượng Image

Frontend:

aws ecr describe-images \
  --repository-name online-boutique-frontend \
  --query 'length(imageDetails)'

Cartservice:

aws ecr describe-images \
  --repository-name online-boutique-cartservice \
  --query 'length(imageDetails)'

Product catalog:

aws ecr describe-images \
  --repository-name online-boutique-productcatalogservice \
  --query 'length(imageDetails)'

Checkout:

aws ecr describe-images \
  --repository-name online-boutique-checkoutservice \
  --query 'length(imageDetails)'

Lưu ý:

Không kỳ vọng image cũ biến mất ngay lập tức.

ECR lifecycle policy thực hiện expire/archive theo cơ chế của ECR; AWS ghi rõ các image bị policy tác động sẽ được expire hoặc archive trong vòng 24 giờ sau khi policy được áp dụng.


14. Tạo thêm image để kiểm tra

Bây giờ chúng ta test thực tế.

Sửa một file bất kỳ:

echo "### Chapter 4B test" >> README.md

Commit:

git add README.md
git commit -m "test ecr lifecycle policy"
git push origin main

GitHub Actions sẽ chạy:

GitHub
   ↓
Matrix
   ↓
Reusable Workflow
   ↓
Docker Build
   ↓
ECR

Image mới được push:

ECR
│
├── image-old
├── image-old
├── image-old
├── image-old
├── image-old
└── image-new

Lifecycle Policy sẽ đảm bảo repository không giữ image vô hạn.


15. Kiểm tra GitHub Actions

Vào:

GitHub
→ Repository
→ Actions
→ Scale CI/CD

Bạn sẽ thấy:

Scale CI/CD
├── frontend
├── cartservice
├── productcatalogservice
└── checkoutservice

Mỗi service:

Docker Build
    ↓
Docker Push
    ↓
ECR

Sau Chapter 4B:

Docker Build
    ↓
ECR
    ↓
Lifecycle Policy
    ↓
Old Image Cleanup

16. Kiểm tra trên AWS Console

Vào:

AWS Console
→ ECR
→ Repositories
→ online-boutique-frontend

Sau đó:

Lifecycle policies

Bạn sẽ thấy rule:

Rule priority: 1

Description:
Keep only the latest 5 images

Image status:
Any

Match criteria:
Image count more than 5

Action:
Expire

AWS Console cũng cho phép tạo lifecycle rule theo image status, tag pattern/prefix và image count hoặc thời gian.


17. Cấu trúc project sau Chapter 4B

Project hiện tại:

online-boutique-cicd/
│
├── .github/
│   └── workflows/
│       ├── reusable-ci-cd.yml
│       └── scale-ci-cd.yml
│
├── ecr/
│   └── lifecycle-policy.json
│
├── src/
│
├── docker-compose.yaml
│
└── README.md

18. Kiến trúc sau Chapter 4B

Chúng ta đã đi từ:

Chapter 3D

GitHub
   ↓
Matrix
   ↓
Reusable Workflow
   ↓
Docker Build
   ↓
SSH
   ↓
EC2
   ↓
Docker Compose Build
   ↓
Docker Compose Up

Chapter 4A

GitHub
   ↓
Matrix
   ↓
Reusable Workflow
   ↓
Docker Build
   ↓
ECR
   ↓
SSH
   ↓
EC2
   ↓
Docker Pull
   ↓
Docker Compose Up

Chapter 4B

GitHub
   ↓
Matrix
   ↓
Reusable Workflow
   ↓
Docker Build
   ↓
ECR
   ↓
Lifecycle Policy
   ↓
Old Images → Expire
   ↓
SSH
   ↓
EC2
   ↓
Docker Pull
   ↓
Docker Compose Up

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

Sau Chapter 4B:

✅ Docker image được build ngoài EC2

✅ Image được lưu tập trung trong ECR

✅ Mỗi microservice có repository riêng

✅ ECR tự động quản lý image cũ

✅ Không cần SSH vào EC2 để cleanup

✅ Không để ECR tăng image vô hạn

✅ Đã bắt đầu có artifact management

Và quan trọng nhất:

Chapter 3
──────────────
How do we build many services?
        ↓
Reusable CI/CD


Chapter 4A
──────────────
Where do we store artifacts?
        ↓
Amazon ECR


Chapter 4B
──────────────
How do we manage old artifacts?
        ↓
ECR Lifecycle Policy

Chapter 4C tiếp theo sẽ giải quyết câu hỏi lớn hơn:

Image đã được lưu trong ECR
        ↓
Nhưng...
        ↓
Image này có an toàn không?
        ↓
Có CVE không?
        ↓
Có vulnerability Critical/High không?
        ↓
Có cho phép deploy không?

Amazon ECR + Amazon Inspector + Image Security Scanning.


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.