쿠버네티스란?
- 도커 컨테이너, 스웜, 컴포즈와 같은 개념을 모두 사용 가능하다.
- 사실상 표준으로 사용되는 컨테이너 오케스트레이션 도구이다. 클라우드 환경에 적합한 오픈소스를 관리하는 Cloud Native(CNCF - 오픈소스 단체)에 속해있다.
- containerd, 프로메테우스 등이 CNCF 소속
장점
- 클러스터링, MSA구조의 컨테이너 배포, 장애 복구 등 운영에 필요한 오케스트레이션 기능을 지원한다.
- 구글, redhat을 비롯한 많은 오픈소스 진영에서 쿠버네티스에 기여하고 있다.
- 영속적 볼륨, 스케줄링, 장애 복구, 오토 스케일링, 서비스 발견, ingress 등의 기능들을 개발자가 직접 설정할 수 있다.
- 다른 클라우드 운영도구와 쉽게 연동
특징
- 모든 리소스는 Object이다.
kubectl api-resources
를 통해 확인 가능하다. - 대부분 리소스는 YAML로 관리한다.
- 여러 개의 컴포넌트가 컨테이너 형태로 구성되어 있다. -> 노드에 ssh 접속해서
docker ps
로 확인 가능- 마스터 노드 - API 서버, 컨트롤러 매니저, 스케줄러, DNS 서버 등
- 모든 노드 - 프록시(오버레이 네트워크 구성을 위한), 네트워크 플러그인
kubelet
: 모든 노드에는 컨테이너 생성, 삭제, 마스터와 워커 노드간 통신 담당하는 에이전트인 kubelet이 실행된다. 이 kubelet은 CRI(Container Runtime Interface)와 통신한다. 도커 컨테이너의 경우 runC라는 런타임을 제어하는 containerd는 자체적으로 CRI를 내장하고 있어, kubelet과 통신 가능하다. 이 CRI를 구현하는 컨테이너라면 다른 컨테이너를 사용해도 사실상 무방하다.
파드
- 컨테이너를 다루는 기본 단위. 하나 이상의 컨테이너로 구성
- 도커 네트워크 중 컨테이너 네트워크의 동작방식처럼 파드 내 컨테이너 간 리눅스 네임스페이스를 공유해, 서로 통신이 가능하다.
- 하나의 파드는 하나의 완전한 애플리케이션이어야 한다.
- e.g. 하나의 파드 내에 두개의 nginx 컨테이너를 띄우는 것은 적절하지 않다.
- 보통 파드 내 사이드카로 로그수집이나 설정 리로딩 프로세스를 띄우는 경우도 있다.
레플리카셋
: Pod의 Lifecycle을 관리해주는 역할. 파드를 yaml로서만 관리하면 생성, 삭제와 같은 관리를 개발자가 직접해줘야 한다. 이러한 방식은 운영 단계에서 분명 한계점이 있는데, 레플리카셋은 이러한 한계점을 해결한다.
- 일정량의 동일한 파드가 항상 실행되도록 관리한다. 이미 일정량의 파드가 실행중이라도 설정을 변경하면 변경된 만큼 파드를 생성 or 삭제해준다.
- 노드 장애 발생 시 해당 노드의 파드를 다른 노드로 다시 실행한다.
동작방식
레플리카셋은 라벨 셀렉터를 이용해 파드와 느슨하게 연결된다.
1 2 3 4 5 6 7 8 9 10 11
... spec: repolicas: 3 selector: matchLabels: app: my-nginx-pod # 레플리카셋의 라벨 셀렉터 template: metadata: name: nginx labels: app: my-nginx-pod # 파드의 라벨
- 라벨은 단순히 메타데이터로써 부가정보만 표시하는 것이 아니라, 리소스를 분류할 때도 사용된다.
- 이미 레플리카셋의 라벨 셀렉터에 셀렉팅 되는 파드가 있다면, 해당 파드를 포함해 생성해야 하는 숫자만큼 생성한다.
- 만약 파드의 라벨이 바뀌면 더이상 해당 레플리카 셋에 의해 관리되지 않는다.
디플로이먼트
: 파드 + 레플리카셋을 정의한다.
- 레플리카셋의 슈퍼셋이다. 공식적으로 디플로이먼트 사용이 권장된다.
- 디플로이먼트를 통해 레플리카셋과 파드를 띄우면 각각 동일한 해시값을 갖는다. 이 해시값은 파드 템플릿으로부터 계산되어, 레플리카셋의 라벨 셀렉터에서
pod-template-hash
라는 이름의 라벨값으로서 자동으로 설정된다.
디플로이먼트를 사용하는 이유
: 레플리카셋의 리비전을 남기고, 파드를 롤링업데이트하는 전략을 지정할 수 있다.
- 파드를 업데이트하면 롤링 업데이트가 수행되는데, 그러면 해당 파드들을 셀렉팅하는 레플리카셋도 새롭게 띄워진다.
kubectl get replicasets
를 통해 확인하면, DESIRED, CURRENT 항목에 숫자가 입력된 레플리카셋(현재)과 숫자가 0인 레플리카셋(이전 버전)을 확인할 수 있다.- 당연히
--to-revision=1
과 같은 옵션을 통해 롤백도 가능하다.
서비스
1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: Service
metadate:
name: hostname-svc
spec:
ports:
- name: port
port: 8080
targetPort: 80 # 실제 파드 내에서 실행되는 port
selector:
app: webserver # 서비스와 매칭할 pod
type: NodePort # 서비스 타입
- 파드는 클러스터 내에서 항상 접근 가능하지만, 파드 IP는 영속적이지 않아 매변 변하기 때문에 발견 가능한 방법이 필요한데, 서비스가 해결해준다.
- 외부에서 접근하는 경우, 도커에서는 컨테이너를 외부로 직접 노출해 접근했는데, k8s에서는 서비스를 통해서 접근해야한다.
- 서비스는 내부 DNS를 사용해 고유한 서비스 도메인 이름을 가질 수 있다.
- 파드 간 상호작용이 필요할때 파드 IP를 알 필요 없이 서비스 이름만 알면 된다.
- 요청받는 서비스는 각 파드들로 LB 해준다.
- 마찬가지로 라벨 셀렉터를 통해 파드와 매칭한다. 매칭이 되면 엔드포인트라는 오브젝트가 생성된다.
종류
: 각각 파드에 접근하는 방식이 다르다.
- ClusterIP: (쿠버네티스 내부에서만) ClusterIP를 프록싱해 파드에 접근하는 방식
- NodePort: 모든 노드의 특정 포트를 개방하는 방식
- 클러스터 외부에서 각 파드가 존재하는 노드의 적절한 port로 접근 가능하다.
- ClusterIP의 기능을 포함하고 있기 때문에 마찬가지로 서비스의 CLUSTER-IP or DNS 이름으로 접근 가능하다. (내부 접근 가능)
- 그런데 실제 운영 환경에서 사용하기엔 여러가지 문제가 있다. (라우팅) 노드가 스케일링, 장애 등의 이유로 IP가 변경되면 클라이언트도 수정되어야 하기도 하고, SSL 문제도 잇따른다.
- LoadBalancer: 서비스 자체를 외부에 노출한다.
- 클라우드 플랫폼 환경에서 사용할 수 있다.
- 클라우드 플랫폼은 LoadBalancer 서비스에 EXTERNER-IP를 부여하는데, 이 주소 + 서비스 PORT로 파드에 접근이 가능하다.
- NodePort와 같은 방식으로 노드로도 접근이 가능하다.
- ExternalName: 외부 도메인으로 리다이렉트한다.
ExternalTrafficPolicy
- 서비스는 기본적으로
externalTrafficPolicy
가 Cluster로 설정된다. 이 경우 노드로 들어온 요청은 다른 노드의 파드로 리다이렉트 되는 경우가 있고, 이 때 네트워크 홉으로 인해 NAT가 발생하며 클라이언트 IP가 보존 불가해진다. externalTrafficPolicy
를 Local로 설정하면 파드가 위치한 노드만 포트를 개방한다. 그런데 이 때는 트래픽이 몰리는 경우도 있을 수 있으므로 잘 판단해 선택해야한다.
Reference)
시작하세요! 도커 / 쿠버네티스