이전 직장에서 프로젝트 중에 Multus를 사용하여 5G환경에서 멀티 네트워크 CNI를 사용해서 패킷을 미러링하고 해당 패킷을 분석하는 프로젝트를 진행했었는데, 당시에 여러 사정으로 아쉽게 된 프로젝트도 존재하고 해서 이번 기회에 시리즈로 정리 해보려고 한다. 이번 포스트에서는 Kind cluster에 Multus를 구성하고 단일 인스턴스에서 노드끼리 통신할 수 있도록 koko를 사용해서 노드간 멀티 네트워크 환경을 구성하는 방법에 대해서 정리해보려고 한다.
Kind: Kind(Kubernetes IN Docker)는 Docker 컨테이너를 사용하여 로컬 Kubernetes 클러스터를 실행할 수 있게 해주는 도구다. 주로 테스트 및 개발 목적으로 사용되며, 빠르고 쉽게 Kubernetes 환경을 구축할 수 있다.
Multus: Multus는 Kubernetes에서 여러 네트워크 인터페이스를 지원하기 위한 CNI 플러그인이다. Multus를 통해 각 Pod가 여러 네트워크에 연결될 수 있으며, 다양한 네트워크 요구 사항을 충족할 수 있다. 특히 5G 워크로드에서 SR-IOV와 함께 사용될 때, Multus는 기본 네트워크 외에도 고성능 네트워크 인터페이스를 제공할 수 있다.
SR-IOV: SR-IOV(Single Root I/O Virtualization)는 하나의 물리적 네트워크 인터페이스를 여러 가상 함수(VF)로 나누어 각 Pod에 직접 할당할 수 있게 해주는 기술이다. 이를 통해 네트워크 성능을 크게 향상시킬 수 있으며, 특히 고성능 네트워킹이 필요한 5G 및 NFV(Network Function Virtualization) 환경에서 중요하게 사용되는 기술이다.
Koko: Koko는 컨테이너 간 네트워크 연결을 위한 도구로, 특히 여러 네트워크 네임스페이스 간의 가상 이더넷 페어를 생성하는 데 사용된다. kind cluster에서 컨테이너로 구성된 노드간 통신을 위해서 사용된다.
Macvlan: Macvlan은 네트워크 인터페이스를 가상화하여 여러 개의 가상 네트워크 인터페이스를 생성할 수 있는 기술이다. 이를 통해 각 컨테이너가 고유한 MAC 주소를 가지며, 물리 네트워크와 직접 통신할 수 있다.
AWS에는 기본 ENI가 포함된 서브넷에서 사용할 수 있는 IP개수는 제한되어 있다. 파드의 수 제한이 발생할 수 있기 때문에 secondary ENI에 다른 서브넷을 사용하여 가용 IP개수를 늘릴수 있다. 또한 보안상의 이유로 파드는 노드의 기본 네트워크 인터페이스와 다른 서브넷 또는 보안 그룹을 사용해야 할 수 있다.
CNI Custom Networking이 활성화가 되면 파드는 다른 서브넷에 생성이 되고, 노드 서브넷의 아이피를 사용하지 않는다.
EKS에서 파드 대역을 분리 하기 위해서 CNI Custom Networking 설정을 진행한다. 해당 env 값을 변경하면 즉시 aws-node 가 교체된다.
Cilium은 Docker 및 Kubernetes와 같은 리눅스 컨테이너 프레임 워크에 API 기반의 네트워크 보안 필터링을 제공하며,
또한, BPF라는 새로운 Linux 커널 기술을 사용하여 컨테이너/POD ID를 기반으로 네트워크 계층 및 응용 프로그램 계층 보안 정책을 정의 및 적용하는 것에 있어서 간단하면서 효율적인 방법을 제공하고 있습니다.
윗분들처럼 커널 자체를 분석하고 공부하고 기여하려면 소요되는 시간이 더 걸릴거 같고 서비스를 운영하고 개발하는 입장에서는 내 프로젝트에 적용 가능성을 검증하는것이 나을것 같아 정리를 해본다.
iptables을 기반으로 IP와 Port기반의 전통적인 포워딩 기술은 벌써 20년이라는 세월동안 널리 사용되어 왔다. 특히 퍼블릭/프라이빗 클라우드 제품군들 모두 iptables기반의 Security Group등을 기본으로 제공하고 있고 Kubernetes 마저도 CNI 핵심으로 iptables을 활용하고 있다.
동적으로 변화하고 매우 복잡한 마이크로서비스를 사용하는 시대에 전통적인 방식의 IP, Port관리는 비효율적인 측면이 없지 않다. BPF(아래인용)을 활용하여 리눅스 커널내에서 데이터 포워딩을 할 수 있고 Kubernetes Service기반 Load Balancing이나 istio와 같은 Service Mesh를 위한 Proxy Injection 을 통해 여러 활용을 할 수 있을거라고 Cilium 프로젝트는 이야기 하고 있다.
버클리 패킷 필터(Berkeley Packet Filter, BPF)
BPF는 버클리 패킷 필터(Berkeley Packet Filter)의 줄임말이다. 이름 그대로 패킷을 걸러내는 필터이다. 그런데 BSD에서의 BPF는 네트워크 탭(리눅스의 PF_PACKET)까지 아우르는 개념이다. 옛날 옛적에 유닉스에는 CSPF(CMU/Stanford Packet Filter)라는 게 있었는데 BPF라는 새 구조가 이를 대체했다. 이후 리눅스에서는 네트워크 탭을 나름의 방식으로 구현하고 패킷 필터 부분만 가져왔다. 리눅스의 패킷 필터를 리눅스 소켓 필터링(LSF: Linux Socket Filtering)이라고도 한다.
(발췌) https://wariua.github.io/facility/extended-bpf.html
Cilium은 Dockercon 2017에서 최초 announce를 하였고 2018년 4월 24일에 1.0이 정식 Release된 이후 많은 관심을 받을것으로 예상되어 실제 서비스에 적용해볼 필요가 있을거 같아 minikube로 테스트한 내용을 끄젹여 본다.
$ kubectl create -n kube-system -f https://raw.githubusercontent.com/cilium/cilium/v1.1/examples/kubernetes/addons/etcd/standalone-etcd.yaml service "etcd-cilium" created statefulset.apps "etcd-cilium" created
Kubernetes 클러스터에 Cilium을 인스톨한다. 기본적으로 DaemonSet 형태로 배포되기 때문에 Node당 한개의 Cilium Pod를 볼 수 있다. Cilium은 kube-system namespace에서 실행된다.
$ kubectl create -f https://raw.githubusercontent.com/cilium/cilium/v1.1/examples/kubernetes/1.9/cilium.yaml configmap "cilium-config" created secret "cilium-etcd-secrets" created daemonset.extensions "cilium" created clusterrolebinding.rbac.authorization.k8s.io "cilium" created clusterrole.rbac.authorization.k8s.io "cilium" created serviceaccount "cilium" created
kube-system namespace에 RBAC설정과 함께 Cilium이 배포되고, ConfigMap, DaemonSet 형태로 배포가 된다.
아래 데모그림을 보면 스타워즈의 영감을 받아서인지 deathstar, xwing 등으로 구분한것을 확인할수 있다. deathstar deployments의 경우 80포트로 http 웹서버가 2개의 pod replica로 Load Balancing되고 있다. deathstar 서비스는 우주선이 착륙할수 있도록 활주로를 서비스하고 있다. 하지만 제국군의 tiefighter 만 착륙하도록 해야하므로 보안설정을 해야하는 상황이다.
아래 http-sw-app.yaml 은 세가지 deployment를 가지고 있고 각각의 deployment는 (org=empire, class=deathstar), (org=empire, class=tiefighter), (org=alliance, class=xwing)와 같이 label 정보를 가진다. deathstar Service는 (org=empire, class=deathstar) label을 가지고 Load Balancing을 한다.
$ kubectl create -f https://raw.githubusercontent.com/cilium/cilium/v1.1/examples/minikube/http-sw-app.yaml service "deathstar" created deployment "deathstar" created deployment "tiefighter" created deployment "xwing" created
총 4개의 pod와 1개의 서비스를 확인할수 있다.
$ kubectl get pods,svc NAME READY STATUS RESTARTS AGE pod/deathstar-566c89f458-mqgfs 1/1 Running 0 1h pod/deathstar-566c89f458-wlc4c 1/1 Running 0 1h pod/tiefighter 1/1 Running 0 1h pod/xwing 1/1 Running 0 1h NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/deathstar ClusterIP 10.109.80.174 <none> 80/TCP 1h service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4h
각각의 pod는 Cilium에서는 Endpoints형태로 표현된다. 아래와 같이 ingress, egress policy를 확인할수 있고 아직 아무런 network policy 적용을 하지 않았기 때문에 모두 Disabled 상태로 보인다.