Kubernetes 클러스터 구축 가이드 (Ubuntu 22.04, Control-plane 1 + Worker 2)
이 문서는 Ubuntu 22.04(서버 3대)에서 kubeadm + containerd 기반의 쿠버네티스 클러스터를 구축하는 과정을 처음부터 끝까지 순서대로 설명합니다.
- 구성: 총 3대
- Control-plane: 1대
- Worker: 2대
- 컨테이너 런타임: containerd
- 설치 방식: kubeadm
- 네트워크 플러그인: Calico
표기 규칙: 모든 명령은 별도 표기가 없으면 모든 노드(Control-plane/Worker 공통)에서 실행합니다.
<PLACEHOLDER>는 실제 값으로 바꿔 입력하세요.
권장 VM 스펙 (Proxmox/KVM 기준)
- 구성: VM 3대 (Control-plane 1:
cp110.10.0.100, Worker 2:wk110.10.0.101,wk210.10.0.102) - Control-plane 권장: 4 vCPU, 8–16 GB RAM, 60–100 GB SSD/NVMe
- Worker 권장(각각): 4 vCPU, 8–16 GB RAM, 100–200 GB SSD/NVMe
- 가상화 옵션(권장):
- CPU Type: host
- QEMU Guest Agent: 활성화
- Disk Bus: VirtIO SCSI, IO Thread 활성화, SSD Emulation(가능 시)
- NIC Model: VirtIO (Paravirtualized), 브릿지
vmbr0(고정 IP) - MTU: 기본 1500 (특수 네트워크 요구가 없으면 기본 유지)
- 설치/운영 팁:
- Ubuntu 22.04 cloud-init 템플릿으로 VM 생성 후 hostname/IP를 사전 지정
- 아웃바운드 인터넷(apt, 컨테이너 이미지 pull) 가능해야 함
- 시간 동기화(NTP) 활성화, 디스크 성능은 NVMe/SSD 권장
- 고가용성 필요 시 Control-plane을 3대로 확장해 etcd 쿼럼 구성
0) 사전 점검 및 고정 값 준비
이 단계는 모든 노드(Control-plane/Worker)에서 수행합니다.
- 고정 IP와 호스트명(예시)
- Control-plane:
cp1/ 10.10.0.100 - Worker1:
wk1/ 10.10.0.101 - Worker2:
wk2/ 10.10.0.102
- Control-plane:
각 서버에서 호스트명 설정과 /etc/hosts 매핑을 해둡니다.
- 각 노드는 자신의 호스트명으로 설정합니다(
cp1/wk1/wk2). /etc/hosts매핑 내용은 세 노드 모두 동일하게 추가/유지합니다.
sudo hostnamectl set-hostname <HOSTNAME>
cat <<EOF | sudo tee -a /etc/hosts
10.10.0.100 cp1
10.10.0.101 wk1
10.10.0.102 wk2
EOF시간 동기화가 필요하면 chrony 또는 systemd-timesyncd를 활성화하세요.
sudo timedatectl set-ntp true
sudo timedatectl status1) 공통 시스템 준비 (모든 노드)
필수 커널 모듈과 sysctl, 스왑, 방화벽 등을 정리합니다.
sudo apt update
# 커널 모듈 로드 설정
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
# 네트워크 관련 sysctl 설정
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sudo sysctl --system
# 스왑 완전 비활성화 (재부팅 후에도 유지)
sudo sed -i.bak '/\sswap\s/d' /etc/fstab
sudo swapoff -a
# UFW를 사용하지 않는 테스트/내부망 환경이라면 비활성화 (선택)
sudo systemctl stop ufw || true
sudo systemctl disable ufw || true네트워크/보안 정책에 따라 UFW를 유지할 경우, 하단의 “포트/방화벽 참고”를 확인해 필요한 포트를 허용하세요.
2) containerd 설치 및 설정 (모든 노드)
sudo apt install -y containerd
# 기본 설정 파일 생성
sudo mkdir -p /etc/containerd
sudo containerd config default | sudo tee /etc/containerd/config.toml >/dev/null
# cgroup 드라이버를 systemd로 사용 (kubelet과 일치)
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
# 필요 시 sandbox 이미지(파즈 이미지) 명시 (선택)
# sudo sed -i 's#sandbox_image = ".*"#sandbox_image = "registry.k8s.io/pause:3.9"#' /etc/containerd/config.toml
sudo systemctl enable --now containerd
sudo systemctl restart containerd3) Kubernetes 저장소 등록 및 패키지 설치 (모든 노드)
공식 APT 저장소(pkgs.k8s.io)를 등록하고 kubelet, kubeadm, kubectl을 설치합니다.
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | \
sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | \
sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt update
sudo apt install -y kubelet kubeadm kubectl
# 자동 업데이트 방지(권장)
sudo apt-mark hold kubelet kubeadm kubectl버전 트랙(v1.30)은 필요 시 최신 안정 버전으로 교체 가능합니다. 트랙을 바꿀 때는 모든 노드에서 동일하게 적용하세요.
4) Control-plane 초기화 (Control-plane 노드만)
먼저 이미지를 미리 받아두면 최초 초기화 시간이 단축됩니다(선택).
sudo kubeadm config images pull클러스터를 초기화합니다. Calico 기본값과 맞추기 위해 --pod-network-cidr=192.168.0.0/16를 사용합니다.
sudo kubeadm init \
--apiserver-advertise-address=10.10.0.100 \
--pod-network-cidr=192.168.0.0/16성공 시 kubeadm join ... 명령이 출력됩니다. Worker 노드 합류에 사용하므로 복사해 보관하세요.
관리자(kubectl) 설정:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config네트워크 플러그인(CNI) 설치: Calico 사용
# Calico 설치 (안정 릴리스 예: v3.27.x)
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.3/manifests/calico.yaml
# 설치 후, 시스템 파드와 노드 상태를 확인
kubectl get pods -n kube-system -w모든 CoreDNS/Calico 파드가 Running이 되고 Control-plane 노드가 Ready가 되면 다음 단계로 진행합니다.
5) Worker 노드 조인 (각 Worker 노드에서)
Control-plane 초기화 시 출력된 kubeadm join 명령을 각 Worker에서 실행합니다. 예:
sudo kubeadm join 10.10.0.100:6443 --token <TOKEN> \
--discovery-token-ca-cert-hash sha256:<CA_CERT_HASH>토큰이 만료되었거나 잃어버렸다면 Control-plane에서 새 토큰을 생성할 수 있습니다.
# Control-plane에서
kubeadm token create --print-join-command6) 클러스터 상태 확인 (Control-plane)
kubectl get nodes -o wide
kubectl get pods -A3개 노드(Control-plane 1, Worker 2)가 모두 Ready 상태면 구축이 완료되었습니다.
7) 선택/운영상 팁
- 여러 NIC/다중 IP 환경에서 노드 IP를 고정하려면(선택):
echo 'KUBELET_EXTRA_ARGS="--node-ip=<NODE_PRIMARY_IP>"' | sudo tee /etc/default/kubelet
sudo systemctl daemon-reload
sudo systemctl restart kubelet- kubectl 자동완성/alias(선택):
sudo apt install -y bash-completion
echo 'source /usr/share/bash-completion/bash_completion' >> ~/.bashrc
echo 'source <(kubectl completion bash)' >> ~/.bashrc
echo 'alias k=kubectl' >> ~/.bashrc
echo 'complete -o default -F __start_kubectl k' >> ~/.bashrc
exec $SHELL -l- 업그레이드 개요(요약):
- Control-plane에서
sudo apt-mark unhold kubeadm && sudo apt install -y kubeadm && sudo kubeadm upgrade plan && sudo kubeadm upgrade apply v1.xx.y - 각 노드에서
kubelet/kubectl패키지 업데이트 후systemctl restart kubelet - 완료 후 다시
apt-mark hold ...
- Control-plane에서
8) 포트/방화벽 참고 (UFW/외부 방화벽 사용하는 경우)
-
Control-plane 필요 포트(기본):
- 6443/tcp (Kubernetes API 서버)
- 2379-2380/tcp (etcd, Control-plane 내부)
- 10250/tcp (kubelet API)
- 10257/tcp (kube-controller-manager)
- 10259/tcp (kube-scheduler)
-
Worker 필요 포트(기본):
- 10250/tcp (kubelet API)
- 30000-32767/tcp (NodePort 서비스)
내부망 테스트라면 UFW를 끄는 편이 간단합니다. 운영환경에서는 최소 허용 정책으로 필요한 포트만 개방하세요.
9) 문제 해결 및 리셋
- 조인 토큰 재발급:
kubeadm token create --print-join-command - 네트워크 플러그인 재설치 전 정리(주의):
/etc/cni/net.d백업/삭제 후 재적용 - 클러스터 리셋(모든 노드, 신중히):
sudo kubeadm reset -f
sudo systemctl restart containerd
sudo rm -rf ~/.kube
sudo rm -rf /etc/cni/net.d/*필요 시 재부팅 후 다시 1) 공통 시스템 준비 → 2) containerd → 3) 패키지 설치 → 4) 초기화/조인 순으로 재시도하세요.
클러스터 아키텍처 다이어그램
아래 다이어그램은 3대 서버(컨트롤 플레인 1, 워커 2)로 구성된 클러스터에서 Ingress → Service → Pod 경로와 모니터링 스택(Grafana/Prometheus), Calico CNI의 위치를 개략적으로 보여줍니다.
graph LR
subgraph Internet["인터넷"]
User["사용자"]
DNS["DNS: flyqa.me / api.flyqa.me"]
end
User -->|"HTTPS"| DNS
subgraph Cluster["Kubernetes Cluster"]
subgraph IngressNS["ns: ingress-nginx"]
Ingress["Ingress Controller (NGINX)"]
end
subgraph FlyqaNS["ns: flyqa"]
FEsvc["Service: flyqa-frontend :80"]
BEsvc["Service: flyqa-backend :3000"]
FEdep["Deployment: flyqa-frontend"]
BEdep["Deployment: flyqa-backend"]
end
subgraph MonitoringNS["ns: monitoring"]
Grafana[("Grafana")]
Prom[("Prometheus")]
Alert["Alertmanager"]
end
subgraph CP["Node: cp1 (Control-plane)"]
APIServer["kube-apiserver"]
Scheduler["kube-scheduler"]
Controller["kube-controller-manager"]
Etcd[("etcd")]
end
subgraph WK1["Node: wk1 (Worker)"]
kubelet1["kubelet"]
Pods1["Pods (FE/BE)"]
end
subgraph WK2["Node: wk2 (Worker)"]
kubelet2["kubelet"]
Pods2["Pods (FE/BE)"]
end
CNI["CNI: Calico (Overlay)"]
end
DNS -->|"HTTP(S)"| Ingress
Ingress -->|"/ -> 80"| FEsvc
Ingress -->|"/api,/socket.io -> 3000"| BEsvc
FEsvc --> FEdep
BEsvc --> BEdep
Prom -->|"scrape"| kubelet1
Prom -->|"scrape"| kubelet2
Grafana --> Prom
Prom -->|"alerts"| Alert
CNI -.->|"네트워킹"| WK1
CNI -.->|"네트워킹"| WK2간단한 범례: Ingress는 도메인 기반 라우팅을 수행하고, Service는 L4 가상 IP로 파드에 로드밸런싱합니다. Prometheus는 노드/파드 메트릭을 수집하고, Grafana는 이를 시각화합니다. Calico는 노드 간 Pod 네트워킹을 제공합니다.
Fly QA 애플리케이션 배포 가이드 (Kubernetes)
사용 도구 개요와 필요성
- Helm: Kubernetes 패키지 관리자. 복잡한 리소스를 템플릿(차트)으로 묶어 버전/값 관리와 업그레이드를 쉽게 합니다. 모니터링 스택(kube-prometheus-stack), cert-manager 등 반복적 설치를 표준화합니다.
- Ingress Controller: L7(HTTP/HTTPS) 트래픽을 클러스터 내부 Service로 라우팅하는 컨트롤러(NGINX, Traefik 등). 도메인 기반 라우팅, TLS 종료, 리버스 프록시 기능을 제공합니다.
- Grafana: 메트릭/로그/트레이싱 데이터의 시각화 대시보드. Prometheus 데이터를 기반으로 시스템 상태를 직관적으로 모니터링할 수 있습니다.
- Prometheus: 시계열 메트릭 수집/저장 시스템. Kubernetes 컴포넌트/노드/파드의 성능 지표를 스크랩해 저장합니다.
- Alertmanager: Prometheus 경보를 집계/라우팅해 Slack/이메일 등으로 알림을 전송합니다.
- metrics-server:
kubectl top과 HPA의 실시간 리소스 사용량(메모리/CPU)을 제공하는 경량 메트릭 어그리게이터. - cert-manager(선택): TLS 인증서(예: Let’s Encrypt)를 Kubernetes 네이티브 방식으로 자동 발급/갱신해 Ingress에 적용합니다.
아래는 본 저장소의 Fly QA를 Kubernetes에 배포하는 표준 절차입니다. 프론트엔드는 Vite로 빌드된 정적 파일을 Nginx 기반 컨테이너로 서비스하고, 백엔드는 NestJS(Playwright 포함) 이미지를 배포합니다. Ingress는 도메인 라우팅에 사용합니다.
전제: 개인/조직 컨테이너 레지스트리(예: Docker Hub, GHCR, ECR 등) 접근 권한이 있고, 클러스터에 Ingress Controller(예: NGINX Ingress)가 설치되어 있어야 합니다.
A) 환경 변수 설계
백엔드에서 필요로 하는 주요 환경 변수(예시):
PORT(기본 3000)NODE_ENV(production)DATABASE_HOST,DATABASE_PORT,DATABASE_USERNAME,DATABASE_PASSWORD,DATABASE_NAMEREDIS_HOST,REDIS_PORT- 프런트엔드에서 API URL 사용 시:
VITE_API_URL(예: https://api.flyqa.me)
민감 정보는 Kubernetes Secret으로 관리하고, 나머지는 ConfigMap 또는 Deployment env로 주입합니다.
B) 컨테이너 이미지 빌드/푸시
레지스트리 네임스페이스/리포지토리를 다음과 같이 가정합니다.
- 백엔드 이미지:
<REGISTRY>/<NAMESPACE>/fly-qa-backend:<TAG> - 프론트엔드 이미지:
<REGISTRY>/<NAMESPACE>/fly-qa-frontend:<TAG>
- 백엔드 이미지 (Playwright 런타임 포함 Dockerfile 사용)
# 저장소 루트에서
docker build -t <REGISTRY>/<NAMESPACE>/fly-qa-backend:<TAG> -f Dockerfile .
docker push <REGISTRY>/<NAMESPACE>/fly-qa-backend:<TAG>- 프론트엔드 이미지 (Vite 정적 빌드 → Nginx 서빙)
아래 Dockerfile 예시를 임시 파일로 생성해 사용합니다(리포지토리에 포함하고 싶다면 apps/frontend/Dockerfile로 추가).
# apps/frontend용 Dockerfile 예시
FROM node:20-alpine AS build
WORKDIR /app
COPY pnpm-workspace.yaml package.json pnpm-lock.yaml* ./
COPY apps/frontend/package.json ./apps/frontend/
COPY shared/types/package.json ./shared/types/
COPY shared/utils/package.json ./shared/utils/
RUN corepack enable && corepack prepare pnpm@latest --activate
RUN pnpm install --frozen-lockfile
COPY . .
RUN pnpm --filter @fly-qa/frontend build
FROM nginx:1.27-alpine
COPY /app/apps/frontend/dist /usr/share/nginx/html
COPY server/nginx/default.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]Nginx 기본 설정 파일 예시(server/nginx/default.conf):
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri /index.html;
}
}이제 프론트엔드 이미지를 빌드/푸시합니다.
docker build -t <REGISTRY>/<NAMESPACE>/fly-qa-frontend:<TAG> -f apps/frontend/Dockerfile .
docker push <REGISTRY>/<NAMESPACE>/fly-qa-frontend:<TAG>C) Kubernetes 매니페스트 예시
네임스페이스 생성(선택):
kubectl create namespace flyqa- Secret/Config (DB/Redis 자격증명)
apiVersion: v1
kind: Secret
metadata:
name: flyqa-secrets
namespace: flyqa
type: Opaque
data:
DATABASE_HOST: <base64-encoded>
DATABASE_PORT: <base64-encoded>
DATABASE_USERNAME: <base64-encoded>
DATABASE_PASSWORD: <base64-encoded>
DATABASE_NAME: <base64-encoded>
REDIS_HOST: <base64-encoded>
REDIS_PORT: <base64-encoded>- Backend Deployment/Service
apiVersion: apps/v1
kind: Deployment
metadata:
name: flyqa-backend
namespace: flyqa
spec:
replicas: 1
selector:
matchLabels:
app: flyqa-backend
template:
metadata:
labels:
app: flyqa-backend
spec:
containers:
- name: backend
image: <REGISTRY>/<NAMESPACE>/fly-qa-backend:<TAG>
imagePullPolicy: IfNotPresent
env:
- name: NODE_ENV
value: "production"
- name: PORT
value: "3000"
envFrom:
- secretRef:
name: flyqa-secrets
ports:
- containerPort: 3000
volumeMounts:
- name: artifacts
mountPath: /app/screenshots
- name: artifacts
mountPath: /app/videos
- name: artifacts
mountPath: /app/reports
volumes:
- name: artifacts
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: flyqa-backend
namespace: flyqa
spec:
selector:
app: flyqa-backend
ports:
- port: 3000
targetPort: 3000
name: http- Frontend Deployment/Service
apiVersion: apps/v1
kind: Deployment
metadata:
name: flyqa-frontend
namespace: flyqa
spec:
replicas: 1
selector:
matchLabels:
app: flyqa-frontend
template:
metadata:
labels:
app: flyqa-frontend
spec:
containers:
- name: frontend
image: <REGISTRY>/<NAMESPACE>/fly-qa-frontend:<TAG>
imagePullPolicy: IfNotPresent
env:
- name: VITE_API_URL
value: "https://api.flyqa.me"
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: flyqa-frontend
namespace: flyqa
spec:
selector:
app: flyqa-frontend
ports:
- port: 80
targetPort: 80
name: http- Ingress (예:
flyqa.me,api.flyqa.me)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: flyqa-ingress
namespace: flyqa
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/proxy-read-timeout: "86400"
nginx.ingress.kubernetes.io/proxy-send-timeout: "86400"
spec:
tls:
- hosts:
- flyqa.me
- www.flyqa.me
- api.flyqa.me
secretName: flyqa-tls # cert-manager로 발급 시 자동 생성 이름 사용
rules:
- host: flyqa.me
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: flyqa-frontend
port:
number: 80
- host: www.flyqa.me
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: flyqa-frontend
port:
number: 80
- host: api.flyqa.me
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: flyqa-backend
port:
number: 3000참고: WebSocket(Socke.IO) 타임아웃을 늘리는 애너테이션을 포함했습니다. 클러스터 Ingress Controller 구성에 따라 조정하세요.
D) 배포 실행
# 네임스페이스
kubectl create namespace flyqa || true
# 시크릿 생성(예시: 리터럴)
kubectl -n flyqa create secret generic flyqa-secrets \
--from-literal=DATABASE_HOST=<DB_HOST> \
--from-literal=DATABASE_PORT=<DB_PORT> \
--from-literal=DATABASE_USERNAME=<DB_USER> \
--from-literal=DATABASE_PASSWORD=<DB_PASS> \
--from-literal=DATABASE_NAME=<DB_NAME> \
--from-literal=REDIS_HOST=<REDIS_HOST> \
--from-literal=REDIS_PORT=<REDIS_PORT>
# 매니페스트 적용
kubectl -n flyqa apply -f k8s/
# 확인
kubectl -n flyqa get deploy,svc,ingress,podsk8s/ 디렉터리에 위 예시들을 파일로 나누어 저장해두면 관리가 편리합니다.
E) 새 버전 배포/롤링 업데이트
- 코드 변경 → 버전 태그 지정 → 이미지 빌드/푸시
export TAG=v1.0.0-$(date +%Y%m%d%H%M)
docker build -t <REGISTRY>/<NAMESPACE>/fly-qa-backend:$TAG -f Dockerfile .
docker push <REGISTRY>/<NAMESPACE>/fly-qa-backend:$TAG
docker build -t <REGISTRY>/<NAMESPACE>/fly-qa-frontend:$TAG -f apps/frontend/Dockerfile .
docker push <REGISTRY>/<NAMESPACE>/fly-qa-frontend:$TAG- Deployment 이미지 태그 갱신(예:
kubectl set image)
kubectl -n flyqa set image deploy/flyqa-backend backend=<REGISTRY>/<NAMESPACE>/fly-qa-backend:$TAG
kubectl -n flyqa set image deploy/flyqa-frontend frontend=<REGISTRY>/<NAMESPACE>/fly-qa-frontend:$TAG- 롤아웃 상태 확인/되돌리기
kubectl -n flyqa rollout status deploy/flyqa-backend
kubectl -n flyqa rollout status deploy/flyqa-frontend
# 문제 시 되돌리기
kubectl -n flyqa rollout undo deploy/flyqa-backend
kubectl -n flyqa rollout undo deploy/flyqa-frontendF) 스토리지/아티팩트 보존(선택)
현재 예시는 실행 스크린샷/리포트를 emptyDir로 두어 파드 수명과 함께 사라집니다. 장기 보존이 필요하면 PVC로 교체하세요.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: flyqa-artifacts
namespace: flyqa
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
---
# Deployment의 volumes/volumeMounts를 아래처럼 변경
volumes:
- name: artifacts
persistentVolumeClaim:
claimName: flyqa-artifacts부록) 빠른 실행 요약
- 모든 노드: 커널 모듈, sysctl, 스왑 비활성, containerd 설치/설정, kubeadm/kubelet/kubectl 설치
- Control-plane:
kubeadm init --apiserver-advertise-address=10.10.0.100 --pod-network-cidr=192.168.0.0/16 - Control-plane: kubeconfig 설정, Calico 적용
- Worker:
kubeadm join ...실행 - Control-plane:
kubectl get nodes로 Ready 확인
운영 모니터링: Grafana + Prometheus (kube-prometheus-stack)
Helm 차트 kube-prometheus-stack(Prometheus Operator 포함)을 사용해 클러스터 메트릭/알림과 대시보드를 손쉽게 구성합니다. Grafana에 Ingress를 붙여 외부에서 접근합니다.
1) Helm 설치 (관리 단말에서 1회)
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
helm version2) Helm 리포지토리 등록/갱신
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update3) 네임스페이스 생성
kubectl create namespace monitoring || true4) values.yaml 예시 작성 (Ingress, TLS, 퍼시스턴스)
아래 내용을 k8s/monitoring/values.yaml로 저장하세요. 도메인과 스토리지 클래스를 환경에 맞게 수정합니다.
grafana:
adminUser: admin
adminPassword: "<SET_STRONG_PASSWORD>"
persistence:
enabled: true
size: 10Gi
# storageClassName: <YOUR_STORAGE_CLASS>
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: nginx
hosts:
- grafana.flyqa.me
tls:
- secretName: grafana-tls
hosts:
- grafana.flyqa.me
prometheus:
prometheusSpec:
retention: 15d
storageSpec:
volumeClaimTemplate:
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 50Gi
# storageClassName: <YOUR_STORAGE_CLASS>
alertmanager:
alertmanagerSpec:
storage:
volumeClaimTemplate:
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 10Gi
# storageClassName: <YOUR_STORAGE_CLASS>TLS 자동 발급을 쓸 경우 cert-manager 설치 후
grafana-tls는 자동 관리되도록 애너테이션/ClusterIssuer를 추가하세요.
5) kube-prometheus-stack 설치
helm upgrade --install monitoring prometheus-community/kube-prometheus-stack \
-n monitoring -f k8s/monitoring/values.yaml설치 후 리소스 확인:
kubectl -n monitoring get pods,svc,ingressGrafana접속: https://grafana.flyqa.me (admin / <SET_STRONG_PASSWORD>)
6) 기본 대시보드/데이터소스
- 기본으로 Kubernetes/Node/Pod/Cluster 대시보드가 포함됩니다.
- 데이터소스는 Prometheus가 자동으로 설정됩니다.
- 필요 시 Import 기능으로 Grafana.com의 대시보드 ID를 추가하세요.
7) metrics-server 설치 (HPA/오토스케일)
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# 확인
kubectl get apiservices | grep metrics
kubectl top nodes
kubectl top pods -A클러스터 네트워킹/인증서 이슈로 metrics-server가 실패할 경우,
--kubelet-insecure-tls플래그를 추가한 배포 매니페스트를 사용하세요(운영환경에서는 권장하지 않음).
8) 알림(선택)
Alertmanager 수신자 구성 예시를 values에 추가하면 Slack/Email/PagerDuty 등으로 경보를 보낼 수 있습니다.
alertmanager:
config:
global:
resolve_timeout: 5m
route:
receiver: "slack"
receivers:
- name: "slack"
slack_configs:
- api_url: "https://hooks.slack.com/services/XXX/YYY/ZZZ"
channel: "#alerts"적용:
helm upgrade --install monitoring prometheus-community/kube-prometheus-stack \
-n monitoring -f k8s/monitoring/values.yaml9) 접근 점검 체크리스트
- Grafana Ingress가
200 OK로 응답하는지 - 기본 대시보드에서 노드/파드 메트릭이 수집되는지
kubectl top nodes/pods가 동작하는지(metrics-server)- 알림 테스트를 보냈을 때 수신되는지