kamal Docker & Self-Hosted Deployment

GitHub

Deploy web apps anywhere.

14,648 stars Ruby Ruby 1 file ยท ~9,363 tokens
RAW Compose
1. Pull Image (DOCKERHUB) docker pull library/registry
2. Docker Run (1-Click Launch) docker run -d --name kamal -p 443:443 --restart always registry:3
3. Podman Run podman run -d --name kamal -p 443:443 --restart always registry:3
4. Skopeo Inspect (Zero-Pull Manifest) skopeo inspect docker://docker.io/library/registry:3
5. ORAS Pull (OCI Artifact) oras pull registry:3
6. Compose Deployment docker compose up -d
test/integration/docker-compose.yml
Download .yml
name: "kamal-test"

volumes:
  shared:
  registry:
  deployer_bundle:
  otel:
  hub-cache:

services:
  shared:
    build:
      context: docker/shared
    volumes:
      - shared:/shared

  deployer:
    privileged: true
    build:
      context: docker/deployer
    environment:
      - TEST_ID=${TEST_ID:-}
    volumes:
      - ../..:/kamal
      - shared:/shared
      - deployer_bundle:/usr/local/bundle/
      - otel:/tmp/otel
    depends_on:
      shared:
        condition: service_healthy

  registry:
    build:
      context: docker/registry
    environment:
      - REGISTRY_HTTP_ADDR=0.0.0.0:4443
      - REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt
      - REGISTRY_HTTP_TLS_KEY=/certs/domain.key
    volumes:
      - shared:/shared
      - registry:/var/lib/registry/
    depends_on:
      shared:
        condition: service_healthy

  # Docker Hub pull-through cache. The deployer and vm inner daemons point their
  # registry-mirrors here (see their boot.sh), so base images (registry:3, nginx,
  # busybox, traefik, basecamp/kamal-proxy) are fetched from Docker Hub at most
  # once per run instead of on every test, dodging Hub rate limits.
  #
  # The cache fetches from Docker Hub on its own (anonymous by default โ€” separate
  # from any `docker login` on the host, since Hub's anonymous limit is per-IP).
  # Export DOCKERHUB_USERNAME and DOCKERHUB_TOKEN (a Hub access token) to have the
  # cache authenticate its upstream pulls against your account's higher quota.
  hub-cache:
    image: registry:3
    environment:
      - REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io
      - REGISTRY_PROXY_USERNAME=${DOCKERHUB_USERNAME:-}
      - REGISTRY_PROXY_PASSWORD=${DOCKERHUB_TOKEN:-}
    volumes:
      - hub-cache:/var/lib/registry
    healthcheck:
      test: [ "CMD", "pgrep", "registry" ]
      interval: 1s

  vm1:
    privileged: true
    build:
      context: docker/vm
    volumes:
      - shared:/shared
    ports:
      - "443"
    depends_on:
      shared:
        condition: service_healthy

  vm2:
    privileged: true
    build:
      context: docker/vm
    volumes:
      - shared:/shared
    depends_on:
      shared:
        condition: service_healthy

  vm3:
    privileged: true
    build:
      context: docker/vm
    volumes:
      - shared:/shared
    depends_on:
      shared:
        condition: service_healthy

  otel_collector:
    build:
      context: docker/otel_collector
    volumes:
      - otel:/tmp/otel

  load_balancer:
    build:
      context: docker/load_balancer
    ports:
      - "80"
      - "443"
    depends_on:
      - vm1
      - vm2
      - vm3