컨테이너를 다루는 표준 아키텍처, 쿠버네티스
앞의 포스트에서 배운 코드를 응용해 컨테이너 인프라 테스트 환경을 자동으로 구축해보겠습니다.
개인 서버에서는 1명의 관리자가 다양한 응용프로그램을 사용하므로 각각의 프로그램을 컨테이너로 구현할 필요가 거의 없습니다.
기업 환경에서는 다수의 관리자가 수백 또는 수천 대의 서버를 함께 관리하기 때문에 일관성을 유지하는 것이 매우 중요합니다.
이런 경우 컨테이너 인프라 환경을 구성하면 눈송이 서버(여러 사람이 작업하여 설정의 일관성이 떨어진 서버)를 방지하는데 효과적입니다.
또한 가상화 환경에서는 각각의 가상 머신이 모두 독립적인 운영 체제 커널을 가지고 있어야 하기 때문에 자원을 더 소모해야하고 성능이 떨어지게 됩니다.
하지만 컨테이너 인프라 환경에서는 OS 커널 하나에 컨테이너 여러 개가 격리된 형태로 실행되기 때문에 자원을 효율적으로 사용할 수 있고 거치는 단계가 적어서 속도도 훨씬 빠릅니다.
도커 스웜(Docker Swarm)
- 간단한 설치, 사용의 용이함
- 기능이 다양하지 않아 대규모 환경에 적용하려면 사용자 환경 변경 필요
- 소규모 환경에서는 유용하다
메소스(Mesos)
- 아파치 오픈 소스 프로젝트 | 트위터, 에어비엔비, 애플, 우버 등에서 검증된 솔루션
- 2016년 DC/OS(Data Center OS, 대규모 서버 환경에서 자원을 유연하게 공유하며 하나의 자원처럼 관리하는 도구) 지원으로 매우 간결해졌다.
- 기능을 충분히 활용하려면 분산 관리 시스템과 연동이 필요하다.
- 따라서 여러가지 솔루션을 유기적으로 구성해야하는 부담이 있다.
노매드(Nomad)
- 베이그런트를 만든 해시코프사의 컨테이너 오케스트레이션
- 간단한 구성으로 컨테이너 오케스트레이션 환경 제공
- 기능이 부족하므로 여러 기능을 사용하는 환경이 아닌 가볍고 간단한 기능만 필요한 환경에서 사용하기 권장됌
- 해시코프의 Consul(서비스 검생, 구성 및 분할 기능 제공)과 Vault(암호화 저장소)와의 연동이 원할하므로 이런 도구에 대한 사용 성숙도가 높은 조직이라면 도입을 고려해도 괜찮음
쿠버네티스(Kubernetes)
- 다른 솔루션보다 시작하는 데 어려움이 있지만, 쉽게 사용할 수 있는 도구들이 있어서 설치가 쉬워지는 추세
- 다양한 형태로 발전하고 있어 컨테이너 오케스트레이션을 넘어 IT 인프라 자체를 컨테이너화하고, 컨테이너화된 인프라 제품군을 쿠버네티스 위에서 동작할 수 있게 만든다.
- 거의 모든 벤더와 오픈 소스 진영에서 쿠버네티스를 지원하고 그에 맞게 통합 개발하고 있다. 그러므로 컨테이너 오케스트레이션을 학습/도입하려면 쿠버네티스를 우선적으로 고려한다.
쿠버네티스 : 컨테이너 오케스트레이션을 위한 솔루션
- 오케스트레이션(Orchestration) : 복잡한 단계를 관리하고 요소들의 유기적인 관계를 미리 정의해 손쉽게 사용하도록 서비스를 제공하는 것
- 컨테이너 오케스트레이션 : 다수의 컨테이너를 유기적으로 연결/실행/종료할 뿐만 아니라 상태를 추적하고 보존하는 등 컨테이너를 안정적으로 사용할 수 있게 만들어 주는 것
퍼블릭 클라우드 업체에서 제공하는 관리형 쿠버네티스인 EKS(Amazon Elastic Kubernetes Service), AKS(Azure Kubernetes Service), GKE(Google Kubernetes Service) 등을 사용합니다.
수세의 Rancher, 레드햇의 OpenShift와 같은 플랫폼에서 제공하는 설치형 쿠버네티스를 사용합니다.
사용하는 시스템에 쿠버네티스 클러스터를 자동으로 구성해주는 솔루션을 사용합니다.
학습을 위해 사용자 설정이 가장 많이 필요한 kubeadam으로 쿠버네티스를 구성하겠습니다.
또한 쿠버네티스가 설치되는 서버 노드는 가상 머신을 이용해 실제 온프레미스에 가깝게 구성합니다.
설치되는 과정을 베이그런트로 자동화해 필요하면 쿠버네티스 테스트 환경을 재구성할 수 있게 합니다.
이전 포스팅에서 알아본 것과 같이 베이그런트는 가상 머신을 프로비저닝을 위해 여러 종류의 명령어를 제공합니다. 자주 사용하는 명령어는 추후 따로 포스팅하겠습니다.
쿠버네티스 실습 환경을 만들어 줄 베이그런트 스크립트 파일과 실습에 사용할 소스코드 파일들을 내려받습니다. 깃허브 링크
ch3/3.1.3 폴더로 이동하여 실습에 필요한 파일이 있는지 확인합니다.
앞선 포스트와 같이 실습에 필요한 파일의 설명은 다음과 같습니다.
vagrant up
을 하면 현재 호스트 내부에 Vagrantfile에 정의된 가상 머신들을 생성하고, 생성한 가상 머신에 쿠버네티스 클러스트를 구성하기 위한 파일들을 호출해 쿠버네티스 클러스터를 자동으로 구성합니다.Vagrantfile의 구성을 살펴보겠습니다.
앞선 포스팅을 참고하며 각 행이 어떤 의미를 가지고 작성되어있는지 꼼꼼히 읽어봅시다. 이번엔 워커 노드 변수, 버전 변수, 마스터/워커 노드를 위한 provision, args의 존재 등이 추가되었군요!
또한 이전 포스팅과 달리 마스터/워커 노드의 메모리가 늘어난 부분도 확인할 수 있네요.
(1..N).each do |i| 반복문에서도 워커 개수 변수인 N의 수정을 통해 워커 노드의 개수를 손쉽게 변경할 수 있다는 점이 눈에 띄네요.
새로운 내용에는 주석을 작성해놓았습니다.
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
N = 3 # 쿠버네티스에서 작업을 수행할 워커 노드의 변수(N=3), (args:N)으로 config.sh로 넘긴다. 사용자가 워커 노드의 개수를 직접 조절할 수 있게 한다.
Ver = '1.18.4' # 쿠버네티스 버전을 사용하자 선택할 수 있도록 변수로 저장
#=============#
# Master Node #
#=============#
config.vm.define "m-k8s" do |cfg|
cfg.vm.box = "sysnet4admin/CentOS-k8s"
cfg.vm.provider "virtualbox" do |vb|
vb.name = "m-k8s(github_SysNet4Admin)"
vb.cpus = 2
vb.memory = 3072
vb.customize ["modifyvm", :id, "--groups", "/k8s-SgMST-1.13.1(github_SysNet4Admin)"]
end
cfg.vm.host_name = "m-k8s"
cfg.vm.network "private_network", ip: "192.168.1.10"
cfg.vm.network "forwarded_port", guest: 22, host: 60010, auto_correct: true, id: "ssh"
cfg.vm.synced_folder "../data", "/vagrant", disabled: true
cfg.vm.provision "shell", path: "config.sh", args: N
# args: [ Ver, "Main" ] 을 추가해 쿠버네티스 버전 정보(Ver)와 Main이라는 문자를 install_pkg.sh로 넘긴다. Ver 변수는 각 노드에 해당 버전의 쿠버네티스를 설치하게 한다. Main은 install_pkg.sh에서 조건문으로 처리해 마스터 노드에만 이 책의 전체 실행 코드를 내려받게 한다.
cfg.vm.provision "shell", path: "install_pkg.sh", args: [ Ver, "Main" ]
# 쿠버네티스 마스터 노드를 위한 master_node.sh를 추가한다.
cfg.vm.provision "shell", path: "master_node.sh"
end
#==============#
# Worker Nodes #
#==============#
(1..N).each do |i|
config.vm.define "w#{i}-k8s" do |cfg|
cfg.vm.box = "sysnet4admin/CentOS-k8s"
cfg.vm.provider "virtualbox" do |vb|
vb.name = "w#{i}-k8s(github_SysNet4Admin)"
vb.cpus = 1
vb.memory = 2560
vb.customize ["modifyvm", :id, "--groups", "/k8s-SgMST-1.13.1(github_SysNet4Admin)"]
end
cfg.vm.host_name = "w#{i}-k8s"
cfg.vm.network "private_network", ip: "192.168.1.10#{i}"
cfg.vm.network "forwarded_port", guest: 22, host: "6010#{i}", auto_correct: true, id: "ssh"
cfg.vm.synced_folder "../data", "/vagrant", disabled: true
cfg.vm.provision "shell", path: "config.sh", args: N
cfg.vm.provision "shell", path: "install_pkg.sh", args: Ver
# 쿠버네티스 워커 노드를 위한 worker_node.sh를 추가한다.
cfg.vm.provision "shell", path: "work_nodes.sh"
end
end
end
#!/usr/bin/env bash
# vim configuration
# vi를 호출하면 vim을 호출하도록 프로파일에 입력합니다. vim을 통해 코드 하이라이트를 넣어 가독성을 높힐 수 있습니다.
echo 'alias vi=vim' >> /etc/profile
# 쿠버네티스의 설치 요구 조건을 맞추기 위해 스왑되지 않도록 설정합니다.
# swapoff -a to disable swapping
swapoff -a
# 시스템이 다시 시작되더라도 스왑되지 않도록 설정합니다.
# sed to comment the swap partition in /etc/fstab
sed -i.bak -r 's/(.+ swap .+)/#\1/' /etc/fstab
# kubernetes repo
# 쿠버네티스의 리포지터리를 설정하기 위한 경로가 너무 길어지지 않게 변수로 처리합니다.
gg_pkg="packages.cloud.google.com/yum/doc" # Due to shorten addr for key
# EOF ~ EOF : 쿠버네티스를 내려받을 리포지터리를 설정하는 구문입니다.
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://${gg_pkg}/yum-key.gpg https://${gg_pkg}/rpm-package-key.gpg
EOF
# selinux가 제한적으로 사용되지 않도록 permissive 모드로 변경합니다.
# Set SELinux in permissive mode (effectively disabling it)
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
# 브리지 네트워크를 통과하는 IPv4와 IPv6의 패킷을 iptables가 관리하게 설정합니다.
# 파드(Pod, 쿠버네티스에서 실행되는 객체의 최소 단위)의 통신을 iptables로 제어합니다. 필요에 따라 IPVS(Ip Virtual Server) 같은 방식으로도 구성할 수 있습니다.
# RHEL/CentOS 7 have reported traffic issues being routed incorrectly due to iptables bypassed(RHEL/CentOS 7은 우회된 iptables로 인해 잘못 라우팅되는 트래픽 문제를 보고했습니다.)
cat <<EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
# br_netfilter 커널 모듈을 사용해 브리지로 네트워크를 구성합니다. 이때 IP 마스커레이드(Masquerade)를 사용해 내부 네트워크와 외부 네트워크를 분리합니다.
# IP 마스커레이드는 쉽게 설명하면 커널에서 제공하는 NAT(네트워크 주소 변환) 기능으로 이해하면 됩니다.
# 실제로는 br_netfilter를 적용함으로써 앞서 적용한 iptables가 활성화됩니다.
modprobe br_netfilter
# 쿠버네티스 안에서 노드 간 통신을 이름으로 할 수 있도록 각 노드의 호스트 이름과 IP를 /etc/hosts에 설정합니다.
# 이떄 워커 노드는 Vagrantfile에서 넘겨받은 N변수로 전달된 노드 수에 맞게 동적으로 생성합니다.
# local small dns & vagrant cannot parse and delivery shell code.
echo "192.168.1.10 m-k8s" >> /etc/hosts
for (( i=1; i<=$1; i++ )); do echo "192.168.1.10$i w$i-k8s" >> /etc/hosts; done
# 외부와 통신할 수 있게 DNS 서버를 지정합니다.
# config DNS
cat <<EOF > /etc/resolv.conf
nameserver 1.1.1.1 #cloudflare DNS
nameserver 8.8.8.8 #Google DNS
EOF
#!/usr/bin/env bash
# install packages
yum install epel-release -y
yum install vim-enhanced -y
yum install git -y # 깃허브 이용을 위해 git을 설치합니다.
# install docker
# 쿠버네티스를 관리하는 컨테이너를 설치하기 위해 도커를 설치/구동합니다.
yum install docker -y && systemctl enable --now docker
# install kubernetes cluster
# 쿠버네티스를 구성하기 위해 첫 번째 변수($1=Ver='1.18.4')로 넘겨받은 1.18.4버전의
# kubectl, kubelet, kubeadm을 설치하고 kubelet을 시작합니다.
yum install kubectl-$1 kubelet-$1 kubeadm-$1 -y
systemctl enable --now kubelet
# git clone _Book_k8sInfra.git
# 이 책의 전체 실행 코드를 마스터 노드에만 내려받도록 Vagrantfile에서 두 번째 변수($2='Main')을 받습니다.
# 깃에서 코드를 clone하여 실습을 진행할 루트 홈디렉토리(/root)로 옮깁니다.
# 배시 스크립트(.sh)를 찾아서 바로 실행 가능한 상태가 되도록 chmod 700으로 설정합니다.
if [ $2 = 'Main' ]; then
git clone https://github.com/sysnet4admin/_Book_k8sInfra.git
mv /home/vagrant/_Book_k8sInfra $HOME
find $HOME/_Book_k8sInfra/ -regex ".*\.\(sh\)" -exec chmod 700 {} \;
fi
#!/usr/bin/env bash
# init kubernetes
# kubeadm을 통해 쿠버네티스의 워커 노드를 받아들일 준비를 합니다. 먼저 토큰을 임의로 지정하고
# ttl(time to live, 유지되는 시간)을 0으로 설정해서 기본값인 24시간 후에 토큰이 계속 유지되게 합니다.
# 워커 노드가 정해진 토큰으로 들어오게 합니다. 쿠버네티스가 자동으로 컨테이너에 부여하는 네트워크를
# 172.16.0.0/16(172.16.0.1~172.16.255.254)로 제공하고,
# 워커 노드가 접속하는 API 서버의 IP를 192.168.1.10으로 지정해 워커 노드들이 자동으로 API서버에 연결되게 합니다.
kubeadm init --token 123456.1234567890123456 --token-ttl 0 \
--pod-network-cidr=172.16.0.0/16 --apiserver-advertise-address=192.168.1.10
# config for master node only
# 마스터 노드에서 현재 사용자가 쿠버네티스를 정상적으로 구동할 수 있게 설정 파일을 루트의 홈디텍토리(/root)에 복사하고 쿠버네티스를 이용할 사용자에게 권한을 줍니다.
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
# config for kubernetes's network
# 컨테이너 네트워크 인터페이스인 캘리코(Calico)의 설정을 적용해 쿠버네티스의 네트워크를 구성합니다.
kubectl apply -f \
https://raw.githubusercontent.com/sysnet4admin/IaC/master/manifests/172.16_net_calico.yaml
#!/usr/bin/env bash
# config for work_nodes only
# kubeadm을 이용해 쿠버네티스 마스터 노드에 접속합니다. 이 떄 연결에 필요한 토큰은 기존에 마스터 노드에서 생성한 임의의 토큰을 사용합니다.
# 간단하게 구성하기 위해 `--discovery-token-unsafe-skip-ca-verification`으로 인증을 무시하고
# API 서버 주소인 192.168.1.10으로 기보 포트 번호인 6443번 포트에 접속하도록 설정합니다.
kubeadm join --token 123456.1234567890123456 \
--discovery-token-unsafe-skip-ca-verification 192.168.1.10:6443
cd /Users/noharam/Desktop/k8s/ch3/3.1.3
vagrant up
m-k8s
를 선택해 터미널에 접속합니다.(이전 포스팅에서 진행했듯이)kubectl get nodes
명령을 입력하여 쿠버네티스 클러스터에 마스터 노드와 워커 노드들이 정상적으로 생성되고 연결됐는지 확인합니다.이렇게 쿠버네티스 클러스터 구성이 끝났습니다. 이제 쿠버네티스를 구성하는 요소를 살펴보면서 쿠버네티스의 개념과 용어를 알아봅시다.
앞에 나온 kubectl, kubelet, API 서버, Calico 등은 모두 쿠버네티스 클러스터를 이루는 구성 요소입니다.
그 외에 etcd, 컨트로럴 매니저, 스케쥴러, kube-proxy, 컨테이너 런타임, 파트 등이 있습니다.
각 요소가 어떤 역할을 담당하는지 차근차근 알아봅시다.
우선 설치된 쿠버네티스 구성 요소를 kubectl get pods --all-namespaces
명령으로 확인해봅시다.
모든 네임스페이스에서 파드를 수집해 보여줍니다. 쿠버네티스 클러스터를 이루는 구성요소들은 파드 형태로 이루어져 있음을 알 수 있습니다.
쿠버네티스의 구성 요소는 동시에 여러 개가 존재하는 경우 중복되 이름을 피하려고 뒤에 Hash 코드가 상비됩니다. 해시 코드는 무작위 문자열로 생성됩니다.
구성 요소의 이름을 직접 지정할 수도 있지만, 언제라도 문제가 발견되면 다시 생성되는 특성을 가지는 파드로 이루어져 있어서 자동으로 이름을 지정하는 것이 관리하기 쉽습니다.
coredns에는 중간에 66bff467f8이라는 문자열이 하나 더 있는데, 이는 레플리카셋(ReplicaSet)을 무작위 문자열로 변형해 추가한 것입니다. 추후에 네임스페이스와 같이 포스팅 하겠습니다.
쿠버네티스의 구성 요소의 유기적인 연결 관계를 표헌하면 다음과 같습니다.(출처 : 컨테이너 인프라 환경 구축을 위한 쿠버네티스/도커 - 조훈,심근우,문성주 지음(2021)")
통신 순서를 따라가며 흐름을 이해하고, 각각의 기능을 파악해봅시다.
파드를 배포하는 순서에 따라 요소들의 역할을 정리해보겠습니다.
0. Kubectl
1. API 서버
2. etcd
3. 컨트롤러 매니저
4. 스케쥴러
5. kubelet
6. 컨테이너 런타임(CRI, Container Runtime Interface)
7. 파드(Pod)
0~7번은 기본 설정으로 배포된 쿠버네티스에서 이루어지는 통신 단계를 구분한 것입니다. 이외에 선택적으로 배포하는 것들은 순서와 상관이 없기 때문에 10번대로 구분하여 표시합니다. 선택 가능한 부가 요소는 너무 깊은 내용이라 간단하게 개념만 살펴보고 넘어갑니다.
11. 네트워크 플러그인
12. CoreDNS
이번엔 파드가 배포된 이후 사용자 입장에서 배포된 파드에 접속하는 과정을 살펴봅시다.
쿠버네티스의 각 구성 요소를 파드의 배포와 접속 관점에서 설명했지만, 아직 이해되지 않는 부분이 많습니다. 파드가 배포되는 과정을 살펴보며 구성 요소를 좀 더 깊이 알아봅시다.
구성 요소의 기능만 나열해서는 이해하기 어려우니 파드가 배포되는 과정을 하나하나 자세히 살펴보며 역할을 정리해봅시다.
쿠버네티스의 가장 큰 강점은 구성 요소마다 하는 일이 명확하게 구분돼 각자의 역할만 충실하게 수행하면 클러스터 시스템이 안정적으로 운영된다는 점입니다.
각자의 역할이 명확하게 나뉘어진 것은 마이크로서비스 아키텍쳐(MSA) 구조와도 밀접하게 연관됩니다.
또한 문제가 발생했을 때 어느 구성 요소에서 문제가 발생했는지 디버깅하기 쉽습니다.
생명주기(Life Cycle)은 파드가 생성, 수정, 삭제되는 과정을 나타냅니다.
kubectl create pod
Kubectl
앞서 kubectl은 마스터 노드에 위치할 필요가 없다고 했습니다. 실제로 쿠버네티스 클러스터 외부에서 쿠버네티스 클러스터에 명령을 내릴 수도 있습니다. 어느 곳에서든지 kubectl을 실행하려면 어떤 부분이 필요한지 봅시다.
SSH CLIENT 세션 창에서 w3-k8s를 더블클릭해 터미널에 접속해서 kubectl get nodes
를 실행합시다.
명령을 실행해도 쿠버네티스의 노드들에 대한 정보가 표시되지 않습니다.
쿠버네티스 클러스터의 정보(/etc/kubernetes/admin.conf)를 마스터 노드에서 scp(secure copy) 명령으로 w3-k8s의 현재 디렉토리(.)에 받아옵니다.
scp root@192.168.1.10:/etc/kubernetes/admin.conf .
kubectl get nodes
에 쿠버네티스 클러스터 정보를 입력받는 옵션(--kubeconfig)과 마스터 노드에서 받아온 admin.conf를 입력하고 실행해봅시다.
kubectl get nodes --kubeconfig admin.conf
kubelet
kubelet은 쿠버네티스에서 파드의 생성과 상태 관리 및 복구 등을 담당하는 매우 중요한 구성 요소입니다. 따라서 kubelet에 문제가 생기면 파드는 정상적으로 관리되지 않습니다.
kubectl create -f ~/_Book_k8sInfra/ch3/3.1.6/nginx-pod.yaml
명령으로 nginx 웹 서버 파드를 배포합니다.kubectl get pod
명령으로 배포된 파드가 정상적으로 배포된 상태(Running)인지 확인합니다.kubectl get pods -o wide
명령을 실행해 파드가 배포된 워커 노드를 확인합니다. systemctl stop kubelet
으로 kubelet 서비스를 멉춥니다.kubectl get pod
으로 상태를 확인하고 kubectl delete pod nginx-pod
명령으로 파드를 삭제합니다.kubectl get pod
명령으로 파드의 상태를 확인합니다. 결과를 보면 nginx-pod를 삭제(Termination)하고 있습니다. 하지만 kubelet 서비스가 작동하지 않는 상태라 파드는 삭제되지 않습니다.systemctl start kubelet
을 실행해 kubelet을 복구합니다.kubectl get pod
명령으로 nginx-pod가 삭제됐는지 확인합니다.kube-proxy
kubelet이 파드의 상태를 관리한다면 kube-proxy는 파드의 통신을 담당합니다. 앞서 config.sh 파일에서 br_netfilter 커널 모듈을 적재하고 iptables를 거쳐 통신하도록 설정했습니다.
그런데 이 설정이 정상적으로 작동하지 않는다면, 즉 kube-proxy에 문제가 생기면 어떻게 되는지 확인해봅시다.
테스트하기 위해 m-k8s에 다시 파드를 배포합니다.
kubectl create -f ~/_Book_k8sInfra/ch3/3.1.6/nginx-pod.yaml
kubectl get pods -o wide
명령을 실행해 IP와 파드가 배포된 워커 노드를 확인합니다.
curl(client URL)로 전 단계에서 확인한 파드의 IP로 nginx 웹 서버 메인 페이지 내용을 확인합니다.
curl 172.16.103.129
w2-k8s 터미널에서 modprobe -r br_netfilter
명령으로 파드가 위치한 워커 노드에서 br_netfilter 모듈을 제거합니다.
다시 m-k8s에서 curl로 nginx 웹 서버의 정보를 받아옵니다. 계속 파드에서 정보를 받아오지 못하는 상태라면 Ctrl+C로 요청을 종료합니다.
kubectl get pod -o wide
로 파드 상태를 확인합니다.
정상적으로 파드의 nginx 웹 서버 페이지 정보를 받아올 수 있는 상태로 만들어 봅시다. 워커 노드에서 modprobe br_netfilter
명령을 실행해 br_netfilter를 커널에 적재하고 시스템을 재시작해서 적용합니다.
modprobe br_netfilter
reboot
일정 시간이 지난 후 다시 마스터 노드에서 파드의 상태를 확인하면 파드가 1회 다시 시작했다는 의미로 RESTARTS가 1로 증가하고 IP가 변경된 것을 확인할 수 있습니다.
바뀐 IP로 curl 명령을 실행해 파드로부터 정보를 정상적으로 받아오는지 확인합니다.
다음 내용을 진행하기 위해 배포한 파드를 삭제합니다.
kubectl delete -f ~/_Book_k8sInfra/ch3/3.1.6/nginx-pod.yaml
쿠버네티스를 사용한다는 것은 결국 사용자에게 효과적으로 파드를 제공한다는 뜻입니다.
따라서 가장 먼저 파드를 생성해 봅시다.
이미 구성 요소 검증 파트에서 nginx 웹 서버 파드를 생성하고 삭제해봤습니다.
그러나 방법이 조금 복잡했습니다. 더 간단하게 생성하는 방법을 알아봅시다.
kubelet run
을 실행하면 쉽게 파드를 생성할 수 있습니다.
run 다음에 나올 nginx는 파드의 이름이고, --image=nginx는 생성할 이미지의 이름입니다.
kubectl run nginx-pod --image=nginx
그렇다면 왜 kubectl create
라는 명령어를 사용할까요? create로 파드를 생성해서 run 방식과 비교해봅시다!
--image 라는 옵션이 없다는 에러 메세지만 나오고 파드는 생성되지 않습니다. create로 파드를 생성하려면 deployment를 추가해서 실행해야 합니다. 이때 기존 파드 이름과 중복을 피하고자 파드의 이름을 dpy-nginx로 지정해 생성합니다.
kubectl create deployment dpy-nginx --image=nginx
생성된 파드의 이름을 확인해봅시다. dpy-nginx-c8d778df-gnqzh
이름에서 dpy-nginx를 제외한 나머지 부분은 무작위로 생성됩니다.(위의 쿠버네티스 구성 요소의 이름 생성 규칙을 참고해주세요!)
두 가지 방식으로 생선한 파드가 모두 제대로 돌아가는지 확인해봅시다. IP를 확인해봅시다.
kubectl get pods -o wide
curl 172.16.103.131
curl 172.16.132.1
두 방식 모두 nginx 웹 서버가 정삭적으로 작동합니다. 그렇다면 run과 create deployment로 생성한 파드엔 무슨 차이가 있을까요?
이제 파드와 디플로이먼트가 어떻게 구성되어 있는지, 디플로이먼트는 파드를 어떻게 관리하는지 알아봅시다!
run
의 사용을 권고하지 않으며, create 혹은 run --generator=run-pod/v1을 사용하도록 권장됩니다.(예시입니다. 실행하지 않으셔도 됩니다.)kubectl create deployment nginx-create --image=nginx
kubectl run nginx-run --image=nginx --generator=run-pod/v1
파드와 디플로이먼트는 스펙(spec)과 상태(status) 등의 값을 가지고 있습니다.
이러한 값을 가지고 있는 파드와 디플로이먼트를 개별 속성을 포함해 부르는 단위를 오브젝트(object)라고 합니다.
쿠버네티스는 여러 유형의 오브젝트를 제공하는데, 기본 오브젝트부터 살펴봅시다.
기본 오브젝트에는 다음 네 가지가 있습니다.
파드(Pod)
네임스페이스(Namespaces)
볼륨(Volume)
서비스(Service)
기본 오브젝트만으로 쿠버네티스를 사용할 수도 있지만, 더 효율적으로 작동하도록 기능을 조합하고 추가해 구현한 것이 디플로이먼트입니다.
이 외에도 데몬셋(DaemonSet), 컨피그맵(ConfigMap), 레플리카셋(ReplicaSet), PV(PersistentVolume), PVC(PersistentVolumeClaim), 스테이트풀셋(StatefulSet) 등이 있으며, 앞으로도 요구 사항에 따라 목적에 맞는 오브젝트들이 추가될 것입니다.
쿠버네티스에서 가장 많이 쓰이는 디플로이먼트 오브젝트는 파드에 기반을 두고 있으며, 레플리카셋 오브젝트를 합쳐 놓은 형태입니다.
레플리카셋은 레플리케이션컨트롤러(ReplicationController)가 발전한 형태지만, 현재는 레플리카셋만 알면 됩니다.
레플리카셋에 관한 자세한 설명은 아래서 진행됩니다.
앞에서 생성한 dpy-nginx의 디플로이먼트 계층 구조는
디플로이먼트 > 레플리카셋 > 파드1,파드2,...
와 같이 이루어져 있씁니다.
실제로 API 서버와 컨트롤러 매니저는 단순히 파드가 생성되는 것을 감시하는 것이 아니라 디플로이먼트처럼 레플리카셋을 포함하는 오브젝트의 생성을 감시합니다!
API서버 / 컨트롤러 매니저
-> 디플로이먼트 생성 감시
<- 레플리카셋 생성
-> 레플리카셋 생성 감시
<- 레플리카셋에서 선언한 파드(s) 생성
쿠버네티스는 한번에 이해하기 어려우니 처음부터 끝까지 실습을 진행해보고 처음부터 다시 읽어보시길 권장드립니다. 또한 쿠버네티스 오브젝트 생태계는 계속 변화하므로 모든 것을 외울 필요 없이 필요한 부분을 찾아 적재적소에 필요한 오브젝트를 사용하는 것이 현명합니다.
간단히 디플로이먼트를 생성하고 삭제해봅시다.
저자의 저장소에서 필요한 이미지를 내려받아 디플로이먼트를 생성합니다.
- 이미지 경로는 sysnet4admin/echo-hname
이며, 전자는 계정 이름이고 후자는 이미지 이름입니다.
생성 : kubectl create deployment dpy-hname --image=sysnet4admin/echo-hname
삭제 : kubectl delete deployment dpy-hname
- create를 delete로 대체하고, --image 옵션을 제외해줍니다.
이제 디플로이먼트를 왜 생성하는지, 왜 필요한지 알아봅시다!
많은 사용자들 대상으로 웹 서비스를 하려면 다수의 파드가 필요한데, 이를 하나씩 생성한다면 매우 비효율적입니다. 그래서 쿠버네티스는 다수의 파드를 만드는 레플리카셋 오브젝트를 제공합니다.
예를 들어 파드를 3개 만들겠다고 레플리카셋에 선언하면 컨트롤러 매니저와 스케줄러가 워커 노드에 파드를 3개 만들도록 선언합니다.
그러나 레플리카셋은 파드 수를 보장하는 기능만 제공하기 때문에 롤링 업데이트 기능 등이 추가된 디플로이먼트를 사용해 파드 수를 관리하기를 권장합니다.
kubectl get pods
scale
명령으로 3개로 증가시킵니다. 여기서 --relicas=3은 파드의 수를 3개로 맞추는 옵션입니다. kubectl scale pod nginx-pod --replicas=3
kubectl scale deployment dpy-nginx --replicas=3
kubectl get pods -o wide
명령으로 확인해봅시다.kubectl delete deployment dpy-nginx
kubectl create deployment
를 통해 디플로이먼트를 생성하긴 했지만, 1개의 파드만 생성되었습니다.
디플로이먼트 생성과 동시에 한꺼번에 여러 파드를 만드는 방법을 알아봅시다!
create
에서는 --replicas
옵션을 사용할 수 없고, scale
은 이미 만들어진 디플로이먼트에서만 사용할 수 있습니다!
이런 설정을 적용하려면 필요한 내용을 파일로 작성해야 합니다.
이때 작성하는 파일을 오브젝트 스펙(spec) 이라고 합니다.
오브젝트 스펙은 일반적으로 야믈(YAML) 문법으로 작성합니다.
최근 상용, 오픈 소스 기술들은 스펙과 상태 값을 주로 야믈로 작성하므로 문법에 익숙해지는 것이 좋습니다.
3개의 nginx 파드를 디플로이먼트 오브젝트로 만들어 보겠습니다. 명령어로는 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 # 사용되는 이미지
apiVersion은 오브젝트를 포함하는 API 버전을 의미합니다. apps/v1은 여러 종류의 오브젝트를 가지고 있는데, 그 중에서 Deployment를 선택해 레플리카셋을 생성합니다.
사용 가능한 API 버전을 확인하려면(사용가능한 버전은 쿠버네티스 버전에 따라 다릅니다)? kubectl api-versions
파일을 살펴보면 이전에 살펴본 nginx-pod.yaml
과 template 부분이 동일함을 알 수 있습니다. 즉, template 하위의 metadata와 spec이 동일하게 사용됩니다!
쿠버네티스는 API 버전마다 포함되는 오브젝트(kind)도 다르고 요구하는 애용도 다릅니다. 그러므로 기존에 만들어진 파일을 수정하면서 이해해 보고 필요한 내용을 그때마다 정리하는 것이 좋습니다.
echo-hname.yaml 파일을 이용해 디플로이먼트를 생성해 봅시다.
kubectl create -f ~/_Book_k8sInfra/ch3/3.2.4/echo-hname.yaml
spec파일(.yaml)을 이용해 생성한 echo-hname 파드가 3개인지 확인합니다.
이번에는 echo-hname.yaml 파일을 수정해 파드를 6개로 늘려보겠습니다.
-i
는 --in0place의 약어로 변경한 내용을 현재 파일에 바로 적용합니다./s
는 주어진 패턴을 원하는 패턴으로 변경합니다.sed -i 's/replicas: 3/replicas: 6/' ~/_Book_k8sInfra/ch3/3.2.4/echo-hname.yaml
replicas의 값이 변경되었는지 확인합니다.
cat ~/_Book_k8sInfra/ch3/3.2.4/echo-hname.yaml | grep replicas
변경된 내용을 적용합니다.
kubectl create -f ~/_Book_k8sInfra/ch3/3.2.4/echo-hname.yaml
echo-hname이 이미 존재하기 때문에 에러가 발생합니다. 물론 scale 명령으로 파드 수를 느릴 수도 있지만, 파일을 통해 파드 수를 늘리려면 어떻게 해야할까요? 배포된 오브젝트의 스펙을 변경하고 싶을 떄는 어떻게 해야할까요? 지금부터 알아봅시다!
replicas를 6으로 수정한 echo-hname.yaml 파일을 kubectl apply 명령으로 적용합니다.
kubectl apply -f ~/_Book_k8sInfra/ch3/3.2.4/echo-hname.yaml
명령이 적용된 후에 echo-hname이 6개로 늘어났는지 확인합니다. 특히 AGE를 확인해 최근 추가된 파드 3개를 확인합니다.
kubectl get pods
kubectl apply
를 활용하면 파일의 변경 사항도 쉽게 적용할 수 있다는 것을 확인했습니다. 명령 창 등에 직접 애드혹(ad-hoc, 일회적 사용)으로 오브젝트를 생성할 때는 create를 사용하고 변경 가능성이 있는 오브젝트는 파일로 작성후 apply를 적용하도록 합시다!
구분 | run | create | apply |
---|---|---|---|
명령 실행 | 제한적임 | 가능함 | 안 됨 |
파일 실행 | 안 됨 | 가능함 | 가능함 |
변경 가능 | 안 됨 | 안 됨 | 가능함 |
실행 편의성 | 매우 좋음 | 매우 좋음 | 좋음 |
기능 유지 | 제한적임 | 지원됨 | 다양하게 지원됨 |
쿠버네티스는 거의 모든 부분이 자동 복구되도록 설계됐습니다.
특히 파드의 자동 복구 기술은 셀프 힐링(Self-Healing)이라고 하는데,
제대로 작동하지 않는 컨테이너를 다시 시작하거나 교체해 파드가 정삭적으로 작동하게 합니다.
셀프 힐링 기능을 확인하는 테스트를 해봅시다!
파드에 접속하려면 파드의 IP를 알아야하니까, kubectl get pods -o wide
로 확인해봅시다.
kubectl exec -it nginx-pod -- /bin/bash
명령을 실행해 파드 컨테이너의 셸(shell)에 접속합니다.
i
옵션은 stdin(standard input, 표준 입력)이고, t는 tty(teletypewriter, 명령줄 인터페이스)를 뜻합니다. --
의 의미 :ls /run
을 입력하면 됩니다. --를 사용할 때는 보이지 않던 DEPRECATED 메세지가 함께 표시됩니다.kubectl exec -it nginx-pod ls /run
kubectl exec -it nginx-pod ls -l /run
--
를 사용합니다.kubectl exec -it nginx-pod -- ls -l /run
배시 셸에 접속하면 컨테이너에서 구동하는 nginx의 PID(Process ID, 프로세스 식별자)를 확인합니다. nginx의 PID은 언제나 1입니다. 그 이유는 나중에 포스팅하도록 하겠습니다.
cat /run/nginx.pid
ls -l 명령으로 프로세스가 생성된 시간을 확인합니다.
ls -l /run/nginx.pid
(mac의 경우)zsh 터미널에서 m-k8s의 터미널을 1개 더 띄우고, 이 터미널 화면에서 nginx-pod의 IP(172.16.132.1, 각자 생성된 IP를 확인해주세요.)에서 돌아가는 웹 페이지를 1초마다 한 번씩 요청하는 스크립트를 실행합니다.
vagrant ssh m-k8s
도 3.1.3 폴더에서 진행합니다.)i=1; while true; do sleep 1; echo $((i++)) `curl --silent 172.16.132.1 | grep title` ; done
다시 돌아와 배시 셸에서 nginx 프로세서인 PID 1번을 kill 명령으로 종료합니다.
zsh 터미널에서 1초마다 nginx 웹 페이지를 받아오는 스크립트의 상태를 확인해봅시다! 잠깐 프로세서가 종료되어 페이지를 받아오지 못하다가 자동 복구된 것을 확인할 수 있습니다.
다시 nginx-pod에 접속합니다. 그리고 ls -l
을 실행합니다.
kubectl exec -it nginx-pod -- /bin/bash
ls -l /run/nginx.pid
ssh로 접근해서 계속 nginx 웹 페이지를 받아오고 있는 zsh 터미널도 종료해줍니다. 터미널을 끄면 자동으로 접속도 해제됩니다.
쿠버네티스는 파드 자체에 문제가 발생하면 파드를 자동 복구해서 항상 동작하도록 보장하는 기능도 있습니다.
사실 이미 앞에서 이 기능을 경험해봤지만, 자세히 살펴봅시다.
파드에 문제가 발생하는 상황을 만듭니다.
kubectl get pods
nginx-pod를 삭제합니다.
kubectl delete pods nginx-pod
파드의 동작을 보증하려면 어떤 조건이 필요합니다. 어떤 조건인지 확인하기 위해 다른 파드도 삭제해 서로 비교해 봅시다.
echo-hname-7894b67f-24blh
를 삭제하겠습니다.kubectl delete pods echo-hname-7894b67f-24blh
삭제가 잘 되었는지 kubectl get pods
로 확인합니다.
하지만 아직도 6개의 파드가 살아 있고, 그 중 하나는 최근에 생성된 것으로 보입니다.
또한 앞에서 삭제한 echo-hname-7894b67f-24blh
는 목록에 없습니다.
그 이유는 nginx-pod는 디플로이먼트에 속한 파드가 아니며 어떤 컨트롤러도 이 파드를 관리하지 않습니다. 따라서 nginx-pod는 바로 삭제되고 다시 생성되지도 않습니다.(단일파드, 동작 보증 X)
echo-hname
은 디플로이먼트에 속한 파드입니다. 그리고 앞에서 echo-hanme에 속한 파드를 replicas=6
으로 선언했습니다.
- replicas는 선언한 파드의 수를 유지하고, 항상 확인하며 부족하면 새로운 파드를 만들어냅니다.
감시 -> 차이 발견 -> 상태 변경 -> 변경 완료 후 다시 감시
순서입니다.이와 같이 디플로이먼트로 생성하는 것이 파드의 동작을 보장하기 위한 조건 입니다!
kubectl delete deployment echo-hname
kubectl get pods
여러가지 상황에서도 쿠버네티스는 파드를 안정적으로 작동하도록 관리한다는 것을 확인했습니다.
그렇다면 노드는 어떤 식으로 관리할까요? 우선 노드의 목적을 알아봅시다.
노드는 쿠버네티스 스커줄러에서 파드를 할당받고 처리하는 역할을 합니다.
최근에 몇 차례 문제가 생긴 노드에 파드를 할당하면 문제가 생길 가능성이 높습니다. 하지만 어쩔 수 없이 해당 노드를 사용해야 한다면 어떻게 할까요?
이런 경우는 영향도가 적은 파드를 할당해 질정 기간 사용하면서 모니터링 해야합니다.
즉, 노드에 문제가 생기더라도 파드에 문제를 최소화해야 합니다.
하지만 쿠버네티스는 모든 노드에 균등하게 파드를 할당하려고 합니다.
그렇다면 어떻게 문제가 생길 가능성이 있는 노드라는 것을 쿠버네티스에게 알려줄까요?
-> 해당 노드에 더는 파드를 할당하지 않는 기능을 사용합니다.
이런 경우에는 cordon
기능을 사용합니다. cordon으로 노드 관리를 실습해봅시다!
kubectl apply -f ~/_Book_k8sInfra/ch3/3.2.8/echo-hname.yaml
kubectl scale deployment echo-hname --replicas=9
kubectl get pods -o wide
대신 kubectl get pods -o=custom-columns
를 사용합니다.-o
는 output을 의미합니다custom-columns
는 사용자가 임의로 구성할 수 있는 열을 의미합니다.NAME, IP, STATUS, NODE
는 열의 제목이고, 콜론(:) 뒤에 내용 값인 .metadata.name, .status.podIP, .status.phase, .spec.nodeName
을 넣고 콤마로 구분합니다.kubectl get pods -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase,NODE:.spec.nodeName
-o yaml
옵션으로 내용을 pod.yaml
에 저장합니다. kubectl get pod echo-hname-7894b67f-6tm7l
kubectl scale deployment echo-hname --replicas=3
kubectl get pods -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase,NODE:.spec.nodeName
kubectl cordon w3-k8s
kubectl get nodes
kubectl scale deployment echo-hname --replicas=9
kubectl get pods -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase,NODE:.spec.nodeName
kubectl scale deployment echo-hname --replicas=3
kubectl get pods -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase,NODE:.spec.nodeName
uncordon
명령으로 w3-k8s에 파드가 할당되지 않게 설정했던 것을 해제하고, 적용됐는지 확인합니다.kubectl uncordon w3-k8s
kubectl get nodes
이렇게 cordon
기능을 통해 노드에 파드를 더 이상 할당되지 않게 하는 방법을 알아봤습니다.
그렇다면 노드의 커널을 업데이트하거나, 노드의 메모리를 증성하는 등의 작업이 필요해서 노드를 꺼야할 때는 어떻게 하면 좋을까요?
쿠버네티스를 사용하다 보면 정기 또는 비정기적인 유지보수를 위해 노드를 꺼야 하는 상황이 발생합니다.
이런 경우를 대비해 쿠버네티스는 drain
기능을 제공합니다.
drain
은 지정된 노드의 파드를 전부 다른 곳으로 이동시켜 해당 노드를 유지보수할 수 있게 합니다.
kubectl drain
명령을 실행해 유지보수할 노드(w3-k8s)를 파드가 없는 상태로 반듭니다.
kubectl drain w3-k8s
drain
이 어떻게 작동하는지 알 수 있습니다.이번에는 drain
명령과 ignore-daemonsets
옵션을 함께 사용합니다. 이 옵션은 DaemonSet을 무시하고 진행합니다. 경고는 발생하지만 모든 파드가 이동됩니다.
kubectl drain w3-k8s --ignore-daemonset
노드 w3-k8s에 파드가 없는지 확인합니다. 그리고 옮긴 노드에 파드가 새로 생성돼 파드 이름과 IP가 부여된 것도 확인합니다.
kubectl get pods -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase,NODE:.spec.nodeName
drain
명령이 수행된 w3-k8s 노드의 상태를 확인합니다. cordon
을 실행했을 때처럼 SchedulingDisabled
상태입니다.
kubectl get nodes
유지보수가 끝났다고 가정하고 w3-k8s에 uncordon 명령을 실행해 스케줄을 받을 수 있는 상태로 복귀시키고, 다시 노드 상태를 확인합니다.
kubectl uncordon w3-k8s
kubectl get nodes
다음 진행을 위해 배포한 echo-hname
을 삭제합니다. 배포된 파드가 없는 것을 확인합니다.
kubectl delete -f ~/_Book_k8sInfra/ch3/3.2.8/echo-hname.yaml
kubectl get pods
파드를 운영하다 보면 컨테이너에 새로운 기능을 추가하거나 치명적인 버그가 발생해 버전을 업데이트해야 할 때가 있습니다.
또는 업데이트 도중 문제가 발생해 기존 버전으로 복구해야 하는 일도 발생합니다.
이런 일을 처리하는 방법을 알아봅시다!
다음 명령으로 컨테이너 버전 업데이트를 테스트하기 위한 파드를 배포합니다.
--record
옵션은 매우 중요한 옵션으로, 배포한 정보의 히스토리를 기록합니다.
kubectl apply -f ~/_Book_k8sInfra/ch3/3.2.10/rollout-nginx.yaml --record
적용한 코드는 다음과 같습니다. 앞서 살펴본 내용과 거의 비슷하며 중요한 부분은 버전을 정하는 image: nginx:1.15.12
입니다. 여기에 컨테이너 버전을 지정하고, 설치한 후에 단계별로 버전을 업테이트합니다.
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
record
옵션으로 기록된 히스토리는 rollout history
명령을 실행해 확인할 수 있습니다.
kubectl rollout history deployment rollout-nginx
배포한 파드의 정보를 확인합니다.
kubectl get pods -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase,NODE:.spec.nodeName
배포된 파드에 속해 있는 nginx 컨테이너 버전을 curl -I
(헤더 정보만 보여주는 옵션) 명령으로 확인합니다.
curl -I --silent 172.16.132.9 | grep Server
set image
명령으로 파드의 nginx 컨테이너 버전을 1.16.0으로 업데이트합니다. 이번에도 --record
명령을 포함해, 실행한 명령을 기록합니다.
kubectl set image deployment rollout-nginx nginx=nginx:1.16.0 --record
업데이트한 후 파드의 상태를 확인합니다.
kubectl get pods -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase,NODE:.spec.nodeName
nginx 컨테이너가 1.16.0으로 모두 업데이트되면 Deployment의 상태를 확인합니다.
kubectl rollout status deployment rollout-nginx
rollout history
명령을 실행해 rollout-nginx에 적용된 명령들을 확인합니다.
kubectl rollout history deployment rollout-nginx
--record
옵션을 적용한 apply
와 set image
명령이 기록되어 있는 것을 확인할 수 있습니다.curl -I
명령으로 업데이트가 제대로 이루어졌는지도 확인합니다.
curl -I --silent 127.16.103.142 | grep Server
업데이트할 때 버전을 잘못 입력하면 어떻게 할까요? 업데이트 실패 시 파드를 복구하는 방법을 알아봅시다!
set image
명령으로 nginx 컨테이너 버전을 의도(1.17.2)와 다르게 1.17.23으로 입력합니다.
kubectl set image deployment rollout-nginx nginx=nginx:1.17.23 --record
한참이 지나고 나서도, 파드의 상태를 확인해보면 파드가 삭제되지 않고 pending(대기 중) 상태에서 변하지 않은 것을 볼 수 있습니다. 확인해봅시다.
kubectl get pods -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase,NODE:.spec.nodeName
어떤 문제인지 파악하기 위해 rollout status
를 실행합니다.
kubectl rollout status deployment rollout-nginx
describe
명령으로 문제점을 좀 더 자세히 살펴봅시다. 이 명령은 쿠버네티스의 상태를 살펴볼 때 유용합니다.
kubectl describe deployment rollout-nginx
rollout
을 사용하고 --record
로 기록하는 것입니다. 이제 정상적인 상태로 복구하는 방법을 알아봅시다. 업데이트할 떄 사용했던 명령들을 rollout history
로 확인합니다.
kubectl rollout history deployment rollout-nginx
rollout undo
로 명령 실행을 취소해 마지막 단계(revision 3)에서 전 단계(revision 2)로 상태를 되돌립니다.
kubectl rollout undo deployment rollout-nginx
파드의 상태를 다시 확인합니다.
kubectl get pods -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase,NODE:.spec.nodeName
rollout history
로 실행된 명령을 확인합니다.
kubectl rollout history deployment rollout-nginx
배포된 컨테이너의 버전을 확인합니다. 버전이 1.16.0이므로 상태가 되돌려졌음을 알 수 있습니다.
curl -I --silent 172.16.103.142 | grep Server
rollout status
명령으로 변경이 정상적으로 적용됐는지 확인합니다.
kubectl rollout status deployment rollout-nginx
describe
로 현재 디플로이먼트 상태도 세부적으로 점검하고 넘어갑니다.
kubectl describe deployment rollout-nginx
방금과 같이 바로 이전 상태가 아니라 특정 시점으로 돌아가고 싶다면 어떻게 할까요?
이럴 땐 --to-revision
옵션을 사용합니다.
kubectl rollout undo deployment rollout-nginx --to-revision=1
kubectl get pods -o=custom-columns=NAME:.metadata.name,IP:.status.podIP,STATUS:.status.phase,NODE:.spec.nodeName
curl -I --silent 172.16.103.143 | grep Server
kubectl delete -f ~/_Book_k8sInfra/ch3/3.2.10/rollout-nginx.yaml
kubectl get pods
지금까지 쿠버네티스의 파드를 통해서 오브젝트 구성을 살펴보고,
파드를 효율적으로 사용할 수 있게 해주는 디플로이먼트에 대해서 알아봤습니다.
또한 오브젝트를 생성하는 3가지 방법을 알아보고 각각의 사용 용도를 확인했습니다.
그리고 쿠버네티스의 가장 큰 강점 주으이 하나인 안정적인 작동을 위해서 제공되는 기능들을 알아보고
유지보수, 업데이트, 그리고 복구하는 방법도 살펴봤습니다.
다음 포스팅에선 쿠버네티스 연결을 담당하는 서비스와 알아두면 쓸모있는 쿠버네티스 오브젝트에 대해 알아보겠습니다!
본 게시물은 "컨테이너 인프라 환경 구축을 위한 쿠버네티스/도커 - 조훈,심근우,문성주 지음(2021)" 기반으로 작성되었습니다.