Kubernetes 리소스 Pod에 대해 이해하고 실습해보기

Bakumando·2022년 5월 22일
0

Kubernetes

목록 보기
5/17

들어가기에 앞서...

  • 본 글은 쿠버네티스 시리즈 중의 하나로, kubernetes 실습을 위한 기본 환경 세팅이 이루어져 있지 않은 분은 시리즈 1편을 확인해주시길 바란다.
  • 쿠버네티스 실습 시리즈는 아래 학습 자료를 참고하고 있다.

0. 블로깅 목적

  • Pod가 무엇이고 어떤 생성 방식을 거치는지 이해한다.
  • 명령형 커맨드로 Pod를 생성 및 실행할 수 있다.
  • 선언형 커맨드로 Pod를 생성 및 실행할 수 있다.
  • 멀티 컨테이너 Pod를 생성 및 실행할 수 있다.
  • Pod 컨테이너의 상태를 모니터링 하는 방법을 이해한다.

1. Pod가 무엇이고 어떤 생성 방식을 거치는지 이해한다.

  • Pod란 쿠버네티스에서 관리하는 가장 작은 배포 단위이다.
  • 도커가 Container를 만든다면, 쿠버네티스는 Container 대신에 Pod를 만든다고 보면 된다.
  • 즉 Pod는 1개 이상의 컨테이너로 구성된 컨테이너 집합이라고 할 수 있다.
  • 동일 파드 내 컨테이너는 여러 리눅스 네임스페이스를 공유한다.
    • 이는 네트워크 네임스페이스도 공유한다는 것이며, 이말인 즉슨 결국 동일 Pod 내의 컨테이너는 모두 동일 IP를 가진다는 뜻이다.
    • 위 그림을 통하면 더 이해하기 쉽다. 에메랄드 큐브는 컨테이너고, 퍼플 큐브는 볼륨이다. Pod 하나는 1개 이상의 컨테이너나 볼륨으로 자유롭게 구성될 수 있으며, 각 Pod 내에 있는 큐브들은 전부 같은 IP 주소를 공유한다.
  • 다중 컨테이너를 포함하는 리소스라는 건 약간 docker-compose의 냄새가 난다고도 할 수 있다.
  • 참고로 쿠버네티스가 지원해주는 애플리케이션과 관련된 다양한 API 리소스 가 있다. (Deployment, Statufulset, DaemonSet, Jon, CronJob, ReplicaSet 등) 근데 이런 것들을 만들어서 애플리케이션을 띄우더라도, 각각의 내부적으로는 전부 Pod를 띄우게 된다.
    • API 리소스는 Pod를 wrapping한다고 할 수 있으며, 자연스레 스스로 Pod를 관리하는 역할을 한다. (어지간하면 사용자가 파드를 직접 관리하진 않는다 라는 것이다.)

2. 명령형 커맨드로 Pod를 생성 및 실행할 수 있다.

간단한 명령형 커맨드를 실습해보자.

$ kubectl run {Pod 이름} --image={이미지 이름}
$ kubectl run -it {Pod 이름} --image={이미지 이름} bash
  • docker에 run이라는 명령어가 있다. 컨테이너의 생성과 실행을 한번에 수행해주는 커맨드이다.
  • kubectl에도 run이라는 명령어가 있다. 마찬가지로 컨테이너의 집합인 Pod를 만들고 실행시킨다.
  • docker와 마찬가지로, kubectl에서도 -it 옵션과 bash 키워드를 통해 쉘 환경에 접속하는 것이 가능하다.
  • 참고로 이 방식은 명령형 방식이다. 전편에서 말했듯 CRUD는 선언형으로 수행하는 게 효과적이다. 하지만 이를 다시 한번 상기시키기 위해 실습을 수행해보자.

  • kubectl run -it ubuntu --image=ubuntu:focal bash
    • 쉘 환경에서 ls를 입력하여 파일리스트를 확인하였다.
    • 참고로 ^D키로 빠져나올 수 있다.

  • kubectl get all
    • ubuntu라는 이름의 pod타입 오브젝트가 확인된다.

참고 1: 기타 pod 리소스 관련 커맨드

  • kubectl api-resources | grep pod
    • api 리소스를 전부 불러오되 그 중에 pod 키워드만 필터링하는 방법이다.

  • kubectl explain pod
    • pod 리소스에 대한 상세한 설명을 볼 수 있다.

3. 선언형 커맨드로 Pod를 생성 및 실행할 수 있다.

yml 파일을 활용하여, 선언형 커맨드로 pod를 생성 및 실행해보자.

  • yml 파일을 준비한다.

pod.yml

apiVersion: v1
kind: Pod
metadata:
  name: hello
spec:
  containers:
  - name: nginx
    image: nginxdemos/hello:plain-text
    ports:
    - name: http
      containerPort: 80
      protocol: TCP

  • cat pod.yml
    • pod 생성 전에 간단하게 파일 내용 출력해본다.

  • kubectl apply -f pod.yml
    • pod를 생성한다. yml을 활용한 선언형 방식이다.

  • kubectl get pod
    • 정상 조회가 된다. (처음에 만들어둔 ubuntu도 같이 보인다.)
    • READY는 {준비된 컨테이너 수}/{총 컨테이너수} 를 뜻한다. 여기서는 총 1개의 컨테이너 중 1개가 준비되었다고 할 수 있겠다.

  • kubectl get pod -o wide
    • 더 많은 정보를 볼 수 있다.
    • pod의 IP를 알 수 있다. hello pod의 IP에 접속해볼까?

  • curl http://172.17.0.4
    • IP에 직접 접속해보았으나 무응답이다.
    • 이유는 간단하다. 도커를 배웠으면 이해하기 어렵지 않다. 컨테이너가 격리된 환경에 존재하기 때문에 외부에서 직접 접근이 불가능 하듯이, 마찬가지로 클러스터도 격리된 환경에 있기 때문에 직접 접근은 안된다.
    • 즉, 클러스터 내부에서만 확인이 가능하다는 것이다.
    • 해당 IP에 접근하는 방법은 2가지다.
      • 직접 클러스터 내부로 들어가는 방법,
      • 클러스터 내에 새로운 Pod를 만들어 쉘환경으로 접속하고 거기에서 해당 Pod에 접근을 하는 방법

(1) 클러스터 내부에 접속하여 접근

  • minikube ssh
    • minikube가 ssh를 지원하기 때문에 클러스터에 진입할 수 있다.
    • 클러스터 내부에선 해당 IP를 사용할 수 있다는 걸 알 수 있다.

(2) 클러스터 내부에 있는 다른 파드에 접속하여 접근

  • kubectl exec -it ubuntu bash
    • 이미 만들어두었던 ubuntu 파드를 활용하여 exec -it 키워드로 쉘 환경에 접속해보았다. 접근도 시도해보자. (이것도 도커와 흡사하다)
    • 성공이다. 이처럼 같은 클러스터 상에서라면 서로 다른 파드 IP에도 접근이 가능한 것이다.
    • ※ 사실 약간의 문제가 있었는데, 생성된 ubuntu가 curl 명령어를 인식하지 못했다. 게다가 설치하려니 apt-get에 curl 패키지도 없어서 아래 명령어들을 순차적으로 수행해주었다는 점을 참고하자.
$ apt-get update
$ apt-get install -y curl

4. 멀티 컨테이너 Pod를 생성 및 실행할 수 있다.

멀티 컨테이너 Pod 실습을 수행해보자.

  • 어떤 목적으로 멀티 컨테이너 Pod를 구축하게 되는 지 알아야 한다. 보통 운영환경에서는 사이드카 패턴을 구성하고자 할때에 멀티 컨테이너 파드를 구축한다.
  • 동일 파드 내에 있는 멀티 컨테이너는 모두 같은 노드에서 실행된다. 이유는 앞서 말했듯이 같은 네임스페이스를 공유하기 때문이다.
  • 그리고 멀티 컨테이너가 존재할 시에는 이제 커맨드를 입력할 때에도 어떤 컨테이너에 명령어를 전달할지 지정을 해줘야 한다. 안그러면 default로 세팅된 기본 컨테이너로 전달이 되거나, 컨테이너를 지정해야 한다는 안내 메시지가 뜬다. 이를 위한 지정 옵션도 실습을 통해 만나보자.

  • 바로 실습으로 들어가보자.
  • 들어가기에 앞서 yml을 또 준비해주자.
  • 그리고 기존에 실습하며 만들어뒀던 pod들도 delete 키워드로 모두 삭제해두자.

multi.yml

apiVersion: v1
kind: Pod
metadata:
  name: hello
spec:
  containers:
  - name: nginx
    image: nginxdemos/hello:plain-text
    ports:
    - name: http
      containerPort: 80
      protocol: TCP
  - name: debug
    image: posquit0/doraemon:latest

  • cat multi.yml
    • pod 생성 전에 간단하게 파일 내용을 출력해본다.
    • pod.yml에서 컨테이너만 하나더 추가한 spec이다.

  • kubectl apply -f multi.yml
    • pod를 생성하고 -o wide로 조회해본다.
    • READY가 2/2이고 동일한 IP를 공유하고 있음을 알 수 있다.

  • kubectl describe pod hello
    • describe로 상세 조회를 할 수 있다.
    • Containers 밑에 두 개의 컨테이너가 있음을 확인할 수 있다.

  • kubectl exec -it hello sh
    • Defaulted container "nginx"라는 문구를 확인할 수 있다. 컨테이너를 지정하지 않았기 때문에 기본 컨테이너로 세팅된 nginx로 명령어가 전달된 것이다.

  • kubectl exec -it hello -c debug sh
    • -c 옵션을 주면, 커맨드를 전달할 컨테이너를 지정할 수 있다.
    • 잘 지정했기 때문에 아무런 안내 메시지가 뜨지 않는다.
    • 이어서 curl 명령어로 localhost 주소Pod ip 주소를 모두 접근해보았다.
      • 당연히 둘다 정상적으로 접근이 된다.

  • kubectl logs hello
    kubectl logs hello -c debug
    • 마지막으로 logs 커맨드도 실행해보았다.
    • -c 옵션을 주지 않으면 마찬가지로 Defaulted container "nginx"가 뜨고 logs가 나온다.
    • -c 옵션을 주면 그런 문구 없이 관련 logs가 출력된다.

참고 1: 사이드카 패턴이란?

  • 메인 컨테이너 옆에 붙어서 이를 보조하는 컨테이너라고 생각하면 된다.
  • 자주 사용되는 사이드카 패턴 (유즈 케이스)
    • Filebeat(Log Agent류): 이를 Pod에 사이드카 컨테이너로 이를 삽입하면, 메인 컨테이너의 로그를 수집 및 정제하여 외부 로그 저장소로 보낼 수 있다.
    • Envoy(proxy-Server류): 서비스 메시 구성할 때에 이러한 Envoy 사이드카 패턴을 삽입하면, 각각의 Pod 끼리 통신을 할 때에 게이트웨이와 같은 역할을 해준다.
    • Valut Agent: 이를 사이드카 패턴으로 삽입하면, 해당 Pod가 띄워지는 시점에 기밀 데이터를 안전하게 Valut로부터 가져와서 해당 Pod에 주입을 해줄 수 있는 역할을 해준다.
    • Nginx Agent류: 이를 사이드카 패턴으로 삽입하면, Nginx와 같은 서버를 Pod로 띄운다고 할 때에, 설정이 변경되는 것을 감지해서 Nginx 프로세스를 리로드하는 역할을 준다.

4. Pod 컨테이너의 상태를 모니터링 하는 방법을 이해한다.

  • 컨테이너 생성과 실제 서비스 준비는 약간의 차이가 있다. 서버를 실행하면 바로 접속할 수 없고 짧게는 수초, 길게는 수분의 초기화 시간이 필요한데 실제로 접속이 가능할 때 서비스가 준비되었다고 말할 수 있다.
  • 쿠버네티스는 컨테이너가 생성되고 서비스가 준비되었다는 것을 체크하는 옵션을 제공하여 초기화하는 동안 서비스되는 것을 막을 수 있다.
  • 참고로 4번 챕터는 https://subicura.com의 쿠버네티스 안내서의 내용을 완전히 그대로 따라간다고 보면 된다.

1) livenessProbe

  • 컨테이너가 정상적으로 동작하는지 체크하고 정상적으로 동작하지 않는다면 컨테이너를 재시작하여 문제를 해결한다.
  • 정상이라는 것은 여러 가지 방식으로 체크할 수 있는데 여기서는 http get 요청을 보내 확인하는 방법을 사용한다.

echo-lp.yml

apiVersion: v1
kind: Pod
metadata:
  name: echo-lp
  labels:
    app: echo
spec:
  containers:
    - name: app
      image: ghcr.io/subicura/echo:v1
      livenessProbe:
        httpGet:
          path: /not/exist
          port: 8080
        initialDelaySeconds: 5
        timeoutSeconds: 2 # Default 1
        periodSeconds: 5 # Defaults 10
        failureThreshold: 1 # Defaults 3
  • 일부러 존재하지 않는 path(/not/exist)와 port(8080)를 입력해주었다.
  • 참고로 httpGet 외에 tcpSocket, exec 방법으로 체크할 수 있다.
  • subicura님의 쿠버네티스 안내서 url을 사용해도 된다: https://subicura.com/k8s/code/guide/pod/echo-rp.yml

  • 준비한 yml 파일로 오브젝트를 생성하고 조회해보자.
  • kubectl apply -f echo-lp.yml
  • kubectl get pod -o wide
    • 정상적으로 응답하지 않았기 때문에 Pod이 여러 번 재시작되고 CrashLoopBackOff 상태로 변경되었음을 확인할 수 있다.
  • kubectl delete -f echo-lp.yml로 제거 해준다.

2) readinessProbe

  • 컨테이너가 준비되었는지 체크하고 정상적으로 준비되지 않았다면 Pod으로 들어오는 요청을 제외한다.
  • livenessProbe와 차이점은 문제가 있어도 Pod을 재시작하지 않고 요청만 제외한다는 점이다.

echo-rp.yml

apiVersion: v1
kind: Pod
metadata:
  name: echo-rp
  labels:
    app: echo
spec:
  containers:
    - name: app
      image: ghcr.io/subicura/echo:v1
      readinessProbe:
        httpGet:
          path: /not/exist
          port: 8080
        initialDelaySeconds: 5
        timeoutSeconds: 2 # Default 1
        periodSeconds: 5 # Defaults 10
        failureThreshold: 1 # Defaults 3
  • 일부러 존재하지 않는 path(/not/exist)와 port(8080)를 입력해주었다.
  • subicura님의 쿠버네티스 안내서 url을 사용해도 된다: https://subicura.com/k8s/code/guide/pod/echo-rp.yml

  • 준비한 yml 파일로 오브젝트를 생성하고 조회해보자.
  • kubectl apply -f echo-rp.yml
  • kubectl get pod -o wide
    • livenessProbe와는 다르게 READY상태가 그냥 0/1인 것을 확인할 수 있다.
  • kubectl delete -f echo-rp.yml로 제거 해준다.

3) livenessProbe + readinessProbe

  • 보통 livenessProbe와 readinessProbe를 같이 적용한다. 상세한 설정은 애플리케이션 환경에 따라 적절하게 조정해준다.

echo-lrp.yml

apiVersion: v1
kind: Pod
metadata:
  name: echo-health
  labels:
    app: echo
spec:
  containers:
    - name: app
      image: ghcr.io/subicura/echo:v1
      livenessProbe:
        httpGet:
          path: /
          port: 3000
      readinessProbe:
        httpGet:
          path: /
          port: 3000
  • subicura님의 쿠버네티스 안내서 url을 사용해도 된다: https://subicura.com/k8s/code/guide/pod/echo-pod-health.yml

  • kubectl apply -f echo-lrp.yml
  • kubectl get pod -o wide
    • 이번엔 3000번 포트와 / 경로를 정상적으로 설정했기 때문에 Pod가 오류없이 생성된 것을 확인할 수 있다.
    • kubectl delete -f echo-lrp.yml 로 삭제하고 마무리한다.
profile
그렇게 바쿠만도는 개발에 퐁당 빠지고 말았답니다.

0개의 댓글