1+ #! /bin/bash
2+
3+ # Multi-platform Docker build script for lambda-nat-proxy
4+ # Builds binaries for multiple operating systems and architectures
5+
6+ set -e
7+
8+ # Colors for output
9+ RED=' \033[0;31m'
10+ GREEN=' \033[0;32m'
11+ YELLOW=' \033[1;33m'
12+ BLUE=' \033[0;34m'
13+ NC=' \033[0m' # No Color
14+
15+ # Build directory
16+ BUILD_DIR=" build"
17+
18+ # Platforms to build for (compatible with older bash)
19+ PLATFORMS=(
20+ " linux-amd64:linux:amd64"
21+ " linux-arm64:linux:arm64"
22+ " darwin-amd64:darwin:amd64"
23+ " darwin-arm64:darwin:arm64"
24+ " windows-amd64:windows:amd64"
25+ )
26+
27+ echo -e " ${BLUE} 🌍 Building lambda-nat-proxy for multiple platforms using Docker...${NC} "
28+
29+ # Check if buildx is available
30+ BUILDX_AVAILABLE=false
31+ if docker buildx version > /dev/null 2>&1 ; then
32+ echo -e " ${GREEN} ✅ Docker buildx detected - using advanced multi-platform build${NC} "
33+ BUILDX_AVAILABLE=true
34+ else
35+ echo -e " ${YELLOW} ⚠️ Docker buildx not available - using sequential builds${NC} "
36+ echo -e " ${YELLOW} 💡 For faster builds, consider updating Docker to support buildx${NC} "
37+ fi
38+
39+ # Create build directory
40+ mkdir -p ${BUILD_DIR}
41+
42+ if [[ " $BUILDX_AVAILABLE " == " true" ]]; then
43+ # Use buildx for efficient multi-platform builds
44+ echo -e " ${BLUE} 🚀 Using Docker buildx for efficient multi-platform build...${NC} "
45+
46+ # Create buildx builder if it doesn't exist
47+ docker buildx create --name multiarch-builder --use 2> /dev/null || docker buildx use multiarch-builder 2> /dev/null || true
48+
49+ # Create multi-stage Dockerfile for cross-compilation
50+ cat > Dockerfile.multiarch << 'EOF '
51+ FROM --platform=$BUILDPLATFORM node:18-alpine AS dashboard-builder
52+ WORKDIR /app
53+ COPY web/package*.json ./web/
54+ WORKDIR /app/web
55+ RUN npm ci --only=production
56+ COPY web/ .
57+ RUN npm run build
58+
59+ FROM --platform=$BUILDPLATFORM golang:1.21-alpine AS go-builder
60+ ARG TARGETOS
61+ ARG TARGETARCH
62+ RUN apk add --no-cache git
63+ WORKDIR /app
64+
65+ # Copy all source code first (needed for replace directive)
66+ COPY . .
67+ COPY --from=dashboard-builder /app/web/dist ./internal/dashboard/web/dist
68+
69+ # Fix the replace directive in lambda/go.mod to use absolute path
70+ RUN sed -i 's|replace github.com/dan-v/lambda-nat-punch-proxy => ..|replace github.com/dan-v/lambda-nat-punch-proxy => /app|' lambda/go.mod
71+
72+ # Download dependencies (replace directive works now)
73+ RUN go mod download && cd lambda && go mod download
74+
75+ # Build Lambda function (always Linux/amd64 for AWS)
76+ RUN cd lambda && GOOS=linux GOARCH=amd64 go build -o ../cmd/lambda-nat-proxy/assets/bootstrap .
77+
78+ # Build main binary for target platform
79+ RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -a -installsuffix cgo -o lambda-nat-proxy ./cmd/lambda-nat-proxy
80+
81+ FROM scratch
82+ COPY --from=go-builder /app/lambda-nat-proxy .
83+ COPY --from=go-builder /app/cmd/lambda-nat-proxy/assets/bootstrap ./bootstrap
84+ EOF
85+
86+ # Build for each platform using buildx
87+ for platform_spec in " ${PLATFORMS[@]} " ; do
88+ IFS=' :' read -r platform_key os arch <<< " $platform_spec"
89+
90+ echo -e " ${BLUE} 🔨 Building for ${os} /${arch} ...${NC} "
91+
92+ binary_name=" lambda-nat-proxy"
93+ if [[ " $os " == " windows" ]]; then
94+ binary_name=" lambda-nat-proxy.exe"
95+ fi
96+
97+ output_dir=" ${BUILD_DIR} /${platform_key} "
98+ mkdir -p " $output_dir "
99+
100+ docker buildx build \
101+ --platform " ${os} /${arch} " \
102+ --file Dockerfile.multiarch \
103+ --output " type=local,dest=${output_dir} " \
104+ .
105+
106+ # Rename binary
107+ mv " ${output_dir} /lambda-nat-proxy" " ${output_dir} /${binary_name} " 2> /dev/null || true
108+
109+ # Copy bootstrap (first time only)
110+ cp " ${output_dir} /bootstrap" " ${BUILD_DIR} /bootstrap" 2> /dev/null || true
111+
112+ # Make executable (not needed for Windows)
113+ if [[ " $os " != " windows" ]]; then
114+ chmod +x " ${output_dir} /${binary_name} "
115+ fi
116+
117+ echo -e " ${GREEN} ✅ Built: ${output_dir} /${binary_name}${NC} "
118+ done
119+
120+ rm -f Dockerfile.multiarch
121+
122+ else
123+ # Fallback: Build using standard Docker with GOOS/GOARCH
124+ echo -e " ${BLUE} 🔨 Using standard Docker builds with Go cross-compilation...${NC} "
125+
126+ # Create standard Dockerfile for cross-compilation
127+ cat > Dockerfile.standard << 'EOF '
128+ FROM node:18-alpine AS dashboard-builder
129+ WORKDIR /app
130+ COPY web/package*.json ./web/
131+ WORKDIR /app/web
132+ RUN npm ci --only=production
133+ COPY web/ .
134+ RUN npm run build
135+
136+ FROM golang:1.21-alpine AS go-builder
137+ ARG TARGETOS
138+ ARG TARGETARCH
139+ RUN apk add --no-cache git
140+ WORKDIR /app
141+
142+ # Copy all source code first (needed for replace directive)
143+ COPY . .
144+ COPY --from=dashboard-builder /app/web/dist ./internal/dashboard/web/dist
145+
146+ # Fix the replace directive in lambda/go.mod to use absolute path
147+ RUN sed -i 's|replace github.com/dan-v/lambda-nat-punch-proxy => ..|replace github.com/dan-v/lambda-nat-punch-proxy => /app|' lambda/go.mod
148+
149+ # Download dependencies (replace directive works now)
150+ RUN go mod download && cd lambda && go mod download
151+
152+ # Build Lambda function (always Linux/amd64 for AWS)
153+ RUN cd lambda && GOOS=linux GOARCH=amd64 go build -o ../cmd/lambda-nat-proxy/assets/bootstrap .
154+
155+ # Build main binary for target platform
156+ RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -a -installsuffix cgo -o lambda-nat-proxy ./cmd/lambda-nat-proxy
157+ EOF
158+
159+ # Build for each platform
160+ for platform_spec in " ${PLATFORMS[@]} " ; do
161+ IFS=' :' read -r platform_key os arch <<< " $platform_spec"
162+
163+ echo -e " ${BLUE} 🔨 Building for ${os} /${arch} ...${NC} "
164+
165+ binary_name=" lambda-nat-proxy"
166+ if [[ " $os " == " windows" ]]; then
167+ binary_name=" lambda-nat-proxy.exe"
168+ fi
169+
170+ output_dir=" ${BUILD_DIR} /${platform_key} "
171+ mkdir -p " $output_dir "
172+
173+ # Build Docker image with target OS/ARCH
174+ docker build \
175+ --build-arg TARGETOS=" ${os} " \
176+ --build-arg TARGETARCH=" ${arch} " \
177+ --file Dockerfile.standard \
178+ --tag " lambda-nat-proxy-${platform_key} " \
179+ .
180+
181+ # Extract binaries from built image
182+ CONTAINER_ID=$( docker create " lambda-nat-proxy-${platform_key} " )
183+ docker cp " ${CONTAINER_ID} :/app/lambda-nat-proxy" " ${output_dir} /${binary_name} "
184+ docker cp " ${CONTAINER_ID} :/app/cmd/lambda-nat-proxy/assets/bootstrap" " ${output_dir} /bootstrap" 2> /dev/null || true
185+ docker rm " ${CONTAINER_ID} "
186+ docker rmi " lambda-nat-proxy-${platform_key} "
187+
188+ # Copy bootstrap (first time only)
189+ cp " ${output_dir} /bootstrap" " ${BUILD_DIR} /bootstrap" 2> /dev/null || true
190+
191+ # Make executable (not needed for Windows)
192+ if [[ " $os " != " windows" ]]; then
193+ chmod +x " ${output_dir} /${binary_name} "
194+ fi
195+
196+ echo -e " ${GREEN} ✅ Built: ${output_dir} /${binary_name}${NC} "
197+ done
198+
199+ rm -f Dockerfile.standard
200+ fi
201+
202+ echo -e " ${GREEN} 🎉 Multi-platform build complete!${NC} "
203+ echo -e " ${GREEN} 📁 Binaries available in: ${BUILD_DIR} /*/lambda-nat-proxy*${NC} "
204+ echo " "
205+ echo -e " ${BLUE} Built platforms:${NC} "
206+ for platform_spec in " ${PLATFORMS[@]} " ; do
207+ IFS=' :' read -r platform_key os arch <<< " $platform_spec"
208+ binary_name=" lambda-nat-proxy"
209+ if [[ " $os " == " windows" ]]; then
210+ binary_name=" lambda-nat-proxy.exe"
211+ fi
212+ echo -e " • ${BUILD_DIR} /${platform_key} /${binary_name} "
213+ done
214+ echo -e " • ${BUILD_DIR} /bootstrap (Lambda function - Linux only)"
215+
216+ # Detect current platform for run suggestion
217+ CURRENT_OS=$( uname -s | tr ' [:upper:]' ' [:lower:]' )
218+ CURRENT_ARCH=$( uname -m | sed ' s/x86_64/amd64/' | sed ' s/aarch64/arm64/' )
219+ echo -e " ${YELLOW} 💡 To run on this system: ./${BUILD_DIR} /${CURRENT_OS} -${CURRENT_ARCH} /lambda-nat-proxy --help${NC} "
0 commit comments