Ubuntu 20.04 에서 Kubernetes 설치하기

By | 2022년 10월 20일
Table of Contents

Ubuntu 20.04 에서 Kubernetes 설치하기

몇년 전에는 좀 고생한 기억이 있는데,
이번에는 뭔가 쉽게 되는군요.

감사

보통은 여러 사이트를 참조하여 문서를 작성하기에 출처를 잘 표시하지 않는데,
이 문서는 여기 에서 상당량의 내용을 가져와서 출처를 적어놓습니다.

준비사항

모든 master/node 에 아래 내용이 반영되어 있어야 합니다.

  • 2G 이상의 메모리
  • 2 CPU core 이상
  • 방화벽 off, 보안그룹 설정(AWS인 경우)
  • Swap off (필수)

테스트용 장비 스펙

운영서버가 아니라 테스트를 위한 장비인 경우,
master 는 2G 메모리면 충분한 듯하다.(t3.small 추천)

worker 는 4G 메모리가 최소이고 더 많이 필요할 수 있다.
디스크는 20G 정도는 할당하자.
(메모리는 올리기 쉬운데 디스크는 복잡하다.)

방화벽 off

sudo ufw disable

또는 허용해야할 포트목록을 지정해 줄 수 있다.

# Master
sudo ufw enable
sudo ufw allow 6443/tcp
sudo ufw allow 2379:2380/tcp
sudo ufw allow 10250/tcp
sudo ufw allow 10251/tcp
sudo ufw allow 10252/tcp
sudo ufw status

# Worker
sudo ufw enable
sudo ufw allow 10250/tcp
sudo ufw allow 30000:32767/tcp
sudo ufw status

add-on Weave Net works 을 사용하는 경우 아래 명령을 실행한다.

sudo ufw route allow in on weave out on weave

보안그룹 설정(AWS)

allow-kubernetes 라는 이름의 보안그룹을 생성합니다.
inbound/outbound 는 설정하지 않습니다.

protect-kubernetes 라는 이름의 보안그룹을 생성합니다.
inbound 에 아래 내용을 설정합니다.

  • 유형 : 모든 TCP
  • 포트범위 : 0 – 65535
  • 소스 : allow-kubernetes

allow-kubernetes, protect-kubernetes 를 모든 master/node 에 할당해 줍니다.

Swap off

테스트 용도로 설치하더라도 실행해 주어야 합니다.

sudo swapoff -a && sudo sed -i '/swap/s/^/#/' /etc/fstab

Docker, containerd 설치 (모든 master, worker node)

Kubernetes 는 컨테이너 기반으로 작동하므로,
Docker, containerd 를 선행하여 설치합니다.

여기

Kubernetes 설치

kubelet, kubeadm, kubectl 설치 (모든 master, worker node)

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
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
sudo systemctl daemon-reload
sudo systemctl restart kubelet

kubelet 실행이 실패하는 것은 신경쓰지 않아도 됩니다.,
아래 명령을 실행하면 kubelet 도 정상적으로 실행됩니다.

Control-plane 구성 (master only)

반드시 master 에서만 실행합니다.

sudo kubeadm init

오류가 발생하면 troubleshoot 확인하세요.

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 172.31.16.157:6443 --token ou08ek.xzjXXXXXXXXXXXXX \
        --discovery-token-ca-cert-hash sha256:6e0305d27b12b3f8b51d8e021138d59227124c2XXXXXXXXXXXXXXXX

위 명령을 이용해 node 가 master 에 접속할 수 있습니다.

아래 명령을 설정해 줌으로 해서 sudo 없이 kubectl 을 실행할 수 있습니다.

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

# sudo 를 붙이지 않습니다.
kubectl get nodes
---------------------------
NAME               STATUS   ROLES           AGE    VERSION
ip-172-31-20-177   NotReady   control-plane   79s   v1.25.3

NotReady 는 무시해도 됩니다.
아래 플러그인을 설치하면 해결됩니다.

Pod network 애드온 설치 (master only)

Pod 간 통신을 위한 add-on Weave Net works 을 설치합니다.

kubectl apply -f https://github.com/weaveworks/weave/releases/download/v2.8.1/weave-daemonset-k8s.yaml

30초 에서 1분 정도 지나면 아래처럼 Ready 로 상태가 변경됩니다.

kubectl get nodes
NAME               STATUS   ROLES           AGE    VERSION
ip-172-31-20-177   Ready    control-plane   3m5s   v1.25.3

Worker Node 를 구성하지 않을 경우 (master only)

테스트 용도로 하나의 서버에 마스터 노드만 구성하고,
그 위에 Pod 를 실행하려는 경우 아래 명령을 실행해 줍니다.

# kubectl taint nodes --all node-role.kubernetes.io/master-
kubectl taint nodes --all node-role.kubernetes.io/control-plane-

Worker node 구성 (worker node only)

아래 명령으로 Worker node 를 등록합니다.

sudo 를 반드시 붙여서 실행해야 합니다.

sudo kubeadm join 172.31.16.157:6443 --token ou08ek.xzjXXXXXXXXXXXXX \
        --discovery-token-ca-cert-hash sha256:6e0305d27b12b3f8b51d8e021138d59227124c2XXXXXXXXXXXXXXXX

Master 에서 노드 확인하기 (master)

아래 명령으로 정상적으로 Node 가 등록된 것을 확인할 수 있습니다.

kubectl get nodes
---------------------------
NAME               STATUS   ROLES           AGE   VERSION
ip-172-31-16-213   Ready    <none>          59s   v1.25.3
ip-172-31-20-177   Ready    control-plane   11m   v1.25.3

자동 완성 설정 (master)

source <(kubectl completion bash)
echo "source <(kubectl completion bash)" >> ~/.bashrc

nginx 실행 및 삭제

테스트를 위해 nginx 를 실행시켜 봅니다.

port 정리

  • nodePort : 외부 포트

    아무 노드에서도 이 포트로 접근하면 service port 로 포워딩된다.
    반드시 외부아이피 + 노드포트로 접속해야 한다.

  • port : 서비스 포트

    pod port 로 포워딩하기 위한 중간 포트
    Worker 노드에서만 사용할 수 있다.
    클러스터아이피 + 서비스포트로 접속해야 한다.

  • containerPort(targetPort) : Pod 의 포트

    Pod 의 포트이다.
    Worker 노드에서만 사용할 수 있다.
    Pod아이피 + 컨테이너포트로 접속해야 한다.

전체적인 흐름은 nodePort -> port -> containerPort(targetPort) 가 된다.

kubectl get pod -o yaml | grep " podIP: "
    podIP: 10.32.0.5
    podIP: 10.32.0.6
    podIP: 10.32.0.7

kubectl get svc | grep my-nginx
my-nginx     NodePort    10.110.214.52   <none>        8080:31001/TCP   69s

머신 내부에서는 podIP + 컨테이너포트 를 통해 바로 접속 가능하다.
Master 에서는 접속할 수 없다.
Worker 노드에서만 접속가능하다.

curl 10.32.0.5

머신 내부에서는 클러스터아이피 + 서비스포트 를 통해 접속 가능하다.
Master 에서는 접속할 수 없다.
Worker 노드에서만 접속가능하다.

NodePort 로는 외부에서만 접속가능하다.
NodePort 로 접속하려면 localhost 와 같이 클러스터 외부 아이피/도메인을 이용해야 한다.

# OK
curl 10.97.13.166:8080

# Timeout
curl 10.97.13.166:31001

# OK
curl localhost:31001/

Deployment 생성

vi nginx-deployment.yaml
---------------------------
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3                 # 3개의 pod
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80   # 컨테이너 포트(pod 포트)
---------------------------
kubectl apply -f nginx-deployment.yaml

3 개의 인스턴스가 실행중인 것을 확인할 수 있습니다.

kubectl get deployments
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           21s
kubectl get pod
kubectl get pod -o yaml | grep nodeName
kubectl get pod -o yaml | grep " podIP: "

nginx 가 실행중인것을 확인할 수 있습니다.
Worker 노드에서만 접속이 가능하다.
Master 노드에서는 접속할 수 없다.

curl 10.44.0.1 | grep title
curl 10.44.0.2 | grep title
curl 10.44.0.3 | grep title

Service 생성

k8s 내부 아이피를 이용해 접속이 가능하지만,
클러스터 외부에서 접속하기 위해서는 서비스를 생성해야 합니다.

vi nginx-svc.yaml
---------------------------
apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  type: NodePort     # 서비스 타입
  ports:
  - nodePort: 31001  # 외부 포트
    port: 8080       # 서비스 포트
    targetPort: 80   # 컨테이너 포트(pod 포트)
    protocol: TCP
    name: http
  selector:
    app: nginx
---------------------------
kubectl apply -f nginx-svc.yaml

nodePort 에 할당된 외부포트 31001 를 통해 nginx 에 접근이 가능합니다.

kubectl get svc | grep my-nginx
my-nginx     NodePort    10.110.214.52   <none>        8080:31001/TCP   69s

http://<node 서버 아이피>:31001/ 로 접속하면 nginx 가 실행된 것을 확인할 수 있다.

Worker 노드에서는 노드아이피 + 서비스포트로 접속이 가능하다.
노드아이피 + 노드포트로는 접속할 수 없다.

Master 노드 Worker 의 외부아이피 + 노드포트 를 이용해 접속할 수 있다.

nginx 삭제

# service 삭제
kubectl delete -n default service my-nginx

# deployments 삭제
kubectl get deployments
kubectl delete deployments nginx-deployment

containerd 명령어

기존 docker 명령어 대신 containerd 를 이용해 도커를 확인할 수 있습니다.

sudo ctr namespaces list
sudo ctr -n k8s.io container list
sudo ctr -n k8s.io image list

Web UI(dashboard) 설치하기 (master)

dashboard 설치

wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.5.0/aio/deploy/recommended.yaml
vi recommended.yaml
---------------------------
kind: Service
apiVersion: v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
spec:
  type: NodePort                     # 이거
  ports:
    - port: 443
      targetPort: 8443
      nodePort: 30239                # 이거
  selector:
    k8s-app: kubernetes-dashboard
---------------------------
kubectl apply -f recommended.yaml
kubectl get deployments -n kubernetes-dashboard
kubectl get pod -n kubernetes-dashboard

kubectl describe pod kubernetes-dashboard-XXXXXXXXXXXX -n kubernetes-dashboard
---------------------------
  Normal  Pulled     2m    kubelet            Successfully pulled image "kubernetesui/dashboard:v2.5.0" in 7.729310884s
  Normal  Created    2m    kubelet            Created container kubernetes-dashboard
  Normal  Started    119s  kubelet            Started container kubernetes-dashboard
kubectl get svc -n kubernetes-dashboard

master 가 아니라 worker node 아이피로 접속합니다.

https://<worker node 아이피>:30239/

만약 Chrome 으로 접속중이라면 인증오류무시하기 버튼이 표시가 안됩니다.
이럴 때는 웹사이트 화면 아무곳이나 클릭 후 thisisunsafe 라고 타이핑하면 접속이 됩니다.

계정 생성

vi dashboard-user.yaml
---------------------------
apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin-user
  namespace: kubernetes-dashboard

---

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: admin-user
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: admin-user
  namespace: kubernetes-dashboard
---------------------------
kubectl apply -f dashboard-user.yaml
kubectl -n kubernetes-dashboard create token admin-user

생성한 token 으로 dashboard 에 접속할 수 있습니다.

위에서 생성한 token 은 1회성입니다.
유효시간이 경과하면 위 명령으로 token 을 재발급합니다.

token ttl 늘리기

쓰다보면 지나치다 싶을 정도로 token ttl 이 짧습니다.
아래 방법으로 ttl 을 12시간으로 늘릴 수 있습니다.

kubectl -n kubernetes-dashboard edit deployments kubernetes-dashboard
---------------------------
    spec:
      securityContext:
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: kubernetes-dashboard
          image: kubernetesui/dashboard:v2.5.0
          imagePullPolicy: Always
          ports:
            - containerPort: 8443
              protocol: TCP
          args:
            - --auto-generate-certificates
            - --namespace=kubernetes-dashboard
            - --token-ttl=43200                   # 여기
---------------------------

Kubernetes Metrics Server

kube-apiserver 설정을 수정합니다.
k8s 가 파일변경을 모니터링해서 kube-apiserver 를 자동으로 재시작해 줍니다.

sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml
---------------------------
spec:
  containers:
  - command:
    - kube-apiserver
    - --enable-aggregator-routing=true         # 여기
    - --advertise-address=172.31.20.177
    - --allow-privileged=true
    - --authorization-mode=Node,RBAC
---------------------------

self signed 인증서를 허용하도록 수정합니다.

wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

vi components.yaml
---------------------------
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server
  namespace: kube-system
spec:
  selector:
    matchLabels:
      k8s-app: metrics-server
  strategy:
    rollingUpdate:
      maxUnavailable: 0
  template:
    metadata:
      labels:
        k8s-app: metrics-server
    spec:
      containers:
      - args:
        - --kubelet-insecure-tls                            # 여기
        - --cert-dir=/tmp
        - --secure-port=4443
---------------------------

kubectl apply -f components.yaml
kubectl get deployment metrics-server -n kube-system
---------------------------
NAME             READY   UP-TO-DATE   AVAILABLE   AGE
metrics-server   1/1     1            1           44m

kubectl logs deployment/metrics-server -n kube-system
kubectl top pod
NAME                                CPU(cores)   MEMORY(bytes)
nginx-deployment-7fb96c846b-2mpg7   0m           1Mi
nginx-deployment-7fb96c846b-d222z   0m           1Mi
nginx-deployment-7fb96c846b-zgqbp   0m           1Mi

kubectl top nodes
NAME               CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
ip-172-31-16-213   29m          1%     1087Mi          28%
ip-172-31-20-177   103m         5%     1407Mi          36%

오류가 발생하면 troubleshoot 확인하세요.

troubleshoot

kubeadm init 중 오류발생

getting status of runtime: rpc error: code = Unimplemented desc = unknown service runtime.v1alpha2.RuntimeService

해결책

아래 명령을 master/node 에 실행합니다.

sudo rm /etc/containerd/config.toml
sudo systemctl restart containerd

ServiceUnavailable

아래와 같은 오류가 발생하면…

kubectl top pod
Error from server (ServiceUnavailable): the server is currently unable to handle the request (get pods.metrics.k8s.io)

kubectl top nodes
Error from server (ServiceUnavailable): the server is currently unable to handle the request (get pods.metrics.k8s.io)

아래 명령을 수행해 줍니다.

kubectl edit deployment.apps/metrics-server -n kube-system
---------------------------
      dnsPolicy: ClusterFirst
      hostNetwork: true
      nodeSelector:
---------------------------

localhost:8080 was refused

The connection to the server localhost:8080 was refused - did you specify the right host or port?

아래 명령을 수행해 줍니다.

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

NetworkPluginNotReady

NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: cni plugin not initialized
sudo systemctl restart containerd
kubectl get nodes

token 재발급

생성된 token 은 24시간의 유효기간을 가집니다.
아래 명령으로 토큰을 재발급할 수 있습니다.

kubeadm token list

# Token 값
kubeadm token create

# Hash 값
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'

# join
kubeadm join <172.31.16.157:6443> --token <Token 값> --discovery-token-ca-cert-hash sha256:<Hash 값>

다시 설치

sudo systemctl stop kubelet
sudo kubeadm reset

sudo rm -rf /etc/cni/net.d
sudo rm -rf $HOME/.kube/

Auto-scaling

One thought on “Ubuntu 20.04 에서 Kubernetes 설치하기

답글 남기기