Red Hat OpenShift 가상화를 위한 Localnet UDN 예시

OpenShift 가상화 VM을 CUDN Localnet 네트워크를 통해 IBM Cloud VPC 서브넷에 연결하여, VLAN 기반의 네임스페이스 격리 트래픽을 구현합니다.

이 튜토리얼에서는 IBM Cloud 의 Red Hat OpenShift on IBM Cloud 에서 가상 사설 클라우드(VPC) 서브넷, 클러스터 사용자 정의 네트워크(CUDN), 로컬넷 및 네임스페이스를 사용하여 3계층 애플리케이션 예제를 만드는 방법을 설명합니다. 이 예제에서는 가상 로컬 영역 네트워크(VLAN) 기반의 localnet 네트워크를 사용하여, ‘ Red Hat OpenShift Virtualization’에서 실행되는 가상 서버를 VPC 서브넷에 직접 연결하는 방법을 보여줍니다. 네트워크 유형에 대한 자세한 내용은 ‘ vSphere® ’ 관리자를 위한 ‘ Red Hat OpenShift ’의 ‘Open Virtual Network(OVN)네트워킹’을 참조하십시오.

개요

이 예제에서는 웹 계층, 데이터베이스 계층, 애플리케이션 계층에 대해 각각 별도의 네트워크 세그먼트를 사용하는 3계층 애플리케이션을 배포합니다. 각 계층은 전용 VPC 서브넷과 고유한 VLAN ID를 가진 로컬넷 CUDN을 사용합니다. 네임스페이스 기반 격리를 보여주기 위해 웹 및 데이터베이스 계층은 하나의 네임스페이스(green)에 배치되고, 애플리케이션 계층은 별도의 네임스페이스(red)에 배치됩니다.

네트워크, 네임스페이스 및 가상 서버 세부 정보

다음 표는 예시 네트워크 구성을 요약한 것입니다.

Localnet CUDN, 네임스페이스 및 가상 서버 구성 예시
Localnet CUDN 네임스페이스 VLAN ID VPC 서브넷 가상 서버
vlan20-prod green 20 198.18.0.0/24 plant-web00, plant-web01
vlan21-db green 21 198.18.1.0/24 plant-db00, plant-db01
vlan22-app red 22 198.18.2.0/24 plant-app00, plant-app01

최종 구성도

Localnet 3계층 애플리케이션 구성
Localnet 3계층 애플리케이션 구성

이 가이드에 있는 각 코드 블록은 파일에 복사한 후 oc apply -f .yml`` 명령어를 사용하여 적용할 수 있습니다. PDF 및 Word 형식에서는 일부 코드 블록이 페이지 경계를 넘을 수 있으며, 일부 긴 줄은 해당 형식에서 줄바꿈될 수 있습니다.

이 가이드에서는 IBM Cloud CLI 명령어에서 ibmcloud 을 나타내는 약어로 ic 을 사용합니다. 셸에서 alias ic=ibmcloud 을 정의하거나, 다음 명령어에서 ic 을 ibmcloud 으로 대체하십시오.

시작하기 전에

다음 항목들이 모두 준비되어 있는지 확인하십시오:

  • VPC 및 Red Hat OpenShift 리소스를 관리할 수 있는 권한이 있는 IBM Cloud 계정.
  • IBM Cloud CLI가 설치되었습니다.
  • container-service 와 vpc-infrastructure 플러그인이 설치되었습니다.

container-service 플러그인은 이 가이드에서 VLAN 가상 네트워크 인터페이스(VNI)를 클러스터에 연결하는 데 사용하는 ic ks 명령을 제공합니다. vpc-infrastructure 플러그인은 이 가이드에서 VPC 서브넷, 가상 네트워크 인터페이스(VNI) 및 기타 인프라를 생성하는 데 사용하는 ic is 명령어를 제공합니다.

필요한 CLI 플러그인을 설치해야 하는 경우, 다음 명령어를 사용하십시오.

ibmcloud plugin install container-service
ibmcloud plugin install vpc-infrastructure

네트워크 전제 조건 검토

Red Hat OpenShift on IBM Cloud 를 사용 중인 경우, 시작하기 전에 Red Hat OpenShift on IBM Cloud 에서 OVN UDN/CUDN 네트워크 필수 구성 요건을 확인하십시오. Red Hat OpenShift Virtualization Service는 기본적으로 이러한 필수 구성 요건을 포함하고 있습니다.

그린 티어를 위한 네임스페이스 및 CUDN Localnet 보조 네트워크 생성

로컬넷(Localnet) 네트워크는 네임스페이스 내에서 로컬넷( Layer 2 ) 기본 네트워크, 로컬넷( Layer 2 ) 보조 네트워크 및 다른 로컬넷과 공존할 수 있습니다. 각 로컬넷에는 VLAN ID 가 필요합니다. 현재 VLAN당 하나의 서브넷만 사용할 수 있습니다.

VLAN은 워커 간에 Layer 2 도메인을 생성하지 않습니다. VLAN은 VPC 내부가 아닌 각 워커 노드 내에서 사용됩니다.

green 네임스페이스와 vlan20-prod 및 vlan21-db 네트워크를 생성합니다. oc apply -f step1.yml 를 사용하여 매니페스트를 적용합니다.

---
apiVersion: v1
kind: Namespace
metadata:
  name: green
---
apiVersion: k8s.ovn.org/v1
kind: ClusterUserDefinedNetwork
metadata:
  name: "vlan20-prod"
spec:
  namespaceSelector:
    matchExpressions:
    - key: kubernetes.io/metadata.name
      operator: In
      values:
      - "green"
  network:
    topology: Localnet
    localnet:
      role: "Secondary"
      physicalNetworkName: "vpc-vlans"
      ipam:
        mode: Disabled
      vlan:
        mode: Access
        access:
          id: 20
---
apiVersion: k8s.ovn.org/v1
kind: ClusterUserDefinedNetwork
metadata:
  name: "vlan21-db"
spec:
  namespaceSelector:
    matchExpressions:
    - key: kubernetes.io/metadata.name
      operator: In
      values:
      - "green"
  network:
    topology: Localnet
    localnet:
      role: "Secondary"
      physicalNetworkName: "vpc-vlans"
      ipam:
        mode: Disabled
      vlan:
        mode: Access
        access:
          id: 21

다음 사항을 유의하시기 바랍니다:

  • Localnet 구성에 서브넷이 정의되어 있지 않습니다.
  • VLAN 1 를 사용하지 마십시오.
  • 2에서 500 사이의 범위에 속하는 VLAN을 사용하십시오. 현재 VLAN 501~4094는 사용이 제한되어 있습니다.

레드 티어를 위해 별도의 네임스페이스와 CUDN Localnet 보조 네트워크 생성

red 네임스페이스와 vlan22-app 네트워크를 생성합니다. oc apply -f step2.yml 를 사용하여 매니페스트를 적용합니다.

---
apiVersion: v1
kind: Namespace
metadata:
  name: red
---
apiVersion: k8s.ovn.org/v1
kind: ClusterUserDefinedNetwork
metadata:
  name: "vlan22-app"
spec:
  namespaceSelector:
    matchExpressions:
    - key: kubernetes.io/metadata.name
      operator: In
      values:
      - "red"
  network:
    topology: Localnet
    localnet:
      role: "Secondary"
      physicalNetworkName: "vpc-vlans"
      ipam:
        mode: Disabled
      vlan:
        mode: Access
        access:
          id: 22

VPC 계정에서 예약된 IP 및 VNI 생성하기

이 단계에서는 각 서브넷에 예약된 IP 주소를 생성한 다음, 해당 예약된 IP 주소를 사용하여 VNI를 생성하고 각 가상 네트워크 인터페이스에 MAC address 를 할당합니다(VNI).

다음 사항을 유의하시기 바랍니다:

  • 이 단계에서는 ‘ VLAN ID ’ 파일이 첨부되어 있지 않습니다.
  • 이 단계에서 사용할 보안 그룹을 반드시 확인해야 합니다. ic is sgs 를 실행하여 사용 가능한 보안 그룹을 나열합니다.
  • 이 단계를 일괄 처리할 수 있습니다.
  • 호스트당 256개의 VNI가 상한선입니다. 다른 호스트로부터의 장애 조치 및 마이그레이션을 대비하여 사용률을 85% 미만으로 유지하십시오.

각 서브넷에 예약된 IP 주소 생성

먼저, 가상 서버를 위해 각 서브넷에 예약된 IP 주소를 생성합니다:

ic is subnet-reserved-ip-create zone1-vm-prod --address 198.18.0.20 --name zone1-web00 --auto-delete false
ic is subnet-reserved-ip-create zone1-vm-db --address 198.18.1.20 --name zone1-db00 --auto-delete false
ic is subnet-reserved-ip-create zone1-vm-app --address 198.18.2.20 --name zone1-app00 --auto-delete false

예약된 IP를 사용하여 VNI 생성하기

이제 이전 단계에서 예약한 IP 이름을 사용하여 VNI를 생성합니다:

ic is virtual-network-interface-create --name zone1-web00 --allow-ip-spoofing false --auto-delete false --protocol-state-filtering-mode disabled --enable-infrastructure-nat true --subnet zone1-vm-prod --vpc my-vpc --rip zone1-web00 --sgs handclap-roundworm-clique-eccentric --resource-group-name Default
ic is virtual-network-interface-create --name zone1-db00 --allow-ip-spoofing false --auto-delete false --protocol-state-filtering-mode disabled --enable-infrastructure-nat true --subnet zone1-vm-db --vpc my-vpc --rip zone1-db00 --sgs handclap-roundworm-clique-eccentric --resource-group-name Default
ic is virtual-network-interface-create --name zone1-app00 --allow-ip-spoofing false --auto-delete false --protocol-state-filtering-mode disabled --enable-infrastructure-nat true --subnet zone1-vm-app --vpc my-vpc --rip zone1-app00 --sgs handclap-roundworm-clique-eccentric --resource-group-name Default

클러스터에 VLAN VNI 연결하기

이전 단계에서 생성한 각 VNI의 ID를 확인한 다음, ‘ IBM Cloud ’ container-service 플러그인을 사용하여 VNI를 클러스터에 연결하십시오. 클러스터 ID가 필요합니다. 이 ID는 ic ks cluster ls`` 명령을 실행하여 확인할 수 있습니다.

다음 사항을 유의하시기 바랍니다:

  • 작업자가 VNI 할당량을 초과하면, 해당 작업이 실패합니다.
  • VNI는 클러스터( floating 라고도 함)나 특정 워커에 연결할 수 있습니다.

VNI ID를 조회하세요.

ic is vni zone1-web00 | awk '$1 ~ /^ID/ {print $NF}'
ic is vni zone1-db00 | awk '$1 ~ /^ID/ {print $NF}'
ic is vni zone1-app00 | awk '$1 ~ /^ID/ {print $NF}'

각 VNI를 해당 VLAN ID와 일치하도록 클러스터에 연결하십시오. 클러스터 ID 와 VNI ID를 사용자의 환경에 맞는 값으로 대체하십시오.

ic ks vni attach baremetal -c <CLUSTER_ID> --vni <VNI_ID_web00> --vlan 20
ic ks vni attach baremetal -c <CLUSTER_ID> --vni <VNI_ID_db00>  --vlan 21
ic ks vni attach baremetal -c <CLUSTER_ID> --vni <VNI_ID_app00> --vlan 22

네임스페이스에 가상 서버 추가하기

다음 매니페스트는 가상 서버 하나를 생성하기 위한 최소한의 YAML 예제입니다. 각 네임스페이스 및 네트워크별로 이 매니페스트를 업데이트할 수 있습니다. 생성한 각 VNI 에 대해 MAC address 가 필요합니다. ic is vnis 를 실행하여 목록을 확인한 후, 템플릿의 ‘ macAddress ’ 필드를 수정하여 DHCP 가 정상적으로 작동하도록 하세요.

다음 명령어를 사용하여 각 VNI 에 대한 MAC address 를 확인하십시오.

ic is vni zone1-web00 | awk '/^Mac Address/ {print $NF}'
ic is vni zone1-db00  | awk '/^Mac Address/ {print $NF}'
ic is vni zone1-app00 | awk '/^Mac Address/ {print $NF}'

각 VNI 에 대한 출력 예시. 두 분의 가치관이 다릅니다:

02:00:01:00:98:A0
02:00:02:00:98:A5
02:00:02:00:98:AA

매니페스트를 적용하기 전에 다음 사항을 유의하시기 바랍니다:

  • 각 매니페스트에서 비밀번호를 업데이트하십시오.
  • 로그인하려면 ‘ ssh_authorized_keys ’ 필드에 실제 SSH 공개 키를 입력해야 합니다.
  • 비밀번호를 사용하여 SSH를 사용할 수 없습니다.
  • 모든 macAddress 값을, 앞서 실행한 명령어를 통해 조회한 해당 VNI의 MAC 주소로 대체하십시오. DHCP 가 예상된 IP 주소를 할당하려면 macAddress 가 VNI와 일치해야 합니다.

oc apply -f <file-name>.yml 를 사용하여 다음 매니페스트를 각각 적용하십시오. 다음 링크를 클릭하면 각 매니페스트로 바로 이동할 수 있습니다.

green 네임스페이스에 있는 가상 서버 plant-web00 (위치: vlan20-prod

# Bare YAML to stand up a Red Hat OpenShift on IBM Cloud virtual machine
---
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: "plant-web00"
  namespace: "green"
  annotations:
    description: "example vm plant-web00"
  labels:
    app: "plant-web00-green-server"
    kubevirt.io/dynamic-credentials-support: 'true'
    vm.kubevirt.io/template: "centos-stream9-server-small"
    vm.kubevirt.io/template.namespace: openshift
    vm.kubevirt.io/template.revision: '1'
    vm.kubevirt.io/template.version: v0.34.0
spec:
  dataVolumeTemplates:
    - apiVersion: cdi.kubevirt.io/v1beta1
      kind: DataVolume
      metadata:
        creationTimestamp: null
        name: "plant-web00-green-server"
      spec:
        sourceRef:
          kind: DataSource
          name: "centos-stream9"
          namespace: openshift-virtualization-os-images
        storage:
          resources:
            requests:
              storage: 30Gi
  runStrategy: RerunOnFailure
  template:
    metadata:
      annotations:
        vm.kubevirt.io/flavor: "small"
        vm.kubevirt.io/os: "centos-stream9"
        vm.kubevirt.io/workload: "server"
      labels:
        kubevirt.io/domain: example
        kubevirt.io/size: "small"
    spec:
      domain:
        cpu:
          cores: 1
          sockets: 1
          threads: 1
        devices:
          disks:
            - disk:
                bus: virtio
              name: rootdisk
            - disk:
                bus: virtio
              name: cloudinitdisk
          interfaces:
            - model: virtio
              name: default
              state: up
              bridge: {}
              macAddress: 02:00:01:00:98:A0 # <- replace with the MAC of VNI zone1-web00
          networkInterfaceMultiqueue: true
          rng: {}
        memory:
          guest: "2Gi"
      hostname: "plant-web00"
      networks:
        - name: default
          multus:
            networkName: vlan20-prod
      terminationGracePeriodSeconds: 180
      volumes:
        - dataVolume:
            name: "plant-web00-green-server"
          name: rootdisk
        - cloudInitNoCloud:
            userData: |-
              #cloud-config
              user: admin
              password: "aRandomPassword9292"
              ssh_authorized_keys:
                 - "ssh-ed25519 AAAA....BBBB....CCCCC.....DDDD put-your-key-here@example.local"
              chpasswd: { expire: False }
              runcmd:
                - [ dnf, install, -y, epel-release ]
                - [ dnf, install, -y, iperf3, nmap-ncat, darkhttpd ]
          name: cloudinitdisk

green 네임스페이스에 있는 가상 서버 plant-db00 (위치: vlan21-db

---
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: "plant-db00"
  namespace: "green"
  annotations:
    description: "example vm plant-db00"
  labels:
    app: "plant-db00-green-server"
    kubevirt.io/dynamic-credentials-support: 'true'
    vm.kubevirt.io/template: "centos-stream9-server-small"
    vm.kubevirt.io/template.namespace: openshift
    vm.kubevirt.io/template.revision: '1'
    vm.kubevirt.io/template.version: v0.34.0
spec:
  dataVolumeTemplates:
    - apiVersion: cdi.kubevirt.io/v1beta1
      kind: DataVolume
      metadata:
        creationTimestamp: null
        name: "plant-db00-green-server"
      spec:
        sourceRef:
          kind: DataSource
          name: "centos-stream9"
          namespace: openshift-virtualization-os-images
        storage:
          resources:
            requests:
              storage: 30Gi
  runStrategy: RerunOnFailure
  template:
    metadata:
      annotations:
        vm.kubevirt.io/flavor: "small"
        vm.kubevirt.io/os: "centos-stream9"
        vm.kubevirt.io/workload: "server"
      labels:
        kubevirt.io/domain: example
        kubevirt.io/size: "small"
    spec:
      domain:
        cpu:
          cores: 1
          sockets: 1
          threads: 1
        devices:
          disks:
            - disk:
                bus: virtio
              name: rootdisk
            - disk:
                bus: virtio
              name: cloudinitdisk
          interfaces:
            - model: virtio
              name: default
              state: up
              bridge: {}
              macAddress: 02:00:01:00:98:A5 # <- replace with the MAC of VNI zone1-db00
          networkInterfaceMultiqueue: true
          rng: {}
        memory:
          guest: "2Gi"
      hostname: "plant-db00"
      networks:
        - name: default
          multus:
            networkName: vlan21-db
      terminationGracePeriodSeconds: 180
      volumes:
        - dataVolume:
            name: "plant-db00-green-server"
          name: rootdisk
        - cloudInitNoCloud:
            userData: |-
              #cloud-config
              user: admin
              password: "aRandomPassword9292"
              ssh_authorized_keys:
                 - "ssh-ed25519 AAAA....BBBB....CCCCC.....DDDD put-your-key-here@example.local"
              chpasswd: { expire: False }
              runcmd:
                - [ dnf, install, -y, epel-release ]
                - [ dnf, install, -y, iperf3, nmap-ncat, darkhttpd ]
          name: cloudinitdisk

red 네임스페이스에 있는 가상 서버 plant-app00 (위치: vlan22-app

---
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: "plant-app00"
  namespace: "red"
  annotations:
    description: "example vm plant-app00"
  labels:
    app: "plant-app00-red-server"
    kubevirt.io/dynamic-credentials-support: 'true'
    vm.kubevirt.io/template: "centos-stream9-server-small"
    vm.kubevirt.io/template.namespace: openshift
    vm.kubevirt.io/template.revision: '1'
    vm.kubevirt.io/template.version: v0.34.0
spec:
  dataVolumeTemplates:
    - apiVersion: cdi.kubevirt.io/v1beta1
      kind: DataVolume
      metadata:
        creationTimestamp: null
        name: "plant-app00-red-server"
      spec:
        sourceRef:
          kind: DataSource
          name: "centos-stream9"
          namespace: openshift-virtualization-os-images
        storage:
          resources:
            requests:
              storage: 30Gi
  runStrategy: RerunOnFailure
  template:
    metadata:
      annotations:
        vm.kubevirt.io/flavor: "small"
        vm.kubevirt.io/os: "centos-stream9"
        vm.kubevirt.io/workload: "server"
      labels:
        kubevirt.io/domain: example
        kubevirt.io/size: "small"
    spec:
      domain:
        cpu:
          cores: 1
          sockets: 1
          threads: 1
        devices:
          disks:
            - disk:
                bus: virtio
              name: rootdisk
            - disk:
                bus: virtio
              name: cloudinitdisk
          interfaces:
            - model: virtio
              name: default
              state: up
              bridge: {}
              macAddress: 02:00:01:00:98:AA # <- replace with the MAC of VNI zone1-app00
          networkInterfaceMultiqueue: true
          rng: {}
        memory:
          guest: "2Gi"
      hostname: "plant-app00"
      networks:
        - name: default
          multus:
            networkName: vlan22-app
      terminationGracePeriodSeconds: 180
      volumes:
        - dataVolume:
            name: "plant-app00-red-server"
          name: rootdisk
        - cloudInitNoCloud:
            userData: |-
              #cloud-config
              user: admin
              password: "aRandomPassword9292"
              ssh_authorized_keys:
                 - "ssh-ed25519 AAAA....BBBB....CCCCC.....DDDD put-your-key-here@example.local"
              chpasswd: { expire: False }
              runcmd:
                - [ dnf, install, -y, epel-release ]
                - [ dnf, install, -y, iperf3, nmap-ncat, darkhttpd ]
          name: cloudinitdisk

네트워크 설정 테스트

IBM 이러한 테스트를 수행할 때는 클러스터와 동일한 VPC 내에 있는 Linux® 점프 호스트를 사용할 것을 권장합니다. Jump 호스트에서 SSH를 사용하여 가상 서버 설정 시 지정한 공개 키로 각 가상 서버에 연결하십시오.

SSH 에이전트 전달을 설정하거나, 점프 호스트에 호스팅된 새 키를 사용하십시오. 개인 키를 시스템 간에 복사하지 마십시오.

터미널 세션 하나에서 SSH를 사용하여 웹 계층 가상 서버에 연결합니다:

ssh admin@198.18.0.20

다른 터미널 세션에서 SSH를 사용하여 데이터베이스 계층 가상 서버에 연결합니다:

ssh admin@198.18.1.20

다른 터미널 세션에서 SSH를 사용하여 애플리케이션 계층 가상 서버에 연결합니다:

ssh admin@198.18.2.20

테스트

네트워크 설정을 확인하려면 다음 테스트를 실행하십시오.

  1. 각 가상 서버에서 간단한 HTTP 서버를 시작합니다.

    • 198.18.0.20 에서 darkhttpd /usr/share/doc/bash --daemon 를 실행하십시오.
    • 198.18.1.20 에서 darkhttpd /usr/share/doc/bash --daemon 를 실행하십시오.
    • 198.18.2.20 에서 darkhttpd /usr/share/doc/bash --daemon 를 실행하십시오.
  2. 198.18.0.20 에서 curl -v http://198.18.1.20:8080 를 실행하십시오.

  3. 198.18.1.20 에서 curl -v http://198.18.0.20:8080 를 실행하십시오.

  4. jump 가상 서버에서 curl -v http://198.18.2.20:8080 을 실행하십시오.

  5. 198.18.1.20 에서 iperf3 서버를 시작합니다: iperf3 -s -p 9090.

  6. 198.18.0.20 에서 green 네임스페이스에 있는 iperf3 서버에 연결합니다: iperf3 -c 198.18.1.20 -p 9090.

  7. 198.18.1.20 에서 198.18.0.20 으로, 그리고 그 반대로 핑을 보내보세요.

  8. 198.18.2.20 와 점프 가상 서버의 IP 주소를 사용하여 앞서 수행한 작업을 다시 실행하십시오.

다중 네트워크 정책을 적용하고 테스트를 다시 실행하기

vlan20-prod 네트워크에 대해 TCP 의 8080번 포트만 허용하는 다중 네트워크 정책을 적용하십시오. 다음 매니페스트를 ‘ my-policy.yml ’라는 이름의 파일로 저장하십시오. 그런 다음, oc apply -f my-policy.yml 을 실행하여 적용하십시오.

---
apiVersion: k8s.ovn.org/v1alpha1
kind: MultiNetworkPolicy
metadata:
  name: allow-8080-tcp
  namespace: green
  annotations:
    k8s.v1.cni.cncf.io/policy-for: vlan20-prod
spec:
  podSelector: {}
  ingress:
    - ports:
        - protocol: TCP
          port: 8080
  egress:
    - ports:
        - protocol: TCP
          port: 8080
  policyTypes:
    - Ingress
    - Egress

vlan20-prod 에서 plant-web00 에 대한 테스트 를 다시 실행하십시오. TCP 8080번 포트는 여전히 작동하지만, ping 이나 9090번 포트의 iperf3 테스트와 같은 다른 트래픽은 해당 네트워크 연결에서 더 이상 작동하지 않습니다.

oc delete -f my-policy.yml 를 실행하여 정책을 제거하고 연결을 복원하십시오. 테스트가 다시 통과되었습니다.