쿠버네티스 기본 사용법

이지우·2023년 5월 4일
0

쿠버네티스

목록 보기
6/9

💻 파드 생성

run으로 파드 생성

kubectl run 명령을 실행하여 쉽게 파드를 생성할 수 있음

kubectl run niginx-pod --image=nginx
nginx-pod : 파드 이름
--image=nginx : 생성할 이미지 이름

create로 파드 생성

kubectl create nginx --image=nginx
-> --image라는 옵션이 없다는 에러 메시지

create로 파드를 생성할 때는 deployment를 추가해서 실행해야 함
kubectl create deployment dpy-nginx --image=nginx

생성된 파드 확인
kubectl get pods -o wide

이름에서 dpy-nginx를 제외한 나머지 부분은 무작위로 생성됨

run과 create deployment 차이점

run으로 생성하면 단일 파드 1개만 생성되고 관리됨

create deployment로 파드를 생성하면 디플로이먼트(Deployment)라는 관리 그룹 내에서 파드가 생성됨


📌 오브젝트란?

파드와 디플로이먼트는 스펙(spec)과 상태(status) 등의 값을 가지고 있음
이 값을 가지고 있는 파드와 디플로이먼트를 개별 속성을 포함해 부르는 단위를 오브젝트(Object)라고 함

참고 링크 [쿠버네티스 공식 사이트]

기본 오브젝트

  • 파드(Pod)
    : 쿠버네티스에서 실행되는 최소 단위
    : 웹 서비스를 구동하는 데 필요한 최소 단위
    : 독립적인 공간과 사용 가능한 IP를 가지고 있음
    : 하나의 파드는 1개 이상의 컨테이너를 갖고 있음
    ; 여러 기능을 묶어 하나의 목적으로 사용할 수 있음
    : 범용으로 사용할 때는 대부분 1개의 파드에 1개의 컨테이너를 적용함

  • 네임스페이스(Namespaces)
    : 쿠버네티스 클러스터에서 사용되는 리소스들을 구분해 관리하는 그룹

    • 기본으로 할당되는 default
    • 쿠버네티스 시스템에서 사용되는 kube-system
    • 온프레미스에서 쿠버네티스를 사용할 경우 외부에서 쿱버네티스 클러스터 내부로 접속하게 도와주는 컨테이너들이 속해 있는 metallb-system
  • 볼륨(Volume)
    : 파드가 사라지더라도 저장과 보존이 가능한 디렉터리를 생성하고 사용
    : 파드는 영속되는 개념이 아니라서 제공되는 디렉터리도 임시로 사용됨

  • 서비스(Service)
    : 파드는 클러스터 내에서 유동적이기 때문에 접속 정보가 고정일 수 없음
    : 파드 접속을 안정적으로 유지하도록 서비스를 통해 내/외부로 연결됨
    : 새로 파드가 생성될 때 부여되는 새로운 IP를 기존에 제공하던 기능과 연결해 줌
    : 쿠버네티스 외부에서 쿠버네티스 내부로 접속할 때 내부가 어떤 구조로 돼 있는지, 파드가 살았는지 죽었는지 신경 쓰지 않아도 이를 논리적으로 연곁하는 것
    : 로드밸런서, 게이트웨이와 비슷한 역할

디플로이먼트

효율적으로 작동하도록 기능들을 조합하고 추가해 구현한 것

파드에 기반을 두고 있으며 레플리카셋 오브젝트를 합쳐 놓은 형태

API 서버와 컨트롤러 매니저는 파드 생성을 감시하는 것 뿐만 아니라 디플로이먼트처럼 레플리카셋을 포함하는 오브젝트의 생성을 감시함


💻 디플로이먼트 생성, 삭제

이미지 경로 : sysnet4admin/echo-hname (책 저자분 저장소)

  1. 디플로이먼트 생성
    kubectl create deployment dpy-hname --image=sysnet4admin/echo-hname

  2. 생성된 디플로이먼트 확인
    kubectl get pods

  3. 디플로이먼트 삭제
    kubectl delete deployment dpy-hname

  4. 삭제되었는지 확인
    kubectl get pods


레플리카셋으로 파드 수 관리

쿠버네티스에서는 다수의 파드를 만드는 레플리카셋 오프젝트를 제공하고 있음

파드를 3개 만들 경우 레플리카셋에 선언하면 컨트롤러 매니저와 스케줄러가 워커 노드에 파드 3개를 만들도록 선언함

파드 수를 보장하는 기능만 제공함
-> 롤링 업데이트 기능 등이 추가된 디플로이먼트를 사용해 파드 수를 관리함

💻 파드 수 관리 과정

  1. 배포되 파드 상태 확인
    kubectl get pods

  2. nginx-pod를 3개로 증가
    kubectl scale pod nginx-pod --replicas=3
    --replicas=3 : 파드의 수를 3개로 맞추는 옵션
    -> 리소스를 찾을 수 없다는 에러 메시지
    -> 디플로이먼트 오브젝트가 아니라 파드라서 그럼

  3. dpy-nginx를 3개로 증가
    kubectl scale deployment dpy-nginx --replicas=3

  4. 파드 생성 확인
    kubectl get pods

  5. 정상적으로 워커 노드에 적용되고 IP가 부여 되었는지 확인
    kubectl get pods -o wide

  6. 생성한 디플로이먼트 삭제
    kubectl delete deployment dpy-nginx

  7. 삭제 확인
    kubectl get pods


스펙을 지정해 오브젝트 생성

📌 오브젝트 스펙

디플로이먼트를 생성하면서 한꺼번에 여러 개의 파드를 만들기
-> 필요한 내용을 파일로 작성해야 함
-> 오브젝트 스펙(spec)

야믈(YAML) 문법으로 작성

야믈(YAML) : '또 다른 마크업 언어(Yet Another Markup Language)의 약어
-> '야믈은 단순히 마크업 언어가 아니다(YAML Ain't Markup Language)라고 다시 정의됨

💻 3개의 디플로이먼트 오브젝트 만들기

~/_Book_k8sInfra/ch3/3.2.4 디렉터리의 예제 파일(echo-hname.yaml) 사용

apiVersion: apps/v1 # API 버전
kind: Deployment # 오브젝트 종류
metadata:
  name: echo-hname
  labels:
    app: nginx
spec:
  replicas: 3 # 몇 개의 파드를 생성할 지 결정
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: echo-hname
        image: sysnet4admin/echo-hname # 사용되는 이미지

nginx-pod.yaml 파일과 디플로이먼트의 template 부분은 동일함
-> template 하위의 metadataspec이 nginx-pod.yaml에서 동일하게 사용됨

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  containers:
  - name: container-name
    image: nginx

  1. echo-hname.yaml 파일로 디플로이먼트 생성
    kubectl create -f ~/_Book_k8sInfra/ch3/3.2.4/echo-hname.yaml

  2. 파드 3개 생성 확인
    kubectl get pods

  3. echo-hname.yaml 파일 수정하여 파드 6개로 늘리기
    sed(streamlined editor) 명령으로 파일 replicas 값을 3에서 6으로 변경
    sed -i 's/replicas: 3/replicas: 6/' ~/_Book_k8sInfra/ch3/3.2.4/echo-hname.yaml
    -i : --in-place의 약어, 변경한 내용을 현재 파일에 바로 적용하겠다는 의미
    s/ : 주어진 패턴을 원하는 패턴으로 변경하겠다는 의미

  4. replicas값이 6으로 변경됐는지 확인
    cat ~/_Book_k8sInfra/ch3/3.2.4/echo-hname.yaml | grep replicas

  5. 변경된 내용 적용
    kubectl create -f ~/_Book_k8sInfra/ch3/3.2.4/echo-hname.yaml
    -> echo-hname이 이미 존재한다는 에러 메시지

배포된 오브젝트의 스펙을 변경하고 싶을 때는 어떻게 해야하는가?


💻 apply로 오브젝트 생성, 관리

  1. replicas를 6으로 수정한 echo-hname.yaml 파일을 kubectl apply 명령으로 적용
    kubectl apply -f ~/_Book_k8sInfra/ch3/3.2.4/echo-hname.yaml
    -> 오브젝트를 처음부터 apply로 생성한 것이 아니어서 경고가 뜸

  2. 6개로 늘어났는지 확인
    kubectl get pods


📌 run / create / apply 비교

create
: 명령 창 등에서 직접 애드혹(ad-hoc, 일회적 사용)으로 오브젝트를 생성할 때

apply
: 변경이 생길 가능성이 있는 복잡한 오브젝트는 파일로 작성한 후 적용

구분RunCreateApply
명령 실행제한적임가능함안 됨
파일 실행안 됨가능함가능함
변경 가능안 됨안 됨가능함
실행 편의성매우 좋음매우 좋음좋음
기능 유지제한적임지원됨다양하게 지원됨

💻 파드의 컨테이너 자동 복구 방법

셀프 힐링(Self-Healing) : 파드의 자동 복구 기술
제대로 작동하지 않는 컨테이너를 다시 시작하거나 교체해 파드가 정상적으로 작도하게 함

  1. 파드의 IP를 알아야 접속할 수 있음
    kubectl get pods -o wide

  2. kubectl exec 명령으로 파드 컨테이너의 셸(shell)에 접속
    nginx-pod에 /bin/bash를 실행해 컨테이너에서 배시(bash) 셸에 접속
    kubectl exec -it nginx-pod -- /bin/bash
    exec : execute(실행)을 의미
    i : stdin(standard input, 표준 입력)
    t : tty(teletypewriter)
    it: 표준 입력을 명령줄 인터페이스로 작성한다는 의미

  3. nginx의 PID 확인 -> nginx의 PID는 항상 1
    cat /run/nginx.pid

  4. ls -l 명령으로 프로세스가 생성된 시간 확인
    ls -l /run/nginx.pid

  5. 슈퍼푸티에서 m-k8s 터미널을 1개 더 띄우고 nginx-pod의 IP에서 돌아가는 웹 페이지를 1초마다 한 번씩 요청하는 스크립트 실행
    i=1; while true; do sleep 1; echo $((i++)) 'curl --silent 172.16.103.132 | grep title' ; done

  6. 배시 셸에서 nginx 프로세서인 PID 1번을 kill 명령으로 종료
    kill 1

  7. 자동으로 복구되고 스크립트가 잘 작동됨

  8. 다시 nginx-pod에 접속하고 ls -l로 생성 시간 확인


💻 파드의 동작 보증 기능

파드 자체에 문제가 발생하면 파드를 자동 복구해서 파드가 항상 동작하도록 보장하는 기능이 있음

  1. 파드에 문제가 발생하는 상황을 만들기 위해 생성한 파드를 삭제하기 전 파드 확인
    kubectl get pods

  2. nginx-pod 삭제
    kubectl delete pods nginx-pod

  3. 동작을 보증하기 위해 필요한 조건 확인을 위해 비교할 다른 파드 삭제
    kubectl delete pods echo-hname-~~(이름 다름)

  4. 삭제 되었는지 확인
    kubectl get pods
    -> 아직 6개의 파드가 살아있고 하나는 최근에 생성됨

동작 이유

nginx-pod는 디플로이먼트에 속한 파드가 아니어서 어떤 컨트롤러도 이 파드를 관리하지 않음
-> nginx-pod는 바로 삭제되고 다시 생성되지 않음

echo-hname은 디플로이먼트에 속한 파드로 replicas를 6개로 선언함
선언한 수대로 유지하도록 파드의 수를 항상 확인하고 부족하면 새로운 파드를 만들어냄

디플로이먼트에 속한 파드 삭제

디플로이먼트에 속한 파드는 상위 디플로이먼트를 삭제해야 파드가 삭제됨

  1. kubectl delete deployment echo-hname 명령으로 디플로이먼트 삭제
  2. 파드가 남아 있는지 확인
    kubectl get pods

노드 자원 보호하기

노드 : 쿠버네티스 스케줄러에서 파드를 할당받고 처리하는 역할

최근에 몇 차례 문제가 생긴 노드에 파드를 할당하면 문제가 생길 가능성이 높음
-> 어쩔 수 없이 해당 노드를 사용해야 한다면?

영향도가 적은 파드를 할당해 일정 기간 사용하면서 모니터링
-> 노드에 문제가 생기더라도 파드의 문제를 최소화

but, 쿠버네티스는 모든 노드에 균등하게 파드를 할당하려고 함

문제가 생길 가능성이 있는 노드라는 것을 쿠버네티스에 알려야 함 !

💻 cordon 기능

  1. echo-hname.yaml을 적용(apply)하여 파드 생성
    kubectl apply -f ~/_Book_k8sInfra/ch3/3.2.8/echo-hname.yaml

  2. scale 명령으로 배포한 파드를 9개로 늘림
    kubectl scale deployment echo-hname --replicas=9

  3. 배포된 파드 확인
    kubectl get pods -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase,NODE:.spec.nodeName
    -o : output
    custom-columns : 사용자가 임의로 구성할 수 있는 열
    NAME, IP, STATUS, NODE : 열의 제목
    .metadata.name, .status.podIP, .status.phase, .spec.nodeName : 내용 값

  4. scale로 파드의 수를 3개로 줄임
    kubectl scale deployment echo-hname --replicas=3

  5. 각 노드에 파드가 1개씩만 남았는지 확인
    kubectl get pods -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase,NODE:.spec.nodeName

  6. w3-k8s 노드에서 문제가 자주 발생해 현재 상태를 보존
    kubectl cordon w3-k8s

  7. kubectl get nodes 명령으로 cordon 명령이 제대로 적용됐는지 확인
    -> cordon 명령을 실행하면 노드에 파드가 할당되지 않게 스케줄되지 않는 상태(SchedulingDisabled)라는 표시를 함

  8. 파드 수를 9개로 늘림
    kubectl scale deployment echo-hname --replicas=9

  9. 노드에 배포된 파드확인
    kubectl get pods -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase,NODE:.spec.nodeName
    -> w3-k8s는 파드 수가 여전히 1개

  10. 파드 수를 3개로 줄임
    kubectl scale deployment echo-hname --replicas=3

  11. 각 노드에 할당된 파드 수가 공평하게 1개씩인지 확인
    kubectl get pods -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase,NODE:.spec.nodeName

  12. w3-k8s에 파드가 할당되지 않게 설정했던 것을 해제
    kubectl uncordon w3-k8s

  13. w3-k8s에 적용됐는지 확인
    kubectl get nodes


💻 노드 유지보수하기

정기 / 비정기적인 유지보수를 위해 노드를 꺼야하는 상황 발생
-> drain 기능 제공

drain

지정된 노드의 파드를 전부 다른 곳으로 이동시켜 해당 노드를 유지보수할 수 있게 함

  1. kubectl drain 명령으로 유지보수할 노드(w3-k8s)를 파드가 없는 상태로 만듬
    kubectl drain w3-k8s
    -> 데몬셋을 지울 수 없어서 명령을 수행할 수 없다고 나옴
    -> drain은 노드에서 파드를 삭제하고 다른 곳에 다시 생성함
    -> DaemonSet은 각 노드에 1개만 있는 파드라서 삭제할 수 없음

  2. drain 명령과 ignore-daemonsets 옵션을 함께 사용하여 DaemonSet을 무시하고 진행
    kubectl drain w3-k8s --ignore-daemonsets

  3. w3-k8s에 파드가 없는지 확인
    -> 옮긴 노드에 파드가 새로 생성되어 파드 이름과 IP가 부여됨
    kubectl get pods -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase,NODE:.spec.nodeName

  4. drain 명령이 수행된 w3-k8s 노드의 상태 확인
    -> cordon을 실행했을 때처럼 SchedulingDisable 상태
    kubectl get nodes

  5. w3-k8s에 uncordon 명령을 실행해 스케줄을 받을 수 있는 상태로 복귀
    kubectl uncordon w3-k8s

  6. 다시 노드 상태 확인
    kubectl get nodes


💻 파드 업데이트하고 복구하기

  • 컨테이너에 새로운 기능을 추가하거나 치명적인 버그가 발생해 버전을 업데이트 해야하는 상황
  • 업데이트하는 도중 문제가 발생해 다시 기존 버전으로 복구해야하는 상황

파드 업데이트

  1. 파드 배포
    kubectl apply -f ~/_Book_k8sInfra/ch3/3.2.10/rollout-nginx.yaml --record
    --record : 배포한 정보의 히스토리 기록
# <rollout-nginx.yaml>
apiVersion: apps/v1
kind: Deployment
metadata:
  name: rollout-nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.15.12 # 중요 포인트 (컨테이너 버전 지정)

  1. record 옵션으로 기록된 히스토리는 rollout history 명령으로 실행해 확인
    kubectl rollout history deployment rollout-nginx

  2. 배포한 파드의 정보 확인
    kubectl get pods -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase,NODE:.spec.nodeName

  3. 배포된 파드에 속해 있는 nginx 컨테이너 버전을 curl -I(헤더 정보만 보여주는 옵션) 명령으로 확인
    curl -I --silent 172.16.103.143 | grep Server (IP 다를 수 있음)

  4. set image 명령으로 파드의 nginx 컨테이너 버전을 1.16.0으로 업데이트
    kubectl set image deployment rollout-nginx nginx=nginx:1.16.0 --record

  5. 업데이트 후 파드 상태 확인
    kubectl get pods -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase,NODE:.spec.nodeName
    -> 파드 이름과 IP가 변경됨

파드에 속한 nginx 컨테이너를 업데이트하는 가장 쉬운 방법
-> 파드를 관리하는 replicas 수를 줄였다가 늘려 파드를 새로 생성하는 것
-> 시스템 영향을 최소화하기 위해 replicas에 속한 파드를 하나씩 순차적으로 지우고 생성함
-> 파드 수가 많으면 하나씩이 아니라 다수의 파드가 업데이트 되기도 함

  1. nginx 컨테이너가 모두 업데이트되면 Deployment 상태 확인
    kubectl rollout status deployment rollout-nginx

  2. rollout history 명령으로 rollout-nginx에 적용된 명령들 확인
    kubectl rollout history deployment rollout-nginx

  3. curl -I명령으로 업데이트가 잘 됐는지 확인
    curl -I --silent 172.16.132.10 | grep Server (IP 다를 수 있음)


업데이트 실패 시 파드 복구하기

  1. set image 명령으로 nginx 컨테이너 버전을 잘못되게 입력
    kubectl set image deployment rollout-nginx nginx=nginx:1.17.23 --record

  2. 한참 지나도 파드가 삭제되지 않고 pending(대기 중) 상태에서 넘어가지 않음
    kubectl get pods -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase,NODE:.spec.nodeName

  3. 문제 확인을 위해 rollout status 실행
    kubectl rollout status deployment rollout-nginx
    -> 새로운 replicas가 생성됐지만 배포하는 단계에서 대기 중(Waiting)

  4. Deployment를 끝내 생성되지 않았다는 메시지 출력

  5. describe 명령으로 쿠버네티스 상태 확인
    kubectl describe deployment rollout-nginx
    -> replicas가 새로 생기는 과정에서 멈춰있음 (1.17.23 버전의 컨테이너가 없어서)
    -> 컨테이너 이미지를 찾을 수 없어서 배포되지 않음
    -> 업데이트할 때 rollout를 사용하고 --record로 기록하는 이유!

  6. 정상적인 상태로 복구하기 위해 사용했던 명령 확인
    kubectl rollout history deployment rollout-nginx

  7. rollout undo 명령으로 실행 취소
    kubectl rollout undo deployment rollout-nginx

  8. 파드 상태 확인
    kubectl get pods -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase,NODE:.spec.nodeName

  9. rollout history로 실행된 명령 확인
    kubectl rollout history deployment rollout-nginx
    -> revision 4가 추가되고 revision 2가 삭제됨

  10. 배포된 컨테이너 버전 확인
    curl -I --silent 172.16.132.10 | grep Server (IP 다름 주의)
    -> 버전이 1.16.0으로 상태가 되돌려짐

  11. rollout status 명령으로 변경이 적용됐는지 확인
    kubectl rollout status deployment rollout-nginx

  12. describe로 현재 디플로이먼트 상태를 세부적으로 점검


특정 시점으로 파드 복구

특정 시점으로 돌아가기 위해서는 --to-revision 옵션 사용

  1. 처음 상태로 돌아가기
    kubectl rollout undo deployment rollout-nginx --to-revision=1

  2. 새로 생성된 파드들의 IP 확인
    kubectl get pods -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase,NODE:.spec.nodeName

  3. curl -I로 nginx 컨테이너 버전 확인
    curl -I --silent 172.16.103.150 | grep Server (IP 다름 주의)

profile
노력형 인간

0개의 댓글