1. Kubernetes Availability & Network
- ์ฟ ๋ฒ๋คํฐ์ค ํด๋ฌ์คํฐ์ ์์ ์ ์ธ ์ด์์ ์ํด ํ์ํ ๊ฐ์ฉ์ฑ ํ๋ณด ๋ฐฉ๋ฒ
- HPA์ VPA๋ฅผ ํตํด ๋ถํ์ ๋ฐ๋ฅธ ์ํฌ๋ก๋์ ์์ง ๋ฐ ์ํ ์๋ ํ์ฅ
- ์ ํ๋ฆฌ์ผ์ด์
์ค์ ๊ณผ ๋ณด์ ์ ๋ณด๋ฅผ ํ๊ฒฝ์ ๋ง๊ฒ ๋ถ๋ฆฌ ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ
- ConfigMap๊ณผ Secret์ ํ์ฉํด ์ค์ ๊ฐ๊ณผ ๋ฏผ๊ฐ ์ ๋ณด๋ฅผ ๋ถ๋ฆฌํ๊ณ ์์ ํ๊ฒ ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์๋๋ค
- ์ฟ ๋ฒ๋คํฐ์ค ์๋น์ค ํ์
์ ํตํ ๋ด๋ถ ๋ฐ ์ธ๋ถ ํธ๋ํฝ ์ฐ๊ฒฐ ๊ตฌ์กฐ ์ดํด
- ClusterIP, NodePort, Ingress ๋ฑ ๋ค์ํ ์๋น์ค ์ ํ์ ํตํด ํด๋ฌ์คํฐ ๋ด๋ถ ๋ฐ ์ธ๋ถ์ ํต์ ํ๋ ๋ฐฉ๋ฒ์ ์ตํ๋๋ค
- ๋ค์ดํฐ๋ธ ์ฟ ๋ฒ๋คํฐ์ค ํ๊ฒฝ์์ ์ฌ์ฉํ๋ ์คํ ๋ฆฌ์ง์ ๊ฐ๋ ๊ณผ ํน์ง ๊ฐ๋จ ์ ๋ฆฌ
์ค์ต ํ๊ฒฝ ๊ตฌ์ฑ (Kind, Controlplane 1 + Worker 1)
- Windows WSL2 ๊ธฐ์ค, kind ๋ฐ ํ๊ฒฝ๊ตฌ์ฑ
# Windows WSL2 (Ubuntu) - PowerShell / CMD (๊ด๋ฆฌ์ ๊ถํ)
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
wsl --list -o
wsl --install -d ubuntu
# WSL2 Ubuntu
sudo snap install docker
sudo groupadd docker
sudo usermod -aG docker $USER
docker --version
# Kind ์ค์น
[ $(uname -m) = x86_64 ] && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.27.0/kind-linux-amd64
sudo chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind
# Kind Cluster ์์ฑ
kind create cluster
# kubectl ์ค์น
sudo snap install kubectl --classic
kubectl get pods -A
# Krew ์ค์น
wget https://github.com/kubernetes-sigs/krew/releases/download/v0.4.5/krew-linux_amd64.tar.gz
tar zxvf krew-linux_amd64
./krew-linux_amd64 install krew
~/.bashrc >> export PATH="${KREW_ROOT:-$HOME/.krew}/bin:$PATH"
source ~/.bashrc
kubectl krew
# k9s ์ค์น
wget https://github.com/derailed/k9s/releases/download/v0.50.4/k9s_linux_amd64.deb
sudo dpkg -i k9s_linux_amd64.deb
sudo apt-get install -f
k9s
# Helm ์ค์น
sudo snap install helm --classic
helm ls
- ๋ฉํฐ๋ ธ๋ ํด๋ฌ์คํฐ with kube-ops-view & Mapping ports
# '์ปจํธ๋กคํ๋ ์ธ, ์์ปค ๋
ธ๋ 1๋' ํด๋ฌ์คํฐ ๋ฐฐํฌ : ํ๋์ ์ ์ํ๊ธฐ ์ํ ํฌํธ ๋งตํ ์ค์
cat <<EOT> kind-2node.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
extraPortMappings:
- containerPort: 30000
hostPort: 30000
listenAddress: "0.0.0.0" # Optional, defaults to "0.0.0.0"
protocol: tcp # Optional, defaults to tcp
- containerPort: 30001
hostPort: 30001
EOT
kind create cluster --config kind-2node.yaml
# ๋ฐฐํฌ ํ์ธ
kind get clusters
kind get nodes
# ๋
ธ๋ ํ์ธ
kubectl get nodes -o wide
# ๋
ธ๋์ Taints ์ ๋ณด ํ์ธ
kubectl describe node kind-control-plane | grep Taints
Taints: node-role.kubernetes.io/control-plane:NoSchedule
kubectl describe node kind-worker | grep Taints
Taints: <none>
# ์ปจํ
์ด๋ ํ์ธ : ์ปจํ
์ด๋ ๊ฐฏ์, ์ปจํ
์ด๋ ์ด๋ฆ ํ์ธ
# kind yaml ์ ํฌํธ ๋งตํ ์ ๋ณด ์ฒ๋ผ, ์์ ์ PC ํธ์คํธ์ 30000 ํฌํธ ์ ์ ์, ์์ปค๋
ธ๋(์ค์ ๋ก๋ ์ปจํ
์ด๋)์ TCP 30000 ํฌํธ๋ก ์ฐ๊ฒฐ
# ์ฆ, ์์ปค๋
ธ๋์ NodePort TCP 31000 ์ค์ ์ ์์ ์ PC ํธ์คํธ์์ ์ ์ ๊ฐ๋ฅ!
docker ps
docker port kind-worker
30000/tcp -> 0.0.0.0:30000
30001/tcp -> 0.0.0.0:30001
๋ฐฐํฌ ํ์ธ
- controlplane, worker ๊ฐ 1๋์ ๋ ธ๋ ํ์ธ
- worker์ ๊ฐ 30000/30001 ํฌํธ๋ ํธ์คํธ์ ๋งคํ๋์ด์์

2. ์ฟ ๋ฒ๋คํฐ์ค ๊ฐ์ฉ์ฑ (Availability)

- ์ฟ ๋ฒ๋คํฐ์ค ํ๊ฒฝ์์๋
๊ฐ์ฉ์ฑ (Availability)์ ํ๋ณดํ๊ธฐ ์ํ ๋ค์ํ ๋ฐฉ๋ฒ์ด ์กด์ฌ- HPA (Horizontal Pod Autoscaling) : Pod ์ํ ํ์ฅ (์ค์ผ์ผ In – Out)
- Pod ๊ฐ์ ์ฆ๊ฐ์ ํตํ ๋ถํ ๋ถ์ฐ
- VPA (Vertical Pod Autoscaling) : Pod ์์ง ํ์ฅ (์ค์ผ์ผ Up)
- Pod ๋ฆฌ์์ค(CPU, Mem ๋ฑ) ์ฆ๊ฐ์ ํตํ ์ฑ๋ฅ ์กฐ์
- CA (Cluster Autoscaling) : Node ํ์ฅ (Cloud ํ๊ฒฝ)
- Worker ๋ ธ๋ ๊ฐ์ ์ฆ๊ฐ์ ํตํ ๋ถํ ๋ถ์ฐ
- HPA (Horizontal Pod Autoscaling) : Pod ์ํ ํ์ฅ (์ค์ผ์ผ In – Out)
- Metrics Server ์ค์น
- k8s ํด๋ฌ์คํฐ ๋ด Pod/Node ๋ฆฌ์์ค ์ฌ์ฉ๋(CPU, ๋ฉ๋ชจ๋ฆฌ ๋ฑ)์ ์์งํ๋ ๊ฒฝ๋ํ๋ ๋ชจ๋
- ๊ฐ ๋ ธ๋์ Kubelet์์ ์งํ๋ฅผ ์ฃผ๊ธฐ์ ์ผ๋ก ์์งํด API Server์ ์ ๊ณต
- HPA๋ VPA ๊ฐ์ ์๋ ํ์ฅ ์ปจํธ๋กค๋ฌ๊ฐ ๋ฆฌ์์ค ์ฌ์ฉ๋์ ๊ธฐ์ค์ผ๋ก ๋์ํ ์ ์๋๋ก ๋ฐ์ดํฐ ์์ง
- ์ค์๊ฐ ๋ชจ๋ํฐ๋ง ๋๊ตฌ๊ฐ ์๋, ์๋ํ๋ ๋ฆฌ์์ค ์กฐ์ ์ ์ํ ์ฉ๋๋ก ์ฌ์ฉ
# Metrics Server ์ค์น
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# Metrics Server SSL ๋ฌด์
kubectl patch deployment metrics-server -n kube-system --type=json \
-p='[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--kubelet-insecure-tls"}]'
# Metrics Server ๋ฐฐํฌ ํ์ธ
kubectl get pods -n kube-system -l k8s-app=metrics-server
# ์ฟ ๋ฒ๋คํฐ์ค ๋ฆฌ์์ค ์์ ์ฌ์ฉ๋ ํ์ธ
kubectl top node
kubectl top pods -A
# CPU, Memory ๋ด๋ฆผ์ฐจ์
kubectl top pods -A --sort-by=cpu
kubectl top pods -A --sort-by=memory
2.1. HPA (Horizontal Pod Autoscaling)

- ์ํ ์ค์ผ์ผ๋ง(HPA, Horizontal Pod Autoscaling)
- ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ถํ์ ๋ฐ๋ผ ํ๋์ ๊ฐ์๋ฅผ ์๋์ผ๋ก ์กฐ์
- CPU ์ฌ์ฉ๋ฅ , ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋, ๋๋ ์ฌ์ฉ์ ์ ์ ๋ฉํธ๋ฆญ์ ๊ธฐ์ค์ผ๋ก ๋์
- Metrics Server๋ก๋ถํฐ ์์งํ ์งํ๊ฐ ์ค์ ๋ ์๊ณ์น๋ฅผ
- ์ด๊ณผํ๋ฉด ํ๋์ replicas ์๋ฅผ ์ฆ๊ฐ
- ์ค์ด๋ค๋ฉด ํ๋์ replicas ์๋ฅผ ๊ฐ์
- ์ํฌ๋ก๋ ๋ณํ์ ๋ฐ๋ผ ๋ฆฌ์์ค๋ฅผ ํจ์จ์ ์ผ๋ก ํ ๋น / ๊ณผ๋ํ ๋ฆฌ์์ค ๋ญ๋น ๋ฐฉ์ง
- ๊ธฐ๋ณธ YAML spec
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: hpa-sample
spec:
scaleTargetRef: # Scale ํ๊ฒ ์ง์
apiVersion: apps/v1
kind: Deployment
name: my-app # Deployment ์ด๋ฆ
minReplicas: 2 # ์ต์ Pod
maxReplicas: 10 # ์ต๋ Pod
metrics: # Scale ๊ธฐ์ค ์งํ ์ค์
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50 # CPU ์ฌ์ฉ๋ฅ 50% ๊ธฐ์ค
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 70 # ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ฅ 70% ๊ธฐ์ค
HPA ๊ตฌ์ฑ
- nginx deploy ๋ฐฐํฌ
cat << EOF >> hpa-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hpa-nginx
spec:
replicas: 1
selector:
matchLabels:
app: hpa-nginx
template:
metadata:
labels:
app: hpa-nginx
spec:
containers:
- name: hpa-nginx
image: nginx
resources:
requests:
cpu: 50m
limits:
cpu: 100m
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: hpa-nginx
labels:
app: hpa-nginx
spec:
ports:
- port: 80
selector:
app: hpa-nginx
EOF
cat hpa-nginx.yaml
# Deployment ๋ฐฐํฌ
kubectl apply -f hpa-nginx.yaml
kubectl get deploy,pod
- ๋ช ๋ นํ์ผ๋ก hpa ์ค์
# HPA ์์ฑ
kubectl autoscale deployment hpa-nginx --cpu-percent=50 --min=1 --max=10
# HPA ํ์ธ
kubectl get hpa
...
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
hpa-nginx Deployment/hpa-nginx cpu: 0%/50% 1 10 1 26s
....
# HPA ์์ธ ์ ๋ณด ํ์ธ
kubectl describe hpa
- pod ๋ถํ ์์ฑ
# ํฐ๋ฏธ๋ 1๋ฒ
while true; do kubectl get hpa; kubectl top pods; sleep 1s; done
# ํฐ๋ฏธ๋ 2๋ฒ
kubectl run -i --tty load-generator --rm --image=busybox:1.28 --restart=Never -- /bin/sh -c "while true; do wget -q -O- http://hpa-nginx.default.svc.cluster.local; done"
# ์ค์ต ์ข
๋ฃ ํ ๋ฆฌ์์ค ์ญ์
kubectl delete hpa --all
kubectl delete -f hpa-nginx.yaml
๊ฒฐ๊ณผ ํ์ธ
- http ์์ฒญ์ ๋ฐ๋ฅธ nginx ํ๋์ CPU ๋ถํ ์ฆ๊ฐ
- metrics-server์ ๊ธฐ๋ก ํ scailng triggered


2.2. VPA (Vertical Pod Autoscaling)

- ์์ง ์ค์ผ์ผ๋ง(VPA, Vertical Pod Autoscaling)
- ํ๋์ ๋ฆฌ์์ค ์์ฒญ๊ฐ(CPU, ๋ฉ๋ชจ๋ฆฌ)์ ์๋์ผ๋ก ์กฐ์
- HPA๊ฐ ํ๋ ๊ฐ์๋ฅผ ์กฐ์ ํ๋ ๊ฒ๊ณผ ๋ฌ๋ฆฌ, VPA๋ ๊ฐ ํ๋๊ฐ ์ฌ์ฉํ๋ ๋ฆฌ์์ค์ ํฌ๊ธฐ๋ฅผ ์กฐ์ ํจ
- VPA Recommender๊ฐ ๋ฆฌ์์ค ์ฌ์ฉ๋์ ๋ถ์ํด ์ต์ ์ ์์ฒญ๊ฐ์ ๊ณ์ฐํ๊ณ ๋ฐ์ํจ
- HPA์ VPA๋ ๊ฐ์ Deployment์ ๋์์ ์ ์ฉํ ์ ์์
- Kubernetes v1.33๋ถํฐ๋ VPA ๊ธฐ๋ฅ์ด ๊ธฐ๋ณธ ํ์ฑํ๋์ด ์์ผ๋, kind์์๋ v1.32๊น์ง ์ง์๋๋ฏ๋ก ๋ณ๋์ ์ปจํธ๋กค๋ฌ ์ค์น๊ฐ ํ์ํจ
- ๊ธฐ๋ณธ ๊ตฌ์ฑ ์์๋ VPA Recommender, Updater, Admission Plugin ์ธ ๊ฐ์ง๋ก ์ด๋ฃจ์ด์ง
- ๊ธฐ๋ณธ YAML ๊ตฌ์ฑ
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: my-app-vpa
spec:
targetRef: # Scale ๋์
apiVersion: apps/v1
kind: Deployment
name: my-app # Deployment ๋ช
์นญ
updatePolicy:
updateMode: "Auto" # VPA Recommender ์ ์ํด ์๋ ์กฐ์ ํ์ฑํ
resourcePolicy:
containerPolicies:
- containerName: my-app-container # Container ๋ช
์นญ "*" ์ฌ์ฉ ๊ฐ๋ฅ
minAllowed: # ์ปจํ
์ด๋๊ฐ ํ ๋น๋ฐ์ ์ ์๋ ์ต์ ๋ฆฌ์์ค
cpu: "200m"
memory: "512Mi"
maxAllowed: # ์ปจํ
์ด๋๊ฐ ํ ๋น๋ฐ์ ์ ์๋ ์ต๋ ๋ฆฌ์์ค
cpu: "2"
memory: "2Gi"
VPA ๊ตฌ์ฑ ๋ฐ ํ ์คํธ
- EKS Workshop ์์ค๋ฅผ ์ฌ์ฉํ VPA ๋ฐฐํฌ
# EKS Workshop ์์ค ์ฌ์ฉ
git clone https://github.com/kubernetes/autoscaler.git
# VPA ๋ฐฐํฌ
cd autoscaler/vertical-pod-autoscaler/
./hack/vpa-up.sh
# VPA Controller ํ์ธ
kubectl get pods -n kube-system | grep vpa
# VPA ์ ๊ฑฐ
./hack/vpa-down.sh
- 0.1 cpu ๋ฅผ ์์ฒญํ 2๊ฐ Pod ๋ฐฐํฌ (์ค์ ์ฌ์ฉ๋๋ณด๋ค ๋ถ์กฑํ ์ํ)
apiVersion: "autoscaling.k8s.io/v1"
kind: VerticalPodAutoscaler
metadata:
name: hamster-vpa
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: hamster
resourcePolicy:
containerPolicies:
- containerName: '*'
minAllowed:
cpu: 100m
memory: 50Mi
maxAllowed:
cpu: 1
memory: 500Mi
controlledResources: ["cpu", "memory"]
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: hamster
spec:
selector:
matchLabels:
app: hamster
replicas: 2
template:
metadata:
labels:
app: hamster
spec:
securityContext:
runAsNonRoot: true
runAsUser: 65534 # nobody
containers:
- name: hamster
image: registry.k8s.io/ubuntu-slim:0.14
resources:
requests:
cpu: 100m
memory: 50Mi
command: ["/bin/sh"]
args:
- "-c"
- "while true; do timeout 0.5s yes >/dev/null; sleep 0.5s; done"
๊ฒฐ๊ณผ ํ์ธ
- ๋ฆฌ์์ค ๋ถ์กฑํ pod ์ ๊ฑฐ(evict) ์ดํ ์ ์ ํ resource request ๋ฅผ ๊ฐ๊ณ ์ฌ์์ฑ



2.3. CA (Cluster Autoscaler)

- Cluster Autoscaler๋ ์ฟ ๋ฒ๋คํฐ์ค ํด๋ฌ์คํฐ์์ ์์ปค ๋ ธ๋์ ์๋ฅผ ์๋์ผ๋ก ์กฐ์ ํ๋ ์ปดํฌ๋ํธ๋ก, ํด๋ฌ์คํฐ์ ์ค์ผ์คํ ์ฌ์ ๊ฐ ์๋ ํ๋๊ฐ ์กด์ฌํ ๊ฒฝ์ฐ ๋ ธ๋๋ฅผ ์๋์ผ๋ก ์ถ๊ฐํ๊ณ , ์ฌ์ฉ๋์ง ์๋ ๋ ธ๋๋ ์๋์ผ๋ก ์ ๊ฑฐํจ
- HPA๋ VPA๋ ํ๋ ๋จ์์์์ ๋ฆฌ์์ค ํ์ฅ์ ๋ค๋ฃจ์ง๋ง, CA๋ ํ๋๊ฐ ๋ฐฐ์น๋ ๊ณต๊ฐ ์์ฒด๊ฐ ์์ ๋ ํด๋ฌ์คํฐ์ ์ธํ๋ผ ๋ ๋ฒจ(๋ ธ๋ ์)์ ์กฐ์ ํจ
- ์ผ๋ฐ์ ์ผ๋ก GCP, AWS, Azure ๊ฐ์ ํด๋ผ์ฐ๋ ํ๊ฒฝ์์ ์ฌ์ฉ๋๋ฉฐ, ํด๋ผ์ฐ๋ ํ๋ก๋ฐ์ด๋ API๋ฅผ ํตํด ์ค์ VM ์ธ์คํด์ค๋ฅผ ์๋์ผ๋ก ์์ฑํ๊ฑฐ๋ ์ญ์ ํจ
- ์ค์ ๋ ๋ ธ๋ ๊ทธ๋ฃน์ด๋ Auto Scaling Group ๋จ์๋ก ๋์ํ๋ฉฐ, ๋ ธ๋์ ์ข ๋ฅ๋ ๊ฐ์๋ ์ฌ์ ์ ์ ํด์ ธ ์์
- ๋์ ๋ฐฉ์
- Cluster Autoscaler๊ฐ ํ์ฑํ๋๋ฉด, ๋๊ธฐ ์ํ(pending)์ ํ๋๊ฐ ์๋์ง ํ์ธํ๋ค. ๊ธฐ๋ณธ ์ค์บ ์ฃผ๊ธฐ๋ 10์ด์ด๋ฉฐ,
--scan-intervalํ๋๊ทธ๋ฅผ ์ฌ์ฉํ์ฌ ์ค์ ํ ์ ์๋ค. - ๋๊ธฐ ์ค์ธ ํ๋๊ฐ ์๊ณ ํด๋ฌ์คํฐ์ ๋ ๋ง์ ๋ฆฌ์์ค๊ฐ ํ์ํ ๊ฒฝ์ฐ, CA๋ ๊ด๋ฆฌ์๊ฐ ์ค์ ํ ์ ์ฝ ์กฐ๊ฑด ๋ด์์ ์๋ก์ด ๋ ธ๋๋ฅผ ์ถ๊ฐํ์ฌ ํด๋ฌ์คํฐ๋ฅผ ํ์ฅํ๋ค. AWS, Azure, GCP ๊ฐ์ ํผ๋ธ๋ฆญ ํด๋ผ์ฐ๋ ๊ณต๊ธ์๋ค์ Kubernetes Cluster Autoscaler ๊ธฐ๋ฅ์ ์ง์ํ๋ฉฐ, ์๋ฅผ ๋ค์ด AWS EKS๋ Auto Scaling Group ๊ธฐ๋ฅ์ ํตํด EC2 ๊ฐ์ ๋จธ์ ์ ์๋์ผ๋ก ์ถ๊ฐํ๊ฑฐ๋ ์ ๊ฑฐํ๋ค.
- Kubernetes๋ ์๋ก ํ๋ก๋น์ ๋๋ ๋ ธ๋๋ฅผ ์ปจํธ๋กค ํ๋ ์ธ์ ๋ฑ๋กํ์ฌ ์ค์ผ์ค๋ฌ๊ฐ ํด๋น ๋ ธ๋๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก ๋ง๋ ๋ค.
- ๋ง์ง๋ง์ผ๋ก Kubernetes ์ค์ผ์ค๋ฌ๊ฐ ๋๊ธฐ ์ค์ธ ํ๋๋ฅผ ์ ๋ ธ๋์ ํ ๋นํ๋ค.

- Karpenter๋ Cluster Autoscaler์ ๋์ผํ๊ฒ ๋ ธ๋์ ์๋ ํ์ฅ์ ์ํํ์ง๋ง, ๋ ์ ์ฐํ๊ณ ๋น ๋ฅธ ๋ฆฌ์์ค ํ๋ก๋น์ ๋์ ์ง์ํ๋ ์ฐจ์ธ๋ ์คํ ์ค์ผ์ผ๋ฌ์
- ๊ธฐ์กด CA๋ ์ ํด์ง ๋ ธ๋ ๊ทธ๋ฃน ๋ด์์ ํ์ฅ์ ์ํํ๋ ๋ฐ๋ฉด, Karpenter๋ ํ๋์ ์๊ตฌ์ฌํญ์ ๋ฐ๋ผ ๊ฐ์ฅ ์ ์ ํ ์ธ์คํด์ค ํ์ ๊ณผ ํฌ๊ธฐ๋ฅผ ์ ํํด ๋ ธ๋๋ฅผ ์์ฑํจ
- ์ฆ, HPA์ ์ํ ํ์ฅ + VPA์ ๋ฆฌ์์ค ๋ถ์ ์ญํ ์ ํฌํจํ ๋ฐฉ์์ผ๋ก, ํด๋ฌ์คํฐ์ ๋ฆฌ์์ค๋ฅผ ๋ ์ ๋ฐํ๊ฒ ์ต์ ํํจ
- ํ๋ ฅ์ ์ธ ๋ฆฌ์์ค ํ์ฉ๊ณผ ํจ๊ป ๋ถํ์ํ ๋ ธ๋๋ฅผ ๋น ๋ฅด๊ฒ ์ ๊ฑฐํ ์ ์์ด, ๋น์ฉ ํจ์จ์ฑ๊ณผ ์๋ต ์๋ ๋ฉด์์ ์ ๋ฆฌํจ
- AWS Fargate, EC2, Bottlerocket ๋ฑ ๋ค์ํ ๋ฐฑ์๋๋ฅผ ์ง์ํ๋ฉฐ, ์ ์ ๊ธฐ์กด CA๋ฅผ ๋์ฒดํ๋ ๋ฐฉํฅ์ผ๋ก ํ์ฐ๋๊ณ ์์
2.4. KEDA (Kubernetes Event-Driven Autoscaler)

KEDA (Kubernetes Event-Driven Autoscaler)
- KEDA(Kubernetes Event-Driven Autoscaler)๋ ์ฟ ๋ฒ๋คํฐ์ค์์ ์ด๋ฒคํธ ๊ธฐ๋ฐ์ผ๋ก ์ํฌ๋ก๋๋ฅผ ์๋ ํ์ฅํด์ฃผ๋ ํ์ฅ ๋๊ตฌ์
- ๊ธฐ์กด์ HPA๋ CPU, ๋ฉ๋ชจ๋ฆฌ์ ๊ฐ์ ๋ฆฌ์์ค ์ฌ์ฉ๋์ ๊ธฐ์ค์ผ๋ก๋ง ํ์ฅ ์กฐ๊ฑด์ ํ๋จํ์ง๋ง, KEDA๋ ์ธ๋ถ ์ด๋ฒคํธ๋ ๋ฉ์์ง ํ ์ํ ๋ฑ ๋ค์ํ ์ ํธ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ์ฅ์ ์ํํจ
- Kafka, RabbitMQ, AWS SQS, Azure Event Hub, Prometheus ์ฟผ๋ฆฌ ๋ฑ 50๊ฐ ์ด์์ ์ด๋ฒคํธ ์์ค๋ฅผ ์ง์ํ์ฌ, ์ค์๊ฐ ํธ๋ํฝ ๋ณํ๋ ๋ฐฑ๊ทธ๋ผ์ด๋ ์์ ์ ์ ์ฐํ๊ฒ ๋์ ๊ฐ๋ฅํจ
- ๋ด๋ถ์ ์ผ๋ก HPA๋ฅผ ์์ฑํ๊ณ ๊ด๋ฆฌํ๋ฉฐ, ์ด๋ฒคํธ ์กฐ๊ฑด์ด ์ถฉ์กฑ๋๋ฉด HPA๋ฅผ ํ์ฑํํ์ฌ Pod ์๋ฅผ ์๋ ์กฐ์ ํจ
- ์๋ฅผ ๋ค์ด, ํน์ ์๊ฐ๋์ ๋ฉ์์ง ํ์ ์์ธ ์์ ๋์ด ๋ง์์ง๋ ๊ฒฝ์ฐ ์ด๋ฅผ ๊ฐ์งํด ํ๋๋ฅผ ๋ฏธ๋ฆฌ ํ์ฅํ๊ฑฐ๋, ์ธ๋ถ ์์ฒญ ์๊ฐ ๊ธ์ฆํ ๋ ๋น ๋ฅด๊ฒ ๋์ํ ์ ์์
- ์ ์ ์ค์ผ์ค๋ง(HPA + cronjob)์ด๋ ๋จ์ ๋ฆฌ์์ค ์ฌ์ฉ๋ฅ ๊ธฐ๋ฐ ํ์ฅ์ ํ๊ณ๋ฅผ ๋ณด์ํ๋ฉฐ, ํด๋ผ์ฐ๋ ๋ค์ดํฐ๋ธ ํ๊ฒฝ์ ์ ํฉํ ํ์ฅ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํจ
3. ์ดํ๋ฆฌ์ผ์ด์ ๋ณ์ ๊ด๋ฆฌ
3.1. ConfigMap

- Kubernetes ์ ํ๋ฆฌ์ผ์ด์ ์ ์ค์ ์ ๋ณด๋ฅผ Key-Value ํํ๋ก ์ ์ฅํ๊ณ ์ธ๋ถ์์ ๊ด๋ฆฌํ ์ ์๋๋ก ์ง์ํ๋ ๋ฆฌ์์ค
- ์ค์ ๋ฐ์ดํฐ๋ฅผ ์ด๋ฏธ์ง์ ์ง์ ํฌํจํ์ง ์๊ณ ๋ถ๋ฆฌํจ์ผ๋ก์จ, ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ๋น๋ํ์ง ์๊ณ ๋ ์ค์ ์ ๋ณ๊ฒฝํ ์ ์์
- ํ๋์ ํ๊ฒฝ ๋ณ์ ๋๋ ๋ณผ๋ฅจ ๋ง์ดํธ๋ฅผ ํตํด ์ปจํ ์ด๋ ๋ด๋ถ์์ ConfigMap ๊ฐ์ ์ฐธ์กฐํ ์ ์์
- ์ฃผ์ ์ฌ์ฉ ๋ชฉ์
- ์ ํ๋ฆฌ์ผ์ด์
์ค์ ๊ด๋ฆฌ
- ๋ฐ์ดํฐ๋ฒ ์ด์ค URL, ์ธ๋ถ API ์ฃผ์ ๋ฑ ๊ตฌ์ฑ ์ ๋ณด๋ฅผ ConfigMap์ ์ ์ฅํ๊ณ ํ๋์ ์ฃผ์ ํ์ฌ ์ฌ์ฉ
- ํ๊ฒฝ๋ณ ์ค์ ๋ถ๋ฆฌ
- ๊ฐ๋ฐ, ์คํ ์ด์ง, ์ด์ ํ๊ฒฝ๋ณ๋ก ๋ค๋ฅธ ์ค์ ๊ฐ์ ๊ด๋ฆฌํ์ฌ ๋์ผํ ์ปจํ ์ด๋ ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ๊ฒ ํจ
# ConfigMap ์ํ ๊ตฌ์ฑ
apiVersion: v1
kind: ConfigMap
metadata:
name: my-config # ConfigMap ๋ช
์นญ
data:
key1: value1 # Key : Value ํํ ๊ฐ ์ฃผ์
key2: value2
# ConfigMap ์ฌ์ฉ ์์
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: my-container
image: my-image
env:
- name: MY_CONFIG_KEY # ์ปจํ
์ด๋์์ ์ฌ์ฉํ ๋ณ์ Key ๊ฐ
valueFrom:
configMapKeyRef:
name: my-config # ์ฌ์ฉํ ConfigMap์ ์ด๋ฆ
key: key1 # ConfigMap ๋ด์ ํค -> ๊ฐ: value1
ConfigMap ๊ธฐ๋ณธ ํ์ฉ
- ๊ธฐ๋ณธ ์์ฑ ๋ฐ ํ์ธ
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql
data:
DBNAME: mydatabase
---
apiVersion: v1
kind: Pod
metadata:
name: nginx-configmap
spec:
containers:
- image: nginx
name: nginx-configmap
env:
- name: DB
valueFrom:
configMapKeyRef:
name: mysql
key: DBNAME
EOF
# ์ค๋ธ์ ํธ ํ์ธ
kubectl get cm,pod
# ์์ธ ์ ๋ณด ์กฐํ
kubectl describe cm mysql
kubectl describe pod nginx-configmap
# pod ๋ด๋ถ ๋ณ์ ํ์ธ
kubectl exec -it nginx-configmap -- /bin/bash -c env
...
DB=mydatabase
...
# ๋ฆฌ์์ค ์ญ์
kubectl delete pod --all
kubectl delete cm nginx-configmap
ConfigMap ์ผ๋ก ์ค์ ํ์ผ ๊ด๋ฆฌ
- yaml ์์ฑ
# ํ
์คํธ ํ์ผ ์์ฑ
cat << EOF >> config-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-configmap-deploy
spec:
replicas: 2
selector:
matchLabels:
app: nginx-configmap
template:
metadata:
labels:
app: nginx-configmap
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: config-volume
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
volumes:
- name: config-volume
configMap:
name: nginx-config
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx-configmap
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 31001
type: NodePort
EOF
cat << EOF >> configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
data:
nginx.conf: |
events {}
http {
server {
listen 80;
location / {
return 200 'Hello from nginx configmap!';
}
}
}
EOF
- ๋ฆฌ์์ค ๋ฐฐํฌ
kubectl apply -f configmap.yaml -f config-deploy.yaml
#
kubectl get cm,deploy,pod
kubectl describe deploy
...
Mounts:
/etc/nginx/nginx.conf from config-volume (rw,path="nginx.conf")
Volumes:
config-volume:
Type: ConfigMap (a volume populated by a ConfigMap)
Name: nginx-config
Optional: false
...
# Nginx ์ ์
open http://localhost:31001
# Nginx ConfigMap ๋ณ๊ฒฝ
vim configmap.yaml
...
return 200 'Modify from nginx configmap!';
...
#
kubectl apply -f configmap.yaml
# pod ์ฌ์์
kubectl rollout restart deploy nginx-configmap-deploy
# ๋ฆฌ์์ค ์ญ์
kubectl delete -f configmap.yaml -f config-deploy.yaml
๊ฒฐ๊ณผ ํ์ธ
- cm ์์ ํ deploy ์ฌ์์ํ์ฌ response ๋ณ๊ฒฝ ํ์ธ
- nginx ์ ๋ด๋ถ์์ ๋ก์ปฌํธ์ถ
kubectl exec -it $(kubectl get pod -l app=nginx-configmap -o jsonpath='{.items[0].metadata.name}') -- curl localhost:80

- ์ฐธ๊ณ ) Reloader

- ConfigMap ๋ณ๊ฒฝ ์ Pod ์๋ ์ฌ๋ฐฐํฌ๊ฐ ํ์ โ ๋นํจ์จ์
- ConfigMap, Secret ์ ๋ณ๋ ์ฌํญ์ ์ฃผ๊ธฐ์ ์ผ๋ก ํ์ธํด์ ์๋์ผ๋ก Rollout ์ ํด์ฃผ๋ ์คํ์์ค ๋๊ตฌ
3.2. Secret

- Kubernetes์ Secret์ ๋น๋ฐ๋ฒํธ, ํ ํฐ, SSH ํค ๋ฑ ๋ฏผ๊ฐํ ์ ๋ณด๋ฅผ ์์ ํ๊ฒ ๊ด๋ฆฌํ๊ธฐ ์ํ ๋ฆฌ์์ค
- ConfigMap๊ณผ ์ ์ฌํ ๋ฐฉ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ์ง๋ง, ๋ชจ๋ ๊ฐ์ Base64 ์ธ์ฝ๋ฉ๋ ์ํ๋ก ์ ์ฅ
- Base64๋ ๋จ์ ์ธ์ฝ๋ฉ์ผ ๋ฟ ์ํธํ๊ฐ ์๋๋ฉฐ, ์ ์ก ์ค ๋ ธ์ถ์ ๋ง๊ธฐ ์ํ ํ์์ผ ๋ฟ ๋ณด์์ฑ์ ๋ณด์ฅํ์ง ์์
- Secret์ ํ๋์ ํ๊ฒฝ ๋ณ์๋ก ์ฃผ์ ํ๊ฑฐ๋ ํ์ผ๋ก ๋ง์ดํธํ์ฌ ์ปจํ ์ด๋ ๋ด๋ถ์์ ์ฌ์ฉํ ์ ์์
- ์ฃผ์ ์ฌ์ฉ ์ฌ๋ก
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋น๋ฐ๋ฒํธ, API ํค, TLS ์ธ์ฆ์ ๋ฑ ์ธ๋ถ์ ๋ ธ์ถ๋๋ฉด ์ ๋๋ ์ ๋ณด ์ ์ฅ
- ConfigMap๊ณผ ๋์ผํ ๋ฐฉ์์ผ๋ก ์ฐธ์กฐ ๊ฐ๋ฅํ์ง๋ง, ๋ณด๋ค ๋ฏผ๊ฐํ ๋ฐ์ดํฐ ์ฒ๋ฆฌ์ ์ ํฉ
# Secret ์ํ
apiVersion: v1
kind: Secret
metadata:
name: my-secret
type: Opaque
data:
username: bXl1c2Vy # base64๋ก ์ธ์ฝ๋ฉ๋ ๊ฐ
password: bXlwYXNzd29yZA== # base64๋ก ์ธ์ฝ๋ฉ๋ ๊ฐ
# Secret ์ฌ์ฉ ์์
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: my-container
image: my-image
env:
- name: DB_USER # Container ์์ ์ฌ์ฉํ ๋ณ์๋ช
valueFrom:
secretKeyRef:
name: my-secret # ์ฌ์ฉํ Secret์ ์ด๋ฆ
key: username # Secret ๋ด์ ํค
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: my-secret # ์ฌ์ฉํ Secret์ ์ด๋ฆ
key: password # Secret ๋ด์ ํค
...
# ๋ง์ดํธ ๋ฐฉ๋ฒ
volumeMounts:
- name: secret-volume # Volume ๋ช
์นญ
mountPath: /etc/secrets # ์ปจํ
์ด๋ ๋ด๋ถ ๋ง์ดํธ ์์น
volumes:
- name: secret-volume # Volume ๋ช
์นญ
secret:
secretName: my-secret # ์ฌ์ฉํ Secret์ ์ด๋ฆ
Secret ๊ธฐ๋ณธ ํ์ฉ
- secret ๋ฆฌ์์ค ์์ฑ ๋ฐ ์กฐํ
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: secret-test
type: Opaque
data:
username: YWRtaW4= # 'admin'์ base64 ์ธ์ฝ๋ฉํ ๊ฐ
password: cGFzc3dvcmQ= # 'password'๋ฅผ base64 ์ธ์ฝ๋ฉํ ๊ฐ
EOF
# Base64 ์ธ์ฝ๋ฉ ๋ฐฉ๋ฒ
echo -n 'admin' | base64
echo -n 'password' | base64
#
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: secret-pod
spec:
containers:
- name: nginx
image: nginx
env:
- name: DB_USER
valueFrom:
secretKeyRef:
name: secret-test
key: username
- name: DB_PASS
valueFrom:
secretKeyRef:
name: secret-test
key: password
EOF
#
kubectl get pod,secret
# ์์ธ ์ ๋ณด ์กฐํ
kubectl describe secret secret-test
kubectl describe pod secret-pod
# pod ๋ด๋ถ ๋ณ์ ํ์ธ
kubectl exec -it secret-pod -- /bin/bash -c env
...
DB_USER=admin
DB_PASS=password
...
# ๋ฆฌ์์ค ์ญ์
kubectl delete pod --all
kubectl delete secret secret-test
๊ฒฐ๊ณผ ํ์ธ
- secret์ ์ ์ฅ๋์ด์๋ ๋ฐ์ดํฐ๋ฅผ base64 decode ํ์ฌ ํ์ธ

- pod ๋ด๋ถ์ ์ ์ฉ๋ env ๊ฐ ํ์ธ

4. Network
- Service – k8s docs
- ์ธ๋ถ์ ์ ํ๋ ๋จ์ผ ์๋ํฌ์ธํธ
- ์๋น์ค ๋ท๋จ์ ์ ํ๋ฆฌ์ผ์ด์ ์ผ๋ก ์ธ๋ถ ํธ๋ํฝ์ ์ ์ก
ClusterIP– ์ฐธ๊ณ- ์ฟ ๋ฒ๋คํฐ์ค ํด๋ฌ์คํฐ ๋ฒ์์ ๊ฐ์ IP ๋ถ์ฌ
- ํด๋ฌ์คํฐ ๋ด๋ถ์์๋ง ClusterIP ๋ก ์ ๊ทผ ๊ฐ๋ฅ
- ์๋น์ค ํ์ ์ ์ง์ ํ์ง ์์ ๊ฒฝ์ฐ ๊ธฐ๋ณธ๊ฐ
NodePort– ์ฐธ๊ณ- ๊ณ ์ ํฌํธ๋ก ๊ฐ ๋ ธ๋(Host) ์ ํฌํธ๋ฅผ ๋ ธ์ถ
- ํด๋ฌ์คํฐ ์ธ๋ถ์์ ๋ ธ๋(Host) ์ IP:Port ๋ฅผ ํตํด ์ ๊ทผ ๊ฐ๋ฅ
LoadBalancer– ์ฐธ๊ณ- ์ธ๋ถ ๋ก๋ ๋ฐธ๋ฐ์๋ฅผ ์ง์ํ๋ ํด๋ผ์ฐ๋ ๊ณต๊ธ์ ์์์ ํ์ฉ
- AWS, Azure, GCP ๋ฑ์ LB ์๋น์ค์ ์ฟ ๋ฒ๋คํฐ์ค ์๋น์ค๋ฅผ ์ฐ๊ฒฐ
4.1. ClusterIP

ํ ์คํธ ํ๊ฒฝ ๋ฐฐํฌ
# ์ดํ๋ฆฌ์ผ์ด์
๋ฐฐํฌ
cat << EOF >> cluster-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: cluster-pod-1
labels:
app: cluster-pod
spec:
containers:
- name: container
image: traefik/whoami
---
apiVersion: v1
kind: Pod
metadata:
name: cluster-pod-2
labels:
app: cluster-pod
spec:
containers:
- name: container
image: traefik/whoami
EOF
# Test ํ๋
cat << EOF >> netshoot-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: netshoot-pod
spec:
containers:
- name: netshoot-pod
image: nicolaka/netshoot
command: ["tail"]
args: ["-f", "/dev/null"]
EOF
# ClusterIP ์๋น์ค ์์ฑ
cat <<EOF>> cluster-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: cluster-svc
spec:
type: ClusterIP
selector:
app: cluster-pod
ports:
- name: cluster
port: 8080
targetPort: 80
EOF
# ๋ฐฐํฌ
kubectl apply -f cluster-pod.yaml -f cluster-svc.yaml -f netshoot-pod.yaml
pod/ClusterIP ํ์ธ
- pod ์์ฑ ํ์ธ
# ํ๋ ๋์ญ ํ์ธ
kubectl get nodes -o jsonpath='{.items[*].spec.podCIDR}'
...
10.244.0.0/24 10.244.1.0/24
...
# SVC ๋์ญ ํ์ธ
kubectl -n kube-system get pods -l component=kube-controller-manager -o yaml | grep service-cluster-ip-range
...
--service-cluster-ip-range=10.96.0.0/16
...
# ํ์ธ
kubectl get pod -o wide
...
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
cluster-pod-1 1/1 Running 0 67s 10.244.1.26 kind-worker <none> <none>
cluster-pod-2 1/1 Running 0 67s 10.244.1.27 kind-worker <none> <none>
netshoot-pod 1/1 Running 0 67s 10.244.1.28 kind-worker <none> <none>
...
# ์๋น์ค ํ์ธ
kubectl get svc cluster-svc
...
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
cluster-svc ClusterIP 10.96.193.184 <none> 8080/TCP 98s
...
# Endpoint ํ์ธ (Pod IP:Port)
kubectl get endpoints cluster-svc
...
NAME ENDPOINTS AGE
cluster-svc 10.244.1.26:80,10.244.1.27:80 113s
...
- ClusterIP ํ์ธ
# ํด๋ผ์ด์ธํธ(TestPod) Shell ์คํ
kubectl exec -it netshoot-pod -- zsh
# ์๋น์ค ClusterIP ์ฃผ์
SVC=10.96.193.184
curl $SVC:8080
curl -s $SVC:8080 | grep Hostname
# 100 ๋ฒ ๋ฐ๋ณต ํธ์ถ
for i in {1..100}; do curl -s $SVC:8080 | grep Hostname; done | sort | uniq -c | sort -nr
...
55 Hostname: cluster-pod-1
45 Hostname: cluster-pod-2
...
๊ฒฐ๊ณผ ํ์ธ
- svc rr ๋์ ํ์ธ

4.2. NodePort

ํ ์คํธ ํ๊ฒฝ ๋ฐฐํฌ
- yaml ์์ฑ
# ์ดํ๋ฆฌ์ผ์ด์
๋ฐฐํฌ
cat << EOF > nodeport-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nodeport-deploy
spec:
replicas: 2
selector:
matchLabels:
app: nodeport-deploy
template:
metadata:
labels:
app: nodeport-deploy
spec:
containers:
- name: container
image: traefik/whoami
EOF
# ClusterIP ์๋น์ค ์์ฑ
cat <<EOF> nodeport-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: nodeport-svc
spec:
type: NodePort
selector:
app: nodeport-deploy
ports:
- name: nodeport-svc
port: 80 # ์๋น์ค ํฌํธ (Cluster ๋ด๋ถ์์ ์ฌ์ฉ)
targetPort: 80 # ์ค์ ์ปจํ
์ด๋ ํฌํธ
nodePort: 31001 # ์ธ๋ถ์์ ์ ๊ทผํ NodePort
EOF
- ์์ฑ ๋ฐ ๋์ ํ์ธ
# ์์ฑ
kubectl apply -f nodeport-pod.yaml -f nodeport-svc.yaml
# ํ์ธ
kubectl get pod,svc
...
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/nodeport-svc NodePort 10.96.115.75 <none> 80:31001/TCP 10s
...
kubectl get endpoints nodeport-svc
NAME ENDPOINTS AGE
nodeport-svc 10.244.1.29:80,10.244.1.30:80 28s
NodePort ๋์ ํ์ธ
- WSL์์ nodeport ์ง์ ์ฐ๋ฅด๊ธฐ๊ฐ ์๋์ด netshoot์์ ๋ ธ๋์ ๋ ธ๋ํฌํธ ์ฐ๋ฅด๊ธฐ
# ๋
ธ๋์ Port ๋ก curl ์์ฒญ
curl http://localhost:31001
curl -s http://localhost:31001 | grep Hostname
# 100 ๋ฒ ๋ฐ๋ณต ํธ์ถ
for i in {1..100}; do curl -s http://localhost:31001 | grep Hostname; done | sort | uniq -c | sort -nr
...
58 Hostname: nodeport-deploy-59b68567d7-6h562
42 Hostname: nodeport-deploy-59b68567d7-k2cpb
...
๊ฒฐ๊ณผ ํ์ธ

4.3. Ingress
- ํด๋ฌ์คํฐ ์ธ๋ถ์์ ๋ด๋ถ ์๋น์ค๋ก ํธ๋ํฝ์ ๋ผ์ฐํ ํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํ๋ ๋ฆฌ์์ค
- ํด๋ฌ์คํฐ ๋ด๋ถ ์๋น์ค (ClusterIP, NodePort, LoadBalancer) ๋ฅผ ์ธ๋ถ๋ก ๋ ธ์ถ (HTTP / HTTPS) – Web Proxy ์ญํ
- Ingress ๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ Ingress Controller ๊ฐ ํ์
- ๋ํ์ ์ธ Ingress Controller
- Nginx Ingress Controller
- Cloud Provider Ingress Controllers
- (ex. AWS ALB Ingress Controller, GCP Ingress Controller)
- ์ฃผ์ ๊ธฐ๋ฅ
- ํธ์คํธ ๊ธฐ๋ฐ ๋ผ์ฐํ
- ํธ์คํธ ์ด๋ฆ (๋๋ฉ์ธ)์ ๊ธฐ๋ฐ์ผ๋ก ํธ๋ํฝ ๋ผ์ฐํ ๊ฐ๋ฅ
api.example.com/www.example.com์ ๊ฐ๊ฐ ๋ค๋ฅธ Service ๋ฆฌ์์ค์ ์ฐ๊ฒฐ
- ๊ฒฝ๋ก ๊ธฐ๋ฐ ๋ผ์ฐํ
- ์์ฒญ ๊ฒฝ๋ก ๊ธฐ๋ฐ์ผ๋ก ํธ๋ํฝ ๋ผ์ฐํ ๊ฐ๋ฅ
/growth,/log๊ฒฝ๋ก๋ฅผ ๊ฐ๊ฐ ๋ค๋ฅธ Service ๋ฆฌ์์ค์ ์ฐ๊ฒฐ
- TLS ์ค์
- TLS ์ธ์ฆ์๋ฅผ ํ์ฉํ์ฌ HTTPS ๊ตฌ์ฑ ๊ฐ๋ฅ
- ๋ก๋ ๋ฐธ๋ฐ์ฑ
- ๋ด๋ถ ์๋น์ค์ ๋ํ ๋ก๋ ๋ฐธ๋ฐ์ฑ
- ํธ์คํธ ๊ธฐ๋ฐ ๋ผ์ฐํ
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
namespace: default
spec:
rules:
- host: example.com # Domain Host
http:
paths:
- path: /service1 # URL Path (example.com/service1)
pathType: Prefix
backend:
service:
name: service1 # /service1 ๋ก ๋ค์ด์จ ํธ๋ํฝ์ ์ ์กํ service ๋ช
port:
number: 80
- path: /service2 # URL Path (example.com/service2)
pathType: Prefix
backend:
service:
name: service2
port:
number: 80 # /service2 ๋ก ๋ค์ด์จ ํธ๋ํฝ์ ์ ์กํ service ๋ช
Nginx Ingress Controller ์ค์น ๋ฐ ๊ตฌ์ฑ
- Ingress Controller ์ค ๊ฐ์ฅ ๋์ค์ ์ด๋ฉฐ Ingress ๋์ ๋ฐฉ์ ํ ์คํธ ๊ฐ๋ฅ
# ๊ธฐ์กด ๋ฆฌ์์ค ์ญ์
kind delete cluster
# kind cluster ์ฌ๋ฐฐํฌ
kind create cluster --config kind-2node.yaml
# Nginx Ingress Controller ์ค์น
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/deploy.yaml
# Service ํ์
๋ณ๊ฒฝ
kubectl patch svc ingress-nginx-controller -n ingress-nginx -p \
'{"spec":{"type":"NodePort","ports":[{"port":80,"targetPort":80,"nodePort":31000},{"port":443,"targetPort":443,"nodePort":31001}]}}'
# Nginx Ingress Controller ๋ฆฌ์์ค ํ์ธ
kubectl get -n ingress-nginx svc,deploy,pod
Service ๋ฐ Ingress ์์ฑ
- ์๋น์ค ์์ฑ
# Growth ์๋น์ค
cat << EOF > svc-growth.yaml
apiVersion: v1
kind: Service
metadata:
name: growth-service
spec:
selector:
app: growth
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: growth-deployment
spec:
replicas: 1
selector:
matchLabels:
app: growth
template:
metadata:
labels:
app: growth
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: growth-html
mountPath: /usr/share/nginx/html
volumes:
- name: growth-html
configMap:
name: growth-html
---
apiVersion: v1
kind: ConfigMap
metadata:
name: growth-html
data:
index.html: |
<html>
<body>
<h1>hello growth</h1>
</body>
</html>
EOF
kubectl apply -f svc-growth.yaml
# Log ์๋น์ค
cat << EOF > svc-log.yaml
apiVersion: v1
kind: Service
metadata:
name: log-service
spec:
selector:
app: log
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: log-deployment
spec:
replicas: 1
selector:
matchLabels:
app: log
template:
metadata:
labels:
app: log
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: log-html
mountPath: /usr/share/nginx/html
volumes:
- name: log-html
configMap:
name: log-html
---
apiVersion: v1
kind: ConfigMap
metadata:
name: log-html
data:
index.html: |
<html>
<body>
<h1>hello log</h1>
</body>
</html>
EOF
kubectl apply -f svc-log.yaml
# ๋ฐฐํฌ ํ์ธ
kubectl get pod,svc,cm
# ConfigMap ํ์ธ
kubectl describe cm growth-html
kubectl describe cm log-html
- Ingress ๋ฐฐํฌ
cat << EOF > ingress-sample.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: growth-log-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: / # /growth, /log ์์ฒญ์ ์๋น์ค๋ก ์ ๋ฌํ ๋ ์ ๋์ฌ ์ ๊ฑฐ. ex) /growth -> growth-service '/'
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /growth
pathType: Prefix
backend:
service:
name: growth-service
port:
number: 80
- path: /log
pathType: Prefix
backend:
service:
name: log-service
port:
number: 80
EOF
kubectl apply -f ingress-sample.yaml
kubectl get ing,svc
#
kubectl describe ingress growth-log-ingress
Ingress ๋์ ํ์ธ
- ๊ฒฝ๋ก ๊ธฐ๋ฐ ์๋ต ํ์ธ
# growth ๊ฒฝ๋ก ํธ์ถ
curl http://localhost:31000/growth
...
<html>
<body>
<h1>hello growth</h1>
</body>
</html>
...
# Log ๊ฒฝ๋ก ํธ์ถ
curl http://localhost:31000/log
...
<html>
<body>
<h1>hello log</h1>
</body>
</html>
...
๊ฒฐ๊ณผ ํ์ธ
- nginx ingress pod์์ ๊ฐ ๊ฒฝ๋ก ํธ์ถ์ ํด๋น pod์ ์๋ต ํ์ธ

5. Storage

emptyDir- Pod ๋ด๋ถ์ ์กด์ฌํ๋ฉฐ ๋์ผํ Pod ์ ์ปจํ ์ด๋ ๊ฐ ๊ณต์ ๋ ์ ์๋ ์คํ ๋ฆฌ์ง
- Pod ์ญ์ ์ ํจ๊ป ์ญ์
- Container ๊ฐ ์ฌ์ฉํ๋ ์์ ์ ์ฅ์
hostPath- Pod ๊ฐ ๋ฐฐํฌ๋ Worker Node ์ Directory Path ๋ฅผ Pod ์ ๋ง์ดํธ
- Pod ๊ฐ ์ญ์ ๋์ด๋ ๋ฐ์ดํฐ๋ Worker Node ์ ์กด์ฌ
- ํ์ง๋ง ํด๋น Pod ๊ฐ ๋ฐฐํฌ๋ Node ์๋ง ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ฏ๋ก, ๋ค๋ฅธ ๋ ธ๋์ ๋ฐฐํฌ๋ ํ๋์๋ ๊ณต์ ํ ์ ์์
Persistent volume (PV)- ์ฟ ๋ฒ๋คํฐ์ค ํด๋ฌ์คํฐ ์ ์ฒด์ ๊ณต์ ๋ณผ๋ฅจ
- ๋ค์ํ ํฌ๊ธฐ์ ๋ณผ๋ฅจ์ ๊ฐ์ง PV ๋ฅผ ๋ฏธ๋ฆฌ ๋ง๋ค์ด ๋๊ณ Pod ๊ฐ ํ์ํ ๋ ์ฐ๊ฒฐํ์ฌ ์ฌ์ฉ
- ์ด ๋, Pod ์ PV ๋ฅผ ์ฐ๊ฒฐํ๋ ์์ ์ด PVC(PersistentVolumeClaim)

