Tagged: 쿠버네티스

쿠버네티스에 프로메테우스(Prometheus) 오퍼레이터 설치하기

프로메테우스(Prometheus)는 모니터링 시스템을 말한다. 프로메테우스는 파일 기반의 타임시리즈(Time-Series) 데이터베이스다. 시스템의 메트릭스들을 수집하기 위해서는 익스포터(Exportor) 를 설치해야 한다. 이외에도 알람을 전달해주는 AlertManager 도 있는데, 전체적인 아키텍쳐는 다음과 같다.

프로메테우스 아키텍쳐

프로메테우스는 쿠버네티스에서도 설치가 가능한데, 이글은 쿠버네티스에 프로메테우스 설치에 대한 글이다.

환경

환경은 다음과 같다.

  • Kubernetes 버전: 1.20
  • Kubernetes Nodes: Master 3개, Worker 3개
  • Prometheus 설치 방법: Helm Operator

설치

프로메테우스(Prometheus) 설치는 매우 다양한데, 검색을 해보면 Helm 을 이용한 방법 그중에서도 오퍼레이터(Operator) 를 이용한 방법이 많이 소개 되어 있다. 여기서도 이 오퍼레이터를 이용한 방법을 사용하고자 한다.

Prometheus Operator 로 검색을 해보면 github 저장소를 찾을 수 있다.

중간에 보면 Prometheus Operator vs kube-prometheus vs community helm chart 가 보인다. 자세히 읽어보면 쿠버네티스에 설치할 수 있는 방법이 세 가지로 나뉜다는 것을 알수 있다.

이중에서 나는 Helm chart 를 이용한 방법을 이용할 생각이다.

노드 레이블 설정

노드에 레이블을 설정하게 되면 쿠버네티스에 앱을 배포할때에 레이블을 지정함으로써 특정 노드에 생성되도록 강제할 수 있다. 프로메테우스 오퍼레이터 설치를 특정 노드에 하기 위해서 레이블을 부여할 생각이다. 대상 노드는 kworker3.systemv.local 노드이며 다음과 같이 레이블을 할당해 줬다.

kworker3.systemv.local 노드에 system.rule=monitoring 레이블이 새겨졌다.

Helm Chart 가지고 오기

Helm 를 이용하면 명령어 한줄로 설치가 되지만 설정을 변경하기 위해서는 챠트(Chart) 를 수정해줘야 한다. 이를 위해서 챠트를 다운받아야만 한다. Helm 챠트는 프로메테우스 커뮤니티에서 관리하고 있다.

많은 챠트가 존재하는데, 여기서 설치 대상은 kube-prometheus-stack 이다.

설정을 하기위해서 프로메테우스 오퍼레이터의 구성을 살펴볼 필요가 있다.

  • Prometheus – 프로메테우스 리소스 정의가 되어 있다. 프로메테우스를 위한 파드(Pod) 의 리플리카(Replica) 갯수, 퍼시스턴스 볼륨 구성등이다. 프로메테이스 오퍼레이터는 파드를 StatefulSet 으로 배포 한다. 그리고 어떤 애플리케이션, 혹은 리소스를 모니터링할 것이지를 지정하는 것인데, 이것은 ServiceMonitor 로 설정이 이루어 진다.
  • ServiceMonitor – 프로메테우스 오퍼레이터는 어노테이션 기반의 서비스 디스커버리를 지원하지 않으며 대신 PodMonitor, ServiceMonitor 를 이용한다. ServiceMonitor는 애플리케이션이나 서비스의 리소스를 모니터링할 것인지를 지정한다. 쿠버네티스의 NodeSelector 처럼 LableSelector 로 서비스의 리소스를 선택할 수 있고, 엔드포인트(EndPoint) 를 통해서 애플리케이션의 메트릭을 수집할 수 있다. ServiceMonitor 는 rule 을 기반으로 Prometheus의 모니터링 대상이 되는 ServiceMonitor를 scan하여 해당 정보를 Secret으로 배포한다. 그리고 이 Secret을 Prometheus StatefulSet에 마운트한다. 이런 방식으로 Prometheus 팟은 자신이 모니터링할 Service가 무엇인지 알 수 있다.
  • Altermanager – 알람 매니저 이다. 프로메테우스 컴포넌트중에 하나다.
  • PodMonitor – 파드에 대한 모니터다. 역시나 LabelSelector 를 통해서 모니터링하고자 하는 파드를 지정할 수 있다.

위 내용을 잘 알야하는 이유는 kube-prometheus-stack 디렉토리에 values.yaml 파일에 구조와 연관이 있다.

values.yaml 파일 편집

프로메테우스 오퍼레이터를 Helm 으로 설치할 때에는 values.yaml 파일의 설정을 참고하도록 되어 있다. values.yaml 에는 altermanager, Grafana, Prometheus 등에 대한 설정 값들이 들어가 있다. 앞에서 특정 노드에 배포하도록 하기 위해서 worker3.systemv.local 노드에 레이블링을 해줬기 때문에 이들 컴포넌트의 NodeSeletor 를 지정해 줘야 한다.

Grafana, Altermanager, Prometheus 의 파드들은 system.rule=monitoring 레이블링 된 노드에만 설치되도록 해뒀다.

Node Exportor 는 system.rule=monitoring 레이블링을 할당하지 않는다. 이들은 노드마다 작동되어야 하기 때문이다.

Helm 설치

이제 설치를 해야 하는데, 설치하기 앞서 의존성 챠트를 업데이트 해야 한다.

이제 다음과 같이 설치를 실행해 준다.

확인

이제 확인을 해보자.

이렇게 설치가 된것으로 보이지만, 사실 프로메테우스의 오퍼레이터는 CRD 를 이용해 리소스를 생성하였기 때문에 이를 알아야 한다. CRD 를 포함한 monitoring 네임스페이스에 모든 리소스를 보기 위해서 다음과 같이 할 수 있다.

이를 통해 확인할 수 있는 CRD 예로 ServiceMonitor, Prometheus 등을 확인해 볼 수 있다.

필자는 Metallb 를 이용해서 LoadBalancer 를 사용할 수 있기 때문에 grafana, prometheus 서비스에 대해서 타입을 ClusterIP 를 LoadBalancer 로 변경해 외부접속이 가능하도록 할 수 있다.

Metallb 에 의해서 EXTERNAL-IP 에 외부접속 IP 가 할당 되었다.

Ingress Nginx

인그레스(Ingress) 는 쿠버네티스에 설치하는 클러스터 내의 서비스에 대한 외부 접근을 관리하는 API 오브젝트이며, 일반적으로 HTTP를 관리한다. 인그레스를 위해서는 인그레스 오브젝트를 설치해야 하는데, 이를 구현한 것들이 꽤 있지만 nginx 가 대표적이다.

여기서는 Ingress-Nginx 에 대해서 간단히 알아 본다.

설치전 고려사항

첫째로 일단 쿠버네티스에 서비스(Service) 에 고려 해야 한다. 쿠버네티스의 서비스는 클러스터내에 접속지점을 생성해 준다. ClusterIP, LoadBalancer, NodePort 세 가지의 타입이 존재한다. 문제는 LoadBalancer 타입인데, 이 타입을 지정해주면 EXTERNAL-IP 가 할당되어야 하지만 일반적인 환경에서는 할당되지 않는다.

LoadBalancer 는 클라우드 서비스 제공 사업자를 위한 것으로 AWS, GCP, Azure 클라우드에서 제공하는 로드밸런서를 위한 것이다. 그래서 일반적인 베어메탈(Bare Metal) 이나 VM 환경(VMware, VirtualBox, KVM) 에서 쿠버네티스를 구성한 상태에서 LoadBalancer 를 사용하게 되면 EXTERNAL-IP 할당되지 않는다.

이렇게 하면 외부에서 접속이 되지 않는다. 이 접속은 클러스터내에 파드(Pod) 에서 호출할 수 있지만 외부에서는 호출이 되지 않는다.

그래서 베어메탈이나 가상환경에서 쿠버네티스에서 LoadBalancer 를 사용할 수 있도록 해주는 Metallb 을 이용했다. 이를 이용하면 서비스 타입을 LoadBalancer 로 지정했을 경우, EXTERNAL-IP 가 할당돼 외부에서 접속이 가능해 진다.

두번째로 ingress-nginx 를 Helm 으로 설치하지 말아야 한다. 현재 Helm 저장소에 올라온 ingress-nginx 는 api 버전이 과거에 버전이다. v1beta 버전으로 되어 있는데, 필자의 쿠버네티스에서는 오래된 버전으로 인식된다.

이를 해결하기 위해서는 github 저장소에 baremetal 버전에 deploy.yaml 파일을 이용해야 한다.

설치

먼저 ingress-nginx 의 github 에 접속해 baremetal 버전을 다운로드 받는다.

이 deploy.yaml 은 baremetal 버전인데, 여기의 서비스 타입은 NodePort 로 되어 있다. 필자는 앞에서도 말했지만 Metallb 를 설치했기 때문에 LoadBalancer 타입으로 변경을 해줘야 한다. deploy.yaml 파일을 열어서 바꿔 준다.

서비스 타입을 바꿨다면 이제 설치를 해 준다.

이 방법으로 설치를 하게 되면 다음과 같은 특징을 갖게 된다.

  • ingress-nginx 네임스페이스가 생성 된다.
  • LoadBalancer 타입이며, Metallb 으로 인해 EXTERNAL-IP 가 할당 된다.
  • apiVersion 이 networking.k8s.io/v1 최신 버전을 지원 한다.

LoadBalancer 에 EXTERNAL-IP 에 외부 접속을 하기 위한 IP가 할당되어 있다.

예제

예제는 springboot 를 이용한 서비스를 배포하고 ingress 를 통해서 접속해 본다. 이 예제는 하나의 서비스에 대한 것이다.

먼저 Deployment, Service 를 다음과 같이 작성 한다.

정상적으로 생성이 되었다. 이제 이것을 인그래스와 연결을 해줘야 한다. 인그래스에서 URI 가 /springboot 이면 지금 배포한 springboot 의 메시지가 화면 표시되도록 했다.

직접해보면 위와같이 오류가 발생한다. 이는 보안 관련 쪽에 문제가 있는 것으로 보이는데, 아마도 TLS 설정에 문제가 있기 때문인 것으로 추정 된다. 이를 해결하기 위해서는 webhook 설정을 삭제해주면 된다.

그리고 다시 한번 ingress-springboot.yaml 파일을 적용해주면 인그래스가 생성 된다.

/springboot URI 는 springboot-service 백엔드로 연결이 되어 있다걸 확인할 수 있다. 이제 인그레스 서비스에 LoadBalancer 의 외부 접속 IP 로 접속을 시도해 보자.

위와같이 인그레스가 정상적으로 동작함을 알 수 있다.

정리

지금까지의 예제는 쿠버네티스 인그레스 문서의 첫번째 다이어그램과 정확하게 같은 것이다.

단일 서비스에 인그레스 적용 다이어그램

클라이언트가 인그레스 로드 밸런서로 접속이 가능해야 했기 때문에 Metallb 을 이용해서 외부접속 IP를 할당해 주도록 설정을 했다.

인그레스 서비스는 설치할때 한번 생성되어지고 이것을 통해서 뒤에 서비스들과 연결이 되어지는데, 이 백엔드 서비스들에 어떻게 연결을 할 것이지에 대한 설정은 인그레스 컨트롤러에 의해서 결정되게 된다.

Metallb 설치하기

쿠버네티스(Kubernetes) 의 서비스(Service) 에 타입에는 Loadbalancer, NodePort 등을 지원한다. 문제는 Loadbalancer 는 클라우드(Cloud) 서비스 사업자를 위한 것으로 AWS, GCP, Azure 에서 제공하는 Loadbalancer 를 위한 것이다.

그런데, 많은 쿠버네티스의 사례를 살펴보면 Loadbalancer 를 사용한 사례가 아주 많다. 그래서 굳이 클라우드 서비스 사업자가 아니라고 하더라도 Loadbalancer 를 사용할 수 있도록 해보자해서 만들어진게 바로 Metallb 이다.

필자는 KVM 리눅스 가상화에 쿠버네티스를 설치했다. KVM 가상 시스템의 게스트 OS 들은 브릿지 네트워크 모드로 이기 때문에 필자의 공유기에서 자동으로 아이피를 할당 받거나, 공유기의 대역에 IP를 고정으로 사용하기도 한다. 필자의 공유기는 192.168.96.0/20 대역폭을 사용하도록 세팅을 해놨기 때문에 할당 가능한 IP는 차고도 넘친다.

Metalb 는 이렇게 외부에서 접속이 가능한 아이피 대역을 할당해 사용한다.

설치

설치를 위해서 필요한게 있는데, CNI 가 먼저 있어야 한다. Flannel, Calico 와 같은 CNI 가 설치가 먼저 되어 있어야 한다. 설치는 설치를 위한 메니페스토 파일을 이용한다.

namespace.yaml 은 그냥 네임스페이스를 만들도록 되어 있어서 명령어로도 가능하다.

이렇게 하면 설치는 되지만 아직 동작하지는 않는데, Metallb 에서 사용할 외부 아이피나 운영 모드등을 설정해줘야 하는데, 이는 ConfigMap 를 이용해 다음과 같이 설정해 줘야 한다.

위와같이 Metal Loadbalancer 에서 사용할 외부 주소 IP 주소 대역을 할당해 준다.

또, 이제 Metallb 의 컴포넌트의 통신을 보호하기 위해서 Secret 를 다음과 같이 생성해 준다.

Ingress-nginx 설치

테스트를 위해서 Ingress-nginx 를 설치해 본다. Ingress-nginx 를 설치하게되면 서비스에 Loadbalancer 타입으로 설치가 되는데, EXTERNAL-IP 가 Metallb 에서 할당해준 IP가 할당이 된다.

EXTERNAL-IP 에 할당한 IP 로 웹 접속을 하게되면 nginx 가 나오게 된다.

Docker, Kubernetes 네트워크

인터넷 검색을 하다보면 Docker, Kubernetes 네트워크에 관한 글이 많이 보인다. 기본적인 이론에서부터 응용까지 잘 설명된 글들이 꽤 많은데, 나는 눈에 보이는 상태를 한번 살펴보기로 했다.

Docker 네트워크

Docker 를 처음 설치하면 어떤 상태일까? 먼저 Docker 를 설치한 리눅스 시스템의 네트워크 상태는 다음과 같다.

docker0 라는 네트워크 인터페이스가 생성되면서 172.17.0.1/16 아이피가 할당되었다. 그리고 이 인터페이스는 Bridge 다.하지만 인터페이스는 DOWN 상태다. Docker 를 막 설치하고 난 후에 이런 모습이다.

Bridge 상태는 다음의 명령으로 확인이 가능하다.

nmcli 를 보면 TYPE 에 bridge 라고 나온다. 그리고 이 docker0 인터페이스는 docker 네트워크에서 Bridge 네트워크에 해당한다고 다음과 같이 확인해 볼수 있다.

“com.docker.network.bridge.name”: “docker0” 로 Docker Bridge 가 docker0 호스트 네트워크 인터페이스라는 걸 말해주고 있으며 여기에 붙은 Container 인 doc1 에 대한 정보를 보여주고 있다. doc1 컨테이너의 IP 는 172.17.0.2/16 이다.

bridge 명령어에서는 아무것도 안나온다. 이제 Docker 컨테이너를 하나 실행해 본다.

이렇게 Docker 컨테이너를 하나 생성하면 docker0 브릿지 인터페이스는 Down -> Up 상태로 변경되며 여기에 veth 가상의 인터페이스가 하나 붙는다.

“veth46d3de6@if8” 가 보인다. 이것은 필시 doc1 컨테이너가 실행되면서 생성되었을게 분명하다. 이것과 doc1 과는 무슨 상관일까?

doc1 컨테이너의 네트워크 인터페이스 eth0 는 8번이다. 그리고 if9 로 인터페이스 9번을 가리키고 있다고 명시하고 있다. 아래 호스트 네트워크 인터페이스를 보면 veth 라고 나오는데, if8 로 인터페이스 8번을 가리고 있다. 인터페이스 8번은 doc1 컨테이너의 네트워크 인터페이스를 말한다.

그러니까 네트워크 인터페이스에 번호로 서로 연관성을 보여주고 있다는 걸 알수 있다.

ip 명령어를 통해서 veth 인터페이스만 뽑아 볼 수 있다. veth 는 가상 이더넷(Virtual Ethernet) 인데, Docker 컨테이너가 생성될때마다 가상 이더넷 카드가 호스트에 하나 생성되고 이런 가상 이더넷은 Docker 컨테이너의 기본 네트워크 인터페이스 카드와 연결된다.

docker0 는 Docker 에 기본 Bridge 인터페이스이며 Docker 컨테이너가 하나도 없으면 DOWN 상태가 되며 단 하나의 컨테이너가 실행될 경우에 UP 상태로 변경되고 가상 이더넷을 생성하고 Bridge 에 붙이게 된다.

Kubernetes 네트워크

Kubernetes 를 설치하고 난후에 상태는 Docker 만 설치한 것과 동일하다. Kubernetes 는 CNI 를 설치를 해줘야 한다. CNI 는 Kubernetes 에 네트워크를 담당할 기능을 붙이기 위한 인터페이스로 다양한 네트워크 기능들을 제공하는 프로그램들이 있다.

Flannel, Weave, Calico 등등이 자주 쓰인다.

한가지 의문(?) 혹은 문제는 이 쿠버네티스 CNI 들은 구조가 모두 다르다. 테스트를 위해서 Flannel 을 사용했다.

정상적으로 설치되었다면 Flannel 이 Pod 로 올라온다. 더불어서 CoreDNS 도 정상으로 나온다.

한가지 쿠버네티스에 대해서 짚고 넘어가야 할게 있는데, 쿠버네티스는 마스터 노드라 불리는 Controller 와 워커 노드로 나뉜다. 적어도 2대의 호스트 서버가 필요하고 여기에 설치가 진행 된다.

Flannel 을 설치하고 nginx 파드(pod) 를 생성한 후에 워커 노드 상태다.

위 상태를 보면, cni0 네트워크 인터페이스가 보인다. 이는 Flannel 에서 생성한 것으로 Bridge 다.

위에 보면 Bridge 네트워크 인터페이스를 볼 수 있는데, Docker0 는 DOWN 이며 cni0 는 UP 상태다. 이 cni0 에 연결된 네트워크 인터페이스는 다음과 같이 확인할 수 있다.

이 인터페이스는 필히 nginx 파드에 것이다. master 브릿지로 cni0 를 사용하고 있다.

그러면, flannel.1 인터페이스는 대체 무엇일까? 다음의 명령어로 확인해 보자.

“vxlan id 1 local 192.168.96.39 dev enp0s3” 로컬 호스트의 enp0s3 에 연결된 vxlan 이라고 나온다.

Flannel 은 VXLAN 기반으로 호스트가 서로 다른 파드에 대한 연결을 만들어주게 되어 있다. 마스터 노드에서 다음의 명령어를 실행해 보자.

backend-type: vxlan 이라고 나오고 있으며 VTEP 도 보인다. 이 장치에 대한 Mac 주소도 나오는데, 이것은 flannel.1 에 있는것과 같다.

파드의 네트워크는 veth 장치를 통해서 패킷이 나가고 이것을 cni0 브릿지가 받는다. 그리고 flannel 이 이것을 flannel.1 장치로 보내게 된다.

이렇게 하는 이유가 있는데, Flannel 은 L2 Layer 스위치다. L2 Layer 스위치는 ARP 라우팅만 가능하다. 파드(Pod) 가 같은 호스트에 있는 경우에는 ARP 라우팅만으로 서로 통신이 가능하겠지만 호스트가 다를 경우, IP 대역이 변경될 경우에는 원격 호스트에 있는 파드를 ARP 라우팅만으로 찾을 수 없다.

그래서 Flannel 은 L3 Layer 계층의 가상의 스위칭 장비를 만들고, 이렇게 만들어진 각 호스트의 가상의 스위칭을 하나로 연결하는데 이것이 바로 VXLAN 이다. 가상의 스위칭 장비가 flannel.1 네트워크 인터페이스 이다. 이때, cni0 에서 올라온 데이터는 L2 Layer 에서 만든 프레임(Frame)으로 이것을 UDP 패킷형태로 IP 를 붙여 캡슐화 한다. 그리면 flannel.1 인터페이스는 다른 호스트와 연결된 또 다른 flannel.1 인터페이스로 브로드캐스팅을 한다.

다른 호스트로 받은 UDP 패킷은 flannel.1 장치에 의해서 까지고(디캡슐화) 자신의 네트워크 대역과 비교하는데, 맞으면 받은 프레임에 destination mac address 를 자신의 mac address 로 넣고 다시 UDP로 캡슐화해 돌려보낸다. 이렇게 함으로써 호스트가 다른 파드의 이더넷 주소(맥주소)를 얻게되어 연결이 이루어지는데, 이게 VXLAN 의 동작 방법이다.

VXLAN 는 L2 Layer 프레임을 UDP L3 Layer 로 캡슐화해 브로드캐스팅하고 목적지 맥주소를 얻는데 있다.

Flannel 은 이렇게 작동하지만 Calico 는 또 다르다. Calico 는 BGP 연결을 통해서 아예 L3 Layer 를 구현 한다. 완전한 Pure L3 Switch 기능을 제공하기 때문에 처음부터 IP 라우팅이 가능해진다. Calico 는 Tunnel.0 인터페이스를 통해서 서로 다른 호스트와 Peer to Peer 연결되어 있어서 IP 라우팅만으로 대상 호스트의 파드를 알아낼 수 있다. 그래서 동작 방법은 (Flannel 보다) 훨씬 간단하다.

메트릭 서버(Metric Server) 설치에 관한 오류들…

다양한 메트릭 서버 설치에 관한 오류들을 알아보자.

kubectl top node Error from server (ServiceUnavailable): the server is currently unable to handle the request (get nodes.metrics.k8s.io)

메트릭 서버(Metric Server) 의 파드(Pod)가 정상적으로 Running 상태라 하더라도 이와같은 오류 메시지를 만날 수 있다. 이 오류는 kube-apiserver 의 로그에 다음과 같이 관련 오류가 나온다.

뒤쪽에 삭제된 부분은 “net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)” 이다. 응답커넥션을 맺다가 안되서 timeout 으로 끝난 것이다.

이것은 kube-apiserver 다음의 커맨드 파라메터를 추가해줘야 한다.

  • –enable-aggregator-routing=true

메트릭 서버의 0.4.3 버전부터는 쿠버네티스의 Aggregator Layer 를 이용한다. API 서버가 실행중인 호스트에 kube-proxy 가 없을 경우에 위 파라메터를 추가해줘야 한다.

워커 노드 메트릭 수집 안됨

쿠버네티스의 Deployments.apps 리소스에 배포된 Metric Server 메니페스트를 다음과 같이 수정해 줘야 한다.

hostNetwork: true 를 추가해줘야 한다.

extension-apiserver 란?

쿠버네티스(Kubernetes)가 발전에 따라서 많은 변화를 겪었다. 최신의 버전에서 extension apiserver 라는 것을 필요로하는 경우가 많다. 이것은 쿠버네티스 문서에서는 aggregation layer 라고 설명하고 있다.

Configuring the aggregation layer allows the Kubernetes apiserver to be extended with additional APIs, which are not part of the core Kubernetes APIs

애그리게이션 레이어 설정은 쿠버네티스 API 코어의 일부가 아닌 추가적인 API를 가지고 확장될 수 있는 쿠버네티스 apiserver 를 가능하게 한다.

Configure the Aggregarion Layer

최근에 구축한 쿠버네티스 서버에 메트릭 서버(Metric Server) 를 설치했는데 제대로 작동되지 않아 왜 그런가 봤더니 바로 이 문제였다. 메트릭 서버 파드(Pod) 에 로그는 다음과 같다.

메시지를 보면 extension-apiserver-authentication 등의 메시지를 볼 수 있다. 문제는 이런 로그가 남는다고 해서 메트릭 서버 파드의 상태가 Running 으로 된다는 것이다. 파트 상태가 Running 이라고 해서 메트릭 서버가 정상으로 작동되는 것은 아닌게 문제의 핵심이다.

이 문제를 해결하기 위해서는 extension-apiserver 기능을 apiserver 가 가지도록 해야 한다. 이것은 kube-apiserver 에 커맨드 파라메터를 다음과 같이 추가 해주고 재시작 해줘야 한다.

요구사항을 보면 인증서가 필요하다는 것을 알게 된다. 인증서 제작은 Kubernetes Hard Way 문서에 잘 정리되어 있다. 필자는 쿠버네티스 하드 웨이 방법을 구축한 서버이기에 이 과정을 진행해 볼 수 있었다.

extension apiserver 를 위한 인증서 작성

인증서 작성은 다음과같이 CSR 파일을 작성함으로서 시작된다.

여기서 주의해야 할 것이 조직(O) 를 system:masters 로 해야 하며, CN 은 –requestheader-allowed-names 파라메터의 값과 동일해야 한다. 이제 다음과 같이 인증서를 제작한다.

이제 이것을 각 master 서버에 배포를 해준다.

kube-apiserver 커맨드 파라메터 수정

배포를 모두 했다면, 이제 kube-apiserver 에 커맨드 파라메터를 수정해 줘야 한다. systemd 에 kube-apiservere 를 등록했기 때문에 유닛 파일을 수정해주면 된다.

정상적으로 구동이 되었다면 이제 메트릭 서버를 재설치하면 정상적으로 작동 된다.

Kubernetes 프로세스별 상태

Kubernetes 는 다양한 컴포넌트들로 인해서 작동된다. 이러한 컴포넌트들은 중요성에 있어서 약간의 차이가 있다. 예를들어 Worker Node 에서 docker 프로세스가 정지되거나 문제가 되었을때에 어떻게 될까? 혹은 Worker Node 에 kubelet 프로세스가 문제가 된다면?

이 문서는 Kubernetes 프로세스별 상태 에 대한 글이다.

환경

여기서 환경은 Kubernetes 의 객체를 말한다. 객체라함은 Pods, Deployments, Services, StatefulSet 으로 했다. 그밖에 다양한 객체가 있지만 이 정도 생성해서 진행해보기로 했다.

docker 정지

이것은 Work Node 에 docker 를 정지 시키는 것이다. 이렇게 되었을때에 Kubernetes 의 각종 컴포넌트들은 어떤 상태를 보일지 알아보자.

먼저, Nodes 상태는 ‘Notready’ 로 변경된다.

Node 의 자세한 상태를 describe 보면 다음과같이 몇가지 상태가 나온다.

  • Warning ContainerGCFailed 38s (x2 over 98s) kubelet, knode rpc error: code = Unknown desc = Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

Conditions 는 다음과 같이 된다.

두번째, Pods 상태.

상태가 STATUS 는 Completed 으로 나오고 READY 도 0/1 로 나온다. 정상으로 나오지 않는다. Pods 하나를 골라 describe 해보면 Ready 는 False 로 나온다.

세번째, Deployment 상태.

READY 가 0/3 으로 모두 문제가 있는 것으로 나온다.

네번째, Services 상태.

Service 에 상태는 없다.

다섯번째, StatefulSet 상태.

StatefulSet 상태로 READY 가 0/2 로 모두 문제가 있는 것으로 나온다. 하지만, Pods Status 에서는 “2 Running / 0 Waiting / 0 Succeeded / 0 Failed” 로 Pod 2개 Running 으로 나온다.

kubelet 정지

kubelet 은 Worker Node 에 명령을 수행하는 중요한 프로세스이다. 이를 정지했을때는 어떤 상태를 보일까..

Node 상태.

Node 상태는 NotReady 가 된다. 그리고 Conditions 상태는 다음과 같다.

Pods 상태

이상하게도 Pods 상태는 모두 정상으로 나온다. 하지만 Port-Foward 를 시도하면 되지 않는다.

Deployment 상태

비정상으로 나온다. READY 가 0/3 으로 표시된다.

StatefulSet 상태

비정상으로 나온다. READY 가 0/2 로 표시된다.

Worker Node 셧다운

이 상태는 kubelet 와 동일한 결과를 보여준다.

StatefulSet 에서 로컬 디스크 사용

이 문서는 StatefulSet 에서 로컬 디스크 사용 에 대한 글이다. Kubernetes 에서 디스크 사용은 어려운감이 있다. PersistentVolume 과 PersistentVolumeClaim 이라는 것을 알아야하고 이를 알고나서도 여러가지 속성들때문에 헷깔리는 경우가 많다.

PersistentVolume 관련해서 문서를 보면 대부분 클라우드가 제공하는 스토리지를 이용하는 예제가 많다. 그것이 아니라면 nfs 를 이용하는 경우가 많아서 나처럼 집에 컴퓨터를 이용하는 경우에 실습해 보기가 쉽지 않은게 사실이다.

StatefulSet 의 경우가 바로 이런 경우였다. StatefulSet 을 연구하기 위해서 여러가지 예제를 찾아봤고 다음과 같은 파일을 찾아냈다.

StatefulSet 은 비상태(stateless) 자원을 생성하는게 아니라 상태를 가지는 자원을 생성하게 해주는 Kubernetes 의 객체다. 대부분 Persistent Data 를 위한 것이기에 PersistentVolume 을 대부분 필요로 한다.

위 예제를 가지고 생성을 해보자.

정상적으로 생성이 됐다고 나온다. 확인을 해보자.

Pod 생성이 Pending 상태를 보이고 있다. 왜 이럴까? 앞에서 객체 생성을 정의한 yaml 파일을 자세히 보면 Persistent Volume 을 요청하고 있다. volumeClaimTemplates 이 바로 그것이다. 이것은 PersistentVolumeClaim 을 요청하는 것으로 나타난다. 확인해 보자.

persistentvolumeclaim 이 Pending 상태이다. 결국에는 이것으로 인해서 Pod 생성도 Pending 이 된 것이다.

해결방안

PersistentVolumeClaim 은 PersistentVolume 이 있어야 한다. 그리고 이것을 묶어줘야하는데 이것을 Bound 라고 한다. 문제는 web.yaml 을 실행했을때에 생성되는 PersistentVolumeClaim 과 PersistentVolume 을 어떻게 연결할 것인가?

좀더 정확하게 말하면 StatefulSet 이 자동으로 생성하는 PersistentVolumeClaim 과 PersistentVolume 을 어떻게 연결할 것인가?

StatefulSet 의 특징은 생성하는 객체의 이름이 임의대로 정해지지 않는다. 정확하게 사람이 인식하기 쉬운 이름으로 결정된다. 앞에서보면 Pod 의 이름이 web-0 이다. 이는 Pod 이름에 Replicas 의 첫번째인 0 을 붙여서 만든다.

StatefulSet 에서 PersistentVolumeClaim 이름은 예측 가능한 패턴을 따른다. volumeclaimtemplates-namestatefulset-namereplica-index. 그래서 생성된 PersistentVolumeClaim 의 이름이 www-web-0 가 된 것이다.

PersistentVolumeClaim 은 PersistentVolume 을 필요로 한다. PersistentVolume 을 생성할때에 claimRef.name 을 PersistentVolumeClaim 이름으로 지정한다. 이렇게 하면 PersistentVolumeClaim 이 생성될때에 PersistentVolume 이 이름과 연결되어 자동으로 Bound 되어진다. 다음과 같이 PersistentVolume 을 만든다.

이것은 Kubernetes Worker 호스트에 파일시스템에 특정 디렉토리를 PersistentVolume 으로 생성한다. 만일 디렉토리가 존재하지 않을 경우에는 생성하도록 한다. 그리고 PersistentVolumeClaim 이 삭제되면 이 볼륨도 함께 삭제되도록 했다.

여기서 중요한 것이 claimRef 필드이다. name 속성에 PersistentVolumeClaim 이름을 지정해준다.

또, nodeAffinity 필드를 이용해서 특정한 Worker 에서 생성되도록 했다.

StatefulSet 에서 replicas 를 2 로 했기 때문에 위 PersistentVolume 생성은 claimRef.name 이 www-web-0, www-web-1 로 두개가 필요하다.

두개의 PersistentVolume 을 생성하고 시간을 갖고 기다리면 다음과 같은 결과를 얻게 된다.

Worker 호스트에 PersistentVolume 에서 생성한 디렉토리가 있는지 확인해 보자.

이렇게 문제를 해결할 수 있다.

참고: StatefulSet 에서 기존 디스크 사용

Kubernetes 설치

Kubernetes 설치에 대해서 다룬다. 이번에는 Ubuntu 20.04 LTS, Centos 8.2 기반으로 진행했으며 이전에 설치에서 CNI 를 Calico 로 진행 했다. 더 나가 Helm, Metric Server 까지 진행 한다.

설치 환경은 다음과 같다.

  • Master
    • Distribution: Ubuntu 20.04
    • IP: 192.168.96.31
    • Hostname: kmaster
    • account: systemv
  • Worker Node
    • Distribution: CentOS 8.2
    • IP: 192.168.96.32
    • Hostname: knode
    • account: systemv
  • CNI: Calico
  • Helm 설치
  • Metric Server 설치

공통 설정 부분

Master, Node 두 서버 모두 Static IP 주소를 가지고 있어야 한다. 그리고 모두 일반 계정을 가지고 있어야 하며 이 일반 계정은 sudo 사용 권한을 가지고 있어야 한다.

sudo 권한 부여

CentOS 8.2 의 경우에 일반 계정을 생성한 후에 sudo 권한을 주고 싶다면 다음과 같이 하면 된다.

CentOS 8.2 에는 wheel 라고 하는 특수한 그룹이 존재하는데, sudo 설정에는 이 그룹에 한해 sudo 사용 권한을 부여하고 있어 일반 계정 systemv 에 sudo 를 사용하게하고 싶다면 wheel 그룹에 포함시키면 된다.

Ubuntu 20.04 에서는 다음과 같이 일반계정에 sudo 권한을 부여할 수 있다.

br_netfilter 모듈 로딩

br_netfilter 커널 모듈을 로딩해 줘야 한다. 기존에는 modprobe 설정으로 했지만 이제는 systemd 를 활용하면 되는데 ubuntu 20.04, CentOS 8.2 이 모두 이를 사용하고 있어서 적용 가능하다.

다음과 같이 모듈이름으로 conf 파일을 생성해 준다.

물론 이렇게 하면 시스템을 재부팅을 하더라도 자동으로 모듈이 로딩 된다.

커널 네트워크 파라메터

다음과 같이 커널 파라메터를 수정해 줘야 한다.

/etc/hosts 파일 편집

Master, Node 서버 양쪽 모두에 /etc/hosts 파일에 각 서버 정보를 다음과 같이 입력해준다.

swapoff 설정

kubernetes 는 swap 파티션이 존재할 경우에 동작하지 않을 수 있다. 예를들어, kubeadm 명령어로 뭔가를 할려고 할경우에 swap 파티션이 존재할 경우에 오류를 내면서 작동되지 않는다.

Master, Worke 양쪽 모두에 swap 을 off 로 해준다.

이렇게 하면 swap 이 비활성화 된다. 그리고 반드시 /etc/fstab 에서 swap 관련 마운트 설정을 주석처리 해준다.

CentOS 8.2 에서 설정

SELinux off

CentOS 8.2 에서 설정은 SELinux 설정이다. 다음과 같이 해준다.

firewalld 비활성화

이것은 systemctl 로 다음과 같이 가능하다.

패키지 설치

Ubuntu 에서 설정

패키지 설치

Docker 설치 및 설정

Kubernetes 는 Docker 를 기반으로하는 서비스다. 당연히 설치를 해줘야 하는데, 설치 관련 내용은 다음에 링크에서 각 배포판마다 잘 설명되어 있다.

한가지, Docker 설치를 위한 패키지 저장소는 명령어와 파일을 생성하는 방법 두가지가 있다.

Ubuntu 20.04

ubuntu 에서는 add-apt-repository 명령어로 저장소 URL 을 추가 가능하다. 예를 들면 다음과 같다.

저장소 추가가 되었다면 다음과 같이 Docker 를 설치해 준다.

CentOS 8.2

CentOS 8.2 에서는 yum-config-manager 명령어를 이용해서 추가할 수 있다. 이 명령어는 yum-utils 패키지에 포함되어 있어 설치하면 사용할 수 있다.

저장소 추가가 되었다면 다음과 같이 Docker 를 설치해 준다.

현시점에서 위와같은 오류가 발생한다. CentOS 8 에 대한 containerd 저장소가 존재하지 않기 때문에 필요한 정보만 출력하고 오류를 낸다. 수동으로 필요한 패키지를 다운받아서 해결한다.

수동으로 설치는 정상적으로 진행된다. 그리고 다음과 같이 Docker 를 설치해 준다.

CentOS 8.2 에서 Docker 를 설치하면 필요한 서비스가 자동으로 시작되지 않는다. 이를 위해서 다음과 같이 systemd 를 설정해주고 시작해준다.

CGroup Driver 설정

Ubuntu, CentOS 모두 공통으로 Docker 를 설정해 주는 부분이 존재한다. 바로 Driver 를 systemd 로 바꿔줘야 한다.

Kubernetes 를 설치할때에 Cgroup driver 를 systemd 로 추천하고 있다. 그래서 Kubernetes 만 systemd 로 드라이버를 교체하면 docker 와 통신이 되지 않는다. 이것을 위해서 Docker 에서도 드라이버를 systemd 로 교체해 준다.

다음과 같이 확인이 가능하다.

Kubernetes 설치

Ubuntu 20.04

Master 로 사용될 Ubuntu 20.04 에서 다음과 같이 Kubernetes 패키지 저장소를 추가 한다.

xenial 은 Ubuntu 16.04 를 말하는데 Ubuntu 20.04 에 설치하는데 아무런 문제가 없다.

다음과 같이 kubeadm, kubelet, kubectl 을 설치해 준다.

CentOS 8.2

CentOS 8.2 에서는 다음과 같이 Kubernetes 패키지 저장소를 추가 한다.

그리고 다음과 같이 Kubernetes 를 설치해 준다.

Master 설정

Master 를 다른 말로 Control Plaine 이라고도 한다. 이것을 만드는 것은 kubeadm 을 이용한다. 일반 계정으로 실행 한다.

Kubernetes Master 명령은 전부 일반계정으로 하도록 되어 있어 있다. 일반계정이 kube api 통신을 위한 설정을 위 출력에 나온데로 실행해주면 된다.

하지만 문제가 있다. 다음을 보자.

kmaster 가 ‘NotReady’ 나오고 coredns 상태가 ‘Pending’ 이다. kubelet 로그를 보자.

NetworkPlugin 이 없어 오류가 나오는 것으로 이는 CNI(Container Network Interface) 를 필요로 한다.

Calico 설치

Calico 는 Flannel 처럼 Kubernetes Cluster 에 네트워킹을 가능하도록 해준다. CNI 를 위한 컴포넌트중에 하나라고 보면 되는데, 한가지 주의해야 할 것은 반드시 메뉴얼을 읽어보고 해야 한다는 것이다.

Calico 는 Kubernetes 가 운영되는 환경에 따라 설치과정에 차이가 있으며 심지여 같은 운영환경이라고 할지라도 node 의 수에 따라서 설치해줘야하는 것도 다르다.

이 메뉴얼은 OnPremise 환경이며, 50 node 이하를 가지고 있음으로 아주 간단하게 다음과 같이 yaml 파일 하나만 다운로드 받아서 적용해주면 된다.

이제 시간을 조금 기달려서 모든 pods 가 정상으로 Running 인지를 확인해 본다.

그리고 nodes 의 상태를 확인해 본다.

“Ready” 상태가 되었음으로 이제 Worker Node 를 추가해 보자.

Worker Node 추가.

Worker Node 는 knode 서버에서 다음과 같이 Kubernetes Cluster 에 join 하겠다는 것으로 실현된다. join 을 위한 파라메터는 kmaster 에서 kubeadm 으로 cluster 를 생성할때 보여준 값을 입력하면 된다.

이렇게 한 다음에 kmaster 서버에서 다음과 같이 knode 가 추가되고 상태가 Ready 된다면 Worker Node 추가가 완료된 것이다.

Helm 3 설치하기

Helm 은 Kubernetes 에서 작동하는 많은 Application 들을 손쉽게 설치하도록 도와주는 프로그램이다. 마치 Ubuntu 의 APT 나 CentOS 의 Yum 이 프로그램 설치를 손쉽게 해주는것과 같다.

한가지 변화가 있다. Helm 2 와 Helm 3 은 완전히 다르다고 생각해야 한다. Helm 2 는 Tiller 라고 해서 Helm 서버가 필요했지만 Helm 3 에서는 이것이 없어졌다.

Helm 3 는 설치 스크립트를 제공함으로 이것을 이용하면 손쉽게 설치할 수 있다. 설치 Node는 kubectl 을 사용할 수 있는 곳이라면 어디선든 사용이 가능하다.

Helm 3 설치

Helm 3 설치는 스크립트로 제공한다.

설치는 그냥 바이너리를 다운로드 받아서 /usr/bin 에 helm 바이너리를 설치하는 것으로 끝난다.

정상적으로 설치됐는지 확인은 다음과 같이 한다.

한가지 문제는 기본 repository 주소가 없어서 뭐든 설치할려면 설치가 안된다. 이를 위해서 다음과 같이 저장소를 추가해 준다.

Helm 3 은 이것으로 끝이다. 이전 Helm 2 버전에 비해 해줘야 하는 것이 없다.

Metric Server 설치

Kubernetes 를 설치하게 되면 자원에 대한 모니터링이 필요하다. 과거에는 Heapster 를 이용했지만 이것은 이제 더 이상 개발이 되지 않고 있으며 이를 대체하는 것이 Metric Server 이다.

Kubernetes 에서 뭔가를 설치하는 것은 대부분 Pods 를 설치하는 것이며 이것에 대한 Rules, Datastore 등도 한꺼번에 설정을 해준다.

Metric Server 를 설치하게 되면 Kubernetes 의 컴포넌트들에 대한 자원 모니터링이 가능해지며 이것을 이용해 Autoscaling 에도 사용이 가능해진다.

Downloads

Metric Server 를 다음과 같이 다운로드를 한다.

TLS 수정

Metric Server 를 설치할때에 주의해야 할 것은 Kube API 서버와의 통신에서 사용할 TLS 를 수정하는 것이다. Metric Server 는 Public TLS 를 기본으로 하지만 Kube API 는 Kube 자체의 TLS 를 사용하기 때문에 그냥 설치하면 문제가 된다.

Deploy

이제 이것을 Deploy 해준다. Kubernetes 에서는 설치라는게 없다. 모두 다 pods 로 다 올라가기 때문에 Deploy 라고 한다.

위와같이 관련된 설정과 pods, deploy, service 등이 생성이 된다.

확인

Metric Server 의 확인은 pods, deploy 가 제대로 되었는지를 살펴보면 된다.

그리고 1~2분을 기다리면 후에 다음과 같이 자원이 출력이 되는지를 보면 된다.

CPU, Memory 등과 같은 자원 현황이 출력이 되면 정상적으로 작동하는 것이다.

Metric Server 설치하기

Kubernetes 를 설치하게 되면 자원에 대한 모니터링이 필요하다. 과거에는 Heapster 를 이용했지만 이것은 이제 더 이상 개발이 되지 않고 있으며 이를 대체하는 것이 Metric Server 이다.

Kubernetes 에서 뭔가를 설치하는 것은 대부분 Pods 를 설치하는 것이며 이것에 대한 Rules, Datastore 등도 한꺼번에 설정을 해준다.

Metric Server 를 설치하게 되면 Kubernetes 의 컴포넌트들에 대한 자원 모니터링이 가능해지며 이것을 이용해 Autoscaling 에도 사용이 가능해진다.

Downloads

Metric Server 를 다음과 같이 다운로드를 한다.

2020.04.19 현 시점에서 v0.3.7 이 있지만 ErrorImagePull 에러가 발생하면서 설치가 진행되지 않는다. 따라서 v0.3.6 으로 설치한다.

TLS 수정

Metric Server 를 설치할때에 주의해야 할 것은 Kube API 서버와의 통신에서 사용할 TLS 를 수정하는 것이다. Metric Server 는 Public TLS 를 기본으로 하지만 Kube API 는 Kube 자체의 TLS 를 사용하기 때문에 그냥 설치하면 문제가 된다.

Deploy

이제 이것을 Deploy 해준다. Kubernetes 에서는 설치라는게 없다. 모두 다 pods 로 다 올라가기 때문에 Deploy 라고 한다.

위와같이 관련된 설정과 pods, deploy, service 등이 생성이 된다.

확인

Metric Server 의 확인은 pods, deploy 가 제대로 되었는지를 살펴보면 된다.

그리고 1~2분을 기다리면 후에 다음과 같이 자원이 출력이 되는지를 보면 된다.

CPU, Memory 등과 같은 자원 현황이 출력이 되면 정상적으로 작동하는 것이다.