stages: - deploy deploy_watchtower: stage: deploy tags: - shared script: - | set -euo pipefail echo "=== [1] Preparing deploy directory ===" mkdir -p /root/docker rm -rf /root/docker/watchtower cp -r watchtower /root/docker/watchtower echo "=== [2] Bringing up Watchtower with docker compose ===" cd /root/docker/watchtower docker compose -f watchtower.yml up -d CONTAINER_NAME="watchtower" echo "=== [3] Waiting a bit for container to (re)start ===" sleep 5 echo "=== [4] Checking container state ===" docker ps -a --filter "name=${CONTAINER_NAME}" STATUS="$(docker inspect -f '{{.State.Status}}' "${CONTAINER_NAME}")" || STATUS="unknown" echo "Container '${CONTAINER_NAME}' status: ${STATUS}" if [ "${STATUS}" != "running" ]; then echo "ERROR: Container '${CONTAINER_NAME}' is not running (status=${STATUS})." echo "Recent logs for ${CONTAINER_NAME}:" docker logs --tail=100 "${CONTAINER_NAME}" || echo "No logs found for ${CONTAINER_NAME}" exit 1 fi echo "Container '${CONTAINER_NAME}' is running ✅" echo "=== [5] Waiting for HEALTHCHECK to become healthy (if defined) ===" MAX_WAIT_SECONDS=120 SLEEP_INTERVAL=5 ELAPSED=0 while true; do HEALTH_STATUS="$(docker inspect -f '{{ if .State.Health }}{{ .State.Health.Status }}{{ end }}' "${CONTAINER_NAME}" || true)" if [ -z "${HEALTH_STATUS}" ]; then echo "No HEALTHCHECK defined for '${CONTAINER_NAME}', skipping health verification." break fi echo "Current health status for '${CONTAINER_NAME}': ${HEALTH_STATUS} (elapsed: ${ELAPSED}s)" if [ "${HEALTH_STATUS}" = "healthy" ]; then echo "Container '${CONTAINER_NAME}' health is healthy ✅" break fi if [ "${HEALTH_STATUS}" = "unhealthy" ]; then echo "ERROR: Container '${CONTAINER_NAME}' health is 'unhealthy'." docker inspect "${CONTAINER_NAME}" | grep -A5 -B2 '"Health"' || true docker logs --tail=100 "${CONTAINER_NAME}" || true exit 1 fi if [ "${ELAPSED}" -ge "${MAX_WAIT_SECONDS}" ]; then echo "ERROR: Container '${CONTAINER_NAME}' health did not become 'healthy' within ${MAX_WAIT_SECONDS}s (last status='${HEALTH_STATUS}')." docker inspect "${CONTAINER_NAME}" | grep -A5 -B2 '"Health"' || true docker logs --tail=100 "${CONTAINER_NAME}" || true exit 1 fi sleep "${SLEEP_INTERVAL}" ELAPSED=$((ELAPSED + SLEEP_INTERVAL)) done echo "=== [6] Deployment completed successfully ✅ ===" only: - main deploy_jellyfin: stage: deploy tags: - shared script: - | set -euo pipefail DEPLOY_DIR="/root/docker/jellyfin" COMPOSE_FILE="${DEPLOY_DIR}/jellyfin.yml" CONTAINER_NAME="jellyfin" echo "=== [1] Preparing deploy directory (safe) ===" # We ONLY touch /root/docker/jellyfin, never your data directories. mkdir -p "${DEPLOY_DIR}" # Copy just the compose file from the repo to the deploy dir cp jellyfin/jellyfin.yml "${COMPOSE_FILE}" echo "=== [2] Bringing up Jellyfin with docker compose ===" cd "${DEPLOY_DIR}" docker compose -f jellyfin.yml pull docker compose -f jellyfin.yml up -d echo "=== [3] Checking container state ===" docker ps -a --filter "name=${CONTAINER_NAME}" STATUS="$(docker inspect -f '{{.State.Status}}' "${CONTAINER_NAME}")" || STATUS="unknown" echo "Container '${CONTAINER_NAME}' status: ${STATUS}" if [ "${STATUS}" != "running" ]; then echo "ERROR: Container '${CONTAINER_NAME}' is not running (status=${STATUS})." echo "Recent logs for ${CONTAINER_NAME}:" docker logs --tail=100 "${CONTAINER_NAME}" || echo "No logs found for ${CONTAINER_NAME}" exit 1 fi echo "Container '${CONTAINER_NAME}' is running ✅" echo "=== [4] Deployment of Jellyfin completed successfully ✅ ===" only: - main deploy_plex: stage: deploy tags: - shared script: - | set -euo pipefail DEPLOY_DIR="/root/docker/plex" COMPOSE_FILE="${DEPLOY_DIR}/plex.yml" CONTAINER_NAME="plex" echo "=== [1] Preparing deploy directory for Plex (safe) ===" # Only ever touch /root/docker/plex, never your media/config paths. mkdir -p "${DEPLOY_DIR}" # Copy just the compose file from the repo into the deploy dir cp plex/plex.yml "${COMPOSE_FILE}" echo "=== [2] Bringing up Plex with docker compose ===" cd "${DEPLOY_DIR}" docker compose -f plex.yml pull docker compose -f plex.yml up -d echo "=== [3] Checking Plex container state ===" docker ps -a --filter "name=${CONTAINER_NAME}" STATUS="$(docker inspect -f '{{.State.Status}}' "${CONTAINER_NAME}")" || STATUS="unknown" echo "Container '${CONTAINER_NAME}' status: ${STATUS}" if [ "${STATUS}" != "running" ]; then echo "ERROR: Container '${CONTAINER_NAME}' is not running (status=${STATUS})." echo "Recent logs for ${CONTAINER_NAME}:" docker logs --tail=100 "${CONTAINER_NAME}" || echo "No logs found for ${CONTAINER_NAME}" exit 1 fi echo "Plex container '${CONTAINER_NAME}' is running ✅" echo "=== [4] Plex deployment completed successfully ✅ ===" only: - main deploy_wg_easy: stage: deploy tags: - shared script: - | set -euo pipefail DEPLOY_DIR="/root/docker/wg-easy" COMPOSE_FILE="${DEPLOY_DIR}/wg-easy.yml" CONTAINER_NAME="wg-easy" echo "=== [1] Preparing deploy directory for wg-easy (safe) ===" mkdir -p "${DEPLOY_DIR}" cp wg-easy/wg-easy.yml "${COMPOSE_FILE}" echo "=== [2] Bringing up wg-easy with docker compose ===" cd "${DEPLOY_DIR}" docker compose -f wg-easy.yml pull docker compose -f wg-easy.yml up -d echo "=== [3] Checking wg-easy container state ===" docker ps -a --filter "name=${CONTAINER_NAME}" STATUS="$(docker inspect -f '{{.State.Status}}' "${CONTAINER_NAME}")" || STATUS="unknown" echo "Container '${CONTAINER_NAME}' status: ${STATUS}" if [ "${STATUS}" != "running" ]; then echo "ERROR: Container '${CONTAINER_NAME}' is not running (status=${STATUS})." echo "Recent logs for ${CONTAINER_NAME}:" docker logs --tail=100 "${CONTAINER_NAME}" || echo "No logs found for ${CONTAINER_NAME}" exit 1 fi echo "wg-easy container '${CONTAINER_NAME}' is running ✅" echo "=== [4] wg-easy deployment completed successfully ✅ ===" only: - main deploy_adguard: stage: deploy tags: - shared # make sure your runner has this tag script: - | set -euo pipefail DEPLOY_DIR="/root/docker/adguard" COMPOSE_FILE="${DEPLOY_DIR}/adguard.yml" CONTAINER_NAME="adguardhome" echo "=== [1] Preparing deploy directory for AdGuard Home ===" # Only manage /root/docker/adguard — we do NOT touch Docker volumes. mkdir -p "${DEPLOY_DIR}" # Copy the compose file from the repo to the deploy directory cp adguard/adguard.yml "${COMPOSE_FILE}" echo "=== [2] Running docker compose (pull + up -d) ===" cd "${DEPLOY_DIR}" docker compose -f adguard.yml pull docker compose -f adguard.yml up -d echo "=== [3] Checking container state ===" docker ps -a --filter "name=${CONTAINER_NAME}" STATUS="$(docker inspect -f '{{.State.Status}}' "${CONTAINER_NAME}")" || STATUS="unknown" echo "Container '${CONTAINER_NAME}' status: ${STATUS}" if [ "${STATUS}" != "running" ]; then echo "❌ ERROR: AdGuard Home is not running (status=${STATUS})" echo "Recent logs:" docker logs --tail=100 "${CONTAINER_NAME}" || echo "No logs found" exit 1 fi echo "✅ AdGuard Home container is running." echo "=== [4] Verifying static IP on hurricane network ===" IP_ON_HURRICANE="$(docker inspect -f '{{range .NetworkSettings.Networks}}{{if eq .NetworkID (index (docker network inspect -f \"{{.Id}}\" hurricane) 0)}}{{.IPAddress}}{{end}}{{end}}' "${CONTAINER_NAME}" 2>/dev/null || true)" # Fallback simple check if the above is too fancy: if [ -z "${IP_ON_HURRICANE}" ]; then IP_ON_HURRICANE="$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "${CONTAINER_NAME}" || true)" fi echo "AdGuard Home IP (as seen by Docker): ${IP_ON_HURRICANE}" echo "=== [5] Deployment completed successfully ✅ ===" only: - main # run this deploy only when pushing to main deploy_portainer: stage: deploy tags: - shared script: | set -euo pipefail echo "=== [1] Preparing deploy directory for Portainer ===" mkdir -p /root/docker/portainer cp portainer/portainer.yml /root/docker/portainer/portainer.yml echo "=== [2] Bringing up Portainer ===" cd /root/docker/portainer docker compose -f portainer.yml pull docker compose -f portainer.yml up -d echo "=== [3] Checking container status ===" sleep 3 docker ps --filter "name=portainer" only: - main deploy_nextcloud: stage: deploy tags: - shared script: | set -euo pipefail echo "=== [1] Preparing nextcloud deploy directory ===" mkdir -p /root/docker/nextcloud echo "Copying compose and env files..." cp nextcloud/nextcloud.yml /root/docker/nextcloud/nextcloud.yml cp nextcloud/.env /root/docker/nextcloud/.env echo "=== [2] Bringing up Nextcloud with docker compose ===" cd /root/docker/nextcloud docker compose -f nextcloud.yml pull docker compose -f nextcloud.yml up -d echo "=== [3] Checking Nextcloud container status ===" sleep 5 docker ps --filter "name=nextcloud" only: - main