# Fellowship DevOps Escape Room Stack # Services: Jenkins (CI), Gitea (Git), code-server (IDE), MailHog (mail) # # Environment-aware Configuration # Usage: # Production: docker compose up -d (containers: fellowship_jenkins, etc.) # Local dev: COMPOSE_PROJECT_NAME=fellowship-local docker compose up -d (containers: fellowship-local_jenkins, etc.) # # Access: # Jenkins: http://localhost:8080 (user: fellowship / fellowship123) # Gitea: http://localhost:3030 (user: fellowship / fellowship123) # code-server: http://localhost:8443 (password: fellowship) # MailHog UI: http://localhost:8025 # # Note: code-server container automatically sets COMPOSE_PROJECT_NAME=fellowship-local via environment services: # ── Jenkins CI ────────────────────────────────────────────────────────────── jenkins: build: context: ../jenkins dockerfile: Dockerfile image: fellowship-jenkins:latest restart: unless-stopped ports: - "8080:8080" - "50000:50000" volumes: - jenkins_home:/var/jenkins_home # Mount Docker socket so Jenkins can run docker commands on the host - /var/run/docker.sock:/var/run/docker.sock environment: JENKINS_ADMIN_PASSWORD: ${JENKINS_ADMIN_PASSWORD:-fellowship123} CASC_JENKINS_CONFIG: /var/jenkins_home/casc_configs # Set by setup_fellowship.sh when CADDY_DOMAIN is known. # JCasC reads this to configure Jenkins' canonical root URL (used in build # links, email notifications, etc.). Defaults to the plain HTTP address. JENKINS_URL: ${JENKINS_URL:-http://localhost:8080/} # Configure Jenkins to reach Gitea internally via docker network GITEA_HTTP_URL: "http://gitea:3000" depends_on: gitea-init: condition: service_completed_successfully healthcheck: test: ["CMD-SHELL", "curl -sf http://localhost:8080/login || exit 1"] interval: 30s timeout: 10s retries: 5 start_period: 90s # ── Gitea (self-hosted Git) ────────────────────────────────────────────────── gitea: image: gitea/gitea:1.22 restart: unless-stopped ports: - "3030:3000" - "2222:22" volumes: - gitea_data:/data - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro environment: USER_UID: "1000" USER_GID: "1000" GITEA__database__DB_TYPE: sqlite3 GITEA__server__DOMAIN: ${GITEA_DOMAIN:-localhost} GITEA__server__HTTP_PORT: "3000" GITEA__server__ROOT_URL: ${GITEA_ROOT_URL:-http://localhost:3030/} GITEA__server__SSH_DOMAIN: localhost GITEA__server__SSH_PORT: "2222" GITEA__service__DISABLE_REGISTRATION: "false" GITEA__service__REQUIRE_SIGNIN_VIEW: "false" # INSTALL_LOCK: true after initialization. Admin will be created by gitea-init container via CLI GITEA__security__INSTALL_LOCK: "true" GITEA__admin__DEFAULT_EMAIL_NOTIFICATIONS: disabled GITEA__mailer__ENABLED: "false" # These are passed to gitea-init for CLI-based user creation, not used directly by Gitea GITEA_ADMIN_USER: "${GITEA_ADMIN_USER:-fellowship}" GITEA_ADMIN_PASSWORD: "${GITEA_ADMIN_PASSWORD:-fellowship123}" GITEA_ADMIN_EMAIL: "${GITEA_ADMIN_EMAIL:-gandalf@fellowship.local}" healthcheck: test: ["CMD-SHELL", "curl -sf http://localhost:3000/api/v1/version || exit 1"] interval: 15s timeout: 5s retries: 6 start_period: 30s # ── Gitea Initializer (one-shot) ───────────────────────────────────────────── gitea-init: platform: linux/amd64 image: alpine:latest restart: on-failure:5 environment: GITEA_URL: "http://gitea:3000" GITEA_ADMIN_USER: "${GITEA_ADMIN_USER:-fellowship}" GITEA_ADMIN_PASSWORD: "${GITEA_ADMIN_PASSWORD:-fellowship123}" GITEA_ADMIN_EMAIL: "${GITEA_ADMIN_EMAIL:-gandalf@fellowship.local}" GITEA_ORG_NAME: "${GITEA_ORG_NAME:-fellowship-org}" GITEA_REPO_NAME: "${GITEA_REPO_NAME:-lotr-sut}" GITEA_DOMAIN: "${GITEA_DOMAIN:-}" SUT_SOURCE_DIR: /sut-source volumes: - ../gitea/init.sh:/init.sh:ro # Mount Docker socket for docker commands - /var/run/docker.sock:/var/run/docker.sock:rw # Mount only the SUT source, not the full project tree (avoids .env / secrets) - ../sut:/sut-source/sut:ro - ../docker-compose.yml:/sut-source/docker-compose.yml:ro - ../caddy:/sut-source/caddy:ro - ../nginx:/sut-source/nginx:ro - ../Jenkinsfile:/sut-source/Jenkinsfile:ro entrypoint: ["/bin/sh", "/init.sh"] depends_on: gitea: condition: service_healthy # ── code-server (VS Code in browser IDE) ──────────────────────────────────── code-server: build: context: ./code-server dockerfile: Dockerfile image: fellowship-code-server:latest restart: unless-stopped ports: - "8443:8080" volumes: - ../:/home/coder/fellowship:rw - codeserver_config:/home/coder/.config # Mount host Docker socket so students can run `docker compose` from the IDE terminal. # The entrypoint aligns the docker group GID at runtime automatically. - /var/run/docker.sock:/var/run/docker.sock environment: PASSWORD: "${CODESERVER_PASSWORD:-fellowship}" # Set compose project name to 'fellowship' so that students can run `docker compose` without -p flag. COMPOSE_PROJECT_NAME: "fellowship-local" # No `user:` here — the entrypoint runs as root to fix Docker group GID, # then drops to the 'coder' user via gosu before starting code-server. command: - --auth=password - --bind-addr=0.0.0.0:8080 - /home/coder/fellowship healthcheck: test: ["CMD-SHELL", "curl -sf http://localhost:8080/ || exit 1"] interval: 30s timeout: 10s retries: 3 start_period: 30s # ── MailHog (mock SMTP + web UI) ──────────────────────────────────────────── mailhog: platform: linux/amd64 image: mailhog/mailhog:v1.0.1 restart: unless-stopped ports: - "1025:1025" - "8025:8025" volumes: jenkins_home: driver: local gitea_data: driver: local codeserver_config: driver: local