commit 9bfa342604fc68f5f375eb6735afe28de8464309 Author: colin Date: Fri Apr 4 12:28:17 2025 -0400 Initial commit diff --git a/.woodpecker.yml b/.woodpecker.yml new file mode 100644 index 0000000..498f98b --- /dev/null +++ b/.woodpecker.yml @@ -0,0 +1,149 @@ +# build:0 +labels: + location: manager +clone: + git: + image: woodpeckerci/plugin-git + settings: + partial: false + depth: 1 +when: + branch: [main] +steps: + # Build and Push for Staging + build-push-staging: + name: build-push-staging + image: woodpeckerci/plugin-docker-buildx + environment: + REGISTRY_USER: + from_secret: REGISTRY_USER + REGISTRY_PASSWORD: + from_secret: REGISTRY_PASSWORD + DOCKER_REGISTRY_USER: + from_secret: DOCKER_REGISTRY_USER + DOCKER_REGISTRY_PASSWORD: + from_secret: DOCKER_REGISTRY_PASSWORD + volumes: + - /var/run/docker.sock:/var/run/docker.sock + commands: + - echo "nameserver 1.1.1.1" > /etc/resolv.conf + - echo "nameserver 1.0.0.1" >> /etc/resolv.conf + - HOSTNAME=$(docker info --format "{{.Name}}") + - echo "Building on $HOSTNAME" + - echo "$${DOCKER_REGISTRY_PASSWORD}" | docker login -u "$${DOCKER_REGISTRY_USER}" --password-stdin + - echo "$${REGISTRY_PASSWORD}" | docker login -u "$${REGISTRY_USER}" --password-stdin git.nixc.us + - docker compose -f docker-compose.staging.yml build --no-cache + - docker compose -f docker-compose.staging.yml push + when: + branch: main + event: push + + # Deploy Staging + deploy-staging: + name: deploy-staging + image: woodpeckerci/plugin-docker-buildx + environment: + REGISTRY_USER: + from_secret: REGISTRY_USER + REGISTRY_PASSWORD: + from_secret: REGISTRY_PASSWORD + volumes: + - /var/run/docker.sock:/var/run/docker.sock + commands: + - echo "nameserver 1.1.1.1" > /etc/resolv.conf + - echo "nameserver 1.0.0.1" >> /etc/resolv.conf + - HOSTNAME=$(docker info --format "{{.Name}}") + - echo "Deploying on $HOSTNAME" + - echo "$${REGISTRY_PASSWORD}" | docker login -u "$${REGISTRY_USER}" --password-stdin git.nixc.us + - docker stack deploy --with-registry-auth -c ./stack.staging.yml $${CI_REPO_NAME}-staging + when: + branch: main + event: push + + # Wait for Deploy to Complete + wait-for-deploy-staging: + name: wait-for-deploy-staging + image: woodpeckerci/plugin-docker-buildx + volumes: + - /var/run/docker.sock:/var/run/docker.sock + commands: + - echo "nameserver 1.1.1.1" > /etc/resolv.conf + - echo "nameserver 1.0.0.1" >> /etc/resolv.conf + - sleep 20 + when: + branch: main + event: push + + # Build and Push for Production + build-push-production: + name: build-push-production + image: woodpeckerci/plugin-docker-buildx + environment: + REGISTRY_USER: + from_secret: REGISTRY_USER + REGISTRY_PASSWORD: + from_secret: REGISTRY_PASSWORD + DOCKER_REGISTRY_USER: + from_secret: DOCKER_REGISTRY_USER + DOCKER_REGISTRY_PASSWORD: + from_secret: DOCKER_REGISTRY_PASSWORD + volumes: + - /var/run/docker.sock:/var/run/docker.sock + commands: + - echo "nameserver 1.1.1.1" > /etc/resolv.conf + - echo "nameserver 1.0.0.1" >> /etc/resolv.conf + - HOSTNAME=$(docker info --format "{{.Name}}") + - echo "Building on $HOSTNAME" + - echo "$${DOCKER_REGISTRY_PASSWORD}" | docker login -u "$${DOCKER_REGISTRY_USER}" --password-stdin + - echo "$${REGISTRY_PASSWORD}" | docker login -u "$${REGISTRY_USER}" --password-stdin git.nixc.us + - docker compose -f docker-compose.production.yml build --no-cache + - docker compose -f docker-compose.production.yml push + when: + branch: main + event: [push, cron] + + # Deploy Production + deploy-production: + name: deploy-production + image: woodpeckerci/plugin-docker-buildx + environment: + REGISTRY_USER: + from_secret: REGISTRY_USER + REGISTRY_PASSWORD: + from_secret: REGISTRY_PASSWORD + volumes: + - /var/run/docker.sock:/var/run/docker.sock + commands: + - echo "nameserver 1.1.1.1" > /etc/resolv.conf + - echo "nameserver 1.0.0.1" >> /etc/resolv.conf + - HOSTNAME=$(docker info --format "{{.Name}}") + - echo "Deploying on $HOSTNAME" + - echo "$${REGISTRY_PASSWORD}" | docker login -u "$${REGISTRY_USER}" --password-stdin git.nixc.us + - docker stack deploy --with-registry-auth -c ./stack.production.yml $${CI_REPO_NAME} + when: + branch: main + event: [push, cron] + + # Cleanup Staging Environment + cleanup-staging: + name: cleanup-staging + image: woodpeckerci/plugin-docker-buildx + environment: + REGISTRY_USER: + from_secret: REGISTRY_USER + REGISTRY_PASSWORD: + from_secret: REGISTRY_PASSWORD + volumes: + - /var/run/docker.sock:/var/run/docker.sock + commands: + - echo "nameserver 1.1.1.1" > /etc/resolv.conf + - echo "nameserver 1.0.0.1" >> /etc/resolv.conf + - HOSTNAME=$(docker info --format "{{.Name}}") + - echo "Cleaning up staging environment on $HOSTNAME" + - for i in {1..5}; do docker stack rm $${CI_REPO_NAME}-staging && break || sleep 10; done + - docker compose -f docker-compose.staging.yml down + - docker compose -f docker-compose.staging.yml rm -f + when: + branch: main + event: [push, cron] + status: success \ No newline at end of file diff --git a/docker-compose.production.yml b/docker-compose.production.yml new file mode 100644 index 0000000..930125d --- /dev/null +++ b/docker-compose.production.yml @@ -0,0 +1,7 @@ +# The only stuff that happens here is template gets replaced and so does possibly nixius +services: + template: + build: + context: ./docker/template + dockerfile: Dockerfile.production + image: git.nixc.us/nixius/template:production \ No newline at end of file diff --git a/docker-compose.staging.yml b/docker-compose.staging.yml new file mode 100644 index 0000000..a96c565 --- /dev/null +++ b/docker-compose.staging.yml @@ -0,0 +1,7 @@ +# The only stuff that happens here is template gets replaced and so does possibly nixius +services: + template: + build: + context: ./docker/template + dockerfile: Dockerfile.staging + image: git.nixc.us/colin/template:staging \ No newline at end of file diff --git a/stack.production.yml b/stack.production.yml new file mode 100644 index 0000000..6f0317d --- /dev/null +++ b/stack.production.yml @@ -0,0 +1,71 @@ +networks: + traefik: + external: true + +services: + template: + image: git.nixc.us/nixius/template:production + deploy: + replicas: 1 + restart_policy: + condition: on-failure + max_attempts: 3 + update_config: + parallelism: 1 + delay: 10s + order: start-first + rollback_config: + parallelism: 1 + delay: 10s + order: stop-first + networks: + - traefik + labels: + - traefik.enable=true + - traefik.http.routers.production_template.rule=Host(`template.nixc.us`) + - traefik.http.routers.production_template.entrypoints=websecure + - traefik.http.routers.production_template.tls=true + - traefik.http.routers.production_template.tls.certresolver=letsencryptresolver + - traefik.http.services.production_template.loadbalancer.server.port=3000 + # - traefik.http.services.production_template.loadbalancer.healthcheck.path=/health + # - traefik.http.services.production_template.loadbalancer.healthcheck.interval=30s + # - traefik.http.services.production_template.loadbalancer.healthcheck.timeout=5s + - traefik.http.routers.production_template.middlewares=secure-headers + + midtownplaydio: + image: git.nixc.us/nixius/midtownplaydio:production + networks: + - traefik + deploy: + replicas: 1 + placement: + constraints: + - node.hostname == macmini1 + + # update_config: + # delay: 0s + # parallelism: 2 + # order: start-first + labels: + traefik.enable: "true" + traefik.http.routers.production_midtownplaydio.rule: "Host(`midtownplaydio.nixc.us`)" + traefik.http.routers.production_midtownplaydio.entrypoints: "websecure" + traefik.http.routers.production_midtownplaydio.tls: "true" + traefik.http.routers.production_midtownplaydio.tls.certresolver: "letsencryptresolver" + traefik.http.routers.production_midtownplaydio.middlewares: "secure-headers" + traefik.http.services.production_midtownplaydio.loadbalancer.server.port: "3000" + traefik.docker.network: "traefik" + # traefik.http.services.production_midtownplaydio.loadbalancer.healthcheck.path: "/health" + # traefik.http.services.production_midtownplaydio.loadbalancer.healthcheck.interval: "30s" + # traefik.http.services.production_midtownplaydio.loadbalancer.healthcheck.timeout: "5s" + + # Security headers middleware + traefik.http.middlewares.secure-headers.headers.stsSeconds: 63072000 + traefik.http.middlewares.secure-headers.headers.stsIncludeSubdomains: "true" + traefik.http.middlewares.secure-headers.headers.stsPreload: "true" + traefik.http.middlewares.secure-headers.headers.forceSTSHeader: "true" + traefik.http.middlewares.secure-headers.headers.frameDeny: "true" + traefik.http.middlewares.secure-headers.headers.contentTypeNosniff: "true" + traefik.http.middlewares.secure-headers.headers.browserXssFilter: "true" + traefik.http.middlewares.secure-headers.headers.referrerPolicy: "no-referrer" + traefik.http.middlewares.secure-headers.headers.featurePolicy: "camera 'none'; geolocation 'none'; microphone 'none'; payment 'none'; usb 'none'; vr 'none'" diff --git a/stack.staging.yml b/stack.staging.yml new file mode 100644 index 0000000..ea38fa1 --- /dev/null +++ b/stack.staging.yml @@ -0,0 +1,33 @@ +networks: + traefik: + external: true + default: + +services: + template: + image: git.nixc.us/nixius/template:staging + deploy: + replicas: 1 + restart_policy: + condition: on-failure + max_attempts: 3 + update_config: + parallelism: 1 + delay: 10s + order: start-first + rollback_config: + parallelism: 1 + delay: 10s + order: stop-first + networks: + - traefik + labels: + - traefik.enable=true + - traefik.http.routers.staging_template.rule=Host(`staging.template.nixc.us`) + - traefik.http.routers.staging_template.entrypoints=websecure + - traefik.http.routers.staging_template.tls=true + - traefik.http.routers.staging_template.tls.certresolver=letsencryptresolver + - traefik.http.services.staging_template.loadbalancer.server.port=3000 + # - traefik.http.services.staging_template.loadbalancer.healthcheck.path=/health + # - traefik.http.services.staging_template.loadbalancer.healthcheck.interval=30s + # - traefik.http.services.staging_template.loadbalancer.healthcheck.timeout=5s