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>
108 lines
3.4 KiB
Python
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()
|