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
-
Node Auto-scaling(Cluster AutuScaler)
https://kubernetes.io/ko/docs/tasks/configmap-secret/_print/
secret