쿠버네티스(kubernetes)란
마이크로 서비스 아키텍처(MSA)가 발전하고, 데브옵스(DevOps)에 대한 개념이 명확해지면서 컨테이너 기반의 환경이 주목받기 시작했다.
대규모의 서비스에서 하드웨어와 VM 의 수가 많아지고 컨테이너의 수가 많아지면 이 컨테이너를 어디에 배포해야 하는지 결정해야 한다. 주어진 자원을 최적으로 사용하기 위해 적절한 위치에 배포해야 한다. 특성에 따라 물리서버에 배포하거나, 가용성을 위해 다른 서버에 배포하기도 한다. 이러한 개념을 스케줄링이라고 한다. 스케줄링을 포함하여 재기동, 모니터링, 삭제 관리 등 종합적으로 관리해주는 환경을 컨테이너 운영환경이라고 한다.
현재 컨테이너 운영환경 중 가장 널리 사용하는 솔루션이 쿠버네티스(kubernetes, K8S)이다. 컨테이너화된 워크로드와 서비스를 관리하기 위한 이식성이 있고, 확장 가능한 오픈소스 플랫폼이다.
개념 이해를 위해 쿠버네티스의 구성요소(Componenet) 및 기본 구성단위인 오브젝트(Object)에 대해 살펴보자. 그리고 쿠버네티스 클러스터를 실제 구축하며 실습을 통해 익혀보자.
kubernetes Component (1)
1. Master Node
- 주요 컨트롤 유닛으로서 Worker Nodes를 관리하는 주체
- 클러스터에 관한 전반적인 결정 및 이벤트를 감지, 반응하는 역할
a. ETCD : 설정관리, 서비스 디스커버리, 스케줄링 등을 위한 데이터를 저장하는 저장소
- 모든 상태와 데이터를 저장
- 분산 시스템으로 구성하여 안정성 높임 (고가용성)
- 가볍고 빠르면서 정확하게 설계 (일관성)
- Key-Value 형태로 데이터 저장
- TTL, watch 같은 부가 기능 제공
- 클러스터의 모든 정보가 etcd에 저장이 되므로 항상 백업
- etcd 스냅샷을 S3 로 저장 가능
b. kubectl
- 관리자가 쿠버네티스에 명령 및 관리하기 위해 사용하는 CLI 명령줄 도구
- API Server 로 요청
c. API Server
- 모든 조회나 요청을 담당
- REST API를 통해 etcd 정보 조회 및 업데이트하고 명령을 실행
- 권한을 체크하여 적절한 권한 없을 경우 차단
- 관리자 요청 뿐 아니라 다양한 내부 모듈과 통신
d. Controllers
- 논리적으로 다양한 컨트롤러가 존재(복제, 노드, 엔드포인트…)
- 지속적으로 상태를 체크하고 원하는 상태를 유지 (Desired State)
- 논리적으로 다양하게 쪼개져 있지만, 실제로는 복잡성을 낮추기 위해
하나의 프로세스로 진행
e. Scheduler
- 새로 생성된 Pod 를 감지하고 실행할 노드를 선택
- Pod 생성을 위해 요청한 리소스, 우선순위 및 기타 제약조건에 따라서 노드에 바인드 역할
- ex) 특정 라벨의 노드에 부여
kubernetes Component (2)
2. Worker Node
- 할당된 task를 요청대로 수행하는 시스템
- 컨테이너들 간의 네트워크 등 서비스에 필요한 전반적인 일들을 마스터 노드와 통신하며 수행
a. kubelet
- 각 노드에서 실행되는 일종의 에이전트
- Pod 를 실행/중지하고 상태를 체크 후에 API Server 에 보고
- 도커 API 를 이용하여 도커 데몬과 통신을 통해 컨테이너 실행
- CRI (Container Runtime) – Docker, Containerd, CRI-O, ……
b. kube-proxy
- 각 노드에서 실행되는 네트워크 프록시로 내/외부 통신 설정
- 지속적으로 서비스와 Pod, iptables 의 변경 사항 확인(상태 체크)
- Pod간 통신(overlay network), 노드간의 통신 가능(Service)
- 성능상의 이유로 별도의 프록시 프로그램 대신
iptables 또는 IPVS 를 사용 (설정만 관리)
- 로드밸런싱 기능 제공
c. pod
가장 작은 배포 단위
- 단일 노드에 배포된 하나 이상의 컨테이너 그룹
- 전체 클러스터에서 고유한 IP 할당
- 포드에 있는 모든 컨테이너는 IP 주소, IPC, 호스트 이름, 기타 리소스를 공유
- 네트워크와 스토리지를 추상화
kubernetes Object
1. Volume
- DB와 같이 영구적으로 파일을 저장해야 하는 경우, 컨테이너 restart와 관련없이 파일을 영구적으로 저장해야 하는데, 이러한 Storage 형태를 뜻함
- Pod를 가동할 때 디폴트로, 컨테이너마다 로컬 디스크를 생성하여 가동되는데, 이 로컬 디스크는 영구적이지 않기 때문. 즉, 컨테이너가 restart 되거나 새로 deploy 될 때마다 로컬 디스크는 Pod의 설정에 따라 새롭게 정의되어 배포되기 때문
- Volume은 Pod 내의 컨테이너 간의 공유 가능
2. Service
- Pod를 Service로 제공할 때, 일반적으로 하나의 Pod로 Service 하는 경우는 드물고, 여러 개의 Pod로 Service하면서 이를 LB를 이용해서 하나의 IP와 Port로 묶어서 Service 제공
- Pod는 동적으로 생성되고, 장애가 생기면 자동으로 restart되면서 IP가 바뀌기 때문에, LB에서 Pod의 목록을 지정할 때 IP주소를 이용하는 것은 어렵다. 또한 Auto Scaling으로 인하여 Pod가 동적으로 추가 또는 삭제되기 때문에, 이렇게 추가/삭제된 Pod 목록을 LB가 유연하게 선택해주어야 한다. 이 때 사용하는 것이 라벨(label)과 라벨 셀렉터(label selector)라는 개념이다.
- Service를 정의할 때, 어떤 Pod를 서비스로 묶을 것인지 정의하는데, 이를 label selector라고 한다. 각 Pod를 생성할 때, metadata 정보 부분에 label을 정의
- Service는 특정 label을 가지고 있는 Pod간에만 Load Balancing을 통하여 외부로 서비스 제공한다.
3. Namespace
- Namespace는 쿠버네티스 클러스터 내의 논리적인 분리 단위
- 즉, 하나의 클러스터 내에 개발/운영/테스트 환경이 있을 때, 클러스터를 개발/운영/테스트 3개의 Namespace로 나눠서 운영
- 사용자별로 각 Namespace 의 접근 권한을 다르게 운영 가능
- Namespace 별로 Pod, Service 등을 나눠 관리 가능
- Namespace 별로 리소스의 할당량을 지정할 수 있다. 개발계의 CPU 100개, 운영계의 CPU 400개과 GPU 100개, 이런 식으로 사용 가능한 리소스의 수를 지정 가능
- 주의할 점은 Namespace는 논리적인 분리 단위이고, 물리적으로 환경을 분리(isolation)한 것은 아니다. 다른 Namespace간의 Pod라도 통신은 가능
K8S Cluster 구축 Manual
1. 기본 설치 (Mater&Worker 공통)
1. sudo su (관리자 권한)
2. 도커 설치
$ apt update $ apt install -y docker.io
3. Installing kubeadm, kubelet and kubectl
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
$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
4. 자동실행 설정 – 시스템 재부팅 시 자동실행되도록 설정
$ systemctl enable docker kubelet
2. Mater 설정
1. 클러스터 생성
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/
$ kubeadm init --pod-network-cidr=192.168.0.0/16
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config
kubeadm join 192.168.104.189:6443 --token duixm1.q32ni39stuifik95 \ --discovery-token-ca-cert-hash sha256:052dcc589796d5737cb66c215ced1c3fa997f3cb7b384fe6c16ed4b0f405a14a
2. kubectl (권한) 설정 – 루트가 아닌 사용자를 위해 kubctl이 작동하도록 하려면 kubeadm init 출력의 일부이기도 한 다음 명령을 실행하시오.
$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 all —all-namespaces 한 번 쳐보기)
kubectl get nodes (아직 NotReady)
3. cluster에 network 배포 (Calico Pod Network)
#calico 설치 $ kubectl apply -f https:*//docs.projectcalico.org/v3.11/manifests/calico.yaml*
#설치 확인 $ kubectl get pods -n kube-system
4. taint 설정 제거 (taint 설정이 된 경우 pod의 스케줄링이 일어나지 않음)
- 마스터 노드에도 pod를 배포하려면 다음과 같이 실행
$ kubectl taint nodes --all node-role.kubernetes.io/master- node/ip-192-168-104-189 untainted node/<your-hostname> untainted
5. 클러스터 노드 확인 (마스터 노드 동작 확인) > STATUS=Ready인지 확인
$ kubectl get nodes -o wide
3. Worker 설정
1. 공통 (도커 및 쿠버네티스) 설치 후
6443 port 열어주기 (마스터, 워커 노드 인스턴스 각각에서. 일단 같은 securitygroup 쓰기 때문에 그 인스턴스에서 port 열어줌. 다른걸 쓴다면 서로의 ip로 6443 포트 열어주면 됨)
kubectl get pod -n kube-system
kubectl ~~ 명령어 입력하면
The connection to ther server localhost:8080 was refused 발생
Master Node에서는 kubectl 권한 설정 해주면 됨.
Worker Node에서는 (Master에서)kubeadm init 했을 때 나왔던, join 해주면 됨
2. Join : Worker Node 추가 (Master에서 kubeadm init 했을 때 나온 token을 join)
- 일반적으로 토큰은 24시간 유효
$ kubeadm join 192.168.104.189:6443 --token duixm1.q32ni39stuifik95 \\ --discovery-token-ca-cert-hash sha256:052dcc589796d5737cb66c215ced1c3fa997f3cb7b384fe6c16ed4b0f405a14a [preflight] Running pre-flight checks [WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". Please follow the guide at <https://kubernetes.io/docs/setup/cri/> [preflight] Reading configuration from the cluster... [preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" [kubelet-start] Starting the kubelet [kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap... This node has joined the cluster: * Certificate signing request was sent to apiserver and a response was received. * The Kubelet was informed of the new secure connection details. Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
- 마스터노드에서 kubectl get nodes 하면 워커노드 조인되고, STATUS: ready인 것 확인 가능.
일반적으로 여기까지하면 cluster 구축 완료.
+) 1번의 token을 잃어버린 경우 재확인
$ kubeadm token list
+) token이 만료된 경우 재생성해 사용 (기본 24시간 후 삭제)
$ kubeadm token create
마치며
이 글을 통해 쿠버네티스에 대한 개념적인 이해와 실전에서 활용할 수 있는 클러스터 구축에 대한 팁까지 얻을 수 있었기를 기대한다. 쿠버네티스의 컨테이너 환경은 퍼블릭/프라이빗 클라우드 혼용 환경 및 온프레미스 환경에서도 동일하게 적용 가능하기 때문에 하이브리드 클라우드 솔루션으로 각광받고 있다. 다양한 환경에서 활용이 용이한 쿠버네티스에 대한 이해의 시작점을 이 글로 삼아 다양한 서비스에 적용해도록 하자.
참조
https://heekim0719.tistory.com/414?category=817909
https://bcho.tistory.com/1256?category=731548