Ubuntu 22.04 에서 CRI-O, Kubernetes 1.28 Cluster, Calico 설치 및 애플리케이션 배포

반응형

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

 

 

 

 

반응형

댓글()