Compare commits

2 Commits
v1.0.0 ... main

Author SHA1 Message Date
Christian van Dijk
d7562d8a30 🔧 enhance Makefile and Readme with Docker Swarm and Kubernetes support, adding new targets for deployment and management
All checks were successful
CI / Lint (push) Successful in 21s
CI / Helm Lint (push) Successful in 5s
CI / Build (push) Successful in 1m48s
CI / Test (push) Successful in 44s
2026-02-23 23:30:20 +01:00
Christian van Dijk
0a78491587 🔧 update docker-compose configuration to include 'handheld-net' network and modify healthcheck settings for services
All checks were successful
CI / Lint (push) Successful in 21s
CI / Helm Lint (push) Successful in 6s
CI / Build (push) Successful in 1m52s
CI / Test (push) Successful in 44s
2026-02-23 23:17:18 +01:00
6 changed files with 265 additions and 12 deletions

View File

@@ -1,5 +1,15 @@
.PHONY: dev up down build test lint install-deps logs logs-api logs-worker logs-all \ .PHONY: dev up down build test lint install-deps logs logs-api logs-worker logs-all \
init-db shell-postgres shell-api shell-worker status clean help init-db shell-postgres shell-api shell-worker status clean help \
k8s-apply-local k8s-apply-a k8s-down-local k8s-down-a \
swarm-build swarm-deploy swarm-down
# Docker Swarm
SWARM_STACK ?= handheld
# Kubernetes
K8S_CHART := k8s/handheld-devices
K8S_NAMESPACE ?= handheld-devices
K8S_CONTEXT_A ?= # set to your A env context, e.g. gke_project_region_cluster
# Default target # Default target
help: help:
@@ -23,6 +33,15 @@ help:
@echo "" @echo ""
@echo " status Show container status" @echo " status Show container status"
@echo " clean Stop and remove volumes" @echo " clean Stop and remove volumes"
@echo ""
@echo " k8s-apply-local Helm upgrade/install to local cluster (minikube, kind)"
@echo " k8s-apply-a Helm upgrade/install to A env (set K8S_CONTEXT_A)"
@echo " k8s-down-local Helm uninstall from local cluster"
@echo " k8s-down-a Helm uninstall from A env (set K8S_CONTEXT_A)"
@echo ""
@echo " swarm-build Build and tag images for Swarm (no build in stack)"
@echo " swarm-deploy Deploy stack to Swarm (requires: docker swarm init)"
@echo " swarm-down Remove stack from Swarm"
install-deps: install-deps:
luarocks install lua-cjson && luarocks install luasocket && luarocks install pgmoon && \ luarocks install lua-cjson && luarocks install luasocket && luarocks install pgmoon && \
@@ -73,3 +92,34 @@ status:
clean: down clean: down
docker-compose down -v docker-compose down -v
k8s-apply-local:
helm upgrade --install handheld-devices $(K8S_CHART) \
-f $(K8S_CHART)/values.yaml \
-f $(K8S_CHART)/values-local.yaml \
-n $(K8S_NAMESPACE) --create-namespace
k8s-apply-a:
helm upgrade --install handheld-devices $(K8S_CHART) \
-f $(K8S_CHART)/values.yaml \
-f $(K8S_CHART)/values-a.yaml \
-n $(K8S_NAMESPACE) --create-namespace \
$(if $(K8S_CONTEXT_A),--kube-context $(K8S_CONTEXT_A))
k8s-down-local:
helm uninstall handheld-devices -n $(K8S_NAMESPACE) --ignore-not-found
k8s-down-a:
helm uninstall handheld-devices -n $(K8S_NAMESPACE) --ignore-not-found \
$(if $(K8S_CONTEXT_A),--kube-context $(K8S_CONTEXT_A))
swarm-build:
docker build -t handheld-devices-api:latest ./devices-api
docker build -t handheld-devices-worker:latest ./devices-worker
docker build -t handheld-devices-frontend:latest ./frontend
swarm-deploy: swarm-build
docker stack deploy -c compose.swarm.yml $(SWARM_STACK)
swarm-down:
docker stack rm $(SWARM_STACK)

View File

@@ -80,7 +80,7 @@ make lint # deno check
From project root: From project root:
| Target | Description | | Target | Description |
| --------------------- | ----------------------------------------- | | --------------------- | ------------------------------------------ |
| `make install-deps` | Install LuaRocks + Deno deps for local dev | | `make install-deps` | Install LuaRocks + Deno deps for local dev |
| `make dev` | Start all services | | `make dev` | Start all services |
| `make down` | Stop all services | | `make down` | Stop all services |
@@ -110,6 +110,30 @@ From project root:
- **Kubernetes**: `helm lint k8s/handheld-devices` - **Kubernetes**: `helm lint k8s/handheld-devices`
- **CI**: See `.github/workflows/ci.yml` (lint, build, unit tests, helm lint) - **CI**: See `.github/workflows/ci.yml` (lint, build, unit tests, helm lint)
## Docker Swarm
Use `compose.swarm.yml` to deploy to Docker Swarm. Postgres is pinned to a single node (via label) so its volume stays on one node.
**Label the node** that will run Postgres before deploying:
```bash
docker node ls
docker node update --label-add db=true <NODE_ID>
```
Then deploy:
```bash
docker swarm init # if not already a swarm manager
make swarm-deploy
```
| Target | Description |
| ------------------- | ------------------------------ |
| `make swarm-build` | Build and tag images for Swarm |
| `make swarm-deploy` | Build images and deploy stack |
| `make swarm-down` | Remove stack from Swarm |
## Environment ## Environment
See `.env.example` for configuration. Key variables: See `.env.example` for configuration. Key variables:

137
compose.swarm.yml Normal file
View File

@@ -0,0 +1,137 @@
# Docker Swarm stack - run: make swarm-deploy (build images first: make swarm-build)
# Postgres is pinned to manager node so its volume stays on one node.
services:
api:
image: handheld-devices-api:latest
networks:
- handheld-net
ports:
- "8080:8080"
env_file:
- .env
environment:
DB_HOST: postgres
DB_PORT: "5432"
DB_NAME: handheld_devices
DB_USER: devices_user
DB_PASSWORD: devices_password
REDIS_HOST: redis
REDIS_PORT: "6379"
healthcheck:
test: ["CMD-SHELL", "wget -q -O - http://localhost:8080/health/live || exit 1"]
interval: 5s
timeout: 5s
retries: 10
start_period: 30s
deploy:
replicas: 2
restart_policy:
condition: on-failure
update_config:
parallelism: 1
delay: 10s
postgres:
image: postgres:15-alpine
networks:
- handheld-net
ports:
- "5432:5432"
environment:
POSTGRES_DB: handheld_devices
POSTGRES_USER: devices_user
POSTGRES_PASSWORD: devices_password
volumes:
- postgres_data:/var/lib/postgresql/data
configs:
- source: postgres_init
target: /docker-entrypoint-initdb.d/001_create_devices.sql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U devices_user -d handheld_devices"]
interval: 5s
timeout: 3s
retries: 10
deploy:
replicas: 1
restart_policy:
condition: on-failure
placement:
constraints:
- node.labels.db == true
redis:
image: redis:7-alpine
networks:
- handheld-net
ports:
- "6379:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
deploy:
replicas: 1
restart_policy:
condition: on-failure
frontend:
image: handheld-devices-frontend:latest
networks:
- handheld-net
ports:
- "8090:8090"
env_file:
- .env
environment:
API_URL: http://localhost:8080
healthcheck:
test: ["CMD-SHELL", "wget -q -O - http://localhost:8090/health || exit 1"]
interval: 10s
timeout: 5s
retries: 3
start_period: 5s
deploy:
replicas: 1
restart_policy:
condition: on-failure
update_config:
parallelism: 1
delay: 10s
worker:
image: handheld-devices-worker:latest
networks:
- handheld-net
env_file:
- .env
environment:
DB_HOST: postgres
DB_PORT: "5432"
DB_NAME: handheld_devices
DB_USER: devices_user
DB_PASSWORD: devices_password
REDIS_HOST: redis
REDIS_PORT: "6379"
healthcheck:
test: ["CMD-SHELL", "pgrep -f 'worker.lua' || exit 1"]
interval: 10s
timeout: 3s
retries: 3
deploy:
replicas: 1
restart_policy:
condition: on-failure
configs:
postgres_init:
file: ./devices-api/migrations/001_create_devices.sql
volumes:
postgres_data:
networks:
handheld-net:
driver: overlay
attachable: true

View File

@@ -4,6 +4,8 @@ services:
context: ./devices-api context: ./devices-api
dockerfile: Dockerfile dockerfile: Dockerfile
container_name: handheld-api container_name: handheld-api
networks:
- handheld-net
ports: ports:
- "8080:8080" - "8080:8080"
volumes: volumes:
@@ -24,15 +26,17 @@ services:
- REDIS_HOST=redis - REDIS_HOST=redis
- REDIS_PORT=6379 - REDIS_PORT=6379
healthcheck: healthcheck:
test: ["CMD-SHELL", "wget -q -O - http://localhost:8080/health/ready || exit 1"] test: ["CMD-SHELL", "wget -q -O - http://localhost:8080/health/live || exit 1"]
interval: 10s interval: 5s
timeout: 5s timeout: 5s
retries: 3 retries: 10
start_period: 10s start_period: 30s
postgres: postgres:
image: postgres:15-alpine image: postgres:15-alpine
container_name: handheld-postgres container_name: handheld-postgres
networks:
- handheld-net
ports: ports:
- "5432:5432" - "5432:5432"
environment: environment:
@@ -51,6 +55,8 @@ services:
redis: redis:
image: redis:7-alpine image: redis:7-alpine
container_name: handheld-redis container_name: handheld-redis
networks:
- handheld-net
ports: ports:
- "6379:6379" - "6379:6379"
healthcheck: healthcheck:
@@ -64,6 +70,8 @@ services:
context: ./frontend context: ./frontend
dockerfile: Dockerfile dockerfile: Dockerfile
container_name: handheld-frontend container_name: handheld-frontend
networks:
- handheld-net
ports: ports:
- "8090:8090" - "8090:8090"
env_file: env_file:
@@ -85,6 +93,8 @@ services:
context: ./devices-worker context: ./devices-worker
dockerfile: Dockerfile dockerfile: Dockerfile
container_name: handheld-worker container_name: handheld-worker
networks:
- handheld-net
volumes: volumes:
- ./devices-worker:/app - ./devices-worker:/app
env_file: env_file:
@@ -107,3 +117,7 @@ services:
interval: 10s interval: 10s
timeout: 3s timeout: 3s
retries: 3 retries: 3
networks:
handheld-net:
name: handheld-devices

View File

@@ -0,0 +1,17 @@
# Overrides for A environment (staging/production)
# Customize: image tags, ingress, apiUrl, replicas, etc.
frontend:
apiUrl: "https://handheld-a.example.com" # override with your A env URL
ingress:
enabled: true
hosts:
- host: handheld-a.example.com
paths:
- path: /api
pathType: Prefix
service: api
port: 8080
- path: /
pathType: Prefix
service: frontend
port: 8090

View File

@@ -0,0 +1,11 @@
# Overrides for local dev (minikube, kind, etc.)
api:
image:
pullPolicy: Never # use locally built images
worker:
image:
pullPolicy: Never
frontend:
image:
pullPolicy: Never
apiUrl: "http://localhost:8080"