3. Kubernetes 설치
1. VM 인스턴스 생성(공통)
1) UTM 실행 후 VM 인스턴스 생성
- UTM 실행 후 Linux로 VM 인스턴스를 3개 생성한다.
- 이때 부팅 이미지는 Ubuntu 20.04 LTS 버전을 사용한다.
- 각 VM 인스턴스의 CPU는 2, 메모리는 2048MB, 스토리지는 20GB로 설정한다.
- 각 VM 인스턴스의 이름은 Master, Node 1 및 Node 2로 설정한다.
- Master는 Control-plane, Node 1 및 Node 2는 Worker 노드 역할을 한다.
- 이외의 설정은 기본값으로 두고 진행한다.
- OS 설치 과정에서 네트워크를 기본값인 DHCP로 두고, OpenSSH Server 설치 옵션을 선택한다.
- OS 설치가 완료되면 UTM 메인 하단의 CD/DVD를 초기화한 후 재부팅한다.
- 다음의 예시는 Master 기준이며, 설치를 진행할 때 나머지 Node 1과 Node 2도 같은 방식으로 적용한다.
saemc
에서root
로 변경한 후 진행한다.
- Ubuntu 패키지 매니저를 업데이트한다.
2) 네트워크 설정
- 네트워크 관리 툴을 설치한다.
- 현재 할당된 IP를 확인하면 네트워크 어댑터
enp0s10
의 IP 주소가192.168.64.27
라는 것을 확인할 수 있다.
enp0s10: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.64.27 netmask 255.255.255.0 broadcast 192.168.64.255
inet6 fd2b:c2bc:e566:db7e:88d8:f2ff:fe17:ee81 prefixlen 64 scopeid 0x0<global>
inet6 fe80::88d8:f2ff:fe17:ee81 prefixlen 64 scopeid 0x20<link>
ether 8a:d8:f2:17:ee:81 txqueuelen 1000 (Ethernet)
RX packets 321 bytes 269078 (269.0 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 279 bytes 35918 (35.9 KB)
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 126 bytes 10426 (10.4 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 126 bytes 10426 (10.4 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
- 라우터를 확인한다.
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.64.1 0.0.0.0 UG 100 0 0 enp0s10
192.168.64.0 0.0.0.0 255.255.255.0 U 0 0 0 enp0s10
192.168.64.1 0.0.0.0 255.255.255.255 UH 100 0 0 enp0s10
- DNS를 확인한다.
Global
LLMNR setting: no
MulticastDNS setting: no
DNSOverTLS setting: no
DNSSEC setting: no
DNSSEC supported: no
DNSSEC NTA: 10.in-addr.arpa
16.172.in-addr.arpa
168.192.in-addr.arpa
17.172.in-addr.arpa
18.172.in-addr.arpa
19.172.in-addr.arpa
20.172.in-addr.arpa
21.172.in-addr.arpa
22.172.in-addr.arpa
23.172.in-addr.arpa
24.172.in-addr.arpa
25.172.in-addr.arpa
26.172.in-addr.arpa
27.172.in-addr.arpa
28.172.in-addr.arpa
29.172.in-addr.arpa
30.172.in-addr.arpa
31.172.in-addr.arpa
corp
d.f.ip6.arpa
home
internal
intranet
lan
local
private
test
Link 2 (enp0s10)
Current Scopes: DNS
DefaultRoute setting: yes
LLMNR setting: yes
MulticastDNS setting: no
DNSOverTLS setting: no
DNSSEC setting: no
DNSSEC supported: no
Current DNS Server: 192.168.64.1
DNS Servers: 192.168.64.1
fe80::f84d:89ff:fe08:fe64
- 이제 동적 할당된 각 IP를 고정 IP로 변경한다.
- 기본 값은 다음과 같다.
- 위의 내용을 다음과 같이 수정하면 되는데, 이때
enp0s10
의addresses
부분만 다르게 설정하면 된다. - 변경할 고정 IP 주소로, Master는
192.168.64.4/24
, Node 1은192.168.64.5/24
, Node 2는192.168.64.6/24
로 설정한다.
# This is the network config written by 'subiquity'
network:
version: 2
renderer: networkd
ethernets:
enp0s10:
dhcp4: no
addresses: [192.168.64.4/24]
routes:
- to: 0.0.0.0/0
via: 192.168.64.1
metric: 100
- to: 192.168.64.1/32
via: 0.0.0.0
metric: 100
nameservers:
addresses: [8.8.8.8, 8.8.4.4]
- 고정 IP로 적용하기 위해 다음 명령어를 입력한다.
ifconfig
,route
,resolvectl
명령을 각각 실행하면 변경된 것을 확인할 수 있다.
- 각 VM 인스턴스의
/etc/hostname
의 내용을master.example.com
,node1.example.com
,node2.example.com
으로 수정한다.
- 모든
/etc/hosts
의 내용은 모두 동일한데, 이미 작성되어 있는 IPv6 윗부분을 수정하면 된다.
127.0.0.1 localhost
192.168.64.4 master.example.com master
192.168.64.5 node1.example.com node1
192.168.64.6 node2.example.com node2
- 모든 VM 인스턴스를 재부팅한다.
- 또는 종료한 후 재시작한다.
3) 호스트(OSX) 터미널에서 SSH 접속
- VM 인스턴스 쉘 자체에서는 작업하기 어려우므로 호스트의 터미널에서 SSH로 접속한다.
- 이때 각 VM 인스턴스는 실행 중이어야 한다.
- 호스트의 터미널 3개를 열어 각 터미널에 다음과 같이 순서대로 입력한다.
- 각 쉘에 진입한 후
root
계정으로 작업한다.
2. Docker 설치(공통)
- https://docs.docker.com/engine/install/ubuntu/를 따라 Docker 설치를 진행한다.
sudo apt-get update && \
sudo apt-get install ca-certificates curl gnupg lsb-release -y && \
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg && \
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null && \
sudo apt-get update && \
sudo apt-get install docker-ce docker-ce-cli containerd.io -y && \
sudo docker --version
/etc/docker
디렉터리가 존재하는지 확인한다.
- 존재한다면 다음으로 넘어가고, 존재하지 않는다면 다음의 명령어를 입력한다.
- 컨테이너의
cgroup
관리에systemd
를 사용하도록 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 재시작과 부팅 시 자동 실행되도록 설정한다.
Synchronizing state of docker.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable docker
3. Kubernetes 설치(공통)
- https://kubernetes.io/ko/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#check-required-ports를 따라 Kubernetes 설치를 진행한다.
1) 준비 사항
- 호환되는 리눅스 머신. 쿠버네티스 프로젝트는 데비안 기반 배포판, 레드햇 기반 배포판, 그리고 패키지 매니저를 사용하지 않는 경우에 대한 일반적인 가이드를 제공한다.
- 2 GB 이상의 램을 장착한 머신. (이 보다 작으면 사용자의 앱을 위한 공간이 거의 남지 않음)
- 2 이상의 CPU.
- 클러스터의 모든 머신에 걸친 전체 네트워크 연결. (공용 또는 사설 네트워크면 괜찮음)
- 모든 노드에 대해 고유한 호스트 이름, MAC 주소 및
product_uuid
. 자세한 내용은 여기를 참고한다. - 컴퓨터의 특정 포트들 개방. 자세한 내용은 여기를 참고한다.
- 스왑의 비활성화.
kubelet
이 제대로 작동하게 하려면 반드시 스왑을 사용하지 않도록 설정한다.
- 방화벽이 켜져 있는 경우 다음과 같이 끈다.
2) MAC 주소 및 product_uuid
가 모든 노드에 대해 고유한지 확인
- 사용자는
ip link
또는ifconfig -a
명령을 사용하여 네트워크 인터페이스의 MAC 주소를 확인할 수 있다. product_uuid
는sudo cat /sys/class/dmi/id/product_uuid
명령을 사용하여 확인할 수 있다.
3) 네트워크 어댑터 확인
- 네트워크 어댑터가 두 개 이상이고, 쿠버네티스 컴포넌트가 디폴트 라우트(default route)에서 도달할 수 없는 경우, 쿠버네티스 클러스터 주소가 적절한 어댑터를 통해 이동하도록 IP 경로를 추가하는 것이 좋다.
4) iptables
가 브리지된 트래픽을 보게 하기
br_netfilter
모듈이 로드되었는지 확인한다.lsmod | grep br_netfilter
를 실행하면 된다. 명시적으로 로드하려면sudo modprobe br_netfilter
를 실행한다.- 리눅스 노드의
iptables
가 브리지된 트래픽을 올바르게 보기 위한 요구 사항으로,sysctl
구성에서net.bridge.bridge-nf-call-iptables
가1
로 설정되어 있는지 확인해야 한다. 다음은 예시이다.
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
* 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 = 2
net.ipv4.conf.all.rp_filter = 2
* Applying /etc/sysctl.d/10-ptrace.conf ...
kernel.yama.ptrace_scope = 1
* Applying /etc/sysctl.d/10-zeropage.conf ...
vm.mmap_min_addr = 32768
* Applying /usr/lib/sysctl.d/50-default.conf ...
net.ipv4.conf.default.promote_secondaries = 1
sysctl: setting key "net.ipv4.conf.all.promote_secondaries": Invalid argument
net.ipv4.ping_group_range = 0 2147483647
net.core.default_qdisc = fq_codel
fs.protected_regular = 1
fs.protected_fifos = 1
* Applying /usr/lib/sysctl.d/50-pid-max.conf ...
kernel.pid_max = 4194304
* Applying /etc/sysctl.d/99-sysctl.conf ...
* Applying /etc/sysctl.d/k8s.conf ...
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
* 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 ...
5) 필수 포트 확인
- 필수 포트들은 쿠버네티스 컴포넌트들이 서로 통신하기 위해서 열려 있어야 한다. 다음과 같이
telnet
명령을 이용하여 포트가 열려 있는지 확인해 볼 수 있다. - 방화벽이 활성화되어 있지 않은 경우 무시해도 된다.
6) 런타임 설치
- 파드에서 컨테이너를 실행하기 위해, 쿠버네티스는 컨테이너 런타임을 사용한다.
- 위에서 런타임으로 Docker를 설치했기 때문에 무시해도 된다.
7) kubeadm
, kubelet
및 kubectl
- 모든 머신에 다음 패키지들을 설치한다.
1] kubeadm
- 클러스터를 부트스트랩하는 명령이다.
2] kubelet
- 클러스터의 모든 머신에서 실행되는 파드와 컨테이너 시작과 같은 작업을 수행하는 컴포넌트이다.
3] kubectl
- 클러스터와 통신하기 위한 커맨드 라인 유틸리티이다.
kubeadm
은kubelet
또는kubectl
을 설치하거나 관리하지 않으므로,kubeadm
이 설치하려는 쿠버네티스 컨트롤 플레인의 버전과 일치하는지 확인해야 한다.- 그렇지 않으면, 예상치 못한 버그 동작으로 이어질 수 있는 버전 차이(skew)가 발생할 위험이 있다.
- 그러나,
kubelet
과 컨트롤 플레인 사이에 하나의 마이너 버전 차이가 지원되지만,kubelet
버전은 API 서버 버전 보다 높을 수 없다. 예를 들어, 1.7.0 버전의kubelet
은 1.8.0 API 서버와 완전히 호환되어야 하지만, 그 반대의 경우는 아니다. kubectl
설치에 대한 정보는 kubectl 설치 및 설정을 참고한다.
apt
패키지 색인을 업데이트하고, 쿠버네티스apt
리포지터리를 사용하는 데 필요한 패키지를 설치한다.
- 구글 클라우드의 공개 사이닝 키를 다운로드 한다.
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
- 쿠버네티스
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
- 위의 코드들을 다음과 같이 한 번에 입력할 수 있다.
sudo apt-get update && \
sudo apt-get install -y apt-transport-https ca-certificates curl && \
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg && \
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 && \
sudo apt-get update && \
sudo apt-get install -y kubelet kubeadm kubectl && \
sudo apt-mark hold kubelet kubeadm kubectl
kubelet
은 이제kubeadm
이 수행할 작업을 알려 줄 때까지 크래시루프(crashloop) 상태로 기다려야 하므로 몇 초마다 다시 시작된다.
8) cgroup 드라이버 구성
- 컨테이너 런타임과
kubelet
은 "cgroup 드라이버"라는 속성을 갖고 있으며, cgroup 드라이버는 리눅스 머신의 cgroup 관리 측면에 있어서 중요하다. - 컨테이너 런타임과
kubelet
의 cgroup 드라이버를 일치시켜야 하며, 그렇지 않으면kubelet
프로세스에 오류가 발생한다. - 위에서 Docker를 설치할 때 구성을 적용했으므로 무시한다.
4. kubeadm
을 사용하여 Kubernetes 클러스터 생성
- https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/를 따라 진행한다.
1) Control-plane 컴포넌트 생성(Master)
- Master VM 인스턴스에서만 다음 명령어를 입력하여 Control-plane 기본 컴포넌트를 생성한다.
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.64.4:6443 --token v5ungx.b961c7wbu2spzpif \
--discovery-token-ca-cert-hash sha256:c3950cf2600b792618b7e019201aa7581d287cfe4c742b6ab99fb5b1b9a5a284
- 위의 출력에서 확인할 수 있듯이 클러스터를 사용하려면 다음 명령어를 입력한다.
mkdir -p $HOME/.kube && \
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config && \
sudo chown $(id -u):$(id -g) $HOME/.kube/config
- 다른 Worker 노드들이 Control-plane에 조인 시 필요한 토큰을 다음과 같이 저장한다.
kubeadm join 192.168.64.4:6443 --token v5ungx.b961c7wbu2spzpif \
--discovery-token-ca-cert-hash sha256:c3950cf2600b792618b7e019201aa7581d287cfe4c742b6ab99fb5b1b9a5a284
2) CNI(Container Network Interface) 설치
- https://www.weave.works/docs/net/latest/kubernetes/kube-addon/를 따라 진행한다.
- CNI로 Weave Net 플러그인을 적용할 것이다.
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"
serviceaccount/weave-net created
clusterrole.rbac.authorization.k8s.io/weave-net created
clusterrolebinding.rbac.authorization.k8s.io/weave-net created
role.rbac.authorization.k8s.io/weave-net created
rolebinding.rbac.authorization.k8s.io/weave-net created
daemonset.apps/weave-net created
- Weave Net이 적용되었는지 다음과 같이 확인할 수 있다.
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-64897985d-72z6k 1/1 Running 0 8m17s
kube-system coredns-64897985d-zb45r 1/1 Running 0 8m17s
kube-system etcd-master.example.com 1/1 Running 0 8m21s
kube-system kube-apiserver-master.example.com 1/1 Running 0 8m20s
kube-system kube-controller-manager-master.example.com 1/1 Running 0 8m21s
kube-system kube-proxy-wjnpw 1/1 Running 0 8m17s
kube-system kube-scheduler-master.example.com 1/1 Running 0 8m20s
kube-system weave-net-4ptn4 2/2 Running 1 (46s ago) 53s
3) Worker 노드를 Control-plane(Master)에 조인
- 먼저 Control-plane(Master VM 인스턴스)에서 다음과 같이 연결된 노드를 확인한다.
- 위에서 저장한 토큰을 각 Worker 노드(Node 1 및 Node 2)에 입력한다.
kubeadm join 192.168.64.4:6443 --token v5ungx.b961c7wbu2spzpif \
--discovery-token-ca-cert-hash sha256:c3950cf2600b792618b7e019201aa7581d287cfe4c742b6ab99fb5b1b9a5a284
[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'
W0221 09:29:35.931319 6982 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.
- Control-plane에서 다음 명령어를 입력하면 연결된 Worker 노드를 확인할 수 있다.
NAME STATUS ROLES AGE VERSION
master.example.com Ready control-plane,master 12m v1.23.4
node1.example.com Ready <none> 96s v1.23.4
node2.example.com Ready <none> 93s v1.23.4
5. kubectl
자동 완성
1) BASH
- 다음과 같이 입력하면 BASH에서 탭 키를 눌러 자동 완성 기능을 사용할 수 있게 된다.
6. 테스트(Master)
- 이제 Control-plane(Master VM 인스턴스)에서
kubectl
을 사용하여 테스트를 진행한다. nginx
Docker 이미지를 이용하여web-server
라는 이름의 파드를 생성한다.
- 생성된 파드를 확인한다.
- 스케일링 테스트를 한다.
- 스케일링된 파드를 확인한다.
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-server-5bc65fc48d-2222q 1/1 Running 0 51s 10.44.0.2 node1.example.com <none> <none>
web-server-5bc65fc48d-bgr8h 1/1 Running 0 2m47s 10.44.0.1 node1.example.com <none> <none>
web-server-5bc65fc48d-dlgxj 1/1 Running 0 51s 10.36.0.1 node2.example.com <none> <none>
- 실행 중인 애플리케이션을 확인한다.
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
web-server 3/3 3 3 3m55s nginx nginx app=web-server
- 만약
root
가 아니라 유저로 작업하는 경우sudo
명령어를 붙여야 한다.