Set CONFIG_FILE after initial registration so act_runner daemon survives restarts.
239 lines
7.6 KiB
YAML
239 lines
7.6 KiB
YAML
# Management plane: portainer, vault, github-runner, watchtower.
|
|
# These manage / underpin the application stacks rather than being part of them,
|
|
# so they are deployed by raw `docker compose` (NOT a Portainer-managed stack) —
|
|
# Portainer cannot manage the stack that contains Portainer itself.
|
|
#
|
|
# This file owns the shared infrastructure networks:
|
|
# - edge : the single reverse-proxy network. Caddy + every service it
|
|
# proxies join this. Replaces caddy's old per-stack network
|
|
# membership. App stacks reference it as external.
|
|
# - portainer_proxy : legacy net for caddy -> portainer. Kept until the monolith
|
|
# is fully dismantled, then dropped (portainer is on edge too).
|
|
#
|
|
# Vault lives here (moved out of the dev stack): it is estate-wide secrets infra,
|
|
# must boot before the app stacks, and should not reseal when a dev tool changes.
|
|
# Vault data is the /config/vault bind mount — moving the service definition here
|
|
# does not touch any data. Re-unseal after (apply-compose.ps1 -VaultUnseal).
|
|
#
|
|
# Fresh-install order:
|
|
# docker compose -f portainer-compose.yml up -d # networks + mgmt plane first
|
|
# (then create the Portainer git stacks for proxy + each app domain)
|
|
|
|
services:
|
|
portainer:
|
|
container_name: portainer
|
|
image: portainer/portainer-ce:latest
|
|
restart: unless-stopped
|
|
networks:
|
|
- portainer_proxy
|
|
- edge
|
|
volumes:
|
|
- /var/run/docker.sock:/var/run/docker.sock
|
|
- /config/portainer:/data
|
|
ports:
|
|
- "9100:9000"
|
|
labels:
|
|
- "com.centurylabs.watchtower.enable=false"
|
|
|
|
# ============================================================
|
|
# VAULT (estate-wide secret management)
|
|
# One-time setup after first start:
|
|
# docker exec -it vault vault operator init
|
|
# vault operator unseal (3x with unseal keys)
|
|
# Unseal keys + root token live in .env (they are the one secret Vault
|
|
# itself cannot hold). Re-unseal after a restart with:
|
|
# powershell -File apply-compose.ps1 -VaultUnseal
|
|
# ============================================================
|
|
vault:
|
|
container_name: vault
|
|
image: hashicorp/vault@sha256:3fd53308acccd9e4e83fde3e6c6cf5b15e0f7fac1ff7510780b8b23f5e4c3de7
|
|
restart: unless-stopped
|
|
networks:
|
|
- edge
|
|
cap_add:
|
|
- IPC_LOCK
|
|
# Newer vault:latest mlocks more than docker's default 64KB memlock ulimit;
|
|
# without this it crash-loops with "Failed to lock memory: cannot allocate
|
|
# memory" despite IPC_LOCK being granted.
|
|
ulimits:
|
|
memlock:
|
|
soft: -1
|
|
hard: -1
|
|
environment:
|
|
- VAULT_ADDR=http://0.0.0.0:8200
|
|
volumes:
|
|
- /config/vault/config:/vault/config:ro
|
|
- /config/vault/data:/vault/data
|
|
- /config/vault/logs:/vault/logs
|
|
command: vault server -config=/vault/config/vault.hcl
|
|
ports:
|
|
- "8200:8200"
|
|
labels:
|
|
- "com.centurylabs.watchtower.enable=false"
|
|
|
|
postgres_gitea:
|
|
container_name: postgres_gitea
|
|
image: postgres:16-alpine
|
|
restart: unless-stopped
|
|
labels:
|
|
- "com.centurylabs.watchtower.enable=false"
|
|
networks:
|
|
- gitea_internal
|
|
environment:
|
|
POSTGRES_USER: gitea
|
|
POSTGRES_PASSWORD: ${GITEA_DB_PASSWORD}
|
|
POSTGRES_DB: gitea
|
|
volumes:
|
|
- /config/gitea/postgres:/var/lib/postgresql/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U gitea -d gitea"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
|
|
gitea:
|
|
container_name: gitea
|
|
image: gitea/gitea:latest
|
|
restart: unless-stopped
|
|
networks:
|
|
gitea_internal: {}
|
|
edge: {}
|
|
environment:
|
|
- USER_UID=1000
|
|
- USER_GID=1000
|
|
- GITEA__database__DB_TYPE=postgres
|
|
- GITEA__database__HOST=postgres_gitea:5432
|
|
- GITEA__database__NAME=gitea
|
|
- GITEA__database__USER=gitea
|
|
- GITEA__database__PASSWD=${GITEA_DB_PASSWORD}
|
|
- GITEA__server__DOMAIN=gitea.ginnoir.com
|
|
- GITEA__server__ROOT_URL=https://gitea.ginnoir.com
|
|
- GITEA__server__SSH_DOMAIN=gitea.ginnoir.com
|
|
- GITEA__server__SSH_PORT=2222
|
|
- GITEA__repository__ROOT=/repos
|
|
- GITEA__lfs__PATH=/repos-lfs
|
|
volumes:
|
|
- /config/gitea:/data
|
|
- /storage1/labdata/gitea/repositories:/repos
|
|
- /storage1/labdata/gitea/lfs:/repos-lfs
|
|
- /etc/localtime:/etc/localtime:ro
|
|
ports:
|
|
- "3030:3000"
|
|
- "2222:22"
|
|
depends_on:
|
|
postgres_gitea:
|
|
condition: service_healthy
|
|
labels:
|
|
- "com.centurylabs.watchtower.enable=false"
|
|
|
|
gitea-runner:
|
|
container_name: gitea_runner
|
|
image: gitea/act_runner:latest
|
|
restart: unless-stopped
|
|
networks:
|
|
- gitea_internal
|
|
environment:
|
|
- GITEA_INSTANCE_URL=https://gitea.ginnoir.com
|
|
- GITEA_RUNNER_REGISTRATION_TOKEN=${GITEA_RUNNER_REGISTRATION_TOKEN}
|
|
- GITEA_RUNNER_NAME=valhalla-management-runner
|
|
- GITEA_RUNNER_LABELS=ubuntu-latest:docker://node:24-bookworm,node-24:docker://node:24-bookworm
|
|
- CONFIG_FILE=/data/config.yaml
|
|
volumes:
|
|
- /config/gitea/act_runner:/data
|
|
- /var/run/docker.sock:/var/run/docker.sock
|
|
- /home/ginnoir/valhalla-lab:/valhalla-lab
|
|
- /config/caddy:/config/caddy
|
|
depends_on:
|
|
gitea:
|
|
condition: service_started
|
|
labels:
|
|
- "com.centurylabs.watchtower.enable=false"
|
|
|
|
gitea-runner-ci:
|
|
container_name: gitea_runner_ci
|
|
image: gitea/act_runner:latest
|
|
restart: unless-stopped
|
|
networks:
|
|
- gitea_internal
|
|
environment:
|
|
- GITEA_INSTANCE_URL=https://gitea.ginnoir.com
|
|
- GITEA_RUNNER_REGISTRATION_TOKEN=${GITEA_RUNNER_REGISTRATION_TOKEN}
|
|
- GITEA_RUNNER_NAME=valhalla-ci-runner-2
|
|
- GITEA_RUNNER_LABELS=ubuntu-latest:docker://node:24-bookworm,node-24:docker://node:24-bookworm
|
|
- CONFIG_FILE=/data/config.yaml
|
|
volumes:
|
|
- /config/gitea/act_runner_ci:/data
|
|
- /var/run/docker.sock:/var/run/docker.sock
|
|
- /home/ginnoir/valhalla-lab:/valhalla-lab
|
|
- /config/caddy:/config/caddy
|
|
depends_on:
|
|
gitea:
|
|
condition: service_started
|
|
labels:
|
|
- "com.centurylabs.watchtower.enable=false"
|
|
|
|
registry:
|
|
container_name: registry
|
|
image: registry:2
|
|
restart: unless-stopped
|
|
networks:
|
|
- registry_internal
|
|
- edge
|
|
environment:
|
|
- REGISTRY_AUTH=htpasswd
|
|
- REGISTRY_AUTH_HTPASSWD_REALM=Valhalla Registry
|
|
- REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd
|
|
- REGISTRY_STORAGE_DELETE_ENABLED=true
|
|
volumes:
|
|
- /storage1/labdata/registry:/var/lib/registry
|
|
- /config/registry/auth:/auth:ro
|
|
ports:
|
|
- "5000:5000"
|
|
labels:
|
|
- "com.centurylabs.watchtower.enable=false"
|
|
|
|
registry-ui:
|
|
container_name: registry_ui
|
|
image: joxit/docker-registry-ui:latest
|
|
restart: unless-stopped
|
|
networks:
|
|
- registry_internal
|
|
- edge
|
|
environment:
|
|
- SINGLE_REGISTRY=true
|
|
- REGISTRY_TITLE=Valhalla Registry
|
|
- NGINX_PROXY_PASS_URL=http://registry:5000
|
|
- SHOW_CONTENT_DIGEST=true
|
|
- DELETE_IMAGES=true
|
|
depends_on:
|
|
- registry
|
|
labels:
|
|
- "com.centurylabs.watchtower.enable=false"
|
|
|
|
watchtower:
|
|
container_name: watchtower
|
|
image: containrrr/watchtower:latest
|
|
restart: unless-stopped
|
|
environment:
|
|
- DOCKER_API_VERSION=1.40
|
|
- WATCHTOWER_NOTIFICATION_SKIP_TITLE=true
|
|
- WATCHTOWER_NOTIFICATION_URL=ntfy://ntfy.ginnoir.com/watchtower?title=WatchtowerUpdates
|
|
volumes:
|
|
- /var/run/docker.sock:/var/run/docker.sock
|
|
labels:
|
|
- "com.centurylabs.watchtower.enable=false"
|
|
|
|
networks:
|
|
edge:
|
|
name: edge
|
|
driver: bridge
|
|
portainer_proxy:
|
|
name: portainer_proxy
|
|
driver: bridge
|
|
gitea_internal:
|
|
name: gitea_internal
|
|
driver: bridge
|
|
registry_internal:
|
|
name: registry_internal
|
|
driver: bridge
|