Hướng Dẫn Di Chuyển Hình Ảnh Docker ECR Giữa Các Kho Chứa (Với Tự Động Hóa)
Mỗi khi làm việc với AWS ECR, có thể bạn sẽ phải đối mặt với tình huống cần phải di chuyển hình ảnh container giữa các kho chứa ECR. Có thể là do quy ước đặt tên đã thay đổi, hoặc có một cấu trúc kho mới được giới thiệu, hoặc bạn chỉ đơn giản muốn dọn dẹp.
Dù lý do là gì, việc thực hiện điều này thủ công - từng hình ảnh một - thật chậm chạp và đau đớn. Trong các đội ngũ phát triển nhanh, bất kỳ điều gì làm chậm lại quy trình làm việc đều ảnh hưởng đến tốc độ và độ tin cậy.
Đó là lý do tại sao tôi đã xây dựng một script tự động hóa để di chuyển hình ảnh một cách nhanh chóng và an toàn. Nó sử dụng skopeo để sao chép hình ảnh giữa các kho chứa mà không cần phải kéo và đẩy chúng một cách thủ công.
🛠️ Yêu Cầu Cần Thiết
- AWS CLI đã được cấu hình với một profile có quyền truy cập vào các kho ECR.
jqđể phân tích cú pháp JSON.skopeođể sao chép hình ảnh container.
Cài Đặt skopeo
- macOS (Homebrew)
bash
brew install skopeo
- Ubuntu/Debian
bash
sudo apt-get update
sudo apt-get -y install skopeo
-
Windows (qua WSL2 hoặc Chocolatey)
- Nếu bạn đang sử dụng WSL2 (Ubuntu), chỉ cần làm theo hướng dẫn cài đặt cho Ubuntu.
- Nếu bạn đang trên Windows với Chocolatey:
bashchoco install skopeo
📜 Script Di Chuyển
Dưới đây là script mà tôi sử dụng trên macOS (cũng hoạt động với GNU/Linux và WSL, chỉ có cú pháp date là khác nhau).
Nó di chuyển tất cả hình ảnh được đẩy trong vòng N ngày qua từ kho ECR nguồn đến kho ECR đích.
👉 Lưu nó với tên migrate-ecr-images.sh và chạy nó.
bash
#!/usr/bin/env bash
set -euo pipefail
# --- kiểm tra skopeo và cài đặt nếu chưa có (macOS Homebrew) ---
if ! command -v skopeo >/dev/null 2>&1; then
echo "skopeo chưa được tìm thấy, đang cài đặt..."
if ! command -v brew >/dev/null 2>&1; then
echo "Homebrew là cần thiết nhưng không được tìm thấy. Vui lòng cài đặt Homebrew trước: https://brew.sh/"
exit 1
fi
brew install skopeo
fi
SRC_REPO="java-micro-repo"
DST_REPO="repo"
WINDOW_DAYS=90
DRY_RUN=false
# --- phát hiện môi trường từ profile AWS ---
REGION="${AWS_REGION:-${AWS_DEFAULT_REGION:-$(aws configure get region)}}"
: "${REGION:?Region chưa được thiết lập trong môi trường hoặc cấu hình AWS}"
ACCOUNT_ID="$(aws sts get-caller-identity --query Account --output text)"
REG_HOST="${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com"
# --- trợ giúp ngày BSD/GNU ---
isi_bsd_date=false
if date -v-1d +%s >/dev/null 2>&1; then is_bsd_date=true; fi
cutoff_epoch() {
if $is_bsd_date; then date -u -v-"${WINDOW_DAYS}"d +%s; else date -u -d "${WINDOW_DAYS} days ago" +%s; fi
}
to_epoch() {
ts="$1"
if $is_bsd_date; then
ts_norm=$(printf "%s" "$ts" \
| sed -E 's/Z$/+0000/' \
| sed -E 's/([+-][0-9]{2}):([0-9]{2})$/\1\2/' \
| sed -E 's/([0-9]{2}:[0-9]{2}:[0-9]{2})\.[0-9]+/\1/')
case "$ts_norm" in *+????|*-[0-9][0-9][0-9][0-9]) : ;; *) ts_norm="${ts_norm}+0000" ;; esac
date -j -u -f "%Y-%m-%dT%H:%M:%S%z" "$ts_norm" +%s
else
date -u -d "$ts" +%s
fi
}
CUTOFF_EPOCH="$(cutoff_epoch)"
echo "Nguồn: ${REG_HOST}/${SRC_REPO}"
echo "Điểm đến: ${REG_HOST}/${DST_REPO}"
echo "Thời gian: trong ${WINDOW_DAYS} ngày qua"
echo "Chạy thử: ${DRY_RUN}"
echo
# --- đảm bảo kho đích tồn tại ---
if ! aws ecr describe-repositories --repository-names "$DST_REPO" >/dev/null 2>&1; then
echo "Tạo kho đích: $DST_REPO"
aws ecr create-repository --repository-name "$DST_REPO" >/dev/null
aws ecr put-image-tag-mutability --repository-name "$DST_REPO" --image-tag-mutability MUTABLE >/dev/null || true
fi
# --- lấy mật khẩu ECR cho xác thực skopeo ---
ECR_PASS="$(aws ecr get-login-password --region "$REGION")"
# --- thu thập các thẻ gần đây ---
TMP_LIST="$(mktemp)"; TMP_TAGS="$(mktemp)"
aws ecr describe-images --repository-name "$SRC_REPO" --output json \
| jq -r '.imageDetails[] | select(.imageTags!=null) | .imagePushedAt as $t | .imageTags[] | "\($t)\t\(.)"' > "$TMP_LIST"
while IFS=$'\t' read -r pushed tag; do
epoch="$(to_epoch "$pushed")" || continue
if [ "$epoch" -ge "$CUTOFF_EPOCH" ]; then printf "%s\n" "$tag"; fi
done < "$TMP_LIST" | sort -u > "$TMP_TAGS"
if ! [ -s "$TMP_TAGS" ]; then
echo "Không có hình ảnh được đẩy trong vòng ${WINDOW_DAYS} ngày qua. Không có gì để làm."
rm -f "$TMP_LIST" "$TMP_TAGS"; exit 0
fi
echo "Đã tìm thấy $(wc -l < "$TMP_TAGS" | tr -d ' ') thẻ(s):"
sed 's/^/ - /' "$TMP_TAGS"
echo
FAILED=()
while IFS= read -r TAG; do
[ -z "$TAG" ] && continue
SRC="docker://${REG_HOST}/${SRC_REPO}:${TAG}"
DST="docker://${REG_HOST}/${DST_REPO}:${TAG}"
echo "Đang sao chép ${TAG}…"
if [ "$DRY_RUN" = true ]; then
echo " [chạy thử] skopeo copy --all ${SRC} -> ${DST}"
continue
fi
if ! skopeo copy --all \
--src-creds "AWS:${ECR_PASS}" \
--dest-creds "AWS:${ECR_PASS}" \
"$SRC" "$DST"; then
echo " ❌ Thất bại: ${TAG}"
FAILED+=("$TAG")
else
echo " ✅ Hoàn thành: ${TAG}"
fi
done < "$TMP_TAGS"
rm -f "$TMP_LIST" "$TMP_TAGS"
echo
if [ "${#FAILED[@]}" -gt 0 ]; then
echo "Hoàn thành với lỗi:"
printf ' - %s\n' "${FAILED[@]}"
exit 1
else
echo "Tất cả các thẻ yêu cầu đã được sao chép thành công."
fi
⚡ Cách Hoạt Động
-
Tìm các hình ảnh gần đây
Sử dụngaws ecr describe-images, nó lọc các thẻ theo ngàyimagePushedAttrong vòngWINDOW_DAYS. -
Tạo kho đích nếu chưa có
Để bạn không phải làm điều này một cách thủ công. -
Sao chép hình ảnh với skopeo
Không cần phải kéo và đẩy lại -skopeosao chép trực tiếp giữa các kho. -
Hỗ trợ chế độ chạy thử
ĐặtDRY_RUN=trueđể xem trước những gì sẽ xảy ra.
🔧 Ví Dụ Sử Dụng
Sao chép 90 ngày hình ảnh gần đây từ java-micro-repo đến repo:
bash
SRC_REPO="java-micro-repo" DST_REPO="repo" WINDOW_DAYS=90 ./migrate-ecr-images.sh
Chạy một chạy thử (không thay đổi gì):
bash
DRY_RUN=true ./migrate-ecr-images.sh
✅ Tại Sao Điều Này Hữu Ích
- Tiết kiệm hàng giờ so với việc sao chép thủ công.
- Tự động hóa việc tạo kho nếu chưa có.
- Tôn trọng tốc độ → cho phép bạn tập trung vào việc lập trình, không phải dọn dẹp.
- Đa nền tảng: hoạt động trên macOS, Ubuntu và Windows.
🎯 Kết Luận
Script này đã trở thành một công cụ tiết kiệm thời gian lớn trong đội ngũ của tôi. Bất cứ khi nào chúng tôi cần đổi tên hoặc cấu trúc lại các kho chứa ECR, chỉ cần một lệnh.
Nếu bạn thường xuyên làm việc với AWS ECR, tôi khuyên bạn nên giữ script này trong bộ công cụ của bạn. 🔧
👉 Bạn đã gặp khó khăn gì trong việc di chuyển hình ảnh ECR chưa? Hãy chia sẻ suy nghĩ của bạn trong phần bình luận - tôi rất muốn biết cách bạn đã giải quyết vấn đề này.