feat: add Docker support with multi-stage build#132
Conversation
Add Dockerfile and .dockerignore for containerized deployment. - Multi-stage build: Node.js (client) → Go (binary) → Alpine (runtime) - Final image size: 34MB (under 50MB target) - Non-root user for security - Volume mounts work with live reload - GOTOOLCHAIN=auto for future Go version compatibility Usage: docker build -t tinkerdown . docker run -v $(pwd):/app -p 8080:8080 tinkerdown Closes #63 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
PR Review: Docker Support with Multi-Stage BuildSummaryThis PR adds Docker support with a well-structured multi-stage build that successfully achieves the 34MB image size (well under the 50MB target). The implementation is solid overall with good security practices. ✅ Strengths
🔍 Issues & RecommendationsCritical Issues1. Go version mismatch (Dockerfile:12) FROM golang:1.24-alpine AS go-builderIssue: The Dockerfile specifies Go 1.24, but Fix: Change to 2. Missing CSS file copy (Dockerfile:32) Fix: Explicitly copy all required files: RUN mkdir -p internal/assets/client && \
cp client/dist/tinkerdown-client.browser.js internal/assets/client/ && \
cp client/dist/tinkerdown-client.browser.js.map internal/assets/client/ && \
cp client/dist/tinkerdown-client.browser.css internal/assets/client/ && \
cp client/dist/tinkerdown-client.browser.css.map internal/assets/client/Medium Priority3. Build arguments usage 4. Missing CI/CD integration 5. Missing healthcheck Minor Improvements6. .dockerignore additions 🧪 Test CoverageMissing:
Recommendation: Add a CI job to test Docker builds and verify image size stays under 50MB. 🔒 SecurityGood:
Consider:
⚡ PerformanceGood:
📋 Checklist Before Merge
Overall AssessmentThis is a well-structured PR that demonstrates good Docker practices. The two critical issues (Go version and CSS files) must be fixed before merge, as they will cause build failures and missing styles. Once fixed, this will be a solid Docker implementation. The 34MB image size is impressive and the security practices are sound. Great work! 🚀 Review generated by Claude Code |
There was a problem hiding this comment.
Pull request overview
Adds containerization support for the tinkerdown CLI via a multi-stage Docker build, aiming for a small runtime image and enabling volume-mounted development workflows.
Changes:
- Introduces a 3-stage
Dockerfile(Node client build → Go build → minimal Alpine runtime). - Adds a
.dockerignoreto reduce Docker build context and improve caching/build performance.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| Dockerfile | Multi-stage build that compiles the TS client and Go binary, then ships a minimal non-root runtime image. |
| .dockerignore | Excludes binaries, VCS metadata, docs, and build artifacts to speed up builds and reduce context size. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ARG VERSION=dev | ||
| ARG BUILD_TIME=unknown | ||
| RUN CGO_ENABLED=0 GOOS=linux go build \ | ||
| -ldflags="-s -w -X main.version=${VERSION} -X main.buildTime=${BUILD_TIME}" \ |
There was a problem hiding this comment.
The ldflags here attempt to set main.version and main.buildTime via -X, but the cmd/tinkerdown main package currently defines version as a const and does not define buildTime at all. go build will fail with -X main.version=...: not a var / missing symbol. Consider switching these to var values in the main package (with defaults) or updating the ldflags to match existing variables.
| -ldflags="-s -w -X main.version=${VERSION} -X main.buildTime=${BUILD_TIME}" \ | |
| -ldflags="-s -w" \ |
Dockerfile
Outdated
| FROM golang:1.24-alpine AS go-builder | ||
|
|
||
| # Install git for version info and ca-certificates for HTTPS | ||
| RUN apk add --no-cache git ca-certificates | ||
|
|
||
| WORKDIR /app | ||
|
|
||
| # Allow Go to download required toolchain version automatically | ||
| ENV GOTOOLCHAIN=auto | ||
|
|
There was a problem hiding this comment.
go.mod specifies go 1.25.3, but this builder stage pins golang:1.24-alpine. Even with GOTOOLCHAIN=auto, this can force an extra toolchain download (hurting build reliability in restricted networks) or fail if the toolchain can't be fetched. Consider aligning the builder image tag to the Go version required by go.mod (or document why you intentionally rely on toolchain auto-download).
- Update Go base image to 1.25-alpine (matches go.mod requirement) - Make CSS/JS file copying explicit for clarity - Add additional patterns to .dockerignore (*.log, .env*, *.sqlite-*) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
PR Review: Docker Support with Multi-Stage BuildOverall, this is a well-crafted PR that adds Docker support with an efficient multi-stage build. The implementation is clean and follows best practices. ✅ Strengths
🔍 Critical IssueGo Version Mismatch (Dockerfile:12)
📋 High Priority Recommendations
📋 Medium/Low Priority
🧪 Testing Recommendations
✅ Final VerdictHigh-quality PR - Nearly ready to merge after fixing the critical Go version issue. Recommendation: ✅ Approve after changing to Other suggestions can be follow-up PRs. Great work on the multi-stage build and achieving 34MB image size! Review by Claude Code |
Summary
Details
3-stage build:
node:20-alpine- builds TypeScript clientgolang:1.24-alpine- compiles Go binaryalpine:3.21- minimal runtime (34MB)Features:
GOTOOLCHAIN=autofor Go version compatibilityUsage
Test plan
Closes #63
🤖 Generated with Claude Code