Skip to main content

Overview

Blnk provides Docker images and Docker Compose configurations for easy deployment. This guide covers both development and production deployments using Docker.

Prerequisites

  • Docker Engine 20.10 or later
  • Docker Compose v2.0 or later
  • At least 4GB RAM available for containers
  • PostgreSQL 16 client tools (included in Blnk image)

Docker Image

Blnk’s official Docker image is available at jerryenebeli/blnk on Docker Hub.

Image Details

The Blnk image is built using a multi-stage Dockerfile:
# Build stage
FROM golang:1.25-alpine as build-env
WORKDIR /go/src/blnk
COPY . .
RUN go build -o /blnk ./cmd/*.go

# Runtime stage
FROM debian:bullseye-slim

# Install PostgreSQL 16 client for backups and migrations
RUN apt-get update && apt-get install -y wget gnupg2 lsb-release && \
    echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \
    wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && \
    apt-get update && \
    apt-get install -y postgresql-client-16 && \
    rm -rf /var/lib/apt/lists/*

COPY --from=build-env /blnk /usr/local/bin/blnk
RUN chmod +x /usr/local/bin/blnk

CMD ["blnk", "start"]
EXPOSE 5001
Key Features:
  • Built on Debian Bullseye Slim for stability
  • Includes PostgreSQL 16 client for database operations
  • Optimized multi-stage build for smaller image size
  • Default port: 5001

Docker Compose Setup

Production Deployment

Create a docker-compose.yaml file:
version: "3.8"

services:
  server:
    image: ${BLNK_IMAGE:-jerryenebeli/blnk:0.13.2}
    container_name: server
    restart: on-failure
    entrypoint: ["/bin/sh", "-c"]
    command:
      - "blnk migrate up && blnk start"
    environment:
      TZ: ${TZ:-Etc/UTC}
      OTEL_EXPORTER_OTLP_ENDPOINT: http://jaeger:4318
    ports:
      - "5001:5001"
      - "80:80"
      - "443:443"
    depends_on:
      - redis
      - postgres
      - jaeger
    volumes:
      - ./blnk.json:/blnk.json

  worker:
    image: ${BLNK_IMAGE:-jerryenebeli/blnk:0.13.2}
    container_name: worker
    restart: on-failure
    entrypoint: ["blnk", "workers"]
    environment:
      OTEL_EXPORTER_OTLP_ENDPOINT: http://jaeger:4318
    ports:
      - "5004:5004"
    depends_on:
      - redis
      - postgres
      - jaeger
    volumes:
      - ./blnk.json:/blnk.json

  redis:
    image: redis:7.2.4
    container_name: redis
    restart: on-failure

  postgres:
    image: ${POSTGRES_IMAGE:-postgres:16}
    container_name: ${POSTGRES_CONTAINER:-postgres}
    restart: on-failure
    ports:
      - "${POSTGRES_OUTER_PORT:-5432}:5432"
    environment:
      TZ: ${TZ:-Etc/UTC}
      POSTGRES_USER: ${POSTGRES_USER:-postgres}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-password}
      POSTGRES_DB: ${POSTGRES_DB:-blnk}
    volumes:
      - pg_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "${POSTGRES_USER:-postgres}"]
      interval: 10s
      timeout: 5s
      retries: 5

  typesense:
    image: typesense/typesense:29.0
    container_name: typesense
    command:
      ["--data-dir", "/data", "--api-key=blnk-api-key", "--listen-port", "8108"]
    volumes:
      - typesense_data:/data
    logging:
      driver: "none"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8108/health"]
      interval: 30s
      timeout: 10s
      retries: 5

  jaeger:
    image: jaegertracing/all-in-one:latest
    container_name: jaeger
    ports:
      - "16686:16686" # Jaeger UI
      - "4317:4317"   # OTLP gRPC
      - "4318:4318"   # OTLP HTTP
    environment:
      - COLLECTOR_OTLP_ENABLED=true
    healthcheck:
      test: ["CMD", "wget", "--spider", "http://localhost:16686"]
      interval: 10s
      timeout: 5s
      retries: 3

volumes:
  pg_data:
  typesense_data:

Development Deployment

For local development with hot-reload:
version: '3.8'

services:
  server:
    build: .
    container_name: server
    restart: on-failure
    environment:
      TZ: ${TZ:-Etc/UTC}
      OTEL_EXPORTER_OTLP_ENDPOINT: jaeger:4318
    ports:
      - "5001:5001"
      - "80:80"
      - "443:443"
    depends_on:
      - redis
      - postgres
      - jaeger
    volumes:
      - ./blnk.json:/blnk.json

  migration:
    build: .
    entrypoint: ["blnk", "migrate", "up"]
    restart: on-failure
    depends_on:
      - postgres
    volumes:
      - ./blnk.json:/blnk.json

  # ... other services same as production

Configuration File

Create a blnk.json configuration file in the same directory:
{
  "project_name": "Blnk Production",
  "data_source": {
    "dns": "postgres://postgres:password@postgres:5432/blnk?sslmode=disable",
    "max_open_conns": 25,
    "max_idle_conns": 10,
    "conn_max_lifetime": "30m",
    "conn_max_idle_time": "5m"
  },
  "redis": {
    "dns": "redis:6379",
    "pool_size": 100,
    "min_idle_conns": 20
  },
  "server": {
    "port": "5001"
  },
  "typesense": {
    "dns": "http://typesense:8108"
  },
  "type_sense_key": "blnk-api-key",
  "enable_telemetry": false,
  "enable_observability": true
}

Environment Variables

Create a .env file for environment-specific configurations:
# Image versions
BLNK_IMAGE=jerryenebeli/blnk:0.13.2
POSTGRES_IMAGE=postgres:16

# PostgreSQL configuration
POSTGRES_USER=postgres
POSTGRES_PASSWORD=your_secure_password_here
POSTGRES_DB=blnk
POSTGRES_CONTAINER=postgres
POSTGRES_OUTER_PORT=5432

# Timezone
TZ=Etc/UTC

Deployment Commands

Start all services

docker-compose up -d

View logs

# All services
docker-compose logs -f

# Specific service
docker-compose logs -f server

Run migrations

docker-compose exec server blnk migrate up

Stop services

docker-compose down

Stop and remove volumes

docker-compose down -v

Volume Mounts

Configuration Volume

volumes:
  - ./blnk.json:/blnk.json
Mounts your configuration file into the container.

PostgreSQL Data Volume

volumes:
  - pg_data:/var/lib/postgresql/data
Persists PostgreSQL data across container restarts.

Typesense Data Volume

volumes:
  - typesense_data:/data
Persists search indexes.

Networking

Docker Compose automatically creates a bridge network. Services communicate using service names:
  • server - Blnk API server (port 5001)
  • worker - Background workers (port 5004)
  • postgres - PostgreSQL database (port 5432)
  • redis - Redis cache/queue (port 6379)
  • typesense - Search engine (port 8108)
  • jaeger - Observability (ports 16686, 4317, 4318)

Production Configuration

Resource Limits

Add resource limits to prevent container overconsumption:
services:
  server:
    # ... other config
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 2G
        reservations:
          cpus: '1'
          memory: 1G

  postgres:
    # ... other config
    deploy:
      resources:
        limits:
          cpus: '4'
          memory: 4G
        reservations:
          cpus: '2'
          memory: 2G

  redis:
    # ... other config
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 1G
        reservations:
          cpus: '0.5'
          memory: 512M

Security Hardening

  1. Use secrets for sensitive data:
secrets:
  postgres_password:
    file: ./secrets/postgres_password.txt

services:
  postgres:
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
    secrets:
      - postgres_password
  1. Run as non-root user:
services:
  server:
    user: "1000:1000"
  1. Read-only root filesystem:
services:
  server:
    read_only: true
    tmpfs:
      - /tmp

Health Checks

Blnk exposes a health endpoint at /health:
services:
  server:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:5001/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

Backup Strategy

PostgreSQL Backup

The Blnk image includes pg_dump for backups:
# Backup to local file
docker-compose exec postgres pg_dump -U postgres blnk > backup.sql

# Backup to container volume
docker-compose exec postgres pg_dump -U postgres blnk -f /var/lib/postgresql/data/backup.sql

Automated Backups

Add a backup service to docker-compose:
services:
  backup:
    image: jerryenebeli/blnk:0.13.2
    entrypoint: ["/bin/sh"]
    command:
      - -c
      - |
        while true; do
          pg_dump -h postgres -U postgres blnk > /backups/blnk_$(date +%Y%m%d_%H%M%S).sql
          find /backups -name "blnk_*.sql" -mtime +7 -delete
          sleep 86400
        done
    depends_on:
      - postgres
    volumes:
      - ./backups:/backups
    environment:
      PGPASSWORD: ${POSTGRES_PASSWORD}

Troubleshooting

Container Won’t Start

Check logs:
docker-compose logs server

Database Connection Issues

Verify PostgreSQL is ready:
docker-compose exec postgres pg_isready -U postgres

Port Already in Use

Change the external port mapping:
ports:
  - "5002:5001"  # Map external 5002 to internal 5001

Permission Denied on Volumes

Fix volume permissions:
sudo chown -R 1000:1000 ./backups

Monitoring

Access monitoring endpoints:

Next Steps

Build docs developers (and LLMs) love