Initial commit
This commit is contained in:
54
infrastructure/README.md
Normal file
54
infrastructure/README.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Infrastructure
|
||||
|
||||
Core cluster services that apps depend on. These are installed before any apps via Flux `dependsOn` ordering.
|
||||
|
||||
## Dependency Chain
|
||||
|
||||
```
|
||||
MetalLB Install ──▶ MetalLB Config ──▶ Traefik Install ──▶ Routes
|
||||
│
|
||||
Cert-Manager Install ──▶ Cert-Manager Issuer │
|
||||
│
|
||||
Apps depend on ─┘
|
||||
```
|
||||
|
||||
## Components
|
||||
|
||||
| Directory | What it does |
|
||||
|-----------|-------------|
|
||||
| `metallb-install/` | Installs MetalLB via Helm — gives LoadBalancer services real LAN IPs |
|
||||
| `metallb-config/` | Configures the IP address pool and L2 advertisement |
|
||||
| `traefik-install/` | Installs Traefik via Helm — reverse proxy and ingress controller |
|
||||
| `cert-manager-install/` | Installs cert-manager via Helm — automates TLS certificate provisioning |
|
||||
| `cert-manager-issuer/` | Configures Let's Encrypt ClusterIssuer with DNS-01 challenge |
|
||||
| `routes/` | Traefik IngressRoutes — one file per app defining how traffic reaches it |
|
||||
|
||||
## How Helm Releases Work Here
|
||||
|
||||
Each Helm-based service follows the same pattern:
|
||||
|
||||
1. **HelmRelease** (`helmrelease.yaml`) — Points to a chart and version from a HelmRepository defined in `bootstrap/repositories/`
|
||||
2. **ConfigMap override** (`*-override.yaml`) — Contains chart values as a YAML string under `data.values.yaml`. Referenced via `valuesFrom` in the HelmRelease.
|
||||
|
||||
This pattern keeps chart values separate from the release definition, making them easier to review and modify.
|
||||
|
||||
## Adding a New Infrastructure Service
|
||||
|
||||
1. Create a HelmRepository in `bootstrap/repositories/` (if the chart source is new)
|
||||
2. Create a directory under `infrastructure/` (e.g. `infrastructure/my-service-install/`)
|
||||
3. Add a `helmrelease.yaml` and optionally a ConfigMap override
|
||||
4. Create a Flux Kustomization in `bootstrap/kustomization/infrastructure/` pointing to your new directory
|
||||
5. Set `dependsOn` appropriately (most infra services should depend on MetalLB being configured)
|
||||
6. Commit and push — Flux handles the rest
|
||||
|
||||
## Adding SOPS Secret Encryption
|
||||
|
||||
The `cert-manager-issuer/secret.yaml` file currently contains a plain-text secret. To encrypt it:
|
||||
|
||||
1. Install [age](https://github.com/FiloSottile/age) and generate a key pair
|
||||
2. Create a `.sops.yaml` at the repo root with creation rules for your paths
|
||||
3. Encrypt secret files: `sops --encrypt --in-place infrastructure/cert-manager-issuer/secret.yaml`
|
||||
4. Add `spec.decryption` to the relevant Flux Kustomizations in `bootstrap/kustomization/`
|
||||
5. Create a `sops-age` Secret in `flux-system` namespace with your age private key
|
||||
|
||||
See the [Flux SOPS guide](https://fluxcd.io/flux/guides/mozilla-sops/) for full instructions.
|
||||
10
infrastructure/cert-manager-install/cert-override.yaml
Normal file
10
infrastructure/cert-manager-install/cert-override.yaml
Normal file
@@ -0,0 +1,10 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cert-manager-chart-overrides
|
||||
namespace: infrastructure
|
||||
data:
|
||||
values.yaml: |-
|
||||
namespace: infrastructure
|
||||
crds:
|
||||
enabled: true
|
||||
19
infrastructure/cert-manager-install/helmrelease.yaml
Normal file
19
infrastructure/cert-manager-install/helmrelease.yaml
Normal file
@@ -0,0 +1,19 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: cert-manager-release
|
||||
namespace: infrastructure
|
||||
spec:
|
||||
chart:
|
||||
spec:
|
||||
chart: cert-manager
|
||||
version: 1.19.2
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: jetstack
|
||||
namespace: flux-system
|
||||
interval: 10m
|
||||
valuesFrom:
|
||||
- kind: ConfigMap
|
||||
name: cert-manager-chart-overrides
|
||||
valuesKey: values.yaml
|
||||
22
infrastructure/cert-manager-issuer/issuer.yaml
Normal file
22
infrastructure/cert-manager-issuer/issuer.yaml
Normal file
@@ -0,0 +1,22 @@
|
||||
# ClusterIssuer for Let's Encrypt using DNS-01 challenge.
|
||||
# This example uses Cloudflare as the DNS provider. If you use a different
|
||||
# provider, see: https://cert-manager.io/docs/configuration/acme/dns01/
|
||||
#
|
||||
# Replace <YOUR_EMAIL> with your email address for Let's Encrypt notifications.
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: ClusterIssuer
|
||||
metadata:
|
||||
name: cert-issuer
|
||||
namespace: infrastructure
|
||||
spec:
|
||||
acme:
|
||||
server: https://acme-v02.api.letsencrypt.org/directory
|
||||
email: <YOUR_EMAIL>
|
||||
privateKeySecretRef:
|
||||
name: letsencrypt-dns-key
|
||||
solvers:
|
||||
- dns01:
|
||||
cloudflare:
|
||||
apiTokenSecretRef:
|
||||
name: cloudflare-credentials
|
||||
key: api-token
|
||||
13
infrastructure/cert-manager-issuer/secrets.yaml
Normal file
13
infrastructure/cert-manager-issuer/secrets.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
# DNS provider API token for cert-manager DNS-01 challenge.
|
||||
# Replace <YOUR_DNS_API_TOKEN> with your Cloudflare API token
|
||||
# (or adjust for your DNS provider).
|
||||
#
|
||||
# Encrypt this file with: sops --encrypt --in-place secrets.yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: cloudflare-credentials
|
||||
namespace: infrastructure
|
||||
type: Opaque
|
||||
stringData:
|
||||
api-token: <YOUR_DNS_API_TOKEN>
|
||||
13
infrastructure/metallb-config/ipaddresspool.yaml
Normal file
13
infrastructure/metallb-config/ipaddresspool.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
# MetalLB IP Address Pool
|
||||
# Replace <YOUR_IP_RANGE> with a range of unused IPs on your LAN.
|
||||
# These IPs will be assigned to LoadBalancer services (e.g. Traefik).
|
||||
# Example: 192.168.1.200-192.168.1.210
|
||||
apiVersion: metallb.io/v1beta1
|
||||
kind: IPAddressPool
|
||||
metadata:
|
||||
name: metallb-pool
|
||||
namespace: infrastructure
|
||||
spec:
|
||||
addresses:
|
||||
- <YOUR_IP_RANGE>
|
||||
autoAssign: true
|
||||
8
infrastructure/metallb-config/l2.yaml
Normal file
8
infrastructure/metallb-config/l2.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
apiVersion: metallb.io/v1beta1
|
||||
kind: L2Advertisement
|
||||
metadata:
|
||||
name: metallb-l2
|
||||
namespace: infrastructure
|
||||
spec:
|
||||
ipAddressPools:
|
||||
- metallb-pool
|
||||
17
infrastructure/metallb-install/helmrelease.yaml
Normal file
17
infrastructure/metallb-install/helmrelease.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2beta1
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: metallb-release
|
||||
namespace: infrastructure
|
||||
spec:
|
||||
chart:
|
||||
spec:
|
||||
chart: metallb
|
||||
version: 0.14.9
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: metallb
|
||||
namespace: flux-system
|
||||
interval: 15m
|
||||
timeout: 10m
|
||||
releaseName: metallb
|
||||
56
infrastructure/routes/gitea.yaml
Normal file
56
infrastructure/routes/gitea.yaml
Normal file
@@ -0,0 +1,56 @@
|
||||
# Gitea ingress routes via Traefik.
|
||||
# Replace <YOUR_DOMAIN> with your domain (e.g. git.example.com).
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: redirect-https
|
||||
namespace: gitea
|
||||
spec:
|
||||
redirectScheme:
|
||||
scheme: https
|
||||
permanent: true
|
||||
---
|
||||
# HTTP entrypoint — redirects all traffic to HTTPS
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: gitea-ingress-http
|
||||
namespace: gitea
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
routes:
|
||||
- match: Host(`<YOUR_DOMAIN>`)
|
||||
kind: Rule
|
||||
middlewares:
|
||||
- name: redirect-https
|
||||
services:
|
||||
- name: gitea-http
|
||||
namespace: gitea
|
||||
port: 3000
|
||||
---
|
||||
# HTTPS entrypoint — serves Gitea with TLS
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: gitea-ingress
|
||||
namespace: gitea
|
||||
annotations:
|
||||
cert-manager.io/issuer: "cert-issuer"
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: Host(`<YOUR_DOMAIN>`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: gitea-http
|
||||
namespace: gitea
|
||||
port: 3000
|
||||
tls:
|
||||
secretName: gitea-tls
|
||||
domains:
|
||||
- main: <YOUR_DOMAIN>
|
||||
sans:
|
||||
- <YOUR_DOMAIN>
|
||||
21
infrastructure/traefik-install/helmrelease.yaml
Normal file
21
infrastructure/traefik-install/helmrelease.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2beta1
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: traefik-release
|
||||
namespace: infrastructure
|
||||
spec:
|
||||
chart:
|
||||
spec:
|
||||
chart: traefik
|
||||
version: 39.0.0
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: traefik
|
||||
namespace: flux-system
|
||||
interval: 15m
|
||||
timeout: 10m
|
||||
releaseName: traefik
|
||||
valuesFrom:
|
||||
- kind: ConfigMap
|
||||
name: traefik-chart-overrides
|
||||
valuesKey: values.yaml
|
||||
25
infrastructure/traefik-install/traefik-override.yaml
Normal file
25
infrastructure/traefik-install/traefik-override.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
# Traefik Helm chart value overrides.
|
||||
# Replace <YOUR_LAN_CIDR> with your local network range (e.g. 192.168.1.0/24).
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: traefik-chart-overrides
|
||||
namespace: infrastructure
|
||||
data:
|
||||
values.yaml: |-
|
||||
deployment:
|
||||
enabled: true
|
||||
replicas: 1
|
||||
ingressClass:
|
||||
enabled: true
|
||||
isDefaultClass: true
|
||||
service:
|
||||
type: LoadBalancer
|
||||
ports:
|
||||
websecure:
|
||||
forwardedHeaders:
|
||||
trustedIPs:
|
||||
- <YOUR_LAN_CIDR>
|
||||
additionalArguments:
|
||||
- "--api.dashboard=true"
|
||||
- "--api.insecure=true"
|
||||
Reference in New Issue
Block a user