카테고리 보관물: Kubernetes

The end of Kubernetes version 1.23 – Ubuntu kubernetes apt install error

2024년 3월 초, docker가 익숙해서 끝까지 버티고 있던 kubernetes v1.23.x 개발 환경 설치에 돌연 문제가 생겼다. Ubuntu에서 kubeadm, kubelet, kubectl 등을 apt로 설치할 수 없게 된 것이다. 원인과 해결 방법에 대해 알아보자.

Kubernetes apt install 에러 현상과 원인

K8s 설치 시 어떤 현상이 발생하는가?

2024년 3월 초부터 ubuntu에 apt install 명령어를 통해 kubeadm, kubelet, kubectl이 설치되지 않는다. 기존 사용하던 개발 환경은 다음과 같다.

OS: jharoian3/ubuntu-22.04-arm64
Kubernetes: 1.23.6-00
Docker: 5:24.0.6-1~ubuntu.22.04~jammy

설치를 위한 명령어는 다음과 같이 사용하고 있었다.

curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-archive-keyring.gpg
echo "deb [signed-by=/etc/apt/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 -y install kubelet="$KUBERNETES_VERSION" kubectl="$KUBERNETES_VERSION" kubeadm="$KUBERNETES_VERSION"

위 명령어를 통해 kubernetes 설치를 진행하면, 다음과 같은 에러 메시지를 확인할 수 있다.

master: deb [signed-by=/etc/apt/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main
master: Hit:1 https://download.docker.com/linux/ubuntu jammy InRelease
master: Hit:3 http://ports.ubuntu.com/ubuntu-ports jammy InRelease
master: Ign:2 https://packages.cloud.google.com/apt kubernetes-xenial InRelease
master: Hit:4 http://ports.ubuntu.com/ubuntu-ports jammy-updates InRelease
master: Err:5 https://packages.cloud.google.com/apt kubernetes-xenial Release
master:   404  Not Found [IP: 142.250.76.142 443]
master: Hit:6 http://ports.ubuntu.com/ubuntu-ports jammy-backports InRelease
master: Get:7 http://ports.ubuntu.com/ubuntu-ports jammy-security InRelease [110 kB]
master: Reading package lists...
master: E: The repository 'https://apt.kubernetes.io kubernetes-xenial Release' does not have a Release file.
master: 
master: WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
master: 
master: Reading package lists...
master: Building dependency tree...
master: Reading state information...
master: E: Unable to locate package kubelet
master: E: Unable to locate package kubectl
master: E: Unable to locate package kubeadm

원인은 package repository에 있다!

위의 에러 메시지를 살펴보면, kubernetes 관련 package 목록을 가져오기 위해 package repository에 접속을 하는데, 404 에러가 발생하고 있음을 알 수 있다. 최근까지 잘 되던 것이 갑자기 되지 않으니까 당황스럽다. 원인은 외부에 있음을 직감하고, kubernetes 공식 문서들을 샅샅이 뒤져보았다.

아니나 다를까, package repository가 대체된다는 안내사항이 있었다. 해당 글에서는 다음과 같이 안내하고 있다.

On behalf of Kubernetes SIG Release, I am very excited to introduce the Kubernetes community-owned software repositories for Debian and RPM packages: pkgs.k8s.io! The new package repositories are replacement for the Google-hosted package repositories (apt.kubernetes.io and yum.kubernetes.io) that we’ve been using since Kubernetes v1.5.

ℹ️ Update (January 12, 2024): the legacy Google-hosted repositories are going away in January 2024. Check out the deprecation announcement for more details about this change.

기존 사용하던 package repository가 2024년 1월부터 아예 사라질 것이라고 되어 있는데, 3월까지 잘 사용한 것도 기적이었던 것이다. 평소 부지런하게 follow up하지 않았던 스스로를 반성하게 된다.

Package repository 관련 문제 해결 방법

Package repository deprecation에 대응하기

안내사항에 따르면, 다음과 같이 package repository를 변경한 후 apt install을 진행하면 된다.

curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.23/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.23/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update

그런데, 이렇게 변경 후 테스트해도 여전히 다음과 같은 에러가 발생한다.

master: Reading package lists...
master: E: Failed to fetch https://pkgs.k8s.io/core:/stable:/v1.23/deb/InRelease  403  Forbidden [IP: 54.192.175.103 443]
master: E: The repository 'https://pkgs.k8s.io/core:/stable:/v1.23/deb  InRelease' is not signed.

한 걸음 나아가긴 했다. 404 Not Found 에러 대신 403 Forbidden 에러가 발생하는 것으로 보아, 적어도 새로운 package repository는 서비스를 하고 있긴 하다는 것을 확인할 수 있다. 그렇다면, 왜 이런 현상이 발생하는 것일까? 이 문제에 대한 원인도 앞서 언급한 안내 글에서 찾을 수 있었다.

The new Kubernetes package repositories contain packages beginning with those Kubernetes versions that were still under support when the community took over the package builds. This means that the new package repositories have Linux packages for all Kubernetes releases starting with v1.24.0.

새로운 package repository는 v1.24.0 이상의 kubernetes만 제공한다는 것이다. 결국, kubernetes의 버전을 올려야 한다.

Docker를 버린 kubernetes v1.24로의 여정

Kubernetes v1.23.x와 v1.24.x 사이에는 큰 차이점이 존재한다. Kubernetes v1.24.0부터는 docker를 버렸다는 것이다. 공식 문서의 내용을 간단히 요약하면 다음과 같다.

  • 1.24 버전 이전에는 docker라는 specific한 CRI를 사용하고 있었다.
  • Kubernetes에서 docker 외에도 다양한 CRI를 지원하기 위해, CRI standard라는 것을 만들었다.
  • Docker는 CRI standard를 따르지 않고 있다.
  • Kubernetes는 docker 지원을 위해 dockershim이라는 코드를 만들어서 제공했다.
  • Kubernetes 개발 참여자들이 docker라는 특수 CRI를 위해 별도로 시간을 할애하는 것이 부담스럽다.
  • Kubernetes v1.24부터 dockershim 지원 안하기로 했다.

실제로, kubernetes v1.24 버전을 설치할 때 docker를 사용하려고 하면, 다음과 같은 에러를 만날 수 있다.

master:     [WARNING SystemVerification]: missing optional cgroups: blkio
master: error execution phase preflight: [preflight] Some fatal errors occurred:
master:     [ERROR CRI]: container runtime is not running: output: time="2024-03-05T00:42:52-08:00" level=fatal msg="validate service connection: CRI v1 runtime API is not implemented for endpoint \"unix:///var/run/containerd/containerd.sock\": rpc error: code = Unimplemented desc = unknown service runtime.v1.RuntimeService"
master: , error: exit status 1
master: [preflight] If you know what you are doing, you can make a check non-fatal with `--ignore-preflight-errors=...`
master: To see the stack trace of this error execute with --v=5 or higher
master: failed to load admin kubeconfig: open /root/.kube/config: no such file or directory
master: To see the stack trace of this error execute with --v=5 or higher

눈물과 함께 kubernetes v1.23과 docker와 작별할 시간이다. 앞서 살펴본 package repository 설정 부분에서 버전을 지정해주는 문자열을 변경하자.

curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.24/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.24/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update

이후 apt-cache policy kubeadm 명령어를 통해 설치 가능한 버전을 조회해보고 apt install을 통해 설치를 진행하면 된다. 이때 주의할 점은, docker가 아니라 containerd를 사용할 것이기 때문에 설치하려는 kubernetes 버전과 호환되는 containerd 버전을 알아보고 미리 설치해두어야 한다는 것이다. Containerd와 kubernetes 버전 호환 관계는 이 문서를 확인하면 된다.

최종적으로 정상화한 개발 환경은 다음과 같다.

OS: jharoian3/ubuntu-22.04-arm64
Kubernetes: 1.24.17-1.1
Containerd: 1.7.0

간단하게 요약하면?

요약 정리

  • 현상: ubuntu에 apt install로 kubernetes를 설치할 때, package list를 불러오는 과정에서 에러 발생
  • 원인: 2024년 초부터 버려진 legacy package repository를 참조하고 있을 가능성 있음
  • 해결책: 새로운 package repository로 변경하면 됨

주의사항

  • 새로운 package repository는 kubernetes v1.24.0 이상만 제공
  • Docker를 쓰고 있었다면, containerd같은 다른 CRI로 변경 필요

[Kubernetes] Understanding how the Calico CNI works

[Kubernetes] Calico CNI 동작원리 이해하기

  • Calico란, 컨테이너, 가상 머신 및 기본 호스트 기반 워크로드를 위한 오픈 소스 네트워킹 및 네트워크 보안 솔루션이다.
  • Kubernetes, OpenShift, Mirantis Kubernetes Engine(MKE), OpenStack 및 베어메탈 서비스를 포함한 광범위한 플랫폼 지원한다.
  • Calico의 eBPF 데이터 플레인을 사용하든 Linux의 표준 네트워킹 파이프라인을 사용하든 Calico는 진정한 클라우드 네이티브 확장성과 함께 놀랍도록 빠른 성능을 제공한다.
  • Calico는 공용 클라우드나 온프레미스, 단일 노드 또는 수천 개의 노드 클러스터에서 실행되는지 여부에 관계없이 개발자와 클러스터 운영자에게 일관된 경험과 기능 세트를 제공한다.

구성 요소 아키텍처(링크)

    • BGP(Border Gateway Protocol): AS 사이에서 이용되는 라우팅 프로토콜. 대규모 네트워크(수천만의 경로 수)에 대응하도록 설계됐다. 그래서 BGP로 동작하는 라우터는 비교적 고가인 제품이 많다.
    • AS(Autonomous System): 하나의 정책을 바탕으로 관리되는 네트워크(자율 시스템)를 말한다. ISP, 엔터프라이즈 기업, 공공기관 같은 조직이 이에 해당하며 인터넷은 이러한 자율 시스템의 집합체이다.여러가지 구성 요소가 많지만, 일단 눈여겨 볼 내용은 Calico가 사용하는 Datastore[1]와 마스터 노드를 포함한 모든 노드들에 존재하는 Calico Pods[2]
      • Felix (필릭스) : 인터페이스 관리, 라우팅 정보 관리, ACL 관리, 상태 체크
      • BIRD (버드): BGP Peer 에 라우팅 정보 전파 및 수신, BGP RR(Route Reflector)
      • Confd : calico global 설정과 BGP 설정 변경 시(트리거) BIRD 에 적용해줌
      • Datastore plugin : calico 설정 정보를 저장하는 곳 – k8s API datastore(kdd) 혹은 etcd 중 선택
      • Calico IPAM plugin : 클러스터 내에서 파드에 할당할 IP 대역
      • calico-kube-controllers : calico 동작 관련 감시(watch)
      • calicoctl : calico 오브젝트를 CRUD 할 수 있다, 즉 datastore 접근 가능

구성 요소 확인하기

  • 데몬셋으로 각 노드에 calico-node 파드가 동작하여, 해당 파드에 birdfelixconfd 등이 동작 + Calico 컨트롤러 파드는 디플로이먼트로 생성
    • Calico의 특징은 BGP를 이용해 각 노드에 할당된 Pod 대역의 정보를 전달한다. 즉, 쿠버네티스 서버뿐만 아니라 물리적인 라우터와도 연동이 가능 하다는 뜻이다. (Flannel의 경우 해당 구성 불가)
    • Calico Pod 안에서 Bird라고 하는 오픈소스 라우팅 데몬 프로그램이 프로세스로 동작하여 각 Node의 Pod 정보가 전파되는 것이다.
    • 이후 Felix라는 컴포넌트가 리눅스 라우터의 라우팅 테이블 및 iptables rule에 전달 받은 정보를 주입하는 형태이다.
    • confd는 변경되는 값을 계속 반영할 수 있도록 트리거 하는 역할이다.

Calico 기본 통신 과정 확인하기

calicoctl 설치

  • 리소스 관리를 위해 Calico CLI를 설치 및 구성

마스터 노드 확인

  • Calico CNI 설치시, 데몬셋이므로 모든 노드에 칼리코 파드가 하나씩 존재하게 된다. (calico-node-*)
  • 칼리코 컨트롤러가 하나 존재하는 것을 확인할 수 있다.
  • calicoctl ipm show 명령어를 통해, IAPM 정보를 확인할 수 있다. 아래 스크린샷에서는 172.16.0.0/16 대역을 해당 쿠버네티스 클러스터에서 사용할 수 있다는 내용을 알 수 있다.

    • IPAM(IP Address Management): 풍부한 사용자 환경을 통해 IP 주소 인프라의 엔드 투 엔드 계획, 배포, 관리 및 모니터링을 지원하는 통합 도구 모음이다.
      IPAM은 네트워크상의 IP 주소 인프라 서버 및 DNS(도메인 이름 시스템) 서버를 자동으로 검색하여 중앙 인터페이스에서 이들 서버를 관리할 수 있다.
    • 옵션을 통해 아래와 같이 특정한 노드에 할당 가능한 대역대를 확인할 수도 있음(Block는 각 노드에 할당된 Pod CIDR 정보를 나타냄)
  • calicoctl node 정보 확인
  • ippool 정보 확인
  • 파드와 서비스 사용 네트워크 대역 정보 확인

실습 1.

동일 노드 내 파드 간 통신

  • 결론: 동일 노드 내의 파드 간 통신은 내부에서 직접 통신됨

파드 생성 전 노드(k8s-w1)의 기본 상태

노드(k8s-w1)에 파드 2개 생성

  • 아래 내용으로 node1-pod2.yaml 파일 작성 후 파드 생성
  • 파드 생성 전후의 변화를 관찰하기 위해 터미널 하단 추가 탭에watch calicoctl get workloadEndpoint 명령어를 사용하여 모니터링
    • calicoctl 명령어로 endpoint 확인: veth 정보도 확인할 수 있음

생성된 파드 정보 확인

네트워크 인터페이스 정보 확인(k8s-w1)

  • calice#~ 두개 추가된 것을 확인할 수 있음
  • 각각 net ns 0,1로 호스트와 구별되는 것을 확인할 수 있음

네트워크 네임스페이스 확인

  • 아래 2개 PAUSE 컨테이너가 각각 파드별로 생성된 것을 확인할 수 있음
  • 바로 위 스크린샷인 link-netnsid 0, link-netnsid 1과 매칭됨

라우팅 테이블 확인

  • 파드의 IP/32bit 호스트 라우팅 대역이 라우팅 테이블에 추가된 것을 확인할 수 있음

파드간 통신 실행 이해

  • (위) 마스터 노드에서 Pod1 Shell에 접근하여 Pod2로 Ping 테스트
  • (아래) 워커 노드(k8s-w1)에서 iptables 필터 테이블에 FORWARD 리스트 중 cali-FORWARD 룰 정보를 필터링해서 watch로 확인
  • 테스트 결과 아래 이미지와 같이 Host iptables에서 FOWRARD라는 테이블의 허용 조건에 따라 정상적으로 통신이 가능한 것을 확인할 수 있다.

파드에서 외부(인터넷)로의 통신

  • 결론: 파드에서 외부(인터넷) 통신 시에는 해당 노드의 네트워크 인터페이스 IP 주소로 MASQUERADE(출발지 IP가 변경) 되어서 외부에 연결됨

파드 배포 전 calico 설정 정보 확인 & 노드에 iptables 확인

  • 마스터 노드에서 아래 내용 확인: natOutgoing의 기본값이 true로 설정되어 있는 것을 확인 할 수 있다. 즉 이 노드에서 외부로 통신할 때 NAT의 MASQUERADE를 사용하겠다는 의미이다.

    NAT – MASQUERADE : 조건에 일치하는 패킷의 출발지 주소를 변환하는 것. 내부에서 전달되는 요청의 출발지 주소를 조건에 지정된 인터페이스의 IP로 변환한다.

  • 워커 노드(k8s-w1)에서도 외부로 통신시 MASQUERADE 동작 Rule이 존재하는 것을 확인할 수 있다.

마스터 노드에서 워커 노드(k8s-w1)에 아래 내용의 파드 1개 생성

외부 통신 가능 여부 확인

  • 통신 전, 워커 노드(k8s-w1)에 iptables NAT MASQUERADE 모니터링을 활성화 하면 외부 통신시 pkts값이 증가하는지 확인할 수 있다.
  • (위) 마스터 노드에서 Pod1 Shell 실행 후, 8.8.8.8로의 통신 성공
  • (아래) pkts 값이 이전 이미지와 다르게 증가한 것을 확인할 수 있다.

다른 노드에서 파드 간 통신

  • 결론: 다른 노드 환경에서 파드 간 통신시에는 IPIP터널(기본값) 모드를 통해서 이루어진다.
    • 각 노드에 파드 네트워크 대역은 Bird에 의해서 BGP로 광고 전파/전달 되며, Felix에 의해서 호스트의 라우팅 테이블에 자동으로 추가/삭제 된다.
    • 다른 노드 간의 파드 통신은 tunl0 인터페이스를 통해 IP 헤더에 감싸져서 상대측 노드로 도달 후 tunl0 인터페이스에서 Outer 헤더를 제거하고 내부 파드와 통신한다.

파드 배포 전, 노드에서 BGP에 의해 전달 받은 정보가 호스트 라우팅 테이블에 존재하는지 확인

  • 아래 명령어를 통해 나머지 노드들의 파드 대역을 자신의 호스트 라우팅 테이블에 가지고 있고, 해당 경로는 tunl0 인터페이스로 보내게 된다는 사실을 알 수 있다.

워커 노드(k8s-w1, w2)의 tunl0 정보 확인

  • 터널 인터페이스가 IP에 할당되어 있음
  • MTU는 1480 (칼리코 사용 시 파드의 인터페이스도 기본 MTU 1480 사용)
  • 현재 TX/RX 카운트는 0 –> 잠시 후, 오버레이 통신시 카운트 값이 증가할 것

마스터 노드에서 워커 노드(k8s-w1, w2) 대상으로 각각 파드 1개씩 생성

  • calicoctl 명령어를 이용하여 생성된 파드의 엔드포인트 확인

각 노드에서 파드 간 통신을 처리하는 라우팅 정보 확인

  • k8s-w1(172.16.158.4/32) 노드에서 w2(172.16.184.0) 노드 대역에 통신하려면 192.168.10.102를 거쳐야 한다는 것을 확인할 수 있다.
  • 반대로 w2(172.16.184.1/32) 노드에서 w1(172.16.158.0) 노드 대역에 통신하려면 192.168.10.101를 거쳐야 한다.

다른 노드 파드 간 통신이 어떻게 실행되는지 확인 ⇒ IPIP

  • (상) Pod2가 속한 노드(k8s-w2)에 tunl0 인터페이스 TX/RX 패킷 카운트 모니터링 세팅
  • (중) 마스터 노드에서 Pod1 Shell 접속 후, Pod2로 Ping 통신 테스트 준비
  • (하) Pod1이 속한 노드(k8s-w1)에서 패킷 덤프 세팅: tunl0 – 터널 인터페이스에 파드간 IP 패킷 정보를 확인할 수 있음
  • 결과
    • (중) Pod1 –> Pod2로 정상 통신 확인
    • (상) tunl0 인터페이스의 TX/RX 패킷 카운트가 각각 10개로 증가
    • (하) 실제 통신을 하게 되는 파드 간 IP 패킷 정보 확인
  • 실제로 오버레이 통신을 하고 있는지 확인하기 위해 패킷덤프 명령어를 아래와 같이 수정하여 Ping 통신을 다시 하였고, 결과적으로 IP Outer(파란색 박스) 헤더 정보 안쪽에 Inner(빨간색 박스) 헤더가 1개 더 있음을 확인할 수 있다.

Calico 네트워크 모드

Calico Mode 요약

  • 칼리코는 다양한 네트워크 통신 방법을 제공한다.

IPIP 모드

  • 파드 간 통신이 노드와 노드 구간에서는 IPIP 인캡슐레이션을 통해 이루어진다.
  • 단, Azure 네트워크에서는 IPIP 통신이 불가능하기 때문에 대신 VXLAN 모드를 사용한다고 한다.

Direct 모드

  • 파드 통신 패킷이 출발지 노드의 라우팅 정보를 보고 목적지 노드로 원본 패킷 그대로 전달된다.
  • 단, 클라우드 사업자 네트워크 사용 시, NIC에 매칭되지 않는 IP 패킷은 차단되니 NIC의 Source/Destination Check 기능을 Disable해야 정상 통신 가능 (AWS 문서 링크)

BGP 연동

  • Kubernetes 클러스터 내부 네트워크와 IDC 내부망 네트워크 간 직접 라우팅도 가능

VXLAN 모드

  • 파드 간 통신이 노드와 노드 구간에서는 VXLAN 인캡슐레이션을 통해서 이루어진다.
  • 다른 노드 간의 파드 통신은 vxlan 인터페이스를 통해 L2 프레임이 UDP – VXLAN에 감싸져 상대 노드로 도달 후 vxlan 인터페이스에서 Outer헤더를 제거하고 내부의 파드와 통신하게 된다.
  • BGP 미사용, VXLAN L3 라우팅을 통해서 동작한다.
  • UDP를 사용하므로 Azure 네트워크에서도 사용 가능하다.

Pod 패킷 암호화(네트워크 레벨)

  • Calico의 다양한 네트워크 모드 환경 위에서 WireGuard 터널을 자동 생성 및 파드 트래픽을 암호화하여 노드 간 전달한다.
  • Yaml 파일에 간단하게 추가하는 것만으로도 네트워크 레벨의 패킷 암호화를 설정할 수 있다.
  • WireGuard는 구닥다리 IPsec 및 OpenVPN의 대항마로 등장한 open source VPN project이며 작년, Linux 5.6 커널에 WireGuard 1.0.0 기본 패키지로 탑재되었다.
  • 정말 간결한 코드 구조와 빠른 성능 (모든 것이 kernel에서 동작하고, 주요 암호 알고리즘에 대해서 병렬처리하므로써 빠른 속도를 자랑함)

실습 2. WireGuard

WireGuard 설정

  • 모든 노드에 WireGuard를 설치(apt install wireguard -y)하고, Enabled 설정
  • 현재 노드에 존재하는 Wireguard 퍼블릭 키 확인
  • wireguard.cali 인터페이스 정보 확인
  • wg로 시작하는 명령어를 사용하여 wireguard.cali 설정 확인: 노드 별로 각각의 상대방 Peer의 IP와 퍼블릭 키를 확인할 수 있음

동작 확인

  • 아래 내용으로 파드 생성
  • (상) 파드가 생성된 노드의 eth0(enp0s8)에서 패킷 덤프 모니터링 세팅
  • (하) 생성한 파드 Shell 접속 후 Ping 통신 준비
  • (하) Pod2 IP 확인
  • (중) Pod1 –> Pod2 Ping 정상 통신
  • (상) 51820 포트 패킷 덤프 내용 확인

3-Tier container environment configuration using Kubernetes (NginX/Tomcat/MySQL)

쿠버네티스를 활용한 3-Tier 컨테이너 환경 구성을 해보고자 한다. 구성은 도커와 동일하게 아래와 같이 간다.

3-Tier container environment configuration using Docker(NginX/Tomcat/MySQL)

이번에는 구성 시에 1-Container에 WEB/WAS/DB Pod를 각각 띄울 예정이다.

동일한 컨테이너에서 기동하기 때문에 서로에 대한 IP는 변하지 않을 것이고 IP Address는 localhost로 설정해주어야 한다.

그렇기 때문에!!

– WEB-WAS 사이의 연동 설정에서 IP를 localhost로 변경

– WAS-DB 사이의 연동 설정(어플리케이션 부분)에서 DB IP를 localhost로 변경

해주어야한다.. 그렇다면 이미지 부터 다시 말아보자.

1. WEB 구성

1-1. NginX의 WAS 연동 설정 파일에서 IP Address를 localhost로 변경 후 다시 이미지 생성

> $ vi /root/nginx-for-petclinic/nginx/conf

17 http {
18     upstream was-list {
19         #server tomcat-petclinic:8080;
20         server localhost:8080;
21     }
22
23     include       mime.types;
24     default_type  application/octet-stream;

1-2. Dockerfile을 이용하여 이미지 생성

root@master:~/nginx-for-petclinic# pwd
/root/nginx-for-petclinic
root@master:~/nginx-for-petclinic# docker build -t nginx-petclinic:2.0 .

# 이미지 생성 후, 확인

root@master:~/nginx-for-petclinic# docker images
REPOSITORY                               TAG       IMAGE ID       CREATED         SIZE
nginx-petclinic                          2.0       1f34b3ccac6d   5 seconds ago   133MB

1-3. 이미지를 Dockerhub에 저장

> 내가 생성한 이미지를 이따 yaml파일에서 로드할  수 있도록..

root@master:~# docker tag nginx-petclinic:2.0 ghkd5216/nginx-petclinic:2.0
root@master:~# docker push ghkd5216/nginx-petclinic:2.0

The push refers to repository [docker.io/ghkd5216/nginx-petclinic]
52efdeec58ec: Pushed
201e7ba1790a: Pushed
9959a332cf6e: Layer already exists
f7e00b807643: Layer already exists
f8e880dfc4ef: Layer already exists
788e89a4d186: Layer already exists
43f4e41372e4: Layer already exists
e81bff2725db: Layer already exists
2.0: digest: sha256:15cf195c6e6575d744fa0eb07b429d0db3d99f61

2. WAS 구성

2-1. WAS에서는 AP쪽에 DB 설정이 있기 때문에 소스 빌드 및 해당 소스가 디플로이된 이미지를 다시 생성해야 한다.

> $vi /root/spring-framework-for-petclinic/pom.xml

> 515번 라인과 같이 localhost로 변경해주면 된다.

509             <id>MySQL</id>
510             <properties>
511                 <db.script>mysql</db.script>
512                 <jpa.database>MYSQL</jpa.database>
513                 <jdbc.driverClassName>com.mysql.jdbc.Driver</jdbc.driverClassName>
514                 <!–<jdbc.url>jdbc:mysql://mysql-petclinic:3306/petclinic?useUnicode=true</jdbc.url>–>
515                 <jdbc.url>jdbc:mysql://localhost:3306/petclinic?useUnicode=true</jdbc.url>
516                 <jdbc.username>root</jdbc.username>
517                 <jdbc.password>petclinic</jdbc.password>
518             </properties>

2-2. 소스 빌드를 위한 자바 변경

> 자바 버전이 1.8이 되도록 수정

root@master:~/spring-framework-for-petclinic# sudo update-java-alternatives –jre-headless –jre –set java-1.8.0-openjdk-amd64

root@master:~/spring-framework-for-petclinic# java -version
openjdk version “1.8.0_292”
OpenJDK Runtime Environment (build 1.8.0_292-8u292-b10-0ubuntu1~20.04-b10)
OpenJDK 64-Bit Server VM (build 25.292-b10, mixed mode)

2-3. 소스 빌드

> 소스를 빌드하고 나면, 현 디렉토리에 target 안에 petclinic.war라는 소스 파일이 빌드되어 있을 것이다.

root@master:~/spring-framework-for-petclinic# mvn clean package -Dmaven.test.skip=true -P MySQL

…(중략)

[INFO] ————————————————————————
[INFO] BUILD SUCCESS
[INFO] ————————————————————————
[INFO] Total time:  13.144 s
[INFO] Finished at: 2021-11-16T18:04:01+09:00
[INFO] ————————————————————————

2-4. WAS 이미지 생성

> 이제 만든 소스를 활용하여 tomcat 이미지를 만들어보도록 하자.

우선 이미지 생성을 위해 Dockerfile을 생성하고 위에서 만들었던 petclinic.war 파일을 Dockerfile 디렉토리에 위치시킨다.

root@master:/home/dockerfile/petclinic# pwd
/home/dockerfile/petclinic
root@master:/home/dockerfile/petclinic# ls -arlt
total 40644
drwxr-xr-x 5 root root     4096 11월  7 14:06 ..
-rw-r–r– 1 root root 41605349 11월  7 14:06 petclinic.war
-rw-r–r– 1 root root       64 11월  7 14:06 Dockerfile
drwxr-xr-x 2 root root     4096 11월  7 14:06 .

==================================================
하기는 Dockerfile 내용이다.
==================================================
root@master:/home/dockerfile/petclinic# cat Dockerfile
From tomcat:8-jre8
ADD petclinic.war /usr/local/tomcat/webapps/

위와 같이 준비가 되었다면 이제 해당 위치에서 이미지 빌드를 하면 된다.

커맨드는 아래와 같다.

root@master:/home/dockerfile/petclinic# docker build -t tomcat-petclinic:2.0 .
Sending build context to Docker daemon  41.61MB
Step 1/2 : From tomcat:8-jre8
—> cff25871f024
Step 2/2 : ADD petclinic.war /usr/local/tomcat/webapps/
—> 1c6d007012d5
Successfully built 1c6d007012d5
Successfully tagged tomcat-petclinic:2.0

2-5. 이미지를 Dockerhub에 저장

> 내가 생성한 이미지를 이따 yaml파일에서 로드할  수 있도록..

root@master:~# docker tag tomcat-petclinic:2.0 ghkd5216/tomcat-petclinic:2.0
root@master:~# docker push ghkd5216/tomcat-petclinic:2.0
The push refers to repository [docker.io/ghkd5216/tomcat-petclinic]
3fe16f1fe077: Pushed
7a1149e8d0d8: Layer already exists
f3d15ade5c54: Layer already exists
80ac7083a323: Layer already exists
01de28a83f3f: Layer already exists
74a293db1084: Layer already exists
68c1e7509c65: Layer already exists
6ccd0e6bdf7a: Layer already exists
9f9f651e9303: Layer already exists
0b3c02b5d746: Layer already exists
62a747bf1719: Layer already exists
2.0: digest: sha256:7ee8909691df00b211aa42f1605062019422b0d93d52053d4ad01034390e04a7 size: 2631

3. YAML 파일 생성

이제 이미지도 준비되었고, yaml 파일만 생성하여 기동해보면 된다.
도커와는 다르게 쿠버네티스의 경우에는 쿠버네티스 클러스터 내에서 동작하기 때문에 생성된 컨테이너의 IP 또한 클러스터 내의 CNI 네트워크 대역으로 할당된다.

그렇기 때문에 외부에서 해당 컨테이너에 접근하여 서비스를 호출하려면 Service를 통해 가능하다. AWS나 GCP같은 Public Cloud의 경우에는 Service에서 LoadBalnancer를 제공하여 외부로 노출할 IP를 할당 받지만, 우리가 테스트하는 방식과 같이 Baremetal(On-Premise) 환경에서는 LoadBalancer 기능이 없다. 그래서 LoadBalancer타입을 지원하게끔 하기 위해 MetalLB라는 놈을 사용해주어야 한다.

먼저 metalb을 설치해보면 아래와 같다.

root@master:~/yaml# kubectl apply -f  https://raw.githubusercontent.com/google/metallb/v0.8.3/manifests/metallb.yaml

=================================
metallb.yaml 파일을 이용하여 파드와 기타 등등의 서비스를 실행한다.
이후, metallb-system 네임스페이스에 있는 리소스들을 조회해본다.
=================================

root@master:~/yaml# kc get all -n metallb-system

NAME                              READY   STATUS    RESTARTS   AGE
pod/controller-675d6c9976-d5k57   1/1     Running   0          9s
pod/speaker-h4l8n                 1/1     Running   0          9s
pod/speaker-rm54l                 1/1     Running   0          9s

NAME                     DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR                 AGE
daemonset.apps/speaker   2         2         2       2            2           beta.kubernetes.io/os=linux   9s

NAME                         READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/controller   1/1     1            1           9s

NAME                                    DESIRED   CURRENT   READY   AGE
replicaset.apps/controller-675d6c9976   1         1         1       9s

이제 3-Tier환경의 컨테이너를 생성할 차례다.

yaml 파일의 경우 아래와 같다.

모든 항목들을 세세히 설명할 수는 없고 하나씩 찾아보면 기본적인 설정(포트/환경변수)만 되어있음을 볼 수 있다.

이 글에서는 가볍게 구성해보는 것이기 때문에 다음 글에서 좀 더 yaml 문법이나 파라미터 값을 공부해보아야 겠다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: petclinic-deployment
  namespace: default
  labels:
    app: petclinic-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
       app: petclinic-app
  template:
    metadata:
      labels:
        app: petclinic-app
    spec:
      containers:
      - image: mysql:5.7.8
        imagePullPolicy: Always
        name: mysql-petclinic
        ports:
        - containerPort: 3306
          protocol: TCP
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: petclinic
        - name: MYSQL_DATABASE
          value: petclinic
      - image: docker.io/ghkd5216/nginx-petclinic:2.0
        imagePullPolicy: Always
        name: nginx-petclinic
        ports:
        - containerPort: 80
          protocol: TCP
      - image: docker.io/ghkd5216/tomcat-petclinic:2.0
        imagePullPolicy: Always
        name: tomcat-petclinic
        env:
        - name: JAVA_OPTS
          value: "-Xms512m -Xmx512m"
        ports:
        - containerPort: 8080
          protocol: TCP
      restartPolicy: Always

---

apiVersion: v1
kind: Service
metadata:
  name: petclinic-svc
spec:
  type: LoadBalancer
  selector:
    app: petclinic-app
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80


---

apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - 192.168.1.240-192.168.1.250

> 제일 하단에 metallb 관련 설정을 보면 addresses 범위 안에서 외부로 노출할 ExternalIP 대역을 설정할 수 있다.

이제 만든 yaml 파일을 실행하여 보자!!

4. Kubernetes를 통한 컨테이너 배포

root@master:~/yaml# kc apply -f petclinic-app.yaml
deployment.apps/petclinic-deployment created
service/petclinic-svc created
configmap/config created

root@master:~/yaml# kc get all
NAME                                        READY   STATUS    RESTARTS   AGE
pod/petclinic-deployment-86dc87794d-j69mm   3/3     Running   0          24s

NAME                    TYPE           CLUSTER-IP       EXTERNAL-IP      PORT(S)        AGE
service/kubernetes      ClusterIP      10.96.0.1        <none>           443/TCP        13d
service/petclinic-svc   LoadBalancer   10.109.251.153   192.168.56.240   80:30560/TCP   24s

NAME                                   READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/petclinic-deployment   1/1     1            1           24s

NAME                                              DESIRED   CURRENT   READY   AGE
replicaset.apps/petclinic-deployment-86dc87794d   1         1         1       24s

> 위와 같이 LoadBalancer 타입의 Service가 생성되어 External-IP를 할당하여 외부로 노출하는 것을 볼 수 있다.

이제 모든 준비가 끝났다.

실제로 외부의 웹 브라우저에서 클라이언트 입장으로 서비스를 호출해보자. 호출 url은 EXTERNAL_IP:[LB PORT]/petclinic 이다.

나의 경우에는 http://192.168.56.240:80/petclinic/으로 호출하면 된다.

5. 서비스 호출

 

 

> 외부 노출 IP로 정상적으로 접근 가능하다. 몇 가지 업무 테스트를 해보면,

 

 

정상적으로 데이터가 DB에 저장되는 것을 볼 수 있다.

Kubernetes Monitoring : HPA (Horizontal Pod Autoscaler)

Overview

쿠버네티스 클러스터에서 hpa를 적용해 시스템 부하상태에 따라 pod을 autoScaling시키는 실습을 진행하겠습니다.

참고 링크 : Kubernetes.io/Horizontal Pod Autoscaler

Prerequisites

먼저 쿠버네티스 클러스터를 생성해주세요.

참고링크 : 호롤리한하루/Install Kubernetes on CentOS/RHEL

본 실습에서 사용한 spec :
OS : CentOS v7.6
Arch : x86

Kubernetes : v1.16.2
Master : 4cpu, ram16G (1개)
Node : 4cpu, ram16G (2개)

Step

그림1

1. Metrics-Server 배포

먼저 top명령어를 입력해봅시다.

$ kubectl top node

Error from server (NotFound): the server could not find the requested resource (get services http:heapster:)

현재는 에러메세지가 뜹니다.
이유는 노드의 system metric들을 수집하는 서비스가 없기 때문입니다.

system metric을 수집하는 Metrics-Server를 배포해주도록 합시다.

$ git clone https://github.com/kubernetes-sigs/metrics-server.git
$ cd metrics-server

쿠버네티스에서 공식으로 서포트하고있는 add-on 컴포넌트인 metrics-server를 클론받고, 배포하기 이전에 yaml파일을 수정해주어야합니다.
클러스터 내에서 사용하는 인증서가 신뢰되지 않은 경우와 호스트 이름을 찾지 못하는 경우를 방지하기 위함입니다

$ vim deploy/kubernetes/metrics-server-deployment.yaml

image
위 그림과 같이 argument들을 수정해줍니다.

args:
  - --kubelet-insecure-tls
  - --kubelet-preferred-address-types=InternalIP
  - --cert-dir=/tmp
  - --secure-port=4443

그리고 나서 metrics-server를 배포하면 :

$ kubectl apply -f deploy/kubernetes/

clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created
clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created
rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created
apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created
serviceaccount/metrics-server created
deployment.apps/metrics-server created
service/metrics-server created
clusterrole.rbac.authorization.k8s.io/system:metrics-server created
clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created

중간에 metrics.k8s.io라는 API가 생성되어 Api server에 등록된 것을 확인할 수 있습니다.

이제 top명령어를 사용할 수 있게 됩니다.

$ kubectl top nodes

NAME       CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
kube-m     248m         6%     1656Mi          10%
kube-n01   112m         2%     760Mi           4%
kube-n02   112m         2%     724Mi           4%

각 노드의 cpu와 memory사용량을 확인할 수 있습니다.

2. 부하테스트를 위한 이미지 작성

이제 시스템의 부하테스트를 위한 이미지를 작성해보겠습니다.

$ mkdir php
cd php

스크립트 작성 :

$ vim index.php

<?php
  $x = 0.0001;
  for ($i = 0; $i <= 1000000; $i++) {
    $x += sqrt($x);
  }
  echo "OK!";
?>

스크립트를 포함하는 도커 이미지 작성 :

$ vim Dockerfile

FROM php:5-apache
ADD index.php /var/www/html/index.php
RUN chmod a+rx index.php

도커 이미지 빌드 :

$ docker build --tag {docker id : totoli78}/php-apache .

$ docker images |grep php

totoli78/php-apache                    latest              39e1797ad29c        23 seconds ago      355MB

생성한 이미지를 본인의 docker hub에 push해줍니다.

$ docker login
...
Login Succeeded

$ docker push totoli78/php-apache

부하테스트를 위해 쿠버네티스 클러스터에 pod으로 배포해줍니다.

$ vim hpa-test.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: php-apache
spec:
  selector:
    matchLabels:
      run: php-apache
  replicas: 1
  template:
    metadata:
      labels:
        run: php-apache
    spec:
      containers:
      - name: php-apache
        image: totoli78/php-apache
        ports:
        - containerPort: 80
        resources:
          limits:
            cpu: 500m
          requests:
            cpu: 200m
---
apiVersion: v1
kind: Service
metadata:
  name: php-apache
  labels:
    run: php-apache
spec:
  ports:
  - port: 80
  selector:
    run: php-apache

yaml을 작성한 뒤에는 배포!

$ kubectl apply -f hpa-test.yaml

deployment.apps/php-apache created
service/php-apache created

3. HPA 배포

이제 오토스케일러를 생성해주면 됩니다.

$ vim autoscaler.yaml

위에서 만든 부하테스트용 pod인 php-apache의 평균 cpu사용량을 50%로 맞추기 위해 레플리카의 개수를 늘리고 줄입니다. (1개~10개)

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache
  minReplicas: 1
  maxReplicas: 10
  targetCPUUtilizationPercentage: 50
$ kubectl apply -f autoscaler.yaml
horizontalpodautoscaler.autoscaling/php-apache created

hpa커맨드를 통해 현재 hpa에 감지되는 시스템 부하정도와 관리하는 pod의 개수를 확인할 수 있습니다.

$ kubectl get hpa
NAME         REFERENCE               TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache   0%/50%    1         10        1          18s

아직은 서버로 어떠한 요청도 하지 않았기 때문에, 현재 cpu소비량은 0%임을 알 수 있습니다. (TARGET은 deployment에 의해 제어되는 pod들의 평균을 뜻합니다.)

부하테스트

부하가 증가함에 따라 오토스케일러가 어떻게 반응하는지 살펴보겠습니다.

창을 하나 더 띄워서 php-apache 서비스에 무한루프 쿼리를 전송합니다.

$ kubectl run -it --rm load-generator --image=busybox /bin/sh

If you don't see a command prompt, try pressing enter.
/ #
/ # while true; do wget -q -O- http://php-apache.default.svc.cluster.local; done
OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!...

1~2분 지난 뒤에 hpa커맨드로 부하상태를 살펴보면 TARGET의 수치가 높아진 것을 확인할 수 있습니다.

$ kubectl get hpa

NAME         REFERENCE               TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache   248%/50%   1         10        1          9m7s

그리고 deployment 컨트롤러를 확인해보면 pod의 replica수가 5개까지 늘어난 것을 확인할 수 있습니다.

$ kubectl get deploy php-apache

NAME         READY   UP-TO-DATE   AVAILABLE   AGE
php-apache   5/5     5            5           12m

busybox컨테이너를 띄운 터미널에서 Ctrl+C로 부하 발생을 중단시키고, 몇 분 후에 결과를 확인합니다.

$ kubectl get hpa

NAME         REFERENCE               TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache   0%/50%    1         10        5          11m

cpu의 사용량이 0%까지 떨어졌고, deployment의 pod replica수도 1개로 줄어든 것을 확인할 수 있습니다.

$ kubectl get deploy php-apache

NAME         READY   UP-TO-DATE   AVAILABLE   AGE
php-apache   1/1     1            1           19m

replica autoscaling은 몇 분 정도 소요됩니다. (체감상 3~5분)

Installing Helm on Ubuntu for Kubernetes

Ubuntu에 Helm을 설치하려면:

1. 다음 명령을 사용하여 최신 버전의 Helm을 다운로드합니다.

wget https://get.helm.sh/helm-v3.4.1-linux-amd64.tar.gz

다운로드가 완료되면 단말기에서 확인 메시지를 출력합니다.

터미널에서 Helm을 다운로드합니다.

2. 다음으로 Linux tar 명령 을 사용하여 Helm 파일의 압축을 풉니다 .

tar xvf helm-v3.4.1-linux-amd64.tar.gz

출력에는 압축이 풀린 4개의 파일이 표시됩니다.

3. linux-amd64/helm파일을 /usr/local/bin디렉터리로 이동합니다.

sudo mv linux-amd64/helm /usr/local/bin

명령이 올바르게 실행된 경우 출력이 없습니다.

투구 풀기.

4. 다음 명령을 사용하여 다운로드한 파일을 제거합니다.

rm helm-v3.4.1-linux-amd64.tar.gz

5. linux-amd64다음을 실행하여 공간을 정리할 디렉터리를 제거합니다.

rm -rf linux-amd64

프로세스가 성공적으로 완료되면 출력이 없습니다.

필요하지 않은 파일을 제거합니다.

6. 마지막으로 소프트웨어 버전을 확인하여 Helm을 성공적으로 설치했는지 확인합니다.

helm version

터미널은 소프트웨어의 버전 번호와 GitCommit, GitTreeState 및 GoVersion의 릴리스 번호를 인쇄합니다.

Helm 설치 완료를 확인합니다.

 

수동으로 최신 버젼의 chart 정보를 레파지토리에 갱신 할 수 있습니다.

$ helm repo add stable https://charts.helm.sh/stable
$ helm repo update  

[kubernetes] kubeadm 사용 고 가용성(HA) 클러스터 설정

kubernetes에서 HA를 구성하는 방법으로 stacked etcd, external etcd 두가지 방법이 있다. 그림 1의 stacked etcd는 control plane node에서 etcd가  작동하는 반면, 그림 2의 external etcd는 control plane node와 etcd가 다른 노드에서 작동한다. HA를 구성하기 위해서는 쿼럼이 과반수를 초과해야만 하기 때문에 최소 3대 이상(3,5,7,…)의 노드를 필요로 한다. 이번 시간에는 stacked etcd 를 구성하는 방법에 대해 알아보고자 한다.

 

[그림 1] HA 토폴로지 – stacked etcd
[그림 1] HA 토폴로지 – external etcd

 

구성환경

Ubuntu 18.04.1, Docker 19.03.8, Kubernet v1.17.4

사전 준비

Docker, Kubernet이 미리 설치 되어 있어야한다.

로드 발란서(Load Balancer)

– dns 로드 발란서 사용, apisvr 라운드로빈(round-robin) 활용, 참고로 도메인은 hoya.com

apisvr    IN      A       192.168.0.160
IN      A       192.168.0.161
IN      A       192.168.0.162

 

첫번째 Control plane node

1. Control plane 초기화

shell> sudo kubeadm init –control-plane-endpoint apisvr.hoya.com:6443 –upload-certs

** apisvr.hoya.com:6443 은 자기 환경에 맞게 설정한다.

–upload-certs : control plane 인스턴스에서 공유해야 하는 인증서를 업로드(자동배포), 수동으로 인증서를 복사할 경우는 이 옵션 생략

control plane 초기화(kubeadm init)를 진행하면 아래와 같은 내용이 출력될 것이다. 아래 내용을 복사해 놓도록 한다. 이 명령어를 이용하여 클러스터에 조인(join) 할수 있다. 파란색글씨(위쪽)는 control plane 노드에서 실행, 주황색 글씨(아래)는 worker node에서 실행

You can now join any number of control-plane node by running the following command on each as a root:
kubeadm join apisvr.hoya.com:6443 –token 9vr73a.a8uxyaju799qwdjv –discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866 –control-plane –certificate-key f8902e114ef118304e561c3ecd4d0b543adc226b7a07f675f56564185ffe0c07Please note that the certificate-key gives access to cluster sensitive data, keep it secret!
As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use kubeadm init phase upload-certs to reload certs afterward.

Then you can join any number of worker nodes by running the following on each as root:
kubeadm join apisvr.hoya.com:6443 –token 9vr73a.a8uxyaju799qwdjv –discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866

참고: certificate-key를 지정하여 나중에 조인에서 사용할 수 있습니다.

shell> sudo kubeadm alpha certs certificate-key
f8902e114ef118304e561c3ecd4d0b543adc226b7a07f675f56564185ffe0c07

참고: worker node에서 토큰을 사용하여 클러스터에 가입하는 데 필요한 전체 ‘kubeadm join’ 플래그를 출력

shell> sudo kubeadm token create –print-join-command

참고: 인증서를 다시 업로드하고 새 암호 해독 키를 생성하려면 이미 클러스터에 연결된 control plane 노드에서 다음 명령을 사용하십시오.

shell> sudo kubeadm init phase upload-certs –upload-certs
W0322 16:20:40.631234  101997 validation.go:28] Cannot validate kube-proxy config – no validator is available
W0322 16:20:40.631413  101997 validation.go:28] Cannot validate kubelet config – no validator is available
[upload-certs] Storing the certificates in Secret “kubeadm-certs” in the “kube-system” Namespace
[upload-certs] Using certificate key:
7f97aaa65bfec1f039c4dbdf3a2073de853c708bd4d9ff9d72b776b0f9874c9d

참고 :  클러스터를 control plane 조인(join)하는 데 필요한 전체 ‘kubeadm join’ 플래그를 출력

shell> sudo kubeadm token create –print-join-command –certificate-key \  7f97aaa65bfec1f039c4dbdf3a2073de853c708bd4d9ff9d72b776b0f9874c9d

2. CNI(Container Network Interface) 플러그인 설치

– 여기서는 weave CNI 플러그인 설치(그외 flannel, Calico, ….)

shell> kubectl apply -f “https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d ‘\n’)”

 

나머지 Control plane 노드

1. 첫번째 Control plane 노드에서 kubeadm init 결과(파란색 글씨)를 실행한다.

shell> kubeadm join apisvr.hoya.com:6443 –token 9vr73a.a8uxyaju799qwdjv –discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866 –control-plane –certificate-key f8902e114ef118304e561c3ecd4d0b543adc226b7a07f675f56564185ffe0c07

2. 확인

– 노드 상태가 Ready인지 확인

shell> kubectl get nodes
NAME        STATUS   ROLES    AGE     VERSION
master1    Ready    master   41s     v1.17.4
master2    Ready    master   3m59s   v1.17.4
master3    Ready    master   92s     v1.17.4
shell>

– pods의 상태(Status)가 모두 Running 상태인지 확인

shell> kubectl get pods –all-namespaces
NAMESPACE     NAME                                READY   STATUS    RESTARTS   AGE
kube-system   coredns-6955765f44-7jk6m            1/1     Running   0          3m42s
kube-system   coredns-6955765f44-vgw2j            1/1     Running   0          3m42s
kube-system   etcd-master3                       1/1     Running   0          31s
kube-system   etcd-master1                       1/1     Running   0          3m44s
kube-system   etcd-master2                      1/1     Running   0          83s
kube-system   kube-apiserver-master3             1/1     Running   0          33s
kube-system   kube-apiserver-master1             1/1     Running   0          3m44s
kube-system   kube-apiserver-master2            1/1     Running   0          84s
kube-system   kube-controller-manager-master3    1/1     Running   0          33s
kube-system   kube-controller-manager-master1    1/1     Running   1          3m44s
kube-system   kube-controller-manager-master2   1/1     Running   0          84s
kube-system   kube-proxy-hd8vq                    1/1     Running   0          84s
kube-system   kube-proxy-v9s8h                    1/1     Running   0          3m42s
kube-system   kube-proxy-z76td                    1/1     Running   0          33s
kube-system   kube-scheduler-master3             1/1     Running   0          33s
kube-system   kube-scheduler-master1             1/1     Running   1          3m44s
kube-system   kube-scheduler-master2            1/1     Running   0          84s
kube-system   weave-net-6dkt6                     2/2     Running   3          84s
kube-system   weave-net-9zswx                     2/2     Running   0          3m3s
kube-system   weave-net-fvf9q                     2/2     Running   0          33s

woker node

1. 첫번째 Control plane 노드에서 kubeadm init 결과(주황색 글씨)를 실행한다.

kubeadm join apisvr.hoya.com:6443 –token 9vr73a.a8uxyaju799qwdjv –discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866

 

HA에서 control plane 노드 제거

 방법 1) 제거 할 노드에서 아래 명령어(kubeadm reset) 실행

shell> sudo kubeadm reset

** kubectl delete node로 control plane노드 를 제거하지 않도록 한다. 만약 kubectl delete node로 삭제하는 경우 이후 추가 되는 control plane 노드들은 HA에 추가 될수 없다. 그 이유는 kubeadm reset은 HA내 다른  control plane 노드의 etcd에서 etcd endpoint 정보를 지우지만 kubectl delete node는 HA 내의 다른 controle plane 노드에서 etcd endpoint 정보를 지우지 못하기 때문이다. 이로 인해 이후 HA에 추가되는 control plane 노드는 삭제된 노드의 etcd endpoint 접속이 되지 않기 때문에 etcd 유효성 검사 과정에서 오류가 발생하게 된다.

– control plane 노드를 kubectl delete node 로 삭제후 control plane 노드 추가시 오류 메시지

shell> kubeadm join ….. –control-plane –certyficate-key
… 생략 …
[check-etcd] Checking that the etcd cluster is healthy
error execution phase check-etcd: etcd cluster is not healthy: failed to dial endpoint https://192.168.0.159:2379 with maintenance client: context deadline exceeded
To see the stack trace of this error execute with –v=5 or higher

 방법 2) etcd member 삭제 진행 절차

  step 1. 유효한 control plane 노드에서 etcd member id 확인

shell> etcdctl –cacert=/etc/kubernetes/pki/etcd/ca.crt \ 
 –cert=/etc/kubernetes/pki/etcd/peer.crt \ 
 –key=/etc/kubernetes/pki/etcd/peer.key  member list 81ce68f24db8ced, started, master1, https://192.168.0.159:2380, https://192.168.0.159:2379, false
5364415ff53d0975, started, master3, https://192.168.0.158:2380, https://192.168.0.158:2379, false
b27f6573a770c244, started, master2, https://192.168.0.149:2380, https://192.168.0.149:2379, false
shell>

  step 2. 멤버 제거

shell> etcdctl -cacert=/etc/kubernetes/pki/etcd/ca.crt  \ 
–cert=/etc/kubernetes/pki/etcd/peer.crt \  
–key=/etc/kubernetes/pki/etcd/peer.key member remove 81ce68f24db8cedMember  81ce68f24db8ced removed from cluster  88707d65fd36eb2
shell>

 

TroubleShooting

참고 : 아래 환경에서 etcdctl 을 이용하여 접속하면 오류가 발생하여 etcd 버전을 업그레이드(v3.4.5)하여 진행, 아마 etcd, etcdctl 은 마이너 버전까지 일치해야만 정상 작동하는듯 하다.

– kubernetes etcd 버전 : 3.4.3-0

– etcdctl 버전

shell> etcdctl –version
etcdctl version: 3.2.10
API version: 2

 

증상 1) etcdctl version 3.2.10 으로 실행 오류 #1 – 404 오류 발생

shell> etcdctl -C https://192.168.0.149:2379 –ca-file=/tmp/pki/ca.crt  \
–cert-file=/tmp/pki/peer.crt  \
–key-file=/tmp/pki/peer.key member list
unexpected status code 404
shell>

증상 2) etcdctl version 3.2.10 으로 실행시 오류 #2( /etc/kubernetes/pki/etcd 디폴트 위치한 인증서 사용시)

shell> etcdctl -C https://192.168.0.149:2379 –ca-file=/etc/kubernetes/pki/etcd/ca.crt  \
–cert-file=/etc/kubernetes/pki/etcd/peer.crt  \
–key-file=/etc/kubernetes/pki/etcd/peer.key member list
open /etc/kubernetes/pki/etcd/peer.crt: permission denied
shell>

kubeadm 이용 Ubuntu 20.04에 Kubernetes 클러스터 설치

Kubernetes는 온프레미스 서버 또는 하이브리드 클라우드 환경에서 대규모로 컨테이너화된 애플리케이션을 오케스트레이션 및 관리하기 위한 도구입니다. Kubeadm은 사용자가 모범 사례 시행을 통해 프로덕션 준비 Kubernetes 클러스터를 설치할 수 있도록 Kubernetes와 함께 제공되는 도구입니다. 이 튜토리얼은 kubeadm을 사용하여 Ubuntu 20.04에 Kubernetes 클러스터를 설치하는 방법을 보여줍니다.

Kubernetes 클러스터 배포에는 두 가지 서버 유형이 사용됩니다.

  • 마스터 : Kubernetes 마스터는 Kubernetes 클러스터의 포드, 복제 컨트롤러, 서비스, 노드 및 기타 구성 요소에 대한 제어 API 호출이 실행되는 곳입니다.
  • Node : Node는 컨테이너에 런타임 환경을 제공하는 시스템입니다. 컨테이너 포드 세트는 여러 노드에 걸쳐 있을 수 있습니다.

실행 가능한 설정을 위한 최소 요구 사항은 다음과 같습니다.

  • 메모리: 컴퓨터당 2GiB 이상의 RAM
  • CPU: 컨트롤 플레인 머신에 최소 2개의 CPU 가 있습니다.
  • 컨테이너 풀링을 위한 인터넷 연결 필요(개인 레지스트리도 사용할 수 있음)
  • 클러스터의 머신 간 전체 네트워크 연결 – 개인 또는 공용입니다.

Ubuntu 20.04에 Kubernetes 클러스터 설치

My Lab 설정에는 3개의 서버가 있습니다. 컨테이너화된 워크로드를 실행하는 데 사용할 하나의 컨트롤 플레인 머신과 두 개의 노드. 예를 들어 HA용 제어 평면 노드 3개 를 사용하여 원하는 사용 사례 및 부하에 맞게 노드를 더 추가할 수 있습니다 .

서버 유형 서버 호스트 이름 명세서
주인 k8s-master01.computingforgeeks.com 4GB 램, 2vcpus
노동자 k8s-worker01.computingforgeeks.com 4GB 램, 2vcpus
노동자 k8s-worker02.computingforgeeks.com 4GB 램, 2vcpus

1단계: Kubernetes 서버 설치

Ubuntu 20.04에서 Kubernetes 배포에 사용할 서버를 프로비저닝합니다. 설정 프로세스는 사용 중인 가상화 또는 클라우드 환경에 따라 다릅니다.

서버가 준비되면 업데이트하십시오.

sudo apt update
sudo apt -y upgrade && sudo systemctl reboot

2단계: kubelet, beadm 및 kubectl 설치

서버가 재부팅되면 Ubuntu 20.04용 Kubernetes 저장소를 모든 서버에 추가하십시오.

sudo apt update
sudo apt -y install curl apt-transport-https
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list

그런 다음 필요한 패키지를 설치합니다.

sudo apt update
sudo apt -y install vim git curl wget kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

kubectl 버전을 확인하여 설치를 확인합니다.

$ kubectl version --client && kubeadm version
Client Version: version.Info{Major:"1", Minor:"22", GitVersion:"v1.22.2", GitCommit:"8b5a19147530eaac9476b0ab82980b4088bbc1b2", GitTreeState:"clean", BuildDate:"2021-09-15T21:38:50Z", GoVersion:"go1.16.8", Compiler:"gc", Platform:"linux/amd64"}
kubeadm version: &version.Info{Major:"1", Minor:"22", GitVersion:"v1.22.2", GitCommit:"8b5a19147530eaac9476b0ab82980b4088bbc1b2", GitTreeState:"clean", BuildDate:"2021-09-15T21:37:34Z", GoVersion:"go1.16.8", Compiler:"gc", Platform:"linux/amd64"}

3단계: 스왑 비활성화

스왑과 방화벽을 끕니다.

sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
sudo swapoff -a
sudo ufw disable

crontab -e
@reboot sudo swapoff -a 

커널 모듈을 활성화하고 sysctl을 구성합니다.

# Enable kernel modules
sudo modprobe overlay
sudo modprobe br_netfilter

# Add some settings to sysctl
sudo tee /etc/sysctl.d/kubernetes.conf<<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF

# Reload sysctl
sudo sysctl --system

4단계: 컨테이너 런타임 설치

Pod에서 컨테이너를 실행하기 위해 Kubernetes는 컨테이너 런타임을 사용합니다. 지원되는 컨테이너 런타임은 다음과 같습니다.

  • 도커
  • CRI-O
  • 컨테이너

참고 : 한 번에 하나의 런타임을 선택해야 합니다 .

도커 런타임 설치:

# Add repo and Install packages
sudo apt update
sudo apt install -y curl gnupg2 software-properties-common apt-transport-https ca-certificates

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

sudo apt update
sudo apt install -y containerd.io docker-ce docker-ce-cli

# Create required directories
sudo mkdir -p /etc/systemd/system/docker.service.d
sudo mkdir -p /etc/docker

# Create daemon json config file
sudo tee /etc/docker/daemon.json <<EOF
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2"
}
EOF

# Start and enable Services
sudo systemctl daemon-reload 
sudo systemctl restart docker
sudo systemctl enable docker

CRI-O 설치:

# Ensure you load modules
sudo modprobe overlay
sudo modprobe br_netfilter

# Set up required sysctl params
sudo tee /etc/sysctl.d/kubernetes.conf<<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF

# Reload sysctl
sudo sysctl --system

# Add Cri-o repo
sudo su -
OS="xUbuntu_20.04"
VERSION=1.22
echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/ /" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
echo "deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$VERSION/$OS/ /" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:$VERSION.list
curl -L https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:$VERSION/$OS/Release.key | apt-key add -
curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/Release.key | apt-key add -

# Update CRI-O CIDR subnet
sudo sed -i 's/10.85.0.0/192.168.0.0/g' /etc/cni/net.d/100-crio-bridge.conf

# Install CRI-O
sudo apt update
sudo apt install cri-o cri-o-runc

# Start and enable Service
sudo systemctl daemon-reload
sudo systemctl restart crio
sudo systemctl enable crio
sudo systemctl status crio

컨테이너 설치:

# Configure persistent loading of modules
sudo tee /etc/modules-load.d/containerd.conf <<EOF
overlay
br_netfilter
EOF

# Load at runtime
sudo modprobe overlay
sudo modprobe br_netfilter

# Ensure sysctl params are set
sudo tee /etc/sysctl.d/kubernetes.conf<<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF

# Reload configs
sudo sysctl --system

# Install required packages
sudo apt install -y curl gnupg2 software-properties-common apt-transport-https ca-certificates

# Add Docker repo
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

# Install containerd
sudo apt update
sudo apt install -y containerd.io

# Configure containerd and start service
sudo su -
mkdir -p /etc/containerd
containerd config default>/etc/containerd/config.toml

# restart containerd
sudo systemctl restart containerd
sudo systemctl enable containerd
systemctl status  containerd

 cgroup 드라이버 설치

systemd cgroup 드라이버를 사용하려면 에서 plugins.cri.systemd_cgroup = true 를 설정 /etc/containerd/config.toml하십시오. kubeadm을 사용할 때 kubelet 용 cgroup 드라이버를 수동으로 구성하십시오.

5단계: 마스터 노드 초기화

마스터로 사용할 서버에 로그인하고 br_netfilter 모듈이 로드되었는지 확인합니다.

$ lsmod | grep br_netfilter
br_netfilter           22256  0 
bridge                151336  2 br_netfilter,ebtable_broute

컨테이너 이미지 가져오기:

$ sudo kubeadm config images pull
[config/images] Pulled k8s.gcr.io/kube-apiserver:v1.22.2
[config/images] Pulled k8s.gcr.io/kube-controller-manager:v1.22.2
[config/images] Pulled k8s.gcr.io/kube-scheduler:v1.22.2
[config/images] Pulled k8s.gcr.io/kube-proxy:v1.22.2
[config/images] Pulled k8s.gcr.io/pause:3.5
[config/images] Pulled k8s.gcr.io/etcd:3.5.0-0
[config/images] Pulled k8s.gcr.io/coredns/coredns:v1.8.4

kubelet 서비스를 활성화합니다.

sudo systemctl enable kubelet

이제 etcd (클러스터 데이터베이스)와 API 서버를 포함하는 컨트롤 플레인 구성 요소를 실행할 시스템을 초기화하려고 합니다.

 

CRI 소켓이 여러 개인 경우 다음 --cri-socket중 하나를 선택 하는 데 사용하십시오.

# CRI-O
sudo kubeadm config images pull --cri-socket /var/run/crio/crio.sock

# Containerd
sudo kubeadm config images pull --cri-socket /run/containerd/containerd.sock

# Docker
sudo kubeadm config images pull --cri-socket /var/run/dockershim.sock

kubeadm init클러스터를 부트스트랩하는 데 사용되는 기본 옵션입니다.

--control-plane-endpoint : 모든 제어 평면 노드에 대한 공유 끝점을 설정합니다. DNS/IP일 수 있음
 --pod-network-cidr : 포드 네트워크 추가 기능을 설정하는 데 사용됨 CIDR
 --cri-socket : 런타임 소켓 경로를 설정하기 위해 컨테이너 런타임이 둘 이상인 경우 사용
 --apiserver-advertise-address : 이 특정 제어 평면 노드의 API 서버에 대한 광고 주소 설정

공유 엔드포인트가 없는 부트스트랩 (Worker 초기 설정 시 진행)

DNS 엔드포인트를 사용하지 않고 클러스터를 부트스트랩하려면 다음을 실행합니다.

sudo kubeadm init \
  --pod-network-cidr=192.168.0.0/16

공유 엔드포인트가 있는 부트스트랩(제어 평면 API의 DNS 이름)

클러스터 엔드포인트 DNS 이름을 설정하거나 /etc/hosts 파일에 레코드를 추가합니다.

$ sudo vim /etc/hosts
172.29.20.5 k8s-cluster.computingforgeeks.com

클러스터 생성: (Master Node 경우)

sudo kubeadm init \
  --pod-network-cidr=192.168.0.0/16 \
  --upload-certs \
  --control-plane-endpoint=k8s-cluster.computingforgeeks.com

참고 : 192.168.0.0/16 이 이미 네트워크 내에서 사용 중인 경우 위 명령에서 192.168.0.0/16을 대체하여 다른 포드 네트워크 CIDR을 선택해야 합니다.

컨테이너 런타임 소켓:

실행 시간 Unix 도메인 소켓 경로
도커 /var/run/docker.sock
용기에 담긴 /run/containerd/containerd.sock
만들기 /var/run/crio/crio.sock

선택적으로 런타임용 소켓 파일을 전달하고 설정에 따라 주소를 알릴 수 있습니다.

# CRI-O
sudo kubeadm init \
  --pod-network-cidr=192.168.0.0/16 \
  --cri-socket /var/run/crio/crio.sock \
  --upload-certs \
  --control-plane-endpoint=k8s-cluster.computingforgeeks.com

# Containerd
sudo kubeadm init \
  --pod-network-cidr=192.168.0.0/16 \
  --cri-socket /run/containerd/containerd.sock \
  --upload-certs \
  --control-plane-endpoint=k8s-cluster.computingforgeeks.com

# Docker
sudo kubeadm init \
  --pod-network-cidr=192.168.0.0/16 \
  --cri-socket /var/run/docker.sock \
  --upload-certs \
  --control-plane-endpoint=k8s-cluster.computingforgeeks.com

다음은 초기화 명령의 출력입니다.

....
[init] Using Kubernetes version: v1.22.2
[preflight] Running pre-flight checks
	[WARNING Firewalld]: firewalld is active, please ensure ports [6443 10250] are open or your cluster may not function correctly
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Starting the kubelet
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Using existing ca certificate authority
[certs] Using existing apiserver certificate and key on disk
[certs] Using existing apiserver-kubelet-client certificate and key on disk
[certs] Using existing front-proxy-ca certificate authority
[certs] Using existing front-proxy-client certificate and key on disk
[certs] Using existing etcd/ca certificate authority
[certs] Using existing etcd/server certificate and key on disk
[certs] Using existing etcd/peer certificate and key on disk
[certs] Using existing etcd/healthcheck-client certificate and key on disk
[certs] Using existing apiserver-etcd-client certificate and key on disk
[certs] Using the existing "sa" key
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
[kubeconfig] Using existing kubeconfig file: "/etc/kubernetes/admin.conf"
[kubeconfig] Using existing kubeconfig file: "/etc/kubernetes/kubelet.conf"
[kubeconfig] Using existing kubeconfig file: "/etc/kubernetes/controller-manager.conf"
[kubeconfig] Using existing kubeconfig file: "/etc/kubernetes/scheduler.conf"
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
W0611 22:34:23.276374    4726 manifests.go:225] the default kube-apiserver authorization-mode is "Node,RBAC"; using "Node,RBAC"
[control-plane] Creating static Pod manifest for "kube-scheduler"
W0611 22:34:23.278380    4726 manifests.go:225] the default kube-apiserver authorization-mode is "Node,RBAC"; using "Node,RBAC"
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s
[apiclient] All control plane components are healthy after 8.008181 seconds
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config-1.21" in namespace kube-system with the configuration for the kubelets in the cluster
[upload-certs] Skipping phase. Please see --upload-certs
[mark-control-plane] Marking the node k8s-master01.computingforgeeks.com as control-plane by adding the label "node-role.kubernetes.io/master=''"
[mark-control-plane] Marking the node k8s-master01.computingforgeeks.com as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule]
[bootstrap-token] Using token: zoy8cq.6v349sx9ass8dzyj
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to get nodes
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

You can now join any number of control-plane nodes by copying certificate authorities
and service account keys on each node and then running the following as root:

  kubeadm join k8s-cluster.computingforgeeks.com:6443 --token sr4l2l.2kvot0pfalh5o4ik \
    --discovery-token-ca-cert-hash sha256:c692fb047e15883b575bd6710779dc2c5af8073f7cab460abd181fd3ddb29a18 \
    --control-plane 

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join k8s-cluster.computingforgeeks.com:6443 --token sr4l2l.2kvot0pfalh5o4ik \
    --discovery-token-ca-cert-hash sha256:c692fb047e15883b575bd6710779dc2c5af8073f7cab460abd181fd3ddb29a18

출력의 명령을 사용하여 kubectl을 구성합니다.

mkdir -p $HOME/.kube
sudo cp -f /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

echo 'export KUBECONFIG=$HOME/.kube/config' >> $HOME/.bashrc

클러스터 상태 확인:

$ kubectl cluster-info
Kubernetes master is running at https://k8s-cluster.computingforgeeks.com:6443
KubeDNS is running at https://k8s-cluster.computingforgeeks.com:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

설치 출력의 명령을 사용하여 마스터 노드를 추가할 수 있습니다.

kubeadm join k8s-cluster.computingforgeeks.com:6443 --token sr4l2l.2kvot0pfalh5o4ik \
    --discovery-token-ca-cert-hash sha256:c692fb047e15883b575bd6710779dc2c5af8073f7cab460abd181fd3ddb29a18 \
    --control-plane 

6단계: 마스터에 네트워크 플러그인 설치

이 가이드에서는 Calico 를 사용 합니다. 지원되는 다른 네트워크 플러그인 을 선택할 수 있습니다 .

kubectl create -f https://docs.projectcalico.org/manifests/tigera-operator.yaml 
kubectl create -f https://docs.projectcalico.org/manifests/custom-resources.yaml

다음 출력이 표시되어야 합니다.

customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/apiservers.operator.tigera.io created
customresourcedefinition.apiextensions.k8s.io/imagesets.operator.tigera.io created
customresourcedefinition.apiextensions.k8s.io/installations.operator.tigera.io created
customresourcedefinition.apiextensions.k8s.io/tigerastatuses.operator.tigera.io created
namespace/tigera-operator created
Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
podsecuritypolicy.policy/tigera-operator created
serviceaccount/tigera-operator created
clusterrole.rbac.authorization.k8s.io/tigera-operator created
clusterrolebinding.rbac.authorization.k8s.io/tigera-operator created
deployment.apps/tigera-operator created
.....
installation.operator.tigera.io/default created
apiserver.operator.tigera.io/default created

모든 포드가 실행 중인지 확인합니다.

$ watch kubectl get pods --all-namespaces
NAMESPACE     NAME                                                         READY   STATUS    RESTARTS   AGE
kube-system   calico-kube-controllers-76d4774d89-nfqrr                     1/1     Running   0          2m52s
kube-system   calico-node-kpprr                                            1/1     Running   0          2m52s
kube-system   coredns-66bff467f8-9bxgm                                     1/1     Running   0          7m43s
kube-system   coredns-66bff467f8-jgwln                                     1/1     Running   0          7m43s
kube-system   etcd-k8s-master01.computingforgeeks.com                      1/1     Running   0          7m58s
kube-system   kube-apiserver-k8s-master01.computingforgeeks.com            1/1     Running   0          7m58s
kube-system   kube-controller-manager-k8s-master01.computingforgeeks.com   1/1     Running   0          7m58s
kube-system   kube-proxy-bt7ff                                             1/1     Running   0          7m43s
kube-system   kube-scheduler-k8s-master01.computingforgeeks.com            1/1     Running   0          7m58s

마스터 노드가 준비되었는지 확인합니다.

# CRI-O
$ kubectl get nodes -o wide
NAME     STATUS   ROLES                  AGE   VERSION   INTERNAL-IP      EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION     CONTAINER-RUNTIME
ubuntu   Ready    control-plane,master   38s   v1.22.2   143.198.114.46   <none>        Ubuntu 20.04.3 LTS   5.4.0-88-generic   cri-o://1.22.0

# Containerd
$ kubectl get nodes -o wide
NAME     STATUS   ROLES                  AGE   VERSION   INTERNAL-IP      EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION     CONTAINER-RUNTIME
ubuntu   Ready    control-plane,master   15m   v1.22.2   143.198.114.46   <none>        Ubuntu 20.04.3 LTS   5.4.0-88-generic   containerd://1.4.11

# Docker
$ kubectl get nodes -o wide
NAME           STATUS   ROLES    AGE   VERSION   INTERNAL-IP      EXTERNAL-IP   OS-IMAGE           KERNEL-VERSION     CONTAINER-RUNTIME
k8s-master01   Ready    master   64m   v1.22.2   135.181.28.113   <none>        Ubuntu 20.04 LTS   5.4.0-37-generic   docker://20.10.8

7단계: 작업자 노드 추가

제어 플레인이 준비되면 예약된 워크로드를 실행하기 위해 클러스터에 작업자 노드를 추가할 수 있습니다.

엔드포인트 주소가 DNS에 없으면 /etc/hosts 에 레코드를 추가 합니다 .

$ sudo vim /etc/hosts
172.29.20.5 k8s-cluster.computingforgeeks.com

주어진 조인 명령은 클러스터에 작업자 노드를 추가하는 데 사용됩니다.

kubeadm join k8s-cluster.computingforgeeks.com:6443 \
  --token sr4l2l.2kvot0pfalh5o4ik \
  --discovery-token-ca-cert-hash sha256:c692fb047e15883b575bd6710779dc2c5af8073f7cab460abd181fd3ddb29a18

산출:

[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'
[kubelet-start] Downloading configuration for the kubelet from the "kubelet-config-1.21" ConfigMap in the kube-system namespace
[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.

제어 플레인에서 아래 명령을 실행하여 노드가 클러스터에 합류했는지 확인합니다.

$ kubectl get nodes
NAME                                 STATUS   ROLES    AGE   VERSION
k8s-master01.computingforgeeks.com   Ready    master   10m   v1.22.2
k8s-worker01.computingforgeeks.com   Ready    <none>   50s   v1.22.2
k8s-worker02.computingforgeeks.com   Ready    <none>   12s   v1.22.2

$ kubectl get nodes -o wide

조인 토큰이 만료된 경우 작업자 노드에 조인하는 방법에 대한 가이드를 참조하십시오.

8단계: 클러스터에 애플리케이션 배포

단일 노드 클러스터만 있는 경우 마스터 노드에서 컨테이너 포드를 실행하는 방법에 대한 가이드를 확인하세요.

애플리케이션을 배포하여 클러스터가 작동하는지 확인해야 합니다.

kubectl apply -f https://k8s.io/examples/pods/commands.yaml

포드가 시작되었는지 확인

$ kubectl get pods
NAME           READY   STATUS      RESTARTS   AGE
command-demo   0/1     Completed   0          16s

9단계: Kubernetes 대시보드 설치(선택 사항)

Kubernetes 대시보드는 컨테이너화된 애플리케이션을 Kubernetes 클러스터에 배포하고, 컨테이너화된 애플리케이션의 문제를 해결하고, 클러스터 리소스를 관리하는 데 사용할 수 있습니다.

설치 가이드를 참조하십시오: NodePort로 Kubernetes 대시보드를 설치하는 방법

10단계: Metrics Server 설치(Pod 및 노드 리소스 사용량 확인용)

Metrics Server  는 리소스 사용량 데이터의 클러스터 전체 집계 도구입니다.  각 노드에서 Kubelet 에 의해 노출된  요약 API 에서 메트릭을 수집  합니다. 아래 가이드를 사용하여 배포하세요.

11단계: Prometheus/Grafana 모니터링 배포

Prometheus는 Kubernetes 클러스터의 고급 메트릭 기능에 액세스할 수 있는 완전한 솔루션입니다. Grafana는 Prometheus 데이터베이스에 수집 및 저장되는 메트릭의 분석 및 대화형 시각화에 사용됩니다. Kubernetes 클러스터에서 전체 모니터링 스택을 설정하는 방법에 대한 완전한 가이드가 있습니다.

12단계: 영구 저장소 구성 아이디어(선택 사항)

Kubernetes용 영구 스토리지 솔루션도 찾고 있다면 다음을 확인하십시오.

13. Nginx 인그레스 컨트롤러 설치

Nginx가 Kubernetes 워크로드용으로 선호하는 Ingress 컨트롤러인 경우 설치 프로세스에 대한 가이드를 사용할 수 있습니다.

더 많은 가이드:

유사한 Kubernetes 배포 가이드:

Kubernetes Virtual Storage (Ceph) Installation

설치에 필요한 도구로 Rook을 사용할 예정입니다. Rook은 오픈소스 클라우드 네이티브 스토리지 오케스트레이터로, 클라우드 네이티브 환경과 기본적으로 통합할 수 있는 다양한 스토리지 솔루션 세트에 대한 플랫폼, 프레임 워크 및 지원합니다. Rook을 통해 Ceph 가상스토리지를 구성하고 공유 파일 시스템을 적용하도록 하겠습니다.

Rook 구성도

Rook은 쿠버네티스 POD에서 실행되며, Ceph, EdgeFS등 가상솔루션을 POD로 배포하여 관리하는 도구입니다. agent를 통해 Ceph, EdgeFS등 가상솔루션을 관리하고, OSD를 통해 데이터를 영구저장합니다.

/images/2020-01-28-kubernetes-rook-ceph/Untitled.png

Ceph vs EdgeFS

Rook에서 제공하는 가상스토리지는 EgdeFS와 Ceph 외에도 다양하게 지원하지만 안정적인 버전은 아래 두가지만 지원합니다.

  • EdgeFS: 데이터베이스처럼 대용량 스토리지가 필요할때 사용됩니다.
  • Ceph: 공유 확장에 특화되어 있는 스토리지가 필요할때 사용됩니다.

공유나 확장에 특화되어 있는 Ceph를 설치하도록 하겠습니다.

Ceph 스토리지 유형

Ceph는 Block, Object, File 기반으로 데이터를 사용할 수 있습니다. 각 유형에 따라서 사용하는 기능에 차이가 있습니다.

  • Block Stroage: 단일 POD에 storage 제공합니다.
  • Object Storage: 애플리케이션이 쿠버네티스 클러스터 내부 또는 외부에서 액세스 할수있느 데이터를 IO 할수있고, S3 API를 스토리지 클러스터에 노출을 제공합니다.
  • Shared Stroage: 여러 POD에서 공유할 수있는 파일 시스템기반 스토리지입니다.

Shared Storage 구성도

이번에 설치해볼 Shared Storage 구성입니다. Ceph 클러스터에 데이터를 저장하고 Ceph를 통해 POD들과 데이터가 공유가 됩니다.

/images/2020-01-28-kubernetes-rook-ceph/Untitled%201.png

Ceph 설치

테스트 환경

쿠버네티스가 설치된 환경이 필요합니다. 설치방법은 쿠버네티스 고가용성 클러스터 구성 블로그를 통해 설치진행 바랍니다.

OS: ubuntu:18.04
Kubernetes: 1.16.4

Ceph 소스 다운로드 및 POD 배포

Rook은 별도의 설치가 없고 github으로 Ceph, EdgeFS 가상스토리지 솔루션을 쿠버네티스에 배포할 수 있도록 제공하고 있습니다.

$ git clone --single-branch --branch release-1.2 https://github.com/rook/rook.git

아래 경로에 보면 common.yaml, operator.yaml이 있습니다. kubectl 명령어를 통해 배포 합니다.

$ kubectl apply -f rook/cluster/examples/kubernetes/ceph/common.yaml
$ kubectl apply -f rook/cluster/examples/kubernetes/ceph/operator.ymal
$ kubectl apply -f rook/cluster/examples/kubernetes/ceph/cluster.yaml

cluster.yaml을 배포하게 되면 POD 중 OSD가 Running 상태인지 확인이 필요합니다. 변경되는 시간이 약 1 ~ 3 분 정도 소요됩니다.
테스트 환경에 따라 OSD 갯수가 차이가 있을 수 있습니다.

$ kubectl get pod -n rook-ceph

/images/2020-01-28-kubernetes-rook-ceph/Untitled%202.png

OSD Running 상태까지가 ceph 클러스터 구성이 완료되었고, Shared Storage 유형을 적용해보겠습니다.

Shared Storage 유형 적용

아래 명령어를 실행하게 되면 MDS POD가 배포가 됩니다. 약 1 ~ 3분 정도 소요됩니다. Shared Storage 옵션을 변경할 수 있는데 자세한 내용은 ceph-filesystem-crd 통해 확인바랍니다.

$ kubectl apply -f rook/cluster/examples/kubernetes/ceph/filesystem.yaml

StorageClass Driver 적용

StorageClass는 POD에서 Ceph 데이터 풀에 접근하기 위해 사용되는 드라이버입니다. kubectl 명령어를 통해 적용합니다.

$ kubectl apply -f rook/cluster/examples/kubernetes/ceph/csi/cephfs/storageclass.yaml

Shared Storage 확인

정상적으로 적용이 되었는지 확인하는 방법압니다. 아래 결과 처럼 myfs가 생성되어 있습니다.

$ kubectl get CephFileSystem -A

결과)

/images/2020-01-28-kubernetes-rook-ceph/Untitled%203.png

Shared Storage 테스트

kube-registry를 배포하면 PVC, docker-registry POD가 배포됩니다. 컨테이너 내부에 접근하여 /var/lib/registry 디렉터리에 dummy 파일을 생성 하여 다른 POD에서 공유되어 보여지는지 확인합니다.

$ kubectl apply -f rook/cluster/examples/kubernetes/ceph/csi/cephfs/kube-registry.yaml

정리

Rook이라는 도구를 이용해서 Ceph를 설치해보았습니다. Ceph를 관리하려면 러닝커브가 있지만 Rook이라는 도구를 이용해서 Ceph 관리와 쿠버네티스와 연동을 쉽게 할 수 있습니다.

Configuring Kubernetes High Availability Clusters

소개

쿠버네티스는 마스터 노드에 내부적으로 API-SERVER를 가지고 있어 마스터 노드를 통해 워커 노드로 통신이 전달됩니다. 대량에 통신량이 발생하게 되면 마스터 노드는 부하를 많이 받아 장애 발생 가능성이 커지게 됩니다. 마스터 노드를 고가용성 클러스터로 연결하게 되면 통신량을 분산시킬 수 있고, 일부가 마스터 노드에서 장애가 발생시 워커 노드의 운영 시스템에는 영향을 줄일 수 있습니다.

구성 환경

아래 사양으로 총 3대 서버를 준비합니다.

OS: CentOS 7
CPU: 2
RAM: 4
Storage: 100G

구성목표

  1. 마스터 노드 3개를 클러스터구성
  2. 가상 네트워크(weave) 적용
  3. ceph storage 적용

도커&쿠버네티스 설치

CentOS 패키지 업데이트와 방화벽을 정지 및 스왑을 종료합니다.

$ sudo yum update -y
$ sudo systemctl disable firewalld && sudo systemctl stop firewalld
$ sudo selinux disabled
$ sudo setenforce 0
$ sudo iptables piv4 forward
$ sudosudo bash -c 'echo 1 > /proc/sys/net/ipv4/ip_forward'
$ sudo swapoff -a
$ sudo sed -i '/swap/d' /etc/fstab

운영 환경에서는 아래 포트를 오픈하여 진행합니다.

노드 포트 TCP/UDP
마스터 6443, 2379-2380, 10250, 10251, 10252 TCP
마스터, 워커 6783 TCP
마스터, 워커 6783, 6784 UDP
워커 10250, 30000-32767 TCP
로드 밸런서 26443 TCP

호스트네임 설정

호스트네임은 서로 다르게 지정해야합니다.

$ sudo hostnamectl set-hostname node1

$ sudo hostnamectl set-hostname node2

$ sudo hostnamectl set-hostname node3

도커 설치

도커 레파지토리를 등록하여 yum 으로 설치 합니다.

$ sudo yum install -y yum-utils \
    device-mapper-persistent-data \
    lvm2

$ sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo

$ sudo yum install docker-ce docker-ce-cli containerd.io

$ sudo systemctl start docker

설치 후 daemon.json을 추가하여 cgroupdriver를 systemd 옵션으로 사용할 수 있도록 합니다.

$ sudo cat <<EOF > /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2",
"storage-opts": [
"overlay2.override_kernel_check=true"
]
}
EOF

$ sudo systemctl daemon-reload
$ sudo systemctl enable docker
$ sudo systemctl restart docker

쿠버네티스 설치

쿠버네티스의 레파지토리 저장소를 등록하여 yum 으로 kubelet, kubeadm, kubectl을 설치합니다.

  • kubeadm: 클러스터 관련 작업시 사용됩니다.
  • kubectl: 클러스터의 서비스 및 pod 관리시 사용됩니다.
  • kubelet: 클러스터 에이전트역할을 합니다.
$ sudo cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=0
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg [https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg](https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg)
EOF

$ sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes

$ sudo systemctl enable kubelet
$ sudo systemctl restart kubelet

node1, node2, node3에 도커와 쿠버네티스가 설치를 하였다면 아래 명령어를 통해 확인해볼 수 있습니다.

$ sudo docker verison
$ kubectl version

로드밸런서 설치

공식문서에서 사용되고 있는 HAProxy를 사용하도록 하겠습니다.
테스트환경이기 때문에 keepalive및 failover 기능없이 진행하도록 하겠습니다.

노드1에만 haproxy 를 설치하도록 하겠습니다.

$ sudo yum install haproxy -y

haproxy 로드밸런싱 설정

node1 IP의 26443포트로 전달받은 데이터를 node1 ~ node3의 6443 포트로 포워드 시켜줍니다.
라운드로빈으로 순차적으로 접근하도록 하겠습니다.

$ sudo cat <<EOF >> /etc/haproxy/haproxy.cfg
frontend kubernetes-master-lb
bind 0.0.0.0:26443
option tcplog
mode tcp
default_backend kubernetes-master-nodes

backend kubernetes-master-nodes
mode tcp
balance roundrobin
option tcp-check
option tcplog
server node1 <node1 IP>:6443 check
server node2 <node2 IP>:6443 check
server node3 <node3 IP>:6443 check
EOF

$ sudo systemctl restart haproxy

haproxy 확인

해당 포트가 오픈되어 있는지 확인합니다.
포트가 오픈되어 있어도 접근이 안될때는 방화벽을 확인해야 합니다.

netstat -an|grep 26443

클러스터 생성

클러스터 생성할때 –upload-certs, –control-plane-endpoint 플래그를 추가해야 인증서가 자동 배포되고, 마스터 노드 조인 명령어가 출력됩니다.

$ sudo kubeadm init --control-plane-endpoint "<노드1 DNS/IP or LoadBalancer DNS/IP>:26443" \
                --upload-certs \
                --pod-network-cidr "10.244.0.0/16"

config 생성

kubectl 사용하기 위해서는 사용자 디렉토리 하위에 .kube/config 가 필요합니다. kubeadm init 명령어를 진행하고 마지막에 로그를 잘보면 config를 생성하는 명령어가 적혀있습니다.

$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config

클러스터 연결

노드1에서 클러스터 생성시 kubeadm join 명령어가 출력되는데 –control-plane –certificate-key 플래그 포함하여 명령어를 실행하면 마스터 노드로 연결이 되고, 플래그는 추가하지 않고 사용하게 되면 워커노드로 연결됩니다.

노드2 클러스터 연결

$ sudo kubeadm join 192.168.248.251:26443 --token 06glbc.s0yaqonyajs95ez3 \
    --discovery-token-ca-cert-hash sha256:379ff0daa2cffa3f6581ae25c96aa3d6e4a9af43df92b8d0ac5a4dbb4c7e5547 \
    --control-plane --certificate-key 8eb7fa9a38ca1579c3fb61e0a1106935c4e9dfd81cbad259121f223f0adf555f

config 생성

노드2의 사용자에서도 kubectl 명령어를 사용하기 위해선 config를 생성해야 합니다.

$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config

노드3 클러스터 연결

노드3에서도 노드2와 동일하게 연결을 진행합니다.

$ sudo kubeadm join 192.168.248.251:26443 --token 06glbc.s0yaqonyajs95ez3 \
    --discovery-token-ca-cert-hash sha256:379ff0daa2cffa3f6581ae25c96aa3d6e4a9af43df92b8d0ac5a4dbb4c7e5547 \
    --control-plane --certificate-key 8eb7fa9a38ca1579c3fb61e0a1106935c4e9dfd81cbad259121f223f0adf555f

config 생성

노드3에서도 동일하게 config를 생성해야합니다.

$ 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 node

마스터 노드에는 기본설정으로 pod 배포가 안됩니다. taint명령어를 통해 pod 배포가 가능하도록 하겠습니다.

$ kubectl taint nodes --all node-role.kubernetes.io/master-

가상 네트워크(weave) 적용

Calico, Canal, Clilum, Flannel, weave 등 다양한 가상네트워크가 있지만 공식문서에서 제공하는 weave를 적용하도록 하겠습니다.

$ kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"

가상네트워크 적용 확인

최초 클러스터를 진행하게 되면 노드의 상태는 NotReady 입니다. 가상네트워크를 적용하게 되면 약 1 ~ 3분 소요되고 Ready 상태로 변경되게 됩니다. 이것으로 가상네트워크 적용이 완료 되었습니다.

$ kubectl get node

nginx 배포 해보기

nginx pod 3개를 배포하는 명령어입니다.

kubectl run --image=nginx --port 80 --replicas=3 nginx-app

아래 명령어를 통해 nginx-app 배포된 노드를 보면 node1 ~ 3 골고루 배포되어 있는걸 확인할 수 있습니다.

kubectl get pod -o wide

정리

이번에 쿠버네티스 고가용성 클러스터를 서버에 구축해보았습니다. 쿠버네티스 버전 1.6 이후 부터는 인증서배포 자동화, 클러스터 연결하는 방법이 간편하게 변경되었습니다. 이전 버전에서는 클러스터 구성하기위해선 복잡한 과정과 설정파일을 만들어야 했지만 이제는 간단하게 명령어 한줄만 입력하면 클러스터에 연결/해지를 하도록 변경되었습니다. 자유로운 노드 할당은 자원 낭비없이 효율적으로 관리하는데 장점이 될 것으로 보여집니다.

참고문서

Ubuntu에 minikube설치하기

내가 가진 리눅스 환경에 쿠버네티스 실습 환경을 만들기 위해 minikube를 설치합니다.

 

이 포스트는 우분투 20.04 LTS버젼 기준으로 작성했습니다. 설치 전에 버전을 꼭 확인 해보세요.

미리 설치해야 하는 것 – Docker, VirtualBox (가상환경 내에 설치시에는 필요 없음)

Docker 설치

도커를 설치 해줍니다. Docker가 설치 되어 있다면 도커 설치는 넘어갑니다.

sudo apt-get update
sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
sudo apt-get install docker-ce docker-ce-cli containerd.io

여기까지가 Docker설치 명령입니다. 단순히 docker-ce만 설치 한다고 되는 것은 아닙니다. 위 단계를 모두 거쳐야 합니다.

 

 

설치가 완료된 후 docker라고 입력 했을 때 위와 같이 나오면 잘 설치 된 것입니다.

버추얼 박스 설치

minikube를 설치 하려면 OS에 맞는 하이퍼바이저를 설치 해주어야 합니다. 저는 virtualbox를 설치 했습니다.

sudo apt-get install virtualbox

위 버추얼박스를 설치 해줍니다.

Minikube설치

아래 명령어로 minikube를 다운로드 받습니다.

curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 \
  && chmod +x minikube
sudo mkdir -p /usr/local/bin/
sudo install minikube /usr/local/bin/

아래 명령어로 minikube를 실행 합니다.

minikube start

 

 

위와 같이 나오면 잘 설치되고 실행된 것입니다.

minikube start –vm-driver=none   (가상환경 내에 구동시 필요)

저 처럼 amd를 사용해서 에러가 나시는 분들은 위 명령어로 실행을 해보시기 바랍니다.

 

 

위와같이 GUEST_MISSING_CONNTRACK 에러가 나는 경우

sudo apt-get install -y conntrack

위 명령어로 conntrack을 설치 하시고 실행 하시기 바랍니다.

Kubectl설치

쿠버네티스 api에 명령을 전송 하려면 kubectl을 이용해야 합니다.

apt-get을 이용해 kubectl을 설치 합니다.

sudo apt-get update && sudo apt-get install -y apt-transport-https gnupg2
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee -a /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubectl

 

Nginx띄워보기

잘 설치되었으면 Nginx를 띄워보겠습니다.

kubectl run webserver –image=nginx:1.14 –port 80

 

 

kubectl get po

위 명령어를 이용해 webserver가 Running상태인지 확인 합니다.

 

end.