쿠버네티스 클러스터 관리

클러스터 생성 및 설정 (Kubeadm)

본질적으로 "Vanilla Kubernetes"는 광범위한 사용 사례에 적합한 쿠버네티스의 표준 버전을 의미하다. 이 버전은 쿠버네티스의 핵심 기능들을 모두 포함하고, 이번 데모에서는 한 물리 서버에, 가상 머신 3대를 사용하여 쿠버네티스 클러스터를 생성할 예정이다.

💡 현재 VMWare Workstation에서 실습 진행 

쿠버네티스 클러스터 설정 시 Swap Memory 비활성화를 권장 한다. Swap Memory는 하드 디스크를 이용하여 RAM을 보충하는 가상 메모리이지만, K8s는 많은 자원을 요구하므로 Swap Memory를 사용하면 성능 저하와 스케줄링 지연이 발생할 수 있다. 또한, Swap Memory는 리소스 관리에 문제를 야기할 수 있으므로 안정적이고 효율적인 성능을 위해 스왑 메모리를 비활성화해야 한다. 더 자세한 내용은 여기 블로그 링크 참고.


CentOS 7에서 K8s 클러스터


Docker Installation

시작 전, 이전 버전들을 삭제 한다

sudo dnf remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine


yum-utils 설치와 로컬 yum repository (저장소) 지정

sudo dnf install -y yum-utils
sudo dnf-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo


도커 최신 버전 설치

sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin


도커 서비스 시작

sudo systemctl start docker


 도커 버전 확인

docker version


Kubernetes Installation

💡 Master Node과 Worker Node에서 동일 하게 작업

Swap Memory 비활성화 

swapoff -a


daemon.json 파일 생성 후 cgroupdriver을 systemd로 설정

vi /etc/docker/daemon.json

{
    "exec-opts": ["native.cgroupdriver=systemd"]
}


daemon 재시작

systemctl daemon-reload
systemctl restart docker


쿠버네티스 로컬 저장소 지정 및 설치

vi /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://packages.cloud.google.com/yum/doc/yum-key.gpg
       https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg

# 쿠버네티스 설치
dnf install -y kubelet-1.19.16-0.x86_64 kubectl-1.19.16-0.x86_64 kubeadm-1.19.16-0.x86_64


쿠버네티스 설치 완료 확인

rpm -qa | grep kube


쿠버네티스 클러스터 요소들 통신을 위해 방화벽 포트 추가

firewall-cmd --permanent --add-port=80/tcp
firewall-cmd --permanent --add-port=443/tcp
firewall-cmd --permanent --add-port=2376/tcp
firewall-cmd --permanent --add-port=2379/tcp
firewall-cmd --permanent --add-port=2380/tcp
firewall-cmd --permanent --add-port=6443/tcp
firewall-cmd --permanent --add-port=8472/udp
firewall-cmd --permanent --add-port=9099/tcp
firewall-cmd --permanent --add-port=10250/tcp
firewall-cmd --permanent --add-port=10251/tcp
firewall-cmd --permanent --add-port=10252/tcp
firewall-cmd --permanent --add-port=10254/tcp
firewall-cmd --permanent --add-port=10255/tcp
firewall-cmd --permanent --add-port=30000-32767/tcp
firewall-cmd --permanent --add-port=30000-32767/udp
firewall-cmd --permanent --add-masquerade
firewall-cmd --reload


💡마스터 노드에서만 진행


쿠버네티스 클러스터 생성

kubeadm init --apiserver-advertise-address=192.168.1.10 --pod-network-cidr=10.244.0.0/16

# K8s control plane 생성 완료 화면
Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

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

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.1.10:6443 --token 172vji.r0u77jcmcnccm6no \
    --discovery-token-ca-cert-hash sha256:72b9648c647f724ab52471847cb06c47b23097375f2e67633b745fc69db16e8d 


kubectl 활성화 위해 admin.conf 복사 작업

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


네트워크 플러그인 다운로드 (Flannel)

[ CNI(Container Network Interface)는 컨테이너를 위한 네트워킹을 제어할 수 있는 플러그인을 만들기 위한 표준이라고 한다. 간단하게 설명 하면 CNI플러그인을 쿠버네티스 클러스터에 설치하여 서로 다른 노드에서 실행되는 컨테이너 간의 네트워킹을 할 수 있다 ]

더 자세한 내용은 링크 참고

curl -O -L https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml


kube-flannel.yml 파일 안에 --iface=(가상 인터페이스 이름) 지정

vi kube-flannel.yml

args:
        - --ip-masq
        - --kube-subnet-mgr
        - --iface=ens160


네트워크 플러그인 YAML 파일 적용 후 kubelet 재시작

kubectl apply -f kube-flannel.yml
systemctl restart kubelet


💡 Worker Node에서 작업


Master Node에서 받은 Discovery Token 값을 join 명령어로 통해 Master과 Worker 노드 묶기

kubeadm join 192.168.1.10:6443 --token 172vji.r0u77jcmcnccm6no \
    --discovery-token-ca-cert-hash sha256:72b9648c647f724ab52471847cb06c47b23097375f2e67633b745fc69db16e8d 
    
This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.


Join 작업이 완료 후 마스터 노드에서 쿠버네티스 클러스터 확인

kubectl get nodes
NAME     STATUS   ROLES    AGE    VERSION
master   Ready    master   107m   v1.19.16
node-1   Ready    <none>   91s    v1.19.16
node-2   Ready    <none>   48s    v1.19.16


Rocky Linux 9.1에서 K8s 클러스터


Docker Installation


업데이트 확인 및 업데이트 있으면 실행

sudo dnf check-update
sudo dnf update


도커 repository (저장소) 추가

sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo


도커 설치

sudo dnf install docker-ce docker-ce-cli containerd.io


도커 시작 및 확인

sudo systemctl start docker 
sudo systemctl enable docker

sudo docker version


'sudo' 생략 하고 docker 만 쓰고 싶으면

sudo usermod -aG docker $(whoami)


Kubernetes Installation

💡 Master Node과 Worker Node에서 동일 하게 작업


Swap Memory 비활성화

sudo swapoff -a


daemon.json 파일 생성 후 cgroupdriver을 systemd로 설정

sudo vi /etc/docker/daemon.json

{
    "exec-opts": ["native.cgroupdriver=systemd"]
}


daemon 재시작

sudo systemctl daemon-reload
sudo systemctl restart docker


쿠버네티스 로컬 저장소 지정 및 설치

sudo vi /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://packages.cloud.google.com/yum/doc/yum-key.gpg
       https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg

# 쿠버네티스 설치
sudo dnf -y kubelet-1.19.16-0.x86_64 kubectl-1.19.16-0.x86_64 kubeadm-1.19.16-0.x86_64


쿠버네티스 설치 완료 확인

sudo rpm -qa | grep kube


쿠버네티스 클러스터 요소들 통신을 위해 방화벽 포트 추가

sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --permanent --add-port=443/tcp
sudo firewall-cmd --permanent --add-port=2376/tcp
sudo firewall-cmd --permanent --add-port=2379/tcp
sudo firewall-cmd --permanent --add-port=2380/tcp
sudo firewall-cmd --permanent --add-port=6443/tcp
sudo firewall-cmd --permanent --add-port=8472/udp
sudo firewall-cmd --permanent --add-port=9099/tcp
sudo firewall-cmd --permanent --add-port=10250/tcp
sudo firewall-cmd --permanent --add-port=10251/tcp
sudo firewall-cmd --permanent --add-port=10252/tcp
sudo firewall-cmd --permanent --add-port=10254/tcp
sudo firewall-cmd --permanent --add-port=10255/tcp
sudo firewall-cmd --permanent --add-port=30000-32767/tcp
sudo firewall-cmd --permanent --add-port=30000-32767/udp
sudo firewall-cmd --permanent --add-masquerade
sudo firewall-cmd --reload


💡마스터 노드에서만 진행


슈퍼 유저 (root 계정)으로 전환

sudo su


쿠버네티스 클러스터 생성

kubeadm init --apiserver-advertise-address=192.168.1.10 --pod-network-cidr=10.244.0.0/16

# K8s control plane 생성 완료 화면
Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

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

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

sudo kubeadm join 192.168.1.10:6443 --token 1x7qb2.dww3u7mjsrq2hoxt --discovery-token-ca-cert-hash sha256:10a6803e9a45bb029af4ad3c1d0d894dfaee9980d2318c495739296daeffb9eb


kubectl 활성화를 위해 admin.conf 복사 작업 (꼭 root계정으로 해야됨!)

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


네트워크 플러그인 다운로드

curl -O -L https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml


네트워크 플러그인 YAML 파일 적용 후 kubelet 재시작 (꼭 root계정으로 해야됨!)

kubectl apply -f kube-flannel.yml
systemctl restart kubelet


💡 Worker Node에서 작업


Master Node에서 받은 Discovery Token 값을 join 명령어로 통해 Master과 Worker 노드 묶기

sudo kubeadm join 192.168.1.10:6443 --token 1x7qb2.dww3u7mjsrq2hoxt \
--discovery-token-ca-cert-hash sha256:10a6803e9a45bb029af4ad3c1d0d894dfaee9980d2318c495739296daeffb9eb

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.


Join 작업이 완료 후 마스터 노드에서 쿠버네티스 클러스터 확인

sudo kubectl get nodes
NAME       STATUS   ROLES    AGE    VERSION
master     Ready    master   33m    v1.19.16
worker-1   Ready    <none>   91s    v1.19.16
worker-2   Ready    <none>   48s    v1.19.16


Ubuntu 20.04.6에서 K8s 클러스터


Docker Installation


업데이트 확인 및 실행

sudo apt update


필수 패키지 설치

sudo apt 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


도커 Repository 등록

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 update
sudo apt install docker-ce docker-ce-cli containerd.io

sudo docker version
sudo systemctl status docker

## 서버 재시작 시 docker 가 자동으로 시작되도록 설정 ##
sudo systemctl enable docker


Kubernetes Installation

💡 Master Node과 Worker Node에서 동일 하게 작업


Swap Memory 비활성화

sudo swapoff -a


노드간 통신을 위한 iptables에 브릿지 관련 설정 추가

sudo vi /etc/modules-load.d/k8s.conf

br_netfilter

sudo vi /etc/sysctl.d/k8s.conf

net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1

# sysctl.conf 파일 맨 아래에도 동일 하게 두 줄 추가
sudo vi /etc/sysctl.conf

net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1

# sysctl 설정 파일들의 변동을 저장 하기 위해
sudo sysctl --system
sudo sysctl -p


daemon.json 파일 생성 후 cgroupdriver을 systemd로 설정

sudo vi /etc/docker/daemon.json

{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2"
}


daemon 재시작

sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl enable docker


apt 업데이트 및 ca 관련 패키지 다운로드 및 설

sudo apt update
sudo apt install -y apt-transport-https ca-certificates curl
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg


도커 gpg 및 소스 리스트 내용 추가 및 apt 업데이

echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt update


kubeadm, kubelet 그리고 kubectl 설치 및 활성화

sudo apt install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

sudo systemctl start kubelet && systemctl enable kubelet


💡마스터 노드에서만 진행


쿠버네티스 클러스터 생성을 위해 kubeadm init 실행

sudo kubeadm init --apiserver-advertise-address=192.168.1.10 --pod-network-cidr=10.244.0.0/16

# K8s control plane 생성 완료 화면
Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

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

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.1.10:6443 --token mu72kx.sn06xzcg3lde7mha \
	--discovery-token-ca-cert-hash sha256:d134654458b474c796667776ab8175adbc0e1dc4bc21a712a19a7bb405ee9273 


kubectl 활성화를 위해 admin.conf 복사 작업

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


네트워크 플러그인 다운로드

curl -O -L https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml


네트워크 플러그인 YAML 파일 적용 후 kubelet 재시작 

kubectl apply -f kube-flannel.yml
sudo systemctl restart kubelet


💡 Worker Node에서 진행


Master Node에서 받은 Discovery Token 값을 join 명령어로 통해 Master과 Worker 노드 묶기

sudo kubeadm join 192.168.1.10:6443 --token mu72kx.sn06xzcg3lde7mha \
	--discovery-token-ca-cert-hash sha256:d134654458b474c796667776ab8175adbc0e1dc4bc21a712a19a7bb405ee9273 

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.


Join 작업이 완료 후 마스터 노드에서 쿠버네티스 클러스터 확인

kubectl get nodes
NAME       STATUS   ROLES    AGE    VERSION
master     Ready    master   33m    v1.19.16
worker-1   Ready    <none>   91s    v1.19.16
worker-2   Ready    <none>   48s    v1.19.16

Error Troubleshooting

[ERROR CRI]: container runtime is not running [Issue Encountered]

이 문제는 사용되는 CRI가 Containerd인 경우 마스터 노드에서 kubeadm init 명령을 실행할 때 자주 발생한다.  대부분의 경우 config.toml 파일에 문제가 있다.

해결
# config.toml 파일을 삭제 한다
sudo rm /etc/containerd/config.toml

# containerd 서비스 재시작
sudo systemctl restart containerd


The connection to the server <IP 주소>:6443 was refused - did you specify the right host or port?

이 에러는 보통 API 서버가 실행 중이지 않거나 네트워킹 문제가 있는 경우 발생할 수 있다. 하지만 이 애러가 마스터 노드 재시작 후 발생 한다면 Swap 메모리 문제일 가능성이 높다. 그런 경우 리소스 제약 때문에 발생한 문제일 가능성이 있다. Swap이 활성화되어 있으면, 커널은 비활성화된 페이지를 디스크로 이동시킬 수 있으며, 이로 인해 API 요청과 같은 지연이 발생할 수 있다. 이러한 시스템 재시작 할때 매번 swap memory를 비활성화 해야 된다. 

해결

/etc/fstab 설정 파일안에서 swap을 주석 처리 해준다

sudo vi /etc/fstab

# /etc/fstab: static file system information.
# 
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
# / was on /dev/sda3 during curtin installation
/dev/disk/by-uuid/05bb7e29-bd2d-4ffb-86c6-8868e48548f4 / ext4 defaults 0 1
# /boot/efi was on /dev/sda2 during curtin installation
/dev/disk/by-uuid/ebbd40d6-5f57-4214-806f-8cf8e929b23d /boot/efi ext4 defaults 0 1
# /swap.img     none    swap    sw      0       0


클러스터 생성 및 설정 (Kubespray)

이번 데모에서는 한 물리 서버에, 가상 머신 4대를 사용하여 쿠버네티스 클러스터를 생성할 예정이다.

💡 현재 VMWare Workstation에서 실습 진행 

Kubespray를 통해 클러스터 생성

Kubespray는 쿠버네티스 클러스터를 배포하고 관리하기 위한 오픈 소스 도구이다. Ansible을 기반으로 하며, 클러스터 설정, 노드 배치, 네트워킹, 보안 설정 등을 자동화 한다. 이를 통해 사용자는 일관된 방식으로 쿠버네티스 클러스터를 배포하고 관리할 수 있으며, 다양한 환경에서 유연하게 사용할 수 있다. 간단하게 생각하면 Kubespray는 K8s를 설치 할 수 있는 Ansible 묶음이다. 중요한 키 포인트들은:

기존에는 Kargo라는 이름이었다. 더 많은 정보는 Kubespray 깃 허브 페이지를 참고 할 수 있다. 

Kubespray Github


Requirements & Prerequisites


💡중요 포인트들!

Ansible은 오픈 소스 IT 자동화 도구로, 서버 설정, 배포, 관리 작업을 간편하게 자동화하는 데 사용 된다. 파이썬으로 작성 되었으며, SSH를 통해 에이전트 없이 호스트를 제어 한다.

Jinja는 파이썬 기반의 템플릿 엔진으로, 동적으로 데이터를 조작하여 텍스트를 생성하는 데 사용 된다. Jinja는 Ansible과 함께 사용되며, 템플릿 파일과 변수를 결합하여 구성 파일을 생성하거나 동적으로 콘텐츠를 생성하는 데 유용 하다.

Ansible과 Jinja를 Control 노드에 설치 하겠다. 이 노드는 클러스터를 배포하는 역할 만 수행하고 실제 클러스터에는 구성 되지 않는다.

그리고 진행 하기 전, selinux 상태도 확인 해야 한다. 

# 파일 안에 selinux=enforcing값을 selinux=disabled로 변경
vi /etc/selinux/config
.
.
selinux=disabled



Kubespray 실행 하기

Control 노드 에서 작업

전체 패키지 업데이트 및 파이썬 그리고 pip을 설치 한다

sudo apt update

# 깃을 사용 하여 kubespray 코드를 가져와야 한다
sudo apt install git python3 python3-pip -y


파이썬 버전과 pip 버전을 확인 한다

python3 -V
python 3.10.6

pip -V
pip 22.0.2 from /usr/lib/python3/dist-packages/pip (python 3.10)

pip을 통해 Ansible 과 Jinja 패키지를 설치 할 수 있다. pip을 통해 설치하는 것이 권장되는 이유는 pip가 파이썬의 패키지 설치 도구이며, Ansible과 Jinja 모두 파이썬 기반 도구이기 때문이다 


git clone 명령어를 통해 kubespray 깃 허브 소스 코드를 내려 받는다

git clone https://github.com/kubernetes-incubator/kubespray.git


kubespray의 깃 허브 소스 코드를 내려 받으면 이미 필요한 요소들을 쉽게 설치 할 수 있는 requirements.txt 파일이 존재 한다

# kubespray 디렉터로 이동
cd kubespray

# 파일 안에 있는 모든 항목들을 pip을 사용 하여 설치 한다
pip install -r requirements.txt

참고로 requirements.txt 파일 안에 존재하는 항목들은

image.png


설치가 무사히 완료 된 후 아래 명렁어를 사용 했을때 ansible 버전을 확인 할 수 있다

ansible --version

ansible [core 2.12.5]
  config file = /home/ansible/kubespray/ansible.cfg
  configured module search path = ['/home/ansible/kubespray/library']
  ansible python module location = /home/ansible/.local/lib/python3.10/site-packages/ansible
  ansible collection location = /home/ansible/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/ansible/.local/bin/ansible
  python version = 3.10.6 (main, Mar 10 2023, 10:55:28) [GCC 11.3.0]
  jinja version = 3.1.2
  libyaml = True


-bash: ansible: command not found?

만약에 설치가 완료 되었지만 ansible 명령어를 찾을 수 없다고 나온다면, Ansible이 설치된 디렉터리가 PATH 환경 변수에 포함되지 않았다는 거다. 

Ansible 설치 경로는 여기서 확인

ls ~/.local/bin/
__pycache__  ansible-config      ansible-console  ansible-galaxy     ansible-playbook  ansible-test   jp.py    pbr
ansible      ansible-connection  ansible-doc      ansible-inventory  ansible-pull      ansible-vault  netaddr

pip을 사용하여 Ansible을 설치하면 기본적으로 ~/.local/bin 디렉토리에 설치 된다. Python packaging의 일반적인 관례로, 사용자 별로 패키지를 격리하고 개별적으로 관리하기 위해 사용자의 로컬 디렉토리에 설치되는 것이다

Ansible의 설치 경로를 ~/.bashrc파일에 추가 해주면 해결 된다

~/.bashrc는 Bash Shell 환경을 자신의 선호에 맞게 구성할 수 있는 파일

vi ~/.bashrc

# 마지막 줄에 추가
export PATH=$PATH:/home/ansible/.local/bin

# 저장 후 나가기
:wq

# bashrc파일의 변경 내용을 업데이트
source ~/.bashrc


ansible이 정상적으로 작동 하는지 확인 후 호스트 파일을 만들기 위해 아래 명령어들을 실행 한다

# inventory/sample 디렉토리의 내용을 inventory/mycluster 디렉토리로 복사한다
# -rfp 옵션을 사용하여 재귀적으로 모든 하위 디렉터리 포함 복사하여 원본 파일의 속성들도 보존 한다
cp -rfp inventory/sample inventory/mycluster

# IPS라는 배열 변수를 선언하고, IP 주소 목록을 할당한다
declare -a IPS=(192.168.1.150 192.168.1.160 192.168.1.170)

# inventory.py라는 파이썬 스크립트를 실행한다
# 스크립트는 CONFIG_FILE 환경 변수가 설정되어야 하므로, hosts.yaml로 설정 한다
CONFIG_FILE=inventory/mycluster/hosts.yml python3 contrib/inventory_builder/inventory.py ${IPS[@]}

# inventory 디렉토리의 주어진 IP 주소와 디렉토리 구조를 사용하여 인벤토리 파일(hosts.yaml)을 생성하는 설정 프로세스


설정 완료 후 hosts.yaml 파일안에 내용을 아래와 같이 수정 한다

vi inventory/mycluster/hosts.yml

all:
  hosts:
    node1:
      ansible_host: 192.168.1.150            # 작업을 실행하기 위해 대상 노드에 연결할 때 사용하는 IP 주소 또는 호스트 이름을 지정하는 필드
      ip: 192.168.1.150
      access_ip: 192.168.1.150
    node2:
      ansible_host: 192.168.1.160
      ip: 192.168.1.160
      access_ip: 192.168.1.160
    node3:
      ansible_host: 192.168.1.170
      ip: 192.168.1.170
      access_ip: 192.168.1.170
  children:
    kube_control_plane:						# 마스터 노드 지정 하는 곳
      hosts:
        node1:
    kube_node:								# 워커 노드 지정 하는 곳
      hosts:
        node2:
        node3:
    etcd:									# etcd 노드 지정 하는 곳
      hosts:
        node1:
    k8s_cluster:
      children:
        kube_control_plane:
        kube_node:
    calico_rr:
      hosts: {}


그 외 쿠버네티스 클러스터 관련 검토 및 수정 할 수 있는 설정 파일은: 

vi inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yml

# 파일 내용이 너무 길어서 중요한 요소들만 지정 하였다

# 20번째 줄
kube_version: v1.26.5

# 70번째 줄
kube_network_plugin: calico

# 76번째 줄
kube_service_addresses: 10.233.0.0/18

# 81번째 줄
kube_pods_subnet: 10.233.64.0/18

# 160번째 줄
cluster_name: cluster.local

# 229번째 줄
container_manager: containerd


마지막으로 추가적인 클러스터 요소들을 클러스터 설치 시 같이 활성화 시킬 수 있게 설정 할 수 있는 파일:

vi inventory/mycluster/group_vars/k8s_cluster/addons.yml

# 파일 내용이 너무 길어서 중요한 요소들만 지정 하였다

# 4번째 줄
dashboard_enabled: false

# 7번째 줄
helm_enabled: false

# 10번째 줄
registry_enabled: false

# 16번째 줄
metrics_server_enabled: false

# 100번째 줄
ingress_nginx_enabled: false

# 177번째 줄
metallb_enabled: false

# 246번째 줄
argocd_enabled: false

만약에 Control 노드에서 root 유저로 지금 까지 진행 하였다면 아래 호스트 노드들에서의 작업이 불필요하다

호스트 노드들에서 작업

현재 까지의 Control노드의 설정들은 'ansible'유저 이름로 진행 되었다. 그렇기 때문에 Ansible 명령어를 실행 하려면 호스트 노드들도 동일한 이름의 유저가 존재 해야 한다. 각각 호스트 노드에 먼저 새로운 'ansible' 유저 생성 후 sudoers.d 파일에 등록 시켜 줘야 한다.

# 모든 호스트노드에서 동일하게 설정
useradd ansible
passwd ansible
New Password:

# root 사용자를 위해 sudoers파일에 ansible 사용자가 비밀번호를 입력 하지 않고도 root 권한으로 모든 명령어를 실행할 수 있게 해 준다
echo "ansible ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/root

Control노드에서 작업

이제 Control 노드가 호스트 노드들 (마스터 와 워커 노드)의 설정들을 자유롭게 할 수 있게 접근권한을 부여 하는 설정을 해야 한다


첫째로 Control노드에서 SSH 접속을 위해 SSH 키를 발행 한다

ssh-keygen


SSH키를 발급 받은 후 그 Public키를 모든 호스트 노드들에게 전달 해야된다. 

# non-root 유저(ansible 유저)로 진행 하였을 경우
ssh-copy-id ansible@192.168.1.150
ssh-copy-id ansible@192.168.1.160
ssh-copy-id ansible@192.168.1.170

# root 유저로 진행 하였을 경우
ssh-copy-id root@192.168.1.150
ssh-copy-id root@192.168.1.160
ssh-copy-id root@192.168.1.170


마지막으로 Kubespray 실행 하기 전에 Firewall을 비활성화 그리고 IPv4 포워딩을 활성화 해주는 작업을 진행 한다.

쿠버네티스는 클러스터의 구성요소간 통신에 다양한 네트워크 포트를 사용 한다. 방화벽을 사용하지 않도록 설정하면 클러스터 노드 간의 원활한 통신을 위해 필요한 포트가 열려 있고 차단되지 않도록 할 수 있다. 그리고 IPv4 Forwarding을 사용 하면 쿠버네티스 클러스터에서는 노드, 포드 및 서비스간 서로 다른 네트워크 인터페이스 또는 서브넷 간에 네트워크 트래픽을 라우팅할 수 있다.

# Kubespray 디렉토리로 이동
cd kubespray

# ansible 명령어를 통해 모든 호스트들의 firewalld 서비스 중단
ansible all -i inventory/mycluster/hosts.yml -m shell -a "sudo systemctl stop firewalld && sudo systemctl disable firewalld"

# IPv4 포트 forwarding 기능 활성화
ansible all -i inventory/mycluster/hosts.yml -m shell -a "echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.conf"

# Swap memory off 설정
ansible all -i inventory/mycluster/hosts.yml -m shell -a "sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab && sudo swapoff -a"


모든 준비 단계들과 요소들이 끝났다. 이제 Kubespray를 통해 Kubernetes 클러스터를 생성 하면 된다

ansible-playbook -i inventory/mycluster/hosts.yml --become --become-user=root cluster.yml

이 한 명령어로 쿠버네티스 클러스터가 생성 된다 (네트워크 속도와 하드웨어 장비의 리소스의 따라 20 ~ 40 분 사이 시간 소요)

모든 설정들이 완료 되면 이런 화면이 보일 것이다

image.png


마스터 노드에서 확인

image.png

Worker노드들의 경우 기본적으로 특정 역할이 할당되지 않으므로 "<none>"으로 표시 된다. "Ready" 상태인 한, Worker 노드들은 올바르게 동작 한다.

추가로 <none> Label을 수동으로 바꿀 수 있는 명령어가 있다
kubectl label node <노드 이름> node-role.kubernetes.io/worker=worker


변경 후:

image.png

웹 페이지 배포

쿠버네티스 클러스터는 이미 생성 되어 있는 관계로 바로 간단한 웹 페이지를 쿠버네티스 클러스터에 배포 및 테스트 해 보겠다. 

제일 먼저 준비 해야 될 것은 물론 배포 해야 될 웹 페이지다. 일단 기존에 테스트 용으로 만든 장고 웹 사이트를 배포 해 보겠다.

먼저, 웹 애플리케이션을 K8s 클러스터에 배포하기 위해서는 애플리케이션의 컨테이너 이미지를 준비해야 한다. 일반적으로 Docker와 같은 컨테이너 플랫폼을 사용하여 애플리케이션을 컨테이너화 하고 이미지를 빌드 한다. 빌드 된 이미지는 컨테이너 레지스트리에 저장되어 클러스터 내에서 사용할 수 있게 된다.

웹 사이트의 소스 코드를 받은 후 Dockerfile을 추가 하였다. Dockerfile은 도커 이미지를 생성하기 위한 설정 파일이다. 이 파일에는 도커 이미지를 구성하는데 필요한 모든 단계와 명령어가 포함된다. Dockerfile을 작성하여 도커 이미지를 생성하면, 도커를 사용하여 해당 이미지를 기반으로 컨테이너를 실행할 수 있다.

# 파이썬 이미지 받기
FROM python:3.11

# 환경 변수 지정
ENV PYTHONUNBUFFERED 1
ENV PYTHONDONTWRITEBYTECODE 1

# 워킹 디렉터리 지정
WORKDIR /app

# 의존성 설치
COPY requirements.txt .
RUN pip install -r requirements.txt

# 컨테이너 안에 소스 코드 복사
COPY . .

# 장고 사이트가 실행 되기 위해 포트 열기
EXPOSE 8000

# 웹 사이트가 실행 하기 위해 초기 명령어
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]


마지막으로 이 Dockerfile을 빌드 및 Docker 레지스트리에 Push 해준다

# Dockerfile을 사용하여 커스텀 이미지 생성
docker build -t django:v2 ./

# 생성된 이미지 태그 달기
docker tag django:v1 waji97/django:v2

# 태그 된 이미지 레지스트리에 업로드
docker push waji97/django:v2


이제 배포를 위해 매니페스트 YAML 파일을 작성 해야 된다. 파일 안에 먼저 Deployment 리소스를 사용하여 애플리케이션의 Replica을 지정 하고 어떤 이미지를 사용 하여 파드를 실행 시킬지 지정 한다. 그 후 Service 리소스 중 Nodeport 서비스를 사용하여 배포 된 웹 사이트를 접근 할 수 있게 포트 번호를 맞춰 준다. 

# 매니페스트 파일 작성 및 적용을 위해 같은 경로 이동
mkdir myapp
cd myapp

# 매니페스트 파일 생성
vi my-app.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: my-app
          image: waji97/django:v2 			# 방금 업로드한 웹 사이트 이미지
          ports:
            - containerPort: 8000 			
---
apiVersion: v1
kind: Service
metadata:
  name: my-app-service
spec:
  type: NodePort
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8000						

이렇게 YAML파일 지정 후 이 파일을 적용 시킨다

kubectl apply -f my-app.yaml
deployment.apps/my-app created
service/my-app-service created

 

적용 후 생성 되는 Pod, Deployment 그리고 Service를 확인 할 수 있다

# Pod 확인
kubectl get pods
NAME                      READY   STATUS    RESTARTS   AGE
my-app-74dd96c584-9plfb   1/1     Running   0          30s
my-app-74dd96c584-lf97s   1/1     Running   0          30s
my-app-74dd96c584-tvl2n   1/1     Running   0          30s

# Service 확인
kubectl get svc
NAME             TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes       ClusterIP   10.96.0.1        <none>        443/TCP        18d
my-app-service   NodePort    10.110.204.183   <none>        80:30001/TCP   50s   

# Deployment 확인
kubectl get deployment
NAME     READY   UP-TO-DATE   AVAILABLE   AGE
my-app   3/3     3            3           40s

 

이제 결과를 확인 하기 위해 노드 중 아무 IP 주소에 30001 포트로 이동

image.png

웹 사이트 접속이 문제 없이 된다는 걸 확인 할 수 있다.

 

💡 만약에 웹 페이지를 수정 하거나, 새로운 웹 페이지의 이미지가 업로드 될 시, Deployment 리소스 덕분에 업데이트가 쉽게 가능하다. 웹 페이지를 배포한 매니페스트 파일 속에서 내가 원하는 이미지 이름을 수정 후 매니페스트 파일을 다시 적용 시키면 웹 사이트가 자동으로 새로운 이미지에 맞게 바뀐다.

간단한 테스트를 해 보았다

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: my-app
          #image: waji97/django:v2 			# 기존 업로드한 웹 사이트 이미지
          image: waji97/ecommerce:v2  		# 새로 업로드한 웹 사이트 이미지
          ports:
            - containerPort: 8000 			
---
apiVersion: v1
kind: Service
metadata:
  name: my-app-service
spec:
  type: NodePort
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8000						

 

다시 업데이트 된 YAML파일을 적용 시킨다

kubectl apply -f my-app.yaml
deployment.apps/my-app configured
service/my-app-service unchanged

 

적용 후 웹 사이트 방문 결과

image.png

External ETCD (수정 중)

External etcd 구성은 쿠버네티스 클러스터에서 etcd 컴포넌트를 마스터 노드와 분리하여 외부에 배치하는 것을 의미한다.

etcd는 쿠버네티스 클러스터의 상태 정보를 안전하게 저장하기 위한 신뢰성 있는 분산형 키-값 저장소

이미 마스터 노드에 포함 되어 있는 컴포넌트를 따로 분리 하여 별도에 노드에 배치하여 제일 좋은 점은 보안이라고 볼 수 있다. 그 외에도 몇 가지 장점을 표현 한다면:


Etcd 컴포넌트를 마스터 노드에서 분리 하여 배치 하는 작업은 클러스터 생성시 설정을 하면 된다. 이미 Kubespray및 Kubeadm으로 클러스터를 생성 해 보았지만, etcd노드를 분리 하여 해 보지는 않았다. 그래서 이번에는 Kubespray를 통해 쿠버네티스 클러스터를 아래와 같은 구성으로 생성 해 보았다


Kubespray를 통해 클러스터 생성

Kubespray를 통해 쿠버네티스 클러스터 생성 하는 방법은 이미 여기에 정리 해 놓았다. 설정 방법과 진행은 다 동일 하지만 다른 점은 hosts.yml 파일 속 추가 된 내용이다.

vi inventory/mycluster/hosts.yml

all:
  hosts:
    node1:
      ansible_host: 192.168.1.150            # 작업을 실행하기 위해 대상 노드에 연결할 때 사용하는 IP 주소 또는 호스트 이름을 지정하는 필드
      ip: 192.168.1.150
      access_ip: 192.168.1.150
    node2:
      ansible_host: 192.168.1.160
      ip: 192.168.1.160
      access_ip: 192.168.1.160
    node3:
      ansible_host: 192.168.1.170
      ip: 192.168.1.170
      access_ip: 192.168.1.170
    node4:
      ansible_host: 192.168.1.180
      ip: 192.168.1.180
      access_ip: 192.168.1.180
    node5:
      ansible_host: 192.168.1.190
      ip: 192.168.1.190
      access_ip: 192.168.1.190
  children:
    kube_control_plane:						# 마스터 노드 지정 하는 곳
      hosts:
        node1:
        node2:
        node3:
    kube_node:								# 워커 노드 지정 하는 곳
      hosts:
        node4:
    etcd:									# etcd 노드 지정 하는 곳
      hosts:
        node5:
    k8s_cluster:
      children:
        kube_control_plane:
        kube_node:
    calico_rr:
      hosts: {}


이렇게 hosts.yml 파일 수정 후 Kubespray Ansible Playbook을 실행 한다. 아무 문제 없이 완료 되면 결과를 확인 할 수 있다.

image.png


이제 마스터 노드 쪽에서 클러스터 생성 결과를 확인 하기 위해:

 


it is normal that when you use the kubectl get nodes command from your master node, you will not see the etcd nodes included in the output. The kubectl get nodes command provides information about the worker nodes in your cluster, not the etcd nodes.

Etcd nodes are not considered as part of the worker node pool and are typically not included in the output of the kubectl get nodes command. Etcd operates as a separate distributed key-value store that stores the cluster's state and configuration information. It is responsible for providing data persistence and coordination among the control plane components.

Helm 패키지 매니저

Helm은 쿠버네티스 애플리케이션의 생성, 패키징, 구성 및 배포를 자동화하는 도구이다. 구성 파일을 하나로 결합하여 재 사용 가능한 패키지로 만들어 준다.

Microservice 아키텍처에서 애플리케이션이 커짐에 따라 더 많은 microservice를 생성하는 경우 관리가 점점 어려워 진다. 쿠버네티스는 오픈 소스 컨테이너 오케스트레이션 기술로, 여러 microservice를 하나의 배포로 그룹화하여 프로세스를 단순화 한다. 그러나 개발 수명 주기 동안의 쿠버네티스 애플리케이션 관리는 버전 관리, 리소스 할당, 업데이트 및 롤 백과 같은 도전 과제를 동반 한다.

Helm은 이러한 문제에 대한 가장 접근 가능한 해결책 중 하나를 제공하여 배포를 더 일관적이고 반복 가능하며 신뢰할 수 있게 만들어 주었다.

쿠버네티스 관리의 단순화를 위한 Helm 컨테이너는 애플리케이션과 해당 종속성을 단일 이미지 파일로 묶는 경량 소프트웨어 구성 요소이다. 컨테이너는 다양한 플랫폼 간에 이식할 수 있으므로 애플리케이션 시작 시간이 빨라지고 쉬운 확장이 가능 하다.

쿠버네티스는 YAML 구성 파일을 사용하여 배포한다. 그렇기 때문에 자주 업데이트되는 복잡한 배포의 경우 이러한 파일의 다양한 버전을 추적하는 것은 어려울 수 있다. Helm은 단일 배포 YAML 파일에 버전 정보를 유지하는 편리한 도구이다. Helm은 Helm 차트 라는 쿠버네티스 클러스터에 애플리케이션을 배포하기 위해 필요한 모든 리소스를 포함하는 패키지 파일이다. 배포, 서비스, Secrets 및 ConfigMap에 대한 YAML 구성 파일을 포함하여 애플리케이션의 원하는 상태를 정의한다.

Helm 차트는 YAML 파일과 템플릿을 함께 패키징하여 매개 변수화된 값을 기반으로 추가 구성 파일을 생성할 수 있다. 이를 통해 환경에 맞게 구성 파일을 사용자 정의하고 다양한 배포에 재사용 가능한 구성을 만들 수 있다. 또한 각 Helm 차트는 독립적으로 버전 관리되므로 다른 구성을 가진 애플리케이션의 여러 버전을 쉽게 유지할 수 있다.

image.png

Helm 아키텍처는 버전 2와 3 사이에서 크게 개선되었다. 버전 2는 Tiller 서버를 사용하여 Helm 클라이언트와 Kubernetes API 서버 간의 중개를 담당했다. Helm을 클러스터에 설치할 때 Tiller가 필요하며 보안 이슈가 있을 수 있습니다. 그러나 Helm 3에서는 Tiller가 제거되었고 Helm 클라이언트가 직접 Kubernetes API 서버와 상호 작용하도록 변경되었습니다.

image.png

Version 3

image.png


요약하자면, Helm은 쿠버네티스 애플리케이션 관리를 단순화하는 도구입니다. Helm 차트를 사용하여 애플리케이션의 배포, 구성 및 관리를 쉽게 할 수 있습니다. Helm은 YAML 파일로 구성된 리소스를 패키지로 묶어 재사용 가능한 차트를 생성하며, Helm 클라이언트와 라이브러리를 통해 쿠버네티스 클러스터와 상호 작용합니다.


Helm 설치

Helm 설치하기 전, Git 먼저 설치

# Red Hat 계열 
dnf install git

# 우분투 계열
sudo apt install git


Helm 설치 하는 방법은 간단하다. 설치 방법들은 공식 Installation 페이지에서 확인 가능. 

Helm Installation 바로가기

많은 설치 방법들 중에 스크립트로 설치하는 방법으로 진행 하였다

# 설치 스크립트를 가져온 다음 로컬에서 실행 한다
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3

# 스크립트 실행하기 위해 권한 수정
chmod 700 get_helm.sh

# 스크립트 실행
./get_helm.sh

Downloading https://get.helm.sh/helm-v3.12.0-linux-amd64.tar.gz
Verifying checksum... Done.
Preparing to install helm into /usr/local/bin
helm installed into /usr/local/bin/helm

# 버전 확인
helm version
version.BuildInfo{Version:"v3.12.0", GitCommit:"c9f554d75773799f72ceef38c51210f1842a1dea", GitTreeState:"clean", GoVersion:"go1.20.3"}

배포 전략 및 설정

배포 전략

쿠버네티스에서 애플리케이션을 배포할 때, 다양한 배포 전략을 고려하는 것이 중요하다. 이를 통해 어플리케이션의 안정성, 확장성, 사용자 경험 등을 최적화할 수 있다. 아래에서 가장 일반적으로 사용되는 배포 전략 몇 가지를 살펴보겠다.

1. 롤링 업데이트 (Rolling Update)

롤링 업데이트는 새로운 버전의 애플리케이션을 점진적으로 배포하는 전략이다. 이전 버전의 파드들을 점차적으로 새로운 버전으로 교체하면서 서비스의 가용성을 유지 한다. 롤링 업데이트는 다음과 같은 단계로 진행된다.

  1. 새로운 버전의 파드를 클러스터에 추가한다.
  2. 서비스의 로드밸런서를 통해 새로운 파드들에 트래픽을 점진적으로 라우팅 한다.
  3. 이전 버전의 파드들을 하나씩 제거하면서 새로운 버전의 파드로 교체 한다.

롤링 업데이트는 배포 과정 중에 중단 없이 서비스를 계속 제공할 수 있으며, 문제가 발생한 경우 롤백도 쉽게 수행할 수 있다.

2. 블루-그린 배포 (Blue-Green Deployment)

블루-그린 배포는 새로운 버전의 애플리케이션을 기존 버전과 완전히 분리된 환경에서 배포하고, 완전히 검증된 후에 트래픽을 전환하는 전략이다. 다음은 블루-그린 배포의 단계다:

  1. 블루 환경에 현재 운영 중인 애플리케이션 버전을 배포한다.
  2. 그린 환경에 새로운 버전의 애플리케이션을 배포하고 테스트 한다.
  3. 테스트가 성공적으로 완료되면 로드밸런서를 이용하여 트래픽을 블루에서 그린으로 전환 한다.
  4. 그린 환경에서 정상적으로 동작하는지 확인한 후, 필요에 따라 블루 환경을 제거 한다.

블루-그린 배포는 롤백 시에도 용이하며, 사용자에게 거의 무감각한 배포를 제공할 수 있다. 하지만 추가 인프라 자원이 필요하며, 배포 시간도 더 오래 걸릴 수 있다.

3. 카나리아 배포 (Canary Deployment)

카나리아 배포는 새로운 버전의 애플리케이션을 일부 사용자 또는 트래픽의 일부에게 노출시켜서 테스트하고, 성능 및 안정성을 확인한 후에 전체로 확장하는 전략 이다. 아래는 카나리아 배포의 주요 단계들이다:

  1. 새로운 버전의 애플리케이션을 일부 파드로 배포 한다.
  2. 로드밸런서를 통해 일부 사용자 또는 일부 트래픽을 새로운 버전의 파드로 라우팅 한다.
  3. 새로운 버전의 파드들에서 성능 및 안정성을 모니터링하고 평가 한다.
  4. 테스트가 성공적으로 완료되면 나머지 파드들에 새로운 버전을 배포하고, 모든 트래픽을 새로운 버전으로 전환 한다.

카나리아 배포는 배포 전략의 일부분을 선택적으로 테스트할 수 있는 유연성을 제공하며, 더 많은 피드백과 데이터를 수집할 수 있다. 그러나 추가적인 관리 비용이 발생하며, 배포 프로세스가 복잡해질 수 있다.

배포 설정

쿠버네티스 에서 애플리케이션을 배포하기 위해서는 몇 가지 기본 설정이 필요하다. 아래는 일반적으로 사용되는 배포 설정의 예시들이다.

1. Pod 정의

애플리케이션의 실행을 담당하는 파드를 정의해야 한다. 이를 위해 Pod의 설정 파일을 작성하고, 컨테이너 이미지, 리소스 요구사항, 환경 변수, 포트 포워딩 등을 설정해야 한다.

2. 서비스 정의

애플리케이션에 접근하기 위한 서비스를 정의해야 한다. 서비스는 파드 집합에 대한 로드밸런싱을 처리하고, 네트워크 연결을 제공한다. 클러스터 내부 또는 외부에서 접근 가능한 엔드포인트를 설정할 수 있다.

3. 볼륨 및 볼륨 클레임 정의

애플리케이션에서 사용하는 데이터를 보존하기 위해 볼륨과 볼륨 클레임을 정의해야 한다. 이를 통해 데이터의 지속성과 공유를 보장할 수 있다.

4. 배포 및 스케일링 설정

애플리케이션의 배포 전략을 선택하고 설정해야 한다. 롤링 업데이트, 블루-그린 배포, 카나리아 배포 등의 전략을 적용할 수 있으며, 파드 의 수를 조정하여 스케일링할 수도 있다.

5. 모니터링 및 로깅 설정

애플리케이션의 모니터링과 로깅 을 위한 설정을 추가해야 한다. 이를 통해 애플리케이션의 상태를 추적하고, 문제를 진단하고 해결할 수 있다. 예를 들어 Prometheus, Grafana, ELK 스택 등의 도구를 활용할 수 있다.

6. 보안 설정

애플리케이션에 대한 보안 설정을 추가해야 한다. 인증, 권한 부여, 네트워크 정책 등을 구성하여 애플리케이션의 안전성을 강화할 수 있다.

이는 일반적인 설정 예시일 뿐이며, 실제 애플리케이션의 요구 사항에 따라 설정이 달라질 수 있다

노드 관리

쿠버네티스에서 노드는 클러스터의 실행 환경으로서 컨테이너화된 애플리케이션을 실행하는 물리적인 또는 가상의 서버이다. 노드 관리는 클러스터의 성능, 안정성 및 가용성을 유지하는 데 중요한 역할을 한다.

1. 노드 추가 및 제거

쿠버네티스에서는 클러스터에 노드를 추가하거나 제거할 수 있다. 새로운 노드를 추가하면 클러스터의 자원 용량이 증가하고 애플리케이션의 수평 확장이 가능해진다. 노드를 제거할 때는 해당 노드에서 실행 중인 파드를 안전하게 이동시키고 클러스터의 자원 사용을 최적화해야 한다.

2. 노드 상태 모니터링

쿠버네티스는 노드의 상태를 지속적으로 모니터링하여 노드의 가용성을 확인 한다. 노드가 정상 상태인지 여부를 확인하고, 필요한 경우 노드의 비정상적인 동작을 감지하고 조치 한다. 이를 통해 클러스터는 노드 장애에 대응하고 애플리케이션의 지속적인 가용성을 유지할 수 있다.

3. 노드 레이블링

쿠버네티스에서는 노드에 레이블을 지정하여 특정 속성이나 기능을 가진 노드를 식별할 수 있다. 노드 레이블은 노드 선택, 파드 스케줄링, 네트워크 정책 등과 같은 다양한 용도로 활용될 수 있다. 이를 통해 애플리케이션을 특정 노드에 배치하거나 특정 노드에서 실행되는 파드 간의 통신을 제어할 수 있다.

4. 노드 업그레이드

쿠버네티스에서는 노드의 운영체제, 컨테이너 런타임, 커널 등을 업그레이드할 수 있다. 노드 업그레이드는 애플리케이션의 가용성을 유지하기 위해 롤링 업데이트 전략을 사용하여 점진적으로 업그레이드를 수행 한다. 이를 통해 클러스터의 노드를 최신 버전으로 유지하고 보안 패치를 적용할 수 있다.

 

//Cron과 Drain?

https://arisu1000.tistory.com/27845

리소스 관리

  1. 라벨링과 애노테이션

모니터링과 로깅

  1. 메트릭 수집
  2. 로그 관리

스케일링 및 롤링 업데이트

쿠버네티스는 애플리케이션의 수평 스케일링과 롤링 업데이트를 지원하여 애플리케이션의 성능 향상과 지속적인 개선을 가능하게 한다. 이를 통해 애플리케이션을 더욱 확장 가능하고 안정적으로 운영할 수 있다. 

1. 수평 스케일링

쿠버네티스는 파드의 수를 동적으로 조정하여 애플리케이션의 수평 스케일링을 지원 한다. 파드 수를 늘리면 애플리케이션의 처리량과 부하 분산이 증가하며, 반대로 파드 수를 줄이면 자원 사용량을 최적화할 수 있다. 이를 통해 애플리케이션의 성능을 향상시킬 수 있다.

2. 롤링 업데이트

롤링 업데이트는 애플리케이션의 새 버전을 점진적으로 배포하는 과정을 말한다. Kubernetes는 롤링 업데이트를 통해 애플리케이션의 가용성을 유지하면서 새로운 버전으로의 전환을 원활하게 처리한다. 롤링 업데이트는 애플리케이션의 가용성을 유지하면서 시스템의 안정성을 보장한다.

3. 블루-그린 배포

블루-그린 배포는 새로운 버전의 애플리케이션을 별도의 환경에 배포한 후, 기존 버전과 새 버전 사이에서 전환하는 전략이다. 쿠버네티스는 블루-그린 배포를 지원하며, 서비스의 라우팅 설정을 변경하여 전환을 수행한다. 이를 통해 애플리케이션의 변경 사항을 테스트하고 문제가 발생하지 않으면 전환을 완료할 수 있다.

클러스터 업그레이드

kubectl 자동 완성 (수정 중)

쿠버네티스의 자동 완성 기능은 긴 쿠버네티스 리소스 이름을 자동 완성 시킬때 꽤 유용 하다. 

자세한 정보는 

k8s 자동완성 설정

먼저

type _init_completion


명령어를 사용하여 이미 설정이 되어 있는지 부터 확인


안되어 있는 경우:

type _init_completion
-bash: type: _init_completion: not found


설정 하려면:

source /usr/share/bash-completion/bash_completion
[root@main ~]# exec bash

만약에 위 명령어 사용 시 'Not Found' 애러 발생 하면, 먼저 'bash-completion'툴을 설치 하고 다시 진행 해야 한다

RHEL 계열:
dnf install bash-completion

Ubuntu 계열:
apt install bash-completion


설정 후

type _init_completion
_init_completion is a function
_init_completion () 

    local exclude= flag outx errx inx OPTIND=1;
    while getopts "n:e:o:i:s" flag "$@"; do
        case $flag in 
            n)
                exclude+=$OPTARG
            ;;
            e)
                errx=$OPTARG
            ;;
            o)
                outx=$OPTARG
            ;;
            i)
                inx=$OPTARG
            ;;
            s)
                split=false;
                exclude+==
            ;;
        esac;
    done;
    COMPREPLY=();
    local redir="@(?([0-9])<|?([0-9&])>?(>)|>&)";
    _get_comp_words_by_ref -n "$exclude<>&" cur prev words cword;
    _variables && return 1;
    if [[ $cur == $redir* || $prev == $redir ]]; then
        local xspec;
        case $cur in 
            2'>'*)
                xspec=$errx
            ;;
            *'>'*)
                xspec=$outx
            ;;
            *'<'*)
                xspec=$inx
            ;;
            *)
                case $prev in 
                    2'>'*)
                        xspec=$errx
                    ;;
                    *'>'*)
                        xspec=$outx
                    ;;
                    *'<'*)
                        xspec=$inx
                    ;;
                esac
            ;;
        esac;
        cur="${cur##$redir}";
        _filedir $xspec;
        return 1;
    fi;
    local i skip;
    for ((i=1; i < ${#words[@]}; 1))
    do
        if [[ ${words[i]} == $redir* ]]; then
            [[ ${words[i]} == $redir ]] && skip=2 || skip=1;
            words=("${words[@]:0:i}" "${words[@]:i+skip}");
            [[ $i -le $cword ]] && cword=$(( cword - skip ));
        else
            i=$(( ++i ));
        fi;
    done;
    [[ $cword -eq 0 ]] && return 1;
    prev=${words[cword-1]};
    [[ -n ${split-} ]] && _split_longopt && split=true;
    return 0
}


그 후 쿠버네티스 상 자동 완성 설정. 이제 kubectl 자동 완성 스크립트가 모든 셸 세션에서 제공되도록 해야 한다. 이를 수행할 수 있는 두 가지 방법이 있다.

현재 사용자에게 만 설정

echo 'source <(kubectl completion bash)' >>~/.bashrc


모든 사용자에게 설정

ubectl completion bash | sudo tee /etc/bash_completion.d/kubectl > /dev/null
[root@node1 ~]# exec bash
[root@node1 ~]# kubectl get ns 
default          kube-node-lease  kube-public      kube-system      
[root@node1 ~]# kubectl get ns

// 미완성

Bastion에서 Kubectl 쓰기 (수정 중)

References:

Installting Kubectl: https://kubernetes.io/docs/tasks/tools/

curl -LO https://dl.k8s.io/release/v1.24.6/bin/linux/amd64/kubectl
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   138  100   138    0     0    666      0 --:--:-- --:--:-- --:--:--   666
100 43.6M  100 43.6M    0     0  21.0M      0  0:00:02  0:00:02 --:--:-- 29.6M

ls
kubectl  kubespray  kubesprayv2.20  original-ks.cfg

curl -LO https://dl.k8s.io/release/v1.24.6/bin/linux/amd64/kubectl.sha256
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   138  100   138    0     0    650      0 --:--:-- --:--:-- --:--:--   650
100    64  100    64    0     0    122      0 --:--:-- --:--:-- --:--:--   122

ls
kubectl  kubectl.sha256  kubespray  kubesprayv2.20  original-ks.cfg

echo "$(cat kubectl.sha256)  kubectl" | sha256sum --check
kubectl: OK

sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

kubectl version --client
WARNING: This version information is deprecated and will be replaced with the output from kubectl version --short.  Use --output=yaml|json to get the full version.
Client Version: version.Info{Major:"1", Minor:"24", GitVersion:"v1.24.6", GitCommit:"b39bf148cd654599a52e867485c02c4f9d28b312", GitTreeState:"clean", BuildDate:"2022-09-21T13:19:24Z", GoVersion:"go1.18.6", Compiler:"gc", Platform:"linux/amd64"}
Kustomize Version: v4.5.4

# Master노드에 있는 '.kube/config' 파일을 복붙
mkdir .kube
cd .kube
vi config

# 그대로 복붙 하면 안됨, 왜냐면 거기에서는 로컬 호스트로 지정 되어 있음
kubectl get nodes
The connection to the server 127.0.0.1:6443 was refused - did you specify the right host or port?

# 그래서 5번째 줄에서 서버 IP를 Master노드 IP로 지정
vi config
server: https://192.168.122.8:6443


kubectl get nodes
NAME    STATUS   ROLES           AGE   VERSION
node1   Ready    control-plane   13d   v1.24.6
node2   Ready    <none>          13d   v1.24.6
node3   Ready    <none>          13d   v1.24.6