๐ฆ 04. K8s ๊ธฐ๋ณธ ๋ฆฌ์์ค
1. Pod
์๋์ ๊ฐ์ด goapp.yaml ํ์ผ์ ๋ง๋ญ๋๋ค.
- Pod ์์ฑ ํด๋ณด๊ธฐ
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
kubectl create -f ./nginx.yaml
ใดใดssss
- ์ผ๋ฐ์ ์ผ๋ก apply ๋ฅผ ๋ ๋ง์ด ์!!
- create ๋ ์ต์ด ์์ฑ์ ์ฌ์ฉ ํ ์ ์์ผ๋ฉฐ, ์ด๋ฏธ ์ค๋ธ์ ํธ๊ฐ ์์ผ๋ฉด ์๋ฌ๋จ
- apply ๋ ์์ผ๋ฉด ๋ง๋ค๊ณ , ์์ผ๋ฉด ์ ๋ฐ์ดํธ ํจ
kubectl get pod
- POD ์๋น์ค ์ ์ ๋ฐ ๋ก๊ทธํ์ธ
- ์ ์์ ์ํ ํฌํธํฌ์๋ฉ
kubectl port-forward nginx-pod 8080:80
- Pod์ ๋คํธ์ํฌ IP ์กฐํ
kubectl get po -o wide
- ๋ค๋ฅธ ํฐ๋ฏธ๋์์ curl ์ ์ด์ฉํด์ ํ ์คํธ
curl http://<Pod-IP-Address>:8080
- POD Bash ์ ์
kubectl exec -it nginx-pod -- bash
- POD ์ด๋ฒคํธ ํ์ธํ๊ธฐ
kubectl describe po nginx-pod
- ์ปจํ ์ด๋ ๋ก๊ทธ ํ์ธ ํด๋ณด๊ธฐ
kubectl logs nginx-pod
- [์ฐ์ต๋ฌธ์ ] 4-1. Pod ์์ฑํ๊ธฐ
์๋ ์กฐ๊ฑด์ ๋ง์กฑํ๋ Pod๋ฅผ ์์ฑํ๋ YAML ํ์ผ์ ์์ฑํ๊ณ , ์ค์ ๋ก ํด๋ฌ์คํฐ์ ๋ฐฐํฌํด๋ณด์ธ์.
- Pod ์ด๋ฆ: my-redis
- ์ปจํ ์ด๋ ์ด๋ฆ: redis
- ์ปจํ ์ด๋ ์ด๋ฏธ์ง: redis:7.2
- ์ปจํ
์ด๋๊ฐ 6379๋ฒ ํฌํธ๋ก ์๋น์ค
redis๊ฐ ์คํ์ค์ธ ์ปจํ ์ด๋์ bash๋ก ์ ์ํ ํ๋ก์ธ์ค๋ฅผ ์กฐํ ํ์ธ์
ํ๋์ ์ด๋ฒคํธ ๋ก๊ทธ๋ฅผ ํ์ธํ์ธ์
redis ์ปจํ ์ด๋์ ๋ก๊ทธ๋ฅผ ํ์ธํ์ธ์
2. ๋ผ๋ฒจ(Label)๊ณผ ์ด๋ ธํ ๋์ (annotaion)
- ๋ผ๋ฒจ(label)
- goapp-with-label.yaml ์ด๋ผ ํ์ผ์ ์๋ ๋ด์ฉ์ ์ถ๊ฐ ํ์ฌ ์์ฑ ํฉ๋๋ค.
apiVersion: v1
kind: Pod
metadata:
name: goapp-pod
labels:
env: prod
tier: backend
spec:
containers:
- image: dangtong/goapp
name: goapp-container
ports:
- containerPort: 8080
protocol: TCP
- yaml ํ์ผ์ ์ด์ฉํด pod ๋ฅผ ์์ฑ ํฉ๋๋ค.
kubectl apply -f ./goapp-with-label.yaml
- ์์ฑ๋ POD๋ฅผ ์กฐํ ํฉ๋๋ค.
kubectl get po --show-labels
- label ํ๊ทธ๋ฅผ ์ถ๋ ฅ ํ๋ฉด์ ์ปฌ๋ผ์ ๋ถ๋ฆฌํด์ ์ถ๋ ฅ
kubectl get po -L env -L tier
- Label ์ถ๊ฐ
kubectl label po goapp-pod app=web
- label ์์
kubectl label po goapp-pod app=api --overwrite
- Label ์ญ์
kubectl label po goapp-pod app-
- ์ด๋ ธํ ์ด์ (Annotation)
- Annotaion ์ถ๊ฐ
kubectl annotate pod goapp-pod maker="dangtong" team="k8s-team"
- Annotation ํ์ธ
kubectl describe po goapp-pod
- Annotation ์ญ์
kubectl annotate po goapp-pod maker- team-
- [์ฐ์ต๋ฌธ์ ] 4-2. Label ๋ฐ Annotaion ์ค์ต
bitnami/apache ์ด๋ฏธ์ง๋ก Pod ๋ฅผ ๋ง๋ค๊ณ tier=FronEnd, app=apache ๋ผ๋ฒจ ์ ๋ณด๋ฅผ ํฌํจํ์ธ์
Pod ์ ๋ณด๋ฅผ ์ถ๋ ฅ ํ ๋ ๋ผ๋ฒจ์ ํจ๊ป ์ถ๋ ฅ ํ์ธ์
app=apache ๋ผ๋ฒจํ ๊ฐ์ง Pod ๋ง ์กฐํ ํ์ธ์
๋ง๋ค์ด์ง Pod์ env=dev ๋ผ๋ ๋ผ๋ฒจ ์ ๋ณด๋ฅผ ์ถ๊ฐ ํ์ธ์
created_by=kevin ์ด๋ผ๋ Annotation์ ์ถ๊ฐ ํ์ธ์
๋ชจ๋ ๋ผ๋ฒจ๊ณผ ์ด๋ ธํ ์ด์ ์ ์ญ์ ํ์ธ์
3. Namespace
- ํ์ฌ ๋ค์์คํ์ด์ค ์กฐํ
kubectl get namespace
kubens
- ํน์ ๋ค์์คํ์ด์ค์ ๋ฆฌ์์ค ์กฐํ
kubectl get po --namespace kube-system
kubectl get po -n kube-system
- ๋ค์์คํ์ด์ค ์์ฑ
- YAML ํ์ผ ์์ฑ : first-namespace.yaml ์ด๋ฆ์ผ๋ก ํ์ผ ์์ฑ
apiVersion: v1
kind: Namespace
metadata:
name: first-namespace
- YAML ํ์ผ์ ์ด์ฉํ ๋ค์ด์คํ์ด์ค ์์ฑ
kubectl create -f first-namespace.yaml
- ์์ฑ๋ ๋ค์์คํ์ด์ค ํ์ธ
kubectl get ns
- ๋ช ๋ น์ด ์ด์ฉํ ๋ค์์คํ์ด์ค ์์ฑ
kubectl create ns second-namespace
- ๋ค์์คํ์ด์ค ์ด๋
๊ธฐ๋ณธ์ ์ผ๋ก ์ฟ ๋ฒ๋คํฐ์ค์์ ์ง์ ํ๋ ๋ฐฉ๋ฒ
kubectl config set-context --current --namespace=<namespace-name>
kubens ๋ฅผ ์ค์นํ๋ฉด ๋ค์์คํ์ด์ค ๋ชฉ๋ก,ํ์ฌ ๋ค์์คํ์ด์ค ํ์ธ ํ๊ณ , ๋ค๋ฅธ ๋ค์์คํ์ด์ค๋ก ์ด๋ ๊ฐ๋ฅ
kubens
kubens kube-system
- ๊ธฐํ ๋ค์์คํ์ด์ค ๊ด๋ จ
- ๋ชจ๋ ๋ค์์คํ์ด์ค์ Pod ์กฐํ
kubectl get po -A
- ๋ชจ๋ ๋ค์์คํ์ด์ค์ ๋ฆฌ์์ค ์กฐํ
kubectl get all -A
- ํน์ ๋ค์์คํ์ด์ค์์์ ๋ฆฌ์์ค ์กฐํ
kubectl get po -n kube-system
- ๋ค์์คํ์ด์ค ๋ ๋ฒจ ๋ฆฌ์์ค ์กฐํ
kubectl api-resources --namespaced=true
- ๋ค์์คํ์ด์ค๊ฐ ์๋ ๋ฆฌ์์ค ์กฐํ
kubectl api-resources --namespaced=false
- ๋ค์์คํ์ด์ค ์ญ์
kubectl delete ns first-namespace second-namespace
4. Probe
- Liveness Probe ํ ์คํธ
์ปจํ ์ด๋๊ฐ ์ด์์๋์ง ํ์ธํ๊ณ , ์คํจ ์ ์ปจํ ์ด๋๋ฅผ ์ฌ์์ํฉ๋๋ค.
HTTP Liveness Probe
- Liveness Probe ์์ฑ
liveness prove๋ Pod์ ์ง์ ๋ ์ฃผ์์ Health Check ๋ฅผ ์ํํ๊ณ ์คํจํ ๊ฒฝ์ฐ Pod๋ฅผ ๋ค์ ์์ ํฉ๋๋ค.
์ด๋ ์ค์ํ ์ ์ ๋จ์ํ ๋ค์ ์์๋ง ํ๋ ๊ฒ์ด ์๋๋ผ, ๋ฆฌํฌ์งํ ๋ฆฌ๋ก ๋ถํฐ ์ด๋ฏธ์ง๋ฅผ ๋ค์ ๋ฐ์ Pod ๋ฅผ ๋ค์ ์์ ํฉ๋๋ค.
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-http
spec:
containers:
- name: liveness
image: k8s.gcr.io/liveness
args:
- /server
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: Custom-Header
value: Awesome
initialDelaySeconds: 3
periodSeconds: 3
K8s.gcr.io/liveness ์ด๋ฏธ์ง๋ liveness ํ
์คํธ๋ฅผ ์ํด ๋ง๋ค์ด์ง ์ด๋ฏธ์ง ์
๋๋ค.
์์ธํ ์ฌํญ์ gihub ์ liveness ์ ์ฐธ๊ณ ํ์ธ์
Go ์ธ์ด๋ก ์์ฑ ๋์์ผ๋ฉฐ, ์ฒ์ 10์ด ๋์์ ์ ์์ ์ธ ์๋น์ค๋ฅผ ํ์ง๋ง, 10์ด ํ์๋ ์๋ฌ๋ฅผ ๋ฐ์ ์ํต๋๋ค. ์ฝ๋๋ฅผ ์์ธํ ๋ณด๋ฉด ์๋์ ๊ฐ์ต๋๋ค.
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
duration := time.Now().Sub(started)
if duration.Seconds() > 10 {
w.WriteHeader(500)
w.Write([]byte(fmt.Sprintf("error: %v", duration.Seconds())))
} else {
w.WriteHeader(200)
w.Write([]byte("ok"))
}
})
- pod ์์ฑ
kubectl create -f ./liveness-probe-pod.yaml
- pod ํ์ธ
kubectl create -f ./liveness-probe-pod.yaml
- pod ์ด๋ฒคํธ ๋ก๊ทธ ํ์ธ
kubectl describe pod liveness-http
Command Liveness Probe
liveness-command-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-command-pod
spec:
containers:
- name: liveness-command
image: busybox:latest
command: ["/bin/sh", "-c", "touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600"]
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
- pod ์์ฑ
kubectl create -f ./liveness-command-pod.yaml
- pod ํ์ธ
kubectl create -f ./liveness-command-pod.yaml
- pod ์ด๋ฒคํธ ๋ก๊ทธ ํ์ธ
kubectl describe pod liveness-command-pod
- Readiness Probe
์ปจํ ์ด๋๊ฐ ์์ฒญ์ ๋ฐ์ ์ค๋น๊ฐ ๋์๋์ง ํ์ธํ๊ณ , ์คํจ ์ ์๋น์ค ์๋ํฌ์ธํธ์์ ์ ๊ฑฐํฉ๋๋ค.
์ค์ต ์์ 1: HTTP Readiness Probe
apiVersion: v1
kind: Pod
metadata:
name: readiness-http-pod
spec:
containers:
- name: readiness-http
image: nginx:latest
ports:
- containerPort: 80
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 3
timeoutSeconds: 2
failureThreshold: 2
์ค์ต ์์ 2: TCP Readiness Probe
apiVersion: v1
kind: Pod
metadata:
name: readiness-tcp-pod
spec:
containers:
- name: readiness-tcp
image: redis:7.2
ports:
- containerPort: 6379
readinessProbe:
tcpSocket:
port: 6379
initialDelaySeconds: 5
periodSeconds: 10
- Startup Probe
์ ํ๋ฆฌ์ผ์ด์ ์ ์ด๊ธฐ ์์ ์๊ฐ์ด ๊ธด ๊ฒฝ์ฐ ์ฌ์ฉํ๋ฉฐ, ์์ ํ๋ก๋ธ๊ฐ ์ฑ๊ณตํ ๋๊น์ง ๋ค๋ฅธ ํ๋ก๋ธ๋ค์ ๋นํ์ฑํ๋ฉ๋๋ค.
์ค์ต ์์ : Startup Probe with Liveness
apiVersion: v1
kind: Pod
metadata:
name: startup-probe-pod
spec:
containers:
- name: startup-app
image: nginx:latest
ports:
- containerPort: 80
startupProbe:
httpGet:
path: /
port: 80
failureThreshold: 30
periodSeconds: 10
livenessProbe:
httpGet:
path: /
port: 80
periodSeconds: 5
readinessProbe:
httpGet:
path: /
port: 80
periodSeconds: 3
- [์ฐ์ต๋ฌธ์ ] 4-3. Probe ์ค์ต
1. Liveness Probe ์ค์ต
์๋ ์กฐ๊ฑด์ ๋ง์กฑํ๋ Pod๋ฅผ ์์ฑํ์ธ์:
- Pod ์ด๋ฆ: liveness-demo
- ์ด๋ฏธ์ง: nginx:latest
- Liveness probe: HTTP GET /health (ํฌํธ 80)
- ์ด๊ธฐ ์ง์ฐ: 10์ด, ์ฃผ๊ธฐ: 5์ด, ํ์์์: 3์ด, ์คํจ ์๊ณ๊ฐ: 3
2. Readiness Probe ์ค์ต
์๋ ์กฐ๊ฑด์ ๋ง์กฑํ๋ Pod๋ฅผ ์์ฑํ์ธ์:
- Pod ์ด๋ฆ: readiness-demo
- ์ด๋ฏธ์ง: redis:7.2
- Readiness probe: TCP ์์ผ (ํฌํธ 6379)
- ์ด๊ธฐ ์ง์ฐ: 5์ด, ์ฃผ๊ธฐ: 10์ด
3. Probe ์ํ ํ์ธ ๋ช ๋ น์ด
# Pod ์ํ ํ์ธ
kubectl get po
# Pod ์์ธ ์ ๋ณด ํ์ธ (Probe ์ํ ํฌํจ)
kubectl describe po <pod-name>
# Pod ๋ก๊ทธ ํ์ธ
kubectl logs <pod-name>
# Pod ์ด๋ฒคํธ ํ์ธ
kubectl get events --sort-by='.lastTimestamp'
4. Probe ํ ์คํธ ๋ฐฉ๋ฒ
# 1. Pod ์์ฑ
kubectl apply -f liveness-demo.yaml
# 2. Pod ์ํ ๋ชจ๋ํฐ๋ง
kubectl get po -w
# 3. Pod ์์ธ ์ ๋ณด ํ์ธ
kubectl describe po liveness-demo
# 4. Pod ๋ก๊ทธ ํ์ธ
kubectl logs liveness-demo
# 5. Pod ์ญ์
kubectl delete po liveness-demo
- Probe ์ค์ ์ต์ ์ค๋ช
๊ณตํต ์ต์ :
initialDelaySeconds: ์ปจํ ์ด๋ ์์ ํ ์ฒซ ๋ฒ์งธ ํ๋ก๋ธ ์คํ๊น์ง ๋๊ธฐ ์๊ฐperiodSeconds: ํ๋ก๋ธ ์คํ ์ฃผ๊ธฐtimeoutSeconds: ํ๋ก๋ธ ํ์์์ ์๊ฐfailureThreshold: ์คํจ ์๊ณ๊ฐ (์ด ํ์๋งํผ ์คํจํ๋ฉด ์คํจ๋ก ๊ฐ์ฃผ)successThreshold: ์ฑ๊ณต ์๊ณ๊ฐ (Readiness/Startup probe์์๋ง ์ฌ์ฉ)
ํ๋ก๋ธ ํ์ :
- httpGet: HTTP GET ์์ฒญ
- tcpSocket: TCP ์์ผ ์ฐ๊ฒฐ
- exec: ๋ช ๋ น์ด ์คํ
5. Replication Controller
- Replication Controller ์์ฑ
apiVersion: v1
kind: ReplicationController
metadata:
name: goapp-rc
spec:
replicas: 3
selector:
app: goapp
template:
metadata:
name: goapp-pod
labels:
tier: forntend
app: goapp
env: prod
priority: high
spec:
containers:
- name: goapp-container
image: dangtong/goapp
ports:
- containerPort: 8080
- ์์ฑ ํ์ธ
kubectl get po,rc
- Pod ์ญ์ ํ ๋ณํ ํ์ธ
kubectl delete pod goapp-rc-<random-hash>
- Pod ์ ๋ณด ์ถ๋ ฅ
kubectl get pod --show-labels
- Pod ๋ผ๋ฒจ ๋ณ๊ฒฝ ๋ฐ ํ์ ํ์ธ
kubectl label pod goapp-rc-szv2r app=goapp-exit --overwrite
kubectl get po
- Pod ์ด๋ฏธ์ง ๋ณ๊ฒฝ
kubectl edit rc goapp-rc
์ด๋ฏธ์ง ๋ถ๋ถ์ ์ฐพ์์ goapp-v2๋ก ๋ณ๊ฒฝํฉ๋๋ค.
template:
metadata:
creationTimestamp: null
labels:
app: goapp
name: goapp-pod
spec:
containers:
- image: dangtong/goapp-v2 # ์ด๋ถ๋ถ์ ๋ณ๊ฒฝ ํฉ๋๋ค.(๊ธฐ์กด : dangtong/goapp)
imagePullPolicy: Always
name: goapp-container
- Pod ์ญ์ ํ๊ณ ์ ์ฉ
- Pod ์กฐํ
kubectl get pod
‘‘‘bash
kubectl delete pod goapp-rc-
```bash
kubectl get po -o wide
- Pod ์ค์ผ์ผ์์
kubectl scale rc goapp-rc --replicas=5
kubectl get po
- Replication Controller ์ญ์
- Pod ๋ ๊ทธ๋๋ ๋๊ณ Replication Controller ๋ง์ญ์
kubectl delete rc goapp-rc --cascade=orphan
- ๋ชจ๋ ์ญ์
kubectl delete rc goapp-rc
6. Replica Set
- ReplicaSet ์์ฑ
Selector ๋ฅผ ์์ฑ ํ ๋ ForntEnd ์ด๊ณ ์ด์๊ณ ์ด๋ฉด์ ์ค์๋๊ฐ High ์ธ POD ์ ๋ํด RS ๋ฅผ ์์ฑ ํฉ๋๋ค.
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
labels:
app: guestbook
tier: frontend
spec:
replicas: 3
selector:
matchLabels:
tier: frontend
matchExpressions:
- {key: env, operator: In, values: [prod]}
- {key: priority, operator: NotIn, values: [low]}
template:
metadata:
labels:
tier: frontend
env: prod
priority: high
spec:
containers:
- name: nginx-frontend
image: nginx:1.29
ports:
- containerPort: 80
kubectl apply -f ./rs.yml
- RS ํ์ธ
kubectl get po -o wide
kubectl get rs -o wide
kubectl get po --show-labels
- [์ฐ์ต๋ฌธ์ ] 4-4. RC,RS ์์ฑ ์ค์ต
Nginx:1.14.2 Pod 3๊ฐ๋ก ๊ตฌ์ฑ๋ Replication Controller๋ฅผ ์์ฑํ์ธ์
Replication Controller๋ง ์ญ์ ํ์ธ์ (Pod๋ ์ ์ง)
๋จ๊ฒจ์ง Nginx Pod๋ฅผ ๊ด๋ฆฌํ๋ ReplicaSet์ ์์ฑํ๋ replica 4๊ฐ๋ก ๊ตฌ์ฑํ์ธ์
Nginx Pod๋ฅผ 6๊ฐ๋ก Scale Out ํ์ธ์
์ ์ฒด ๊ณผ์ ํ์ธ ๋ช ๋ น์ด
7. DeamonSet
- DaemonSet ์์ฑ
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: goapp-on-ssd
spec:
selector:
matchLabels:
app: goapp-pod
template:
metadata:
labels:
app: goapp-pod
spec:
nodeSelector:
disk: ssd
containers:
- name: goapp-container
image: dangtong/goapp
kubectl apply -f ./ds.yaml
kubectl get po,ds
์กฐํ ํ๋ฉด Pod ๋ ์กด์ฌํ์ง ์๊ณ ๋ฐ๋ชฌ์
์ ๋ณด๋ฅผ ์กฐํ ํด๋ ๋ชจ๋ 0 ์ผ๋ก ๋์ต๋๋ค. ๋
ธ๋์ disk=ssd ๋ผ๋ฒจ์ด ์๊ธฐ ๋๋ฌธ์
๋๋ค.
๋ฐ๋ผ์, ์กฐ๊ฑด์ ๋ง์กฑ ์ํค๊ธฐ ์ํด Label ์ ๋
ธ๋์ ์ถ๊ฐ ํฉ๋๋ค.
- ๋ ธ๋๋ผ๋ฒจ ์ถ๊ฐ
- ํ์ฌ ๋ ธ๋ ๋ชฉ๋ก ์กฐํ
kubectl get no
- ํน์ ๋ ธ๋์ Label ์ถ๊ฐ
kubectl label node <node-name> disk=ssd
kubectl get ds -o wide
8. Deployment
Deployment๋ Pod์ ReplicaSet์ ๋ํ ์ ์ธ์ ์ ๋ฐ์ดํธ๋ฅผ ์ ๊ณตํ๋ฉฐ, ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฐฐํฌ์ ์ ๋ฐ์ดํธ๋ฅผ ๊ด๋ฆฌํฉ๋๋ค.
- ๊ธฐ๋ณธ Deployment ์์ฑ
1. nginx Deployment ์์ฑ
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.29
ports:
- containerPort: 80
2. Deployment ์์ฑ ๋ฐ ํ์ธ
kubectl apply -f nginx-deployment.yaml
kubectl get deployment
kubectl get pods -l app=nginx
- Deployment ์ ๋ฐ์ดํธ
1. Change Cause๋ฅผ ํฌํจํ ์ด๋ฏธ์ง ์ ๋ฐ์ดํธ
# kubectl set image ๋ช
๋ น์ด ์ฌ์ฉ (change cause ํฌํจ)
kubectl set image deployment/nginx-deployment nginx=nginx:1.14.2 --record
# ๋๋ YAML ํ์ผ ์์ ํ ์ ์ฉ (change cause ํฌํจ)
kubectl apply -f nginx-deployment-v2.yaml --record
์ฐธ๊ณ : --record ํ๋๊ทธ๋ ์ต์ Kubernetes ๋ฒ์ ์์ deprecated๋์์ต๋๋ค. Change cause๋ฅผ ์ถ์ ํ๋ ค๋ฉด kubectl annotate๋ฅผ ์ฌ์ฉํ์ธ์:
# Annotate๋ฅผ ์ฌ์ฉํ change cause ์ค์ (๊ถ์ฅ ๋ฐฉ๋ฒ)
kubectl annotate deployment/nginx-deployment kubernetes.io/change-cause="Update to nginx 1.30 for performance improvements"
2. ์ ๋ฐ์ดํธ ๊ณผ์ ํ์ธ
# ์
๋ฐ์ดํธ ์ํ ํ์ธ
kubectl rollout status deployment/nginx-deployment
# ์
๋ฐ์ดํธ ์ด๋ ฅ ํ์ธ (change cause ํฌํจ)
kubectl rollout history deployment/nginx-deployment
# ์์ธ ์ด๋ ฅ ํ์ธ
kubectl rollout history deployment/nginx-deployment --revision=2
# ์์ธ ์ ๋ณด ํ์ธ
kubectl describe deployment nginx-deployment
3. Change Cause ํ์ธ ์์
# ์ด๋ ฅ ํ์ธ (change cause ํ์)
kubectl rollout history deployment/nginx-deployment
# ์ถ๋ ฅ ์์:
# REVISION CHANGE-CAUSE
# 1 kubectl apply --filename=nginx-deployment.yaml --record=true
# 2 kubectl set image deployment/nginx-deployment nginx=nginx:1.30 --record=true
# 3 kubectl set image deployment/nginx-deployment nginx=nginx:1.31 --record=true
- Deployment ๋กค๋ฐฑ
1. ์ด์ ๋ฒ์ ์ผ๋ก ๋กค๋ฐฑ
# ์ด์ ๋ฒ์ ์ผ๋ก ๋กค๋ฐฑ
kubectl rollout undo deployment/nginx-deployment
# ํน์ ๋ฒ์ ์ผ๋ก ๋กค๋ฐฑ
kubectl rollout undo deployment/nginx-deployment --to-revision=2
2. ๋กค๋ฐฑ ํ์ธ
# ๋กค๋ฐฑ ์ํ ํ์ธ
kubectl rollout status deployment/nginx-deployment
# ๋กค๋ฐฑ ์ด๋ ฅ ํ์ธ
kubectl rollout history deployment/nginx-deployment
- Deployment ์ค์ผ์ผ๋ง
1. Replica ์ ๋ณ๊ฒฝ
# ์ค์ผ์ผ ์์
kubectl scale deployment nginx-deployment --replicas=5
# ์ค์ผ์ผ ์ธ
kubectl scale deployment nginx-deployment --replicas=2
2. ์ค์ผ์ผ๋ง ํ์ธ
kubectl get deployment nginx-deployment
kubectl get pods -l app=nginx
- Deployment ์ ๋ต
1. Rolling Update (๊ธฐ๋ณธ)
- Deployment ์์ฑ
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 5
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.29
ports:
- containerPort: 80
- ์ด๋ฏธ์ง ์ ๋ฐ์ดํธ
kubectl set image deployment/nginx-deployment nginx=nginx:1.14.2 --record
- ๋กค๋ง ์ ๋ฐ์ดํธ ์ํ ํ์ธ
kubectl rollout status deployment/nginx-deployment
kubectl get po -w
kubectl get po
2. Recreate ์ ๋ต
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-recreate
spec:
replicas: 3
strategy:
type: Recreate
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.29
ports:
- containerPort: 80
- [์ฐ์ต๋ฌธ์ ] 4-5. Deployment ์ค์ต
1. ๊ธฐ๋ณธ Deployment ์์ฑ
์๋ ์กฐ๊ฑด์ ๋ง์กฑํ๋ Deployment๋ฅผ ์์ฑํ์ธ์:
- Deployment ์ด๋ฆ: httpd-deployment
- ์ด๋ฏธ์ง: httpd:2.4
- Replica: 3๊ฐ
- ํฌํธ: 80
2. Deployment ์ ๋ฐ์ดํธ (Change Cause ํฌํจ)
์์ฑ๋ Deployment์ ์ด๋ฏธ์ง๋ฅผ httpd:latest๋ก ์ ๋ฐ์ดํธํ๊ณ change cause๋ฅผ ๊ธฐ๋กํ์ธ์.
3. Deployment ์ค์ผ์ผ๋ง
Deployment๋ฅผ 5๊ฐ replica๋ก ์ค์ผ์ผ ์์ํ์ธ์.
4. Deployment ๋กค๋ฐฑ (Change Cause ํ์ธ)
- rollout ํ์คํ ๋ฆฌ๋ฅผ ํ์ํ์ธ์
- version 2 ์ ์์ธ ์ํ๋ฅผ ํ์ธํ์ธ์
- ์ด์ ๋ฒ์ ์ผ๋ก ๋กค๋ฐฑํ๊ณ change cause๋ฅผ ํ์ธํ์ธ์.
5. Deployment ๊ด๋ฆฌ ๋ช ๋ น์ด (Change Cause ํฌํจ)
- Deployment ์ฌ์ฉ ์ฌ๋ก
- ์น ์ ํ๋ฆฌ์ผ์ด์ : nginx, Apache ๋ฑ
- API ์๋ฒ: REST API, GraphQL ๋ฑ
- ๋ง์ดํฌ๋ก์๋น์ค: ๊ฐ ์๋น์ค๋ณ ๋ ๋ฆฝ์ ๋ฐฐํฌ
- ๋ฐฐ์น ์์ : ์ฃผ๊ธฐ์ ์คํ๋๋ ์์
- ์ ๋ฆฌ
# ๋ฆฌ์์ค ์ญ์
kubectl delete deployment nginx-deployment
kubectl delete deployment nginx-deployment-recreate
kubectl delete deployment httpd-deployment
9. StatefulSet
StatefulSet ์ ๋์คํฌ๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ์คํ ๋ฆฌ์ง๋ฅผ ํ์ตํ ํ์ ๋ฐฐ์ฐ๋๋ก ํ ๊ป์!
- ์ ํ๋ฆฌ์ผ์ด์ ์ด๋ฏธ์ง ์์ฑ
// docker/app.js
const http = require('http');
const os = require('os');
const fs = require('fs');
const dataFile = "/var/data/kubia.txt";
const port = 8080;
// ํ์ผ ์กด์ฌ ์ /๋ฌด ๊ฒ์ฌ
function fileExists(file) {
try {
fs.statSync(file);
return true;
} catch (e) {
return false;
}
}
var handler = function(request, response) {
// POST ์์ฒญ์ผ ๊ฒฝ์ฐ BODY์ ์๋ ๋ด์ฉ์ ํ์ผ์ ๊ธฐ๋ก ํจ
if (request.method == 'POST') {
var file = fs.createWriteStream(dataFile);
file.on('open', function (fd) {
request.pipe(file);
console.log("New data has been received and stored.");
response.writeHead(200);
response.end("Data stored on pod " + os.hostname() + "\n");
});
// GET ์์ฒญ์ผ ๊ฒฝ์ฐ ํธ์คํธ๋ช
๊ณผ ํ์ผ์ ๊ธฐ๋ก๋ ๋ด์ฉ์ ๋ฐํ ํจ
} else {
var data = fileExists(dataFile) ? fs.readFileSync(dataFile, 'utf8') : "No data posted yet";
response.writeHead(200);
response.write("You've hit " + os.hostname() + "\n");
response.end("Data stored on this pod: " + data + "\n");
}
};
var www = http.createServer(handler);
www.listen(port);
- ๋์ปค ์ด๋ฏธ์ง ๋ง๋ค๊ธฐ
# docker/Dockerfile
FROM node:7
ADD app.js /app.js
ENTRYPOINT ["node", "app.js"]
docker build <Docker-ID>/nodejs:sfs . --push
docker buildx build --platform linux/amd64,linux/arm64 -t <Docker-ID>/nodejs:sfs . --push
docker login -u <Docker-ID>
docker push <Docker-ID>/nodejs:sfs
- StatefulSet ์์ฑ
# kubetemp/sts.yml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nodejs-sfs
spec:
selector:
matchLabels:
app: nodejs-sfs
serviceName: nodejs-sfs
replicas: 2
template:
metadata:
labels:
app: nodejs-sfs
spec:
containers:
- name: nodejs-sfs
image: <Your-Docker-ID>/nodejs:sfs
ports:
- name: http
containerPort: 8080
volumeMounts:
- name: data
mountPath: /var/data
volumeClaimTemplates:
- metadata:
name: data
spec:
resources:
requests:
storage: 1Mi
accessModes:
- ReadWriteOnce
storageClassName: gp2
kubectl apply -f ./sts.yml
kubectl get po -w
- LoadBalancer ์์ฑ
# kubetemp/lb.yml
apiVersion: v1
kind: Service
metadata:
name: nodesjs-sfs-lb
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: external
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
spec:
type: LoadBalancer
sessionAffinity: None
ports:
- port: 80
targetPort: 8080
selector:
app: nodejs-sfs
kubectl apply -f ./lb.yml
- ์๋น์ค ํ์ธ
kubectl get svc
- ๋ก๋๋ฐธ๋ฐ์ ํ์ฑ ์ํ ํ์ธ (State ํญ๋ชฉ ํ์ธ)
aws elbv2 describe-load-balancers
- ๋ฐ์ดํ ์กฐํ
curl http://<public-domain>
- ๋ฐ์ดํฐ ์ ๋ ฅ
curl -X POST -d "hi, my name is dangtong-1" <public-domain>
curl -X POST -d "hi, my name is dangtong-2" <public-domain>
curl -X POST -d "hi, my name is dangtong-3" <public-domain>
curl -X POST -d "hi, my name is dangtong-4" <public-domain>
curl -X POST -d "hi, my name is dangtong-5" <public-domain>
๋ฐ์ดํฐ ์ ๋ ฅ์ ๋ฐ๋ณตํ์ ๋๊ฐ ๋ ธ๋ ๋ชจ๋์ ๋ฐ์ดํฐ๋ฅผ ๋ชจ๋ ์ ์ฅ ํฉ๋๋ค. ์์ชฝ ๋ ธ๋์ ์ด๋ค ๋ฐ์ดํฐ๊ฐ ์ ๋ ฅ ๋์๋์ง ๊ธฐ์ต ํ๊ณ ๋ค์ ๋จ๊ณ๋ก ๋์ด ๊ฐ๋๋ค.
10. StatefulSet ์ฐ์ต๋ฌธ์
์ฐ์ต๋ฌธ์ ์ฉ ๋ค์์คํ์ด์ค ์์ฑ
kubectl create namespace statefulset-lab
kubectl config set-context --current --namespace=statefulset-lab
์ฐ์ต๋ฌธ์ 1: ๊ธฐ๋ณธ StatefulSet ์์ฑ
๋ฌธ์
์๋ ์กฐ๊ฑด์ ๋ง์กฑํ๋ StatefulSet์ ์์ฑํ์ธ์:
ํ์ธ ๋ช ๋ น์ด
# StatefulSet ์ํ ํ์ธ
kubectl get statefulset
# Pod ์ํ ํ์ธ
kubectl get pods
# PVC ํ์ธ (AWS EBS ๋ณผ๋ฅจ ํ์ธ)
kubectl get pvc
kubectl describe pvc www-web-0
# EBS ๋ณผ๋ฅจ ํ์ธ (AWS CLI)
aws ec2 describe-volumes --filters "Name=tag:kubernetes.io/cluster/*,Values=owned" --query 'Volumes[*].[VolumeId,Size,State]' --output table
# Pod ์ด๋ฆ ํจํด ๊ด์ฐฐ
kubectl get pods -l app=nginx
# StorageClass ํ์ธ
kubectl get storageclass
kubectl describe storageclass gp2
# ๋ฌธ์ ํด๊ฒฐ: PVC ๋ฐ์ธ๋ฉ ์ํ ํ์ธ
kubectl get pvc -o wide
kubectl describe pvc www-web-0
# EBS CSI Driver ์ํ ํ์ธ
kubectl get pods -n kube-system | grep ebs-csi
kubectl logs -n kube-system deployment/ebs-csi-controller
# ๋
ธ๋์ EBS CSI Driver ์ค์น ํ์ธ
kubectl get pods -n kube-system | grep ebs-csi-node
ํ์ธ ์ฌํญ
- StatefulSet์ด ์ ์์ ์ผ๋ก ์์ฑ๋จ
- Pod ์ด๋ฆ์ด
web-0,web-1,web-2ํจํด์ผ๋ก ์์ฑ๋จ - ๊ฐ Pod๋ง๋ค ๊ณ ์ ํ PVC๊ฐ ์์ฑ๋จ
- Pod๊ฐ ์์๋๋ก ์์ฑ๋จ (0๋ฒ๋ถํฐ ์์)
์ฐ์ต๋ฌธ์ 2: StatefulSet๊ณผ Headless Service ์ฐ๋
๋ฌธ์
๊ธฐ์กด StatefulSet๊ณผ ์ฐ๋๋๋ Headless Service๋ฅผ ์์ฑํ๊ณ , ๊ฐ๋ณ Pod์ ์ ๊ทผํ๋ ๋ฐฉ๋ฒ์ ํ์ธํ์ธ์.
์๊ตฌ์ฌํญ:
- Service ์ด๋ฆ: nginx
- ํฌํธ: 80
- Headless Service (clusterIP: None)
- Selector: app=nginx
DNS ํ ์คํธ ๋ช ๋ น์ด
# Service ๋ฐฐํฌ
kubectl apply -f nginx-headless-service.yaml
# DNS ์กฐํ ํ
์คํธ
kubectl run test-dns --image=busybox --rm -it --restart=Never -- nslookup nginx
# ๊ฐ๋ณ Pod DNS ์กฐํ
kubectl run test-pod-dns --image=busybox --rm -it --restart=Never -- nslookup web-0.nginx.statefulset-lab.svc.cluster.local
kubectl run test-pod-dns --image=busybox --rm -it --restart=Never -- nslookup web-1.nginx.statefulset-lab.svc.cluster.local
kubectl run test-pod-dns --image=busybox --rm -it --restart=Never -- nslookup web-2.nginx.statefulset-lab.svc.cluster.local
์ฐ์ต๋ฌธ์ 3: ์๊ตฌ ์คํ ๋ฆฌ์ง์ ๋ฐ์ดํฐ ์ง์์ฑ
๋ฌธ์
StatefulSet์ ์๊ตฌ ์คํ ๋ฆฌ์ง ํน์ฑ์ ํ์ธํ๊ณ ๋ฐ์ดํฐ ์ง์์ฑ์ ํ ์คํธํ์ธ์.
3-1. ๋ฐ์ดํฐ ์ฐ๊ธฐ ๋ฐ ํ์ธ
# ๊ฐ Pod์ ๊ณ ์ ํ ๋ฐ์ดํฐ ์ฐ๊ธฐ
kubectl exec web-0 -- sh -c "echo 'Data from web-0 at $(date)' > /usr/share/nginx/html/index.html"
kubectl exec web-1 -- sh -c "echo 'Data from web-1 at $(date)' > /usr/share/nginx/html/index.html"
kubectl exec web-2 -- sh -c "echo 'Data from web-2 at $(date)' > /usr/share/nginx/html/index.html"
# ๊ฐ Pod์ ๋ฐ์ดํฐ ํ์ธ
kubectl exec web-0 -- cat /usr/share/nginx/html/index.html
kubectl exec web-1 -- cat /usr/share/nginx/html/index.html
kubectl exec web-2 -- cat /usr/share/nginx/html/index.html
3-2. Pod ์ฌ์์ ํ ๋ฐ์ดํฐ ์ง์์ฑ ํ์ธ
# web-0 Pod ์ญ์ (์ฌ์์ ์๋ฎฌ๋ ์ด์
)
kubectl delete pod web-0
# Pod ์ฌ์์ฑ ๋๊ธฐ
kubectl wait --for=condition=ready pod web-0
# ๋ฐ์ดํฐ ์ง์์ฑ ํ์ธ
kubectl exec web-0 -- cat /usr/share/nginx/html/index.html
3-3. StatefulSet ์ค์ผ์ผ๋ง ํ ์คํธ
# StatefulSet์ 5๊ฐ๋ก ํ์ฅ
kubectl scale statefulset web --replicas=5
# ์๋ก์ด Pod๋ค์ ๋ฐ์ดํฐ ํ์ธ
kubectl exec web-3 -- cat /usr/share/nginx/html/index.html
kubectl exec web-4 -- cat /usr/share/nginx/html/index.html
# ๋ค์ 3๊ฐ๋ก ์ถ์
kubectl scale statefulset web --replicas=3
์ฐ์ต๋ฌธ์ 4: ๊ณ ๊ธ StatefulSet ๊ตฌ์ฑ
๋ฌธ์
ํ๊ฒฝ๋ณ์, ๋ฆฌ์์ค ์ ํ, ํฌ์ค์ฒดํฌ๋ฅผ ํฌํจํ ๊ณ ๊ธ StatefulSet์ ๊ตฌ์ฑํ์ธ์.
์๊ตฌ์ฌํญ:
- StatefulSet ์ด๋ฆ: web-advanced
- Service ์ด๋ฆ: nginx-advanced
- ํ๊ฒฝ๋ณ์: NGINX_HOST, NGINX_PORT
- ๋ฆฌ์์ค ์ ํ: CPU 500m, Memory 128Mi
- Liveness Probe: HTTP GET /, 30์ด ์ด๊ธฐ์ง์ฐ, 10์ด ์ฃผ๊ธฐ
- Readiness Probe: HTTP GET /, 5์ด ์ด๊ธฐ์ง์ฐ, 5์ด ์ฃผ๊ธฐ
- PVC: www (1Gi), config (100Mi) - StorageClass: gp2
๋ฐฐํฌ ๋ฐ ํ ์คํธ
# ๊ธฐ์กด StatefulSet ์ญ์
kubectl delete statefulset web
kubectl delete service nginx
# ์๋ก์ด StatefulSet ๋ฐฐํฌ
kubectl apply -f advanced-statefulset.yaml
kubectl apply -f nginx-advanced-service.yaml
# ์ํ ํ์ธ
kubectl get statefulset
kubectl get pods
kubectl get pvc
# EBS ๋ณผ๋ฅจ ํ์ธ
kubectl describe pvc www-web-advanced-0
kubectl describe pvc config-web-advanced-0
# AWS EBS ๋ณผ๋ฅจ ์ํ ํ์ธ
aws ec2 describe-volumes --filters "Name=tag:kubernetes.io/cluster/*,Values=owned" --query 'Volumes[*].[VolumeId,Size,State,VolumeType]' --output table
# ํฌ์ค์ฒดํฌ ํ
์คํธ
kubectl logs web-advanced-0
kubectl describe pod web-advanced-0
kubectl exec web-advanced-0 -- env | grep NGINX
# ๋ฆฌ์์ค ์ฌ์ฉ๋ ํ์ธ
kubectl top pods -l app=nginx-advanced
ํ์ธ ์ฌํญ
- ๊ณ ๊ธ StatefulSet์ด ์ ์ ๋ฐฐํฌ๋จ
- ํ๊ฒฝ๋ณ์๊ฐ ์ ์ ์ค์ ๋จ
- ๋ฆฌ์์ค ์ ํ์ด ์ ์ฉ๋จ
- ํฌ์ค์ฒดํฌ๊ฐ ์ ์ ์๋ํจ
- ์ฌ๋ฌ PVC๊ฐ ์์ฑ๋จ
์ฐ์ต๋ฌธ์ 5: StatefulSet ์ ๋ฐ์ดํธ ์ ๋ต
๋ฌธ์
StatefulSet์ ๋กค๋ง ์ ๋ฐ์ดํธ๋ฅผ ์ํํ๊ณ ๋ถ๋ถ ์ ๋ฐ์ดํธ๋ฅผ ํ ์คํธํ์ธ์.
5-1. ๋กค๋ง ์ ๋ฐ์ดํธ ์ํ
# ์ด๋ฏธ์ง๋ฅผ nginx:1.22๋ก ์
๋ฐ์ดํธ
kubectl set image statefulset/web-advanced nginx=nginx:1.22
# ์
๋ฐ์ดํธ ์งํ ์ํฉ ํ์ธ
kubectl rollout status statefulset/web-advanced
# Pod ์ํ ํ์ธ
kubectl get pods -l app=nginx-advanced
5-2. ๋ถ๋ถ ์ ๋ฐ์ดํธ ํ ์คํธ
# partition์ 1๋ก ์ค์ ํ์ฌ web-0๋ง ์
๋ฐ์ดํธ
kubectl patch statefulset web-advanced -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":1}}}}'
# ์ด๋ฏธ์ง๋ฅผ nginx:1.23์ผ๋ก ์
๋ฐ์ดํธ
kubectl set image statefulset/web-advanced nginx=nginx:1.23
# ์
๋ฐ์ดํธ๋ Pod ํ์ธ
kubectl get pods -l app=nginx-advanced
5-3. ๋กค๋ฐฑ ํ ์คํธ
# ์ด์ ๋ฒ์ ์ผ๋ก ๋กค๋ฐฑ
kubectl rollout undo statefulset/web-advanced
# ๋กค๋ฐฑ ์ํ ํ์ธ
kubectl rollout status statefulset/web-advanced
ํ์ธ ์ฌํญ
- ๋กค๋ง ์ ๋ฐ์ดํธ๊ฐ ์์๋๋ก ์งํ๋จ
- ๋ถ๋ถ ์ ๋ฐ์ดํธ๊ฐ ์ ์ ์๋ํจ
- ๋กค๋ฐฑ์ด ์ ์์ ์ผ๋ก ์ํ๋จ
- ์ ๋ฐ์ดํธ ์ค์๋ ์๋น์ค๊ฐ ์ค๋จ๋์ง ์์
์ฐ์ต๋ฌธ์ ์ ๋ฆฌ
์ต์ข ํ์ธ ์ฌํญ
- StatefulSet์ ๊ธฐ๋ณธ ๊ฐ๋ ์ดํด
- Headless Service์์ ์ฐ๋
- ์๊ตฌ ์คํ ๋ฆฌ์ง์ ๋์ ๋ฐฉ์
- ๊ณ ๊ธ ๊ตฌ์ฑ ์์ ์ ์ฉ
- ์ ๋ฐ์ดํธ ์ ๋ต ์ดํด
์ ๋ฆฌ ๋ช ๋ น์ด
# ๋ชจ๋ ๋ฆฌ์์ค ์ญ์
kubectl delete statefulset --all
kubectl delete service --all
kubectl delete pvc --all
# EBS ๋ณผ๋ฅจ ์ ๋ฆฌ ํ์ธ (์ญ์ ๋์ง ์์ ๋ณผ๋ฅจ์ด ์์ ์ ์์)
aws ec2 describe-volumes --filters "Name=tag:kubernetes.io/cluster/*,Values=owned" --query 'Volumes[*].[VolumeId,Size,State]' --output table
# ๋ค์์คํ์ด์ค ์ญ์
kubectl delete namespace statefulset-lab
# AWS EBS ๋ณผ๋ฅจ ์๋ ์ญ์ (ํ์์)
# aws ec2 delete-volume --volume-id vol-xxxxxxxxx
ํน์๋ ์๊ฐ ๋จ์ผ๋ฉด ์ถ๊ฐ ๋์ !!!
๋์ 1: MySQL StatefulSet ๊ตฌ์ฑ
MySQL StatefulSet์ ๊ตฌ์ฑํ๊ณ ๋ฐ์ดํฐ ์ง์์ฑ์ ํ์ธํด๋ณด์ธ์.
๋์ 2: Redis Cluster ๊ตฌ์ฑ
Redis Cluster๋ฅผ StatefulSet์ผ๋ก ๊ตฌ์ฑํด๋ณด์ธ์.
๋์ 3: ๋ชจ๋ํฐ๋ง ์ถ๊ฐ
Prometheus์ Grafana๋ฅผ ์ฌ์ฉํ์ฌ StatefulSet ๋ชจ๋ํฐ๋ง์ ๊ตฌ์ฑํด๋ณด์ธ์.