2024년 3월 초, docker가 익숙해서 끝까지 버티고 있던 kubernetes v1.23.x 개발 환경 설치에 돌연 문제가 생겼다. Ubuntu에서 kubeadm, kubelet, kubectl 등을 apt로 설치할 수 없게 된 것이다. 원인과 해결 방법에 대해 알아보자.
Kubernetes apt install 에러 현상과 원인
K8s 설치 시 어떤 현상이 발생하는가?
2024년 3월 초부터 ubuntu에 apt install 명령어를 통해 kubeadm, kubelet, kubectl이 설치되지 않는다. 기존 사용하던 개발 환경은 다음과 같다.
위 명령어를 통해 kubernetes 설치를 진행하면, 다음과 같은 에러 메시지를 확인할 수 있다.
master: deb [signed-by=/etc/apt/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main
master: Hit:1 https://download.docker.com/linux/ubuntu jammy InRelease
master: Hit:3 http://ports.ubuntu.com/ubuntu-ports jammy InRelease
master: Ign:2 https://packages.cloud.google.com/apt kubernetes-xenial InRelease
master: Hit:4 http://ports.ubuntu.com/ubuntu-ports jammy-updates InRelease
master: Err:5 https://packages.cloud.google.com/apt kubernetes-xenial Release
master: 404 Not Found [IP: 142.250.76.142 443]
master: Hit:6 http://ports.ubuntu.com/ubuntu-ports jammy-backports InRelease
master: Get:7 http://ports.ubuntu.com/ubuntu-ports jammy-security InRelease [110 kB]
master: Reading package lists...
master: E: The repository 'https://apt.kubernetes.io kubernetes-xenial Release' does not have a Release file.
master:
master: WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
master:
master: Reading package lists...
master: Building dependency tree...
master: Reading state information...
master: E: Unable to locate package kubelet
master: E: Unable to locate package kubectl
master: E: Unable to locate package kubeadm
원인은 package repository에 있다!
위의 에러 메시지를 살펴보면, kubernetes 관련 package 목록을 가져오기 위해 package repository에 접속을 하는데, 404 에러가 발생하고 있음을 알 수 있다. 최근까지 잘 되던 것이 갑자기 되지 않으니까 당황스럽다. 원인은 외부에 있음을 직감하고, kubernetes 공식 문서들을 샅샅이 뒤져보았다.
아니나 다를까, package repository가 대체된다는 안내사항이 있었다. 해당 글에서는 다음과 같이 안내하고 있다.
On behalf of Kubernetes SIG Release, I am very excited to introduce the Kubernetes community-owned software repositories for Debian and RPM packages: pkgs.k8s.io! The new package repositories are replacement for the Google-hosted package repositories (apt.kubernetes.io and yum.kubernetes.io) that we’ve been using since Kubernetes v1.5.
ℹ️ Update (January 12, 2024): the legacy Google-hosted repositories are going away in January 2024. Check out the deprecation announcement for more details about this change.
기존 사용하던 package repository가 2024년 1월부터 아예 사라질 것이라고 되어 있는데, 3월까지 잘 사용한 것도 기적이었던 것이다. 평소 부지런하게 follow up하지 않았던 스스로를 반성하게 된다.
Package repository 관련 문제 해결 방법
Package repository deprecation에 대응하기
안내사항에 따르면, 다음과 같이 package repository를 변경한 후 apt install을 진행하면 된다.
master: Reading package lists...
master: E: Failed to fetch https://pkgs.k8s.io/core:/stable:/v1.23/deb/InRelease 403 Forbidden [IP: 54.192.175.103 443]
master: E: The repository 'https://pkgs.k8s.io/core:/stable:/v1.23/deb InRelease' is not signed.
한 걸음 나아가긴 했다. 404 Not Found 에러 대신 403 Forbidden 에러가 발생하는 것으로 보아, 적어도 새로운 package repository는 서비스를 하고 있긴 하다는 것을 확인할 수 있다. 그렇다면, 왜 이런 현상이 발생하는 것일까? 이 문제에 대한 원인도 앞서 언급한 안내 글에서 찾을 수 있었다.
The new Kubernetes package repositories contain packages beginning with those Kubernetes versions that were still under support when the community took over the package builds. This means that the new package repositories have Linux packages for all Kubernetes releases starting with v1.24.0.
새로운 package repository는 v1.24.0 이상의 kubernetes만 제공한다는 것이다. 결국, kubernetes의 버전을 올려야 한다.
Docker를 버린 kubernetes v1.24로의 여정
Kubernetes v1.23.x와 v1.24.x 사이에는 큰 차이점이 존재한다. Kubernetes v1.24.0부터는 docker를 버렸다는 것이다. 공식 문서의 내용을 간단히 요약하면 다음과 같다.
1.24 버전 이전에는 docker라는 specific한 CRI를 사용하고 있었다.
Kubernetes에서 docker 외에도 다양한 CRI를 지원하기 위해, CRI standard라는 것을 만들었다.
Docker는 CRI standard를 따르지 않고 있다.
Kubernetes는 docker 지원을 위해 dockershim이라는 코드를 만들어서 제공했다.
Kubernetes 개발 참여자들이 docker라는 특수 CRI를 위해 별도로 시간을 할애하는 것이 부담스럽다.
Kubernetes v1.24부터 dockershim 지원 안하기로 했다.
실제로, kubernetes v1.24 버전을 설치할 때 docker를 사용하려고 하면, 다음과 같은 에러를 만날 수 있다.
master: [WARNING SystemVerification]: missing optional cgroups: blkio
master: error execution phase preflight: [preflight] Some fatal errors occurred:
master: [ERROR CRI]: container runtime is not running: output: time="2024-03-05T00:42:52-08:00" level=fatal msg="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"
master: , error: exit status 1
master: [preflight] If you know what you are doing, you can make a check non-fatal with `--ignore-preflight-errors=...`
master: To see the stack trace of this error execute with --v=5 or higher
master: failed to load admin kubeconfig: open /root/.kube/config: no such file or directory
master: To see the stack trace of this error execute with --v=5 or higher
눈물과 함께 kubernetes v1.23과 docker와 작별할 시간이다. 앞서 살펴본 package repository 설정 부분에서 버전을 지정해주는 문자열을 변경하자.
이후 apt-cache policy kubeadm 명령어를 통해 설치 가능한 버전을 조회해보고 apt install을 통해 설치를 진행하면 된다. 이때 주의할 점은, docker가 아니라 containerd를 사용할 것이기 때문에 설치하려는 kubernetes 버전과 호환되는 containerd 버전을 알아보고 미리 설치해두어야 한다는 것이다. Containerd와 kubernetes 버전 호환 관계는 이 문서를 확인하면 된다.
Kubernetes는 온프레미스 서버 또는 하이브리드 클라우드 환경에서 대규모로 컨테이너화된 애플리케이션을 오케스트레이션 및 관리하기 위한 도구입니다. Kubeadm은 사용자가 모범 사례 시행을 통해 프로덕션 준비 Kubernetes 클러스터를 설치할 수 있도록 Kubernetes와 함께 제공되는 도구입니다. 이 튜토리얼은 kubeadm을 사용하여 Ubuntu 20.04에 Kubernetes 클러스터를 설치하는 방법을 보여줍니다.
Kubernetes 클러스터 배포에는 두 가지 서버 유형이 사용됩니다.
마스터 : Kubernetes 마스터는 Kubernetes 클러스터의 포드, 복제 컨트롤러, 서비스, 노드 및 기타 구성 요소에 대한 제어 API 호출이 실행되는 곳입니다.
Node : Node는 컨테이너에 런타임 환경을 제공하는 시스템입니다. 컨테이너 포드 세트는 여러 노드에 걸쳐 있을 수 있습니다.
실행 가능한 설정을 위한 최소 요구 사항은 다음과 같습니다.
메모리: 컴퓨터당 2GiB 이상의 RAM
CPU: 컨트롤 플레인 머신에 최소 2개의 CPU 가 있습니다.
컨테이너 풀링을 위한 인터넷 연결 필요(개인 레지스트리도 사용할 수 있음)
클러스터의 머신 간 전체 네트워크 연결 – 개인 또는 공용입니다.
Ubuntu 20.04에 Kubernetes 클러스터 설치
My Lab 설정에는 3개의 서버가 있습니다. 컨테이너화된 워크로드를 실행하는 데 사용할 하나의 컨트롤 플레인 머신과 두 개의 노드. 예를 들어 HA용 제어 평면 노드 3개 를 사용하여 원하는 사용 사례 및 부하에 맞게 노드를 더 추가할 수 있습니다 .
서버 유형
서버 호스트 이름
명세서
주인
k8s-master01.computingforgeeks.com
4GB 램, 2vcpus
노동자
k8s-worker01.computingforgeeks.com
4GB 램, 2vcpus
노동자
k8s-worker02.computingforgeeks.com
4GB 램, 2vcpus
1단계: Kubernetes 서버 설치
Ubuntu 20.04에서 Kubernetes 배포에 사용할 서버를 프로비저닝합니다. 설정 프로세스는 사용 중인 가상화 또는 클라우드 환경에 따라 다릅니다.
systemd cgroup 드라이버를 사용하려면 에서 plugins.cri.systemd_cgroup = true 를 설정 /etc/containerd/config.toml하십시오. kubeadm을 사용할 때 kubelet 용 cgroup 드라이버를 수동으로 구성하십시오.
--control-plane-endpoint : 모든 제어 평면 노드에 대한 공유 끝점을 설정합니다. DNS/IP일 수 있음
--pod-network-cidr : 포드 네트워크 추가 기능을 설정하는 데 사용됨 CIDR
--cri-socket : 런타임 소켓 경로를 설정하기 위해 컨테이너 런타임이 둘 이상인 경우 사용
--apiserver-advertise-address : 이 특정 제어 평면 노드의 API 서버에 대한 광고 주소 설정
....
[init] Using Kubernetes version: v1.22.2
[preflight] Running pre-flight checks
[WARNING Firewalld]: firewalld is active, please ensure ports [6443 10250] are open or your cluster may not function correctly
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Starting the kubelet
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Using existing ca certificate authority
[certs] Using existing apiserver certificate and key on disk
[certs] Using existing apiserver-kubelet-client certificate and key on disk
[certs] Using existing front-proxy-ca certificate authority
[certs] Using existing front-proxy-client certificate and key on disk
[certs] Using existing etcd/ca certificate authority
[certs] Using existing etcd/server certificate and key on disk
[certs] Using existing etcd/peer certificate and key on disk
[certs] Using existing etcd/healthcheck-client certificate and key on disk
[certs] Using existing apiserver-etcd-client certificate and key on disk
[certs] Using the existing "sa" key
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
[kubeconfig] Using existing kubeconfig file: "/etc/kubernetes/admin.conf"
[kubeconfig] Using existing kubeconfig file: "/etc/kubernetes/kubelet.conf"
[kubeconfig] Using existing kubeconfig file: "/etc/kubernetes/controller-manager.conf"
[kubeconfig] Using existing kubeconfig file: "/etc/kubernetes/scheduler.conf"
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
W0611 22:34:23.276374 4726 manifests.go:225] the default kube-apiserver authorization-mode is "Node,RBAC"; using "Node,RBAC"
[control-plane] Creating static Pod manifest for "kube-scheduler"
W0611 22:34:23.278380 4726 manifests.go:225] the default kube-apiserver authorization-mode is "Node,RBAC"; using "Node,RBAC"
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s
[apiclient] All control plane components are healthy after 8.008181 seconds
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config-1.21" in namespace kube-system with the configuration for the kubelets in the cluster
[upload-certs] Skipping phase. Please see --upload-certs
[mark-control-plane] Marking the node k8s-master01.computingforgeeks.com as control-plane by adding the label "node-role.kubernetes.io/master=''"
[mark-control-plane] Marking the node k8s-master01.computingforgeeks.com as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule]
[bootstrap-token] Using token: zoy8cq.6v349sx9ass8dzyj
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to get nodes
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy
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:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
You can now join any number of control-plane nodes by copying certificate authorities
and service account keys on each node and then running the following as root:
kubeadm join k8s-cluster.computingforgeeks.com:6443 --token sr4l2l.2kvot0pfalh5o4ik \
--discovery-token-ca-cert-hash sha256:c692fb047e15883b575bd6710779dc2c5af8073f7cab460abd181fd3ddb29a18 \
--control-plane
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join k8s-cluster.computingforgeeks.com:6443 --token sr4l2l.2kvot0pfalh5o4ik \
--discovery-token-ca-cert-hash sha256:c692fb047e15883b575bd6710779dc2c5af8073f7cab460abd181fd3ddb29a18
$ kubectl cluster-info
Kubernetes master is running at https://k8s-cluster.computingforgeeks.com:6443
KubeDNS is running at https://k8s-cluster.computingforgeeks.com:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/apiservers.operator.tigera.io created
customresourcedefinition.apiextensions.k8s.io/imagesets.operator.tigera.io created
customresourcedefinition.apiextensions.k8s.io/installations.operator.tigera.io created
customresourcedefinition.apiextensions.k8s.io/tigerastatuses.operator.tigera.io created
namespace/tigera-operator created
Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
podsecuritypolicy.policy/tigera-operator created
serviceaccount/tigera-operator created
clusterrole.rbac.authorization.k8s.io/tigera-operator created
clusterrolebinding.rbac.authorization.k8s.io/tigera-operator created
deployment.apps/tigera-operator created
.....
installation.operator.tigera.io/default created
apiserver.operator.tigera.io/default created
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'
[kubelet-start] Downloading configuration for the kubelet from the "kubelet-config-1.21" ConfigMap in the kube-system namespace
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...
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.
제어 플레인에서 아래 명령을 실행하여 노드가 클러스터에 합류했는지 확인합니다.
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master01.computingforgeeks.com Ready master 10m v1.22.2
k8s-worker01.computingforgeeks.com Ready <none> 50s v1.22.2
k8s-worker02.computingforgeeks.com Ready <none> 12s v1.22.2
$ kubectl get nodes -o wide
Prometheus는 Kubernetes 클러스터의 고급 메트릭 기능에 액세스할 수 있는 완전한 솔루션입니다. Grafana는 Prometheus 데이터베이스에 수집 및 저장되는 메트릭의 분석 및 대화형 시각화에 사용됩니다. Kubernetes 클러스터에서 전체 모니터링 스택을 설정하는 방법에 대한 완전한 가이드가 있습니다.