🔧 enhance Makefile and Readme with Docker Swarm and Kubernetes support, adding new targets for deployment and management
This commit is contained in:
52
Makefile
52
Makefile
@@ -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)
|
||||||
|
|||||||
38
Readme.md
38
Readme.md
@@ -79,14 +79,14 @@ 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 |
|
||||||
| `make build` | Build Docker images |
|
| `make build` | Build Docker images |
|
||||||
| `make test` | Run API unit tests |
|
| `make test` | Run API unit tests |
|
||||||
| `make lint` | Luacheck + Deno check |
|
| `make lint` | Luacheck + Deno check |
|
||||||
| `make logs` | Follow API logs |
|
| `make logs` | Follow API logs |
|
||||||
| `make logs-worker` | Follow worker logs |
|
| `make logs-worker` | Follow worker logs |
|
||||||
| `make init-db` | Run DB migrations manually |
|
| `make init-db` | Run DB migrations manually |
|
||||||
@@ -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
137
compose.swarm.yml
Normal 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
|
||||||
17
k8s/handheld-devices/values-a.yaml
Normal file
17
k8s/handheld-devices/values-a.yaml
Normal 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
|
||||||
11
k8s/handheld-devices/values-local.yaml
Normal file
11
k8s/handheld-devices/values-local.yaml
Normal 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"
|
||||||
Reference in New Issue
Block a user