docker/push_docker.sh
Rama main · réplica de lectura del repositorio original.
#!/bin/bash
# Exit on error
set -e
# Default values
MODE=""
AWS_REGION="us-east-2"
CUSTOM_TAG=""
TEST_MODE=false
DONT_PRUNE=false
SELECTED_IMAGES=()
PLATFORMS="linux/amd64,linux/arm64"
CLOUD_BUILDER=false
# Function to show usage
show_usage() {
echo "Usage: $0 --mode <dockerhub|ecr> [OPTIONS]"
echo ""
echo "Modes:"
echo " --mode dockerhub Push to Docker Hub"
echo " --mode ecr Push to AWS ECR"
echo ""
echo "Options:"
echo " -t, --test Test mode (show commands without executing)"
echo " --dont-prune Don't prune Docker images before building"
echo " -c, --custom-tag Custom tag suffix"
echo " -r, --region AWS region (default: us-east-2, ECR mode only)"
echo " -i, --image Select specific image to build (can be used multiple times)"
echo " -p, --platforms Target platforms (default: linux/amd64,linux/arm64)"
echo " -h, --help Show this help message"
echo ""
echo "Examples:"
echo " $0 --mode dockerhub"
echo " $0 --mode ecr --region us-west-2 --custom-tag hotfix"
echo " $0 --mode dockerhub --test"
echo " $0 --mode ecr --image web --image jawn"
echo " $0 --mode dockerhub --platforms linux/amd64"
echo " $0 --mode ecr --platforms linux/arm64,linux/amd64"
}
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
--mode)
MODE="$2"
shift 2
;;
-t|--test)
TEST_MODE=true
shift
;;
--dont-prune)
DONT_PRUNE=true
shift
;;
-c|--custom-tag)
CUSTOM_TAG="$2"
shift 2
;;
-r|--region)
AWS_REGION="$2"
shift 2
;;
-i|--image)
SELECTED_IMAGES+=("$2")
shift 2
;;
-p|--platforms)
PLATFORMS="$2"
shift 2
;;
-h|--help)
show_usage
exit 0
;;
*)
echo "Unknown option: $1"
show_usage
exit 1
;;
esac
done
# Validate mode is provided
if [ -z "$MODE" ]; then
echo "Error: --mode is required"
show_usage
exit 1
fi
# Validate mode value
if [[ "$MODE" != "dockerhub" && "$MODE" != "ecr" ]]; then
echo "Error: --mode must be either 'dockerhub' or 'ecr'"
show_usage
exit 1
fi
# Function to run commands in test mode or normal mode
run_command() {
if [ "$TEST_MODE" = true ]; then
echo "$@"
else
"$@"
fi
}
# Function to setup Docker buildx for multi-platform builds
setup_buildx() {
echo "Setting up Docker buildx for multi-platform builds..."
# Prefer builder supplied by CI (from docker/setup-buildx-action outputs)
if [ -n "$BUILDX_BUILDER" ]; then
echo "Using buildx builder from environment: '$BUILDX_BUILDER'"
run_command docker buildx use "$BUILDX_BUILDER"
else
# Try to detect an already selected builder (leading '*' in ls output)
CURRENT_BUILDER=$(docker buildx ls 2>/dev/null | sed -n 's/^\* \([^ ]\+\).*/\1/p' || true)
if [ -n "$CURRENT_BUILDER" ]; then
echo "Detected current buildx builder '$CURRENT_BUILDER'. Using it as-is."
run_command docker buildx use "$CURRENT_BUILDER"
else
# Fallback: create or use a local builder
if ! docker buildx ls | grep -q "helicone-builder"; then
echo "Creating new buildx builder 'helicone-builder'..."
run_command docker buildx create --name helicone-builder --use
else
echo "Using existing buildx builder 'helicone-builder'..."
run_command docker buildx use helicone-builder
fi
fi
fi
# Determine if current builder is cloud
ACTIVE_BUILDER=$(docker buildx ls 2>/dev/null | sed -n 's/^\* \([^ ]\+\).*/\1/p' || true)
if [ -z "$ACTIVE_BUILDER" ] && [ -n "$BUILDX_BUILDER" ]; then
ACTIVE_BUILDER="$BUILDX_BUILDER"
fi
DRIVER_LINE=$(docker buildx inspect "$ACTIVE_BUILDER" 2>/dev/null | grep -i '^Driver:' || true)
if echo "$DRIVER_LINE" | grep -qi 'cloud'; then
CLOUD_BUILDER=true
fi
# Bootstrap the builder
run_command docker buildx inspect --bootstrap
}
# Function to create ECR repository if it doesn't exist (ECR mode only)
create_ecr_repo() {
local repo_name=$1
echo "Checking if repository $repo_name exists..."
if ! aws ecr describe-repositories --repository-names "$repo_name" --region "$AWS_REGION" &>/dev/null; then
echo "Creating repository $repo_name..."
run_command aws ecr create-repository \
--repository-name "$repo_name" \
--image-scanning-configuration scanOnPush=true \
--region "$AWS_REGION"
fi
}
# Function to get existing ECR tags and find available version tag
get_available_ecr_tag() {
local repo_name=$1
local base_tag=$2
echo "Checking existing tags for ECR repository $repo_name..." >&2
local existing_tags
existing_tags=$(aws ecr describe-images --repository-name "$repo_name" --region "$AWS_REGION" --query 'imageDetails[].imageTags[]' --output text 2>/dev/null || echo "")
local tag=$base_tag
local counter=1
while [[ $existing_tags =~ $tag ]]; do
tag=$base_tag-$counter
((counter++))
done
echo "$tag"
}
# Setup Docker buildx for multi-platform builds
setup_buildx
# Prune Docker images if not disabled (skip when using a cloud builder)
if [ "$DONT_PRUNE" = false ] && [ "$CLOUD_BUILDER" = false ]; then
echo "Pruning Docker images..."
if [ "$MODE" = "dockerhub" ]; then
run_command bash -c 'echo "y" | docker system prune -a'
else
run_command docker system prune -af
fi
fi
# Generate version tag
if [ "$MODE" = "dockerhub" ]; then
DATE=$(date +%Y.%m.%d)
VERSION_TAG="v$DATE"
else
VERSION_TAG="v$(date +'%Y-%m-%d')"
fi
if [ ! -z "$CUSTOM_TAG" ]; then
if [ "$MODE" = "dockerhub" ]; then
VERSION_TAG="${VERSION_TAG}-${CUSTOM_TAG}"
else
VERSION_TAG="${VERSION_TAG}-${CUSTOM_TAG}"
fi
fi
# Define images and their contexts (unified for both modes)
IMAGES=(
"helicone/web:.."
"helicone/jawn:.."
"helicone/migrations:.."
)
# Docker Hub mode
if [ "$MODE" = "dockerhub" ]; then
echo "=== Docker Hub Mode ==="
# Filter out legacy dockerhub-only images for the unified approach
DOCKERHUB_IMAGES=(
"helicone/web:.."
"helicone/jawn:.."
"helicone/migrations:.."
"helicone/helicone-all-in-one:.."
)
# Filter images if specific ones were selected
if [ ${#SELECTED_IMAGES[@]} -gt 0 ]; then
FILTERED_IMAGES=()
for IMAGE_INFO in "${DOCKERHUB_IMAGES[@]}"; do
IFS=':' read -r IMAGE_NAME _ <<< "$IMAGE_INFO"
for SELECTED in "${SELECTED_IMAGES[@]}"; do
if [[ "$IMAGE_NAME" == *"$SELECTED"* ]]; then
FILTERED_IMAGES+=("$IMAGE_INFO")
break
fi
done
done
DOCKERHUB_IMAGES=("${FILTERED_IMAGES[@]}")
fi
for IMAGE_INFO in "${DOCKERHUB_IMAGES[@]}"; do
IFS=':' read -r IMAGE_NAME CONTEXT <<< "$IMAGE_INFO"
echo "Processing $IMAGE_NAME..."
# Get the Docker tags for the current image from Docker Hub
echo "Checking existing tags for $IMAGE_NAME..."
tags=$(curl -s "https://hub.docker.com/v2/repositories/${IMAGE_NAME}/tags/?page_size=100" | jq -r '.results|.[]|.name' 2>/dev/null || echo "")
# Check if the current date tag exists already
tag=$VERSION_TAG
counter=1
while [[ $tags =~ $tag ]]; do
# If it does, increment the counter and append it to the date tag
tag=$VERSION_TAG-$counter
((counter++))
done
# Get Dockerfile path and context
DOCKERFILE_NAME=$(basename "$IMAGE_NAME" | tr '-' '_')
DOCKERFILE_PATH="dockerfiles/dockerfile_${DOCKERFILE_NAME}"
BUILD_CONTEXT="$CONTEXT"
if [ "$DOCKERFILE_NAME" = "jawn" ]; then
DOCKERFILE_PATH="../valhalla/dockerfile"
elif [ "$DOCKERFILE_NAME" = "migrations" ]; then
DOCKERFILE_PATH="dockerfiles/dockerfile_migrations"
elif [ "$DOCKERFILE_NAME" = "ai_gateway" ]; then
DOCKERFILE_PATH="../aigateway/Dockerfile"
BUILD_CONTEXT="../aigateway"
elif [[ "$DOCKERFILE_NAME" == *"all_in_one" ]]; then
DOCKERFILE_PATH="../Dockerfile"
BUILD_CONTEXT=".."
fi
# Build and push multi-platform image
FULL_IMAGE_TAG="$IMAGE_NAME:$tag"
LATEST_TAG="$IMAGE_NAME:latest"
echo "Building and pushing multi-platform image $FULL_IMAGE_TAG for platforms: $PLATFORMS"
run_command docker buildx build \
--platform "$PLATFORMS" \
-t "$FULL_IMAGE_TAG" \
-t "$LATEST_TAG" \
-f "$DOCKERFILE_PATH" \
--push \
"$BUILD_CONTEXT"
done
# ECR mode
elif [ "$MODE" = "ecr" ]; then
echo "=== ECR Mode ==="
# Get AWS account ID
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
# Login to ECR
echo "Logging in to ECR..."
run_command aws ecr get-login-password --region "$AWS_REGION" | docker login --username AWS --password-stdin "$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com"
# Use only the core images for ECR
ECR_IMAGES=(
"helicone/web:.."
"helicone/jawn:.."
"helicone/migrations:.."
"helicone/ai-gateway:.."
"helicone/helicone-all-in-one:.."
)
# Create ECR repositories first
for IMAGE_INFO in "${ECR_IMAGES[@]}"; do
IFS=':' read -r IMAGE_NAME _ <<< "$IMAGE_INFO"
# Skip if specific images were selected and this isn't one of them
if [ ${#SELECTED_IMAGES[@]} -gt 0 ]; then
SKIP=true
for SELECTED in "${SELECTED_IMAGES[@]}"; do
if [[ "$IMAGE_NAME" == *"$SELECTED"* ]]; then
SKIP=false
break
fi
done
if [ "$SKIP" = true ]; then
continue
fi
fi
create_ecr_repo "$IMAGE_NAME"
done
# Process each image
for IMAGE_INFO in "${ECR_IMAGES[@]}"; do
IFS=':' read -r IMAGE_NAME CONTEXT <<< "$IMAGE_INFO"
# Skip if specific images were selected and this isn't one of them
if [ ${#SELECTED_IMAGES[@]} -gt 0 ]; then
SKIP=true
for SELECTED in "${SELECTED_IMAGES[@]}"; do
if [[ "$IMAGE_NAME" == *"$SELECTED"* ]]; then
SKIP=false
break
fi
done
if [ "$SKIP" = true ]; then
echo "Skipping $IMAGE_NAME (not selected)"
continue
fi
fi
echo "Processing $IMAGE_NAME..."
# Get available tag (with counter if needed)
tag=$(get_available_ecr_tag "$IMAGE_NAME" "$VERSION_TAG")
# Get Dockerfile path and context
DOCKERFILE_NAME=$(basename "$IMAGE_NAME" | tr '-' '_')
DOCKERFILE_PATH="dockerfiles/dockerfile_${DOCKERFILE_NAME}"
BUILD_CONTEXT="$CONTEXT"
if [ "$DOCKERFILE_NAME" = "jawn" ]; then
DOCKERFILE_PATH="../valhalla/dockerfile"
elif [ "$DOCKERFILE_NAME" = "migrations" ]; then
DOCKERFILE_PATH="dockerfiles/dockerfile_migrations"
elif [ "$DOCKERFILE_NAME" = "ai_gateway" ]; then
DOCKERFILE_PATH="../aigateway/Dockerfile"
BUILD_CONTEXT="../aigateway"
elif [[ "$DOCKERFILE_NAME" == *"all_in_one" ]]; then
DOCKERFILE_PATH="../Dockerfile"
BUILD_CONTEXT=".."
fi
# Build and push multi-platform image
ECR_REPO="$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$IMAGE_NAME"
FULL_IMAGE_TAG="$ECR_REPO:$tag"
LATEST_TAG="$ECR_REPO:latest"
echo "Building and pushing multi-platform image $FULL_IMAGE_TAG for platforms: $PLATFORMS"
run_command docker buildx build \
--platform "$PLATFORMS" \
-t "$FULL_IMAGE_TAG" \
-t "$LATEST_TAG" \
-f "$DOCKERFILE_PATH" \
--push \
"$BUILD_CONTEXT"
done
fi
echo "Done!"