Container Orchestration System

Contents

  • Why Use Docker?
  • What is Container?
  • What is Docket?
  • Container Orchestration System
  • 쿠버네티스 구성요소 개념

    • 클러스터
    • 컴포넌트 종류와 구성
    • 파드와 노드
    • 인그레스
    • 컨트롤러
    • 서비스와 레이블
  • 쿠버네티스 동작 Flow
  • 컴토넌트 종류와 구성
  • K8S 설치

    • CNI
    • 웹사이트 이용
    • 도커 데스크탑 설치
    • k8s 직접 설치
    • GCP에 클러스터 구성하기
  • 컨테이너 실행 방법

    • kubectl run
    • deployment 사용하기
    • yaml 파일 사용
  • 쿠버네티스 실습 및 세부개념

    • Pod

      • Self-healing Pod (livenessProbe)
    • Controller

      • ReplicationController
      • ReplicaSet
      • Deployment
      • StatefulSet
      • Job
      • CronJob
    • Service
    • Ingress

Why Use Docker?

Docker에 접속하면 "Debug your app, not your environment "라는 문구를 가장 먼저 접하게 됩니다. 특정 소프트웨어를 사용하기 위한 설치 과정에서 어떠한 문제를 마주칠 수 있습니다. 그러면 설치 중 마주친 이 문제를 해결하고 다시 설치 과정을 진행해야 합니다. 이것이 Docker가 해결하고자 하는 문제입니다.

우리가 애플리케이션을 배포하려 한다면, 개발 환경이 아닌 다른 곳에서 애플리케이션을 작동시켜야 합니다. 예를 들어, 클라우드에 애플리케이션 배포 시 직접적인 제어나 설치가 쉽지 않기 때문에 애플리케이션 구동에 어려움을 겪을 수 있습니다. 이러한 어려움을 해결할 수 있는 방법 중 하나가 애플리케이션이 의존하는 환경을 번들링하는 소프트웨어를 사용하는 것입니다. 이러한 소프트웨어에는 Container와 Virtual Machine이 있습니다.

What is Container?

Container란 애플리케이션 배포 시 앞서 언급한 배포 환경이 일치하지 않는 문제를 해결해 줍니다.

애플리케이션 배포를 위해서는 환경을 설정해 주어야 합니다. 환경 설정이라고 하면 애플리케이션과 그와 관련된 설정 파일, 앱의 의존성 설치 및 런타임 환경 설정 등이 있을 수 있습니다. 하지만 개발 환경과 배포 환경의 차이에서 오는 문제로 배포 실패를 여러분은 아마도 경험해 보셨을 거라 생각합니다.

이를 위해 Virtual Machine이나 Container를 이용할 수 있어요. VM 과 Container는 개발 환경과 Production과의 간극을 최소화 해주고, 동시에 앱을 스케일링 할 때에도 사용됩니다.

VM and Containers solve the "It works on my machine problem".

VM은 Operating System과 가상의 하드웨어를 포함해서, 온전한 컴퓨터 한 대를 가상화 한 것과 같습니다. 하나의 물리적 컴퓨터는 여러 가상화 머신을 실행할 수 있고, 이를 통해 독립적인 애플리케이션을 여럿 확장할 수 있습니다.

하지만, 온전한 가상화 머신 하나를 실행하는 것은 리소스를 많이 필요로 합니다. 반면, 컨테이너는 하나의 Operating System 위에서 리눅스 커널에 내장 돼 있는 namespace와 cgroup 등을 활용해 호스트의 커널을 공유합니다. 가상의 Operating System이나 하드웨어가 없기 때문에 상대적으로 좀 더 가벼운 가상환경을 구성하고 적은 리소스가 사용됩니다.

what is docker?

Docker를 사용한다고 하면, 보통 Container를 생성하고 실행할 수 있도록 하는 전반적인 환경 또는 플랫폼을 말합니다. 이를 구성하는 요소로는 Docker Client, Docker Server, Docker Images 등이 있습니다.

터미널에서 docker run redis를 입력하면 뒤에서는 일련의 동작이 일어납니다. docker cli를 이용해 docker hub에서 접근해 image를 다운로드 합니다. 여기서 image는 특정 프로그램을 실행하기 위한 모든 의존성과 설정을 포함하고 있습니다. 그리고 이 이미지를 이용해 컨테이너를 생성하고 독립된 공간에서 프로그램을 실행시키게 됩니다.

Container Orchestration System

도커를 이용시 컨테이너 런타임만 있으면, 개발과 운영환경 차이에 따른 여러 문제를 해결할 수 있습니다. 하지만 컨테이너만으로 규모가 큰 서비스를 운영하는데 여럿 불편한 점이 발생할 수 있습니다. 서비스 운영 시 컨테이너만 사용을 한다면 여러 대 서버에 수동으로 배포를 진행해야 합니다.

하지만, 컨테이너 오케스트레이션 시스템을 사용하면 수동으로 제어하는 부분을 자동화 할 수 있습니다.

그리고 일부 클러스터에 장애가 발생하면, 장애가 발생한 서버의 컨테이너를 정상 운영 중인 다른 서버로 자동으로 옮겨 실행시켜줍니다.

이외에도 서비스 규모가 커질수록 고려해야 할 사항이 발생합니다.

  • 여러 컴퓨터의 클러스터에 어떻게 컨테이너 인스턴스를 프로비전할 것인지
  • 배포된 후 컨테이너는 어떻게 서로 검색하고 통신할지
  • 컨테이너 규모의 확장 및 축서 방법
  • 각 컨테이너의 상태 모니터링

이와 같은 여러 사항들을 해결하기 위해 컨테이너 오케스트레이션이라는 도구가 등장했습니다. 이 중 쿠버네티스를 이용하면 네트워크, 스토리지와 같은 클라우드 리소스를 개발자가 제어하고 자동화할 수 있습니다. 또한, 컨테이너를 클러스터에 분산 및 스케줄링하는 작업을 효율적으로 자동화 해 줍니다.

쿠버네티스 동작 Flow

쿠버네티스를 이용해 컨테이너가 어떻게 생성되고 운영이 되는지 전체적인 흐름에 대해 알아보겠습니다.

개발 진행한 컨테이너를 도커 허브에 저장 합니다. 그리고 그림의 3번과 같이 쿠버네티스에게 컨테이너를 실행을 요청합니다. 그러면, 쿠버네티스 control plane의 Api Server가 명령을 받고, 새로 생성할 컨테이너를 어디에 두면 좋을지 Scheduler에게 질의합니다. 응답으로 받은 노드의 kubelet에 컨테이너를 실행해 달라고 요청합니다. 그러면, 해당 노드의 kubelet은 전달 받은 요청을 도커 데몬에게 컨테이너 실행 요청을 합니다. 그러면, 도커 데몬은 요청 받은 도커 허브에서 이미지를 받은 후 실행합니다. 쿠버네티스는 이렇게 동작하는 컨테이너를 Pod 단위로 관리합니다.

쿠버네티스 구성요소 개념

클러스터 컴포넌트 종류와 구성

쿠버네티스 클러스터는 아래 두 가지 형태의 자원으로 구성됩니다.

  • 마스터: 클러스터를 조율하는 관리자
  • 노드: 애플리케이션을 구동하는 작업자

노드란, 쿠버네티스 클러스터 내 워커 머신으로 VM 또는 물리적 컴퓨터입니다. 마스터 노드는 Control Plane으로도 부릅니다. Control Plane과 워커 노드에는 아래와 같은 컴포넌트로 구성됩니다.


마스터 컴포넌트

  • etcd
  • kube-apiserver
  • kube-scheduler
  • kube-controller-manager

워커 노드 컴포넌트

  • kubelet
  • kube-proxy
  • 컨테이너 런타임

각 컴포넌트를 아래와 같이 그림으로 표현해 볼 수 있습니다.

애플리케이션을 쿠버네티스에 배포한다는 것은 "마스터에 애플리케이션 컨테이너를 구동하라고 명령하는 것"과 같은 맥락입니다.

예를 들어, 만약 kubectl create -f nginx-pod.yaml 명령어를 실행했다면, Control Plane에 API 컴포넌트가 해당 요청에 대한 문법, 권한 등을 확인합니다. etcd에는 워커 노드, 도커, 쿠버네티스 등의 상태 정보가 저장됩니다.

각 노드에는 kubelet이라는 데몬 컴포넌트가 있습니다. kubelet 안에는 cAdvisor라는 컨테이너 모니터링 툴이 포함되어 있어 컨테이너의 상태 정보를 수집합니다. kubelet이 컨테이너 및 하드웨어 정보를 Control Plane의 api에 전달하면, Control Plane은 그 정보를 etcd 안에 저장하게 됩니다.

kubectl을 통해 요청을 받으면, Control Plane은 노드에 대한 정보를 받아 Scheduler에게 문의를 하고, scheduler는 어떤 노드가 적절한지 응답을 줍니다. 응답을 받은 Control Plane은 응답으로 받은 노드의 kubelet에게 nginx 웹서버 실행 요청을 합니다. 그러면 kubelet은 컨테이너 런타임에 해당앱 실행을 요청합니다.

그리고 만약 nginx 웹서버 1개 실행을 요청했다고 하면, controller가 파드를 관찰하며 이를 보장해 줍니다.

파드와 노드

Pod는 컨테이너를 표현하는 k8s api의 최소 단위입니다. Pod에는 한 개 또는 복수의 컨테이너가 포함될 수 있습니다.

인그레스

인그레스는 클러스터 외부에서 안으로 접근하는 요청을 어떻게 처리할지 정의한 규칙입니다.

컨트롤러

컨트롤러는 파드를 관리하는 역할을 합니다. 주로 특정 애플리케이션을 실행해 주는 파드를 몇 개 운영할 지 결정하고 파드의 수를 보장해 줍니다.

위의 그림에서와 같이 쿠버네티스 api에 nginx 파드 세 개 실행을 요청을 하면, api는 etcd에서 노드에 대한 정보를 가져와 스케쥴러에 어디에 피드를 배치할지 확인합니다. 그리고 api가 해당 노드에 파드를 배치 전 컨트롤러에 해당 파드의 replicas를 보장하도록 요청합니다.

ReplicationController
지정한 숫자만큼의 파드가 클러스터 안에서 실행되도록 관리합니다. 파드에 이상이 생겼을 때 컨트롤러를 사용하지 않으면 파드를 재시작 하는 것이 쉽지 않습니다. selector를 기준으로 파드를 살펴보고, 요구하는 파드의 개수보다 부족한 수가 실행 시 template을 이용해 파드를 추가합니다.

ReplicaSet
레플리케이션과 같지만 집합 기반의 셀렉터와 여러 연산자를 지원합니다.

Deployment
Deployment는 파드의 개수를 보장하며, 앱 배포 시 롤링 업데이트, 파드 개수 조정, 롤백 등의 기능을 사용할 수 있습니다.

StatefulSet
이름과 같이 상태가 있는 파드를 관리하는 컨트롤러

Job

CronJob

Demonset
데몬세트는 클러스터 전체 노드에 특정 파드를 실행할 때 사용하는 컨트롤러 입니다.

서비스와 레이블

K8S 설치

CNI (Container Network Interface)

쿠버네티스 설치 전 알고 있어야 할 CNI 개념에 대해 알아볼게요. CNI는 컨테이너와 컨터네이가 통신을 하기 위해 필요한 인터페이스를 지원해 주는 소프트웨어입니다. 리액트 앱이 실행중인 컨테이너가 인증 관련 API 서버가 실행중인 컨테이너와 통신을 하기 위해서 CNI를 통해 다른 노드의 파드와 통신할 수 있습니다.

kubernetes

웹사이트 이용

별도의 설치 없이 아래 웹사이트에서 쿠버네티스를 사용해 볼 수 있습니다.

  • katacoda master, node1이 구성되어 있어 바로 사용가능.
  • Play with kubernetes master, worker node를 직접 구성 후 사용가능.

도커 데스크탑 설치

여러 대 서버를 클러스터로 구성해 쿠버테네스를 사용하지만, 각자의 컴퓨터에 도커 데스크탑을 설치해 쿠버네티스를 사용할 수도 있습니다. (관련 글)

Kubernetes 직접 설치하기

쿠버네티스의 클러스터를 구성하는 도구로는 공식 툴인 kubeadm이 있고, 오픈소스로 만들어진 kubespray가 있습니다. kubespray는 멀티 마스터 구현 시 좀 더 적합하다고 합니다.

여기서는 kubeadm을 사용해 설치하는 방법을 소개할게요. 그리고, 컨테이너 간 통신을 지원하기 위해 CNI 플러그인을 사용해야 하는데, 저는 weavenet을 설치해 사용하도록 할게요.

쿠버네티스 클러스터는 아래와 같이 구성하도록 할거에요.

- Control Plane (master node)
- Worker Node 2

로컬에서 쿠버네티스 설치를 하기 위한 절차는 아래 순서로 진행을 했습니다.

  1. 가상머신에 ubuntu 설치
  2. ubuntu에 도커 설치
  3. 쿠버네티스 설치

    • 설치 전 환경설정
    • kubeadm, kubectl, kubelet 설치
    • control-plane 구성
    • worker node 구성

1. 가상머신에 ubuntu 설치

우선 저는 맥북 M1을 사용하고 있어서, 버츄얼박스 대신 UTM을 이용해 가상머신 3대를 만들고 ubuntu를 설치했습니다. 공식 문서 상 kubeadm으로 설치시에는 메모리 2GB 이상, CPU 2 코어 이상이어야 한다고 하니 머신 생성 시 참고해 주세요.


2. ubuntu에 도커 설치

쿠버네티스를 온프로미스로 설치하기 위해 우선 도커 설치가 필요합니다. 생성한 ubuntu에 도커를 먼저 설치해 줍니다. 도커 설치 방법은 공식문서에 잘 나와 있어서 아래와 같이 그대로 따라하며 설치했습니다.

# 필요한 패키지 설치
 sudo apt-get update

 sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

# GPG 키 추가
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

# 도커 레파지도리 등록
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  
# 도커 설치
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io

여기까지 가상머신 3대를 생성 후 각 가상머신에 도커를 설치했습니다. 설치 작업 시 편의를 위해 터미널에서 가상머신에 ssh로 접속했고, 도커가 설치된 것을 확인해 봅니다.

3. 쿠버네티스 설치

  • 설치 전 환경설정
    앞서도 언급했지만, kubeadm으로 쿠버테티스 설치를 위해서 메모리 2GB 이상, CPU 2 코어 이상이어야 합니다. 그리고, 마스터와 노드 모두 swap을 disable 해야합니다. 아래 명령어를 마스터와 노드에서 실행해 swap을 disable 시켜줍니다.

    # swap 끄기
    swapoff -a && sed -i '/swap/s/^/#/' /etc/fstab
  • 브릿지 네트워크 지원
    마스터와 노드가 브릿지 네트워크를 리슨할 수 있도록 지원을 위해 아래 명령어를 실행애 줍니다.

    cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
    br_netfilter
    EOF
    cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
    net.bridge.bridge-nf-call-ip6tables = 1
    net.bridge.bridge-nf-call-iptables = 1
    EOF
    sudo sysctl --system
  • 방화벽 끄기

    systemctl stop firewalld 
    systemctl disable firewalld
  • kubeadm, kubectl, kubelet 설치
    설치 전 환경 설정이 마무리 되었으면, kubeadm, kubectl, kubelet을 설치합니다. 설치 방법은 공식 문서에 잘 나와있습니다. 문서에 나온 대로 마스터와 노드에 설치를 진행해 주시면 됩니다.

문서 상 패키지에 대한 설명이 간략히 나와 있습니다. kubeadm은 쿠버네티스 전체를 관장 및 관리할 수 있게 하는 명령어입니다. kubelet은 데몬입니다. 쿠버네티스 컨테이너를 조작해 주고 마스터와 통신할 때 사용합니다. kubectl은 클러스터를 수정할 수 있는 커맨드라인 툴입니다.


  • control-plane 구성
    설치가 성공적으로 되었으면, 마스터에서 control-plane을 구성해 줍니다. 마스터에서 kubeadm init 명령어를 실행해 줍니다. 명령어가 성공적으로 실행이 되면 아래와 같은 메세지를 볼 수 있습니다.

메세지 마지막에 워커 노드에서 클러스터에 조인 시 필요한 명령어가 나오는데, 이 명령어를 별도로 잘 저장해 두어야 합니다. 아래와 같이 마스터 노드에서 token.txt 파일을 생성해 명령어를 저장해 두었습니다.

root@master:~# cat token.txt
kubeadm join 172.30.1.39:6443 --token 12zot7.ies1heg24jimwx2h \
	--discovery-token-ca-cert-hash sha256:3c9918d4819c53afb1dc102fc7f25c4a7402f6a25d73a9e14f2826a4259d7fba

추가로, kubeadm 성공메세지에 아래와 같은 명령어도 나오는데, 메세지에 따라 마스터노드에서 실행을 해 줍니다. 루트 계정이나 다른 계정에서 kubectl 명령어를 이용하기 위해 계정의 홈디렉토리 내 /.kube 경로에 config 파일을 생성해 실행해 주는 명령어입니다.

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

루트가 아닌 유저가 kubectl 명령어를 사용하기 위해, 위 명령어를 해당 유저로 전환 후 실행해 줍니다. 그리고 kubectl 명령어를 입력해 봅니다.

root@master:~# kubectl get nodes
NAME     STATUS     ROLES                  AGE   VERSION
master   NotReady   control-plane,master   11m   v1.23.5
root@master:~# exit
  • 위브넷 설치 kubectl로 마스터의 상태를 확인해 보니 NotReady로 나타납니다. 아직 Container Network Interface가 미설치 된 상태이기 때문인데요. CNI를 설치해 줍니다.
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"

그리고 다시 마스터를 확인해 보면 아래와 같이 Ready 상태를 확인할 수 있습니다.

root@master:~# kubectl get nodes
NAME     STATUS   ROLES                  AGE   VERSION
master   Ready    control-plane,master   15m   v1.23.5

여기까지 진행이 됐으면, 이제 아래와 같이 마스터에 필요한 컴포넌트들이 구성이 된 상태입니다.

  • worker node 구성

워커 노드를 마스터에 조인시키기 위해서, 아까 token.txt 파일에 저장했던 명령어를 각 노드에서 실행해 줍니다. 그러면 드디어 마스터에 각 워커 노드가 조인된 상태를 확인할 수 있습니다.

GCP에 클러스터 구성하기

VM Instance 생성

구글 클라우드 플랫폼에서 가상 서버를 생성 후 쿠버네티스 클러스터 구성을 할 수 있습니다. 아래와 같이 우선 기본 설정에서 부팅디스크만 Ubuntu 20.04 LTS로 변경한 VM 인스턴스 4개를 생성했습니다.

그리고 마스터로 사용할 서버에서 다른 서버에 원격 접속이 필요하므로, 마스터 노드에서 SSH키를 생성해 공개키를 다른 서버에 배포해 주어야 합니다. instance-1에 접속 해 아래와 같이 ssh-keygen -t rsa 명령어로 공개키와 비밀키를 생성해 줍니다.

cat .ssh/id_rsa.pub을 이용해 공개키 내용을 확인할 수 있습니다. 공개키를 복사 후 GCP의 메타데이터 기능을 이용하면 프로젝트 내 모든 인스턴스에 공개키를 쉽게 배포할 수 있습니다.

자체 서버에 수동으로 배포를 하려면 ssh-copy-id 계정이름@서버ip 명령어로 공개키를 배포하거나, 대상 서버에 직접 접속해 .ssh/authorized_keys 파일 안에 공개키를 복사해 줄 수 있어요.

Kubespray 설치

문서 보고 설치해 주세요~

Kubespray 설정

클러스터 구성 완료 후 마스터 노드에서 sudo -i로 root 계정으로 전환 후 아래와 같이 kubectl 명령어를 사용할 수 있습니다.

root@instance-1:~# kubectl get node
NAME         STATUS   ROLES                  AGE   VERSION
instance-1   Ready    control-plane,master   26m   v1.23.5
instance-2   Ready    control-plane,master   25m   v1.23.5
instance-3   Ready    control-plane,master   25m   v1.23.5
instance-4   Ready    <none>                 24m   v1.23.5

컨테이너 실행 방법

kubectl run 사용하기

쿠버네티스 설치를 완료했으니, kubectl을 이용해 컨테이너를 생성해 보고, 생성한 결과를 확인해 보는 작업을 진행할 수 있습니다. 아래와같이 kubectl run 명령어를 이용해 pod를 생성해 컨테이너틑 실행할 수 있습니다.

실행한 컨테이너테 curl 명령어를 이용해 접속해 보면 nginx 웹페이지를 확인할 수 있어요.

deployment 사용하기

뒤쪽에서 더 살펴보겠지만, kubectl create deplyment 명령어로도 실행할 수 있습니다. 명령어 뒤에 replicas를 지정해서 여러 서버를 생성할 수 있습니다.

guru@master:~$ kubectl create deployment ui --image=httpd --replicas=3
deployment.apps/ui created
guru@master:~$ kubectl get deployments.apps
NAME   READY   UP-TO-DATE   AVAILABLE   AGE
ui     3/3     3            3           32s

위 명령어로 deployment를 생성하면 위와 같이 replicas에 지정한 3개가 생성된 것을 확인할 수 있어요.

작동중인 오브젝트를 수정할 때는 edit 명령어를 사용할 수 있는데요. 여기서는 edit 명령어를 이용해 현재 3개 실행중인 것을 5개로 늘려보도록 할게요.

kubectl edit deployments.apps (디플로이먼트 이릉) 명령어를 입력하면 vi 에디터로 이동합니다. 여기서 기존의 replicas를 3에서 5로 수정해줍니다. 그리고 다시 pod를 확인하면 5개로 늘어난 것을 확인할 수 있어요.

특정 컨테이너 수정하기

쿠버네티스로 컨테이너 생성 후 특정 컨테이너에 접근해 수정 작업을 할 수 있습니다. 저는 위에서 생성한 nginx 웹서버에 접근해 index.html 파일을 수정하는 작업을 진행하려 합니다. 도커에서 특정 컨테이너에 접근하듯이 exec 명령어를 이용할 수 있습니다.

yaml 파일 사용하기

특정 컨테이너가 실행 가능한 상태인지만 확인을 하기 위해 dry run 명령어를 사용할 수 있는데요. 이 실행 가능한 상태를 아래 명령어로 yaml 파일 형태로 출력할 수 있습니다.

kubectl run webserver --image=nginx:1.14 --port 80 --dry-run -o yaml > webserver.pod.yaml

새로 생성된 webserver.pod.yaml 파일을 열고 아래와 같이 불필요한 항목 삭제 후 수정했습니다.

"webserver.pod.yaml" 17L, 284C                                                                                                1,1           All
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: webserver
  name: webserver
spec:
  containers:
  - image: nginx:1.14
    name: webserver
    ports:
    - containerPort: 80

그러면 우리는 이 yaml을 기반으로 파드를 실행할 수 있습니다. yaml 파일을 가지고 파드를 실행하려면 kubectl create -f webserver.pod.yaml 명령어를 입력할 수 있어요.

Pod

쿠버네티스에서 파드를 실행하기 위해서는 CLI 명령어 또는 yaml을 이용해 생성할 수 있습니다. CLI 명령어로는 kubecel run webserver --image=nginx:1.14와 같이 실행해 파드를 생성할 수 있습니다. 아래 예제와 같은 yaml 파일을 이용해 pod를 생성할 수도 있습니다.

apiVersion: v1
kind: Pod
metadata:
  name: webserver
spec:
  containers:
    - name: nginx-container
      image: nginx:1.14
      imagePullPolicy: Always
      ports:
      - containerPort: 80
        protocol: TCP

Pod 실행
yaml 파일을 이용해 Pod를 실행하기 위해서 kubectl create -f pod-nginx.yaml 명령어와 같이 입력해 줄 수 있습니다. 실행중인 Pod 확인을 위해 kubectl get pods를 이용하는데 아래와 같이 옵션을 주어 어려 포맷으로도 확인할 수 있습니다.

kubectl get pods
kubectl get pods -o wide
kubectl get pods -o yaml
kubectl get pods -o json

--dry-run 옵션과 yaml 파일 출력 옵션으로 파트의 스펙을 정의한 yaml 파일을 별도로 생성할 수도 있습니다.

Pod 동작 flow

Self-healing Pod (livenessProbe)

Self-healing 기능은 Kubernetes의 주요 특징 중 하나이며, livenessProbe를 이용해 셀프 힐링 파드를 생성할 수 있습니다. 파드 스펙 정의 시 livenessProbe를 아래와 같이 정의할 수 있습니다.

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  containers:
    - name: nginx-container
      image: nginx:1.14
      livenessProbe:
        httpGet:
          path: /
          port: 80

위와 같이 livenessProbe를 정의 시, 쿠버네티스는 위 파드가 정상적으로 서비스 중인지 검진을 합니다. 위 스펙에서는 정상 서비스 상태인지 확인을 위해 운영중인 파드의 80번 포트로 http 프로토콜 주기적 접속을 해 정상 응답이 오는지 확인을 합니다.

livenessProbe 메커니즘

쿠버네티스가 컨테이너를 진단하는 방법은 컨테이너의 핸들러를 kuberlet이 호출해 실행하며, 핸들러 종류에는 아래의 세 가지가 있습니다.

  • HttpGetAction: Get 요청을 보내 응답을 확입니다.

    livenessProbe:
    httpGet:
    path: /
    port: 80
  • TCPSocketAction: TCP 포트가 열려 있는지 확인

    livenessProbe:
    tcpSocket:
    port: 22
  • ExecAction: 지정된 명령어를 실행 후 종료 코드가 0인지 확인

    livenessProbe:
    exec:
    command:
      - ls
      - /data.file

livenessProbe를 적용해 nginx 파드를 생성하고, kubectl get pods nginx-pod-liveness -o yaml로 파드 정보를 확인하면 livenessProbe가 스펙에 추가된 것을 확인할 수 있습니다.

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: "2022-05-10T14:08:34Z"
  name: nginx-pod-liveness
  namespace: default
  resourceVersion: "1362964"
  uid: aaa982fd-bec2-4e64-922d-f0868a79a894
spec:
  containers:
  - image: nginx:1.14
    imagePullPolicy: IfNotPresent
    livenessProbe:
      failureThreshold: 3
      httpGet:
        path: /
        port: 80
        scheme: HTTP
      periodSeconds: 10
      successThreshold: 1
      timeoutSeconds: 1
    name: nginx-container
..
..

저는 path, port는 설정했지만, timeoutSeconds 등과 같은 다른 추가된 옵션이 디폴트 값으로 설정된 것을 확인할 수 있습니다. 위 옵션 값을 livenessProbe 정의 시 설정할 수도 있습니다. 별도 옵션겂을 설정해 아래와 같이 테스트 해 볼 수 있습니다.

apiVersion: v1
kind: Pod
metadata:
  name: unhealthy-pod
spec:
  containers:
    - name: unhealthy-container
      image: busybox
      args:
        - /bin/sh
        - -c
        - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
      livenessProbe:
        exec:
          command:
            - ls
            - /tmp/healthy
        initialDelaySeconds: 10
        periodSeconds: 5
        successThreshold: 1
        failureThreshold: 2

위 컨테이너는 실행 후 /tmp/healthy 파일을 생성하고 30초 후 해당 파일을 삭제합니다. 컨테이너 체크를 위해 exec probe로 5초 간격으로 healthy 파일이 있는지 확인합니다. 2번 실패 시 컨테이너를 재시작하며, 헬스체크는 파드 실행 10초 후부터 실행합니다.

시간이 경과 후 healthy 파일을 존재하지 않을 때, livenessProbe가 실패하고 컨테이너를 재시작하는 것을 확인할 수 있습니다. 파드가 아니라 컨테이너가 재시작하기 때문에 파드는 그대로 있고 IP도 변경이 되지 않습니다.

Resource