[번역] Enabling Pods to pull from external image repositories in vSphere with Kubernetes

출처 : https://cormachogan.com/2020/04/28/enabling-pods-to-pull-from-external-image-repositories-in-vsphere-with-kubernetes/

Cloud-Native-Apps-Icon-2020.png

일반 독자들은 내가 최근에 이전에 Project Pacific으로 알려진 vSphere with Kubernetes와 VMware Cloud Foundation(VCF) 4.0에 대해 이야기하는 데 상당한 시간을 할애하고 있다는 것을 알게 될 것이다. 지난 한 달여 동안 우리는 VCF 4.0 Management Domain을 구축하는 방법을 알아보았다. 또한 VCF 4.0 VI 워크로드 도메인을 생성하는 동시에 현재 VCF 4.0에서 자동화된 워크로드 도메인에 NSX-T 3.0 Edge 클러스터를 배포하는 방법에 대해서도 살펴보았다.

이 모든 것을 구성한 후, VCF 4.0 SDDC Manager의 새로운 솔루션 섹션을 통해 시작된 이 새로 생성된 워크로드 도메인에 vSphere with Kubernetes를 구축하는 단계를 거쳤다. 그런 다음 vSphere with Kubernetes에 더 깊이 침투하여 네임스페이스를 만들고 하버 이미지 레지스트리를 활성화하고 Supervisor Cluster에 컨테이너형 애플리케이션을 최초로 배치했다. 그런 다음, 우리는 vSphere with Kubernetes의 자체 네임스페이스에 Tanzu Kubernetes 클러스터(이전에는 게스트 클러스터로 알려져 있음)를 배포하고 Tanzu Kubernetes 클러스터에 컨테이너형 앱을 배포하는 단계를 살펴보았다.

이 게시물에서는 NSX-T 3.0 Edge 클러스터를 배포할 때 얼버무렸던 영역을 다시 살펴보고자 하며, 이는 정적 경로 옵션 선택과 관련이 있다. 내 배포는 "upstream 라우터"에 액세스할 수 없는 환경에 있으므로, 나는 BGP, Border Gateway Protocol을 사용하는 "upstream 라우터"와 NSX-T 3.0 Tier-0 논리적 라우터를 연결할 위치에 있지 않았다. BGP는 피어링된 라우터가 서로 알려진 경로를 공유하기 때문에 매우 유용하다. 간단히 말해, 패킷이 하나의 라우터에 도착하고, 패킷을 직접 라우팅할 수 있는 장소가 없다면, 피어링된 라우터 중 어떤 라우터가 패킷을 어디로 보낼지 알고 있는지 확인하고 라우터로 포워드 할 수 있다. BGP가 없으면, 이것은 훨씬 더 노동 집약적이 된다.

이제 BGP가 아닌 NSX-T 에지 클러스터 배포를 위한 정적 경로를 사용했기 때문에 배포가 완전히 작동하려면 몇 가지 추가 수동 단계가 필요하다.

  1. '내부' 네트워크에서 생성된 모든 패킷이 전달되도록 Tier-0 Logical Router Static Route를 추가한다. 여기에는 vSphere with Kubernetes를 배포하는 동안 정의된 로드 밸런서/수신 범위가 포함된다.
  2. 슈퍼바이저에 생성된 Add a Tier-0 Logical Router SNAT Rule for the PodVMs를 추가한다. 이 IP 주소의 범위는 Tier-1 논리적 라우터에 이미 SNAT가 설정되어 있지만 외부로 라우팅하려면 Tier-0에 다른 SNAT가 필요하다.
  3. 마찬가지로 Tier-0 Logical Router SNAT Rule for the Pods created on the TKG(guest) cluster를 추가한다. 이 IP 주소의 범위는 TKG 클러스터에 대해 생성된 Tier-1 논리적 라우터에 이미 SNAT가 설정되어 있지만 외부로 라우팅하려면 Tier-0에 다른 SNAT가 필요하다.

이제 이 단계들을 좀 더 자세히 살펴봅시다.

1. Tier-0 논리적 라우터에 정적 라우트 추가

Tier-0 논리적 라우터에 추가된 정적 경로를 사용하지 않으면, Kubernetes를 사용하여 vSphere를 배포하는 동안 정의된 IP 주소의 수신 범위에 연결할 수 없게 된다. 수신 범위는 로드 밸런서 IP 주소에 사용되므로 슈퍼바이저 클러스터 API Server Endpoint에 연결할 수 없다. 따라서 이 위치에서 호스팅되는 Kubernetes CLI Tools에 연결할 수 없다. 또한 TKG 클러스터 API Server Endpoint 또는 하버 이미지 레지스트리 UI에 연결할 수 없다.

Tier-0 논리적 라우터에 정적 경로를 추가하려면 NSX-T 3.0 Manager에 로그인하십시오. 오른쪽 상단에 "Policy"이 선택되어 있는지 확인한다. "Networking"을 선택한 다음 "Tier-0 Gateways"를 선택한다. 여기에는 Tier-0 게이트웨이 aka 논리적 라우터가 나열된다. Tier-0 이름 옆에는 세 개의 수직 점이 있다. 이 점을 클릭하면 드롭다운 메뉴가 제공된다. 메뉴에서 "Edit" 옵션을 선택한다. Edit 보기에서 "ROUTING" 옆에 있는 셰브론을 누른다. Static Routes는 현재 0이어야 한다. 새 정적 경로를 추가하려면 "0"을 클릭하십시오. "Set Static Route" 설정 팝업 창에서 네트워크 이름을 입력한다. 설정에서 모든 것이 라우팅되도록 네트워크를 "0.0.0/0"으로 설정했다. "Set Next Hops"을 클릭한다. "Set Next Hops" 팝업 창에서 "Add Next Hop"를 누른다. 이 경우Edge 업링크가 연결된 네트워크에 있는 기본 게이트웨이의 IP 주소를 추가했다. 일단 저장한 정적 경로 구성은 다음과 같이 보였다.

Tier-0-Static-Routes-Configuration.png

이제 Tier-0 논리적 라우터의 Routing 섹션에 있는 Static Routes 숫자가 1로 설정되어야 한다. 편집을 마치려면 오른쪽 하단의 "Close Editing"를 클릭한다. 모든 것이 제대로 작동하는 경우 이제 브라우저를 API Server Endpoint로 가리키고 Kubernetes CLI Tools 페이지를 참조한다.

k8s-cli-tools.png

정적 경로 구성이 완료되었다. 이제 새 NSX-T 3.0 Network Topology 보기에서 네트워킹 설정에 대해 살펴보자. 이는 Harbor 이미지 레지스트리를 활성화하고 TKG 클러스터를 생성한 후다. domain-c8 Tier-1 Logical Router를 통해 네트워크로 연결된 3개의 VM 그룹은 vSphere with Kubernetes Supervisor 클러스터를 사용하는 3개의 제어부 VM이다. 9 x Pods는 하버 이미지 레지스트리 배포에서 나온 7 x PodVM과 테스트를 위해 직접 생성한 2개의 샘플 PodVM이다. vnet-domain-c8 Tier-1 논리적 라우터를 통해 네트워크로 연결된 4개의 VM 그룹은 TKG 게스트 클러스터의 1 x 제어면과 3 x 작업자 노드다. 연결된 세그먼트가 없는 다른 Tier-1(T1)은 VCF 4.0에서 NSX-T Edge Cluster를 배포하는 동안 구축되지만 사용되지 않는다.

Network-Topology-View.png

이 개요를 염두에 두고, 이제 이러한 서로 다른 클러스터에서 컨테이너형 앱/팟을 활성화하는 방법에 대해 살펴보자.

2. Supervisor 클러스터 노드에 Tier-0 SNAT 규칙 추가

감독자 제어부 VM을 확장하면 다음과 같은 네트워크 토폴로지를 볼 수 있다. 우리는 그것이 10.244.0.97/28 네트워크 세그먼트를 통해 Tier-1 논리적 라우터에 연결되어 있다고 본다. 제어부 VM 중 하나를 클릭하면 아래와 같이 네트워크 경로가 파란색으로 강조 표시된다.

SupervisorCP-Network-Topology.png

NSX-T 3.0 매니저에서 Network Services > NAT으로 이동하여 domain-c8 Tier-1 논리적 라우터를 선택하면 vSphere for Kubernetes가 구축될 때 적용된 SNAT 규칙을 볼 수 있다. 10.244.0.97/28 범위는 배포 시 제공된 송신 범위에 정의된 IP 주소로 변환됨을 알 수 있다. 이 경우, 송신 범위는 vSphere for Kubernetes 구축 중에 30.0.0/24로 정의되었다. 이 경우 30.0.0.5로 매핑된 번역 주소를 확인하십시오.

SNAT-Rules.png

그러나 이것은 Tier-1과 Tier-0 사이의 SNAT이다. 우리는 그 30.0.0.5 주소가 외부로 나가는 것을 허락하는 SNAT를 가지고 있지 않다(또는 적어도 회신 받기). vSphere with Kubernetes의 네임스페이스에서 외부 이미지를 끌어들이는 PodVM을 생성하려고 할 때 이러한 문제가 스스로 나타나는 것이다. 다음 이벤트는 외부 Google 리포지토리(메시지 오른쪽 스크롤)에서 작업 상자 이미지를 가져오려고 했던 실패한 PodVM 배포의 kubectl describe pod로부터 취해진다. 연결 시간이 초과되었다는 것을 알 수 있다.

Events:  
  Type     Reason                        Age                            From                                                 Message
  ----     ------                        ----                           ----                                                 -------
  Normal   Scheduled                     <unknown>                      default-scheduler                                    Successfully assigned podvm-ns/ch-busybox to esxi-dell-n.rainpole.com
  Normal   Image                         <invalid>                      image-controller                                     Image busybox-91fc8f6fc85b4a0bfe94da01c9913d8e9bcdfb96-v0 bound successfully
  Normal   SuccessfulRealizeNSXResource  <invalid> (x3 over <invalid>)  nsx-container-ncp, 421df2f065306960d445646b70afb7e8  Successfully realized NSX resource for Pod
  Normal   Pulling                       <invalid>                      kubelet, esxi-dell-n.rainpole.com                    Waiting for Image podvm-ns/busybox-91fc8f6fc85b4a0bfe94da01c9913d8e9bcdfb96-v0
  Warning  Failed                        <invalid>                      kubelet, esxi-dell-n.rainpole.com                    failed to get images: Image podvm-ns/busybox-91fc8f6fc85b4a0bfe94da01c9913d8e9bcdfb96-v0 
                                                                                                                             has failed. Error: Failed to resolve on node esxi-dell-n.rainpole.com. Reason: Http request 
                                                                                                                             failed. Code 400: ErrorType(2) failed to do request: Head https://k8s.gcr.io/v2/busybox/manifests/latest: 
                                                                                                                             dial tcp 74.125.133.82:443: connect: connection timed out

30.0.0.5 IP 주소는 외부 네트워크에 연결할 수 없으므로 외부 이미지 저장소에 연결할 수 없다. 나는 또 다른 SNAT 규칙이 필요하지만, 이번에는 30.0.0.5 IP 주소를 내 외부 네트워크에 상주하고 외부로 라우팅할 수 있는 IP 주소로 변환하기 위해서다. 이 경우 NSX-T Edge가 업링크로 사용하고 있는 IP 주소 중 하나를 선택했다(10.27.51.145).

NSX-T Manager의 NAT 섹션에 머무르면서 게이트웨이를 Tier-0 논리적 라우터로 변경한다. 그런 다음 "Add NAT Rule"를 클릭한다. 규칙의 이름을 지정하고 작업을 Reflective(NSX-T 에지 클러스터 구성이 Active/Active인 경우에만 옵션)로 유지한 다음 Source IP 주소 30.0.0.5를 입력한다. Translated 필드에서 외부 네트워크에 주소를 추가한다. 이 경우 NSX-T Edge 업링크 IP 주소 10.27.51.145 중 하나를 선택했다. 다른 모든 것은 디폴트로 남겨둘 수 있다. Save을 누른다. 이 규칙은 다음과 같이 보여야 한다.

Supervisor-SNAT.png

슈퍼바이저에 대해 Tier-0 SNAT 규칙이 설정된 후, Busybox PodVM의 배포를 재시도할 수 있다. 이 작업은 이제 성공해야 한다(메시지에 대해 오른쪽 스크롤).

Events:
  Type    Reason                        Age                            From                                                 Message
  ----    ------                        ----                           ----                                                 -------
  Normal  Scheduled                     <unknown>                      default-scheduler                                    Successfully assigned podvm-ns/ch-busybox to esxi-dell-n.rainpole.com
  Normal  Image                         <invalid>                      image-controller                                     Image busybox-91fc8f6fc85b4a0bfe94da01c9913d8e9bcdfb96-v0 bound successfully
  Normal  SuccessfulRealizeNSXResource  <invalid> (x3 over <invalid>)  nsx-container-ncp, 421df2f065306960d445646b70afb7e8  Successfully realized NSX resource for Pod
  Normal  Pulling                       <invalid>                      kubelet, esxi-dell-n.rainpole.com                    Waiting for Image podvm-ns/busybox-91fc8f6fc85b4a0bfe94da01c9913d8e9bcdfb96-v0
  Normal  Pulled                        <invalid>                      kubelet, esxi-dell-n.rainpole.com                    Image podvm-ns/busybox-91fc8f6fc85b4a0bfe94da01c9913d8e9bcdfb96-v0 is ready

이제 Supervisor 클러스터가 외부 이미지 저장소에서 이미지를 성공적으로 끌어낼 수 있게 되었으니, TKG 클러스터로 관심을 돌리고 외부 저장소에서 이미지를 풀(pull)할 수 있도록 합자.

3. TKG 클러스터 노드에 대한 Tier-0 SNAT 규칙 추가

슈퍼바이저 제어기처럼 Tanzu Kubernetes 클러스터의 네트워크 토폴로지를 먼저 검토해보자. 자체 Tier-1 논리적 라우터(vnet-domain-c8)를 가지고 있으며, 이는 슈퍼바이저 제어부 VM과 동일한 Tier-0 논리적 라우터에 차례로 연결되어 있음을 알 수 있다.

TKG-topology.png

NSX-T 3.0에서 SNAT를 사용하기 전에 이 TKG 클러스터의 외부 리포지토리에서 이미지를 사용하여 컨테이너형 애플리케이션(Pod)을 생성하려고 하면 어떻게 되는지 살펴본다(메시지 오른쪽 스크롤). 다시, 외부 리포지토리에서 이미지를 끄집어내려고 할 때 슈퍼바이저에서 본 것과 유사한 시간 초과 메시지가 또 보인다.

Events:
  Type     Reason     Age                            From                                                      Message
  ----     ------     ----                           ----                                                      -------
  Normal   Scheduled  <unknown>                      default-scheduler                                         Successfully assigned default/ch-busybox to ch-tkg-cluster01-workers-lwnf7-7988497879-h6cwg
  Normal   BackOff    <invalid>                      kubelet, ch-tkg-cluster01-workers-lwnf7-7988497879-h6cwg  Back-off pulling image "k8s.gcr.io/busybox"
  Warning  Failed     <invalid>                      kubelet, ch-tkg-cluster01-workers-lwnf7-7988497879-h6cwg  Error: ImagePullBackOff
  Normal   Pulling    <invalid> (x2 over <invalid>)  kubelet, ch-tkg-cluster01-workers-lwnf7-7988497879-h6cwg  Pulling image "k8s.gcr.io/busybox"
  Warning  Failed     <invalid> (x2 over <invalid>)  kubelet, ch-tkg-cluster01-workers-lwnf7-7988497879-h6cwg  Failed to pull image "k8s.gcr.io/busybox": rpc error: code = Unknown desc = Error response 
                                                     from daemon: Get https://k8s.gcr.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
  Warning  Failed     <invalid> (x2 over <invalid>)  kubelet, ch-tkg-cluster01-workers-lwnf7-7988497879-h6cwg  Error: ErrImagePull

앞서와 비슷한 상황에 처해 있다. TKG 클러스터의 포드들이 외부 네트워크와 통신할 수 있도록 Tier-0 논리적 라우터에 다른 SNAT 규칙을 추가해야 한다. TKG 클러스터가 만들어졌을 때, 여기서 볼 수 있듯이, 이미 Tier-1 논리적 라우터에서 SNAT를 받았다. TKG 노드에서 사용하는 주소에 대해 변환된 IP 주소는 30.0.0.16이다.

T1-TKG-SNAT-rule.png

이전과 마찬가지로 Tier-0 논리적 라우터로 다시 이동하고 이전과 마찬가지로 새 SNAT 규칙을 추가하십시오. 그러나 이번에는 다른 NSX-T Edge 업링크 IP 주소(10.27.51.147)의 IP 주소를 번역에 사용할 것이다.

T0-TKG-SNAT-rule.png

이제 TKG 클러스터에서 새로운 Pod를 생성하면 외부 저장소에서 이미지를 끌어오는 데 성공하게 된다.

Events:
  Type    Reason     Age        From                                                      Message
  ----    ------     ----       ----                                                      -------
  Normal  Scheduled  <unknown>  default-scheduler                                         Successfully assigned default/ch-busybox to ch-tkg-cluster01-workers-lwnf7-7988497879-xzd8h
  Normal  Pulling    <invalid>  kubelet, ch-tkg-cluster01-workers-lwnf7-7988497879-xzd8h  Pulling image "k8s.gcr.io/busybox"
  Normal  Pulled     <invalid>  kubelet, ch-tkg-cluster01-workers-lwnf7-7988497879-xzd8h  Successfully pulled image "k8s.gcr.io/busybox"
  Normal  Created    <invalid>  kubelet, ch-tkg-cluster01-workers-lwnf7-7988497879-xzd8h  Created container busybox
  Normal  Started    <invalid>  kubelet, ch-tkg-cluster01-workers-lwnf7-7988497879-xzd8h  Started container busybox

이때 클러스터 외부에 상주하는 이미지를 TKG 클러스터의 컨테이너에 성공적으로 배포할 수 있다. 업스트림 라우터에 대한 액세스 권한이 없거나 BGP를 사용하지 않으려는 간단한 랩을 실행 중인 경우, 간략한 단계를 통해 vSphere with Kubernetes를 시작하고 실행한다.

4. 기타 이미지 풀(pull) 문제 – DNS

외부 리포지토리에서 이미지를 성공적으로 가져오지 못할 수 있는 다른 문제를 해결하고 싶었는데, 이때 DNS가 제대로 작동하지 않는 경우였습니다. 이제 포드에서는 k8s.gcr.io 등의 호스트 이름을 확인해야 한다. 따라서 vSphere with Kubernetes 배포 시 제공한 DNS 서버에 액세스해야 한다. 이러한 요청은 송신 IP 주소 범위(내 경우 30.0.0.x)에 나타나기 때문에 DNS 서버에 정적 경로를 추가하여 이 네트워크로부터의 요청에 응답하는 방법을 알아야 했다. 이 정적 경로를 추가하기 전에 이미지 꺼내기가 다음과 같이 실패하고 있었다(메시지 오른쪽 스크롤).

Events:
  Type     Reason          Age        From                                                      Message
  ----     ------          ----       ----                                                      -------
  Normal   Scheduled       <unknown>  default-scheduler                                         Successfully assigned default/ch-busybox to ch-tkg-cluster01-workers-kjbtn-54b75dd4d7-mllkf
  Normal   Pulling         <invalid>  kubelet, ch-tkg-cluster01-workers-kjbtn-54b75dd4d7-mllkf  Pulling image "k8s.gcr.io/busybox"
  Warning  Failed          <invalid>  kubelet, ch-tkg-cluster01-workers-kjbtn-54b75dd4d7-mllkf  Failed to pull image "k8s.gcr.io/busybox": rpc error: code = Unknown desc = Error response 
                                                                                                from daemon: Get https://k8s.gcr.io/v2/: dial tcp: lookup k8s.gcr.io on 127.0.0.53:53: read 
                                                                                                udp 127.0.0.1:54821->127.0.0.53:53:i/o timeout
  Warning  Failed          <invalid>  kubelet, ch-tkg-cluster01-workers-kjbtn-54b75dd4d7-mllkf  Error: ErrImagePull

위의 내용은 외부 리포지토리에 접근할 수 없는 것이 아니라 조회 실패라는 점에 유의하십시오. 이 문제 역시 나를 사로잡았으니, 문제를 해결하기 전에 kubectl describe pod 출력을 설명하는 데 실패한 이유를 주의 깊게 읽어보기 바란다.

마지막 감사 인사 – 소피아 사무소의 Ianislav Trendafilov에게 다시 한 번 감사드리며, 그는 항상 나의 NSX-T 관련 질문에 대답해 주었다.