Cloud Tech

Calico CNI 이해

Hanhorang31 2024. 9. 20. 17:25
 

Overview

k8s CNI인 Calico를 Mac M1 환경에서 VM를 통해 배포해보고, 구성 요소를 확인하겠습니다.

 

실습 환경 구성

쿠버네티스 구성 환경은 Vagrant를 통해 Mac 에서 구성하겠습니다.

네트워크 서브넷 192.169.10.0/24, 192.168.20.0/24 두 개에 서버를 구성하여 쿠버네티스 클러스터를 구성합니다. 우측 Router 서버에 각 서브넷의 네트워크 인터페이스를 연결하여 통신이 가능하도록 구성할 예정입니다.(KANS3 스터디 참고)

 

필자 환경은 MAC M1 에서 진행했습니다. 실습 환경으로 최소 vCPU 4, 12GiB RAM이 필요합니다

 

MaC M1에서의 Vagrant 환경 구성은 sejkim님의 블로그를 참고하였습니다.

맥 환경 구성을 위한 OS, 네트워크 설정 등의 트러블슈팅이 자세히 나와있습니다.

# vagrant 설치
brew install vgrant 
brew install --cask vagrant-vmware-utility


# vagrant 파일 다운로드(mac m1)
git clone https://github.com/icebreaker70/kans-calico.git
cd kans-calico


# 구성 동작 ( 네트워크 구성을 위해 여러번 실행해야 합니다.)
vagrant up --provision

# 동작 확인
vagrant status 
  • 네트워크 구성 환경 설정으로 vagrant up --provision 명령어를 여러번 실행해야 합니다.
더보기
M1 MaC에서 인텔칩 기반의 환경 구성시 실패 공유

7.0.X 버전에서 VirtualBox 에서 Arm 기반 아키텍처 칩을 제공한다고 하여 실습 환경 구성을 시도하였으나, 호환성 문제로 안되는 것을 확인하였습니다.

아래 로그 메세지를 공유하니 참고 부탁드립니다.

A customization command failed:

["modifyvm", :id, "--groups", "/Calico-Lab"]

The following error was experienced:

#<Vagrant::Errors::VBoxManageError: There was an error while executing `VBoxManage`, a CLI used by Vagrant
for controlling VirtualBox. The command and stderr is shown below.

Command: ["modifyvm", "1c2e1327-da91-46ee-8d0a-b6c4dec72acf", "--groups", "/Calico-Lab"]

Stderr: VBoxManage: error: Could not rename the directory '/Users/hanseungho/VirtualBox VMs/Calico-k8s-m' to '/Users/hanseungho/VirtualBox VMs/Calico-Lab/Calico-k8s-m' to save the settings file (VERR_ALREADY_EXISTS)
VBoxManage: error: Details: code NS_ERROR_FAILURE (0x80004005), component SessionMachine, interface IMachine, callee nsISupports
VBoxManage: error: Context: "SaveSettings()" at line 3640 of file VBoxManageModifyVM.cpp
>

Please fix this customization and try again.

기존 VM과 설정파일이 겹쳐 생기는 오류입니다. 생성 경로로 이동하여 기존 파일을 삭제해주세요.

cd /Users/hanseungho/VirtualBox VMs
rm -rf ./*

ARM 아키텍처가 안맞는 경우 (결론)

# 컨트롤 노드 접근
vagrant ssh k8s-m

# 쿠버네티스 자원 확인
kubectl get nodes -o wide
kubectl get pods -A
kubectl get pods -v 6

# 노드 포트 서비스 접근을 위한 hosts 설정
cat <<-EOF >> /etc/hosts
## K8S
192.168.10.10  k8s-m
192.168.10.101 k8s-w1
192.168.10.102 k8s-w2
192.168.20.100 k8s-w0
## End of K8S
EOF
  • 노드 자원 확인시 Status 가 NotReady로 표시됩니다. CNI 설치가 되지 않았기 때문입니다.

Caclio CNI를 설치하겠습니다.

# Caclio CNI 설치
kubectl apply -f https://raw.githubusercontent.com/gasida/KANS/main/kans3/calico-kans.yaml

# Calico CLI 설치(linux arm64 전용 3.28.1 ) 
curl -L https://github.com/projectcalico/calico/releases/download/v3.28.1/calicoctl-linux-arm64 -o calicoctl
chmod +x calicoctl && mv calicoctl /usr/bin
calicoctl version
  • Caclio CNI 설치 구성 설정은 공식문서를 참고해주세요. 스터디에서 제공한 yaml 은 가시성으로 subnet mask를 26에서 24로 설정하였습니다.

설치를 완료하면 caclio 파드와 네트워크 자원들을 확인할 수 있습니다.

Caclio의 추가 라우터, 네트워크 인터페이스 및 Iptable 규칙들이 추가되었습니다.


# kube-ops-view 설치
helm repo add geek-cookbook https://geek-cookbook.github.io/charts/
helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set service.main.type=NodePort,service.main.ports.http.nodePort=30000 --set env.TZ="Asia/Seoul" --namespace kube-system

# 경로 확인
echo -e "KUBE-OPS-VIEW URL = http://192.168.10.10:30000/#scale=2"
http://192.168.10.10:30000/#scale=2

 

 

Calico ?

Calico는 쿠버네티스 CNI입니다. Calico CNI는 BGP 기반의 프로토콜을 통해 고성능의 네트워킹을 제공하며 온프렘 & 클라우드 적용 호환성이 높습니다. 또한, 네트워크 구성에 eBPF 비롯한 다양한 모드를 제공하며, 네트워크 정책을 통해 보안 기능도 제공합니다.

구성 컴포넌트는 크게 3가지로 구분됩니다.

  1. 칼리코 데이터베이스 저장소 : 칼리코 동작을 위한 데이터 저장소이며 쿠버네티스 API 저장소, ETCD에 저장됩니다.
  2. 칼리코 데몬셋 : 각 노드에서 동작하는 칼리코 데몬셋입니다. 데몬셋 구성 요소로 bird, feix, confd 가 구성됩니다. 네트워크 동작한 핵심 요소입니다.
  3. 칼리코 IPAM 플러그인 : 칼리코 자체의 IPAM을 통해 파드 IP 를 관리합니다. 호스트 로컬 IPAM 플러그인을 포함한 다른 많은 CNI IPAM 플러그인에 비해 IP 주소 공간 사용이 더 효율적입니다.

칼리코 데몬셋 구성요소를 확인하여 네트워크 핵심 요소를 파악하겠습니다.

칼리코 데몬셋 노드(KANS3기)
  • bird는 BGP로 각 노드에 Pod 대역 정보를 전파합니다.
  • felix는 bird로 학습한 파드 네트워크 대역을 호스트 라우팅 테이블에 적용시킵니다.
## kdd 의미는 쿠버네티스 API 를 데이터저장소로 사용 : k8s API datastore(kdd)
calicoctl version 

calicoctl node status
calicoctl node checksystem 

# ippool 정보 확인 : 클러스터가 사용하는 IP 대역 정보와 칼리코 모드 정보 확인
calicoctl get ippool -o wide

# 파드와 서비스 사용 네트워크 대역 정보 확인 
kubectl cluster-info dump | grep -m 2 -E "cluster-cidr|service-cluster-ip-range"
calicoctl get workloadEndpoint -o wide -A 

# 프로세스 확인
ps axf 

위 명령어를 통해 파드네트워크 인터페이스의 iptables rule를 확인할 수 있습니다.

# 파드별 iptables rule 확인
iptables -L -n -v
iptables -v --numeric --table filter --list cali-tw-<자신의 파드에 매핑되는 calice# 인터페이스 이름>
root@k8s-w1:~# iptables -v --numeric --table filter --list cali-tw-calice0906292e2

iptables filter 에 추가되는 정책 (예시) : 파드가 추가되면 배수의 Rule 들이 추가됩니다.

다만, 파드 개수가 많아진다면 Rule 이 많아지고 순차적으로 확인함에 따라 네트워크 성능에 영향이 있을 수 있습니다.

칼리코 데몬셋에서 birdctl 툴로 각 노드의 라우팅 정보 확인이 가능합니다.

bird> show protocol
bird> show route all
bird> show status

 

 

파드 통신 패킷 덤프 뜨기

네트워크 구성 요소를 확인하여 파드간 통신 확인 후 덤프를 뜨겠습니다.

파드간 통신에서 각 파드들은 네트워크 인터페이스를 통해 통신합니다.

  • 같은 노드간 통신시에는 tunnel 사용하지않음
# netshot 파드 두개 배포 
curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/4/node1-pod2.yaml
kubectl apply -f node1-pod2.yaml

# veth 확인
calicoctl get web -A 
ip -c addr 

# k8s-w1 에서 tcpdump
tcpdump -i calice0906292e2  -nn -w /tmp/calico-ipip.pcap 

# 파드 1에서 2로 통신
## ARP 활성화 (1) 필요, 기본 설정되어 있음
kubectl get pods -o wide 

ping -c 2 

# 덤프 PC로 가져오기
vagrant plugin install vagrant-scp
vagrant scp k8s-w1:/tmp/calico-ipip.pcap .

 

 

모니터링

칼리코 CNI에 대한 모니터링으로 프로메테우스와 그라파나를 사용하여 확인할 수 있습니다.

구성은 calico 공식 문서 와 KANS3 스터디를 참고하였습니다.

 
더보기
프로메테우스 구성

1. felix 지표 수집을 활성화합니다.

## 프로메테우스 옵션 설정
calicoctl patch felixconfiguration default  --patch '{"spec":{"prometheusMetricsEnabled": true}}'

##  프로메테우스 지표 수집을 위한 felix 서비스 생성
kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: felix-metrics-svc
  namespace: kube-system
spec:
  clusterIP: None
  selector:
    k8s-app: calico-node
  ports:
  - port: 9091
    targetPort: 9091
EOF

kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: kube-controllers-metrics-svc
  namespace: kube-system
spec:
  clusterIP: None
  selector:
    k8s-app: calico-kube-controllers
  ports:
  - port: 9094
    targetPort: 9094
EOF 

typha 파드는 규모가 작아 없으므로 제외하였습니다.

2. 지표 수집을 위한 네임스페이스 및 service role 설정

# Namespace creation
kubectl create -f -<<EOF
apiVersion: v1
kind: Namespace
metadata:
  name: calico-monitoring
  labels:
    app:  ns-calico-monitoring
    role: monitoring
EOF
kubectl get ns

# Service account creation
kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: calico-prometheus-user
rules:
- apiGroups: [""]
  resources:
  - endpoints
  - services
  - pods
  verbs: ["get", "list", "watch"]
- nonResourceURLs: ["/metrics"]
  verbs: ["get"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: calico-prometheus-user
  namespace: calico-monitoring
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: calico-prometheus-user
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: calico-prometheus-user
subjects:
- kind: ServiceAccount
  name: calico-prometheus-user
  namespace: calico-monitoring
EOF
kubectl get sa -n calico-monitoring

3. 프로메테우스 배포

kubectl apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-config
  namespace: calico-monitoring
data:
  prometheus.yml: |-
    global:
      scrape_interval:   15s
      external_labels:
        monitor: 'tutorial-monitor'
    scrape_configs:
    - job_name: 'prometheus'
      scrape_interval: 5s
      static_configs:
      - targets: ['localhost:9090']
    - job_name: 'felix_metrics'
      scrape_interval: 5s
      scheme: http
      kubernetes_sd_configs:
      - role: endpoints
      relabel_configs:
      - source_labels: [__meta_kubernetes_service_name]
        regex: felix-metrics-svc
        replacement: $1
        action: keep
    - job_name: 'felix_windows_metrics'
      scrape_interval: 5s
      scheme: http
      kubernetes_sd_configs:
      - role: endpoints
      relabel_configs:
      - source_labels: [__meta_kubernetes_service_name]
        regex: felix-windows-metrics-svc
        replacement: $1
        action: keep
    - job_name: 'typha_metrics'
      scrape_interval: 5s
      scheme: http
      kubernetes_sd_configs:
      - role: endpoints
      relabel_configs:
      - source_labels: [__meta_kubernetes_service_name]
        regex: typha-metrics-svc
        replacement: $1
        action: keep
    - job_name: 'kube_controllers_metrics'
      scrape_interval: 5s
      scheme: http
      kubernetes_sd_configs:
      - role: endpoints
      relabel_configs:
      - source_labels: [__meta_kubernetes_service_name]
        regex: kube-controllers-metrics-svc
        replacement: $1
        action: keep
EOF
kubectl get cm -n calico-monitoring prometheus-config

# Create Prometheus pod
kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: prometheus-pod
  namespace: calico-monitoring
  labels:
    app: prometheus-pod
    role: monitoring
spec:
  nodeSelector:
    kubernetes.io/os: linux
  serviceAccountName: calico-prometheus-user
  containers:
  - name: prometheus-pod
    image: prom/prometheus
    resources:
      limits:
        memory: "128Mi"
        cpu: "500m"
    volumeMounts:
    - name: config-volume
      mountPath: /etc/prometheus/prometheus.yml
      subPath: prometheus.yml
    ports:
    - containerPort: 9090
  volumes:
  - name: config-volume
    configMap:
      name: prometheus-config
EOF
kubectl get pods prometheus-pod -n calico-monitoring -owide
  • 프로메테우스 configmap 내 felix_metrics , kube_controllers_metrics 지표 수집을 활성화합니다. prometheus-operator 설치시 위 스크립트만 추가하면 됩니다.

4. 프로메테우스 지표 확인

# 파드 IP 확인
kubectl get pods prometheus-pod -n calico-monitoring -owide

# 프로메테우스 서비스 배포
kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: prometheus-dashboard-svc
  namespace: calico-monitoring
spec:
  type: NodePort
  selector:
    app: prometheus-pod
    role: monitoring
  ports:
    - protocol: TCP
      port: 9090
      targetPort: 9090
      nodePort: 30001 
EOF

# 프로메테우스 접속 주소
echo -e "Prometheus URL = http://192.168.10.10:30001"

 

더보기
그라파나 대시보드 구성
# Provisioning datasource
kubectl apply -f - <http://prometheus-dashboard-svc.calico-monitoring.svc:9090",
                "version": 1
            }
        ]
    }
EOF
kubectl get cm -n calico-monitoring

# Provisioning Calico dashboards : Here you will create a configmap with Felix and Typha dashboards.
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.1/manifests/grafana-dashboards.yaml

# Creating Grafana pod
kubectl apply -f - <
  • 그라파나가 프로메테우스 서비스에서 지표를 수집합니다. 대시보드는 Configmap에서 정의한 대시보드를 토대로 구성합니다.

felix 는 호스트 네트워크 라우터 및 iptables를 관리합니다. felix 관련 지표로 각 노드에서 호스트 네트워크에 정책 반영하시는 시간 및 오류에 대한 지표를 확인할 수 있습니다.

지표
설명
Felix cluster policies
각 노드에 적용된 Felix 클러스터 정책 수를 나타냅니다.
iptables save errors
iptables 규칙 저장 중 발생한 오류입니다.
ipset errors
ipset 명령어 실행 중 발생한 오류입니다.
iptables restore errors
iptables 규칙 복원 중 발생한 오류입니다.
Felix log errors
Felix 로그에서 발생한 오류입니다.
Felix resync started
Felix 재동기화가 시작된 횟수입니다.
Felix dropped logs
Felix가 삭제한 로그 수를 보여줍니다.
Dataplane apply time quantile (0.5, 0.9, 0.99)
정책 적용 시간을 백분위로 나누어 표시합니다. (중간 및 상위 99%)
Route table list seconds quantile (0.5, 0.9)
라우팅 테이블을 가져오는 데 걸린 시간을 백분위로 나누어 표시합니다.
Errors plot
특정 시간대에 발생한 오류를 시각화한 그래프입니다.
Felix dropped logs
Felix가 기록에서 삭제한 로그 수를 나타냅니다.

 

 

운영 최적 옵션 설정

AWS VPC에서 Calico 활용 방안

AWS 클라우드에서는 VPC CNI 를 통해 EKS 네트워크를 관리합니다. VPC CNI가 구성된 상태로 calio CNI를 사용해야하는 이유로는 네트워크 보안 정책이 있는 데(아래 표), EKS 1.25 버전 이상 부터 EKS 클러스터에서 네트워크 보안 정책을 제공하므로 그 이점이 없어졌습니다.

또한, VPC에서 포드 IP 고갈 이나, 노드 당 지원하는 최대 포드 수가 충분하지 않은 경우에 검토 대상이 될 수 있다고 합니다. 다만 VPC 세컨더리 IP prefix 설정으로 IP 부족 문제를 해결 할 수 있기에 특별한 이점이 없는 한 calico CNI를 도입하는 것은 꺼려질 것으로 예상됩니다.

MTU 설정

MTU 는 최대 전송 단위(MTU)입니다. MTU를 늘리면 성능이 향상되고, MTU가 너무 높을 경우 낮추면 패킷 손실 및 조각화 문제를 해결할 수 있습니다. 기본 네트워크에 가장 적합하도록 Calico의 MTU를 구성하여 네트워크 최적화를 할 수 있습니다.

calio 에서는 오버레이 모드에 따라 헤더 값이 달라집니다.

설정 네트워크 대역 값에서 오버레이 헤더 값을 제외하고 설정하는 것을 권고하고 있습니다.

MTU 설정은 calio-config 수정으로 설정할 수 있습니다.

kubectl patch configmap/calico-config -n kube-system --type merge \
  -p '{"data":{"veth_mtu": "1440"}}'