Docker Support
Deploy applications using Docker containers with Gokku.
Overview
Gokku uses Docker containers for all applications with blue-green deployment for zero-downtime updates.
All applications run in Docker containers regardless of language:
- Go - Compiled in container
- Python - Interpreted in container
- Node.js - Interpreted in container
- Ruby - Interpreted in container
Configuration
All applications use Docker by default. Configure your app:
apps:
my-app:
lang: python
path: ./app
entrypoint: main.pyAutomatic Dockerfile Generation
If no Dockerfile exists, Gokku generates one based on your language:
Python
apps:
flask-app:
lang: python
path: .
entrypoint: app.pyGenerated Dockerfile:
FROM python:3.11-slim
WORKDIR /app
RUN apt-get update && apt-get install -y --no-install-recommends gcc && rm -rf /var/lib/apt/lists/*
COPY requirements.txt* ./
RUN if [ -f requirements.txt ]; then pip install --no-cache-dir -r requirements.txt; fi
COPY . .
EXPOSE ${PORT:-8080}
CMD ["python", "app.py"]Node.js
apps:
node-app:
lang: nodejs
path: .
entrypoint: index.jsGenerated Dockerfile:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE ${PORT:-8080}
CMD ["node", "index.js"]Go (with Docker)
apps:
go-app:
path: .Generated Dockerfile:
FROM golang:1.25-alpine AS builder
WORKDIR /app
COPY go.* ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o app .
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/app .
EXPOSE ${PORT:-8080}
CMD ["./app"]Custom Dockerfile
Use your own Dockerfile:
apps:
my-app:
dockerfile: ./DockerfileExample: Python with System Dependencies
FROM python:3.11-slim
# Install system packages
RUN apt-get update && apt-get install -y \
gcc \
ffmpeg \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE ${PORT:-8080}
CMD ["gunicorn", "--bind", "0.0.0.0:${PORT:-8080}", "app:app"]Example: Multi-Stage Build
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY --from=builder /app/dist ./dist
EXPOSE ${PORT:-8080}
CMD ["node", "dist/server.js"]Base Images
Configure Global Base Images
docker:
base_images:
go: "golang:1.25-alpine"
python: "python:3.11-slim"
nodejs: "node:20-alpine"Per-App Base Image
apps:
ml-service:
lang: python
image: "python:3.11" # Full image, not slimFrom Private Registry
docker:
registry: "registry.example.com"
apps:
api:
image: "registry.example.com/python:3.11-custom"Login on server first:
ssh ubuntu@server "docker login registry.example.com"Custom Dockerfiles
Gokku supports custom Dockerfiles for advanced use cases.
python 3.11
ffmpeg 8.0Gokku generates:
FROM python:3.11-slim
WORKDIR /app
# Install dependencies
RUN apt-get update && apt-get install -y curl git build-essential && rm -rf /var/lib/apt/lists/*
# Copy application
COPY . .
EXPOSE ${PORT:-8080}
CMD ["python", "app.py"].tool-versions:
python 3.11
ffmpeg 8.0
whispercpp 1.5.0Generated Dockerfile includes plugin installation:
# Install custom dependencies
RUN apt-get update && apt-get install -y ffmpeg
# ...Image Management
Tagging
Gokku automatically tags images:
my-app:release-1
my-app:release-2
my-app:release-3Each deployment creates a new tag.
Keep Images
Configure how many images to keep:
apps:
my-app:
deployment:
keep_images: 10 # Keep last 10 imagesOld images are automatically pruned after deployment.
Manual Cleanup
# List images
ssh ubuntu@server "docker images | grep my-app"
# Remove specific image
ssh ubuntu@server "docker rmi my-app:release-5"
# Remove all unused images
ssh ubuntu@server "docker image prune -a"Port Mapping
Docker maps: 8080:8080
Custom Ports
Set via environment variables:
gokku config set PORT=8081 --app api --env production -a api-productionThen redeploy.
Container Management
View Running Containers
ssh ubuntu@server "docker ps | grep my-app"View Logs
# Using CLI
gokku logs -a my-app-production -f
# Or directly
ssh ubuntu@server "docker logs -f my-app-blue"Restart Container
# Using CLI
gokku restart -a my-app-production
# Or directly
ssh ubuntu@server "docker restart my-app-blue"Stop Container
ssh ubuntu@server "docker stop my-app-blue"Start Container
ssh ubuntu@server "docker start my-app-blue"Access Container Shell
ssh ubuntu@server "docker exec -it my-app-blue /bin/sh"Inspect Container
ssh ubuntu@server "docker inspect my-app-blue"Environment Variables
All environment variables are passed to the container:
# Set variable
gokku config set DATABASE_URL=postgres://... -a api-production
# Restart container to pick up changes
gokku restart -a api-productionHealth Checks
Add health check to Dockerfile:
FROM python:3.11-slim
WORKDIR /app
COPY . .
EXPOSE ${PORT:-8080}
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:${PORT:-8080}/health')" || exit 1
CMD ["python", "app.py"]Check health status:
ssh ubuntu@server "docker inspect --format='{{.State.Health.Status}}' api-blue"Volumes (Limited Support)
Gokku doesn't currently support Docker volumes in config. Workarounds:
Option 2: Host Bind Mount (Manual)
Modify the hook template (advanced users):
docker run -d \
--name $APP_NAME-blue \
-v /data/uploads:/app/uploads \
-p $PORT:$PORT \
$IMAGE_NAMEOption 3: Separate Data Container
Run database/redis outside Gokku:
# On server
docker run -d \
--name postgres \
-v /data/postgres:/var/lib/postgresql/data \
-p 5432:5432 \
postgres:15Networking
Container to Container
Use Docker host IP (172.17.0.1) or host.docker.internal.
Blue-Green Deployment
Gokku uses blue-green deployment for zero-downtime updates:
How It Works
- New Deployment: Code is deployed to the green environment
- Health Check: System verifies the green environment is healthy
- Traffic Switch: Traffic is switched from blue to green
- Cleanup: Old blue environment is stopped and cleaned up
Enable Zero-Downtime
gokku config set ZERO_DOWNTIME=true -a <app>-<env>Container Naming
- Active Container:
<app-name>-blue - New Container:
<app-name>-green
For more details, see Blue-Green Deployment Guide.
Troubleshooting
Build Failed
Check deploy logs:
ssh ubuntu@server "cat /opt/gokku/apps/my-app/production/deploy.log"Container Won't Start
Check Docker logs:
ssh ubuntu@server "docker logs my-app-blue"Out of Disk Space
Clean up old images:
ssh ubuntu@server "docker system prune -a"Image Pull Failed
Check registry login:
ssh ubuntu@server "docker login registry.example.com"Advanced
Custom Docker Run Options
To add custom Docker run options, modify the hook template:
/opt/gokku/hooks/post-receive-docker.template
Add options to the docker run command.
Docker Compose (Not Supported)
Gokku uses docker run, not docker-compose. For multi-container apps:
- Deploy each service separately
- Or use a process manager inside one container (supervisord)
Private Registry
docker:
registry: "registry.example.com"
apps:
api:
image: "registry.example.com/python:3.11"Login on server:
ssh ubuntu@server "docker login registry.example.com"Next Steps
- Environment Variables - Configure containers
- Rollback - Rollback to previous images
- Examples - Real-world examples