143 lines
4.5 KiB
YAML

x-info:
github: https://github.com/go-gitea/gitea
docs: https://docs.gitea.com/
changelog: https://github.com/go-gitea/gitea/releases
homelab_status: stable
last_updated: 2026-03-09
version: "3.9"
services:
server:
image: docker.gitea.com/gitea:1.25.1
environment:
- TZ=America/New_York
- GITEA__database__DB_TYPE=postgres
- GITEA__database__HOST=gitea-db:5432
- GITEA__database__NAME=gitea
- GITEA__database__PASSWD={{ vault_gitea_db_password }}
- GITEA__database__USER=gitea
- GITEA__server__ROOT_URL=https://git.castaldifamily.com/
volumes:
- /mnt/homelab/apps/gitea/data:/data
ports:
- "8251:3000"
# Keep container labels for compatibility with external route publishers
# that inspect task/container metadata instead of Swarm service metadata.
labels:
- "traefik.enable=true"
- "traefik.http.routers.gitea.rule=Host(`git.castaldifamily.com`)"
- "traefik.http.routers.gitea.entrypoints=websecure"
- "traefik.http.routers.gitea.tls=true"
- "traefik.http.routers.gitea.tls.certresolver=cloudflare"
- "traefik.http.services.gitea.loadbalancer.server.url=http://{{ edge_routing.swarm.bind_ip }}:8251"
networks:
- proxy-net
deploy:
labels:
- "traefik.enable=true"
- "traefik.http.routers.gitea.rule=Host(`git.castaldifamily.com`)"
- "traefik.http.routers.gitea.entrypoints=websecure"
- "traefik.http.routers.gitea.tls=true"
- "traefik.http.routers.gitea.tls.certresolver=cloudflare"
- "traefik.http.services.gitea.loadbalancer.server.url=http://{{ edge_routing.swarm.bind_ip }}:8251"
# - "glance.name=Gitea"
# - "glance.icon=si:gitea"
# - "glance.url=https://git.castaldifamily.com"
# - "glance.category=dev-tools"
# - "glance.hide=false"
replicas: 1
placement:
constraints:
- node.hostname == {{ gitea_placement_node | default('swarm-manager-1') }}
resources:
limits:
memory: 1G
cpus: "0.5"
restart_policy:
# WHY any (not on-failure): Gitea is a persistent web service. Swarm's
# on-failure policy does NOT restart a container that exits cleanly
# (SIGTERM → code 0). A graceful shutdown during a rolling update
# would leave the service at 0/1 permanently until manually forced.
# 'any' ensures the service is always rescheduled regardless of exit code.
condition: any
delay: 10s
update_config:
delay: 10s
monitor: 30s
rollback_config:
parallelism: 1
order: stop-first
gitea-db:
image: postgres:17.4
environment:
- TZ=America/New_York
- POSTGRES_DB=gitea
- POSTGRES_PASSWORD={{ vault_gitea_db_password }}
- POSTGRES_USER=gitea
volumes:
- /mnt/homelab/apps/gitea/data/db:/var/lib/postgresql/data
networks:
- proxy-net
healthcheck:
test: ["CMD-SHELL", "pg_isready -U gitea -d gitea"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
deploy:
replicas: 1
placement:
constraints:
- node.hostname == {{ gitea_placement_node | default('swarm-manager-1') }}
resources:
limits:
memory: 1G
cpus: "0.5"
restart_policy:
condition: on-failure
delay: 10s
max_attempts: 3
window: 60s
update_config:
parallelism: 1
order: stop-first
failure_action: rollback
delay: 10s
monitor: 30s
rollback_config:
parallelism: 1
order: stop-first
networks:
proxy-net:
external: true
name: proxy-net
# runner:
# image: gitea/act_runner:0.2.13
# deploy:
# replicas: 1
# placement:
# constraints:
# - node.hostname == {{ gitea_placement_node | default('swarm-manager-1') }}
# resources:
# limits:
# memory: 512M
# cpus: "0.3"
# restart_policy:
# condition: on-failure
# volumes:
# - /mnt/homelab/apps/gitea/data/config.yaml:/config.yaml
# - /mnt/homelab/apps/gitea/data/runner/data:/data
# - /var/run/docker.sock:/var/run/docker.sock
# environment:
# - TZ=America/New_York
# - CONFIG_FILE=/config.yaml
# - GITEA_INSTANCE_URL=https://git.castaldifamily.com
# - GITEA_RUNNER_REGISTRATION_TOKEN=SET_VAULT_TOKEN_IF_ENABLING_RUNNER
# - GITEA_RUNNER_NAME=homelab
# networks:
# - proxy-net