ํŠœํ† ๋ฆฌ์–ผ

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋ฌธ์„œ์˜ ๋ณธ ์„น์…˜์€ ํŠœํ† ๋ฆฌ์–ผ์„ ํฌํ•จํ•˜๊ณ  ์žˆ๋‹ค. ํŠœํ† ๋ฆฌ์–ผ์€ ๊ฐœ๋ณ„ ์ž‘์—… ๋‹จ์œ„๋ณด๋‹ค ๋” ํฐ ๋ชฉํ‘œ๋ฅผ ๋‹ฌ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค€๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ํŠœํ† ๋ฆฌ์–ผ์€ ๊ฐ๊ฐ ์ˆœ์ฐจ์  ๋‹จ๊ณ„๊ฐ€ ์žˆ๋Š” ์—ฌ๋Ÿฌ ์„น์…˜์œผ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค. ๊ฐ ํŠœํ† ๋ฆฌ์–ผ์„ ๋”ฐ๋ผํ•˜๊ธฐ ์ „์—, ๋‚˜์ค‘์— ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋„๋ก ํ‘œ์ค€ ์šฉ์–ด์ง‘ ํŽ˜์ด์ง€๋ฅผ ๋ถ๋งˆํฌํ•˜๊ธฐ๋ฅผ ๊ถŒํ•œ๋‹ค.

๊ธฐ์ดˆ

  • ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๊ธฐ์ดˆ๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์‹œ์Šคํ…œ์„ ์ดํ•ดํ•˜๋Š”๋ฐ ๋„์›€์ด ๋˜๊ณ  ๊ธฐ์ดˆ์ ์ธ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๊ธฐ๋Šฅ์„ ์ผ๋ถ€ ์‚ฌ์šฉํ•ด ๋ณผ ์ˆ˜ ์žˆ๋Š” ์‹ฌ๋„์žˆ๋Š” ๋Œ€ํ™”ํ˜• ํŠœํ† ๋ฆฌ์–ผ์ด๋‹ค.

  • Introduction to Kubernetes (edX)

  • Hello Minikube

๊ตฌ์„ฑ

์ƒํƒœ ์œ ์ง€๋ฅผ ํ•˜์ง€ ์•Š๋Š”(stateless) ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜

์ƒํƒœ ์œ ์ง€๊ฐ€ ํ•„์š”ํ•œ(stateful) ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜

์„œ๋น„์Šค

๋ณด์•ˆ

๋‹ค์Œ ๋‚ด์šฉ

ํŠœํ† ๋ฆฌ์–ผ์„ ์ž‘์„ฑํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, ํŠœํ† ๋ฆฌ์–ผ ํŽ˜์ด์ง€ ์œ ํ˜•์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ์žˆ๋Š” ์ฝ˜ํ…์ธ  ํŽ˜์ด์ง€ ์œ ํ˜• ํŽ˜์ด์ง€๋ฅผ ์ฐธ์กฐํ•œ๋‹ค.

1 - Hello Minikube

์ด ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” Minikube๋ฅผ ์ด์šฉํ•˜์—ฌ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์—์„œ ์ƒ˜ํ”Œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์–ด๋–ป๊ฒŒ ์‹คํ–‰ํ•˜๋Š”์ง€ ์‚ดํŽด๋ณธ๋‹ค. ์ด ํŠœํ† ๋ฆฌ์–ผ์€ NGINX๋ฅผ ํ†ตํ•ด ๋ชจ๋“  ์š”์ฒญ์„ ๊ทธ๋Œ€๋กœ ๋˜๋Œ๋ ค ์ฃผ๋Š” (echo back) ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

๋ชฉ์ 

  • ์ƒ˜ํ”Œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ minikube์— ๋ฐฐํฌํ•œ๋‹ค.
  • ๋ฐฐํฌํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•œ๋‹ค.
  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋กœ๊ทธ๋ฅผ ํ™•์ธํ•œ๋‹ค.

์‹œ์ž‘ํ•˜๊ธฐ ์ „์—

์ด ํŠœํ† ๋ฆฌ์–ผ์€ ์ด๋ฏธ minikube๊ฐ€ ์ด๋ฏธ ๊ตฌ์ถ•๋˜์–ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•œ๋‹ค. ์„ค์น˜ ๋ฐฉ๋ฒ•์€ minikube ์‹œ์ž‘์˜ Step 1, Installation ์„ ์ฐธ๊ณ ํ•œ๋‹ค.

๋˜ํ•œ, kubectl ์„ ์„ค์น˜ํ•ด์•ผ ํ•œ๋‹ค. ์„ค์น˜ ๋ฐฉ๋ฒ•์€ ๋„๊ตฌ ์„ค์น˜๋ฅผ ์ฐธ๊ณ ํ•œ๋‹ค.

minikube ํด๋Ÿฌ์Šคํ„ฐ ๋งŒ๋“ค๊ธฐ

minikube start

๋Œ€์‹œ๋ณด๋“œ ์ ‘์†ํ•˜๊ธฐ

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋Œ€์‹œ๋ณด๋“œ๋ฅผ ์—ฌ๋Š” ๋ฐฉ๋ฒ•์€ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

์ƒˆ ํ„ฐ๋ฏธ๋„์„ ์—ด๊ณ  ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

# ์ƒˆ ํ„ฐ๋ฏธ๋„์—์„œ ์‹œ์ž‘ํ•˜๊ณ , ํ•ด๋‹น ํ„ฐ๋ฏธ๋„์€ ์‹คํ–‰ ์ƒํƒœ๋กœ ๋‘์–ด์•ผ ํ•จ.
minikube dashboard

์ด์ œ minikube start๋ฅผ ์‹คํ–‰ํ–ˆ๋˜ ํ„ฐ๋ฏธ๋„๋กœ ๋‹ค์‹œ ์ „ํ™˜ํ•œ๋‹ค.

minikube๊ฐ€ ์ž๋™์œผ๋กœ ์›น ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์—ด์ง€ ์•Š๊ฒŒ ํ•˜๋ ค๋ฉด, dashboard ์„œ๋ธŒ์ปค๋งจ๋“œ๋ฅผ --url ํ”Œ๋ž˜๊ทธ์™€ ํ•จ๊ป˜ ์‹คํ–‰ํ•œ๋‹ค. minikube๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์„ ํ˜ธํ•˜๋Š” ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก URL์„ ์ถœ๋ ฅํ•œ๋‹ค.

์ƒˆ ํ„ฐ๋ฏธ๋„์„ ์—ด๊ณ  ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

# ์ƒˆ ํ„ฐ๋ฏธ๋„์—์„œ ์‹œ์ž‘ํ•˜๊ณ , ํ•ด๋‹น ํ„ฐ๋ฏธ๋„์€ ์‹คํ–‰ ์ƒํƒœ๋กœ ๋‘์–ด์•ผ ํ•จ.
minikube dashboard --url

์ด์ œ ์ด URL์„ ์‚ฌ์šฉํ•˜์—ฌ minikube start๋ฅผ ์‹คํ–‰ํ–ˆ๋˜ ํ„ฐ๋ฏธ๋„๋กœ ๋‹ค์‹œ ์ „ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋””ํ”Œ๋กœ์ด๋จผํŠธ ๋งŒ๋“ค๊ธฐ

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํŒŒ๋“œ๋Š” ๊ด€๋ฆฌ์™€ ๋„คํŠธ์›Œํ‚น ๋ชฉ์ ์œผ๋กœ ํ•จ๊ป˜ ๋ฌถ์—ฌ ์žˆ๋Š” ํ•˜๋‚˜ ์ด์ƒ์˜ ์ปจํ…Œ์ด๋„ˆ ๊ทธ๋ฃน์ด๋‹ค. ์ด ํŠœํ† ๋ฆฌ์–ผ์˜ ํŒŒ๋“œ์—๋Š” ๋‹จ ํ•˜๋‚˜์˜ ์ปจํ…Œ์ด๋„ˆ๋งŒ ์žˆ๋‹ค. ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋””ํ”Œ๋กœ์ด๋จผํŠธ๋Š” ํŒŒ๋“œ์˜ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๊ณ , ํŒŒ๋“œ์˜ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ข…๋ฃŒ๋˜์—ˆ๋‹ค๋ฉด ์žฌ์‹œ์ž‘ํ•œ๋‹ค. ํŒŒ๋“œ์˜ ์ƒ์„ฑ ๋ฐ ์Šค์ผ€์ผ๋ง์„ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ๋””ํ”Œ๋กœ์ด๋จผํŠธ๋ฅผ ๊ถŒ์žฅํ•œ๋‹ค.

  1. kubectl create ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ํŒŒ๋“œ๋ฅผ ๊ด€๋ฆฌํ•  ๋””ํ”Œ๋กœ์ด๋จผํŠธ๋ฅผ ๋งŒ๋“ ๋‹ค. ์ด ํŒŒ๋“œ๋Š” ์ œ๊ณต๋œ Docker ์ด๋ฏธ์ง€๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

    # ํ…Œ์ŠคํŠธ์šฉ ์›น ์„œ๋ฒ„ ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.
    kubectl create deployment hello-node --image=registry.k8s.io/e2e-test-images/agnhost:2.39 -- /agnhost netexec --http-port=8080
    
  2. ๋””ํ”Œ๋กœ์ด๋จผํŠธ ๋ณด๊ธฐ

    kubectl get deployments
    

    ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ์ถœ๋ ฅ๋œ๋‹ค.

    NAME         READY   UP-TO-DATE   AVAILABLE   AGE
    hello-node   1/1     1            1           1m
    

    (ํŒŒ๋“œ๊ฐ€ ์ค€๋น„๋˜๋Š” ๋ฐ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆด ์ˆ˜ ์žˆ๋‹ค. "0/1"์ด ํ‘œ์‹œ๋˜๋ฉด ๋ช‡ ์ดˆ ํ›„์— ๋‹ค์‹œ ์‹œ๋„ํ•ด๋ณธ๋‹ค.)

  3. ํŒŒ๋“œ ๋ณด๊ธฐ

    kubectl get pods
    

    ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ์ถœ๋ ฅ๋œ๋‹ค.

    NAME                          READY     STATUS    RESTARTS   AGE
    hello-node-5f76cf6ccf-br9b5   1/1       Running   0          1m
    
  4. ํด๋Ÿฌ์Šคํ„ฐ ์ด๋ฒคํŠธ ๋ณด๊ธฐ

    kubectl get events
    
  5. kubectl ํ™˜๊ฒฝ์„ค์ • ๋ณด๊ธฐ

    kubectl config view
    
  6. ํŒŒ๋“œ ๋‚ด ์ปจํ…Œ์ด๋„ˆ์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ๊ทธ๋ฅผ ํ™•์ธํ•œ๋‹ค. (ํŒŒ๋“œ ์ด๋ฆ„์„ kubectl get pods ๋ช…๋ น์–ด๋กœ ์–ป์€ ์ด๋ฆ„์œผ๋กœ ๊ต์ฒดํ•œ๋‹ค)

    kubectl logs hello-node-5f76cf6ccf-br9b5
    

    ์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•˜๋‹ค.

    I0911 09:19:26.677397       1 log.go:195] Started HTTP server on port 8080
    I0911 09:19:26.677586       1 log.go:195] Started UDP server on port  8081
    

์„œ๋น„์Šค ๋งŒ๋“ค๊ธฐ

๊ธฐ๋ณธ์ ์œผ๋กœ ํŒŒ๋“œ๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ ๋‚ด๋ถ€์˜ IP ์ฃผ์†Œ๋กœ๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค. hello-node ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๊ฐ€์ƒ ๋„คํŠธ์›Œํฌ ์™ธ๋ถ€์—์„œ ์ ‘๊ทผํ•˜๋ ค๋ฉด ํŒŒ๋“œ๋ฅผ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์„œ๋น„์Šค๋กœ ๋…ธ์ถœํ•ด์•ผ ํ•œ๋‹ค.

  1. kubectl expose ๋ช…๋ น์–ด๋กœ ํผ๋ธ”๋ฆญ ์ธํ„ฐ๋„ท์— ํŒŒ๋“œ ๋…ธ์ถœํ•˜๊ธฐ

    kubectl expose deployment hello-node --type=LoadBalancer --port=8080
    

    --type=LoadBalancerํ”Œ๋ž˜๊ทธ๋Š” ํด๋Ÿฌ์Šคํ„ฐ ๋ฐ–์˜ ์„œ๋น„์Šค๋กœ ๋…ธ์ถœํ•˜๊ธฐ ์›ํ•œ๋‹ค๋Š” ๋œป์ด๋‹ค.

    registry.k8s.io/echoserver ์ด๋ฏธ์ง€ ๋‚ด์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ๋Š” TCP ํฌํŠธ 8080์—์„œ๋งŒ ์ˆ˜์‹ ํ•œ๋‹ค. kubectl expose๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค๋ฅธ ํฌํŠธ๋ฅผ ๋…ธ์ถœํ•œ ๊ฒฝ์šฐ, ํด๋ผ์ด์–ธํŠธ๋Š” ๋‹ค๋ฅธ ํฌํŠธ์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์—†๋‹ค.

  2. ์ƒ์„ฑํ•œ ์„œ๋น„์Šค ์‚ดํŽด๋ณด๊ธฐ

    kubectl get services
    

    ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ์ถœ๋ ฅ๋œ๋‹ค.

    NAME         TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
    hello-node   LoadBalancer   10.108.144.78   <pending>     8080:30369/TCP   21s
    kubernetes   ClusterIP      10.96.0.1       <none>        443/TCP          23m
    

    ๋กœ๋“œ ๋ฐธ๋Ÿฐ์„œ๋ฅผ ์ง€์›ํ•˜๋Š” ํด๋ผ์šฐ๋“œ ๊ณต๊ธ‰์ž์˜ ๊ฒฝ์šฐ์—๋Š” ์„œ๋น„์Šค์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ์™ธ๋ถ€ IP ์ฃผ์†Œ๊ฐ€ ํ”„๋กœ๋น„์ €๋‹ ํ•œ๋‹ค. minikube์—์„œ LoadBalancerํƒ€์ž…์€ minikube service ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด์„œ ํ•ด๋‹น ์„œ๋น„์Šค๋ฅผ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค.

  3. ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•œ๋‹ค

    minikube service hello-node
    

    ์ด ๋ช…๋ น์€ ๋ธŒ๋ผ์šฐ์ € ์ฐฝ์„ ์—ด์–ด ์•ฑ์„ ๋ณด์—ฌ์ฃผ๊ณ , ๊ทธ ์‘๋‹ต์„ ํ‘œ์‹œํ•œ๋‹ค.

์• ๋“œ์˜จ ์‚ฌ์šฉํ•˜๊ธฐ

minikube ํˆด์€ ํ™œ์„ฑํ™”ํ•˜๊ฑฐ๋‚˜ ๋น„ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ๊ณ  ๋กœ์ปฌ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํ™˜๊ฒฝ์—์„œ ์ ‘์†ํ•ด ๋ณผ ์ˆ˜ ์žˆ๋Š” ๋‚ด์žฅ ์• ๋“œ์˜จ ์…‹์ด ํฌํ•จ๋˜์–ด ์žˆ๋‹ค.

  1. ํ˜„์žฌ ์ง€์›ํ•˜๋Š” ์• ๋“œ์˜จ ๋ชฉ๋ก์„ ํ™•์ธํ•œ๋‹ค.

    minikube addons list
    

    ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ์ถœ๋ ฅ๋œ๋‹ค.

    addon-manager: enabled
    dashboard: enabled
    default-storageclass: enabled
    efk: disabled
    freshpod: disabled
    gvisor: disabled
    helm-tiller: disabled
    ingress: disabled
    ingress-dns: disabled
    logviewer: disabled
    metrics-server: disabled
    nvidia-driver-installer: disabled
    nvidia-gpu-device-plugin: disabled
    registry: disabled
    registry-creds: disabled
    storage-provisioner: enabled
    storage-provisioner-gluster: disabled
    
  2. ์• ๋“œ์˜จ์„ ํ™œ์„ฑํ™” ํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” metrics-server๋ฅผ ์˜ˆ์‹œ๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

    minikube addons enable metrics-server
    

    ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ์ถœ๋ ฅ๋œ๋‹ค.

    The 'metrics-server' addon is enabled
    
  3. ์ƒ์„ฑํ•œ ํŒŒ๋“œ์™€ ์„œ๋น„์Šค๋ฅผ ํ™•์ธํ•œ๋‹ค.

    kubectl get pod,svc -n kube-system
    

    ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ์ถœ๋ ฅ๋œ๋‹ค.

    NAME                                        READY     STATUS    RESTARTS   AGE
    pod/coredns-5644d7b6d9-mh9ll                1/1       Running   0          34m
    pod/coredns-5644d7b6d9-pqd2t                1/1       Running   0          34m
    pod/metrics-server-67fb648c5                1/1       Running   0          26s
    pod/etcd-minikube                           1/1       Running   0          34m
    pod/influxdb-grafana-b29w8                  2/2       Running   0          26s
    pod/kube-addon-manager-minikube             1/1       Running   0          34m
    pod/kube-apiserver-minikube                 1/1       Running   0          34m
    pod/kube-controller-manager-minikube        1/1       Running   0          34m
    pod/kube-proxy-rnlps                        1/1       Running   0          34m
    pod/kube-scheduler-minikube                 1/1       Running   0          34m
    pod/storage-provisioner                     1/1       Running   0          34m
    
    NAME                           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
    service/metrics-server         ClusterIP   10.96.241.45    <none>        80/TCP              26s
    service/kube-dns               ClusterIP   10.96.0.10      <none>        53/UDP,53/TCP       34m
    service/monitoring-grafana     NodePort    10.99.24.54     <none>        80:30002/TCP        26s
    service/monitoring-influxdb    ClusterIP   10.111.169.94   <none>        8083/TCP,8086/TCP   26s
    
  4. metrics-server์˜ ์ถœ๋ ฅ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•œ๋‹ค.

    kubectl top pods
    

    ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ์ถœ๋ ฅ๋œ๋‹ค.

    NAME                         CPU(cores)   MEMORY(bytes)   
    hello-node-ccf4b9788-4jn97   1m           6Mi             
    

    ๋งŒ์•ฝ ๋‹ค์Œ์˜ ๋ฉ”์‹œ์ง€๊ฐ€ ๋ณด์ธ๋‹ค๋ฉด, ์ž ์‹œ ๊ธฐ๋‹ค๋ ธ๋‹ค๊ฐ€ ๋‹ค์‹œ ์‹œ๋„ํ•œ๋‹ค.

    error: Metrics API not available
    
  5. metrics-server๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•œ๋‹ค.

    minikube addons disable metrics-server
    

    ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ์ถœ๋ ฅ๋œ๋‹ค.

    metrics-server was successfully disabled
    

์ œ๊ฑฐํ•˜๊ธฐ

์ด์ œ ํด๋Ÿฌ์Šคํ„ฐ์—์„œ ๋งŒ๋“ค์–ด์ง„ ๋ฆฌ์†Œ์Šค๋ฅผ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl delete service hello-node
kubectl delete deployment hello-node

Minikube ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ์ข…๋ฃŒํ•œ๋‹ค.

minikube stop

ํ•„์š”ํ•˜๋ฉด minikube VM์„ ์‚ญ์ œํ•œ๋‹ค.

# ์„ ํƒ์‚ฌํ•ญ
minikube delete

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋ฅผ ๋” ๋ฐฐ์šฐ๊ธฐ ์œ„ํ•ด minikube๋ฅผ ๋‹ค์‹œ ์‚ฌ์šฉํ•  ๊ณ„ํš์ด๋ผ๋ฉด, ๊ตณ์ด ์‚ญ์ œํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

๊ฒฐ๋ก 

์ด ํŽ˜์ด์ง€์—์„œ๋Š” minikube ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋ฐฐํฌํ•˜๊ธฐ ์œ„ํ•œ ๊ธฐ๋ณธ์ ์ธ ๋‚ด์šฉ์„ ๋‹ค๋ฃจ์—ˆ๋‹ค. ์ด์ œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋ฐฐํฌํ•  ์ค€๋น„๊ฐ€ ๋˜์—ˆ๋‹ค.

๋‹ค์Œ ๋‚ด์šฉ

2 - ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๊ธฐ์ดˆ ํ•™์Šต

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๊ธฐ์ดˆ

์ด ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ์‹œ์Šคํ…œ์˜ ๊ธฐ์ดˆ๋ฅผ ์ตํž ์ˆ˜ ์žˆ๋Š” ๊ฐ€์ด๋“œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ๊ฐ๊ฐ์˜ ๋ชจ๋“ˆ์—๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์˜ ์ฃผ์š” ๊ธฐ๋Šฅ๊ณผ ๊ฐœ๋…์— ๋Œ€ํ•œ ๋ฐฐ๊ฒฝ ์ง€์‹์ด ๋‹ด๊ฒจ ์žˆ์œผ๋ฉฐ ๋Œ€ํ™”ํ˜• ์˜จ๋ผ์ธ ํŠœํ† ๋ฆฌ์–ผ๋„ ํฌํ•จ๋˜์–ด ์žˆ๋‹ค. ๋Œ€ํ™”ํ˜• ํŠœํ† ๋ฆฌ์–ผ์—์„œ ๊ฐ„๋‹จํ•œ ํด๋Ÿฌ์Šคํ„ฐ์™€ ๊ทธ ํด๋Ÿฌ์Šคํ„ฐ ์ƒ์˜ ์ปจํ…Œ์ด๋„ˆํ™” ๋œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ง์ ‘ ๊ด€๋ฆฌํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค.

๋Œ€ํ™”ํ˜• ํŠœํ† ๋ฆฌ์–ผ์„ ์‚ฌ์šฉํ•ด์„œ ๋‹ค์Œ์˜ ๋‚ด์šฉ์„ ๋ฐฐ์šธ ์ˆ˜ ์žˆ๋‹ค.

  • ์ปจํ…Œ์ด๋„ˆํ™”๋œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํด๋Ÿฌ์Šคํ„ฐ์— ๋ฐฐํฌํ•˜๊ธฐ.
  • ๋””ํ”Œ๋กœ์ด๋จผํŠธ๋ฅผ ์Šค์ผ€์ผ๋งํ•˜๊ธฐ.
  • ์ปจํ…Œ์ด๋„ˆํ™”๋œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ƒˆ๋กœ์šด ์†Œํ”„ํŠธ์›จ์–ด ๋ฒ„์ „์œผ๋กœ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ.
  • ์ปจํ…Œ์ด๋„ˆํ™”๋œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋””๋ฒ„๊ทธํ•˜๊ธฐ.

์ด ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” Katacoda๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋…์ž์˜ ์›น๋ธŒ๋ผ์šฐ์ €์—์„œ Minikube๊ฐ€ ๋™์ž‘ํ•˜๋Š” ๊ฐ€์ƒ ํ„ฐ๋ฏธ๋„์„ ๊ตฌ๋™์‹œํ‚จ๋‹ค. Minikube๋Š” ๋กœ์ปฌ์— ์„ค์น˜ํ•  ์ˆ˜ ์žˆ๋Š” ์ž‘์€ ๊ทœ๋ชจ์˜ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋กœ์จ ์–ด๋””์—์„œ๋“  ์ž‘๋™๋œ๋‹ค. ์–ด๋–ค ์†Œํ”„ํŠธ์›จ์–ด๋„ ์„ค์น˜ํ•  ํ•„์š”๊ฐ€ ์—†๊ณ , ์•„๋ฌด ๊ฒƒ๋„ ์„ค์ •ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๋Œ€ํ™”ํ˜• ํŠœํ† ๋ฆฌ์–ผ์ด ์›น๋ธŒ๋ผ์šฐ์ € ์ž์ฒด์—์„œ ๋ฐ”๋กœ ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.


์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๊ฐ€ ์–ด๋–ค ๋„์›€์ด ๋ ๊นŒ?

์˜ค๋Š˜๋‚ ์˜ ์›น์„œ๋น„์Šค์— ๋Œ€ํ•ด์„œ, ์‚ฌ์šฉ์ž๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด 24/7 ๊ฐ€์šฉํ•˜๊ธฐ๋ฅผ ๋ฐ”๋ผ๊ณ , ๊ฐœ๋ฐœ์ž๋Š” ํ•˜๋ฃจ์—๋„ ๋ช‡ ๋ฒˆ์ด๊ณ  ์ƒˆ๋กœ์šด ๋ฒ„์ „์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋ฐฐํฌํ•˜๊ธฐ๋ฅผ ๋ฐ”๋ž€๋‹ค. ์ปจํ…Œ์ด๋„ˆํ™”๋ฅผ ํ†ตํ•ด ์†Œํ”„ํŠธ์›จ์–ด๋ฅผ ํŒจํ‚ค์ง€ํ•˜๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋‹ค์šดํƒ€์ž„ ์—†์ด ๋ฆด๋ฆฌ์Šค ๋ฐ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์–ด์„œ ์ด๋Ÿฐ ๋ชฉํ‘œ๋ฅผ ๋‹ฌ์„ฑํ•˜๋Š”๋ฐ ๋„์›€์ด ๋œ๋‹ค. ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋Š” ์ด๋ ‡๊ฒŒ ์ปจํ…Œ์ด๋„ˆํ™”๋œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์›ํ•˜๋Š” ๊ณณ ์–ด๋””์—๋“  ๋˜ ์–ธ์ œ๋“  ๊ตฌ๋™์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค๋Š” ํ™•์‹ ์„ ๊ฐ–๋Š”๋ฐ ๋„์›€์„ ์ฃผ๋ฉฐ, ๊ทธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ž‘๋™ํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ ์ž์›๊ณผ ๋„๊ตฌ๋ฅผ ์ฐพ๋Š” ๊ฒƒ์„ ๋„์™€์ค€๋‹ค. ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋Š” ๊ตฌ๊ธ€์˜ ์ปจํ…Œ์ด๋„ˆ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ๋ถ€๋ฌธ์˜ ์ถ•์ ๋œ ๊ฒฝํ—˜์œผ๋กœ ์„ค๊ณ„๋˜๊ณ  ์ปค๋ฎค๋‹ˆํ‹ฐ๋กœ๋ถ€ํ„ฐ ๋„์ถœ๋œ ์ตœ๊ณ ์˜ ์•„์ด๋””์–ด๊ฐ€ ๊ฒฐํ•ฉ๋œ ์šด์˜ ์ˆ˜์ค€์˜ ์˜คํ”ˆ ์†Œ์Šค ํ”Œ๋žซํผ์ด๋‹ค.


2.1 - ํด๋Ÿฌ์Šคํ„ฐ ์ƒ์„ฑํ•˜๊ธฐ

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ์— ๋Œ€ํ•œ ๋‚ด์šฉ์„ ํ™•์ธํ•˜๊ณ  Minikube๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ„๋‹จํ•œ ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ์ƒ์„ฑํ•ด ๋ณธ๋‹ค.

2.1.1 - Minikube๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํด๋Ÿฌ์Šคํ„ฐ ์ƒ์„ฑํ•˜๊ธฐ

๋ชฉํ‘œ

  • ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ๋ฐฐ์šด๋‹ค.
  • Minikube๊ฐ€ ๋ฌด์—‡์ธ์ง€ ๋ฐฐ์šด๋‹ค.
  • ์˜จ๋ผ์ธ ํ„ฐ๋ฏธ๋„์„ ์‚ฌ์šฉํ•ด์„œ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ์‹œ์ž‘ํ•œ๋‹ค.

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋Š” ์ปดํ“จํ„ฐ๋“ค์„ ์—ฐ๊ฒฐํ•˜์—ฌ ๋‹จ์ผ ํ˜•์ƒ์œผ๋กœ ๋™์ž‘ํ•˜๋„๋ก ์ปดํ“จํŒ… ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ  ๋†’์€ ๊ฐ€์šฉ์„ฑ์„ ์ œ๊ณตํ•˜๋„๋ก ์กฐ์œจํ•œ๋‹ค. ์‚ฌ์šฉ์ž๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์˜ ์ถ”์ƒํ™” ๊ฐœ๋…์„ ํ†ตํ•ด ๊ฐœ๋ณ„ ๋จธ์‹ ์— ์–ฝ๋งค์ด์ง€ ์•Š๊ณ  ์ปจํ…Œ์ด๋„ˆํ™”๋œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํด๋Ÿฌ์Šคํ„ฐ์— ๋ฐฐํฌํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ ‡๊ฒŒ ์ƒˆ๋กœ์šด ๋ฐฐํฌ ๋ชจ๋ธ์„ ํ™œ์šฉํ•˜๋ ค๋ฉด, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ณ„ ํ˜ธ์ŠคํŠธ์— ๋…๋ฆฝ์ ์ธ ๋ฐฉ์‹์œผ๋กœ ํŒจํ‚ค์ง•ํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค. ์ฆ‰, ์ปจํ…Œ์ด๋„ˆํ™”๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ์˜ˆ์ „ ๋ฐฐ์น˜ ๋ชจ๋ธ์ธ ์„ค์น˜ํ˜• ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ํŠน์ • ๋จธ์‹ ์˜ ํ˜ธ์ŠคํŠธ์™€ ๋ฐ€์ ‘ํ•˜๊ฒŒ ํ†ตํ•ฉ๋˜๋Š” ํŒจํ‚ค์ง€์ธ ๊ฒƒ์— ๋น„ํ•ด, ์ปจํ…Œ์ด๋„ˆํ™”๋œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์œ ์—ฐ์„ฑ(flexible)๊ณผ ๊ฐ€์šฉ์„ฑ(available)์ด ํ›จ์”ฌ ๋†’๋‹ค. ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋Š” ์ด๋Ÿฌํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํด๋Ÿฌ์Šคํ„ฐ์— ๋ถ„์‚ฐ์‹œํ‚ค๊ณ  ์Šค์ผ€์ค„๋งํ•˜๋Š” ์ผ์„ ๋”์šฑ ํšจ์œจ์ ์œผ๋กœ ์ž๋™ํ™”ํ•œ๋‹ค. ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋Š” ์˜คํ”ˆ์†Œ์Šค ํ”Œ๋žซํผ์ด๋ฉฐ ์šด์˜ ์ˆ˜์ค€์˜ ์•ˆ์ •์„ฑ(production-ready)์„ ์ œ๊ณตํ•œ๋‹ค.

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ๋Š” ๋‘ ๊ฐ€์ง€ ํ˜•ํƒœ์˜ ์ž์›์œผ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค.

  • ์ปจํŠธ๋กค ํ”Œ๋ ˆ์ธ์€ ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ์กฐ์œจํ•œ๋‹ค.
  • ๋…ธ๋“œ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌ๋™ํ•˜๋Š” ์ž‘์—…์ž(worker)์ด๋‹ค.

์š”์•ฝ:

  • ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ
  • Minikube

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋Š” ์ปดํ“จํ„ฐ ํด๋Ÿฌ์Šคํ„ฐ์— ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปจํ…Œ์ด๋„ˆ์˜ ๋ฐฐ์น˜(์Šค์ผ€์ค„๋ง) ๋ฐ ์‹คํ–‰์„ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ํ•˜๋Š” ์šด์˜ ์ˆ˜์ค€์˜ ์˜คํ”ˆ์†Œ์Šค ํ”Œ๋žซํผ์ด๋‹ค.


ํด๋Ÿฌ์Šคํ„ฐ ๋‹ค์ด์–ด๊ทธ๋žจ


์ปจํŠธ๋กค ํ”Œ๋ ˆ์ธ์€ ํด๋Ÿฌ์Šคํ„ฐ ๊ด€๋ฆฌ๋ฅผ ๋‹ด๋‹นํ•œ๋‹ค. ์ปจํŠธ๋กค ํ”Œ๋ ˆ์ธ์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์Šค์ผ€์ค„๋งํ•˜๊ฑฐ๋‚˜, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํ•ญ์ƒ์„ฑ์„ ์œ ์ง€ํ•˜๊ฑฐ๋‚˜, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์Šค์ผ€์ผ๋งํ•˜๊ณ , ์ƒˆ๋กœ์šด ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ์ˆœ์„œ๋Œ€๋กœ ๋ฐ˜์˜(rolling out)ํ•˜๋Š” ์ผ๊ณผ ๊ฐ™์€ ํด๋Ÿฌ์Šคํ„ฐ ๋‚ด ๋ชจ๋“  ํ™œ๋™์„ ์กฐ์œจํ•œ๋‹ค.

๋…ธ๋“œ๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ ๋‚ด ์›Œ์ปค ๋จธ์‹ ์œผ๋กœ ๋™์ž‘ํ•˜๋Š” VM ๋˜๋Š” ๋ฌผ๋ฆฌ์ ์ธ ์ปดํ“จํ„ฐ๋‹ค. ๊ฐ ๋…ธ๋“œ๋Š” ๋…ธ๋“œ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์ปจํŠธ๋กค ํ”Œ๋ ˆ์ธ๊ณผ ํ†ต์‹ ํ•˜๋Š” Kubelet์ด๋ผ๋Š” ์—์ด์ „ํŠธ๋ฅผ ๊ฐ–๋Š”๋‹ค. ๋…ธ๋“œ๋Š” ์ปจํ…Œ์ด๋„ˆ ์šด์˜์„ ๋‹ด๋‹นํ•˜๋Š” containerd ๋˜๋Š” ๋„์ปค์™€ ๊ฐ™์€ ํˆด๋„ ๊ฐ–๋Š”๋‹ค. ์šด์˜ ํŠธ๋ž˜ํ”ฝ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ๋Š” ์ตœ์†Œ ์„ธ ๋Œ€์˜ ๋…ธ๋“œ๋ฅผ ๊ฐ€์ ธ์•ผ ํ•˜๋Š”๋ฐ, ์ด๋Š” ํ•œ ๋…ธ๋“œ๊ฐ€ ๋‹ค์šด๋˜๋ฉด etcd ๋ฉค๋ฒ„์™€ ์ปจํŠธ๋กค ํ”Œ๋ ˆ์ธ ์ธ์Šคํ„ด์Šค๊ฐ€ ์‚ฌ๋ผ์ ธ ์ค‘๋ณต์„ฑ(redundancy)์„ ์žƒ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ปจํŠธ๋กค ํ”Œ๋ ˆ์ธ ๋…ธ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์ด๋Ÿฌํ•œ ์œ„ํ—˜์„ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

์ปจํŠธ๋กค ํ”Œ๋ ˆ์ธ์€ ์‹คํ–‰ ์ค‘์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํ˜ธ์ŠคํŒ…ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ๋…ธ๋“œ์™€ ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค.

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์— ๋ฐฐํฌํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š”, ์ปจํŠธ๋กค ํ”Œ๋ ˆ์ธ์— ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปจํ…Œ์ด๋„ˆ์˜ ๊ตฌ๋™์„ ์ง€์‹œํ•˜๋ฉด ๋œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์ปจํŠธ๋กค ํ”Œ๋ ˆ์ธ์€ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํด๋Ÿฌ์Šคํ„ฐ์˜ ์–ด๋А ๋…ธ๋“œ์— ๊ตฌ๋™์‹œํ‚ฌ์ง€ ์Šค์ผ€์ค„ํ•œ๋‹ค. ๋…ธ๋“œ๋Š” ์ปจํŠธ๋กค ํ”Œ๋ ˆ์ธ์ด ์ œ๊ณตํ•˜๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค API๋ฅผ ํ†ตํ•ด์„œ ์ปจํŠธ๋กค ํ”Œ๋ ˆ์ธ๊ณผ ํ†ต์‹ ํ•œ๋‹ค. ์ตœ์ข… ์‚ฌ์šฉ์ž๋„ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค API๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํด๋Ÿฌ์Šคํ„ฐ์™€ ์ง์ ‘ ์ƒํ˜ธ์ž‘์šฉ(interact)ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ๋Š” ๋ฌผ๋ฆฌ ๋ฐ ๊ฐ€์ƒ ๋จธ์‹  ๋ชจ๋‘์— ์„ค์น˜๋  ์ˆ˜ ์žˆ๋‹ค. ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๊ฐœ๋ฐœ์„ ์‹œ์ž‘ํ•˜๋ ค๋ฉด Minikube๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. Minikube๋Š” ๊ฐ€๋ฒผ์šด ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๊ตฌํ˜„์ฒด์ด๋ฉฐ, ๋กœ์ปฌ ๋จธ์‹ ์— VM์„ ๋งŒ๋“ค๊ณ  ํ•˜๋‚˜์˜ ๋…ธ๋“œ๋กœ ๊ตฌ์„ฑ๋œ ๊ฐ„๋‹จํ•œ ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. Minikube๋Š” ๋ฆฌ๋ˆ…์Šค, ๋งฅ, ๊ทธ๋ฆฌ๊ณ  ์œˆ๋„์šฐ ์‹œ์Šคํ…œ์—์„œ ๊ตฌ๋™์ด ๊ฐ€๋Šฅํ•˜๋‹ค. Minikube CLI๋Š” ํด๋Ÿฌ์Šคํ„ฐ์— ๋Œ€ํ•ด ์‹œ์ž‘, ์ค‘์ง€, ์ƒํƒœ ์กฐํšŒ ๋ฐ ์‚ญ์ œ ๋“ฑ์˜ ๊ธฐ๋ณธ์ ์ธ ๋ถ€ํŠธ์ŠคํŠธ๋ž˜ํ•‘(bootstrapping) ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค. ํ•˜์ง€๋งŒ, ๋ณธ ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” Minikube๊ฐ€ ๋ฏธ๋ฆฌ ์„ค์น˜๋œ ์ฑ„๋กœ ์ œ๊ณต๋˜๋Š” ์˜จ๋ผ์ธ ํ„ฐ๋ฏธ๋„์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋‹ค.

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์•Œ์•„๋ดค์œผ๋‹ˆ, ์ด์ œ ์˜จ๋ผ์ธ ํŠœํ† ๋ฆฌ์–ผ๋กœ ์ด๋™ํ•ด์„œ ์šฐ๋ฆฌ์˜ ์ฒซ ๋ฒˆ์งธ ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ์‹œ์ž‘ํ•ด๋ณด์ž!


2.1.2 - ๋Œ€ํ™”ํ˜• ํŠœํ† ๋ฆฌ์–ผ - ํด๋Ÿฌ์Šคํ„ฐ ์ƒ์„ฑํ•˜๊ธฐ

ํ™”๋ฉด์ด ๋„ˆ๋ฌด ์ข์•„ ํ„ฐ๋ฏธ๋„๊ณผ ์ƒํ˜ธ์ž‘์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋ฐ์Šคํฌํ†ฑ/ํƒœ๋ธ”๋ฆฟ์„ ์‚ฌ์šฉํ•ด์ฃผ์„ธ์š”.

2.2 - ์•ฑ ๋ฐฐํฌํ•˜๊ธฐ

2.2.1 - kubectl์„ ์‚ฌ์šฉํ•ด์„œ ๋””ํ”Œ๋กœ์ด๋จผํŠธ ์ƒ์„ฑํ•˜๊ธฐ

๋ชฉํ‘œ

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋””ํ”Œ๋กœ์ด๋จผํŠธ(Deployment)์— ๋Œ€ํ•ด ๋ฐฐ์šด๋‹ค.
  • kubectl๋กœ ์ฒซ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์— ๋ฐฐํฌํ•œ๋‹ค.

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋””ํ”Œ๋กœ์ด๋จผํŠธ

์ผ๋‹จ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ๊ตฌ๋™์‹œํ‚ค๋ฉด, ๊ทธ ์œ„์— ์ปจํ…Œ์ด๋„ˆํ™”๋œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋ฐฐํฌํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๊ธฐ ์œ„ํ•ด์„œ, ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋””ํ”Œ๋กœ์ด๋จผํŠธ ์„ค์ •์„ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค. ๋””ํ”Œ๋กœ์ด๋จผํŠธ๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๊ฐ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์–ด๋–ป๊ฒŒ ์ƒ์„ฑํ•˜๊ณ  ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•˜๋Š”์ง€๋ฅผ ์ง€์‹œํ•œ๋‹ค. ๋””ํ”Œ๋กœ์ด๋จผํŠธ๊ฐ€ ๋งŒ๋“ค์–ด์ง€๋ฉด, ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์ปจํŠธ๋กค ํ”Œ๋ ˆ์ธ์ด ํ•ด๋‹น ๋””ํ”Œ๋กœ์ด๋จผํŠธ์— ํฌํ•จ๋œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ํด๋Ÿฌ์Šคํ„ฐ์˜ ๊ฐœ๋ณ„ ๋…ธ๋“œ์—์„œ ์‹คํ–‰๋˜๋„๋ก ์Šค์ผ€์ค„ํ•œ๋‹ค.

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜๋ฉด, ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋””ํ”Œ๋กœ์ด๋จผํŠธ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ์ง€์†์ ์œผ๋กœ ์ด๋“ค ์ธ์Šคํ„ด์Šค๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•œ๋‹ค. ์ธ์Šคํ„ด์Šค๋ฅผ ๊ตฌ๋™ ์ค‘์ธ ๋…ธ๋“œ๊ฐ€ ๋‹ค์šด๋˜๊ฑฐ๋‚˜ ์‚ญ์ œ๋˜๋ฉด, ๋””ํ”Œ๋กœ์ด๋จผํŠธ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์ธ์Šคํ„ด์Šค๋ฅผ ํด๋Ÿฌ์Šคํ„ฐ ๋‚ด๋ถ€์˜ ๋‹ค๋ฅธ ๋…ธ๋“œ์˜ ์ธ์Šคํ„ด์Šค๋กœ ๊ต์ฒด์‹œ์ผœ์ค€๋‹ค.์ด๋ ‡๊ฒŒ ๋จธ์‹ ์˜ ์žฅ์• ๋‚˜ ์ •๋น„์— ๋Œ€์‘ํ•  ์ˆ˜ ์žˆ๋Š” ์ž๋™ ๋ณต๊ตฌ(self-healing) ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ œ๊ณตํ•œ๋‹ค.

์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ๊ธฐ๋Šฅ์ด ์—†๋˜ ํ™˜๊ฒฝ์—์„œ๋Š”, ์„ค์น˜ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹œ์ž‘ํ•˜๋Š”๋ฐ ์ข…์ข… ์‚ฌ์šฉ๋˜๊ณค ํ–ˆ์ง€๋งŒ, ๋จธ์‹ ์˜ ์žฅ์• ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ ๋ณต๊ตฌ๋ฅผ ํ•ด์ฃผ์ง€๋Š” ์•Š์•˜๋‹ค. ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋””ํ”Œ๋กœ์ด๋จผํŠธ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ด์ฃผ๊ณ  ์—ฌ๋Ÿฌ ๋…ธ๋“œ์— ๊ฑธ์ณ์„œ ์ง€์†์ ์œผ๋กœ ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ตฌ๋™๋˜๋„๋ก ํ•˜๋Š” ๋‘ ๊ฐ€์ง€๋ฅผ ๋ชจ๋‘ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ์ ‘๊ทผ๋ฒ•์—์„œ ๊ทผ๋ณธ์ ์ธ ์ฐจ์ด๋ฅผ ๊ฐ€์ ธ๋‹ค์ค€๋‹ค.

์š”์•ฝ:

  • ๋””ํ”Œ๋กœ์ด๋จผํŠธ
  • Kubectl

๋””ํ”Œ๋กœ์ด๋จผํŠธ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์—…๋ฐ์ดํŠธํ•˜๋Š” ์—ญํ• ์„ ๋‹ด๋‹นํ•œ๋‹ค.


์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์— ์ฒซ ๋ฒˆ์งธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฐฐํฌํ•˜๊ธฐ


Kubectl์ด๋ผ๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค CLI๋ฅผ ํ†ตํ•ด ๋””ํ”Œ๋กœ์ด๋จผํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. Kubectl์€ ํด๋Ÿฌ์Šคํ„ฐ์™€ ์ƒํ˜ธ ์ž‘์šฉํ•˜๊ธฐ ์œ„ํ•ด ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค API๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์ด ๋ชจ๋“ˆ์—์„œ๋Š”, ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ ์ƒ์— ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌ๋™์‹œํ‚ค๋Š” ๋””ํ”Œ๋กœ์ด๋จผํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ Kubectl ๋ช…๋ น์–ด๋ฅผ ๋ฐฐ์šฐ๊ฒŒ ๋œ๋‹ค.

๋””ํ”Œ๋กœ์ด๋จผํŠธ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋Œ€ํ•œ ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€์™€ ๊ตฌ๋™์‹œํ‚ค๊ณ ์ž ํ•˜๋Š” ๋ณต์ œ ์ˆ˜๋ฅผ ์ง€์ •ํ•ด์•ผ ํ•œ๋‹ค. ๋””ํ”Œ๋กœ์ด๋จผํŠธ๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์„œ ์ด๋Ÿฐ ์ •๋ณด๋ฅผ ๋‚˜์ค‘์— ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ชจ๋“ˆ 5์™€ 6์˜ ๋ถ€ํŠธ์บ ํ”„์—์„œ ์–ด๋–ป๊ฒŒ ์Šค์ผ€์ผํ•˜๊ณ  ์—…๋ฐ์ดํŠธํ•˜๋Š”์ง€์— ๋Œ€ํ•ด ๋‹ค๋ฃฌ๋‹ค.

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์ƒ์— ๋ฐฐํฌ๋˜๋ ค๋ฉด ์ง€์›๋˜๋Š” ์ปจํ…Œ์ด๋„ˆ ํ˜•์‹ ์ค‘ ํ•˜๋‚˜๋กœ ํŒจํ‚ค์ง€ ๋˜์–ด์•ผํ•œ๋‹ค.

์ฒซ ๋ฒˆ์งธ ๋””ํ”Œ๋กœ์ด๋จผํŠธ๋กœ, NGINX๋ฅผ ์‚ฌ์šฉํ•ด ๋ชจ๋“  ์š”์ฒญ์„ ์—์ฝ”(echo)ํ•˜๋Š” ๋„์ปค ์ปจํ…Œ์ด๋„ˆ๋กœ ํŒจํ‚ค์ง€ํ•œ hello-node ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‚ฌ์šฉํ•ด๋ณด์ž. (์•„์ง hello-node ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ž‘์„ฑํ•˜๊ณ  ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ™œ์šฉํ•ด์„œ ๋ฐฐํฌํ•ด๋ณด์ง€ ์•Š์•˜๋‹ค๋ฉด, Hello Minikube ํŠœํ† ๋ฆฌ์–ผ์˜ ์ง€์‹œ๋ฅผ ๋”ฐ๋ฅธ๋‹ค.)

์ด์ œ ๋””ํ”Œ๋กœ์ด๋จผํŠธ๋ฅผ ์ดํ•ดํ–ˆ์œผ๋‹ˆ, ์˜จ๋ผ์ธ ํŠœํ† ๋ฆฌ์–ผ์„ ํ†ตํ•ด ์šฐ๋ฆฌ์˜ ์ฒซ ๋ฒˆ์งธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋ฐฐํฌํ•ด๋ณด์ž!


2.2.2 - ๋Œ€ํ™”ํ˜• ํŠœํ† ๋ฆฌ์–ผ - ์•ฑ ๋ฐฐํฌํ•˜๊ธฐ

ํŒŒ๋“œ๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ธฐ๋ณธ ์‹คํ–‰ ๋‹จ์œ„์ด๋‹ค. ๊ฐ ํŒŒ๋“œ๋Š” ํด๋Ÿฌ์Šคํ„ฐ์—์„œ ์‹คํ–‰์ค‘์ธ ์›Œํฌ๋กœ๋“œ์˜ ์ผ๋ถ€๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค. ํŒŒ๋“œ์— ๋Œ€ํ•ด ๋” ์ž์„ธํžˆ ์•Œ์•„๋ณธ๋‹ค.


ํ„ฐ๋ฏธ๋„๋กœ ์ƒํ˜ธ ์ž‘์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ, ๋ฐ์Šคํฌํƒ‘/ํƒœ๋ธ”๋ฆฟ ๋ฒ„์ „์„ ์‚ฌ์šฉํ•ด์ฃผ์„ธ์š”

2.3 - ์•ฑ ์กฐ์‚ฌํ•˜๊ธฐ

2.3.1 - ํŒŒ๋“œ์™€ ๋…ธ๋“œ ๋ณด๊ธฐ

๋ชฉํ‘œ

  • ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํŒŒ๋“œ์— ๋Œ€ํ•ด ๋ฐฐ์šด๋‹ค.
  • ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋…ธ๋“œ์— ๋Œ€ํ•ด ๋ฐฐ์šด๋‹ค.
  • ๋ฐฐํฌ๋œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ๋‹ค.

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํŒŒ๋“œ

๋ชจ๋“ˆ 2์—์„œ ๋ฐฐํฌ๋ฅผ ์ƒ์„ฑํ–ˆ์„ ๋•Œ, ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋Š” ์—ฌ๋Ÿฌ๋ถ„์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ธ์Šคํ„ด์Šค์— ํŒŒ๋“œ๋ฅผ ์ƒ์„ฑํ–ˆ๋‹ค. ํŒŒ๋“œ๋Š” ํ•˜๋‚˜ ๋˜๋Š” ๊ทธ ์ด์ƒ์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปจํ…Œ์ด๋„ˆ (๋„์ปค์™€ ๊ฐ™์€)๋“ค์˜ ๊ทธ๋ฃน์„ ๋‚˜ํƒ€๋‚ด๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์˜ ์ถ”์ƒ์  ๊ฐœ๋…์œผ๋กœ ์ผ๋ถ€๋Š” ์ปจํ…Œ์ด๋„ˆ์— ๋Œ€ํ•œ ์ž์›์„ ๊ณต์œ ํ•œ๋‹ค. ๊ทธ ์ž์›์€ ๋‹ค์Œ์„ ํฌํ•จํ•œ๋‹ค:

  • ๋ณผ๋ฅจ๊ณผ ๊ฐ™์€, ๊ณต์œ  ์Šคํ† ๋ฆฌ์ง€
  • ํด๋Ÿฌ์Šคํ„ฐ IP ์ฃผ์†Œ์™€ ๊ฐ™์€, ๋„คํŠธ์›Œํ‚น
  • ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€ ๋ฒ„์ „ ๋˜๋Š” ์‚ฌ์šฉํ•  ํŠน์ • ํฌํŠธ์™€ ๊ฐ™์ด, ๊ฐ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๋™์ž‘ํ•˜๋Š” ๋ฐฉ์‹์— ๋Œ€ํ•œ ์ •๋ณด

ํŒŒ๋“œ๋Š” ํŠน์œ ํ•œ "๋กœ์ปฌํ˜ธ์ŠคํŠธ" ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ชจํ˜•์„ ๋งŒ๋“ค์–ด. ์ƒ๋Œ€์ ์œผ๋กœ ๋ฐ€์ ‘ํ•˜๊ฒŒ ๊ฒฐํ•ฉ๋˜์–ด์ง„ ์ƒ์ดํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปจํ…Œ์ด๋„ˆ๋“ค์„ ์ˆ˜์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฐ€๋ น, ํŒŒ๋“œ๋Š” Node.js ์•ฑ๊ณผ ๋”๋ถˆ์–ด Node.js ์›น์„œ๋ฒ„์— ์˜ํ•ด ๋ฐœํ–‰๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ณต๊ธ‰ํ•˜๋Š” ์ƒ์ดํ•œ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ•จ๊ป˜ ์ˆ˜์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ํŒŒ๋“œ ๋‚ด ์ปจํ…Œ์ด๋„ˆ๋Š” IP ์ฃผ์†Œ, ๊ทธ๋ฆฌ๊ณ  ํฌํŠธ ์ŠคํŽ˜์ด์Šค๋ฅผ ๊ณต์œ ํ•˜๊ณ  ํ•ญ์ƒ ํ•จ๊ป˜ ์œ„์น˜ํ•˜๊ณ  ํ•จ๊ป˜ ์Šค์ผ€์ฅด๋ง ๋˜๊ณ  ๋™์ผ ๋…ธ๋“œ ์ƒ์˜ ์ปจํ…์ŠคํŠธ๋ฅผ ๊ณต์œ ํ•˜๋ฉด์„œ ๋™์ž‘ํ•œ๋‹ค.

ํŒŒ๋“œ๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํ”Œ๋žซํผ ์ƒ์—์„œ ์ตœ์†Œ ๋‹จ์œ„๊ฐ€ ๋œ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์—์„œ ๋ฐฐํฌ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ, ๊ทธ ๋ฐฐํฌ๋Š” ์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€์—์„œ ์ปจํ…Œ์ด๋„ˆ์™€ ํ•จ๊ป˜ ํŒŒ๋“œ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ๊ฐ ํŒŒ๋“œ๋Š” ์Šค์ผ€์ฅด ๋˜์–ด์ง„ ๋…ธ๋“œ์—๊ฒŒ ๋ฌถ์—ฌ์ง€๊ฒŒ ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  (์žฌ๊ตฌ๋™ ์ •์ฑ…์— ๋”ฐ๋ผ) ์†Œ๋ฉธ๋˜๊ฑฐ๋‚˜ ์‚ญ์ œ๋˜๊ธฐ ์ „๊นŒ์ง€ ๊ทธ ๋…ธ๋“œ์— ์œ ์ง€๋œ๋‹ค. ๋…ธ๋“œ์— ์‹คํŒจ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ, ํด๋Ÿฌ์Šคํ„ฐ ๋‚ด์— ๊ฐ€์šฉํ•œ ๋‹ค๋ฅธ ๋…ธ๋“œ๋“ค์„ ๋Œ€์ƒ์œผ๋กœ ์Šค์ผ€์ฅด๋˜์–ด์ง„๋‹ค.

์š”์•ฝ:

  • ํŒŒ๋“œ
  • ๋…ธ๋“œ
  • Kubectl ์ฃผ์š” ๋ช…๋ น์–ด

ํŒŒ๋“œ๋Š” ํ•˜๋‚˜ ๋˜๋Š” ๊ทธ ์ด์ƒ์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปจํ…Œ์ด๋„ˆ (๋„์ปค์™€ ๊ฐ™์€)๋“ค์˜ ๊ทธ๋ฃน์ด๊ณ  ๊ณต์œ  ์Šคํ† ๋ฆฌ์ง€ (๋ณผ๋ฅจ), IP ์ฃผ์†Œ ๊ทธ๋ฆฌ๊ณ  ๊ทธ๊ฒƒ์„ ๋™์ž‘์‹œํ‚ค๋Š” ๋ฐฉ์‹์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ๋‹ค.


ํŒŒ๋“œ ๊ฐœ์š”


๋…ธ๋“œ

ํŒŒ๋“œ๋Š” ์–ธ์ œ๋‚˜ ๋…ธ๋“œ ์ƒ์—์„œ ๋™์ž‘ํ•œ๋‹ค. ๋…ธ๋“œ๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์—์„œ ์›Œ์ปค ๋จธ์‹ ์„ ๋งํ•˜๋ฉฐ ํด๋Ÿฌ์Šคํ„ฐ์— ๋”ฐ๋ผ ๊ฐ€์ƒ ๋˜๋Š” ๋ฌผ๋ฆฌ ๋จธ์‹ ์ผ ์ˆ˜ ์žˆ๋‹ค. ๊ฐ ๋…ธ๋“œ๋Š” ์ปจํŠธ๋กค ํ”Œ๋ ˆ์ธ์— ์˜ํ•ด ๊ด€๋ฆฌ๋œ๋‹ค. ํ•˜๋‚˜์˜ ๋…ธ๋“œ๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํŒŒ๋“œ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๊ณ , ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์ปจํŠธ๋กค ํ”Œ๋ ˆ์ธ์€ ํด๋Ÿฌ์Šคํ„ฐ ๋‚ด ๋…ธ๋“œ๋ฅผ ํ†ตํ•ด์„œ ํŒŒ๋“œ์— ๋Œ€ํ•œ ์Šค์ผ€์ฅด๋ง์„ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค. ์ปจํŠธ๋กค ํ”Œ๋ ˆ์ธ์˜ ์ž๋™ ์Šค์ผ€์ค„๋ง์€ ๊ฐ ๋…ธ๋“œ์˜ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ฆฌ์†Œ์Šค๋ฅผ ๋ชจ๋‘ ๊ณ ๋ คํ•œ๋‹ค.

๋ชจ๋“  ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋…ธ๋“œ๋Š” ์ตœ์†Œํ•œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋™์ž‘ํ•œ๋‹ค.

  • Kubelet์€, ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์ปจํŠธ๋กค ํ”Œ๋ ˆ์ธ๊ณผ ๋…ธ๋“œ ๊ฐ„ ํ†ต์‹ ์„ ์ฑ…์ž„์ง€๋Š” ํ”„๋กœ์„ธ์Šค์ด๋ฉฐ, ํ•˜๋‚˜์˜ ๋จธ์‹  ์ƒ์—์„œ ๋™์ž‘ํ•˜๋Š” ํŒŒ๋“œ์™€ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค.
  • ์ปจํ…Œ์ด๋„ˆ ๋Ÿฐํƒ€์ž„(๋„์ปค์™€ ๊ฐ™์€)์€ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์—์„œ ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€๋ฅผ ๊ฐ€์ ธ์™€ ๋ฌถ์—ฌ ์žˆ๋Š” ๊ฒƒ์„ ํ’€๊ณ  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋™์ž‘์‹œํ‚ค๋Š” ์ฑ…์ž„์„ ๋งก๋Š”๋‹ค.

๋งŒ์•ฝ ์ปจํ…Œ์ด๋„ˆ๋“ค์ด ๋ฐ€์ ‘ํ•˜๊ฒŒ ๊ฒฐํ•ฉ๋˜์–ด ์žˆ๊ณ  ๋””์Šคํฌ์™€ ๊ฐ™์€ ์ž์›์„ ๊ณต์œ ํ•ด์•ผ ํ•œ๋‹ค๋ฉด ์˜ค์ง ํ•˜๋‚˜์˜ ๋‹จ์ผ ํŒŒ๋“œ์— ํ•จ๊ป˜ ์Šค์ผ€์ฅด๋˜์–ด์ ธ์•ผ ํ•œ๋‹ค.


๋…ธ๋“œ ๊ฐœ์š”


kubectl๋กœ ๋ฌธ์ œํ•ด๊ฒฐํ•˜๊ธฐ

๋ชจ๋“ˆ 2์—์„œ, Kubectl ์ปค๋งจ๋“œ-๋ผ์ธ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค. ๋ฐฐํฌ๋œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ๊ทธ ํ™˜๊ฒฝ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด ๋ชจ๋“ˆ3์—์„œ๋„ ๊ณ„์† ๊ทธ๊ฒƒ์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋‹ค. ๊ฐ€์žฅ ๋ณดํŽธ์ ์ธ ์šด์šฉ์—…๋ฌด๋Š” ๋‹ค์Œ kubectl ๋ช…๋ น์–ด๋ฅผ ์ด์šฉํ•˜์—ฌ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค:

  • kubectl get - ์ž์›์„ ๋‚˜์—ดํ•œ๋‹ค
  • kubectl describe - ์ž์›์— ๋Œ€ํ•ด ์ƒ์„ธํ•œ ์ •๋ณด๋ฅผ ๋ณด์—ฌ์ค€๋‹ค.
  • kubectl logs - ํŒŒ๋“œ ๋‚ด ์ปจํ…Œ์ด๋„ˆ์˜ ๋กœ๊ทธ๋“ค์„ ์ถœ๋ ฅํ•œ๋‹ค
  • kubectl exec - ํŒŒ๋“œ ๋‚ด ์ปจํ…Œ์ด๋„ˆ์— ๋Œ€ํ•œ ๋ช…๋ น์„ ์‹คํ–‰ํ•œ๋‹ค.

์–ธ์ œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋ฐฐํฌ๋˜์—ˆ์œผ๋ฉฐ, ํ˜„์žฌ ์ƒํƒœ๊ฐ€ ์–ด๋– ํ•œ์ง€, ๊ทธ๊ฒƒ์˜ ๊ตฌ์„ฑ์€ ์–ด๋– ํ•œ์ง€ ๋“ฑ์„ ๋ณด๊ธฐ ์œ„ํ•ด ์ด๋Ÿฌํ•œ ๋ช…๋ น์„ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด์ œ ํด๋Ÿฌ์Šคํ„ฐ ์ปดํฌ๋„ŒํŠธ์™€ ์ปค๋งจ๋“œ ๋ผ์ธ์— ๋Œ€ํ•ด ์•Œ์•„ ๋ณด์•˜์œผ๋‹ˆ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์กฐ์‚ฌํ•ด ๋ณด์ž.

๋…ธ๋“œ๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์— ์žˆ์–ด์„œ ์›Œ์ปค ๋จธ์‹ ์ด๋ฉฐ ํด๋Ÿฌ์Šคํ„ฐ์— ๋”ฐ๋ผ VM ๋˜๋Š” ๋ฌผ๋ฆฌ ๋จธ์‹ ์ด ๋  ์ˆ˜ ์žˆ๋‹ค. ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํŒŒ๋“œ๋Š” ํ•˜๋‚˜์˜ ๋…ธ๋“œ ์œ„์—์„œ ๋™์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.


2.3.2 - ๋Œ€ํ™”ํ˜• ํŠœํ† ๋ฆฌ์–ผ - ์•ฑ ์กฐ์‚ฌํ•˜๊ธฐ


ํ„ฐ๋ฏธ๋„๊ณผ ์ƒํ˜ธ์ž‘์šฉํ•˜๊ธฐ ์œ„ํ•ด, ๋ฐ์Šคํฌํƒ‘/ํƒœ๋ธ”๋ฆฟ ๋ฒ„์ „์„ ์ด์šฉํ•œ๋‹ค.

2.4 - ์•ฑ ์™ธ๋ถ€๋กœ ๋…ธ์ถœํ•˜๊ธฐ

2.4.1 - ์•ฑ ๋…ธ์ถœ์„ ์œ„ํ•ด ์„œ๋น„์Šค ์ด์šฉํ•˜๊ธฐ

๋ชฉํ‘œ

  • ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์˜ ์„œ๋น„์Šค์— ๋Œ€ํ•ด ๋ฐฐ์šด๋‹ค.
  • ๋ ˆ์ด๋ธ”๊ณผ ๋ ˆ์ด๋ธ”์…€๋ž™ํ„ฐ ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์–ด๋–ป๊ฒŒ ์„œ๋น„์Šค์™€ ์—ฐ๊ด€๋˜๋Š”์ง€ ์ดํ•ดํ•œ๋‹ค.
  • ์„œ๋น„์Šค๋ฅผ ์ด์šฉํ•˜์—ฌ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ ์™ธ๋ถ€๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋…ธ์ถœํ•œ๋‹ค.

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์„œ๋น„์Šค๋“ค์— ๋Œ€ํ•œ ๊ฐœ์š”

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํŒŒ๋“œ๋“ค ์€ ์–ธ์  ๊ฐ€๋Š” ์ฃฝ๊ฒŒ๋œ๋‹ค. ํŒŒ๋“œ๋“ค์€ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ฐ–๋Š”๋‹ค. ์›Œ์ปค ๋…ธ๋“œ๊ฐ€ ์ฃฝ์œผ๋ฉด, ๋…ธ๋“œ ์ƒ์—์„œ ๋™์ž‘ํ•˜๋Š” ํŒŒ๋“œ๋“ค ๋˜ํ•œ ์ข…๋ฃŒ๋œ๋‹ค. ๋ ˆํ”Œ๋ฆฌ์นด์…‹(ReplicaSet)์€ ์—ฌ๋Ÿฌ๋ถ„์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ง€์†์ ์œผ๋กœ ๋™์ž‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ƒˆ๋กœ์šด ํŒŒ๋“œ๋“ค์˜ ์ƒ์„ฑ์„ ํ†ตํ•ด ๋™์ ์œผ๋กœ ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ๋ฏธ๋ฆฌ ์ง€์ •ํ•ด ๋‘” ์ƒํƒœ๋กœ ๋˜๋Œ๋ ค ์ค„ ์ˆ˜๋„ ์žˆ๋‹ค. ๋˜ ๋‹ค๋ฅธ ์˜ˆ์‹œ๋กœ์„œ, 3๊ฐœ์˜ ๋ณต์ œ๋ณธ์„ ๊ฐ–๋Š” ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ์šฉ ๋ฐฑ์—”๋“œ๋ฅผ ๊ณ ๋ คํ•ด ๋ณด์ž. ๊ทธ ๋ณต์ œ๋ณธ๋“ค์€ ๊ต์ฒด ๊ฐ€๋Šฅํ•œ ์ƒํƒœ์ด๋‹ค. ๊ทธ๋ž˜์„œ ํ”„๋ก ํŠธ์—”๋“œ ์‹œ์Šคํ…œ์€ ํ•˜๋‚˜์˜ ํŒŒ๋“œ๊ฐ€ ์†Œ๋ฉธ๋˜์–ด ์žฌ์ƒ์„ฑ์ด ๋˜๋”๋ผ๋„, ๋ฐฑ์—”๋“œ ๋ณต์ œ๋ณธ๋“ค์— ์˜ํ•œ ์˜ํ–ฅ์„ ๋ฐ›์•„์„œ๋Š” ์•ˆ๋œ๋‹ค. ์ฆ‰, ๋™์ผ ๋…ธ๋“œ ์ƒ์˜ ํŒŒ๋“œ๋“ค์ด๋ผ ํ• ์ง€๋ผ๋„, ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ ๋‚ด ๊ฐ ํŒŒ๋“œ๋Š” ์œ ์ผํ•œ IP ์ฃผ์†Œ๋ฅผ ๊ฐ€์ง€๋ฉฐ, ์—ฌ๋Ÿฌ๋ถ„์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๋“ค์ด ์ง€์†์ ์œผ๋กœ ๊ธฐ๋Šฅํ•  ์ˆ˜ ์žˆ๋„๋ก ํŒŒ๋“œ๋“ค ์†์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ณ€ํ™”์— ๋Œ€ํ•ด ์ž๋™์œผ๋กœ ์กฐ์ •ํ•ด ์ค„ ๋ฐฉ๋ฒ•์ด ์žˆ์–ด์•ผ ํ•œ๋‹ค.

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์—์„œ ์„œ๋น„์Šค๋Š” ํ•˜๋‚˜์˜ ๋…ผ๋ฆฌ์ ์ธ ํŒŒ๋“œ ์…‹๊ณผ ๊ทธ ํŒŒ๋“œ๋“ค์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ์ •์ฑ…์„ ์ •์˜ํ•˜๋Š” ์ถ”์ƒ์  ๊ฐœ๋…์ด๋‹ค. ์„œ๋น„์Šค๋Š” ์ข…์†์ ์ธ ํŒŒ๋“œ๋“ค ์‚ฌ์ด๋ฅผ ๋А์Šจํ•˜๊ฒŒ ๊ฒฐํ•ฉ๋˜๋„๋ก ํ•ด์ค€๋‹ค. ์„œ๋น„์Šค๋Š” ๋ชจ๋“  ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์˜ค๋ธŒ์ ํŠธ๋“ค๊ณผ ๊ฐ™์ด YAML (๋ณด๋‹ค ์„ ํ˜ธํ•˜๋Š”) ๋˜๋Š” JSON์„ ์ด์šฉํ•˜์—ฌ ์ •์˜๋œ๋‹ค. ์„œ๋น„์Šค๊ฐ€ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” ํŒŒ๋“œ ์…‹์€ ๋ณดํ†ต LabelSelector์— ์˜ํ•ด ๊ฒฐ์ •๋œ๋‹ค (์—ฌ๋Ÿฌ๋ถ„์ด ์™œ ์ŠคํŽ™์— selector๊ฐ€ ํฌํ•จ๋˜์ง€ ์•Š์€ ์„œ๋น„์Šค๋ฅผ ํ•„์š”๋กœ ํ•˜๊ฒŒ ๋  ์ˆ˜๋„ ์žˆ๋Š”์ง€์— ๋Œ€ํ•ด ์•„๋ž˜์—์„œ ํ™•์ธํ•ด ๋ณด์ž).

๋น„๋ก ๊ฐ ํŒŒ๋“œ๋“ค์ด ๊ณ ์œ ์˜ IP๋ฅผ ๊ฐ–๊ณ  ์žˆ๊ธฐ๋Š” ํ•˜์ง€๋งŒ, ๊ทธ IP๋“ค์€ ์„œ๋น„์Šค์˜ ๋„์›€์—†์ด ํด๋Ÿฌ์Šคํ„ฐ ์™ธ๋ถ€๋กœ ๋…ธ์ถœ๋˜์–ด์งˆ ์ˆ˜ ์—†๋‹ค. ์„œ๋น„์Šค๋“ค์€ ์—ฌ๋Ÿฌ๋ถ„์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๋“ค์—๊ฒŒ ํŠธ๋ž˜ํ”ฝ์ด ์‹ค๋ฆด ์ˆ˜ ์žˆ๋„๋ก ํ—ˆ์šฉํ•ด์ค€๋‹ค. ์„œ๋น„์Šค๋“ค์€ ServiceSpec์—์„œ type์„ ์ง€์ •ํ•จ์œผ๋กœ์จ ๋‹ค์–‘ํ•œ ๋ฐฉ์‹๋“ค๋กœ ๋…ธ์ถœ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค:

  • ClusterIP (๊ธฐ๋ณธ๊ฐ’) - ํด๋Ÿฌ์Šคํ„ฐ ๋‚ด์—์„œ ๋‚ด๋ถ€ IP ์— ๋Œ€ํ•ด ์„œ๋น„์Šค๋ฅผ ๋…ธ์ถœํ•ด์ค€๋‹ค. ์ด ๋ฐฉ์‹์€ ์˜ค์ง ํด๋Ÿฌ์Šคํ„ฐ ๋‚ด์—์„œ๋งŒ ์„œ๋น„์Šค๊ฐ€ ์ ‘๊ทผ๋  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค.
  • NodePort - NAT๊ฐ€ ์ด์šฉ๋˜๋Š” ํด๋Ÿฌ์Šคํ„ฐ ๋‚ด์—์„œ ๊ฐ๊ฐ ์„ ํƒ๋œ ๋…ธ๋“œ๋“ค์˜ ๋™์ผํ•œ ํฌํŠธ์— ์„œ๋น„์Šค๋ฅผ ๋…ธ์ถœ์‹œ์ผœ์ค€๋‹ค. <NodeIP>:<NodePort>๋ฅผ ์ด์šฉํ•˜์—ฌ ํด๋Ÿฌ์Šคํ„ฐ ์™ธ๋ถ€๋กœ๋ถ€ํ„ฐ ์„œ๋น„์Šค๊ฐ€ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค. ClusterIP์˜ ์ƒ์œ„ ์ง‘ํ•ฉ์ด๋‹ค.
  • LoadBalancer - (์ง€์› ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ) ๊ธฐ์กด ํด๋ผ์šฐ๋“œ์—์„œ ์™ธ๋ถ€์šฉ ๋กœ๋“œ๋ฐธ๋Ÿฐ์„œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์„œ๋น„์Šค์— ๊ณ ์ •๋œ ๊ณต์ธ IP๋ฅผ ํ• ๋‹นํ•ด์ค€๋‹ค. NodePort์˜ ์ƒ์œ„ ์ง‘ํ•ฉ์ด๋‹ค.
  • ExternalName - CNAME ๋ ˆ์ฝ”๋“œ ๋ฐ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•จ์œผ๋กœ์จ ์„œ๋น„์Šค๋ฅผ externalName ํ•„๋“œ์˜ ๋‚ด์šฉ(์˜ˆ๋ฅผ ๋“ค๋ฉด, foo.bar.example.com)์— ๋งคํ•‘ํ•œ๋‹ค. ์–ด๋– ํ•œ ์ข…๋ฅ˜์˜ ํ”„๋ก์‹œ๋„ ์„ค์ •๋˜์ง€ ์•Š๋Š”๋‹ค. ์ด ๋ฐฉ์‹์€ kube-dns v1.7 ์ด์ƒ ๋˜๋Š” CoreDNS ๋ฒ„์ „ 0.0.8 ์ด์ƒ์„ ํ•„์š”๋กœ ํ•œ๋‹ค.

๋‹ค๋ฅธ ์„œ๋น„์Šค ํƒ€์ž…๋“ค์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ์ •๋ณด๋Š” ์†Œ์Šค IP ์ด์šฉํ•˜๊ธฐ ํŠœํ† ๋ฆฌ์–ผ์—์„œ ํ™•์ธ ๊ฐ€๋Šฅํ•˜๋‹ค. ๋˜ํ•œ ์„œ๋น„์Šค๋“ค๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ ‘์†ํ•˜๊ธฐ๋„ ์ฐธ๊ณ ํ•ด ๋ณด์ž.

๋ถ€๊ฐ€์ ์œผ๋กœ, spec์— selector๋ฅผ ์ •์˜ํ•˜์ง€ ์•Š๊ณ  ๋ง์•„๋„ฃ์€ ์„œ๋น„์Šค๋“ค์˜ ๋ช‡ ๊ฐ€์ง€ ์œ ์ฆˆ์ผ€์ด์Šค๋“ค์ด ์žˆ์Œ์„ ์ฃผ์˜ํ•˜์ž. selector ์—†์ด ์ƒ์„ฑ๋œ ์„œ๋น„์Šค๋Š” ์ƒ์‘ํ•˜๋Š” ์—”๋“œํฌ์ธํŠธ ์˜ค๋ธŒ์ ํŠธ๋“ค ๋˜ํ•œ ์ƒ์„ฑํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ด๋กœ์จ ์‚ฌ์šฉ์ž๋“ค๋กœ ํ•˜์—ฌ๊ธˆ ํ•˜๋‚˜์˜ ์„œ๋น„์Šค๋ฅผ ํŠน์ •ํ•œ ์—”๋“œํฌ์ธํŠธ์— ๋งคํ•‘ ์‹œํ‚ฌ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค. selector๋ฅผ ์ƒ๋žตํ•˜๊ฒŒ ๋˜๋Š” ๋˜ ๋‹ค๋ฅธ ๊ฐ€๋Šฅ์„ฑ์€ ์—ฌ๋Ÿฌ๋ถ„์ด type: ExternalName์„ ์ด์šฉํ•˜๊ฒ ๋‹ค๊ณ  ํ™•๊ณ ํ•˜๊ฒŒ ์˜๋„ํ•˜๋Š” ๊ฒฝ์šฐ์ด๋‹ค.

์š”์•ฝ

  • ํŒŒ๋“œ๋“ค์„ ์™ธ๋ถ€ ํŠธ๋ž˜ํ”ฝ์— ๋…ธ์ถœํ•˜๊ธฐ
  • ์—ฌ๋Ÿฌ ํŒŒ๋“œ์— ๊ฑธ์ณ์„œ ํŠธ๋ž˜ํ”ฝ ๋กœ๋“œ๋ฐธ๋Ÿฐ์‹ฑ ํ•˜๊ธฐ
  • ๋ ˆ์ด๋ธ” ์‚ฌ์šฉํ•˜๊ธฐ

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์„œ๋น„์Šค๋Š” ๋…ผ๋ฆฌ์  ํŒŒ๋“œ ์…‹์„ ์ •์˜ํ•˜๊ณ  ์™ธ๋ถ€ ํŠธ๋ž˜ํ”ฝ ๋…ธ์ถœ, ๋กœ๋“œ๋ฐธ๋Ÿฐ์‹ฑ ๊ทธ๋ฆฌ๊ณ  ๊ทธ ํŒŒ๋“œ๋“ค์— ๋Œ€ํ•œ ์„œ๋น„์Šค ๋””์Šค์ปค๋ฒ„๋ฆฌ๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” ์ถ”์ƒ ๊ณ„์ธต์ด๋‹ค.


์„œ๋น„์Šค์™€ ๋ ˆ์ด๋ธ”

์„œ๋น„์Šค๋Š” ํŒŒ๋“œ ์…‹์— ๊ฑธ์ณ์„œ ํŠธ๋ž˜ํ”ฝ์„ ๋ผ์šฐํŠธํ•œ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์œผ๋ฉด์„œ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์—์„œ ํŒŒ๋“œ๋“ค์ด ์ฃฝ๊ฒŒ๋„ ํ•˜๊ณ , ๋ณต์ œ๊ฐ€ ๋˜๊ฒŒ๋„ ํ•ด์ฃผ๋Š” ์ถ”์ƒ์  ๊ฐœ๋…์ด๋‹ค. ์ข…์†์ ์ธ ํŒŒ๋“œ๋“ค ์‚ฌ์ด์—์„œ์˜ ๋””์Šค์ปค๋ฒ„๋ฆฌ์™€ ๋ผ์šฐํŒ…์€ (ํ•˜๋‚˜์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ํ”„๋กœํŠธ์—”๋“œ์™€ ๋ฐฑ์—”๋“œ ์ปดํฌ๋„ŒํŠธ์™€ ๊ฐ™์€) ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์„œ๋น„์Šค๋“ค์— ์˜ํ•ด ์ฒ˜๋ฆฌ๋œ๋‹ค.

์„œ๋น„์Šค๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์˜ ๊ฐ์ฒด๋“ค์— ๋Œ€ํ•ด ๋…ผ๋ฆฌ ์—ฐ์‚ฐ์„ ํ—ˆ์šฉํ•ด์ฃผ๋Š” ๊ธฐ๋ณธ ๊ทธ๋ฃนํ•‘ ๋‹จ์œ„์ธ, ๋ ˆ์ด๋ธ”๊ณผ ์…€๋ ‰ํ„ฐ๋ฅผ ์ด์šฉํ•˜์—ฌ ํŒŒ๋“œ ์…‹๊ณผ ๋งค์น˜์‹œํ‚จ๋‹ค. ๋ ˆ์ด๋ธ”์€ ์˜ค๋ธŒ์ ํŠธ๋“ค์— ๋ถ™์—ฌ์ง„ ํ‚ค/๋ฐธ๋ฅ˜ ์Œ์œผ๋กœ ๋‹ค์–‘ํ•œ ๋ฐฉ์‹์œผ๋กœ ์ด์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค:

  • ๊ฐœ๋ฐœ, ํ…Œ์ŠคํŠธ, ๊ทธ๋ฆฌ๊ณ  ์ƒ์šฉํ™˜๊ฒฝ์— ๋Œ€ํ•œ ๊ฐ์ฒด๋“ค์˜ ์ง€์ •
  • ์ž„๋ฒ ๋””๋“œ๋œ ๋ฒ„์ „ ํƒœ๊ทธ๋“ค
  • ํƒœ๊ทธ๋“ค์„ ์ด์šฉํ•˜๋Š” ๊ฐ์ฒด๋“ค์— ๋Œ€ํ•œ ๋ถ„๋ฅ˜


๋ ˆ์ด๋ธ”์€ ์˜ค๋ธŒ์ ํŠธ์˜ ์ƒ์„ฑ ์‹œ์  ๋˜๋Š” ์ดํ›„ ์‹œ์ ์— ๋ถ™์—ฌ์งˆ ์ˆ˜ ์žˆ๋‹ค. ์–ธ์ œ๋“ ์ง€ ์ˆ˜์ •์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ์ด์ œ ์„œ๋น„์Šค๋ฅผ ์ด์šฉํ•˜์—ฌ ์šฐ๋ฆฌ์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋…ธ์ถœ๋„ ์‹œ์ผœ๋ณด๊ณ  ๋ ˆ์ด๋ธ”๋„ ์ ์šฉํ•ด ๋ณด์ž.


2.4.2 - ๋Œ€ํ™”ํ˜• ํŠœํ† ๋ฆฌ์–ผ - ์•ฑ ๋…ธ์ถœํ•˜๊ธฐ

ํ„ฐ๋ฏธ๋„๊ณผ ์ƒํ˜ธ์ž‘์šฉํ•˜๊ธฐ ์œ„ํ•ด, ๋ฐ์Šคํฌํƒ‘/ํƒœ๋ธ”๋ฆฟ ๋ฒ„์ „์„ ์ด์šฉํ•œ๋‹ค.

2.5 - ์•ฑ ์Šค์ผ€์ผ๋งํ•˜๊ธฐ

2.5.1 - ๋ณต์ˆ˜์˜ ์•ฑ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ตฌ๋™ํ•˜๊ธฐ

๋ชฉํ‘œ

  • kubectl์„ ์‚ฌ์šฉํ•ด์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์Šค์ผ€์ผํ•œ๋‹ค.

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์Šค์ผ€์ผํ•˜๊ธฐ

์ง€๋‚œ ๋ชจ๋“ˆ์—์„œ ๋””ํ”Œ๋กœ์ด๋จผํŠธ๋ฅผ ๋งŒ๋“ค๊ณ , ์„œ๋น„์Šค๋ฅผ ํ†ตํ•ด์„œ ๋””ํ”Œ๋กœ์ด๋จผํŠธ๋ฅผ ์™ธ๋ถ€์— ๋…ธ์ถœ์‹œ์ผœ ๋ดค๋‹ค. ํ•ด๋‹น ๋””ํ”Œ๋กœ์ด๋จผํŠธ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌ๋™ํ•˜๊ธฐ ์œ„ํ•ด ๋‹จ ํ•˜๋‚˜์˜ ํŒŒ๋“œ๋งŒ์„ ์ƒ์„ฑํ–ˆ์—ˆ๋‹ค. ํŠธ๋ž˜ํ”ฝ์ด ์ฆ๊ฐ€ํ•˜๋ฉด, ์‚ฌ์šฉ์ž ์š”์ฒญ์— ๋งž์ถ”์–ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ทœ๋ชจ๋ฅผ ์กฐ์ •ํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

๋””ํ”Œ๋กœ์ด๋จผํŠธ์˜ ๋ณต์ œ ์ˆ˜๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด ์Šค์ผ€์ผ๋ง์ด ์ˆ˜ํ–‰๋œ๋‹ค

์š”์•ฝ:

  • ๋””ํ”Œ๋กœ์ด๋จผํŠธ ์Šค์ผ€์ผ๋งํ•˜๊ธฐ

kubectl create deployment ๋ช…๋ น์— --replicas ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋ณต์ˆ˜์˜ ์ธ์Šคํ„ด์Šค๋กœ ๊ตฌ๋™๋˜๋Š” ๋””ํ”Œ๋กœ์ด๋จผํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ๋‹ค


์Šค์ผ€์ผ๋ง ๊ฐœ์š”


๋””ํ”Œ๋กœ์ด๋จผํŠธ๋ฅผ ์Šค์ผ€์ผ ์•„์›ƒํ•˜๋ฉด ์‹ ๊ทœ ํŒŒ๋“œ๊ฐ€ ์ƒ์„ฑ๋˜์–ด์„œ ๊ฐ€์šฉํ•œ ์ž์›์ด ์žˆ๋Š” ๋…ธ๋“œ์— ์Šค์ผ€์ค„๋œ๋‹ค. ์Šค์ผ€์ผ๋ง ๊ธฐ๋Šฅ์€ ์ƒˆ๋กœ ์˜๋„ํ•œ ์ƒํƒœ(desired state)๊นŒ์ง€ ํŒŒ๋“œ์˜ ์ˆ˜๋ฅผ ๋Š˜๋ฆฐ๋‹ค. ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋Š” ํŒŒ๋“œ์˜ ์˜คํ† ์Šค์ผ€์ผ๋ง ๋„ ์ง€์›ํ•˜์ง€๋งŒ ๋ณธ ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” ๋‹ค๋ฃจ์ง€ ์•Š๋Š”๋‹ค. 0๊นŒ์ง€ ์Šค์ผ€์ผ๋งํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค. ์ด ๊ฒฝ์šฐ ํ•ด๋‹น ๋””ํ”Œ๋กœ์ด๋จผํŠธ์˜ ๋ชจ๋“  ํŒŒ๋“œ๊ฐ€ ์ข…๋ฃŒ๋œ๋‹ค.

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ณต์ˆ˜๋กœ ๊ตฌ๋™ํ•˜๊ฒŒ ๋˜๋ฉด ํŠธ๋ž˜ํ”ฝ์„ ํ•ด๋‹น ์ธ์Šคํ„ด์Šค ๋ชจ๋‘์— ๋ถ„์‚ฐ์‹œํ‚ฌ ๋ฐฉ๋ฒ•์ด ํ•„์š”ํ•ด์ง„๋‹ค. ์„œ๋น„์Šค๋Š” ๋…ธ์ถœ๋œ ๋””ํ”Œ๋กœ์ด๋จผํŠธ์˜ ๋ชจ๋“  ํŒŒ๋“œ์— ๋„คํŠธ์›Œํฌ ํŠธ๋ž˜ํ”ฝ์„ ๋ถ„์‚ฐ์‹œ์ผœ์ค„ ํ†ตํ•ฉ๋œ ๋กœ๋“œ๋ฐธ๋Ÿฐ์„œ๋ฅผ ๊ฐ–๋Š”๋‹ค. ์„œ๋น„์Šค๋Š” ์—”๋“œํฌ์ธํŠธ๋ฅผ ์ด์šฉํ•ด์„œ ๊ตฌ๋™์ค‘์ธ ํŒŒ๋“œ๋ฅผ ์ง€์†์ ์œผ๋กœ ๋ชจ๋‹ˆํ„ฐ๋งํ•จ์œผ๋กœ์จ ๊ฐ€์šฉํ•œ ํŒŒ๋“œ์—๋งŒ ํŠธ๋ž˜ํ”ฝ์ด ์ „๋‹ฌ๋˜๋„๋ก ํ•ด์ค€๋‹ค.

๋””ํ”Œ๋กœ์ด๋จผํŠธ์˜ ๋ณต์ œ ์ˆ˜๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด ์Šค์ผ€์ผ๋ง์ด ์ˆ˜ํ–‰๋œ๋‹ค.


์ผ๋‹จ ๋ณต์ˆ˜์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ตฌ๋™ ์ค‘์ด๋ฉด, ๋‹ค์šดํƒ€์ž„ ์—†์ด ๋กค๋ง ์—…๋ฐ์ดํŠธ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹ค์Œ ๋ชจ๋“ˆ์—์„œ ์ด ๋‚ด์šฉ์„ ๋‹ค๋ฃจ๋„๋ก ํ•˜๊ฒ ๋‹ค. ์ด์ œ ์˜จ๋ผ์ธ ํ„ฐ๋ฏธ๋„๋กœ ๊ฐ€์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์Šค์ผ€์ผํ•ด๋ณด์ž.


2.5.2 - ๋Œ€ํ™”ํ˜• ํŠœํ† ๋ฆฌ์–ผ - ์•ฑ ์Šค์ผ€์ผ๋งํ•˜๊ธฐ

ํ„ฐ๋ฏธ๋„๋กœ ์ƒํ˜ธ ์ž‘์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ, ๋ฐ์Šคํฌํƒ‘/ํƒœ๋ธ”๋ฆฟ ๋ฒ„์ „์„ ์‚ฌ์šฉํ•ด์ฃผ์„ธ์š”

2.6 - ์•ฑ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ

2.6.1 - ๋กค๋ง ์—…๋ฐ์ดํŠธ ์ˆ˜ํ–‰ํ•˜๊ธฐ

๋ชฉํ‘œ

  • kubectl์„ ์ด์šฉํ•˜์—ฌ ๋กค๋ง ์—…๋ฐ์ดํŠธ ์ˆ˜ํ–‰ํ•˜๊ธฐ

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ

์‚ฌ์šฉ์ž๋“ค์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ํ•ญ์ƒ ๊ฐ€์šฉํ•œ ์ƒํƒœ์ผ ๊ฒƒ์ด๋ผ ์—ฌ๊ธฐ๊ณ  ๊ฐœ๋ฐœ์ž๋“ค์€ ํ•˜๋ฃจ์— ์—ฌ๋Ÿฌ๋ฒˆ์”ฉ ์ƒˆ๋กœ์šด ๋ฒ„์ „์„ ๋ฐฐํฌํ•˜๋„๋ก ์š”๊ตฌ ๋ฐ›๊ณ ์žˆ๋‹ค. ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์—์„œ๋Š” ์ด๊ฒƒ์„ ๋กค๋ง ์—…๋ฐ์ดํŠธ๋ฅผ ํ†ตํ•ด ์ด๋ฃจ๊ณ  ์žˆ๋‹ค. ๋กค๋ง ์—…๋ฐ์ดํŠธ๋Š” ํŒŒ๋“œ ์ธ์Šคํ„ด์Šค๋ฅผ ์ ์ง„์ ์œผ๋กœ ์ƒˆ๋กœ์šด ๊ฒƒ์œผ๋กœ ์—…๋ฐ์ดํŠธํ•˜์—ฌ ๋””ํ”Œ๋กœ์ด๋จผํŠธ ์—…๋ฐ์ดํŠธ๊ฐ€ ์„œ๋น„์Šค ์ค‘๋‹จ ์—†์ด ์ด๋ฃจ์–ด์งˆ ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค. ์ƒˆ๋กœ์šด ํŒŒ๋“œ๋Š” ๊ฐ€์šฉํ•œ ์ž์›์„ ๋ณด์œ ํ•œ ๋…ธ๋“œ๋กœ ์Šค์ผ€์ค„๋  ๊ฒƒ์ด๋‹ค.

์ด์ „ ๋ชจ๋“ˆ์—์„œ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋™์ž‘์‹œํ‚ค๋„๋ก ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์Šค์ผ€์ผํ–ˆ๋‹ค. ์ด๊ฒƒ์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ฐ€์šฉ์„ฑ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์œผ๋ฉด์„œ ์—…๋ฐ์ดํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ์š”๊ตฌ์ด๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ, ์—…๋ฐ์ดํŠธ๊ฐ€ ์ด๋ฃจ์–ด์ง€๋Š” ๋™์•ˆ ์ด์šฉ ๋ถˆ๊ฐ€ํ•œ ํŒŒ๋“œ์˜ ์ตœ๋Œ€ ๊ฐœ์ˆ˜์™€ ์ƒ์„ฑ ๊ฐ€๋Šฅํ•œ ์ƒˆ๋กœ์šด ํŒŒ๋“œ์˜ ์ตœ๋Œ€ ๊ฐœ์ˆ˜๋Š” ํ•˜๋‚˜๋‹ค. ๋‘ ์˜ต์…˜์€ (ํŒŒ๋“œ์— ๋Œ€ํ•œ) ๊ฐœ์ˆ˜ ๋˜๋Š” ๋ฐฑ๋ถ„์œจ๋กœ ๊ตฌ์„ฑ๋  ์ˆ˜ ์žˆ๋‹ค. ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์—์„œ, ์—…๋ฐ์ดํŠธ๋Š” ๋ฒ„์ „์œผ๋กœ ๊ด€๋ฆฌ๋˜๊ณ  ์–ด๋– ํ•œ ๋””ํ”Œ๋กœ์ด๋จผํŠธ ์—…๋ฐ์ดํŠธ๋ผ๋„ ์ด์ „์˜ (์•ˆ์ •์ ์ธ) ๋ฒ„์ „์œผ๋กœ ์›๋ณต์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

์š”์•ฝ:

  • ์•ฑ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ

๋กค๋ง ์—…๋ฐ์ดํŠธ๋Š” ํŒŒ๋“œ ์ธ์Šคํ„ด์Šค๋ฅผ ์ ์ง„์ ์œผ๋กœ ์ƒˆ๋กœ์šด ๊ฒƒ์œผ๋กœ ์—…๋ฐ์ดํŠธํ•˜์—ฌ ๋””ํ”Œ๋กœ์ด๋จผํŠธ ์—…๋ฐ์ดํŠธ๊ฐ€ ์„œ๋น„์Šค ์ค‘๋‹จ ์—†์ด ์ด๋ฃจ์–ด์งˆ ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค.


๋กค๋ง ์—…๋ฐ์ดํŠธ ๊ฐœ์š”


์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์Šค์ผ€์ผ๋ง๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ, ๋””ํ”Œ๋กœ์ด๋จผํŠธ๊ฐ€ ์™ธ๋ถ€๋กœ ๋…ธ์ถœ๋˜๋ฉด, ์„œ๋น„์Šค๋Š” ์—…๋ฐ์ดํŠธ๊ฐ€ ์ด๋ฃจ์–ด์ง€๋Š” ๋™์•ˆ ์˜ค์ง ๊ฐ€์šฉํ•œ ํŒŒ๋“œ์—๊ฒŒ๋งŒ ํŠธ๋ž˜ํ”ฝ์„ ๋กœ๋“œ๋ฐธ๋Ÿฐ์Šค ํ•  ๊ฒƒ์ด๋‹ค. ๊ฐ€์šฉํ•œ ํŒŒ๋“œ๋ž€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์‚ฌ์šฉ์ž๋“ค์—๊ฒŒ ๊ฐ€์šฉํ•œ ์ƒํƒœ์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งํ•œ๋‹ค.

๋กค๋ง ์—…๋ฐ์ดํŠธ๋Š” ๋‹ค์Œ ๋™์ž‘๋“ค์„ ํ—ˆ์šฉํ•ด์ค€๋‹ค:

  • ํ•˜๋‚˜์˜ ํ™˜๊ฒฝ์—์„œ ๋˜ ๋‹ค๋ฅธ ํ™˜๊ฒฝ์œผ๋กœ์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ”„๋กœ๋ชจ์…˜ (์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€ ์—…๋ฐ์ดํŠธ๋ฅผ ํ†ตํ•ด)
  • ์ด์ „ ๋ฒ„์ „์œผ๋กœ์˜ ๋กค๋ฐฑ
  • ์„œ๋น„์Šค ์ค‘๋‹จ ์—†๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ง€์†์ ์ธ ํ†ตํ•ฉ๊ณผ ์ง€์†์ ์ธ ์ „๋‹ฌ

๋””ํ”Œ๋กœ์ด๋จผํŠธ๊ฐ€ ์™ธ๋ถ€๋กœ ๋…ธ์ถœ๋˜๋ฉด, ์„œ๋น„์Šค๋Š” ์—…๋ฐ์ดํŠธ๊ฐ€ ์ด๋ฃจ์–ด์ง€๋Š” ๋™์•ˆ ์˜ค์ง ๊ฐ€์šฉํ•œ ํŒŒ๋“œ์—๊ฒŒ๋งŒ ํŠธ๋ž˜ํ”ฝ์„ ๋กœ๋“œ๋ฐธ๋Ÿฐ์Šค ํ•  ๊ฒƒ์ด๋‹ค.


๋‹ค์Œ ๋Œ€ํ™”ํ˜• ํŠœํ† ๋ฆฌ์–ผ์—์„œ, ์ƒˆ๋กœ์šด ๋ฒ„์ „์œผ๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์—…๋ฐ์ดํŠธํ•˜๊ณ , ๋กค๋ฐฑ ๋˜ํ•œ ์ˆ˜ํ–‰ํ•ด ๋ณผ ๊ฒƒ์ด๋‹ค.


2.6.2 - ๋Œ€ํ™”ํ˜• ํŠœํ† ๋ฆฌ์–ผ - ์•ฑ ์—…๋ฐ์ดํŠธ ํ•˜๊ธฐ

ํ„ฐ๋ฏธ๋„๊ณผ ์ƒํ˜ธ์ž‘์šฉํ•˜๊ธฐ ์œ„ํ•ด, ๋ฐ์Šคํฌํƒ‘/ํƒœ๋ธ”๋ฆฟ ๋ฒ„์ „์„ ์ด์šฉํ•œ๋‹ค.

3 - ์„ค์ •

3.1 - ์ปจํ”ผ๊ทธ๋งต์„ ์‚ฌ์šฉํ•ด์„œ Redis ์„ค์ •ํ•˜๊ธฐ

์ด ํŽ˜์ด์ง€์—์„œ๋Š” ์ปจํ”ผ๊ทธ๋งต(ConfigMap)์„ ์‚ฌ์šฉํ•ด์„œ Redis๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์‹ค์„ธ๊ณ„ ์˜ˆ์ œ๋ฅผ ์ œ๊ณตํ•˜๊ณ , ์ปจํ”ผ๊ทธ๋งต์„ ์‚ฌ์šฉํ•ด์„œ ํŒŒ๋“œ ์„ค์ •ํ•˜๊ธฐ ํƒœ์Šคํฌ๋กœ ๋นŒ๋“œ๋ฅผ ํ•œ๋‹ค.

๋ชฉ์ 

  • Redis ์„ค์ •๊ฐ’์œผ๋กœ ์ปจํ”ผ๊ทธ๋งต์„ ์ƒ์„ฑํ•œ๋‹ค.
  • ์ƒ์„ฑ๋œ ์ปจํ”ผ๊ทธ๋งต์„ ๋งˆ์šดํŠธํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” Redis ํŒŒ๋“œ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
  • ์„ค์ •์ด ์ž˜ ์ ์šฉ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

์‹œ์ž‘ํ•˜๊ธฐ ์ „์—

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ๊ฐ€ ํ•„์š”ํ•˜๊ณ , kubectl ์ปค๋งจ๋“œ-๋ผ์ธ ํˆด์ด ํด๋Ÿฌ์Šคํ„ฐ์™€ ํ†ต์‹ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •๋˜์–ด ์žˆ์–ด์•ผ ํ•œ๋‹ค. ์ด ํŠœํ† ๋ฆฌ์–ผ์€ ์ปจํŠธ๋กค ํ”Œ๋ ˆ์ธ ํ˜ธ์ŠคํŠธ๊ฐ€ ์•„๋‹Œ ๋…ธ๋“œ๊ฐ€ ์ ์–ด๋„ 2๊ฐœ ํฌํ•จ๋œ ํด๋Ÿฌ์Šคํ„ฐ์—์„œ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค. ๋งŒ์•ฝ, ์•„์ง ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š๋‹ค๋ฉด, minikube๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ๋‹ค์Œ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํ”Œ๋ ˆ์ด๊ทธ๋ผ์šด๋“œ ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฒ„์ „ ํ™•์ธ์„ ์œ„ํ•ด์„œ, ๋‹ค์Œ ์ปค๋งจ๋“œ๋ฅผ ์‹คํ–‰ kubectl version.

์‹ค์„ธ์ƒ ์˜ˆ์ œ: ์ปจํ”ผ๊ทธ๋งต์„ ์‚ฌ์šฉํ•ด์„œ Redis ์„ค์ •ํ•˜๊ธฐ

์•„๋ž˜ ๋‹จ๊ณ„๋ฅผ ํ†ตํ•ด์„œ, ์ปจํ”ผ๊ทธ๋งต์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” Redis ์บ์‹œ๋ฅผ ์„ค์ •ํ•œ๋‹ค.

์šฐ์„ , ๋น„์–ด ์žˆ๋Š” ์„ค์ •์œผ๋กœ ์ปจํ”ผ๊ทธ๋งต์„ ์ƒ์„ฑํ•œ๋‹ค.

cat <<EOF >./example-redis-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: example-redis-config
data:
  redis-config: ""
EOF

์œ„์—์„œ ์ƒ์„ฑํ•œ ์ปจํ”ผ๊ทธ๋งต์„ Redis ํŒŒ๋“œ ๋งค๋‹ˆํŽ˜์ŠคํŠธ์™€ ํ•จ๊ป˜ ์ ์šฉํ•œ๋‹ค.

kubectl apply -f example-redis-config.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/pods/config/redis-pod.yaml

Redis ํŒŒ๋“œ ๋งค๋‹ˆํŽ˜์ŠคํŠธ์˜ ๋‚ด์šฉ์„ ๊ฒ€ํ† ํ•˜๊ณ  ๋‹ค์Œ์˜ ์‚ฌํ•ญ์„ ์—ผ๋‘์— ๋‘”๋‹ค.

  • config ๋ผ๋Š” ์ด๋ฆ„์˜ ๋ณผ๋ฅจ์€ spec.volumes[1] ์— ์˜ํ•ด์„œ ์ƒ์„ฑ๋œ๋‹ค.
  • spec.volumes[1].configMap.items[0] ๋‚ด๋ถ€์˜ key ์™€ path ๋Š” config ๋ณผ๋ฅจ์— redis.conf ๋ผ๋Š” ํŒŒ์ผ๋ช…์œผ๋กœ ์ง€์ •๋œ example-redis-config ์ปจํ”ผ๊ทธ๋งต์˜ redis-config ํ‚ค๋ฅผ ๋…ธ์ถœ์‹œํ‚จ๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  config ๋ณผ๋ฅจ์€ spec.containers[0].volumeMounts[1] ์— ์˜ํ•ด์„œ /redis-master ์— ๋งˆ์šดํŠธ๋œ๋‹ค.

์ด ๋‚ด์šฉ์€ ์œ„์˜ example-redis-config ์ปจํ”ผ๊ทธ๋งต์˜ data.redis-config ๋‚ด๋ถ€ ๋ฐ์ดํ„ฐ๋ฅผ ํŒŒ๋“œ ์•ˆ์— ์žˆ๋Š” /redis-master/redis.conf ํŒŒ์ผ์˜ ๋‚ด์šฉ์œผ๋กœ ๋…ธ์ถœ์‹œํ‚ค๋Š” ์ˆœํšจ๊ณผ(net effect)๋ฅผ ๋‚ธ๋‹ค.

apiVersion: v1
kind: Pod
metadata:
  name: redis
spec:
  containers:
  - name: redis
    image: redis:5.0.4
    command:
      - redis-server
      - "/redis-master/redis.conf"
    env:
    - name: MASTER
      value: "true"
    ports:
    - containerPort: 6379
    resources:
      limits:
        cpu: "0.1"
    volumeMounts:
    - mountPath: /redis-master-data
      name: data
    - mountPath: /redis-master
      name: config
  volumes:
    - name: data
      emptyDir: {}
    - name: config
      configMap:
        name: example-redis-config
        items:
        - key: redis-config
          path: redis.conf

์ƒ์„ฑ๋œ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ํ™•์ธํ•œ๋‹ค.

kubectl get pod/redis configmap/example-redis-config

๋‹ค์Œ์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

NAME        READY   STATUS    RESTARTS   AGE
pod/redis   1/1     Running   0          8s

NAME                             DATA   AGE
configmap/example-redis-config   1      14s

example-redis-config ์ปจํ”ผ๊ทธ๋งต์˜ redis-config ํ‚ค๋ฅผ ๊ณต๋ž€์œผ๋กœ ๋‘” ๊ฒƒ์„ ๊ธฐ์–ตํ•˜์ž.

kubectl describe configmap/example-redis-config

redis-config ํ‚ค๊ฐ€ ๋น„์–ด ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

Name:         example-redis-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
redis-config:

kubectl exec ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŒŒ๋“œ์— ์ ‘์†ํ•˜๊ณ , ํ˜„์žฌ ์„ค์ • ํ™•์ธ์„ ์œ„ํ•ด์„œ redis-cli ๋„๊ตฌ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

kubectl exec -it redis -- redis-cli

maxmemory ๋ฅผ ํ™•์ธํ•œ๋‹ค.

127.0.0.1:6379> CONFIG GET maxmemory

๊ธฐ๋ณธ๊ฐ’์ธ 0์„ ๋ณผ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

1) "maxmemory"
2) "0"

์œ ์‚ฌํ•˜๊ฒŒ, maxmemory-policy ๋ฅผ ํ™•์ธํ•œ๋‹ค.

127.0.0.1:6379> CONFIG GET maxmemory-policy

์ด๊ฒƒ๋„ ๊ธฐ๋ณธ๊ฐ’์ธ noeviction ์„ ๋ณด์—ฌ์ค„ ๊ฒƒ์ด๋‹ค.

1) "maxmemory-policy"
2) "noeviction"

์ด์ œ example-redis-config ์ปจํ”ผ๊ทธ๋งต์— ๋ช‡ ๊ฐ€์ง€ ์„ค์ •๊ฐ’์„ ์ถ”๊ฐ€ํ•ด ๋ณธ๋‹ค.

apiVersion: v1
kind: ConfigMap
metadata:
  name: example-redis-config
data:
  redis-config: |
    maxmemory 2mb
    maxmemory-policy allkeys-lru    

๊ฐฑ์‹ ๋œ ์ปจํ”ผ๊ทธ๋งต์„ ์ ์šฉํ•œ๋‹ค.

kubectl apply -f example-redis-config.yaml

์ปจํ”ผ๊ทธ๋งต์ด ๊ฐฑ์‹ ๋œ ๊ฒƒ์„ ํ™•์ธํ•œ๋‹ค.

kubectl describe configmap/example-redis-config

๋ฐฉ๊ธˆ ์ถ”๊ฐ€ํ•œ ์„ค์ •๊ฐ’์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

Name:         example-redis-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
redis-config:
----
maxmemory 2mb
maxmemory-policy allkeys-lru

์„ค์ •์ด ์ ์šฉ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๋ ค๋ฉด, kubectl exec ๋ฅผ ํ†ตํ•œ redis-cli ๋กœ Redis ํŒŒ๋“œ๋ฅผ ๋‹ค์‹œ ํ™•์ธํ•œ๋‹ค.

kubectl exec -it redis -- redis-cli

maxmemory ๋ฅผ ํ™•์ธํ•œ๋‹ค.

127.0.0.1:6379> CONFIG GET maxmemory

๊ธฐ๋ณธ๊ฐ’์ธ 0์„ ๋ณผ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

1) "maxmemory"
2) "0"

์œ ์‚ฌํ•˜๊ฒŒ, maxmemory-policy ๋„ ๊ธฐ๋ณธ ์„ค์ •์ธ noeviction ์„ ๋ณด์—ฌ์ค„ ๊ฒƒ์ด๋‹ค.

127.0.0.1:6379> CONFIG GET maxmemory-policy

์œ„์˜ ๋ช…๋ น์€ ๋‹ค์Œ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

1) "maxmemory-policy"
2) "noeviction"

ํŒŒ๋“œ๋Š” ์—ฐ๊ด€๋œ ์ปจํ”ผ๊ทธ๋งต์—์„œ ๊ฐฑ์‹ ๋œ ๊ฐ’์„ ์ธ์ง€ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์žฌ์‹œ์ž‘์ด ํ•„์š”ํ•˜๋ฏ€๋กœ ํ•ด๋‹น ์„ค์ •๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์€ ์ƒํƒœ์ด๋‹ค. ํŒŒ๋“œ๋ฅผ ์‚ญ์ œํ•˜๊ณ  ๋‹ค์‹œ ์ƒ์„ฑํ•œ๋‹ค.

kubectl delete pod redis
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/pods/config/redis-pod.yaml

์ด์ œ ๋งˆ์ง€๋ง‰์œผ๋กœ ์„ค์ •๊ฐ’์„ ๋‹ค์‹œ ํ™•์ธํ•ด ๋ณธ๋‹ค.

kubectl exec -it redis -- redis-cli

maxmemory ๋ฅผ ํ™•์ธํ•œ๋‹ค.

127.0.0.1:6379> CONFIG GET maxmemory

์ด๊ฒƒ์€ ์ด์ œ ๊ฐฑ์‹ ๋œ ๊ฐ’์ธ 2097152๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

1) "maxmemory"
2) "2097152"

์œ ์‚ฌํ•˜๊ฒŒ, maxmemory-policy ๋„ ๊ฐฑ์‹ ๋˜์–ด ์žˆ๋‹ค.

127.0.0.1:6379> CONFIG GET maxmemory-policy

์ด๊ฒƒ์€ ์›ํ•˜๋Š” ๊ฐ’์ธ allkeys-lru ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

1) "maxmemory-policy"
2) "allkeys-lru"

์ƒ์„ฑ๋œ ์ž์›์„ ์‚ญ์ œํ•˜์—ฌ ์ž‘์—…์„ ์ •๋ฆฌํ•œ๋‹ค.

kubectl delete pod/redis configmap/example-redis-config

๋‹ค์Œ ๋‚ด์šฉ

4 - ๋ณด์•ˆ

4.1 - AppArmor๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ์ปจํ…Œ์ด๋„ˆ์˜ ์ ‘๊ทผ ์ œํ•œ

๊ธฐ๋Šฅ ์ƒํƒœ: Kubernetes v1.4 [beta]

AppArmor๋Š” ํ‘œ์ค€ ๋ฆฌ๋ˆ…์Šค ์‚ฌ์šฉ์ž์™€ ๊ทธ๋ฃน ๊ธฐ๋ฐ˜์˜ ๊ถŒํ•œ์„ ๋ณด์™„ํ•˜์—ฌ, ํ•œ์ •๋œ ๋ฆฌ์†Œ์Šค ์ง‘ํ•ฉ์œผ๋กœ ํ”„๋กœ๊ทธ๋žจ์„ ์ œํ•œํ•˜๋Š” ๋ฆฌ๋ˆ…์Šค ์ปค๋„ ๋ณด์•ˆ ๋ชจ๋“ˆ์ด๋‹ค. AppArmor๋Š” ์ž„์˜์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋Œ€ํ•ด์„œ ์ž ์žฌ์ ์ธ ๊ณต๊ฒฉ ๋ฒ”์œ„๋ฅผ ์ค„์ด๊ณ  ๋”์šฑ ์‹ฌ์ธต์ ์ธ ๋ฐฉ์–ด๋ฅผ ์ œ๊ณตํ•˜๋„๋ก ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ธฐ๋Šฅ์€ ํŠน์ • ํ”„๋กœ๊ทธ๋žจ์ด๋‚˜ ์ปจํ…Œ์ด๋„ˆ์—์„œ ํ•„์š”ํ•œ ๋ฆฌ๋ˆ…์Šค ๊ธฐ๋Šฅ, ๋„คํŠธ์›Œํฌ ์‚ฌ์šฉ, ํŒŒ์ผ ๊ถŒํ•œ ๋“ฑ์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•˜๋Š” ํ”„๋กœํŒŒ์ผ๋กœ ๊ตฌ์„ฑํ•œ๋‹ค. ๊ฐ ํ”„๋กœํŒŒ์ผ์€ ํ—ˆ์šฉํ•˜์ง€ ์•Š์€ ๋ฆฌ์†Œ์Šค ์ ‘๊ทผ์„ ์ฐจ๋‹จํ•˜๋Š” ๊ฐ•์ œ(enforcing) ๋ชจ๋“œ ๋˜๋Š” ์œ„๋ฐ˜๋งŒ์„ ๋ณด๊ณ ํ•˜๋Š” ๋ถˆํ‰(complain) ๋ชจ๋“œ๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

AppArmor๋ฅผ ์ด์šฉํ•˜๋ฉด ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์ž‘์—…์„ ์ œํ•œํ•˜๊ณ  ๋˜๋Š” ์‹œ์Šคํ…œ ๋กœ๊ทธ๋ฅผ ํ†ตํ•ด ๋” ๋‚˜์€ ๊ฐ์‚ฌ๋ฅผ ์ œ๊ณตํ•˜์—ฌ ๋” ์•ˆ์ „ํ•œ ๋ฐฐํฌ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ AppArmor๊ฐ€ ์€ํƒ„ํ™˜(์–ธ์ œ๋‚˜ ํ†ตํ•˜๋Š” ๋ฌด์ ์˜ ๋ฐฉ๋ฒ•)์ด ์•„๋‹ˆ๋ฉฐ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ ์ทจ์•ฝ์ ์„ ๋ณดํ˜ธํ•˜๊ธฐ ์œ„ํ•œ ์—ฌ๋Ÿฌ ์กฐ์น˜๋ฅผ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ ๋ฟ์ž„์„ ์žŠ์œผ๋ฉด ์•ˆ๋œ๋‹ค. ์–‘ํ˜ธํ•˜๊ณ  ์ œํ•œ์ ์ธ ํ”„๋กœํŒŒ์ผ์„ ์ œ๊ณตํ•˜๊ณ , ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ์—ฌ๋Ÿฌ ์ธก๋ฉด์—์„œ ๊ฐ•ํ™”ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

๋ชฉ์ 

  • ๋…ธ๋“œ์— ํ”„๋กœํŒŒ์ผ์„ ์–ด๋–ป๊ฒŒ ์ ์žฌํ•˜๋Š”์ง€ ์˜ˆ์‹œ๋ฅผ ๋ณธ๋‹ค.
  • ํŒŒ๋“œ์— ํ”„๋กœํŒŒ์ผ์„ ์–ด๋–ป๊ฒŒ ๊ฐ•์ œ ์ ์šฉํ•˜๋Š”์ง€ ๋ฐฐ์šด๋‹ค.
  • ํ”„๋กœํŒŒ์ผ์ด ์ ์žฌ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์šด๋‹ค.
  • ํ”„๋กœํŒŒ์ผ์„ ์œ„๋ฐ˜ํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ์‚ดํŽด๋ณธ๋‹ค.
  • ํ”„๋กœํŒŒ์ผ์„ ์ ์žฌํ•  ์ˆ˜ ์—†์„ ๊ฒฝ์šฐ๋ฅผ ์‚ดํŽด๋ณธ๋‹ค.

์‹œ์ž‘ํ•˜๊ธฐ ์ „์—

๋‹ค์Œ์„ ๋ณด์žฅํ•ด์•ผ ํ•œ๋‹ค.

  1. ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋ฒ„์ „์€ ์ตœ์†Œ 1.4 ์ด๋‹ค. -- ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค v1.4๋ถ€ํ„ฐ AppArmor ์ง€์›์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค. v1.4 ์ด์ „ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์ปดํฌ๋„ŒํŠธ๋Š” ์ƒˆ๋กœ์šด AppArmor ์–ด๋…ธํ…Œ์ด์…˜์„ ์ธ์‹ํ•˜์ง€ ๋ชปํ•˜๊ณ  ์ œ๊ณต๋˜๋Š” AppArmor ์„ค์ •์„ ์กฐ์šฉํžˆ ๋ฌด์‹œํ•  ๊ฒƒ์ด๋‹ค. ํŒŒ๋“œ์—์„œ ์˜ˆ์ƒํ•˜๋Š” ๋ณดํ˜ธ๋ฅผ ๋ฐ›๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋ ค๋ฉด ํ•ด๋‹น ๋…ธ๋“œ์˜ Kubelet ๋ฒ„์ „์„ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

    $ kubectl get nodes -o=jsonpath=$'{range .items[*]}{@.metadata.name}: {@.status.nodeInfo.kubeletVersion}\n{end}'
    
    gke-test-default-pool-239f5d02-gyn2: v1.4.0
    gke-test-default-pool-239f5d02-x1kf: v1.4.0
    gke-test-default-pool-239f5d02-xwux: v1.4.0
    
  2. AppArmor ์ปค๋„ ๋ชจ๋“ˆ์„ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ด์•ผ ํ•œ๋‹ค. -- ๋ฆฌ๋ˆ…์Šค ์ปค๋„์— AppArmor ํ”„๋กœํŒŒ์ผ์„ ๊ฐ•์ œ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด AppArmor ์ปค๋„ ๋ชจ๋“ˆ์€ ๋ฐ˜๋“œ์‹œ ์„ค์น˜๋˜์–ด ์žˆ๊ณ  ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ด์•ผ ํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด Ubuntu ๋ฐ SUSE ๊ฐ™์€ ๋ฐฐํฌํŒ์€ ๋ชจ๋“ˆ์„ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์ง€์›ํ•˜๊ณ , ๊ทธ ์™ธ ๋งŽ์€ ๋‹ค๋ฅธ ๋ฐฐํฌํŒ๋“ค์€ ์„ ํƒ์ ์œผ๋กœ ์ง€์›ํ•œ๋‹ค. ๋ชจ๋“ˆ์ด ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ์ง€ ํ™•์ธํ•˜๋ ค๋ฉด /sys/module/apparmor/parameters/enabled ํŒŒ์ผ์„ ํ™•์ธํ•œ๋‹ค.

    $ cat /sys/module/apparmor/parameters/enabled
    Y
    

    Kubelet(>=v1.4)์ด AppArmor ๊ธฐ๋Šฅ ์ง€์›์„ ํฌํ•จํ•˜์ง€๋งŒ, ์ปค๋„ ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์œผ๋ฉด ํŒŒ๋“œ์—์„œ AppArmor ์˜ต์…˜์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ๊ฑฐ๋ถ€๋œ๋‹ค.

  1. ์ปจํ…Œ์ด๋„ˆ ๋Ÿฐํƒ€์ž„์ด AppArmor์„ ์ง€์›ํ•œ๋‹ค. -- ํ˜„์žฌ ๋ชจ๋“  ์ผ๋ฐ˜์ ์ธ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋ฅผ ์ง€์›ํ•˜๋Š” ๋„์ปค(Docker), CRI-O ๋˜๋Š” containerd ์™€ ๊ฐ™์€ ์ปจํ…Œ์ด๋„ˆ ๋Ÿฐํƒ€์ž„๋“ค์€ AppArmor๋ฅผ ์ง€์›ํ•ด์•ผ ํ•œ๋‹ค. ์ด ๋Ÿฐํƒ€์ž„ ์„ค๋ช…์„œ๋ฅผ ์ฐธ์กฐํ•ด์„œ ํด๋Ÿฌ์Šคํ„ฐ๊ฐ€ AppArmor๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ์š”๊ตฌ ์‚ฌํ•ญ์„ ์ถฉ์กฑํ•˜๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค.

  2. ํ”„๋กœํŒŒ์ผ์ด ์ ์žฌ๋˜์–ด ์žˆ๋‹ค. -- AppArmor๋Š” ๊ฐ ์ปจํ…Œ์ด๋„ˆ์™€ ํ•จ๊ป˜ ์‹คํ–‰ํ•ด์•ผ ํ•˜๋Š” AppArmor ํ”„๋กœํŒŒ์ผ์„ ์ง€์ •ํ•˜์—ฌ ํŒŒ๋“œ์— ์ ์šฉํ•œ๋‹ค. ์ปค๋„์— ์ง€์ •ํ•œ ํ”„๋กœํŒŒ์ผ์ด ์ ์žฌ๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด, Kubelet(>= v1.4)์€ ํŒŒ๋“œ๋ฅผ ๊ฑฐ๋ถ€ํ•œ๋‹ค. ํ•ด๋‹น ๋…ธ๋“œ์— ์–ด๋–ค ํ”„๋กœํŒŒ์ผ์ด ์ ์žฌ๋˜์—ˆ๋Š”์ง€๋Š” /sys/kernel/security/apparmor/profiles ํŒŒ์ผ์„ ํ†ตํ•ด ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด,

    $ ssh gke-test-default-pool-239f5d02-gyn2 "sudo cat /sys/kernel/security/apparmor/profiles | sort"
    
    apparmor-test-deny-write (enforce)
    apparmor-test-audit-write (enforce)
    docker-default (enforce)
    k8s-nginx (enforce)
    

    ๋…ธ๋“œ์— ํ”„๋กœํŒŒ์ผ์„ ์ ์žฌํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ๋” ์ž์„ธํ•œ ๋‚ด์šฉ์€ ํ”„๋กœํŒŒ์ผ๊ณผ ํ•จ๊ป˜ ๋…ธ๋“œ ์„ค์ •ํ•˜๊ธฐ.

AppArmor ์ง€์›์ด ํฌํ•จ๋œ Kubelet (>= v1.4)์ด๋ฉด ์–ด๋–ค ์ „์ œ ์กฐ๊ฑด์ด ์ถฉ์กฑ๋˜์ง€ ์•Š์œผ๋ฉด AppArmor์™€ ํ•จ๊ป˜ํ•œ ํŒŒ๋“œ๋ฅผ ๊ฑฐ๋ถ€ํ•œ๋‹ค. ๋…ธ๋“œ ์ƒ์— AppArmor ์ง€์› ์—ฌ๋ถ€๋Š” ๋…ธ๋“œ ์ค€๋น„ ์กฐ๊ฑด ๋ฉ”์‹œ์ง€๋ฅผ ํ™•์ธํ•˜์—ฌ(์ดํ›„ ๋ฆด๋ฆฌ์Šค์—์„œ๋Š” ์‚ญ์ œ๋  ๊ฒƒ ๊ฐ™์ง€๋งŒ) ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl get nodes -o=jsonpath='{range .items[*]}{@.metadata.name}: {.status.conditions[?(@.reason=="KubeletReady")].message}{"\n"}{end}'
gke-test-default-pool-239f5d02-gyn2: kubelet is posting ready status. AppArmor enabled
gke-test-default-pool-239f5d02-x1kf: kubelet is posting ready status. AppArmor enabled
gke-test-default-pool-239f5d02-xwux: kubelet is posting ready status. AppArmor enabled

ํŒŒ๋“œ ๋ณด์•ˆ ๊ฐ•ํ™”ํ•˜๊ธฐ

AppArmor ํ”„๋กœํŒŒ์ผ์€ ์ปจํ…Œ์ด๋„ˆ๋งˆ๋‹ค ์ง€์ •๋œ๋‹ค. ํ•จ๊ป˜ ์‹คํ–‰ํ•  ํŒŒ๋“œ ์ปจํ…Œ์ด๋„ˆ์— AppArmor ํ”„๋กœํŒŒ์ผ์„ ์ง€์ •ํ•˜๋ ค๋ฉด ํŒŒ๋“œ์˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ์— ์–ด๋…ธํ…Œ์ด์…˜์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

container.apparmor.security.beta.kubernetes.io/<container_name>: <profile_ref>

<container_name>์€ ํ”„๋กœํŒŒ์ผ์„ ์ ์šฉํ•˜๋Š” ์ปจํ…Œ์ด๋„ˆ ์ด๋ฆ„์ด๊ณ , <profile_ref>๋Š” ์ ์šฉํ•  ํ”„๋กœํŒŒ์ผ์„ ์ง€์ •ํ•œ๋‹ค. profile_ref๋Š” ๋‹ค์Œ ์ค‘์— ํ•˜๋‚˜์ด๋‹ค.

  • ๋Ÿฐํƒ€์ž„์˜ ๊ธฐ๋ณธ ํ”„๋กœํŒŒ์ผ์„ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•œ runtime/default
  • <profile_name>๋กœ ์ด๋ฆ„ํ•œ ํ˜ธ์ŠคํŠธ์— ์ ์žฌ๋˜๋Š” ํ”„๋กœํŒŒ์ผ์„ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•œ localhost/<profile_name>
  • ์ ์žฌํ•  ํ”„๋กœํŒŒ์ผ์ด ์—†์Œ์„ ๋‚˜ํƒ€๋‚ด๋Š” unconfined

์–ด๋…ธํ…Œ์ด์…˜๊ณผ ํ”„๋กœํŒŒ์ผ ์ด๋ฆ„ ํ˜•์‹์˜ ์ž์„ธํ•œ ๋‚ด์šฉ์€ API ์ฐธ์กฐ๋ฅผ ์‚ดํŽด๋ณธ๋‹ค.

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค AppArmor ์˜ ์ž‘๋™ ์ˆœ์„œ๋Š” ๋ชจ๋“  ์„ ํ–‰ ์กฐ๊ฑด์ด ์ถฉ์กฑ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ์ ์šฉ์„ ์œ„ํ•ด ์„ ํƒํ•œ ํ”„๋กœํŒŒ์ผ์„ ์ปจํ…Œ์ด๋„ˆ ๋Ÿฐํƒ€์ž„์œผ๋กœ ์ „๋‹ฌํ•˜์—ฌ ์ด๋ฃจ์–ด์ง„๋‹ค. ๋งŒ์•ฝ ์„ ํ–‰ ์กฐ๊ฑด์ด ์ถฉ์กฑ๋˜์ง€ ์•Š์œผ๋ฉด ํŒŒ๋“œ๋Š” ๊ฑฐ๋ถ€๋˜๊ณ  ์‹คํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค.

ํ”„๋กœํŒŒ์ผ์ด ์ ์šฉ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด, ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ ์ด๋ฒคํŠธ์— ๋‚˜์—ด๋œ AppArmor ๋ณด์•ˆ ์˜ต์…˜์„ ์ฐพ์•„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

kubectl get events | grep Created
22s        22s         1         hello-apparmor     Pod       spec.containers{hello}   Normal    Created     {kubelet e2e-test-stclair-node-pool-31nt}   Created container with docker id 269a53b202d3; Security:[seccomp=unconfined apparmor=k8s-apparmor-example-deny-write]

์ปจํ…Œ์ด๋„ˆ์˜ ๋ฃจํŠธ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ ํ”„๋กœํŒŒ์ผ๋กœ ์‹คํ–‰๋˜๋Š”์ง€๋Š” proc attr์„ ํ™•์ธํ•˜์—ฌ ์ง์ ‘ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl exec <pod_name> -- cat /proc/1/attr/current
k8s-apparmor-example-deny-write (enforce)

์˜ˆ์‹œ

์ด ์˜ˆ์‹œ๋Š” AppArmor๋ฅผ ์ง€์›ํ•˜๋Š” ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ์ด๋ฏธ ๊ตฌ์„ฑํ•˜์˜€๋‹ค๊ณ  ๊ฐ€์ •ํ•œ๋‹ค.

๋จผ์ € ๋…ธ๋“œ์—์„œ ์‚ฌ์šฉํ•˜๋ ค๋Š” ํ”„๋กœํŒŒ์ผ์„ ์ ์žฌํ•ด์•ผ ํ•œ๋‹ค. ์‚ฌ์šฉํ•  ํ”„๋กœํŒŒ์ผ์€ ํŒŒ์ผ ์“ฐ๊ธฐ๋ฅผ ๊ฑฐ๋ถ€ํ•œ๋‹ค.

#include <tunables/global>

profile k8s-apparmor-example-deny-write flags=(attach_disconnected) {
  #include <abstractions/base>

  file,

  # Deny all file writes.
  deny /** w,
}

ํŒŒ๋“œ๋ฅผ ์–ธ์ œ ์Šค์ผ€์ค„ํ• ์ง€ ์•Œ์ง€ ๋ชปํ•˜๋ฏ€๋กœ ๋ชจ๋“  ๋…ธ๋“œ์— ํ”„๋กœํŒŒ์ผ์„ ์ ์žฌํ•ด์•ผ ํ•œ๋‹ค. ์ด ์˜ˆ์‹œ์—์„œ๋Š” SSH๋ฅผ ์ด์šฉํ•˜์—ฌ ํ”„๋กœํŒŒ์ผ์„ ์„ค์น˜ํ•  ๊ฒƒ์ด๋‚˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์€ ํ”„๋กœํŒŒ์ผ๊ณผ ํ•จ๊ป˜ ๋…ธ๋“œ ์„ค์ •ํ•˜๊ธฐ์—์„œ ๋…ผ์˜ํ•œ๋‹ค.

NODES=(
    # The SSH-accessible domain names of your nodes
    gke-test-default-pool-239f5d02-gyn2.us-central1-a.my-k8s
    gke-test-default-pool-239f5d02-x1kf.us-central1-a.my-k8s
    gke-test-default-pool-239f5d02-xwux.us-central1-a.my-k8s)
for NODE in ${NODES[*]}; do ssh $NODE 'sudo apparmor_parser -q <<EOF
#include <tunables/global>

profile k8s-apparmor-example-deny-write flags=(attach_disconnected) {
  #include <abstractions/base>

  file,

  # Deny all file writes.
  deny /** w,
}
EOF'
done

๋‹ค์Œ์œผ๋กœ ์“ฐ๊ธฐ ๊ธˆ์ง€ ํ”„๋กœํŒŒ์ผ๋œ "Hello AppArmor" ํŒŒ๋“œ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

apiVersion: v1
kind: Pod
metadata:
  name: hello-apparmor
  annotations:
    # ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์— 'k8s-apparmor-example-deny-write' AppArmor ํ”„๋กœํŒŒ์ผ์„ ์ ์šฉํ•จ์„ ์•Œ๋ฆฐ๋‹ค.
    # ์žŠ์ง€ ๋ง ๊ฒƒ์€ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋…ธ๋“œ์—์„œ ์‹คํ–‰ ์ค‘์ธ ๋ฒ„์ „์ด 1.4 ์ด์ƒ์ด ์•„๋‹Œ ๊ฒฝ์šฐ์—๋Š” ์ด ์„ค์ •์€ ๋ฌด์‹œ๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
    container.apparmor.security.beta.kubernetes.io/hello: localhost/k8s-apparmor-example-deny-write
spec:
  containers:
  - name: hello
    image: busybox:1.28
    command: [ "sh", "-c", "echo 'Hello AppArmor!' && sleep 1h" ]
kubectl create -f ./hello-apparmor.yaml

ํŒŒ๋“œ ์ด๋ฒคํŠธ๋ฅผ ์‚ดํŽด๋ณด๋ฉด, 'k8s-apparmor-example-deny-write' AppArmor ํ”„๋กœํŒŒ์ผ๋กœ ์ƒ์„ฑ๋œ ํŒŒ๋“œ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl get events | grep hello-apparmor
14s        14s         1         hello-apparmor   Pod                                Normal    Scheduled   {default-scheduler }                           Successfully assigned hello-apparmor to gke-test-default-pool-239f5d02-gyn2
14s        14s         1         hello-apparmor   Pod       spec.containers{hello}   Normal    Pulling     {kubelet gke-test-default-pool-239f5d02-gyn2}   pulling image "busybox"
13s        13s         1         hello-apparmor   Pod       spec.containers{hello}   Normal    Pulled      {kubelet gke-test-default-pool-239f5d02-gyn2}   Successfully pulled image "busybox"
13s        13s         1         hello-apparmor   Pod       spec.containers{hello}   Normal    Created     {kubelet gke-test-default-pool-239f5d02-gyn2}   Created container with docker id 06b6cd1c0989; Security:[seccomp=unconfined apparmor=k8s-apparmor-example-deny-write]
13s        13s         1         hello-apparmor   Pod       spec.containers{hello}   Normal    Started     {kubelet gke-test-default-pool-239f5d02-gyn2}   Started container with docker id 06b6cd1c0989

proc attr์„ ํ™•์ธํ•˜์—ฌ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์‹ค์ œ๋กœ ํ•ด๋‹น ํ”„๋กœํŒŒ์ผ๋กœ ์‹คํ–‰ ์ค‘์ธ์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl exec hello-apparmor -- cat /proc/1/attr/current
k8s-apparmor-example-deny-write (enforce)

๋งˆ์ง€๋ง‰์œผ๋กœ ํŒŒ์ผ ์“ฐ๊ธฐ๋ฅผ ํ†ตํ•ด ํ”„๋กœํŒŒ์ผ์„ ์œ„๋ฐ˜ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl exec hello-apparmor -- touch /tmp/test
touch: /tmp/test: Permission denied
error: error executing remote command: command terminated with non-zero exit code: Error executing in Docker Container: 1

์ด์ œ ์ •๋ฆฌํ•˜๋ฉด์„œ, ์ ์žฌ๋˜์ง€ ์•Š์€ ํ”„๋กœํŒŒ์ผ์„ ์ง€์ •ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋˜๋Š”์ง€ ์‚ดํŽด๋ณธ๋‹ค.

kubectl create -f /dev/stdin <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: hello-apparmor-2
  annotations:
    container.apparmor.security.beta.kubernetes.io/hello: localhost/k8s-apparmor-example-allow-write
spec:
  containers:
  - name: hello
    image: busybox:1.28
    command: [ "sh", "-c", "echo 'Hello AppArmor!' && sleep 1h" ]
EOF
pod/hello-apparmor-2 created
kubectl describe pod hello-apparmor-2
Name:          hello-apparmor-2
Namespace:     default
Node:          gke-test-default-pool-239f5d02-x1kf/
Start Time:    Tue, 30 Aug 2016 17:58:56 -0700
Labels:        <none>
Annotations:   container.apparmor.security.beta.kubernetes.io/hello=localhost/k8s-apparmor-example-allow-write
Status:        Pending
Reason:        AppArmor
Message:       Pod Cannot enforce AppArmor: profile "k8s-apparmor-example-allow-write" is not loaded
IP:
Controllers:   <none>
Containers:
  hello:
    Container ID:
    Image:     busybox
    Image ID:
    Port:
    Command:
      sh
      -c
      echo 'Hello AppArmor!' && sleep 1h
    State:              Waiting
      Reason:           Blocked
    Ready:              False
    Restart Count:      0
    Environment:        <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-dnz7v (ro)
Conditions:
  Type          Status
  Initialized   True
  Ready         False
  PodScheduled  True
Volumes:
  default-token-dnz7v:
    Type:    Secret (a volume populated by a Secret)
    SecretName:    default-token-dnz7v
    Optional:   false
QoS Class:      BestEffort
Node-Selectors: <none>
Tolerations:    <none>
Events:
  FirstSeen    LastSeen    Count    From                        SubobjectPath    Type        Reason        Message
  ---------    --------    -----    ----                        -------------    --------    ------        -------
  23s          23s         1        {default-scheduler }                         Normal      Scheduled     Successfully assigned hello-apparmor-2 to e2e-test-stclair-minion-group-t1f5
  23s          23s         1        {kubelet e2e-test-stclair-node-pool-t1f5}             Warning        AppArmor    Cannot enforce AppArmor: profile "k8s-apparmor-example-allow-write" is not loaded

ํŒŒ๋“œ ์ƒํƒœ๋Š” Pending์ด๋ฉฐ, ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋Š” Pod Cannot enforce AppArmor: profile "k8s-apparmor-example-allow-write" is not loaded์ด๋‹ค. ์ด๋ฒคํŠธ๋„ ๋™์ผํ•œ ๋ฉ”์‹œ์ง€๋กœ ๊ธฐ๋ก๋˜์—ˆ๋‹ค.

๊ด€๋ฆฌ

ํ”„๋กœํŒŒ์ผ๊ณผ ํ•จ๊ป˜ ๋…ธ๋“œ ์„ค์ •ํ•˜๊ธฐ

ํ˜„์žฌ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋Š” AppArmor ํ”„๋กœํŒŒ์ผ์„ ๋…ธ๋“œ์— ์ ์žฌํ•˜๊ธฐ ์œ„ํ•œ ๋„ค์ดํ‹ฐ๋ธŒ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š”๋‹ค. ํ”„๋กœํŒŒ์ผ์„ ์„ค์ •ํ•˜๋Š” ์—ฌ๋Ÿฌ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • ๊ฐ ๋…ธ๋“œ์—์„œ ํŒŒ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋ฐ๋ชฌ์…‹์„ ํ†ตํ•ด์„œ ์˜ฌ๋ฐ”๋ฅธ ํ”„๋กœํŒŒ์ผ์ด ์ ์žฌ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค. ์˜ˆ์‹œ ๊ตฌํ˜„์€ ์—ฌ๊ธฐ์—์„œ ์ฐพ์•„๋ณผ ์ˆ˜ ์žˆ๋‹ค.
  • ๋…ธ๋“œ ์ดˆ๊ธฐํ™” ์‹œ๊ฐ„์— ๋…ธ๋“œ ์ดˆ๊ธฐํ™” ์Šคํฌ๋ฆฝํŠธ(์˜ˆ๋ฅผ ๋“ค์–ด Salt, Ansible ๋“ฑ)๋‚˜ ์ด๋ฏธ์ง€๋ฅผ ์ด์šฉ
  • ์˜ˆ์‹œ์—์„œ ๋ณด์—ฌ์ค€ ๊ฒƒ์ฒ˜๋Ÿผ, ํ”„๋กœํŒŒ์ผ์„ ๊ฐ ๋…ธ๋“œ์— ๋ณต์‚ฌํ•˜๊ณ  SSH๋ฅผ ํ†ตํ•ด ์ ์žฌํ•œ๋‹ค.

์Šค์ผ€์ค„๋Ÿฌ๋Š” ์–ด๋–ค ํ”„๋กœํŒŒ์ผ์ด ์–ด๋–ค ๋…ธ๋“œ์— ์ ์žฌ๋˜๋Š”์ง€ ๊ณ ๋ คํ•˜์ง€ ์•Š์œผ๋‹ˆ, ํ”„๋กœํŒŒ์ผ ์ „์ฒด ์ง‘ํ•ฉ์ด ๋ชจ๋“  ๋…ธ๋“œ์— ์ ์žฌ๋˜์–ด์•ผ ํ•œ๋‹ค. ๋Œ€์•ˆ์ ์ธ ๋ฐฉ๋ฒ•์€ ๊ฐ ํ”„๋กœํŒŒ์ผ(ํ˜น์€ ํ”„๋กœํŒŒ์ผ์˜ ํด๋ž˜์Šค)์„ ์œ„ํ•œ ๋…ธ๋“œ ๋ ˆ์ด๋ธ”์„ ๋…ธ๋“œ์— ์ถ”๊ฐ€ํ•˜๊ณ , ๋…ธ๋“œ ์…€๋ ‰ํ„ฐ๋ฅผ ์ด์šฉํ•˜์—ฌ ํŒŒ๋“œ๊ฐ€ ํ•„์š”ํ•œ ํ”„๋กœํŒŒ์ผ์ด ์žˆ๋Š” ๋…ธ๋“œ์—์„œ ์‹คํ–‰๋˜๋„๋ก ํ•œ๋‹ค.

AppArmor ๋น„ํ™œ์„ฑํ™”

ํด๋Ÿฌ์Šคํ„ฐ์—์„œ AppArmor๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ ค๋ฉด, ์ปค๋งจ๋“œ๋ผ์ธ ํ”Œ๋ž˜๊ทธ๋กœ ๋น„ํ™œ์„ฑํ™” ํ•  ์ˆ˜ ์žˆ๋‹ค.

--feature-gates=AppArmor=false

๋น„ํ™œ์„ฑํ™”๋˜๋ฉด, AppArmor ํ”„๋กœํŒŒ์ผ์„ ํฌํ•จํ•œ ํŒŒ๋“œ๋Š” "Forbidden" ์˜ค๋ฅ˜๋กœ ๊ฒ€์ฆ ์‹คํŒจํ•œ๋‹ค.

ํ”„๋กœํŒŒ์ผ ์ œ์ž‘

AppArmor ํ”„๋กœํŒŒ์ผ์„ ๋งŒ๋“ค๊ณ  ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ง€์ •ํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ๊นŒ๋‹ค๋กœ์šธ ์ˆ˜ ์žˆ๋‹ค. ๋‹คํ–‰ํžˆ ์ด ์ž‘์—…์— ๋„์›€ ๋˜๋Š” ๋„๊ตฌ๊ฐ€ ์žˆ๋‹ค.

  • aa-genprof์™€ aa-logprof๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ™œ๋™๊ณผ ๋กœ๊ทธ์™€ ์ˆ˜ํ–‰์— ํ•„์š”ํ•œ ํ–‰๋™์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜์—ฌ ์ผ๋ฐ˜ ํ”„๋กœํŒŒ์ผ ๊ทœ์น™์„ ์ƒ์„ฑํ•œ๋‹ค. ์ž์„ธํ•œ ์‚ฌ์šฉ๋ฐฉ๋ฒ•์€ AppArmor ๋ฌธ์„œ์—์„œ ์ œ๊ณตํ•œ๋‹ค.
  • bane์€ ๋‹จ์ˆœํ™”๋œ ํ”„๋กœํŒŒ์ผ ์–ธ์–ด๋ฅผ ์ด์šฉํ•˜๋Š” ๋„์ปค๋ฅผ ์œ„ํ•œ AppArmor ํ”„๋กœํŒŒ์ผ ์ƒ์„ฑ๊ธฐ์ด๋‹ค.

AppArmor ๋ฌธ์ œ๋ฅผ ๋””๋ฒ„๊น…ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๊ฑฐ๋ถ€๋œ ๊ฒƒ์œผ๋กœ ๋ณด์ด๋Š” ์‹œ์Šคํ…œ ๋กœ๊ทธ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. AppArmor ๋กœ๊ทธ๋Š” dmesg์—์„œ ๋ณด์ด๋ฉฐ, ์˜ค๋ฅ˜๋Š” ๋ณดํ†ต ์‹œ์Šคํ…œ ๋กœ๊ทธ๋‚˜ journalctl์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ๋” ๋งŽ์€ ์ •๋ณด๋Š” AppArmor ์‹คํŒจ์—์„œ ์ œ๊ณตํ•œ๋‹ค.

API ์ฐธ์กฐ

ํŒŒ๋“œ ์–ด๋…ธํ…Œ์ด์…˜

์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‹คํ–‰ํ•  ํ”„๋กœํŒŒ์ผ์„ ์ง€์ •ํ•œ๋‹ค.

  • ํ‚ค: container.apparmor.security.beta.kubernetes.io/<container_name> <container_name>๋Š” ํŒŒ๋“œ ๋‚ด์— ์ปจํ…Œ์ด๋„ˆ ์ด๋ฆ„๊ณผ ์ผ์น˜ํ•œ๋‹ค. ๋ถ„๋ฆฌ๋œ ํ”„๋กœํŒŒ์ผ์€ ํŒŒ๋“œ ๋‚ด์— ๊ฐ ์ปจํ…Œ์ด๋„ˆ๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๊ฐ’: ์•„๋ž˜ ๊ธฐ์ˆ ๋œ ํ”„๋กœํŒŒ์ผ ์ฐธ์กฐ

ํ”„๋กœํŒŒ์ผ ์ฐธ์กฐ

  • runtime/default: ๊ธฐ๋ณธ ๋Ÿฐํƒ€์ž„ ํ”„๋กœํŒŒ์ผ์„ ์ฐธ์กฐํ•œ๋‹ค.
    • (๊ธฐ๋ณธ ํŒŒ๋“œ์‹œํ๋ฆฌํ‹ฐํด๋ฆฌ์‹œ ์—†์ด) ํ”„๋กœํŒŒ์ผ์„ ์ง€์ •ํ•˜์ง€ ์•Š๊ณ  AppArmor๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๋™๋“ฑํ•˜๋‹ค.
    • ์‹ค์ œ๋กœ๋Š”, ๋งŽ์€ ์ปจํ…Œ์ด๋„ˆ ๋Ÿฐํƒ€์ž„์€ ๋™์ผํ•œ OCI ๊ธฐ๋ณธ ํ”„๋กœํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜๋ฉฐ, ์ด๋Š” https://github.com/containers/common/blob/main/pkg/apparmor/apparmor_linux_template.go ์— ์ •์˜๋˜์–ด ์žˆ๋‹ค.
  • localhost/<profile_name>: ๋…ธ๋“œ(localhost)์— ์ ์žฌ๋œ ํ”„๋กœํŒŒ์ผ์„ ์ด๋ฆ„์œผ๋กœ ์ฐธ์กฐํ•œ๋‹ค.
  • unconfined: ์ด๊ฒƒ์€ ์ปจํ…Œ์ด๋„ˆ์—์„œ AppArmor๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ๋น„ํ™œ์„ฑ์‹œํ‚จ๋‹ค.

๋‹ค๋ฅธ ์–ด๋–ค ํ”„๋กœํŒŒ์ผ ์ฐธ์กฐ ํ˜•์‹๋„ ์œ ํšจํ•˜์ง€ ์•Š๋‹ค.

๋‹ค์Œ ๋‚ด์šฉ

์ฐธ๊ณ  ์ž๋ฃŒ

4.2 - ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๋ฅผ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์ˆ˜์ค€์— ์ ์šฉํ•˜๊ธฐ

ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์–ด๋“œ๋ฏธ์…˜(PSA, Pod Security Admission)์€ ๋ฒ ํƒ€๋กœ ๋ณ€๊ฒฝ๋˜์–ด v1.23 ์ด์ƒ์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ™œ์„ฑํ™”๋˜์–ด ์žˆ๋‹ค. ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์–ด๋“œ๋ฏธ์…˜์€ ํŒŒ๋“œ๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ(Pod Security Standards)๋ฅผ ์ ์šฉํ•˜๋Š” ์–ด๋“œ๋ฏธ์…˜ ์ปจํŠธ๋กค๋Ÿฌ์ด๋‹ค. ์ด ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š”, ๊ฐ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ณ„๋กœ baseline ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๋ฅผ ๊ฐ•์ œ(enforce)ํ•  ๊ฒƒ์ด๋‹ค.

ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๋ฅผ ํด๋Ÿฌ์Šคํ„ฐ ์ˆ˜์ค€์—์„œ ์—ฌ๋Ÿฌ ๋„ค์ž„์ŠคํŽ˜์ด์Šค์— ํ•œ ๋ฒˆ์— ์ ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์ด์— ๋Œ€ํ•œ ์•ˆ๋‚ด๋Š” ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๋ฅผ ํด๋Ÿฌ์Šคํ„ฐ ์ˆ˜์ค€์— ์ ์šฉํ•˜๊ธฐ๋ฅผ ์ฐธ๊ณ ํ•œ๋‹ค.

์‹œ์ž‘ํ•˜๊ธฐ ์ „์—

์›Œํฌ์Šคํ…Œ์ด์…˜์— ๋‹ค์Œ์„ ์„ค์น˜ํ•œ๋‹ค.

ํด๋Ÿฌ์Šคํ„ฐ ์ƒ์„ฑํ•˜๊ธฐ

  1. ๋‹ค์Œ๊ณผ ๊ฐ™์ด KinD ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

    kind create cluster --name psa-ns-level --image kindest/node:v1.23.0
    

    ๋‹ค์Œ๊ณผ ๋น„์Šทํ•˜๊ฒŒ ์ถœ๋ ฅ๋  ๊ฒƒ์ด๋‹ค.

    Creating cluster "psa-ns-level" ...
     โœ“ Ensuring node image (kindest/node:v1.23.0) ๐Ÿ–ผ 
     โœ“ Preparing nodes ๐Ÿ“ฆ  
     โœ“ Writing configuration ๐Ÿ“œ 
     โœ“ Starting control-plane ๐Ÿ•น๏ธ 
     โœ“ Installing CNI ๐Ÿ”Œ 
     โœ“ Installing StorageClass ๐Ÿ’พ 
    Set kubectl context to "kind-psa-ns-level"
    You can now use your cluster with:
    
    kubectl cluster-info --context kind-psa-ns-level
    
    Not sure what to do next? ๐Ÿ˜…  Check out https://kind.sigs.k8s.io/docs/user/quick-start/
    
  2. kubectl context๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•œ ํด๋Ÿฌ์Šคํ„ฐ๋กœ ์„ค์ •ํ•œ๋‹ค.

    kubectl cluster-info --context kind-psa-ns-level
    

    ๋‹ค์Œ๊ณผ ๋น„์Šทํ•˜๊ฒŒ ์ถœ๋ ฅ๋  ๊ฒƒ์ด๋‹ค.

    Kubernetes control plane is running at https://127.0.0.1:50996
    CoreDNS is running at https://127.0.0.1:50996/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
    
    To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
    

๋„ค์ž„์ŠคํŽ˜์ด์Šค ์ƒ์„ฑํ•˜๊ธฐ

example์ด๋ผ๋Š” ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

kubectl create ns example

๋‹ค์Œ๊ณผ ๋น„์Šทํ•˜๊ฒŒ ์ถœ๋ ฅ๋  ๊ฒƒ์ด๋‹ค.

namespace/example created

ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ ์ ์šฉํ•˜๊ธฐ

  1. ๋‚ด์žฅ ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์–ด๋“œ๋ฏธ์…˜์ด ์ง€์›ํ•˜๋Š” ๋ ˆ์ด๋ธ”์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด ๋„ค์ž„์ŠคํŽ˜์ด์Šค์— ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๋ฅผ ํ™œ์„ฑํ™”ํ•œ๋‹ค. ์ด ๋‹จ๊ณ„์—์„œ๋Š” latest ๋ฒ„์ „(๊ธฐ๋ณธ๊ฐ’)์— ๋”ฐ๋ผ baseline(๊ธฐ์ค€) ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ์— ๋Œ€ํ•ด ๊ฒฝ๊ณ ๋ฅผ ์„ค์ •ํ•œ๋‹ค.

    kubectl label --overwrite ns example \
       pod-security.kubernetes.io/warn=baseline \
       pod-security.kubernetes.io/warn-version=latest
    
  2. ์–ด๋– ํ•œ ๋„ค์ž„์ŠคํŽ˜์ด์Šค์—๋„ ๋ณต์ˆ˜ ๊ฐœ์˜ ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๋ฅผ ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋Š” ๋ ˆ์ด๋ธ”์„ ์ด์šฉํ•˜์—ฌ ๊ฐ€๋Šฅํ•˜๋‹ค. ๋‹ค์Œ ๋ช…๋ น์–ด๋Š” ์ตœ์‹  ๋ฒ„์ „(๊ธฐ๋ณธ๊ฐ’)์— ๋”ฐ๋ผ, baseline(๊ธฐ์ค€) ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๋Š” enforce(๊ฐ•์ œ)ํ•˜์ง€๋งŒ restricted(์ œํ•œ๋œ) ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ์— ๋Œ€ํ•ด์„œ๋Š” warn(๊ฒฝ๊ณ ) ๋ฐ audit(๊ฐ์‚ฌ)ํ•˜๋„๋ก ์„ค์ •ํ•œ๋‹ค.

    kubectl label --overwrite ns example \
      pod-security.kubernetes.io/enforce=baseline \
      pod-security.kubernetes.io/enforce-version=latest \
      pod-security.kubernetes.io/warn=restricted \
      pod-security.kubernetes.io/warn-version=latest \
      pod-security.kubernetes.io/audit=restricted \
      pod-security.kubernetes.io/audit-version=latest
    

ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ ๊ฒ€์ฆํ•˜๊ธฐ

  1. example ๋„ค์ž„์ŠคํŽ˜์ด์Šค์— ์ตœ์†Œํ•œ์˜ ํŒŒ๋“œ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

    cat <<EOF > /tmp/pss/nginx-pod.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx
    spec:
      containers:
        - image: nginx
          name: nginx
          ports:
            - containerPort: 80
    EOF
    
  2. ํด๋Ÿฌ์Šคํ„ฐ์˜ example ๋„ค์ž„์ŠคํŽ˜์ด์Šค์— ํ•ด๋‹น ํŒŒ๋“œ ์ŠคํŽ™์„ ์ ์šฉํ•œ๋‹ค.

    kubectl apply -n example -f /tmp/pss/nginx-pod.yaml
    

    ๋‹ค์Œ๊ณผ ๋น„์Šทํ•˜๊ฒŒ ์ถœ๋ ฅ๋  ๊ฒƒ์ด๋‹ค.

    Warning: would violate PodSecurity "restricted:latest": allowPrivilegeEscalation != false (container "nginx" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "nginx" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "nginx" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "nginx" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")
    pod/nginx created
    
  3. ํด๋Ÿฌ์Šคํ„ฐ์˜ default ๋„ค์ž„์ŠคํŽ˜์ด์Šค์— ํ•ด๋‹น ํŒŒ๋“œ ์ŠคํŽ™์„ ์ ์šฉํ•œ๋‹ค.

    kubectl apply -n default -f /tmp/pss/nginx-pod.yaml
    

    ๋‹ค์Œ๊ณผ ๋น„์Šทํ•˜๊ฒŒ ์ถœ๋ ฅ๋  ๊ฒƒ์ด๋‹ค.

    pod/nginx created
    

ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๋Š” example ๋„ค์ž„์ŠคํŽ˜์ด์Šค์—๋งŒ ์ ์šฉ๋˜์—ˆ๋‹ค. ๋™์ผํ•œ ํŒŒ๋“œ๋ฅผ default ๋„ค์ž„์ŠคํŽ˜์ด์Šค์— ์ƒ์„ฑํ•˜๋”๋ผ๋„ ๊ฒฝ๊ณ ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.

์ •๋ฆฌํ•˜๊ธฐ

kind delete cluster --name psa-ns-level ๋ช…๋ น์„ ์‹คํ–‰ํ•˜์—ฌ ์ƒ์„ฑํ–ˆ๋˜ ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ์‚ญ์ œํ•œ๋‹ค.

๋‹ค์Œ ๋‚ด์šฉ

4.3 - ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๋ฅผ ํด๋Ÿฌ์Šคํ„ฐ ์ˆ˜์ค€์— ์ ์šฉํ•˜๊ธฐ

ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์–ด๋“œ๋ฏธ์…˜(PSA, Pod Security Admission)์€ ๋ฒ ํƒ€๋กœ ๋ณ€๊ฒฝ๋˜์–ด v1.23 ์ด์ƒ์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ™œ์„ฑํ™”๋˜์–ด ์žˆ๋‹ค. ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์–ด๋“œ๋ฏธ์…˜์€ ํŒŒ๋“œ๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ(Pod Security Standards)๋ฅผ ์ ์šฉํ•˜๋Š” ์–ด๋“œ๋ฏธ์…˜ ์ปจํŠธ๋กค๋Ÿฌ์ด๋‹ค. ์ด ํŠœํ† ๋ฆฌ์–ผ์€ baseline ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๋ฅผ ํด๋Ÿฌ์Šคํ„ฐ ์ˆ˜์ค€(level)์— ์ ์šฉํ•˜์—ฌ ํ‘œ์ค€ ๊ตฌ์„ฑ์„ ํด๋Ÿฌ์Šคํ„ฐ์˜ ๋ชจ๋“  ๋„ค์ž„์ŠคํŽ˜์ด์Šค์— ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ ์ค€๋‹ค.

ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๋ฅผ ํŠน์ • ๋„ค์ž„์ŠคํŽ˜์ด์Šค์— ์ ์šฉํ•˜๋ ค๋ฉด, ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๋ฅผ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์ˆ˜์ค€์— ์ ์šฉํ•˜๊ธฐ๋ฅผ ์ฐธ๊ณ ํ•œ๋‹ค.

๋งŒ์•ฝ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋ฒ„์ „์ด v1.34์ด ์•„๋‹ˆ๋ผ๋ฉด, ํ•ด๋‹น ๋ฒ„์ „์˜ ๋ฌธ์„œ๋ฅผ ํ™•์ธํ•˜์ž.

์‹œ์ž‘ํ•˜๊ธฐ ์ „์—

์›Œํฌ์Šคํ…Œ์ด์…˜์— ๋‹ค์Œ์„ ์„ค์น˜ํ•œ๋‹ค.

์ ์šฉํ•  ์•Œ๋งž์€ ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ ์„ ํƒํ•˜๊ธฐ

ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์–ด๋“œ๋ฏธ์…˜์„ ์ด์šฉํ•˜์—ฌ enforce, audit, ๋˜๋Š” warn ๋ชจ๋“œ ์ค‘ ํ•˜๋‚˜๋กœ ๋‚ด์žฅ ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ˜„์žฌ ๊ตฌ์„ฑ์— ๊ฐ€์žฅ ์ ํ•ฉํ•œ ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๋ฅผ ๊ณ ๋ฅด๋Š” ๋ฐ ๋„์›€์ด ๋˜๋Š” ์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•˜๋ ค๋ฉด, ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

  1. ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๊ฐ€ ์ ์šฉ๋˜์ง€ ์•Š์€ ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

    kind create cluster --name psa-wo-cluster-pss --image kindest/node:v1.24.0
    

    ๋‹ค์Œ๊ณผ ๋น„์Šทํ•˜๊ฒŒ ์ถœ๋ ฅ๋  ๊ฒƒ์ด๋‹ค.

    Creating cluster "psa-wo-cluster-pss" ...
    โœ“ Ensuring node image (kindest/node:v1.24.0) ๐Ÿ–ผ
    โœ“ Preparing nodes ๐Ÿ“ฆ  
    โœ“ Writing configuration ๐Ÿ“œ
    โœ“ Starting control-plane ๐Ÿ•น๏ธ
    โœ“ Installing CNI ๐Ÿ”Œ
    โœ“ Installing StorageClass ๐Ÿ’พ
    Set kubectl context to "kind-psa-wo-cluster-pss"
    You can now use your cluster with:
    
    kubectl cluster-info --context kind-psa-wo-cluster-pss
    
    Thanks for using kind! ๐Ÿ˜Š
    
  2. kubectl context๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•œ ํด๋Ÿฌ์Šคํ„ฐ๋กœ ์„ค์ •ํ•œ๋‹ค.

    kubectl cluster-info --context kind-psa-wo-cluster-pss
    

    ๋‹ค์Œ๊ณผ ๋น„์Šทํ•˜๊ฒŒ ์ถœ๋ ฅ๋  ๊ฒƒ์ด๋‹ค.

     Kubernetes control plane is running at https://127.0.0.1:61350
    
    CoreDNS is running at https://127.0.0.1:61350/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
    
    To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
    
  3. ํด๋Ÿฌ์Šคํ„ฐ์˜ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ๋ชฉ๋ก์„ ์กฐํšŒํ•œ๋‹ค.

    kubectl get ns
    

    ๋‹ค์Œ๊ณผ ๋น„์Šทํ•˜๊ฒŒ ์ถœ๋ ฅ๋  ๊ฒƒ์ด๋‹ค.

    NAME                 STATUS   AGE
    default              Active   9m30s
    kube-node-lease      Active   9m32s
    kube-public          Active   9m32s
    kube-system          Active   9m32s
    local-path-storage   Active   9m26s
    
  4. --dry-run=server๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค๋ฅธ ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๊ฐ€ ์ ์šฉ๋˜์—ˆ์„ ๋•Œ ์–ด๋–ค ๊ฒƒ์ด ๋ณ€๊ฒฝ๋˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

    1. Privileged
      kubectl label --dry-run=server --overwrite ns --all \
      pod-security.kubernetes.io/enforce=privileged
      

    ๋‹ค์Œ๊ณผ ๋น„์Šทํ•˜๊ฒŒ ์ถœ๋ ฅ๋  ๊ฒƒ์ด๋‹ค.

    namespace/default labeled
    namespace/kube-node-lease labeled
    namespace/kube-public labeled
    namespace/kube-system labeled
    namespace/local-path-storage labeled
    
    1. Baseline
      kubectl label --dry-run=server --overwrite ns --all \
      pod-security.kubernetes.io/enforce=baseline
      

    ๋‹ค์Œ๊ณผ ๋น„์Šทํ•˜๊ฒŒ ์ถœ๋ ฅ๋  ๊ฒƒ์ด๋‹ค.

    namespace/default labeled
    namespace/kube-node-lease labeled
    namespace/kube-public labeled
    Warning: existing pods in namespace "kube-system" violate the new PodSecurity enforce level "baseline:latest"
    Warning: etcd-psa-wo-cluster-pss-control-plane (and 3 other pods): host namespaces, hostPath volumes
    Warning: kindnet-vzj42: non-default capabilities, host namespaces, hostPath volumes
    Warning: kube-proxy-m6hwf: host namespaces, hostPath volumes, privileged
    namespace/kube-system labeled
    namespace/local-path-storage labeled
    
    1. Restricted
     kubectl label --dry-run=server --overwrite ns --all \
     pod-security.kubernetes.io/enforce=restricted
    

    ๋‹ค์Œ๊ณผ ๋น„์Šทํ•˜๊ฒŒ ์ถœ๋ ฅ๋  ๊ฒƒ์ด๋‹ค.

    namespace/default labeled
    namespace/kube-node-lease labeled
    namespace/kube-public labeled
    Warning: existing pods in namespace "kube-system" violate the new PodSecurity enforce level "restricted:latest"
    Warning: coredns-7bb9c7b568-hsptc (and 1 other pod): unrestricted capabilities, runAsNonRoot != true, seccompProfile
    Warning: etcd-psa-wo-cluster-pss-control-plane (and 3 other pods): host namespaces, hostPath volumes, allowPrivilegeEscalation != false, unrestricted capabilities, restricted volume types, runAsNonRoot != true
    Warning: kindnet-vzj42: non-default capabilities, host namespaces, hostPath volumes, allowPrivilegeEscalation != false, unrestricted capabilities, restricted volume types, runAsNonRoot != true, seccompProfile
    Warning: kube-proxy-m6hwf: host namespaces, hostPath volumes, privileged, allowPrivilegeEscalation != false, unrestricted capabilities, restricted volume types, runAsNonRoot != true, seccompProfile
    namespace/kube-system labeled
    Warning: existing pods in namespace "local-path-storage" violate the new PodSecurity enforce level "restricted:latest"
    Warning: local-path-provisioner-d6d9f7ffc-lw9lh: allowPrivilegeEscalation != false, unrestricted capabilities, runAsNonRoot != true, seccompProfile
    namespace/local-path-storage labeled
    

์œ„์˜ ์ถœ๋ ฅ์—์„œ, privileged ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๋ฅผ ์ ์šฉํ•˜๋ฉด ๋ชจ๋“  ๋„ค์ž„์ŠคํŽ˜์ด์Šค์—์„œ ๊ฒฝ๊ณ ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ baseline ๋ฐ restricted ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ์— ๋Œ€ํ•ด์„œ๋Š” kube-system ๋„ค์ž„์ŠคํŽ˜์ด์Šค์—์„œ ๊ฒฝ๊ณ ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

๋ชจ๋“œ, ๋ฒ„์ „, ๋ฐ ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ ์„ค์ •

์ด ์„น์…˜์—์„œ๋Š”, ๋‹ค์Œ์˜ ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๋ฅผ latest ๋ฒ„์ „์— ์ ์šฉํ•œ๋‹ค.

  • baseline ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๋Š” enforce ๋ชจ๋“œ๋กœ ์ ์šฉ
  • restricted ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๋Š” warn ๋ฐ audit ๋ชจ๋“œ๋กœ ์ ์šฉ

baseline ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๋Š” ์˜ˆ์™ธ ๋ชฉ๋ก์„ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์œ ์ง€ํ•˜๊ณ  ์•Œ๋ ค์ง„ ๊ถŒํ•œ ์ƒ์Šน(privilege escalations)์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋Š” ํŽธ๋ฆฌํ•œ ์ ˆ์ถฉ์•ˆ์„ ์ œ๊ณตํ•œ๋‹ค.

์ถ”๊ฐ€์ ์œผ๋กœ, kube-system ๋‚ด์˜ ํŒŒ๋“œ๊ฐ€ ์‹คํŒจํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด, ํ•ด๋‹น ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋Š” ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๊ฐ€ ์ ์šฉ๋˜์ง€ ์•Š๋„๋ก ์ œ์™ธํ•  ๊ฒƒ์ด๋‹ค.

์‚ฌ์šฉ ์ค‘์ธ ํ™˜๊ฒฝ์— ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์–ด๋“œ๋ฏธ์…˜์„ ์ ์šฉํ•  ๋•Œ์—๋Š” ๋‹ค์Œ์˜ ์‚ฌํ•ญ์„ ๊ณ ๋ คํ•œ๋‹ค.

  1. ํด๋Ÿฌ์Šคํ„ฐ์— ์ ์šฉ๋œ ์œ„ํ—˜ ์ƒํƒœ์— ๋”ฐ๋ผ, restricted์™€ ๊ฐ™์€ ๋” ์—„๊ฒฉํ•œ ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๊ฐ€ ๋” ์ข‹์„ ์ˆ˜๋„ ์žˆ๋‹ค.

  2. kube-system ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ์ ์šฉ ๋Œ€์ƒ์—์„œ ์ œ์™ธํ•˜๋ฉด ์ด ๋„ค์ž„์ŠคํŽ˜์ด์Šค์˜ ํŒŒ๋“œ๊ฐ€ privileged๋กœ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋‹ค. ์‹ค์ œ ์‚ฌ์šฉ ํ™˜๊ฒฝ์—์„œ๋Š”, ์ตœ์†Œ ๊ถŒํ•œ ์›์น™์„ ์ค€์ˆ˜ํ•˜๋„๋ก, ์ ‘๊ทผ์„ kube-system ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋กœ ์ œํ•œํ•˜๋Š” ์—„๊ฒฉํ•œ RBAC ์ •์ฑ…์„ ์ ์šฉํ•  ๊ฒƒ์„ ๊ฐ•๋ ฅํžˆ ๊ถŒ์žฅํ•œ๋‹ค.

  3. ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์–ด๋“œ๋ฏธ์…˜ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์ด๋Ÿฌํ•œ ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ตฌ์„ฑ ํŒŒ์ผ์„ ์ƒ์„ฑํ•œ๋‹ค.

    mkdir -p /tmp/pss
    cat <<EOF > /tmp/pss/cluster-level-pss.yaml 
    apiVersion: apiserver.config.k8s.io/v1
    kind: AdmissionConfiguration
    plugins:
    - name: PodSecurity
      configuration:
        apiVersion: pod-security.admission.config.k8s.io/v1
        kind: PodSecurityConfiguration
        defaults:
          enforce: "baseline"
          enforce-version: "latest"
          audit: "restricted"
          audit-version: "latest"
          warn: "restricted"
          warn-version: "latest"
        exemptions:
          usernames: []
          runtimeClasses: []
          namespaces: [kube-system]
    EOF
    
  4. API ์„œ๋ฒ„๊ฐ€ ํด๋Ÿฌ์Šคํ„ฐ ์ƒ์„ฑ ๊ณผ์ •์—์„œ ์ด ํŒŒ์ผ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌ์„ฑํ•œ๋‹ค.

    cat <<EOF > /tmp/pss/cluster-config.yaml 
    kind: Cluster
    apiVersion: kind.x-k8s.io/v1alpha4
    nodes:
    - role: control-plane
      kubeadmConfigPatches:
      - |
        kind: ClusterConfiguration
        apiServer:
            extraArgs:
              admission-control-config-file: /etc/config/cluster-level-pss.yaml
            extraVolumes:
              - name: accf
                hostPath: /etc/config
                mountPath: /etc/config
                readOnly: false
                pathType: "DirectoryOrCreate"
      extraMounts:
      - hostPath: /tmp/pss
        containerPath: /etc/config
        # optional: if set, the mount is read-only.
        # default false
        readOnly: false
        # optional: if set, the mount needs SELinux relabeling.
        # default false
        selinuxRelabel: false
        # optional: set propagation mode (None, HostToContainer or Bidirectional)
        # see https://kubernetes.io/ko/docs/concepts/storage/volumes/#๋งˆ์šดํŠธ-์ „ํŒŒ-propagation
        # default None
        propagation: None
    EOF
    
  5. ์ด๋Ÿฌํ•œ ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์Šคํƒ ๋‹ค๋“œ๋ฅผ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด ํŒŒ๋“œ ์‹œํ๋ฆฌํ‹ฐ ์–ด๋“œ๋ฏธ์…˜์„ ์‚ฌ์šฉํ•˜๋Š” ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

     kind create cluster --name psa-with-cluster-pss --image kindest/node:v1.24.0 --config /tmp/pss/cluster-config.yaml
    

    ๋‹ค์Œ๊ณผ ๋น„์Šทํ•˜๊ฒŒ ์ถœ๋ ฅ๋  ๊ฒƒ์ด๋‹ค.

     Creating cluster "psa-with-cluster-pss" ...
      โœ“ Ensuring node image (kindest/node:v1.24.0) ๐Ÿ–ผ 
      โœ“ Preparing nodes ๐Ÿ“ฆ  
      โœ“ Writing configuration ๐Ÿ“œ 
      โœ“ Starting control-plane ๐Ÿ•น๏ธ 
      โœ“ Installing CNI ๐Ÿ”Œ 
      โœ“ Installing StorageClass ๐Ÿ’พ 
     Set kubectl context to "kind-psa-with-cluster-pss"
     You can now use your cluster with:
    
     kubectl cluster-info --context kind-psa-with-cluster-pss
    
     Have a question, bug, or feature request? Let us know! https://kind.sigs.k8s.io/#community ๐Ÿ™‚
    
  6. kubectl context๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•œ ํด๋Ÿฌ์Šคํ„ฐ๋กœ ์„ค์ •ํ•œ๋‹ค.

     kubectl cluster-info --context kind-psa-with-cluster-pss
    

    ๋‹ค์Œ๊ณผ ๋น„์Šทํ•˜๊ฒŒ ์ถœ๋ ฅ๋  ๊ฒƒ์ด๋‹ค.

     Kubernetes control plane is running at https://127.0.0.1:63855
     CoreDNS is running at https://127.0.0.1:63855/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
    
     To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
    
  7. ๊ธฐ๋ณธ ๋„ค์ž„์ŠคํŽ˜์ด์Šค์— ์ƒ์„ฑํ•  ์ตœ์†Œํ•œ์˜ ๊ตฌ์„ฑ์— ๋Œ€ํ•œ ํŒŒ๋“œ ๋ช…์„ธ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ƒ์„ฑํ•œ๋‹ค.

    cat <<EOF > /tmp/pss/nginx-pod.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx
    spec:
      containers:
        - image: nginx
          name: nginx
          ports:
            - containerPort: 80
    EOF
    
  8. ํด๋Ÿฌ์Šคํ„ฐ์— ํ•ด๋‹น ํŒŒ๋“œ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

     kubectl apply -f /tmp/pss/nginx-pod.yaml
    

    ๋‹ค์Œ๊ณผ ๋น„์Šทํ•˜๊ฒŒ ์ถœ๋ ฅ๋  ๊ฒƒ์ด๋‹ค.

     Warning: would violate PodSecurity "restricted:latest": allowPrivilegeEscalation != false (container "nginx" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "nginx" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "nginx" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "nginx" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")
     pod/nginx created
    

์ •๋ฆฌํ•˜๊ธฐ

kind delete cluster --name psa-with-cluster-pss ๋ฐ kind delete cluster --name psa-wo-cluster-pss ๋ช…๋ น์„ ์‹คํ–‰ํ•˜์—ฌ ์ƒ์„ฑํ–ˆ๋˜ ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ์‚ญ์ œํ•œ๋‹ค.

๋‹ค์Œ ๋‚ด์šฉ

5 - ์ƒํƒœ ์œ ์ง€๋ฅผ ํ•˜์ง€ ์•Š๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜

5.1 - ์™ธ๋ถ€ IP ์ฃผ์†Œ๋ฅผ ๋…ธ์ถœํ•˜์—ฌ ํด๋Ÿฌ์Šคํ„ฐ์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ ‘์†ํ•˜๊ธฐ

์ด ํŽ˜์ด์ง€์—์„œ๋Š” ์™ธ๋ถ€ IP ์ฃผ์†Œ๋ฅผ ๋…ธ์ถœํ•˜๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์„œ๋น„์Šค ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์„ค๋ช…ํ•œ๋‹ค.

์‹œ์ž‘ํ•˜๊ธฐ ์ „์—

  • kubectl์„ ์„ค์น˜ํ•œ๋‹ค.
  • Google Kubernetes Engine ๋˜๋Š” Amazon Web Services์™€ ๊ฐ™์€ ํด๋ผ์šฐ๋“œ ๊ณต๊ธ‰์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ์ด ํŠœํ† ๋ฆฌ์–ผ์€ ์™ธ๋ถ€ ๋กœ๋“œ ๋ฐธ๋Ÿฐ์„œ๋ฅผ ์ƒ์„ฑํ•˜๋Š”๋ฐ, ํด๋ผ์šฐ๋“œ ๊ณต๊ธ‰์ž๊ฐ€ ํ•„์š”ํ•˜๋‹ค.
  • kubectl์ด ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค API ์„œ๋ฒ„์™€ ํ†ต์‹ ํ•˜๋„๋ก ์„ค์ •ํ•œ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ํด๋ผ์šฐ๋“œ ๊ณต๊ธ‰์ž์˜ ์„ค๋ช…์„ ์ฐธ๊ณ ํ•œ๋‹ค.

๋ชฉ์ 

  • Hello World ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋‹ค์„ฏ ๊ฐœ์˜ ์ธ์Šคํ„ด์Šค๋กœ ์‹คํ–‰ํ•œ๋‹ค.
  • ์™ธ๋ถ€ IP ์ฃผ์†Œ๋ฅผ ๋…ธ์ถœํ•˜๋Š” ์„œ๋น„์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
  • ์‹คํ–‰ ์ค‘์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด ์„œ๋น„์Šค ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

๋‹ค์„ฏ ๊ฐœ์˜ ํŒŒ๋“œ์—์„œ ์‹คํ–‰๋˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋Œ€ํ•œ ์„œ๋น„์Šค ๋งŒ๋“ค๊ธฐ

  1. ํด๋Ÿฌ์Šคํ„ฐ์—์„œ Hello World ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•œ๋‹ค.

    apiVersion: apps/v1
       kind: Deployment
       metadata:
         labels:
           app.kubernetes.io/name: load-balancer-example
         name: hello-world
       spec:
         replicas: 5
         selector:
           matchLabels:
             app.kubernetes.io/name: load-balancer-example
         template:
           metadata:
             labels:
               app.kubernetes.io/name: load-balancer-example
           spec:
             containers:
             - image: gcr.io/google-samples/node-hello:1.0
               name: hello-world
               ports:
               - containerPort: 8080
       
    kubectl apply -f https://k8s.io/examples/service/load-balancer-example.yaml
    

    ์œ„์˜ ๋ช…๋ น์–ด๋Š” ๋””ํ”Œ๋กœ์ด๋จผํŠธ(Deployment) ์˜ค๋ธŒ์ ํŠธ์™€ ๊ด€๋ จ๋œ ๋ ˆํ”Œ๋ฆฌ์นด์…‹(ReplicaSet) ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ๋ ˆํ”Œ๋ฆฌ์นด์…‹์€ ๋‹ค์„ฏ ๊ฐœ์˜ ํŒŒ๋“œ๊ฐ€ ์žˆ์œผ๋ฉฐ, ๊ฐ ํŒŒ๋“œ๋Š” Hello World ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•œ๋‹ค.

  2. ๋””ํ”Œ๋กœ์ด๋จผํŠธ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ํ™•์ธํ•œ๋‹ค.

    kubectl get deployments hello-world
    kubectl describe deployments hello-world
    
  3. ๋ ˆํ”Œ๋ฆฌ์นด์…‹ ์˜ค๋ธŒ์ ํŠธ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ํ™•์ธํ•œ๋‹ค.

    kubectl get replicasets
    kubectl describe replicasets
    
  4. ๋””ํ”Œ๋กœ์ด๋จผํŠธ๋ฅผ ์™ธ๋ถ€๋กœ ๋…ธ์ถœ์‹œํ‚ค๋Š” ์„œ๋น„์Šค ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

    kubectl expose deployment hello-world --type=LoadBalancer --name=my-service
    
  5. ์„œ๋น„์Šค์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ํ™•์ธํ•œ๋‹ค.

    kubectl get services my-service
    

    ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ๋‚˜ํƒ€๋‚œ๋‹ค.

    NAME         TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)    AGE
    my-service   LoadBalancer   10.3.245.137   104.198.205.71   8080/TCP   54s
    
  6. ์„œ๋น„์Šค์— ๋Œ€ํ•œ ์ž์„ธํ•œ ์ •๋ณด๋ฅผ ํ™•์ธํ•œ๋‹ค.

    kubectl describe services my-service
    

    ์ถœ๋ ฅ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•˜๋‹ค.

    Name:           my-service
    Namespace:      default
    Labels:         app.kubernetes.io/name=load-balancer-example
    Annotations:    <none>
    Selector:       app.kubernetes.io/name=load-balancer-example
    Type:           LoadBalancer
    IP:             10.3.245.137
    LoadBalancer Ingress:   104.198.205.71
    Port:           <unset> 8080/TCP
    NodePort:       <unset> 32377/TCP
    Endpoints:      10.0.0.6:8080,10.0.1.6:8080,10.0.1.7:8080 + 2 more...
    Session Affinity:   None
    Events:         <none>
    

    ์„œ๋น„์Šค์— ์˜ํ•ด ๋…ธ์ถœ๋œ ์™ธ๋ถ€ IP ์ฃผ์†Œ (LoadBalancer Ingress)๋ฅผ ๊ธฐ์–ตํ•ด๋‘์ž. ์˜ˆ์‹œ์—์„œ ์™ธ๋ถ€ IP ์ฃผ์†Œ๋Š” 104.198.205.71์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  Port์™€NodePort์˜ ๊ฐ’์„ ๊ธฐ์–ตํ•ด๋‘์ž. ์˜ˆ์‹œ์—์„œ Port๋Š” 8080์ด๊ณ  NodePort๋Š” 32377์ด๋‹ค.

  7. ์œ„์˜ ์ถœ๋ ฅ ๊ฒฐ๊ณผ๋ฅผ ํ†ตํ•ด, ์„œ๋น„์Šค์— ์—ฌ๋Ÿฌ ์—”๋“œํฌ์ธํŠธ๊ฐ€ ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. 10.0.0.6:8080,10.0.1.6:8080,10.0.1.7:8080 + 2. ์ด ์ฃผ์†Œ๋Š” Hello World ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ ์ค‘์ธ ํŒŒ๋“œ์˜ ๋‚ด๋ถ€ ์ฃผ์†Œ๋‹ค. ํ•ด๋‹น ์ฃผ์†Œ๊ฐ€ ํŒŒ๋“œ ์ฃผ์†Œ์ธ์ง€ ํ™•์ธํ•˜๋ ค๋ฉด, ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ๋œ๋‹ค.

    kubectl get pods --output=wide
    

    ์ถœ๋ ฅ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•˜๋‹ค.

    NAME                         ...  IP         NODE
    hello-world-2895499144-1jaz9 ...  10.0.1.6   gke-cluster-1-default-pool-e0b8d269-1afc
    hello-world-2895499144-2e5uh ...  10.0.1.8   gke-cluster-1-default-pool-e0b8d269-1afc
    hello-world-2895499144-9m4h1 ...  10.0.0.6   gke-cluster-1-default-pool-e0b8d269-5v7a
    hello-world-2895499144-o4z13 ...  10.0.1.7   gke-cluster-1-default-pool-e0b8d269-1afc
    hello-world-2895499144-segjf ...  10.0.2.5   gke-cluster-1-default-pool-e0b8d269-cpuc
    
  8. Hello World ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด ์™ธ๋ถ€ IP ์ฃผ์†Œ (LoadBalancer Ingress)๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

    curl http://<external-ip>:<port>
    

    <external-ip>๋Š” ์„œ๋น„์Šค์˜ ์™ธ๋ถ€ IP ์ฃผ์†Œ (LoadBalancer Ingress)๋ฅผ ์˜๋ฏธํ•˜๋ฉฐ, <port>๋Š” ์„œ๋น„์Šค ์ •๋ณด์—์„œ Port ๊ฐ’์„ ์˜๋ฏธํ•œ๋‹ค. ๋งŒ์•ฝ minikube๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋ฉด, minikube service my-service ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด, ์ž๋™์œผ๋กœ ๋ธŒ๋ผ์šฐ์ € ๋‚ด์—์„œ Hello World ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.

    ์„ฑ๊ณต์ ์ธ ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ hello ๋ฉ”์„ธ์ง€๊ฐ€ ๋‚˜ํƒ€๋‚œ๋‹ค.

    Hello Kubernetes!
    

์ •๋ฆฌํ•˜๊ธฐ

์„œ๋น„์Šค๋ฅผ ์‚ญ์ œํ•˜๋ ค๋ฉด, ์•„๋ž˜์˜ ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•œ๋‹ค.

kubectl delete services my-service

Hello World ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ ์ค‘์ธ ๋””ํ”Œ๋กœ์ด๋จผํŠธ, ๋ ˆํ”Œ๋ฆฌ์นด์…‹, ํŒŒ๋“œ๋ฅผ ์‚ญ์ œํ•˜๋ ค๋ฉด, ์•„๋ž˜์˜ ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•œ๋‹ค.

kubectl delete deployment hello-world

๋‹ค์Œ ๋‚ด์šฉ

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ์„œ๋น„์Šค ์—ฐ๊ฒฐํ•˜๊ธฐ์— ๋Œ€ํ•ด ๋” ๋ฐฐ์›Œ ๋ณธ๋‹ค.

5.2 - ์˜ˆ์‹œ: Redis๋ฅผ ์‚ฌ์šฉํ•œ PHP ๋ฐฉ๋ช…๋ก ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฐฐํฌํ•˜๊ธฐ

์ด ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์™€ Docker๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ„๋‹จํ•œ (์šด์˜ ์ˆ˜์ค€์ด ์•„๋‹Œ) ๋ฉ€ํ‹ฐ ํ‹ฐ์–ด ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋นŒ๋“œํ•˜๊ณ  ๋ฐฐํฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค€๋‹ค. ์ด ์˜ˆ์ œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ตฌ์„ฑ์œผ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๋‹ค.

  • ๋ฐฉ๋ช…๋ก ํ•ญ๋ชฉ์„ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ๋‹จ์ผ ์ธ์Šคํ„ด์Šค Redis
  • ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์›น ํ”„๋ก ํŠธ์—”๋“œ ์ธ์Šคํ„ด์Šค

๋ชฉ์ 

  • Redis ๋ฆฌ๋”๋ฅผ ์‹คํ–‰
  • 2๊ฐœ์˜ Redis ํŒ”๋กœ์›Œ๋ฅผ ์‹คํ–‰
  • ๋ฐฉ๋ช…๋ก ํ”„๋ก ํŠธ์—”๋“œ๋ฅผ ์‹คํ–‰
  • ํ”„๋ก ํŠธ์—”๋“œ ์„œ๋น„์Šค๋ฅผ ๋…ธ์ถœํ•˜๊ณ  ํ™•์ธ
  • ์ •๋ฆฌํ•˜๊ธฐ

์‹œ์ž‘ํ•˜๊ธฐ ์ „์—

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ๊ฐ€ ํ•„์š”ํ•˜๊ณ , kubectl ์ปค๋งจ๋“œ-๋ผ์ธ ํˆด์ด ํด๋Ÿฌ์Šคํ„ฐ์™€ ํ†ต์‹ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •๋˜์–ด ์žˆ์–ด์•ผ ํ•œ๋‹ค. ์ด ํŠœํ† ๋ฆฌ์–ผ์€ ์ปจํŠธ๋กค ํ”Œ๋ ˆ์ธ ํ˜ธ์ŠคํŠธ๊ฐ€ ์•„๋‹Œ ๋…ธ๋“œ๊ฐ€ ์ ์–ด๋„ 2๊ฐœ ํฌํ•จ๋œ ํด๋Ÿฌ์Šคํ„ฐ์—์„œ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค. ๋งŒ์•ฝ, ์•„์ง ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š๋‹ค๋ฉด, minikube๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ๋‹ค์Œ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํ”Œ๋ ˆ์ด๊ทธ๋ผ์šด๋“œ ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์„œ๋ฒ„์˜ ๋ฒ„์ „์€ ๋‹ค์Œ๊ณผ ๊ฐ™๊ฑฐ๋‚˜ ๋” ๋†’์•„์•ผ ํ•จ. ๋ฒ„์ „: v1.14.

๋ฒ„์ „ ํ™•์ธ์„ ์œ„ํ•ด์„œ, ๋‹ค์Œ ์ปค๋งจ๋“œ๋ฅผ ์‹คํ–‰ kubectl version.

Redis ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์‹คํ–‰

๋ฐฉ๋ช…๋ก ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ Redis๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•œ๋‹ค.

Redis ๋””ํ”Œ๋กœ์ด๋จผํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ

์•„๋ž˜์˜ ๋งค๋‹ˆํŽ˜์ŠคํŠธ ํŒŒ์ผ์€ ๋‹จ์ผ ๋ณต์ œ๋ณธ Redis ํŒŒ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋””ํ”Œ๋กœ์ด๋จผํŠธ ์ปจํŠธ๋กค๋Ÿฌ์— ๋Œ€ํ•œ ๋ช…์„ธ๋ฅผ ๋‹ด๊ณ  ์žˆ๋‹ค.

# SOURCE: https://cloud.google.com/kubernetes-engine/docs/tutorials/guestbook
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-leader
  labels:
    app: redis
    role: leader
    tier: backend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
        role: leader
        tier: backend
    spec:
      containers:
      - name: leader
        image: "docker.io/redis:6.0.5"
        resources:
          requests:
            cpu: 100m
            memory: 100Mi
        ports:
        - containerPort: 6379
  1. ๋งค๋‹ˆํŽ˜์ŠคํŠธ ํŒŒ์ผ์„ ๋‹ค์šด๋กœ๋“œํ•œ ๋””๋ ‰ํ„ฐ๋ฆฌ์—์„œ ํ„ฐ๋ฏธ๋„ ์ฐฝ์„ ์‹œ์ž‘ํ•œ๋‹ค.

  2. redis-leader-deployment.yaml ํŒŒ์ผ์„ ์ด์šฉํ•˜์—ฌ Redis ๋””ํ”Œ๋กœ์ด๋จผํŠธ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

    kubectl apply -f https://k8s.io/examples/application/guestbook/redis-leader-deployment.yaml
    
  3. ํŒŒ๋“œ์˜ ๋ชฉ๋ก์„ ์งˆ์˜ํ•˜์—ฌ Redis ํŒŒ๋“œ๊ฐ€ ์‹คํ–‰ ์ค‘์ธ์ง€ ํ™•์ธํ•œ๋‹ค.

    kubectl get pods
    

    ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ๋‚˜ํƒ€๋‚œ๋‹ค.

    NAME                            READY     STATUS    RESTARTS   AGE
    redis-leader-fb76b4755-xjr2n   1/1     Running   0          13s
    
  4. Redis ๋ฆฌ๋” ํŒŒ๋“œ์˜ ๋กœ๊ทธ๋ฅผ ๋ณด๋ ค๋ฉด ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

    kubectl logs -f deployment/redis-leader
    

Redis ๋ฆฌ๋” ์„œ๋น„์Šค ์ƒ์„ฑํ•˜๊ธฐ

๋ฐฉ๋ช…๋ก ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์“ฐ๋ ค๋ฉด Redis์™€ ํ†ต์‹ ํ•ด์•ผ ํ•œ๋‹ค. Redis ํŒŒ๋“œ๋กœ ํŠธ๋ž˜ํ”ฝ์„ ํ”„๋ก์‹œํ•˜๋ ค๋ฉด ์„œ๋น„์Šค๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค. ์„œ๋น„์Šค๋Š” ํŒŒ๋“œ์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•œ ์ •์ฑ…์„ ์ •์˜ํ•œ๋‹ค.

# SOURCE: https://cloud.google.com/kubernetes-engine/docs/tutorials/guestbook
apiVersion: v1
kind: Service
metadata:
  name: redis-leader
  labels:
    app: redis
    role: leader
    tier: backend
spec:
  ports:
  - port: 6379
    targetPort: 6379
  selector:
    app: redis
    role: leader
    tier: backend
  1. redis-leader-service.yaml ํŒŒ์ผ์„ ์ด์šฉํ•˜์—ฌ Redis ์„œ๋น„์Šค๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

    kubectl apply -f https://k8s.io/examples/application/guestbook/redis-leader-service.yaml
    
  2. ์„œ๋น„์Šค์˜ ๋ชฉ๋ก์„ ์งˆ์˜ํ•˜์—ฌ Redis ์„œ๋น„์Šค๊ฐ€ ์‹คํ–‰ ์ค‘์ธ์ง€ ํ™•์ธํ•œ๋‹ค.

    kubectl get service
    

    ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ๋‚˜ํƒ€๋‚œ๋‹ค.

    NAME           TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
    kubernetes     ClusterIP   10.0.0.1     <none>        443/TCP    1m
    redis-leader   ClusterIP   10.103.78.24 <none>        6379/TCP   16s
    

Redis ํŒ”๋กœ์›Œ ๊ตฌ์„ฑํ•˜๊ธฐ

Redis ๋ฆฌ๋”๋Š” ๋‹จ์ผ ํŒŒ๋“œ์ด์ง€๋งŒ, ๋ช‡ ๊ฐœ์˜ Redis ํŒ”๋กœ์›Œ ๋˜๋Š” ๋ณต์ œ๋ณธ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ๊ฐ€์šฉ์„ฑ์„ ๋†’์ด๊ณ  ํŠธ๋ž˜ํ”ฝ ์š”๊ตฌ๋ฅผ ์ถฉ์กฑํ•  ์ˆ˜ ์žˆ๋‹ค.

# SOURCE: https://cloud.google.com/kubernetes-engine/docs/tutorials/guestbook
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-follower
  labels:
    app: redis
    role: follower
    tier: backend
spec:
  replicas: 2
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
        role: follower
        tier: backend
    spec:
      containers:
      - name: follower
        image: gcr.io/google_samples/gb-redis-follower:v2
        resources:
          requests:
            cpu: 100m
            memory: 100Mi
        ports:
        - containerPort: 6379
  1. redis-follower-deployment.yaml ํŒŒ์ผ์„ ์ด์šฉํ•˜์—ฌ Redis ์„œ๋น„์Šค๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

    kubectl apply -f https://k8s.io/examples/application/guestbook/redis-follower-deployment.yaml
    
  2. ํŒŒ๋“œ์˜ ๋ชฉ๋ก์„ ์งˆ์˜ํ•˜์—ฌ 2๊ฐœ์˜ Redis ํŒ”๋กœ์›Œ ๋ ˆํ”Œ๋ฆฌ์นด๊ฐ€ ์‹คํ–‰ ์ค‘์ธ์ง€ ํ™•์ธํ•œ๋‹ค.

    kubectl get pods
    

    ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ๋‚˜ํƒ€๋‚œ๋‹ค.

    NAME                             READY   STATUS    RESTARTS   AGE
    redis-follower-dddfbdcc9-82sfr   1/1     Running   0          37s
    redis-follower-dddfbdcc9-qrt5k   1/1     Running   0          38s
    redis-leader-fb76b4755-xjr2n     1/1     Running   0          11m
    

Redis ํŒ”๋กœ์›Œ ์„œ๋น„์Šค ์ƒ์„ฑํ•˜๊ธฐ

๋ฐฉ๋ช…๋ก ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์œผ๋ ค๋ฉด Redis ํŒ”๋กœ์›Œ์™€ ํ†ต์‹ ํ•ด์•ผ ํ•œ๋‹ค. Redis ํŒ”๋กœ์›Œ๋ฅผ ๋ฐœ๊ฒฌ ๊ฐ€๋Šฅ(discoverable)ํ•˜๊ฒŒ ๋งŒ๋“œ๋ ค๋ฉด, ์ƒˆ๋กœ์šด ์„œ๋น„์Šค๋ฅผ ๊ตฌ์„ฑํ•ด์•ผ ํ•œ๋‹ค.

# SOURCE: https://cloud.google.com/kubernetes-engine/docs/tutorials/guestbook
apiVersion: v1
kind: Service
metadata:
  name: redis-follower
  labels:
    app: redis
    role: follower
    tier: backend
spec:
  ports:
    # the port that this service should serve on
  - port: 6379
  selector:
    app: redis
    role: follower
    tier: backend
  1. redis-follower-service.yaml ํŒŒ์ผ์„ ์ด์šฉํ•˜์—ฌ Redis ์„œ๋น„์Šค๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

    kubectl apply -f https://k8s.io/examples/application/guestbook/redis-follower-service.yaml
    
  2. ์„œ๋น„์Šค์˜ ๋ชฉ๋ก์„ ์งˆ์˜ํ•˜์—ฌ Redis ์„œ๋น„์Šค๊ฐ€ ์‹คํ–‰ ์ค‘์ธ์ง€ ํ™•์ธํ•œ๋‹ค.

    kubectl get service
    

    ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ๋‚˜ํƒ€๋‚œ๋‹ค.

    NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
    kubernetes       ClusterIP   10.96.0.1       <none>        443/TCP    3d19h
    redis-follower   ClusterIP   10.110.162.42   <none>        6379/TCP   9s
    redis-leader     ClusterIP   10.103.78.24    <none>        6379/TCP   6m10s
    

๋ฐฉ๋ช…๋ก ํ”„๋ก ํŠธ์—”๋“œ๋ฅผ ์„ค์ •ํ•˜๊ณ  ๋…ธ์ถœํ•˜๊ธฐ

๋ฐฉ๋ช…๋ก์„ ์œ„ํ•œ Redis ์ €์žฅ์†Œ๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ  ์‹คํ–‰ํ–ˆ์œผ๋ฏ€๋กœ, ์ด์ œ ๋ฐฉ๋ช…๋ก ์›น ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•œ๋‹ค. Redis ํŒ”๋กœ์›Œ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, ํ”„๋ก ํŠธ์—”๋“œ๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋””ํ”Œ๋กœ์ด๋จผํŠธ(Deployment)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐํฌ๋œ๋‹ค.

๋ฐฉ๋ช…๋ก ์•ฑ์€ PHP ํ”„๋ก ํŠธ์—”๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. DB์— ๋Œ€ํ•œ ์š”์ฒญ์ด ์ฝ๊ธฐ์ธ์ง€ ์“ฐ๊ธฐ์ธ์ง€์— ๋”ฐ๋ผ, Redis ํŒ”๋กœ์›Œ ๋˜๋Š” ๋ฆฌ๋” ์„œ๋น„์Šค์™€ ํ†ต์‹ ํ•˜๋„๋ก ๊ตฌ์„ฑ๋œ๋‹ค. ํ”„๋ก ํŠธ์—”๋“œ๋Š” JSON ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋…ธ์ถœํ•˜๊ณ , jQuery-Ajax ๊ธฐ๋ฐ˜ UX๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

๋ฐฉ๋ช…๋ก ํ”„๋ก ํŠธ์—”๋“œ์˜ ๋””ํ”Œ๋กœ์ด๋จผํŠธ ์ƒ์„ฑํ•˜๊ธฐ

# SOURCE: https://cloud.google.com/kubernetes-engine/docs/tutorials/guestbook
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
spec:
  replicas: 3
  selector:
    matchLabels:
        app: guestbook
        tier: frontend
  template:
    metadata:
      labels:
        app: guestbook
        tier: frontend
    spec:
      containers:
      - name: php-redis
        image: gcr.io/google_samples/gb-frontend:v5
        env:
        - name: GET_HOSTS_FROM
          value: "dns"
        resources:
          requests:
            cpu: 100m
            memory: 100Mi
        ports:
        - containerPort: 80
  1. frontend-deployment.yaml ํŒŒ์ผ์„ ์ด์šฉํ•˜์—ฌ ํ”„๋ก ํŠธ์—”๋“œ ๋””ํ”Œ๋กœ์ด๋จผํŠธ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

    kubectl apply -f https://k8s.io/examples/application/guestbook/frontend-deployment.yaml
    
  2. ํŒŒ๋“œ์˜ ๋ชฉ๋ก์„ ์งˆ์˜ํ•˜์—ฌ ์„ธ ๊ฐœ์˜ ํ”„๋ก ํŠธ์—”๋“œ ๋ณต์ œ๋ณธ์ด ์‹คํ–‰๋˜๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

    kubectl get pods -l app=guestbook -l tier=frontend
    

    ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ๋‚˜ํƒ€๋‚œ๋‹ค.

    NAME                        READY   STATUS    RESTARTS   AGE
    frontend-85595f5bf9-5tqhb   1/1     Running   0          47s
    frontend-85595f5bf9-qbzwm   1/1     Running   0          47s
    frontend-85595f5bf9-zchwc   1/1     Running   0          47s
    

ํ”„๋ก ํŠธ์—”๋“œ ์„œ๋น„์Šค ์ƒ์„ฑํ•˜๊ธฐ

์„œ๋น„์Šค์˜ ๊ธฐ๋ณธ ์œ ํ˜•์€ ClusterIP ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ƒ์„ฑํ•œ Redis ์„œ๋น„์Šค๋Š” ์ปจํ…Œ์ด๋„ˆ ํด๋Ÿฌ์Šคํ„ฐ ๋‚ด์—์„œ๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค. ClusterIP๋Š” ์„œ๋น„์Šค๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ํŒŒ๋“œ ์ง‘ํ•ฉ์— ๋Œ€ํ•œ ๋‹จ์ผ IP ์ฃผ์†Œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ์ด IP ์ฃผ์†Œ๋Š” ํด๋Ÿฌ์Šคํ„ฐ ๋‚ด์—์„œ๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ฒŒ์ŠคํŠธ๊ฐ€ ๋ฐฉ๋ช…๋ก์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋ ค๋ฉด, ์™ธ๋ถ€์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋„๋ก ํ”„๋ก ํŠธ์—”๋“œ ์„œ๋น„์Šค๋ฅผ ๊ตฌ์„ฑํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ํ•˜๋ฉด ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ ์™ธ๋ถ€์—์„œ ์„œ๋น„์Šค๋ฅผ ์š”์ฒญํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์‚ฌ์šฉ์ž๋Š” ClusterIP๋ฅผ ์‚ฌ์šฉํ•˜๋”๋ผ๋„ kubectl port-forward๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์„œ๋น„์Šค์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.

# SOURCE: https://cloud.google.com/kubernetes-engine/docs/tutorials/guestbook
apiVersion: v1
kind: Service
metadata:
  name: frontend
  labels:
    app: guestbook
    tier: frontend
spec:
  # if your cluster supports it, uncomment the following to automatically create
  # an external load-balanced IP for the frontend service.
  # type: LoadBalancer
  #type: LoadBalancer
  ports:
    # the port that this service should serve on
  - port: 80
  selector:
    app: guestbook
    tier: frontend
  1. frontend-service.yaml ํŒŒ์ผ์„ ์ด์šฉํ•˜์—ฌ ํ”„๋ก ํŠธ์—”๋“œ ์„œ๋น„์Šค๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

    kubectl apply -f https://k8s.io/examples/application/guestbook/frontend-service.yaml
    
  2. ์„œ๋น„์Šค์˜ ๋ชฉ๋ก์„ ์งˆ์˜ํ•˜์—ฌ ํ”„๋ก ํŠธ์—”๋“œ ์„œ๋น„์Šค๊ฐ€ ์‹คํ–‰ ์ค‘์ธ์ง€ ํ™•์ธํ•œ๋‹ค.

    kubectl get services
    

    ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ๋‚˜ํƒ€๋‚œ๋‹ค.

    NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
    frontend         ClusterIP   10.97.28.230    <none>        80/TCP     19s
    kubernetes       ClusterIP   10.96.0.1       <none>        443/TCP    3d19h
    redis-follower   ClusterIP   10.110.162.42   <none>        6379/TCP   5m48s
    redis-leader     ClusterIP   10.103.78.24    <none>        6379/TCP   11m
    

kubectl port-forward๋ฅผ ํ†ตํ•ด ํ”„๋ก ํŠธ์—”๋“œ ์„œ๋น„์Šค ํ™•์ธํ•˜๊ธฐ

  1. ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•ด์„œ ๋กœ์ปฌ ๋จธ์‹ ์˜ 8080 ํฌํŠธ๋ฅผ ์„œ๋น„์Šค์˜ 80 ํฌํŠธ๋กœ ์ „๋‹ฌํ•œ๋‹ค.

    kubectl port-forward svc/frontend 8080:80
    

    ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ๋‚˜ํƒ€๋‚œ๋‹ค.

    Forwarding from 127.0.0.1:8080 -> 80
    Forwarding from [::1]:8080 -> 80
    
  2. ๋ฐฉ๋ช…๋ก์„ ๋ณด๊ธฐ ์œ„ํ•ด ๋ธŒ๋ผ์šฐ์ €์—์„œ http://localhost:8080 ํŽ˜์ด์ง€๋ฅผ ๋กœ๋“œํ•œ๋‹ค.

LoadBalancer๋ฅผ ํ†ตํ•ด ํ”„๋ก ํŠธ์—”๋“œ ์„œ๋น„์Šค ํ™•์ธํ•˜๊ธฐ

frontend-service.yaml ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ LoadBalancer์™€ ํ•จ๊ป˜ ๋ฐฐํฌํ•œ ๊ฒฝ์šฐ, ๋ฐฉ๋ช…๋ก์„ ๋ณด๊ธฐ ์œ„ํ•ด IP ์ฃผ์†Œ๋ฅผ ์ฐพ์•„์•ผ ํ•œ๋‹ค.

  1. ํ”„๋ก ํŠธ์—”๋“œ ์„œ๋น„์Šค์˜ IP ์ฃผ์†Œ๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

    kubectl get service frontend
    

    ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ๋‚˜ํƒ€๋‚œ๋‹ค.

    NAME       TYPE           CLUSTER-IP      EXTERNAL-IP        PORT(S)        AGE
    frontend   LoadBalancer   10.51.242.136   109.197.92.229     80:32372/TCP   1m
    
  2. IP ์ฃผ์†Œ๋ฅผ ๋ณต์‚ฌํ•˜๊ณ , ๋ฐฉ๋ช…๋ก์„ ๋ณด๊ธฐ ์œ„ํ•ด ๋ธŒ๋ผ์šฐ์ €์—์„œ ํŽ˜์ด์ง€๋ฅผ ๋กœ๋“œํ•œ๋‹ค.

์›น ํ”„๋ก ํŠธ์—”๋“œ ํ™•์žฅํ•˜๊ธฐ

์„œ๋ฒ„๊ฐ€ ๋””ํ”Œ๋กœ์ด๋จผํŠธ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์„œ๋น„์Šค๋กœ ์ •์˜๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ํ•„์š”์— ๋”ฐ๋ผ ํ™•์žฅ ๋˜๋Š” ์ถ•์†Œํ•  ์ˆ˜ ์žˆ๋‹ค.

  1. ํ”„๋ก ํŠธ์—”๋“œ ํŒŒ๋“œ์˜ ์ˆ˜๋ฅผ ํ™•์žฅํ•˜๊ธฐ ์œ„ํ•ด ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

    kubectl scale deployment frontend --replicas=5
    
  2. ํŒŒ๋“œ์˜ ๋ชฉ๋ก์„ ์งˆ์˜ํ•˜์—ฌ ์‹คํ–‰ ์ค‘์ธ ํ”„๋ก ํŠธ์—”๋“œ ํŒŒ๋“œ์˜ ์ˆ˜๋ฅผ ํ™•์ธํ•œ๋‹ค.

    kubectl get pods
    

    ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ๋‚˜ํƒ€๋‚œ๋‹ค.

    NAME                             READY   STATUS    RESTARTS   AGE
    frontend-85595f5bf9-5df5m        1/1     Running   0          83s
    frontend-85595f5bf9-7zmg5        1/1     Running   0          83s
    frontend-85595f5bf9-cpskg        1/1     Running   0          15m
    frontend-85595f5bf9-l2l54        1/1     Running   0          14m
    frontend-85595f5bf9-l9c8z        1/1     Running   0          14m
    redis-follower-dddfbdcc9-82sfr   1/1     Running   0          97m
    redis-follower-dddfbdcc9-qrt5k   1/1     Running   0          97m
    redis-leader-fb76b4755-xjr2n     1/1     Running   0          108m
    
  3. ํ”„๋ก ํŠธ์—”๋“œ ํŒŒ๋“œ์˜ ์ˆ˜๋ฅผ ์ถ•์†Œํ•˜๊ธฐ ์œ„ํ•ด ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

    kubectl scale deployment frontend --replicas=2
    
  4. ํŒŒ๋“œ์˜ ๋ชฉ๋ก์„ ์งˆ์˜ํ•˜์—ฌ ์‹คํ–‰ ์ค‘์ธ ํ”„๋ก ํŠธ์—”๋“œ ํŒŒ๋“œ์˜ ์ˆ˜๋ฅผ ํ™•์ธํ•œ๋‹ค.

    kubectl get pods
    

    ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ๋‚˜ํƒ€๋‚œ๋‹ค.

    NAME                            READY     STATUS    RESTARTS   AGE
    frontend-85595f5bf9-cpskg        1/1     Running   0          16m
    frontend-85595f5bf9-l9c8z        1/1     Running   0          15m
    redis-follower-dddfbdcc9-82sfr   1/1     Running   0          98m
    redis-follower-dddfbdcc9-qrt5k   1/1     Running   0          98m
    redis-leader-fb76b4755-xjr2n     1/1     Running   0          109m
    

์ •๋ฆฌํ•˜๊ธฐ

๋””ํ”Œ๋กœ์ด๋จผํŠธ ๋ฐ ์„œ๋น„์Šค๋ฅผ ์‚ญ์ œํ•˜๋ฉด ์‹คํ–‰ ์ค‘์ธ ๋ชจ๋“  ํŒŒ๋“œ๋„ ์‚ญ์ œ๋œ๋‹ค. ๋ ˆ์ด๋ธ”์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•˜๋‚˜์˜ ๋ช…๋ น์–ด๋กœ ์—ฌ๋Ÿฌ ์ž์›์„ ์‚ญ์ œํ•ด๋ณด์ž.

  1. ๋ชจ๋“  ํŒŒ๋“œ, ๋””ํ”Œ๋กœ์ด๋จผํŠธ, ์„œ๋น„์Šค๋ฅผ ์‚ญ์ œํ•˜๊ธฐ ์œ„ํ•ด ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

    kubectl delete deployment -l app=redis
    kubectl delete service -l app=redis
    kubectl delete deployment frontend
    kubectl delete service frontend
    

    ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ๋‚˜ํƒ€๋‚œ๋‹ค.

    deployment.apps "redis-follower" deleted
    deployment.apps "redis-leader" deleted
    deployment.apps "frontend" deleted
    service "frontend" deleted
    
  2. ํŒŒ๋“œ์˜ ๋ชฉ๋ก์„ ์งˆ์˜ํ•˜์—ฌ ์‹คํ–‰ ์ค‘์ธ ํŒŒ๋“œ๊ฐ€ ์—†๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

    kubectl get pods
    

    ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ๋‚˜ํƒ€๋‚œ๋‹ค.

    No resources found in default namespace.
    

๋‹ค์Œ ๋‚ด์šฉ

6 - ์ƒํƒœ ์œ ์ง€๊ฐ€ ํ•„์š”ํ•œ(stateful) ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜

6.1 - ์Šคํ…Œ์ดํŠธํ’€์…‹ ๊ธฐ๋ณธ

์ด ํŠœํ† ๋ฆฌ์–ผ์€ ์Šคํ…Œ์ดํŠธํ’€์…‹(StatefulSet)์„ ์ด์šฉํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์†Œ๊ฐœํ•œ๋‹ค. ์–ด๋–ป๊ฒŒ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์‚ญ์ œํ•˜๋ฉฐ, ์Šค์ผ€์ผ๋งํ•˜๊ณ , ์—…๋ฐ์ดํŠธํ•˜๋Š”์ง€ ์‹œ์—ฐํ•œ๋‹ค.

์‹œ์ž‘ํ•˜๊ธฐ ์ „์—

ํŠœํ† ๋ฆฌ์–ผ์„ ์‹œ์ž‘ํ•˜๊ธฐ ์ „์— ๋‹ค์Œ์˜ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์ปจ์…‰์— ๋Œ€ํ•ด ์ต์ˆ™ํ•ด์•ผ ํ•œ๋‹ค.

๋ชฉ์ 

์Šคํ…Œ์ดํŠธํ’€์…‹์€ ์ƒํƒœ ์œ ์ง€๊ฐ€ ํ•„์š”ํ•œ(stateful) ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ๋ถ„์‚ฐ์‹œ์Šคํ…œ์—์„œ ์ด์šฉํ•˜๋„๋ก ์˜๋„ํ–ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์ƒ์— ์Šคํ…Œ์ดํŠธํ’€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ๋ถ„์‚ฐ์‹œ์Šคํ…œ์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์€ ๊ด‘๋ฒ”์œ„ํ•˜๊ณ  ๋ณต์žกํ•œ ์ฃผ์ œ์ด๋‹ค. ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ๊ธฐ๋ณธ ๊ธฐ๋Šฅ์„ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด ์ด ๋‘˜์„ ๊ฒฐํ•ฉํ•˜์ง€ ์•Š๊ณ , ์Šคํ…Œ์ดํŠธํ’€์…‹์„ ์‚ฌ์šฉํ•œ ๋‹จ์ˆœ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋ฐฐํฌํ•  ๊ฒƒ์ด๋‹ค.

์ด ํŠœํ† ๋ฆฌ์–ผ์„ ๋งˆ์น˜๋ฉด ๋‹ค์Œ ํ•ญ๋ชฉ์— ๋Œ€ํ•ด ์ต์ˆ™ํ•ด์งˆ ๊ฒƒ์ด๋‹ค.

  • ์Šคํ…Œ์ดํŠธํ’€์…‹์„ ์–ด๋–ป๊ฒŒ ์ƒ์„ฑํ•˜๋Š”์ง€
  • ์Šคํ…Œ์ดํŠธํ’€์…‹์ด ์–ด๋–ป๊ฒŒ ํŒŒ๋“œ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š”์ง€
  • ์Šคํ…Œ์ดํŠธํ’€์…‹์„ ์–ด๋–ป๊ฒŒ ์‚ญ์ œํ•˜๋Š”์ง€
  • ์Šคํ…Œ์ดํŠธํ’€์…‹์€ ์–ด๋–ป๊ฒŒ ์Šค์ผ€์ผ๋งํ•˜๋Š”์ง€
  • ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๋Š” ์–ด๋–ป๊ฒŒ ์—…๋ฐ์ดํŠธํ•˜๋Š”์ง€

์Šคํ…Œ์ดํŠธํ’€์…‹ ์ƒ์„ฑํ•˜๊ธฐ

์•„๋ž˜ ์˜ˆ์ œ๋ฅผ ์ด์šฉํ•ด์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹์„ ์ƒ์„ฑํ•˜์ž. ์ด๋Š” ์Šคํ…Œ์ดํŠธํ’€์…‹ ๊ฐœ๋…์—์„œ ๋ณด์ธ ์˜ˆ์ œ์™€ ์œ ์‚ฌํ•˜๋‹ค. ์ด๊ฒƒ์€ web๊ณผ ์ด ์Šคํ…Œ์ดํŠธํ’€์…‹ ํŒŒ๋“œ์˜ IP ์ฃผ์†Œ๋ฅผ ๊ฒŒ์‹œํ•˜๋Š” ํ—ค๋“œ๋ฆฌ์Šค ์„œ๋น„์Šค์ธ nginx ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx"
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: registry.k8s.io/nginx-slim:0.8
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi

์œ„์— ์˜ˆ์ œ๋ฅผ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์•„์„œ ํŒŒ์ผ์ด๋ฆ„์„ web.yaml์œผ๋กœ ์ €์žฅํ•˜์ž.

2๊ฐœ์˜ ํ„ฐ๋ฏธ๋„์ฐฝ์„ ์‚ฌ์šฉํ•œ๋‹ค. ์ฒซ์งธ ํ„ฐ๋ฏธ๋„์—์„œ kubectl get์„ ์ด์šฉํ•ด์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๊ฐ€ ์ƒ์„ฑ๋˜๋Š”์ง€ ๊ฐ์‹œํ•˜์ž.

kubectl get pods -w -l app=nginx

๋‘ ๋ฒˆ์งธ ํ„ฐ๋ฏธ๋„์—์„œ kubectl apply๋กœ web.yaml์— ์ •์˜๋œ ํ—ค๋“œ๋ฆฌ์Šค ์„œ๋น„์Šค์™€ ์Šคํ…Œ์ดํŠธํ’€์…‹์„ ์ƒ์„ฑํ•œ๋‹ค.

kubectl apply -f web.yaml
service/nginx created
statefulset.apps/web created

์ƒ๊ธฐ ๋ช…๋ น์–ด๋Š” NGINX ์›น ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•˜๋Š” 2๊ฐœ์˜ ํŒŒ๋“œ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. nginx ์„œ๋น„์Šค์˜ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.

kubectl get service nginx
NAME      TYPE         CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
nginx     ClusterIP    None         <none>        80/TCP    12s

๊ทธ๋ฆฌ๊ณ  web ์Šคํ…Œ์ดํŠธํ’€์…‹ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์™€์„œ ๋ชจ๋‘ ์„ฑ๊ณต์ ์œผ๋กœ ์ƒ์„ฑ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

kubectl get statefulset web
NAME      DESIRED   CURRENT   AGE
web       2         1         20s

์ฐจ๋ก€๋Œ€๋กœ ํŒŒ๋“œ ์ƒ์„ฑํ•˜๊ธฐ

N๊ฐœ์˜ ๋ ˆํ”Œ๋ฆฌ์นด๋ฅผ ๊ฐ€์ง„ ์Šคํ…Œ์ดํŠธํ’€์…‹์€ ๋ฐฐํฌ ์‹œ์— ์ˆœ์ฐจ์ ์œผ๋กœ {0..N-1} ์ˆœ์œผ๋กœ ์ƒ์„ฑ๋œ๋‹ค. ์ฒซ์งธ ํ„ฐ๋ฏธ๋„์—์„œ kubectl get ๋ช…๋ น์˜ ์ถœ๋ ฅ ๋‚ด์šฉ์„ ์‚ดํŽด๋ณด์ž. ๊ฒฐ๊ตญ ๊ทธ ๋‚ด์šฉ์€ ์•„๋ž˜ ์˜ˆ์™€ ๋น„์Šทํ•  ๊ฒƒ์ด๋‹ค.

kubectl get pods -w -l app=nginx
NAME      READY     STATUS    RESTARTS   AGE
web-0     0/1       Pending   0          0s
web-0     0/1       Pending   0         0s
web-0     0/1       ContainerCreating   0         0s
web-0     1/1       Running   0         19s
web-1     0/1       Pending   0         0s
web-1     0/1       Pending   0         0s
web-1     0/1       ContainerCreating   0         0s
web-1     1/1       Running   0         18s

์ฐธ๊ณ ๋กœ web-1 ํŒŒ๋“œ๋Š” web-0 ํŒŒ๋“œ๊ฐ€ Running (ํŒŒ๋“œ์˜ ๋‹จ๊ณ„ ์ฐธ๊ณ ) ๋ฐ Ready (ํŒŒ๋“œ์˜ ์ปจ๋””์…˜์—์„œ type ์ฐธ๊ณ ) ์ƒํƒœ๊ฐ€ ๋˜๊ธฐ ์ „์—๋Š” ์‹œ์ž‘๋˜์ง€ ์•Š์Œ์— ์ฃผ์˜ํ•œ๋‹ค.

์Šคํ…Œ์ดํŠธํ’€์…‹ ์•ˆ์— ํŒŒ๋“œ

์Šคํ…Œ์ดํŠธํ’€์…‹ ์•ˆ์— ํŒŒ๋“œ๋Š” ๊ณ ์œ ํ•œ ์ˆœ๋ฒˆ๊ณผ ๋™์ผํ•œ ๋„คํŠธ์›Œํฌ ์‹ ์›์„ ๊ฐ€์ง„๋‹ค.

ํŒŒ๋“œ ์ˆœ๋ฒˆ ์‚ดํŽด๋ณด๊ธฐ

์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๋ฅผ ๊ฐ€์ ธ์˜ค์ž.

kubectl get pods -l app=nginx
NAME      READY     STATUS    RESTARTS   AGE
web-0     1/1       Running   0          1m
web-1     1/1       Running   0          1m

์Šคํ…Œ์ดํŠธํ’€์…‹ ๊ฐœ๋…์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๋Š” ๋ˆ๋ˆํ•˜๊ณ  ๊ณ ์œ ํ•œ ์ •์ฒด์„ฑ์„ ๊ฐ€์ง„๋‹ค. ์ด ์ •์ฒด์„ฑ์€ ์Šคํ…Œ์ดํŠธํ’€์…‹ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ๊ฐ ํŒŒ๋“œ์— ์ฃผ์–ด์ง€๋Š” ๊ณ ์œ ํ•œ ์ˆœ๋ฒˆ์— ๊ธฐ์ธํ•œ๋‹ค. ํŒŒ๋“œ์˜ ์ด๋ฆ„์˜ ํ˜•์‹์€ <์Šคํ…Œ์ดํŠธํ’€์…‹ ์ด๋ฆ„>-<์ˆœ๋ฒˆ> ์ด๋‹ค. ์•ž์„œ web ์Šคํ…Œ์ดํŠธํ’€์…‹์€ 2๊ฐœ์˜ ๋ ˆํ”Œ๋ฆฌ์นด๋ฅผ ๊ฐ€์กŒ์œผ๋ฏ€๋กœ web-0 ๊ณผ web-1 2๊ฐœ ํŒŒ๋“œ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

์•ˆ์ •์ ์ธ ๋„คํŠธ์›Œํฌ ์‹ ์› ์‚ฌ์šฉํ•˜๊ธฐ

๊ฐ ํŒŒ๋“œ๋Š” ๊ฐ ์ˆœ๋ฒˆ์— ๋”ฐ๋ฅธ ์•ˆ์ •์ ์ธ ํ˜ธ์ŠคํŠธ๋„ค์ž„์„ ๊ฐ–๋Š”๋‹ค. ๊ฐ ํŒŒ๋“œ์—์„œ hostname ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜๋„๋ก kubectl exec๋ฅผ ์ด์šฉํ•˜์ž.

for i in 0 1; do kubectl exec "web-$i" -- sh -c 'hostname'; done
web-0
web-1

dnsutils ํŒจํ‚ค์ง€์—์„œ nslookup ๋ช…๋ น์„ ์ œ๊ณตํ•˜๋Š” ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‹คํ–‰ํ•˜๋„๋ก kubectl run์„ ์ด์šฉํ•˜์ž. ํŒŒ๋“œ์˜ ํ˜ธ์ŠคํŠธ๋„ค์ž„์— nslookup์„ ์ด์šฉํ•˜๋ฉด ํด๋Ÿฌ์Šคํ„ฐ ๋‚ด๋ถ€ DNS ์ฃผ์†Œ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl run -i --tty --image busybox:1.28 dns-test --restart=Never --rm

์œ„ ๋ช…๋ น์œผ๋กœ ์ƒˆ๋กœ์šด ์…ธ์„ ์‹œ์ž‘ํ•œ๋‹ค. ์ƒˆ ์…ธ์—์„œ ๋‹ค์Œ์„ ์‹คํ–‰ํ•œ๋‹ค.

# dns-test ์ปจํ…Œ์ด๋„ˆ ์…ธ์—์„œ ๋‹ค์Œ์„ ์‹คํ–‰ํ•œ๋‹ค.
nslookup web-0.nginx

์ถœ๋ ฅ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๋น„์Šทํ•˜๋‹ค.

Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-0.nginx
Address 1: 10.244.1.6

nslookup web-1.nginx
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-1.nginx
Address 1: 10.244.2.6

(์ด์ œ exit ๋ช…๋ น์œผ๋กœ ์ปจํ…Œ์ด๋„ˆ ์…ธ์—์„œ ์ข…๋ฃŒํ•œ๋‹ค.)

ํ—ค๋“œ๋ฆฌ์Šค ์„œ๋น„์Šค์˜ CNAME์€ SRV ๋ ˆ์ฝ”๋“œ๋ฅผ ์ง€์นญํ•œ๋‹ค (Running๊ณผ Ready ์ƒํƒœ์˜ ๊ฐ ํŒŒ๋“œ๋งˆ๋‹ค 1๊ฐœ). SRV ๋ ˆ์ฝ”๋“œ๋Š” ํŒŒ๋“œ์˜ IP ์ฃผ์†Œ๋ฅผ ํฌํ•จํ•œ A ๋ ˆ์ฝ”๋“œ ์—”ํŠธ๋ฆฌ๋ฅผ ์ง€์นญํ•œ๋‹ค.

์ฒซ์งธ ํ„ฐ๋ฏธ๋„์—์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๋ฅผ ๊ฐ€์ ธ์˜ค์ž.

kubectl get pod -w -l app=nginx

๋‘ ๋ฒˆ์งธ ํ„ฐ๋ฏธ๋„์—์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹ ๋‚ด์— ํŒŒ๋“œ๋ฅผ ๋ชจ๋‘ ์‚ญ์ œํ•˜๊ธฐ ์œ„ํ•ด kubectl delete๋ฅผ ์ด์šฉํ•˜์ž.

kubectl delete pod -l app=nginx
pod "web-0" deleted
pod "web-1" deleted

์Šคํ…Œ์ดํŠธํ’€์…‹์ด ์žฌ์‹œ์ž‘๋˜๊ณ  ๋‘ ํŒŒ๋“œ๊ฐ€ Running๊ณผ Ready ์ƒํƒœ๋กœ ์ „ํ™˜๋˜๋„๋ก ๊ธฐ๋‹ค๋ฆฌ์ž.

kubectl get pod -w -l app=nginx
NAME      READY     STATUS              RESTARTS   AGE
web-0     0/1       ContainerCreating   0          0s
NAME      READY     STATUS    RESTARTS   AGE
web-0     1/1       Running   0          2s
web-1     0/1       Pending   0         0s
web-1     0/1       Pending   0         0s
web-1     0/1       ContainerCreating   0         0s
web-1     1/1       Running   0         34s

ํŒŒ๋“œ์˜ ํ˜ธ์ŠคํŠธ๋„ค์ž„๊ณผ ํด๋Ÿฌ์Šคํ„ฐ ๋‚ด๋ถ€ DNS ์—”ํŠธ๋ฆฌ๋ฅผ ๋ณด๊ธฐ ์œ„ํ•ด kubectl exec๊ณผ kubectl run์„ ์ด์šฉํ•˜์ž. ๋จผ์ €, ํŒŒ๋“œ์˜ ํ˜ธ์ŠคํŠธ๋„ค์ž„์„ ํ™•์ธํ•œ๋‹ค.

for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; done
web-0
web-1

๊ทธ๋ฆฌ๊ณ  ๋‹ค์Œ์„ ์‹คํ–‰ํ•œ๋‹ค.

kubectl run -i --tty --image busybox:1.28 dns-test --restart=Never --rm /bin/sh

์ด ๋ช…๋ น์œผ๋กœ ์ƒˆ๋กœ์šด ์…ธ์ด ์‹œ์ž‘๋œ๋‹ค. ์ƒˆ ์…ธ์—์„œ ๋‹ค์Œ์„ ์‹คํ–‰ํ•œ๋‹ค.

# dns-test ์ปจํ…Œ์ด๋„ˆ ์…ธ์—์„œ ์ด๊ฒƒ์„ ์‹คํ–‰ํ•œ๋‹ค.
nslookup web-0.nginx

์ถœ๋ ฅ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๋น„์Šทํ•˜๋‹ค.

Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-0.nginx
Address 1: 10.244.1.7

nslookup web-1.nginx
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-1.nginx
Address 1: 10.244.2.8

(์ด์ œ exit ๋ช…๋ น์œผ๋กœ ์ปจํ…Œ์ด๋„ˆ ์…ธ์„ ์ข…๋ฃŒํ•œ๋‹ค.)

ํŒŒ๋“œ์˜ ์ˆœ๋ฒˆ, ํ˜ธ์ŠคํŠธ๋„ค์ž„, SRV ๋ ˆ์ฝ”๋“œ์™€ A ๋ ˆ์ฝ”๋“œ์ด๋ฆ„์€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์ง€๋งŒ ํŒŒ๋“œ์˜ IP ์ฃผ์†Œ๋Š” ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Š” ํŠœํ† ๋ฆฌ์–ผ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ํด๋Ÿฌ์Šคํ„ฐ๋‚˜ ๋‹ค๋ฅธ ํด๋Ÿฌ์Šคํ„ฐ์—๋„ ๋™์ผํ•˜๋‹ค. ๋”ฐ๋ผ์„œ ๋‹ค๋ฅธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด IP ์ฃผ์†Œ๋กœ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ์— ์ ‘์†ํ•˜์ง€ ์•Š๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํ™œ์„ฑ ๋ฉค๋ฒ„๋ฅผ ์ฐพ์•„ ์—ฐ๊ฒฐํ•  ๊ฒฝ์šฐ ํ—ค๋“œ๋ฆฌ์Šค ์„œ๋น„์Šค(nginx.default.svc.cluster.local)์˜ CNAME์„ ์ฟผ๋ฆฌํ•ด์•ผ ํ•œ๋‹ค. CNAME๊ณผ ์—ฐ๊ด€๋œ SRV ๋ ˆ์ฝ”๋“œ๋Š” ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ Running๊ณผ Ready ์ƒํƒœ์˜ ๋ชจ๋“  ํŒŒ๋“œ๋“ค์„ ๋‹ด๊ณ  ์žˆ๋‹ค.

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ด๋ฏธ ํ™œ์„ฑ์ƒํƒœ(liveness)์™€ ์ค€๋น„์„ฑ(readiness) ํ…Œ์ŠคํŠธํ•˜๋Š” ์—ฐ๊ฒฐ ๋กœ์ง์„ ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค๋ฉด ํŒŒ๋“œweb-0.nginx.default.svc.cluster.local, web-1.nginx.default.svc.cluster.local)์˜ SRV๋ ˆ์ฝ”๋“œ๋ฅผ ์•ˆ์ •์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ํŒŒ๋“œ๊ฐ€ Running๊ณผ Ready ์ƒํƒœ๋กœ ์ „ํ™˜ํ•  ๋•Œ ํŒŒ๋“œ์˜ ์ฃผ์†Œ๋ฅผ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

์•ˆ์ •์ ์ธ ์Šคํ† ๋ฆฌ์ง€์— ์“ฐ๊ธฐ

web-0๊ณผ web-1์— ๋Œ€ํ•ด ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจํด๋ ˆ์ž„(PersistentVolumeClaim)์„ ๊ฐ€์ ธ์˜ค์ž.

kubectl get pvc -l app=nginx

์ถœ๋ ฅ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๋น„์Šทํ•˜๋‹ค.

NAME        STATUS    VOLUME                                     CAPACITY   ACCESSMODES   AGE
www-web-0   Bound     pvc-15c268c7-b507-11e6-932f-42010a800002   1Gi        RWO           48s
www-web-1   Bound     pvc-15c79307-b507-11e6-932f-42010a800002   1Gi        RWO           48s

์Šคํ…Œ์ดํŠธํ’€์…‹ ์ปจํŠธ๋กค๋Ÿฌ๋Š” 2๊ฐœ์˜ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ์— ๋ฌถ์ธ 2๊ฐœ์˜ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจํด๋ ˆ์ž„์„ ์ƒ์„ฑํ–ˆ๋‹ค.

๋ณธ ํŠœํ† ๋ฆฌ์–ผ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ํด๋Ÿฌ์Šคํ„ฐ๋Š” ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ์„ ๋™์ ์œผ๋กœ ํ”„๋กœ๋น„์ €๋‹ํ•˜๋„๋ก ์„ค์ •๋˜์—ˆ์œผ๋ฏ€๋กœ ์ƒ์„ฑ๋œ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ๋„ ์ž๋™์œผ๋กœ ๋ฌถ์ธ๋‹ค.

NGINX ์›น์„œ๋ฒ„๋Š” ๊ธฐ๋ณธ ์ƒ‰์ธ ํŒŒ์ผ๋กœ /usr/share/nginx/html/index.html์„ ์ด์šฉํ•ฉ๋‹ˆ๋‹ค. ์Šคํ…Œ์ดํŠธํ’€์…‹ spec๋‚ด์˜ volumeMounts ํ•„๋“œ๋Š” /usr/share/nginx/html ๋””๋ ‰ํ„ฐ๋ฆฌ๊ฐ€ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ์œผ๋กœ ์ œ๊ณต๋˜๋Š”์ง€ ๋ณด์ฆํ•ฉ๋‹ˆ๋‹ค.

ํŒŒ๋“œ์˜ ํ˜ธ์ŠคํŠธ๋„ค์ž„์„ index.html ํŒŒ์ผ์— ์ž‘์„ฑํ•˜๊ณ  NGINX ์›น์„œ๋ฒ„๊ฐ€ ํ•ด๋‹น ํ˜ธ์ŠคํŠธ๋„ค์ž„์„ ์ œ๊ณตํ•˜๋Š”์ง€ ํ™•์ธํ•ด๋ณด์ž.

for i in 0 1; do kubectl exec "web-$i" -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html'; done

for i in 0 1; do kubectl exec -it "web-$i" -- curl localhost; done
web-0
web-1

์ฒซ์งธ ํ„ฐ๋ฏธ๋„์—์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๋ฅผ ๊ฐ์‹œํ•˜์ž.

kubectl get pod -w -l app=nginx

๋‘ ๋ฒˆ์งธ ํ„ฐ๋ฏธ๋„์—์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ๋ชจ๋“  ํŒŒ๋“œ๋ฅผ ์‚ญ์ œํ•˜์ž.

kubectl delete pod -l app=nginx
pod "web-0" deleted
pod "web-1" deleted

์ฒซ ๋ฒˆ์งธ ํ„ฐ๋ฏธ๋„์—์„œ ์‹คํ–‰ ์ค‘์ธ kubectl get๋ช…๋ น์–ด์˜ ์ถœ๋ ฅ์„ ํ™•์ธํ•˜๊ณ , ๋ชจ๋“  ํŒŒ๋“œ๊ฐ€ Running๊ณผ Ready ์ƒํƒœ๋กœ ์ „ํ™˜๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ž.

kubectl get pod -w -l app=nginx
NAME      READY     STATUS              RESTARTS   AGE
web-0     0/1       ContainerCreating   0          0s
NAME      READY     STATUS    RESTARTS   AGE
web-0     1/1       Running   0          2s
web-1     0/1       Pending   0         0s
web-1     0/1       Pending   0         0s
web-1     0/1       ContainerCreating   0         0s
web-1     1/1       Running   0         34s

์›น์„œ๋ฒ„์—์„œ ์ž์‹ ์˜ ํ˜ธ์ŠคํŠธ๋„ค์ž„์„ ๊ณ„์† ์ œ๊ณตํ•˜๋Š”์ง€ ํ™•์ธํ•˜์ž.

for i in 0 1; do kubectl exec -i -t "web-$i" -- curl http://localhost/; done
web-0
web-1

๋น„๋ก web-0๊ณผ web-1์ด ์žฌ์Šค์ผ€์ค„๋ง๋˜์–ด๋„ ๊ณ„์†ํ•ด์„œ ์ž์‹ ์˜ ํ˜ธ์ŠคํŠธ๋„ค์ž„์„ ์ œ๊ณตํ•˜๋Š”๋ฐ ์ด๋Š” ๊ฐ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจํด๋ ˆ์ž„์— ์—ฐ๊ด€๋œ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ์ด ํ•ด๋‹น volumeMounts๋กœ ์žฌ๋งˆ์šดํŠธ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. web-0๊ณผ web-1์˜ ์Šค์ผ€์ค„๋ง์— ๊ด€๊ณ„์—†์ด ๊ฐ๊ฐ์˜ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ์€ ์ ์ ˆํ•˜๊ฒŒ ๋งˆ์šดํŠธ๋œ๋‹ค.

์Šคํ…Œ์ดํŠธํ’€์…‹ ์Šค์ผ€์ผ๋ง

์Šคํ…Œ์ดํŠธํ’€์…‹์„ ์Šค์ผ€์ผ๋งํ•˜๋Š” ๊ฒƒ์€ ๋ ˆํ”Œ๋ฆฌ์นด ๊ฐœ์ˆ˜๋ฅผ ๋Š˜๋ฆฌ๊ฑฐ๋‚˜ ์ค„์ด๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค. ์ด๊ฒƒ์€ replicas ํ•„๋“œ๋ฅผ ๊ฐฑ์‹ ํ•˜์—ฌ ์ด๋ค„์ง„๋‹ค. kubectl scale์ด๋‚˜ kubectl patch์„ ์ด์šฉํ•ด์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹์„ ์Šค์ผ€์ผ๋งํ•  ์ˆ˜ ์žˆ๋‹ค.

์Šค์ผ€์ผ ์—…

ํ„ฐ๋ฏธ๋„์ฐฝ์—์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๋ฅผ ๊ฐ์‹œํ•˜์ž.

kubectl get pods -w -l app=nginx

๋‹ค๋ฅธ ํ„ฐ๋ฏธ๋„์ฐฝ์—์„œ kubectl scale์„ ์ด์šฉํ•˜์—ฌ ๋ ˆํ”Œ๋ฆฌ์นด ๊ฐœ์ˆ˜๋ฅผ 5๋กœ ์Šค์ผ€์ผ๋งํ•˜์ž.

kubectl scale sts web --replicas=5
statefulset.apps/web scaled

์ฒซ ๋ฒˆ์งธ ํ„ฐ๋ฏธ๋„์—์„œ ์‹คํ–‰ ์ค‘์ธ kubectl get๋ช…๋ น์–ด์˜ ์ถœ๋ ฅ์„ ํ™•์ธํ•˜๊ณ , 3๊ฐœ์˜ ์ถ”๊ฐ€ ํŒŒ๋“œ๊ฐ€ Running๊ณผ Ready ์ƒํƒœ๋กœ ์ „ํ™˜๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ž.

kubectl get pods -w -l app=nginx
NAME      READY     STATUS    RESTARTS   AGE
web-0     1/1       Running   0          2h
web-1     1/1       Running   0          2h
NAME      READY     STATUS    RESTARTS   AGE
web-2     0/1       Pending   0          0s
web-2     0/1       Pending   0         0s
web-2     0/1       ContainerCreating   0         0s
web-2     1/1       Running   0         19s
web-3     0/1       Pending   0         0s
web-3     0/1       Pending   0         0s
web-3     0/1       ContainerCreating   0         0s
web-3     1/1       Running   0         18s
web-4     0/1       Pending   0         0s
web-4     0/1       Pending   0         0s
web-4     0/1       ContainerCreating   0         0s
web-4     1/1       Running   0         19s

์Šคํ…Œ์ดํŠธํ’€์…‹ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ๋ ˆํ”Œ๋ฆฌ์นด ๊ฐœ์ˆ˜๋ฅผ ์Šค์ผ€์ผ๋งํ•œ๋‹ค. ์Šคํ…Œ์ดํŠธํ’€์…‹ ์ƒ์„ฑ์œผ๋กœ ์Šคํ…Œ์ดํŠธํ’€์…‹ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ๊ฐ ํŒŒ๋“œ์„ ์ˆœ์ฐจ์ ์œผ๋กœ ๊ฐ ์ˆœ๋ฒˆ์— ๋”ฐ๋ผ ์ƒ์„ฑํ•˜๊ณ  ํ›„์† ํŒŒ๋“œ ์‹œ์ž‘ ์ „์— ์ด์ „ ํŒŒ๋“œ๊ฐ€ Running๊ณผ Ready ์ƒํƒœ๊ฐ€ ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.

์Šค์ผ€์ผ ๋‹ค์šด

ํ„ฐ๋ฏธ๋„์—์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๋ฅผ ๊ฐ์‹œํ•˜์ž.

kubectl get pods -w -l app=nginx

๋‹ค๋ฅธ ํ„ฐ๋ฏธ๋„์—์„œ kubectl patch์œผ๋กœ ์Šคํ…Œ์ดํŠธํ’€์…‹์„ ๋‹ค์‹œ 3๊ฐœ์˜ ๋ ˆํ”Œ๋ฆฌ์นด๋กœ ์Šค์ผ€์ผ๋งํ•˜์ž.

kubectl patch sts web -p '{"spec":{"replicas":3}}'
statefulset.apps/web patched

web-4์™€ web-3์ด Terminating์œผ๋กœ ์ „ํ™˜๋˜๊ธฐ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ž.

kubectl get pods -w -l app=nginx
NAME      READY     STATUS              RESTARTS   AGE
web-0     1/1       Running             0          3h
web-1     1/1       Running             0          3h
web-2     1/1       Running             0          55s
web-3     1/1       Running             0          36s
web-4     0/1       ContainerCreating   0          18s
NAME      READY     STATUS    RESTARTS   AGE
web-4     1/1       Running   0          19s
web-4     1/1       Terminating   0         24s
web-4     1/1       Terminating   0         24s
web-3     1/1       Terminating   0         42s
web-3     1/1       Terminating   0         42s

์ˆœ์ฐจ ํŒŒ๋“œ ์ข…๋ฃŒ

์ปจํŠธ๋กค๋Ÿฌ๋Š” ์ˆœ๋ฒˆ์˜ ์—ญ์ˆœ์œผ๋กœ ํ•œ ๋ฒˆ์— 1๊ฐœ ํŒŒ๋“œ๋ฅผ ์‚ญ์ œํ•˜๊ณ  ๋‹ค์Œ ํŒŒ๋“œ๋ฅผ ์‚ญ์ œํ•˜๊ธฐ ์ „์— ๊ฐ๊ฐ์ด ์™„์ „ํ•˜๊ฒŒ ์ข…๋ฃŒ๋˜๊ธฐ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.

์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจํด๋ ˆ์ž„์„ ๊ฐ€์ ธ์˜ค์ž.

kubectl get pvc -l app=nginx
NAME        STATUS    VOLUME                                     CAPACITY   ACCESSMODES   AGE
www-web-0   Bound     pvc-15c268c7-b507-11e6-932f-42010a800002   1Gi        RWO           13h
www-web-1   Bound     pvc-15c79307-b507-11e6-932f-42010a800002   1Gi        RWO           13h
www-web-2   Bound     pvc-e1125b27-b508-11e6-932f-42010a800002   1Gi        RWO           13h
www-web-3   Bound     pvc-e1176df6-b508-11e6-932f-42010a800002   1Gi        RWO           13h
www-web-4   Bound     pvc-e11bb5f8-b508-11e6-932f-42010a800002   1Gi        RWO           13h

์—ฌ์ „ํžˆ 5๊ฐœ์˜ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจํด๋ ˆ์ž„๊ณผ 5๊ฐœ์˜ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ์ด ์žˆ๋‹ค. ํŒŒ๋“œ์˜ ์•ˆ์ „ํ•œ ์Šคํ† ๋ฆฌ์ง€๋ฅผ ํƒ์ƒ‰ํ•˜๋ฉด์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๊ฐ€ ์‚ญ์ œ๋  ๋•Œ์— ํŒŒ๋“œ์— ๋งˆ์šดํŠธ๋œ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ์ด ์‚ญ์ œ๋˜์ง€ ์•Š์€ ๊ฒƒ์„ ๋ณด์•˜๋‹ค. ์Šคํ…Œ์ดํŠธํ’€์…‹ ์Šค์ผ€์ผ ๋‹ค์šด์œผ๋กœ ํŒŒ๋“œ ์‚ญ์ œํ•  ๋•Œ์—๋„ ์—ฌ์ „ํžˆ ์‚ฌ์‹ค์ด๋‹ค.

์Šคํ…Œ์ดํŠธํ’€์…‹ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค 1.7 ์ด์ƒ์—์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ์ž๋™ ์—…๋ฐ์ดํŠธ๋ฅผ ์ง€์›ํ•œ๋‹ค. ์ „๋žต์€ ์Šคํ…Œ์ดํŠธํ’€์…‹ API ์˜ค๋ธŒ์ ํŠธ์˜ spec.updateStrategy ํ•„๋“œ๋กœ ๊ฒฐ์ •๋œ๋‹ค. ์ด ๊ธฐ๋Šฅ์€ ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€, ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ๋ฆฌ์†Œ์Šค ์š”์ฒญ์ด๋‚˜ ํ˜น์€ ํ•œ๊ณ„์™€ ๋ ˆ์ด๋ธ”๊ณผ ํŒŒ๋“œ์˜ ์–ด๋…ธํ…Œ์ด์…˜์„ ์—…๊ทธ๋ ˆ์ด๋“œํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค. RollingUpdate๊ณผ OnDelete์˜ 2๊ฐœ์˜ ์œ ํšจํ•œ ์—…๋ฐ์ดํŠธ ์ „๋žต์ด ์žˆ๋‹ค.

RollingUpdate ์—…๋ฐ์ดํŠธ ์ „๋žต์€ ์Šคํ…Œ์ดํŠธํ’€์…‹์—์„œ ๊ธฐ๋ณธ ๊ฐ’์ด๋‹ค.

๋กค๋ง ์—…๋ฐ์ดํŠธ

RollingUpdate ์—…๋ฐ์ดํŠธ ์ „๋žต์€ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ๋ณด์žฅ์‚ฌํ•ญ์„ ์œ ์ง€ํ•˜๋ฉด์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹ ๋‚ด์˜ ๋ชจ๋“  ํŒŒ๋“œ๋ฅผ ์—ญ์ˆœ์œผ๋กœ ์—…๋ฐ์ดํŠธํ•œ๋‹ค.

์Šคํ…Œ์ดํŠธํ’€์…‹ web์˜ ์—…๋ฐ์ดํŠธ ์ „๋žต์„ RollingUpdate์œผ๋กœ ํŒจ์น˜ํ•˜์ž.

kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate"}}}'
statefulset.apps/web patched

ํ„ฐ๋ฏธ๋„ ์ฐฝ์—์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹ web์˜ ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€๋ฅผ ๋ฐ”๊พธ๋„๋ก ๋˜ ํŒจ์น˜ํ•˜์ž.

kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"gcr.io/google_containers/nginx-slim:0.8"}]'
statefulset.apps/web patched

๋‹ค๋ฅธ ํ„ฐ๋ฏธ๋„์ฐฝ์—์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๋ฅผ ๊ฐ์‹œํ•˜์ž.

kubectl get pod -l app=nginx -w

์ถœ๋ ฅ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๋น„์Šทํ•˜๋‹ค.

NAME      READY     STATUS    RESTARTS   AGE
web-0     1/1       Running   0          7m
web-1     1/1       Running   0          7m
web-2     1/1       Running   0          8m
web-2     1/1       Terminating   0         8m
web-2     1/1       Terminating   0         8m
web-2     0/1       Terminating   0         8m
web-2     0/1       Terminating   0         8m
web-2     0/1       Terminating   0         8m
web-2     0/1       Terminating   0         8m
web-2     0/1       Pending   0         0s
web-2     0/1       Pending   0         0s
web-2     0/1       ContainerCreating   0         0s
web-2     1/1       Running   0         19s
web-1     1/1       Terminating   0         8m
web-1     0/1       Terminating   0         8m
web-1     0/1       Terminating   0         8m
web-1     0/1       Terminating   0         8m
web-1     0/1       Pending   0         0s
web-1     0/1       Pending   0         0s
web-1     0/1       ContainerCreating   0         0s
web-1     1/1       Running   0         6s
web-0     1/1       Terminating   0         7m
web-0     1/1       Terminating   0         7m
web-0     0/1       Terminating   0         7m
web-0     0/1       Terminating   0         7m
web-0     0/1       Terminating   0         7m
web-0     0/1       Terminating   0         7m
web-0     0/1       Pending   0         0s
web-0     0/1       Pending   0         0s
web-0     0/1       ContainerCreating   0         0s
web-0     1/1       Running   0         10s

์Šคํ…Œ์ดํŠธํ’€์…‹ ๋‚ด์— ํŒŒ๋“œ๋Š” ์ˆœ๋ฒˆ์˜ ์—ญ์ˆœ์œผ๋กœ ์—…๋ฐ์ดํŠธ๋œ๋‹ค. ์ด ์Šคํ…Œ์ดํŠธํ’€์…‹ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ๊ฐ ํŒŒ๋“œ๋ฅผ ์ข…๋ฃŒ์‹œํ‚ค๊ณ  ๋‹ค์Œ ํŒŒ๋“œ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ์ „์— ๊ทธ๊ฒƒ์ด Running๊ณผ Ready ์ƒํƒœ๋กœ ์ „ํ™˜๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค. ์•Œ์•„๋‘˜ ๊ฒƒ์€ ๋น„๋ก ์Šคํ…Œ์ดํŠธํ’€์…‹ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์ด์ „ ํŒŒ๋“œ๊ฐ€ Running๊ณผ Ready ์ƒํƒœ๊ฐ€ ๋˜๊ธฐ๊นŒ์ง€ ๋‹ค์Œ ํŒŒ๋“œ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜์ง€ ์•Š์•„๋„ ํ˜„์žฌ ๋ฒ„์ „์œผ๋กœ ํŒŒ๋“œ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋‹ค ์‹คํŒจํ•˜๋ฉด ๋ณต์›ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

์—…๋ฐ์ดํŠธ๋ฅผ ์ด๋ฏธ ๋ฐ›์€ ํŒŒ๋“œ๋Š” ์—…๋ฐ์ดํŠธ๋œ ๋ฒ„์ „์œผ๋กœ ๋ณต์›๋˜๊ณ  ์•„์ง ์—…๋ฐ์ดํŠธ๋ฅผ ๋ฐ›์ง€ ๋ชปํ•œ ํŒŒ๋“œ๋Š” ์ด์ „ ๋ฒ„์ „์œผ๋กœ ๋ณต์›ํ•œ๋‹ค. ์ด๋Ÿฐ ์‹์œผ๋กœ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ๊ฐ„ํ—์ ์ธ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ด๋„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ณ„์† ๊ฑด๊ฐ•ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๊ณ  ์—…๋ฐ์ดํŠธ๋„ ์ผ๊ด€๋˜๊ฒŒ ์œ ์ง€ํ•˜๋ ค ํ•œ๋‹ค.

์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€๋ฅผ ์‚ดํŽด๋ณด๊ธฐ ์œ„ํ•ด ํŒŒ๋“œ๋ฅผ ๊ฐ€์ ธ์˜ค์ž.

for p in 0 1 2; do kubectl get pod "web-$p" --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done
registry.k8s.io/nginx-slim:0.8
registry.k8s.io/nginx-slim:0.8
registry.k8s.io/nginx-slim:0.8

์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ๋ชจ๋“  ํŒŒ๋“œ๊ฐ€ ์ง€๊ธˆ์€ ์ด์ „ ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€๋ฅผ ์‹คํ–‰ ์ค‘์ด์ด๋‹ค.

๋‹จ๊ณ„์ ์œผ๋กœ ์—…๋ฐ์ดํŠธ ํ•˜๊ธฐ

RollingUpdate ์—…๋ฐ์ดํŠธ ์ „๋žต์˜ ํŒŒ๋ผ๋ฏธํ„ฐ์ธ partition๋ฅผ ์ด์šฉํ•˜์—ฌ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ๋‹จ๊ณ„์ ์œผ๋กœ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹จ๊ณ„์  ์—…๋ฐ์ดํŠธ๋Š” ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ๋ชจ๋“  ํŒŒ๋“œ๋ฅผ ํ˜„์žฌ ๋ฒ„์ „์œผ๋กœ ์œ ์ง€ํ•˜๋ฉด์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ .spec.template์— ๋ณ€๊ฒฝ์„ ํ—ˆ์šฉํ•œ๋‹ค.

์Šคํ…Œ์ดํŠธํ’€์…‹ web์˜ updateStrategy ํ•„๋“œ์— partition์„ ์ถ”๊ฐ€ํ•˜์ž.

kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":3}}}}'
statefulset.apps/web patched

์ปจํ…Œ์ด๋„ˆ์˜ ์ด๋ฏธ์ง€๋ฅผ ๋ฐ”๊พธ๋„๋ก ์Šคํ…Œ์ดํŠธํ’€์…‹์„ ๋‹ค์‹œ ํŒจ์น˜ํ•œ๋‹ค.

kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"registry.k8s.io/nginx-slim:0.7"}]'
statefulset.apps/web patched

์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๋ฅผ ์‚ญ์ œํ•˜์ž.

kubectl delete pod web-2
pod "web-2" deleted

ํŒŒ๋“œ๊ฐ€ Running๊ณผ Ready ์ƒํƒœ๊ฐ€ ๋˜๊ธฐ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ž.

kubectl get pod -l app=nginx -w
NAME      READY     STATUS              RESTARTS   AGE
web-0     1/1       Running             0          4m
web-1     1/1       Running             0          4m
web-2     0/1       ContainerCreating   0          11s
web-2     1/1       Running   0         18s

ํŒŒ๋“œ์˜ ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€๋ฅผ ๊ฐ€์ ธ์˜ค์ž.

kubectl get pod web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
registry.k8s.io/nginx-slim:0.8

๋น„๋ก ์—…๋ฐ์ดํŠธ ์ „๋žต์ด RollingUpdate์ด์ง€๋งŒ ์Šคํ…Œ์ดํŠธํ’€์…‹์€ ํŒŒ๋“œ๋ฅผ ๊ทธ๊ฒƒ์˜ ์›๋ž˜ ์ปจํ…Œ์ด๋„ˆ๋กœ ๋ณต์›ํ•œ๋‹ค. ํŒŒ๋“œ์˜ ์ˆœ๋ฒˆ์ด updateStrategy์—์„œ ์ง€์ •๋œ ํŒŒํ‹ฐ์…˜๋ณด๋‹ค ์ž‘๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์นด๋‚˜๋ฆฌ(Canary) ๋กค๋ง ์•„์›ƒ

์œ„์—์„œ ์ง€์ •ํ•œ partition๊ฐ’์„ ์ฐจ๊ฐ์‹œํ‚ค๋ฉด ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•ด ์นด๋‚˜๋ฆฌ ๋กค์•„์›ƒ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

์Šคํ…Œ์ดํŠธํ’€์…‹์— partition์„ ์ฐจ๊ฐํ•˜๋„๋ก ํŒจ์น˜ํ•˜์ž.

kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":2}}}}'
statefulset.apps/web patched

web-2 ํŒŒ๋“œ๊ฐ€ Running๊ณผ Ready ์ƒํƒœ๊ฐ€ ๋˜๊ธฐ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ž.

kubectl get pod -l app=nginx -w
NAME      READY     STATUS              RESTARTS   AGE
web-0     1/1       Running             0          4m
web-1     1/1       Running             0          4m
web-2     0/1       ContainerCreating   0          11s
web-2     1/1       Running   0         18s

ํŒŒ๋“œ์˜ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๊ฐ€์ ธ์˜ค์ž.

kubectl get po web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
registry.k8s.io/nginx-slim:0.7

partition์„ ๋ฐ”๊พธ๋ฉด ์Šคํ…Œ์ดํŠธํ’€์…‹ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ์ž๋™์œผ๋กœ web-2 ํŒŒ๋“œ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š”๋ฐ ์ด๋Š” ํ•ด๋‹น ํŒŒ๋“œ์˜ ์ˆœ๋ฒˆ์ด partition ์ด์ƒ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

web-1 ํŒŒ๋“œ๋ฅผ ์‚ญ์ œํ•˜์ž.

kubectl delete pod web-1
pod "web-1" deleted

web-1 ํŒŒ๋“œ๊ฐ€ Running๊ณผ Ready ์ƒํƒœ๊ฐ€ ๋˜๊ธฐ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ž.

kubectl get pod -l app=nginx -w

์ถœ๋ ฅ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๋น„์Šทํ•˜๋‹ค.

NAME      READY     STATUS        RESTARTS   AGE
web-0     1/1       Running       0          6m
web-1     0/1       Terminating   0          6m
web-2     1/1       Running       0          2m
web-1     0/1       Terminating   0         6m
web-1     0/1       Terminating   0         6m
web-1     0/1       Terminating   0         6m
web-1     0/1       Pending   0         0s
web-1     0/1       Pending   0         0s
web-1     0/1       ContainerCreating   0         0s
web-1     1/1       Running   0         18s

web-1 ํŒŒ๋“œ์˜ ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€๋ฅผ ๊ฐ€์ ธ์˜ค์ž.

kubectl get pod web-1 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
registry.k8s.io/nginx-slim:0.8

web-1 ๋Š” ์›๋ž˜ ํ™˜๊ฒฝ์„ค์ •์œผ๋กœ ๋ณต์›๋˜์—ˆ๋Š”๋ฐ ์ด๋Š” ํŒŒ๋“œ์˜ ์ˆœ๋ฒˆ์ด partition๋ณด๋‹ค ์ž‘๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ .spec.template์ด ๊ฐฑ์‹ ๋˜๋ฉด, ์ง€์ •๋œ partition ์ด์ƒ์˜ ์ˆœ๋ฒˆ์„ ๊ฐ€์ง„ ๋ชจ๋“  ํŒŒ๋“œ๋Š” ์—…๋ฐ์ดํŠธ๋œ๋‹ค. ๋ฏธ๋งŒ์˜ ์ˆœ๋ฒˆ์„ ๊ฐ€์ง„ ํŒŒ๋“œ๋ผ๋ฉด ์‚ญ์ œ๋˜๊ฑฐ๋‚˜ ์ข…๋ฃŒ๋˜์–ด ์›๋ž˜ ํ™˜๊ฒฝ์„ค์ •์œผ๋กœ ๋ณต์›๋œ๋‹ค.

๋‹จ๊ณ„์  ๋กค์•„์›ƒ

์นด๋‚˜๋ฆฌ ๋กค์•„์›ƒ์—์„œ ํ–ˆ๋˜ ๋ฐฉ๋ฒ•๊ณผ ๋น„์Šทํ•˜๊ฒŒ ๋ถ„ํ• ๋œ ๋กค๋ง ์—…๋ฐ์ดํŠธ๋ฅผ ์ด์šฉํ•˜์—ฌ ๋‹จ๊ณ„์  ๋กค์•„์›ƒ(e.g. ์„ ํ˜•, ๊ธฐํ•˜ ๋˜๋Š” ์ง€์ˆ˜์  ๋กค์•„์›ƒ)์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹จ๊ณ„์  ๋กค์•„์›ƒ์„ ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์—…๋ฐ์ดํŠธ๋ฅผ ์ผ์‹œ ์ค‘์ง€ํ•  ์ˆœ๋ฒˆ์œผ๋กœ partition๋ฅผ ์ •ํ•˜์ž.

partition์€ ํ˜„์žฌ 2์ด๋‹ค. partition์„ 0์œผ๋กœ ๋ฐ”๊พธ์ž.

kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":0}}}}'
statefulset.apps/web patched

์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ๋ชจ๋“  ํŒŒ๋“œ๊ฐ€ Running๊ณผ Ready ์ƒํƒœ๊ฐ€ ๋˜๊ธฐ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ž.

kubectl get pod -l app=nginx -w

์ถœ๋ ฅ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๋น„์Šทํ•˜๋‹ค.

NAME      READY     STATUS              RESTARTS   AGE
web-0     1/1       Running             0          3m
web-1     0/1       ContainerCreating   0          11s
web-2     1/1       Running             0          2m
web-1     1/1       Running   0         18s
web-0     1/1       Terminating   0         3m
web-0     1/1       Terminating   0         3m
web-0     0/1       Terminating   0         3m
web-0     0/1       Terminating   0         3m
web-0     0/1       Terminating   0         3m
web-0     0/1       Terminating   0         3m
web-0     0/1       Pending   0         0s
web-0     0/1       Pending   0         0s
web-0     0/1       ContainerCreating   0         0s
web-0     1/1       Running   0         3s

์Šคํ…Œ์ดํŠธํ’€์…‹์— ์žˆ๋Š” ํŒŒ๋“œ์˜ ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€ ์ƒ์„ธ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค์ž.

for p in 0 1 2; do kubectl get pod "web-$p" --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done
registry.k8s.io/nginx-slim:0.7
registry.k8s.io/nginx-slim:0.7
registry.k8s.io/nginx-slim:0.7

partition์„ 0์œผ๋กœ ์ด๋™ํ•˜์—ฌ ์Šคํ…Œ์ดํŠธํ’€์…‹์—์„œ ๊ณ„์†ํ•ด์„œ ์—…๋ฐ์ดํŠธ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋„๋ก ํ—ˆ์šฉํ•˜์˜€๋‹ค.

์‚ญ์ œ ์‹œ ๋™์ž‘

OnDelete ์—…๋ฐ์ดํŠธ ์ „๋žต์€ ์˜ˆ์ „ ๋™์ž‘(1.6 ์ดํ•˜)์œผ๋กœ, ์ด ์—…๋ฐ์ดํŠธ ์ „๋žต์„ ์„ ํƒํ•˜๋ฉด, ์Šคํ…Œ์ดํŠธํ’€์…‹ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ .spec.template ํ•„๋“œ์— ์ˆ˜์ • ์‚ฌํ•ญ์ด ๋ฐœ์ƒํ•ด๋„ ์ž๋™์œผ๋กœ ํŒŒ๋“œ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ด ์ „๋žต์€ .spec.template.updateStrategy.type์„ OnDelete๋กœ ์„ค์ •ํ•˜์—ฌ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค.

์Šคํ…Œ์ดํŠธํ’€์…‹ ์‚ญ์ œํ•˜๊ธฐ

์Šคํ…Œ์ดํŠธํ’€์…‹์€ ๋น„์ข…์†์ (non-cascading), ์ข…์†์ (cascading) ์‚ญ์ œ๋ฅผ ๋‘˜ ๋‹ค ์ง€์›ํ•œ๋‹ค. ๋น„์ข…์†์  ์‚ญ์ œ์—์„œ๋Š” ์Šคํ…Œ์ดํŠธํ’€์…‹์ด ์ง€์›Œ์งˆ ๋•Œ์— ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๋Š” ์ง€์›Œ์ง€์ง€ ์•Š๋Š”๋‹ค. ์ข…์†์  ์‚ญ์ œ์—์„œ๋Š” ์Šคํ…Œ์ดํŠธํ’€์…‹๊ณผ ๊ทธ์— ์†ํ•œ ํŒŒ๋“œ๊ฐ€ ๋ชจ๋‘ ์ง€์›Œ์ง„๋‹ค.

๋น„์ข…์†์  ์‚ญ์ œ

ํ„ฐ๋ฏธ๋„์ฐฝ์—์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๋ฅผ ๊ฐ์‹œํ•˜์ž.

kubectl get pods -w -l app=nginx

๋‹ค๋ฅธ ํ„ฐ๋ฏธ๋„์—์„œ๋Š” ์Šคํ…Œ์ดํŠธํ’€์…‹์„ ์ง€์šฐ๊ธฐ ์œ„ํ•ด kubectl delete ๋ช…๋ น์–ด๋ฅผ ์ด์šฉํ•˜์ž. ์ด ๋ช…๋ น์–ด์— --cascade=orphan ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ๋‹ค. ์ด ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์— ์Šคํ…Œ์ดํŠธํ’€์…‹๋งŒ ์‚ญ์ œํ•˜๊ณ  ๊ทธ์— ์†ํ•œ ํŒŒ๋“œ๋Š” ์ง€์šฐ์ง€ ์•Š๋„๋ก ์š”์ฒญํ•œ๋‹ค.

kubectl delete statefulset web --cascade=orphan
statefulset.apps "web" deleted

์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ํŒŒ๋“œ๋ฅผ ๊ฐ€์ ธ์˜ค์ž.

kubectl get pods -l app=nginx
NAME      READY     STATUS    RESTARTS   AGE
web-0     1/1       Running   0          6m
web-1     1/1       Running   0          7m
web-2     1/1       Running   0          5m

๋น„๋ก web์ด ์‚ญ์ œ๋˜๊ณ  ์žˆ์–ด๋„, ๋ชจ๋“  ํŒŒ๋“œ๋Š” ์—ฌ์ „ํžˆ Running๊ณผ Ready ์ƒํƒœ์ด๋‹ค. web-0์„ ์‚ญ์ œํ•˜์ž.

kubectl delete pod web-0
pod "web-0" deleted

์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๋ฅผ ๊ฐ€์ ธ์˜ค์ž.

kubectl get pods -l app=nginx
NAME      READY     STATUS    RESTARTS   AGE
web-1     1/1       Running   0          10m
web-2     1/1       Running   0          7m

์Šคํ…Œ์ดํŠธํ’€์…‹ web์ด ์‚ญ์ œ๋˜๋Š” ๋™์•ˆ web-0์€ ์žฌ์‹œ์ž‘ํ•˜์ง€ ์•Š์•˜๋‹ค.

์ฒซ์งธ ํ„ฐ๋ฏธ๋„์—์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๋ฅผ ๊ฐ์‹œํ•˜์ž.

kubectl get pods -w -l app=nginx

๋‘ ๋ฒˆ์งธ ํ„ฐ๋ฏธ๋„์—์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹์„ ๋‹ค์‹œ ์ƒ์„ฑํ•˜์ž. nginx ์„œ๋น„์Šค(๊ฐ€์ง€์ง€ ๋ง์•˜์–ด์•ผ ํ•˜๋Š”)๋ฅผ ์‚ญ์ œํ•˜๊ธฐ ์ „๊นŒ์ง€๋Š” ๊ทธ ์„œ๋น„์Šค๊ฐ€ ์ด๋ฏธ ์กด์žฌํ•œ๋‹ค๋Š” ์—๋Ÿฌ๋ฅผ ๋ณผ ๊ฒƒ์ด๋ผ๋Š” ๊ฒƒ์„ ๋ช…์‹ฌํ•˜์ž.

kubectl apply -f web.yaml
statefulset.apps/web created
service/nginx unchanged

์ด ์—๋Ÿฌ๋Š” ๋ฌด์‹œํ•˜์ž. ์ด๊ฒƒ์€ ๋‹ค๋งŒ ํ•ด๋‹น ์„œ๋น„์Šค๊ฐ€ ์žˆ๋”๋ผ๋„ nginx ํ—ค๋“œ๋ฆฌ์Šค ์„œ๋น„์Šค๋ฅผ ์ƒ์„ฑํ•˜๋ ค๊ณ  ํ–ˆ์Œ์„ ๋œปํ•œ๋‹ค.

์ฒซ์งธ ํ„ฐ๋ฏธ๋„์—์„œ ์‹คํ–‰ ์ค‘์ธ kubectl get ๋ช…๋ น์–ด์˜ ์ถœ๋ ฅ์„ ์‚ดํŽด๋ณด์ž.

kubectl get pods -w -l app=nginx
NAME      READY     STATUS    RESTARTS   AGE
web-1     1/1       Running   0          16m
web-2     1/1       Running   0          2m
NAME      READY     STATUS    RESTARTS   AGE
web-0     0/1       Pending   0          0s
web-0     0/1       Pending   0         0s
web-0     0/1       ContainerCreating   0         0s
web-0     1/1       Running   0         18s
web-2     1/1       Terminating   0         3m
web-2     0/1       Terminating   0         3m
web-2     0/1       Terminating   0         3m
web-2     0/1       Terminating   0         3m

web ์Šคํ…Œ์ดํŠธํ’€์…‹์ด ๋‹ค์‹œ ์ƒ์„ฑ๋  ๋•Œ ๋จผ์ € web-0 ์‹œ์ž‘ํ•œ๋‹ค. web-1์€ ์ด๋ฏธ Running๊ณผ Ready ์ƒํƒœ์ด๋ฏ€๋กœ web-0์ด Running๊ณผ Ready ์ƒํƒœ๋กœ ์ „ํ™˜๋  ๋•Œ๋Š” ์ด ํŒŒ๋“œ์— ์ ์šฉ๋๋‹ค. ์Šคํ…Œ์ดํŠธํ’€์…‹์— replicas๋ฅผ 2๋กœ ํ•˜๊ณ  web-0์„ ์žฌ์ƒ์„ฑํ–ˆ๋‹ค๋ฉด web-1์ด ์ด๋ฏธ Running๊ณผ Ready ์ƒํƒœ์ด๊ณ , web-2์€ ์ข…๋ฃŒ๋˜์—ˆ์„ ๊ฒƒ์ด๋‹ค.

ํŒŒ๋“œ์˜ ์›น์„œ๋ฒ„์—์„œ ์ œ๊ณตํ•œ index.html ํŒŒ์ผ ๋‚ด์šฉ์„ ๋‹ค๋ฅธ ๊ด€์ ์œผ๋กœ ์‚ดํŽด๋ณด์ž.

for i in 0 1; do kubectl exec -i -t "web-$i" -- curl http://localhost/; done
web-0
web-1

์Šคํ…Œ์ดํŠธํ’€์…‹๊ณผ web-0 ํŒŒ๋“œ๋ฅผ ๋‘˜ ๋‹ค ์‚ญ์ œํ–ˆ์œผ๋‚˜ ์—ฌ์ „ํžˆ index.html ํŒŒ์ผ์— ์ž…๋ ฅํ–ˆ๋˜ ์›๋ž˜ ํ˜ธ์ŠคํŠธ๋„ค์ž„์„ ์ œ๊ณตํ•œ๋‹ค. ์Šคํ…Œ์ดํŠธํ’€์…‹์€ ํŒŒ๋“œ์— ํ• ๋‹น๋œ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ์„ ๊ฒฐ์ฝ” ์‚ญ์ œํ•˜์ง€ ์•Š๊ธฐ๋•Œ๋ฌธ์ด๋‹ค. ๋‹ค์‹œ ์Šคํ…Œ์ดํŠธํ’€์…‹์„ ์ƒ์„ฑํ•˜๋ฉด web-0์„ ์‹œ์ž‘ํ•˜๋ฉฐ ์›๋ž˜ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ์„ ๋‹ค์‹œ ๋งˆ์šดํŠธํ•œ๋‹ค.

๋‹จ๊ณ„์‹ ์‚ญ์ œ

ํ„ฐ๋ฏธ๋„์ฐฝ์—์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๋ฅผ ๊ฐ์‹œํ•˜์ž.

kubectl get pods -w -l app=nginx

๋‹ค๋ฅธ ํ„ฐ๋ฏธ๋„์ฐฝ์—์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹์„ ๋‹ค์‹œ ์ง€์šฐ์ž. ์ด๋ฒˆ์—๋Š” --cascade=orphan ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ƒ๋žตํ•˜์ž.

kubectl delete statefulset web
statefulset.apps "web" deleted

์ฒซ์งธ ํ„ฐ๋ฏธ๋„์—์„œ ์‹คํ–‰ ์ค‘์ธ kubectl get ๋ช…๋ น์–ด์˜ ์ถœ๋ ฅ์„ ์‚ดํŽด๋ณด๊ณ  ๋ชจ๋“  ํŒŒ๋“œ๊ฐ€ Terminating ์ƒํƒœ๋กœ ์ „ํ™˜๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ž.

kubectl get pods -w -l app=nginx
NAME      READY     STATUS    RESTARTS   AGE
web-0     1/1       Running   0          11m
web-1     1/1       Running   0          27m
NAME      READY     STATUS        RESTARTS   AGE
web-0     1/1       Terminating   0          12m
web-1     1/1       Terminating   0         29m
web-0     0/1       Terminating   0         12m
web-0     0/1       Terminating   0         12m
web-0     0/1       Terminating   0         12m
web-1     0/1       Terminating   0         29m
web-1     0/1       Terminating   0         29m
web-1     0/1       Terminating   0         29m

์Šค์ผ€์ผ ๋‹ค์šด ์„น์…˜์—์„œ ๋ณด์•˜๋“ฏ ํŒŒ๋“œ๋Š” ๊ฐ ์ˆœ๋ฒˆ์˜ ์—ญ์ˆœ์œผ๋กœ ํ•˜๋‚˜์”ฉ ์ข…๋ฃŒ๋œ๋‹ค. ํŒŒ๋“œ๊ฐ€ ์ข…๋ฃŒ๋  ๋•Œ ์Šคํ…Œ์ดํŠธํ’€ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ์ด์ „ ํŒŒ๋“œ๊ฐ€ ์™„์ „ํžˆ ์ข…๋ฃŒ๋˜๊ธฐ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.

kubectl delete service nginx
service "nginx" deleted

์Šคํ…Œ์ดํŠธํ’€์…‹๊ณผ ํ—ค๋“œ๋ฆฌ์Šค ์„œ๋น„์Šค๋ฅผ ํ•œ๋ฒˆ ๋” ๋‹ค์‹œ ์ƒ์„ฑํ•˜์ž.

kubectl apply -f web.yaml
service/nginx created
statefulset.apps/web created

์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ๋ชจ๋“  ํŒŒ๋“œ๊ฐ€ Running๊ณผ Ready ์ƒํƒœ๋กœ ์ „ํ™˜๋  ๋•Œ index.html ํŒŒ์ผ ๋‚ด์šฉ์„ ๊ฒ€์ƒ‰ํ•˜์ž.

for i in 0 1; do kubectl exec -i -t "web-$i" -- curl http://localhost/; done
web-0
web-1

์Šคํ…Œ์ดํŠธํ’€์…‹๊ณผ ๊ทธ ๋‚ด๋ถ€์˜ ๋ชจ๋“  ํŒŒ๋“œ๋ฅผ ์‚ญ์ œํ–ˆ์ง€๋งŒ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ์ด ๋งˆ์šดํŠธ๋œ ์ฑ„๋กœ ๋‹ค์‹œ ์ƒ์„ฑ๋˜๊ณ  web-0๊ณผ web-1์€ ๊ณ„์† ๊ฐ ํ˜ธ์ŠคํŠธ๋„ค์ž„์„ ์ œ๊ณตํ•œ๋‹ค.

์ตœ์ข…์ ์œผ๋กœ nginx ์„œ๋น„์Šค๋ฅผ ์‚ญ์ œํ•œ๋‹ค.

kubectl delete service nginx
service "nginx" deleted

๊ทธ๋ฆฌ๊ณ  web ์Šคํ…Œ์ดํŠธํ’€์…‹์„ ์‚ญ์ œํ•œ๋‹ค.

kubectl delete statefulset web
statefulset "web" deleted

ํŒŒ๋“œ ๊ด€๋ฆฌ ์ •์ฑ…

์ผ๋ถ€ ๋ถ„์‚ฐ ์‹œ์Šคํ…œ์˜ ๊ฒฝ์šฐ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ์ˆœ์„œ ๋ณด์ฆ์€ ๋ถˆํ•„์š”ํ•˜๊ฑฐ๋‚˜ ๋ฐ”๋žŒ์งํ•˜์ง€ ์•Š๋‹ค. ์ด๋Ÿฌํ•œ ์‹œ์Šคํ…œ์€ ๊ณ ์œ ์„ฑ๊ณผ ์‹ ์›๋งŒ ํ•„์š”ํ•˜๋‹ค. ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค 1.7์—์„œ .spec.podManagementPolicy๋ฅผ ์Šคํ…Œ์ดํŠธํ’€์…‹ API ์˜ค๋ธŒ์ ํŠธ์— ๋„์ž…ํ–ˆ๋‹ค.

OrderedReady ํŒŒ๋“œ ๊ด€๋ฆฌ

OrderedReady ํŒŒ๋“œ ๊ด€๋ฆฌ๋Š” ์Šคํ…Œ์ดํŠธํ’€์…‹์—์„œ๋Š” ๊ธฐ๋ณธ์ด๋‹ค. ์ด๋Š” ์Šคํ…Œ์ดํŠธํ’€์…‹ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์ง€๊ธˆ๊นŒ์ง€ ์œ„์—์„œ ์„ค๋ช…ํ–ˆ๋˜ ์ˆœ์„œ๋ฅผ ๋ณด์ฆํ•จ์„ ๋œปํ•œ๋‹ค.

Parallel ํŒŒ๋“œ ๊ด€๋ฆฌ

Parallel ํŒŒ๋“œ ๊ด€๋ฆฌ๋Š” ์Šคํ…Œ์ดํŠธํ’€์…‹ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ๋ชจ๋“  ํŒŒ๋“œ๋ฅผ ๋ณ‘๋ ฌ๋กœ ์‹œ์ž‘ํ•˜๊ณ  ์ข…๋ฃŒํ•˜๋Š” ๊ฒƒ์œผ๋กœ, ๋‹ค๋ฅธ ํŒŒ๋“œ๋ฅผ ์‹œ์ž‘/์ข…๋ฃŒํ•˜๊ธฐ ์ „์— ํŒŒ๋“œ๊ฐ€ Running๊ณผ Ready ์ƒํƒœ๋กœ ์ „ํ™˜๋˜๊ฑฐ๋‚˜ ์™„์ „ํžˆ ์ข…๋ฃŒ๋˜๊ธฐ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š์Œ์„ ๋œปํ•œ๋‹ค. ์ด ์˜ต์…˜์€ ์Šค์ผ€์ผ๋ง ๋™์ž‘์—๋งŒ ์˜ํ–ฅ์„ ๋ฏธ์น˜๋ฉฐ, ์—…๋ฐ์ดํŠธ ๋™์ž‘์—๋Š” ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š๋Š”๋‹ค.

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx"
  podManagementPolicy: "Parallel"
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: registry.k8s.io/nginx-slim:0.8
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi

์ƒ๊ธฐ ์˜ˆ์ œ๋ฅผ ๋‹ค์šด๋กœ๋“œ๋ฐ›์•„ ํŒŒ์ผ ์ด๋ฆ„์„ web-parallel.yaml๋กœ ์ €์žฅํ•˜์ž.

์ด ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋Š” web ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ .spec.podManagementPolicy์ด Parallel์ธ ๊ฒƒ ๋ง๊ณ ๋Š” ์ด์ „์— ๋‹ค์šด๋กœ๋“œ ๋ฐ›์•˜๋˜ ๊ฒƒ๊ณผ ๋™์ผํ•˜๋‹ค.

ํ„ฐ๋ฏธ๋„์—์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๋ฅผ ๊ฐ์‹œํ•˜์ž.

kubectl get pod -l app=nginx -w

๋‹ค๋ฅธ ํ„ฐ๋ฏธ๋„์—์„œ ๋งค๋‹ˆํŽ˜์ŠคํŠธ ์•ˆ์— ์Šคํ…Œ์ดํŠธํ’€์…‹๊ณผ ์„œ๋น„์Šค๋ฅผ ์ƒ์„ฑํ•˜์ž.

kubectl apply -f web-parallel.yaml
service/nginx created
statefulset.apps/web created

์ฒซ์งธ ํ„ฐ๋ฏธ๋„์—์„œ ์‹คํ–‰ํ–ˆ๋˜ kubectl get ๋ช…๋ น์–ด์˜ ์ถœ๋ ฅ์„ ์‚ดํŽด๋ณด์ž.

kubectl get pod -l app=nginx -w
NAME      READY     STATUS    RESTARTS   AGE
web-0     0/1       Pending   0          0s
web-0     0/1       Pending   0         0s
web-1     0/1       Pending   0         0s
web-1     0/1       Pending   0         0s
web-0     0/1       ContainerCreating   0         0s
web-1     0/1       ContainerCreating   0         0s
web-0     1/1       Running   0         10s
web-1     1/1       Running   0         10s

์Šคํ…Œ์ดํŠธํ’€์…‹ ์ปจํŠธ๋กค๋Ÿฌ๋Š” web-0์™€ web-1๋ฅผ ๋‘˜ ๋‹ค ๋™์‹œ์— ์‹œ์ž‘ํ–ˆ๋‹ค.

๋‘ ๋ฒˆ์งธ ํ„ฐ๋ฏธ๋„์„ ์—ด์–ด ๋†“๊ณ  ๋‹ค๋ฅธ ํ„ฐ๋ฏธ๋„์ฐฝ์—์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹์„ ์Šค์ผ€์ผ๋งํ•˜์ž.

kubectl scale statefulset/web --replicas=4
statefulset.apps/web scaled

kubectl get ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ ์ค‘์ธ ํ„ฐ๋ฏธ๋„์˜ ์ถœ๋ ฅ์„ ์‚ดํŽด๋ณด์ž.

web-3     0/1       Pending   0         0s
web-3     0/1       Pending   0         0s
web-3     0/1       Pending   0         7s
web-3     0/1       ContainerCreating   0         7s
web-2     1/1       Running   0         10s
web-3     1/1       Running   0         26s

์Šคํ…Œ์ดํŠธํ’€์…‹์€ ๋‘ ๊ฐœ์˜ ์ƒˆ ํŒŒ๋“œ๋ฅผ ์‹œ์ž‘ํ•˜์˜€๋‹ค. ๋‘ ๋ฒˆ์งธ ๊ฒƒ์„ ๋Ÿฐ์นญํ•˜๊ธฐ ์œ„ํ•ด ๋จผ์ € ๋Ÿฐ์นญํ•œ ๊ฒƒ์ด Running๊ณผ Ready ์ƒํƒœ๊ฐ€ ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.

์ •๋ฆฌํ•˜๊ธฐ

์ •๋ฆฌ์˜ ์ผํ™˜์œผ๋กœ kubectl ๋ช…๋ น์„ ์‹คํ–‰ํ•  ์ค€๋น„๊ฐ€ ๋œ ๋‘ ๊ฐœ์˜ ํ„ฐ๋ฏธ๋„์ด ์—ด๋ ค ์žˆ์–ด์•ผ ํ•œ๋‹ค.

kubectl delete sts web
# sts๋Š” statefulset์˜ ์•ฝ์ž์ด๋‹ค.

kubectl get ๋ช…๋ น์œผ๋กœ ํ•ด๋‹น ํŒŒ๋“œ๊ฐ€ ์‚ญ์ œ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl get pod -l app=nginx -w
web-3     1/1       Terminating   0         9m
web-2     1/1       Terminating   0         9m
web-3     1/1       Terminating   0         9m
web-2     1/1       Terminating   0         9m
web-1     1/1       Terminating   0         44m
web-0     1/1       Terminating   0         44m
web-0     0/1       Terminating   0         44m
web-3     0/1       Terminating   0         9m
web-2     0/1       Terminating   0         9m
web-1     0/1       Terminating   0         44m
web-0     0/1       Terminating   0         44m
web-2     0/1       Terminating   0         9m
web-2     0/1       Terminating   0         9m
web-2     0/1       Terminating   0         9m
web-1     0/1       Terminating   0         44m
web-1     0/1       Terminating   0         44m
web-1     0/1       Terminating   0         44m
web-0     0/1       Terminating   0         44m
web-0     0/1       Terminating   0         44m
web-0     0/1       Terminating   0         44m
web-3     0/1       Terminating   0         9m
web-3     0/1       Terminating   0         9m
web-3     0/1       Terminating   0         9m

์‚ญ์ œํ•˜๋Š” ๋™์•ˆ, ์Šคํ…Œ์ดํŠธํ’€์…‹์€ ๋ชจ๋“  ํŒŒ๋“œ๋ฅผ ๋™์‹œ์— ์‚ญ์ œํ•œ๋‹ค. ํ•ด๋‹น ํŒŒ๋“œ๋ฅผ ์‚ญ์ œํ•˜๊ธฐ ์ „์— ๊ทธ ํŒŒ๋“œ์˜ ์ˆœ์„œ์ƒ ํ›„๊ณ„์ž๋ฅผ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.

kubectl get ๋ช…๋ น์–ด๊ฐ€ ์‹คํ–‰๋œ ํ„ฐ๋ฏธ๋„์„ ๋‹ซ๊ณ  nginx ์„œ๋น„์Šค๋ฅผ ์‚ญ์ œํ•˜์ž.

kubectl delete svc nginx

์ด ํŠœํ† ๋ฆฌ์–ผ์—์„œ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ์œผ๋กœ ์‚ฌ์šฉํ–ˆ๋˜ ์˜๊ตฌ ์Šคํ† ๋ฆฌ์ง€๋ฅผ ์‚ญ์ œํ•œ๋‹ค.

kubectl get pvc
NAME        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
www-web-0   Bound    pvc-2bf00408-d366-4a12-bad0-1869c65d0bee   1Gi        RWO            standard       25m
www-web-1   Bound    pvc-ba3bfe9c-413e-4b95-a2c0-3ea8a54dbab4   1Gi        RWO            standard       24m
www-web-2   Bound    pvc-cba6cfa6-3a47-486b-a138-db5930207eaf   1Gi        RWO            standard       15m
www-web-3   Bound    pvc-0c04d7f0-787a-4977-8da3-d9d3a6d8d752   1Gi        RWO            standard       15m
www-web-4   Bound    pvc-b2c73489-e70b-4a4e-9ec1-9eab439aa43e   1Gi        RWO            standard       14m
kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS   REASON   AGE
pvc-0c04d7f0-787a-4977-8da3-d9d3a6d8d752   1Gi        RWO            Delete           Bound    default/www-web-3   standard                15m
pvc-2bf00408-d366-4a12-bad0-1869c65d0bee   1Gi        RWO            Delete           Bound    default/www-web-0   standard                25m
pvc-b2c73489-e70b-4a4e-9ec1-9eab439aa43e   1Gi        RWO            Delete           Bound    default/www-web-4   standard                14m
pvc-ba3bfe9c-413e-4b95-a2c0-3ea8a54dbab4   1Gi        RWO            Delete           Bound    default/www-web-1   standard                24m
pvc-cba6cfa6-3a47-486b-a138-db5930207eaf   1Gi        RWO            Delete           Bound    default/www-web-2   standard                15m
kubectl delete pvc www-web-0 www-web-1 www-web-2 www-web-3 www-web-4
persistentvolumeclaim "www-web-0" deleted
persistentvolumeclaim "www-web-1" deleted
persistentvolumeclaim "www-web-2" deleted
persistentvolumeclaim "www-web-3" deleted
persistentvolumeclaim "www-web-4" deleted
kubectl get pvc
No resources found in default namespace.

6.2 - ์˜ˆ์‹œ: WordPress์™€ MySQL์„ ํผ์‹œ์Šคํ„ดํŠธ ๋ณผ๋ฅจ์— ๋ฐฐํฌํ•˜๊ธฐ

์ด ํŠœํ† ๋ฆฌ์–ผ์€ WordPress ์‚ฌ์ดํŠธ์™€ MySQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ Minikube๋ฅผ ์ด์šฉํ•˜์—ฌ ์–ด๋–ป๊ฒŒ ๋ฐฐํฌํ•˜๋Š”์ง€ ๋ณด์—ฌ์ค€๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‘˜ ๋‹ค ํผ์‹œ์Šคํ„ดํŠธ ๋ณผ๋ฅจ๊ณผ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจํด๋ ˆ์ž„์„ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.

ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ(PV)๋Š” ๊ด€๋ฆฌ์ž๊ฐ€ ์ˆ˜๋™์œผ๋กœ ํ”„๋กœ๋น„์ €๋‹ํ•œ ํด๋Ÿฌ์Šคํ„ฐ๋‚˜ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์Šคํ† ๋ฆฌ์ง€ํด๋ž˜์Šค๋ฅผ ์ด์šฉํ•ด ๋™์ ์œผ๋กœ ํ”„๋กœ๋น„์ €๋‹๋œ ์ €์žฅ์†Œ์˜ ์ผ๋ถ€์ด๋‹ค. ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจํด๋ ˆ์ž„(PVC)์€ PV๋กœ ์ถฉ์กฑํ•  ์ˆ˜ ์žˆ๋Š” ์‚ฌ์šฉ์ž์— ์˜ํ•œ ์Šคํ† ๋ฆฌ์ง€ ์š”์ฒญ์ด๋‹ค. ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ์€ ํŒŒ๋“œ ๋ผ์ดํ”„์‚ฌ์ดํด๊ณผ ๋…๋ฆฝ์ ์ด๋ฉฐ ์žฌ์‹œ์ž‘, ์žฌ์Šค์ผ€์ค„๋ง์ด๋‚˜ ํŒŒ๋“œ๋ฅผ ์‚ญ์ œํ•  ๋•Œ์—๋„ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์กดํ•œ๋‹ค.

๋ชฉ์ 

  • ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจํด๋ ˆ์ž„๊ณผ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ ์ƒ์„ฑ
  • ๋‹ค์Œ์„ ํฌํ•จํ•˜๋Š” kustomization.yaml ์ƒ์„ฑ
    • ์‹œํฌ๋ฆฟ ์ƒ์„ฑ์ž
    • MySQL ๋ฆฌ์†Œ์Šค ๊ตฌ์„ฑ
    • WordPress ๋ฆฌ์†Œ์Šค ๊ตฌ์„ฑ
  • kubectl apply -k ./๋กœ ์ƒ์„ฑํ•œ kustomization ์„ ์ ์šฉ
  • ์ •๋ฆฌ

์‹œ์ž‘ํ•˜๊ธฐ ์ „์—

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ๊ฐ€ ํ•„์š”ํ•˜๊ณ , kubectl ์ปค๋งจ๋“œ-๋ผ์ธ ํˆด์ด ํด๋Ÿฌ์Šคํ„ฐ์™€ ํ†ต์‹ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •๋˜์–ด ์žˆ์–ด์•ผ ํ•œ๋‹ค. ์ด ํŠœํ† ๋ฆฌ์–ผ์€ ์ปจํŠธ๋กค ํ”Œ๋ ˆ์ธ ํ˜ธ์ŠคํŠธ๊ฐ€ ์•„๋‹Œ ๋…ธ๋“œ๊ฐ€ ์ ์–ด๋„ 2๊ฐœ ํฌํ•จ๋œ ํด๋Ÿฌ์Šคํ„ฐ์—์„œ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค. ๋งŒ์•ฝ, ์•„์ง ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š๋‹ค๋ฉด, minikube๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ๋‹ค์Œ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํ”Œ๋ ˆ์ด๊ทธ๋ผ์šด๋“œ ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฒ„์ „ ํ™•์ธ์„ ์œ„ํ•ด์„œ, ๋‹ค์Œ ์ปค๋งจ๋“œ๋ฅผ ์‹คํ–‰ kubectl version.

์ด ์˜ˆ์‹œ๋Š” kubectl 1.14 ์ด์ƒ ๋ฒ„์ „์—์„œ ๋™์ž‘ํ•œ๋‹ค.

๋‹ค์Œ ์„ค์ • ํŒŒ์ผ์„ ๋‹ค์šด๋กœ๋“œํ•œ๋‹ค.

  1. mysql-deployment.yaml

  2. wordpress-deployment.yaml

ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจํด๋ ˆ์ž„๊ณผ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ ์ƒ์„ฑ

MySQL๊ณผ Wordpress๋Š” ๊ฐ๊ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ์ด ํ•„์š”ํ•˜๋‹ค. ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจํด๋ ˆ์ž„์€ ๋ฐฐํฌ ๋‹จ๊ณ„์— ์ƒ์„ฑ๋œ๋‹ค.

๋งŽ์€ ํด๋Ÿฌ์Šคํ„ฐ ํ™˜๊ฒฝ์—์„œ ์„ค์น˜๋œ ๊ธฐ๋ณธ ์Šคํ† ๋ฆฌ์ง€ํด๋ž˜์Šค(StorageClass)๊ฐ€ ์žˆ๋‹ค. ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจํด๋ ˆ์ž„์— ์Šคํ† ๋ฆฌ์ง€ํด๋ž˜์Šค๋ฅผ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด ํด๋Ÿฌ์Šคํ„ฐ์˜ ๊ธฐ๋ณธ ์Šคํ† ๋ฆฌ์ง€ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจํด๋ ˆ์ž„์ด ์ƒ์„ฑ๋˜๋ฉด ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ์ด ์Šคํ† ๋ฆฌ์ง€ํด๋ž˜์Šค ์„ค์ •์„ ๊ธฐ์ดˆ๋กœ ๋™์ ์œผ๋กœ ํ”„๋กœ๋น„์ €๋‹๋œ๋‹ค.

kustomization.yaml ์ƒ์„ฑํ•˜๊ธฐ

์‹œํฌ๋ฆฟ ์ƒ์„ฑ์ž ์ถ”๊ฐ€

์‹œํฌ๋ฆฟ์€ ์•”ํ˜ธ๋‚˜ ํ‚ค ๊ฐ™์€ ๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ๋“ค์„ ์ €์žฅํ•˜๋Š” ์˜ค๋ธŒ์ ํŠธ์ด๋‹ค. 1.14 ๋ฒ„์ „๋ถ€ํ„ฐ kubectl์€ kustomization ํŒŒ์ผ์„ ์ด์šฉํ•ด์„œ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค. kustomization.yaml์˜ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋กœ ์‹œํฌ๋ฆฟ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‹ค์Œ ๋ช…๋ น์–ด๋กœ kustomization.yaml ๋‚ด์— ์‹œํฌ๋ฆฟ ์ œ๋„ค๋ ˆ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค. YOUR_PASSWORD๋Š” ์‚ฌ์šฉํ•˜๊ธฐ ์›ํ•˜๋Š” ์•”ํ˜ธ๋กœ ๋ณ€๊ฒฝํ•ด์•ผ ํ•œ๋‹ค.

cat <<EOF >./kustomization.yaml
secretGenerator:
- name: mysql-pass
  literals:
  - password=YOUR_PASSWORD
EOF

MySQL๊ณผ WordPress์— ํ•„์š”ํ•œ ๋ฆฌ์†Œ์Šค ๊ตฌ์„ฑ ์ถ”๊ฐ€ํ•˜๊ธฐ

๋‹ค์Œ ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋Š” MySQL ๋””ํ”Œ๋กœ์ด๋จผํŠธ ๋‹จ์ผ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ธฐ์ˆ ํ•œ๋‹ค. MySQL ์ปจ์ผ€์ด๋„ˆ๋Š” ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ์„ /var/lib/mysql์— ๋งˆ์šดํŠธํ•œ๋‹ค. MYSQL_ROOT_PASSWORD ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋Š” ์‹œํฌ๋ฆฟ์—์„œ ๊ฐ€์ ธ์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์•”ํ˜ธ๋กœ ์„ค์ •ํ•œ๋‹ค.

apiVersion: v1
kind: Service
metadata:
  name: wordpress-mysql
  labels:
    app: wordpress
spec:
  ports:
    - port: 3306
  selector:
    app: wordpress
    tier: mysql
  clusterIP: None
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress-mysql
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: mysql
    spec:
      containers:
      - image: mysql:8.0
        name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-pass
              key: password
        - name: MYSQL_DATABASE
          value: wordpress
        - name: MYSQL_USER
          value: wordpress
        - name: MYSQL_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-pass
              key: password
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim

๋‹ค์Œ์˜ ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋Š” ๋‹จ์ผ-์ธ์Šคํ„ด์Šค WordPress ๋””ํ”Œ๋กœ์ด๋จผํŠธ๋ฅผ ๊ธฐ์ˆ ํ•œ๋‹ค. WordPress ์ปจํ…Œ์ด๋„ˆ๋Š” ์›น์‚ฌ์ดํŠธ ๋ฐ์ดํ„ฐ ํŒŒ์ผ์„ ์œ„ํ•ด /var/www/html์— ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ์„ ๋งˆ์šดํŠธํ•œ๋‹ค. WORDPRESS_DB_HOST ํ™˜๊ฒฝ ๋ณ€์ˆ˜์—๋Š” ์œ„์—์„œ ์ •์˜ํ•œ MySQL ์„œ๋น„์Šค์˜ ์ด๋ฆ„์ด ์„ค์ •๋˜๋ฉฐ, WordPress๋Š” ์„œ๋น„์Šค๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ‘๊ทผํ•œ๋‹ค. WORDPRESS_DB_PASSWORD ํ™˜๊ฒฝ ๋ณ€์ˆ˜์—๋Š” kustomize๊ฐ€ ์ƒ์„ฑํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํŒจ์Šค์›Œ๋“œ๊ฐ€ ์„ค์ •๋œ๋‹ค.

apiVersion: v1
kind: Service
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  ports:
    - port: 80
  selector:
    app: wordpress
    tier: frontend
  type: LoadBalancer
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wp-pv-claim
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: frontend
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: frontend
    spec:
      containers:
      - image: wordpress:4.8-apache
        name: wordpress
        env:
        - name: WORDPRESS_DB_HOST
          value: wordpress-mysql
        - name: WORDPRESS_DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-pass
              key: password
        ports:
        - containerPort: 80
          name: wordpress
        volumeMounts:
        - name: wordpress-persistent-storage
          mountPath: /var/www/html
      volumes:
      - name: wordpress-persistent-storage
        persistentVolumeClaim:
          claimName: wp-pv-claim
  1. MySQL ๋””ํ”Œ๋กœ์ด๋จผํŠธ ๊ตฌ์„ฑ ํŒŒ์ผ์„ ๋‹ค์šด๋กœ๋“œํ•œ๋‹ค.

    curl -LO https://k8s.io/examples/application/wordpress/mysql-deployment.yaml
    
  2. WordPress ๊ตฌ์„ฑ ํŒŒ์ผ์„ ๋‹ค์šด๋กœ๋“œํ•œ๋‹ค.

    curl -LO https://k8s.io/examples/application/wordpress/wordpress-deployment.yaml
    
  3. ๋‘ ํŒŒ์ผ์„ kustomization.yaml์— ์ถ”๊ฐ€ํ•˜์ž.

cat <<EOF >>./kustomization.yaml
resources:
  - mysql-deployment.yaml
  - wordpress-deployment.yaml
EOF

์ ์šฉํ•˜๊ณ  ํ™•์ธํ•˜๊ธฐ

kustomization.yaml์€ WordPress ์‚ฌ์ดํŠธ์™€ MySQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๋ฐฐํฌํ•˜๋Š” ๋ชจ๋“  ๋ฆฌ์†Œ์Šค๋ฅผ ํฌํ•จํ•œ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl apply -k ./

์ด์ œ ๋ชจ๋“  ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

  1. ์‹œํฌ๋ฆฟ์ด ์กด์žฌํ•˜๋Š”์ง€ ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ํ™•์ธํ•œ๋‹ค.

    kubectl get secrets
    

    ์‘๋‹ต์€ ์•„๋ž˜์™€ ๋น„์Šทํ•ด์•ผ ํ•œ๋‹ค.

    NAME                    TYPE                                  DATA   AGE
    mysql-pass-c57bb4t7mf   Opaque                                1      9s
    
  2. ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ์ด ๋™์ ์œผ๋กœ ํ”„๋กœ๋น„์ €๋‹๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

    kubectl get pvc
    

    ์‘๋‹ต์€ ์•„๋ž˜์™€ ๋น„์Šทํ•ด์•ผ ํ•œ๋‹ค.

    NAME             STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS       AGE
    mysql-pv-claim   Bound     pvc-8cbd7b2e-4044-11e9-b2bb-42010a800002   20Gi       RWO            standard           77s
    wp-pv-claim      Bound     pvc-8cd0df54-4044-11e9-b2bb-42010a800002   20Gi       RWO            standard           77s
    
  3. ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ํŒŒ๋“œ๊ฐ€ ์‹คํ–‰ ์ค‘์ธ์ง€ ํ™•์ธํ•œ๋‹ค.

    kubectl get pods
    

    ์‘๋‹ต์€ ์•„๋ž˜์™€ ๋น„์Šทํ•ด์•ผ ํ•œ๋‹ค.

    NAME                               READY     STATUS    RESTARTS   AGE
    wordpress-mysql-1894417608-x5dzt   1/1       Running   0          40s
    
  4. ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์„œ๋น„์Šค๊ฐ€ ์‹คํ–‰ ์ค‘์ธ์ง€ ํ™•์ธํ•ด๋ณด์ž.

    kubectl get services wordpress
    

    ์‘๋‹ต์€ ์•„๋ž˜์™€ ๋น„์Šทํ•ด์•ผ ํ•œ๋‹ค.

    NAME        TYPE            CLUSTER-IP   EXTERNAL-IP   PORT(S)        AGE
    wordpress   LoadBalancer    10.0.0.89    <pending>     80:32406/TCP   4m
    
  5. ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์—ฌ WordPress ์„œ๋น„์Šค์˜ IP ์ฃผ์†Œ๋ฅผ ์–ป์–ด์˜จ๋‹ค.

    minikube service wordpress --url
    

    ์‘๋‹ต์€ ์•„๋ž˜์™€ ๋น„์Šทํ•ด์•ผ ํ•œ๋‹ค.

    http://1.2.3.4:32406
    
  6. IP ์ฃผ์†Œ๋ฅผ ๋ณต์‚ฌํ•ด์„œ ์›น ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‚ฌ์ดํŠธ๋ฅผ ์—ด์–ด ๋ณด์ž.

    ์•„๋ž˜ ์Šคํฌ๋ฆฐ์ƒท๊ณผ ์œ ์‚ฌํ•œ WordPress ์„ค์ • ํŽ˜์ด์ง€๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

    wordpress-init

์ •๋ฆฌํ•˜๊ธฐ

  1. ๋‹ค์Œ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜์—ฌ ์‹œํฌ๋ฆฟ, ๋””ํ”Œ๋กœ์ด๋จผํŠธ, ์„œ๋น„์Šค์™€ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจํด๋ ˆ์ž„์„ ์‚ญ์ œํ•˜์ž.

    kubectl delete -k ./
    

๋‹ค์Œ ๋‚ด์šฉ

6.3 - ์˜ˆ์‹œ: ์นด์‚ฐ๋“œ๋ผ๋ฅผ ์Šคํ…Œ์ดํŠธํ’€์…‹์œผ๋กœ ๋ฐฐํฌํ•˜๊ธฐ

์ด ํŠœํ† ๋ฆฌ์–ผ์€ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์—์„œ ์•„ํŒŒ์น˜ ์นด์‚ฐ๋“œ๋ผ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์†Œ๊ฐœํ•œ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์ธ ์นด์‚ฐ๋“œ๋ผ๋Š” ๋ฐ์ดํ„ฐ ๋‚ด๊ตฌ์„ฑ์„ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด ํผ์‹œ์Šคํ„ดํŠธ ์Šคํ† ๋ฆฌ์ง€๊ฐ€ ํ•„์š”ํ•˜๋‹ค(์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ƒํƒœ). ์ด ์˜ˆ์ œ์—์„œ ์‚ฌ์šฉ์ž ์ง€์ • ์นด์‚ฐ๋“œ๋ผ ์‹œ๋“œ ๊ณต๊ธ‰์ž๋Š” ์นด์‚ฐ๋“œ๋ผ๊ฐ€ ํด๋Ÿฌ์Šคํ„ฐ์— ๊ฐ€์ž…ํ•  ๋•Œ ์นด์‚ฐ๋“œ๋ผ๊ฐ€ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.

์Šคํ…Œ์ดํŠธํ’€์…‹ ์€ ์ƒํƒœ์žˆ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ์— ์‰ฝ๊ฒŒ ๋ฐฐํฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค. ์ด ํŠœํ† ๋ฆฌ์–ผ์—์„œ ์ด์šฉํ•  ๊ธฐ๋Šฅ์˜ ์ž์„ธํ•œ ์ •๋ณด๋Š” ์Šคํ…Œ์ดํŠธํ’€์…‹์„ ์ฐธ์กฐํ•œ๋‹ค.

๋ชฉ์ 

  • ์นด์‚ฐ๋“œ๋ผ ํ—ค๋“œ๋ฆฌ์Šค Service๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ฒ€์ฆํ•œ๋‹ค.
  • ์Šคํ…Œ์ดํŠธํ’€์…‹(StatefulSet)์„ ์ด์šฉํ•˜์—ฌ ์นด์‚ฐ๋“œ๋ผ ๋ง์„ ์ƒ์„ฑํ•œ๋‹ค.
  • ์Šคํ…Œ์ดํŠธํ’€์…‹์„ ๊ฒ€์ฆํ•œ๋‹ค.
  • ์Šคํ…Œ์ดํŠธํ’€์…‹์„ ์ˆ˜์ •ํ•œ๋‹ค.
  • ์Šคํ…Œ์ดํŠธํ’€์…‹๊ณผ ํฌํ•จ๋œ ํŒŒ๋“œ๋ฅผ ์‚ญ์ œํ•œ๋‹ค.

์‹œ์ž‘ํ•˜๊ธฐ ์ „์—

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ๊ฐ€ ํ•„์š”ํ•˜๊ณ , kubectl ์ปค๋งจ๋“œ-๋ผ์ธ ํˆด์ด ํด๋Ÿฌ์Šคํ„ฐ์™€ ํ†ต์‹ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •๋˜์–ด ์žˆ์–ด์•ผ ํ•œ๋‹ค. ์ด ํŠœํ† ๋ฆฌ์–ผ์€ ์ปจํŠธ๋กค ํ”Œ๋ ˆ์ธ ํ˜ธ์ŠคํŠธ๊ฐ€ ์•„๋‹Œ ๋…ธ๋“œ๊ฐ€ ์ ์–ด๋„ 2๊ฐœ ํฌํ•จ๋œ ํด๋Ÿฌ์Šคํ„ฐ์—์„œ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค. ๋งŒ์•ฝ, ์•„์ง ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š๋‹ค๋ฉด, minikube๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ๋‹ค์Œ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํ”Œ๋ ˆ์ด๊ทธ๋ผ์šด๋“œ ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด ํŠœํ† ๋ฆฌ์–ผ์„ ์™„๋ฃŒํ•˜๋ ค๋ฉด, ํŒŒ๋“œ, ์„œ๋น„์Šค, ์Šคํ…Œ์ดํŠธํ’€์…‹์— ๋Œ€ํ•œ ๊ธฐ๋ณธ ์ง€์‹์ด ์žˆ์–ด์•ผ ํ•œ๋‹ค.

์ถ”๊ฐ€์ ์ธ Minikube ์„ค์ • ์š”๋ น

์นด์‚ฐ๋“œ๋ผ๋ฅผ ์œ„ํ•œ ํ—ค๋“œ๋ฆฌ์Šค ์„œ๋น„์Šค ์ƒ์„ฑํ•˜๊ธฐ

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์—์„œ ์„œ๋น„์Šค๋Š” ๋™์ผ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํŒŒ๋“œ์˜ ์ง‘ํ•ฉ์„ ๊ธฐ์ˆ ํ•œ๋‹ค.

๋‹ค์Œ์˜ ์„œ๋น„์Šค๋Š” ํด๋Ÿฌ์Šคํ„ฐ์—์„œ ์นด์‚ฐ๋“œ๋ผ ํŒŒ๋“œ์™€ ํด๋ผ์ด์–ธํŠธ ๊ฐ„์— DNS ์ฐพ์•„๋ณด๊ธฐ ์šฉ๋„๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

apiVersion: v1
kind: Service
metadata:
  labels:
    app: cassandra
  name: cassandra
spec:
  clusterIP: None
  ports:
  - port: 9042
  selector:
    app: cassandra

cassandra-service.yaml ํŒŒ์ผ์—์„œ ์นด์‚ฐ๋“œ๋ผ ์Šคํ…Œ์ดํŠธํ’€์…‹ ๋…ธ๋“œ๋ฅผ ๋ชจ๋‘ ์ถ”์ ํ•˜๋Š” ์„œ๋น„์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

kubectl apply -f https://k8s.io/examples/application/cassandra/cassandra-service.yaml

๊ฒ€์ฆํ•˜๊ธฐ(์„ ํƒ)

์นด์‚ฐ๋“œ๋ผ ์„œ๋น„์Šค ์‚ดํŽด๋ณด๊ธฐ

kubectl get svc cassandra

๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

NAME        TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
cassandra   ClusterIP   None         <none>        9042/TCP   45s

cassandra ์„œ๋น„์Šค๊ฐ€ ๋ณด์ด์ง€ ์•Š๋Š”๋‹ค๋ฉด, ์ด์™€ ๋‹ค๋ฅธ ์‘๋‹ต์ด๋ผ๋ฉด ์„œ๋น„์Šค ์ƒ์„ฑ์— ์‹คํŒจํ•œ ๊ฒƒ์ด๋‹ค. ์ผ๋ฐ˜์ ์ธ ๋ฌธ์ œ์— ๋Œ€ํ•œ ์„œ๋น„์Šค ๋””๋ฒ„๊น…ํ•˜๊ธฐ๋ฅผ ์ฝ์–ด๋ณด์ž.

์นด์‚ฐ๋“œ๋ผ ๋ง์„ ์ƒ์„ฑํ•˜๋Š” ์Šคํ…Œ์ดํŠธํ’€์…‹ ์ด์šฉํ•˜๊ธฐ

์Šคํ…Œ์ดํŠธํ’€์…‹ ๋งค๋‹ˆํŽ˜์ŠคํŠธ์—๋Š” ๋‹ค์Œ์„ ํฌํ•จํ•˜๋Š”๋ฐ 3๊ฐœ ํŒŒ๋“œ๋กœ ๊ตฌ์„ฑ๋œ ์นด์‚ฐ๋“œ๋ผ ๋ง์„ ์ƒ์„ฑํ•œ๋‹ค.

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: cassandra
  labels:
    app: cassandra
spec:
  serviceName: cassandra
  replicas: 3
  selector:
    matchLabels:
      app: cassandra
  template:
    metadata:
      labels:
        app: cassandra
    spec:
      terminationGracePeriodSeconds: 500
      containers:
      - name: cassandra
        image: gcr.io/google-samples/cassandra:v13
        imagePullPolicy: Always
        ports:
        - containerPort: 7000
          name: intra-node
        - containerPort: 7001
          name: tls-intra-node
        - containerPort: 7199
          name: jmx
        - containerPort: 9042
          name: cql
        resources:
          limits:
            cpu: "500m"
            memory: 1Gi
          requests:
            cpu: "500m"
            memory: 1Gi
        securityContext:
          capabilities:
            add:
              - IPC_LOCK
        lifecycle:
          preStop:
            exec:
              command:
              - /bin/sh
              - -c
              - nodetool drain
        env:
          - name: MAX_HEAP_SIZE
            value: 512M
          - name: HEAP_NEWSIZE
            value: 100M
          - name: CASSANDRA_SEEDS
            value: "cassandra-0.cassandra.default.svc.cluster.local"
          - name: CASSANDRA_CLUSTER_NAME
            value: "K8Demo"
          - name: CASSANDRA_DC
            value: "DC1-K8Demo"
          - name: CASSANDRA_RACK
            value: "Rack1-K8Demo"
          - name: POD_IP
            valueFrom:
              fieldRef:
                fieldPath: status.podIP
        readinessProbe:
          exec:
            command:
            - /bin/bash
            - -c
            - /ready-probe.sh
          initialDelaySeconds: 15
          timeoutSeconds: 5
        # These volume mounts are persistent. They are like inline claims,
        # but not exactly because the names need to match exactly one of
        # the stateful pod volumes.
        volumeMounts:
        - name: cassandra-data
          mountPath: /cassandra_data
  # These are converted to volume claims by the controller
  # and mounted at the paths mentioned above.
  # do not use these in production until ssd GCEPersistentDisk or other ssd pd
  volumeClaimTemplates:
  - metadata:
      name: cassandra-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: fast
      resources:
        requests:
          storage: 1Gi
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: fast
provisioner: k8s.io/minikube-hostpath
parameters:
  type: pd-ssd

cassandra-statefulset.yaml ํŒŒ์ผ๋กœ ์นด์‚ฐ๋“œ๋ผ ์Šคํ…Œ์ดํŠธํ’€์…‹ ์ƒ์„ฑ

# cassandra-statefulset.yaml์„ ์ˆ˜์ •ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ์— ์ด๊ฒƒ์„ ์‚ฌ์šฉํ•œ๋‹ค.
kubectl apply -f https://k8s.io/examples/application/cassandra/cassandra-statefulset.yaml

ํด๋Ÿฌ์Šคํ„ฐ์— ๋งž๊ฒŒ cassandra-statefulset.yaml ๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ๋‹ค์Œ์„ ๋‹ค์šด๋กœ๋“œํ•œ ๋‹ค์Œ ์ˆ˜์ •๋œ ๋ฒ„์ „์„ ์ €์žฅํ•œ ํด๋”์—์„œ ํ•ด๋‹น ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ์ ์šฉํ•œ๋‹ค. https://k8s.io/examples/application/cassandra/cassandra-statefulset.yaml

# cassandra-statefulset.yaml์„ ๋กœ์ปฌ์—์„œ ์ˆ˜์ •ํ•œ ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•œ๋‹ค.
kubectl apply -f cassandra-statefulset.yaml

์นด์‚ฐ๋“œ๋ผ ์Šคํ…Œ์ดํŠธํ’€์…‹ ๊ฒ€์ฆํ•˜๊ธฐ

  1. ์นด์‚ฐ๋“œ๋ผ ์Šคํ…Œ์ดํŠธํ’€์…‹ ์–ป๊ธฐ

    kubectl get statefulset cassandra
    

    ์‘๋‹ต์€ ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•˜๋‹ค.

    NAME        DESIRED   CURRENT   AGE
    cassandra   3         0         13s
    

    StatefulSet๋ฆฌ์†Œ์Šค๋Š” ์ˆœ์ฐจ์ ์œผ๋กœ ํŒŒ๋“œ๋ฅผ ๋ฐฐํฌํ•œ๋‹ค.

  2. ์ˆœ์ฐจ์ ์œผ๋กœ ์ƒ์„ฑ๋œ ํ˜„ํ™ฉ์„ ๋ณด๊ธฐ ์œ„ํ•ด ํŒŒ๋“œ๋ฅผ ์‚ดํŽด๋ณด์ž.

    kubectl get pods -l="app=cassandra"
    

    ์‘๋‹ต์€ ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•˜๋‹ค.

    NAME          READY     STATUS              RESTARTS   AGE
    cassandra-0   1/1       Running             0          1m
    cassandra-1   0/1       ContainerCreating   0          8s
    

    ๋ชจ๋“  3๊ฐœ ํŒŒ๋“œ๊ฐ€ ๋ฐฐํฌ๋˜๊ธฐ๊นŒ์ง€ ๋ช‡ ๋ถ„์ด ์†Œ์š”๋  ์ˆ˜ ์žˆ๋‹ค. ๋ฐฐํฌ ํ›„, ๋™์ผ ๋ช…๋ น์€ ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ์‘๋‹ตํ•œ๋‹ค.

    NAME          READY     STATUS    RESTARTS   AGE
    cassandra-0   1/1       Running   0          10m
    cassandra-1   1/1       Running   0          9m
    cassandra-2   1/1       Running   0          8m
    
  3. ์ฒซ ๋ฒˆ์งธ ํŒŒ๋“œ ๋‚ด๋ถ€์— ๋ง์˜ ์ƒํƒœ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ์นด์‚ฐ๋“œ๋ผ nodetool์„ ์‹คํ–‰ํ•˜์ž.

    kubectl exec -it cassandra-0 -- nodetool status
    

    ์ด ์‘๋‹ต์€ ๋‹ค์Œ๊ณผ ๋น„์Šทํ•˜๊ฒŒ ๋ณด์ผ ๊ฒƒ์ด๋‹ค.

    Datacenter: DC1-K8Demo
    ======================
    Status=Up/Down
    |/ State=Normal/Leaving/Joining/Moving
    --  Address     Load       Tokens       Owns (effective)  Host ID                               Rack
    UN  172.17.0.5  83.57 KiB  32           74.0%             e2dd09e6-d9d3-477e-96c5-45094c08db0f  Rack1-K8Demo
    UN  172.17.0.4  101.04 KiB  32           58.8%             f89d6835-3a42-4419-92b3-0e62cae1479c  Rack1-K8Demo
    UN  172.17.0.6  84.74 KiB  32           67.1%             a6a1e8c2-3dc5-4417-b1a0-26507af2aaad  Rack1-K8Demo
    

์นด์‚ฐ๋“œ๋ผ ์Šคํ…Œ์ดํŠธํ’€์…‹ ์ˆ˜์ •ํ•˜๊ธฐ

kubectl edit๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์นด์‚ฐ๋“œ๋ผ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํฌ๊ธฐ๋ฅผ ์ˆ˜์ •ํ•œ๋‹ค.

  1. ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

    kubectl edit statefulset cassandra
    

    ์ด ๋ช…๋ น์€ ํ„ฐ๋ฏธ๋„์—์„œ ํŽธ์ง‘๊ธฐ๋ฅผ ์—ฐ๋‹ค. ๋ณ€๊ฒฝํ•ด์•ผํ•  ํ–‰์€ replicas ํ•„๋“œ์ด๋‹ค. ๋‹ค์Œ ์˜ˆ์ œ๋Š” ์Šคํ…Œ์ดํŠธํ’€์…‹ ํŒŒ์ผ์—์„œ ๋ฐœ์ทŒํ–ˆ๋‹ค.

    # ๋‹ค์Œ์˜ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ˆ˜์ •ํ•œ๋‹ค. '#'๋กœ ์‹œ์ž‘ํ•˜๋Š” ํ–‰์€ ๋ฌด์‹œ๋˜๊ณ ,
    # ๋นˆ ํŒŒ์ผ์€ ํŽธ์ง‘์„ ์ค‘๋‹จํ•œ๋‹ค. ์ €์žฅํ•  ๋•Œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์ด ํŒŒ์ผ์ด
    # ๊ด€๋ จ ์‹คํŒจ์™€ ํ•จ๊ป˜ ๋‹ค์‹œ ์—ด๋ฆฐ๋‹ค.
    #
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      creationTimestamp: 2016-08-13T18:40:58Z
      generation: 1
      labels:
      app: cassandra
      name: cassandra
      namespace: default
      resourceVersion: "323"
      uid: 7a219483-6185-11e6-a910-42010a8a0fc0
    spec:
      replicas: 3
    
  2. ๋ ˆํ”Œ๋ฆฌ์นด ๊ฐœ์ˆ˜๋ฅผ 4๋กœ ๋ฐ”๊พธ๊ณ , ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ์ €์žฅํ•œ๋‹ค.

    ์Šคํ…Œ์ดํŠธํ’€์…‹์€ 4๊ฐœ์˜ ํŒŒ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์Šค์ผ€์ผ ํ•œ๋‹ค.

  3. ๊ฒ€์ฆํ•˜๊ธฐ ์œ„ํ•ด ์นด์‚ฐ๋“œ๋ผ ์Šคํ…Œ์ดํŠธํ’€์…‹์„ ์‚ดํŽด๋ณด์ž

    kubectl get statefulset cassandra
    

    ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•˜๋‹ค.

    NAME        DESIRED   CURRENT   AGE
    cassandra   4         4         36m
    

์ •๋ฆฌํ•˜๊ธฐ

์Šคํ…Œ์ดํŠธํ’€์…‹์„ ์‚ญ์ œํ•˜๊ฑฐ๋‚˜ ์Šค์ผ€์ผ๋งํ•˜๋Š” ๊ฒƒ์€ ์Šคํ…Œ์ดํŠธํ’€์…‹์— ์—ฐ๊ด€๋œ ๋ณผ๋ฅจ์„ ์‚ญ์ œํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋‹น์‹ ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ๊ด€๋ จ๋œ ๋ชจ๋“  ๋ฆฌ์†Œ์Šค๋ฅผ ์ž๋™์œผ๋กœ ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋” ๊ฐ€์น˜์žˆ๊ธฐ์— ์ด ์„ค์ •์€ ๋‹น์‹ ์˜ ์•ˆ์ „์„ ์œ„ํ•œ ๊ฒƒ์ด๋‹ค.

  1. ๋‹ค์Œ ๋ช…๋ น์–ด(ํ•œ ์ค„๋กœ ์—ฐ๊ฒฐ๋œ)๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์นด์‚ฐ๋“œ๋ผ ์Šคํ…Œ์ดํŠธํ’€์…‹์„ ๋ชจ๋‘ ์ œ๊ฑฐํ•˜์ž.

    grace=$(kubectl get pod cassandra-0 -o=jsonpath='{.spec.terminationGracePeriodSeconds}') \
      && kubectl delete statefulset -l app=cassandra \
      && echo "Sleeping ${grace} seconds" 1>&2 \
      && sleep $grace \
      && kubectl delete persistentvolumeclaim -l app=cassandra
    
  2. ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์นด์‚ฐ๋“œ๋ผ์— ๋Œ€ํ•ด ์„ค์ •ํ•œ ์„œ๋น„์Šค๋ฅผ ์ œ๊ฑฐํ•˜์ž.

    kubectl delete service -l app=cassandra
    

์นด์‚ฐ๋“œ๋ผ ์ปจํ…Œ์ด๋„ˆ ํ™˜๊ฒฝ ๋ณ€์ˆ˜

์ด ํŠœํ† ๋ฆฌ์–ผ์˜ ํŒŒ๋“œ ๋Š” ๊ตฌ๊ธ€์˜ ์ปจํ…Œ์ด๋„ˆ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— gcr.io/google-samples/cassandra:v13 ์ด๋ฏธ์ง€๋ฅผ ์ด์šฉํ•œ๋‹ค. ์ด ๋„์ปค ์ด๋ฏธ์ง€๋Š” debian-base์— ๊ธฐ๋ฐ˜ํ•˜์˜€๊ณ  OpenJDK 8์„ ํฌํ•จํ•œ๋‹ค.

์ด ์ด๋ฏธ์ง€๋Š” ์•„ํŒŒ์น˜ ๋ฐ๋น„์•ˆ ๋ฆฌํฌ์˜ ํ‘œ์ค€ ์นด์‚ฐ๋“œ๋ผ ์„ค์น˜๋ณธ์„ ํฌํ•จํ•œ๋‹ค. ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ cassandra.yaml์— ์‚ฝ์ž…๋œ ๊ฐ’์„ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค.

ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ธฐ๋ณธ๊ฐ’
CASSANDRA_CLUSTER_NAME'Test Cluster'
CASSANDRA_NUM_TOKENS32
CASSANDRA_RPC_ADDRESS0.0.0.0

๋‹ค์Œ ๋‚ด์šฉ

6.4 - ๋ถ„์‚ฐ ์‹œ์Šคํ…œ ์ฝ”๋””๋„ค์ดํ„ฐ ZooKeeper ์‹คํ–‰ํ•˜๊ธฐ

์ด ํŠœํ† ๋ฆฌ์–ผ์€ ์•„ํŒŒ์น˜ ZooKeeper ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์—์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹๊ณผ PodDisruptionBudget๊ณผ ํŒŒ๋“œ์•ˆํ‹ฐ์–ดํ”ผ๋‹ˆํ‹ฐ(PodAntiAffinity)๋ฅผ ์ด์šฉํ•œ Apache Zookeeper ์‹คํ–‰์„ ์„ค๋ช…ํ•œ๋‹ค.

์‹œ์ž‘ํ•˜๊ธฐ ์ „์—

์ด ํŠœํ† ๋ฆฌ์–ผ์„ ์‹œ์ž‘ํ•˜๊ธฐ ์ „์— ๋‹ค์Œ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๊ฐœ๋…์— ์นœ์ˆ™ํ•ด์•ผ ํ•œ๋‹ค.

๋ฐ˜๋“œ์‹œ ์ตœ์†Œํ•œ 4๊ฐœ์˜ ๋…ธ๋“œ๊ฐ€ ์žˆ๋Š” ํด๋Ÿฌ์Šคํ„ฐ๊ฐ€ ํ•„์š”ํ•˜๋ฉฐ, ๊ฐ ๋…ธ๋“œ๋Š” ์ ์–ด๋„ 2 ๊ฐœ์˜ CPU์™€ 4 GiB ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ์ด ํŠœํ† ๋ฆฌ์–ผ์—์„œ ํด๋Ÿฌ์Šคํ„ฐ ๋…ธ๋“œ๋ฅผ ํ†ต์ œ(cordon)ํ•˜๊ณ  ๋น„์šฐ๊ฒŒ(drain) ํ•  ๊ฒƒ์ด๋‹ค. ์ด๊ฒƒ์€ ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ์ข…๋ฃŒํ•˜์—ฌ ๋…ธ๋“œ์˜ ๋ชจ๋“  ํŒŒ๋“œ๋ฅผ ์ถ•์ถœ(evict)ํ•˜๋Š” ๊ฒƒ์œผ๋กœ, ๋ชจ๋“  ํŒŒ๋“œ๋Š” ์ž„์‹œ๋กœ ์–ธ์Šค์ผ€์ค„๋œ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค. ์ด ํŠœํ† ๋ฆฌ์–ผ์„ ์œ„ํ•ด ์ „์šฉ ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ์ด์šฉํ•˜๊ฑฐ๋‚˜, ๋‹ค๋ฅธ ํ…Œ๋„ŒํŠธ์— ๊ฐ„์„ญ์„ ํ•˜๋Š” ํ˜ผ๋ž€์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด ํŠœํ† ๋ฆฌ์–ผ์€ ํด๋Ÿฌ์Šคํ„ฐ๊ฐ€ ๋™์ ์œผ๋กœ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ์„ ํ”„๋กœ๋น„์ €๋‹ํ•˜๋„๋ก ๊ตฌ์„ฑํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•œ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ์„ค์ •๋˜์–ด ์žˆ์ง€ ์•Š๋‹ค๋ฉด ํŠœํ† ๋ฆฌ์–ผ์„ ์‹œ์ž‘ํ•˜๊ธฐ ์ „์— ์ˆ˜๋™์œผ๋กœ 3๊ฐœ์˜ 20 GiB ๋ณผ๋ฅจ์„ ํ”„๋กœ๋น„์ €๋‹ํ•ด์•ผ ํ•œ๋‹ค.

๋ชฉ์ 

์ด ํŠœํ† ๋ฆฌ์–ผ์„ ๋งˆ์น˜๋ฉด ๋‹ค์Œ์— ๋Œ€ํ•ด ์•Œ๊ฒŒ ๋œ๋‹ค.

  • ์–ด๋–ป๊ฒŒ ์Šคํ…Œ์ดํŠธํ’€์…‹์„ ์ด์šฉํ•˜์—ฌ ZooKeeper ์•™์ƒ๋ธ”์„ ๋ฐฐํฌํ•˜๋Š”๊ฐ€.
  • ์–ด๋–ป๊ฒŒ ์•™์ƒ๋ธ”์„ ์ผ๊ด€๋˜๊ฒŒ ์„ค์ •ํ•˜๋Š”๊ฐ€.
  • ์–ด๋–ป๊ฒŒ ZooKeeper ์„œ๋ฒ„ ๋””ํ”Œ๋กœ์ด๋จผํŠธ๋ฅผ ์•™์ƒ๋ธ” ์•ˆ์—์„œ ํผ๋œจ๋ฆฌ๋Š”๊ฐ€.
  • ์–ด๋–ป๊ฒŒ PodDisruptionBudget์„ ์ด์šฉํ•˜์—ฌ ๊ณ„ํš๋œ ์ ๊ฒ€ ๊ธฐ๊ฐ„ ๋™์•ˆ ์„œ๋น„์Šค ๊ฐ€์šฉ์„ฑ์„ ๋ณด์žฅํ•˜๋Š”๊ฐ€.

ZooKeeper

์•„ํŒŒ์น˜ ZooKeeper๋Š” ๋ถ„์‚ฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์œ„ํ•œ ๋ถ„์‚ฐ ์˜คํ”ˆ ์†Œ์Šค ์ฝ”๋””๋„ค์ด์…˜ ์„œ๋น„์Šค์ด๋‹ค. ZooKeeper๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ณ  ์“ฐ๊ณ  ๊ฐฑ์‹ ์„ ์ง€์ผœ๋ณด๋„๋ก ํ•œ๋‹ค. ๋ฐ์ดํ„ฐ๋Š” ํŒŒ์ผ์‹œ์Šคํ…œ์ฒ˜๋Ÿผ ๊ณ„์ธต์ ์œผ๋กœ ๊ด€๋ฆฌ๋˜๊ณ  ์•™์ƒ๋ธ”(ZooKeeper ์„œ๋ฒ„์˜ ์ง‘ํ•ฉ) ๋‚ด์— ๋ชจ๋“  ZooKeeper์„œ๋ฒ„์— ๋ณต์ œ๋œ๋‹ค. ๋ฐ์ดํ„ฐ์— ๋ชจ๋“  ์—ฐ์‚ฐ์€ ์›์ž์ ์ด๊ณ  ์ˆœ์ฒ˜์ ์œผ๋กœ ์ผ๊ด€๋œ๋‹ค. ZooKeeper๋Š” Zab ํ•ฉ์˜ ํ”„๋กœํ† ์ฝœ์„ ์ด์šฉํ•˜์—ฌ ์•™์ƒ๋ธ” ๋‚ด์— ๋ชจ๋“  ์„œ๋ฒ„์— ๊ฑธ์ณ ์ƒํƒœ ๋จธ์‹ ์„ ๋ณต์ œํ•˜์—ฌ ์ด๋ฅผ ๋ณด์žฅํ•œ๋‹ค.

์•™์ƒ๋ธ”์€ ๋ฆฌ๋” ์„ ์ถœ์„ ์œ„ํ•ด Zab ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•˜๊ณ , ๋ฆฌ๋” ์„ ์ถœ๊ณผ ์„ ๊ฑฐ๊ฐ€ ์™„๋ฃŒ๋˜๊ธฐ ์ „๊นŒ์ง€ ์•™์ƒ๋ธ”์€ ๋ฐ์ดํ„ฐ๋ฅผ ์“ธ ์ˆ˜ ์—†๋‹ค. ์™„๋ฃŒ๋˜๋ฉด ์•™์ƒ๋ธ”์€ Zab์„ ์ด์šฉํ•˜์—ฌ ํ™•์ธํ•˜๊ณ  ํด๋ผ์ด์–ธํŠธ์— ๋ณด์ด๋„๋ก ๋ชจ๋“  ์“ฐ๊ธฐ๋ฅผ ์ฟผ๋Ÿผ(quorum)์— ๋ณต์ œํ•œ๋‹ค. ๊ฐ€์ค‘์น˜์žˆ๋Š” ์ฟผ๋Ÿผ๊ณผ ๊ด€๋ จ ์—†์ด, ์ฟผ๋Ÿผ์€ ํ˜„์žฌ ๋ฆฌ๋”๋ฅผ ํฌํ•จํ•˜๋Š” ์•™์ƒ๋ธ”์˜ ๋Œ€๋‹ค์ˆ˜ ์ปดํฌ๋„ŒํŠธ์ด๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์•™์ƒ๋ธ”์ด 3๊ฐœ ์„œ๋ฒ„์ธ ๊ฒฝ์šฐ, ๋ฆฌ๋”์™€ ๋‹ค๋ฅธ ์„œ๋ฒ„๋กœ ์ฟผ๋Ÿผ์„ ๊ตฌ์„ฑํ•œ๋‹ค. ์•™์ƒ๋ธ”์ด ์ฟผ๋Ÿผ์„ ๋‹ฌ์„ฑํ•  ์ˆ˜ ์—†๋‹ค๋ฉด, ์•™์ƒ๋ธ”์€ ๋ฐ์ดํ„ฐ๋ฅผ ์“ธ ์ˆ˜ ์—†๋‹ค.

ZooKeeper๋Š” ์ „์ฒด ์ƒํƒœ ๋จธ์‹ ์„ ๋ฉ”๋ชจ๋ฆฌ์— ๋ณด์กดํ•˜๊ณ  ๋ชจ๋“  ๋Œ์—ฐ๋ณ€์ด๋ฅผ ์ €์žฅ ๋ฏธ๋””์–ด์˜ ๋‚ด๊ตฌ์„ฑ ์žˆ๋Š” WAL(Write Ahead Log)์— ๊ธฐ๋กํ•œ๋‹ค. ์„œ๋ฒ„ ์žฅ์• ์‹œ WAL์„ ์žฌ์ƒํ•˜์—ฌ ์ด์ „ ์ƒํƒœ๋ฅผ ๋ณต์›ํ•  ์ˆ˜ ์žˆ๋‹ค. WAL์ด ๋ฌด์ œํ•œ์œผ๋กœ ์ปค์ง€๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ZooKeeper๋Š” ์ฃผ๊ธฐ์ ์œผ๋กœ ์ €์žฅ ๋ฏธ๋””์–ด์— ๋ฉ”๋ชจ๋ฆฌ ์ƒํƒœ์˜ ์Šค๋ƒ…์ƒท์„ ์ €์žฅํ•œ๋‹ค. ์ด ์Šค๋ƒ…์ƒท์€ ๋ฉ”๋ชจ๋ฆฌ์— ์ง์ ‘ ์ ์žฌํ•  ์ˆ˜ ์žˆ๊ณ  ์Šค๋ƒ…์ƒท ์ด์ „์˜ ๋ชจ๋“  WAL ํ•ญ๋ชฉ์€ ์‚ญ์ œ๋  ์ˆ˜ ์žˆ๋‹ค.

ZooKeeper ์•™์ƒ๋ธ” ์ƒ์„ฑํ•˜๊ธฐ

์•„๋ž˜ ๋งค๋‹ˆํŽ˜์ŠคํŠธ์—๋Š” ํ—ค๋“œ๋ฆฌ์Šค ์„œ๋น„์Šค, ์„œ๋น„์Šค, PodDisruptionBudget, ์Šคํ…Œ์ดํŠธํ’€์…‹์„ ํฌํ•จํ•œ๋‹ค.

apiVersion: v1
kind: Service
metadata:
  name: zk-hs
  labels:
    app: zk
spec:
  ports:
  - port: 2888
    name: server
  - port: 3888
    name: leader-election
  clusterIP: None
  selector:
    app: zk
---
apiVersion: v1
kind: Service
metadata:
  name: zk-cs
  labels:
    app: zk
spec:
  ports:
  - port: 2181
    name: client
  selector:
    app: zk
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: zk-pdb
spec:
  selector:
    matchLabels:
      app: zk
  maxUnavailable: 1
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: zk
spec:
  selector:
    matchLabels:
      app: zk
  serviceName: zk-hs
  replicas: 3
  updateStrategy:
    type: RollingUpdate
  podManagementPolicy: OrderedReady
  template:
    metadata:
      labels:
        app: zk
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: "app"
                    operator: In
                    values:
                    - zk
              topologyKey: "kubernetes.io/hostname"
      containers:
      - name: kubernetes-zookeeper
        imagePullPolicy: Always
        image: "registry.k8s.io/kubernetes-zookeeper:1.0-3.4.10"
        resources:
          requests:
            memory: "1Gi"
            cpu: "0.5"
        ports:
        - containerPort: 2181
          name: client
        - containerPort: 2888
          name: server
        - containerPort: 3888
          name: leader-election
        command:
        - sh
        - -c
        - "start-zookeeper \
          --servers=3 \
          --data_dir=/var/lib/zookeeper/data \
          --data_log_dir=/var/lib/zookeeper/data/log \
          --conf_dir=/opt/zookeeper/conf \
          --client_port=2181 \
          --election_port=3888 \
          --server_port=2888 \
          --tick_time=2000 \
          --init_limit=10 \
          --sync_limit=5 \
          --heap=512M \
          --max_client_cnxns=60 \
          --snap_retain_count=3 \
          --purge_interval=12 \
          --max_session_timeout=40000 \
          --min_session_timeout=4000 \
          --log_level=INFO"
        readinessProbe:
          exec:
            command:
            - sh
            - -c
            - "zookeeper-ready 2181"
          initialDelaySeconds: 10
          timeoutSeconds: 5
        livenessProbe:
          exec:
            command:
            - sh
            - -c
            - "zookeeper-ready 2181"
          initialDelaySeconds: 10
          timeoutSeconds: 5
        volumeMounts:
        - name: datadir
          mountPath: /var/lib/zookeeper
      securityContext:
        runAsUser: 1000
        fsGroup: 1000
  volumeClaimTemplates:
  - metadata:
      name: datadir
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 10Gi

ํ„ฐ๋ฏธ๋„์„ ์—ด๊ณ  kubectl apply ๋ช…๋ น์–ด๋กœ ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•˜์ž.

kubectl apply -f https://k8s.io/examples/application/zookeeper/zookeeper.yaml

์ด๋Š” zk-hs ํ—ค๋“œ๋ฆฌ์Šค ์„œ๋น„์Šค, zk-cs ์„œ๋น„์Šค, zk-pdb PodDisruptionBudget๊ณผ zk ์Šคํ…Œ์ดํŠธํ’€์…‹์„ ์ƒ์„ฑํ•œ๋‹ค.

service/zk-hs created
service/zk-cs created
poddisruptionbudget.policy/zk-pdb created
statefulset.apps/zk created

kubectl get์„ ์‚ฌ์šฉํ•˜์—ฌ ์Šคํ…Œ์ดํŠธํ’€์…‹ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์Šคํ…Œ์ดํŠธํ’€์…‹ ํŒŒ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

kubectl get pods -w -l app=zk

zk-2 ํŒŒ๋“œ๊ฐ€ Running and Ready ์ƒํƒœ๊ฐ€ ๋˜๋ฉด, CTRL-C๋ฅผ ๋ˆŒ๋Ÿฌ kubectl์„ ์ข…๋ฃŒํ•˜์ž.

NAME      READY     STATUS    RESTARTS   AGE
zk-0      0/1       Pending   0          0s
zk-0      0/1       Pending   0         0s
zk-0      0/1       ContainerCreating   0         0s
zk-0      0/1       Running   0         19s
zk-0      1/1       Running   0         40s
zk-1      0/1       Pending   0         0s
zk-1      0/1       Pending   0         0s
zk-1      0/1       ContainerCreating   0         0s
zk-1      0/1       Running   0         18s
zk-1      1/1       Running   0         40s
zk-2      0/1       Pending   0         0s
zk-2      0/1       Pending   0         0s
zk-2      0/1       ContainerCreating   0         0s
zk-2      0/1       Running   0         19s
zk-2      1/1       Running   0         40s

์Šคํ…Œ์ดํŠธํ’€์…‹ ์ปจํŠธ๋กค๋Ÿฌ๋Š” 3๊ฐœ์˜ ํŒŒ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ๊ฐ ํŒŒ๋“œ๋Š” ZooKeeper ์„œ๋ฒ„๋ฅผ ํฌํ•จํ•œ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๊ฐ€์ง„๋‹ค.

๋ฆฌ๋” ์„ ์ถœ ์ด‰์ง„

์ต๋ช… ๋„คํŠธ์›Œํฌ์—์„œ ๋ฆฌ๋” ์„ ์ถœ์„ ์œ„ํ•œ ์ข…๋ฃŒ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์—†๊ธฐ์—, Zab์€ ๋ฆฌ๋” ์„ ์ถœ์„ ์œ„ํ•ด ๋ช…์‹œ์ ์ธ ๋ฉค๋ฒ„ ๊ตฌ์„ฑ์„ ํ•ด์•ผ ํ•œ๋‹ค. ์•™์ƒ๋ธ”์˜ ๊ฐ ์„œ๋ฒ„๋Š” ๊ณ ์œ  ์‹๋ณ„์ž๋ฅผ ๊ฐ€์ ธ์•ผ ํ•˜๊ณ , ๋ชจ๋“  ์„œ๋ฒ„๋Š” ์‹๋ณ„์ž ์ „์—ญ ์ง‘ํ•ฉ์„ ์•Œ์•„์•ผ ํ•˜๋ฉฐ, ๊ฐ ์‹๋ณ„์ž๋Š” ๋„คํŠธ์›Œํฌ ์ฃผ์†Œ์— ์—ฐ๊ด€๋˜์–ด์•ผ ํ•œ๋‹ค.

kubectl exec๋ฅผ ์ด์šฉํ•˜์—ฌ zk ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ์˜ ํ˜ธ์ŠคํŠธ๋„ค์ž„์„ ์•Œ์•„๋‚ด์ž.

for i in 0 1 2; do kubectl exec zk-$i -- hostname; done

์Šคํ…Œ์ดํŠธํ’€์…‹ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ๊ฐ ์ˆœ๋ฒˆ ์ธ๋ฑ์Šค์— ๊ธฐ์ดˆํ•˜์—ฌ ๊ฐ ํŒŒ๋“œ์— ๊ณ ์œ ํ•œ ํ˜ธ์ŠคํŠธ๋„ค์ž„์„ ๋ถ€์—ฌํ•œ๋‹ค. ๊ฐ ํ˜ธ์ŠคํŠธ๋„ค์ž„์€ <์Šคํ…Œ์ดํŠธํ’€์…‹ ์ด๋ฆ„>-<์ˆœ๋ฒˆ ์ธ๋ฑ์Šค> ํ˜•์‹์„ ์ทจํ•œ๋‹ค. zk ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ replicas ํ•„๋“œ๋Š” 3์œผ๋กœ ์„ค์ •๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์—, ๊ทธ ์Šคํ…Œ์ดํŠธํ’€์…‹ ์ปจํŠธ๋กค๋Ÿฌ๋Š” 3๊ฐœ ํŒŒ๋“œ์˜ ํ˜ธ์ŠคํŠธ๋„ค์ž„์„ zk-0, zk-1, zk-2๋กœ ์ •ํ•œ๋‹ค.

zk-0
zk-1
zk-2

ZooKeeper ์•™์ƒ๋ธ”์— ์„œ๋ฒ„๋“ค์€ ๊ณ ์œ  ์‹๋ณ„์ž๋กœ์„œ ์ž์—ฐ์ˆ˜๋ฅผ ์ด์šฉํ•˜๊ณ  ์„œ๋ฒ„ ๋ฐ์ดํ„ฐ ๋””๋ ‰ํ„ฐ๋ฆฌ์— my ๋ผ๋Š” ํŒŒ์ผ๋กœ ์„œ๋ฒ„ ์‹๋ณ„์ž๋ฅผ ์ €์žฅํ•œ๋‹ค.

๊ฐ ์„œ๋ฒ„์—์„œ ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์ด์šฉํ•˜์—ฌ myid ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ ํ™•์ธํ•˜์ž.

for i in 0 1 2; do echo "myid zk-$i";kubectl exec zk-$i -- cat /var/lib/zookeeper/data/myid; done

์‹๋ณ„์ž๋Š” ์ž์—ฐ์ˆ˜์ด๊ณ , ์ˆœ๋ฒˆ ์ธ๋ฑ์Šค๋“ค๋„ ์Œ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ฏ€๋กœ, ์ˆœ๋ฒˆ์— 1์„ ๋”ํ•˜์—ฌ ์ˆœ๋ฒˆ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

myid zk-0
1
myid zk-1
2
myid zk-2
3

zk ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ๊ฐ ํŒŒ๋“œ Fully Qualified Domain Name (FQDN)์„ ์–ป๊ธฐ ์œ„ํ•ด ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์ด์šฉํ•˜์ž.

for i in 0 1 2; do kubectl exec zk-$i -- hostname -f; done

zk-hs ์„œ๋น„์Šค๋Š” ๋ชจ๋“  ํŒŒ๋“œ๋ฅผ ์œ„ํ•œ ๋„๋ฉ”์ธ์ธ zk-hs.default.svc.cluster.local์„ ๋งŒ๋“ ๋‹ค.

zk-0.zk-hs.default.svc.cluster.local
zk-1.zk-hs.default.svc.cluster.local
zk-2.zk-hs.default.svc.cluster.local

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค DNS์˜ A ๋ ˆ์ฝ”๋“œ๋Š” FQDN์„ ํŒŒ๋“œ์˜ IP ์ฃผ์†Œ๋กœ ํ’€์–ด๋‚ธ๋‹ค. ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๊ฐ€ ํŒŒ๋“œ๋ฅผ ๋ฆฌ์Šค์ผ€์ค„ํ•˜๋ฉด, ํŒŒ๋“œ์˜ ์ƒˆ IP ์ฃผ์†Œ๋กœ A ๋ ˆ์ฝ”๋“œ๋ฅผ ๊ฐฑ์‹ ํ•˜์ง€๋งŒ, A ๋ ˆ์ฝ”๋“œ์˜ ์ด๋ฆ„์€ ๋ฐ”๋€Œ์ง€ ์•Š๋Š”๋‹ค.

ZooKeeper๋Š” ๊ทธ๊ฒƒ์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ™˜๊ฒฝ์„ค์ •์„ zoo.cfg ํŒŒ์ผ์— ์ €์žฅํ•œ๋‹ค. kubectl exec๋ฅผ ์ด์šฉํ•˜์—ฌ zk-0 ํŒŒ๋“œ์˜ zoo.cfg ๋‚ด์šฉ์„ ๋ณด์ž.

kubectl exec zk-0 -- cat /opt/zookeeper/conf/zoo.cfg

์•„๋ž˜ ํŒŒ์ผ์˜ server.1, server.2, server.3 ์†์„ฑ์—์„œ 1, 2, 3์€ ZooKeeper ์„œ๋ฒ„์˜ myid ํŒŒ์ผ์— ๊ตฌ๋ถ„์ž์™€ ์—ฐ๊ด€๋œ๋‹ค. ์ด๋“ค์€ zk ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ์˜ FQDNS์„ ์„ค์ •ํ•œ๋‹ค.

clientPort=2181
dataDir=/var/lib/zookeeper/data
dataLogDir=/var/lib/zookeeper/log
tickTime=2000
initLimit=10
syncLimit=2000
maxClientCnxns=60
minSessionTimeout= 4000
maxSessionTimeout= 40000
autopurge.snapRetainCount=3
autopurge.purgeInterval=0
server.1=zk-0.zk-hs.default.svc.cluster.local:2888:3888
server.2=zk-1.zk-hs.default.svc.cluster.local:2888:3888
server.3=zk-2.zk-hs.default.svc.cluster.local:2888:3888

ํ•ฉ์˜ ๋‹ฌ์„ฑ

ํ•ฉ์˜ ํ”„๋กœํ† ์ฝœ์—์„œ ๊ฐ ์ฐธ๊ฐ€์ž์˜ ์‹๋ณ„์ž๋Š” ์œ ์ผํ•ด์•ผ ํ•œ๋‹ค. Zab ํ”„๋กœํ† ์ฝœ์—์„œ ๋™์ผํ•œ ๊ณ ์œ  ์‹๋ณ„์ž๋ฅผ ์š”์ฒญํ•˜๋Š” ์ฐธ๊ฐ€์ž๋Š” ์—†๋‹ค. ์ด๋Š” ์‹œ์Šคํ…œ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์–ด๋–ค ํ”„๋กœ์„ธ์Šค๊ฐ€ ์–ด๋–ค ๋ฐ์ดํ„ฐ๋ฅผ ์ปค๋ฐ‹ํ–ˆ๋Š”์ง€ ๋™์˜ํ•˜๊ฒŒ ํ•˜๋Š”๋ฐ ํ•„์š”ํ•˜๋‹ค. 2๊ฐœ ํŒŒ๋“œ๋ฅผ ๋™์ผ ์ˆœ๋ฒˆ์œผ๋กœ ์‹œ์ž‘ํ•˜์˜€๋‹ค๋ฉด ๋‘ ๋Œ€์˜ ZooKeeper ์„œ๋ฒ„๋Š” ๋‘˜ ๋‹ค ์Šค์Šค๋กœ๋ฅผ ๋™์ผ ์„œ๋ฒ„๋กœ ์‹๋ณ„ํ•œ๋‹ค.

ํ•ฉ์˜ ํ”„๋กœํ† ์ฝœ์—์„œ ๊ฐ ์ฐธ์—ฌ์ž์˜ ์‹๋ณ„์ž๋Š” ๊ณ ์œ ํ•ด์•ผ ํ•œ๋‹ค. Zab ํ”„๋กœํ† ์ฝœ์— ๋‘ ์ฐธ์—ฌ์ž๊ฐ€ ๋™์ผํ•œ ๊ณ ์œ  ์‹๋ณ„์ž๋กœ ์š”์ฒญํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค. ์ด๋Š” ์‹œ์Šคํ…œ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์–ด๋–ค ํ”„๋กœ์„ธ์Šค๊ฐ€ ์–ด๋–ค ๋ฐ์ดํ„ฐ๋ฅผ ์ปค๋ฐ‹ํ–ˆ๋Š”์ง€ ๋™์˜ํ•˜๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด ํ•„์ˆ˜์ ์ด๋‹ค. ๋™์ผ ์ˆœ๋ฒˆ์œผ๋กœ ๋‘ ๊ฐœ์˜ ํŒŒ๋“œ๊ฐ€ ์‹คํ–‰ํ–ˆ๋‹ค๋ฉด ๋‘ ZooKeeper ์„œ๋ฒ„๋Š” ๋ชจ๋‘ ๋™์ผํ•œ ์„œ๋ฒ„๋กœ ์‹๋ณ„๋œ๋‹ค.

kubectl get pods -w -l app=zk
NAME      READY     STATUS    RESTARTS   AGE
zk-0      0/1       Pending   0          0s
zk-0      0/1       Pending   0         0s
zk-0      0/1       ContainerCreating   0         0s
zk-0      0/1       Running   0         19s
zk-0      1/1       Running   0         40s
zk-1      0/1       Pending   0         0s
zk-1      0/1       Pending   0         0s
zk-1      0/1       ContainerCreating   0         0s
zk-1      0/1       Running   0         18s
zk-1      1/1       Running   0         40s
zk-2      0/1       Pending   0         0s
zk-2      0/1       Pending   0         0s
zk-2      0/1       ContainerCreating   0         0s
zk-2      0/1       Running   0         19s
zk-2      1/1       Running   0         40s

๊ฐ ํŒŒ๋“œ์˜ A ๋ ˆ์ฝ”๋“œ๋Š” ํŒŒ๋“œ๊ฐ€ Ready ์ƒํƒœ๊ฐ€ ๋˜๋ฉด ์ž…๋ ฅ๋œ๋‹ค. ๋”ฐ๋ผ์„œ ZooKeeper ์„œ๋ฒ„์˜ FQDN์€ ๋‹จ์ผ ์—”๋“œํฌ์ธํŠธ๋กœ ํ™•์ธ๋˜๊ณ  ํ•ด๋‹น ์—”๋“œํฌ์ธํŠธ๋Š” myid ํŒŒ์ผ์— ๊ตฌ์„ฑ๋œ ์‹๋ณ„์ž๋ฅผ ๊ฐ€์ง„ ๊ณ ์œ ํ•œ ZooKeeper ์„œ๋ฒ„๊ฐ€ ๋œ๋‹ค.

zk-0.zk-hs.default.svc.cluster.local
zk-1.zk-hs.default.svc.cluster.local
zk-2.zk-hs.default.svc.cluster.local

์ด๊ฒƒ์€ ZooKeeper์˜ zoo.cfg ํŒŒ์ผ์— servers ์†์„ฑ์ด ์ •ํ™•ํžˆ ๊ตฌ์„ฑ๋œ ์•™์ƒ๋ธ”๋กœ ๋‚˜ํƒ€๋‚˜๋Š” ๊ฒƒ์„ ๋ณด์ฆํ•œ๋‹ค.

server.1=zk-0.zk-hs.default.svc.cluster.local:2888:3888
server.2=zk-1.zk-hs.default.svc.cluster.local:2888:3888
server.3=zk-2.zk-hs.default.svc.cluster.local:2888:3888

์„œ๋ฒ„๊ฐ€ Zab ํ”„๋กœํ† ์ฝœ๋กœ ๊ฐ’์„ ์ปค๋ฐ‹ ์‹œ๋„ํ•˜๋ฉด, ํ•ฉ์˜๋ฅผ ์ด๋ฃจ์–ด ๊ฐ’์„ ์ปค๋ฐ‹ํ•˜๊ฑฐ๋‚˜(๋ฆฌ๋” ์„ ์ถœ์— ์„ฑ๊ณตํ–ˆ๊ณ  ๋‚˜๋จธ์ง€ ๋‘ ๊ฐœ ํŒŒ๋“œ๋„ Running๊ณผ Ready ์ƒํƒœ๋ผ๋ฉด) ์‹คํŒจํ•œ๋‹ค(์กฐ๊ฑด ์ค‘ ํ•˜๋‚˜๋ผ๋„ ์ถฉ์กฑํ•˜์ง€ ์•Š์œผ๋ฉด). ๋‹ค๋ฅธ ์„œ๋ฒ„๋ฅผ ๋Œ€์‹ ํ•˜์—ฌ ์“ฐ๊ธฐ๋ฅผ ์Šน์ธํ•˜๋Š” ์ƒํƒœ๋Š” ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.

์•™์ƒ๋ธ” ๋ฌด๊ฒฐ์„ฑ ํ…Œ์ŠคํŠธ

๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ํ…Œ์ŠคํŠธ๋Š” ํ•œ ZooKeeper ์„œ๋ฒ„์— ๋ฐ์ดํ„ฐ๋ฅผ ์“ฐ๊ณ  ๋‹ค๋ฅธ ZooKeeper ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๋Š” ๊ฒƒ์ด๋‹ค.

์•„๋ž˜ ๋ช…๋ น์–ด๋Š” ์•™์ƒ๋ธ” ๋‚ด์— zk-0 ํŒŒ๋“œ์—์„œ /hello ๊ฒฝ๋กœ๋กœ world๋ฅผ ์“ฐ๋Š” ์Šคํฌ๋ฆฝํŠธ์ธ zkCli.sh๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

kubectl exec zk-0 -- zkCli.sh create /hello world
WATCHER::

WatchedEvent state:SyncConnected type:None path:null
Created /hello

zk-1 ํŒŒ๋“œ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ธฐ ์œ„ํ•ด ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์ด์šฉํ•˜์ž.

kubectl exec zk-1 -- zkCli.sh get /hello

zk-0์—์„œ ์ƒ์„ฑํ•œ ๊ทธ ๋ฐ์ดํ„ฐ๋Š” ์•™์ƒ๋ธ” ๋‚ด์— ๋ชจ๋“  ์„œ๋ฒ„์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

WATCHER::

WatchedEvent state:SyncConnected type:None path:null
world
cZxid = 0x100000002
ctime = Thu Dec 08 15:13:30 UTC 2016
mZxid = 0x100000002
mtime = Thu Dec 08 15:13:30 UTC 2016
pZxid = 0x100000002
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0

๋‚ด๊ตฌ์„ฑ์žˆ๋Š” ์ €์žฅ์†Œ ์ œ๊ณต

ZooKeeper ๊ธฐ๋ณธ ์„น์…˜์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ZooKeeper๋Š” ๋ชจ๋“  ํ•ญ๋ชฉ์„ ๋‚ด๊ตฌ์„ฑ์žˆ๋Š” WAL์— ์ปค๋ฐ‹ํ•˜๊ณ  ๋ฉ”๋ชจ๋ฆฌ ์ƒํƒœ์˜ ์Šค๋ƒ…์ƒท์„ ์ €์žฅ ๋ฏธ๋””์—์— ์ฃผ๊ธฐ์ ์œผ๋กœ ์ €์žฅํ•œ๋‹ค. ๋‚ด๊ตฌ์„ฑ์„ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด WAL์„ ์ด์šฉํ•˜๋Š” ๊ฒƒ์€ ๋ณต์ œ๋œ ์ƒํƒœ ๋จธ์‹ ์„ ์ด๋ฃจ๋Š” ํ•ฉ์˜ ํ”„๋กœํ† ์ฝœ์—์„œ ์ด์šฉํ•˜๋Š” ์ผ๋ฐ˜์ ์ธ ๊ธฐ๋ฒ•์ด๋‹ค.

kubectl delete ๋ช…๋ น์„ ์ด์šฉํ•˜์—ฌ zk ์Šคํ…Œ์ดํŠธํ’€์…‹์„ ์‚ญ์ œํ•˜์ž.

kubectl delete statefulset zk
statefulset.apps "zk" deleted

์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๊ฐ€ ์ข…๋ฃŒ๋˜๋Š” ๊ฒƒ์„ ์ง€์ผœ๋ณด์ž.

kubectl get pods -w -l app=zk

zk-0์ด ์™„์ „ํžˆ ์ข…๋ฃŒ๋˜๋ฉด CTRL-C๋ฅผ ์ด์šฉํ•ด kubectl์„ ์ข…๋ฃŒํ•˜์ž.

zk-2      1/1       Terminating   0         9m
zk-0      1/1       Terminating   0         11m
zk-1      1/1       Terminating   0         10m
zk-2      0/1       Terminating   0         9m
zk-2      0/1       Terminating   0         9m
zk-2      0/1       Terminating   0         9m
zk-1      0/1       Terminating   0         10m
zk-1      0/1       Terminating   0         10m
zk-1      0/1       Terminating   0         10m
zk-0      0/1       Terminating   0         11m
zk-0      0/1       Terminating   0         11m
zk-0      0/1       Terminating   0         11m

zookeeper.yaml ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ๋‹ค์‹œ ์ ์šฉํ•œ๋‹ค.

kubectl apply -f https://k8s.io/examples/application/zookeeper/zookeeper.yaml

zk ์Šคํ…Œ์ดํŠธํ’€์…‹ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜์ง€๋งŒ, ๋งค๋‹ˆํŽ˜์ŠคํŠธ์— ๋‹ค๋ฅธ API ์˜ค๋ธŒ์ ํŠธ๋Š” ์ด๋ฏธ ์กด์žฌํ•˜๋ฏ€๋กœ ์ˆ˜์ •๋˜์ง€ ์•Š๋Š”๋‹ค.

์Šคํ…Œ์ดํŠธํ’€์…‹ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์Šคํ…ŒํŠธํ’€์…‹์˜ ํŒŒ๋“œ๋ฅผ ์žฌ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•œ๋‹ค.

kubectl get pods -w -l app=zk

zk-2 ํŒŒ๋“œ๊ฐ€ Running๊ณผ Ready๊ฐ€ ๋˜๋ฉด CTRL-C๋ฅผ ์ด์šฉํ•˜์—ฌ kubectl์„ ์ข…๋ฃŒํ•œ๋‹ค.

NAME      READY     STATUS    RESTARTS   AGE
zk-0      0/1       Pending   0          0s
zk-0      0/1       Pending   0         0s
zk-0      0/1       ContainerCreating   0         0s
zk-0      0/1       Running   0         19s
zk-0      1/1       Running   0         40s
zk-1      0/1       Pending   0         0s
zk-1      0/1       Pending   0         0s
zk-1      0/1       ContainerCreating   0         0s
zk-1      0/1       Running   0         18s
zk-1      1/1       Running   0         40s
zk-2      0/1       Pending   0         0s
zk-2      0/1       Pending   0         0s
zk-2      0/1       ContainerCreating   0         0s
zk-2      0/1       Running   0         19s
zk-2      1/1       Running   0         40s

์•„๋ž˜ ๋ช…๋ น์–ด๋กœ ๋ฌด๊ฒฐ์„ฑ ํ…Œ์ŠคํŠธ์—์„œ ์ž…๋ ฅํ•œ ๊ฐ’์„ zk-2 ํŒŒ๋“œ์—์„œ ์–ป์–ด์˜จ๋‹ค.

kubectl exec zk-2 zkCli.sh get /hello

zk ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ๋ชจ๋“  ํŒŒ๋“œ๋ฅผ ์ข…๋ฃŒํ•˜๊ณ  ์žฌ์ƒ์„ฑํ–ˆ์Œ์—๋„, ์•™์ƒ๋ธ”์€ ์—ฌ์ „ํžˆ ์›๋ž˜ ๊ฐ’์„ ๋Œ๋ ค์ค€๋‹ค.

WATCHER::

WatchedEvent state:SyncConnected type:None path:null
world
cZxid = 0x100000002
ctime = Thu Dec 08 15:13:30 UTC 2016
mZxid = 0x100000002
mtime = Thu Dec 08 15:13:30 UTC 2016
pZxid = 0x100000002
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0

zk ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ spec์— volumeClaimTemplates ํ•„๋“œ๋Š” ๊ฐ ํŒŒ๋“œ์— ํ”„๋กœ๋น„์ „๋  ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ์„ ์ง€์ •ํ•œ๋‹ค.

volumeClaimTemplates:
  - metadata:
      name: datadir
      annotations:
        volume.alpha.kubernetes.io/storage-class: anything
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 20Gi

์Šคํ…Œ์ดํŠธํ’€์…‹ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ๊ฐ ํŒŒ๋“œ์— ๋Œ€ํ•œ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจํด๋ ˆ์ž„์„ ์ƒ์„ฑํ•œ๋‹ค.

๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์ด์šฉํ•˜์—ฌ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจํด๋ ˆ์ž„์„ ์‚ดํŽด๋ณด์ž.

kubectl get pvc -l app=zk

์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๋ฅผ ์žฌ์ƒ์„ฑํ•  ๋•Œ์— ํŒŒ๋“œ์˜ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ๋„ ๋‹ค์‹œ ๋งˆ์šดํŠธํ•œ๋‹ค.

NAME           STATUS    VOLUME                                     CAPACITY   ACCESSMODES   AGE
datadir-zk-0   Bound     pvc-bed742cd-bcb1-11e6-994f-42010a800002   20Gi       RWO           1h
datadir-zk-1   Bound     pvc-bedd27d2-bcb1-11e6-994f-42010a800002   20Gi       RWO           1h
datadir-zk-2   Bound     pvc-bee0817e-bcb1-11e6-994f-42010a800002   20Gi       RWO           1h

์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ์ปจํ…Œ์ด๋„ˆ template์˜ volumeMounts ๋ถ€๋ถ„์ด ZooKeeper ์„œ๋ฒ„์˜ ๋ฐ์ดํ„ฐ ๋””๋ ‰ํ„ฐ๋ฆฌ์— ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ ๋งˆ์šดํŠธํ•˜๋Š” ๋‚ด์šฉ์ด๋‹ค.

volumeMounts:
- name: datadir
  mountPath: /var/lib/zookeeper

zk ์Šคํ…Œ์ดํŠธํ’€์…‹์ด (์žฌ)์Šค์ผ€์ค„๋ง๋  ๋•Œ ํ•ญ์ƒ ๋™์ผํ•œ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ์„ ZooKeeper์˜ ์„œ๋ฒ„ ๋””๋ ‰ํ„ฐ๋ฆฌ์— ๋งˆ์šดํŠธํ•œ๋‹ค. ํŒŒ๋“œ๋ฅผ ์žฌ์Šค์ผ€์ค„ํ•  ๋•Œ์—๋„ ZooKeeper์˜ WAL์„ ํ†ตํ•ด ์ด๋ค„์ง„ ๋ชจ๋“  ์“ฐ๊ธฐ์™€ ๋ชจ๋“  ๊ทธ ์Šค๋ƒ…์ƒท๋„ ๋‚ด๊ตฌ์„ฑ์„ ์œ ์ง€ํ•œ๋‹ค.

์ผ๊ด€๋œ ๊ตฌ์„ฑ ๋ณด์žฅํ•˜๊ธฐ

๋ฆฌ๋” ์„ ์ถœ ์ด‰์ง„๊ณผ ํ•ฉ์˜ ๋‹ฌ์„ฑ ์„น์…˜์—์„œ ์•Œ๋ ธ๋“ฏ์ด, ZooKeeper ์•™์ƒ๋ธ”์— ์„œ๋ฒ„๋Š” ๋ฆฌ๋” ์„ ์ถœ๊ณผ ์ฟผ๋Ÿผ์„ ๊ตฌ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ์ผ๊ด€๋œ ์„ค์ •์ด ํ•„์š”ํ•˜๋‹ค. ๋˜ํ•œ Zab ํ”„๋กœํ† ์ฝœ์˜ ์ผ๊ด€๋œ ์„ค์ •๋„ ๋„คํŠธ์›Œํฌ์— ๊ฑธ์ณ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋™์ž‘ํ•˜๊ธฐ ์œ„ํ•ด์„œ ํ•„์š”ํ•˜๋‹ค. ์ด ์˜ˆ์‹œ์—์„œ๋Š” ๋งค๋‹ˆํŽ˜์ŠคํŠธ์— ๊ตฌ์„ฑ์„ ์ง์ ‘ ํฌํ•จ์‹œ์ผœ์„œ ์ผ๊ด€๋œ ๊ตฌ์„ฑ์„ ๋‹ฌ์„ฑํ•œ๋‹ค.

zk ์Šคํ…Œ์ดํŠธํ’€์…‹์„ ์‚ดํŽด๋ณด์ž.

kubectl get sts zk -o yaml
โ€ฆ
command:
      - sh
      - -c
      - "start-zookeeper \
        --servers=3 \
        --data_dir=/var/lib/zookeeper/data \
        --data_log_dir=/var/lib/zookeeper/data/log \
        --conf_dir=/opt/zookeeper/conf \
        --client_port=2181 \
        --election_port=3888 \
        --server_port=2888 \
        --tick_time=2000 \
        --init_limit=10 \
        --sync_limit=5 \
        --heap=512M \
        --max_client_cnxns=60 \
        --snap_retain_count=3 \
        --purge_interval=12 \
        --max_session_timeout=40000 \
        --min_session_timeout=4000 \
        --log_level=INFO"
โ€ฆ

ZooKeeper ์„œ๋ฒ„๋ฅผ ์‹œ์ž‘ํ•˜๋Š”๋ฐ ์‚ฌ์šฉํ•œ ๋ช…๋ น์–ด๋Š” ์ปค๋งจ๋“œ๋ผ์ธ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ํ™˜๊ฒฝ ๊ตฌ์„ฑ์„ ์ „๋‹ฌํ–ˆ๋‹ค. ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ์„œ๋„ ์•™์ƒ๋ธ”์— ํ™˜๊ฒฝ ๊ตฌ์„ฑ์„ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

๋กœ๊น… ์„ค์ •ํ•˜๊ธฐ

zkGenConfig.sh ์Šคํฌ๋ฆฝํŠธ๋กœ ์ƒ์„ฑ๋œ ํŒŒ์ผ ์ค‘ ํ•˜๋‚˜๋Š” ZooKeeper์˜ ๋กœ๊น…์„ ์ œ์–ดํ•œ๋‹ค. ZooKeeper๋Š” Log4j๋ฅผ ์ด์šฉํ•˜๋ฉฐ ๊ธฐ๋ณธ ๋กœ๊น… ๊ตฌ์„ฑ์œผ๋กœ๋Š” ์‹œ๊ฐ„๊ณผ ํŒŒ์ผ ํฌ๊ธฐ ๊ธฐ์ค€์˜ ๋กค๋ง ํŒŒ์ผ ์–ดํŽœ๋”๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

zk ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํ•œ ํŒŒ๋“œ์—์„œ ๋กœ๊น… ์„ค์ •์„ ์‚ดํŽด๋ณด๋Š” ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์ด์šฉํ•˜์ž.

kubectl exec zk-0 cat /usr/etc/zookeeper/log4j.properties

์•„๋ž˜ ๋กœ๊น… ๊ตฌ์„ฑ์€ ZooKeeper๊ฐ€ ๋ชจ๋“  ๋กœ๊ทธ๋ฅผ ํ‘œ์ค€ ์ถœ๋ ฅ ์ŠคํŠธ๋ฆผ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ํ•œ๋‹ค.

zookeeper.root.logger=CONSOLE
zookeeper.console.threshold=INFO
log4j.rootLogger=${zookeeper.root.logger}
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=${zookeeper.console.threshold}
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} [myid:%X{myid}] - %-5p [%t:%C{1}@%L] - %m%n

์ด๋Š” ์ปจํ…Œ์ด๋„ˆ ๋‚ด์—์„œ ์•ˆ์ „ํ•˜๊ฒŒ ๋กœ๊น…ํ•˜๋Š” ๊ฐ€์žฅ ๋‹จ์ˆœํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค. ํ‘œ์ค€ ์ถœ๋ ฅ์œผ๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ๊ทธ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด, ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋Š” ๋กœ๊ทธ ๋กœํ…Œ์ด์…˜์„ ์ฒ˜๋ฆฌํ•œ๋‹ค. ๋˜ํ•œ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ํ‘œ์ค€ ์ถœ๋ ฅ๊ณผ ํ‘œ์ค€ ์˜ค๋ฅ˜์— ์“ฐ์ธ ๋กœ๊ทธ๋กœ ์ธํ•˜์—ฌ ๋กœ์ปฌ ์ €์žฅ ๋ฏธ๋””์–ด๊ฐ€ ๊ณ ๊ฐˆ๋˜์ง€ ์•Š๋„๋ก ๋ณด์žฅํ•˜๋Š” ์ •์ƒ์ ์ธ ๋ณด์กด ์ •์ฑ…์„ ๊ตฌํ˜„ํ•œ๋‹ค.

ํŒŒ๋“œ์˜ ๋งˆ์ง€๋ง‰ 20์ค„์˜ ๋กœ๊ทธ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” kubectl logs ๋ช…๋ น์„ ์ด์šฉํ•˜์ž.

kubectl logs zk-0 --tail 20

kubectl logs๋ฅผ ์ด์šฉํ•˜๊ฑฐ๋‚˜ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋Œ€์‹œ๋ณด๋“œ์—์„œ ํ‘œ์ค€ ์ถœ๋ ฅ๊ณผ ํ‘œ์ค€ ์˜ค๋ฅ˜๋กœ ์“ฐ์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ๊ทธ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

2016-12-06 19:34:16,236 [myid:1] - INFO  [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxn@827] - Processing ruok command from /127.0.0.1:52740
2016-12-06 19:34:16,237 [myid:1] - INFO  [Thread-1136:NIOServerCnxn@1008] - Closed socket connection for client /127.0.0.1:52740 (no session established for client)
2016-12-06 19:34:26,155 [myid:1] - INFO  [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxnFactory@192] - Accepted socket connection from /127.0.0.1:52749
2016-12-06 19:34:26,155 [myid:1] - INFO  [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxn@827] - Processing ruok command from /127.0.0.1:52749
2016-12-06 19:34:26,156 [myid:1] - INFO  [Thread-1137:NIOServerCnxn@1008] - Closed socket connection for client /127.0.0.1:52749 (no session established for client)
2016-12-06 19:34:26,222 [myid:1] - INFO  [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxnFactory@192] - Accepted socket connection from /127.0.0.1:52750
2016-12-06 19:34:26,222 [myid:1] - INFO  [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxn@827] - Processing ruok command from /127.0.0.1:52750
2016-12-06 19:34:26,226 [myid:1] - INFO  [Thread-1138:NIOServerCnxn@1008] - Closed socket connection for client /127.0.0.1:52750 (no session established for client)
2016-12-06 19:34:36,151 [myid:1] - INFO  [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxnFactory@192] - Accepted socket connection from /127.0.0.1:52760
2016-12-06 19:34:36,152 [myid:1] - INFO  [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxn@827] - Processing ruok command from /127.0.0.1:52760
2016-12-06 19:34:36,152 [myid:1] - INFO  [Thread-1139:NIOServerCnxn@1008] - Closed socket connection for client /127.0.0.1:52760 (no session established for client)
2016-12-06 19:34:36,230 [myid:1] - INFO  [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxnFactory@192] - Accepted socket connection from /127.0.0.1:52761
2016-12-06 19:34:36,231 [myid:1] - INFO  [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxn@827] - Processing ruok command from /127.0.0.1:52761
2016-12-06 19:34:36,231 [myid:1] - INFO  [Thread-1140:NIOServerCnxn@1008] - Closed socket connection for client /127.0.0.1:52761 (no session established for client)
2016-12-06 19:34:46,149 [myid:1] - INFO  [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxnFactory@192] - Accepted socket connection from /127.0.0.1:52767
2016-12-06 19:34:46,149 [myid:1] - INFO  [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxn@827] - Processing ruok command from /127.0.0.1:52767
2016-12-06 19:34:46,149 [myid:1] - INFO  [Thread-1141:NIOServerCnxn@1008] - Closed socket connection for client /127.0.0.1:52767 (no session established for client)
2016-12-06 19:34:46,230 [myid:1] - INFO  [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxnFactory@192] - Accepted socket connection from /127.0.0.1:52768
2016-12-06 19:34:46,230 [myid:1] - INFO  [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxn@827] - Processing ruok command from /127.0.0.1:52768
2016-12-06 19:34:46,230 [myid:1] - INFO  [Thread-1142:NIOServerCnxn@1008] - Closed socket connection for client /127.0.0.1:52768 (no session established for client)

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋Š” ๋งŽ์€ ๋กœ๊ทธ ์†”๋ฃจ์…˜๊ณผ ํ†ตํ•ฉ๋œ๋‹ค. ํด๋Ÿฌ์Šคํ„ฐ์™€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๊ฐ€์žฅ ์ ํ•ฉํ•œ ๋กœ๊ทธ ์†”๋ฃจ์…˜์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค. ํด๋Ÿฌ์Šคํ„ฐ ์ˆ˜์ค€์˜ ๋กœ๊ทธ ์ ์žฌ(ship)์™€ ํ†ตํ•ฉ์„ ์œ„ํ•ด์„œ๋Š” ๋กœ๊ทธ ์ˆœํ™˜๊ณผ ์ ์žฌ๋ฅผ ์œ„ํ•ด ์‚ฌ์ด๋“œ์นด ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋ฐฐํฌํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•œ๋‹ค.

๊ถŒํ•œ ์—†๋Š” ์‚ฌ์šฉ์ž๋ฅผ ์œ„ํ•ด ๊ตฌ์„ฑํ•˜๊ธฐ

์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€์˜ ๊ถŒํ•œ์žˆ๋Š” ์œ ์ €๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ์ตœ์ƒ์˜ ๋ฐฉ๋ฒ•์€ ๋…ผ์Ÿ๊ฑฐ๋ฆฌ์ด๋‹ค. ์กฐ์ง์—์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ถŒํ•œ ์—†๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์‹คํ–‰ํ•œ๋‹ค๋ฉด, ์ง„์ž…์ ์„ ์‹คํ–‰ํ•  ์‚ฌ์šฉ์ž๋ฅผ ์ œ์–ดํ•˜๊ธฐ ์œ„ํ•ด ์‹œํ๋ฆฌํ‹ฐ์ปจํ…์ŠคํŠธ๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

zk ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ template์€ SecurityContext๋ฅผ ํฌํ•จํ•œ๋‹ค.

securityContext:
  runAsUser: 1000
  fsGroup: 1000

ํŒŒ๋“œ ์ปจํ…Œ์ด๋„ˆ์—์„œ UID 1000์€ ZooKeeper ์‚ฌ์šฉ์ž์ด๋ฉฐ, GID 1000์€ ZooKeeper์˜ ๊ทธ๋ฃน์— ํ•ด๋‹นํ•œ๋‹ค.

zk-0 ํŒŒ๋“œ์—์„œ ํ”„๋กœ์„ธ์Šค ์ •๋ณด๋ฅผ ์–ป์–ด์˜ค์ž.

kubectl exec zk-0 -- ps -elf

securityContext ์˜ค๋ธŒ์ ํŠธ์˜ runAsUser ํ•„๋“œ ๊ฐ’์ด 1000 ์ด๋ฏ€๋กœ ๋ฃจํŠธ ์‚ฌ์šฉ์ž๋กœ ์‹คํ–‰ํ•˜๋Š” ๋Œ€์‹  ZooKeeper ํ”„๋กœ์„ธ์Šค๋Š” ZooKeeper ์‚ฌ์šฉ์ž๋กœ ์‹คํ–‰๋œ๋‹ค.

F S UID        PID  PPID  C PRI  NI ADDR SZ WCHAN  STIME TTY          TIME CMD
4 S zookeep+     1     0  0  80   0 -  1127 -      20:46 ?        00:00:00 sh -c zkGenConfig.sh && zkServer.sh start-foreground
0 S zookeep+    27     1  0  80   0 - 1155556 -    20:46 ?        00:00:19 /usr/lib/jvm/java-8-openjdk-amd64/bin/java -Dzookeeper.log.dir=/var/log/zookeeper -Dzookeeper.root.logger=INFO,CONSOLE -cp /usr/bin/../build/classes:/usr/bin/../build/lib/*.jar:/usr/bin/../share/zookeeper/zookeeper-3.4.9.jar:/usr/bin/../share/zookeeper/slf4j-log4j12-1.6.1.jar:/usr/bin/../share/zookeeper/slf4j-api-1.6.1.jar:/usr/bin/../share/zookeeper/netty-3.10.5.Final.jar:/usr/bin/../share/zookeeper/log4j-1.2.16.jar:/usr/bin/../share/zookeeper/jline-0.9.94.jar:/usr/bin/../src/java/lib/*.jar:/usr/bin/../etc/zookeeper: -Xmx2G -Xms2G -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only=false org.apache.zookeeper.server.quorum.QuorumPeerMain /usr/bin/../etc/zookeeper/zoo.cfg

๊ธฐ๋ณธ์ ์œผ๋กœ ํŒŒ๋“œ์˜ ํผ์‹œ์Šคํ„ดํŠธ๋ณผ๋ฅจ์€ ZooKeeper ์„œ๋ฒ„์˜ ๋ฐ์ดํ„ฐ ๋””๋ ‰ํ„ฐ๋ฆฌ์— ๋งˆ์šดํŠธ๋˜๊ณ , ๋ฃจํŠธ ์‚ฌ์šฉ์ž๋งŒ์ด ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๋‹ค. ์ด ๊ตฌ์„ฑ์€ ZooKeeper ํ”„๋กœ์„ธ์Šค๊ฐ€ WAL์— ๊ธฐ๋กํ•˜๊ณ  ์Šค๋ƒ…์ƒท์„ ์ €์žฅํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•œ๋‹ค.

zk-0 ํŒŒ๋“œ์˜ ZooKeeper ๋ฐ์ดํ„ฐ ๋””๋ ‰ํ„ฐ๋ฆฌ์˜ ๊ถŒํ•œ์„ ์–ป์–ด์˜ค๋Š” ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์ด์šฉํ•˜์ž.

kubectl exec -ti zk-0 -- ls -ld /var/lib/zookeeper/data

securityContext ์˜ค๋ธŒ์ ํŠธ์˜ fsGroup ํ•„๋“œ ๊ฐ’์ด 1000 ์ด๋ฏ€๋กœ, ํŒŒ๋“œ์˜ ํผ์‹œ์Šคํ„ดํŠธ ๋ณผ๋ฅจ์˜ ์†Œ์œ ๊ถŒ์€ ZooKeeper ๊ทธ๋ฃน์œผ๋กœ ์ง€์ •๋˜์–ด ZooKeeper ํ”„๋กœ์„ธ์Šค์—์„œ ์ฝ๊ณ  ์“ธ ์ˆ˜ ์žˆ๋‹ค.

drwxr-sr-x 3 zookeeper zookeeper 4096 Dec  5 20:45 /var/lib/zookeeper/data

ZooKeeper ํ”„๋กœ์„ธ์Šค ๊ด€๋ฆฌํ•˜๊ธฐ

ZooKeeper ๋ฌธ์„œ์—์„œ๋Š” "ZooKeeper์˜ ์„œ๋ฒ„ ํ”„๋กœ์„ธ์Šค(JVM)์„ ๊ด€๋ฆฌํ•  ๊ฐ๋… ํ”„๋กœ์„ธ์Šค๋ฅผ ํ•„์š”ํ•  ๊ฒƒ์ด๋‹ค."๋ผ๊ณ  ๋งํ•œ๋‹ค. ์™€์น˜๋…(๊ฐ๋… ํ”„๋กœ์„ธ์Šค)๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์‹คํŒจํ•œ ํ”„๋กœ์„ธ์Šค๋ฅผ ์žฌ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์€ ๋ถ„์‚ฐ์‹œ์Šคํ…œ์—์„œ ์ผ๋ฐ˜์ ์ธ ๋ฐฉ์‹์ด๋‹ค. ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์—์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋ฐฐํฌํ•  ๋•Œ์—๋Š” ๊ฐ๋… ํ”„๋กœ์„ธ์Šค๋กœ ์™ธ๋ถ€ ์œ ํ‹ธ๋ฆฌํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋ณด๋‹ค ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋ฅผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์™€์น˜๋…์œผ๋กœ์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

์•™์ƒ๋ธ” ๊ด€๋ฆฌํ•˜๊ธฐ

zk ์Šคํ…Œ์ดํŠธํ’€์…‹์€ RollingUpdate ์—…๋ฐ์ดํŠธ ์ „๋žต์„ ์ด์šฉํ•˜๋„๋ก ๊ตฌ์„ฑ๋˜์—ˆ๋‹ค.

kubectl patch๋กœ ์„œ๋ฒ„์— ํ• ๋‹น๋œ cpu ์ˆ˜๋ฅผ ๊ฐฑ์‹ ํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl patch sts zk --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/resources/requests/cpu", "value":"0.3"}]'
statefulset.apps/zk patched

์—…๋ฐ์ดํŠธ ์ƒํ™ฉ์„ ์ง€์ผœ๋ณด๊ธฐ ์œ„ํ•ด kubectl rollout status ์ด์šฉํ•˜์ž.

kubectl rollout status sts/zk
waiting for statefulset rolling update to complete 0 pods at revision zk-5db4499664...
Waiting for 1 pods to be ready...
Waiting for 1 pods to be ready...
waiting for statefulset rolling update to complete 1 pods at revision zk-5db4499664...
Waiting for 1 pods to be ready...
Waiting for 1 pods to be ready...
waiting for statefulset rolling update to complete 2 pods at revision zk-5db4499664...
Waiting for 1 pods to be ready...
Waiting for 1 pods to be ready...
statefulset rolling update complete 3 pods at revision zk-5db4499664...

์ด๊ฒƒ์€ ํŒŒ๋“œ๋ฅผ ์—ญ์ˆœ์œผ๋กœ ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์”ฉ ์ข…๋ฃŒํ•˜๊ณ , ์ƒˆ๋กœ์šด ๊ตฌ์„ฑ์œผ๋กœ ์žฌ์ƒ์„ฑํ•œ๋‹ค. ์ด๋Š” ๋กค๋ง์—…๋ฐ์ดํŠธ ๋™์•ˆ์— ์ฟผ๋Ÿผ์„ ์œ ์ง€ํ•˜๋„๋ก ๋ณด์žฅํ•œ๋‹ค.

์ด๋ ฅ๊ณผ ์ด์ „ ๊ตฌ์„ฑ์„ ๋ณด๊ธฐ ์œ„ํ•ด kubectl rollout history ๋ช…๋ น์„ ์ด์šฉํ•˜์ž.

kubectl rollout history sts/zk

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๋น„์Šทํ•  ๊ฒƒ์ด๋‹ค.

statefulsets "zk"
REVISION
1
2

์ˆ˜์ •์‚ฌํ•ญ์„ ๋กค๋ฐฑํ•˜๊ธฐ ์œ„ํ•ด kubectl rollout undo ๋ช…๋ น์„ ์ด์šฉํ•˜์ž.

kubectl rollout undo sts/zk

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๋น„์Šทํ•  ๊ฒƒ์ด๋‹ค.

statefulset.apps/zk rolled back

ํ”„๋กœ์„ธ์Šค ์žฅ์•  ๊ด€๋ฆฌํ•˜๊ธฐ

์žฌ์‹œ์ž‘ ์ •์ฑ…์€ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๊ฐ€ ํŒŒ๋“œ ๋‚ด์— ์ปจํ…Œ์ด๋„ˆ์˜ ์ง„์ž…์ ์—์„œ ํ”„๋กœ์„ธ์Šค ์‹คํŒจ๋ฅผ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฃจ๋Š”์ง€ ์ œ์–ดํ•œ๋‹ค. ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ์—์„œ ์˜ค์ง ์ ์ ˆํ•œ ์žฌ์‹œ์ž‘ ์ •์ฑ…๋Š” Always์ด๋ฉฐ ์ด๊ฒƒ์ด ๊ธฐ๋ณธ ๊ฐ’์ด๋‹ค. ์ƒํƒœ๊ฐ€ ์œ ์ง€๋˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์œ„ํ•ด ๊ธฐ๋ณธ ์ •์ฑ…์„ ์ ˆ๋Œ€๋กœ ๋ณ€๊ฒฝํ•˜์ง€ ๋ง์ž.

zk-0 ํŒŒ๋“œ์—์„œ ์‹คํ–‰ ์ค‘์ธ ZooKeeper ์„œ๋ฒ„์—์„œ ํ”„๋กœ์„ธ์Šค ํŠธ๋ฆฌ๋ฅผ ์‚ดํŽด๋ณด๊ธฐ ์œ„ํ•ด ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์ด์šฉํ•˜์ž.

kubectl exec zk-0 -- ps -ef

์ปจํ…Œ์ด๋„ˆ์˜ ์—”ํŠธ๋ฆฌ ํฌ์ธํŠธ๋กœ PID 1 ์ธ ๋ช…๋ น์ด ์‚ฌ์šฉ๋˜์—ˆ์œผ๋ฉฐ ZooKeeper ํ”„๋กœ์„ธ์Šค๋Š” ์—”ํŠธ๋ฆฌ ํฌ์ธํŠธ์˜ ์ž์‹ ํ”„๋กœ์„ธ์Šค๋กœ PID 27 ์ด๋‹ค.

UID        PID  PPID  C STIME TTY          TIME CMD
zookeep+     1     0  0 15:03 ?        00:00:00 sh -c zkGenConfig.sh && zkServer.sh start-foreground
zookeep+    27     1  0 15:03 ?        00:00:03 /usr/lib/jvm/java-8-openjdk-amd64/bin/java -Dzookeeper.log.dir=/var/log/zookeeper -Dzookeeper.root.logger=INFO,CONSOLE -cp /usr/bin/../build/classes:/usr/bin/../build/lib/*.jar:/usr/bin/../share/zookeeper/zookeeper-3.4.9.jar:/usr/bin/../share/zookeeper/slf4j-log4j12-1.6.1.jar:/usr/bin/../share/zookeeper/slf4j-api-1.6.1.jar:/usr/bin/../share/zookeeper/netty-3.10.5.Final.jar:/usr/bin/../share/zookeeper/log4j-1.2.16.jar:/usr/bin/../share/zookeeper/jline-0.9.94.jar:/usr/bin/../src/java/lib/*.jar:/usr/bin/../etc/zookeeper: -Xmx2G -Xms2G -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only=false org.apache.zookeeper.server.quorum.QuorumPeerMain /usr/bin/../etc/zookeeper/zoo.cfg

๋‹ค๋ฅธ ํ„ฐ๋ฏธ๋„์—์„œ ๋‹ค์Œ ๋ช…๋ น์–ด๋กœ zk ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๋ฅผ ํ™•์ธํ•œ๋‹ค.

kubectl get pod -w -l app=zk

๋˜ ๋‹ค๋ฅธ ํ„ฐ๋ฏธ๋„์—์„œ ๋‹ค์Œ ๋ช…๋ น์–ด๋กœ zk-0 ํŒŒ๋“œ์˜ ZooKeeper ํ”„๋กœ์„ธ์Šค๋ฅผ ์ข…๋ฃŒ์‹œํ‚จ๋‹ค.

kubectl exec zk-0 -- pkill java

ZooKeeper ํ”„๋กœ์„ธ์Šค์˜ ์ข…๋ฃŒ๋Š” ๋ถ€๋ชจ ํ”„๋กœ์„ธ์Šค์˜ ์ข…๋ฃŒ๋ฅผ ์ผ์œผํ‚จ๋‹ค. ์ปจํ…Œ์ด๋„ˆ ์žฌ์‹œ์ž‘์ •์ฑ…์ด Always์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ถ€๋ชจ ํ”„๋กœ์„ธ์Šค๋ฅผ ์žฌ์‹œ์ž‘ํ–ˆ๋‹ค.

NAME      READY     STATUS    RESTARTS   AGE
zk-0      1/1       Running   0          21m
zk-1      1/1       Running   0          20m
zk-2      1/1       Running   0          19m
NAME      READY     STATUS    RESTARTS   AGE
zk-0      0/1       Error     0          29m
zk-0      0/1       Running   1         29m
zk-0      1/1       Running   1         29m

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์Šคํฌ๋ฆฝํŠธ(zkServer.sh ๊ฐ™์€)๋ฅผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง์„ ๊ตฌํ˜„ํ•œ ํ”„๋กœ์„ธ์Šค๋ฅผ ์‹œ์ž‘ํ•˜๊ธฐ ์œ„ํ•ด ์ด์šฉํ•œ๋‹ค๋ฉด, ๊ทธ ์Šคํฌ๋ฆฝํŠธ๋Š” ์ž์‹ ํ”„๋กœ์„ธ์Šค์™€ ํ•จ๊ป˜ ๋ฐ˜๋“œ์‹œ ์ข…๋ฃŒ๋˜์–ด์•ผ ํ•œ๋‹ค. ์ด๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๊ฐ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง์„ ๊ตฌํ˜„ํ•œ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์‹คํŒจํ•  ๋•Œ์— ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์žฌ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์„ ๋ณด์ฆํ•œ๋‹ค.

ํ™œ์„ฑ๋„(Liveness) ํ…Œ์ŠคํŠธํ•˜๊ธฐ

์‹คํŒจํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์žฌ์‹œ์ž‘ํ•˜๋„๋ก ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ์€ ๋ถ„์‚ฐ ์‹œ์Šคํ…œ์„ ๊ฑด๊ฐ•ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋Š”๋ฐ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š๋‹ค. ์‹œ์Šคํ…œ์˜ ํ”„๋กœ์„ธ์Šค๋Š” ์‚ด์•„์žˆ์ง€๋งŒ ์‘๋‹ต์ด ์—†์„ ์ˆ˜ ์žˆ๊ณ , ํ˜น์€ ๋‹ค๋ฅธ ๊ฑด๊ฐ•ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ์˜ ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์žˆ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๊ฑด๊ฐ•ํ•˜์ง€ ์•Š๊ณ  ์žฌ์‹œ์ž‘ํ•ด์•ผ๋งŒ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์—๊ฒŒ ์•Œ๋ฆฌ๋„๋ก ํ™œ์„ฑ๋„ ๊ฒ€์‚ฌ๋ฅผ ์ด์šฉํ•ด์•ผ ํ•œ๋‹ค.

zk ์Šคํ…Œ์ดํŠธํ’€์…‹์— ํŒŒ๋“œ template์— ํ™œ์„ฑ๋„ ๊ฒ€์‚ฌ๋ฅผ ๋ช…์‹œํ•œ๋‹ค.

  livenessProbe:
    exec:
      command:
      - sh
      - -c
      - "zookeeper-ready 2181"
    initialDelaySeconds: 15
    timeoutSeconds: 5

๊ฒ€์‚ฌ๋Š” ZooKeeper์˜ ruok 4 ๊ธ€์ž ๋‹จ์–ด๋ฅผ ์ด์šฉํ•ด์„œ ์„œ๋ฒ„์˜ ๊ฑด๊ฐ•์„ ํ…Œ์ŠคํŠธํ•˜๋Š” ๋ฐฐ์‰ฌ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

OK=$(echo ruok | nc 127.0.0.1 $1)
if [ "$OK" == "imok" ]; then
    exit 0
else
    exit 1
fi

ํ•œ ํ„ฐ๋ฏธ๋„์—์„œ zk ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๋ฅผ ์ง€์ผœ๋ณด๊ธฐ ์œ„ํ•ด ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์ด์šฉํ•˜์ž.

kubectl get pod -w -l app=zk

๋‹ค๋ฅธ ์ฐฝ์—์„œ zk-0 ํŒŒ๋“œ์˜ ํŒŒ์ผ์‹œ์Šคํ…œ์—์„œ zookeeper-ready ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ญ์ œํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์ด์šฉํ•˜์ž.

kubectl exec zk-0 -- rm /opt/zookeeper/bin/zookeeper-ready

ZooKeeper์˜ ํ™œ์„ฑ๋„ ๊ฒ€์‚ฌ์— ์‹คํŒจํ•˜๋ฉด, ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋Š” ์ž๋™์œผ๋กœ ํ”„๋กœ์„ธ์Šค๋ฅผ ์žฌ์‹œ์ž‘ํ•˜์—ฌ ์•™์ƒ๋ธ”์— ๊ฑด๊ฐ•ํ•˜์ง€ ์•Š์€ ํ”„๋กœ์„ธ์Šค๋ฅผ ์žฌ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์„ ๋ณด์ฆํ•œ๋‹ค.

kubectl get pod -w -l app=zk
NAME      READY     STATUS    RESTARTS   AGE
zk-0      1/1       Running   0          1h
zk-1      1/1       Running   0          1h
zk-2      1/1       Running   0          1h
NAME      READY     STATUS    RESTARTS   AGE
zk-0      0/1       Running   0          1h
zk-0      0/1       Running   1         1h
zk-0      1/1       Running   1         1h

์ค€๋น„๋„ ํ…Œ์ŠคํŠธ

์ค€๋น„๋„๋Š” ํ™œ์„ฑ๋„์™€ ๋™์ผํ•˜์ง€ ์•Š๋‹ค. ํ”„๋กœ์„ธ์Šค๊ฐ€ ์‚ด์•„ ์žˆ๋‹ค๋ฉด, ์Šค์ผ€์ค„๋ง๋˜๊ณ  ๊ฑด๊ฐ•ํ•˜๋‹ค. ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ค€๋น„๋˜๋ฉด ์ž…๋ ฅ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. ํ™œ์„ฑ๋„๋Š” ํ•„์ˆ˜์ ์ด๋‚˜ ์ค€๋น„๋„์˜ ์กฐ๊ฑด์œผ๋กœ๋Š” ์ถฉ๋ถ„ํ•˜์ง€ ์•Š๋‹ค. ๋ช‡๋ช‡ ๊ฒฝ์šฐ ํŠน๋ณ„ํžˆ ์ดˆ๊ธฐํ™”์™€ ์ข…๋ฃŒ ์‹œ์— ํ”„๋กœ์„ธ์Šค๋Š” ์‚ด์•„์žˆ์ง€๋งŒ ์ค€๋น„๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค.

์ค€๋น„๋„ ๊ฒ€์‚ฌ๋ฅผ ์ง€์ •ํ•˜๋ฉด, ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋Š” ์ค€๋น„๋„๊ฐ€ ํ†ต๊ณผํ•  ๋•Œ๊นŒ์ง€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋„คํŠธ์›Œํฌ ํŠธ๋ž˜ํ”ฝ์„ ์ˆ˜์‹ ํ•˜์ง€ ์•Š๊ฒŒ ํ•œ๋‹ค.

ZooKeeper ์„œ๋ฒ„์—์„œ๋Š” ์ค€๋น„๋„๊ฐ€ ํ™œ์„ฑ๋„๋ฅผ ๋‚ดํฌํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ zookeeper.yaml ๋งค๋‹ˆํŽ˜์ŠคํŠธ์—์„œ ์ค€๋น„๋„ ๊ฒ€์‚ฌ๋Š” ํ™œ์„ฑ๋„ ๊ฒ€์‚ฌ์™€ ๋™์ผํ•˜๋‹ค.

  readinessProbe:
    exec:
      command:
      - sh
      - -c
      - "zookeeper-ready 2181"
    initialDelaySeconds: 15
    timeoutSeconds: 5

ํ™œ์„ฑ๋„์™€ ์ค€๋น„๋„ ๊ฒ€์‚ฌ๊ฐ€ ๋™์ผํ•จ์—๋„ ๋‘˜ ๋‹ค ์ง€์ •ํ•˜๋Š” ๊ฒƒ์€ ์ค‘์š”ํ•˜๋‹ค. ์ด๋Š” ZooKeeper ์•™์ƒ๋ธ”์— ๊ฑด๊ฐ•ํ•œ ์„œ๋ฒ„๋งŒ ์•„๋‹ˆ๋ผ ๋„คํŠธ์›Œํฌ ํŠธ๋ž˜ํ”ฝ์„ ์ˆ˜์‹ ํ•˜๋Š” ๊ฒƒ์„ ๋ณด์žฅํ•œ๋‹ค.

๋…ธ๋“œ ์‹คํŒจ ๋ฐฉ์ง€

ZooKeeper๋Š” ๋ณ€์กฐ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์„ฑ๊ณต์ ์œผ๋กœ ์ปค๋ฐ‹ํ•˜๊ธฐ ์œ„ํ•œ ์„œ๋ฒ„์˜ ์ฟผ๋Ÿผ์ด ํ•„์š”ํ•˜๋‹ค. 3๊ฐœ์˜ ์„œ๋ฒ„ ์•™์ƒ๋ธ”์—์„œ ์„ฑ๊ณต์ ์œผ๋กœ ์ €์žฅํ•˜๋ ค๋ฉด 2๊ฐœ ์„œ๋ฒ„๋Š” ๋ฐ˜๋“œ์‹œ ๊ฑด๊ฐ•ํ•ด์•ผ ํ•œ๋‹ค. ์ฟผ๋Ÿผ ๊ธฐ๋ฐ˜ ์‹œ์Šคํ…œ์—์„œ, ๋ฉค๋ฒ„๋Š” ๊ฐ€์šฉ์„ฑ์„ ๋ณด์žฅํ•˜๋Š” ์‹คํŒจ ์˜์—ญ์— ๊ฑธ์ณ ๋ฐฐํฌ๋œ๋‹ค. ์ค‘๋‹จ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๊ฐœ๋ณ„ ์‹œ์Šคํ…œ์˜ ์†์‹ค๋กœ ์ธํ•ด ๋ชจ๋ฒ” ์‚ฌ๋ก€์—์„œ๋Š” ๋™์ผํ•œ ์‹œ์Šคํ…œ์— ์—ฌ๋Ÿฌ ์ธ์Šคํ„ด์Šค์˜ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์„ ํ•จ๊ป˜ ๋ฐฐ์น˜ํ•˜๋Š” ๊ฒƒ์„ ๋ฐฐ์ œํ•œ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋Š” ๋™์ผ ๋…ธ๋“œ์ƒ์— ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๋ฅผ ์œ„์น˜์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค. ์ƒ์„ฑํ•œ 3๊ฐœ์˜ ์„œ๋ฒ„ ์•™์ƒ๋ธ”์—์„œ 2๊ฐœ์˜ ์„œ๋ฒ„๊ฐ€ ๊ฐ™์€ ๋…ธ๋“œ์— ์žˆ๋‹ค๋ฉด, ๊ทธ ๋…ธ๋“œ๋Š” ์‹คํŒจํ•˜๊ณ  ZooKeeper ์„œ๋น„์Šค ํด๋ผ์ด์–ธํŠธ๋Š” ๊ทธ ํŒŒ๋“œ๋“ค์˜ ์ตœ์†Œ ํ•˜๋‚˜๊ฐ€ ์žฌ์Šค์ผ€์ค„๋ง๋  ๋•Œ๊นŒ์ง€ ์ž‘๋™ ์ค‘๋‹จ์„ ๊ฒฝํ—˜ํ•  ๊ฒƒ์ด๋‹ค.

๋…ธ๋“œ ์‹คํŒจํ•˜๋Š” ์‚ฌ๊ฑด ์ค‘์—๋„ ์ค‘์š” ์‹œ์Šคํ…œ์˜ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์žฌ์Šค์ผ€์ค„๋  ์ˆ˜ ์žˆ๊ฒŒ ํ•ญ์ƒ ์ถ”๊ฐ€์ ์ธ ์šฉ๋Ÿ‰์„ ํ”„๋กœ๋น„์ „ํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ํ•˜๋ฉด ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์Šค์ผ€์ค„๋Ÿฌ๊ฐ€ ZooKeeper ์„œ๋ฒ„ ํ•˜๋‚˜๋ฅผ ๋‹ค์‹œ ์Šค์ผ€์ค„ํ•˜๋Š” ๋™์•ˆ๊นŒ์ง€๋งŒ ์ž‘๋™ ์ค‘๋‹จ๋  ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์„œ๋น„์Šค์—์„œ ๋…ธ๋“œ ์‹คํŒจ๋กœ ์ธํ•œ ๋‹ค์šดํƒ€์ž„์„ ๋ฐฉ์ง€ํ•˜๋ ค ํ•œ๋‹ค๋ฉด, ํŒŒ๋“œ์•ˆํ‹ฐ์–ดํ”ผ๋‹ˆํ‹ฐ๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•œ๋‹ค.

zk ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ์˜ ๋…ธ๋“œ๋ฅผ ์•Œ์•„๋ณด๊ธฐ ์œ„ํ•ด ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์ด์šฉํ•˜์ž.

for i in 0 1 2; do kubectl get pod zk-$i --template {{.spec.nodeName}}; echo ""; done

zk ์Šคํ…Œ์ดํŠธํ’€์…‹์— ๋ชจ๋“  ํŒŒ๋“œ๋Š” ๋‹ค๋ฅธ ๋…ธ๋“œ์— ๋ฐฐํฌ๋œ๋‹ค.

kubernetes-node-cxpk
kubernetes-node-a5aq
kubernetes-node-2g2d

์ด๋Š” zk ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ์— ํŒŒ๋“œ์•ˆํ‹ฐ์–ดํ”ผ๋‹ˆํ‹ฐ(PodAntiAffinity)๋ฅผ ์ง€์ •ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

affinity:
  podAntiAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
            - key: "app"
              operator: In
              values:
                - zk
        topologyKey: "kubernetes.io/hostname"

requiredDuringSchedulingIgnoredDuringExecution ํ•„๋“œ๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์Šค์ผ€์ค„๋Ÿฌ์— topologyKey๋กœ ์ •์˜๋œ ๋„๋ฉ”์ธ์—์„œ app์ด zk๋ผ๊ณ  ๋ ˆ์ด๋ธ”๋ง๋œ ๋‘ ๊ฐœ ํŒŒ๋“œ๊ฐ€ ์œ„์น˜ํ•˜์ง€ ์•Š๋„๋ก ํ•œ๋‹ค. topologyKey kubernetes.io/hostname์€ ๋„๋ฉ”์ธ์ด ๊ฐœ๋ณ„ ๋…ธ๋“œ์ž„์„ ๋‚˜ํƒ€๋‚ธ๋‹ค. ๋‹ค๋ฅธ ๊ทœ์น™๊ณผ ๋ ˆ์ด๋ธ”, ์…€๋ ‰ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•™์ƒ๋ธ”์„ ๋ฌผ๋ฆฌ์ ์ธ, ๋„คํŠธ์›Œํฌ, ์ „์› ์žฅ์•  ๋ถ„์•ผ์— ๊ฑธ์ณ ํ™•์‚ฐํ•˜๋„๋ก ์ด ๊ธฐ๋ฒ•์„ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.

์ƒ์กด ์œ ์ง€

์ด ์„น์…˜์—์„œ๋Š” ๋…ธ๋“œ๋ฅผ ํ†ต์ œ(cordon)ํ•˜๊ณ  ๋น„์šด๋‹ค(drain). ๊ณต์œ ๋œ ํด๋Ÿฌ์Šคํ„ฐ์—์„œ ์ด ํŠœํ† ๋ฆฌ์–ผ์„ ์ง„ํ–‰ํ•œ๋‹ค๋ฉด, ๋‹ค๋ฅธ ํ…Œ๋„ŒํŠธ์— ๋ถ€์ •์ ์ธ ์˜ํ–ฅ์„ ๋น„์น˜์ง€ ์•Š์Œ์„ ๋ณด์ฆํ•ด์•ผ ํ•œ๋‹ค.

์ด์ „ ์„น์…˜์€ ๊ณ„ํš๋˜์ง€ ์•Š์€ ๋…ธ๋“œ ์‹คํŒจ์—์„œ ์‚ด์•„๋‚จ๋„๋ก ์–ด๋–ป๊ฒŒ ํŒŒ๋“œ๋ฅผ ํ™•์‚ฐํ•  ๊ฒƒ์ธ๊ฐ€์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•˜๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ณ„ํš๋œ ์ ๊ฒ€์œผ๋กœ ์ธํ•ด ๋ฐœ์ƒํ•˜๋Š” ์ผ์‹œ์ ์ธ ๋…ธ๋“œ ์‹คํŒจ์— ๋Œ€ํ•œ ๊ณ„ํš๋„ ํ•„์š”ํ•˜๋‹ค.

ํด๋Ÿฌ์Šคํ„ฐ์—์„œ ๋‹ค์Œ ๋ช…๋ น์œผ๋กœ ๋…ธ๋“œ๋ฅผ ์‚ดํŽด๋ณด์ž.

kubectl get nodes

์ด ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” ํด๋Ÿฌ์Šคํ„ฐ๊ฐ€ ์ตœ์†Œ 4๊ฐœ์˜ ๋…ธ๋“œ๋กœ ๊ตฌ์„ฑ๋˜์—ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•œ๋‹ค. ํด๋Ÿฌ์Šคํ„ฐ์˜ ๋…ธ๋“œ๊ฐ€ 4๊ฐœ๋ณด๋‹ค ๋งŽ๋‹ค๋ฉด, kubectl cordon ๋ช…๋ น์„ ์ด์šฉํ•˜์—ฌ 4๊ฐœ ๋…ธ๋“œ๋ฅผ ์ œ์™ธํ•˜๊ณ  ๋‹ค๋ฅธ ๋ชจ๋“  ๋…ธ๋“œ๋ฅผ ํ†ต์ œ(cordon)ํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ 4๊ฐœ ๋…ธ๋“œ๋งŒ ์‚ฌ์šฉํ•˜๋„๋ก ์ œํ•œํ•˜์—ฌ, ๋‹ค์Œ์˜ ์œ ์ง€๋ณด์ˆ˜ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ์˜ˆ์‹œ์—์„œ ์ฃผํ‚คํผ ํŒŒ๋“œ๋ฅผ ์Šค์ผ€์ค„๋งํ•  ๋•Œ ์–ดํ”ผ๋‹ˆํ‹ฐ์™€ PodDisruptionBudget ์ œ์•ฝ์ด ๋ฐœ์ƒํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl cordon <๋…ธ๋“œ-์ด๋ฆ„>

zk-pdb PodDisruptionBudget์„ ์‚ดํŽด๋ณด๊ณ ์ž ์ด ๋ช…๋ น์–ด๋ฅผ ์ด์šฉํ•˜์ž.

kubectl get pdb zk-pdb

max-unavailable ํ•„๋“œ๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๊ฐ€ zk ์Šคํ…Œ์ดํŠธํ’€์…‹์—์„œ ์ตœ๋Œ€ 1๊ฐœ์˜ ํŒŒ๋“œ๋Š” ์–ธ์ œ๋“ ์ง€ ๊ฐ€์šฉํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Œ์„ ๋‚˜ํƒ€๋‚ธ๋‹ค.

NAME      MIN-AVAILABLE   MAX-UNAVAILABLE   ALLOWED-DISRUPTIONS   AGE
zk-pdb    N/A             1                 1

ํ•œ ํ„ฐ๋ฏธ๋„์—์„œ zk ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๋ฅผ ์ง€์ผœ๋ณด๋Š” ์ด ๋ช…๋ น์–ด๋ฅผ ์ด์šฉํ•˜์ž.

kubectl get pods -w -l app=zk

๋‹ค๋ฅธ ํ„ฐ๋ฏธ๋„์—์„œ ํ˜„์žฌ ์Šค์ผ€์ค„๋˜๋Š” ํŒŒ๋“œ์˜ ๋…ธ๋“œ๋ฅผ ์‚ดํŽด๋ณด์ž.

for i in 0 1 2; do kubectl get pod zk-$i --template {{.spec.nodeName}}; echo ""; done

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๋น„์Šทํ•  ๊ฒƒ์ด๋‹ค.

kubernetes-node-pb41
kubernetes-node-ixsl
kubernetes-node-i4c4

zk-0ํŒŒ๋“œ๊ฐ€ ์Šค์ผ€์ค„๋˜๋Š” ๋…ธ๋“œ๋ฅผ ํ†ต์ œํ•˜๊ธฐ ์œ„ํ•ด kubectl drain๋ฅผ ์ด์šฉํ•˜์ž.

kubectl drain $(kubectl get pod zk-0 --template {{.spec.nodeName}}) --ignore-daemonsets --force --delete-emptydir-data

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๋น„์Šทํ•  ๊ฒƒ์ด๋‹ค.

node "kubernetes-node-group-pb41" cordoned

WARNING: Deleting pods not managed by ReplicationController, ReplicaSet, Job, or DaemonSet: fluentd-cloud-logging-kubernetes-node-group-pb41, kube-proxy-kubernetes-node-group-pb41; Ignoring DaemonSet-managed pods: node-problem-detector-v0.1-o5elz
pod "zk-0" deleted
node "kubernetes-node-group-pb41" drained

ํด๋Ÿฌ์Šคํ„ฐ์— 4๊ฐœ ๋…ธ๋“œ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— kubectl drain์ด ์„ฑ๊ณตํ•˜์—ฌ zk-0์„ ๋‹ค๋ฅธ ๋…ธ๋“œ๋กœ ์žฌ์Šค์ผ€์ค„๋ง ๋œ๋‹ค.

NAME      READY     STATUS    RESTARTS   AGE
zk-0      1/1       Running   2          1h
zk-1      1/1       Running   0          1h
zk-2      1/1       Running   0          1h
NAME      READY     STATUS        RESTARTS   AGE
zk-0      1/1       Terminating   2          2h
zk-0      0/1       Terminating   2         2h
zk-0      0/1       Terminating   2         2h
zk-0      0/1       Terminating   2         2h
zk-0      0/1       Pending   0         0s
zk-0      0/1       Pending   0         0s
zk-0      0/1       ContainerCreating   0         0s
zk-0      0/1       Running   0         51s
zk-0      1/1       Running   0         1m

๊ณ„์†ํ•ด์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๋ฅผ ์ฒซ ํ„ฐ๋ฏธ๋„์—์„œ ์ง€์ผœ๋ณด๊ณ  zk-1 ์ด ์Šค์ผ€์ค„๋œ ๋…ธ๋“œ๋ฅผ ๋น„์›Œ๋ณด์ž.

kubectl drain $(kubectl get pod zk-1 --template {{.spec.nodeName}}) --ignore-daemonsets --force --delete-emptydir-data

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๋น„์Šทํ•  ๊ฒƒ์ด๋‹ค.

"kubernetes-node-ixsl" cordoned
WARNING: Deleting pods not managed by ReplicationController, ReplicaSet, Job, or DaemonSet: fluentd-cloud-logging-kubernetes-node-ixsl, kube-proxy-kubernetes-node-ixsl; Ignoring DaemonSet-managed pods: node-problem-detector-v0.1-voc74
pod "zk-1" deleted
node "kubernetes-node-ixsl" drained

zk-1 ํŒŒ๋“œ๋Š” ์Šค์ผ€์ค„๋˜์ง€ ์•Š๋Š”๋ฐ ์ด๋Š” zk StatefulSet์ด ์˜ค์ง 2๊ฐœ ๋…ธ๋“œ๊ฐ€ ์Šค์ผ€์ค„๋˜๋„๋ก ํŒŒ๋“œ๋ฅผ ์œ„์น˜์‹œํ‚ค๋Š” ๊ฒƒ์„ ๊ธˆํ•˜๋Š” PodAntiAffinity ๊ทœ์น™์„ ํฌํ•จํ•˜์˜€๊ธฐ ๋•Œ๋ฌธ์ด๊ณ  ๊ทธ ํŒŒ๋“œ๋Š” Pending ์ƒํƒœ๋กœ ๋‚จ์„ ๊ฒƒ์ด๋‹ค.

kubectl get pods -w -l app=zk

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๋น„์Šทํ•  ๊ฒƒ์ด๋‹ค.

NAME      READY     STATUS    RESTARTS   AGE
zk-0      1/1       Running   2          1h
zk-1      1/1       Running   0          1h
zk-2      1/1       Running   0          1h
NAME      READY     STATUS        RESTARTS   AGE
zk-0      1/1       Terminating   2          2h
zk-0      0/1       Terminating   2         2h
zk-0      0/1       Terminating   2         2h
zk-0      0/1       Terminating   2         2h
zk-0      0/1       Pending   0         0s
zk-0      0/1       Pending   0         0s
zk-0      0/1       ContainerCreating   0         0s
zk-0      0/1       Running   0         51s
zk-0      1/1       Running   0         1m
zk-1      1/1       Terminating   0         2h
zk-1      0/1       Terminating   0         2h
zk-1      0/1       Terminating   0         2h
zk-1      0/1       Terminating   0         2h
zk-1      0/1       Pending   0         0s
zk-1      0/1       Pending   0         0s

๊ณ„์†ํ•ด์„œ ์Šคํ…Œ์ดํŠธํ’€์…‹์˜ ํŒŒ๋“œ๋ฅผ ์ง€์ผœ๋ณด๊ณ  zk-2๊ฐ€ ์Šค์ผ€์ค„๋œ ๋…ธ๋“œ๋ฅผ ๋น„์›Œ๋ณด์ž.

kubectl drain $(kubectl get pod zk-2 --template {{.spec.nodeName}}) --ignore-daemonsets --force --delete-emptydir-data

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๋น„์Šทํ•  ๊ฒƒ์ด๋‹ค.

node "kubernetes-node-i4c4" cordoned

WARNING: Deleting pods not managed by ReplicationController, ReplicaSet, Job, or DaemonSet: fluentd-cloud-logging-kubernetes-node-i4c4, kube-proxy-kubernetes-node-i4c4; Ignoring DaemonSet-managed pods: node-problem-detector-v0.1-dyrog
WARNING: Ignoring DaemonSet-managed pods: node-problem-detector-v0.1-dyrog; Deleting pods not managed by ReplicationController, ReplicaSet, Job, or DaemonSet: fluentd-cloud-logging-kubernetes-node-i4c4, kube-proxy-kubernetes-node-i4c4
There are pending pods when an error occurred: Cannot evict pod as it would violate the pod's disruption budget.
pod/zk-2

kubectl ์„ ์ข…๋ฃŒํ•˜๊ธฐ ์œ„ํ•ด CTRL-C๋ฅผ ์ด์šฉํ•˜์ž.

zk-2๋ฅผ ์ถ”์ถœํ•˜๋Š” ๊ฒƒ์€ zk-budget์„ ์œ„๋ฐ˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์…‹์งธ ๋…ธ๋“œ๋ฅผ ๋น„์šธ ์ˆ˜ ์—†๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ ๋…ธ๋“œ๋Š” ํ†ต์ œ ์ƒํƒœ๋กœ ๋‚จ๋Š”๋‹ค.

zk-0์—์„œ ์˜จ์ „์„ฑ ํ…Œ์ŠคํŠธ ๋•Œ์— ์ž…๋ ฅํ•œ ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๋Š” zkCli.sh๋ฅผ ์ด์šฉํ•˜์ž.

kubectl exec zk-0 zkCli.sh get /hello

PodDisruptionBudget์ด ์กด์ค‘๋˜๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋น„์Šค๋Š” ์—ฌ์ „ํžˆ ๊ฐ€์šฉํ•˜๋‹ค.

WatchedEvent state:SyncConnected type:None path:null
world
cZxid = 0x200000002
ctime = Wed Dec 07 00:08:59 UTC 2016
mZxid = 0x200000002
mtime = Wed Dec 07 00:08:59 UTC 2016
pZxid = 0x200000002
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0

kubectl uncordon ์ด์šฉํ•˜์—ฌ ์ฒซ ๋…ธ๋“œ์˜ ํ†ต์ œ๋ฅผ ํ’€์ž.

kubectl uncordon kubernetes-node-pb41

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๋น„์Šทํ•  ๊ฒƒ์ด๋‹ค.

node "kubernetes-node-pb41" uncordoned

zk-1์€ ์ด ๋…ธ๋“œ์—์„œ ์žฌ์Šค์ผ€์ค„๋œ๋‹ค. zk-1์ด Running๊ณผ Ready๊ฐ€ ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ž.

kubectl get pods -w -l app=zk

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๋น„์Šทํ•  ๊ฒƒ์ด๋‹ค.

NAME      READY     STATUS    RESTARTS   AGE
zk-0      1/1       Running   2          1h
zk-1      1/1       Running   0          1h
zk-2      1/1       Running   0          1h
NAME      READY     STATUS        RESTARTS   AGE
zk-0      1/1       Terminating   2          2h
zk-0      0/1       Terminating   2         2h
zk-0      0/1       Terminating   2         2h
zk-0      0/1       Terminating   2         2h
zk-0      0/1       Pending   0         0s
zk-0      0/1       Pending   0         0s
zk-0      0/1       ContainerCreating   0         0s
zk-0      0/1       Running   0         51s
zk-0      1/1       Running   0         1m
zk-1      1/1       Terminating   0         2h
zk-1      0/1       Terminating   0         2h
zk-1      0/1       Terminating   0         2h
zk-1      0/1       Terminating   0         2h
zk-1      0/1       Pending   0         0s
zk-1      0/1       Pending   0         0s
zk-1      0/1       Pending   0         12m
zk-1      0/1       ContainerCreating   0         12m
zk-1      0/1       Running   0         13m
zk-1      1/1       Running   0         13m

zk-2๊ฐ€ ์Šค์ผ€์ค„๋œ ๋…ธ๋“œ๋ฅผ ๋น„์›Œ๋ณด์ž.

kubectl drain $(kubectl get pod zk-2 --template {{.spec.nodeName}}) --ignore-daemonsets --force --delete-emptydir-data

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๋น„์Šทํ•  ๊ฒƒ์ด๋‹ค.

node "kubernetes-node-i4c4" already cordoned
WARNING: Deleting pods not managed by ReplicationController, ReplicaSet, Job, or DaemonSet: fluentd-cloud-logging-kubernetes-node-i4c4, kube-proxy-kubernetes-node-i4c4; Ignoring DaemonSet-managed pods: node-problem-detector-v0.1-dyrog
pod "heapster-v1.2.0-2604621511-wht1r" deleted
pod "zk-2" deleted
node "kubernetes-node-i4c4" drained

์ด๋ฒˆ์—” kubectl drain ์ด ์„ฑ๊ณตํ•œ๋‹ค.

zk-2๊ฐ€ ์žฌ์Šค์ผ€์ค„๋˜๋„๋ก ๋‘ ๋ฒˆ์งธ ๋…ธ๋“œ์˜ ํ†ต์ œ๋ฅผ ํ’€์–ด๋ณด์ž.

kubectl uncordon kubernetes-node-ixsl

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๋น„์Šทํ•  ๊ฒƒ์ด๋‹ค.

node "kubernetes-node-ixsl" uncordoned

kubectl drain์„ PodDisruptionBudget๊ณผ ๊ฒฐํ•ฉํ•˜๋ฉด ์œ ์ง€๋ณด์ˆ˜ ์ค‘์—๋„ ์„œ๋น„์Šค๋ฅผ ๊ฐ€์šฉํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค. drain์œผ๋กœ ๋…ธ๋“œ๋ฅผ ํ†ต์ œํ•˜๊ณ  ์œ ์ง€๋ณด์ˆ˜๋ฅผ ์œ„ํ•ด ๋…ธ๋“œ๋ฅผ ์˜คํ”„๋ผ์ธํ•˜๊ธฐ ์ „์— ํŒŒ๋“œ๋ฅผ ์ถ”์ถœํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์„œ๋น„์Šค๋Š” ํ˜ผ๋ž€ ์˜ˆ์‚ฐ์„ ํ‘œ๊ธฐํ•œ ์„œ๋น„์Šค๋Š” ๊ทธ ์˜ˆ์‚ฐ์ด ์กด์ค‘์€ ์กด์ค‘๋  ๊ฒƒ์ด๋‹ค. ํŒŒ๋“œ๊ฐ€ ์ฆ‰๊ฐ์ ์œผ๋กœ ์žฌ์Šค์ผ€์ค„ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ญ์ƒ ์ค‘์š” ์„œ๋น„์Šค๋ฅผ ์œ„ํ•œ ์ถ”๊ฐ€ ์šฉ๋Ÿ‰์„ ํ• ๋‹นํ•ด์•ผ ํ•œ๋‹ค.

์ •๋ฆฌํ•˜๊ธฐ

  • kubectl uncordon์€ ํด๋Ÿฌ์Šคํ„ฐ ๋‚ด์— ๋ชจ๋“  ๋…ธ๋“œ๋ฅผ ํ†ต์ œ ํ•ด์ œํ•œ๋‹ค.
  • ๋ฐ˜๋“œ์‹œ ์ด ํŠœํ† ๋ฆฌ์–ผ์—์„œ ์‚ฌ์šฉํ•œ ํผ์‹œ์Šคํ„ดํŠธ ๋ณผ๋ฅจ์„ ์œ„ํ•œ ํผ์‹œ์Šคํ„ดํŠธ ์Šคํ† ๋ฆฌ์ง€ ๋ฏธ๋””์–ด๋ฅผ ์‚ญ์ œํ•˜์ž. ๊ท€ํ•˜์˜ ํ™˜๊ฒฝ๊ณผ ์Šคํ† ๋ฆฌ์ง€ ๊ตฌ์„ฑ๊ณผ ํ”„๋กœ๋น„์ €๋‹ ๋ฐฉ๋ฒ•์—์„œ ํ•„์š”ํ•œ ์ ˆ์ฐจ๋ฅผ ๋”ฐ๋ผ์„œ ๋ชจ๋“  ์Šคํ† ๋ฆฌ์ง€๊ฐ€ ์žฌํ™•๋ณด๋˜๋„๋ก ํ•˜์ž.

7 - ์„œ๋น„์Šค

7.1 - ์„œ๋น„์Šค์™€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์—ฐ๊ฒฐํ•˜๊ธฐ

์ปจํ…Œ์ด๋„ˆ ์—ฐ๊ฒฐ์„ ์œ„ํ•œ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋ชจ๋ธ

์ง€์†์ ์œผ๋กœ ์‹คํ–‰์ค‘์ด๊ณ , ๋ณต์ œ๋œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋ฉด ๋„คํŠธ์›Œํฌ์— ๋…ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋Š” ํŒŒ๋“œ๊ฐ€ ๋ฐฐ์น˜๋œ ํ˜ธ์ŠคํŠธ์™€๋Š” ๋ฌด๊ด€ํ•˜๊ฒŒ ๋‹ค๋ฅธ ํŒŒ๋“œ์™€ ํ†ต์‹ ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•œ๋‹ค. ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋Š” ๋ชจ๋“  ํŒŒ๋“œ์—๊ฒŒ ์ž์ฒด ํด๋Ÿฌ์Šคํ„ฐ-ํ”„๋ผ์ด๋น— IP ์ฃผ์†Œ๋ฅผ ์ œ๊ณตํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํŒŒ๋“œ๊ฐ„์— ๋ช…์‹œ์ ์œผ๋กœ ๋งํฌ๋ฅผ ๋งŒ๋“ค๊ฑฐ๋‚˜ ์ปจํ…Œ์ด๋„ˆ ํฌํŠธ๋ฅผ ํ˜ธ์ŠคํŠธ ํฌํŠธ์— ๋งคํ•‘ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. ์ด๊ฒƒ์€ ํŒŒ๋“œ ๋‚ด์˜ ์ปจํ…Œ์ด๋„ˆ๋Š” ๋ชจ๋‘ ๋กœ์ปฌํ˜ธ์ŠคํŠธ(localhost)์—์„œ ์„œ๋กœ์˜ ํฌํŠธ์— ๋„๋‹ฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ํด๋Ÿฌ์Šคํ„ฐ์˜ ๋ชจ๋“  ํŒŒ๋“œ๋Š” NAT ์—†์ด ์„œ๋กœ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค. ์ด ๋ฌธ์„œ์˜ ๋‚˜๋จธ์ง€ ๋ถ€๋ถ„์—์„œ๋Š” ์ด๋Ÿฌํ•œ ๋„คํŠธ์›Œํ‚น ๋ชจ๋ธ์—์„œ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ์„œ๋น„์Šค๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์„ค๋ช…ํ•  ๊ฒƒ์ด๋‹ค.

์ด ํŠœํ† ๋ฆฌ์–ผ์€ ๊ฐ„๋‹จํ•œ nginx ์„œ๋ฒ„๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐœ๋…์„ ์‹œ์—ฐํ•œ๋‹ค.

ํŒŒ๋“œ๋ฅผ ํด๋Ÿฌ์Šคํ„ฐ์— ๋…ธ์ถœํ•˜๊ธฐ

์ด ์ž‘์—…์€ ์ด์ „ ์˜ˆ์‹œ์—์„œ ์ˆ˜ํ–‰ํ•ด ๋ณด์•˜์ง€๋งŒ, ๋„คํŠธ์›Œํ‚น ๊ด€์ ์„ ์ค‘์ ์— ๋‘๊ณ  ๋‹ค์‹œ ํ•œ๋ฒˆ ์ˆ˜ํ–‰ํ•ด ๋ณด์ž. nginx ํŒŒ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ํ•ด๋‹น ํŒŒ๋“œ์— ์ปจํ…Œ์ด๋„ˆ ํฌํŠธ ์‚ฌ์–‘์ด ์žˆ๋Š” ๊ฒƒ์„ ์ฐธ๊ณ ํ•œ๋‹ค.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํด๋Ÿฌ์Šคํ„ฐ์˜ ๋ชจ๋“  ๋…ธ๋“œ์—์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค. ํŒŒ๋“œ๋ฅผ ์‹คํ–‰ ์ค‘์ธ ๋…ธ๋“œ๋ฅผ ํ™•์ธํ•œ๋‹ค.

kubectl apply -f ./run-my-nginx.yaml
kubectl get pods -l run=my-nginx -o wide
NAME                        READY     STATUS    RESTARTS   AGE       IP            NODE
my-nginx-3800858182-jr4a2   1/1       Running   0          13s       10.244.3.4    kubernetes-minion-905m
my-nginx-3800858182-kna2y   1/1       Running   0          13s       10.244.2.5    kubernetes-minion-ljyd

ํŒŒ๋“œ์˜ IP๋ฅผ ํ™•์ธํ•œ๋‹ค.

kubectl get pods -l run=my-nginx -o custom-columns=POD_IP:.status.podIPs
    POD_IP
    [map[ip:10.244.3.4]]
    [map[ip:10.244.2.5]]

์ด์ œ ํด๋Ÿฌ์Šคํ„ฐ์˜ ๋ชจ๋“  ๋…ธ๋“œ๋กœ ssh ์ ‘์†ํ•˜๊ฑฐ๋‚˜ curl๊ณผ ๊ฐ™์€ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‘ IP ์ฃผ์†Œ์— ์งˆ์˜๋ฅผ ์ „์†กํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค. ์ปจํ…Œ์ด๋„ˆ๋Š” ๋…ธ๋“œ์˜ ํฌํŠธ 80์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉฐ , ํŠธ๋ž˜ํ”ฝ์„ ํŒŒ๋“œ๋กœ ๋ผ์šฐํŒ…ํ•˜๋Š” ํŠน๋ณ„ํ•œ NAT ๊ทœ์น™๋„ ์—†๋‹ค๋Š” ๊ฒƒ์„ ์ฐธ๊ณ ํ•œ๋‹ค. ์ด๊ฒƒ์€ ๋™์ผํ•œ containerPort๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋™์ผํ•œ ๋…ธ๋“œ์—์„œ ์—ฌ๋Ÿฌ nginx ํŒŒ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๊ณ , ๋˜ํ•œ ์„œ๋น„์Šค์— ํ• ๋‹น๋œ IP ์ฃผ์†Œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํด๋Ÿฌ์Šคํ„ฐ์˜ ๋‹ค๋ฅธ ํŒŒ๋“œ๋‚˜ ๋…ธ๋“œ์—์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค. ํ˜ธ์ŠคํŠธ ๋…ธ๋“œ์˜ ํŠน์ • ํฌํŠธ๋ฅผ ๋ฐฐํ›„(backing) ํŒŒ๋“œ๋กœ ํฌ์›Œ๋“œํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, ๊ฐ€๋Šฅ์€ ํ•˜์ง€๋งŒ ๋„คํŠธ์›Œํ‚น ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ทธ๋ ‡๊ฒŒ ํ•  ํ•„์š”๊ฐ€ ์—†์–ด์•ผ ํ•œ๋‹ค.

๋งŒ์•ฝ ๊ถ๊ธˆํ•˜๋‹ค๋ฉด ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋„คํŠธ์›Œํ‚น ๋ชจ๋ธ์„ ์ž์„ธํžˆ ์ฝ์–ด๋ณธ๋‹ค.

์„œ๋น„์Šค ์ƒ์„ฑํ•˜๊ธฐ

์ด์ œ ์šฐ๋ฆฌ์—๊ฒŒ๋Š” ํ”Œ๋žซ(flat)ํ•˜๊ณ  ํด๋Ÿฌ์Šคํ„ฐ ์ „์—ญ์— ๊ฑธ์น˜๋Š” ์ฃผ์†Œ ๊ณต๊ฐ„์—์„œ ์‹คํ–‰๋˜๊ณ  ์žˆ๋Š” nginx ํŒŒ๋“œ๊ฐ€ ์žˆ๋‹ค. ์ด๋ก ์ ์œผ๋กœ๋Š” ์ด๋Ÿฌํ•œ ํŒŒ๋“œ์™€ ์ง์ ‘ ๋Œ€ํ™”ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋…ธ๋“œ๊ฐ€ ์ฃฝ์œผ๋ฉด ์–ด๋–ป๊ฒŒ ๋˜๋Š”๊ฐ€? ํŒŒ๋“œ๊ฐ€ ํ•จ๊ป˜ ์ฃฝ์œผ๋ฉด ๋””ํ”Œ๋กœ์ด๋จผํŠธ์—์„œ ๋‹ค๋ฅธ IP๋ฅผ ๊ฐ€์ง„ ์ƒˆ๋กœ์šด ํŒŒ๋“œ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋กœ ์„œ๋น„์Šค์ด๋‹ค.

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์„œ๋น„์Šค๋Š” ํด๋Ÿฌ์Šคํ„ฐ ์–ด๋”˜๊ฐ€์—์„œ ์‹คํ–‰๋˜๋Š” ๋…ผ๋ฆฌ์ ์ธ ํŒŒ๋“œ ์ง‘ํ•ฉ์„ ์ •์˜ํ•˜๊ณ  ์ถ”์ƒํ™”ํ•จ์œผ๋กœ์จ ๋ชจ๋‘ ๋™์ผํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค. ์ƒ์„ฑ์‹œ ๊ฐ ์„œ๋น„์Šค์—๋Š” ๊ณ ์œ ํ•œ IP ์ฃผ์†Œ(clusterIP๋ผ๊ณ ๋„ ํ•œ๋‹ค)๊ฐ€ ํ• ๋‹น๋œ๋‹ค. ์ด ์ฃผ์†Œ๋Š” ์„œ๋น„์Šค์˜ ์ˆ˜๋ช…๊ณผ ์—ฐ๊ด€๋˜์–ด ์žˆ์œผ๋ฉฐ, ์„œ๋น„์Šค๊ฐ€ ํ™œ์„ฑํ™” ๋˜์–ด ์žˆ๋Š” ๋™์•ˆ์—๋Š” ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š”๋‹ค. ํŒŒ๋“œ๋Š” ์„œ๋น„์Šค์™€ ํ†ต์‹ ํ•˜๋„๋ก ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์„œ๋น„์Šค์™€์˜ ํ†ต์‹ ์€ ์„œ๋น„์Šค์˜ ๋งด๋ฒ„ ์ค‘ ์ผ๋ถ€ ํŒŒ๋“œ์— ์ž๋™์ ์œผ๋กœ ๋กœ๋“œ-๋ฐธ๋Ÿฐ์‹ฑ ๋œ๋‹ค.

kubectl expose ๋ฅผ ์‚ฌ์šฉํ•ด์„œ 2๊ฐœ์˜ nginx ๋ ˆํ”Œ๋ฆฌ์นด์— ๋Œ€ํ•œ ์„œ๋น„์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl expose deployment/my-nginx
service/my-nginx exposed

์ด๊ฒƒ์€ ๋‹ค์Œ yaml ํŒŒ์ผ์„ kubectl apply -f ๋กœ ์‹คํ–‰ํ•œ ๊ฒƒ๊ณผ ๋™์ผํ•˜๋‹ค.

apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    run: my-nginx

์ด ์‚ฌ์–‘์€ run: my-nginx ๋ ˆ์ด๋ธ”์ด ๋ถ€์ฐฉ๋œ ๋ชจ๋“  ํŒŒ๋“œ์— TCP ํฌํŠธ 80์„ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“ค๊ณ  ์ถ”์ƒํ™”๋œ ์„œ๋น„์Šค ํฌํŠธ์— ๋…ธ์ถœ์‹œํ‚จ๋‹ค (targetPort ๋Š” ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ํŠธ๋ž˜ํ”ฝ์„ ์ˆ˜์‹ ํ•˜๋Š” ํฌํŠธ, port ๋Š” ์ถ”์ƒํ™”๋œ ์„œ๋น„์Šค ํฌํŠธ๋กœ ๋‹ค๋ฅธ ํŒŒ๋“œ๋“ค์ด ์„œ๋น„์Šค์— ์ ‘์†ํ•˜๊ธฐ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  ํฌํŠธ์ผ ์ˆ˜ ์žˆ๋‹ค). ์„œ๋น„์Šค์˜ API ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๋ณด๊ณ  ์„œ๋น„์Šค ์ •์˜์—์„œ ์ง€์›๋˜๋Š” ํ•„๋“œ ๋ชฉ๋ก์„ ํ™•์ธํ•œ๋‹ค. ์„œ๋น„์Šค๋ฅผ ํ™•์ธํ•œ๋‹ค.

kubectl get svc my-nginx
NAME       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
my-nginx   ClusterIP   10.0.162.149   <none>        80/TCP    21s

์•ž์—์„œ ์–ธ๊ธ‰ํ•œ ๋ฐ”์™€ ๊ฐ™์ด, ์„œ๋น„์Šค ๋ฐ‘์—๋Š” ์—ฌ๋Ÿฌ ํŒŒ๋“œ๋“ค์ด ์žˆ๋‹ค. ์ด ํŒŒ๋“œ๋“ค์€ ์—”๋“œํฌ์ธํŠธ์Šฌ๋ผ์ด์Šค(EndpointSlice)๋ฅผ ํ†ตํ•ด ๋…ธ์ถœ๋œ๋‹ค. ํ•ด๋‹น ์„œ๋น„์Šค์˜ ์…€๋ ‰ํ„ฐ๋Š” ์ง€์†์ ์œผ๋กœ ํ‰๊ฐ€๋˜๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋Š” ๋ ˆ์ด๋ธ”์„ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋น„์Šค์— ์—ฐ๊ฒฐ๋œ ์—”๋“œํฌ์ธํŠธ์Šฌ๋ผ์ด์Šค๋กœ POST๋œ๋‹ค. ํŒŒ๋“œ๊ฐ€ ์ฃฝ์œผ๋ฉด, ํ•ด๋‹น ํŒŒ๋“œ๋ฅผ ์—”๋“œํฌ์ธํŠธ๋กœ ๊ฐ–๋Š” ์—”๋“œํฌ์ธํŠธ์Šฌ๋ผ์ด์Šค์—์„œ ์ž๋™์œผ๋กœ ์ œ๊ฑฐ๋œ๋‹ค. ์‹ ๊ทœ ํŒŒ๋“œ๊ฐ€ ํŠน์ • ์„œ๋น„์Šค์˜ ์…€๋ ‰ํ„ฐ์— ๋งค์น˜๋˜๋ฉด ํ•ด๋‹น ์„œ๋น„์Šค๋ฅผ ์œ„ํ•œ ์—”๋“œํฌ์ธํŠธ์Šฌ๋ผ์ด์Šค์— ์ž๋™์œผ๋กœ ์ถ”๊ฐ€๋œ๋‹ค. ์—”๋“œํฌ์ธํŠธ๋ฅผ ํ™•์ธํ•ด ๋ณด๋ฉด, IP๊ฐ€ ์ฒซ ๋ฒˆ์งธ ๋‹จ๊ณ„์—์„œ ์ƒ์„ฑ๋œ ํŒŒ๋“œ์˜ IP์™€ ๋™์ผํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

kubectl describe svc my-nginx
Name:                my-nginx
Namespace:           default
Labels:              run=my-nginx
Annotations:         <none>
Selector:            run=my-nginx
Type:                ClusterIP
IP:                  10.0.162.149
Port:                <unset> 80/TCP
Endpoints:           10.244.2.5:80,10.244.3.4:80
Session Affinity:    None
Events:              <none>
kubectl get ep my-nginx
NAME       ENDPOINTS                     AGE
my-nginx   10.244.2.5:80,10.244.3.4:80   1m

์ด์ œ ํด๋Ÿฌ์Šคํ„ฐ์˜ ๋ชจ๋“  ๋…ธ๋“œ์—์„œ <CLUSTER-IP>:<PORT> ๋กœ nginx ์„œ๋น„์Šค๋ฅผ curl์„ ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค. ์„œ๋น„์Šค IP๋Š” ์™„์ „ํžˆ ๊ฐ€์ƒ์ด๋ฏ€๋กœ ์™ธ๋ถ€์—์„œ๋Š” ์ ˆ๋Œ€๋กœ ์—ฐ๊ฒฐ๋˜์ง€ ์•Š์Œ์— ์ฐธ๊ณ ํ•œ๋‹ค. ๋งŒ์•ฝ ์ด๊ฒƒ์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ๊ถ๊ธˆํ•˜๋‹ค๋ฉด ์„œ๋น„์Šค ํ”„๋ก์‹œ์— ๋Œ€ํ•ด ๋” ์ฝ์–ด๋ณธ๋‹ค.

์„œ๋น„์Šค์— ์ ‘๊ทผํ•˜๊ธฐ

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋Š” ์„œ๋น„์Šค๋ฅผ ์ฐพ๋Š” ๋‘ ๊ฐ€์ง€ ๊ธฐ๋ณธ ๋ชจ๋“œ์ธ ํ™˜๊ฒฝ ๋ณ€์ˆ˜์™€ DNS๋ฅผ ์ง€์›ํ•œ๋‹ค. ์ „์ž๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ž‘๋™ํ•˜์ง€๋งŒ ํ›„์ž๋Š” CoreDNS ํด๋Ÿฌ์Šคํ„ฐ ์• ๋“œ์˜จ์ด ํ•„์š”ํ•˜๋‹ค.

ํ™˜๊ฒฝ ๋ณ€์ˆ˜

ํŒŒ๋“œ๊ฐ€ ๋…ธ๋“œ์—์„œ ์‹คํ–‰๋  ๋•Œ kubelet์€ ๊ฐ๊ธฐ ํ™œ์„ฑํ™”๋œ ์„œ๋น„์Šค์— ๋Œ€ํ•ด ์ผ๋ จ์˜ ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์ง‘ํ•ฉ์„ ์ถ”๊ฐ€ํ•œ๋‹ค. ์ด๊ฒƒ์€ ์ˆœ์„œ ๋ฌธ์ œ๋ฅผ ์•ผ๊ธฐํ•œ๋‹ค. ์ด์œ ๋ฅผ ํ™•์ธํ•˜๋ ค๋ฉด ์‹คํ–‰ ์ค‘์ธ nginx ํŒŒ๋“œ ํ™˜๊ฒฝ์„ ์ ๊ฒ€ํ•ด์•ผ ํ•œ๋‹ค(์‹ค์ œ ์‚ฌ์šฉ์ž์˜ ํŒŒ๋“œ ์ด๋ฆ„์€ ๋‹ค๋ฅผ ๊ฒƒ์ด๋‹ค).

kubectl exec my-nginx-3800858182-jr4a2 -- printenv | grep SERVICE
KUBERNETES_SERVICE_HOST=10.0.0.1
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443

์„œ๋น„์Šค์— ๋Œ€ํ•œ ์–ธ๊ธ‰์ด ์—†๋‹ค๋Š” ๊ฒƒ์— ์ฐธ๊ณ ํ•ด์•ผ ํ•œ๋‹ค. ์ด๊ฒƒ์€ ์„œ๋น„์Šค ์ด์ „์— ๋ ˆํ”Œ๋ฆฌ์นด๋ฅผ ์ƒ์„ฑํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ๋•Œ ๋˜ ๋‹ค๋ฅธ ๋‹จ์ ์€ ์Šค์ผ€์ค„๋Ÿฌ๊ฐ€ ๋‘ ํŒŒ๋“œ๋ฅผ ๋ชจ๋‘ ๋™์ผํ•œ ๋จธ์‹ ์— ๋ฐฐ์น˜ํ•  ์ˆ˜๋„ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋ฉฐ, ์ด๋กœ ์ธํ•ด ์ „์ฒด ์„œ๋น„์Šค๊ฐ€ ์ค‘๋‹จ๋  ์ˆ˜ ์žˆ๋‹ค. ๋‘๊ฐœ์˜ ํŒŒ๋“œ๋ฅผ ์ฃฝ์ด๊ณ  ๋””ํ”Œ๋กœ์ด๋จผํŠธ๊ฐ€ ํŒŒ๋“œ๋ฅผ ์žฌ์ƒ์„ฑํ•˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ฒƒ์œผ๋กœ ์ด๋ฅผ ์ •์ƒํ™” ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฒˆ์—๋Š” ์„œ๋น„์Šค๊ฐ€ ๋ ˆํ”Œ๋ฆฌ์นด๋“ค ์ „ ์— ์กด์žฌํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์˜ฌ๋ฐ”๋ฅธ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํŒŒ๋“œ์˜ ์Šค์ผ€์ค„๋Ÿฌ-์ˆ˜์ค€์˜ ์„œ๋น„์Šค ๋ถ„๋ฐฐ(๋ชจ๋“  ๋…ธ๋“œ์— ๋™์ผํ•œ ์šฉ๋Ÿ‰์ด ์ œ๊ณต๋˜๋Š” ๊ฒฝ์šฐ)๊ฐ€ ๋œ๋‹ค.

kubectl scale deployment my-nginx --replicas=0; kubectl scale deployment my-nginx --replicas=2;

kubectl get pods -l run=my-nginx -o wide
NAME                        READY     STATUS    RESTARTS   AGE     IP            NODE
my-nginx-3800858182-e9ihh   1/1       Running   0          5s      10.244.2.7    kubernetes-minion-ljyd
my-nginx-3800858182-j4rm4   1/1       Running   0          5s      10.244.3.8    kubernetes-minion-905m

ํŒŒ๋“œ๊ฐ€ ์ฃฝ๊ณ  ์žฌ์ƒ์„ฑ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ ์ด๋ฆ„์„ ๊ฐ€์ง€๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

kubectl exec my-nginx-3800858182-e9ihh -- printenv | grep SERVICE
KUBERNETES_SERVICE_PORT=443
MY_NGINX_SERVICE_HOST=10.0.162.149
KUBERNETES_SERVICE_HOST=10.0.0.1
MY_NGINX_SERVICE_PORT=80
KUBERNETES_SERVICE_PORT_HTTPS=443

DNS

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋Š” DNS ํด๋Ÿฌ์Šคํ„ฐ ์• ๋“œ์˜จ ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ dns ์ด๋ฆ„์„ ๋‹ค๋ฅธ ์„œ๋น„์Šค์— ์ž๋™์œผ๋กœ ํ• ๋‹นํ•œ๋‹ค. ๋‹ค์Œ ๋ช…๋ น์–ด๋กœ ์ด๊ฒƒ์ด ํด๋Ÿฌ์Šคํ„ฐ์—์„œ ์‹คํ–‰ ์ค‘์ธ์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl get services kube-dns --namespace=kube-system
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
kube-dns   ClusterIP   10.0.0.10    <none>        53/UDP,53/TCP   8m

์ด ์„น์…˜์˜ ๋‚˜๋จธ์ง€ ๋ถ€๋ถ„์—์„œ๋Š” ์ˆ˜๋ช…์ด ๊ธด IP์˜ ์„œ๋น„์Šค(my-nginx)์™€ ์ด IP ์— ์ด๋ฆ„์„ ํ• ๋‹นํ•œ DNS ์„œ๋ฒ„๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” CoreDNS ํด๋Ÿฌ์Šคํ„ฐ ์• ๋“œ์˜จ(์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ด๋ฆ„ kube-dns)์„ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ, ํ‘œ์ค€ ๋ฐฉ๋ฒ•(์˜ˆ: gethostbyname())์„ ์‚ฌ์šฉํ•ด์„œ ํด๋Ÿฌ์Šคํ„ฐ์˜ ๋ชจ๋“  ํŒŒ๋“œ์—์„œ ์„œ๋น„์Šค์™€ ํ†ต์‹ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋งŒ์•ฝ CoreDNS๊ฐ€ ์‹คํ–‰ ์ค‘์ด ์•„๋‹ˆ๋ผ๋ฉด CoreDNS README ๋˜๋Š” CoreDNS ์„ค์น˜๋ฅผ ์ฐธ์กฐํ•ด์„œ ํ™œ์„ฑํ™” ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๊ฒƒ์„ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค๋ฅธ curl ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•œ๋‹ค.

kubectl run curl --image=radial/busyboxplus:curl -i --tty
Waiting for pod default/curl-131556218-9fnch to be running, status is Pending, pod ready: false
Hit enter for command prompt

์ด์ œ, nslookup my-nginx ๋ฅผ ์ž…๋ ฅํ•˜๊ณ  ์‹คํ–‰ํ•œ๋‹ค:

[ root@curl-131556218-9fnch:/ ]$ nslookup my-nginx
Server:    10.0.0.10
Address 1: 10.0.0.10

Name:      my-nginx
Address 1: 10.0.162.149

์„œ๋น„์Šค ๋ณด์•ˆ

์ง€๊ธˆ๊นŒ์ง€๋Š” ํด๋Ÿฌ์Šคํ„ฐ ๋‚ด๋ถ€์—์„œ๋งŒ ngnix ์„œ๋ฒ„์— ์—‘์„ธ์Šค ํ•ด์™”๋‹ค. ์„œ๋น„์Šค๋ฅผ ์ธํ„ฐ๋„ท์— ๊ณต๊ฐœํ•˜๊ธฐ ์ „์— ํ†ต์‹  ์ฑ„๋„์ด ์•ˆ์ „ํ•œ์ง€ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด์„  ๋‹ค์Œ์ด ํ•„์š”ํ•˜๋‹ค.

  • https์— ๋Œ€ํ•œ ์ž์ฒด ์„œ๋ช…ํ•œ ์ธ์ฆ์„œ (์‹ ์› ์ธ์ฆ์„œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š์€ ๊ฒฝ์šฐ)
  • ์ธ์ฆ์„œ๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๊ตฌ์„ฑ๋œ nginx ์„œ๋ฒ„
  • ํŒŒ๋“œ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ์ธ์ฆ์„œ๋ฅผ ๋งŒ๋“œ๋Š” ์‹œํฌ๋ฆฟ

nginx https ์˜ˆ์ œ์—์„œ ์ด ๋ชจ๋“  ๊ฒƒ์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด์„œ๋Š” ๋„๊ตฌ๋ฅผ ์„ค์น˜ํ•ด์•ผ ํ•œ๋‹ค. ๋งŒ์•ฝ ์„ค์น˜ํ•˜์ง€ ์•Š์œผ๋ ค๋ฉด ๋‚˜์ค‘์— ์ˆ˜๋™์œผ๋กœ ๋‹จ๊ณ„๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค. ํ•œ๋งˆ๋””๋กœ:

make keys KEY=/tmp/nginx.key CERT=/tmp/nginx.crt
kubectl create secret tls nginxsecret --key /tmp/nginx.key --cert /tmp/nginx.crt
secret/nginxsecret created
kubectl get secrets
NAME                  TYPE                                  DATA      AGE
nginxsecret           kubernetes.io/tls                     2         1m

๊ทธ๋ฆฌ๊ณ  ๋˜ํ•œ ์ปจํ”ผ๊ทธ๋งต:

kubectl create configmap nginxconfigmap --from-file=default.conf
configmap/nginxconfigmap created
kubectl get configmaps
NAME             DATA   AGE
nginxconfigmap   1      114s

๋‹ค์Œ์€ make๋ฅผ ์‹คํ–‰ํ•˜๋Š”๋ฐ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ์— ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜๋Š” ์ˆ˜๋™ ๋‹จ๊ณ„์ด๋‹ค(์˜ˆ์‹œ๋กœ windows).

# Create a public private key pair
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /d/tmp/nginx.key -out /d/tmp/nginx.crt -subj "/CN=my-nginx/O=my-nginx"
# Convert the keys to base64 encoding
cat /d/tmp/nginx.crt | base64
cat /d/tmp/nginx.key | base64

์ด์ „ ๋ช…๋ น์˜ ์ถœ๋ ฅ์„ ์‚ฌ์šฉํ•ด์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด yaml ํŒŒ์ผ์„ ์ƒ์„ฑํ•œ๋‹ค. base64๋กœ ์ธ์ฝ”๋”ฉ๋œ ๊ฐ’์€ ๋ชจ๋‘ ํ•œ ์ค„์— ์žˆ์–ด์•ผ ํ•œ๋‹ค.

apiVersion: "v1"
kind: "Secret"
metadata:
  name: "nginxsecret"
  namespace: "default"
type: kubernetes.io/tls
data: 
  # ์ฐธ๊ณ : ์•„๋ž˜ ๊ฐ’๋“ค์„ ์ง์ ‘ base64๋กœ ์ธ์ฝ”๋”ฉํ•œ ์ธ์ฆ์„œ์™€ ํ‚ค๋กœ ๊ต์ฒดํ•˜์„ธ์š”.
  tls.crt: "REPLACE_WITH_BASE64_CERT" 
  tls.key: "REPLACE_WITH_BASE64_KEY"

์ด์ œ ํŒŒ์ผ์„ ์‚ฌ์šฉํ•ด์„œ ์‹œํฌ๋ฆฟ์„ ์ƒ์„ฑํ•œ๋‹ค.

kubectl apply -f nginxsecrets.yaml
kubectl get secrets
NAME                  TYPE                                  DATA      AGE
nginxsecret           kubernetes.io/tls                     2         1m

์ด์ œ nginx ๋ ˆํ”Œ๋ฆฌ์นด๋ฅผ ์ˆ˜์ •ํ•˜์—ฌ ์•”ํ˜ธํ™”๋œ ์ธ์ฆ์„œ๋ฅผ ์‚ฌ์šฉํ•œ https ์„œ๋ฒ„์™€ ์„œ๋น„์Šค๋ฅผ ์‹คํ–‰ํ•˜๊ณ , ๋‘ ํฌํŠธ(80๊ณผ 443)๋ฅผ ๋…ธ์ถœํ•œ๋‹ค.

apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  type: NodePort
  ports:
  - port: 8080
    targetPort: 80
    protocol: TCP
    name: http
  - port: 443
    protocol: TCP
    name: https
  selector:
    run: my-nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 1
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      volumes:
      - name: secret-volume
        secret:
          secretName: nginxsecret
      - name: configmap-volume
        configMap:
          name: nginxconfigmap
      containers:
      - name: nginxhttps
        image: bprashanth/nginxhttps:1.0
        ports:
        - containerPort: 443
        - containerPort: 80
        volumeMounts:
        - mountPath: /etc/nginx/ssl
          name: secret-volume
        - mountPath: /etc/nginx/conf.d
          name: configmap-volume

nginx-secure-app์˜ ๋งค๋‹ˆํŽ˜์ŠคํŠธ์— ๋Œ€ํ•œ ์ฃผ๋ชฉํ• ๋งŒํ•œ ์ :

  • ์ด๊ฒƒ์€ ๋™์ผํ•œ ํŒŒ์ผ์— ๋””ํ”Œ๋กœ์ด๋จผํŠธ์™€ ์„œ๋น„์Šค์˜ ์‚ฌ์–‘์„ ๋ชจ๋‘ ํฌํ•จํ•˜๊ณ  ์žˆ๋‹ค.
  • nginx ์„œ๋ฒ„ ๋Š” ํฌํŠธ 80์—์„œ HTTP ํŠธ๋ž˜ํ”ฝ์„ 443์—์„œ HTTPS ํŠธ๋ž˜ํ”ฝ ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•˜๊ณ , nginx ์„œ๋น„์Šค๋Š” ๋‘ ํฌํŠธ๋ฅผ ๋ชจ๋‘ ๋…ธ์ถœํ•œ๋‹ค.
  • ๊ฐ ์ปจํ…Œ์ด๋„ˆ๋Š” /etc/nginx/ssl ์— ๋งˆ์šดํŠธ๋œ ๋ณผ๋ฅจ์„ ํ†ตํ•ด ํ‚ค์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๊ฒƒ์€ nginx ์„œ๋ฒ„๊ฐ€ ์‹œ์ž‘๋˜๊ธฐ ์ „์— ์„ค์ •๋œ ๊ฒƒ์ด๋‹ค.
kubectl delete deployments,svc my-nginx; kubectl create -f ./nginx-secure-app.yaml

์ด ์‹œ์ ์—์„œ ๋ชจ๋“  ๋…ธ๋“œ์—์„œ nginx ์„œ๋ฒ„์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl get pods -l run=my-nginx -o custom-columns=POD_IP:.status.podIPs
    POD_IP
    [map[ip:10.244.3.5]]
node $ curl -k https://10.244.3.5
...
<h1>Welcome to nginx!</h1>

๋งˆ์ง€๋ง‰ ๋‹จ๊ณ„์—์„œ curl์— -k ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ œ๊ณตํ•œ ๋ฐฉ๋ฒ•์— ์ฐธ๊ณ ํ•œ๋‹ค. ์ด๋Š” ์ธ์ฆ์„œ ์ƒ์„ฑ์‹œ nginx๋ฅผ ์‹คํ–‰ํ•˜๋Š” ํŒŒ๋“œ์— ๋Œ€ํ•ด ์•„๋ฌด๊ฒƒ๋„ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— curl์— CName ๋ถˆ์ผ์น˜๋ฅผ ๋ฌด์‹œํ•˜๋„๋ก ์ง€์‹œํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์„œ๋น„์Šค๋ฅผ ์ƒ์„ฑํ•ด์„œ ์ธ์ฆ์„œ์— ์‚ฌ์šฉ๋œ CName์„ ์„œ๋น„์Šค ์กฐํšŒ์‹œ ํŒŒ๋“œ์—์„œ ์‚ฌ์šฉ๋œ ์‹ค์ œ DNS ์ด๋ฆ„๊ณผ ์—ฐ๊ฒฐํ–ˆ๋‹ค. ํŒŒ๋“œ์—์„œ ์ด๊ฒƒ์„ ํ…Œ์ŠคํŠธ ํ•ด๋ณด์ž(๋‹จ์ˆœํžˆ ๋™์ผํ•œ ์‹œํฌ๋ฆฟ์ด ์žฌ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์œผ๋ฉฐ, ํŒŒ๋“œ๋Š” ์„œ๋น„์Šค์— ์ ‘๊ทผํ•˜๊ธฐ์œ„ํ•ด nginx.crt๋งŒ ํ•„์š”ํ•˜๋‹ค).

apiVersion: apps/v1
kind: Deployment
metadata:
  name: curl-deployment
spec:
  selector:
    matchLabels:
      app: curlpod
  replicas: 1
  template:
    metadata:
      labels:
        app: curlpod
    spec:
      volumes:
      - name: secret-volume
        secret:
          secretName: nginxsecret
      containers:
      - name: curlpod
        command:
        - sh
        - -c
        - while true; do sleep 1; done
        image: radial/busyboxplus:curl
        volumeMounts:
        - mountPath: /etc/nginx/ssl
          name: secret-volume
kubectl apply -f ./curlpod.yaml
kubectl get pods -l app=curlpod
NAME                               READY     STATUS    RESTARTS   AGE
curl-deployment-1515033274-1410r   1/1       Running   0          1m
kubectl exec curl-deployment-1515033274-1410r -- curl https://my-nginx --cacert /etc/nginx/ssl/tls.crt
...
<title>Welcome to nginx!</title>
...

์„œ๋น„์Šค ๋…ธ์ถœํ•˜๊ธฐ

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ผ๋ถ€์ธ ๊ฒฝ์šฐ ์›ํ•œ๋‹ค๋ฉด ์™ธ๋ถ€ IP ์ฃผ์†Œ์— ์„œ๋น„์Šค๋ฅผ ๋…ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋Š” ์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” 2๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ธ NodePorts์™€ LoadBalancers๋ฅผ์ง€์›ํ•œ๋‹ค. ๋งˆ์ง€๋ง‰ ์„น์…˜์—์„œ ์ƒ์„ฑ๋œ ์„œ๋น„์Šค๋Š” ์ด๋ฏธ NodePort ๋ฅผ ์‚ฌ์šฉํ–ˆ๊ธฐ์— ๋…ธ๋“œ์— ๊ณต์šฉ IP๊ฐ€ ์žˆ๋Š”๊ฒฝ์šฐ nginx HTTPS ๋ ˆํ”Œ๋ฆฌ์นด๊ฐ€ ์ธํ„ฐ๋„ท ํŠธ๋ž˜ํ”ฝ์„ ์ฒ˜๋ฆฌํ•  ์ค€๋น„๊ฐ€ ๋˜์–ด ์žˆ๋‹ค.

kubectl get svc my-nginx -o yaml | grep nodePort -C 5
  uid: 07191fb3-f61a-11e5-8ae5-42010af00002
spec:
  clusterIP: 10.0.162.149
  ports:
  - name: http
    nodePort: 31704
    port: 8080
    protocol: TCP
    targetPort: 80
  - name: https
    nodePort: 32453
    port: 443
    protocol: TCP
    targetPort: 443
  selector:
    run: my-nginx
kubectl get nodes -o yaml | grep ExternalIP -C 1
    - address: 104.197.41.11
      type: ExternalIP
    allocatable:
--
    - address: 23.251.152.56
      type: ExternalIP
    allocatable:
...

$ curl https://<EXTERNAL-IP>:<NODE-PORT> -k
...
<h1>Welcome to nginx!</h1>

์ด์ œ ํด๋ผ์šฐ๋“œ ๋กœ๋“œ ๋ฐธ๋Ÿฐ์„œ๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ์„œ๋น„์Šค๋ฅผ ์žฌ์ƒ์„ฑํ•œ๋‹ค. my-nginx ์„œ๋น„์Šค์˜ Type ์„ NodePort ์—์„œ LoadBalancer ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.

kubectl edit svc my-nginx
kubectl get svc my-nginx
NAME       TYPE           CLUSTER-IP     EXTERNAL-IP        PORT(S)               AGE
my-nginx   LoadBalancer   10.0.162.149   xx.xxx.xxx.xxx     8080:30163/TCP        21s
curl https://<EXTERNAL-IP> -k
...
<title>Welcome to nginx!</title>

EXTERNAL-IP ์˜ IP ์ฃผ์†Œ๋Š” ๊ณต์šฉ ์ธํ„ฐ๋„ท์—์„œ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ฃผ์†Œ์ด๋‹ค. CLUSTER-IP ๋Š” ํด๋Ÿฌ์Šคํ„ฐ/ํ”„๋ผ์ด๋น— ํด๋ผ์šฐ๋“œ ๋„คํŠธ์›Œํฌ ๋‚ด์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

AWS์—์„œ๋Š” LoadBalancer ์œ ํ˜•์€ IP๊ฐ€ ์•„๋‹Œ (๊ธด)ํ˜ธ์ŠคํŠธ๋„ค์ž„์„ ์‚ฌ์šฉํ•˜๋Š” ELB๋ฅผ ์ƒ์„ฑํ•œ๋‹ค๋Š” ์ ์„ ์ฐธ๊ณ ํ•œ๋‹ค. ์ด๊ฒƒ์€ ์ผ๋ฐ˜์ ์ธ kubectl get svc ์˜ ์ถœ๋ ฅ์— ๋งž์ถ”๊ธฐ์—๋Š” ๋งค์šฐ ๊ธธ๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ๋กœ ์ด๋ฅผ ๋ณด๋ ค๋ฉด kubectl describe service my-nginx ๋ฅผ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•œ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒƒ์„ ๋ณด๊ฒŒ ๋œ๋‹ค.

kubectl describe service my-nginx
...
LoadBalancer Ingress:   a320587ffd19711e5a37606cf4a74574-1142138393.us-east-1.elb.amazonaws.com
...

๋‹ค์Œ ๋‚ด์šฉ

7.2 - ์†Œ์Šค IP ์ฃผ์†Œ ์ด์šฉํ•˜๊ธฐ

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ์—์„œ ์‹คํ–‰ ์ค‘์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์„œ๋น„์Šค ์ถ”์ƒํ™”๋ฅผ ํ†ตํ•ด์„œ ์„œ๋กœ๋ฅผ, ๊ทธ๋ฆฌ๊ณ  ์™ธ๋ถ€ ์„ธ๊ณ„๋ฅผ ์ฐพ๊ณ  ํ†ต์‹ ํ•œ๋‹ค. ์ด ๋ฌธ์„œ๋Š” ๋‹ค๋ฅธ ์ข…๋ฅ˜์˜ ์„œ๋น„์Šค๋กœ ์ „์†ก๋œ ํŒจํ‚ท์˜ ์†Œ์Šค IP์— ์–ด๋–ค ์ผ์ด ๋ฒŒ์–ด์ง€๋Š”์ง€์™€ ์ด ๋™์ž‘์„ ํ•„์š”์— ๋”ฐ๋ผ ์–ด๋–ป๊ฒŒ ์ „ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์„ค๋ช…ํ•œ๋‹ค.

์‹œ์ž‘ํ•˜๊ธฐ ์ „์—

์šฉ์–ด

์ด ๋ฌธ์„œ๋Š” ๋‹ค์Œ ์šฉ์–ด๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

NAT
๋„คํŠธ์›Œํฌ ์ฃผ์†Œ ๋ณ€ํ™˜
์†Œ์Šค NAT
ํŒจํ‚ท ์ƒ์˜ ์†Œ์Šค IP ์ฃผ์†Œ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ. ์ด ํŽ˜์ด์ง€์—์„œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋…ธ๋“œ IP ์ฃผ์†Œ๋กœ์˜ ๋ณ€๊ฒฝ์„ ์˜๋ฏธํ•จ.
๋Œ€์ƒ NAT
ํŒจํ‚ท ์ƒ์˜ ๋Œ€์ƒ IP ์ฃผ์†Œ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ. ์ด ํŽ˜์ด์ง€์—์„œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ํŒŒ๋“œ IP ์ฃผ์†Œ๋กœ์˜ ๋ณ€๊ฒฝ์„ ์˜๋ฏธํ•จ.
VIP
์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์˜ ๋ชจ๋“  ์„œ๋น„์Šค์— ํ• ๋‹น๋˜์–ด ์žˆ๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€, ๊ฐ€์ƒ IP ์ฃผ์†Œ.
Kube-proxy
๋ชจ๋“  ๋…ธ๋“œ์—์„œ ์„œ๋น„์Šค VIP ๊ด€๋ฆฌ๋ฅผ ์กฐ์œจํ•˜๋Š” ๋„คํŠธ์›Œํฌ ๋ฐ๋ชฌ.

์ „์ œ ์กฐ๊ฑด

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ๊ฐ€ ํ•„์š”ํ•˜๊ณ , kubectl ์ปค๋งจ๋“œ-๋ผ์ธ ํˆด์ด ํด๋Ÿฌ์Šคํ„ฐ์™€ ํ†ต์‹ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •๋˜์–ด ์žˆ์–ด์•ผ ํ•œ๋‹ค. ์ด ํŠœํ† ๋ฆฌ์–ผ์€ ์ปจํŠธ๋กค ํ”Œ๋ ˆ์ธ ํ˜ธ์ŠคํŠธ๊ฐ€ ์•„๋‹Œ ๋…ธ๋“œ๊ฐ€ ์ ์–ด๋„ 2๊ฐœ ํฌํ•จ๋œ ํด๋Ÿฌ์Šคํ„ฐ์—์„œ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค. ๋งŒ์•ฝ, ์•„์ง ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š๋‹ค๋ฉด, minikube๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ๋‹ค์Œ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํ”Œ๋ ˆ์ด๊ทธ๋ผ์šด๋“œ ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด ์˜ˆ์‹œ๋Š” HTTP ํ—ค๋”๋กœ ์ˆ˜์‹ ํ•œ ์š”์ฒญ์˜ ์†Œ์Šค IP ์ฃผ์†Œ๋ฅผ ํšŒ์‹ ํ•˜๋Š” ์ž‘์€ nginx ์›น ์„œ๋ฒ„๋ฅผ ์ด์šฉํ•œ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl create deployment source-ip-app --image=registry.k8s.io/echoserver:1.10

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

deployment.apps/source-ip-app created

๋ชฉ์ 

  • ๊ฐ„๋‹จํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋‹ค์–‘ํ•œ ์„œ๋น„์Šค ์ข…๋ฅ˜๋กœ ๋…ธ์ถœํ•˜๊ธฐ
  • ๊ฐ ์„œ๋น„์Šค ์œ ํ˜•์— ๋”ฐ๋ฅธ ์†Œ์Šค IP NAT ์˜ ๋™์ž‘ ์ดํ•ดํ•˜๊ธฐ
  • ์†Œ์Šค IP ์ฃผ์†Œ ๋ณด์กด์— ๊ด€ํ•œ ์ ˆ์ถฉ ์‚ฌํ•ญ ์ดํ•ด

Type=ClusterIP ์ธ ์„œ๋น„์Šค์—์„œ ์†Œ์Šค IP

iptables ๋ชจ๋“œ (๊ธฐ๋ณธ๊ฐ’)์—์„œ kube-proxy๋ฅผ ์šด์˜ํ•˜๋Š” ๊ฒฝ์šฐ ํด๋Ÿฌ์Šคํ„ฐ ๋‚ด์—์„œ ํด๋Ÿฌ์Šคํ„ฐIP๋กœ ํŒจํ‚ท์„ ๋ณด๋‚ด๋ฉด ์†Œ์Šค NAT๋ฅผ ํ†ต๊ณผํ•˜์ง€ ์•Š๋Š”๋‹ค. kube-proxy๊ฐ€ ์‹คํ–‰์ค‘์ธ ๋…ธ๋“œ์—์„œ http://localhost:10249/proxyMode ๋ฅผ ์ž…๋ ฅํ•ด์„œ kube-proxy ๋ชจ๋“œ๋ฅผ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl get nodes

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•˜๋‹ค.

NAME                           STATUS     ROLES    AGE     VERSION
kubernetes-node-6jst   Ready      <none>   2h      v1.13.0
kubernetes-node-cx31   Ready      <none>   2h      v1.13.0
kubernetes-node-jj1t   Ready      <none>   2h      v1.13.0

ํ•œ ๋…ธ๋“œ์˜ ํ”„๋ก์‹œ ๋ชจ๋“œ๋ฅผ ํ™•์ธํ•œ๋‹ค. (kube-proxy๋Š” ํฌํŠธ 10249์—์„œ ์ˆ˜์‹ ๋Œ€๊ธฐํ•œ๋‹ค.)

# ์งˆ์˜ ํ•  ๋…ธ๋“œ์˜ ์‰˜์—์„œ ์ด๊ฒƒ์„ ์‹คํ–‰ํ•œ๋‹ค.
curl localhost:10249/proxyMode

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

iptables

์†Œ์Šค IP ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํ†ตํ•ด ์„œ๋น„์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์†Œ์Šค IP ์ฃผ์†Œ ๋ณด์กด ์—ฌ๋ถ€๋ฅผ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl expose deployment source-ip-app --name=clusterip --port=80 --target-port=8080

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

service/clusterip exposed
kubectl get svc clusterip

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
clusterip    ClusterIP   10.0.170.92   <none>        80/TCP    51s

๊ทธ๋ฆฌ๊ณ  ๋™์ผํ•œ ํด๋Ÿฌ์Šคํ„ฐ์˜ ํŒŒ๋“œ์—์„œ ํด๋Ÿฌ์Šคํ„ฐIP๋ฅผ ์น˜๋ฉด:

kubectl run busybox -it --image=busybox:1.28 --restart=Never --rm

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

Waiting for pod default/busybox to be running, status is Pending, pod ready: false
If you don't see a command prompt, try pressing enter.

๊ทธ๋Ÿฐ ๋‹ค์Œ ํ•ด๋‹น ํŒŒ๋“œ ๋‚ด์—์„œ ๋ช…๋ น์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

# "kubectl run" ์œผ๋กœ ํ„ฐ๋ฏธ๋„ ๋‚ด์—์„œ ์ด๊ฒƒ์„ ์‹คํ–‰ํ•œ๋‹ค.
ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1460 qdisc noqueue
    link/ether 0a:58:0a:f4:03:08 brd ff:ff:ff:ff:ff:ff
    inet 10.244.3.8/24 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::188a:84ff:feb0:26a5/64 scope link
       valid_lft forever preferred_lft forever

๊ทธ๋Ÿฐ ๋‹ค์Œ wget ์„ ์‚ฌ์šฉํ•ด์„œ ๋กœ์ปฌ ์›น ์„œ๋ฒ„์— ์ฟผ๋ฆฌํ•œ๋‹ค.

# "10.0.170.92"๋ฅผ "clusterip"๋ผ๋Š” ์ด๋ฆ„์˜ ์„œ๋น„์Šค์˜ IPv4 ์ฃผ์†Œ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.
wget -qO - 10.0.170.92
CLIENT VALUES:
client_address=10.244.3.8
command=GET
...

client_address ๋Š” ํด๋ผ์ด์–ธํŠธ ํŒŒ๋“œ์™€ ์„œ๋ฒ„ ํŒŒ๋“œ๊ฐ€ ๊ฐ™์€ ๋…ธ๋“œ ๋˜๋Š” ๋‹ค๋ฅธ ๋…ธ๋“œ์— ์žˆ๋Š”์ง€ ์—ฌ๋ถ€์— ๊ด€๊ณ„์—†์ด ํ•ญ์ƒ ํด๋ผ์ด์–ธํŠธ ํŒŒ๋“œ์˜ IP ์ฃผ์†Œ์ด๋‹ค.

Type=NodePort ์ธ ์„œ๋น„์Šค์—์„œ ์†Œ์Šค IP

Type=NodePort์ธ ์„œ๋น„์Šค๋กœ ๋ณด๋‚ด์ง„ ํŒจํ‚ท์€ ์†Œ์Šค NAT๊ฐ€ ๊ธฐ๋ณธ์œผ๋กœ ์ ์šฉ๋œ๋‹ค. NodePort ์„œ๋น„์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์ด๊ฒƒ์„ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl expose deployment source-ip-app --name=nodeport --port=80 --target-port=8080 --type=NodePort

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

service/nodeport exposed
NODEPORT=$(kubectl get -o jsonpath="{.spec.ports[0].nodePort}" services nodeport)
NODES=$(kubectl get nodes -o jsonpath='{ $.items[*].status.addresses[?(@.type=="InternalIP")].address }')

ํด๋ผ์šฐ๋“œ ๊ณต๊ธ‰์ž ์ƒ์—์„œ ์‹คํ–‰ํ•œ๋‹ค๋ฉด, ์œ„์— ๋ณด๊ณ ๋œ nodes:nodeport๋ฅผ ์œ„ํ•œ ๋ฐฉํ™”๋ฒฝ ๊ทœ์น™์„ ์—ด์–ด์ฃผ์–ด์•ผ ํ•œ๋‹ค. ์ด์ œ ์œ„์— ๋…ธ๋“œ ํฌํŠธ๋กœ ํ• ๋‹น๋ฐ›์€ ํฌํŠธ๋ฅผ ํ†ตํ•ด ํด๋Ÿฌ์Šคํ„ฐ ์™ธ๋ถ€์—์„œ ์„œ๋น„์Šค์— ๋„๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

for node in $NODES; do curl -s $node:$NODEPORT | grep -i client_address; done

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•˜๋‹ค.

client_address=10.180.1.1
client_address=10.240.0.5
client_address=10.240.0.3

๋ช…์‹ฌํ•  ๊ฒƒ์€ ์ •ํ™•ํ•œ ํด๋ผ์ด์–ธํŠธ IP ์ฃผ์†Œ๊ฐ€ ์•„๋‹ˆ๊ณ , ํด๋Ÿฌ์Šคํ„ฐ ๋‚ด๋ถ€ IP ์ฃผ์†Œ์ด๋‹ค. ์™œ ์ด๋Ÿฐ ์ผ์ด ๋ฐœ์ƒํ–ˆ๋Š”์ง€ ์„ค๋ช…ํ•œ๋‹ค.

  • ํด๋ผ์ด์–ธํŠธ๋Š” node2:nodePort๋กœ ํŒจํ‚ท์„ ๋ณด๋‚ธ๋‹ค.
  • node2๋Š” ์†Œ์Šค IP ์ฃผ์†Œ(SNAT)๋ฅผ ํŒจํ‚ท ์ƒ์—์„œ ์ž์‹ ์˜ IP ์ฃผ์†Œ๋กœ ๊ต์ฒดํ•œ๋‹ค.
  • noee2๋Š” ๋Œ€์ƒ IP๋ฅผ ํŒจํ‚ท ์ƒ์—์„œ ํŒŒ๋“œ์˜ IP๋กœ ๊ต์ฒดํ•œ๋‹ค.
  • ํŒจํ‚ท์€ node 1๋กœ ๋ผ์šฐํŒ… ๋œ ๋‹ค์Œ ์—”๋“œํฌ์ธํŠธ๋กœ ๋ผ์šฐํŒ… ๋œ๋‹ค.
  • ํŒŒ๋“œ์˜ ์‘๋‹ต์€ node2๋กœ ๋‹ค์‹œ ๋ผ์šฐํŒ…๋œ๋‹ค.
  • ํŒŒ๋“œ์˜ ์‘๋‹ต์€ ํด๋ผ์ด์–ธํŠธ๋กœ ๋‹ค์‹œ ์ „์†ก๋œ๋‹ค.

์ด๋ฅผ ๊ทธ๋ฆผ์œผ๋กœ ํ‘œํ˜„ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

source IP nodeport figure 01

๊ทธ๋ฆผ. Source IP Type=NodePort using SNAT

์ด๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋Š” ํด๋ผ์ด์–ธํŠธ ์†Œ์Šค IP ์ฃผ์†Œ๋ฅผ ๋ณด์กดํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์žˆ๋‹ค. service.spec.externalTrafficPolicy ์˜ ๊ฐ’์„ Local ๋กœ ํ•˜๋ฉด ์˜ค์ง ๋กœ์ปฌ ์—”๋“œํฌ์ธํŠธ๋กœ๋งŒ ํ”„๋ก์‹œ ์š”์ฒญํ•˜๊ณ  ๋‹ค๋ฅธ ๋…ธ๋“œ๋กœ ํŠธ๋ž˜ํ”ฝ ์ „๋‹ฌํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ด ๋ฐฉ๋ฒ•์€ ์›๋ณธ ์†Œ์Šค IP ์ฃผ์†Œ๋ฅผ ๋ณด์กดํ•œ๋‹ค. ๋งŒ์•ฝ ๋กœ์ปฌ ์—”๋“œ ํฌ์ธํŠธ๊ฐ€ ์—†๋‹ค๋ฉด, ๊ทธ ๋…ธ๋“œ๋กœ ๋ณด๋‚ด์ง„ ํŒจํ‚ท์€ ๋ฒ„๋ ค์ง€๋ฏ€๋กœ ํŒจํ‚ท ์ฒ˜๋ฆฌ ๊ทœ์น™์—์„œ ์ •ํ™•ํ•œ ์†Œ์Šค IP ์ž„์„ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ํŒจํ‚ท์„ ์—”๋“œํฌ์ธํŠธ๊นŒ์ง€ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด service.spec.externalTrafficPolicy ํ•„๋“œ๋ฅผ ์„ค์ •ํ•˜์ž.

kubectl patch svc nodeport -p '{"spec":{"externalTrafficPolicy":"Local"}}'

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

service/nodeport patched

์ด์ œ ๋‹ค์‹œ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•ด๋ณด์ž.

for node in $NODES; do curl --connect-timeout 1 -s $node:$NODEPORT | grep -i client_address; done

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•˜๋‹ค.

client_address=104.132.1.79

์—”๋“œํฌ์ธํŠธ ํŒŒ๋“œ๊ฐ€ ์‹คํ–‰ ์ค‘์ธ ๋…ธ๋“œ์—์„œ ์˜ฌ๋ฐ”๋ฅธ ํด๋ผ์ด์–ธํŠธ IP ์ฃผ์†Œ์ธ ๋”ฑ ํ•œ ์ข…๋ฅ˜์˜ ์‘๋‹ต๋งŒ ์ˆ˜์‹ ํ•œ๋‹ค.

์–ด๋–ป๊ฒŒ ์ด๋ ‡๊ฒŒ ๋˜์—ˆ๋Š”๊ฐ€:

  • ํด๋ผ์ด์–ธํŠธ๋Š” ํŒจํ‚ท์„ ์—”๋“œํฌ์ธํŠธ๊ฐ€ ์—†๋Š” node2:nodePort ๋ณด๋‚ธ๋‹ค.
  • ํŒจํ‚ท์€ ๋ฒ„๋ ค์ง„๋‹ค.
  • ํด๋ผ์ด์–ธํŠธ๋Š” ํŒจํ‚ท์„ ์—”๋“œํฌ์ธํŠธ๋ฅผ ๊ฐ€์ง„ node1:nodePort ๋ณด๋‚ธ๋‹ค.
  • node1์€ ํŒจํ‚ท์„ ์˜ฌ๋ฐ”๋ฅธ ์†Œ์Šค IP ์ฃผ์†Œ๋กœ ์—”๋“œํฌ์ธํŠธ๋กœ ๋ผ์šฐํŒ… ํ•œ๋‹ค.

์ด๋ฅผ ์‹œ๊ฐ์ ์œผ๋กœ ํ‘œํ˜„ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

source IP nodeport figure 02

๊ทธ๋ฆผ. Source IP Type=NodePort preserves client source IP address

Type=LoadBalancer ์ธ ์„œ๋น„์Šค์—์„œ ์†Œ์Šค IP

Type=LoadBalancer์ธ ์„œ๋น„์Šค๋กœ ๋ณด๋‚ธ ํŒจํ‚ท์€ ์†Œ์Šค NAT๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ํ•˜๋Š”๋ฐ, Ready ์ƒํƒœ๋กœ ๋ชจ๋“  ์Šค์ผ€์ค„๋œ ๋ชจ๋“  ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋…ธ๋“œ๋Š” ๋กœ๋“œ ๋ฐธ๋Ÿฐ์‹ฑ ํŠธ๋ž˜ํ”ฝ์— ์ ํ•ฉํ•˜๋‹ค. ๋”ฐ๋ผ์„œ ์—”๋“œํฌ์ธํŠธ๊ฐ€ ์—†๋Š” ๋…ธ๋“œ์— ํŒจํ‚ท์ด ๋„์ฐฉํ•˜๋ฉด ์‹œ์Šคํ…œ์€ ์—”๋“œํฌ์ธํŠธ๋ฅผ ํฌํ•จํ•œ ๋…ธ๋“œ์— ํ”„๋ก์‹œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ณ  ํŒจํ‚ท ์ƒ์—์„œ ๋…ธ๋“œ์˜ IP ์ฃผ์†Œ๋กœ ์†Œ์Šค IP ์ฃผ์†Œ๋ฅผ ๋ณ€๊ฒฝํ•œ๋‹ค (์ด์ „ ์„น์…˜์—์„œ ๊ธฐ์ˆ ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ).

๋กœ๋“œ๋ฐธ๋Ÿฐ์„œ๋ฅผ ํ†ตํ•ด source-ip-app์„ ๋…ธ์ถœํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl expose deployment source-ip-app --name=loadbalancer --port=80 --target-port=8080 --type=LoadBalancer

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

service/loadbalancer exposed

์„œ๋น„์Šค์˜ IP ์ฃผ์†Œ๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.

kubectl get svc loadbalancer

๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ์ถœ๋ ฅ๋œ๋‹ค.

NAME           TYPE           CLUSTER-IP    EXTERNAL-IP       PORT(S)   AGE
loadbalancer   LoadBalancer   10.0.65.118   203.0.113.140     80/TCP    5m

๋‹ค์Œ์œผ๋กœ ์ด ์„œ๋น„์Šค์˜ ์™ธ๋ถ€ IP์— ์š”์ฒญ์„ ์ „์†กํ•œ๋‹ค.

curl 203.0.113.140

๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ์ถœ๋ ฅ๋œ๋‹ค.

CLIENT VALUES:
client_address=10.240.0.5
...

๊ทธ๋Ÿฌ๋‚˜ ๊ตฌ๊ธ€ ํด๋ผ์šฐ๋“œ ์—”์ง„/GCE ์—์„œ ์‹คํ–‰ ์ค‘์ด๋ผ๋ฉด ๋™์ผํ•œ service.spec.externalTrafficPolicy ํ•„๋“œ๋ฅผ Local๋กœ ์„ค์ •ํ•˜๋ฉด ์„œ๋น„์Šค ์—”๋“œํฌ์ธํŠธ๊ฐ€ ์—†๋Š” ๋…ธ๋“œ๋Š” ๊ณ ์˜๋กœ ํ—ฌ์Šค ์ฒดํฌ์— ์‹คํŒจํ•˜์—ฌ ๊ฐ•์ œ๋กœ ๋กœ๋“œ๋ฐธ๋Ÿฐ์‹ฑ ํŠธ๋ž˜ํ”ฝ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ๋…ธ๋“œ ๋ชฉ๋ก์—์„œ ์ž์‹ ์„ ์Šค์Šค๋กœ ์ œ๊ฑฐํ•œ๋‹ค.

์ด๋ฅผ ๊ทธ๋ฆผ์œผ๋กœ ํ‘œํ˜„ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

Source IP with externalTrafficPolicy

์ด๊ฒƒ์€ ์–ด๋…ธํ…Œ์ด์…˜์„ ์„ค์ •ํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl patch svc loadbalancer -p '{"spec":{"externalTrafficPolicy":"Local"}}'

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์— ์˜ํ•ด service.spec.healthCheckNodePort ํ•„๋“œ๊ฐ€ ์ฆ‰๊ฐ์ ์œผ๋กœ ํ• ๋‹น๋˜๋Š” ๊ฒƒ์„ ๋ด์•ผ ํ•œ๋‹ค.

kubectl get svc loadbalancer -o yaml | grep -i healthCheckNodePort

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•˜๋‹ค.

  healthCheckNodePort: 32122

service.spec.healthCheckNodePort ํ•„๋“œ๋Š” /healthz์—์„œ ํ—ฌ์Šค ์ฒดํฌ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋ชจ๋“  ๋…ธ๋“œ์˜ ํฌํŠธ๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค. ์ด๊ฒƒ์„ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl get pod -o wide -l app=source-ip-app

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•˜๋‹ค.

NAME                            READY     STATUS    RESTARTS   AGE       IP             NODE
source-ip-app-826191075-qehz4   1/1       Running   0          20h       10.180.1.136   kubernetes-node-6jst

๋‹ค์–‘ํ•œ ๋…ธ๋“œ์—์„œ /healthz ์—”๋“œํฌ์ธํŠธ๋ฅผ ๊ฐ€์ ธ์˜ค๋ ค๋ฉด curl ์„ ์‚ฌ์šฉํ•œ๋‹ค.

# ์„ ํƒํ•œ ๋…ธ๋“œ์—์„œ ๋กœ์ปฌ๋กœ ์ด๊ฒƒ์„ ์‹คํ–‰ํ•œ๋‹ค.
curl localhost:32122/healthz
1 Service Endpoints found

๋‹ค๋ฅธ ๋…ธ๋“œ์—์„œ๋Š” ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

# ์„ ํƒํ•œ ๋…ธ๋“œ์—์„œ ๋กœ์ปฌ๋กœ ์ด๊ฒƒ์„ ์‹คํ–‰ํ•œ๋‹ค.
curl localhost:32122/healthz
No Service Endpoints Found

์ปจํŠธ๋กค ํ”Œ๋ ˆ์ธ์—์„œ ์‹คํ–‰์ค‘์ธ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ํด๋ผ์šฐ๋“œ ๋กœ๋“œ ๋ฐธ๋Ÿฐ์„œ๋ฅผ ํ• ๋‹นํ•œ๋‹ค. ๋˜ํ•œ ๊ฐ™์€ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ๊ฐ ๋…ธ๋“œ์—์„œ ํฌํŠธ/๊ฒฝ๋กœ(port/path)๋ฅผ ๊ฐ€๋ฅดํ‚ค๋Š” HTTP ์ƒํƒœ ํ™•์ธ๋„ ํ• ๋‹นํ•œ๋‹ค. ์—”๋“œํฌ์ธํŠธ๊ฐ€ ์—†๋Š” 2๊ฐœ์˜ ๋…ธ๋“œ๊ฐ€ ์ƒํƒœ ํ™•์ธ์— ์‹คํŒจํ•  ๋•Œ๊นŒ์ง€ ์•ฝ 10์ดˆ๊ฐ„ ๋Œ€๊ธฐํ•œ ๋‹ค์Œ, curl ์„ ์‚ฌ์šฉํ•ด์„œ ๋กœ๋“œ๋ฐธ๋Ÿฐ์„œ์˜ IPv4 ์ฃผ์†Œ๋ฅผ ์ฟผ๋ฆฌํ•œ๋‹ค.

curl 203.0.113.140

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•˜๋‹ค.

CLIENT VALUES:
client_address=198.51.100.79
...

ํฌ๋กœ์Šค-ํ”Œ๋žซํผ ์ง€์›

์ผ๋ถ€ ํด๋ผ์šฐ๋“œ ๊ณต๊ธ‰์ž๋งŒ Type=LoadBalancer ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์„œ๋น„์Šค๋ฅผ ํ†ตํ•ด ์†Œ์Šค IP ๋ณด์กด์„ ์ง€์›ํ•œ๋‹ค. ์‹คํ–‰ ์ค‘์ธ ํด๋ผ์šฐ๋“œ ๊ณต๊ธ‰์ž์—์„œ ๋ช‡ ๊ฐ€์ง€ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ ๋กœ๋“œ๋ฐธ๋Ÿฐ์„œ๋ฅผ ์š”์ฒญํ•œ๋‹ค.

  1. ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ์„ ์ข…๋ฃŒํ•˜๊ณ  ์ƒˆ ์—ฐ๊ฒฐ์„ ์—ฌ๋Š” ํ”„๋ก์‹œ๋ฅผ ์ด์šฉํ•œ๋‹ค. ์ด ๊ฒฝ์šฐ ์†Œ์Šค IP ์ฃผ์†Œ๋Š” ํด๋ผ์ด์–ธํŠธ IP ์ฃผ์†Œ๊ฐ€ ์•„๋‹ˆ๊ณ  ํ•ญ์ƒ ํด๋ผ์šฐ๋“œ ๋กœ๋“œ๋ฐธ๋Ÿฐ์„œ์˜ IP ์ฃผ์†Œ์ด๋‹ค.

  2. ๋กœ๋“œ๋ฐธ๋Ÿฐ์„œ์˜ VIP์— ์ „๋‹ฌ๋œ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ณด๋‚ธ ์š”์ฒญ์„ ์ค‘๊ฐ„ ํ”„๋ก์‹œ๊ฐ€ ์•„๋‹Œ ํด๋ผ์ด์–ธํŠธ ์†Œ์Šค IP ์ฃผ์†Œ๊ฐ€ ์žˆ๋Š” ๋…ธ๋“œ๋กœ ๋๋‚˜๋Š” ํŒจํ‚ท ์ „๋‹ฌ์ž๋ฅผ ์ด์šฉํ•œ๋‹ค.

์ฒซ ๋ฒˆ์งธ ๋ฒ”์ฃผ์˜ ๋กœ๋“œ๋ฐธ๋Ÿฐ์„œ๋Š” ์ง„์งœ ํด๋ผ์ด์–ธํŠธ IP๋ฅผ ํ†ต์‹ ํ•˜๊ธฐ ์œ„ํ•ด HTTP Forwarded ๋˜๋Š” X-FORWARDED-FOR ํ—ค๋” ๋˜๋Š” ํ”„๋ก์‹œ ํ”„๋กœํ† ์ฝœ๊ณผ ๊ฐ™์€ ๋กœ๋“œ๋ฐธ๋Ÿฐ์„œ์™€ ๋ฐฑ์—”๋“œ ๊ฐ„์— ํ•ฉ์˜๋œ ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. ๋‘ ๋ฒˆ์งธ ๋ฒ”์ฃผ์˜ ๋กœ๋“œ๋ฐธ๋Ÿฐ์„œ๋Š” ์„œ๋น„์Šค์˜ service.spec.healthCheckNodePort ํ•„๋“œ์˜ ์ €์žฅ๋œ ํฌํŠธ๋ฅผ ๊ฐ€๋ฅดํ‚ค๋Š” HTTP ํ—ฌ์Šค ์ฒดํฌ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์œ„์—์„œ ์„ค๋ช…ํ•œ ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์ •๋ฆฌํ•˜๊ธฐ

์„œ๋น„์Šค๋ฅผ ์‚ญ์ œํ•œ๋‹ค.

kubectl delete svc -l app=source-ip-app

๋””ํ”Œ๋กœ์ด๋จผํŠธ, ๋ ˆํ”Œ๋ฆฌ์นด์…‹ ๊ทธ๋ฆฌ๊ณ  ํŒŒ๋“œ๋ฅผ ์‚ญ์ œํ•œ๋‹ค.

kubectl delete deployment source-ip-app

๋‹ค์Œ ๋‚ด์šฉ