상세 컨텐츠

본문 제목

kubernetes 설치 [CentOS 9/v1.27.4]

Kubernetes/Install

by 걸어서뉴욕까지 2023. 8. 5. 09:41

본문

구성 환경

  • k8s 버전 : 1.27.4
  • OS 버전 : CentOS-Stream-Release-9.0.21.el9.noarch
  • CRI : containerd github.com/containerd/containerd v1.7.1
  • CNI : Calico
  • kube-proxy mode : ipvs

 

Prerequisites

  • CPU 2 코어 이상
  • Memory 2 GB 이상 권장 (2 GB 보다 작을 시 Application을 위한 공간이 없음)
  • 노드 간 Network 연결에 이상 無
  • k8s에서 사용하는 port 개방 [k8s Ports and Protocols]
  • calico에서 사용하는 port 개방 [Calico Ports]
  • firewalld에 calico pod ip 대역 및 kube-dns port 개방
더보기

※ zone은 사용중이신걸로 변경

 

kubernetes ports

# Control Plane
firewall-cmd --permanent --zone=public --add-port=6443/tcp
firewall-cmd --permanent --zone=public --add-port=2379-2380/tcp
firewall-cmd --permanent --zone=public --add-port=10250/tcp
firewall-cmd --permanent --zone=public --add-port=10259/tcp
firewall-cmd --permanent --zone=public --add-port=10257/tcp

 

# Worker Node
firewall-cmd --permanent --zone=public --add-port=10250/tcp
firewall-cmd --permanent --zone=public --add-port=30000-32726/tcp

 

※ kube-apiserver (443 open)

 

Calico Ports

# Control Plane

firewall-cmd --permanent --zone=public --add-port=179/tcp
firewall-cmd --permanent --zone=public --add-port=2379/tcp
firewall-cmd --permanent --zone=public --add-port=5473/tcp
firewall-cmd --permanent --zone=public --add-port=4789/udp
firewall-cmd --permanent --zone=public --add-port=51820-51821/udp

 

# Worker Node
firewall-cmd --permanent --zone=public --add-port=179/tcp

firewall-cmd --permanent --zone=public --add-port=5473/tcp

firewall-cmd --permanent --zone=public --add-port=4789/udp

firewall-cmd --permanent --zone=public --add-port=51820-51821/udp

 

firewalld

# Worker Node

firewall-cmd --permanent --zone=public --add-source=192.168.0.0/16

firewall-cmd --permanent --zone=public --add-port=53/udp

firewall-cmd --permanent --zone=public --add-port=53/tcp

firewall-cmd --permanent --zone=public --add-port=9153/tcp

 

노드별 hostname 설정

마스터 노드에서 hostnamectl을 사용하여 hostname을 설정

sudo hostnamectl set-hostname control01
sudo exec bash

나머지 워커 노드에서도 동일하게 작업

sudo hostnamectl set-hostname worker01        # 1st worker
sudo hostnamectl set-hostname worker02        # 2nd worker
exec bash

/etc/hosts에 각 노드들을 추가

10.0.163.1    kubemaster01    control01
10.0.163.2    kubeworker01    worker01
10.0.163.3    kubeworker02    worker02

 

스왑 Disable

kubelet이 정상 작동하기 위해서는 반드시 스왑을 사용하지 않도록 설정해줘야 한다.

# swap off
sudo swapoff -a

# /etc/fstab의 모든 라인에 주석 추가
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab	# /etc/fstab 파일을 열어서 /dev/mapper/cs-swap을 주석처리해도 무방하다

 

SELinux 설정 변경

# SELinux permissive로 설정
setenforce 0

# 확인
sestatus

... 중략 ...

Current mode:              permissive
Mode from config file:     permissive


# config 파일에서 permissive로 변경
vi /etc/selinux/config

# SELINUX 값을 permissive로 변경

... 중략 ...

SELINUX=permissive

...

 

커널 모듈 로딩 설정

Containerd를 사용할 것임으로 containerd.conf에 overlay와 br_netfilter 모듈 정보를 등록합니다.

sudo tee /etc/modules-load.d/containerd.conf <<EOF
overlay
br_netfilter
EOF

sudo modprobe overlay            # overlay
sudo modprobe br_netfilter        # kubernetes pod 간의 VxLAN Protocol 통신과 masquerading을 위해

OverLay Network / Masquerading

 

커널 파라미터 설정

kubernetes에서 bridge를 통과하는 패킷이 iptables로 전송될지에 대한 설정 (on == 1)

sudo tee /etc/sysctl.d/kubernetes.conf <<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF

변경 사항 Reload

sudo sysctl --system

 

Container runtime 설치

해당 포스트에서는 containerd를 사용합니다. containerd 설치는 아래 글을 참고해주세요.

[Linux] - Containerd 설치

 

Containerd systemd cgroup driver 설정

kubernetes v1.22 이상에서는 cgroup driver를 default로 systemd를 사용하도록 코드가 변경되었기 때문에 systemd를 cgroup driver로 사용할 수 있도록 containerd 설정을 변경을 해줘야 합니다. /etc/containerd/config.toml 파일을 열어서 아래와 같이 SystemdCgroup을 true로 설정해줍니다.

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
  ...
  [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
    SystemdCgroup = true

변경 후 containerd를 restart 해줍니다.

systemctl restart containerd

 

kubeadm, kubelet, kubectl 설치

Control Plane과 Worker Node에 모두 설치한다.

  • kubeadm : k8s 클러스터 구성을 위한 bootstrap
  • kubelet    : k8s 클러스터의 각 노드들에서 실행되는 Agent로 Control Plane에서 작업을 요청하면 Work의 kubelet이 컨테이너가 pod에서 실행될 수 있게 해줍니다.
  • kubectl    : command line에서 사용하는 cluster 유틸 프로그램
# kubernetes.io document 발췌

cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-\$basearch
enabled=1
gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl
EOF

# permissive 모드로 SELinux 설정(효과적으로 비활성화)
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes

sudo systemctl enable --now kubelet

 

Control-Plane 초기화

설치한 kubeadm을 이용하여 control-plane을 초기화한다, 초기화시 kube-apiserver와 control plane의 endpoint 그리고 calico 사용을 위한 pod network cidr 값을 설정해준다.

# control plane 초기화
kubeadm init --apiserver-advertise-address=10.0.163.1 --control-plane-endpoint=control01 --pod-network-cidr=192.168.0.0/16

# 정상 설치 완료 시 아래와 같이 config 설정과 관련된 메세지와
# control-plane 혹은 work로 편입되기 위한 명령어가 나온다


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

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

You can now join any number of machines by running the following on each node
as root:

  kubeadm join <control-plane-host>:<control-plane-port> --token <token> --discovery-token-ca-cert-hash sha256:<hash>

※ 위와 같이 성공 메세지와 추가로 설정들에 대한 메세지가 나왔다면, 메세지 內 mkdir 부터 chown까지의 작업을 진행해, 특정 사용자 계정에서 kubectl을 사용할 수 있도록 설정해줍니다.

 

위 설정을 모두 진행했다면 아래 명령어를 실행해 node의 상태와 kube-system의 pod를 확인해봅니다.

# ===================================================================
# node 확인
# ===================================================================
kubectl get nodes

NAME        STATUS     ROLES           AGE     VERSION
control01   NotReady   control-plane   14s     v1.27.4


# ===================================================================
# kube-system pod 확인
# ===================================================================
kubectl get pod -n kube-system

NAME                                READY   STATUS              RESTARTS        AGE
coredns-5d78c9869d-l7gwc            0/1     ContainerCreating   0               14s
etcd-control01                      1/1     Running             0               13s
kube-apiserver-control01            1/1     Running             0               13s
kube-controller-manager-control01   1/1     Running             0               14s
kube-proxy-8rcfl                    1/1     Running             0               14s
kube-scheduler-control01            1/1     Running             0               14s

※ 위와 같이 node의 상태가 NotReady로, kube-system 아래의 pod가 coredns를 제외하고 Running이면 정상입니다.

클러스터 DNS(coredns는 CNI 기반 네트워크가 설치되기 전에는 시작되지 않습니다. calico나 flannel등을 설치후 Running으로 상태가 변경됩니다.)

 

Work Join

초기화시 나타난 메세지를 이용하여 k8s 클러스터에 worker node를 편입시킵니다.

# ===================================================================
# kubernetes cluster에 worker node 편입
# ===================================================================
kubeadm join control01:6443 --token xxxxxx.xxxxxxxxxxxx        --discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


# ===================================================================
# kubernetes node 확인
# ===================================================================
NAME        STATUS     ROLES           AGE   VERSION
worker01    NotReady   <none>          11m   v1.27.4
control01   NotReady   control-plane   10m   v1.27.4

cni를 설치하지 않고 클러스터를 구성할 시 위 처럼 워커 노드가 NotReady로 되어있는것을 볼 수 있는데, 에러 내용은 아래와 같이 확인이 가능하다.

# ===================================================================
# kubernetes node 확인
# ===================================================================
kubectl describe node worker01

... 중략 ...
Conditions:
Ready        False     ... 중략 ...
KubeletNotReady        container runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: cni plugin not initialized

# ===================================================================
# 노드의 kubelet에서도 위와 동일한 에러를 확인할 수 있습니다.
# ===================================================================
journalctl -u kubelet --no-page -f

... 중략 ...
... err="network is not ready: container runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: cni plugin not initialized"

CNI가 설치되어있지 않아 kubelet에서 network plugin을 초기화 할 수 없다는 에러가 발생하고 있는것을 볼 수 있다.

 

Control Plane의 coreDns 그리고 worker의 Ready상태를 위해서 CNI를 설치한다. 해당 포스팅에서는 Calico를 사용합니다. 그외 다른 CNI를 사용하셔도 무방합니다. (다만 각각의 플러그인에 맞는 클러스터 초기화를 진행해주세요)

 

Calico install

calico 설치는 아래 페이지의 메니페스트들을 적용해주면 됩니다. 설치 과정이 모두 해당 페이지에 있으므로 해당 글에 추가로 적어두지는 않겠습니다.

 

Install Calico networking and network policy for on-premises deployments | Calico Documentation

Install Calico networking and network policy for on-premises deployments.

docs.tigera.io

 

Node와 Pod 상태 확인

CNI를 설치했다면 각 Node들의 상태가 Ready가 되어야하고 kube-system에 있는 coredns도 Running 상태로 변경되어야 한다. 또한 calico-system에 있는 pod들 또한 정상적으로 Running 상태가 되어있어야 합니다.

# ===================================================================
# kubernetes node 확인
# ===================================================================
kubectl get nodes

NAME        STATUS   ROLES           AGE     VERSION
worker01    Ready    <none>          12m     v1.27.4
worker02    Ready    <none>          9m25s   v1.27.4
control01   Ready    control-plane   13m     v1.27.4

# ===================================================================
# kube-system namespace 확인
# ===================================================================
kubectl get pod -n kube-system

NAME                                READY   STATUS    RESTARTS   AGE
coredns-5d78c9869d-cd5nr            1/1     Running   0          14m
coredns-5d78c9869d-lxbq7            1/1     Running   0          14m
etcd-psnname01                      1/1     Running   0          15m
kube-apiserver-psnname01            1/1     Running   0          15m
kube-controller-manager-psnname01   1/1     Running   0          15m
kube-proxy-2nq7t                    1/1     Running   0          14m
kube-proxy-cb5dn                    1/1     Running   0          13m
kube-proxy-vn9sz                    1/1     Running   0          10m
kube-scheduler-psnname01            1/1     Running   0          15m


# ===================================================================
# calico-system namespace 확인
# ===================================================================
kubectl get pod -n calico-system

NAME                                      READY   STATUS    RESTARTS   AGE
calico-kube-controllers-5cbf7d5df-r7ldh   1/1     Running   0          13m
calico-node-hhfbb                         1/1     Running   0          13m
calico-node-j66vz                         1/1     Running   0          11m
calico-node-v5b24                         1/1     Running   0          13m
calico-typha-547447d4b8-48dt5             1/1     Running   0          11m
calico-typha-547447d4b8-bb9xp             1/1     Running   0          13m
csi-node-driver-bpx89                     2/2     Running   0          11m
csi-node-driver-kzh7n                     2/2     Running   0          13m
csi-node-driver-t7lkr                     2/2     Running   0          13m

 

kube-proxy mode 설정

해당 포스트에서는 kube-proxy의 mode를 ipvs를 사용하도록 설정할 것이다.

kube-system의 kube-proxy configmap의 mode를 ipvs로 변경해주고, kube-proxy를 재생성해주도록 하자.

# ===================================================================
# kube-proxy mode 변경
# ===================================================================
kubectl edit cm -n kube-system kube-proxy

apiVersion: v1
data:
  config.conf: |-
    apiVersion: kubeproxy.config.k8s.io/v1alpha1
    bindAddress: 0.0.0.0
    bindAddressHardFail: false
    
    ... 중략 ...
    
      tcpFinTimeout: 0s
      tcpTimeout: 0s
      udpTimeout: 0s
    kind: KubeProxyConfiguration
    metricsBindAddress: ""
    mode: "ipvs"

# ===================================================================
# kube-proxy pod 삭제
# ===================================================================
kubectl get pod -n kube-system | grep kube-proxy | awk '{system("kubectl delete pod "$1" -n kube-system")}'

# ===================================================================
# 변경된 kube-proxy mode 확인
# ===================================================================
kubectl logs -n kube-system kube-proxy-8z6ck

... 중략 ...
I0821 13:27:42.896249       1 server_others.go:265] "Using ipvs Proxier"


# ===================================================================
# ipvs 확인
# ===================================================================
ipvsadm -Ln

IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.96.0.1:443 rr
  -> 10.0.20.2:6443               Masq    1      0          0
TCP  10.96.0.10:53 rr
  -> 192.168.191.194:53           Masq    1      0          0
  -> 192.168.191.195:53           Masq    1      0          0
TCP  10.96.0.10:9153 rr
  -> 192.168.191.194:9153         Masq    1      0          0
  -> 192.168.191.195:9153         Masq    1      0          0
TCP  10.100.48.129:443 rr
  -> 192.168.191.197:5443         Masq    1      0          0
  -> 192.168.241.130:5443         Masq    1      0          0

 

테스트 pod 생성

테스트용 pod로 nginx pod를 아래를 참고하여 하나 생성해봅니다.

아래 내용을 텍스트 파일로 생성 후 kubectl apply -f [파일 이름]으로 pod를 생성합니다.

apiVersion: v1
kind: Pod
metadata:
  name: my-first-pod
spec:
  containers:
  - name: my-nginx-container
    image: nginx:latest
    ports:
    - containerPort: 80
      protocol: TCP

특정 namespace를 명시하지 않았음으로 kubectl get pod 명령어를 통해 생성된 pod를 확인합니다.

# ===================================================================
# 생성된 pod 확인
# ===================================================================
kubectl get pod

NAME           READY   STATUS    RESTARTS   AGE
my-first-pod   1/1     Running   0          4m8s