Red Hat Blog를 보다가 관심 가는 글이 보여서 AI번역+약간 교정해 보았습니다.
출처: https://developers.redhat.com/articles/2025/05/01/native-network-segmentation-virtualization-workloads
이 문서에서는 Red Hat OpenShift 에서 클러스터 기본 네트워크를 재정의하고 관리형 IPAM (IP Address Management)을 통해 레이어 2 격리 네트워크를 사용하여 워크로드를 연결하는 방법을 보여줍니다. 이러한 유형의 네트워크는 NAT (Network Address Translation) 없이 동서 통신을 제공하고 전체 수명 주기 동안 안정적인 IPAM 구성을 제공함으로써 쿠버네티스 플랫폼의 가상화 워크로드 과제를 해결합니다. 이를 위해 user-defined network (UDN) 기능을 소개합니다.
동기 부여
가상화 관점에서 OpenShift 사용자는 두 가지 유형으로 구분됩니다. 하나는 NAT 없이 동서 통신을 위한 격리된 네트워크(OpenStack Neutron 방식)를 원하는 기존 가상화 사용자이고, 다른 하나는 IPAM을 포함한 완벽하게 관리되는 네트워크 환경을 원하는 Kubernetes 사용자입니다. 이를 통해 사용자는 워크로드에 고정 주소를 할당하거나 네트워크에 DHCP(동적 호스트 구성 프로토콜) 서버를 배포할 필요가 없습니다.
사용자 유형에 관계없이 두 가지 모두 동일한 목표를 공유합니다. 즉, 안정적인 IPAM 구성(IP 주소, 게이트웨이, DNS 구성)이 필요하고 네트워킹 솔루션은 베어 메탈과 클라우드 플랫폼 모두에서 작동해야 합니다.
문제
이 경우, 사용자의 목표 달성을 방해하는 것은 쿠버네티스 플랫폼 자체, 특히 쿠버네티스 네트워킹 모델입니다. 간단히 말해, 쿠버네티스 플랫폼은 지나치게 고집이 센 편입니다.
플랫폼의 모든 워크로드를 연결하는 단일 네트워크를 제공합니다. 사용자가 워크로드 간 트래픽을 제한하려는 경우, NetworkPolicy를 프로비저닝하는 것이 유일한 방법입니다. 이 방법은 두 가지 이유로 비용이 많이 듭니다. 누군가 정책을 작성하고 유지 관리해야 하며, 네트워크에서 변경 사항이 발생할 때마다 정책을 조정해야 하기 때문입니다. 모든 것을 연결하는 단일 네트워크가 있기 때문에 이러한 작업이 빈번하게 발생합니다.
설상가상으로, 쿠버네티스 네트워크 정책은 네트워크와 전송 OSI 계층(3계층과 4계층)에서 작동합니다. 즉, 쿠버네티스 자체적으로 계층 2 격리를 수행할 방법이 없다는 뜻입니다.
목표
이제 이러한 격리된 2계층 네트워크를 통해 무엇을 해결하려는지, 그리고 그 이유를 이해했으므로 이에 대한 목표를 나열해 보겠습니다.
- 워크로드/테넌트 격리: 서로 통신할 수 없는 서로 다른 격리된 네트워크에서 다양한 유형의 애플리케이션을 그룹화하는 기능입니다.
- 중복되는 서브넷: 동일한 Pod 서브넷 범위로 클러스터에 여러 네트워크를 만들어 동일한 설정을 복사할 수 있습니다.
- 네이티브 쿠버네티스 API 통합: 쿠버네티스 네트워크 API를 완벽하게 지원합니다. 즉, 서비스, 네트워크 정책, 관리 네트워크 정책을 UDN에서 사용할 수 있습니다.
- OpenShift 네트워크 API와의 기본 통합: OpenShift 네트워크 API를 지원합니다. 현재 UDN에서 송신 IP를 사용할 수 있습니다. OpenShift 경로에 대한 지원을 추가할 계획입니다.
- 안정적인 IPAM 구성: 워크로드는 수명 주기 동안 IP, 게이트웨이, DNS 구성이 안정적이어야 합니다.
- 클라우드 플랫폼 지원: 패킷은 해당 패킷이 실행되는 노드의 IP 주소와 함께 클러스터 노드에서 나가야 합니다. 그렇지 않으면 클라우드 공급자가 해당 패킷을 삭제합니다.
- 클러스터 기본 네트워크에서 사용 가능한 일부 Kubernetes 인프라 서비스에 대한 액세스: UDN에 연결된 워크로드에서
kube-dns와kube-api에 대한 액세스가 가능하며 계속 사용 가능합니다. - 동서 트래픽에는 NAT가 없습니다.
요구 사항
- OpenShift 클러스터, 버전 >= 4.18
- Red Hat OpenShift Virtualization과 MetalLB를 설치하고 구성했습니다(후자는 서비스 부분 에만 필요합니다). 자세한 내용은 OpenShift 문서를 참조하세요 .
사용 사례
OpenShift UDN 기능을 통해 다루는 두 가지 주요 사용 사례는 네임스페이스 격리 와 격리된 클러스터 전체 네트워크입니다 . 이전 섹션에서 언급한 모든 목표는 두 사용 사례 모두에 적용된다는 점을 명심하세요 .
네임스페이스 격리
이 사용 사례에서 네임스페이스의 모든 워크로드는 서로 액세스할 수 있지만 클러스터의 나머지 부분과는 격리됩니다. 즉, 다른 UserDefinedNetwork의 워크로드는 해당 워크로드에 액세스하거나 접근할 수 없습니다. 클러스터 기본 네트워크에 연결된 워크로드도 마찬가지이며, UDN Pod에 연결할 수 없습니다(또는 그 반대의 경우도 마찬가지).
그림 1에서 이 개념의 그래픽 표현을 확인할 수 있습니다. 녹색 네임스페이스의 워크로드와 파란색 네임스페이스의 워크로드 간 통신은 차단되어 있지만, 같은 네임스페이스의 다른 포드와는 자유롭게 통신할 수 있습니다.

이 사용 사례를 달성하기 위해 OpenShift 4.18에서 사용자는 UserDefinedNetwork CR을 프로비저닝할 수 있습니다. 이는 네임스페이스의 워크로드가 기본 UDN을 통해 연결되고 다른 UDN(또는 클러스터의 기본 네트워크)의 워크로드가 액세스할 수 없음을 나타냅니다.
네임스페이스의 워크로드는 클러스터를 이그레스하고 목표 섹션 에 나열된 쿠버네티스 기능과 통합될 수 있습니다 . 이를 위해 사용자는 먼저 네임스페이스를 생성하고, 네임스페이스의 워크로드는 클러스터를 이그레스하고 목표 섹션 에 나열된 쿠버네티스 기능과 통합될 수 있습니다 . 이를 위해 사용자는 먼저 네임스페이스를 생성하고, 레이블을 추가하여 기본 클러스터 네트워크를 UDN으로 재정의하려는 의사를 명시적으로 표시해야 합니다 k8s.ovn.org/primary-user-defined-network 레이블을 추가하여 기본 클러스터 네트워크를 UDN으로 재정의하려는 의사를 명시적으로 표시해야 합니다.
참조 매니페스트는 다음 YAML을 참조하세요.
---
apiVersion: v1
kind: Namespace
metadata:
name: green
labels:
k8s.ovn.org/primary-user-defined-network: ""
---
apiVersion: k8s.ovn.org/v1
kind: UserDefinedNetwork
metadata:
name: namespace-scoped
namespace: green
spec:
topology: Layer2
layer2:
role: Primary
subnets:
- 192.168.0.0/16
ipam:
lifecycle: Persistent이제 UDN을 프로비저닝했으니, 가장 관련성 높은 기능을 보여주기 위해 UDN에 연결된 몇 가지 워크로드를 만들어 보겠습니다. 이 경우, 웹 서버 컨테이너 하나와 가상 머신(VM) 두 개를 생성합니다. 다음 YAML 매니페스트를 프로비저닝합니다.
---
apiVersion: v1
kind: Pod
metadata:
name: webserver
namespace: green
spec:
containers:
- args:
- "netexec"
- "--http-port"
- "9000"
image: registry.k8s.io/e2e-test-images/agnhost:2.45
imagePullPolicy: IfNotPresent
name: agnhost-container
restartPolicy: Always
securityContext: {}
serviceAccount: default
serviceAccountName: default
---
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
labels:
kubevirt.io/vm: vm-a
name: vm-a
namespace: green
spec:
runStrategy: Always
template:
metadata:
name: vm-a
namespace: green
spec:
domain:
devices:
disks:
- disk:
bus: virtio
name: containerdisk
- disk:
bus: virtio
name: cloudinitdisk
interfaces:
- name: isolated-namespace
binding:
name: l2bridge
rng: {}
resources:
requests:
memory: 2048M
networks:
- pod: {}
name: isolated-namespace
terminationGracePeriodSeconds: 0
volumes:
- containerDisk:
image: quay.io/kubevirt/fedora-with-test-tooling-container-disk:v1.4.0
name: containerdisk
- cloudInitNoCloud:
userData: |-
#cloud-config
password: fedora
chpasswd: { expire: False }
name: cloudinitdisk
---
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
labels:
kubevirt.io/vm: vm-b
name: vm-b
namespace: green
spec:
runStrategy: Always
template:
metadata:
name: vm-b
namespace: green
spec:
domain:
devices:
disks:
- disk:
bus: virtio
name: containerdisk
- disk:
bus: virtio
name: cloudinitdisk
interfaces:
- name: isolated-namespace
binding:
name: l2bridge
rng: {}
resources:
requests:
memory: 2048M
networks:
- pod: {}
name: isolated-namespace
terminationGracePeriodSeconds: 0
volumes:
- containerDisk:
image: quay.io/kubevirt/fedora-with-test-tooling-container-disk:v1.4.0
name: containerdisk
- cloudInitNoCloud:
userData: |-
#cloud-config
password: fedora
chpasswd: { expire: False }
name: cloudinitdisk동서 연결성
세 가지 워크로드가 실행되면 VM 중 하나에서 웹 서버 포드의 HTTP 서버에 접속하여 동서 트래픽이 제대로 작동하는지 확인할 수 있습니다. 하지만 이를 위해서는 먼저 웹 서버 IP 주소를 파악해야 합니다. 이 작업은 다음 k8snetworkplumbing network-status 주석을 참고합니다.
kubectl get pods -ngreen webserver -ojsonpath="{@.metadata.annotations.k8s\.v1\.cni\.cncf\.io\/network-status}" | jq
[
{
"name": "ovn-kubernetes",
"interface": "eth0",
"ips": [
"10.244.1.10"
],
"mac": "0a:58:0a:f4:01:0a",
"dns": {}
},
{
"name": "ovn-kubernetes",
"interface": "ovn-udn1",
"ips": [
"192.168.0.4"
],
"mac": "0a:58:cb:cb:00:04",
"default": true,
"dns": {}
}
]
# login using fedora/fedora
virtctl console -ngreen vm-a
Successfully connected to vm-a console. The escape sequence is ^]
vm-a login: fedora
Password:
[fedora@vm-a ~]$ curl 192.168.0.4:9000/hostname
webserver # reply from the webserver다른 UDN이나 기본 클러스터 네트워크에 연결된 작업 부하에서 웹 서버에 액세스하려고 하면 성공하지 못합니다.
인터넷으로의 이탈
인터넷으로의 이탈이 예상대로 작동하는지 확인할 수도 있습니다.
[fedora@vm-a ~]$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1400 qdisc fq_codel state UP group default qlen 1000
link/ether 0a:58:cb:cb:00:05 brd ff:ff:ff:ff:ff:ff
altname enp1s0
inet 203.203.0.5/16 brd 203.203.255.255 scope global dynamic noprefixroute eth0
valid_lft 2786sec preferred_lft 2786sec
inet6 fe80::858:cbff:fecb:5/64 scope link
valid_lft forever preferred_lft forever
[fedora@vm-a ~]$ ip r
default via 203.203.0.1 dev eth0 proto dhcp metric 100
203.203.0.0/16 dev eth0 proto kernel scope link src 203.203.0.5 metric 100
[fedora@vm-a ~]$ ping -c 2 www.google.com
PING www.google.com (142.250.200.100) 56(84) bytes of data.
64 bytes from 142.250.200.100 (142.250.200.100): icmp_seq=1 ttl=115 time=7.15 ms
64 bytes from 142.250.200.100 (142.250.200.100): icmp_seq=2 ttl=115 time=6.55 ms
--- www.google.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 6.548/6.849/7.150/0.301 ms원활한 라이브 마이그레이션
이제 이 가상 머신 중 하나의 원활한 라이브 마이그레이션을 확인해 보겠습니다. TCP 연결이 가상 머신 마이그레이션 후에도 유지된다는 주장을 입증하기 위해, iperf 서버를 시작할 vm-b를 마이그레이션하는 동안 iperf 세션의 처리량을 모니터링할 것입니다.
# let's start the iperf server in `vm-b` (for instance) # password is also fedora/fedora virtctl console -ngreen vm-b Successfully connected to vm-b console. The escape sequence is ^] vm-b login: fedora Password: [fedora@vm-b ~]$ iperf3 -s -p 9500 -1 ----------------------------------------------------------- Server listening on 9500 (test #1) -----------------------------------------------------------
iperf 클라이언트가 될 vm-a VM 에서 연결해보겠습니다.
virtctl console -ngreen vm-a Successfully connected to vm-a console. The escape sequence is ^] # keep in mind the iperf server is located at 203.203.0.6, port 9500 ... [fedora@vm-a ~]$ iperf3 -c 203.203.0.6 -p9500 -t3600 Connecting to host 203.203.0.6, port 9500 [ 5] local 203.203.0.5 port 56618 connected to 203.203.0.6 port 9500 [ ID] Interval Transfer Bitrate Retr Cwnd [ 5] 0.00-1.00 sec 2.59 GBytes 22.2 Gbits/sec 0 2.30 MBytes [ 5] 1.00-2.00 sec 2.53 GBytes 21.7 Gbits/sec 0 2.78 MBytes [ 5] 2.00-3.00 sec 2.95 GBytes 25.3 Gbits/sec 0 3.04 MBytes [ 5] 3.00-4.00 sec 3.93 GBytes 33.7 Gbits/sec 0 3.04 MBytes [ 5] 4.00-5.00 sec 3.83 GBytes 32.9 Gbits/sec 0 3.04 MBytes [ 5] 5.00-6.00 sec 3.99 GBytes 34.3 Gbits/sec 0 3.04 MBytes [ 5] 6.00-7.00 sec 3.89 GBytes 33.4 Gbits/sec 0 3.04 MBytes [ 5] 7.00-8.00 sec 3.88 GBytes 33.3 Gbits/sec 0 3.04 MBytes [ 5] 8.00-9.00 sec 3.94 GBytes 33.8 Gbits/sec 0 3.04 MBytes [ 5] 9.00-10.00 sec 3.80 GBytes 32.7 Gbits/sec 0 3.04 MBytes [ 5] 10.00-11.00 sec 3.98 GBytes 34.2 Gbits/sec 0 3.04 MBytes [ 5] 11.00-12.00 sec 3.67 GBytes 31.5 Gbits/sec 0 3.04 MBytes [ 5] 12.00-13.00 sec 3.87 GBytes 33.3 Gbits/sec 0 3.04 MBytes [ 5] 13.00-14.00 sec 3.82 GBytes 32.8 Gbits/sec 0 3.04 MBytes [ 5] 14.00-15.00 sec 3.80 GBytes 32.6 Gbits/sec 0 3.04 MBytes ...
이제 virtctl 도구를 사용하여 서버 VM을 마이그레이션해 보겠습니다.
virtctl migrate -ngreen vm-b VM vm-b was scheduled to migrate kubectl get pods -ngreen -w NAME READY STATUS RESTARTS AGE virt-launcher-vm-a-r44bp 2/2 Running 0 22m virt-launcher-vm-b-44vs4 2/2 Running 0 22m virt-launcher-vm-b-wct76 0/2 PodInitializing 0 8s webserver 1/1 Running 0 22m virt-launcher-vm-b-wct76 2/2 Running 0 13s virt-launcher-vm-b-wct76 2/2 Running 0 16s virt-launcher-vm-b-wct76 2/2 Running 0 16s virt-launcher-vm-b-wct76 2/2 Running 0 16s virt-launcher-vm-b-wct76 2/2 Running 0 17s virt-launcher-vm-b-44vs4 1/2 NotReady 0 22m virt-launcher-vm-b-44vs4 0/2 Completed 0 23m virt-launcher-vm-b-44vs4 0/2 Completed 0 23m # and this is what the client sees when the migration occurs: ... [ 5] 40.00-41.00 sec 2.79 GBytes 23.9 Gbits/sec 0 3.04 MBytes [ 5] 41.00-42.00 sec 2.53 GBytes 21.7 Gbits/sec 0 3.04 MBytes [ 5] 42.00-43.00 sec 2.57 GBytes 22.1 Gbits/sec 0 3.04 MBytes [ 5] 43.00-44.00 sec 2.67 GBytes 22.9 Gbits/sec 0 3.04 MBytes [ 5] 44.00-45.00 sec 2.94 GBytes 25.2 Gbits/sec 0 3.04 MBytes [ 5] 45.00-46.00 sec 3.16 GBytes 27.1 Gbits/sec 0 3.04 MBytes [ 5] 46.00-47.00 sec 3.33 GBytes 28.6 Gbits/sec 0 3.04 MBytes [ 5] 47.00-48.00 sec 3.11 GBytes 26.7 Gbits/sec 0 3.04 MBytes [ 5] 48.00-49.00 sec 2.62 GBytes 22.5 Gbits/sec 0 3.04 MBytes [ 5] 49.00-50.00 sec 2.77 GBytes 23.8 Gbits/sec 0 3.04 MBytes [ 5] 50.00-51.00 sec 2.79 GBytes 23.9 Gbits/sec 0 3.04 MBytes [ 5] 51.00-52.00 sec 2.19 GBytes 18.8 Gbits/sec 0 3.04 MBytes [ 5] 52.00-53.00 sec 3.29 GBytes 28.3 Gbits/sec 2229 2.30 MBytes [ 5] 53.00-54.00 sec 3.80 GBytes 32.6 Gbits/sec 0 2.43 MBytes [ 5] 54.00-55.00 sec 5.08 GBytes 43.6 Gbits/sec 0 2.60 MBytes [ 5] 55.00-56.00 sec 5.18 GBytes 44.5 Gbits/sec 0 2.62 MBytes [ 5] 56.00-57.00 sec 5.35 GBytes 46.0 Gbits/sec 0 2.74 MBytes [ 5] 57.00-58.00 sec 5.14 GBytes 44.2 Gbits/sec 0 2.89 MBytes [ 5] 58.00-59.00 sec 5.28 GBytes 45.4 Gbits/sec 0 2.93 MBytes [ 5] 59.00-60.00 sec 5.22 GBytes 44.9 Gbits/sec 0 2.97 MBytes [ 5] 60.00-61.00 sec 4.97 GBytes 42.7 Gbits/sec 0 2.99 MBytes [ 5] 61.00-62.00 sec 4.78 GBytes 41.1 Gbits/sec 0 3.02 MBytes [ 5] 62.00-63.00 sec 5.14 GBytes 44.1 Gbits/sec 0 3.02 MBytes [ 5] 63.00-64.00 sec 5.06 GBytes 43.5 Gbits/sec 0 3.02 MBytes [ 5] 64.00-65.00 sec 5.02 GBytes 43.1 Gbits/sec 0 3.02 MBytes [ 5] 65.00-66.00 sec 5.07 GBytes 43.5 Gbits/sec 0 3.02 MBytes [ 5] 66.00-67.00 sec 5.34 GBytes 45.9 Gbits/sec 0 3.02 MBytes [ 5] 67.00-68.00 sec 4.99 GBytes 42.9 Gbits/sec 0 3.02 MBytes [ 5] 68.00-69.00 sec 5.17 GBytes 44.4 Gbits/sec 0 3.02 MBytes [ 5] 69.00-70.00 sec 5.39 GBytes 46.3 Gbits/sec 0 3.02 MBytes [ 5] 70.00-70.29 sec 1.57 GBytes 46.0 Gbits/sec 0 3.02 MBytes - - - - - - - - - - - - - - - - - - - - - - - - - [ ID] Interval Transfer Bitrate Retr [ 5] 0.00-70.29 sec 260 GBytes 31.8 Gbits/sec 2229 sender [ 5] 0.00-70.29 sec 0.00 Bytes 0.00 bits/sec receiver
보시다시피 TCP 연결은 마이그레이션을 견뎌냈고 다운타임도 없었습니다. 단지 52~53초 동안 약간의 문제가 발생했을 뿐입니다.
NetworkPolicy 통합
이전 섹션에서 동서 연결에 대해 설명했는데, 웹 서버 포드에 어떻게 접속할 수 있었는지 기억하시나요? 그런 일이 발생하지 않도록 네트워크 정책을 프로비저닝해 보겠습니다. TCP 포트 9001을 통한 수신 트래픽만 허용하는 더 유용한 네트워크 정책을 프로비저닝해 보겠습니다.
다음 매니페스트를 참조하세요.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ingress-port-9001-only
namespace: green
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- ports:
- protocol: TCP
port: 9001이 정책이 프로비저닝되면 VM은 더 이상 웹 서버 포드에 액세스할 수 없습니다. 하지만 올바른 포트(예: 9001)를 수신하는 다른 웹 서버를 만들어 보겠습니다.
---
apiVersion: v1
kind: Pod
metadata:
name: new-webserver
namespace: green
spec:
containers:
- args:
- "netexec"
- "--http-port"
- "9001"
image: registry.k8s.io/e2e-test-images/agnhost:2.45
imagePullPolicy: IfNotPresent
name: agnhost-container
nodeName: ovn-worker
restartPolicy: Always
securityContext: {}
serviceAccount: default
serviceAccountName: default접근해 보겠습니다.
# example for a pod named new-webserver, which listens on port 9001
kubectl get pods -ngreen new-webserver -ojsonpath="{@.metadata.annotations.k8s\.v1\.cni\.cncf\.io\/network-status}" | jq
[
{
"name": "ovn-kubernetes",
"interface": "eth0",
"ips": [
"10.244.1.13"
],
"mac": "0a:58:0a:f4:01:0d",
"dns": {}
},
{
"name": "ovn-kubernetes",
"interface": "ovn-udn1",
"ips": [
"203.203.0.8"
],
"mac": "0a:58:cb:cb:00:08",
"default": true,
"dns": {}
}
]
virtctl console -ngreen vm-a
Successfully connected to vm-a console. The escape sequence is ^]
[fedora@vm-a ~]$ curl 203.203.0.8:9001/hostname
new-webserver상호 연결된 네임스페이스 격리
이 다른 사용 사례를 통해 사용자는 필요에 따라 여러 네임스페이스를 연결할 수 있습니다. 이렇게 상호 연결된 네임스페이스는 격리된 네트워크에 연결된 모든 워크로드에서 접근 가능하지만, 다른 클러스터 전체 UDN 또는 클러스터 기본 네트워크에 연결된 워크로드에서는 접근할 수 없습니다.
그림 2에서 이 개념의 그래픽 표현을 볼 수 있는데, 빨간색과 파란색 네임스페이스의 포드는 해피 네트워크를 통해 서로 통신할 수 있지만, 슬픈 네트워크에 연결된 주황색과 녹색 네임스페이스에는 연결되어 있지 않습니다.

이 사용 사례를 구현하려면 사용자는 ClusterUserDefinedNetwork라는 별도의 CR을 프로비저닝해야 합니다. 이는 클러스터 관리자만 프로비저닝할 수 있는 클러스터 전체 리소스입니다. 네트워크를 정의하고 해당 네트워크로 상호 연결되는 네임스페이스를 지정할 수 있습니다.
이 시나리오는 다음 YAML 매니페스트를 적용하여 구성됩니다.
---
apiVersion: v1
kind: Namespace
metadata:
name: red-namespace
labels:
k8s.ovn.org/primary-user-defined-network: ""
---
apiVersion: v1
kind: Namespace
metadata:
name: blue-namespace
labels:
k8s.ovn.org/primary-user-defined-network: ""
---
apiVersion: k8s.ovn.org/v1
kind: ClusterUserDefinedNetwork
metadata:
name: happy-tenant
spec:
namespaceSelector:
matchExpressions:
- key: kubernetes.io/metadata.name
operator: In
values:
- red-namespace
- blue-namespace
network:
topology: Layer2
layer2:
role: Primary
ipam:
lifecycle: Persistent
subnets:
- 203.203.0.0/16
---
apiVersion: v1
kind: Namespace
metadata:
name: orange-namespace
labels:
k8s.ovn.org/primary-user-defined-network: ""
---
apiVersion: v1
kind: Namespace
metadata:
name: green-namespace
labels:
k8s.ovn.org/primary-user-defined-network: ""
---
apiVersion: k8s.ovn.org/v1
kind: ClusterUserDefinedNetwork
metadata:
name: happy-tenant
spec:
namespaceSelector:
matchExpressions:
- key: kubernetes.io/metadata.name
operator: In
values:
- orange-namespace
- green-namespace
network:
topology: Layer2
layer2:
role: Primary
ipam:
lifecycle: Persistent
subnets:
- 192.168.0.0/16보시다시피 UserDefinedNetwork CRD와 두 가지 차이점이 있습니다.
- 클러스터 전체 리소스입니다(즉,
metadata.namespace없음) - 관리자가 상호 연결할 네임스페이스를 나열할 수 있는
spec.namespace선택기를 찾습니다.
후자의 구성은 Kubernetes 표준 네임스페이스 선택기입니다.
이 시나리오는 다른 CRD를 사용하여 구성되지만, 기본 네임스페이스 격리 사용 사례를 구성하는 UserDefinedNetwork CRD에 사용 가능한 모든 기능 세트는 상호 연결된 네임스페이스 격리 시나리오에 사용할 수 있습니다. 따라서 이 다른 사용 사례에서는 동서 연결, 인터넷으로의 이탈, 원활한 라이브 마이그레이션 및 네트워크 정책 통합이 모두 가능합니다.
ClusterUserDefinedNetwork CRD를 사용하여 서비스 통합을 보여드리겠습니다(하지만 동일한 기능은 UDN CRD를 통해 구성되는 네임스페이스 격리 사용 사례에도 사용 가능합니다).
서비스
Kubernetes 서비스를 사용하여 UDN(또는 cUDN)에 연결된 VM을 노출할 수 있습니다. 일반적인 사용 사례는 VM에서 실행 중인 애플리케이션을 외부에 노출하는 것입니다.
HTTP 서버를 실행할 VM을 만들어 보겠습니다. 다음 YAML을 프로비저닝하세요.
---
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
labels:
kubevirt.io/vm: red
name: red
namespace: red-namespace
spec:
runStrategy: Always
template:
metadata:
labels:
app.kubernetes.io/name: nginx
spec:
domain:
devices:
disks:
- disk:
bus: virtio
name: containerdisk
- disk:
bus: virtio
name: cloudinitdisk
interfaces:
- name: happy
binding:
name: l2bridge
rng: {}
resources:
requests:
memory: 2048M
networks:
- pod: {}
name: happy
terminationGracePeriodSeconds: 0
volumes:
- containerDisk:
image: quay.io/kubevirt/fedora-with-test-tooling-container-disk:v1.4.0
name: containerdisk
- cloudInitNoCloud:
userData: |-
#cloud-config
password: fedora
chpasswd: { expire: False }
packages:
- nginx
runcmd:
- [ "systemctl", "enable", "--now", "nginx" ]
name: cloudinitdisk이 VM은 기본적으로 80번 포트에서 웹 서버를 실행하는 nginx를 실행합니다. 이제 이 포트를 클러스터 외부에 노출하는 로드 밸런서 서비스를 프로비저닝해 보겠습니다. 이를 위해 다음 YAML 파일을 프로비저닝합니다.
apiVersion: v1 kind: Service metadata: name: webapp namespace: red-namespace spec: selector: app.kubernetes.io/name: nginx ports: - protocol: TCP port: 80 targetPort: 80 type: LoadBalancer
이제 서비스 상태를 확인할 수 있습니다.
kubectl get service -nred-namespace webapp -oyaml apiVersion: v1 kind: Service metadata: ... name: webapp namespace: red-namespace resourceVersion: "588976" uid: 9d8a723f-bd79-48e5-95e7-3e235c023314 spec: allocateLoadBalancerNodePorts: true clusterIP: 172.30.162.106 clusterIPs: - 172.30.162.106 externalTrafficPolicy: Cluster internalTrafficPolicy: Cluster ipFamilies: - IPv4 ipFamilyPolicy: SingleStack ports: - nodePort: 30600 port: 80 protocol: TCP targetPort: 80 selector: app.kubernetes.io/name: redvm sessionAffinity: None type: LoadBalancer status: loadBalancer: ingress: - ip: 192.168.10.0 ipMode: VIP # lets ensure we have endpoints ... kubectl get endpoints -nred-namespace NAME ENDPOINTS AGE webapp 10.132.2.66:80 16m
서비스 상태를 통해 노출된 VM에 액세스하는 데 사용할 IP 주소를 파악할 수 있습니다.
클러스터 외부에서 접근해 보겠습니다.
curl -I 192.168.10.0 HTTP/1.1 200 OK Server: nginx/1.22.1 Date: Tue, 11 Mar 2025 18:09:12 GMT Content-Type: text/html Content-Length: 8474 Last-Modified: Fri, 26 Mar 2021 17:49:58 GMT Connection: keep-alive ETag: "605e1ec6-211a" Accept-Ranges: bytes
결론
이 글에서는 주요 UDN 기능을 소개하고, 이 기능을 사용하여 OpenShift 클러스터에서 가상화 워크로드에 대한 기본 네트워크 세분화를 제공하고 네임스페이스 격리를 달성하거나 선택한 네임스페이스를 상호 연결하는 방법을 설명했습니다.
또한 UDN 기능이 Kubernetes API와 기본적으로 통합되는 방식을 보여드렸으며, 이를 통해 사용자는 Kubernetes 서비스를 사용하여 UDN에 연결된 워크로드를 노출하고 UDN에 마이크로 세그먼테이션을 작성하여 UDN에서 허용되는 트래픽을 더욱 제한할 수 있습니다.
자세히 알아보세요: