ArgoCD가 GitLab repo를 읽기 시작한 뒤, 일반 앱을 바로 올리기 전에 기본 운영 구성을 먼저 정리함.
구축 매뉴얼 기준으로 11장부터 13장까지 진행.
- Monitoring / Logging / Alerting
- 앱 배포와 namespace 구조
- Storage / PV / PVC / NFS / 백업 구조
먼저 관측 스택.
앱이 떠 있는지만 보는 걸로는 부족해서 metrics, logs, alerts를 나눠서 구성함.
Monitoring
= Prometheus, Grafana, kube-state-metrics, node-exporter
Logging
= Loki, Fluent Bit, Grafana
Alerting
= PrometheusRule, Alertmanager, Telegram
흐름은 대충 이 구조.
[Metrics]
Node / Pod / App
-> Prometheus
-> Grafana
[Logs]
Pod / Container logs
-> Fluent Bit
-> Loki
-> Grafana
[Alerts]
PrometheusRule
-> Prometheus
-> Alertmanager
-> Telegram
일반 앱보다 관측 스택을 먼저 올림.
문제가 생겼을 때 Pod 상태, 로그, 알림을 볼 수 있어야 하기 때문.
중요한 순서.
1. monitoring namespace와 Secret 준비
2. kube-prometheus-stack CRD 선설치
3. monitoring Application sync
4. Loki PV/PVC 준비
5. Loki sync
6. Loki ready 확인
7. Fluent Bit sync
8. PrometheusRule / AlertmanagerConfig / ScrapeConfig 반영
9. Prometheus, Loki, Alertmanager 검증
monitoring Application 설정 확인.
# monitoring Application Helm values에 crds.enabled=false와 ServerSideApply=true가 있는지 확인한다.
cd /home/ioniere/gitlab-project-clones/ioniere/cluster-apps
grep -nE 'values:|crds:|enabled: false|grafana:|ServerSideApply' apps/monitoring.yaml -A4 -B2
kube-prometheus-stack의 CRD는 크기가 커서 일반 apply로 처리하면 annotation 크기 문제가 날 수 있음.
그래서 CRD는 server-side apply로 먼저 넣고, Helm chart 쪽에서는 CRD 설치를 끔.
monitoring namespace 생성.
# monitoring namespace를 먼저 생성한다.
kubectl create namespace monitoring --dry-run=client -o yaml | kubectl apply -f -
monitoring 쪽 Secret은 SOPS로 복구.
값은 출력하지 않음.
대상은 Grafana admin, Alertmanager Telegram Secret.
그 다음 ArgoCD에서 monitoring, loki, fluent-bit 순서로 sync.
Loki가 준비되기 전에 Fluent Bit을 먼저 올리면 로그 전송 실패가 쌓일 수 있어서 순서를 나눔.
Loki ready 확인.
# Loki가 ready 상태인지 확인한다.
kubectl -n monitoring get pods -l app.kubernetes.io/name=loki
# Loki ready endpoint를 확인한다.
kubectl -n monitoring port-forward svc/loki 3100:3100
# Loki ready 응답을 확인한다.
curl -sS http://127.0.0.1:3100/ready
이제 앱 배포 구조 정리.
ArgoCD root Application이 child Application을 만들고, child Application이 실제 앱을 배포하는 구조.
cluster-apps repo
-> bootstrap/root-application.yaml
-> ArgoCD root Application
-> apps/*.yaml
-> child Application
-> 각 앱 namespace
-> Deployment / StatefulSet / Service / Ingress / PVC
앱이 뜨려면 Application만 있어서는 부족함.
먼저 재료가 있어야 함.
namespace
registry Secret
app Secret
PV/PVC 또는 NFS 저장소
Deployment / StatefulSet
Service
Ingress
root Application과 child Application 확인.
# root Application과 child Application 생성 상태를 확인한다.
kubectl -n argocd get applications.argoproj.io \
-o custom-columns=NAME:.metadata.name,SYNC:.status.sync.status,HEALTH:.status.health.status,REVISION:.status.sync.revision
일반 앱 namespace.
3004-uptime-kuma
3007-japan
3008-bingbingsubway
3009-yeonghoon-kim
3035-mbti-mini
money
waf-dashboard
앱 Helm values에는 namespace.create=false로 둔 경우가 있음.
즉, chart가 namespace를 만들지 않고 운영자가 먼저 namespace를 준비하는 방식.
namespace.create=false
= 앱 chart가 namespace를 만들지 않음
= sync 전에 namespace를 먼저 준비해야 함
Secret도 두 종류로 나눠서 봄.
registry Secret
= private registry에서 image를 받기 위한 인증 정보
app Secret
= 앱 실행에 필요한 DB password, app key, token 등
registry Secret이 없으면 이미지를 못 받아서 ImagePullBackOff가 날 수 있음.
app Secret이 없으면 이미지는 받았는데 앱이 DB 접속 실패 등으로 죽을 수 있음.
마지막으로 저장소 구조 정리.
Kubernetes에서 Pod는 언제든 다시 만들어질 수 있음.
그래서 DB, CMS 파일, Loki 데이터, Uptime Kuma 같은 데이터는 Pod 안에만 두면 안 됨.
이 환경에서는 주로 DGX host의 NFS 경로를 사용.
NFS root
= /mnt/k8s-nfs
daily backup root
= /backup/dgx/daily
구조는 이렇게 봄.
Pod
-> PVC
-> PV
-> NFS /mnt/k8s-nfs
-> backup /backup/dgx/daily
-> 원격지 백업서버
NFS와 백업 경로 확인.
# NFS root와 daily backup root가 존재하고, 어느 디스크에 붙어 있는지 확인한다.
df -h /mnt/k8s-nfs /backup/dgx/daily
# NFS root의 상위 구조를 확인한다. Secret 값이나 민감한 파일 내용은 출력하지 않는다.
find /mnt/k8s-nfs -maxdepth 2 -type d | sort | sed -n '1,80p'
PV/PVC 상태 확인.
# 클러스터 전체 PV 상태를 확인한다.
kubectl get pv
# 모든 namespace의 PVC 상태를 확인한다.
kubectl get pvc -A
PV가 실제 NFS 경로를 가리키는지 확인.
# PV가 어떤 NFS 서버와 경로를 바라보는지 확인한다.
kubectl get pv -o custom-columns=NAME:.metadata.name,STATUS:.status.phase,CLAIM:.spec.claimRef.name,SERVER:.spec.nfs.server,PATH:.spec.nfs.path,RECLAIM:.spec.persistentVolumeReclaimPolicy
중요한 데이터는 PVC/PV가 Bound인지 확인.
Pending이면 저장소가 아직 연결되지 않은 상태라서 앱 sync를 계속 밀면 안 됨.
Stateful 앱은 더 조심해서 봄.
# StatefulSet과 PVC를 함께 확인한다.
kubectl get statefulset -A
kubectl get pvc -A
# 비정상 Pod를 확인한다.
kubectl get pods -A --field-selector=status.phase!=Running,status.phase!=Succeeded