본문 바로가기

study/KANS 3기

KANS 3기 3주차 두번째

Calico 네트워크 모드

- Calico다양한 네트워크 통신 방법(모드)를 제공합니다.

- CalicoCilium 에서 파드 혹은 네임스페이스의 레벨에서 IN/OUT 트래픽에 대한 통제가 가능합니다.

 

Calico 라우팅 모드

 

 

 

 

Direct 모드

파드 통신 패킷이 출발지 노드의 라우팅 정보를 보고 목적지 노드로 원본 패킷 그대로 전달합니다

 

 

클라우드 사업자 네트워크의 경우 NIC 에 매칭되지 않는 IP 패킷은 차단되니, NIC에 Source/Destination Check 기능을 Disable 해야 합니다 - 링크

# AWS CLI 로 특정 인스턴스의 Source/Destination Check 기능을 Disable 하기
aws ec2 modify-instance-attribute --instance-id <INSTANCE_ID> --source-dest-check "{\"Value\": false}"

 

 

 

 

Direct 모드 설정

-Direct 모드 설정 및 확인

# 모드 정보 확인 : IPIPMODE 가 Never 로 변경!
calicoctl get ippool -o wide
NAME                  CIDR            NAT    IPIPMODE   VXLANMODE   DISABLED   SELECTOR
default-ipv4-ippool   172.16.0.0/16   true   Always     Never       false      all()

# (옵션) 모니터링
watch -d "route -n | egrep '(Destination|UG)'"

# 설정
calicoctl get ippool default-ipv4-ippool -o yaml
calicoctl get ippool default-ipv4-ippool -o yaml | sed -e "s/ipipMode: Always/ipipMode: Never/" | calicoctl apply -f -

# 모드 정보 확인 : IPIPMODE 가 Never 로 변경!
calicoctl get ippool -o wide
root@k8s-m:~/yaml# calicoctl get ippool -o wide
NAME                  CIDR            NAT    IPIPMODE   VXLANMODE   DISABLED   SELECTOR
default-ipv4-ippool   172.16.0.0/16   true   Never      Never       false      all()

# BGP 로 전달 받은 파드 네트워크 대역이 호스트 라우팅 테이블에 적용되었는지 확인 : Iface 가 tunl0 에서 enp0s8 로 변경!
route -n | egrep '(Destination|UG)'
root@k8s-w1:~# route -n | egrep '(Destination|UG)'
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
172.16.29.0     192.168.100.10  255.255.255.192 UG    0      0        0 enp0s8
172.16.46.0     192.168.100.102 255.255.255.192 UG    0      0        0 enp0s8
172.16.197.0    192.168.100.103 255.255.255.192 UG    0      0        0 enp0s8

 


동작 확인

파드 생성

# 파드 생성
curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/5/node3-pod3.yaml
kubectl apply -f node3-pod3.yaml

# 파드 IP 정보 확인
kubectl get pod -o wide
calicoctl get wep

 

파드간 ping 통신 실행 및 패킷 캡쳐 확인

# 파드 Shell 접속(zsh)
kubectl exec -it pod1 -- zsh
## 파드 Shell 에서 아래 입력
ping <pod2 혹은 pod3 IP>

# 파드가 동작하는 노드의 eth0(예시)에서 패킷 덤프
tcpdump -i <eth0> -nn icmp
tcpdump -i ens5 -nn icmp
혹은 아래 처럼 파일로 저장 후 해당 파일을 다운받아서 확인(wireshark 등 사용)
tcpdump -i <eth0> icmp -w /tmp/calico-direct.pcap
tcpdump -i ens5 icmp -w /tmp/calico-direct.pcap

 

 

!!워커노드1(파드)워커노드2(파드) or 워커노드0(파드)통신 확인해보자! 되는 경우 어떻게 되는 걸까? 안되는 경우는 왜일까? ⇒ Overlay 네트워크 기법이 필요한 이유!

 

 

파드 삭제

kubectl delete -f node3-pod3.yaml

 

 

 

CrossSubnet 모드

노드 간 같은 네트워크 대역(Direct 모드로 동작) , 노드 간 다른 네트워크 대역(IPIP 모드로 동작)

# CrossSubnet 모드 설정
calicoctl patch ippool default-ipv4-ippool -p '{"spec":{"ipipMode":"CrossSubnet"}}'
calicoctl get ippool default-ipv4-ippool -o yaml | sed -e "s/ipipMode: Never/ipipMode: CrossSubnet/" | calicoctl apply -f -

# 모드 확인
calicoctl get ippool -o wide
NAME                  CIDR            NAT    IPIPMODE      VXLANMODE   DISABLED   SELECTOR
default-ipv4-ippool   172.16.0.0/16   true   CrossSubnet   Never       false      all()

# 파드 생성
kubectl apply -f node3-pod3.yaml
calicoctl get wep

# 호스트 라우팅 정보 확인
route -n | grep UG
root@ip-172-20-63-146:~# route -n | grep UG
100.105.79.128  172.20.61.184   255.255.255.192 UG    0      0        0 ens5  # 노드간 같은 네트워크 대역 - Direct 모드
100.125.78.64   172.20.59.153   255.255.255.192 UG    0      0        0 ens5  # 노드간 같은 네트워크 대역 - Direct 모드
100.127.64.128  172.20.64.181   255.255.255.192 UG    0      0        0 tunl0 # 노드간 다른 네트워크 대역 - IPIP 모드

# 파드 Shell 접속(zsh)
kubectl exec -it pod1 -- zsh
## 파드 Shell 에서 아래 입력
ping <pod2 혹은 pod3 IP>

 

파드 삭제

kubectl delete -f node3-pod3.yaml

 

 

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

WireGuard 소개 한글 분석

 

WireGuard VPN 해부

WireGuard VPN 동작 원리 분석

slowbootkernelhacks.blogspot.com

 

- WireGuard는 구닥다리 IPsec 및 OpenVPN의 대항마로 등장한 open source VPN project 이며 작년, Linux 5.6 커널에 WireGuard 1.0.0 기본 패키지로 탑재되었다.

- 정말 간결한 코드 구조빠른 성능 (모든 것이 kernel에서 동작하고, 주요 암호 알고리즘에 대해서 병렬처리하므로써 빠른 속도를 자랑함)

 

 

노드에 WireGuard 설치 - 링크 ← 이미 설치되어 있음

 

Installation - WireGuard

Installation Windows [7, 8.1, 10, 11, 2008R2, 2012R2, 2016, 2019, 2022] Download Windows Installer Browse MSIs Download from App Store $ sudo apt install wireguard Android [play store & direct apk file] Download from Play Store Download APK File Download f

www.wireguard.com

# 설치
apt install wireguard -y

# WireGuard 버전 확인
wg version

 

WireGuard 설정 및 확인

# 설정
calicoctl get felixconfiguration -o yaml
calicoctl patch felixconfiguration default --type='merge' -p '{"spec":{"wireguardEnabled":true}}'

# 확인
calicoctl get felixconfiguration default -o yaml | grep wireguardEnabled
root@k8s-m:~/yaml# calicoctl get felixconfiguration default -o yaml | grep wireguardEnabled
  wireguardEnabled: true

calicoctl get node -o yaml | grep wireguardPublicKey
calicoctl get node <노드 Name> -o yaml | grep wireguardPublicKey
root@k8s-m:~/yaml# calicoctl get node k8s-w1 -o yaml | grep wireguardPublicKey
  wireguardPublicKey: BToK9bLEhMaPUJsuKy3KdrxVOpklyo0qlGRdMN6lHWc=

# wireguard.cali 인터페이스 확인
ip -c -d addr show wireguard.cali
root@k8s-w1:~# ip -c -d addr show wireguard.cali
12: wireguard.cali: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1440 qdisc noqueue state UNKNOWN group default qlen 1000
    link/none  promiscuity 0 minmtu 0 maxmtu 2147483552
    wireguard numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
    inet 172.16.228.74/32 scope global wireguard.cali
       valid_lft forever preferred_lft forever

ifconfig wireguard.cali
root@k8s-w1:~# ifconfig wireguard.cali
wireguard.cali: flags=209<UP,POINTOPOINT,RUNNING,NOARP>  mtu 1440
        inet 172.16.228.69  netmask 255.255.255.255  destination 172.16.228.69
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 1000  (UNSPEC)

# wireguard.cali 설정 확인 : 통신 포트, Peer/Endpoint 정보, 패킷 암호화를 위한 공개키/사설키 정보
wg showconf wireguard.cali
root@k8s-w1:~# wg showconf wireguard.cali
[Interface]
ListenPort = 51820
FwMark = 0x100000
PrivateKey = AIgTihI2p4icwVMR4sIvuVaSqwKlkxMImQp4A/Gm+Gg=

[Peer]
PublicKey = BToK9bLEhMaPUJsuKy3KdrxVOpklyo0qlGRdMN6lHWc=
AllowedIPs = 172.16.228.64/26, 172.16.228.69/32, 172.16.228.67/32
Endpoint = 192.168.100.101:51820

[Peer]
PublicKey = 9TCD8hG6SLutZSOZSzQeqj6O0icJAxA3RPIipcBKBxs=
AllowedIPs = 172.16.197.0/26, 172.16.197.3/32, 172.16.197.5/32
Endpoint = 192.168.100.103:51820

[Peer]
PublicKey = Ercb/0pNZ+I1ELOkiXlWbZA9J0Fjt7XqsstDH4GhNmI=
AllowedIPs = 172.16.46.3/32, 172.16.46.0/26, 172.16.46.5/32
Endpoint = 192.168.100.102:51820

# Peer 의 정보(고유한 index)
wg show
interface: wireguard.cali
  public key: 8TNaYyzzc1N4SHfqE+Y5b4rMBKX/lqPe0tWO/h8sOB4=
  private key: (hidden)
  listening port: 51820
  fwmark: 0x100000

peer: 6WtZqEKSmoSKiFp20fhk/jyTcrTqf9qshyZI1HvE9Qk=
  endpoint: 192.168.10.102:51820
  allowed ips: 172.16.184.0/32, 172.16.184.0/24, 172.16.184.1/32

peer: +fOEOJgFxueIbrp709iB4F4gFRb2ny4lWKbxCNNfczM=
  endpoint: 192.168.20.100:51820
  allowed ips: 172.16.34.0/32, 172.16.34.0/24, 172.16.34.1/32

peer: d2LgXvRo4DwsyhiLXUn9TEt6D3l4pFIVlCD7KESR/m0=
  endpoint: 192.168.10.101:51820
  allowed ips: 172.16.158.0/32, 172.16.158.0/24, 172.16.158.1/32

# 키 정보 확인
wg show all public-key
wireguard.cali	8TNaYyzzc1N4SHfqE+Y5b4rMBKX/lqPe0tWO/h8sOB4=

wg show all private-key
wireguard.cali	kJbrfATGFP2v4sl+Wqg1Gv8zwFpIXshYFFD3udMDd3k=

wg show all preshared-keys
wireguard.cali	6WtZqEKSmoSKiFp20fhk/jyTcrTqf9qshyZI1HvE9Qk=	(none)
wireguard.cali	+fOEOJgFxueIbrp709iB4F4gFRb2ny4lWKbxCNNfczM=	(none)
wireguard.cali	d2LgXvRo4DwsyhiLXUn9TEt6D3l4pFIVlCD7KESR/m0=	(none)

# 그외 키타 정보
wg show all dump
wg show all endpoints
wg show all peers
wg show all transfer
wg show all persistent-keepalive

 

키 정보 확인

 

 

파드 생성

kubectl apply -f node3-pod3.yaml

 

 

파드간 ping 통신 실행 및 패킷 캡쳐 확인

# 파드 Shell 접속(zsh)
kubectl exec -it pod1 -- zsh
## 파드 Shell 에서 아래 입력
ping <pod2 혹은 pod3 IP>

# 파드가 동작하는 노드의 eth0(예시)에서 패킷 덤프
ss -unlp
tcpdump -i <eth0> -nn udp port 51820
tcpdump -i ens5 -nn udp port 51820
혹은 아래 처럼 파일로 저장 후 해당 파일을 다운받아서 확인(wireshark 등 사용)
tcpdump -i <eth0> udp port 51820 -w /tmp/calico-wireguard.pcap
tcpdump -i ens5 udp port 51820 -w /tmp/calico-wireguard.pcap

# 현재 모든 워커 노드에 tcpdump 후 ping curl 테스트 시 모든 노드에서 트래픽이 발생한다 >> 이유는 VirtualBox 에 nic2 에 "무작위 모드 : 모두 허용" 상태여서, 모든 노드로 패킷이 전달됨
# VirtualBox 에 nic2 에 "무작위 모드 : 거부"로 설정 후 테스트 하게 되면 정확하게, 출발지와 목적지의 VM에서만 패킷이 확인된다!
모드워커노드) tcpdump -i ens5 -nn udp port 51820

 

 

 

 

부가 기능

파드에 고정 IP를 직접 지정해서 배포 - Docs

 

Use a specific IP address with a pod | Calico Documentation

Specify the IP address for a pod instead of allowing Calico to automatically choose one.

docs.tigera.io

# 배포
cat <<EOF| kubectl apply -f - 
apiVersion: v1
kind: Pod
metadata:
  name: static-ip-pod
  annotations:
    "cni.projectcalico.org/ipAddrs": "[\"172.16.100.100\"]"
spec:
  containers:
  - name: static-ip-pod
    image: nicolaka/netshoot
    command: ["tail"]
    args: ["-f", "/dev/null"]
  terminationGracePeriodSeconds: 0
EOF

# 확인 : annotations 에 지정한 IP를 파드에 직접 할당 확인!
kubectl get pod static-ip-pod -o wide
NAME            READY   STATUS    RESTARTS   AGE    IP               NODE     NOMINATED NODE   READINESS GATES
static-ip-pod   1/1     Running   0          110s   172.16.100.100   k8s-w1   <none>           <none>

# 삭제
kubectl delete pod static-ip-pod

 

 

 

Floating IP 를 파드에 할당 : Add a floating IP to a pod - Docs

 

 

 

 

모니터링

Monitor Calico component metrics - Docs

 

Monitor Calico component metrics | Calico Documentation

Use open source Prometheus for monitoring and alerting on Calico components.

docs.tigera.io

 

 

Configure Calico to enable metrics reporting

# Felix configuration
calicoctl get felixconfiguration -o yaml
calicoctl patch felixconfiguration default  --patch '{"spec":{"prometheusMetricsEnabled": true}}'

# Creating a service to expose Felix metrics : Felix by default uses port 9091 TCP to publish its metrics.
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 get svc,ep -n kube-system felix-metrics-svc

# kube-controllers configuration : Prometheus metrics are enabled by default on TCP port 9094 for calico-kube-controllers
## Creating a service to expose kube-controllers metrics
calicoctl get kubecontrollersconfiguration default -o yaml
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
kubectl get svc,ep -n kube-system kube-controllers-metrics-svc

 

 

Cluster preparation

# 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

 

Install prometheus

#
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

 

 

View metrics

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

# 파드 IP metrics 엔드포인트 curl 접속 확인
curl <파드 IP>:9090/metrics
curl 172.16.34.7:9090/metrics

#
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
kubectl get svc,ep -n calico-monitoring

# 프로메테우스 접속 주소
echo -e "Prometheus URL = http://$(curl -s ipinfo.io/ip):30001"

 

 

Visualizing metrics via Grafana - Docs

 

Visualizing metrics via Grafana | Calico Documentation

Use open source Grafana for visualizing Calico components.

docs.tigera.io

# Provisioning datasource
kubectl apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
  name: grafana-config
  namespace: calico-monitoring
data:
  prometheus.yaml: |-
    {
        "apiVersion": 1,
        "datasources": [
            {
               "access":"proxy",
                "editable": true,
                "name": "calico-demo-prometheus",
                "orgId": 1,
                "type": "prometheus",
                "url": "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 - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: grafana-pod
  namespace: calico-monitoring
  labels:
    app:  grafana-pod
    role: monitoring
spec:
  nodeSelector:
    kubernetes.io/os: linux
  containers:
  - name: grafana-pod
    image: grafana/grafana:latest
    resources:
      limits:
        memory: "128Mi"
        cpu: "500m"
    volumeMounts:
    - name: grafana-config-volume
      mountPath: /etc/grafana/provisioning/datasources
    - name: grafana-dashboards-volume
      mountPath: /etc/grafana/provisioning/dashboards
    - name: grafana-storage-volume
      mountPath: /var/lib/grafana
    ports:
    - containerPort: 3000
  volumes:
  - name: grafana-storage-volume
    emptyDir: {}
  - name: grafana-config-volume
    configMap:
      name: grafana-config
  - name: grafana-dashboards-volume
    configMap:
      name: grafana-dashboards-config
EOF

#
kubectl get pod -n calico-monitoring

#
kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: grafana
  namespace: calico-monitoring
spec:
  type: NodePort
  selector:
    app:  grafana-pod
    role: monitoring
  ports:
    - protocol: TCP
      port: 3000
      targetPort: 3000
      nodePort: 30002 
EOF
kubectl get svc,ep -n calico-monitoring

# 프로메테우스 접속 주소 : 초기 계정 ( admin , admin )
echo -e "Grafana URL = http://$(curl -s ipinfo.io/ip):30002"

 

 

실습환경 삭제

# CloudFormation 스택 삭제
aws cloudformation delete-stack --stack-name mylab

# [모니터링] CloudFormation 스택 상태 : 삭제 확인
while true; do 
  date
  AWS_PAGER="" aws cloudformation list-stacks \
    --stack-status-filter CREATE_IN_PROGRESS CREATE_COMPLETE CREATE_FAILED DELETE_IN_PROGRESS DELETE_FAILED \
    --query "StackSummaries[*].{StackName:StackName, StackStatus:StackStatus}" \
    --output table
  sleep 1
done

'study > KANS 3기' 카테고리의 다른 글

KANS 3기 5주차 두번째  (0) 2024.10.04
KANS 3기 4주차  (0) 2024.09.28
KANS 3기 3주차 첫번째  (0) 2024.09.18
KANS 3기 3주차 실습환경 구축  (0) 2024.09.08
KANS 3기 2주차 두번째  (0) 2024.09.07