Cloud #15
스테이트풀 셋(StatefulSet)
쿠버네티스의 스테이트풀 셋는 퍼시스턴트 볼륨과 파드를 함께 조합해서 제어하는 컨트롤러이다. 이 컨트롤러는 파드와 퍼시스턴트 볼륨의 대응 관계를 더욱 엄격히 관리해서 퍼시스턴트 볼륨의 데이터 보관을 우선해서 작동된다. 원래 스테이트풀하다는 것은 내부에 예상되는 일정한 어느 상태를 가지고 있어서 내용이 달라져도 원래대로 상태를 유지하려는 것을 의미하는데, 예를 들어서 커피 자판기의 동전 투입 대기 상태와 주문 대기 상태를 생각해 볼 수 있다. 동전 투입 대기 상태에서는 어느 일도 하지 않고, 동전이 충분히 투입되면 주문 대기 상태가 된다. 이제 주문 버튼을 누르면 제품이 나오는데 여기서는 2개의 상태를 가지는 스테이트풀한 프로그램이 있다고 볼 수 있다.
컨테이너/파드는 태생적으로 데이터를 보관하는 것이 어렵기 때문에 파드와 퍼시스턴트 볼륨을 조합해서 실행해야 데이터를 저장하고 보호될 수 있는데 이런 면 때문에 쿠버네티스에서는 스테이트풀 셋이라는 컨트롤러를 사용한다. 스테이트풀 셋으로 노드 장애 시 자동으로 컨테이너를 복구되게 해주는데, 예를 들어서 노드 A가 장애 상황이라면 쿠버네티스 클러스터에서 해당 노드 A를 제외시키고 다른 노드 B에서 노드 A의 파드를 실행시키는 일을 한다. 이를 위해서 컨테이너는 kubectl 대신 쿠버네티스 API 파이썬 라이브러리를 사용하고, 파드의 쿠버네티스 클러스터의 조작 권한을 부여하기 위해서 서비스 계정과 RBAC을 사용한다.
- 디플로이먼트와 차이
스테이트풀 셋도 파드 템플릿에 기술한 replica 수에 해당하는 파드를 실행시킨다. 이때 파드의 이름은 스테이트풀 셋의 이름 뒤에 순서대로 번호가 부여된다. (이와 유사한 역할을 하는 디플로이먼트에서는 해시가 붙는다).
- 파드 분실 시는
스테이트풀 셋이 관리하는 파드의 IP는 랜덤하게 설정된다. 따라서 스테이트풀 셋이 관리하는 어느 파드에게 외부에서 요청이 전달될 때에는 파드의 IP가 아니라 IP가 없는 ClusterIP의 Headless 모드를 사용하는데-파드의 IP 대신 Service_명으로 처리해준다. 이 경우 스테이트풀 셋의 매니페스트에 spec.serviceName과 연동되는 서비스_명을 설정해주면, 각 파드의 이름으로 파드의 IP_주소를 얻어올 수 있다. 데이터베이스를 샤딩(shadding)해서 각각의 서버에 접속하는 경우처럼 매우 유용한 기법이다.
- 노드 장애 시
스테이트풀 셋이 관리하는 파드에 노드 장애 등이 있으면 동일한 이름으로 새롭게 파드를 실행시켜서 이전의 파드가 실행했었던 퍼시스턴트 볼륨을 계속해서 사용하게 한다. 하지만 파드의 이름은 같아도 파드의 IP_주소는 변하는 것에 주의한다. 이런 문제로 인해서 스테이트풀 셋 관리하의 파드에 접속할 때에는 IP_주소보다 내부 DNS를 사용해서 Service_명으로 연결하는 것이 좋다.
스테이트풀 셋은 상태를 유지한다는 의미로써, 하드웨어 장애나 네트워크 장애가 있을 때 특정 노드가 마스터와 연결이 끊어져도 데이터를 분실하지 않게 설계한 모듈이다. 파드가 퍼시스턴트 불륨(local, nfs, iscsi, NAS, ...)을 마운트할 때 ReadWriteMany 액세스 모드로 여러 노드에서 읽고/쓸 수 있고, ReadWriteOnly 액세스 모드로 하나의 노드에서만 읽고/쓸 수 있는 모드가 있지만 외부 스토리지에 종속된 특성이기 때문에 NFS와 같은 공유 퍼시스턴트 볼륨에 적용해도 제대로 작동하지 못할 수도 있다.
스테이트풀 셋은 장애 노드를 쿠버네티스 클러스터의 멤버에서 제외하거나, 문제가 있는 파드를 강제 종료하거나, 또는 장애로 인해 정지한 노드를 재가동하는 경우에 분실된 파드를 다른 노드에서 재실행시킬 수 있게 해준다. 하지만 스테이트풀 셋이 노드의 장애를 감지했을 때 대체 노드에 파드를 실행시키는 것은 위험할 수도 있는데 장애라고 판단한 노드에서 파드가 계속 실행되고 있을 경우 동일한 파드가 중복되어서 실행되기 때문이다. 이럴 때에는 장애 노드를 쿠버네티스 클러스터에서 제외하거나 재가동시키면 된다.
하지만 노드의 재실행이나 제외를 스테이트풀 셋이 할 수 없어서 외부에서 ‘kubectl delete node 장애_노드’식으로 장애_노드를 수동으로 제외해 주어야 한다. 그것도 마스터 노드와 장애_노드가 통신되지 못하면 작업할 수 없기 때문에 장애 노드를 자동으로 감지해서 대처해주는 활성 프로브(Liveness Probe)를 사용하는 것이 좋다.
- 수동 테이크오버(Take-over) 기법
앞의 Stateful Set와 이어지는 내용이다. 하드웨어 보수 작업 등으로 노드를 일시 정지해야 할 때가 있다. 현재 worker2 노드에서 mysql-0 파드가 실행되고 있는데 이 worker02 노드를 일시적으로 정지시키면, 죽은 worker02 노드에서 실행되던 mysql-0 파드를 다른 노드 worker01로 자동 이동되어서 worker01 노드에서 mysql-0 파드가 실행되게 된다.
=>만일 MySQL에서 작업 중이라면 mysql-0 파드의 이동은 라이브 마이그레션이 아니기 때문에 실행중인 MySQL 서비스를 일단 정지시킨 뒤, 수동으로 이동해야 MySQL에서 실행 중인 작업이 트랜젝션되거나 작업이 취소되어 롤백될 수 있다.
RBAC(Role-Based Access Control) 권한 부여
RBAC(역할기반)은 쿠버네티스 클러스터 내의 역할(Role)을 설정하고 그 역할에 접근 가능한 권한을 정의하는 접근 제어법인데 ABAC(Attribute-Based Access Control: 속성기반)보다 관리가 편해서 쿠버네티스의 디폴트 접근방식이다. 쿠버네티스에서 RBAC으로 정의한 역할은 서비스 계정과 매핑된다. 사용자 계정은 개인을 식별하는 계정이고 서비스 계정은 파드로 동작하는 컨터이너를 식별해주는 계정이다.
서비스 계정을 사용해서 필요한 최소한의 권한을 컨테이너에 부여함으로써 쿠버네티스는 사용자가 소속된 조직의 데이터베이스와의 동기화, 복잡한 워크 플로, 조직 변경 등에 대응하게 한다. 하지만 클라우드 서비스나 소프트웨어 제품에서는 개인별 사용자의 관리가 필수적이기 때문에 사용자 계정과 서비스 계정이 대응하게 하기도 한다.
데몬 셋을 이용한 클러스터 변경 자동 대응
데몬 셋은 쿠버네티스 클러스터를 구성하는 모든 노드에서 파드를 실행하게 하는 컨트롤러인데 클라이언트의 요청을 백그라운드에서 처리해주는 프로세스이다. 데몬 셋 관리 하의 파드는 쿠버네티스 클러스터의 모든 노드에서 실행된다. 그리고 데몬 셋 컨트롤러가 삭제되면 그 관리 하에 있던 모든 노드에서 파드가 삭제된다.
데몬 셋을 사용해서 전체 노드가 아닌 일부 노드에만 파드를 배치하고 싶을 때에는 노드 셀렉터를 설정하면 된다.
인그레스(Ingress)
인그레스는 쿠버네티스 클러스터 외부에서의 요청을 쿠버네티스 내부의 파드상 어플과 연결하기 위한 API 객체이다. 디플로이먼트 관리 하의 어플을 외부 공개용 URL과 매핑해서 인터넷에 공개할 수도 있다. 인그레스는 SSL/TLS 암호화나 세션 Affinity 등의 기능을 가지고 있어서 기존 어플을 쿠버네티스화 하는데 유용한 객체이다.
- 인그레스의 기능
인그레스는 공개 URL과 어플의 매핑, 복수의 도메인 이름을 가지는 가상 호스트 가능, 클라이언트의 요청을 여러 파드에 분산, SSL/TLS 암호화 통신의 HTTPS, 그리고 Session Affinity를 객체화 할 때 유용하다. 인그레스를 이용하면 기존의 로드밸런서나 리버스 프록시를 대체할 수 있고, 공개용 URL의 경로에 어플을 매핑해서 로드밸런싱, HTTPS 통신, 세션 어피니티를 구성할 수 있다. 인그레스 컨트롤러는 마스터상의 kube-controller-manager의 일부로 실행되지 않는다. 여러 인그레스 컨트롤러가 있는데 NGINX 인그레스 컨틀로러가 대표적이다. 또 로드밸런서로 유명한 F5 BIG-IP 컨트롤러도 널리 사용된다.
인그레스를 사용하기 위해서는 쿠버네티스 클러스터에 인그레스 컨트롤러를 설정해야 하는데 공공기관에서 사용하는 퍼블릭 클라우드에는 원래 설정되어져 있다. 인그레스를 설정할 때 인그레스 컨트롤러 구성에 따라 인터넷에 공인_IP를 취득하는 기능이 없을 수도 있기 때문에 퍼블릭 클라우드의 쿠버네티스 관리 서비스는 클라우드의 기능과 인그레스를 연동해서 공식 IP_주소와 연결시킨다. 그리고 온 프레미스(사설 클라우드)에서 쿠버네티스 클러스터를 구축하는 경우에는 공식 IP_주소(이를 VIP로 부름)를 노드와 공유하는 기능을 다음처럼 추가해준다.
a) minikube addons enable ingress
b) minikube addons list 해서 ingress: enabled를 확인한다. 이제 미니쿠베의 가상서버의 IP_주소로 인그레스를 사용할 수 있다.
c) minikube ip 해서 IP_주소를 확인할 수 있다.
- 공개 URL과 어플의 매핑
인그레스를 사용하면 공개 URL의 경로 부분에 복수의 파드내의 어플을 매핑할 수 있다. 예를 들어 http://abc.kahn.edu라는 URL의 reservation과 order라는 경로에 각각 전용 어플을 매핑해서
http://abc.kahn.edu/api-res 예약 파드,
http://abc.kahn.edu/api-order 주문 파드와 매핑해서 정보를 전송할 수 있다. 사용자 입장에서는 하나의 URL이지만 내부적으로 어플이 적절히 분리되어 있어서 느슨하게 결합된(스케일러블한) 어플의 집합체로 볼 수 있다.
인그레스는 공개 URL의 경로에 대한 요청을 연계된 파드에게 전송한다. 인그레스는 가상 호스트 기능이 있어서 하나의 공식 IP_주소를 공유해서 전송하는데 도메인_명으로 지정할 수 있다. 브라우저에서 http://abc.kahn.edu로 접속하면, DNS 서버에서 IP_주소로 반환하고, 이 주소에는 해당 어플이 실행되는 파드가 있다. 이 기능은 일시적으로 도메인_명을 필요로 하는 http://abc.kahn.edu/api-slaes를 즉석에서 생성해서 사용하게 할 수도 있다. 인그레스를 설정하는 매니페스트에서는 Metadata와 Annotation이 중요한 역할을 하는데 어노테이션에 키와 값을 기술해서
kubeanetes.io/ingress.class: 'nginx'와
nginx.ingress.kubernetes.io/rewrite-target: /식으로 기술하면 인그레스 컨트롤러에게 명령(값)을 전달한다. 이를 위해서 설정파일을 네임스페이스에 저장하는 ConfigMap 객체를 사용하는데, 다음처럼 파드에 컨피크맵을 디스크처럼 마운트할 수 있다.