kubeadm
을 사용하여 k8s
클러스터 구성을 실습해 보겠습니다.
실습 환경은 AWS Lightsail Linux Ubuntu 20.04 LTS
이며, 2CPU
, 4Gi Memory
스펙을 가진 VM 3대(마스터1 - 워커2)를 사용합니다.
master
노드 구성$ swapoff -a && sed -i '/swap/s/^/#/' /etc/fstab
Ip-[IP]
이니 추후 운영할 때 식별하기가 헷갈리므로 호스트명을 변경해 줍니다.$ sudo vi /etc/cloud/cloud.cfg
...
# preserve_hostname 의 값을 true로 변경해 줍니다.
preserve_hostname: false
$ sudo hostnamectl set-hostname k8s-master-1
$ sudo modprobe br_netfilter
$ 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 reboot
$ curl -fsL https://get.docker.com | sh -
$ sudo usermod -aG docker $USER
.. 이후 재 로그인
kubeadm
을 설치합니다. 순서대로 입력합니다.$ 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
kubeadm
을 사용하여 클러스터를 초기화합니다. CNI 플러그인으로는 kube-flannel을 사용할것이기 때문에 pod-network-cidr
은 kube-flannel
에서 제공해주는 기본값을 사용합니다.$ sudo kubeadm init --pod-network-cidr=10.244.0.0/16
unknown service runtime.v1alpha2.RuntimeService
과 같은 오류가 발생하게 되면 컨테이너 런타임에서 CRI 기능을 비활성화 한 경우이므로 다음 추가 작업을 진행합니다.$ sudo vi /etc/containerd/config.toml
# 아래 줄을 주석 처리합니다.
disabled_plugins = ["cri"]
또는,
$ sudo rm /etc/containerd/config.toml
작업 후에는 컨테이너 서비스를 재시작 해 줍니다.
$ sudo systemctl restart containerd.service
kubeadm join 172.26.8.85:6443 --token twfgx... \
--discovery-token-ca-cert-hash sha256:...
kubectl
명령어를 위한 설정을 진행합니다.$ mkdir ~/.kube
$ sudo cp /etc/kubernetes/admin.conf ~/.kube/config
$ sudo chmod 644 ~/.kube/config
$ sudo chown $(id -u):$(id -g) ~/.kube/config
$ echo 'export KUBECONFIG="$HOME/.kube/config"' >> ~/.bashrc
CNI
플러그인을 설치하여야 합니다.$ kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
$ kubectl get pods --all-namespaces
===
NAME READY STATUS RESTARTS AGE
coredns-6d4b75cb6d-grbrk 1/1 Running 0 1m
coredns-6d4b75cb6d-m74v4 1/1 Running 0 1m
etcd-k8s-master 1/1 Running 0 1m
kube-apiserver-k8s-master 1/1 Running 0 1m
kube-controller-manager-k8s-master 1/1 Running 0 1m
kube-flannel-ds-9bjp6 1/1 Running 0 1m
kube-flannel-ds-fcw8g 1/1 Running 0 1m
kube-flannel-ds-k2qwt 1/1 Running 0 1m
kube-proxy-plvdb 1/1 Running 0 1m
kube-proxy-v8rp5 1/1 Running 0 1m
kube-proxy-wbr5w 1/1 Running 0 1m
kube-scheduler-k8s-master 1/1 Running 0 1m
coredns
와 kube-flannel
이 정상적으로 Running
상태가 되어야 합니다.worker-1
, worker-2
노드 구성master
노드의 kubeadm init
명령어 이전까지는 같습니다.
master
노드를 구성했을 때 복사해 둔, join 명령어를 사용합니다.$ sudo kubeadm join 172.26.8.85:6443 --token twfgx... \
--discovery-token-ca-cert-hash sha256:...
master
노드에서 연결 상태를 확인합니다.$ kubectl get nodes
===
NAME STATUS ROLES AGE VERSION
k8s-master Ready control-plane 8m v1.24.1
k8s-worker-1 Ready <none> 3m v1.24.1
k8s-worker-2 Ready <none> 1m v1.24.1
kubectl
명령어는 master
노드에서 실행하고, worker-1
, worker-2
노드는 파드를 실행하기만 합니다. 이를 위해서는 어느 노드에서 파드를 구동할지를 정하기 위해서 레이블을 지정해 주어야 합니다.
# 노드의 타입을 worker 로 지정합니다.
$ kubectl label nodes k8s-worker-1 type=worker
$ kubectl label nodes k8s-worker-2 type=worker
$ kubectl get nodes --show-labels
===
NAME STATUS ROLES AGE VERSION LABELS
k8s-master Ready control-plane 14m v1.24.1 beta.kubernetes.io/arch=amd64,...
k8s-worker-1 Ready <none> 9m v1.24.1 ..,kubernetes.io/os=linux,type=worker
k8s-worker-2 Ready <none> 7m v1.24.1 ..,kubernetes.io/os=linux,type=worker
nginx
서비스를 배포해 줍니다.# nginx.yml
---
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- protocol: TCP
port: 80
targetPort: 80
selector:
app: nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: Always
ports:
- containerPort: 80
affinity:
# 파드를 구동할 노드를 선택합니다.
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
# 레이블의 key가 type이고, value가 worker 인 노드
- matchExpressions:
- key: type
operator: In
values:
- worker
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
values:
- nginx
operator: In
# 호스트명은 각 노드에 고유하기 때문에 하나의 노드에는
# 하나의 파드만 할당됩니다.
topologyKey: kubernetes.io/hostname
# 스케일러 (옵셔널)
---
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: nginx
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx
minReplicas: 2
maxReplicas: 4
targetCPUUtilizationPercentage: 50
$ kubectl apply -f nginx.yml
$ kubectl get pods -o wide
===
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-794b7556d9-pf7px 1/1 Running 0 4m 10.244.2.2 k8s-worker-2 <none> <none>
nginx-794b7556d9-szf8v 1/1 Running 0 4m 10.244.1.2 k8s-worker-1 <none> <none>
의도한 대로 각 worker 노드에서 잘 동작하고 있음을 확인할 수 있습니다.