๐งฑ 1๋จ๊ณ: K8s ํด๋ฌ์คํฐ ์ํคํ
์ฒ ์ค๊ณ
โ
๋ชฉํ ์์ฝ
- Master 3๋ ๊ตฌ์ฑ → HA(High Availability) ํด๋ฌ์คํฐ (.100)
- Node 3๋ ๊ตฌ์ฑ (.101 ~ .103)
- NFS + DNS 1๋ ๊ตฌ์ฑ (.99)
- Harbor 1๋ ๊ตฌ์ฑ ← Docker + Compose (.98)
- etcd ๋ฐฑ์
๋ฐ ๋ณต์
- LB ๊ตฌ์ฑ ํ์ (master API ์ ์ ์ํ ๋จ์ผ ์ง์
์ )
โ
ํต์ฌ ๊ฐ๋
์ค๋ช
โถ๏ธ ์ Master๋ 3๋ ์ด์์ด์ด์ผ ํ๋์?
- etcd๋ quorum ๊ธฐ๋ฐ์ ๋ถ์ฐ DB์
๋๋ค.
quorum์ด๋, ํด๋ฌ์คํฐ ๋ด์์ ๊ณผ๋ฐ์ ์ด์์ด ํฉ์๋ฅผ ํด์ผ ์ฐ๊ธฐ ์์
์ด ๊ฐ๋ฅํ๋ค๋ ์๋ฏธ์
๋๋ค.
- Master 2๋๋ฅผ ๊ตฌ์ฑํ ๊ฒฝ์ฐ, ํ๋๊ฐ ์ฅ์ ๋๋ฉด ๋จ์ 1๋๋ quorum์ ๋ง์กฑํ์ง ๋ชปํ์ฌ ์ฐ๊ธฐ ์์
์ด ์ค๋จ๋ฉ๋๋ค.
- 3๋๋ฅผ ๊ตฌ์ฑํ๋ฉด 1๋๊ฐ ์ฃฝ์ด๋ quorum(2/3)์ด ์ ์ง๋์ด ์์คํ
์ด ์ ์์ ์ผ๋ก ์ด์๋ ์ ์์ต๋๋ค.
โถ๏ธ HA๋ฅผ ์ํ Load Balancer
- Master๊ฐ ์ฌ๋ฌ ๋์ผ ๊ฒฝ์ฐ, ํด๋ฌ์คํฐ์ ์ ์ํ ๋๋ง๋ค ์ด๋ master์ ๋ถ์์ง ๋ถ์ฐ์ด ํ์ํฉ๋๋ค.
- ์ด๋ฅผ ์ํด ํด๋ฌ์คํฐ ์ง์
์ ์ผ๋ก HAProxy ๋๋ Keepalived + Nginx ๊ฐ์ L4/L7 LB๊ฐ ํ์ํฉ๋๋ค.
- kubeadm ์ค์ ์ controlPlaneEndpoint: "lb-address:6443" ๊ฐ์ ํํ๋ก LB ์ฃผ์๋ฅผ ์ ๊ณตํฉ๋๋ค.
๐๏ธ 2๋จ๊ณ: NFS + DNS ๊ตฌ์ฑ
โ
๋ชฉํ ์์ฝ
- NFS: Pod์ ์์ ๋ฐ์ดํฐ๋ฅผ ์ํ ๋์ PV ํ๋ก๋น์ ๋
- DNS: Harbor ๋๋ฉ์ธ hub.aws9.pri, Ingress์ฉ www.aws9.pri ๋ฑ ๋ด๋ถ ๋๋ฉ์ธ ๋ค์ ๋งคํ
โ
๊ฐ๋
์ค๋ช
โถ๏ธ NFS๋ก ๋์ ํ๋ก๋น์ ๋์ด ๊ฐ๋ฅํ๋ ค๋ฉด?
- NFS ์๋ฒ๋ฅผ ๋ณ๋๋ก ๊ตฌ์ถ
- /shared ๊ฒฝ๋ก๋ฅผ export
- Kubernetes์ NFS-CSI ๋๋ผ์ด๋ฒ ์ค์น
- StorageClass๋ฅผ ์ ์ (Provisioner๊ฐ NFS๋ฅผ ํ์ฉ)
- ์ดํ PVC ์์ฑ ์ StorageClass๋ฅผ ์ง์ ํ๋ฉด ๋์ ์ผ๋ก PV๊ฐ ์์ฑ๋ฉ๋๋ค.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-sc
provisioner: nfs.csi.k8s.io
parameters:
server: nfs.aws9.pri
share: /shared
reclaimPolicy: Retain
mountOptions:
- nfsvers=4.1
โถ๏ธ DNS ์ค์ ํฌ์ธํธ
- CoreDNS์ hosts ๋ฐฉ์ ๋๋ forward ์ค์ ์ผ๋ก ์ฌ์ค ๋๋ฉ์ธ ๋งคํ
- hub.aws9.pri → Harbor IP
- www.aws9.pri → Ingress Controller (์: nginx-ingress) IP
- ์ธ๋ถ์์ ์ ๊ทผํ์ง ์์๋ ๋๋ฏ๋ก CoreDNS๋ง์ผ๋ก ํด๊ฒฐ ๊ฐ๋ฅ
๐ 3๋จ๊ณ: Harbor ๊ตฌ์ฑ
โ
๋ชฉํ ์์ฝ
- Harbor๋ฅผ hub.aws9.pri๋ก ์ ๊ทผ ๊ฐ๋ฅํ๊ฒ ๊ตฌ์ฑ
- ์ฌ์ฉ์๋ณ private repo ์์ฑ
- TLS๋ ์ฌ์ค ํ๊ฒฝ์ด๋ฏ๋ก self-signed ์ธ์ฆ์ ์ฌ์ฉ ๊ฐ๋ฅ
โ
์ฃผ์ ์ค์ ํฌ์ธํธ
- DNS ์ค์ ์ด ์๋ฃ๋์ด์ผ docker login hub.aws9.pri ๊ฐ๋ฅ
- Harbor์ harbor.yml ์ค์ ์ hostname์ hub.aws9.pri๋ก ๋ณ๊ฒฝ ํ ๋ค์ prepare → start
- ์ฌ์ฉ์ ๊ณ์ ๋ฐ๊ธ ํ, ํ๋ก์ ํธ(Repo)๋ฅผ ์์ฑํ์ฌ ์ ๊ทผ ๊ถํ ๋ถ์ฌ
๐ ๏ธ 4๋จ๊ณ: ArgoCD + Namespace ๊ธฐ๋ฐ GitOps
โ
๋ชฉํ ์์ฝ
- ๊ฐ๋ฐ์๋ง๋ค ๋
๋ฆฝ๋ GitHub ์ ์ฅ์ ์ฌ์ฉ
- ๊ฐ ๊ฐ๋ฐ์๋ ์์ ๋ง์ namespace์์ ์ฑ์ ๊ด๋ฆฌ
- ArgoCD App์ Namespace ๋จ์๋ก ๊ด๋ฆฌ
โ
๊ฐ๋
์ ๋ฆฌ
- ArgoCD๋ GitOps ๊ธฐ๋ฐ ๋๊ตฌ๋ก, Git์ ์ ์ธ๋ ์ํ๋ฅผ ํด๋ฌ์คํฐ์ ๋๊ธฐํํฉ๋๋ค.
- Namespace์ RBAC๋ฅผ ์กฐํฉํ์ฌ ์ฌ์ฉ์ ๊ฒฉ๋ฆฌ ๊ฐ๋ฅ
- ๋ค์๊ณผ ๊ฐ์ ๋ฐฉ์์ผ๋ก ๊ตฌ์ฑ:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: blog-app
namespace: argocd
spec:
destination:
namespace: team-blog
server: https://kubernetes.default.svc
source:
repoURL: https://github.com/user/blog-yamls
targetRevision: HEAD
path: manifests
project: default
syncPolicy:
automated:
prune: true
selfHeal: true
โ๏ธ 5๋จ๊ณ: HPA + KEDA ์ค์ผ์ผ๋ง
โ
๋ชฉํ ์์ฝ
- ์๊ฐ ๊ธฐ๋ฐ: 9์~18์ → 3๊ฐ, ๊ทธ ์ธ → 1๊ฐ
- CPU ๊ธฐ๋ฐ: 60% ์ด์ → max 10๊ฐ๊น์ง ํ์ฅ
โ
๊ตฌํ ๋ฐฉํฅ
- KEDA๋ Cron ๊ธฐ๋ฐ ์ค์ผ์ผ๋ง์ ์ ๊ณตํฉ๋๋ค
- HPA๋ CPU ์ฌ์ฉ๋ ๊ธฐ๋ฐ์ผ๋ก ๋์
- KEDA + HPA๋ฅผ ํจ๊ป ์ค์ ํ์ฌ ์๊ฐ ๊ธฐ๋ฐ ๊ธฐ๋ณธ๊ฐ๊ณผ ๋ถํ ๊ธฐ๋ฐ ํ์ฅ ๋ ๋ค ๊ฐ๋ฅ
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: shop-scaler
namespace: team-shop
spec:
scaleTargetRef:
name: shop-deployment
minReplicaCount: 1
maxReplicaCount: 10
triggers:
- type: cron
metadata:
timezone: Asia/Seoul
start: "09:00"
end: "18:00"
desiredReplicas: "3"
- type: cpu
metadata:
type: Utilization
value: "60"
๐ 6๋จ๊ณ: Ingress ๊ตฌ์ฑ
โ
๋ชฉํ
- www.aws9.pri/shop, .../blog, .../news ๋ฑ Path ๊ธฐ๋ฐ Routing
- ๋ชจ๋ ๋ผ์ฐํ
์ Ingress๋ก ํตํฉ
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: main-ingress
namespace: team-shop
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
rules:
- host: www.aws9.pri
http:
paths:
- path: /shop(/|$)(.*)
pathType: Prefix
backend:
service:
name: shop-svc
port:
number: 80
๊ฐ ์๋น์ค(blog/news ๋ฑ)๋ namespace์ svc ์ด๋ฆ๋ง ๋ฐ๊ฟ์ ๋์ผ ๊ตฌ์กฐ๋ก ์์ฑํ์๋ฉด ๋ฉ๋๋ค.
๐ 7๋จ๊ณ: etcd ๋ฐฑ์
/๋ณต์
โ
์ ์ฐจ ์์ฝ
- etcd ๋ฐฑ์
:
ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-snapshot.db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
- pod ๋๋ deployment ์ญ์
- ๋ณต์ ์ ์ฐจ (ํ
์คํธ ํด๋ฌ์คํฐ๋ ์ฌ๋ถํ
ํ์):
ETCDCTL_API=3 etcdctl snapshot restore /backup/etcd-snapshot.db \
--data-dir /var/lib/etcd-from-backup
- kubelet์ ์ฌ์์ํ๊ฑฐ๋ etcd๋ฅผ ๋ณต์๋ ๋๋ ํ ๋ฆฌ๋ก ๊ต์ฒด
๐ฆ 8๋จ๊ณ: ๊ธฐํ ์ฌํญ (Node Label / Taint / Toleration ๋ฑ)
- ํน์ Pod๊ฐ ํน์ ๋
ธ๋์๋ง ๋ฐฐ์น๋๋๋ก ํ๋ ค๋ฉด:
kubectl label node node1 disktype=ssd
Pod ์ค์ :
spec:
nodeSelector:
disktype: ssd
- taint๊ฐ ์๋ ๋
ธ๋์ ๋ฐฐ์นํ๋ ค๋ฉด:
kubectl taint node node2 dedicated=group1:NoSchedule
Pod toleration ์ค์ :
tolerations:
- key: "dedicated"
operator: "Equal"
value: "group1"
effect: "NoSchedule"