Kubernetes Network & Cilium

작성자: @asbubam
 
이 문서는 Open Container Korea 슬랙에서 Infra에 관심있는 분들과 스터디를 진행하면서 `Kubernetes Network & Cilium` 이란 주제로 발표했던 내용을 정리한 문서입니다. 대부분 영상 북마크는, 클릭하면 해당 스크린샷을 찍은 위치로 이동합니다. 이런 형태로 영상을 스크린샷 찍어 문서로 공유하는 것이 문제가 된다면 노션 코멘트나 @asbubam 으로 연락 부탁드립니다. Cilium에 대해서 깊게 파보자! 라는 처음 생각과는 달리 Kubernetes Network 그리고 Cilium에 대해서 공부하는 과정, 참고한 자료를 나열하는 수준의 문서에 그쳤지만... 같은 주제에 관심을 가진 누군가에게 도움이 되었으면 하는 마음에서 문서를 공유합니다.
 
K8s 클러스터를 구성할 때 Network Plugin은 주로 Calico 를 사용했다. 제일 처음 클러스터를 만들 때는 Weave Net을 사용했었는데 운영 중에 원인 모를 네트워크 이슈가 있었고, CNI 를 Calico로 바꾼 것 만으로 문제가 재발하지 않아서 이후에는 Calico를 쭉 써왔다.
그러던 중 Cilium 을 알게 되었고, Bear 에 검색해보니, Cloud Native 행사에서 아래와 같이 정리한 메모가 발견된 걸 보면 대규모 클러스터를 운영하는 카카오, 라인도 쓴다고 하니까 관심을 갖게 된 것 같다.
* 솔루션 업체들은 대부분 calico 를 사용하고 카카오, 라인은 Cilium 을 사용함 * Cilium이 리눅스 커널의 BPF기술을 사용해서 좀 더 성능이 좋은 것으로 알고 있음.
2018.10 Cilium을 처음 사용해본 기억2018.10 Cilium을 처음 사용해본 기억
2018.10 Cilium을 처음 사용해본 기억
Cilium을 사용하기 위해서는 Etcd 버전을 3.1.0 이상으로, 베이스 이미지의 커널버전을 특정 버전(≥4.9) 이상으로 올려야 했다. 이 때, 한번 클러스터에 올려보고 이후에는 괜히 잘 알지도 못하는 거 멋있다고 쓰지말자고 생각해서 왠지 모르게 안정감 느껴지는 Calico를 계속 사용했다.
 
그리고 쭉 관심만 가지고 있었는데...
 
2년동안 공부는 안하고 링크만 공유하다가, 이번 인프라스터디 때 CNCF 프로젝트 골라 발표하기 코너에서
"이제는 정말 공부해야지." 싶어서 Cilium을 발표한다고 써냈다. 내가 왜 그랬을까?
 
서론이 길었다.

Network Plugin

앞에서 Cilium은 Network Plugin 중 하나라고 했는데, Network Plugin은 뭘까?
Network Plugin을 위해서는 먼저 Kubernetes Networking model에 대해서 이해할 필요가 있다.

Kubernetes Networking model

Every Pod gets its own IP address. This means you do not need to explicitly create links between Pods and you almost never need to deal with mapping container ports to host ports.
 
Kubernetes imposes the following fundamental requirements on any networking implementation (barring any intentional network segmentation policies):
  • pods on a node can communicate with all pods on all nodes without NAT
  • agents on a node (e.g. system daemons, kubelet) can communicate with all pods on that node
Note: For those platforms that support Pods running in the host network (e.g. Linux):
  • pods in the host network of a node can communicate with all pods on all nodes without NAT
ref:
 
간단히 이야기하면,
All Pods can reach all other Pods, across Nodes.
Many implementations:
  • Flat (별도 스위칭을 통하지 않은 직결 연결)
  • Overlays (e.g. VXLAN)
  • Routing Config (e.g. BGP)
 
Kubernetes는 기본적으로 네트워크를 위해 kubenet을 제공하지만
Kubenet은 리눅스에서만 사용할 수 있는 매우 기본적이고, 간단한 네트워크 플러그인이다. 그 자체로는, 크로스-노드 네트워킹 또는 네트워크 정책과 같은 고급 기능을 구현하지 않는다.
 
그래서 크로스 노드 네트워킹, 네트워크 정책 적용을 하기 위해 CNI 0.4.0 spec 을 구현한 Network Plugin을 사용하게된다. 이 Network Plugin이 우리가 알고 있는 Calico, WeaveNet, Cilium 등이 되겠다.
ref:
 
다음과 같이 Network Plugin 마다 네트워크 구현방식이 조금씩 다르다.
notion imagenotion image
ref:
 
Overlay와 Double encapsulation이라는 용어가 나오는데...
  • Overlay는 말 그대로 물리적인 호스트 네트워크 위에, VXLAN등을 사용해서 가상의 네트워크(우리의 경우는 Kubernetes Cluster Network)를 구성한 형태를 의미한다. (여기에는 bridge, veth, routing등이 사용된다.) 아래 영상에서는 청중이(?) "VPN 연결 같은건가요?" 라고 하면, "비슷하다고 할 수 있지" 하고 이야기한다.
  • Encapsulation은 아래 그림과 같이 Pod to Pod 네트워크에서 host 를 벗어나 전송될 때는 SRC, DST가 host ip로 한단계 포장되서 전송된다고 이해할 수 있다. (Packet 구성 시 Payload 앞에 SRC, DST 가 한겹 더 있음)
notion imagenotion image
ref:
 
Pod to Pod을 연결하기 위한 Kubernetes Object에 대해 복습해보자.

Service

우리가 익히 알고 있는 그 Service.
 
Service "expose" a group of pods
Pod의 그룹은 Service를 통해서 expose된다.
VirtualIP(ClusterIP) for Endpoints Service는 Endpoints를 대표하는 가상의 IP일 뿐 물리적으로 존재하지 않는다.
(보통 Service IP 와 Pod IP 가 할당되는 대역이 다르게 구분되어 있다.)
 
Service는 Endpoint Controller를 통해 Endpoints를 할당 받는다.
notion imagenotion image
Endpoints에 address가 너무 많아지면서 이를 저장하고 관리하는데 문제가 발생했고, Endpoint를 100개 이하로 그룹핑해서 관리하는 EndpointSlicesFEATURE STATE: Kubernetes v1.17 [beta] 로 추가되었다 (v1.20 GA)

DNS

Generally runs as pods in the cluster
Containers are configured by kubelet to use kube-dns
  • Search paths make using if event easier
Default implementation is CoreDNS
notion imagenotion image

kube-proxy

Default implementation of Services
Runs on every Node in the cluster
Uses the node as a proxy for traffic from pods on that node
notion imagenotion image
ref:
 
정리하면
Pod은 Service에 의해서 노출되며,
kube-proxy는 Service의 구현체이다.
 
Kube-proxy is a controller - it watches the API for services.
notion imagenotion image
ref:
 
다음 그림처럼
Service를 kube-dns에 query하면 → foo
VirtualIP(ClusterIP) 를 리턴받고 → 100.96.0.30
kube-proxy는 전달받은 100.96.0.30 (Virtual IP)를 Pod IP (Endpoint)로 패킷의 destination을 변환(DNAT)한다.
notion imagenotion image
 
ref:
 
같은 이야기...
notion imagenotion image
 
kube-proxy는 어떻게 ClusterIP 와 Endpoint를 관리하는 걸까?
kube-proxy 는 iptables 혹은 ipvs를 백엔드로 사용한다.
 
정리하면, kube-proxy는
iptables, ipvs 의 ruleset을 업데이트 하는 역할 + DNAT iptables rules을 통해 로드밸런싱 하는 역할을 한다.
 
Kubernetes 1.2 버전 미만에서는 kube-proxy 가 service IP 로 들어오는 요청을 받아(훔쳐) endpoint(Pod ip)로 전달하는 프록시의 역할까지 했지만, 모든 패킷이 프록시를 통해 전달되어야 하기 때문에 부하가 발생했고
Kubernetes 1.2 이상으로 버전이 올라가면서, kube-proxy는 netfliter의 chain rule을 (iptables를 사용해서) 수정하는 역할만 하게 되었다.
 

iptables (and netfliter)

netfilter

packet processing framework in the linux kernel and which is used by iptables and ipvs.
iptables and ipvs is used by kube-proxy to implement the service abstraction
ref:
 
iptables는 유저레벨에서 커널레벨의 netfilter와 소통할 수 있는 인터페이스 역할을 한다.
 
notion imagenotion image
ref:
 
iptables와 netfilter에 대해서 좀 더 궁금하다면 다음 글을 참고해보자.
 
Kubernetes Networking Model 을 어느정도 정리했으니 다시 Network Plugin으로 돌아가보자.

Network Plugin

Calico

늘 하던대로 Calico를 사용해서 k8s 클러스터를 구성했다.
 
hello를 출력하는 hello-node pod을 2개 실행하고, 앞단에는 hello-node service 를 LoadBalancer type으로 생성했다. (LoadBalancer type으로 생성해도 service에는 항상 culster IP (virtual IP)가 생성된다.
 
다음 커맨드를 통해서 Calico를 사용하는 클러스터의 iptables NAT 테이블을 확인해보자.
  • iptables 확인
# K8s node에 접속해서 hello-node service(cluster ip) 로 부터 # hello-node pod (endpoint)으로의 연결을 확인할 수 있다. $ iptables -S -t nat # KUBE-SERVICES -A KUBE-SERVICES ! -s 100.96.0.0/11 -d 100.64.32.248/32 -p tcp -m comment --comment "default/hello-node cluster IP" -m tcp --dport 8080 -j KUBE-MARK-MASQ -A KUBE-SERVICES -d 100.64.32.248/32 -p tcp -m comment --comment "default/hello-node cluster IP" -m tcp --dport 8080 -j KUBE-SVC-666FUMINWJLRRQPD # KUBE-SVC 가 2개의 endpoint로 나눠진다. -A KUBE-SVC-666FUMINWJLRRQPD -m comment --comment "default/hello-node" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-Q6JIJSINM5KCCZHJ -A KUBE-SVC-666FUMINWJLRRQPD -m comment --comment "default/hello-node" -j KUBE-SEP-WECAVRMQP76URME4 # pod(endpoint) ip (100.127.44.195) -A KUBE-SEP-WECAVRMQP76URME4 -s 100.127.44.195/32 -m comment --comment "default/hello-node" -j KUBE-MARK-MASQ -A KUBE-SEP-WECAVRMQP76URME4 -p tcp -m comment --comment "default/hello-node" -m tcp -j DNAT --to-destination 100.127.44.195:8080 # pod(endpoint) ip (100.113.232.4) -A KUBE-SEP-Q6JIJSINM5KCCZHJ -s 100.113.232.4/32 -m comment --comment "default/hello-node" -j KUBE-MARK-MASQ -A KUBE-SEP-Q6JIJSINM5KCCZHJ -p tcp -m comment --comment "default/hello-node" -m tcp -j DNAT --to-destination 100.113.232.4:8080 # kubectl 명령을 통해 해당 pod ip가 위에서 조회한 endpoint와 동일함을 확인할 수 있다. $ kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES hello-node-6fc5d99f85-6jl92 1/1 Running 0 44h 100.127.44.195 ip-10-0-101-66.ap-northeast-2.compute.internal <none> <none> hello-node-6fc5d99f85-fpq4f 1/1 Running 0 44h 100.113.232.4 ip-10-0-102-95.ap-northeast-2.compute.internal <none> <none>
  • IPAM block 확인
# kubectl 을 통해서 calico의 CRD인 ipamblocks.crd.projectcalico.org 를 조회하면 # master, 2개의 worker node의 ipam block을 확인할 수 있다. $ kubectl get ipamblocks.crd.projectcalico.org NAME AGE 100-112-78-128-26 44h 100-113-232-0-26 44h 100-127-44-192-26 44h # 노드 하나를 선택해서 ipamblocks 확인 $ kubectl describe ipamblocks.crd.projectcalico.org 100-113-232-0-26 ... Cidr: 100.113.232.0/26 ... # hello-node-6fc5d99f85-fpq4f pod 이 `100-113-232-0-26` node의 POD CIDR 내에 위치함을 알 수 있다. 이 정보를 통해 endpoint IP -> 실제 패킷을 전송할 노드를 추론할 수 있다. $ kubectl get pod -n default -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES hello-node-6fc5d99f85-6jl92 1/1 Running 0 44h 100.127.44.195 ip-10-0-101-66.ap-northeast-2.compute.internal <none> <none> hello-node-6fc5d99f85-fpq4f 1/1 Running 0 44h 100.113.232.4 ip-10-0-102-95.ap-northeast-2.compute.internal <none> <none>
 
여기서 문제가 발생한다.
다음 그림은 iptables의 packet flow 인데, 보기만 해도 복잡하다.
영상에서도 다 알 필요는 없다고 한다. 그냥 복잡하다...를 이야기하고 싶은 듯
notion imagenotion image
ref:
 
다음 그림처럼, (클러스터가 확장되서) iptables rule이 늘어날 수록 복잡도도 높아진다.
notion imagenotion image
ref:
 

Cilium

eBPF-based Networking, Observability, and Security
notion imagenotion image
이 영상(2016년)을 보면 Thomas Graf가 몇달 전 부터 cilium이라는 프로젝트를 시작했다고 이야기한다.
이 때는 Cisco에 있었던 것 같고, 이후에 https://isovalent.com/ 를 창업해서 Cilium을 주축으로 개발하고 있는 것으로 보인다.
Title에서 보이는 것처럼 BPF를 사용한 Programmable Datapath 를 강조한다.
 
Cilium blog에서는 다음과 같이 GKE가 networking dataplane으로 eBPF를 사용하는 것에 대해 이야기한 내용을 첨부해서 설명한다.

Programmability

The programmability of eBPF makes it possible to adjust to the quickly evolving cloud-native requirements and tackle the increase in scale with ease. Here is an example on how the programmability of eBPF lead Google to adopt Cilium as its new networking dataplane for GKE:
As more and more enterprises adopt Kubernetes, the gamut of use cases is widening with new requirements around multi-cloud, security, visibility and scalability. In addition, new technologies such as service mesh and serverless demand more customization from the underlying Kubernetes layer. These new requirements all have something in common: they need a more programmable dataplane that can perform Kubernetes-aware packet manipulations without sacrificing performance.Enter Extended Berkeley Packet Filter (eBPF), a new Linux networking paradigm that exposes programmable hooks to the network stack inside the Linux kernel.-- Gobind Johar, Product Manager, Google Kubernetes Engine
ref:
 
기존에 CNI 들과는 다르게 BPF기반의 container networking & security를 구현해서
iptables/ipvs을 사용했던 기존 Netfilter기반의 network이 가진 한계점들을 해결하려고 했던 것 같다.
 
kops 에서는 kops create cluster ... networking=cilium 명령으로 선택가능하고,
이미 클러스터가 생성된 상황에서는 (ex EKS) https://docs.cilium.io/en/v1.9/gettingstarted/k8s-install-default/ 가이드를 참고해서 kubectl apply 혹은 helm install 명령을 통해 설치할 수 있다.
 
Cilium 과 다른 Network Plugin 을 비교하기 전에 Cilium에서 강조하는 eBPF에 대해서 알아볼 필요가 있다.
Calico 3.13 (2020.3 release) 에서도 kube-proxy를 사용하지 않고, eBPF를 data plane으로 사용할 수 있도록 릴리즈 되었지만, 아직 production ready까지는 아니라고 한다. ref:

eBPF

extended Berkeley Packet Filter
eBPF is a revolutionary technology that can run sandboxed programs in the Linux kernel without changing kernel source code or loading kernel modules.
 
커널에 삽입되서, 패킷을 필터링 하는 용도로 개발됐던(libpcap에서 사용) BPF(1992년) 를 확장해서 eBPF가 (2014년, Alexei Starovoitov) 탄생했다.
eBPF가 나온 뒤, 기존 BPF는 cBPF(Classic BPF) 라고도 한다.
달라진 점.
  • BPF VM 레지스터가 32 비트 레지스터 2개 → 64비트 레지스터 10개
  • 기존 BPF interpreter보다 빠른 명령어 집합을 산출, BPF보다 최대 4배 빠름
  • 유저 영역에서도 BPF에 접근할 수 있도록 패치 추가
  • 기존에는 BPF 함수내에서, 다른 함수호출이 불가했으나, 이제 가능해짐
ref: Linux Observability with BPF, 한빛미디어,
 
What is eBPF
eBPF does to Linux what JavaScript does to HTML. (Sort of.) So instead of a static HTML website, JavaScript lets you define mini programs that run on events like mouse clicks, which are run in a safe virtual machine in the browser. And with eBPF, instead of a fixed kernel, you can now write mini programs that run on events like disk I/O, which are run in a safe virtual machine in the kernel. In reality, eBPF is more like the v8 virtual machine that runs JavaScript, rather than JavaScript itself. eBPF is part of the Linux kernel.
Programming in eBPF directly is incredibly hard, the same as coding in v8 bytecode. But no one codes in v8: they code in JavaScript, or often a framework on top of JavaScript (jQuery, Angular, React, etc). It's the same with eBPF. People will use it and code in it via frameworks. For tracing, the main ones are bcc and bpftrace. These don't live in the kernel code base, they live in a Linux Foundation project on github called iovisor.
ref:
 
eBPF is a Linux kernel bytecode interpreter originally introduced to filter network packets, e.g. tcpdump and socket filters
ref:
 
Kernel Layer에서 동작하는 Bytecode를 안전하게 Kernel에 Loading(injection) 할 수 있다. (아래 링크의 영상 중에서...)
Naver Computing Platform에서 eBPF를 사용해서 NAT를 구현한 내용인데, 아주 구체적으로 설명하고 있어 추천.. (아직 다 이해하지는 못했지만 대단하다! 는 것은 알았다.)
ref:
 
 
BPF를 통해 Kernel 레벨의 네트워크 레이어를 동적으로 조정할 수 있다.
notion imagenotion image
ref:
 
좀 더 자세히 설명한 그림
notion imagenotion image
ref:
 
다음과 같이, 기존 iptables 기반의 Network Policy 처리과정을 BPF를 통해 단순화할 수 있다.
notion imagenotion image
notion imagenotion image
ref:

다시 Cilium으로 돌아와서

 
Calico 때와 마찬가지로,
hello를 출력하는 hello-node pod을 2개 실행하고, 앞단에는 hello-node service 를 LoadBalancer type으로 생성했다. (LoadBalancer type으로 생성해도 service에는 항상 culster IP (virtual IP)가 생성된다.
 
다음 커맨드를 통해서 Cilium을 사용하는 클러스터의 iptables NAT 테이블을 확인해보자.
$ iptables -S -t nat # 기존 calico에서 조회되던 지저분한 ruleset이 없어졌다. $ kubectl get pod -A | grep kube-proxy # kube-proxy도 없다. # iptables 가 가지고 있던 정보들은 어디로 갔을까? # cilium pod에 설치된 cilium CLI를 사용해서 service list를 조회해보자. # Frontend 는 Service IP, Backend 는 Pod IP(endpoint IP)를 보여준다. $ kubectl exec -it cilium-wc6cp -- cilium service list ID Frontend Service Type Backend 1 100.64.0.1:443 ClusterIP 1 => 10.0.101.48:443 2 100.64.0.10:53 ClusterIP 1 => 100.96.2.88:53 2 => 100.96.1.221:53 ... # endpoint 리스트 조회 $ kubectl exec -it cilium-wc6cp -- cilium endpoint list ENDPOINT POLICY (ingress) POLICY (egress) IDENTITY LABELS (source:key[=value]) IPv6 IPv4 STATUS ENFORCEMENT ENFORCEMENT 598 Disabled Disabled 4 reserved:health 100.96.1.244 ready 834 Disabled Disabled 37052 k8s:io.cilium.k8s.policy.cluster=default 100.96.1.191 ready k8s:io.cilium.k8s.policy.serviceaccount=hubble-ui k8s:io.kubernetes.pod.namespace=kube-system k8s:k8s-app=hubble-ui 1011 Disabled Disabled 12412 k8s:io.cilium.k8s.policy.cluster=default 100.96.1.137 ready k8s:io.cilium.k8s.policy.serviceaccount=default k8s:io.kubernetes.pod.namespace=cilium-test k8s:name=pod-to-b-intra-node-nodeport 1242 Disabled Disabled 15189 k8s:io.cilium.k8s.policy.cluster=default 100.96.1.153 ready k8s:io.cilium.k8s.policy.serviceaccount=default k8s:io.kubernetes.pod.namespace=cilium-test k8s:name=echo-b ... # endpoint hash map을 확인할 수 있다. $ kubectl exec -it cilium-wc6cp -- cilium map get cilium_lxc Key Value State Error 100.96.1.191:0 id=834 flags=0x0000 ifindex=36 mac=42:B6:74:AF:8E:ED nodemac=32:EE:A1:76:65:7B sync 100.96.1.162:0 id=2670 flags=0x0000 ifindex=38 mac=5E:06:78:A2:78:24 nodemac=CA:D8:87:11:22:BC sync 100.96.1.221:0 id=2327 flags=0x0000 ifindex=10 mac=CE:EE:61:FC:01:7D nodemac=3E:49:48:3D:F2:49 sync # endpoint 역시 CRD를 사용해서 저장되어 있다. $ kubectl get ciliumendpoints.cilium.io -A # ipam 정보는? $ kubectl get ciliumnodes.cilium.io # 노드 목록이 조회된다. # 특정 노드를 선택해 조회해보면 $ kubectl describe ciliumnodes.cilium.io ip-10-0-102-238.ap-northeast-2.compute.internal # 에서 ipam CIDR을 확인할 수 있다.
notion imagenotion image
ref:
 
 

Architecture

notion imagenotion image

Cilium 의 구성

Agent

The Cilium agent (cilium-agent) runs on each node in the cluster. At a high-level, the agent accepts configuration via Kubernetes or APIs that describes networking, service load-balancing, network policies, and visibility & monitoring requirements.
The Cilium agent listens for events from orchestration systems such as Kubernetes to learn when containers or workloads are started and stopped. It manages the eBPF programs which the Linux kernel uses to control all network access in / out of those containers.

Client(CLI)

The Cilium CLI client (cilium) is a command-line tool that is installed along with the Cilium agent. It interacts with the REST API of the Cilium agent running on the same node. The CLI allows inspecting the state and status of the local agent. It also provides tooling to directly access the eBPF maps to validate their state.

Operator

The Cilium Operator is responsible for managing duties in the cluster which should logically be handled once for the entire cluster, rather than once for each node in the cluster. The Cilium operator is not in the critical path for any forwarding or network policy decision. A cluster will generally continue to function if the operator is temporarily unavailable. However, depending on the configuration, failure in availability of the operator can lead to:
  • Delays in IP Address Management (IPAM) and thus delay in scheduling of new workloads if the operator is required to allocate new IP addresses
  • Failure to update the kvstore heartbeat key which will lead agents to declare kvstore unhealthiness and restart.

CNI Plugin

The CNI plugin (cilium-cni) is invoked by Kubernetes when a pod is scheduled or terminated on a node. It interacts with the Cilium API of the node to trigger the necessary datapath configuration to provide networking, load-balancing and network policies for the pod.
 
ref:
 
 
(Docker Container) 실행 시, BPF 코드가 생성되어 인젝션된다.
notion imagenotion image
ref:
 
notion imagenotion image
notion imagenotion image
notion imagenotion image
 
외부 접속은 다음과 같이 연결된다.
notion imagenotion image
notion imagenotion image
ref:
Calico + eBPF dataplane도 유사하게 동작하는 듯 하다.
notion imagenotion image
ref:
 
eBPF Datapath가 L1, L2, L3....올라가면서 어떻게 구성되고, 동작하는지는, 다음 영상에 자세히 설명해주는데
어려워서 거의 이해를 못했다. 하지만 관심이 있다면 참고!
 
다음 블로그를 통해서 Cilium을 사용해서 Pod to Pod으로 packet이 어떻게 전달되는 지 각 단계별로 자세히 알아볼 수 있다.
notion imagenotion image
ref:
 
notion imagenotion image
BPF가 Layer마다 촘촘히 활약하고 있다. ref:
 
각 Node에 떠있는 Cilium agent는 데이터를 공유하기 위해서
CRD 혹은, Key/Value store를 사용할 수 있는데 대부분 etcd를 사용한다.
kops 의 경우 cilium-etcd를 별도 구성하거나, k8s 클러스터의 etcd를 공유(default)해서 사용할 수 있다.
 
Overlay, Native(Host) mode가 존재한다.
notion imagenotion image
 
다음과 같이 L3, L4, L7 레이어에 Network Policy를 설정할 수 있다.
다른 Network Plugin도 Network Policy 설정이 가능하지만 eBPF사용으로, 디버깅/시각화면에서 좀 더 좋을 것으로 생각된다.
notion imagenotion image
notion imagenotion image
notion imagenotion image
ref:
 
cilium에서 제공하는 connectivity-test.yaml 이 생성한 NetworkPolicy를 다음 명령으로 확인할 수 있다.
$ kubectl get ciliumnetworkpolicies.cilium.io -A NAMESPACE NAME AGE cilium-test pod-to-a-allowed-cnp 44h cilium-test pod-to-a-denied-cnp 44h cilium-test pod-to-external-fqdn-allow-google-cnp 44h # pod-to-a-allowed-cnp은 echo-a pod으로 8080 요청을 허용한다. $ kubectl describe ciliumnetworkpolicies.cilium.io pod-to-a-allowed-cnp -n cilium-test To Endpoints: Match Labels: Name: echo-a To Ports: Ports: Port: 8080 Protocol: TCP # pod-to-a-allowed-cnp 는 echo-a pod으로 8080요청이 허용되지 않아(denied) block 된다. $ kubectl describe ciliumnetworkpolicies.cilium.io pod-to-a-denied-cnp -n cilium-test
다음 Hubble 데모에서 policy에 의해 block 된 라우팅을 확인할 수 있다.
Hubble에서 echo-a pod에 allow/drop 된 요청을 살펴보자.
notion imagenotion image
pod-to-a-denied-cnp는 drop 되서 붉은색으로 표시된다
notion imagenotion image
dropped (더블클릭하면 잘 보임)
notion imagenotion image

Hubble

Network, Service & Security Observability for Kubernetes
 
Hubble can answer questions such as:
Service dependencies & communication map:
  • What services are communicating with each other? How frequently? What does the service dependency graph look like?
  • What HTTP calls are being made? What Kafka topics does a service consume from or produce to?
Operational monitoring & alerting:
  • Is any network communication failing? Why is communication failing? Is it DNS? Is it an application or network problem? Is the communication broken on layer 4 (TCP) or layer 7 (HTTP)?
  • Which services have experienced a DNS resolution problems in the last 5 minutes? Which services have experienced an interrupted TCP connection recently or have seen connections timing out? What is the rate of unanswered TCP SYN requests?
Application monitoring:
  • What is the rate of 5xx or 4xx HTTP response codes for a particular service or across all clusters?
  • What is the 95th and 99th percentile latency between HTTP requests and responses in my cluster? Which services are performing the worst? What is the latency between two services?
Security observability:
  • Which services had connections blocked due to network policy? What services have been accessed from outside the cluster? Which services have resolved a particular DNS name?
notion imagenotion image
notion imagenotion image
notion imagenotion image
 
ref:
 
  • 다음 명령을 통해 connectivity-check.yaml 를 설치하고 Hubble에서 조회해 볼 수 있다.
$ kubectl create ns cilium-test # connectivity-check.yaml 을 통해 cilium의 동작을 확인한다. $ kubectl apply -n cilium-test -f https://raw.githubusercontent.com/cilium/cilium/v1.9/examples/kubernetes/connectivity-check/connectivity-check.yaml # cilium 이 설치된 상태에서도 delete -f quick-install.yaml 한다음 appyl -f quick-install.yaml 그리고 quick-hubble-install.yaml 을 해야 정상적으로 설치가 되었다. # 아마도 다음 옵션 때문인듯 # Enable Hubble gRPC service. enable-hubble: "true" # UNIX domain socket for Hubble server to listen to. hubble-socket-path: "/var/run/cilium/hubble.sock" # Hubble을 허용한 Cilium 설치 $ kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/v1.9/install/kubernetes/quick-install.yaml # Hubble 설치 $ kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/v1.9/install/kubernetes/quick-hubble-install.yaml $ kubectl port-forward -n $CILIUM_NAMESPACE svc/hubble-ui --address 0.0.0.0 --address :: 12000:80
 
Hubble은 생각보다 빠르지는 않다. (설정이 잘못된 것일까?)
영상을 보면, Network Policy도 조회할 수 있는 UI가 있다.
 
Kubernetes Network과 eBPF 그리고 Cilium에 대해서 얕게 알아봤다.
Cilium에 대해 좀 더 공부하고 싶다면, http://arthurchiao.art/articles/ 의 Cilium Code Walk 시리즈가 도움될 것 같다.
틀린 내용이나 조금 더 이야기하고 싶은 부분이 있다면 노션 코멘트나 @asbubam 으로 연락을 부탁드립니다.

References