쿠버네티스를 공부하기 위해서는 제일 처음으로 할일이 여러 노드에 kubernates패키지를 설치하고 master 노드와 worker노드간의 연결을 설정하는 일이다.
집에 있는 Synology 718+의 VMM 으로 VM을 3개 만들어 그들간에 cluster를 구성해보려고 한다.
시작하기 전에
- 호환 되는 Linux는 Debian 및 Red Hat 기반 Linux 배포판.
- 머신당 2GB 이상의 RAM.
- 2 CPU 이상.
- 클러스터의 모든 시스템 간의 전체 네트워크 연결(공용 또는 사설 네트워크).
- 모든 노드에 대한 고유한 호스트 이름, MAC 주소 및 product_uuid.
- kubelet 위해서는 스왑을 사용하지 않도록 설정함.
마스터 노드 (Master Node)
- 노드들의 상태를 제어하고 관리
- 쿠버네티스의 데이터 저장소로 사용하는 etcd를 함께 설치하거나 별도 노드에 분리 가능
- etcd, kube-apiserver, kube-scheduler, kube-controller-manager, kubelet, kube-proxy, docker 등의 컴포넌트가 실행
- 상용 서비스라면 고가용성을 고려해 3대 ~ 5대 구성 가능
- 여러 대의 마스터 노드를 구성하더라도 kube-controller-manager가 활성화 상태로 동작할 수 있는 리더 마스터 노드는 1대만 가능
워커 노드 (Worker Node)
- kubelet 이라는 프로세스를 통해서 마스터 노드의 명령을 받아 사용자가 선언한 파드 등을 실제로 실행하는 노드
- kubelet, kube-proxy, docker 등의 컴포넌트가 실행
MAC 주소와 product_uuid가 모든 노드에 대해 고유한지 확인
- ifconfig -a 로 각 노드에 할당된 Mac address 및 IP를 조회하여 충돌이 나지 않는지 확인한다.
root@kindlove-Standard-PC-i440FX-PIIX-1996:~# ifconfig -a
ens3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.30.1.22 netmask 255.255.255.0 broadcast 172.30.1.255
inet6 fe80::bc91:db54:8d6d:f646 prefixlen 64 scopeid 0x20<link>
ether 02:11:32:24:f3:f3 txqueuelen 1000 (Ethernet)
RX packets 973060 bytes 384142144 (384.1 MB)
RX errors 0 dropped 8 overruns 0 frame 0
TX packets 31297 bytes 2575688 (2.5 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 5653 bytes 513619 (513.6 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 5653 bytes 513619 (513.6 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
- product_uuid는 다음 명령을 사용하여 확인한다. sudo cat /sys/class/dmi/id/product_uuid
root@kindlove-Standard-PC-i440FX-PIIX-1996:~# cat /sys/class/dmi/id/product_uuid
4d442e6b-82ba-430a-a322-feaab44fe01b
iptables가 브리지된 트래픽을 보도록 허용
lsmod | grep br_netfilter br_netfilter모듈이 로드 되었는지 확인한다.
명시적으로 로드하려면 sudo modprobe br_netfilter로 모듈을 로딩한다.
root@kindlove-Standard-PC-i440FX-PIIX-1996:~# sudo modprobe br_netfilter
root@kindlove-Standard-PC-i440FX-PIIX-1996:~# lsmod | grep br
br_netfilter 28672 0
bridge 176128 1 br_netfilter
stp 16384 1 bridge
llc 16384 2 bridge,stp
Linux 노드의 iptables가 브리지된 트래픽을 올바르게 보기 위한 요구 사항으로 구성 net.bridge.bridge-nf-call-iptables에서 가 1로 설정되어 있는지 확인한다. 콘솔창에서 다음을 실행한다.
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sudo sysctl --system
root@kindlove-Standard-PC-i440FX-PIIX-1996:~# sudo sysctl --system
* Applying /etc/sysctl.d/10-console-messages.conf ...
kernel.printk = 4 4 1 7
* Applying /etc/sysctl.d/10-ipv6-privacy.conf ...
net.ipv6.conf.all.use_tempaddr = 2
net.ipv6.conf.default.use_tempaddr = 2
* Applying /etc/sysctl.d/10-kernel-hardening.conf ...
kernel.kptr_restrict = 1
* Applying /etc/sysctl.d/10-link-restrictions.conf ...
fs.protected_hardlinks = 1
fs.protected_symlinks = 1
* Applying /etc/sysctl.d/10-magic-sysrq.conf ...
kernel.sysrq = 176
* Applying /etc/sysctl.d/10-network-security.conf ...
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.tcp_syncookies = 1
* Applying /etc/sysctl.d/10-ptrace.conf ...
kernel.yama.ptrace_scope = 1
* Applying /etc/sysctl.d/10-zeropage.conf ...
vm.mmap_min_addr = 65536
* Applying /usr/lib/sysctl.d/50-default.conf ...
net.ipv4.conf.all.promote_secondaries = 1
net.core.default_qdisc = fq_codel
* Applying /etc/sysctl.d/99-sysctl.conf ...
* Applying /etc/sysctl.d/k8s.conf ...
* Applying /etc/sysctl.conf ...
Hostname 변경
master노드임을 알수 있게 hostname을 변경한다. (재로그인시 반영됨)
root@ubuntu-Standard-PC-i440FX-PIIX-1996:~# hostnamectl set-hostname master
SELinux, firewall 해제
root@kindlove-Standard-PC-i440FX-PIIX-1996:~# setenforce 0
setenforce: SELinux is disabled
root@kindlove-Standard-PC-i440FX-PIIX-1996:~# ufw disable
방화벽이 비활성 되었으며 시스템이 시작할 때 사용되지 않습니다
root@kindlove-Standard-PC-i440FX-PIIX-1996:~#
Swap 해제
root@worker1:~# # swapon && cat /etc/fstab
root@worker1:~# # swapoff -a && sed -i '/swap/s/^/#/' /etc/fstab
런타임 설치
Pod에서 컨테이너를 실행하기 위해 Kubernetes는 컨테이터 런타임이 필요하다. (Ubuntu에 Docker 설치하기를 참조 : https://kindloveit.tistory.com/18)
기본적으로 Kubernetes는 컨테이너 런타임 인터페이스 (CRI)를 사용하여 선택한 컨테이너 런타임과 인터페이스하기 때문이다.
런타임을 지정하지 않으면 kubeadm은 잘 알려진 Unix 도메인 소켓 목록을 검색하여 설치된 컨테이너 런타임을 자동으로 감지하려고 시도한다. 현재 자동으로 디텍트 가능한 컨테이너는 다음과 같다.
RuntimePath to Unix domain socket
Docker | /var/run/dockershim.sock |
containerd | /run/containerd/containerd.sock |
CRI-O | /var/run/crio/crio.sock |
kubeadm, kubelet 및 kubectl 설치
모든 컴퓨터에 다음 패키지를 설치합니다.
- kubeadm: 클러스터를 부트스트랩 함.
- kubelet: 클러스터의 모든 머신에서 실행되고 포드 및 컨테이너 시작과 같은 작업을 수행하는 구성 요소.
- kubectl: 클러스터와 통신하기 위한 명령줄 util
현재 실습용으로 사용하고 있는 linux 배포판은 ubuntu 이므로 Debian 기반 배포판 기준으로 아래 설치 방법을 알아본다.
- apt패키지 인덱스를 업데이트하고 Kubernetes apt저장소 를 사용하는 데 필요한 패키지를 설치한다.
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl
- Google Cloud 공개 서명 키를 다운로드합니다.
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
- Kubernetes apt리포지토리를 추가 합니다.
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
- apt패키지 인덱스를 업데이트 하고 kubelet, kubeadm 및 kubectl을 설치하고 해당 버전을 고정합니다.
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
kubeadm이 수행할 작업을 지시할 때까지 충돌 루프에서 대기하므로 kubelet은 이제 몇 초마다 다시 시작됩니다.
kubelet cgroup 드라이버 구성 (Docker container 기반)
-
cgroupfs를 컨테이너 런타임과 kubelt에 의해서 제어할 수 있도록 구성한다.
sudo mkdir /etc/docker
cat <<EOF | sudo tee /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
EOF
- Docker를 다시 시작하고 부팅 시 활성화:
sudo systemctl enable docker
sudo systemctl daemon-reload
sudo systemctl restart docker
kubeadm을 사용하여 kubernetes cluster 구성하기
[마스터 노드에서만 실행] kubeadm init 명령을 통해서 클러스터를 생성한다.
root@kindlove-Standard-PC-i440FX-PIIX-1996:~# kubeadm init
[init] Using Kubernetes version: v1.23.1
[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 [kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local master] and IPs [10.96.0.1 172.30.1.16]
[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 [localhost master] and IPs [172.30.1.16 127.0.0.1 ::1]
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [localhost master] and IPs [172.30.1.16 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
[kubelet-check] Initial timeout of 40s passed.
[apiclient] All control plane components are healthy after 68.017142 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 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 master as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule]
[bootstrap-token] Using token: 5v5tqi.9fbmk1t5bq4rr89l
[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 172.30.1.16:6443 --token 5v5tqi.9fbmk1t5bq4rr89l \
--discovery-token-ca-cert-hash sha256:e5d020b5cd0ba5f0a45b9482f8b41fdc1704e9a8fbc88c961b43b986cfc57c38
위와 같이 정상적으로 init이 끝나면 Command 실행이 되게 환경 변수를 설정해준다.
root@kindlove-Standard-PC-i440FX-PIIX-1996:~# export KUBECONFIG=/etc/kubernetes/admin.conf
[마스터 노드에서만 실행] 쿠버네티스 클러스터에 조인하기 위한 명령어 구문을 저장 해둔다.
root@master:~# cat > token.sh
kubeadm join 172.30.1.16:6443 --token 5v5tqi.9fbmk1t5bq4rr89l \
--discovery-token-ca-cert-hash sha256:e5d020b5cd0ba5f0a45b9482f8b41fdc1704e9a8fbc88c961b43b986cfc57c38
root@master:~# chmod +x token.sh (실행권한 부여)
[마스터 노드에서만 실행] Pod가 서로 통신 할 수 있도록 CNI(Container Network Interface) 기반 Pod 네트워크 추가 기능 구성한다.
root@kindlove-Standard-PC-i440FX-PIIX-1996:~# wget https://docs.projectcalico.org/manifests/calico.yaml
root@kindlove-Standard-PC-i440FX-PIIX-1996:~# kubectl apply -f calico.yaml
정상적으로 노드가 ready 되었는지 확인한다.
root@master:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready control-plane,master 9m13s v1.23.1
calico및 kubernetes pods가 정상 running되는지 확인한다.
root@master:~# kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system calico-kube-controllers-647d84984b-rbp5b 1/1 Running 0 4m45s
kube-system calico-node-gft4v 1/1 Running 0 4m47s
kube-system coredns-64897985d-2ndcp 1/1 Running 0 9m1s
kube-system coredns-64897985d-bn7r8 1/1 Running 0 9m2s
kube-system etcd-master 1/1 Running 0 9m20s
kube-system kube-apiserver-master 1/1 Running 0 9m28s
kube-system kube-controller-manager-master 1/1 Running 0 9m20s
kube-system kube-proxy-bvcx9 1/1 Running 0 9m2s
kube-system kube-scheduler-master 1/1 Running 0 9m20s
[워커 노드에서만 실행] 각 Worker노드에서 master노드에 등록을 수행한다.
kubeadm init 후에 저장한 token.sh을 각 worker 노드로 전송한다.
root@master:~# scp token.sh ubuntu@172.30.1.10:~/
ubuntu@172.30.1.10's password:
token.sh
root@master:~# scp token.sh ubuntu@172.30.1.36:~/
ubuntu@172.30.1.36's password:
token.sh
token.sh을 전달받은 각 노드는 실행해서 cluster에 연결한다.
root@worker2:/home/ubuntu# ./token.sh
[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'
W0106 13:23:42.637670 15397 utils.go:69] The recommended value for "resolvConf" in "KubeletConfiguration" is: /run/systemd/resolve/resolv.conf; the provided value is: /run/systemd/resolve/resolv.conf
[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.
Master 노드에서 최종 cluster에 붙은 모든 노드들을 확인한다.
root@master:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready control-plane,master 4h57m v1.23.1
worker1 Ready <none> 4m7s v1.23.1
worker2 Ready <none> 94s v1.23.1
-- The End --
'Devops > Kubernetes' 카테고리의 다른 글
[Kubernetes] apt-get 시 public key is not available: NO_PUBKEY 에러 수정 (1) | 2023.12.21 |
---|---|
[Kubernetes] 쿠버네티스 Service 개념 - ClusterIP, NodePort (0) | 2022.01.23 |
[Kubernetes] Controller - Replicaset (0) | 2022.01.22 |
[Kubernetes] 네임스페이스(Namespace) 살펴보기 (0) | 2022.01.17 |
[Kubernetes] 쿠버네티스 Architecture와 기본 동작 (0) | 2022.01.16 |