////
Search

3장 - 컨테이너를 다루는 표준 아키텍처, 쿠버네티스

Created
2022/09/03 11:24
Tags
다양한 형태의 설정이 추가된 눈송이 서버
컨테이너 인프라 환경이란? 리눅스 운영 체제의 커널 하나에서 여러 개의 컨테이너가 격리된 상태로 실행되는 인프라 환경을 말합니다.
여기서 컨테이너는 하나 이상의 목적을 위하 독립적으로 작동하는 프로세스 입니다.
컨테이너 인프라 환경을 구성하면 눈송이 서버를 방지하는데 효과적 임
눈송이 서버 = 여러 사람이 만져서 설정의 일관성이 떨어진 서버
가상화 환경에서는 각각의 가상머신이 모두 독립적인 운영 체제 커널을 가지고 있어야 하기 때문에 그만큼 자원을 더 소모해야 하고 성능이 떨어질 수밖에 없다.
But. 컨테이너 인프라 환경은 운영 체제 커널 하나에 컨테이너 여러 개가 격리된 형태로 실행 때문에 자원의 효율적 사용, 거치는 단계가 적어 속도도 훨씬 빠름!
가상화 환경과 컨테이너 인프라 환경 비교
컨테이너 인프라 환경이 성장하게 된 결정적 계기는 구글이 쿠버네티스를 오픈소스로 공개한데 있다.
이를 통해 쿠버네티스를 누구나 자유롭게 이용하게 되면서 컨테이너 인프라 환경을 좀 더 효율적으로 관리할 수 있게 되었음
여러 기능이 추가되며 쿠버네티스는 컨테이너 인프라 관리 솔루션의 표준으로 자리잡게 됨

3.1 쿠버네티스 이해하기

쿠버네티스를 컨테이너 관리 도구라고 설명했지만, 실제로 쿠버네티스는 컨테이너 오케스트레이션을 위한 솔루션입니다.
오케스트레이션이란? 복잡한 단계를 관리하고 요소들의 유기적인 관계를 미리 정의해 손쉽게 사용하도록 서비스를 제공하는 것을 의미합니다.

3.1.1 왜 쿠버네티스일까

구분
도커 스웜
메소드
노매드
쿠버네티스
설치 난이도
쉬움
매우 어려움
쉬움
어려움
사용 편의성
매우 좋음
좋음
매우 좋음
좋음
세부 설정 지원
거의 없음
있음
거의 없음
다양하게 있음
안정성
매우 안정적인
안정적임
안정적임
매우 안정적임
확장성
어려움
매우 잘 됨
어려움
매우 잘 됨
정보량
많음
적음
적음
매우 많음
에코파트너
없음
거의 없움
있음
매우 많음
학습 곡선
쉬움
매우 어려움
어려움
어려움
k8s의 의미
쿠버네티스는 그 이름 자체가 긴 단어이기 때문에 문자 수를 표기하는 방법으로 약어를 만들었습니다.
k8(ubernete = 8글자)s

3.1.2 쿠버네티스 구성 방법

쿠버네티스를 구성하는 방법은 크게 3가지로 구분됩니다.
1.
퍼블릭 클라우드 업체에서 제공하는 관리형 쿠버네티스인 EKS, AKS, GKE 등을 사용합니다.
구성이 이미 다 갖춰져 있고 마스터 노드를 클라우드 업체에서 관리하기 때문에 학습용으로는 적합하지 않음
2.
수세의 Rancher, 레드햇의 OpenShift와 같은 플랫폼에서 제공하는 설치형 쿠버네티스를 사용합니다.
유료이기 때문에 쉽게 접근이 어렵다.
3.
사용하는 시스템에 쿠버네티스 클러스터를 자동으로 구성해주는 솔루션을 사용한다.
kubeadm, kops, KRIB, kubespray가 대표적
위 4가지 솔루션중 kubeadm가 가장 널리 알려져 있다.
사용자 변경이 수월
온프레미스와 클라우드를 모두 지원
배우기도 쉬움

3.1.3 쿠버네티스 구성하기

학습을 위해 사용자 설정이 많이 필요한 kubeadm으로 쿠버네티스를 구성
쿠버네티스가 설치되는 서버 노드는 가상 머신을 이용해 실제 온프레미스에 가깝게 구성

3.1.4 파드 배포를 중심으로 쿠버네티스 구성요소 살펴보기

# kubectl get pods --all-namespaces
Plain Text
복사
--all-namespaces는 기본 네임스페이스인 default외에 모든 것을 표시하겠다는 의미
쿠버네티스 클러스터를 이루는 구성요소들은 파드 형태로 이루어져 있음을 알 수 있음

관리자나 개발자가 파드를 배포할 때

통신 순서가 있어 흐름을 이해할 수 있지만, 각각의 기능을 파악하기는 어려움
파드를 배포하는 순서에 따라 요소들의 역할을 정리
1.
kubectl : 쿠버네티스 클러스터에 명령을 내리는 역할
다른 구성요소들과 다르게 바로 실행되는 명령 형태인 바이너리로 배포되기 때문에 마스터 노드에 있을 필요는 없다.
통상적으로 API 서버와 주로 통신
2.
API 서버 : 주로 상태 값을 저장하는 etcd와 통신
그 밖의 요소들 또한 API 서버를 중심으로 통신
때문에 API 서버의 역할이 매우 중요
3.
etcd : 구성 요소들의 상태 값이 모두 저장되는 곳
회사의 관리자가 모든 보고 내용을 기록하는 노트라고 생각하면 됨
실제로 etcd외 다른 구성요소는 상태 값을 관리하지 않는다.
때문에 etcd의 정보만 백업돼 있다면 긴습한 장애 상황에서도 쿠버네티스 클러스터를 복구할 수 있음
또한 etcd는 분산 저장이 가능한 key-value 저장소로서 복제해 여러 곳에 저장해 두면 하나의 etcd에서 장애가 나도 시스템 가용성을 확보할 수 있음
etcd(엣시디)는 리눅스 구성 정보를 주로 가지는 etc 디렉터리와 distributed(퍼뜨렸다)의 합성어 = 구성 정보를 퍼뜨려 저장하겠다는 의미
4.
컨트롤러 매니저 : 쿠버네티스 클러스터의 오브젝트 상태를 관리
워커 노드에서 통신이 되지 않는 경우. 상태 체크와 복구는 컨트롤러 매니저에 속한 노드 컨트롤러에서 이루어짐
서비스와 파드를 연결하는 역할을 하는 엔드 포인트 컨트롤러 또한 컨트롤러 매니저임
이와 같이 다양한 상태 값을 관리하는 주체들이 컨트롤러 매니저에 소속돼 각자의 역할을 수행
5.
스케줄러 : 노드의 상태와 자원, 레이블, 요구 조건 등을 고려해 어떤 워커 노드에 파드를 생성할 것인지 결정하고 할당하는 역할
이름에 걸맞게 파드를 조건에 맞는 워커 노드에 지정하고, 파드가 워커 노드에 할당되는 일정을 관리하는 역할을 담당
6.
kubelet : 파드의 구성 내용(PodSpec)을 받아 컨테이너 런타임에 전달, 파드 안의 컨테이너들이 정상적으로 작동하는지 모니터링 함
7.
컨테이너 런타임 : 파드를 이루는 컨테이너 실행을 담당
파드 안에서 다양한 종류의 컨테이너가 문제 없이 작동하게 만드는 표준 인터페이스
8.
파드(Pod) : 한 개 이상의 컨테이너로 단일 목적의 일을 하기 위해 모인 단위
파드는 언제라도 죽을 수 있는 존재
쿠버네티스를 처음 배울 때 가장 이해하기 어려운 부분
가상 머신은 언제라도 죽을 수 있다고 가정하고 디자인하지 않지만, 파드는 언제라도 죽을 수 있다고 가정하고 설계되었음
때문에 쿠버네티스는 여러 대안을 디자인했음
파드와 컨테이너의 관계
그외 추가적으로 선택 가능한 구성요소
1.
네트워크 플러그인 : 쿠버네티스 클러스터의 통신을 위해 네트워크 플러그인을 선택하고 구성할 수 있음
네트워크 플러그인은 일반적으로 CNI로 구성
CNI(Container Network Interface, 컨테이너 네트워크 인터페이스)
클라우드 네이티브 컴퓨팅 재단의 프로젝트
컨테이너의 네트워크 안정성과 확장성을 보장하기 위해 개발 됨
네트워크 프로토콜인 BGP와 VXLAN의 지원, ACL 지원, 보안 기능 제공 등 살펴보고 필요한 조건을 가지고 있는 네트워크 플러그인을 선택할 수 있어 설계 유연성이 매우 높음
2.
CoreDNS : 클라우드 네이티브 컴퓨팅 재단에서 보증하는 프로젝트
빠르고 유연한 DNS 서버
클러스터 구성시 IP보다 도메인 네임을 편리하게 관리해주는 CoreDNS를 사용하는게 일반적

사용자가 배포된 파드에 접속할 때

1.
kube-proxy : 쿠버네티스 클러스터는 파드가 위치한 노드에 kube-proxy를 통해 파드가 통신할 수 있는 네트워크를 설정함
이때 실제 통신은 br_netfilter과 iptables로 관리
2.
파드 : 이미 배포된 파드에 접속하고 필요한 내용을 전달받음
이때 대부분 사용자는 파드가 어느 워커노드에 위치하든지 신경 쓰지 않아도 됨

3.1.5 파드의 생명주기로 쿠버네티스 구성 요소 살펴보기

파드의 생명주기
쿠버네티스의 구성요소를 개별적으로 기능만 나열해서는 이해하기가 어렵다.
따라서 파드가 배포되는 과정을 하나하나 자세히 살펴보면서 쿠버네티스의 구성요소들이 어떤 역할을 담당하는지 정리해보자
1.
kubectl을 통해 API 서버에 파드 생성을 요청한다.
2.
(업데이트가 있을 때마다 매번) API 서버에 전달된 내용이 있으면 API 서버는 etcd에 전달된 내용을 모두 기록해 클러스터의 상태 값을 최신으로 유지한다.
3.
API 서버에 파드 생성이 요청된 것을 컨트롤러 매니저가 인지
a.
컨트롤러 매니저는 파드를 생성
b.
아직 어떤 워커노드에 파드를 적용할지는 결정되지 않는 상태로 파드를 생성
4.
API 서버에 파드가 생성됐다는 정보를 스케줄러가 인지한다.
a.
스케줄러는 생성된 파드를 어떤 워커 노드에 적용할지 조건을 고려해 결정하고 해당 워커노드에 파드를 띄우도록 요청한다.
5.
API 서버에 전달된 정보대로 지정한 워커 노드에 파드가 속해있는지 스케줄러가 kubelet으로 확인한다.
6.
kebelet에서 컨테이너 런타임으로 파드 생성을 요청한다.
7.
파드가 생성된다.
8.
파드가 사용 가능한 상태가 된다.

3.1.6 쿠버네티스 구성 요소의 기능 검증하기

kubectl

kubectl은 꼭 마스터 노드에 위치할 필요가 없다. 실제로 쿠버네티스 클러스터의 외부에서 쿠버네티스 클러스터에 명령을 내릴 수도 있다.
어느 곳에서든지 kubectl을 실행하려면 어떤 부분이 필요한지 확인해보자.
1.
슈퍼푸티 세션 창에서 w3-k8s를 더블클릭해 터미널에 접속
2.
kubectl get nodes를 실행
3.
쿠버네티스 클러스터 정보를 마스터노드에서 scp명령으로 w3-k8s의 현재 디렉터리에 받아옴
a.
이때 접속기록이 없기 때문에 known_hosts로 저장하도록 함
4.
kubectl get nodes 명령에 추가로 쿠버네티스 클러스터 정보를 입력받는 옵션(--kubeconfig)과 마스터 노드에서 받아온 admin.conf를 입력하고 실행

kubelet

kubelet으 쿠버네티스에서 파드의 생성과 상태 관리 및 복구 등을 담당하는 매우 중요한 구성요소
따라서 kubelet에 문제가 생기면 파드가 정상적으로 관리되지 않음
1.
기능 검증을 위해서는 실제 파드를 배포해야함
a.
kubectl create -f ~/_Book_k8sInfra/ch3/3.1.6/nginx-pod.yaml명령으로 nginx 파드를 배포
2.
kubectl get pod 명령으로 배포된 파드가 정상적으로 작동중(Running)인지 확인
3.
kubectl get pods -o wide 명령을 실행해 파드가 배포된 워커 노드를 확인
a.
-o느 output의 약어로 출력을 특정 형식으로 해주는 옵션
b.
wide는 재공되는 출력 형식 중에서 출력 정보를 더 많이 표시해 주는 옵션
4.
배포된 노드에 접속해 systemctl stop kubelet으로 kubelet 서비스를 멈춘다.
5.
m-k8s에서 kubectl get pod로 상태를 확인하고, kubectl delete pod nginx-pod로 파드를 삭제
6.
이후 명령어가 Terminating 상태에서 진행되지 않는것을 확인
7.
다시 노드에 접속해 systemctl start kubelet 명령어를 통해서 kubelet을 복구
8.
잠시 후 kubelet get pod 명령어를 통해 파드가 삭제되었는지 확인

kebe-proxy

kubelet이 파드 상태를 관리한다면 kube-proxy는 파드의 통신을 담당합니다.
1.
테스트하기 위해 마스터 노드인 m-k8s에서 다시 파드를 배포합니다.
2.
kubectl get pod -o wide 명령으로 파드의 IP와 워커 노드를 확인합니다.
3.
curl로 파드의 전 단계에서 파드의 전 단계에서 확인한 파드의 IP

3.2 쿠버네티스의 기본 사용법

쿠버네티스를 사용한다는 것은 결국 사용자에게 효과적으로 파드를 제공한다는 뜻
kubectl run nginx-pod --image=nginx kubectl create deployment dpy-nginx --image=nginx
Plain Text
복사
nginx 파드를 생성하는 명령어
두 명령어의 차이는?
run = 단일 파드로 생성되고 관리 (초코파이 단일품)
create deployment = deployment라는 관리 그룹 내세엇 파드가 생성됨 (초코파이 한상자)

오브젝트란

쿠버네티스를 사용하는 관점에서 파드와 디플로이먼트는 스펙과 상태 등을 가지고 있다.
기본 오브젝트
파드 = 쿠버네티스에서 실행되는 최소 단위, 웹 서비스를 구동하는데 필요한 최소 단위
네임스페이스 = 쿠버네티스 클러스터에서 사용되는 리소스들을 구분해 관리하는 그룹
볼륨 = 파드가 생성될 때 파드에서 사용할 수 있는 디렉터리를 제공
파드가 사라지더라도 저장과 보존이 가능한 디렉터리 볼륨 오브젝트를 생성/사용 가능
서비스 = 파드는 클러스터 내에서 유동적이기 때문에 접속 정보가 고정일 수 없음
파드 접속을 안정적으로 유지하도록 서비스를 통해 내/외부로 연결됨
디플로이먼트
기본 오브젝트만으로도 쿠버네티스를 사용할 수 있지만, 좀 더 효율적인 사용을 위해 구현된것이 바로 디플로이먼트
이 외에도 데몬셋, 컨피그맵, 레플리카셋, PV, PVC, 스테이트풀셋, 등이 있으며 요구사항에 따라 목적에 맞는 오브젝트들이 추가될 것
쿠버네티스에서 가장 많이 쓰이는 디플로이먼트 오브젝트는 파드에 기반을 두고 있다.
레플리카셋 오브젝트를 합쳐 놓은 형태
실제로 API 서버와 컨트롤러 매니저는 단순히 파드가 생성되는 것을 감시하는 것이 아니라 디플로이먼트처럼 레플리카셋을 포함하는 오브젝트의 생성을 감시

3.2.3 레플리카셋으로 파드 수 관리하기

쿠버네티스에서는 다수의 파드를 만드는 레플리카셋 오브젝트를 제공함
파드를 3개 만들겠다고 선언하면 컨트롤러 매니저와 스케줄러가 워커 노드에 파드 3개를 만들도록 선언, 레플리카셋은 파드 수를 보장하는 기능만 제공
롤링 업데이트 등이 추가된 디플로이먼트를 사용해 파드수를 관리하는것을 권장

3.2.4 스펙을 지정해 오브젝트 생성

디플로이먼트를 생성하면서 한꺼번에 여러개의 파드를 생성하는 방법
야믈문법으로 작성한 오브젝트 스펙을 이용하는 방법
apiVersion: apps/v1 # API 버전 kind: Deployment # 오브젝트 종류 metadata: name: echo-hname labels: app: nginx spec: replicas: 3 # 몇 개의 파드를 생성할지 결정 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: echo-hname image: sysnet4admin/echo-hname # 사용되는 이미지
YAML
복사
야믈 파일의 구조를 시각화

3.2.5 apply로 오브젝트 생성하고 관리하기

run은 파드를 생성하는 매우 편리한 방법 But 단일 파드만 생성 가능
create로 디플로이먼트를 생성하면 파일의 변경 사항을 바로 적용할 수 없음
이럴 때를 위해 apply를 통해서 오브젝트 관리가 가능함
구분
Run
Create
Apply
명령 실행
제한적
가능
안 됨
파일 실행
안 됨
가능
가능
변경 가능
안 됨
안 됨
가능
실행 편의성
매우 좋음
매우 좋음
좋음
기능 유지
제한적
지원됨
다양하게 지원됨
오브젝트 생성 명령어 비교

3.2.6 파드의 컨테이너 자동 복구 방법

쿠버네티스는 거의 모든 부분이 자동 복구되도록 설계되어있음
특히 파드의 자동 복구 기술을 셀프 힐링이라 하는데, 제대로 작동하지 않는 컨테이너를 다시 시작/교체해 파드가 정상적으로 작동하게 함

3.2.7 파드의 동작 보증 기능

디플로이먼트에 속한 파드의 삭제 및 복구 과정

3.2.8 노드 자원 보호하기

여러 상황 속에서도 쿠버네티스는 파드를 안정적으로 작동하도록 관리 함
노드는 쿠버네티스 스케줄러에서 파드를 할당받고 처리하는 역할을 함
지속적으로 문제가 생기는 노드의 경우 cordon을 통해서 노드를 관리할 수 있음

3.2.9 노드 유지보수하기

쿠버네티스를 사용하다 보면 정기 또는 비정기적 유지보수를 위해 노드를 꺼야하는 상황이 발생할 수 있음
이때 drain을 통해서 지정된 노드의 파드를 다른 곳으로 이동시켜 해당 노드를 유지보수할 수 있게 함

3.3 쿠버네티스 연결을 담당하는 서비스

외부에서 크버네티스 클러스터에 접속하는 방법을 서비스라고 함

3.3.1 가장 간단하게 연결하는 노드포트

외부에서 클러스터의 내부에 접속하는 가장 쉬운 방법은 노드포트 서비스를 이용하는 것
노드포트 서비스를 설정하면 모든 워커 노드의 특정 포트를 열고 여기로 오는 모든 요청을 노드포트 서비스로 전달함
apiVersion: v1 kind: Service metadata: name: np-svc spec: selector: app: np-pods ports: - name: http protocol: TCP port: 80 targetPort: 80 nodePort: 30000 # 30000번의 노드포트를 허용함 type: NodePort
YAML
복사

3.3.2 사용 목적별로 연결하는 인그레스

NGINX 인그레스 컨트롤러 서비스 구성도
노드포트 서비스는 포트의 중복사용이 불가하여 1개의 노드포트에 1개의 디플로이먼트만 적용이 가능함
인그레스는 고유한 주소를 제공해 사용 목적에 따라 다른 응답을 제공할 수 있고, 트래픽에 대한 L4/L7 로드밸런서와 보안 인증서를 처리하는 기능을 제공
인그레스 컨트롤러는 파드와 직접 통신할 수 없어서 노드포트 또는 로드밸런서 서비스와 연동되어야 함
apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: ingress-nginx annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: rules: - http: paths: - path: backend: serviceName: hname-svc-default servicePort: 80 - path: /ip backend: serviceName: ip-svc servicePort: 80 - path: /your-directory backend: serviceName: your-svc servicePort: 80
YAML
복사

3.3.3 클라우드에서 쉽게 구성 가능한 로드밸런서

앞서 배운 방식은 들어오는 요청을 모두 워커 노드의 노드포트를 통해 노드포트 서비스로 이동하고 이를 다시 쿠버네티스의 파드로 보내는 구조
이 방식은 매우 비효율적
때문에 쿠버네티스에서는 로그밸런서라는 서비스 타입을 제공해 간단하 구조로 파드를 외부에 노출시키고 부하를 분산
kubectl expose deployment ex-lb --type=LoadBalance --name=ex-svc
YAML
복사

3.3.4 온프레미스에서 로드밸런서를 제공하는 MetalLB

MetalLB는 베어메탈로 구성된 쿠버네티스에서도 로드밸러서를 사용할 수 있게 고안된 프로젝트
특별한 네트워크 설정이나 구성이 있는 것이 아닌 기존의 L2 네트워크와 L3 네트워크로 로드밸런서를 구현함
때문에 네트워크를 새로 배워야 할 부담도 적으며 연동하기도 쉬움
MetalLB의 컨트롤러는 작동 방식을 정의하고 EXTERNAL-IP를 부여해 관리한다.
MetalLB 스피커는 정해진 작동 방식(L2/ARP, L3/BGP)에 따라 경로를 만들 수 있도록 네트워크 정보를 광고하고 수집해 각 파드의 경로를 제공
apiVersion: v1 kind: ConfigMap metadata: namespace: metallb-system name: config data: config: | address-pools: - name: nginx-ip-range protocol: layer2 addresses: - 192.168.1.11-192.168.1.13
YAML
복사

3.3.5 부하에 따라 자동으로 파드 수를 조절하는 HPA

사용자가 갑자기 늘어난다면 파드가 더 이상 감당할 수 없어 서비스 불가라는 결과를 초래할 수 있음
이런 경우를 대비해 부하량에 따라 디플로이먼트의 파드 수를 유동적으로 관리하는 기능을 제공함
이를 HPA(Horizontal Pod Autoscaler)라고 함
HPA 작동 구조
HPA가 작동하려면 자원을 요청할 때 메트릭 서버를 통해 계측값을 전달 받아야함
HPA를 통해서 늘어나는 파드 수 계산 방법
디플로이먼트 스펙에서 resources의 CPU를 10m으로 설정하고, autoscale에서 cpu-percent를 50%로 했다고 가정
파드가 29m 라는 부하를 받을 때 한개의 파드가 처리할 수 있는 부하량은 10m으로 CPU 부하량의 50%가 넘으면 자동으로 파드를 생성해야 하기 때문에 5m이 넘으면 파드를 증설
29/5를 한뒤 올림하면 6이라는 숫자가 나오고, 결국 증가하는 파드는6임

3.4 알아두면 쓸모 있는 쿠버네티스 오브젝트

데몬셋

데몬셋은 디플로이먼트의 replicas가 노드 수만큼 정해져 있는 형태, 노드 하나당 파드 한 개만을 생성
노드를 관리하는 파드라면 데몬셋이 가장 효율적

컨피그맵

컨피그맵은 이름 그대로 설정을 목적으로 사용하는 오브젝트

PV와 PVC

때때로 파드에서 생성한 내용을 기록하고 보관하거나 모든 파드가 동일한 설정을 유지하고 관리하기 위해 공유된 볼륨으로부터 공통된 설정을 가지고 올 수 있도록 설계할 때 이용
임시: emptyDir
로컬: host Path, local
원격: persistentVolumeClaim, cephfs, csi, fc 등등
특수목적: downwardAPI, configMap, secret 등등
클라우드: awsElasticBlockStore, azureDisk
PVC는 준비될 볼륨에서 일정 공간을 할당 받는 것
PV는 볼륨을 사용할 수 있게 준비하는 단계

스테이트풀셋

지금까지는 파드가 replicas에 선언된 만큼 무작위로 생성될 뿐이었음. 하지만 파드가 만들어지는 이름과 순서를 예측해야 할 때가 있다.
주로 레디스, 주키퍼, 카산드라, 몽고DB 등 마스터-슬레이브 구조 시스템에서 필요
레플리카풀셋은 volumeClaimTemplates기능을 사용해 PVC를 자동으로 생성할 수 있고, 각 파드가 순서대로 생성되기 때문에 고정된 이름과 볼륨, 설정 등을 가질 수 있음
다만 효율성 측면에서 좋지 않기 때문에 요구사항에 맞게 적절히 사용하는게 좋음