Compare commits

...

10 Commits

Author SHA1 Message Date
625c9c2367 fix(gitea-runner): use Docker-in-Docker sidecar
K3S uses containerd, not Docker. Use DinD sidecar container
to provide Docker daemon for the runner.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 20:40:29 +09:00
fa63d0f86a feat: add Gitea credentials and Actions runner
- Add gitea-creds ExternalSecret for ArgoCD authentication to Gitea
- Enable Gitea Actions in helm-values.yaml
- Add gitea-runner deployment for CI/CD

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 20:38:03 +09:00
5d54ee767a REFACTOR(argocd): separate image-updater manifests
- Move ExternalSecrets to image-updater-manifests folder
- Add manifests source to image-updater Application
- Remove unnecessary ignoreDifferences from argocd
2026-01-10 20:05:43 +09:00
b174afbc0d FIX(argocd): add ignoreDifferences for API defaults
- Ignore ExternalSecret default values from API server
- Ignore ServiceMonitor metric relabelings
2026-01-10 20:03:07 +09:00
e7f97888cc REFACTOR(cert-manager): move to security repo
- Remove cert-manager folder
- Update kustomization references
2026-01-10 19:58:03 +09:00
ad591293f1 CHORE(traefik): disable dashboard
- Remove dashboard and api.dashboard settings
- Remove --api.insecure argument
- Keep core settings (DaemonSet, metrics, crossNamespace)
2026-01-10 19:52:46 +09:00
b650c0af56 REFACTOR(argocd): merge priority-classes into argocd
- Move priority-classes to argocd/manifests
- Remove separate priority-classes Application
- Simplify platform folder structure
2026-01-10 19:47:30 +09:00
81c42f67e9 REFACTOR(argocd): merge image-updater into argocd
- Move image-updater Application to argocd folder
- Move helm-values and secrets to argocd
- Remove separate argocd-image-updater folder
- Update kustomization references
2026-01-10 19:44:02 +09:00
121d5eb198 REFACTOR(gitea): move from applications repo
- Add gitea Application manifests
- Update repoURL to reference platform repo
- Include helm-values, kustomization, redirect configs
2026-01-10 19:38:35 +09:00
c31046a322 REFACTOR(traefik): remove control-plane scheduling
- Remove tolerations for control-plane taint
- Remove svclb tolerations annotation
- Allow pods to schedule on any available node
2026-01-10 18:35:15 +09:00
19 changed files with 399 additions and 177 deletions

View File

@@ -1,6 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- argocd.yaml
- manifests/secret.yaml

View File

@@ -48,3 +48,35 @@ spec:
remoteRef: remoteRef:
key: github key: github
property: password property: password
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: gitea-creds
namespace: argocd
spec:
refreshInterval: 1h
secretStoreRef:
kind: ClusterSecretStore
name: vault-backend
target:
name: gitea-creds
creationPolicy: Owner
template:
metadata:
labels:
argocd.argoproj.io/secret-type: repo-creds
data:
type: git
url: https://github0213.com
username: "{{ .username }}"
password: "{{ .password }}"
data:
- secretKey: username
remoteRef:
key: gitea
property: username
- secretKey: password
remoteRef:
key: gitea
property: password

View File

@@ -11,13 +11,13 @@ spec:
targetRevision: 0.11.0 targetRevision: 0.11.0
helm: helm:
valueFiles: valueFiles:
- $values/argocd-image-updater/helm-values.yaml - $values/argocd/image-updater-values.yaml
- repoURL: https://github.com/K3S-HOME/platform.git - repoURL: https://github.com/K3S-HOME/platform.git
targetRevision: main targetRevision: main
ref: values ref: values
- repoURL: https://github.com/K3S-HOME/platform.git - repoURL: https://github.com/K3S-HOME/platform.git
targetRevision: main targetRevision: main
path: argocd-image-updater/manifests path: argocd/image-updater-manifests
destination: destination:
server: https://kubernetes.default.svc server: https://kubernetes.default.svc
namespace: argocd namespace: argocd

View File

@@ -3,6 +3,9 @@ kind: Kustomization
resources: resources:
# ArgoCD Application (self-managed via Helm chart) # ArgoCD Application (self-managed via Helm chart)
- argocd.yaml - argocd.yaml
# ArgoCD Image Updater Application
- image-updater.yaml
# Additional manifests (applied alongside Helm chart) # Additional manifests (applied alongside Helm chart)
- manifests/namespace.yaml - manifests/namespace.yaml
- manifests/webhook-ingress.yaml - manifests/webhook-ingress.yaml
- manifests/priority-classes.yaml

View File

@@ -1,70 +0,0 @@
# Cert-Manager Helm Values
# Chart: https://github.com/cert-manager/cert-manager/tree/master/deploy/charts/cert-manager
# Install CRDs with Helm
installCRDs: true
replicaCount: 1
resources:
requests:
cpu: 23m
memory: 115Mi
limits:
memory: 115Mi
webhook:
replicaCount: 1
resources:
requests:
cpu: 23m
memory: 115Mi
limits:
memory: 115Mi
# Affinity - Soft Anti-Affinity to spread pods across nodes
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app.kubernetes.io/name: cert-manager-webhook
topologyKey: kubernetes.io/hostname
cainjector:
replicaCount: 1
resources:
requests:
cpu: 23m
memory: 230Mi
limits:
memory: 230Mi
# Affinity - Soft Anti-Affinity to spread pods across nodes
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app.kubernetes.io/name: cert-manager-cainjector
topologyKey: kubernetes.io/hostname
# Affinity - Soft Anti-Affinity to spread pods across nodes
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app.kubernetes.io/name: cert-manager
topologyKey: kubernetes.io/hostname
# Prometheus metrics
prometheus:
enabled: true
servicemonitor:
enabled: false

View File

@@ -1,41 +0,0 @@
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
# Let's Encrypt Production 서버
# 실제 운영 환경에서 사용
# Rate limit: 50 certificates per registered domain per week
server: https://acme-v02.api.letsencrypt.org/directory
# 인증서 만료 알림을 받을 이메일 주소
email: bluemayne0213@icloud.com
# ACME 계정의 private key를 저장할 Secret 이름
privateKeySecretRef:
name: letsencrypt-prod
# HTTP-01 challenge를 사용하여 도메인 소유권 검증
# Traefik Ingress를 통해 /.well-known/acme-challenge/ 경로로 검증
solvers:
- http01:
ingress:
class: traefik
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
# Let's Encrypt Staging 서버
# 테스트용 - 브라우저에서 신뢰하지 않지만 rate limit 없음
server: https://acme-staging-v02.api.letsencrypt.org/directory
email: bluemayne0213@icloud.com
privateKeySecretRef:
name: letsencrypt-staging
solvers:
- http01:
ingress:
class: traefik

28
gitea-runner/argocd.yaml Normal file
View File

@@ -0,0 +1,28 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: gitea-actions-runner
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: https://github.com/K3S-HOME/platform.git
targetRevision: main
path: gitea-runner/manifests
destination:
server: https://kubernetes.default.svc
namespace: gitea
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m

View File

@@ -0,0 +1,97 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: gitea-runner
namespace: gitea
labels:
app: gitea-runner
spec:
replicas: 1
selector:
matchLabels:
app: gitea-runner
template:
metadata:
labels:
app: gitea-runner
spec:
containers:
# Docker-in-Docker sidecar
- name: dind
image: docker:dind
securityContext:
privileged: true
env:
- name: DOCKER_TLS_CERTDIR
value: ""
volumeMounts:
- name: docker-graph
mountPath: /var/lib/docker
resources:
requests:
cpu: 100m
memory: 512Mi
limits:
memory: 2Gi
# Gitea Actions Runner
- name: runner
image: gitea/act_runner:latest
command:
- sh
- -c
- |
# Wait for Docker to be ready
echo "Waiting for Docker daemon..."
while ! docker info > /dev/null 2>&1; do
sleep 2
done
echo "Docker is ready!"
# Wait for Gitea to be ready
while ! wget -q --spider http://gitea-http.gitea.svc:3000/api/v1/version; do
echo "Waiting for Gitea to be ready..."
sleep 5
done
echo "Gitea is ready!"
# Register runner if not already registered
if [ ! -f /data/.runner ]; then
act_runner register --no-interactive \
--instance https://github0213.com \
--token $(cat /secrets/token) \
--name k3s-runner \
--labels k3s-home:docker://node:20-alpine,ubuntu-latest:docker://ubuntu:latest,arm64:host
fi
act_runner daemon
env:
- name: GITEA_INSTANCE_URL
value: "https://github0213.com"
- name: DOCKER_HOST
value: "tcp://localhost:2375"
volumeMounts:
- name: runner-data
mountPath: /data
- name: runner-secret
mountPath: /secrets
readOnly: true
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
memory: 1Gi
volumes:
- name: docker-graph
emptyDir: {}
- name: runner-data
emptyDir: {}
- name: runner-secret
secret:
secretName: gitea-runner-secret
nodeSelector:
node-role.kubernetes.io/control-plane: "true"
tolerations:
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule

View File

@@ -0,0 +1,18 @@
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: gitea-runner-secret
namespace: gitea
spec:
refreshInterval: 1h
secretStoreRef:
kind: ClusterSecretStore
name: vault-backend
target:
name: gitea-runner-secret
creationPolicy: Owner
data:
- secretKey: token
remoteRef:
key: gitea
property: runner_token

View File

@@ -1,28 +1,28 @@
apiVersion: argoproj.io/v1alpha1 apiVersion: argoproj.io/v1alpha1
kind: Application kind: Application
metadata: metadata:
name: cert-manager name: gitea
namespace: argocd namespace: argocd
finalizers: finalizers:
- resources-finalizer.argocd.argoproj.io - resources-finalizer.argocd.argoproj.io
spec: spec:
project: default project: default
sources: sources:
- repoURL: https://charts.jetstack.io - repoURL: https://dl.gitea.com/charts/
chart: cert-manager chart: gitea
targetRevision: v1.16.2 targetRevision: 12.4.0
helm: helm:
valueFiles: valueFiles:
- $values/cert-manager/helm-values.yaml - $values/gitea/helm-values.yaml
- repoURL: https://github.com/K3S-HOME/platform.git - repoURL: https://github.com/K3S-HOME/platform.git
targetRevision: main targetRevision: main
ref: values ref: values
- repoURL: https://github.com/K3S-HOME/platform.git - repoURL: https://github.com/K3S-HOME/platform.git
targetRevision: main targetRevision: main
path: cert-manager path: gitea
destination: destination:
server: https://kubernetes.default.svc server: https://kubernetes.default.svc
namespace: cert-manager namespace: gitea
syncPolicy: syncPolicy:
automated: automated:
prune: true prune: true
@@ -38,7 +38,4 @@ spec:
duration: 5s duration: 5s
factor: 2 factor: 2
maxDuration: 3m maxDuration: 3m
managedNamespaceMetadata:
labels:
goldilocks.fairwinds.com/enabled: 'true'
revisionHistoryLimit: 10 revisionHistoryLimit: 10

137
gitea/helm-values.yaml Normal file
View File

@@ -0,0 +1,137 @@
# Gitea Helm Chart Values
# Self-contained deployment with SQLite and local-path storage
# =============================================================================
# DISABLE ALL EXTERNAL DEPENDENCIES
# =============================================================================
postgresql-ha:
enabled: false
postgresql:
enabled: false
valkey-cluster:
enabled: false
valkey:
enabled: false
# =============================================================================
# PERSISTENCE - local-path StorageClass
# =============================================================================
persistence:
enabled: true
create: true
mount: true
size: 10Gi
accessModes:
- ReadWriteOnce
storageClass: local-path-retain
annotations:
helm.sh/resource-policy: keep
# =============================================================================
# ADMIN USER
# =============================================================================
gitea:
admin:
existingSecret: gitea-admin-secret
username: Mayne0213
email: bluemayne0213@icloud.com
passwordMode: keepUpdated
# Gitea configuration (app.ini)
config:
APP_NAME: Gitea - K3S-HOME
server:
DOMAIN: github0213.com
ROOT_URL: https://github0213.com
HTTP_PORT: 3000
SSH_DOMAIN: github0213.com
SSH_PORT: 22
SSH_LISTEN_PORT: 2222
LFS_START_SERVER: true
database:
DB_TYPE: sqlite3
PATH: /data/gitea/gitea.db
SQLITE_TIMEOUT: 500
SQLITE_JOURNAL_MODE: WAL
session:
PROVIDER: memory
cache:
ADAPTER: memory
queue:
TYPE: level
security:
INSTALL_LOCK: true
service:
DISABLE_REGISTRATION: false
REQUIRE_SIGNIN_VIEW: false
DEFAULT_KEEP_EMAIL_PRIVATE: true
log:
MODE: console
LEVEL: info
actions:
ENABLED: true
DEFAULT_ACTIONS_URL: github
# =============================================================================
# INGRESS
# =============================================================================
ingress:
enabled: true
className: traefik
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: github0213.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: github-tls
hosts:
- github0213.com
# =============================================================================
# RESOURCES
# =============================================================================
resources:
requests:
cpu: 63m
memory: 237Mi
limits:
memory: 237Mi
# =============================================================================
# POD CONFIGURATION
# =============================================================================
strategy:
type: Recreate
tolerations:
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
nodeSelector:
node-role.kubernetes.io/control-plane: "true"
priorityClassName: high-priority
# =============================================================================
# SSH SERVICE
# =============================================================================
service:
ssh:
type: ClusterIP
port: 22

View File

@@ -1,4 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1 apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization kind: Kustomization
resources: resources:
- manifests/cluster-issuer.yaml - redirect.yaml
namespace: gitea

70
gitea/redirect.yaml Normal file
View File

@@ -0,0 +1,70 @@
# Traefik Middleware for GitHub redirect
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: redirect-to-github
namespace: gitea
spec:
redirectRegex:
regex: ".*"
replacement: "https://github.com/mayne0213"
permanent: true
---
# IngressRoute for HTTPS
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: gitea-redirect-https
namespace: gitea
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
entryPoints:
- websecure
routes:
- match: Host(`gitea0213.kro.kr`) || Host(`www.gitea0213.kro.kr`)
kind: Rule
middlewares:
- name: redirect-to-github
services:
- name: noop@internal
kind: TraefikService
tls:
secretName: gitea-tls
domains:
- main: gitea0213.kro.kr
sans:
- www.gitea0213.kro.kr
---
# IngressRoute for HTTP (redirect to HTTPS first, then to GitHub)
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: gitea-redirect-http
namespace: gitea
spec:
entryPoints:
- web
routes:
- match: Host(`gitea0213.kro.kr`) || Host(`www.gitea0213.kro.kr`)
kind: Rule
middlewares:
- name: redirect-to-github
services:
- name: noop@internal
kind: TraefikService
---
# Certificate for TLS
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: gitea-certificate
namespace: gitea
spec:
secretName: gitea-tls
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- gitea0213.kro.kr
- www.gitea0213.kro.kr

View File

@@ -6,8 +6,8 @@ resources:
- application.yaml - application.yaml
# Core infrastructure # Core infrastructure
- priority-classes/argocd.yaml
- cert-manager/argocd.yaml
- traefik/argocd.yaml - traefik/argocd.yaml
- argocd-image-updater/argocd.yaml
- argocd/argocd.yaml - argocd/argocd.yaml
- argocd/image-updater.yaml
- gitea/argocd.yaml
- gitea-runner/argocd.yaml

View File

@@ -1,17 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: priority-classes
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/K3S-HOME/platform.git
targetRevision: HEAD
path: priority-classes/manifests
destination:
server: https://kubernetes.default.svc
syncPolicy:
automated:
prune: true
selfHeal: true

View File

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

View File

@@ -28,39 +28,17 @@ spec:
app.kubernetes.io/name: traefik app.kubernetes.io/name: traefik
topologyKey: kubernetes.io/hostname topologyKey: kubernetes.io/hostname
# Control-plane 노드에도 배치 허용
tolerations:
- key: node-role.kubernetes.io/control-plane
operator: Exists
# Traefik Dashboard 활성화
dashboard:
enabled: true
# API 활성화 (Dashboard에서 필요)
api:
dashboard: true
# Cross-namespace middleware 허용 # Cross-namespace middleware 허용
providers: providers:
kubernetesCRD: kubernetesCRD:
allowCrossNamespace: true allowCrossNamespace: true
# CLI 추가 인자
additionalArguments:
- "--api.insecure=true"
# ports 설정 # ports 설정
ports: ports:
traefik: traefik:
expose: expose:
default: true default: true
# svclb tolerations for control-plane node
service:
annotations:
svccontroller.k3s.cattle.io/tolerations: '[{"key":"node-role.kubernetes.io/control-plane","operator":"Exists","effect":"NoSchedule"}]'
# Prometheus metrics # Prometheus metrics
metrics: metrics:
prometheus: prometheus: