Compare commits

...

2 Commits

Author SHA1 Message Date
forust b752bf88bd feat: add edu_master k8s manifests for k0s migration
ci / lint-prettier (push) Successful in 10s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 5s
ci / validate (push) Successful in 5s
ci / build (push) Successful in 35s
2026-09-06 15:00:51 +02:00
forust 587611ca88 chore: remove empty middlewares blocks from k8s ingresses 2026-09-02 12:17:04 +02:00
22 changed files with 326 additions and 19 deletions
-2
View File
@@ -9,13 +9,11 @@ spec:
routes:
- match: Host(`adguard.forust.xyz`) || Host(`dns.forust.xyz`)
kind: Rule
middlewares:
services:
- name: adguard-service
port: 3000
- match: (Host(`adguard.forust.xyz`) || Host(`dns.forust.xyz`)) && PathPrefix(`/dns-query`)
kind: Rule
middlewares:
services:
- name: adguard-service
port: 3000
-1
View File
@@ -9,7 +9,6 @@ spec:
routes:
- match: Host(`auth.forust.xyz`)
kind: Rule
middlewares:
services:
- name: authentik-server-service
port: 9000
-1
View File
@@ -9,7 +9,6 @@ spec:
routes:
- match: Host(`cmk.forust.xyz`)
kind: Rule
middlewares:
services:
- name: checkmk-service
port: 5000
+4
View File
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: edu-master
+57
View File
@@ -0,0 +1,57 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: playwright-service
namespace: edu-master
labels:
app: edu-master-playwright
spec:
replicas: 1
selector:
matchLabels:
app: edu-master-playwright
template:
metadata:
labels:
app: edu-master-playwright
spec:
containers:
- name: playwright
image: mcr.microsoft.com/playwright:v1.56.0-jammy
imagePullPolicy: IfNotPresent
command:
- npx
- -y
- playwright@1.56.0
- run-server
- --port
- "3000"
- --path
- /ws
ports:
- containerPort: 3000
readinessProbe:
tcpSocket:
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
livenessProbe:
tcpSocket:
port: 3000
initialDelaySeconds: 15
periodSeconds: 20
timeoutSeconds: 3
---
apiVersion: v1
kind: Service
metadata:
name: playwright-service
namespace: edu-master
spec:
selector:
app: edu-master-playwright
ports:
- name: ws
port: 3000
targetPort: 3000
+74
View File
@@ -0,0 +1,74 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace: edu-master
labels:
app: edu-master-redis
spec:
replicas: 1
selector:
matchLabels:
app: edu-master-redis
template:
metadata:
labels:
app: edu-master-redis
spec:
containers:
- name: redis
image: redis:alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 6379
volumeMounts:
- name: redis-data
mountPath: /data
resources:
requests:
cpu: 25m
memory: 64Mi
limits:
cpu: 250m
memory: 256Mi
readinessProbe:
exec:
command: ["redis-cli", "ping"]
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
livenessProbe:
exec:
command: ["redis-cli", "ping"]
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 3
volumes:
- name: redis-data
persistentVolumeClaim:
claimName: redis-data-pvc
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: redis-data-pvc
namespace: edu-master
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: Service
metadata:
name: redis
namespace: edu-master
spec:
selector:
app: edu-master-redis
ports:
- name: redis
port: 6379
targetPort: 6379
@@ -0,0 +1,50 @@
# Разовый Job для переноса состояния redis из docker compose в k8s (maintenance window).
# Файл .example -> deploy-пайплайн его не применяет (маска *.example.yaml).
#
# Runbook:
# 1. docker compose -f <repo>/edu_master/compose.yaml stop # SIGTERM -> redis сбросит dump.rdb
# 2. docker run --rm -v edu_master_redis-data:/data \
# -v /tmp/edu-master-backup:/backup \
# redis:alpine sh -c "cp /data/dump.rdb /backup/ && ls -la /backup"
# 3. kubectl apply -f edu_master/k8s/namespace.yaml
# 4. kubectl apply -f <только PVC из redis.yaml> # seed строго ДО старта redis-пода
# 5. kubectl apply -f edu_master/k8s/restore-seed-job.yaml.example
# kubectl wait --for=condition=complete job/redis-restore-seed -n edu-master --timeout=120s
# 6. kubectl delete job redis-restore-seed -n edu-master
# 7. kubectl apply -f edu_master/k8s/ -R # остальные манифесты
apiVersion: batch/v1
kind: Job
metadata:
name: redis-restore-seed
namespace: edu-master
spec:
backoffLimit: 2
ttlSecondsAfterFinished: 3600
template:
spec:
restartPolicy: Never
containers:
- name: seed
image: redis:alpine
command:
- /bin/sh
- -ec
- |
ls -la /backup
cp /backup/dump.rdb /data/dump.rdb
chmod 644 /data/dump.rdb
ls -la /data
volumeMounts:
- name: redis-data
mountPath: /data
- name: backup
mountPath: /backup
readOnly: true
volumes:
- name: redis-data
persistentVolumeClaim:
claimName: redis-data-pvc
- name: backup
hostPath:
path: /tmp/edu-master-backup
type: DirectoryOrCreate
+26
View File
@@ -0,0 +1,26 @@
apiVersion: v1
kind: Secret
metadata:
name: edu-master-secrets
namespace: edu-master
type: Opaque
stringData:
# PHPSESSID keeper
KEEPER_LOGIN: ""
KEEPER_PASSWORD: ""
KEEPER_INTERVAL: "10"
# EDU links
EDU_URL_BASE: "https://edu.edu.vn.ua"
EDU_URL_LOGIN: "/user/login"
EDU_URL_COURSES: "/course/userlist"
EDU_URL_WEBINAR: "/webinar/useractive"
# Playwright
USER_AGENT: ""
PLAYWRIGHT_WS: "ws://playwright-service:3000/ws"
# Webinar-checker
WEBINAR_TELEGRAM_TOKEN: ""
WEBINAR_ADMIN_ID: ""
WEBINAR_CHECK_INTERVAL: "60"
# Database
REDIS_HOST: "redis"
REDIS_PORT: "6379"
+52
View File
@@ -0,0 +1,52 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: session-keeper
namespace: edu-master
labels:
app: edu-master-session-keeper
spec:
replicas: 1
selector:
matchLabels:
app: edu-master-session-keeper
template:
metadata:
labels:
app: edu-master-session-keeper
spec:
initContainers:
- name: wait-redis
image: redis:alpine
command:
- /bin/sh
- -ec
- |
i=0
until redis-cli -h redis ping | grep -q PONG; do
i=$((i+1))
[ "$i" -ge 300 ] && echo "TIMEOUT: redis not ready" && exit 1
sleep 2
done
echo "redis is ready"
containers:
- name: session-keeper
image: gcr.forust.xyz/forust/session-keeper:latest
imagePullPolicy: Always
envFrom:
- secretRef:
name: edu-master-secrets
resources:
requests:
cpu: 25m
memory: 96Mi
limits:
cpu: 250m
memory: 256Mi
readinessProbe:
exec:
command: ["/bin/sh", "-ec", "redis-cli -h redis EXISTS EDU_PHPSESSID | grep -q 1"]
initialDelaySeconds: 15
periodSeconds: 30
timeoutSeconds: 5
failureThreshold: 10
+59
View File
@@ -0,0 +1,59 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: webinar-checker
namespace: edu-master
labels:
app: edu-master-webinar-checker
spec:
replicas: 1
selector:
matchLabels:
app: edu-master-webinar-checker
template:
metadata:
labels:
app: edu-master-webinar-checker
spec:
initContainers:
# Держит порядок зависимостей как в compose depends_on:
# redis healthy -> session-keeper healthy (EXISTS EDU_PHPSESSID) -> playwright started
- name: wait-deps
image: redis:alpine
command:
- /bin/sh
- -ec
- |
i=0
until redis-cli -h redis ping | grep -q PONG; do
i=$((i+1))
[ "$i" -ge 300 ] && echo "TIMEOUT: redis not ready" && exit 1
sleep 2
done
echo "redis ok"
until [ "$(redis-cli -h redis EXISTS EDU_PHPSESSID)" = "1" ]; do
i=$((i+1))
[ "$i" -ge 300 ] && echo "TIMEOUT: no PHPSESSID (session-keeper down?)" && exit 1
sleep 2
done
echo "PHPSESSID ok"
until nc -z playwright-service 3000; do
i=$((i+1))
[ "$i" -ge 300 ] && echo "TIMEOUT: playwright-service not reachable" && exit 1
sleep 2
done
echo "playwright ok"
containers:
- name: webinar-checker
image: gcr.forust.xyz/forust/webinar-checker:latest
imagePullPolicy: Always
envFrom:
- secretRef:
name: edu-master-secrets
resources:
requests:
cpu: 25m
memory: 128Mi
limits:
cpu: 300m
memory: 384Mi
-2
View File
@@ -9,13 +9,11 @@ spec:
routes:
- match: Host(`gitea.forust.xyz`)
kind: Rule
middlewares:
services:
- name: gitea-service
port: 3000
- match: Host(`gcr.forust.xyz`) && PathPrefix(`/v2`)
kind: Rule
middlewares:
services:
- name: gitea-service
port: 3000
-3
View File
@@ -18,19 +18,16 @@ spec:
routes:
- match: Host(`hs.forust.xyz`)
kind: Rule
middlewares:
services:
- name: headscale-server-external
port: 8080
- match: Host(`hs.forust.xyz`) && PathPrefix(`/admin`)
kind: Rule
middlewares:
services:
- name: headscale-ui-external
port: 80
- match: Host(`hs.forust.xyz`) && PathPrefix(`/metrics`)
kind: Rule
middlewares:
services:
- name: headscale-server-external
port: 9090
-2
View File
@@ -9,7 +9,6 @@ spec:
routes:
- match: Host(`forust.xyz`) || Host(`www.forust.xyz`)
kind: Rule
middlewares:
priority: 10
services:
- name: forust-homepage-service
@@ -44,7 +43,6 @@ spec:
routes:
- match: Host(`xdfnx.cfd`)
kind: Rule
middlewares:
services:
- name: xdfnx-homepage-service
port: 80
-1
View File
@@ -9,7 +9,6 @@ spec:
routes:
- match: Host(`status.forust.xyz`)
kind: Rule
middlewares:
services:
- name: kener-service
port: 3000
-1
View File
@@ -9,7 +9,6 @@ spec:
routes:
- match: Host(`n8n.forust.xyz`)
kind: Rule
middlewares:
services:
- name: n8n-service
port: 5678
-1
View File
@@ -9,7 +9,6 @@ spec:
routes:
- match: Host(`nm.forust.xyz`)
kind: Rule
middlewares:
services:
- name: netronome-service
port: 7575
-1
View File
@@ -9,7 +9,6 @@ spec:
routes:
- match: Host(`portainer.forust.xyz`)
kind: Rule
middlewares:
services:
- name: portainer-service
port: 9000
-1
View File
@@ -9,7 +9,6 @@ spec:
routes:
- match: Host(`s.forust.xyz`) || Host(`search.forust.xyz`)
kind: Rule
middlewares:
services:
- name: searxng-service
port: 8080
-1
View File
@@ -9,7 +9,6 @@ spec:
routes:
- match: Host(`termix.forust.xyz`)
kind: Rule
middlewares:
services:
- name: termix-service
port: 8080
-1
View File
@@ -10,7 +10,6 @@ spec:
routes:
- match: Host(`traefik.forust.xyz`)
kind: Rule
middlewares:
services:
- name: api@internal
kind: TraefikService
-1
View File
@@ -9,7 +9,6 @@ spec:
routes:
- match: Host(`uptime.forust.xyz`)
kind: Rule
middlewares:
services:
- name: uptime-kuma-service
port: 3001
+4
View File
@@ -4,6 +4,8 @@ metadata:
name: vaultwarden-prod
namespace: vaultwarden
spec:
entryPoints:
- websecure
routes:
- match: Host(`vw.forust.xyz`)
kind: Rule
@@ -19,6 +21,8 @@ metadata:
name: vaultwarden-local
namespace: vaultwarden
spec:
entryPoints:
- websecure
routes:
- match: Host(`vw.workstation.internal`) || Host(`vw.gigaforust.internal`)
kind: Rule