86 lines
2.7 KiB
Markdown
86 lines
2.7 KiB
Markdown
|
|
# CONTAINER SERVICES (m3-atlas)
|
||
|
|
|
||
|
|
**Container orchestration with Podman + Traefik reverse proxy**
|
||
|
|
|
||
|
|
## OVERVIEW
|
||
|
|
11 containerized services on dedicated `web` network (10.89.0.0/24) with Traefik SSL termination.
|
||
|
|
|
||
|
|
## STRUCTURE
|
||
|
|
```
|
||
|
|
containers/
|
||
|
|
├── default.nix # Network setup + service imports
|
||
|
|
├── baserow.nix # 10.89.0.10 - No-code database
|
||
|
|
├── ghost.nix # 10.89.0.11 - Blog platform
|
||
|
|
├── kestra.nix # 10.89.0.12 - Workflow orchestration
|
||
|
|
├── littlelink.nix # 10.89.0.13 - Link aggregator
|
||
|
|
├── matomo.nix # 10.89.0.14 - Analytics
|
||
|
|
├── restreamer.nix # 10.89.0.15 - Video streaming
|
||
|
|
├── slash.nix # 10.89.0.16 - Link shortener
|
||
|
|
└── slash-nemoti.nix # 10.89.0.17 - Personal link shortener
|
||
|
|
```
|
||
|
|
|
||
|
|
## WHERE TO LOOK
|
||
|
|
|
||
|
|
| Task | Action | Notes |
|
||
|
|
|------|--------|-------|
|
||
|
|
| Add container | Copy existing .nix, increment IP | Must update default.nix imports |
|
||
|
|
| Fix networking | Check IP conflicts in 10.89.0.0/24 | Gateway always 10.89.0.1 |
|
||
|
|
| Debug Traefik | Check router rules in service file | Domain must match DNS |
|
||
|
|
| Access database | Use `--add-host=mysql:10.89.0.1` | Gateway IP for host services |
|
||
|
|
|
||
|
|
## CONVENTIONS
|
||
|
|
|
||
|
|
### Container Definition Template
|
||
|
|
```nix
|
||
|
|
virtualisation.oci-containers.containers.<name> = {
|
||
|
|
image = "registry/image:tag";
|
||
|
|
ports = ["127.0.0.1:<external>:<internal>"];
|
||
|
|
volumes = ["/var/lib/<service>:/data"];
|
||
|
|
environmentFiles = [config.age.secrets.<name>-env.path];
|
||
|
|
extraOptions = [
|
||
|
|
"--network=web"
|
||
|
|
"--ip=10.89.0.<sequential>"
|
||
|
|
"--add-host=mysql:10.89.0.1" # If DB needed
|
||
|
|
];
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### Traefik Integration
|
||
|
|
```nix
|
||
|
|
services.traefik.dynamicConfigOptions.http = {
|
||
|
|
services.<name>.loadBalancer.servers = [{
|
||
|
|
url = "http://127.0.0.1:<port>";
|
||
|
|
}];
|
||
|
|
routers.<name> = {
|
||
|
|
rule = "Host(`<subdomain>.m3ta.dev`)";
|
||
|
|
service = "<name>";
|
||
|
|
tls.certResolver = "godaddy";
|
||
|
|
};
|
||
|
|
# Legacy redirect (if needed)
|
||
|
|
routers.<name>-old = {
|
||
|
|
rule = "Host(`<subdomain>.m3tam3re.com`)";
|
||
|
|
service = "<name>";
|
||
|
|
middlewares = ["redirect-m3ta"];
|
||
|
|
};
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### IP Allocation
|
||
|
|
- **10.89.0.1**: Gateway (host)
|
||
|
|
- **10.89.0.10-17**: Assigned containers
|
||
|
|
- **10.89.0.18+**: Available for new services
|
||
|
|
|
||
|
|
## ANTI-PATTERNS
|
||
|
|
|
||
|
|
- **DON'T** expose ports publicly - bind to 127.0.0.1 only
|
||
|
|
- **DON'T** skip static IP assignment - routing breaks without it
|
||
|
|
- **DON'T** hardcode secrets - use age-encrypted env files
|
||
|
|
- **DON'T** forget to add imports to default.nix
|
||
|
|
|
||
|
|
## NOTES
|
||
|
|
|
||
|
|
- Network created via activation script in default.nix
|
||
|
|
- All services behind Traefik - no direct external access
|
||
|
|
- MySQL/PostgreSQL run on host, accessed via gateway IP
|
||
|
|
- Secrets pattern: `<service>-env.age` with environment variables
|