Skip to content

Commit 404ca3e

Browse files
dan-vclaude
andcommitted
Add Docker-based build system
- Multi-stage Docker builds for zero-dependency compilation - Cross-platform build scripts for Linux/macOS/Windows - Single and multi-platform build support with buildx - Automated dependency management (Node.js, Go) - Build artifacts organization and cleanup - Fallback support for systems without Docker buildx 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 9697198 commit 404ca3e

File tree

4 files changed

+369
-0
lines changed

4 files changed

+369
-0
lines changed

Dockerfile.build

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Multi-stage Docker build for lambda-nat-proxy
2+
# This ensures reproducible builds with all dependencies included
3+
4+
# Stage 1: Node.js environment for dashboard build
5+
FROM node:18-alpine AS dashboard-builder
6+
7+
# Set working directory
8+
WORKDIR /app
9+
10+
# Copy package files
11+
COPY web/package*.json ./web/
12+
WORKDIR /app/web
13+
14+
# Install dependencies and build dashboard
15+
RUN npm ci --only=production
16+
COPY web/ .
17+
RUN npm run build
18+
19+
# Stage 2: Go environment for binary build
20+
FROM golang:1.21-alpine AS go-builder
21+
22+
# Build arguments for target platform
23+
ARG TARGETOS=linux
24+
ARG TARGETARCH=amd64
25+
26+
# Install build dependencies
27+
RUN apk add --no-cache git
28+
29+
# Set working directory
30+
WORKDIR /app
31+
32+
# Copy source code first
33+
COPY . .
34+
35+
# Copy built dashboard from previous stage
36+
COPY --from=dashboard-builder /app/web/dist ./internal/dashboard/web/dist
37+
38+
# Fix the replace directive in lambda/go.mod to use absolute path
39+
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
40+
41+
# Download dependencies
42+
RUN go mod download
43+
RUN cd lambda && go mod download
44+
45+
# Build Lambda function
46+
RUN cd lambda && GOOS=linux GOARCH=amd64 go build -o ../cmd/lambda-nat-proxy/assets/bootstrap .
47+
48+
# Build main binary for target platform
49+
RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -a -installsuffix cgo -o lambda-nat-proxy ./cmd/lambda-nat-proxy
50+
51+
# Stage 3: Final minimal image (optional, for running)
52+
FROM alpine:latest AS final
53+
54+
RUN apk --no-cache add ca-certificates
55+
WORKDIR /root/
56+
57+
COPY --from=go-builder /app/lambda-nat-proxy .
58+
COPY --from=go-builder /app/cmd/lambda-nat-proxy/assets/bootstrap ./assets/
59+
60+
CMD ["./lambda-nat-proxy"]

scripts/build-dashboard.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/bin/bash
2+
3+
# Build Dashboard Script
4+
# This script builds the React frontend and prepares it for embedding
5+
6+
set -e
7+
8+
echo "🔨 Building React frontend..."
9+
cd web
10+
npm run build
11+
12+
echo "📁 Copying build files to Go embed location..."
13+
cd ..
14+
rm -rf internal/dashboard/web/dist
15+
mkdir -p internal/dashboard/web
16+
cp -r web/dist internal/dashboard/web/
17+
18+
echo "✅ Dashboard frontend build complete!"
19+
echo "💡 Dashboard is now ready for embedding in the Go binary"

scripts/docker-build-all.sh

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
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}"

scripts/docker-build.sh

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#!/bin/bash
2+
3+
# Docker-based build script for lambda-nat-proxy
4+
# This script builds the entire project using Docker, eliminating host dependencies
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+
echo -e "${BLUE}🐳 Building lambda-nat-proxy using Docker...${NC}"
19+
echo -e "${YELLOW}📦 This includes all dependencies (Node.js, Go, etc.)${NC}"
20+
21+
# Create build directory
22+
mkdir -p ${BUILD_DIR}
23+
24+
# Build using Docker
25+
# Detect host platform for building native binary
26+
HOST_OS=$(uname -s | tr '[:upper:]' '[:lower:]')
27+
HOST_ARCH=$(uname -m | sed 's/x86_64/amd64/' | sed 's/aarch64/arm64/')
28+
29+
echo -e "${BLUE}🔨 Building Docker image for ${HOST_OS}/${HOST_ARCH}...${NC}"
30+
31+
# Build the Docker image with host platform targeting
32+
docker build \
33+
--build-arg TARGETOS="${HOST_OS}" \
34+
--build-arg TARGETARCH="${HOST_ARCH}" \
35+
-f Dockerfile.build \
36+
-t lambda-nat-proxy-builder \
37+
.
38+
39+
# Extract binaries from the built image
40+
echo -e "${BLUE}📤 Extracting built binaries...${NC}"
41+
42+
# Create a temporary container and copy files
43+
CONTAINER_ID=$(docker create lambda-nat-proxy-builder)
44+
45+
# Copy main binary
46+
docker cp ${CONTAINER_ID}:/root/lambda-nat-proxy ./${BUILD_DIR}/lambda-nat-proxy
47+
48+
# Copy lambda bootstrap
49+
docker cp ${CONTAINER_ID}:/root/assets/bootstrap ./${BUILD_DIR}/bootstrap
50+
51+
# Clean up container
52+
docker rm ${CONTAINER_ID}
53+
54+
# Make binaries executable
55+
chmod +x ${BUILD_DIR}/lambda-nat-proxy
56+
chmod +x ${BUILD_DIR}/bootstrap
57+
58+
echo -e "${GREEN}✅ Build complete!${NC}"
59+
echo -e "${GREEN}📁 Binaries available in: ${BUILD_DIR}/${NC}"
60+
echo ""
61+
echo -e "${BLUE}Built artifacts:${NC}"
62+
echo -e "${BUILD_DIR}/lambda-nat-proxy (CLI with embedded dashboard and Lambda)"
63+
echo -e "${BUILD_DIR}/bootstrap (Lambda function)"
64+
echo ""
65+
echo -e "${YELLOW}💡 To run: ./${BUILD_DIR}/lambda-nat-proxy --help${NC}"
66+
67+
# Optional: Clean up Docker image
68+
if [[ "${CLEANUP:-yes}" == "yes" ]]; then
69+
echo -e "${BLUE}🧹 Cleaning up Docker image...${NC}"
70+
docker rmi lambda-nat-proxy-builder
71+
fi

0 commit comments

Comments
 (0)