Kubernetes

Calico 설치 및 Mode 변경

Operation CWAL 2021. 1. 29. 22:06

Calico 설치

본 설치는 50개 이하 Node로 구성된 on-prem K8s 클러스터에 적합한 방식이며, 그외에는 Calico 공식 홈페이지를 참고하도록 하자.

 

테스트 환경은 Master 1개, Worker 2개로 이루어진 간단한 Cluster이며, 각 Node의 IP와 Pod CIDR은 다음과 같다.

  • master: 172.30.1.42
  • worker-1: 172.30.1.45
  • worker-2: 172.30.1.29
  • Pod CIDR: 192.168.0.0/16

 

1. Manifest 다운로드

Manifest 파일은 아래 명령어를 통해 Download 하도록 하자. 해당 파일을 종종 수정해야 할 일이 생기므로, 매번 인터넷에서 가져오는 것보다 직접 갖고 있는 편이 좋다.

curl https://docs.projectcalico.org/archive/v3.17/manifests/calico.yaml -O

2. Pod CIDR 수정

K8s인 경우, 자동으로 Pod CIDR를 감지하기 때문에 이 과정은 생략한다. 다른 CO(ex: Mesos) 라면 calico.yaml 파일에서 CALICO_IPV4POOL_CIDR 변수의 주석 제거 후, 정확한 값을 입력할 것.

 

3. Manifest 파일 적용

kubectl apply -f calico.yaml

 

calicoctl 설치

calico 설정 변경은 k8s에서 직접 수행하는 대신, 전용 tool인 'calicoctl'을 사용하는 것이 일반적이다.

다양한 설치 방법(binary, docker, k8s pod 등)이 존재하며, 여기선 binary를 다운로드하여 설치하는 방법으로 진행한다.

 

# 현재 경로에 calicoctl binary 다운로드
curl -O -L  https://github.com/projectcalico/calicoctl/releases/download/v3.17.1/calicoctl

# +x 모드 추가 
chmod +x calicoctl

# 아무 경로에서 사용 가능하도록 PATH에 등록된 곳(ex: /usr/local/bin)으로 파일 이동
sudo mv calicoctl /usr/local/bin

 

Calico Routing Options

Calico는 public cloud, on-prem, baremetal 등과 같이 다양한 K8s 환경의 Container Networking을 지원하기 위해 다음 3개의 Mode를 제공한다.

 

Direct (Non-overlay)

같은 L2 네트워크(ex: Switch)로 연결된 노드로 이루어진 K8s 클러스터의 경우, 별도의 Tunneling 없이 BGP Route만으로 Container Networking이 가능하다. Encapsulation을 사용하지 않고 순전히 Routing Table을 통해 Pod에서 Pod으로 패킷 전송이 이루어진다. 가장 성능이 뛰어나지만, Subnet이 다른 경우엔 사용하기 어려운 단점이 있다.

 

아래 설정을 통해 사용할 수 있다.

1. ippool manifest 파일 가져오기

calicoctl get ippool default-ipv4-ippool -o yaml > calico-ipool.yaml

2. ippool manifest 수정

apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
  name: default-ipv4-ippool
spec:
  blockSize: 26
  cidr: 192.168.0.0/16
  ipipMode: Never
  natOutgoing: true
  nodeSelector: all()
  vxlanMode: Never

.spec.ipipMode를 'Never'로 변경시, Direct Mode가 활성화된다. 이와 동시에 불필요한 필드(ex: uid)도 같이 제거해준다.

 

3. ippool manifest 적용

calicoctl apply -f calico-ipool.yaml

 

Routing Table을 확인할 경우, 다음과 같은 사실을 알 수 있다.

 

  • Host 안에 존재하는 Pod의 IP(ex: 192.168.219.74)는 각 veth 인터페이스 사용
  • 192.168.226.65~192.168.226.127는 Host 인터페이스(enp0s3)를 통해 worker-1(172.30.1.45)로 전송
  • 192.168.133.193~192.168.133.254는 Host 인터페이스(enp0s3)를 통해 worker-2(172.30.1.29)로 전송

실제 Packet은 어떻게 전송되는지, worker-1의 Pod에서 worker-2의 Pod으로 트래픽을 발생시켜 보자.

worker-1의 Pod(192.168.226.67)
worker-2의 Pod(192.168.133.196)

worker-2의 Pod은 80번 포트를 열어 놓은 상태로 대기하며, worker-1에서 curl을 통해 HTTP Request를 전달한다.

Wireshark를 사용한 Packet sniffing

worker-2의 enps03 인터페이스를 통해 전달받은 패킷 내용은 위와 같다.  Src/Dst 모두 별도의 NAT이나 Packet Encapsulation없이 Pod IP로만 전달되며, Host Network는 VRF(Virtual Routing and Forwading)만 수행한다.

IP-in-IP(ipip)

Calico 설치시 기본으로 제공하는 옵션이며, IP-in-IP 프로토콜을 통한 Tunneling으로 Overlay Network 망을 구성한다. Pod에서 전송한 Original Packet(L3)은 Host Network의 Outer Packet에 포장되어 Target Pod이 위치한 Node로 전송된다. Pod이 어떤 Node에 위치하는지 알고 있어야 하므로, BGP를 사용한다. Tunneling 기법을 사용한 기술임에도 불구하고, 구조나 메커니즘이 단순하여 이해하기 쉬운 편이다. 하지만 Multicast를 지원하지 않는 등의 약점 또한 가지고 있다.

 

Direct 모드에서 설정한 것과 반대로 수행하여 적용할 수 있다.

 

1. ippool manifest 수정

apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
  name: default-ipv4-ippool
spec:
  blockSize: 26
  cidr: 192.168.0.0/16
  ipipMode: Always
  natOutgoing: true
  nodeSelector: all()
  vxlanMode: Never

.spec.ipipMode를 'Always'로 변경하여, ipip 모드를 활성화한다.

 

2. ippool manifest 적용

calicoctl apply -f calico-ipool.yaml

Routing Table을 확인하여, 다음과 같은 내용이 변경되었음을 알 수 있다.

 

  • Host 안에 존재하는 Pod의 IP(ex: 192.168.219.74)는 각 veth 인터페이스 사용
  • 192.168.226.65~192.168.226.127는 tunl0 인터페이스를 통해, worker-1(172.30.1.45)로 전송
  • 192.168.133.193~192.168.133.254는 tunl0 인터페이스를 통해, worker-2(172.30.1.29)로 전송

worker-1의 Pod에서 worker-2의 Pod으로 트래픽을 발생시켜보자.

worker-1의 Pod(192.168.226.67)

 

worker-2의 Pod(192.168.133.196)

이전 테스트와 마찬가지로 worker-2의 Pod은 80번 포트를 열어 놓은 상태로 대기하며, worker-1에서 curl을 통해 HTTP Request를 전달한다.

 

Wireshark를 사용한 Packet sniffing

IP 패킷 내에 또 다른 IP 패킷이 존재함을 알 수 있다. Outer Packet의 경우, 각 Node IP가 Src/Dst로 지정되었으며, Inner Packet의 경우, 실제 Pod IP가 Src/Dst로 설정되었다. 한가지 재밌는 점은, Outer Packet의 IP Header를 확인해보면 아래와 같이 IPIP(프로토콜 #4)가 명시되어 있다는 사실이다. 

Azure 등 일부 Public Cloud의 경우, IPIP 프로토콜을 지원하지 않기 때문에 이 모드를 사용할 수 없는 것으로 알려져 있다.

VXLAN

기존 Canal 프로젝트(Flannel + Calico)에서 제공하던 모드였으나, Calico 3.7 이후부터 Flannel에서 구현한 VXLAN 모드를 차용하여 자체적으로 제공하고 있다. Original Ethernet Frame(L2)은 VXLAN 디바이스를 통해 Host Network의 UDP 패킷으로 포장되어 Target Pod이 위치한 Node로 전송된다. 이 과정에서 두 Pod 사이의 가상의 LAN이 존재하는 것과 같이 동작한다. 해당 모드는 BGP를 사용하지 않는다.

최초 설치인 경우는 다음과 같이 Manifest 파일을 수정한다. 

 

1. Calico Manifest 수정

 

변경 전 변경
calico_backend: "bird" -> "vxlan" calico_backend: "vxlan"
-name: CALICO_IPV4POOL_IPIP
 value: "Always"
-name: CALICO_IPV4POOL_IPIP
 value: "Never"
-name: CALICO_IPV4POOL_VXLAN
 value: "Never"
-name: CALICO_IPV4POOL_VXLAN
 value: "Always"
- -bird-live 삭제
- -bird-ready 삭제

BGP Route를 사용하지 않기 때문에 Calico에서 BGP Client로 사용하는 'bird' 역시 비활성화해야 한다.

 

2. Calico Manifest 적용

kubectl apply -f calico.yaml

worker-1의 VXLAN 인터페이스
worker-2의 VXLAN 인터페이스

  • Host 안에 존재하는 Pod의 IP(ex: 192.168.219.74)는 각 veth 인터페이스 사용
  • 192.168.226.65~192.168.226.127는 vxlan 인터페이스를 통해, worker-1의 vxlan으로 전송
  • 192.168.133.193~192.168.133.254는 vxlan 인터페이스를 통해, worker-2의 vxlan으로 전송
참고. 이미 IPIP모드로 설치되어 IP Pool이 생성된 시점에선 위 방식은 아무 효과가 없으므로 calicoctl을 사용하여 설정을 변경해야 한다. 그리고 기존 생성된 Pod의 경우, Network 설정이 충돌하여 다른 Pod으로 패킷이 전송되지 않는 문제가 발생할 수 있으니 유의할 것.

vxlan 모드를 사용하기 위한 IPPool Manifest

다음과 같이 worker-1의 Pod에서 worker-2의 Pod으로 트래픽을 발생시켜보자.

Packet Sniffing

Underlying Network를 통해 전달받은 패킷의 UDP Datagram 안에 실제 Pod으로 보내는 Ethernet Frame이 들어있음을 확인할 수 있다. 또한 해당 프레임의 Src/Dst MAC 주소엔 각자 Host에 생성된 VXLAN 디바이스가 지정되어 있다. 이를 통해 각 Pod이 가상의 L2 Network 위에 연결된 것과 같이 동작한다.

worker-1 vxlan의 MAC 주소

 

worker-2 vxlan의 MAC 주소

 

결론

Calico 설치와 다양한 Routing 모드에 대해 살펴보았다. 각 상황에 맞는 모드를 선택할 수 있고, 그 장단점을 이해하고 있다면 클러스터의 전반적인 네트워크 성능 개선과 트러블슈팅에 큰 도움이 줄 수 있다. CNI 플러그인은 Kubernetes의 보이지 않는 영역에서 가장 중요한 일을 하는 Component 중 하나이므로, 이를 적게나마 알고 있어야 K8s가 어떻게 돌아가는지 이해할 수 있다.

창피한 이야기지만 필자는 예전 프로젝트에 처음으로 K8s 클러스터를 구축하던 시절, 이런 차이점을 전혀 모르고 있는 상태에서 가이드 내용 그대로 CNI 플러그인을 설치했다. 시간이 꽤 지나고 나서 누군가에게 왜 네트워크를 이렇게 구성했는지에 대해 질문을 받았을 때, 제대로 답을 하지 못해 큰 망신을 당한 적이 있는데 부디 이 글을 읽는 여러분은 이러한 실수를 반복하지 않길 바란다.

 

 

 

참고
Install calicoctl
Configure Networking - Project Calico
Calico Routing Modes - octetz

'Kubernetes' 카테고리의 다른 글

ETCD Encryption  (0) 2021.04.21
Imperative Vs. Declarative  (0) 2021.04.08
Container Runtime과 Docker  (0) 2021.03.09
Calico IPAM  (0) 2021.01.31
StatefulSet  (0) 2021.01.25