cicd: initial kubernetes infrastructure

This commit is contained in:
Szymon Wałachowski 2026-03-31 23:37:01 +02:00
commit 601a0328b8
28 changed files with 1385 additions and 0 deletions

228
RUNBOOK.md Normal file
View file

@ -0,0 +1,228 @@
# Szymiserver Infrastructure Runbook
## Overview
This server runs a Kubernetes cluster (kind) hosting:
| Service | URL | Notes |
|---------|-----|-------|
| Forgejo | https://git.szymi.ddns.net | Git + CI/CD |
| ArgoCD | https://argocd.szymi.ddns.net | GitOps deployment |
| Registry | https://registry.szymi.ddns.net | Private Docker registry |
| Nextcloud | https://nextcloud.szymi.ddns.net | File storage |
| Draw.io | https://drawio.szymi.ddns.net | Diagrams |
All TLS certificates are automatically issued and renewed via Let's Encrypt (cert-manager).
Apps are deployed via **ArgoCD GitOps** — push to Forgejo → ArgoCD syncs automatically.
---
## Prerequisites
- Linux machine with Docker installed
- `kind` installed (`go install sigs.k8s.io/kind@latest`)
- `kubectl` installed
- Ports 80, 443, 2222 open on the firewall/router
- DNS A records pointing to server's public IP for all subdomains
- `/media/ssd` mounted (SSD for persistent data)
---
## Fresh Install From Scratch
### Step 1: Clone the repo
```bash
git clone https://git.szymi.ddns.net/szymi/szymiserver.git
cd szymiserver
```
### Step 2: Create the kind cluster
```bash
kind create cluster --config cluster-config.yml
```
This creates a cluster named `szymicluster` with:
- Port 80, 443 exposed (for ingress HTTP/HTTPS)
- Port 2222 exposed (for Forgejo SSH)
- `/media/ssd` mounted into the kind container (persistent volumes)
- `/var/run/docker.sock` mounted (for Forgejo runner)
### Step 3: Deploy infrastructure
```bash
chmod +x k8s/deploy-infrastructure.sh
./k8s/deploy-infrastructure.sh
```
**What the script does, in order:**
1. Fixes kind container DNS (forces IPv4 — prevents ImagePullBackOff on servers with broken IPv6)
2. Creates required host directories on `/media/ssd`
3. Applies all infrastructure via kustomize (ingress-nginx, cert-manager, CoreDNS, registry, ArgoCD, Forgejo)
4. Waits for cert-manager to be ready, then applies the ClusterIssuer
5. Waits for ingress-nginx to be ready
6. Restarts CoreDNS to pick up internal DNS config
7. Applies ArgoCD Application definitions (deploys apps via GitOps)
### Step 4: Wait for pods and certificates
```bash
# Watch pods come up (takes 2-5 min)
kubectl get pods -A -w
# Check TLS certificates (takes 1-3 min after pods are up)
kubectl get certificates -A
```
All certificates should show `READY = True`.
### Step 5: Get ArgoCD admin password
```bash
kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath="{.data.password}" | base64 -d && echo
```
Login at https://argocd.szymi.ddns.net with `admin` / above password.
---
## Manual Steps After Fresh Install
These cannot be automated and must be done once:
### Forgejo: Create admin account
1. Open https://git.szymi.ddns.net
2. Complete the setup wizard (first user becomes admin)
3. Create the repositories: `szymiserver`, `nextcloud`, `drawio`
### Forgejo Runner: Register
The runner pod expects `/media/ssd/forgejo/runner-data/` to contain a registered config.
```bash
# Get a runner registration token from Forgejo:
# Site Administration → Actions → Runners → Create new Runner
# Register the runner (exec into the pod):
kubectl exec -it -n forgejo deployment/forgejo-runner -- \
forgejo-runner register \
--instance https://git.szymi.ddns.net \
--token <TOKEN_FROM_FORGEJO> \
--name szymiserver \
--no-interactive
```
---
## Day-to-Day Operations
### Deploying a new app via ArgoCD
1. Create Kubernetes manifests in your app repo (see `drawio` or `nextcloud` repos as examples)
2. Add `nextcloud.szymi.ddns.net` to CoreDNS internal hosts:
```yaml
# k8s/infrastructure/coredns/coredns-custom.yaml
10.96.0.100 newapp.szymi.ddns.net
```
3. Create an ArgoCD Application in `k8s/argocd-apps/newapp.yaml`
4. Push to Forgejo and apply:
```bash
kubectl apply -f k8s/infrastructure/coredns/coredns-custom.yaml
kubectl rollout restart deployment coredns -n kube-system
kubectl apply -f k8s/argocd-apps/newapp.yaml
```
### After server restart (if pods have ImagePullBackOff)
Kind container loses its DNS config on restart:
```bash
docker exec szymicluster-control-plane bash -c 'echo "nameserver 8.8.8.8" > /etc/resolv.conf'
kubectl delete pods -n argocd --all
```
### Checking overall health
```bash
# All pods status
kubectl get pods -A | grep -v Running | grep -v Completed
# Certificate status
kubectl get certificates -A
# ArgoCD app sync status
kubectl get applications -n argocd
```
### Forcing ArgoCD to re-sync
```bash
kubectl patch application <app-name> -n argocd \
--type merge -p '{"metadata":{"annotations":{"argocd.argoproj.io/refresh":"hard"}}}'
```
---
## Architecture
```
Internet
Router (ports 80, 443, 2222 → server)
Linux Host (/media/ssd for persistent data)
kind container (szymicluster-control-plane)
├── ingress-nginx ← routes all HTTP/HTTPS traffic
├── cert-manager ← issues Let's Encrypt TLS certs
├── CoreDNS ← internal DNS (routes *.szymi.ddns.net to ingress)
├── ArgoCD ← watches Forgejo, deploys apps automatically
├── Forgejo ← git server + CI/CD runner
├── Registry ← private Docker image registry
├── Nextcloud ← deployed via ArgoCD
└── Draw.io ← deployed via ArgoCD
```
### Why CoreDNS has internal hosts
cert-manager needs to verify domain ownership via HTTP-01 challenge. Inside the cluster, `*.szymi.ddns.net` would resolve to the external IP, which doesn't route back in. CoreDNS overrides these to point directly to ingress-nginx's fixed ClusterIP (`10.96.0.100`).
---
## File Structure
```
szymiserver/
├── cluster-config.yml # kind cluster definition (run once)
├── RUNBOOK.md # this file
├── k8s/
│ ├── deploy-infrastructure.sh # main deployment script
│ ├── infrastructure/
│ │ ├── kustomization.yaml # applies all infrastructure
│ │ ├── coredns/ # internal DNS overrides
│ │ ├── ingress-nginx/ # ingress controller
│ │ ├── cert-manager/ # TLS certificates
│ │ ├── argocd/ # GitOps controller
│ │ ├── forgejo/ # git server + runner
│ │ └── registry/ # private Docker registry
│ └── argocd-apps/
│ ├── drawio.yaml # ArgoCD app for draw.io
│ └── nextcloud.yaml # ArgoCD app for Nextcloud
```
---
## Persistent Data (on host at /media/ssd)
| Path | Used by |
|------|---------|
| `/media/ssd/forgejo/forgejo-data` | Forgejo repos, config, DB |
| `/media/ssd/forgejo/runner-data` | Runner registration + config |
| `/media/ssd/registry` | Docker image layers |
| `/media/ssd/nextcloud` | Nextcloud files |
| `/media/ssd/mariadb` | Nextcloud database |

17
cluster-config.yml Normal file
View file

@ -0,0 +1,17 @@
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: szymicluster
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 80
hostPort: 80
- containerPort: 443
hostPort: 443
- containerPort: 2222
hostPort: 2222
extraMounts:
- hostPath: /media/ssd
containerPath: /media/ssd
- hostPath: /var/run/docker.sock
containerPath: /var/run/docker.sock

View file

@ -0,0 +1,23 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: drawio
namespace: argocd
spec:
project: default
source:
repoURL: https://git.szymi.ddns.net/szymi/drawio.git
targetRevision: master
path: deployment
destination:
server: https://kubernetes.default.svc
namespace: drawio
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true

View file

@ -0,0 +1,23 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: nextcloud
namespace: argocd
spec:
project: default
source:
repoURL: https://git.szymi.ddns.net/szymi/nextcloud.git
targetRevision: master
path: deployment
destination:
server: https://kubernetes.default.svc
namespace: nextcloud
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true

53
k8s/deploy-infrastructure.sh Executable file
View file

@ -0,0 +1,53 @@
#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR/.."
echo "=== Deploying Infrastructure ==="
echo "0. Fixing kind container DNS (prevents ImagePullBackOff on IPv6-only DNS)..."
docker exec szymicluster-control-plane bash -c 'echo "nameserver 8.8.8.8" > /etc/resolv.conf'
echo "1. Creating required host data directories..."
mkdir -p /media/ssd/forgejo/forgejo-data
mkdir -p /media/ssd/forgejo/runner-data
mkdir -p /media/ssd/registry
echo "2. Applying main infrastructure (coredns, ingress-nginx, cert-manager, registry, argocd, forgejo)..."
kubectl apply -k k8s/infrastructure/
echo "3. Waiting for cert-manager to be ready..."
kubectl wait --namespace cert-manager \
--for=condition=ready pod \
--selector=app.kubernetes.io/instance=cert-manager \
--timeout=120s
echo "4. Applying ClusterIssuer for Let's Encrypt..."
kubectl apply -f k8s/infrastructure/cert-manager/cluster-issuer.yaml
echo "5. Waiting for ingress-nginx to be ready..."
kubectl wait --namespace ingress-nginx \
--for=condition=ready pod \
--selector=app.kubernetes.io/component=controller \
--timeout=120s
echo "6. Restarting CoreDNS to pick up internal DNS config..."
kubectl rollout restart deployment coredns -n kube-system
kubectl rollout status deployment coredns -n kube-system --timeout=60s
echo "7. Applying ArgoCD applications..."
kubectl apply -f k8s/argocd-apps/
echo "=== Infrastructure deployment complete ==="
echo ""
echo "Checking certificate status (may take a few minutes to issue):"
kubectl get certificates -A
echo ""
echo "To check challenge status: kubectl get challenges -A"
echo "To check pods: kubectl get pods -A"
echo ""
echo "Services accessible at:"
echo " - https://git.szymi.ddns.net (Forgejo)"
echo " - https://argocd.szymi.ddns.net (ArgoCD)"
echo " - https://registry.szymi.ddns.net (Docker Registry)"

View file

@ -0,0 +1,26 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argocd-server
namespace: argocd
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
ingressClassName: nginx
tls:
- hosts:
- argocd.szymi.ddns.net
secretName: argocd-tls
rules:
- host: argocd.szymi.ddns.net
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: argocd-server
port:
name: https

View file

@ -0,0 +1,9 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: argocd
resources:
- namespace.yaml
- https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
- ingress.yaml

View file

@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: argocd

View file

@ -0,0 +1,14 @@
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@szymi.ddns.net
privateKeySecretRef:
name: letsencrypt-prod-account-key
solvers:
- http01:
ingress:
class: nginx

View file

@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- https://github.com/cert-manager/cert-manager/releases/download/v1.14.4/cert-manager.yaml

View file

@ -0,0 +1,38 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
ready
hosts {
10.96.0.100 git.szymi.ddns.net
10.96.0.100 argocd.szymi.ddns.net
10.96.0.100 registry.szymi.ddns.net
10.96.0.100 drawio.szymi.ddns.net
10.96.0.100 nextcloud.szymi.ddns.net
fallthrough
}
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf {
max_concurrent 1000
}
cache 30 {
disable success cluster.local
disable denial cluster.local
}
loop
reload
loadbalance
}

View file

@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- coredns-custom.yaml

View file

@ -0,0 +1,55 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: forgejo
namespace: forgejo
spec:
replicas: 1
selector:
matchLabels:
app: forgejo
template:
metadata:
labels:
app: forgejo
spec:
containers:
- name: forgejo
image: codeberg.org/forgejo/forgejo:11
ports:
- containerPort: 3000
name: http
- containerPort: 22
name: ssh
hostPort: 2222
volumeMounts:
- name: forgejo-data
mountPath: /data
env:
- name: USER_UID
value: "1000"
- name: USER_GID
value: "1000"
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "1Gi"
cpu: "1000m"
livenessProbe:
httpGet:
path: /api/healthz
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /api/healthz
port: 3000
initialDelaySeconds: 5
periodSeconds: 5
volumes:
- name: forgejo-data
persistentVolumeClaim:
claimName: forgejo-pvc

View file

@ -0,0 +1,24 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: forgejo
namespace: forgejo
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- git.szymi.ddns.net
secretName: forgejo-tls
rules:
- host: git.szymi.ddns.net
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: forgejo
port:
number: 3000

View file

@ -0,0 +1,10 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- pv.yaml
- deployment.yaml
- service.yaml
- ingress.yaml
- runner-deployment.yaml

View file

@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: forgejo

View file

@ -0,0 +1,35 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: forgejo-pv
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: local-storage
local:
path: /media/ssd/forgejo/forgejo-data
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- szymicluster-control-plane
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: forgejo-pvc
namespace: forgejo
spec:
accessModes:
- ReadWriteOnce
storageClassName: local-storage
resources:
requests:
storage: 50Gi
volumeName: forgejo-pv

View file

@ -0,0 +1,50 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: forgejo-runner
namespace: forgejo
spec:
replicas: 1
selector:
matchLabels:
app: forgejo-runner
template:
metadata:
labels:
app: forgejo-runner
spec:
containers:
- name: runner
image: code.forgejo.org/forgejo/runner:6
command:
- forgejo-runner
- daemon
- --config
- /data/config.yaml
env:
- name: ACT_RUNNER_APPEND_RUN_ARGS
value: "-v /var/run/docker.sock:/var/run/docker.sock"
volumeMounts:
- name: runner-data
mountPath: /data
- name: docker-sock
mountPath: /var/run/docker.sock
securityContext:
runAsUser: 0
privileged: true
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
volumes:
- name: runner-data
hostPath:
path: /media/ssd/forgejo/runner-data
type: Directory
- name: docker-sock
hostPath:
path: /var/run/docker.sock
type: Socket

View file

@ -0,0 +1,12 @@
apiVersion: v1
kind: Service
metadata:
name: forgejo
namespace: forgejo
spec:
selector:
app: forgejo
ports:
- name: http
port: 3000
targetPort: 3000

View file

@ -0,0 +1,582 @@
apiVersion: v1
kind: Namespace
metadata:
name: ingress-nginx
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx
namespace: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- apiGroups:
- ""
resources:
- configmaps
- pods
- secrets
- endpoints
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- networking.k8s.io
resources:
- ingressclasses
verbs:
- get
- list
- watch
- apiGroups:
- coordination.k8s.io
resources:
- leases
resourceNames:
- ingress-nginx-leader
verbs:
- get
- update
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- create
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- list
- watch
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission
namespace: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
- namespaces
verbs:
- list
- watch
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- networking.k8s.io
resources:
- ingressclasses
verbs:
- get
- list
- watch
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- list
- watch
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission
rules:
- apiGroups:
- admissionregistration.k8s.io
resources:
- validatingwebhookconfigurations
verbs:
- get
- update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx
namespace: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ingress-nginx
subjects:
- kind: ServiceAccount
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission
namespace: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ingress-nginx-admission
subjects:
- kind: ServiceAccount
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ingress-nginx
subjects:
- kind: ServiceAccount
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ingress-nginx-admission
subjects:
- kind: ServiceAccount
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: v1
data:
allow-snippet-annotations: "false"
kind: ConfigMap
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-controller
namespace: ingress-nginx
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
clusterIP: 10.96.0.100
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- appProtocol: http
name: http
port: 80
protocol: TCP
targetPort: http
- appProtocol: https
name: https
port: 443
protocol: TCP
targetPort: https
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
type: NodePort
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-controller-admission
namespace: ingress-nginx
spec:
ports:
- appProtocol: https
name: https-webhook
port: 443
targetPort: webhook
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
minReadySeconds: 0
revisionHistoryLimit: 10
selector:
matchLabels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
template:
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
spec:
containers:
- args:
- /nginx-ingress-controller
- --election-id=ingress-nginx-leader
- --controller-class=k8s.io/ingress-nginx
- --ingress-class=nginx
- --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
- --validating-webhook=:8443
- --validating-webhook-certificate=/usr/local/certificates/cert
- --validating-webhook-key=/usr/local/certificates/key
- --watch-ingress-without-class=true
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: LD_PRELOAD
value: /usr/local/lib/libmimalloc.so
image: registry.k8s.io/ingress-nginx/controller:v1.9.5
imagePullPolicy: IfNotPresent
lifecycle:
preStop:
exec:
command:
- /wait-shutdown
livenessProbe:
failureThreshold: 5
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
name: controller
ports:
- containerPort: 80
hostPort: 80
name: http
protocol: TCP
- containerPort: 443
hostPort: 443
name: https
protocol: TCP
- containerPort: 8443
name: webhook
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
resources:
requests:
cpu: 100m
memory: 90Mi
securityContext:
allowPrivilegeEscalation: true
capabilities:
add:
- NET_BIND_SERVICE
drop:
- ALL
runAsUser: 101
volumeMounts:
- mountPath: /usr/local/certificates/
name: webhook-cert
readOnly: true
dnsPolicy: ClusterFirst
nodeSelector:
kubernetes.io/os: linux
serviceAccountName: ingress-nginx
terminationGracePeriodSeconds: 300
volumes:
- name: webhook-cert
secret:
secretName: ingress-nginx-admission
---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: nginx
spec:
controller: k8s.io/ingress-nginx
---
apiVersion: batch/v1
kind: Job
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission-create
namespace: ingress-nginx
spec:
template:
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission-create
spec:
containers:
- args:
- create
- --host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc
- --namespace=$(POD_NAMESPACE)
- --secret-name=ingress-nginx-admission
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20231011-8b53cabe0
imagePullPolicy: IfNotPresent
name: create
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 2000
nodeSelector:
kubernetes.io/os: linux
restartPolicy: OnFailure
securityContext:
fsGroup: 2000
runAsNonRoot: true
runAsUser: 2000
serviceAccountName: ingress-nginx-admission
---
apiVersion: batch/v1
kind: Job
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission-patch
namespace: ingress-nginx
spec:
template:
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission-patch
spec:
containers:
- args:
- patch
- --webhook-name=ingress-nginx-admission
- --namespace=$(POD_NAMESPACE)
- --patch-mutating=false
- --secret-name=ingress-nginx-admission
- --patch-failure-policy=Fail
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20231011-8b53cabe0
imagePullPolicy: IfNotPresent
name: patch
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 2000
nodeSelector:
kubernetes.io/os: linux
restartPolicy: OnFailure
securityContext:
fsGroup: 2000
runAsNonRoot: true
runAsUser: 2000
serviceAccountName: ingress-nginx-admission

View file

@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ingress-nginx.yaml

View file

@ -0,0 +1,10 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- coredns/
- ingress-nginx/
- cert-manager/
- registry/
- argocd/
- forgejo/

View file

@ -0,0 +1,9 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- registry-namespace.yaml
- registry-pv.yaml
- registry-deployment.yaml
- registry-service.yaml
- registry-ingress.yaml

View file

@ -0,0 +1,55 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: registry
namespace: registry
labels:
app: registry
spec:
replicas: 1
selector:
matchLabels:
app: registry
template:
metadata:
labels:
app: registry
spec:
containers:
- name: registry
image: registry:3.0
ports:
- containerPort: 5000
name: registry
protocol: TCP
env:
- name: REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY
value: /var/lib/registry
- name: REGISTRY_STORAGE_DELETE_ENABLED
value: "true"
volumeMounts:
- name: registry-data
mountPath: /var/lib/registry
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /
port: 5000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 5000
initialDelaySeconds: 5
periodSeconds: 5
volumes:
- name: registry-data
persistentVolumeClaim:
claimName: registry-pvc

View file

@ -0,0 +1,27 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: registry
namespace: registry
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/proxy-body-size: "0"
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
spec:
ingressClassName: nginx
tls:
- hosts:
- registry.szymi.ddns.net
secretName: registry-tls
rules:
- host: registry.szymi.ddns.net
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: registry
port:
number: 5000

View file

@ -0,0 +1,6 @@
apiVersion: v1
kind: Namespace
metadata:
name: registry
labels:
name: registry

View file

@ -0,0 +1,40 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: registry-pv
labels:
app: registry
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: local-storage
hostPath:
path: /media/ssd/image-registry
type: DirectoryOrCreate
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- szymicluster-control-plane
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: registry-pvc
namespace: registry
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
storageClassName: local-storage
selector:
matchLabels:
app: registry

View file

@ -0,0 +1,16 @@
apiVersion: v1
kind: Service
metadata:
name: registry
namespace: registry
labels:
app: registry
spec:
type: ClusterIP
ports:
- port: 5000
targetPort: 5000
protocol: TCP
name: registry
selector:
app: registry