@putnami/docker
v0.0.3-cfbc20e
Published
Docker support for building, publishing, and running containerized applications
Downloads
87
Readme
@putnami/docker
Docker support for building, publishing, and running containerized applications in the Putnami monorepo.
Overview
The @putnami/docker plugin provides a unified interface for Docker operations across all runtime/service projects. It delegates the concrete Docker image implementation to technology-specific plugins (TypeScript, Python, Go) while providing consistent commands for building, publishing, and running containers.
Installation
Add @putnami/docker to your project's devDependencies:
{
"devDependencies": {
"@putnami/docker": "workspace:*",
"@putnami/typescript": "workspace:*"
}
}Commands
Project Resolution Defaults (project-scoped commands):
- If run inside a project directory with no project argument,
.is used. - If run from the workspace root with no project argument,
[impacted]is used.
docker build
Build a Docker image for a project.
putnami docker build [project]Options:
--tag <tag>: Image tag (default: branch-based tag with SHA, e.g.,canary.abc1234)--registry <registry>: Docker registry (default: from workspace config or local)--platform <platform>: Target platform (default:linux/amd64)--no-cache: Disable build cache--push: Push image after build--file <file>: Custom Dockerfile path (overrides auto-generation)--port <port>: Port to expose (default: from project config or 3000)--workspace-builder-image <image>: Shared workspace builder image to use for build stage
Dockerfile Resolution (first match wins):
--file <path>(absolute or relative to the project root)Dockerfileat the project root- Generated Dockerfile at
{project}/.gen/Dockerfile
Tag Strategy:
When --tag is not provided, the build uses the same strategy as registry publishing:
- Uses branch-based tag with git SHA (e.g.,
canary.abc1234for main branch) - Format:
{branch-tag}.{sha}or{branch-tag}.{sha}.{dirty-hash}for uncommitted changes - Main/master branches use
canaryas the branch tag - Other branches use sanitized branch name as the tag
Example:
# Build image for current project
putnami docker build .
# Build with custom tag
putnami docker build my-app --tag my-app:v1.0.0
# Build and push to registry
putnami docker build my-app --registry ghcr.io/myorg --push
# Build using shared workspace builder image
putnami docker build my-app --workspace-builder-image ghcr.io/myorg/putnami-workspace-builder:canarydocker build-workspace
Build a shared workspace builder image (Bun cache + full workspace build output).
When no custom Dockerfile is provided, the generated Dockerfile is stored at .putnami/projects/[workspace]/@putnami-docker/Dockerfile and copies all workspace projects discovered by Putnami.
putnami docker build-workspaceOptions:
--image <image>: Full image name (overrides registry/name/tag)--tag <tag>: Image tag (default: branch-based tag with SHA)--registry <registry>: Docker registry (default: from workspace config or local)--platform <platform>: Target platform (default:linux/amd64)--no-cache: Disable build cache--push: Push image after build--file <file>: Custom Dockerfile path (overrides auto-generation)
Default naming:
If --image is not provided, the image is named:
{workspace}-workspace-builder:{branch-tag}.{sha}
Example:
# Build workspace builder image (default naming)
putnami docker build-workspace
# Build with custom tag
putnami docker build-workspace --tag canary
# Build and push to registry
putnami docker build-workspace --registry ghcr.io/myorg --push
# Use the workspace builder for project images
putnami docker build my-app --workspace-builder-image ghcr.io/myorg/putnami-workspace-builder:canarydocker publish
Publish a Docker image to a registry.
putnami docker publish [project] --registry <registry>Options:
--tag <tag>: Image tag (default: version from package.json)--registry <registry>: Docker registry (required, or from workspace config)--platform <platform>: Target platform (default:linux/amd64)--latest: Also tag aslatest(otherwise uses branch-based tag like registry dist-tags)--dry-run: Show what would be published
Tag Strategy:
When --tag is not provided, the publish uses the same strategy as registry publishing:
- Uses version from
package.jsonas the base tag - If
--latestis set, also tags aslatest - Otherwise, also tags with branch-based tag (e.g.,
canary) similar to registry dist-tags - Example: For version
1.0.0onmainbranch, publishes tags:1.0.0andcanary
Base Image Resolution:
- Publishes from the image tagged with the current branch-based suffix (e.g.,
canary.abc1234) - If that image does not exist, falls back to a local
latestimage - If neither exists, publish fails (build with
putnami docker build <project> --no-cache)
Requirements:
- A version in
package.jsonor--tagis required, otherwise no tags can be published
Example:
# Publish with version tag
putnami docker publish my-app --registry ghcr.io/myorg
# Publish with latest tag
putnami docker publish my-app --registry ghcr.io/myorg --latest
# Dry run to see what would be published
putnami docker publish my-app --registry ghcr.io/myorg --dry-rundocker run
Run a Docker container locally.
putnami docker run [project]Options:
--tag <tag>: Image tag to run (default:latest)--port <port>: Port mapping (format:host:containeror just port number, can be specified multiple times; defaults to imagePORT/EXPOSEor 3000)--env <key=value>: Environment variable (can be specified multiple times)--detach: Run in detached mode--rm: Remove container after exit (default: true)--name <name>: Container name
Behavior:
- Removes any existing container with the same name before starting
- Starts the container in detached mode and tails logs unless
--detachis set Ctrl+Cstops the container and removes it when--rmis true
Example:
# Run container
putnami docker run my-app
# Run with port mapping
putnami docker run my-app --port 3000:3000
# Run with environment variables
putnami docker run my-app --env NODE_ENV=production --env API_KEY=secret
# Run in detached mode
putnami docker run my-app --detachDetailed Command Docs
Technology Plugin Integration
The docker plugin automatically detects which technology plugin is available and delegates image building to it. Currently supported:
- @putnami/typescript: Generates multi-stage Dockerfiles for Bun/TypeScript projects
How It Works
- The docker plugin detects which technology plugin is in your
devDependencies - It imports the docker implementation from that plugin (e.g.,
@putnami/typescript/docker) - The technology plugin generates a Dockerfile optimized for that technology
- The docker plugin builds the image using the generated Dockerfile
TypeScript/Bun Implementation
For TypeScript projects, the plugin generates a multi-stage Dockerfile:
- Builder stage: Full Bun runtime with all dependencies
- Runtime stage: Minimal
bun:1-slimimage with only production dependencies
The Dockerfile is optimized for:
- CI time: Layer caching separates dependency installation from source code
- Artifact size: Multi-stage build removes build tools from final image
- Reproducibility: Uses
--frozen-lockfilefor consistent builds
Configuration
Configure Docker behavior at either the workspace or project level. Project-level configuration overrides workspace-level configuration.
Workspace-Level Configuration
In putnami.json at workspace root:
{
"defaultParams": {
"@putnami/docker": {
"registry": "europe-west9-docker.pkg.dev/myorg/images",
"platform": "linux/amd64"
}
}
}Project-Level Configuration
In your project's .putnamirc.json:
{
"commands": {
"@putnami/docker": {
"registry": "ghcr.io/myorg",
"platform": "linux/amd64",
"port": 3000
}
}
}Configuration Priority
Configuration is merged in the following order (highest to lowest priority):
- Command-line arguments (e.g.,
--registry) - Project-level
commandsin.putnamirc.json - Workspace-level
defaultParamsinputnami.json
Job Dependencies
The docker jobs have the following dependencies:
docker build: Depends on^buildand/docker-build-workspace(builds dependencies and the shared workspace builder image first)docker build-workspace: Depends on*build(builds all workspace projects before creating the builder image)docker publish: Depends ondocker-buildand^docker-publish(publishes dependencies first)docker run: Depends ondocker-build(ensures the image is built before running)
This ensures that:
- All project dependencies are built before building the Docker image
- Dependencies are published before the project itself
CI/CD Integration
GitHub Actions Example
name: Build and Publish Docker Images
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: oven-sh/setup-bun@v1
- name: Install dependencies
run: bun install
- name: Build Docker images
run: bunx putnami docker build --impacted
- name: Publish Docker images
run: |
echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
bunx putnami docker publish --impacted --registry ghcr.io/myorg --latestBest Practices
- Use layer caching: Don't use
--no-cacheunless necessary - Build dependencies first: The plugin handles this automatically via job dependencies
- Use version tags: Let the plugin generate version-based tags for reproducibility
- Multi-stage builds: Technology plugins generate optimized multi-stage Dockerfiles
- Minimal base images: Use slim/alpine variants when possible
Troubleshooting
Docker not available
If you see "Docker is not available", ensure:
- Docker is installed and running
- Docker daemon is accessible
Technology plugin not found
If you see "No technology plugin found", ensure:
- You have
@putnami/typescript,@putnami/python, or@putnami/goindevDependencies - The plugin supports Docker (exports
./docker)
Build fails
Common issues:
- Missing build output: Ensure you've run
putnami buildfirst - Workspace dependencies: Ensure all workspace dependencies are built
- Port conflicts: Check if the port is already in use
Architecture
See PLAN.md for detailed architecture and implementation details.
