Skip to content

Commit b489a02

Browse files
mcollinaclaude
andcommitted
Add local build and push script for Docker images
Provides a convenient way to build and push all variants locally with proper version tagging, without needing GitHub Actions. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 4cf0506 commit b489a02

1 file changed

Lines changed: 221 additions & 0 deletions

File tree

scripts/build-and-push.sh

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Build and push all Docker variants to DockerHub with proper version tags.
4+
# Supports multi-architecture builds (amd64/arm64) using docker buildx.
5+
#
6+
# Usage:
7+
# ./scripts/build-and-push.sh # Build and push all variants
8+
# ./scripts/build-and-push.sh --no-push # Build only, don't push
9+
# ./scripts/build-and-push.sh bookworm # Build and push specific variant
10+
# ./scripts/build-and-push.sh --local # Build for local arch only (faster)
11+
#
12+
13+
set -euo pipefail
14+
15+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
16+
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
17+
18+
# Configuration
19+
IMAGE_NAME="${IMAGE_NAME:-platformatic/node-pointer-compression}"
20+
VARIANTS=("bookworm" "slim" "alpine")
21+
PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}"
22+
23+
# Parse arguments
24+
PUSH=true
25+
LOCAL_ONLY=false
26+
SELECTED_VARIANTS=()
27+
28+
while [[ $# -gt 0 ]]; do
29+
case $1 in
30+
--no-push)
31+
PUSH=false
32+
shift
33+
;;
34+
--local)
35+
LOCAL_ONLY=true
36+
PLATFORMS="linux/$(uname -m | sed 's/x86_64/amd64/' | sed 's/aarch64/arm64/')"
37+
shift
38+
;;
39+
--help|-h)
40+
echo "Usage: $0 [OPTIONS] [VARIANTS...]"
41+
echo ""
42+
echo "Options:"
43+
echo " --no-push Build images but don't push to registry"
44+
echo " --local Build for local architecture only (faster)"
45+
echo " --help Show this help message"
46+
echo ""
47+
echo "Variants: bookworm, slim, alpine (default: all)"
48+
echo ""
49+
echo "Environment variables:"
50+
echo " IMAGE_NAME Docker image name (default: platformatic/node-pointer-compression)"
51+
echo " PLATFORMS Target platforms (default: linux/amd64,linux/arm64)"
52+
exit 0
53+
;;
54+
*)
55+
SELECTED_VARIANTS+=("$1")
56+
shift
57+
;;
58+
esac
59+
done
60+
61+
# Use all variants if none specified
62+
if [[ ${#SELECTED_VARIANTS[@]} -eq 0 ]]; then
63+
SELECTED_VARIANTS=("${VARIANTS[@]}")
64+
fi
65+
66+
# Colors for output
67+
RED='\033[0;31m'
68+
GREEN='\033[0;32m'
69+
YELLOW='\033[1;33m'
70+
BLUE='\033[0;34m'
71+
NC='\033[0m' # No Color
72+
73+
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
74+
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
75+
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
76+
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
77+
78+
# Ensure buildx is available and configured
79+
setup_buildx() {
80+
log_info "Setting up docker buildx..."
81+
82+
if ! docker buildx inspect multiarch-builder &>/dev/null; then
83+
docker buildx create --name multiarch-builder --use
84+
else
85+
docker buildx use multiarch-builder
86+
fi
87+
88+
# Bootstrap the builder
89+
docker buildx inspect --bootstrap
90+
}
91+
92+
# Extract Node.js version from a built image
93+
get_node_version() {
94+
local image="$1"
95+
docker run --rm "$image" node --version | sed 's/^v//'
96+
}
97+
98+
# Build a single variant
99+
build_variant() {
100+
local variant="$1"
101+
local dockerfile="$PROJECT_DIR/docker/$variant/Dockerfile"
102+
103+
if [[ ! -f "$dockerfile" ]]; then
104+
log_error "Dockerfile not found: $dockerfile"
105+
return 1
106+
fi
107+
108+
log_info "Building $variant variant for platforms: $PLATFORMS"
109+
110+
local build_args=(
111+
--file "$dockerfile"
112+
--platform "$PLATFORMS"
113+
)
114+
115+
if [[ "$PUSH" == "true" ]]; then
116+
build_args+=(--push)
117+
elif [[ "$LOCAL_ONLY" == "true" ]]; then
118+
build_args+=(--load)
119+
else
120+
# Multi-arch without push requires --push or outputting to a file
121+
log_warn "Multi-arch builds require --push or --local. Using --local for this build."
122+
PLATFORMS="linux/$(uname -m | sed 's/x86_64/amd64/' | sed 's/aarch64/arm64/')"
123+
build_args=(--file "$dockerfile" --platform "$PLATFORMS" --load)
124+
fi
125+
126+
# First build with a temporary tag to extract version
127+
local temp_tag="$IMAGE_NAME:${variant}-temp"
128+
129+
if [[ "$LOCAL_ONLY" == "true" ]] || [[ "$PUSH" == "false" ]]; then
130+
# For local builds, we can load and inspect
131+
docker buildx build "${build_args[@]}" --tag "$temp_tag" "$PROJECT_DIR"
132+
133+
# Extract version
134+
NODE_VERSION=$(get_node_version "$temp_tag")
135+
log_info "Detected Node.js version: $NODE_VERSION"
136+
137+
# Remove temp tag
138+
docker rmi "$temp_tag" 2>/dev/null || true
139+
else
140+
# For push builds, build once and tag appropriately
141+
# We need to build a local image first to get the version
142+
log_info "Building local image to detect Node.js version..."
143+
local local_platform="linux/$(uname -m | sed 's/x86_64/amd64/' | sed 's/aarch64/arm64/')"
144+
docker buildx build --file "$dockerfile" --platform "$local_platform" --load --tag "$temp_tag" "$PROJECT_DIR"
145+
146+
NODE_VERSION=$(get_node_version "$temp_tag")
147+
log_info "Detected Node.js version: $NODE_VERSION"
148+
149+
docker rmi "$temp_tag" 2>/dev/null || true
150+
fi
151+
152+
# Build tags
153+
local tags=(
154+
"--tag" "$IMAGE_NAME:${NODE_VERSION}-${variant}"
155+
"--tag" "$IMAGE_NAME:${variant}"
156+
)
157+
158+
# Bookworm is the default variant
159+
if [[ "$variant" == "bookworm" ]]; then
160+
tags+=(
161+
"--tag" "$IMAGE_NAME:${NODE_VERSION}"
162+
"--tag" "$IMAGE_NAME:latest"
163+
)
164+
fi
165+
166+
# Final build with all tags
167+
log_info "Building and tagging $variant..."
168+
docker buildx build "${build_args[@]}" "${tags[@]}" "$PROJECT_DIR"
169+
170+
log_success "Built $variant variant"
171+
echo " Tags:"
172+
echo " - $IMAGE_NAME:${NODE_VERSION}-${variant}"
173+
echo " - $IMAGE_NAME:${variant}"
174+
if [[ "$variant" == "bookworm" ]]; then
175+
echo " - $IMAGE_NAME:${NODE_VERSION}"
176+
echo " - $IMAGE_NAME:latest"
177+
fi
178+
}
179+
180+
# Main
181+
main() {
182+
log_info "Docker image: $IMAGE_NAME"
183+
log_info "Platforms: $PLATFORMS"
184+
log_info "Variants: ${SELECTED_VARIANTS[*]}"
185+
log_info "Push: $PUSH"
186+
echo ""
187+
188+
# Check Docker login if pushing
189+
if [[ "$PUSH" == "true" ]]; then
190+
if ! docker info 2>/dev/null | grep -q "Username"; then
191+
log_warn "Not logged in to Docker Hub. Run 'docker login' first."
192+
read -p "Continue anyway? [y/N] " -n 1 -r
193+
echo
194+
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
195+
exit 1
196+
fi
197+
fi
198+
fi
199+
200+
setup_buildx
201+
echo ""
202+
203+
# Build each variant
204+
for variant in "${SELECTED_VARIANTS[@]}"; do
205+
if [[ ! " ${VARIANTS[*]} " =~ " ${variant} " ]]; then
206+
log_error "Unknown variant: $variant (valid: ${VARIANTS[*]})"
207+
exit 1
208+
fi
209+
210+
build_variant "$variant"
211+
echo ""
212+
done
213+
214+
log_success "All builds completed!"
215+
216+
if [[ "$PUSH" == "true" ]]; then
217+
log_info "Images pushed to Docker Hub: https://hub.docker.com/r/$IMAGE_NAME"
218+
fi
219+
}
220+
221+
main

0 commit comments

Comments
 (0)