K8s의 Multus CNI 플러그인은 단일 파드에 여러 네트워크 인터페이스를 연결할 수 있는 기능을 제공합니다. K8s에서 각 Pod는 기본적으로 루프백 외에 하나의 네트워크 인터페이스만 가지지만, Multus CNI을 이용하면 다음과 같이 활용할 수 있습니다.
고성능 애플리케이션을 위한 SRIOV 인터페이스를 파드에 연결
파드에 다중 인터페이스를 제공해서 멀티호밍 기능 활용
Multus는 사용자에게 뛰어난 유연성과 활용법을 제공하지만 동시에 몇 가지 단점이 있습니다.
Multus가 제공하는 보조 네트워크는 로드밸런서 서비스를 사용할 수 없습니다.
K8s의 엑세스 제어 및 보안 정책이 적용되지 않습니다.
이 포스트에서는 loxilb를 사용해서 로드 밸런서 서비스를 Multus 기반 워크로드에 제공하는 방법을 설명합니다. (PS: 해당 loxilb 기능은 아직 베타 버전입니다.)
Multus 워크로드에 seamless한 LB 서비스를 제공할 수 있다면, Multus 사용자들에게 간편한 워크로드 확장 및 정책/엑세스 제어 기능을 지원할 수 있습니다. 이러한 요구사항을 해결하기 위해서 사람들이 몇 가지 아이디어를 제시하기도 했지만, 대부분 K8s에서 제시하는 컨벤션을 위반한다는 구조적 문제점을 가지고 있었습니다.
해당 포스트에서는 k3s를 사용해서 Kubernetes를 배포하겠습니다. k3s를 설치하는 방법은 다음 포스트를 참조하시면 됩니다. 주의할 점은, Multus와 k3s간 호환성 문제 때문에 최신 버전이 아니라 약간 이전 버전(v1.22.9+k3s1)을 선택해서 설치하셔야 합니다.
$ curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.22.9+k3s1 INSTALL_K3S_EXEC="server --disable traefik --disable servicelb --disable-cloud-controller --kubelet-arg cloud-provider=external" K3S_KUBECONFIG_MODE="644" sh -
테스트에 사용할 토폴로지는 다음 그림과 같습니다.
loxilb는 일반적으로 로드 밸런서 역할을 수행하는 외부 노드에서 실행됩니다. 이 포스트의 예제처럼 Kubernetes의 daemonset으로 실행 역시 가능하지만, 여기서는 Multus 워크로드를 사용하는 파드로 로드 밸런싱이 이루어지는 것을 보여주기 위해서 외부 노드에서 loxilb를 실행하겠습니다.
loxilb 설치 방법은 다음과 같습니다.
다음은 Multus 플러그인을 K8s에 설치합니다. 설치 방법은 다음과 같습니다.
1. 해당 링크를 참조하여 Multus daemonset을 배포합니다.
2. Multus 설정을 위해, 다음 예시처럼 NetworkAttachmentDefinition을 생성합니다.
cat <<EOF | kubectl create -f -
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
name: macvlan1
spec:
config: '{
"cniVersion": "0.3.1",
"type": "macvlan",
"master": "ensp0",
"mode": "bridge",
"ipam": {
"type": "host-local",
"ranges": [
[ {
"subnet": "192.168.20.0/24",
"rangeStart": "192.168.20.20",
"rangeEnd": "192.168.20.200",
"gateway": "192.168.20.1"
} ]
]
}
}'
EOF
3. 아래 예제처럼 Multus 인터페이스가 추가된 파드를 생성합니다. 2번에서 생성한 NetworkAttachmentDefinition의 이름을 k8s.v1.cni.cncf.io/networks annotations에 사용합니다.
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
name: pod-01
labels:
app: pod-01
annotations:
k8s.v1.cni.cncf.io/networks: macvlan1
spec:
containers:
- name: nginx-multus-test
image: nginx:stable
ports:
- containerPort: 80
EOF
4. 아래 예시처럼 서비스를 생성합니다. 서비스의 annotations를 보면 loxilb.io/multus-nets 어노테이션을 사용합니다. 이 어노테이션은 LB 룰을 생성할 때 사용할 Multus 네트워크를 지정합니다. 해당 어노테이션을 사용하면 loxilb는 Multus 인터페이스를 사용하는 로드 밸런서 룰만 생성합니다.
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Service
metadata:
name: multus-service
annotations:
loxilb.io/multus-nets : macvlan1,macvlan2
spec:
loadBalancerClass: loxilb.io/loxilb
selector:
app: pod-01
ports:
- port: 55003
targetPort: 80
type: LoadBalancer
EOF
이제 생성된 결과물을 확인합니다.
1. 다음 명령어로 Multus 및 kube-loxilb와 테스트용 파드가 생성되었는지 확인합니다.
$ kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system local-path-provisioner-84bb864455-qr2l5 1/1 Running 0 50m
kube-system coredns-7796b77cd4-nd2p2 1/1 Running 0 50m
kube-system metrics-server-ff9dbcb6c-8sgvd 1/1 Running 0 50m
kube-system kube-loxilb-f9c5cd878-25ppx 1/1 Running 0 49m
kube-system kube-multus-ds-amd64-7kbms 1/1 Running 0 20m
default pod-01 1/1 Running 0 6m41s
위에서 Multus 네트워크 구성에 사용한 macvlan 플러그인은 기본적으로 k3s에 설치되어 있지 않기 때문에 파드를 생성하는 과정에서 에러가 발생할 수 있습니다.
$ kubectl get pods -A | grep pod-01
default pod-01 0/1 ContainerCreating 0 66s
$ kubectl describe pods pod-01 | grep -i "failed"
Warning FailedCreatePodSandBox 3s kubelet Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "e3e214462723c973ff5a343a9cff1e370fed5c4ccd570c8d84a408ede6419acb": plugin type="multus" name="multus-cni-network" failed (add): [default/pod-case-01:macvlan-conf-1]: error adding container to network "macvlan-conf-1": failed to find plugin "macvlan" in path [/opt/cni/bin /var/lib/rancher/k3s/data/995f5a281daabc1838b33f2346f7c4976b95f449c703b6f1f55b981966eba456/bin]
해당 에러가 발생하면 macvlan 플러그인을 수동으로 빌드해서 설치해야 합니다.
$ git clone https://github.com/containernetworking/plugins.git
$ cd plugins
$ ./build_linux.sh
$ ls bin/macvlan
$ sudo cp -f ./bin/macvlan /var/lib/rancher/k3s/data/current/bin/
2. 서비스가 올바르게 생성되었는지 확인합니다.
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 48m
nginx-service ClusterIP 10.43.177.140 <none> 8080/TCP 47m
multus-service LoadBalancer 10.43.134.27 123.123.123.1 55003:31250/TCP 4s
3. loxilb 룰이 올바르게 생성되었는지 확인합니다. (loxilb 노드에서 확인해야 합니다)
$ docker exec -it loxilb loxicmd get lb -o wide
| EXTERNAL IP | PORT | PROTOCOL | BLOCK | SELECT | MODE | ENDPOINT IP | TARGET PORT | WEIGHT | STATE |
|---------------|-------|----------|-------|--------|---------|----------------|-------------|--------|----------|
| 123.123.123.1 | 55003 | tcp | 0 | rr | default | 192.168.20.20 | 80 | 10 | - |
4. 마지막으로 트래픽이 정상적으로 흐르는지 확인합니다.
$ curl -s --connect-timeout 10 http://123.123.123.1:55003
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
Comments