2021–01–13 업데이트: Ubuntu 20.04, Kubernetes 1.23기준으로 업데이트
테스트 목적으로 Kubernetes 클러스터를 생성한다면 microk8s나 minikube 같은 편리한 방법들이 있다. 하지만 클라우드가 아닌 일반 Bare-metal 환경일지라도 확장성을 고려한다거나 좀 더 정밀하게 제어하고 싶다면 kubeadm으로 Kubernetes 클러스터를 생성할 수 있다.
OS 설치
여기서는 Ubuntu 20.04 LTS Server 버전을 사용하였다.
설치 문서에 보면 Swap 기능을 비활성화시키라고 한다. 다음과 같은 명령을 입력하자.
sudo swapoff -a
재부팅을 해도 계속 비활성화되도록 /etc/fstab
에서도 swap 관련 라인이 있다면 제거하자.
Docker 설치
여러 가지 컨테이너 런타임 중에 하나를 설치해야 하는데 가장 익숙한 Docker를 설치해보자. 이 문서를 따라서 다음 명령을 차례대로 수행한다.
sudo apt-get update
sudo apt-get install \
ca-certificates \
curl \
gnupg \
lsb-releasecurl -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/nullsudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.iocat <<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
sudo systemctl enable docker
sudo systemctl daemon-reload
sudo systemctl restart docker
docker version
명령어나 docker container ls
명령 등으로 문제가 없는지 확인한다.
sudo docker version
sudo docker run hello-world
sudo docker image ls
sudo docker container ls
root
계정 외에도 docker
명령을 사용하도록 하려면 다음 명령을 입력한다.
sudo usermod -aG docker $USER
로그아웃 & 로그인 하면 적용된다.
kubeadm/kubelet/kubectl 설치
이 문서를 따라 다음 명령어를 차례대로 입력한다.
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curlsudo 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.listsudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
Kubernetes 클러스터 생성
본격적인 클러스터 생성 전에 Network Addon을 선택해야 한다. 여기서는 Flannel을 선택하였다. 애드온 설명과 Flannel 설명을 보면 처음 kubeadm init
을 할 때 반드시 --pod-network-cidr=10.244.0.0/16
옵션을 지정하라고 되어 있다.
또한 AWS 같은 환경에 설치하면서 외부에서 kubectl
로 접속하고 싶은 경우 외부 IP 혹은 도메인 이름을 미리 --apiserver-cert-extra-sans=kube.example.org
처럼 옵션에 추가하는것이 편하다.
이제 준비가 끝났으니 설치 문서에 따라 클러스터를 생성해 보자.
sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-cert-extra-sans=kube.example.org
잠시 시간이 지나면 설치가 완료되고 다음과 같은 가이드 내용이 표시된다.
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/configAlternatively, if you are the root user, you can run: export KUBECONFIG=/etc/kubernetes/admin.confYou 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.31.26.245:6443 --token cml8w5.aem9su86pztp735y \
--discovery-token-ca-cert-hash sha256:15bd2983695a078b8c664e2aee482692da171881789682871f8bcd898c83e2d4
설명해주는 데로 자신의 홈디렉토리 아래 설정 파일을 복사한다.
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
이제 다음 명령어를 입력해 보자.
kubectl get pods --all-namespaces
다음과 같이 현재 생성된 모든 POD가 표시된다.
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-64897985d-29kvh 0/1 Pending 0 67s
kube-system coredns-64897985d-d6ptk 0/1 Pending 0 67s
kube-system etcd-ip-172-31-26-245 1/1 Running 0 80s
kube-system kube-apiserver-ip-172-31-26-245 1/1 Running 0 80s
kube-system kube-controller-manager-ip-172-31-26-245 1/1 Running 0 80s
kube-system kube-proxy-52r7c 1/1 Running 0 67s
kube-system kube-scheduler-ip-172-31-26-245 1/1 Running 0 80s
coredns
는 생성이 완료되지 않고 Pending된 것을 볼 수 있다.
이제 다음 명령어로 Flannel Network Addon을 설치해 보자.
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
잠시 기다리면 다음과 같이 kube-flannel
POD가 생성되고 coredns
도 Running
상태가 된다.
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-5644d7b6d9-c5mn2 1/1 Running 0 8m8s
kube-system coredns-5644d7b6d9-s2rwt 1/1 Running 0 8m8s
kube-system etcd-ubuntu 1/1 Running 0 7m1s
kube-system kube-apiserver-ubuntu 1/1 Running 0 7m1s
kube-system kube-controller-manager-ubuntu 1/1 Running 0 7m4s
kube-system kube-flannel-ds-amd64-hwdfq 1/1 Running 0 93s
kube-system kube-proxy-fsgmj 1/1 Running 0 8m8s
kube-system kube-scheduler-ubuntu 1/1 Running 0 7m25s
단일 노드 클러스터이기 때문에 이 노드에 일반 POD도 띄울 수 있게 다음 명령어를 입력한다.
kubectl taint nodes --all node-role.kubernetes.io/master-
이제 노드 외부에서도 kubectl
명령으로 접속할 수 있도록 .kube/config 파일을 외부에 복사해서 테스트 해보자. 만약 config 파일 안에 서버 주소가 사설 IP 였다면 --apiserver-cert-extra-sans
옵션으로 지정했던 DNS 주소로 교체한다.
Ingress 설치
설치
Bare-metal 용 문서를 따라 NGINX Ingress를 설치해 보자.
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.0/deploy/static/provider/baremetal/deploy.yaml
NodePort 사용
기본 설치는 NodePort를 사용하게 되어 있다. 다음 명령으로 몇 번 포트가 열려 있는지 확인한다.
kubectl -n ingress-nginx get svc
80, 443 포트가 외부 몇 번 포트로 맵핑되었는지 확인한다.
HostNetwork 사용
외부에서 80/443포트를 사용하여 접속하려면 이 부분에서 설명해 주는 것처럼 hostNetwork 옵션을 켜야 한다. 다음 명령어로 직접 수정해 보자.
kubectl edit deploy/nginx-ingress-controller -n ingress-nginx
다음과 같이 파일을 편집한다.
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
hostNetwork: true
containers:
- args:
브라우저나 curl
을 사용해 80포트에 접속되는지 확인해 본다.
Dashboard 설치
설치
이 문서를 따라 다음 명령어를 입력하여 Dashboard를 설치한다.
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.4.0/aio/deploy/recommended.yaml
테스트 접속
로컬 머신이 kubectl
로 접속 가능한 상태라면 다음 명령으로 프록시를 실행한다.
kubectl proxy
그리고 http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/ 주소로 접속하면 대시보드 로그인 화면을 볼 수 있다.
외부 오픈
외부 접속은 https를 통해서만 가능하다. SSL 인증서를 준비하고 다음 명령어로 등록한다.
kubectl create secret tls example.com --key privkey.pem --cert fullchain.pem -n kubernetes-dashboard
다음과 같은 manifest 파일을 생성 후 적용한다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: kubernetes-dashboard
namespace: kubernetes-dashboard
annotations:
kubernetes.io/ingress.class: "nginx"
kubernetes.io/tls-acme: "true"
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
nginx.ingress.kubernetes.io/server-snippet: |
proxy_ssl_verify off;
spec:
tls:
- hosts:
- kube.example.com
secretName: example.com
rules:
- host: kube.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: kubernetes-dashboard
port:
number: 443
계정 생성
이 문서의 내용처럼 접속을 위한 토큰을 얻기 위해 관리자 계정을 만들어 보자.
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 -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}')
브라우저로 접속하여 토큰으로 로그인이 잘 되는지 확인한다.
Metric Server 설치
노드나 파드들의 CPU, 메모리 사용량 등을 확인할 수 있도록 Metric Server를 설치한다.
kubelet이 공식 인증서를 사용하는 상태가 아니기 때문에 manifest를 바로 적용하지 말고 다운 받아서 수정하다.
curl -LO https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
파일을 열고 아래 부분을 찾아서 --kubelet-insecure-tls
옵션을 추가한다.
spec:
containers:
- args:
- --cert-dir=/tmp
- --secure-port=4443
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --kubelet-use-node-status-port
- --metric-resolution=15s
- --kubelet-insecure-tls
수정한 파일을 적용한다.
kubectl apply -f components.yaml
설치하고 시간이 조금 지나면 kubectl top node
등을 사용할 수 있고 대시보드에도 정보가 표시된다.
Rook/Ceph 설치
Persistent Volume을 사용하기 위해서 Rook를 설치해 보자. 1.3 버전 부터는 일반 디렉토리를 사용하지 못 하고 포멧되지 않은 디스크나 파티션을 준비해야 한다.
이 문서에 나오는 것처럼 필요한 manifest들을 모두 적용한다. 단 cluster.yaml
을 최소 3개의 노드를 필요로 하므로 테스트 용도인 cluster-test.yaml
을 사용하자.
git clone --single-branch --branch v1.8.2 https://github.com/rook/rook.git
cd rook/deploy/examples
kubectl create -f crds.yaml -f common.yaml -f operator.yaml
kubectl create -f cluster-test.yaml
kubectl create -f csi/rbd/storageclass-test.yaml
Dashboard에 들어가서 rook-ceph
네임스페이스에 있는 POD가 생성되길 기다린다. (처음에 operator POD가 생성되고 기다리면 대략 8개 정도의 POD가 생성된다.) 생성이 완료되면 PV를 사용하는 예제를 적용해 보자.
kubectl apply -f mysql.yaml
PV를 생성할 때 매번 storageclass
를 rook-ceph-block
로 지정하는것은 불편하므로 다음과 같이 설정을 수정해 보자.
kubectl patch storageclass rook-ceph-block -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
더 자세한 Ceph 상태를 보고 싶다면 이 문서를 따라 Ceph Dashboard를 설치해 보자.
Docker Registry 설치
만약 사용할 수 있는 외부 Docker Registry가 없다면 Kubernetes 안에 간단하게 하나 설치할 수도 있다. 다음 명령어로 Namespace를 만들고 위에서처럼 인증서를 등록한다.
kubectl create ns registry
kubectl create secret tls example.com --key privkey.pem --cert fullchain.pem -n registry
다음과 같은 manifeset 파일을 생성하고 적용해 보자. (Persistent Volume을 사용하지 않았으므로 POD가 재시작 되면 업로드 되었던 이미지는 삭제된다)
apiVersion: apps/v1
kind: Deployment
metadata:
name: registry
namespace: registry
spec:
selector:
matchLabels:
app: registry
template:
metadata:
labels:
app: registry
spec:
containers:
- image: registry:2.7
name: registry
ports:
- containerPort: 5000
---
apiVersion: v1
kind: Service
metadata:
name: registry
namespace: registry
spec:
ports:
- port: 5000
targetPort: 5000
selector:
app: registry
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: registry
namespace: registry
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "0"
spec:
tls:
- hosts:
- registry.example.com
secretName: example.com
rules:
- host: registry.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: registry
port:
number: 5000
위 내용 중 proxy-body-size
annotation
은 업로드 크기 제한을 해제하기 위함이다.
다음과 같이 curl을 사용해 접속이 잘 되는지 확인해 보자.
curl https://registry.example.com/v2/
Registry가 잘 동작하는지 확인하기 위해 커스텀 이미지를 만들어 등록해 보자. Dockerfile 파일을 만들고 다음 내용을 입력한다.
FROM nginx
이미지를 생성해보자.
docker build -t registry.example.com/my-nginx .
생성한 이미지를 Registry에 등록한다.
docker push registry.example.com/my-nginx
다음 명령어로 잘 등록되었는지 확인해 보자.
curl https://registry.example.com/v2/_catalog