RHEL 8 Kubernetes v1.32 설치 및 트러블 슈팅하기

Kubernetes는 여러 개의 컨테이너를 효율적으로 관리하고, 배포를 자동화하는 오케스트레이션 플랫폼이다.

RHEL 8 환경에서 Kubernetes v1.32 버전을 기준으로, Kubernetes의 주요 컴포넌트를 설치하여 클러스터를 구성하는 방법과 설치 과정 중 발생할 수 있는 트러블슈팅을 정리했다.

 

쿠버네티스 주요 컴포넌트

  • kubectl: 클러스터 관리하는 명령어 도구
  • kubeadm: 클러스터 설정 도구. (kubeadm) → 프로세스
  • kubelet: 클러스터의 모든 서버에서 실행되는 프로세스. 파드(pod)와 컨테이너 실행/관리한다. → 사용자의 명령어를 실행하는 프로세스

 

 

 

 

설치 환경

  • AMI: RHEL 8.6(RHEL-8.6.0_HVM-20230301-x86_64-0-Hourly2-GP2)
  • 기본 설정: SELinux disabled, Firewalld 미설치된 상태
  • 계정: root

 

RHEL 8 기본 패키지 명령어는 dnf이지만, yum 또는 dnf 명령을 모두 사용할 수 있다.

yum은 dnf에 소프트 링크되어 있으며 RHEL 8에서 이전 버전과의 호환성을 위해 유지된다.

 

 

 

 

 

설치할 Kubernetes 버전 및 조건 확인

쿠버네티스 1.20 버전 부터 컨테이너 런타임을 dockershim 대신 containerd을 컨테이너 런타임 엔진으로 사용한다.

 

 

컨트롤 플레인, 워커 노드 동일하게 설정한다.

 

 

 

 

사전 설정

 

 

 

방화벽 비활성화

systemctl status firewalld
systemctl disable firewalld

 

 

커널 버전 업데이트

dnf update kernel 명령어 입력 시, 기본 레포지토리에서 공식 지원하는 커널 버전(4.18.x) 내에서만 업데이트가 이루어진다. (4.18.0-372.46.1.el8_6.x86_64 → 4.18.0-553.32.1.el8_10.x86_64)

따라서, 5.18 이상으로 업데이트하려면 최신 커널을 지원하는 패키지를 설치하는 별도 작업이 필요하다.

# 커널 버전 확인
uname -r
# 4.18.0-372.46.1.el8_6.x86_64 출력 확인

dnf update kernel
# 4.18.0-553.32.1.el8_10.x86_64 출력 확인

 

 

 

트러블 슈팅

This system is not registered with an entitlement server. You can use subscription-manager to register. 라는 메시지가 뜨면, vi /etc/yum/pluginconf.d/subscription-manager.conf 파일을 수정하여 저장소 접근을 해제한다.

Red Hat에서는 소프트웨어 업데이트/패키지 설치 유료 서비스인 “Red Hat Subscription”을 제공한다.

subscription-manager 파일은 시스템이 레드햇 구독을 관리하고 유료 패키지 저장소에 접근할 수 있도록 인증하는 설정 파일이다.

구독을 하고 있지 않기 때문에 subsciption-manager를 비활성화 설정한다.

# AS-IS
[main]
enabled=1

# When following option is set to 1, then all repositories defined outside redhat.repo will be disabled
# every time subscription-manager plugin is triggered by dnf or yum
disable_system_repos=0

# TO-BE
[main]
enabled=0

# When following option is set to 1, then all repositories defined outside redhat.repo will be disabled
# every time subscription-manager plugin is triggered by dnf or yum
disable_system_repos=0

 

 

 

 

ELRepo를 이용한 yum(kernel 5.x) 설치

# ELRepo (GPG key) 공개키 가져오기
rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org

# ELRepo 설치
yum install https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm -y

# yum kernel 5.x 설치
yum --enablerepo=elrepo-kernel install kernel-ml -y

# 재부팅하여 커널 버전 반영
reboot

# 커널 버전 확인
uname -r
# 6.12.5-1.el8.elrepo.x86_64 출력 확인

 

 

 

cgroup v2 활성화 확인

# cgroup2 이 있는지 확인
ls -lart /sys/fs/cgroup | grep controllers

# cgroup2 값이 없으면
# 부트 로더 설정 파일 편집
vi /etc/default/grub
## GRUB_CMDLINE_LINUX 변수에 "systemd.unified_cgroup_hierarchy=1" 값 추가

# 부트 로더 설정 파일 업데이트
grub2-mkconfig -o /boot/grub2/grub.cfg

# 변경사항 반영
reboot

# cgroup2 활성화 확인
stat -fc %T /sys/fs/cgroup/

 

 

 

 

 

 

트러블 슈팅

CGROUPS_CPUSET: missing , missing required cgroups: cpuset cgroup 미활성화 시, cgroup v2 활성화하거나 cpuset 모듈을 로드해야 한다.

cgroup (Control Group)은 리눅스에서 프로세스들이 사용하는 리소스(CPU, 메모리)를 제어/제한하는 기술이다.

쿠버네티스에서 컨테이너는 독립적인 환경에서 실행되므로, 리소스를 제한/격리되도록 관리하기 위해 하나의 통합 설정으로 리소스를 관리하는 cgroup v2를 사용한다.

 

 

 

 

 

 

/etc/default/grub 수정 확인

/etc/default/grub: GRUB 부트 로더 설정 파일. GRUB은 리눅스가 부팅할 때 커널에 전달할 옵션을 설정하는 파일

 

Output:

# AS-IS
GRUB_CMDLINE_LINUX="console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto"
GRUB_TIMEOUT=0
GRUB_ENABLE_BLSCFG=true
GRUB_DEFAULT=saved

# TO-BE
GRUB_CMDLINE_LINUX="console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto systemd.unified_cgroup_hierarchy=1"
GRUB_TIMEOUT=0
GRUB_ENABLE_BLSCFG=true
GRUB_DEFAULT=saved

 

 

 

 

 

kubeadm, kubelet, kubectl 설치

# 스왑 비활성화 확인
swapon --show
## 아무것도 출력되지 않으면, 스왑 비활성화

## 스왑 설정이 되어 있으면,
swapoff -a
sed -i '/swap/s/^/#/' /etc/fstab

# 쿠버네티스 레포지토리 추가
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.32/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.32/rpm/repodata/repomd.xml.key
exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni
EOF

# kubelet, kubeadm, kubectl 설치
yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes

 

 

 

 

트러블 슈팅

Kubernetes 레포지토리 설정

Errors during downloading metadata for repository ‘kubernetes’: Status code: 404 for https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64/repodata/repomd.xml (IP: 142.251.220.14) 쿠버네티스 레포지토리를 찾을 수 없어서 yum 패키지로 설치 불가한 에러 발생 시,

vi /etc/yum.repos.d/kubernetes.repo

# TO-BE
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.32/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.32/rpm/repodata/repomd.xml.key
exclude=kubelet kubectl cri-tools kubernetes-cni
# 변경된 레포지토리 반영
yum clean all
yum makecache

 

 

 

 

 

IP 포워딩 활성화 확인

/proc/sys/net/ipv4/ip_forward: IP 포워딩 설정 파일

IP 포워딩이란, 서버가 한 네트워크에서 받은 데이터를 다른 네트워크로 전달하는 기능(라우팅 기능)이다.

쿠버네티스 클러스터에서 파드 간 통신, CNI 구성, 노드 간 통신 및 서비스 접근(LoadBalancer, NodePort)을 하기 위해 필요하다.

# IP 포워딩 활성화 확인
cat <<EOF | tee /etc/sysctl.d/k8s.conf
net.ipv4.ip_forward = 1
EOF
## 활성화 되어 있지 않으면,
# 커널 파라미터 재적용
sysctl --system

# IPv4 패킷 포워딩을 활성화
echo '1' > /proc/sys/net/ipv4/ip_forward

# 적용 여부 확인
cat /proc/sys/net/ipv4/ip_forward
# 1 출력 확인

# 0이 출력 된다면
sysctl -p

# 커널 파라미터 재적용

# 설정 적용 확인
cat /proc/sys/net/ipv4/ip_forward

 

 

 

 

 

쉘 자동완성 활성화(bash-completion) 설치

명령어를 k로 단축하여 사용하고 명령어를 자동 완성하기 위해 bash completion을 설치한다.

# Bash Completion 설치
dnf install bash-completion -y

# .bashrc 파일에 자동 완성 설정 추가
cat <<EOF >> ~/.bashrc
source /usr/share/bash-completion/bash_completion
source <(kubectl completion bash)
alias k=kubectl
complete -o default -F __start_kubectl k
EOF

# 설정 적용
source ~/.bashrc

# 적용 확인
type _init_completion

 

 

 

 

 

~/.bashrc 설정 적용 확인

Output:

# AS-IS
# .bashrc

# User specific aliases and functions

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

# TO-BE
# .bashrc

# User specific aliases and functions

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

# Source global definitions
if [ -f /etc/bashrc ]; then
    . /etc/bashrc
fi
source /usr/share/bash-completion/bash_completion
source <(kubectl completion bash)
alias k=kubectl
complete -o default -F __start_kubectl k

 

 

 

 

 

Control Plane 구성

클러스터 구성

kubeadm init 명령어로 클러스터를 구성하면 api, controller, scheuler, etcd, coreDNS 컴포넌트들이 구성된다.

# API 서버 지정하여 초기화
kubeadm init --apiserver-advertise-address=[마스터 노드 IP 주소]
# 예:
kubeadm init --apiserver-advertise-address=10.0.2.173 --pod-network-cidr=10.10.0.0/24

export KUBECONFIG=/etc/kubernetes/admin.conf
echo $KUBECONFIG

 

 

 

--pod-network-cidr 옵션

--pod-network-cidr옵션은 쿠버네티스 클러스터 내에서 사용될 파드의 네트워크의 가상 IP 대역을 설정하는 옵션이다.

클러스터의 실제 네트워크 서브넷과 겹치지 않는 다른 IP 대역을 지정하여 클러스터의 실제 서브넷과 겹치지 않도록 해야한다.

 

또한, 보안 그룹에서 인바운드 규칙을 설정하여, 파드 네트워크 대역에 대한 접근을 허용 설정한다.

 

 

 

출력 확인

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 10.0.2.173:6443 --token h77qar.almhn5cx82cjlrjs \
    --discovery-token-ca-cert-hash sha256:fc7954bcd8d206fedbf00684019e828cb4869d769ecfb25579eddb6995d6f497

 

 

 

 

트러블 슈팅

validate CRI v1 runtime API for endpoint API 통신 에러가 뜨면, API 서버의 IP 주소를 지정한다. 마스터 노드 IP 주소를 지정하지 않으면 컨트롤 플레인을 인지하지 못해서 API 서버를 바인딩할 수 없는 문제가 생길 수 있다.

--apiserver-advertise-address 옵션으로 API 서버(마스터 노드)의 IP 주소를 명시적으로 지정해야 API 서버를 인식하고 다른 노드와 통신할 수 있다.

6443번 포트(kubernetes api server) 열려 있는지 확인

[root@ip-10-0-2-173 ~]# netstat -antup | grep 6443
tcp        0      0 10.0.2.173:48676        10.0.2.173:6443         ESTABLISHED 26954/kubelet
tcp        0      0 10.0.2.173:41248        10.0.2.173:6443         TIME_WAIT   -
tcp        0      0 10.0.2.173:53950        10.0.2.173:6443         ESTABLISHED 26954/kubelet
tcp6       0      0 :::6443                 :::*                    LISTEN      45996/kube-apiserve
tcp6       0      0 10.0.2.173:6443         10.0.2.173:41236        TIME_WAIT   -
tcp6       0      0 10.0.2.173:6443         10.0.2.173:53950        ESTABLISHED 45996/kube-apiserve
tcp6       0      0 ::1:6443                ::1:44144               ESTABLISHED 45996/kube-apiserve
tcp6       0      0 10.0.2.173:6443         10.0.2.173:48676        ESTABLISHED 45996/kube-apiserve
tcp6       0      0 10.0.2.173:6443         10.0.2.173:57726        TIME_WAIT   -
tcp6       0      0 10.0.2.173:6443         10.0.2.173:57714        TIME_WAIT   -
tcp6       0      0 10.0.2.173:6443         10.0.2.173:34982        TIME_WAIT   -
tcp6       0      0 10.0.2.173:6443         10.0.2.173:57734        TIME_WAIT   -
tcp6       0      0 10.0.2.173:6443         10.0.2.173:57702        TIME_WAIT   -
tcp6       0      0 ::1:44144               ::1:6443                ESTABLISHED 45996/kube-apiserve

 

 

 

 

토큰 저장

kubeadm init 실행 후 출력된 kubeadm join 명령어에 포함된 토큰을 저장해둔다.

토큰은 워커 노드를 클러스터에 추가할 때 사용한다.

cat > token.txt
kubeadm join 10.0.2.173:6443 --token qnuac9.29afrel4gn5xh1lm \
    --discovery-token-ca-cert-hash sha256:63c71d76256a46f18e42f9663122c9e2a630e53aad0c4ab26082652830b6be43

 

 

 

 

컨트롤 플레인 노드 정상 구성 확인

[root@ip-10-0-2-173 ~]# kubectl get nodes
NAME                                            STATUS     ROLES           AGE     VERSION
ip-10-0-2-173.ap-northeast-2.compute.internal   NotReady   control-plane   2m42s   v1.32.0

[root@ip-10-0-2-173 ~]# kubectl get nodes
NAME                                            STATUS   ROLES           AGE     VERSION
ip-10-0-2-173.ap-northeast-2.compute.internal   Ready    control-plane   2m43s   v1.32.0

 

 

 

 

 

CRI 플러그인 활성화

Kubernetes 1.26 이상을 사용하려면, containerd를 1.6 이상으로 업그레이드해야 한다.

validate service connection: CRI v1 runtime API is not implemented for endpoint \"unix:///var/run/containerd/containerd.sock\": rpc error: code = Unimplemented desc = unknown service runtime.v1.RuntimeService 에러 시,

containerd 설정 파일(/etc/containerd/config.toml)에서 CRI 플러그인이 비활성화되었는지 확인하고 활성화한다.

# containerd 설정 파일 확인
cat /etc/containerd/config.toml
# disabled_plugin = ["cri"]이 주석처리 되어 있지 않으면,

# 주석 처리
sed -i 's/^disabled_plugins = \["cri"\]/#disabled_plugins = \["cri"\]/' /etc/containerd/config.toml

# containerd 재시작하여 변경사항 반영
systemctl restart containerd

 

 

 

 

 

/etc/containerd/config.toml 수정 내용 확인

Output:

# AS-IS
disabled_plugins = ["cri"]

#root = "/var/lib/containerd"
#state = "/run/containerd"
#subreaper = true
#oom_score = 0

#[grpc]
#  address = "/run/containerd/containerd.sock"
#  uid = 0
#  gid = 0

#[debug]
#  address = "/run/containerd/debug.sock"
#  uid = 0
#  gid = 0
#  level = "info"

# TO-BE-1
#disabled_plugins = ["cri"]

#root = "/var/lib/containerd"
#state = "/run/containerd"
#subreaper = true
#oom_score = 0

#[grpc]
#  address = "/run/containerd/containerd.sock"
#  uid = 0
#  gid = 0

#[debug]
#  address = "/run/containerd/debug.sock"
#  uid = 0
#  gid = 0
#  level = "info"

# TO-BE-2
disabled_plugins = []

#root = "/var/lib/containerd"
#state = "/run/containerd"
#subreaper = true
#oom_score = 0

#[grpc]
#  address = "/run/containerd/containerd.sock"
#  uid = 0
#  gid = 0

#[debug]
#  address = "/run/containerd/debug.sock"
#  uid = 0
#  gid = 0
#  level = "info"

 

 

 

 

 

CRI 플러그인 설치

kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml

 

 

 

 

Worker Node 구성

컨트롤 플레인 노드에서 생성된 토큰(token)을 입력해서 워커 노드를 클러스터에 추가한다.

토큰을 이용하면 워커 노드가 인증을 거쳐 클러스터에 추가되는데 워커 노드가 클러스터에 정상 추가 되면, 컨트롤 플레인에서 kubectl get nodes를 실행하면 워커 노드가 Ready 상태로 표시된다.

워커 노드 구성 시, kubeadm init은 진행하지 않는다!

 

 

 

 

 

저장해 둔 토큰 입력

예:

kubeadm join 10.0.2.173:6443 --token y21ux3.5qn096yzuouqiup9 \
    --discovery-token-ca-cert-hash sha256:f44ca959b3a9d256b03c0bd25a874a5c2772a2d0af91291ca95247f8bd41d791

 

 

 

 

트러블 슈팅

kubelet 미작동 확인

[root@ip-10-0-2-173 ~]# systemctl status kublet
Unit kublet.service could not be found.
[root@ip-10-0-2-173 ~]# systemctl status kubelet
● kubelet.service - kubelet: The Kubernetes Node Agent
   Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; vendor preset: disabled)
  Drop-In: /usr/lib/systemd/system/kubelet.service.d
           └─10-kubeadm.conf
   Active: activating (auto-restart) (Result: exit-code) since Tue 2024-12-17 23:45:56 UTC; 4s ago
     Docs: https://kubernetes.io/docs/
  Process: 2027 ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS (code=exited, status=1/FAIL)
 Main PID: 2027 (code=exited, status=1/FAILURE)

 

 

 

 

 

로그 확인

[root@ip-10-0-2-173 ~]# journalctl -u kubelet -f
-- Logs begin at Tue
 2024-12-17 23:28:44 UTC. --
Dec 17 23:46:47 ip-10-0-2-173.ap-northeast-2.compute.internal kubelet[2067]: E1217 23:46:47.798168    2067 run.go:72] "command failed" err="failed to load kubelet config file, path: /var/lib/kubelet/config.yaml, error: failed to load Kubelet config file /var/lib/kubelet/config.yaml, error failed to read kubelet config file \"/var/lib/kubelet/config.yaml\", error: open /var/lib/kubelet/config.yaml: no such file or directory"

"command failed" err="failed to load kubelet config file, path: /var/lib/kubelet/config.yaml, error: failed to load Kubelet config file /var/lib/kubelet/config.yaml, error failed to read kubelet config file \"/var/lib/kubelet/config.yaml\", error: open /var/lib/kubelet/config.yaml: no such file or directory"

kubelet이 active 되지 않으면, kubeadm init을 한다.

/var/lib/kubelet/config.yaml은 클러스터 마스터 노드 초기화(kubeadmin init)를 하면 생성되는 각 노드의 상태를 관리하는 설정 파일이다.

 

 

 

 

 

클러스터 생성 확인

노드 상태 확인

컨트롤 플레인에서 노드가 정상 구성되었는지 확인한다.

# 노드 상태 확인
kubectl get nodes -o wide

# 파드 상태 확인
kubectl get pod --all-namespaces

 

 

 

 

 

kube-proxy CrashLoopBackOff 상태인 경우, 쿠버네티스 클러스터 내 네트워크 통신 문제 오류다.

클러스터 구성(init) 과정 중 kubeadm reset 을 사용하면 클러스터 구성 요소가 초기화된다.

이때, CRI 네트워크 플러그인은 서버에 설치하는 게 아니고 클러스터에 플러그인을 설치하는 것이기 때문에 kubeadm reset 을 하면 플러그인까지 삭제된다.

따라서, 플러그인을 재설치하여 해결했다.

 

 

 

Output:

[root@ip-10-0-2-173 ~]# kubectl get pods -A
NAMESPACE     NAME                                                                    READY   STATUS              RESTARTS         AGE
kube-system   calico-kube-controllers-7498b9bb4c-bvxm2                                0/1     ContainerCreating   0                11s
kube-system   calico-node-2kh2t                                                       0/1     Running             0                11s
kube-system   calico-node-ndzbw                                                       0/1     Init:2/3            0                11s
kube-system   calico-node-r8zw2                                                       0/1     Init:1/3            0                11s
kube-system   coredns-668d6bf9bc-kcl9s                                                0/1     ContainerCreating   0                14m
kube-system   coredns-668d6bf9bc-x57w5                                                0/1     ContainerCreating   0                14m
kube-system   etcd-ip-10-0-2-173.ap-northeast-2.compute.internal                      1/1     Running             82 (5m35s ago)   14m
kube-system   kube-apiserver-ip-10-0-2-173.ap-northeast-2.compute.internal            1/1     Running             86 (5m5s ago)    14m
kube-system   kube-controller-manager-ip-10-0-2-173.ap-northeast-2.compute.internal   1/1     Running             3 (5m35s ago)    14m
kube-system   kube-proxy-dplzp                                                        1/1     Running             6 (3m29s ago)    13m
kube-system   kube-proxy-tb6pz                                                        0/1     CrashLoopBackOff    5 (2m36s ago)    13m
kube-system   kube-proxy-xgpc7                                                        1/1     Running             12 (3m44s ago)   14m
kube-system   kube-scheduler-ip-10-0-2-173.ap-northeast-2.compute.internal            1/1     Running             90 (5m35s ago)   14m

 

 

 

 

 

 

 

추가 설정

KUBECONFIG 환경변수 영구 설정

마스터 노드에서 kubectl을 실행할 때 인증 파일(/etc/kubernetes/admin.conf)을 사용해야만, kubectl이 마스터 노드의 API 서버에 접근하여 명령어를 실행할 수 있다.

export는 환경 변수 설정이 로그인 세션에 한정되기 때문에 사용자 환경 변수를 설정하여 VM을 재시작해도 설정이 유지되도록 설정했다.

 

# 사용자(root)의 환경 변수 파일 편집
vi ~/.bashrc

# 맨 아래에 추가
export KUBECONFIG=/etc/kubernetes/admin.conf

# 변경사항 적용
~/.bashrc

 

 

 


 

쿠버네티스 설치를 3일 만에 완료했다..🫠

 

 

 

'Kubernetes' 카테고리의 다른 글

워커 노드 삭제 후 재등록하기  (0) 2024.12.19