Standalone CIS Default Mode – BIG-IP CIS Multi-Cluster 구성

Standalone CIS(Container Ingress Services)는 단일 CIS 인스턴스로 여러 Kubernetes/OpenShift 클러스터를 하나의 BIG-IP에서 통합 관리할 수 있는 Multi-Cluster 구성 방식입니다.
동일한 목적의 클러스터를 BIG-IP 레벨에서 통합함으로써, 클러스터 단위의 고가용성 구성을 구현할 수 있습니다.

이번 포스트에서는 서로 다른 버전의 OpenShift 클러스터 2개를 대상으로 Standalone CIS를 Default Mode로 구성하고, 두 클러스터에 Pod를 배포한 후 CIS의 VirtualServer 리소스를 배포하여 BIG-IP Pool Member로 정상 등록되는지 확인하는 과정을 살펴보겠습니다.

이번 포스트의 내용은 BIG-IP CIS의 Static Route를 통한 ClusterIP 모드로 구성되었습니다.

목차

1. Standalone CIS Default Mode란?
  1-1. 동작 방식
2. 환경/버전 정보
3. Standalone CIS 구성 전 사전 준비
  3-1. 보조 클러스터 접근을 위한 kubeconfig Secret 생성
  3-2. Default Mode Extended ConfigMap 생성
4. Standalone CIS – Default Mode 배포
5. VirtualServer 구성 및 BIG-IP Pool 확인
6. 결론

1. Standalone CIS Default Mode란?

Standalone CIS Default Mode는 단일 CIS 인스턴스가 여러 Kubernetes/OpenShift 클러스터를 관리하는 Multi-Cluster 구성 방식입니다. CIS가 배포된 로컬 클러스터뿐만 아니라, kubeconfig를 통해 연결된 외부 클러스터의 리소스도 함께 조회하여 BIG-IP Pool Member로 등록합니다.

CIS의 Multi-Cluster 구성 방식은 크게 두 가지로 나뉩니다. Standalone CIS는 단일 CIS 인스턴스가 여러 클러스터를 관리하는 방식이며, High Availability CIS는 여러 클러스터 중 두 클러스터에 CIS 인스턴스를 배포하여 이중화된 CIS 구성을 갖추는 방식입니다.
또한 Multi-Cluster 구성에서는 트래픽 분배 방식에 따라 Default Mode와 Ratio Mode를 선택할 수 있습니다. Default Mode는 모든 클러스터의 Pool Member를 동등하게 등록하여 BIG-IP의 기본 로드밸런싱 알고리즘에 따라 트래픽을 분배하는 방식입니다. Ratio Mode는 클러스터 별로 가중치를 지정하여 트래픽 비율을 조정할 수 있는 방식으로, 클러스터 간 점진적 트래픽 전환이 필요한 경우에 활용됩니다.

이번 포스트에서는 Standalone CIS를 Default Mode로 구성하여, 서로 다른 버전의 OCP 클러스터 2개의 Pool Member가 BIG-IP에 정상적으로 등록되는지 확인해 보겠습니다.

1-1. 동작 방식

Standalone CIS Default Mode는 다음과 같은 방식으로 동작합니다.

  • CIS는 로컬 클러스터(1번 클러스터)에 Pod 형태로 배포되며, multi_cluster_mode: standalone 옵션으로 Multi-Cluster, standalone 모드로 동작합니다.
  • Extended ConfigMap에 정의된 kubeconfig Secret을 통해 외부 클러스터 정보를 참조하여, 2번 클러스터의 리소스를 함께 조회합니다.
  • VirtualServer 등의 CIS Custom Resource에 multiClusterServices 옵션으로 외부 클러스터의 Service를 지정하면, CIS는 로컬 및 외부 클러스터의 Pod(혹은 Node)를 모두 BIG-IP Pool Member로 등록합니다.
  • 최종적으로 BIG-IP는 등록된 Pool Member를 대상으로 트래픽을 분배합니다.

2. 환경/버전 정보

구성 요소버전
Red Hat OpenShift Cluster 14.18.24
Red Hat OpenShift Cluster 24.21.6
CNIOVN-Kubernetes
F5 BIG-IP VE17.5.0
F5 Container Ingress Services Operatorv1.21.0
F5 BIG-IP CIS2.20.3
AS3(Application Services 3) Extensionv3.56.0

3. Standalone CIS 구성 전 사전 준비

Standalone CIS Default Mode 구성 전에, BIG-IP CIS Multi-Cluster 환경에 필요한 사전 준비를 진행합니다.

주의:

1번 클러스터의 노드에서 2번 클러스터 API 서버(포트 6443)로의 네트워크 접근이 허용되어 있어야 합니다. 방화벽 또는 보안 그룹 정책에서 해당 통신이 차단되어 있으면 CIS가 외부 클러스터 리소스를 조회할 수 없습니다.

3-1. 보조 클러스터 접근을 위한 kubeconfig Secret 생성

Standalone CIS는 1번 클러스터에 배포되어 2번 클러스터의 리소스를 함께 조회합니다. 이를 위해 2번 클러스터에 CIS 전용 ServiceAccount와 권한을 생성하고, 해당 권한(토큰)으로 kubeconfig 파일을 만들어 1번 클러스터에 Secret으로 등록하는 과정을 진행합니다.

다음 yaml 파일을 사용하여, 2번 클러스터의 kube-system 네임스페이스에 bigip-ctlr Service Account를 생성하고, nodes, services, endpoints, namespaces, pods 리소스에 대해 get, list, watch 권한을 부여합니다.

external-cluster-rbac.yaml
# for reference only
# Should be changed as per your cluster requirements
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: bigip-ctlr-clusterrole
rules:
- apiGroups: [""]
resources: ["nodes", "services", "endpoints", "namespaces", "pods"]
verbs: ["get", "list", "watch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: bigip-ctlr-clusterrole-binding
namespace: kube-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: bigip-ctlr-clusterrole
subjects:
- apiGroup: ""
kind: ServiceAccount
name: bigip-ctlr
namespace: kube-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: bigip-ctlr
namespace: kube-system
# cluster1-2
$ oc apply -f external-cluster-rbac.yaml
clusterrole.rbac.authorization.k8s.io/bigip-ctlr-clusterrole created
clusterrolebinding.rbac.authorization.k8s.io/bigip-ctlr-clusterrole-binding created
serviceaccount/bigip-ctlr created

다음 yaml 파일을 사용하여 앞서 생성한 bigip-ctlr Service Account와 연결된 토큰을 생성합니다.

token-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: bigip-ctlr-token
namespace: kube-system
annotations:
kubernetes.io/service-account.name: bigip-ctlr
type: kubernetes.io/service-account-token

# cluster1-2
$ oc apply -f token-secret.yaml
secret/bigip-ctlr-token created

다음 스크립트를 사용하여 생성한 토큰으로부터 kubeconfig 파일을 생성합니다.

create_kubeconfig.sh
#!/bin/bash
# 변수 설정
SA_NAME="bigip-ctlr"
NAMESPACE="kube-system"
CLUSTER_NAME="cluster1-2" # 2번 클러스터 이름
FILE_NAME="${CLUSTER_NAME}-kubeconfig.yaml"
# API 서버 주소 추출 (현재 컨텍스트 기준)
SERVER_URL=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
# CA 인증서 추출 (Base64 인코딩 상태 그대로 사용)
CA_CERT=$(kubectl get secret ${SA_NAME}-token -n ${NAMESPACE} -o jsonpath='{.data.ca\.crt}')
# SA 토큰 추출 (Base64 디코딩하여 사용)
TOKEN=$(kubectl get secret ${SA_NAME}-token -n ${NAMESPACE} -o jsonpath='{.data.token}' | base64 --decode)
# kubeconfig 파일 생성
cat <<EOF > ${FILE_NAME}
apiVersion: v1
kind: Config
clusters:
- name: ${CLUSTER_NAME}
cluster:
certificate-authority-data: ${CA_CERT}
server: ${SERVER_URL}
contexts:
- name: f5-cis-context
context:
cluster: ${CLUSTER_NAME}
namespace: ${NAMESPACE}
user: ${SA_NAME}
current-context: f5-cis-context
users:
- name: ${SA_NAME}
user:
token: ${TOKEN}
EOF
echo "${FILE_NAME} 파일이 성공적으로 생성되었습니다."
# cluster1-2
$ ./create_kubeconfig.sh
cluster1-2-kubeconfig.yaml 파일이 성공적으로 생성되었습니다.

생성한 2번 클러스터의 kubeconfig 파일을 사용하여, 1번 클러스터에서 secret을 kube-system 네임스페이스에 생성합니다.
앞서 스크립트로 생성한 파일의 이름이 cluster1-2-kubeconfig.yaml 이므로 --from-file=kubeconfig=값에 파일 이름을 입력합니다.

# cluster1-1
$ oc create secret generic kubeconfig-cluster1-2 -n kube-system --from-file=kubeconfig=cluster1-2-kubeconfig.yaml
secret/kubeconfig-cluster1-2 created

3-2. Default Mode Extended ConfigMap 생성

BIG-IP CIS Multi-Cluster 구성에서 참조할 다른 클러스터의 정보를 정의하는 ConfigMap을 생성합니다.
이전 과정에서 kubeconfig 파일로 생성한 secret을 참조합니다.

extended-config-default.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: extended-spec-config
namespace: kube-system
data:
extendedSpec: |
mode: default
externalClustersConfig:
- clusterName: cluster1-2
secret: kube-system/kubeconfig-cluster1-2
  • mode : Multi-Cluster 구성에서 사용할 모드를 정의합니다. Standalone CIS Default Mode이므로 default를 사용합니다.
  • clusterName: CIS가 조회할 보조 클러스터의 이름을 정의합니다.
  • secret: 해당하는 보조 클러스터의 kubeconfig로 생성한 secret의 네임스페이스/이름 을 지정합니다.
# cluster1-1
$ oc apply -f extended-config-default.yaml
configmap/extended-spec-config configured

4. Standalone CIS – Default Mode 배포

1번 클러스터에 Standalone CIS를 Default Mode로 배포합니다.

이 포스트에서는 OpenShift 클러스터에 설치된 F5 Container Ingress Services Operator를 사용하여 CIS를 배포했습니다. Static Route를 활용한 ClusterIP 모드로 구성했으며, NodePort 모드도 동일하게 구성 가능합니다.

f5bigipctlr-f5bigipctlr.yaml
kind: F5BigIpCtlr
apiVersion: cis.f5.com/v1
metadata:
name: f5bigipctlr
namespace: openshift-operators
spec:
args:
agent: as3
bigip_partition: ocp-cluster-1 # CIS 연동할 BIG-IP 파티션
bigip_url: 192.168.40.121 # BIG-IP VE IP
insecure: true
log_as3_response: true
log_level: INFO
manage_routes: false
manage_ingress: false
custom_resource_mode: true # Custom Resource 사용 모드 설정
### OpenShift OVN-K8s 사용 clusterIP, static routing 설정
pool_member_type: cluster
static_routing_mode: true
orchestration_cni: ovn-k8s
### CIS Multi-Cluster 설정
multi_cluster_mode: standalone # Standalone CIS 설정
local_cluster_name: cluster1-1 # CIS 배포 클러스터 이름 설정
extended_spec_configmap: kube-system/extended-spec-config # 앞서 생성한 Extended ConfigMap의 네임스페이스/이름
bigip_login_secret: f5-bigip-ctlr-login # BIG-IP 로그인 정보가 기록된 secret
image:
pullPolicy: Always
repo: k8s-bigip-ctlr
user: f5networks
ingressClass:
create: false
defaultController: false
ingressClassName: f5
namespace: kube-system
rbac:
create: true
resources: {}
serviceAccount:
create: true
version: latest

Helm 활용 배포 시에도 동일한 옵션을 사용 가능하나, 일부 옵션의 값에 차이가 있어 확인이 필요합니다.
예: F5BigIpCtlr(Operator): custom_resource_mode / Helm: custom-resource-mode

Helm value 전체 옵션은 링크에서 확인하세요.

배포가 완료된 후 CIS Pod의 로그를 조회하면, Multi-Cluster 모드, standalone CIS 로 동작 중인 것을 확인할 수 있습니다. 또한 custom resource mode로 동작하여 관련 informer의 시작 상태도 확인할 수 있습니다.

$ oc get po -n kube-system
NAME READY STATUS RESTARTS AGE
f5bigipctlr-f5-bigip-ctlr-59dcd47b66-5f9h8 1/1 Running 0 2m39s
------
$ oc logs f5bigipctlr-f5-bigip-ctlr-59dcd47b66-5f9h8 -n kube-system
2026/04/08 05:35:40 [INFO] [MultiCluster] CIS running with multi-cluster-mode: standalone
2026/04/08 05:35:40 [INFO] [INIT] Starting: Container Ingress Services - Version: v2.20.3, BuildInfo: gitlab-16324349-acadb9e63a1117defbb70d6096950df1fe5db713
......
2026/04/08 05:36:04 [INFO] Starting VirtualServer Informer
2026/04/08 05:36:04 [INFO] Starting TLSProfile Informer
2026/04/08 05:36:04 [INFO] Starting TransportServer Informer
2026/04/08 05:36:04 [INFO] Starting IngressLink Informer
I0408 05:36:04.732975 1 shared_informer.go:240] Waiting for caches to sync for F5 CIS Ingress Controller
I0408 05:36:05.133512 1 shared_informer.go:247] Caches are synced for F5 CIS Ingress Controller
2026/04/08 05:36:05 [WARNING] Ensure Global Extended Configmap is created in CIS monitored namespace
2026/04/08 05:36:05 [INFO] Using cluster-specific CIS identifier: 192.168.40.121_cluster1-1 (cluster: cluster1-1, nodeLabelSelector: )

5. VirtualServer 구성 및 BIG-IP Pool 확인

각 클러스터에 동일한 애플리케이션의 Deployment/Service를 배포하고, CIS Custom Resource인 VirtualServer를 구성하여 각 클러스터의 Pod가 BIG-IP Pool로 구성되는 것을 확인하겠습니다.

백엔드 Pod를 생성하고 연결하기 위해 Deployment와 Service를 1번, 2번 클러스터 모두 배포합니다.

default 네임스페이스에 배포했습니다.

coffee-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: coffee
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: coffee
template:
metadata:
labels:
app: coffee
spec:
containers:
- name: coffee
image: nginxdemos/hello
ports:
- containerPort: 80
coffee-service.yaml
apiVersion: v1
kind: Service
metadata:
name: coffee-svc
namespace: default
labels:
app: coffee-svc
spec:
ports:
- name: coffee-svc
port: 80
protocol: TCP
targetPort: 80
selector:
app: coffee
## cluster 1
$ oc get po,svc -n default -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/coffee-56b689cd7-d2x6f 1/1 Running 0 78s 10.128.0.24 c1-1-node <none> <none>
pod/coffee-56b689cd7-x9ctv 1/1 Running 0 110s 10.128.0.23 c1-1-node <none> <none>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/coffee-svc ClusterIP 172.30.177.236 <none> 80/TCP 110s app=coffee
service/kubernetes ClusterIP 172.30.0.1 <none> 443/TCP 7d22h <none>
service/openshift ExternalName <none> kubernetes.default.svc.cluster.local <none> 7d22h <none>
------
## cluster 2
$ oc get po,svc -n default -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/coffee-86f468ccd6-kzv6n 1/1 Running 0 35s 10.128.129.97 c1-2-node <none> <none>
pod/coffee-86f468ccd6-w2889 1/1 Running 0 48s 10.128.129.96 c1-2-node <none> <none>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/coffee-svc ClusterIP 172.30.121.220 <none> 80/TCP 38s app=coffee
service/kubernetes ClusterIP 172.30.0.1 <none> 443/TCP 7d5h <none>
service/openshift ExternalName <none> kubernetes.default.svc.cluster.local <none> 7d4h <none>

배포한 Pod로 트래픽을 전달하기 위한 CIS의 VirtualServer 리소스를 CIS Pod가 배포된 1번 클러스터에 배포합니다.

동일하게 default 네임스페이스에 배포합니다.

cis-vs.yaml
apiVersion: "cis.f5.com/v1"
kind: VirtualServer
metadata:
name: cafe-coffee-vs
namespace: default
# CIS가 관리할 VirtualServer 리소스임을 식별하는 레이블
labels:
f5cr: "true"
spec:
virtualServerAddress: "192.168.40.230" # BIG-IP에 생성될 VIP
virtualServerName: "cafe_coffee_vs" # BIG-IP에 생성될 VirtualServer 이름
host: "cafeone.example.com"
pools:
- path: "/coffee"
# BIG-IP에 구성될 monitor 설정(Health Check)
monitor:
type: http
send: "GET /coffee HTTP/1.1\r\nHost: cafeone.example.com\r\nConnection: Close\r\n\r\n"
recv: ""
interval: 5
timeout: 16
# 멀티 클러스터 구성에서 트래픽을 전달할 클러스터 이름, 네임스페이스, 서비스 이름 및 포트 정보
multiClusterServices:
- clusterName: cluster1-1 # CIS 설정의 local_cluster_name
namespace: default
service: coffee-svc
servicePort: 80
- clusterName: cluster1-2 # Extended ConfigMap에 구성된 clusterName
namespace: default
service: coffee-svc
servicePort: 80

배포가 완료되고, CIS가 정상적으로 처리하면 OK STATUS를 확인할 수 있습니다.

$ oc apply -f cis-vs.yaml
virtualserver.cis.f5.com/cafe-coffee-vs created
$ oc get virtualservers.cis.f5.com -n default
NAME HOST TLSPROFILENAME HTTPTRAFFIC IPADDRESS IPAMLABEL IPAMVSADDRESS STATUS AGE
cafe-coffee-vs cafeone.example.com 192.168.40.230 192.168.40.230 OK 73s

CIS Pod의 로그를 확인하면 VirtualServer 구성에 기반한 설정을 BIG-IP로 설정하여 반영하는 것을 확인할 수 있습니다.

$ oc logs f5bigipctlr-f5-bigip-ctlr-59dcd47b66-5f9h8 -n kube-system
...
2026/04/08 07:28:38 [INFO] [Request: 9] cluster cluster1-2 requested CREATE in ENDPOINTS default/coffee-svc
2026/04/08 07:28:40 [INFO] [Request: 9][AS3] creating a new AS3 manifest
2026/04/08 07:28:40 [INFO] [Request: 9][AS3][BigIP] posting request to https://192.168.40.121 for tenants
2026/04/08 07:28:54 [INFO] [Request: 9][AS3][BigIP] post resulted in SUCCESS
2026/04/08 07:28:54 [INFO] [AS3][POST] SUCCESS: code: 200 --- tenant:ocp-cluster-1 --- message: success
2026/04/08 07:28:54 [INFO] Successfully updated status of VirtualServer:default/cafe-coffee-vs in Cluster cluster1-1

BIG-IP GUI에 접속하여, 좌측 메뉴 바의 Local Traffic > Virtual Servers 메뉴로 이동합니다.

우측 상단의 파티션 지정 메뉴에서 CIS와 연동된 파티션을 선택하면, 클러스터 내부에 배포한 VirtualServers 리소스로 생성된 Virtual Server를 확인할 수 있습니다.

Standalone CIS VirtualServer

좌측 메뉴 바의 Local Traffic > Pools 메뉴로 이동하면 리스트에서 클러스터 별로 개별 Pool이 구성된 것을 확인할 수 있습니다.

Standalone CIS Pools

개별 Pool의 이름을 클릭하고, 상단의 Members 버튼을 클릭하면 개별 Pod를 확인할 수 있습니다. CIS를 NodePort 모드로 구성한 경우 노드가 member로 구성됩니다.

Standalone CIS Pool members
Standalone CIS Pool members
## cluster 1
$ oc get po -n default -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/coffee-56b689cd7-d2x6f 1/1 Running 0 78s 10.128.0.24 c1-1-node <none> <none>
pod/coffee-56b689cd7-x9ctv 1/1 Running 0 110s 10.128.0.23 c1-1-node <none> <none>
------
## cluster 2
$ oc get po -n default -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/coffee-86f468ccd6-kzv6n 1/1 Running 0 35s 10.128.129.97 c1-2-node <none> <none>
pod/coffee-86f468ccd6-w2889 1/1 Running 0 48s 10.128.129.96 c1-2-node <none> <none>

결과적으로 두 클러스터의 Pod가 각각 Pool Member로 등록되며, BIG-IP는 이를 단일 Virtual Server에서 통합적으로 로드밸런싱하게 됩니다.

6. 결론

이번 포스트에서는 Standalone CIS를 Default Mode로 구성하여, 서로 다른 OpenShift 클러스터의 애플리케이션을 하나의 BIG-IP Virtual Server로 통합하는 방법을 확인했습니다.

보조 클러스터의 kubeconfig Secret 생성부터 Extended ConfigMap 구성, CIS 배포까지의 흐름을 확인했으며, VirtualServer 구성을 통해 각 클러스터 별로 Pool이 등록되는 것을 BIG-IP GUI를 통해 확인했습니다.

BIG-IP CIS와 F5 NGINX Ingress Controller를 활용하여 Kubernetes/OpenShift 환경의 트래픽을 통합 관리하고 싶으시다면 NGINX STORE를 통해 문의하세요.

NGINX STORE를 통한 솔루션 도입 및 기술지원 무료 상담 신청

* indicates required