Container Orchestration/Kubernetes

Kubernetes 클러스터 구축하기(kubeadm)

Somaz 2022. 5. 3. 20:43
728x90
반응형

Overview

 

kubeadm 도구를 사용하여 현 최신버전 kubernetes cluster를 구성하자.

 

 

버전

  • OS : Debian 11.3 Bullseye
  • kubernetes : v1.14.0
  • CRI(Container Runtime Interface) : containerd v1.2.5
  • CNI(Container Network Interface) : calico v3.5

 

서버구성

서버 유형 Hostname OS CPU 메모리 IP 계정
가상머신 k-master Debian
Bullseye
4
Cores
4G 192.168.xxx.235
(/24)
root,
user
가상머신 k-node1 Debian
Bullseye
4
Cores
4G 192.168.xxx.236
(/24)
root,
user
가상머신 k-node1 Debian
Bullseye
4
Cores
4G 192.168.xxx.237
(/24)
root,
user

 


 

VM 생성하기(KVM)

 

기본 패키지 설치 / ISO 파일 다운로드

$ apt-get install qemu-kvm livirt virt-install bridge-utils wget vncviewer

$ sudo wget https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-11.3.0-amd64-netinst.iso

 

 

이미지 디스크 생성

다음과 같이 qemu-img 명령을 사용하여 비어있는 이미지 디스크를 생성한다.

이 때 QCOW2, RAW 포맷 등 몇가지 디스크 타입이 있지만 이미지 포맷에 따라 디스크 저장 방식이 다르다.

저는 QCOW2 타입으로 Debian11를 위한 디스크를 생성하도록 하겠다.

 

$ cd /data/dong/disk

$ qemu-img create -f qcow2 k-master.qcow2 200G
Formatting 'k-master.qcow2', fmt=qcow2 size=214748364800 cluster_size=65536 lazy_refcounts=off refcount_bits=16

$ qemu-img create -f qcow2 k-node1.qcow2 200G
Formatting 'k-node1.qcow2', fmt=qcow2 size=214748364800 cluster_size=65536 lazy_refcounts=off refcount_bits=16

$ qemu-img create -f qcow2 k-node2.qcow2 200G
Formatting 'k-node2.qcow2', fmt=qcow2 size=214748364800 cluster_size=65536 lazy_refcounts=off refcount_bits=16

$ ls -l
합계 588
-rw-r--r-- 1 user user 199808  5월  2 11:28 k-master.qcow2
-rw-r--r-- 1 user user 199808  5월  2 11:29 k-node1.qcow2
-rw-r--r-- 1 user user 199808  5월  2 11:29 k-node2.qcow2

 

 

리눅스 가상머신 생성 및 설정

 

아래와 같이 리눅스 가상머신을 생성한다.

  • Debian 11
$ virt-install 
> --name k-master 
> --ram 4096 
> --cpu=host 
> --vcpus=4 
> --os-type=debian 
> --os-variant=debianwheezy 
> --disk path=/data/dong/disk/k-master.qcow2,format=qcow2,bus=virtio 
> --cdrom=/data/dong/iso/debian-11.3.0-amd64-netinst.iso 
> --network bridge=mgmt,model=virtio --graphics vnc,listen=0.0.0.0

 

동일하게 k-node1, k-node2도 생성해준다.

$ virsh list
 Id    Name              State
----------------------------------
 243   k-master          running
 244   k-node1           running
 245   k-node2           running
// vm 생성확인

$ ip a | grep virbr0
// vnc로 접속할 IP 확인

$ virsh dumpxml k-master | less
// 포트 확인

 

네트워크 설정을 진행해준다. 

# The primary network interface
auto ens3
iface ens3 inet static
    address <사용할 IP>
    gateway <사용할 GATEWAY>

// k-master : 235 k-node1 : 236  k-node2 : 237

$ ifup ens3

// 3대 전부 동일하게 진행

 

sudo 설정을 해준다.

# su -

// root 권한을 획득한다.


# vi /etc/sudoers

%sudo   ALL=(ALL:ALL) NOPASSWD:ALL

// sudo 그룹에 포함된 계정은 암호를 묻지 않도록 하자.

# gpasswd -a <사용할 계정> sudo

// 나의 계정은 sudo 그룹에 포함시킨다.

 

자, 이제 VM 생성은 끝이 낫다. 참고로 내가 사용하는 VM은 KVM이다!

 


선행작업

쿠버네티스를 설치하기 전 선행 작업이 필요하다.

이 설정은 모든 머신(마스터와 노드)에서 수행되어야 한다.

 

패키지 업데이트 및 hosts파일 업데이트

# apt update && apt upgrade
# vi /etc/hosts
...
192.168.xxx.235  k-master
192.168.xxx.236  k-node1
192.168.xxx.237  k-node2

 

swap 비활성화

# swapoff -a
#UUID.....
// UUID 부분 주석처리해준다.

 


CRI(Container Runtime Interface) 설치

CRI로 docker가 아닌 containerd를 사용할 것이다.

CRI 설치도 모든 머신(마스터와 노드)에서 커맨드를 수행한다.

 

모듈 로드

# modprobe overlay
# modprobe br_netfilter

# echo br_netfilter >> /etc/modules
  •  overlay : 오버레이 파일시스템을 위한 모듈
  • br_netfilter : 브릿지 방화벽을 위한 모듈
  • br_netfilter 모듈은 리부팅시 자동으로 load되지 않아 /etc/modules 파일에 추가하였다.

 

커널 파라미터 설정

# cat > /etc/sysctl.d/99-kubernetes-cri.conf <<EOF
> net.bridge.bridge-nf-call-iptables = 1
> net.ipv4.ip_forward = 1
> net.bridge.bridge-nf-call-ip6tables = 1
> EOF

# sysctl --system
* Applying /usr/lib/sysctl.d/50-pid-max.conf ...
kernel.pid_max = 4194304
* Applying /etc/sysctl.d/99-kubernetes-cri.conf ...
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
* Applying /etc/sysctl.d/99-sysctl.conf ...
* Applying /usr/lib/sysctl.d/protect-links.conf ...
fs.protected_fifos = 1
fs.protected_hardlinks = 1
fs.protected_regular = 2
fs.protected_symlinks = 1
* Applying /etc/sysctl.conf ...

 

필수 패키지 설치

# apt install -y apt-transport-https \
                  ca-certificates \
                  curl \
                  software-properties-common

 

도커 저장소 GPG key 추가

# curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -
E: gnupg, gnupg2 and gnupg1 do not seem to be installed, but one of them is required for this operation

# apt install gnupg gnupg2 gnupg1

# curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -
Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead (see apt-key(8)).
OK

 

apt 소스리스트 추가

# add-apt-repository \
                        "deb [arch=amd64] https://download.docker.com/linux/debian \
                        $(lsb_release -cs) stable"
 
 
containerd 설치
# apt update && apt install -y containerd.io

 


 

containerd 설정파일 만들기

containerd의 cgroup 드라이버는 기본값이 cgroupfs이다.

systemd로 변경하자. group driver는 리눅스 배포판의 init 시스템에 따라 결정하는 것이 안정적이다.

데비안 스트레치는 init시스템이 systemd이기 때문에 cgroup driver를 systemd로 변경할 것이다

 

 

cgroup 드라이버 설정

# vi /etc/containerd/config.toml

[plugins. "io.containerd.grpc.v1.cri"]
  systemd_cgroup= false
  
// 위에 껀 아니다.

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
  ...
  [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
    SystemdCgroup = true
    
// 여기있는걸 바꿔줘야 한다.

cgroup 드라이버로 cgroupfs대신 systemd를 사용한다.

주의할점은 sytemd_cgroup 과 Systemd_Cgroup 이 있다.

잘 확인하고 설정해주길 바란다. 안그러면 에러가 발생할 것이다.

 

 

containerd 재시작

# systemctl restart containerd

 

containerd 버전 확인

# containerd --version
containerd containerd.io 1.5.11 3df54a852345ae127d1fa3092b95168e4a88e2f8

 


kubeadm, kublet, kubectl

 

쿠버네티스를 구성하기 위해 필수 패키지를 설치한다.

  • kubeadm : 쿠버네티스 클러스터를 구성하기 위한 도구
  • kubelet : 쿠버네티스 apiserver와 통신하기 위한 노드 에이전트

모든 머신(마스터와 노드)에서 커맨드를 수행한다.

 

구글 클라우드 공개 사이닝 키를 저장하자.

위에서 받았던 도커 gpg 키를 받는 이유와 동일하다.

# curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg

 

 

쿠버네티스 레포지토리를 추가하자

# cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main
EOF

 

패키지 업데이트 후, kubelet, kubeadm, kubectl을 설치하자

# apt-get update
# apt-get install -y kubelet kubeadm kubectl

 

kubectl은 master에서 사용하는 쿠버네티스 CLI 툴이라, 노드에서 필요하진 않다.

그런데 kubeadm 패키지의 의존성 때문에 같이 설치된다.

추가로 kubernetes-cni 와 cri-tools 패키지도 같이 설치된다.

cri-tools패키지는 docker cli를 대체할 수 있는 CLI 툴이다.

 

이 툴을 containerd에서 사용하도록 하자.

# vi /etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock

 

패키지 업그레이드 제외하기

# apt-mark hold kubelet kubeadm kubectl
kubelet set on hold.
kubeadm set on hold.
kubectl set on hold.
  • 쿠버네티스 패키지들은 apt 업그레이드 목록에서 제외한다.
  • 이유는 버전 업그레이드로 인해 버전이 달라짐에 따라 문제가 발생될 수 있다.

 


kublet에서 사용하는 cgroup 드라이버 구성

 

이것도 역시 모든 머신(마스터와 노드)모두에서 커맨드를 수행한다.

kubelet에서 사용하는 cgroup 드라이버를 systemd로 사용하기 위해 설정한다.

# vi /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
...
Environment="KUBELET_EXTRA_ARGS=--cgroup-driver=systemd"

# systemctl daemon-reload

 

master 설정

 

쿠버네티스 마스터를 구성하자.

# systemctl restart containerd.service 
# kubeadm init --apiserver-advertise-address=192.168.xxx.235
[init] Using Kubernetes version: v1.23.6
[preflight] Running pre-flight checks
[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'
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Generating "ca" certificate and key
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [k-master kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 192.168.21.235]
[certs] Generating "apiserver-kubelet-client" certificate and key
[certs] Generating "front-proxy-ca" certificate and key
[certs] Generating "front-proxy-client" certificate and key
[certs] Generating "etcd/ca" certificate and key
[certs] Generating "etcd/server" certificate and key
[certs] etcd/server serving cert is signed for DNS names [k-master localhost] and IPs [192.168.21.235 127.0.0.1 ::1]
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [k-master localhost] and IPs [192.168.21.235 127.0.0.1 ::1]
[certs] Generating "etcd/healthcheck-client" certificate and key
[certs] Generating "apiserver-etcd-client" certificate and key
[certs] Generating "sa" key and public key
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
[kubeconfig] Writing "admin.conf" kubeconfig file
[kubeconfig] Writing "kubelet.conf" kubeconfig file
[kubeconfig] Writing "controller-manager.conf" kubeconfig file
[kubeconfig] Writing "scheduler.conf" kubeconfig file
[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
[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"
[control-plane] Creating static Pod manifest for "kube-scheduler"
[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 19.506141 seconds
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config-1.23" in namespace kube-system with the configuration for the kubelets in the cluster
NOTE: The "kubelet-config-1.23" naming of the kubelet ConfigMap is deprecated. Once the UnversionedKubeletConfigMap feature gate graduates to Beta the default name will become just "kubelet-config". Kubeadm upgrade will handle this transition transparently.
[upload-certs] Skipping phase. Please see --upload-certs
[mark-control-plane] Marking the node k-master as control-plane by adding the labels: [node-role.kubernetes.io/master(deprecated) node-role.kubernetes.io/control-plane node.kubernetes.io/exclude-from-external-load-balancers]
[mark-control-plane] Marking the node k-master as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule]
[bootstrap-token] Using token: c5ihdc.21cnwf1zutkpy1gf
[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

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.xxx.235:<포트> --token c5ihdc.21cnwf1zutkpy1gf \
	--discovery-token-ca-cert-hash sha256:4feb71c883da278e99019ce8fdba05479c96ea13011c3b91068f9321851685a5

 

 

문제가 생겼다면 아래 명령으로 리셋할 수 있다.

# kubeadm reset

 

 

kubectl 명령을 root가 아닌 user 계정으로 실행할 수 있도록 한다.

user@k-master:~$ mkdir .kube
user@k-master:~$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
user@k-master:~$ sudo chown $(id -u):$(id -g) $HOME/.kube/config

 

kubectl 자동완성 기능도 적용하자.

root@k-master:~# apt install bash-completion
root@k-master:~# echo 'source <(kubectl completion bash)' >>~/.bashrc
root@k-master:~# . ~/.bashrc

 

CNI (Container Network Interfaces) 설치

 

다른 노드에 있는 파드간 통신할 수 있도록 CNI를 설치하자.

CNI를 설치하면 CoreDNS pod도 시작될 것이다.

CNI로 Calico를 사용할 것이다.

 

 

Calico 공식 홈페이지 문서를 보고 설치를 진행하였다.

# cd /etc/kubernetes/manifests/

# curl https://projectcalico.docs.tigera.io/manifests/calico.yaml -O
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  217k  100  217k    0     0   175k      0  0:00:01  0:00:01 --:--:--  175k

 

calico 설치한다.

# kubectl apply -f calico.yaml
configmap/calico-config created
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/caliconodestatuses.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/ipreservations.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
clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created
clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created
clusterrole.rbac.authorization.k8s.io/calico-node created
clusterrolebinding.rbac.authorization.k8s.io/calico-node created
daemonset.apps/calico-node created
serviceaccount/calico-node created
deployment.apps/calico-kube-controllers created
serviceaccount/calico-kube-controllers created
Warning: policy/v1beta1 PodDisruptionBudget is deprecated in v1.21+, unavailable in v1.25+; use policy/v1 PodDisruptionBudget
poddisruptionbudget.policy/calico-kube-controllers created

 

모든 파드를 확인해보자.

# kubectl get pod -o wide --all-namespaces
NAMESPACE     NAME                                      READY   STATUS    RESTARTS   AGE        NODE       NOMINATED NODE   READINESS GATES
kube-system   calico-kube-controllers-7c845d499-4l8v9   1/1     Running   0          6m7s       k-master   <none>           <none>
kube-system   calico-node-kfcq9                         1/1     Running   0          6m7s       k-master   <none>           <none>
kube-system   coredns-64897985d-snp6h                   1/1     Running   0          54m        k-master   <none>           <none>
kube-system   coredns-64897985d-zfd5t                   1/1     Running   0          54m        k-master   <none>           <none>
kube-system   etcd-k-master                             1/1     Running   0          54m        k-master   <none>           <none>
kube-system   kube-apiserver-k-master                   1/1     Running   0          54m        k-master   <none>           <none>
kube-system   kube-controller-manager-k-master          1/1     Running   0          54m        k-master   <none>           <none>
kube-system   kube-proxy-5z2wk                          1/1     Running   0          54m        k-master   <none>           <none>
kube-system   kube-scheduler-k-master                   1/1     Running   0          54m        k-master   <none>           <none>

 


Node 설정

 

마스터의 클러스터로 조인한다.

 

k-node1,2에서 실행한다.

kubeadm 으로 실행할 때 조인하는 방법이 나와있다! 잘 기억하도록 하자.
# kubeadm join 192.168.xxx.235:<포트> --token c5ihdc.21cnwf1zutkpy1gf \
	--discovery-token-ca-cert-hash sha256:4feb71c883da278e99019ce8fdba05479c96ea13011c3b91068f9321851685a5
    
[preflight] Running pre-flight checks
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[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.

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

마스터에서 확인해보자. 정상적으로 설치가 완료되었다.

# kubectl get node
NAME       STATUS   ROLES                  AGE    VERSION
k-master   Ready    control-plane,master   149m   v1.23.6
k-node1    Ready    <none>                 82m    v1.23.6
k-node2    Ready    <none>                 96s    v1.23.6

 

728x90
반응형