werf Cheat Sheet
Overview
werf is an open-source CI/CD tool that implements a Git-native approach to delivery. It integrates with any CI system and manages the full lifecycle of building Docker images, deploying Helm charts to Kubernetes, and cleaning up unused images. werf uses Git as the single source of truth, building reproducible images based on Git history.
werf provides advanced features like content-based tagging (images are tagged by content hash rather than Git commit), Helm chart deployment with built-in tracking of resource readiness, multi-platform builds, and automatic cleanup of unused container registry images based on Git branch and tag policies.
Installation
# Linux/macOS (multiwerf installer)
curl -sSL https://werf.io/install.sh | bash -s -- --ci
# macOS
brew tap werf/tap
brew install werf
# Linux
curl -sSLO https://tuf.werf.io/targets/releases/2.10.4/linux-amd64/bin/werf
chmod +x werf
sudo mv werf /usr/local/bin/
# Verify
werf version
Core Commands
| Command | Description |
|---|---|
werf converge | Build, publish, and deploy |
werf build | Build images |
werf run | Run built image locally |
werf dismiss | Delete deployed release |
werf cleanup | Clean up container registry |
werf render | Render Helm templates |
werf plan | Preview deployment changes |
werf bundle publish | Publish as Helm bundle |
werf bundle apply | Deploy from bundle |
Configuration
Basic werf.yaml
configVersion: 1
project: my-app
---
image: backend
dockerfile: Dockerfile
context: backend
---
image: frontend
dockerfile: Dockerfile
context: frontend
args:
NODE_ENV: production
Stapel Image (werf-native builder)
configVersion: 1
project: my-app
---
image: app
from: ubuntu:22.04
git:
- add: /src
to: /app/src
- add: /requirements.txt
to: /app/requirements.txt
shell:
beforeInstall:
- apt-get update && apt-get install -y python3 python3-pip
install:
- pip3 install -r /app/requirements.txt
setup:
- echo "App version: $(date +%Y%m%d)" > /app/version.txt
docker:
WORKDIR: /app
CMD: ["python3", "src/main.py"]
EXPOSE: "8080"
Multi-Stage Dockerfile
configVersion: 1
project: my-app
---
image: app
dockerfile: Dockerfile
target: production
context: .
args:
GO_VERSION: "1.22"
---
image: migrations
dockerfile: Dockerfile
target: migrations
context: .
Deployment
Converge (Build + Deploy)
# Build and deploy
werf converge --repo registry.example.com/my-app
# Deploy to specific environment
werf converge --repo registry.example.com/my-app --env production
# Deploy with custom values
werf converge --repo registry.example.com/my-app \
--set replicaCount=3 \
--values .helm/values-production.yaml
# Dry run / plan
werf plan --repo registry.example.com/my-app
Helm Chart Structure
.helm/
Chart.yaml
values.yaml
templates/
deployment.yaml
service.yaml
ingress.yaml
# .helm/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-app
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ .Release.Name }}
template:
spec:
containers:
- name: app
image: {{ .Values.werf.image.app }}
ports:
- containerPort: 8080
Environment-Specific Values
# .helm/values.yaml (default)
replicaCount: 1
ingress:
enabled: false
# .helm/values-production.yaml
replicaCount: 3
ingress:
enabled: true
host: app.example.com
Advanced Usage
CI/CD Integration (GitLab)
# .gitlab-ci.yml
stages:
- build
- deploy
- cleanup
build:
stage: build
script:
- werf build --repo $CI_REGISTRY_IMAGE
deploy-staging:
stage: deploy
script:
- werf converge --repo $CI_REGISTRY_IMAGE --env staging
environment:
name: staging
deploy-production:
stage: deploy
script:
- werf converge --repo $CI_REGISTRY_IMAGE --env production
environment:
name: production
when: manual
cleanup:
stage: cleanup
script:
- werf cleanup --repo $CI_REGISTRY_IMAGE
only:
- schedules
GitHub Actions
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: werf/actions/install@v2
- uses: werf/actions/converge@v2
with:
env: production
env:
WERF_REPO: ghcr.io/${{ github.repository }}
WERF_KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
Registry Cleanup
# Clean unused images based on Git policies
werf cleanup --repo registry.example.com/my-app
# Custom cleanup policies in werf.yaml
# werf.yaml cleanup policies
cleanup:
keepPolicies:
- references:
branch: /^main$/
imagesPerReference:
last: 10
- references:
tag: /^v\d+\.\d+\.\d+$/
imagesPerReference:
last: 5
- references:
branch: /.*/
imagesPerReference:
last: 2
in: 168h # 7 days
Bundles (Distributable Charts)
# Publish a bundle
werf bundle publish --repo registry.example.com/my-app --tag v1.0.0
# Deploy from bundle
werf bundle apply --repo registry.example.com/my-app --tag v1.0.0 \
--release my-app --namespace production
Giterminism
# werf-giterminism.yaml
giterminismConfigVersion: 1
config:
goTemplateRendering:
allowEnvVariables:
- WERF_ENV
- CI_*
dockerfile:
allowContextAddFiles:
- configs/
helm:
allowUncommittedFiles:
- .helm/values-local.yaml
Troubleshooting
| Issue | Solution |
|---|---|
| Build cache not used | Check content-based tagging; ensure Git history is fetched |
| Converge timeout | Increase --timeout flag; check pod readiness |
| Registry auth fails | Run docker login or configure --repo credentials |
| Giterminism error | Commit changes or configure werf-giterminism.yaml |
| Cleanup too aggressive | Adjust keepPolicies in cleanup config |
| Helm render error | Run werf render to debug template output |
# Debug build
werf build --repo registry.example.com/my-app --log-verbose
# Render templates without deploying
werf render --repo registry.example.com/my-app
# Plan deployment changes
werf plan --repo registry.example.com/my-app
# Delete deployment
werf dismiss --env staging
# Check werf version
werf version