#!/usr/bin/env bash
set -euo pipefail
# Container Registry Management & Image Lifecycle
# ============================================
# AWS ECR Setup and Operations
# ============================================
# Create ECR repository with scanning enabled
aws ecr create-repository \
--repository-name myapp/api \
--image-scanning-configuration scanOnPush=true \
--image-tag-mutability IMMUTABLE \
--encryption-configuration encryptionType=KMS
# ECR lifecycle policy — auto-cleanup old images
aws ecr put-lifecycle-policy \
--repository-name myapp/api \
--lifecycle-policy-text '{
"rules": [
{
"rulePriority": 1,
"description": "Keep last 10 production images",
"selection": {
"tagStatus": "tagged",
"tagPrefixList": ["v"],
"countType": "imageCountMoreThan",
"countNumber": 10
},
"action": { "type": "expire" }
},
{
"rulePriority": 2,
"description": "Remove untagged images after 1 day",
"selection": {
"tagStatus": "untagged",
"countType": "sinceImagePushed",
"countUnit": "days",
"countNumber": 1
},
"action": { "type": "expire" }
},
{
"rulePriority": 3,
"description": "Remove dev images after 7 days",
"selection": {
"tagStatus": "tagged",
"tagPrefixList": ["dev-", "feature-"],
"countType": "sinceImagePushed",
"countUnit": "days",
"countNumber": 7
},
"action": { "type": "expire" }
}
]
}'
# Login to ECR
aws ecr get-login-password --region us-east-1 | \
docker login --username AWS --password-stdin \
123456789.dkr.ecr.us-east-1.amazonaws.com
# ============================================
# Image Tagging Strategy
# ============================================
REGISTRY="123456789.dkr.ecr.us-east-1.amazonaws.com"
REPO="myapp/api"
GIT_SHA=$(git rev-parse --short HEAD)
GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD | tr '/' '-')
BUILD_DATE=$(date -u +%Y%m%d)
VERSION=$(cat VERSION) # Semantic version, e.g., 1.2.3
# Build with multiple tags
docker build \
--label "org.opencontainers.image.revision=${GIT_SHA}" \
--label "org.opencontainers.image.created=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--label "org.opencontainers.image.version=${VERSION}" \
-t "${REGISTRY}/${REPO}:${VERSION}" \
-t "${REGISTRY}/${REPO}:${GIT_SHA}" \
-t "${REGISTRY}/${REPO}:${GIT_BRANCH}-${BUILD_DATE}" \
-t "${REGISTRY}/${REPO}:latest" \
.
# Push all tags
docker push "${REGISTRY}/${REPO}" --all-tags
# ============================================
# Vulnerability Scanning with Trivy
# ============================================
# Scan local image
trivy image --severity HIGH,CRITICAL "${REGISTRY}/${REPO}:${VERSION}"
# Scan with JSON output for CI pipeline
trivy image \
--format json \
--output trivy-report.json \
--severity HIGH,CRITICAL \
--exit-code 1 \
"${REGISTRY}/${REPO}:${VERSION}"
# Scan and fail CI if critical vulnerabilities found
trivy image \
--severity CRITICAL \
--exit-code 1 \
--ignore-unfixed \
--no-progress \
"${REGISTRY}/${REPO}:${VERSION}"
# ============================================
# GitHub Container Registry (ghcr.io)
# ============================================
# Login to GHCR
echo "${GITHUB_TOKEN}" | docker login ghcr.io -u "${GITHUB_ACTOR}" --password-stdin
# Build and push
docker build -t "ghcr.io/myorg/myapp:${VERSION}" .
docker push "ghcr.io/myorg/myapp:${VERSION}"
# ============================================
# Multi-arch builds with buildx
# ============================================
# Create builder for multi-platform
docker buildx create --name multiarch --use
docker buildx inspect --bootstrap
# Build for AMD64 and ARM64
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t "${REGISTRY}/${REPO}:${VERSION}" \
--push \
.
# ============================================
# Image cleanup on local machine
# ============================================
# Remove dangling images
docker image prune -f
# Remove images older than 24h
docker image prune -a --filter "until=24h" -f
# Remove all images for a specific repo
docker images "${REGISTRY}/${REPO}" -q | xargs -r docker rmi -f