ci-actions/deploy-static-site/generate-job.py
Christopher Mühl 55652569b2
feat: add deploy-static-site action, site-lib, images; remove deploy-oci-site
Content now served from S3 at runtime via shared static-server image.
- deploy-static-site: reads creds from Nomad vars, builds site, pushes
  tarball to S3, generates per-domain Nomad job JSON, deploys
- generate-job.py: emits Nomad job JSON for a static site deployment
- site-lib/flake.nix: mkSite helper, packages.default + devShells only
- images/flake.nix: shared static-server OCI image (sws + awscli2 + tools)
- images CI: builds and pushes static-server on images/flake.nix changes
- deploy-oci-site: removed (superseded by deploy-static-site)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-18 11:27:27 +01:00

108 lines
3.4 KiB
Python

#!/usr/bin/env python3
"""
Generate a Nomad job JSON for a static site deployment.
Reads from environment variables, prints JSON to stdout.
Pipe to: nomad job run -json -
"""
import json
import os
import sys
domain = os.environ["DOMAIN"]
site_hash = os.environ["SITE_HASH"]
server_image = os.environ.get("SERVER_IMAGE", "registry.toph.so/static-server:latest")
datacenter = os.environ.get("DATACENTER", "contabo")
s3_bucket = os.environ["S3_BUCKET"]
job_id = "site-" + domain.replace(".", "-")
startup_cmd = (
f"mkdir -p /var/www && "
f"aws s3 cp s3://{s3_bucket}/sites/{domain}/{site_hash}.tar.gz - "
f"| tar xz -C /var/www/ && "
f"exec static-web-server --port 8080 --root /var/www"
)
nomad_template_data = (
'{{ with nomadVar "static-sites/s3" }}'
"AWS_ACCESS_KEY_ID={{ .access_key }}\n"
"AWS_SECRET_ACCESS_KEY={{ .secret_key }}\n"
"AWS_ENDPOINT_URL={{ .endpoint }}\n"
"{{ end }}"
)
job = {
"Job": {
"ID": job_id,
"Name": job_id,
"Namespace": "static-sites",
"Type": "service",
"Datacenters": [datacenter],
"Update": {
"MinHealthyTime": 5000000000, # 5s in nanoseconds
"HealthyDeadline": 60000000000, # 60s in nanoseconds
"MaxParallel": 1,
},
"TaskGroups": [
{
"Name": "site",
"Count": 1,
"Networks": [
{
"DynamicPorts": [
{"Label": "http", "To": 8080}
]
}
],
"Services": [
{
"Name": job_id,
"Provider": "nomad",
"PortLabel": "http",
"Tags": [
"traefik.enable=true",
f"traefik.http.routers.{job_id}.rule=Host(`{domain}`)",
f"traefik.http.routers.{job_id}.entrypoints=websecure",
f"traefik.http.routers.{job_id}.tls.certresolver=letsencrypt",
],
"Checks": [
{
"Type": "http",
"Path": "/",
"Interval": 30000000000, # 30s
"Timeout": 5000000000, # 5s
}
],
}
],
"Tasks": [
{
"Name": "server",
"Driver": "docker",
"Config": {
"image": server_image,
"command": "/bin/bash",
"args": ["-c", startup_cmd],
"ports": ["http"],
},
"Templates": [
{
"EmbeddedTmpl": nomad_template_data,
"DestPath": "secrets/s3.env",
"Envvars": True,
}
],
"Resources": {
"CPU": 100,
"MemoryMB": 128,
},
}
],
}
],
}
}
json.dump(job, sys.stdout, indent=2)
print()