Build Options
Learn how to optimize builds with caching, build arguments, and advanced Docker build features.
Build Arguments
Pass variables to your Dockerfile during build time using --build-arg.
Basic Build Args
Dockerfile:
ARG VERSION=dev
ARG BUILD_DATE
LABEL version="${VERSION}"
LABEL build-date="${BUILD_DATE}"
Build with arguments:
uc build --build-arg VERSION=1.2.3 --build-arg BUILD_DATE=2024-03-15
Or using uc deploy:
uc deploy --build-arg VERSION=1.2.3
Multiple Build Args
Pass multiple arguments:
uc build \
--build-arg NODE_ENV=production \
--build-arg API_URL=https://api.example.com \
--build-arg VERSION=1.2.3
Build Args in compose.yaml
Define build args in your compose file:
services:
web:
build:
context: .
args:
NODE_ENV: production
VERSION: "1.2.3"
image: myapp:latest
Override from command line:
uc build --build-arg NODE_ENV=development
Command line args take precedence over compose.yaml.
Environment Variable Build Args
Use environment variables:
export VERSION=1.2.3
uc build --build-arg VERSION
Or inline:
VERSION=1.2.3 uc build --build-arg VERSION
Common Build Arg Patterns
Version tagging:
ARG VERSION=latest
ENV APP_VERSION=${VERSION}
uc build --build-arg VERSION=$CI_COMMIT_SHA
Environment-specific builds:
ARG BUILD_ENV=development
RUN if [ "$BUILD_ENV" = "production" ]; then \
npm run build:prod; \
else \
npm run build:dev; \
fi
uc build --build-arg BUILD_ENV=production
Conditional dependencies:
ARG ENABLE_FEATURE_X=false
RUN if [ "$ENABLE_FEATURE_X" = "true" ]; then \
apt-get install -y feature-x-deps; \
fi
Build Caching
Docker caches build layers to speed up subsequent builds. Understanding caching is key to fast iteration.
How Caching Works
Docker caches each instruction in your Dockerfile:
FROM node:20-alpine # Cached if base image unchanged
WORKDIR /app # Cached
COPY package*.json ./ # Cached if package files unchanged
RUN npm install # Cached if previous layer cached
COPY . . # Cached if source files unchanged
RUN npm run build # Cached if previous layer cached
Changes to any instruction invalidate cache for that layer and all subsequent layers.
Optimize for Caching
Good: Dependencies cached separately from source
FROM node:20-alpine
WORKDIR /app
# Install dependencies (cached unless package files change)
COPY package*.json ./
RUN npm install
# Copy source (cached unless source changes)
COPY . .
RUN npm run build
Bad: Everything rebuilds on any source change
FROM node:20-alpine
WORKDIR /app
# Copy everything (cache invalidated on any file change)
COPY . .
RUN npm install && npm run build
Disable Caching
Force a complete rebuild without using cache:
uc build --no-cache
When to use:
- Debugging build issues
- Cache is stale or corrupted
- External dependencies changed
- Want to ensure a clean build
Selective Cache Invalidation
Use .dockerignore to prevent cache invalidation from irrelevant files:
# .dockerignore
.git
node_modules
*.log
.env
README.md
Changes to these files won't invalidate Docker cache.
Pull Base Images
Control whether Docker pulls newer base images before building.
Always Pull
Pull latest base images during build:
uc build --pull
Dockerfile:
FROM node:20-alpine # Pulls latest 20-alpine before building
When to use:
- Using
:latestor floating tags - Want security updates from base images
- CI/CD builds to ensure fresh base images
Default Behavior
By default, Docker uses locally cached base images if available.
uc build # Uses cached node:20-alpine
Build Context
The build context is the set of files available during the build.
Default Context
By default, context is the directory containing your Dockerfile:
services:
web:
build: . # Context is current directory
Custom Context
Specify a different build context:
services:
web:
build:
context: ./backend
dockerfile: Dockerfile
Large Build Context
Large contexts slow down builds. Use .dockerignore:
# .dockerignore
node_modules
.git
*.log
dist/
build/
.env*
Multiple Build Contexts
Use additional contexts (Docker BuildKit feature):
services:
web:
build:
context: .
additional_contexts:
shared: ../shared-library
In Dockerfile:
FROM node:20-alpine
COPY --from=shared /src /app/shared
Multi-stage Builds
Optimize image size with multi-stage builds.
Basic Multi-stage Build
# Build stage
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# Production stage
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY package*.json ./
RUN npm install --production
CMD ["node", "dist/main.js"]
Final image only contains production assets.
Target Specific Stage
Build only up to a specific stage:
services:
web:
build:
context: .
target: builder # Stop at builder stage
uc build --target builder
Use case: Build development images with extra tools.
Development vs Production
# Base stage
FROM node:20 AS base
WORKDIR /app
COPY package*.json ./
# Development stage
FROM base AS development
RUN npm install
COPY . .
CMD ["npm", "run", "dev"]
# Build stage
FROM base AS builder
RUN npm install
COPY . .
RUN npm run build
# Production stage
FROM node:20-alpine AS production
WORKDIR /app
COPY --from=builder /app/dist ./dist
RUN npm install --production
CMD ["node", "dist/main.js"]
Build for development:
uc build --target development
Build for production:
uc build --target production
Platform-specific Builds
Build for specific CPU architectures.
Specify Platform
services:
web:
build:
context: .
platform: linux/amd64
Multi-architecture Builds
Build for multiple platforms:
docker buildx build --platform linux/amd64,linux/arm64 -t myapp:latest .
Note: Multi-arch builds require Docker Buildx.
Validation and Checks
Validate Build Configuration
Check build config without actually building:
uc build --check
This validates:
- Dockerfile exists
- Build context is accessible
compose.yamlsyntax is correct- Build arguments are valid
Use case: Pre-commit hooks, CI checks
Build Progress
View Build Output
By default, you see full Docker build output:
uc build
Output shows:
Building service web...
[+] Building 12.5s (14/14) FINISHED
=> [internal] load build definition
=> [internal] load .dockerignore
=> [internal] load metadata for docker.io/library/node:20
=> [1/6] FROM docker.io/library/node:20
=> [2/6] WORKDIR /app
=> [3/6] COPY package*.json ./
=> [4/6] RUN npm install
=> [5/6] COPY . .
=> [6/6] RUN npm run build
=> exporting to image
=> => naming to myapp:latest
Service Selection
Build Specific Services
Build only named services:
# Build only frontend
uc build frontend
# Build frontend and API
uc build frontend api
Build with Dependencies
Build a service and its dependencies:
uc build api --deps
If API depends on shared libraries or other services, they're built too.
Best Practices
1. Optimize Layer Caching
Place frequently changing instructions last:
FROM python:3.11
WORKDIR /app
# Rarely changes - cached
COPY requirements.txt .
RUN pip install -r requirements.txt
# Changes often - separate layer
COPY . .
2. Use .dockerignore
Exclude unnecessary files:
.git
*.log
node_modules
__pycache__
.env*
.vscode
3. Multi-stage for Size
Keep final images small:
FROM golang:1.21 AS builder
COPY . .
RUN go build -o app
FROM alpine:latest
COPY --from=builder /app /app
CMD ["/app"]
4. Pin Base Image Versions
Use specific versions in production:
FROM node:20.11.0-alpine # Specific version
# Not: FROM node:latest
5. Leverage Build Args for Flexibility
ARG NODE_ENV=production
ARG VERSION=latest
ENV NODE_ENV=${NODE_ENV}
LABEL version="${VERSION}"
uc build --build-arg NODE_ENV=production --build-arg VERSION=1.2.3
Troubleshooting
Build Failures
Check build output for errors:
uc build
Common issues:
- Missing dependencies in Dockerfile
- Incorrect build context
- Network issues during package installation
Slow Builds
Speed up builds:
- Use
.dockerignoreto reduce context size - Optimize layer caching (dependencies first)
- Use multi-stage builds to parallelize
- Consider smaller base images
Cache Issues
If cache seems wrong:
uc build --no-cache
Out of Disk Space
Clean up old images:
docker image prune -a
Next Steps
- Pushing Images - Learn how to push images to cluster and registries
- When to Build - Understand when to use
uc buildvsuc deploy - Deploy from Dockerfile - See build options in action