쿠버네티스란?

이지우·2023년 4월 15일
0

쿠버네티스

목록 보기
5/9

컨테이너 인프라 환경
리눅스 운영 체제의 커널 하나에서 여러 개의 컨테이너가 격리된 상태로 실행되는 인프라 환경

컨테이너
: 하나 이상의 목적을 위해 독립적으로 작동하는 프로세스
: 친구와 대화를 주고받는 메신저 프로그램이나 음악 감상 프로그램을 컨테이너로 구현할 수 있음

개인환경
1명의 관리자가 다양한 응용프로그램을 사용함
-> 각각의 프로그램을 컨테이너로 구현할 필요가 거의 없음

기업 환경
다수의 관리자가 수백 또는 수천 대의 서버를 함께 관리함
-> 일관성을 유지하는 것이 매우 중요함

가상화 환경에서는 각각의 가상 머신이 모두 독립적인 운영 체제 커널을 가지고 있어야 함
-> 그만큼 자원을 더 소모해야 하고 성능이 떨어짐

컨테이너 인프라 환경은 운영 체제 커널 하나에 컨테이너 여러 개가 격리된 형태로 실행됨
-> 자원을 효율적으로 사용할 수 있고 거치는 단계가 적어서 속도도 훨씬 빠름


📌쿠버네티스

컨테이너 오케스트레이션을 위한 솔루션

오케스트레이션(Orchestration)
: 복잡한 단계를 관리하고 요소들의 유기적인 관계를 미리 정의해 손쉽게 사용하도록 서비스를 제공하는 것
: 다수의 컨테이너를 유기적으로 연결, 실행, 종료, 상태를 추적하고 보존
: 컨테이너를 안정적으로 사용할 수 있게 만들어주는 것

컨테이너 오케스트레이션 솔루션 비교

[k8s 의미]

- k8s는 쿠버네티스(Kubernetes)의 약어
- k8(ubernete, 8글자)s의 형식으로 만들어짐
- 쿠버네티스는 그리스어로 도선사(pilot, 배를 수로로 안전하게 안내하는 사람)나
  조타수(helmsman, 배의 키를 조정해 올바른 방향으로 나아가게 하는 사람)를 의미함

📌 구성 방법

  1. 퍼블릭 클라우드 업체에서 제공하는 관리형 쿠버네티스인 EKS(Amazon Elastic Kubernetes Service), AKS(Azurc Kubernetes Service), GKE(Google Kubernetes Engine) 등을 사용
    -> 구성이 이미 다 갖춰져 있고 마스터 노드를 클라우드 업체에서 관리하기 때문에 학습용으로는 적합하지 않음

  2. 수세의 Rancher, 레드햇의 OpenShift와 같은 플랫폼에서 제공하는 설치형 쿠버네티스를 사용
    -> 유료라 쉽게 접근하기 어려움

  3. 사용하는 시스템에 쿠버네티스 클러스티를 자동으로 구성해주는 구성형 쿠버네티스를 사용
    -> kubeadm, kops(Kubernetes Operations), KRIB(Kubernetes Rebar Intergrated Bootstrap), kubespray
    -> kubeadm이 가장 널리 알려져 있음
    -> kubeadm은 사용자가 변경 하기도 수월하고, 온프레미스(On-Premises)와 클라우드를 모두 지원하며, 배우기도 쉬움

📌 구성 파일

kubeadm으로 구성
서버 노드는 가상 머신을 이용하여 온프레미스에 가깝게 구성
설치되는 과정을 베이그런트로 자동화

  • Vagrantfile
  • config.sh
  • intstall_pkg.sh
  • master_node.sh
  • work_nodes.sh

Vagrantfile

: 베이그런트 프로비저닝을 위한 정보를 담고 있는 메인 파일

cmd 창(Vagrantfile이 있는 경로)에서 vagrant up 명령을 입력
-> 현재 호스트 내부에 Vagrantfile에 정의된 가상 머신들을 생성
-> 생성한 가상 머신에 쿠버네티스 클러스트를 구성하기 위한 파일들을 호출해 쿠버네티스 클러스터를 자동으로 구성

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  N = 3 # max number of worker nodes
  Ver = '1.18.4' # Kubernetes Version to install

  #=============#
  # 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
      cfg.vm.provision "shell", path: "install_pkg.sh", args: [ Ver, "Main" ]
      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
      cfg.vm.provision "shell", path: "work_nodes.sh"
    end
  end

end

  • 5번째 줄 : N = 3 # max number of worker nodes
    : 쿠버네티스에서 작업을 수행할 워커 노드의 수
    : 24번째 줄, 46번째 줄에서 config.sh로 넘김
    : 사용자가 워커 노드의 개수를 직접 조절할 수 있음

  • 6번째 줄 : Ver = '1.18.4' # Kubernetes Version to install
    : 쿠버네티스 버전을 사용자가 선택할 수 있음
    : 다른 쿠버네티스 버전을 사용하기 위해 값을 변경하면 됨

  • 25번째 줄 : cfg.vm.provision "shell", path: "install_pkg.sh", args: [ Ver, "Main" ]
    : 쿠버네티스 버전 정보(Ver)와 Main이라는 문자를 install_pkg.sh로 넘김
    : Ver 변수는 각 노드에 해당 버전의 쿠버네티스 버전을 설치함
    : Main 문자는 install_pkg.sh에서 조건문으로 처리해 마스터 노드에만 이 책의 전체 실행 코드를 내려받게 함

  • 26번째 줄 : cfg.vm.provision "shell", path: "master_node.sh"
    : 쿠버네티스 마스터 노드를 위한 master_node.sh 코드 추가

  • 48번째 줄 : cfg.vm.provision "shell", path: "work_nodes.sh"
    워커 노드를 위한 work_nodes.sh 코드 추가


config.sh

: kubeadm으로 쿠버네티스를 설치하기 위한 사전 조건을 설정하는 스크립트 파일

#!/usr/bin/env bash

# vim configuration 
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
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

# Set SELinux in permissive mode (effectively disabling it)
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

# RHEL/CentOS 7 have reported traffic issues being routed incorrectly due to iptables bypassed
cat <<EOF >  /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
modprobe br_netfilter

# 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

# config DNS  
cat <<EOF > /etc/resolv.conf
nameserver 1.1.1.1 #cloudflare DNS
nameserver 8.8.8.8 #Google DNS
EOF

  • 4번째 줄 echo 'alias vi=vim' >> /etc/profile
    : vi를 호출하면 vim을 호출하도록 프로파일에 입력
    : 코드에 하이라이트를 넣어 코드를 쉽게 구분할 수 있음

  • 7번째 줄 swapoff -a
    : 쿠버네티스의 설치 요구 조건을 맞추기 위해 스왑되지 않도록 설정

  • 9번째 줄 sed -i.bak -r 's/(.+ swap .+)/#\1/' /etc/fstab
    : 시스템이 다시 시작되더라도 스왑되지 않도록 설정

  • 12번째 줄 gg_pkg="packages.cloud.google.com/yum/doc" # Due to shorten addr for key
    : 쿠버네티스의 리포지터리를 설정하기 위한 경로를 변수로 처리

  • 13~21번째 줄
    : 쿠버네티스를 내려받을 리포지터리를 설정하는 구문
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

  • 24~25번째 줄
    : selinux가 제한적으로 사용되지 않도록 permissive 모드로 변경
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

  • 28~31번째 줄
    : 브리지 네트워크를 통과하는 IPv4와 IPv6의 패킷을 iptables가 관리하게 설정
    : 파드의 통신을 iptables로 제어
    : 필요에 따라 IPVS(IP Virtual Server) 같은 방식으로도 구성할 수 있음
cat <<EOF >  /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF

  • 32번째 줄 modprobe br_netfilter
    : br_netfilter 커널 모듈을 사용해 브리지로 네트워크를 구성
    : IP 마스커레이드(Masquerade)를 사용해 내부 네트워크와 외부 네트워크를 분리
    : br_netfilter를 적용함으로써 28~31번째 줄에서 적용한 iptables가 활성화 됨

IP 마스커레이드 : 커널에서 제공하는 NAT(Network Address Translation) 기능


  • 35~36번째 줄
    : 쿠버네티스 안에서 노드 간 통신을 이름으로 할 수 있도록 각 노드의 호스트 이름과 IP를 /etc/hosts에 설정
    : 워커 노드는 Vagrantfile에서 넘겨받은 N 변수로 전달된 노드 수에 맞게 동적으로 생성
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

  • 39~42번째 줄
    : 외부와 통신할 수 있게 DNS 서버 지정
cat <<EOF > /etc/resolv.conf
nameserver 1.1.1.1 #cloudflare DNS
nameserver 8.8.8.8 #Google DNS
EOF

install_pkg.sh

: 클러스터를 구성하기 위해 가상머신에 설치되어야 하는 의존성 패키지를 명시함
: 실습에 필요한 소스 코드를 특정 가상머신(m-k8s) 내부에 내려받도록 설정되어 있음

#!/usr/bin/env bash

# install packages 
yum install epel-release -y
yum install vim-enhanced -y
yum install git -y

# install docker 
yum install docker -y && systemctl enable --now docker

# install kubernetes cluster 
yum install kubectl-$1 kubelet-$1 kubeadm-$1 -y
systemctl enable --now kubelet

# git clone _Book_k8sInfra.git 
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
  • 6번째 줄
    yum install git -y
    : 깃허브에서 코드를 내려받을 수 있게 깃(git)을 설치함

  • 9번째 줄
    yum install docker -y && systemctl enable --now docker
    : 쿠버네티스를 관리하는 컨테이너를 설치하기 위해 도커를 설치하고 구동함

  • 12~13번째 줄
    : 쿠버네티스를 구성하기 위해 첫 번째 변수($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

  • 16~20번째 줄
    : 전체 실행 코드를 마스터 노드에만 내려받도록 Vagrantfile에서 두 번째 변수($2='Main')을 넘겨받음
    : 깃에서 코드를 내려받아 실습을 진행할 루트 홈디렉터리(/root)로 옮김
    : 배시 스크립트(.sh)를 find로 찾아서 바로 실행 가능한 상태가 되도록 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

master_node.sh

: 1개의 가상 머신(m-k8s)을 쿠버네티스 마스터 노드로 구성하는 스크립트
: 쿠버네티스 클러스터를 구성할 때 꼭 선택해야 하는 컨테이너 네트워크 인터페이스(CNI, Container Network Interface)도 함께 구성

#!/usr/bin/env bash

# init kubernetes 
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 
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 
kubectl apply -f \
https://raw.githubusercontent.com/sysnet4admin/IaC/master/manifests/172.16_net_calico.yaml

  • 4~5번째 줄
    : kubeadm을 통해 쿠버네티스의 워커 노드를 받아들일 준비를 함
    : 토큰을 123456.1234567890123456으로 지정
    : ttl(time to live)을 0으로 설정해서 기본값이 24시간 후에 토큰이 계속 유지되게 함
    : 워커 노드가 정해진 토큰으로 들어오게 함
    : 쿠버네티스가 자동으로 컨테이너에 부여하는 네트워크를 172.16.0.0/16으로 제공
    : 워커 노드가 접속하는 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 

  • 8~10번째 줄
    : 마스터 노드에서 현재 사용자가 쿠버네티스를 정상적으로 구동할 수 있게 설정 파일을 루트의 홈디렉터리(/root)에 복사
    : 쿠버네티스를 이용할 사용자에게 권한을 줌
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config

  • 13~14번째 줄
    : 컨테이너 네트워크 인터페이스(CNI)인 캘리코(Calico)의 설정을 적용해 쿠버네티스의 네트워크를 구성
kubectl apply -f \
https://raw.githubusercontent.com/sysnet4admin/IaC/master/manifests/172.16_net_calico.yaml

work_nodes.sh

: 3대의 가상 머신(w1-k8s, w2-k8s, w3-k8s)에 쿠버네티스 워커 노드를 구성하는 스크립트
: 마스터 노드에 구성된 클러스터에 조인이 필요한 정보가 모두 코드화 되어있음
: 스크림트를 실행하기만 하면 편하게 워커 노드로서 쿠버네티스 클러스터에 조인됨

#!/usr/bin/env bash

# config for work_nodes only 
kubeadm join --token 123456.1234567890123456 \
             --discovery-token-unsafe-skip-ca-verification 192.168.1.10:6443

: kubeadm을 이용해 쿠버네티스 마스터 노드에 접속함
: 연결에 필요한 토큰은 기존에 마스터 노드에서 생성한 123456.1234567890123456을 사용함
: 간단하게 구성하기 위해 --discovery-token-unsafe-skip-ca-verification으로 인증을 무시함
: API 서버 주소로 기본 포트 번호인 6443번 포트에 접속하도록 설정


📌 구성 과정

  1. cmd에서 쿠버네티스 설치 파일 디렉터리로 이동
  2. vagrant up 명령 실행
  3. 슈퍼푸티에서 m-k8s 클릭하여 터미널 접속
  4. kubectl get nodes 명령으로 정상적으로 생성, 연결되었는지 확인

📌 구성 요소

  • kubectl
  • kubelet
  • API 서버
  • 캘리코
  • etcd
  • 컨트롤러 매니저
  • 스케줄러
  • kube-proxy
  • 컨테이너 런타임
  • 파드

kubectl get pods --all-namespaces 명령
: 설치된 구성 요소 확인
: 기본 네임스페이스인 default 외에 모든 것을 표시
: 네임스페이스에서 파드를 수집해 보여줌
: 구성 요소들은 파드 형태로 이루어져 있음


🔎 구성 요소들의 역할

▼ 쿠버네티스의 구성 요소의 유기적인 연결 관계 & 관리자나 개발자가 파드 배포 명령을 수행했을 때 실행되는 순서

마스터 노드

  1. kubectl
    : 쿠버네티스 클러스터에 명령을 내리는 역할
    : 다른 구성 요소들과 다르게 바로 실행되는 명령 형태인 바이너리(binary)로 배포됨 -> 마스터 노드에 있을 필요는 없음
    : API 서버와 주로 통신하므로 마스터 노드에 구성함

  2. API 서버
    : 쿠버네티스 클러스터의 중심 역할을 하는 통로
    : 주로 상태 값을 저장하는 etcd와 통신
    : 다른 요소들도 API 서버를 중심에 두고 통신하므로 API 서버의 역할이 매우 중요
    : 모든 직원과 상황을 관리하고 목표를 설정하는 관리자 역할

  3. etcd
    : 구성 요소들의 상태 값이 모두 저장되는 곳
    : 다른 구성 요소들은 상태 값을 관리하지 않음
    : etcd 정보만 백업되어 있으면 긴급한 장애 상황에서도 클러스터를 복구할 수 있음
    : 분산 저장인 가능한 key-value 저장소 -> 복제하여 여러 곳에 저장해두면 가용성 확보 가능
    : 회사의 관리자가 모든 보고 내용을 기록하는 노트
    etcd 의미 : 리눅스의 구성 정보를 가지고 있는 etc 디렉터리와 distributed의 합성어
    -> 구성 정보를 퍼뜨려 저장하겠다는 의미

  4. 컨트롤러 매니저
    : 쿠버네티스 클러스터의 오브젝트 상태를 관리
    : 워커 노드에서 통신이 되지 않는 경우, 상태 체크와 복구가 이루어짐
    컨트롤러 종류

  5. 스케줄러
    : 노드의 상태와 자원, 레이블, 요구 조건 등을 고려하여 파드를 어떤 워커 노드에 생성할 것인지 결정하고 할당함
    : 파드를 조건에 맞는 워커 노드에 지정하고, 파드가 워커 노드에 할당되는 일정을 관리

워커 노드

  1. kubelet
    : 파드의 구성 내용(PodSpec)을 받아서 컨테이너 런타임으로 전달
    : 파드 안의 컨테이너들이 정상적으로 작동하는지 모니터링

  2. 컨테이너 런타임(CRI, Container Runtime Interface)
    : 파드를 이루는 컨테이너의 실행을 담당함
    : 파드 안에서 다양한 종류의 컨테이너가 문제 없이 작동하게 만드는 표준 인터페이스

  3. 파드(pod)
    : 한 개 이상의 컨테이너로 단일 목적의 일을 하기 위해서 모인 단위
    : 웹서버 역할을 할 수도 있고 로그나 톄이터를 분석할 수도 있음
    : 언제라도 죽을 수 있는 존재 -> 여러 대안을 디자인

선택 가능한 구성 요소

  • 네트워크 플러그인
    : 클러스터의 통신을 위해서 네트워크 플러그인을 선택하고 구성해야 함
    : 일반적으로 CNI로 구성
    : 캘리코, 플래널, 실리움, 큐브 라우터, 로마나, 위브넷, Canal
    CNI(Container Network Interface) : 컨테이너의 네트워크 안전성과 확장성을 보장하기 위해 개발됨

  • CoreDNS
    : 빠르고 유연한 DNS 서버
    : 클러스터에서 도메인 이름을 이용해 통신하는 데 사용함
    : 실부에서 쿠버네티스 클러스터를 구성하여 사용할 때는 IP보다 CoreDNS를 사용하는 것이 일반적임
    홈페이지


배포된 파드에 접속하는 과정

  1. kube-proxy
    : 파드가 위치한 노드에 kube-proxy를 통해 파드가 통신할 수 있는 네트워크를 설정함
    : 실제 통신은 br_netfilter와 iptables로 관리함

  2. 파드
    : 배포된 파드에 접속하고 필요한 내용을 전달받음
    : 파드가 어느 워커 노드에 위치하는지 신경 쓰지 않아도 됨


🔎 파드의 생명주기

쿠버네티스의 장점
: 구성 요소마다 하는 일이 명확하게 구분되어 각자의 역할만 충실하게 수행하면 클러스터 시스템이 안정적으로 운영됨
: 문제가 발생했을 때 어느 부분에서 문제가 발생했는지 디버깅하기 쉬움

  1. kubectl을 통해 API 서버에 파드 생성을 요청함

  2. (업 데이트가 있을 때마다 매번) API 서버에 전달된 내용이 있으면 API 서버는 etcd에 전달된 내용을 모두 기록해 클러스터의 상태 값을 최신으로 유지함
    -> 각 요소가 상태를 업데이트할 매마다 모두 API 서버를 통해 etcd에 기록됨

  3. API 서버에 파드 생성이 요청된 것을 컨트롤러 매니저가 인지하면 컨트롤러 매니저는 파드를 생성하고, 이 상태를 API 서버에 전달함
    (아직 어떤 워커 노드에 파드를 적용할지는 결정되지 않은 상태로 파드만 생성됨)

  4. API 서버에 파드가 생성됐다는 정보를 스케줄러가 인지함
    스케줄러는 생성된 파드를 어떤 워커 노드에 적용할지 조건을 고려해 결정하고 해당 워커 노드에 파드를 띄우도록 요청함

  5. API 서버에 전달된 정보대로 지정한 워커 노드에 파드가 속해 있는지 스케줄러가 kubelet으로 확인함

  6. kubelet에서 컨테이너 런타임으로 파드 생성을 요청함

  7. 파드가 생성됨

  8. 파드가 사용 가능한 상태가 됨

쿠버네티스의 상태 유지 방법

선언적인 시스템 구조 : 추구하는 상태를 선언하면 현재 상태와 맞는지 점검하고 그것에 맞추려고 노력하는 구조

API 서버에 추구하는 상태를 선언함
-> 다른 요소들은 API 서버에 와서 현재 상태와 비교하면서 상태를 변경하려고 함

API는 현재 상태 값을 가지고 있고 이를 보존하기 위해 etcd가 필요함


💻 구성 요소 기능 검증하기

kubectl

마스터 노드에 위치할 필요 없음
외부에서 쿠버네티스 클러스터에 명령을 내릴 수도 있음

  1. 슈퍼푸티 w3-k8s 터미널 접속

  2. kubectl get nodes 명령어 실행
    -> 노드들에 대한 정보가 표시되지 않음
    -> kubectl이 정보를 알 수 없기 때문

  3. 클러스터의 정보(/etc/kubernetes/admin.conf)를 마스터 노드에서 scp 명령으로 w3-k8s의 현재 디렉터리(.)에 받아옴
    접속 기록이 없기 때문에 known_hosts로 저장하도록 yes 입력
    접속 암호 vagrant도 입력
    scp root@192.168.1.10:/etc/kubernetes/admin.conf .

  4. kubectl get nodes 명령에 추가로 정보를 입력받는 옵션(--kubeconfig)과 마스터 노드에서 받아온 admin.conf를 입력하고 실행
    kubectl get nodes --kubeconfig admin.conf


kubelet

쿠버네티스에 파드의 생성과 상태 관리 및 복구 담당
kubelet에 문제가 생기면 파드가 정상적으로 관리되지 않음

  1. m-k8s(마스터 노드)에서 kubectl create -f ~/_Book_k8sInfra/ch3/3.1.6/nginx-pod.yaml 명령으로 nginx 웹 서버 파드 배포
    -f : filename을 의미함

  2. kubectl get pod 명령으로 패보된 파드 상태 확인

  3. kubectl get pods -o wide 명령으로 파드가 배포된 워커 노드 확인
    -o : output의 약어로 출력을 특정 형식으로 해 주는 옵션
    wide : 제공되는 출력 형식 중에서 출력 정보를 더 많이 표시해 주는 옵션

  4. 배포된 노드에 접속해 systemctl stop kubelet으로 kubelet 서비스를 멈춤

  5. m-k8s에서 kubectl get pod로 상태 확인
    kubectl delete pod nginx-pod 명령으로 파드 삭제

  6. 기다리다가 ^C로 명령 중지

  7. 다시 kubectl get pod 명령으로 상태 확인
    -> nginx-pod를 삭제(Terminating)하는 중
    -> kubelet이 작동하지 않는 상태라 파드가 삭제되지 않음

  8. 배포된 노드에서 systemctl start kubelet 명령으로 kubelet 복구

  9. 잠시 후에 m-k8s에서 kubectl get pod 명령으로 nginx-pod가 삭제되었는지 확인


kube-proxy

파드의 통신을 담당

config.sh 파일에서 br_netfilter 커널 모듈을 적재하고 iptables를 거쳐 통신하도록 설정되어 있음

cat <<EOF >  /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
modprade br_netfilter

이 설정이 정상적으로 작동하지 않는다면(kube-proxy에 문제가 생긴다면) 어떻게 될지 확인해보도록 함

  1. 마스터 노드 m-k8s에서 파드 배포
    kubectl create -f ~/_Book_k8sInfra/ch3/3.1.6/nginx-pod.yaml

  2. kubectl get pods -o wide 명령으로 파드의 IP와 워커 노드 확인

  3. curl(client URL)로 전 단계에서 확인한 파드의 IP로 nginx 웹 서버 메인 페이지 내용을 확인함
    curl 172.16.103.129 (IP 다를 수 있음)

  4. kube-proxy에 문제가 생기는 상황 만들기
    배포된 노드에 접속해 modprobe -r br_netfilter 명령으로 파드가 위치한 워커 노드에서 br_netfilter 모듈 제거
    -r : remove 의미
    systemctl restart network 명령으로 네트워크를 다시 시작해 변경된 내용 적용

  5. m-k8s에서 다시 한 번 curl로 파드의 nginx 웹 서버 페이지 정보를 받아옴
    curl 172.16.103.129
    기다려도 종료가 안되면 ^C로 종료

  6. kubectl get pods -o wide로 파드 상태 확인
    파드 노드 위치나 IP가 변경되지 않았는지, 작동 상태에 문제 없는지 확인
    -> 모두 문제가 없음
    -> kube-proxy가 이용하는 br_netfilter에 문제가 있어서 파드의 nginx 웹 서버와의 통신만이 정상적으로 이루어지지 않는 상태
    (Connection timed out)

  7. 정상적으로 파드의 nginx 웹 서버 페이지 정보를 받아올 수 있는 상태로 만들기
    워커 노드에서 modprobe br_netfilter 로 br_netfilter를 커널에 적재하고 시스템을 다시 시작함 reboot

  8. m-k8s에서 파드 상태를 확인하면 RESTARTS가 1로 증가되고 IP가 변경됨
    kubectl get pods -o wide

  9. 바뀐 IP로 curl 명령 실행하여 정보를 정상적으로 받아오는지 확인

  10. 배포된 파드 삭제
    kubectl delete -f ~/_Book_k8sInfra/ch3/3.1.6/nginx-pod.yaml

profile
노력형 인간

0개의 댓글