Kubernetes 는 컨테이너의 생성, 배포, 실행을 하는 등 컨테이너를 관리하는 오픈소스 플랫폼 입니다.
여기에서는 Ubuntu 22.04 버전의 서버 3대로 (master 노드 1대 / worker 노드 2대) Kubernetes 1.28 을 구성하는 방법에 대해 설명합니다.
- 공식 Documents : https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
1. CRI-O 설치
CRI-O 공식 홈페이지 : https://cri-o.io
Pod 를 실행하고 관리할 수 있도록 Containerd 나 CRI-O 와 같은 컨테이너 런타임을 설치해야 합니다.
여기에서는 CRI-O 를 설치하도록 하겠습니다.
(모든 노드에서)
서버별로 호스트네임을 설정하고 각 노드에 호스트명으로 통신 가능하도록 hosts 파일에 추가합니다.
# hostnamectl set-hostname master // master 노드에서
# hostnamectl set-hostname worker1 // worker1 노드에서
# hostnamectl set-hostname worker2 // worker2 노드에서
# vi /etc/hosts
127.0.0.1 localhost 10.101.0.5 master 10.101.0.10 worker1 10.101.0.12 worker2 |
CRI-O 는 설치할 Kubernetes 버전과 동일한 버전으로 설치합니다.
(모든 노드에서)
# OS=xUbuntu_22.04
# VERSION=1.28
# echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/ /" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
# echo "deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$VERSION/$OS/ /" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:$VERSION.list
# curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$VERSION/$OS/Release.key | apt-key add -
# curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/Release.key | apt-key add -
# apt -y update
# apt -y upgrade // 설치중 묻는 질문에 기본값으로 답변
# apt -y install cri-o cri-o-runc cri-tools // 설치중 묻는 질문에 기본값으로 답변
# systemctl enable --now crio
설치를 잘 마쳤으면 CRI-O 버전이 확인됩니다.
# crio version
crio version 1.28.0
Version: 1.28.0
GitCommit: unknown
GitCommitDate: unknown
GitTreeState: clean
BuildDate: 2023-08-28T05:59:01Z
GoVersion: go1.19
Compiler: gc
Platform: linux/amd64
Linkmode: dynamic
...
2. Kubernetes 설치
Kubernetes 공식 홈페이지 : https://kubernetes.io
(모든 노드에서)
kubelet 사용을 위해 swap 을 반드시 비활성화 시켜줍니다.
# swapoff -a
# cat /etc/fstab
fstab 에서도 swap 파티션이 존재한다면 주석처리하여 비활성화 시킵니다.
이제 kubeadm, kubelet, kubectl 를 설치해야 하는데, 이 세가지는 모두 Kubernetes 클러스터 관리와 상호 작용을 위한 도구입니다.
- kubeadm : 클러스터를 부트스트랩하는 명령
- kubelet : 클러스터의 모든 노드에서 실행되는 POD와 컨테이너 시작과 같은 작업을 수행하는 컴포넌트
- kubectl : 클러스터와 통신하기 위한 CLI 유틸리티
패키지 저장소에서 파일을 안전하게 다운로드 받기 위해 아래 패키지를 설치합니다.
# apt -y install apt-transport-https ca-certificates
현재 기준 Kubernetes 최신 버전인 1.28 버전의 공용 서명 키를 다운로드합니다.
# curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
Kubernetes Repository 를 추가합니다.
# echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
APT 패키지 인덱스를 업데이트하고 kubelet, kubeadm, kubectl 을 설치합니다.
그리고 패키지가 자동으로 버전업 되지 않도록 고정합니다.
# apt -y update
# apt -y install kubelet kubeadm kubectl // 설치중 묻는 질문에 기본값으로 답변
# apt-mark hold kubelet kubeadm kubectl
커널에 필요한 모듈을 로드 합니다.
(모든 노드에서)
# modprobe overlay
# modprobe br_netfilter
# cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sysctl 파라메타 값을 설정하고 리부팅 없이 적용합니다.
# cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
# sysctl --system
CRI-O는 기본적으로 systemd 라는 cgroup 드라이버를 사용합니다.
(모든 노드에서)
# cat <<EOF | sudo tee /etc/crio/crio.conf.d/02-cgroup-manager.conf
[crio.runtime]
conmon_cgroup = "pod"
cgroup_manager = "systemd"
EOF
3. Cluster 생성
서버간 통신할 사설 네트워크 대역을 설정합니다.
현재 노드와 중복되지 않도록 새로운 대역으로 설정해 주었습니다.
- Nodes network : 10.101.0.0/24
- Pods network : 10.101.1.0/24
쿠버네티스 구성에 필요한 이미지를 다운로드 받아야 하므로 이 단계에서 시간이 약간 소요됩니다.
(master 노드에서)
# kubeadm init --pod-network-cidr=10.101.1.0/24
아래는 쿠버네티스 컨트롤 플레인이 성공적으로 초기화 되었을때 출력하는 메세지 입니다.
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 10.101.0.5:6443 --token w6ioaq.l37qcxuvs98q4n02 \ --discovery-token-ca-cert-hash sha256:bddfcfabe16f76edbb6a8af08a835ebf9defc67d902dd02091174e1bccacaa76 |
위에 나와있는 안내 대로 추가 명령을 실행하는데, 현재는 root 상태이므로 아래명령으로 Kubernetes 사용자 환경을 로드 합니다.
일반 사용자 상태로 진행을 원할 경우 위 안내된 mkdir 부분부터 세줄 명령을 실행하면 됩니다.
(master 노드에서)
# export KUBECONFIG=/etc/kubernetes/admin.conf
앞으로 SSH 접속시마다 자동으로 환경이 로드 되도록 하면 편리합니다.
# echo 'export KUBECONFIG="/etc/kubernetes/admin.conf"' >> ~/.bashrc
master 노드에서 확인 가능한 노드 상태를 출력합니다.
# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready control-plane 39s v1.28.1
worker 노드에서는 아래와 같이 master 서버에 join (가입) 합니다.
token 과 hash 값은 쿠버네티스 컨트롤 플레인이 초기화 되었을때 출력된 값으로 합니다.
(모든 worker 노드에서)
# kubeadm join 10.101.0.5:6443 --token w6ioaq.l37qcxuvs98q4n02 \
--discovery-token-ca-cert-hash sha256:bddfcfabe16f76edbb6a8af08a835ebf9defc67d902dd02091174e1bccacaa76
다시 master 노드에서 확인 가능한 노드 상태를 출력하면 가입된 worker 노드 리스트까지 확인이 됩니다.
ROLES 부분이 아래와 같이 출력 되었는지 확인합니다.
(master 노드에서)
# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready control-plane 2m24s v1.28.1
worker1 Ready <none> 88s v1.28.1
worker2 Ready <none> 81s v1.28.1
[참고 : Cluster 삭제]
이번에는 Cluster 를 삭제하는 방법을 안내합니다.
계속 Cluster 구성 진행을 원하시는 분은 이 부분을 건너뛰면 되고, 구성이 꼬이거나 처음부터 다시 하실 분만 참고하시면 됩니다.
(master 노드에서)
# kubeadm reset
# rm -r /etc/cni/net.d/*
# systemctl restart kubelet
(모든 worker 노드에서)
kubeadm join 명령을 하기 전에 아래 명령으로 기존 Cluster 정보를 삭제해야 합니다.
# kubeadm reset
# rm -rf /etc/kubernetes/*
# systemctl stop kubelet
4. Calico 설치
Calico 공식 홈페이지 : https://www.tigera.io/project-calico
Project Calico 는 Kubernetes에 대한 네트워크 정책 엔진입니다.
Calico 네트워크 정책 집행을 통해 네트워크 세분화 및 테넌트 격리를 구현할 수 있습니다.
1) Calico 설치하기
(master 노드에서)
Tigera Calico 연산자 및 사용자 지정 리소스 정의를 설치합니다.
현재 기준 Calico 최신버전은 3.26.1 입니다.
# kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/tigera-operator.yaml
필요한 커스텀 리소스를 생성하여 Calico 를 설치합니다.
배포하는 yaml 파일에서 CIDR 정보를 자신이 사용하는 네트워크 정보로 수정하고 생성합니다.
# wget https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/custom-resources.yaml
# sed -i 's/192.168.0.0\/16/10.101.1.0\/24/' custom-resources.yaml
# kubectl create -f custom-resources.yaml
다음 명령을 사용하여 모든 Pod 가 실행 중인지 확인합니다.
이 부분에서 모든 STATUS 값이 Running 이 되기까지 약간의 시간이 소요됩니다.
# kubectl get pods -n calico-system
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-7fd8984cb7-b5t6n 1/1 Running 0 2m37s
calico-node-74bjg 1/1 Running 0 2m37s
calico-node-8mrfw 1/1 Running 0 2m37s
calico-node-9xn6h 1/1 Running 0 2m37s
calico-typha-d4c4b7984-l4p5j 1/1 Running 0 2m37s
calico-typha-d4c4b7984-lc9hm 1/1 Running 0 2m31s
csi-node-driver-9lmnz 2/2 Running 0 2m37s
csi-node-driver-hzt8h 2/2 Running 0 2m37s
csi-node-driver-ljsds 2/2 Running 0 2m37s
5. 애플리케이션 배포
볼륨을 포함한 애플리케이션을 배포하고 외부에서 접근하기 위한 네트워크 설정 및 도메인 연결 예제입니다.
1) Namespace
애플리케이션을 생성하고 배포할 작업공간을 생성하고 현재의 공간으로 변경해줍니다.
(master 노드에서)
# kubectl create ns sysdocu
# kubectl config set-context --current --namespace=sysdocu
2) Volume 생성
NFS, GlusterFS, Ceph 등 별도의 서버를 미리 구성하고 해당 공간을 할당받기 위해
PV (Persistent Volume) 와 PVC (Persistent Volume Claim) 를 생성하는 방법도 있지만,
여기에서는 Pod 가 배포된 worker 노드의 공간을 할애하는 hostPath 방법으로 진행해 보겠습니다.
hostPath 를 사용할 경우 디렉토리를 지정하는 것 외에 별도 작업은 없습니다.
html 데이터를 저장할 디렉토리를 생성합니다.
(모든 worker 노드에서)
# mkdir /html
3) Deployment 생성
Deployment 를 사용하면 Pod 생성 및 여러가지 옵션을 추가하여 다양한 구성이 가능합니다.
Deployment yaml 파일을 작성합니다.
(master 노드에서)
# vi deployment.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest ports: - containerPort: 80 volumeMounts: - name: html-volume mountPath: /html/user001 volumes: - name: html-volume hostPath: path: /usr/share/nginx/html type: DirectoryOrCreate |
작성한 yaml 파일을 적용하여 생성합니다.
# kubectl apply -f deployment.yaml
deployment.apps/nginx-deployment created
Pod 가 자동 생성되는데, 아래와 같이 확인이 가능합니다.
# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-694db9fb84-b5h2r 1/1 Running 0 20s
4) Service 생성
네트워크 접근이 가능하도록 Service 를 생성해 줍니다.
테스트 목적이긴 하지만 외부 네트워크에서 접근이 되도록 해보겠습니다.
Service yaml 파일을 작성합니다.
# vi service.yaml
apiVersion: v1 kind: Service metadata: name: nginx spec: selector: app: nginx type: NodePort ports: - protocol: TCP port: 80 targetPort: 80 nodePort: 30080 # 여기에 원하는 NodePort 값을 지정하세요. (범위 : 30000~32767) |
* 참고
Service 에서 생성할 type 은 ClusterIP, NodePort, LoadBalancer 가 있습니다.
- ClusterIP : 클러스터 내부 통신만 가능한 IP
- NodePort : worker 노드의 IP 와 지정한 포트 (30000~32767 로 제한) 를 이용해 Pod 에 연결 가능
- LoadBalancer : 별도의 공인 IP 가 할당되고, 포트를 마음대로 사용 가능 (베어메탈 환경에서는 MetalLB 를 설치 필요)
작성한 yaml 파일을 적용하여 생성합니다.
# kubectl apply -f service.yaml
service/nginx created
Service 생성시 Endpoint 도 같이 생성되는데, 두가지 정보를 함께 출력해보면 아래와 같습니다.
# kubectl get services,ep
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx NodePort 10.110.222.108 <none> 80:30080/TCP 17s
NAME ENDPOINTS AGE
nginx 10.101.1.66:80 17s
외부 네트워크에서 접근되는지 확인합니다.
접근할 IP 는 Pod 가 위치하는 worker 노드인데, 아래 명령으로 확인 가능합니다.
# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-694db9fb84-b5h2r 1/1 Running 0 7m22s 10.101.1.66 worker2 <none> <none>
worker2 노드인것을 확인하였으며, 외부에서 worker2 노드의 공인 IP 와 위에서 설정한 포트 30080 으로 접근시 nginx 초기페이지가 출력되는것이 확인됩니다. 예제에서는 worker2 노드의 공인 IP 로 연결하였지만 실제로는 꼭 worker2 노드의 공인 IP 로 할 필요는 없습니다. NodePort 의 경우 master 또는 어떤 worker 노드로 연결하던 설정한 Pod 로 연결됩니다.
# curl 115.68.249.176:30080
5) Ingress 생성
Ingress 를 사용하면 도메인 연결이 가능합니다.
Ingress yaml 파일을 작성합니다.
# ingress.yaml
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx namespace: sysdocu spec: rules: - host: nginx.sysdocu.kr # 사용할 도메인 http: paths: - path: / pathType: Prefix backend: service: name: nginx # 연결할 Service 이름 port: number: 80 # 연결할 Service 포트 번호 |
작성한 yaml 파일을 적용합니다.
# ingress.networking.k8s.io/nginx created
Ingress 가 생성되었습니다.
# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
nginx <none> nginx.sysdocu.kr 80 30s
사용할 도메인 (nginx.sysdocu.kr) 은 DNS 에서 IP 를 worker 노드의 IP 로 미리 등록해 놓아야 합니다.
아래와 같이 접속이 확인되었습니다.
# curl nginx.sysdocu.kr:30080
nginx 와 같은 웹서버에서 사용하는 포트는 보통 80 또는 443 이지만, NodePort 사용시 번거롭게 30000~32767 사이의 포트 번호를 사용해야 연결이 됩니다. 포트 번호없이 도메인만으로 접속을 원하는 경우 MetalLB 를 구성해 공인 IP 를 할당해 주면 됩니다.
- MetalLB 설치 : https://sysdocu.tistory.com/1854