Skip to content

Docker Integration

This guide demonstrates how to integrate Go Overlay into Docker containers to manage multiple services within a single container. While the microservices pattern typically uses one service per container, there are valid use cases for running multiple processes in a container, and Go Overlay makes this simple and reliable.

Use Cases

Running multiple services in a single container is appropriate when:

  • Legacy application migration: Transitioning monolithic applications to containers
  • Tightly coupled services: Services that must run together (e.g., app + sidecar)
  • Development environments: Simplified local development with multiple services
  • Resource constraints: Reducing overhead in resource-limited environments
  • Batch processing: Running multiple workers with a coordinator

Basic Docker Integration

Alpine-based Image

Alpine Linux provides a minimal base image, perfect for production containers.

FROM alpine:3.22

# Install runtime dependencies
RUN apk add --no-cache \
    ca-certificates \
    tzdata \
    bash

# Install Go Overlay
ADD https://github.com/srelabz/go-overlay/releases/latest/download/go-overlay /go-overlay

# Make it executable
RUN chmod +x /go-overlay

# Create application directory
WORKDIR /app

# Copy your application binaries
COPY ./bin/server /app/server
COPY ./bin/worker /app/worker

# Copy Go Overlay configuration
COPY services.toml /services.toml

# Create non-root user
RUN addgroup -g 1000 appuser && \
    adduser -D -u 1000 -G appuser appuser && \
    chown -R appuser:appuser /app

# Expose application port
EXPOSE 8080

# Use Go Overlay as entrypoint
ENTRYPOINT ["/go-overlay"]

Key Points:

  • Uses Alpine 3.22 for minimal image size
  • Downloads Go Overlay directly from GitHub releases
  • Creates non-root user for security
  • Sets Go Overlay as the container entrypoint
  • Configuration file is copied into the image

Ubuntu-based Image

Ubuntu provides more packages and compatibility, useful for complex applications.

FROM ubuntu:22.04

# Prevent interactive prompts during build
ENV DEBIAN_FRONTEND=noninteractive

# Install runtime dependencies
RUN apt-get update && apt-get install -y \
    ca-certificates \
    wget \
    curl \
    && rm -rf /var/lib/apt/lists/*

# Install Go Overlay
RUN wget -O /go-overlay \
    https://github.com/srelabz/go-entrypoint/releases/latest/download/go-overlay-linux-amd64 && \
    chmod +x /go-overlay

# Install application dependencies (example: Node.js app)
RUN apt-get update && apt-get install -y \
    nodejs \
    npm \
    nginx \
    redis-server \
    && rm -rf /var/lib/apt/lists/*

# Create application directory
WORKDIR /app

# Copy application files
COPY package*.json ./
RUN npm ci --only=production

COPY . .

# Copy Go Overlay configuration
COPY services.toml /services.toml

# Copy nginx configuration
COPY nginx.conf /etc/nginx/nginx.conf

# Create non-root user
RUN useradd -m -u 1000 appuser && \
    chown -R appuser:appuser /app

# Expose ports
EXPOSE 80 8080

# Use Go Overlay as entrypoint
ENTRYPOINT ["/go-overlay"]
CMD ["daemon", "--config", "/services.toml"]

Key Points:

  • Uses Ubuntu 22.04 for broader package availability
  • Installs multiple services (Node.js, Nginx, Redis)
  • Cleans up apt cache to reduce image size
  • Suitable for applications with complex dependencies

Multi-Service Configuration Examples

Example 1: Web App + Nginx + Redis

This example runs a web application with Nginx as a reverse proxy and Redis for caching.

services.toml:

[timeouts]
service_shutdown_timeout = 10
global_shutdown_timeout = 30

# Redis cache
[[services]]
name = "redis"
command = "/usr/bin/redis-server"
args = ["--bind", "127.0.0.1", "--port", "6379"]
enabled = true
required = true

# Node.js application
[[services]]
name = "app"
command = "/usr/bin/node"
args = ["/app/server.js"]
enabled = true
required = true
depends_on = ["redis"]
wait_after = { redis = 2 }
user = "appuser"

# Nginx reverse proxy
[[services]]
name = "nginx"
command = "/usr/sbin/nginx"
args = ["-g", "daemon off;"]
enabled = true
required = true
depends_on = ["app"]
wait_after = { app = 3 }

Complete Dockerfile:

FROM ubuntu:22.04

ENV DEBIAN_FRONTEND=noninteractive

# Install all dependencies
RUN apt-get update && apt-get install -y \
    ca-certificates \
    wget \
    nodejs \
    npm \
    nginx \
    redis-server \
    && rm -rf /var/lib/apt/lists/*

# Install Go Overlay
RUN wget -O /go-overlay \
    https://github.com/srelabz/go-entrypoint/releases/latest/download/go-overlay-linux-amd64 && \
    chmod +x /go-overlay

WORKDIR /app

# Install Node.js dependencies
COPY package*.json ./
RUN npm ci --only=production

# Copy application code
COPY . .

# Copy configurations
COPY services.toml /services.toml
COPY nginx.conf /etc/nginx/nginx.conf

# Create user and set permissions
RUN useradd -m -u 1000 appuser && \
    chown -R appuser:appuser /app && \
    mkdir -p /var/log/nginx /var/lib/nginx && \
    chown -R appuser:appuser /var/log/nginx /var/lib/nginx

EXPOSE 80

ENTRYPOINT ["/go-overlay"]
CMD ["daemon", "--config", "/services.toml"]

Example 2: Python App + Celery Workers

This example runs a Flask application with Celery workers for background tasks.

services.toml:

[timeouts]
service_shutdown_timeout = 15
global_shutdown_timeout = 45

# Redis (used by Celery)
[[services]]
name = "redis"
command = "/usr/bin/redis-server"
args = ["--bind", "127.0.0.1"]
enabled = true
required = true

# Flask web application
[[services]]
name = "web"
command = "/usr/local/bin/gunicorn"
args = [
    "--bind", "0.0.0.0:8000",
    "--workers", "4",
    "--timeout", "60",
    "app:app"
]
enabled = true
required = true
depends_on = ["redis"]
wait_after = { redis = 2 }
user = "appuser"

# Celery worker
[[services]]
name = "celery-worker"
command = "/usr/local/bin/celery"
args = [
    "-A", "app.celery",
    "worker",
    "--loglevel=info",
    "--concurrency=2"
]
enabled = true
required = false
depends_on = ["redis"]
wait_after = { redis = 2 }
user = "appuser"

# Celery beat scheduler
[[services]]
name = "celery-beat"
command = "/usr/local/bin/celery"
args = [
    "-A", "app.celery",
    "beat",
    "--loglevel=info"
]
enabled = true
required = false
depends_on = ["redis"]
wait_after = { redis = 2 }
user = "appuser"

Dockerfile:

FROM python:3.11-slim

# Install system dependencies
RUN apt-get update && apt-get install -y \
    wget \
    redis-server \
    && rm -rf /var/lib/apt/lists/*

# Install Go Overlay
RUN wget -O /go-overlay \
    https://github.com/srelabz/go-entrypoint/releases/latest/download/go-overlay-linux-amd64 && \
    chmod +x /go-overlay

WORKDIR /app

# Install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code
COPY . .

# Copy Go Overlay configuration
COPY services.toml /services.toml

# Create non-root user
RUN useradd -m -u 1000 appuser && \
    chown -R appuser:appuser /app

EXPOSE 8000

ENTRYPOINT ["/go-overlay"]
CMD ["daemon", "--config", "/services.toml"]

Docker Compose Integration

You can also use Go Overlay with Docker Compose for local development.

docker-compose.yml:

version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
      - "80:80"
    volumes:
      - ./services.toml:/services.toml
      - ./app:/app
    environment:
      - APP_ENV=development
      - LOG_LEVEL=debug
    restart: unless-stopped

  # External database (not managed by Go Overlay)
  postgres:
    image: postgres:15-alpine
    environment:
      - POSTGRES_DB=myapp
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

Key Points:

  • Go Overlay manages services within the app container
  • External services like PostgreSQL run in separate containers
  • Configuration can be mounted as a volume for easy updates
  • Suitable for development environments

Advanced Patterns

Health Checks

Add Docker health checks to monitor Go Overlay:

HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
    CMD /go-overlay status || exit 1

This checks if Go Overlay is running and services are healthy.

Multi-Stage Builds

Reduce image size with multi-stage builds:

# Build stage
FROM golang:1.21-alpine AS builder

WORKDIR /build

# Copy and build your application
COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o server ./cmd/server
RUN CGO_ENABLED=0 GOOS=linux go build -o worker ./cmd/worker

# Runtime stage
FROM alpine:3.22

RUN apk add --no-cache ca-certificates tzdata bash

# Install Go Overlay
RUN wget -O /go-overlay \
    https://github.com/srelabz/go-entrypoint/releases/latest/download/go-overlay-linux-amd64 && \
    chmod +x /go-overlay

WORKDIR /app

# Copy only the built binaries
COPY --from=builder /build/server /app/server
COPY --from=builder /build/worker /app/worker
COPY services.toml /services.toml

RUN addgroup -g 1000 appuser && \
    adduser -D -u 1000 -G appuser appuser && \
    chown -R appuser:appuser /app

EXPOSE 8080

ENTRYPOINT ["/go-overlay"]
CMD ["daemon", "--config", "/services.toml"]

Benefits:

  • Smaller final image (no build tools)
  • Faster deployment
  • Improved security (fewer packages)

Environment-Specific Configuration

Use environment variables to customize behavior:

# Copy base configuration
COPY services.toml /services.toml

# Allow override via environment variable
ENV GO_SUPERVISOR_CONFIG=/services.toml

ENTRYPOINT ["/go-overlay"]
CMD ["daemon", "--config", "${GO_SUPERVISOR_CONFIG}"]

Then override when running:

docker run -e GO_SUPERVISOR_CONFIG=/app/custom-services.toml myapp

Best Practices

  1. Use specific base image versions: Avoid latest tags for reproducible builds

    FROM alpine:3.22  # Good
    FROM alpine       # Avoid
    

  2. Minimize layers: Combine RUN commands to reduce image size

    RUN apk add --no-cache package1 package2 && \
        rm -rf /tmp/*
    

  3. Run as non-root: Always create and use a non-root user

    USER appuser
    

  4. Clean up package managers: Remove cache after installing packages

    RUN apt-get update && apt-get install -y package && \
        rm -rf /var/lib/apt/lists/*
    

  5. Use .dockerignore: Exclude unnecessary files from build context

    .git
    .gitignore
    node_modules
    *.md
    .env
    

  6. Pin Go Overlay version: Use specific version instead of latest

    RUN wget -O /go-overlay \
        https://github.com/srelabz/go-entrypoint/releases/download/v1.0.0/go-overlay-linux-amd64
    

  7. Add labels: Document your image with labels

    LABEL maintainer="your-email@example.com"
    LABEL version="1.0"
    LABEL description="My app with Go Overlay"
    

  8. Use health checks: Monitor container health

    HEALTHCHECK CMD go-overlay status || exit 1
    

Building and Running

Build the Image

docker build -t myapp:latest .

Run the Container

docker run -d \
    --name myapp \
    -p 8080:8080 \
    -v $(pwd)/services.toml:/services.toml \
    myapp:latest

View Logs

# All logs
docker logs -f myapp

# Specific service logs (if using structured logging)
docker logs myapp 2>&1 | grep "service=web"

Check Service Status

docker exec myapp go-overlay status

Restart Services

docker exec myapp go-overlay restart web

Troubleshooting

Container Exits Immediately

Symptom: Container starts and exits right away.

Possible Causes:

  1. Go Overlay not found
  2. Check: docker run myapp which go-overlay
  3. Solution: Verify installation path

  4. Configuration file missing

  5. Check: docker run myapp ls -la /services.toml
  6. Solution: Ensure COPY command in Dockerfile

  7. Permission issues

  8. Check: docker run myapp ls -la /go-overlay
  9. Solution: Verify chmod +x was executed

Services Won't Start

Symptom: Container runs but services fail to start.

Check logs:

docker logs myapp

Common issues:

  1. Missing dependencies
  2. Solution: Install required packages in Dockerfile

  3. Permission denied

  4. Solution: Check file ownership and user configuration

  5. Port already in use

  6. Solution: Change port mapping or service configuration

High Memory Usage

Symptom: Container uses excessive memory.

Solutions:

  1. Limit container memory:

    docker run -m 512m myapp
    

  2. Configure service-specific limits in services.toml

  3. Use Alpine-based images for smaller footprint

Next Steps