Kubernetes 네이티브 네트워크 자동화 에이전트
OpenStack 환경에서 Kubernetes 노드의 다중 네트워크 인터페이스를 완전 자동으로 관리하는 Controller + Job 기반 시스템입니다.
- 단일 이미지, 이중 실행: 하나의 컨테이너 이미지에서 Controller/Agent 모드로 동작
- 자동화 워크플로우: CR 생성/수정 시 즉시 해당 노드에 Agent Job 스케줄링
- 노드별 맞춤 실행: 각 노드의 SystemUUID 검증 후 네트워크 인터페이스 자동 설정
- 실시간 상태 동기화: Job 완료 후 Controller가 자동으로 CR status 업데이트
- 라우팅 충돌 방지: 전역 라우팅 직렬화로 네트워크 테이블 안정성 보장
- 성능 최적화: 안정성 우선 동시성 제어 (기본 1개 작업, 설정 가능)
- Controller (Deployment): CR 변경사항을 실시간 감시
- Agent (Job): 특정 노드에서만 실행되어 네트워크 인터페이스 설정
- 자동 스케줄링: CR 업데이트 → 해당 노드용 Agent Job 생성 → 네트워크 구성 → 상태 업데이트
- 런타임 적용은
ip기반으로 즉시 반영(이름/MTU/IPv4/라우트) - 영속성은 OS별 파일 “작성만” 수행(즉시
netplan apply/nmcli reload호출 없음) - Ubuntu: netplan YAML에
match.macaddress + set-name포함으로 이름 영속 - RHEL:
.link(systemd-udev, 이름 영속) +.nmconnection(NetworkManager, 권한 600) 작성, Helm이/etc/systemd/network도 마운트 - Preflight: UP NIC이라도 IPv4/라우트/마스터 소속이 없으면 허용; 우회 플래그
PREFLIGHT_ALLOW_UP제공 - 라우팅/기본경로 변경은 전역 직렬화
graph TB
%% 상단: MGMT Cluster
subgraph "MGMT Cluster"
Operator[Operator]
ViolaAPI[Viola API]
end
%% Biz Cluster
subgraph "Kubernetes Cluster (Biz)"
subgraph "CR 처리"
MultiNICController[MultiNIC Controller\nCR Watch]
NodeCR[MultiNicNodeConfig CR\n노드별 Interface 데이터]
end
subgraph "Job 실행"
Job1[Agent Job\nNode1 대상]
Job2[Agent Job\nNode2 대상]
Job3[Agent Job\nNode3 대상]
end
subgraph "Worker Nodes"
Node1[Node1\nSystemUUID: b4975c5f-50bb]
Node2[Node2\nSystemUUID: d4defd76-faa9]
Node3[Node3\nSystemUUID: a1b2c3d4-e5f6]
end
end
%% Network Interfaces
subgraph "Network Interfaces"
NIC1[Node1: multinic0, multinic1]
NIC2[Node2: multinic0]
NIC3[Node3: multinic0, multinic1, multinic2]
end
%% 데이터 흐름
Operator -->|인터페이스 정보 POST| ViolaAPI
ViolaAPI -->|CR 생성| NodeCR
NodeCR -.->|Watch Event| MultiNICController
MultiNICController -->|Node별 Job 스케줄링| Job1
MultiNICController -->|Node별 Job 스케줄링| Job2
MultiNICController -->|Node별 Job 스케줄링| Job3
Job1 -->|ip 적용 + 영속 파일 작성| Node1
Job2 -->|ip 적용 + 영속 파일 작성| Node2
Job3 -->|ip 적용 + 영속 파일 작성| Node3
Node1 -->|인터페이스 생성| NIC1
Node2 -->|인터페이스 생성| NIC2
Node3 -->|인터페이스 생성| NIC3
%% 스타일(렌더러 미지원 시 제거 가능)
classDef mgmt fill:#e8f5e8
classDef controller fill:#f3e5f5
classDef cr fill:#fff3e0
classDef job fill:#ffecb3
classDef node fill:#fafafa
classDef nic fill:#ffcdd2
class Operator,ViolaAPI mgmt
class MultiNICController controller
class NodeCR cr
class Job1,Job2,Job3 job
class Node1,Node2,Node3 node
class NIC1,NIC2,NIC3 nic
sequenceDiagram
participant 운영 as Config Source
participant API as Kubernetes API
participant 컨트롤러 as Controller
participant 잡 as Agent Job
participant 노드 as Target Node
운영->>API: CR 생성/수정 (MAC, IP, CIDR, MTU)
note over 운영,API: 외부 API도 CR을 직접 생성/갱신할 수 있음
API-->>컨트롤러: Watch 이벤트 전달
컨트롤러->>API: 노드 정보 조회(osImage/SystemUUID)
컨트롤러->>API: Agent Job 생성(nodeSelector)
API->>잡: 대상 노드에서 실행
잡->>노드: Preflight (MAC 확인, 미사용 NIC 허용)
잡->>노드: ip 기반 적용(이름, MTU, IPv4, 라우트)
잡->>노드: 영속 파일만 작성(Ubuntu: netplan, RHEL: .link + .nmconnection)
잡->>노드: 검증 및 termination log 기록
잡-->>컨트롤러: 요약 전달
컨트롤러->>API: CR 상태 업데이트(Configured/Failed)
컨트롤러->>API: Job 정리(TTL)
-
시작 시 정리 수행(RUN_MODE=job):
- Ubuntu:
/etc/netplan/9*-multinic*.yaml고아 파일만 삭제(즉시netplan apply는 호출하지 않음) - RHEL: RHEL9+에서는
/etc/sysconfig/network-scripts가 없을 수 있으므로.nmconnection고아 파일만 정리하고 디렉터리 부재는 무시 - 시스템 기본 파일(
50-cloud-init.yaml등)은 건드리지 않음 - 남아있는
multinic0~9인터페이스는 DOWN 상태일 때만 altname(ens*/enp*)으로 rename 시도(없으면 스킵)
- Ubuntu:
-
이름 충돌 방지(사전 배정): 실행 시작 시 MAC→
multinicX이름을 미리 배정해 중복 이름 충돌을 제거 -
검증 방식 전환(이름→MAC):
- 적용 후 검증은
ip -o link show전체에서 CR의 MAC 존재 여부로 판단(특정 이름에 의존하지 않음)
- 적용 후 검증은
-
처리 순서: "정리 → 설정(적용) → 검증"으로 실행
-
라우팅 충돌 방지:
- 전역 mutex를 통한 라우팅 테이블 직렬화
- 동시 네트워크 설정으로 인한 라우팅 테이블 경쟁 상태 방지
- 라우팅 작업 메트릭 수집 (실행 시간, 성공/실패율)
-
동시성 제어 최적화:
- 기본 최대 동시 작업 수: 1개 (안정성 우선)
-
Helm values를 통한 설정 가능 (
agent.maxConcurrentTasks)- 대규모 환경에서 라우팅 충돌 최소화
# 기본 설정 (안정성 최우선)
helm upgrade --install multinic-agent ./deployments/helm \
-n multinic-system \
--set image.tag=1.0.2 \
--set agent.maxConcurrentTasks=1
# 대규모 환경 (성능 우선시)
helm upgrade --install multinic-agent ./deployments/helm \
-n multinic-system \
--set image.tag=1.0.2 \
--set agent.maxConcurrentTasks=3
수동 전체 정리(옵션):
# 컨트롤러가 생성하는 Job에 환경변수로 전달되면 모든 multinic 파일만 정리
AGENT_ACTION=cleanup- 기본: 소스 기반 정책 라우팅 +
noprefixroute적용 → main 테이블/ens3 기본 라우트 유지 - ARP 플럭스/RPF 완화:
arp_ignore=1,arp_announce=2,rp_filter=2를 인터페이스 단위로 적용 - 설정값(환경변수/Helm
agent.network.*):NETWORK_POLICY_ROUTING_ENABLED(default: true)NETWORK_ROUTING_TABLE_BASE(default: 100),NETWORK_ROUTE_METRIC(default: 100)NETWORK_NOPREFIXROUTE(default: true)NETWORK_SET_ARP_SYSCTLS(default: true),NETWORK_SET_RP_FILTER_LOOSE(default: true)
multinic-agent/
├── cmd/
│ ├── agent/ # Agent Job 바이너리
│ └── controller/ # Controller 바이너리
├── internal/ # Clean Architecture
│ ├── domain/ # 도메인 계층
│ │ ├── entities/ # NetworkInterface, InterfaceName
│ │ ├── interfaces/ # Repository, Network 인터페이스
│ │ └── services/ # InterfaceNamingService, RoutingCoordinator
│ ├── application/ # 애플리케이션 계층
│ │ └── usecases/ # ConfigureNetwork, DeleteNetwork
│ ├── infrastructure/ # 인프라스트럭처 계층
│ │ ├── persistence/ # NodeCR Repository (K8s CR 기반)
│ │ ├── network/ # Netplan, RHEL Adapter
│ │ ├── metrics/ # Prometheus 메트릭 수집
│ │ └── config/ # 설정 관리
│ └── controller/ # Controller 구현
│ ├── reconciler.go # CR 처리 로직
│ ├── watcher.go # Watch 이벤트 처리
│ └── service.go # Controller 서비스
├── deployments/
│ ├── crds/ # CRD 정의 및 샘플
│ └── helm/ # Helm 차트
└── scripts/ # 배포 자동화
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: multinicnodeconfigs.multinic.io
spec:
group: multinic.io
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
nodeName:
type: string
description: "Target Kubernetes node name"
instanceId:
type: string
description: "OpenStack Instance UUID"
interfaces:
type: array
items:
type: object
properties:
id:
type: integer
name:
type: string
macAddress:
type: string
address:
type: string
cidr:
type: string
mtu:
type: integer
status:
type: object
properties:
state:
type: string
enum: ["Pending", "InProgress", "Configured", "Failed"]
lastProcessed:
type: string
interfaceStatuses:
type: array
items:
type: object
properties:
name:
type: stringapiVersion: multinic.io/v1alpha1
kind: MultiNicNodeConfig
metadata:
name: viola2-biz-worker01
namespace: multinic-system
labels:
multinic.io/node-name: viola2-biz-worker01
multinic.io/instance-id: b4975c5f-50bb-479f-9e7b-a430815ae852
spec:
nodeName: viola2-biz-worker01
instanceId: b4975c5f-50bb-479f-9e7b-a430815ae852
interfaces:
- id: 0
name: multinic0
macAddress: fa:16:3e:1c:1a:6e
address: 11.11.11.37
cidr: 11.11.11.0/24
mtu: 1450
- id: 1
name: multinic1
macAddress: fa:16:3e:0a:17:3b
address: 11.11.11.148
cidr: 11.11.11.0/24
mtu: 1450name은 선택사항이지만, 설정 시 id는 name의 인덱스로 해석됩니다.
id는 09 범위이며 name(multinic09)과 동일한 인덱스로 맞추는 것을 권장합니다.
# deploy.sh 스크립트에서 SSH_PASSWORD 수정
vi scripts/deploy.sh
# SSH_PASSWORD=${SSH_PASSWORD:-"YOUR_SSH_PASSWORD"} → 실제 패스워드로 변경- Kubernetes 1.24+
- Helm 3.0+
- kubectl
- nerdctl (컨테이너 런타임)
방법 A: 로컬 이미지 수동 배포 (Air-gap 환경)
# 사전 빌드된 이미지 사용 (권장)
# deployments/images/ 디렉토리에 있는 tar 파일을 모든 노드에 배포
# A-1: 스크립트로 모든 노드에 배포 (권장) - SSH 패스워드 사용
NODES=(192.168.1.10 192.168.1.11 192.168.1.12) # 실제 노드 IP로 변경
for node in "${NODES[@]}"; do
echo "Deploying to $node..."
scp deployments/images/multinic-agent-1.0.2.tar root@$node:/tmp/
ssh root@$node "nerdctl load -i /tmp/multinic-agent-1.0.2.tar && rm /tmp/multinic-agent-1.0.2.tar"
done
# A-2: SSH Key를 사용하는 경우
NODES=(192.168.1.10 192.168.1.11 192.168.1.12) # 실제 노드 IP로 변경
SSH_KEY_PATH="~/.ssh/id_rsa" # SSH private key 경로
for node in "${NODES[@]}"; do
echo "Deploying to $node..."
scp -i $SSH_KEY_PATH -o StrictHostKeyChecking=no deployments/images/multinic-agent-1.0.2.tar root@$node:/tmp/
ssh -i $SSH_KEY_PATH -o StrictHostKeyChecking=no root@$node "nerdctl load -i /tmp/multinic-agent-1.0.2.tar && rm /tmp/multinic-agent-1.0.2.tar"
done
# A-3: 개별 노드에 수동 배포
scp deployments/images/multinic-agent-1.0.2.tar [email protected]:/tmp/
ssh [email protected] "nerdctl load -i /tmp/multinic-agent-1.0.2.tar"
# A-4: 직접 빌드 (개발용)
nerdctl build -t multinic-agent:1.0.2 .방법 B: Nexus Registry 사용 (Registry 환경)
# B-1: Nexus에 이미지 푸시 (관리자 작업)
nerdctl build -t multinic-agent:1.0.2 .
nerdctl tag multinic-agent:1.0.2 nexus.your-domain.com:5000/multinic-agent:1.0.2
nerdctl push nexus.your-domain.com:5000/multinic-agent:1.0.2
# B-2: 인증이 필요한 경우 로그인
nerdctl login nexus.your-domain.com:5000
# B-3: 각 노드에서 자동으로 이미지 Pull (Kubernetes가 자동 처리)
# helm install 시 --set image.repository=nexus.your-domain.com:5000/multinic-agent 사용kubectl create namespace multinic-system# MultiNicNodeConfig CRD 설치
kubectl apply -f deployments/crds/multinicnodeconfig-crd.yaml
# CRD 설치 확인
kubectl get crd multinicnodeconfigs.multinic.io로컬 이미지 사용 시:
# Controller Deployment + RBAC + ServiceAccount 생성
helm upgrade --install multinic-agent ./deployments/helm \
--namespace multinic-system \
--set image.tag=1.0.2 \
--set agent.metricsPort=18080 \
--set agent.preflightAllowUp=false \
--wait --timeout=300sNexus Registry 사용 시:
# Nexus Registry에서 이미지 가져와서 배포
helm upgrade --install multinic-agent ./deployments/helm \
--namespace multinic-system \
--set image.repository=nexus.your-domain.com:5000/multinic-agent \
--set image.tag=1.0.2 \
--wait --timeout=300s
# 다른 Registry 예시들:
# --set image.repository=192.168.1.50:5000/multinic-agent
# --set image.repository=nexus.company.com:8082/docker/multinic-agent배포 확인:
# Controller 상태 확인
kubectl get pods -n multinic-system -l app.kubernetes.io/name=multinic-agent-controller이 단계에서 생성되는 리소스:
- Controller Deployment: CR 감시 및 Agent Job 스케줄링
- ServiceAccount + RBAC: Job 생성 권한 설정
- 자동화 시작: 이제 CR 생성 시 자동으로 Agent Job 실행
# 차트 업그레이드
helm upgrade multinic-agent ./deployments/helm \
--namespace multinic-system \
--set image.tag=1.0.3 \
--wait --timeout=300s# 차트 제거
helm uninstall multinic-agent -n multinic-system
# CRD 제거 (선택사항)
kubectl delete crd multinicnodeconfigs.multinic.io
# 네임스페이스 제거 (선택사항)
kubectl delete namespace multinic-system이 Helm 차트는 MultiNic Agent의 모든 컴포넌트를 Kubernetes 클러스터에 배포하고 관리합니다.
vi ./scripts/deploy.sh
SSH_PASSWORD=${SSH_PASSWORD:-"배포 대상 ssh password 입력"}
저장 후 deploy.sh 실행# 자동 배포 실행
./scripts/deploy.sh배포 스크립트 기능:
- 필수 도구 확인 (
nerdctl,helm,kubectl,sshpass) - 이미지 빌드 (
nerdctl build) - 모든 노드에 이미지 배포 (
scp+nerdctl load) - CRD 설치 (
kubectl apply) - Helm 차트 배포 (
helm upgrade --install) - 배포 상태 확인
- 라우팅 직렬화 설정 유지, 메트릭 수집 활성화
# Controller Pod 실행 확인
kubectl get pods -n multinic-system -l app.kubernetes.io/name=multinic-agent-controller
# Controller 로그 확인
kubectl logs -n multinic-system -l app.kubernetes.io/name=multinic-agent-controller# 샘플 CR 적용
kubectl apply -n multinic-system -f deployments/crds/samples/
# CR 상태 확인
kubectl get multinicnodeconfigs -n multinic-system
# 생성된 Job 확인
kubectl get jobs -n multinic-system -l app.kubernetes.io/name=multinic-agent# CR 상태가 "Configured"인지 확인
kubectl get multinicnodeconfigs -n multinic-system -o custom-columns=NAME:.metadata.name,STATE:.status.state예상 성공 결과
root@bastion:~/multinic-agent# kubectl get multinicnodeconfigs -n multinic-system -o custom-columns=NAME:.metadata.name,STATE:.status.state
NAME STATE
viola2-biz-master03 Configured
# 동시성 제어 (안정성 vs 성능 균형)
agent:
maxConcurrentTasks: 1 # 기본값: 안정성 우선 (1-10 권장)
# 이미지 설정
image:
repository: multinic-agent
tag: "1.0.2"
pullPolicy: IfNotPresent
# 컨트롤러 Job 보존 설정
controller:
jobTTLSeconds: "3600"
jobDeleteDelaySeconds: "1800"
metricsPort: "9090"SELinux enforcing 환경에서는 생성된 파일에 대해 restorecon을 권장합니다.
restorecon -Rv /etc/NetworkManager/system-connections
restorecon -Rv /etc/systemd/network# Pod 리소스 제한
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
# 보안 컨텍스트
securityContext:
runAsNonRoot: false # 네트워크 설정을 위해 root 권한 필요
privileged: true # 호스트 네트워크 접근 필요helm upgrade --install multinic-agent ./deployments/helm \
--namespace multinic-system \
--set agent.maxConcurrentTasks=3 \
--set image.pullPolicy=Always \
--set resources.limits.cpu=1000m \
--set resources.limits.memory=1Gihelm upgrade --install multinic-agent ./deployments/helm \
--namespace multinic-system \
--set agent.maxConcurrentTasks=1 \
--set resources.limits.cpu=500m \
--set resources.limits.memory=512Mi# 라우팅 작업 메트릭 확인
curl http://localhost:8080/metrics | grep routing
# 예상 메트릭:
# routing_operation_duration_seconds_sum
# routing_operation_duration_seconds_count
# routing_operation_total{operation="configure",result="success"}# Controller 로그 (CR 처리 과정)
kubectl logs -n multinic-system -l app.kubernetes.io/name=multinic-agent-controller -f
# Agent Job 로그 (실제 네트워크 설정)
kubectl logs -n multinic-system -l app.kubernetes.io/name=multinic-agent-job -f