Nixius
/
template
Template
2
1
Fork 1

Compare commits

..

8 Commits
main ... main

Author SHA1 Message Date
Leopere cca4581530 Add SMTP configuration through environment variables
ci/woodpecker/push/woodpecker Pipeline was successful Details
2025-04-25 10:10:11 -04:00
Leopere 286004dbcf FIXUP: Move Traefik labels inside deploy directive for proper Swarm routing
ci/woodpecker/push/woodpecker Pipeline was successful Details
2025-04-24 10:13:33 -04:00
Leopere 7da58b08da FIXUP: Update image names in docker-compose.*.yml to match stack files
ci/woodpecker/push/woodpecker Pipeline was successful Details
2025-04-24 09:03:04 -04:00
Leopere 26d678e499 Add debugging script for investigating deployment issues
ci/woodpecker/push/woodpecker Pipeline was successful Details
2025-04-23 14:27:16 -04:00
Leopere 63f0651bd9 FIXUP: Pin services to macmini14 and add logging for better debugging
ci/woodpecker/push/woodpecker Pipeline was successful Details
2025-04-23 14:24:13 -04:00
Leopere c7a738d6cd FIXUP: Add volumes section to stack.production.yml and update image URLs
ci/woodpecker/push/woodpecker Pipeline was successful Details
2025-04-23 11:26:21 -04:00
Leopere 3d7cb01820 FIXUP: Fix Docker base image references in production Dockerfiles
ci/woodpecker/push/woodpecker Pipeline failed Details
2025-04-23 11:11:38 -04:00
Leopere 50f6ee3c07 Add environment variables to stack and development files
ci/woodpecker/push/woodpecker Pipeline failed Details
2025-04-23 11:04:53 -04:00
23 changed files with 679 additions and 281 deletions

View File

@ -1,85 +1,81 @@
{ {
"version": 1, "version": 1,
"rules": [ "rules": [
{ {
"pattern": "**/*", "pattern": "**/*",
"rule": "project-structure.mdc" "rule": "project-structure.mdc"
}, },
{ {
"pattern": "**/docker/template/Dockerfile", "pattern": "**/docker/template/Dockerfile",
"rule": "dockerfiles.mdc" "rule": "dockerfiles.mdc"
}, },
{ {
"pattern": "**/docker/template/Dockerfile.production", "pattern": "**/docker/template/Dockerfile.production",
"rule": "dockerfiles.mdc" "rule": "dockerfiles.mdc"
}, },
{ {
"pattern": "**/docker-compose.dev.yml", "pattern": "**/docker-compose.dev.yml",
"rule": "docker-compose-files.mdc" "rule": "docker-compose-files.mdc"
}, },
{ {
"pattern": "**/docker-compose.production.yml", "pattern": "**/docker-compose.staging.yml",
"rule": "docker-compose-files.mdc" "rule": "docker-compose-files.mdc"
}, },
{ {
"pattern": "**/docker-compose.test.yml", "pattern": "**/docker-compose.production.yml",
"rule": "docker-compose-files.mdc" "rule": "docker-compose-files.mdc"
}, },
{ {
"pattern": "**/stack.production.yml", "pattern": "**/docker-compose.test.yml",
"rule": "stack-files.mdc" "rule": "docker-compose-files.mdc"
}, },
{ {
"pattern": "**/*.sh", "pattern": "**/stack.staging.yml",
"rule": "scripts.mdc" "rule": "stack-files.mdc"
}, },
{ {
"pattern": "**/build-test-run.sh", "pattern": "**/stack.production.yml",
"rule": "git-workflow.mdc" "rule": "stack-files.mdc"
}, },
{ {
"pattern": "**/temp/**/*", "pattern": "**/*.sh",
"rule": [ "rule": "scripts.mdc"
"temp-directory.mdc", },
"gitkeep-handling.mdc" {
] "pattern": "**/build-test-run.sh",
}, "rule": "git-workflow.mdc"
{ },
"pattern": "**/.gitignore", {
"rule": "gitignore.mdc" "pattern": "**/temp/**/*",
}, "rule": ["temp-directory.mdc", "gitkeep-handling.mdc"]
{ },
"pattern": "**/.git/**/*", {
"rule": "git-workflow.mdc" "pattern": "**/.gitignore",
}, "rule": "gitignore.mdc"
{ },
"pattern": "**/docker/template/src/**/*", {
"rule": [ "pattern": "**/.git/**/*",
"source-code.mdc", "rule": "git-workflow.mdc"
"gitkeep-handling.mdc" },
] {
}, "pattern": "**/docker/template/src/**/*",
{ "rule": ["source-code.mdc", "gitkeep-handling.mdc"]
"pattern": "**/.gitkeep", },
"rule": "gitkeep-handling.mdc" {
}, "pattern": "**/.gitkeep",
{ "rule": "gitkeep-handling.mdc"
"pattern": "**/temp/", },
"rule": [ {
"temp-directory.mdc", "pattern": "**/temp/",
"gitkeep-handling.mdc" "rule": ["temp-directory.mdc", "gitkeep-handling.mdc"]
] },
}, {
{ "pattern": "**/docker/template/src/",
"pattern": "**/docker/template/src/", "rule": ["source-code.mdc", "gitkeep-handling.mdc"]
"rule": [ },
"source-code.mdc", {
"gitkeep-handling.mdc" "pattern": "**/.woodpecker.yml",
] "rule": "project-structure.mdc"
}, }
{ ]
"pattern": "**/.woodpecker.yml", }
"rule": "project-structure.mdc"
}
]
}

View File

@ -20,11 +20,19 @@ alwaysApply: false
- Configures development environment variables - Configures development environment variables
- Mounts the [temp](mdc:temp) directory for local testing - Mounts the [temp](mdc:temp) directory for local testing
- [docker-compose.staging.yml](mdc:docker-compose.staging.yml): Staging build configuration
- Builds and tags the staging image
- Used by CI/CD for staging deployments
- [docker-compose.production.yml](mdc:docker-compose.production.yml): Production build configuration - [docker-compose.production.yml](mdc:docker-compose.production.yml): Production build configuration
- Builds and tags the production image - Builds and tags the production image
- Used by CI/CD for production deployments - Used by CI/CD for production deployments
## Stack Files ## Stack Files
- [stack.staging.yml](mdc:stack.staging.yml): Staging stack deployment
- Configures service deployment for staging environment
- Sets up Traefik routing rules
- [stack.production.yml](mdc:stack.production.yml): Production stack deployment - [stack.production.yml](mdc:stack.production.yml): Production stack deployment
- Configures service deployment for production environment - Configures service deployment for production environment
- Sets up Traefik routing rules with appropriate security headers - Sets up Traefik routing rules with appropriate security headers

View File

@ -1,5 +1,45 @@
--- ---
description: description:
globs: globs:
alwaysApply: false alwaysApply: false
--- ---
<!-- build 0 -->
# Git Workflow
This document describes the standard git workflow for this project.
## Commit Guidelines
1. Use descriptive commit messages
2. Use 'FIXUP:' prefix for quick fixes to existing code
3. Add 'HOTFIX:' prefix for emergency fixes
4. Document significant changes in your commit message
## Efficient Git Commands
Always use the one-liner command to save time when committing changes:
```bash
git add . && git commit -m "Your message here" && git push
```
### Fixing Previous Commits
When fixing issues in previous commits, use the FIXUP prefix:
```bash
git add . && git commit -m "FIXUP: Brief description of the fix" && git push
```
## Branch Strategy
- `main` - Main development branch
- `staging` - For staging environment testing
- `production` - Production-ready code
## Quick Reference
Common patterns:
- New feature: `git add . && git commit -m "Add new feature X" && git push`
- Bug fix: `git add . && git commit -m "FIXUP: Fix issue with X" && git push`
- Emergency: `git add . && git commit -m "HOTFIX: Resolve critical issue X" && git push`

View File

@ -10,6 +10,70 @@ clone:
when: when:
branch: [main] branch: [main]
steps: 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 and Push for Production
build-push-production: build-push-production:
name: build-push-production name: build-push-production
@ -58,4 +122,28 @@ steps:
- docker stack deploy --with-registry-auth -c ./stack.production.yml $${CI_REPO_NAME} - docker stack deploy --with-registry-auth -c ./stack.production.yml $${CI_REPO_NAME}
when: when:
branch: main branch: main
event: [push, cron] 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

View File

@ -1,3 +1,4 @@
<!-- build 0 -->
# Template Project # Template Project
This is a template project that follows a standardized structure for Docker-based applications. This is a template project that follows a standardized structure for Docker-based applications.
@ -17,7 +18,9 @@ This is a template project that follows a standardized structure for Docker-base
├── temp/ # Local testing scratch space ├── temp/ # Local testing scratch space
├── docker-compose.dev.yml # Docker Compose for local development ├── docker-compose.dev.yml # Docker Compose for local development
├── docker-compose.production.yml ├── docker-compose.production.yml
├── docker-compose.staging.yml
├── docker-compose.test.yml ├── docker-compose.test.yml
├── stack.staging.yml
└── stack.production.yml └── stack.production.yml
``` ```

40
check-images.sh Executable file
View File

@ -0,0 +1,40 @@
#!/bin/bash
# Script to check if required Docker images exist
# Set colors for output
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m' # No Color
echo -e "${YELLOW}Checking Docker images for Easy Appointments...${NC}"
# Images to check
APP_IMAGE="git.nixc.us/colin/easy-appointments:production"
DB_IMAGE="git.nixc.us/colin/easy-appointments:production-mariadb"
# Check app image
echo -e "\n${YELLOW}Checking application image: ${APP_IMAGE}${NC}"
if docker pull $APP_IMAGE >/dev/null 2>&1; then
echo -e "${GREEN}✓ Image $APP_IMAGE exists and is pullable${NC}"
else
echo -e "${RED}✗ Image $APP_IMAGE does not exist or is not pullable${NC}"
echo -e "${YELLOW}Let's check if you have login access to git.nixc.us:${NC}"
docker login git.nixc.us
fi
# Check db image
echo -e "\n${YELLOW}Checking database image: ${DB_IMAGE}${NC}"
if docker pull $DB_IMAGE >/dev/null 2>&1; then
echo -e "${GREEN}✓ Image $DB_IMAGE exists and is pullable${NC}"
else
echo -e "${RED}✗ Image $DB_IMAGE does not exist or is not pullable${NC}"
fi
echo -e "\n${YELLOW}Looking for similar images that might exist:${NC}"
docker image ls | grep "easy-appointments" || echo -e "${RED}No easy-appointments images found locally${NC}"
echo -e "\n${YELLOW}Recommended next steps:${NC}"
echo "1. Make sure you've logged in to git.nixc.us: docker login git.nixc.us"
echo "2. Build and push the images: docker compose -f docker-compose.production.yml build && docker compose -f docker-compose.production.yml push"
echo "3. Deploy the stack: docker stack deploy --with-registry-auth -c stack.production.yml easy-appointments"

114
debug-deployment.sh Executable file
View File

@ -0,0 +1,114 @@
#!/bin/bash
# Debug script for Easy Appointments deployment issues
# Run this on macmini7 to gather diagnostic information
# Set colors for output
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo -e "${BLUE}===== Easy Appointments Deployment Debug =====${NC}"
echo "Running on $(hostname) at $(date)"
echo
# Create output directory
OUTDIR="debug-output-$(date +%Y%m%d-%H%M%S)"
mkdir -p $OUTDIR
echo -e "${YELLOW}Saving all output to ${OUTDIR}/${NC}"
echo
# Check Docker and Swarm status
echo -e "${GREEN}1. Checking Docker and Swarm status${NC}"
echo "Docker version:" > $OUTDIR/docker-info.txt
docker version >> $OUTDIR/docker-info.txt 2>&1
echo -e "\nDocker info:" >> $OUTDIR/docker-info.txt
docker info >> $OUTDIR/docker-info.txt 2>&1
echo -e "\nSwarm nodes:" >> $OUTDIR/docker-info.txt
docker node ls >> $OUTDIR/docker-info.txt 2>&1
echo "Done. See $OUTDIR/docker-info.txt"
echo
# Check services
echo -e "${GREEN}2. Checking services${NC}"
echo "Service list:" > $OUTDIR/services.txt
docker service ls >> $OUTDIR/services.txt 2>&1
echo -e "\neasy-appointments service details:" >> $OUTDIR/services.txt
docker service ps easy-appointments_easy-appointments --no-trunc >> $OUTDIR/services.txt 2>&1
echo -e "\nmariadb service details:" >> $OUTDIR/services.txt
docker service ps easy-appointments_mariadb --no-trunc >> $OUTDIR/services.txt 2>&1
echo "Done. See $OUTDIR/services.txt"
echo
# Collect logs
echo -e "${GREEN}3. Collecting service logs${NC}"
echo "Fetching easy-appointments logs..."
docker service logs easy-appointments_easy-appointments --tail 1000 > $OUTDIR/easy-appointments.log 2>&1
echo "Fetching mariadb logs..."
docker service logs easy-appointments_mariadb --tail 1000 > $OUTDIR/mariadb.log 2>&1
echo "Fetching traefik logs..."
docker service logs traefik --tail 200 > $OUTDIR/traefik.log 2>&1
echo "Done. See logs in $OUTDIR/"
echo
# Check volumes
echo -e "${GREEN}4. Checking volumes${NC}"
echo "Volume list:" > $OUTDIR/volumes.txt
docker volume ls >> $OUTDIR/volumes.txt 2>&1
echo -e "\nmariadb_data volume:" >> $OUTDIR/volumes.txt
docker volume inspect easy-appointments_mariadb_data >> $OUTDIR/volumes.txt 2>&1
echo "Done. See $OUTDIR/volumes.txt"
echo
# Check networks
echo -e "${GREEN}5. Checking networks${NC}"
echo "Network list:" > $OUTDIR/networks.txt
docker network ls >> $OUTDIR/networks.txt 2>&1
echo -e "\nTraefik network:" >> $OUTDIR/networks.txt
docker network inspect traefik >> $OUTDIR/networks.txt 2>&1
echo -e "\nDefault network:" >> $OUTDIR/networks.txt
docker network inspect easy-appointments_default >> $OUTDIR/networks.txt 2>&1
echo "Done. See $OUTDIR/networks.txt"
echo
# Check system resources
echo -e "${GREEN}6. Checking system resources${NC}"
echo "Disk usage:" > $OUTDIR/resources.txt
df -h >> $OUTDIR/resources.txt 2>&1
echo -e "\nMemory usage:" >> $OUTDIR/resources.txt
free -m >> $OUTDIR/resources.txt 2>&1
echo -e "\nCPU info:" >> $OUTDIR/resources.txt
top -bn1 | head -20 >> $OUTDIR/resources.txt 2>&1
echo "Done. See $OUTDIR/resources.txt"
echo
# Check DNS and connectivity
echo -e "${GREEN}7. Checking DNS and connectivity${NC}"
echo "cal.colinknapp.com DNS:" > $OUTDIR/connectivity.txt
nslookup cal.colinknapp.com >> $OUTDIR/connectivity.txt 2>&1
echo -e "\nstaging.cal.colinknapp.com DNS:" >> $OUTDIR/connectivity.txt
nslookup staging.cal.colinknapp.com >> $OUTDIR/connectivity.txt 2>&1
echo -e "\nHTTP check:" >> $OUTDIR/connectivity.txt
curl -I cal.colinknapp.com >> $OUTDIR/connectivity.txt 2>&1
echo "Done. See $OUTDIR/connectivity.txt"
echo
# Create a tar archive of all debug info
echo -e "${GREEN}8. Creating archive of all debug information${NC}"
tar -czf easy-appointments-debug.tar.gz $OUTDIR
echo "Archive created: easy-appointments-debug.tar.gz"
echo
echo -e "${BLUE}===== Debug information collection complete =====${NC}"
echo "All debug information has been saved to $OUTDIR/"
echo "A compressed archive is available at: easy-appointments-debug.tar.gz"
echo
echo -e "${YELLOW}To analyze the results:${NC}"
echo "1. Check service status in $OUTDIR/services.txt"
echo "2. Review logs in $OUTDIR/easy-appointments.log and $OUTDIR/mariadb.log"
echo "3. Look for any networking issues in $OUTDIR/networks.txt"
echo "4. Check system resources in $OUTDIR/resources.txt"
echo
echo -e "${YELLOW}To transfer the archive:${NC}"
echo "scp $(whoami)@$(hostname):$(pwd)/easy-appointments-debug.tar.gz /your/local/directory"

View File

@ -1,29 +1,49 @@
# Development configuration for local testing # Development configuration for local testing
services: services:
template: easy-appointments:
build: build:
context: ./docker/template context: ./docker/easy-appointments
dockerfile: Dockerfile dockerfile: Dockerfile.staging
image: template:dev image: git.nixc.us/colin/easy-appointments:staging
environment:
BASE_URL: "http://localhost"
DEBUG_MODE: "TRUE"
DB_HOST: "mariadb"
DB_NAME: "easyappointments"
DB_USERNAME: "root"
DB_PASSWORD: "secret"
# SMTP Configuration
SMTP_HOST: "box.p.nixc.us"
SMTP_PORT: "465"
SMTP_USERNAME: "appointments@colinknapp.com"
SMTP_PASSWORD: "uQH33ygJVrNWSW0MzWXZgMMVmLGhE3ZI"
SMTP_SECURITY: "ssl"
COMPANY_NAME: "Colin Knapp Appointments (Dev)"
COMPANY_EMAIL: "appointments@colinknapp.com"
COMPANY_LINK: "https://colinknapp.com"
volumes: volumes:
- ./docker/template/src:/scratch - ./docker/easy-appointments/src:/scratch
- ./temp:/temp - ./temp:/temp
networks: networks:
- dev_network - dev_network
ports:
- "8080:80"
# Add any additional services you need here mariadb:
# Example: build:
# db: context: ./docker/mariadb
# image: postgres:14 dockerfile: Dockerfile.staging
# environment: image: git.nixc.us/colin/template:staging-mariadb
# - POSTGRES_PASSWORD=postgres environment:
# - POSTGRES_USER=postgres - MARIADB_ROOT_PASSWORD=secret
# - POSTGRES_DB=template - MARIADB_DATABASE=easyappointments
# volumes: networks:
# - ./temp/postgres-data:/var/lib/postgresql/data - dev_network
# networks: volumes:
# - dev_network - mariadb_data:/var/lib/mysql
networks: networks:
dev_network: dev_network:
driver: bridge
volumes:
mariadb_data:

View File

@ -2,6 +2,12 @@
services: services:
template: template:
build: build:
context: ./docker/template context: ./docker/easy-appointments
dockerfile: Dockerfile.production dockerfile: Dockerfile.production
image: git.nixc.us/nixius/template:production image: git.nixc.us/colin/easy-appointments:production
mariadb:
build:
context: ./docker/mariadb
dockerfile: Dockerfile.production
image: git.nixc.us/colin/easy-appointments:production-mariadb

View File

@ -0,0 +1,13 @@
# The only stuff that happens here is template gets replaced and so does possibly nixius
services:
template:
build:
context: ./docker/easy-appointments
dockerfile: Dockerfile.staging
image: git.nixc.us/colin/easy-appointments:staging
mariadb:
build:
context: ./docker/mariadb
dockerfile: Dockerfile.staging
image: git.nixc.us/colin/easy-appointments:staging-mariadb

View File

@ -2,9 +2,15 @@
services: services:
template: template:
build: build:
context: ./docker/template context: ./docker/easy-appointments
dockerfile: Dockerfile dockerfile: Dockerfile.staging
image: template:test image: git.nixc.us/colin/easy-appointments:test
volumes: volumes:
- ./docker/template/src:/scratch - ./docker/easy-appointments/src:/scratch
- ./temp:/temp - ./temp:/temp
mariadb:
build:
context: ./docker/mariadb
dockerfile: Dockerfile.staging
image: git.nixc.us/colin/easy-appointments:test-mariadb

View File

@ -0,0 +1 @@
FROM git.nixc.us/colin/easy-appointments:staging

View File

@ -0,0 +1 @@
FROM alextselegidis/easyappointments:latest

View File

@ -0,0 +1 @@
FROM git.nixc.us/colin/easy-appointments:staging-mariadb

View File

@ -0,0 +1 @@
FROM mariadb:10.5

View File

View File

@ -1,10 +0,0 @@
FROM alpine:3.18
# Create directories for volume mounts
RUN mkdir -p /scratch /temp
# Set working directory
WORKDIR /scratch
# Simple command to keep container running
CMD ["tail", "-f", "/dev/null"]

View File

@ -1,3 +0,0 @@
FROM alpine:3.18
WORKDIR /app
CMD ["tail", "-f", "/dev/null"]

View File

@ -1,23 +1,16 @@
networks: networks:
traefik: traefik:
external: true external: true
default:
services: services:
template: easy-appointments:
image: git.nixc.us/nixius/template:production image: git.nixc.us/colin/easy-appointments:production
deploy: deploy:
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
replicas: 1 replicas: 1
placement:
constraints:
- node.hostname == macmini14
restart_policy: restart_policy:
condition: on-failure condition: on-failure
max_attempts: 3 max_attempts: 3
@ -29,5 +22,70 @@ services:
parallelism: 1 parallelism: 1
delay: 10s delay: 10s
order: stop-first order: stop-first
labels:
- traefik.enable=true
- traefik.http.routers.production_easy-appointments.rule=Host(`cal.colinknapp.com`)
- traefik.http.routers.production_easy-appointments.entrypoints=websecure
- traefik.http.routers.production_easy-appointments.tls=true
- traefik.http.routers.production_easy-appointments.tls.certresolver=letsencryptresolver
- traefik.http.services.production_easy-appointments.loadbalancer.server.port=80
# - traefik.http.services.production_easy-appointments.loadbalancer.healthcheck.path=/health
# - traefik.http.services.production_easy-appointments.loadbalancer.healthcheck.interval=30s
# - traefik.http.services.production_easy-appointments.loadbalancer.healthcheck.timeout=5s
- traefik.http.routers.production_easy-appointments.middlewares=secure-headers
environment:
BASE_URL: "https://cal.colinknapp.com"
DEBUG_MODE: "TRUE"
DB_HOST: "mariadb"
DB_NAME: "easyappointments"
DB_USERNAME: "root"
DB_PASSWORD: "secret"
# SMTP Configuration
SMTP_HOST: "box.p.nixc.us"
SMTP_PORT: "465"
SMTP_USERNAME: "appointments@colinknapp.com"
SMTP_PASSWORD: "uQH33ygJVrNWSW0MzWXZgMMVmLGhE3ZI"
SMTP_SECURITY: "ssl"
COMPANY_NAME: "Colin Knapp Appointments"
COMPANY_EMAIL: "appointments@colinknapp.com"
COMPANY_LINK: "https://colinknapp.com"
networks: networks:
- traefik - traefik
- default
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
mariadb:
image: git.nixc.us/colin/easy-appointments:production-mariadb
deploy:
replicas: 1
placement:
constraints:
- node.hostname == macmini14
restart_policy:
condition: on-failure
max_attempts: 3
environment:
- MARIADB_ROOT_PASSWORD=secret
- MARIADB_DATABASE=easyappointments
networks:
- default
volumes:
- mariadb_data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p$$MARIADB_ROOT_PASSWORD"]
interval: 10s
retries: 5
start_period: 30s
timeout: 5s
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
volumes:
mariadb_data:

77
stack.staging.yml Normal file
View File

@ -0,0 +1,77 @@
networks:
traefik:
external: true
default:
services:
easy-appointments:
image: git.nixc.us/colin/easy-appointments:staging
deploy:
replicas: 1
placement:
constraints:
- node.hostname == macmini14
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
labels:
- traefik.enable=true
- traefik.http.routers.staging_easy-appointments.rule=Host(`staging.cal.colinknapp.com`)
- traefik.http.routers.staging_easy-appointments.entrypoints=websecure
- traefik.http.routers.staging_easy-appointments.tls=true
- traefik.http.routers.staging_easy-appointments.tls.certresolver=letsencryptresolver
- traefik.http.services.staging_easy-appointments.loadbalancer.server.port=80
environment:
BASE_URL: "https://staging.cal.colinknapp.com"
DEBUG_MODE: "FALSE"
DB_HOST: "mariadb"
DB_NAME: "easyappointments"
DB_USERNAME: "root"
DB_PASSWORD: "secret"
# SMTP Configuration
SMTP_HOST: "box.p.nixc.us"
SMTP_PORT: "465"
SMTP_USERNAME: "appointments@colinknapp.com"
SMTP_PASSWORD: "uQH33ygJVrNWSW0MzWXZgMMVmLGhE3ZI"
SMTP_SECURITY: "ssl"
COMPANY_NAME: "Colin Knapp Appointments (Staging)"
COMPANY_EMAIL: "appointments@colinknapp.com"
COMPANY_LINK: "https://colinknapp.com"
networks:
- traefik
- default
mariadb:
image: git.nixc.us/colin/easy-appointments:staging-mariadb
deploy:
replicas: 1
placement:
constraints:
- node.hostname == macmini14
restart_policy:
condition: on-failure
max_attempts: 3
environment:
- MARIADB_ROOT_PASSWORD=secret
- MARIADB_DATABASE=easyappointments
networks:
- default
volumes:
- mariadb_data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p$$MARIADB_ROOT_PASSWORD"]
interval: 10s
retries: 5
start_period: 30s
timeout: 5s
volumes:
mariadb_data:

View File

@ -1,106 +1,3 @@
Build started at Wed Apr 23 10:27:39 EDT 2025 Build started at Wed Apr 23 11:13:22 EDT 2025
Building Docker images... Building Docker images...
#0 building with "desktop-linux" instance using docker driver service "mariadb" refers to undefined network dev_network: invalid compose project
#1 [template internal] load build definition from Dockerfile
#1 transferring dockerfile: 279B done
#1 DONE 0.0s
#2 [template internal] load metadata for docker.io/library/alpine:3.18
#2 DONE 4.5s
#3 [template internal] load .dockerignore
#3 transferring context: 2B done
#3 DONE 0.0s
#4 [template 1/3] FROM docker.io/library/alpine:3.18@sha256:de0eb0b3f2a47ba1eb89389859a9bd88b28e82f5826b6969ad604979713c2d4f
#4 resolve docker.io/library/alpine:3.18@sha256:de0eb0b3f2a47ba1eb89389859a9bd88b28e82f5826b6969ad604979713c2d4f 0.0s done
#4 sha256:95459497489f07b9d71d294c852a09f9bbf1af51bb35db752a31f6f48935e293 0B / 3.34MB 0.2s
#4 sha256:95459497489f07b9d71d294c852a09f9bbf1af51bb35db752a31f6f48935e293 1.05MB / 3.34MB 0.3s
#4 sha256:95459497489f07b9d71d294c852a09f9bbf1af51bb35db752a31f6f48935e293 3.34MB / 3.34MB 0.4s done
#4 extracting sha256:95459497489f07b9d71d294c852a09f9bbf1af51bb35db752a31f6f48935e293 0.1s done
#4 DONE 0.5s
#5 [template 2/3] RUN mkdir -p /scratch /temp
#5 DONE 0.2s
#6 [template 3/3] WORKDIR /scratch
#6 DONE 0.0s
#7 [template] exporting to image
#7 exporting layers 0.0s done
#7 exporting manifest sha256:15b202f67217697a010a43b0d8ef636c8bd4a00a7258dc8334ce1220aa5ad10d done
#7 exporting config sha256:e4f5b35710a25e9116a133bde6255ccc3f91a39c9b99e4f4a44d7eaf27024e7d done
#7 exporting attestation manifest sha256:1381754eaa2ff6ca7277a69421f9a2e9bfd02920098acac0b6d9a0d87b4abe9c done
#7 exporting manifest list sha256:59daf10da628c4a24e9396d0656c99dff8d7036f3b29e0ec6d7392c1e72adfc0 done
#7 naming to docker.io/library/template:dev done
#7 unpacking to docker.io/library/template:dev 0.0s done
#7 DONE 0.1s
#8 [template] resolving provenance for metadata file
#8 DONE 0.0s
template Built
Running tests...
Running tests...
Test results have been saved to ./temp/test_output.log
Test started at Wed Apr 23 10:27:45 EDT 2025
Testing Docker build...
#0 building with "desktop-linux" instance using docker driver
#1 [template internal] load build definition from Dockerfile
#1 transferring dockerfile: 279B done
#1 DONE 0.0s
#2 [template internal] load metadata for docker.io/library/alpine:3.18
#2 DONE 0.2s
#3 [template internal] load .dockerignore
#3 transferring context: 2B done
#3 DONE 0.0s
#4 [template 1/3] FROM docker.io/library/alpine:3.18@sha256:de0eb0b3f2a47ba1eb89389859a9bd88b28e82f5826b6969ad604979713c2d4f
#4 resolve docker.io/library/alpine:3.18@sha256:de0eb0b3f2a47ba1eb89389859a9bd88b28e82f5826b6969ad604979713c2d4f done
#4 DONE 0.0s
#5 [template 2/3] RUN mkdir -p /scratch /temp
#5 CACHED
#6 [template 3/3] WORKDIR /scratch
#6 CACHED
#7 [template] exporting to image
#7 exporting layers done
#7 exporting manifest sha256:15b202f67217697a010a43b0d8ef636c8bd4a00a7258dc8334ce1220aa5ad10d done
#7 exporting config sha256:e4f5b35710a25e9116a133bde6255ccc3f91a39c9b99e4f4a44d7eaf27024e7d done
#7 exporting attestation manifest sha256:ec2582c7e07cfeaaeb69797430b3d687550c642903473dbe1fbcdea58fefc2cb 0.0s done
#7 exporting manifest list sha256:1f3404b565e38ec1490f2d56d612438b611b2fd31e213e39e37c8e3e80c4b3ff done
#7 naming to docker.io/library/template:test done
#7 unpacking to docker.io/library/template:test done
#7 DONE 0.0s
#8 [template] resolving provenance for metadata file
#8 DONE 0.0s
template Built
Testing container startup...
Network template_default Creating
Network template_default Created
Container template-template-1 Recreate
Container template-template-1 Recreated
Container template-template-1 Starting
Container template-template-1 Started
Container status:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
Cleaning up...
Container template-template-1 Stopping
Container template-template-1 Stopped
Container template-template-1 Removing
Container template-template-1 Removed
Network template_default Removing
Network template_default Removed
Tests completed at Wed Apr 23 10:27:52 EDT 2025
Starting services...
Container template-template-1 Creating
Container template-template-1 Created
Container template-template-1 Starting
Container template-template-1 Started
Build and run completed at Wed Apr 23 10:27:53 EDT 2025

View File

@ -1,55 +1,96 @@
Test started at Wed Apr 23 10:27:45 EDT 2025 Test started at Wed Apr 23 10:58:08 EDT 2025
Testing Docker build... Testing Docker build...
#0 building with "desktop-linux" instance using docker driver #0 building with "desktop-linux" instance using docker driver
#1 [template internal] load build definition from Dockerfile #1 [mariadb internal] load build definition from Dockerfile.staging
#1 transferring dockerfile: 279B done #1 transferring dockerfile: 100B done
#1 DONE 0.0s #1 DONE 0.0s
#2 [template internal] load metadata for docker.io/library/alpine:3.18 #2 [template internal] load build definition from Dockerfile.staging
#2 DONE 0.2s #2 transferring dockerfile: 287B done
#2 DONE 0.0s
#3 [template internal] load .dockerignore #3 [template internal] load metadata for docker.io/library/alpine:3.18
#3 transferring context: 2B done #3 ...
#3 DONE 0.0s
#4 [template 1/3] FROM docker.io/library/alpine:3.18@sha256:de0eb0b3f2a47ba1eb89389859a9bd88b28e82f5826b6969ad604979713c2d4f #4 [mariadb internal] load metadata for docker.io/library/mariadb:10.5
#4 resolve docker.io/library/alpine:3.18@sha256:de0eb0b3f2a47ba1eb89389859a9bd88b28e82f5826b6969ad604979713c2d4f done #4 DONE 0.3s
#4 DONE 0.0s
#5 [template 2/3] RUN mkdir -p /scratch /temp #5 [mariadb internal] load .dockerignore
#5 CACHED #5 transferring context: 2B done
#5 DONE 0.0s
#6 [template 3/3] WORKDIR /scratch #6 [mariadb 1/1] FROM docker.io/library/mariadb:10.5@sha256:c8bb76c7d0fd384a8a9f230c42a879be8e1052783c8007caa1320a630273b425
#6 resolve docker.io/library/mariadb:10.5@sha256:c8bb76c7d0fd384a8a9f230c42a879be8e1052783c8007caa1320a630273b425 done
#6 CACHED #6 CACHED
#7 [template] exporting to image #7 [mariadb] exporting to image
#7 exporting layers done #7 exporting layers done
#7 exporting manifest sha256:15b202f67217697a010a43b0d8ef636c8bd4a00a7258dc8334ce1220aa5ad10d done #7 exporting manifest sha256:67ef4d7011fcf8bda1b124dc9f2017e9cd24ffc75c81a44f5ee8dfc4f5e97272 done
#7 exporting config sha256:e4f5b35710a25e9116a133bde6255ccc3f91a39c9b99e4f4a44d7eaf27024e7d done #7 exporting config sha256:812d99d7ea8dc6b118c8a744483eab5b3e5fbb0380aed0f65ba822532f413754 done
#7 exporting attestation manifest sha256:ec2582c7e07cfeaaeb69797430b3d687550c642903473dbe1fbcdea58fefc2cb 0.0s done #7 exporting attestation manifest sha256:7aca870e0ff4f86c1fa6d851de62930967f801fb0ab78b125b90b881a1902d77 0.0s done
#7 exporting manifest list sha256:1f3404b565e38ec1490f2d56d612438b611b2fd31e213e39e37c8e3e80c4b3ff done #7 exporting manifest list sha256:d4ed6fde413437ace9621431c6eb2a01a2e697f76f9eb75bfd8867d854ed0329 done
#7 naming to docker.io/library/template:test done #7 naming to git.nixc.us/nixius/template:staging-mariadb done
#7 unpacking to docker.io/library/template:test done #7 unpacking to git.nixc.us/nixius/template:staging-mariadb done
#7 DONE 0.0s #7 DONE 0.1s
#8 [template] resolving provenance for metadata file #8 [mariadb] resolving provenance for metadata file
#8 DONE 0.0s #8 DONE 0.0s
#3 [template internal] load metadata for docker.io/library/alpine:3.18
#3 DONE 0.5s
#9 [template internal] load .dockerignore
#9 transferring context: 2B done
#9 DONE 0.0s
#10 [template 1/3] FROM docker.io/library/alpine:3.18@sha256:de0eb0b3f2a47ba1eb89389859a9bd88b28e82f5826b6969ad604979713c2d4f
#10 resolve docker.io/library/alpine:3.18@sha256:de0eb0b3f2a47ba1eb89389859a9bd88b28e82f5826b6969ad604979713c2d4f 0.0s done
#10 DONE 0.0s
#11 [template 2/3] RUN mkdir -p /scratch /temp
#11 CACHED
#12 [template 3/3] WORKDIR /scratch
#12 CACHED
#13 [template] exporting to image
#13 exporting layers done
#13 exporting manifest sha256:df84d578a4eccddc7f7d15d3c610d35803bd529ce0f90f1eb1099bbf982d9341 done
#13 exporting config sha256:c48b4c75f46025fb4e6a7ba120f44c3a0f8bb216a3724a138aacaac8bdb20d79 done
#13 exporting attestation manifest sha256:9019fbf8cbfc0b2044e242e9ec9dbdb71d7cc56fcaf67b83f0f5f52f9004db31 done
#13 exporting manifest list sha256:cae7893861af71be867d14ed053aaa6dab448b864649480d90264a3522d580bd done
#13 naming to docker.io/library/template:test done
#13 unpacking to docker.io/library/template:test done
#13 DONE 0.0s
#14 [template] resolving provenance for metadata file
#14 DONE 0.0s
mariadb Built
template Built template Built
Testing container startup... Testing container startup...
Network template_default Creating Network easy-appointments_default Creating
Network template_default Created Network easy-appointments_default Created
Container template-template-1 Recreate Container easy-appointments-mariadb-1 Creating
Container template-template-1 Recreated Container easy-appointments-template-1 Creating
Container template-template-1 Starting Container easy-appointments-template-1 Created
Container template-template-1 Started Container easy-appointments-mariadb-1 Created
Container easy-appointments-mariadb-1 Starting
Container easy-appointments-template-1 Starting
Container easy-appointments-mariadb-1 Started
Container easy-appointments-template-1 Started
Container status: Container status:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
easy-appointments-template-1 template:test "tail -f /dev/null" template 6 seconds ago Up 5 seconds
Cleaning up... Cleaning up...
Container template-template-1 Stopping Container easy-appointments-template-1 Stopping
Container template-template-1 Stopped Container easy-appointments-mariadb-1 Stopping
Container template-template-1 Removing Container easy-appointments-mariadb-1 Stopped
Container template-template-1 Removed Container easy-appointments-mariadb-1 Removing
Network template_default Removing Container easy-appointments-mariadb-1 Removed
Network template_default Removed Container easy-appointments-template-1 Stopped
Tests completed at Wed Apr 23 10:27:52 EDT 2025 Container easy-appointments-template-1 Removing
Container easy-appointments-template-1 Removed
Network easy-appointments_default Removing
Network easy-appointments_default Removed
Tests completed at Wed Apr 23 10:58:27 EDT 2025