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"
# 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 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
'Container Orchestration > Kubernetes' 카테고리의 다른 글
Kubernetes 어피니티 (0) | 2022.05.13 |
---|---|
Kubernetes 컨테이너 이미지 생성하기 (0) | 2022.05.10 |
Kubernetes 클러스터 구축하기(kubespray) (0) | 2022.05.10 |
쿠버네티스 배포 도구 : Kubeadm vs Kubespray vs Kops (0) | 2022.05.03 |
Kubernetes 개념과 Minikube 실습 (0) | 2022.03.22 |