시작하며
안녕하세요. 카카오페이증권 DevOps 팀의 데릭입니다. 저희 팀은 Gateway, Kubernetes, CI/CD Pipeline, 로깅 등 다양한 업무를 담당하고 있습니다.
이 글은 Gateway 전환 프로젝트에서 Cilium Egress Gateway를 도입한 이유와 적용 방법을 공유하는 내용이며 DevOps팀과 Kubernetes를 사용하는 네트워크 엔지니어분들에게 도움이 되었으면 좋겠습니다.
본격적으로 Cilium Egress Gateway 설명하기 전에 Cilium의 개념과 저희 카카오페이증권이 왜 Cilium을 채택하여 사용하고 있는지 그 배경을 설명드리고자 합니다.
Cilium ?
Cilium 공식 문서에서는 Cilium을 아래와 같이 설명하고 있습니다.
Cilium은 Linux 컨테이너 관리 플랫폼을(Docker, Kubernetes) 사용하여 배포된 애플리케이션 서비스 간 네트워크 연결을 보호하는 오픈 소스 소프트웨어입니다. Cilium의 기반에는 eBPF라는 Linux 커널 기술이 사용되었습니다. 이를 통해 Linux 자체에 강력한 보안 가시성(Security visibility)과 제어 로직을 동적으로 입력할 수 있습니다. eBPF는 Linux 커널 내에서 실행되기 때문에 애플리케이션 코드나 컨테이너 구성을 변경하지 않고도 Cilium 보안 정책을 적용하고 업데이트할 수 있습니다.
위 설명의 키 포인트는 “eBPF 기반, 보안 관리, 모니터링” 입니다. 조금 더 상세하게 저희가 생각하는 이점을 아래와 같이 정리해 보았습니다.
- Cilium은 eBPF 기반의 CNI이며 kube-proxy Replacement할 수 있다.
- Hubble을 통해 실시간 네트워크 가시성 및 다양한 메트릭 제공을 통해 효율적으로 클러스터를 운영할 수 있다.
- eBPF의 특성으로 애플리케이션 코드나 컨테이너 구성을 변경하지 않고 네트워크 정책 적용이 가능하다.
Cilium의 핵심 기술인 eBPF를 이해하기 전에, Cilium이 왜 기존의 kube-proxy를 대체할 수 있는지 알아보겠습니다. kube-proxy의 작동 방식을 이해하면 Cilium의 강점을 더 쉽게 이해할 수 있습니다.
kube-proxy
kube-proxy는 iptables 기반으로 동작하며 Chain 및 규칙을 생성 및 배포하게 됩니다. 여기서 iptables 기반 환경의 잠재적 문제가 존재하게 되는데 내용은 아래와 같습니다.
- iptables는 iptable list가 많아지는 만큼 규칙을 평가에 많은 시간이 소요됩니다.
- iptables는 Incremental Update을 지원하지 않습니다. 따라서 새로운 규칙을 적용하기 위해서 전체 iptable list를 교체합니다. 이 말은 즉 많은 서비스가 생성/삭제/운영되는 환경에서는 적합하지 않습니다.
이러한 kube-proxy의 한계를 극복하기 위해 Cilium은 eBPF를 활용합니다. 그렇다면, eBPF란 무엇이며, eBPF를 이용해서 어떻게 네트워크 성능을 향상할 수 있을까요?
eBPF ?
BPF는 Kernel에 Sandbox 형태로 설치되어 Packet에 대한 제어를 할 수 있습니다. 이러한 BPF를 확장한 것이 eBPF(extended BPF)이며 Linux Kernel에 내장되어 시스템의 변경 없이 시스템 호출을 통해 요청을 처리합니다.
eBPF에서는 빠른 패킷 처리, tracing & profileing, 사용자 정의 메트릭을 통한 Observability, 높은 수준의 Security 처리가 가능하다고 소개하고 있습니다.
이러한 eBPF의 기능들은 Cilium의 모니터링 툴인 Hubble과 결합되었을 때 더욱 강력한 성능을 발휘합니다. Hubble으로 어떻게 eBPF의 강력한 모니터링 및 보안 기능이 실제로 구현되는지 살펴보겠습니다.
Hubble
Hubble은 컨테이너 네트워킹과 보안을 위한 분산형 관찰 플랫폼입니다. Cilium과 eBPF 기술 기반으로 구축되어 서비스 간 통신, 서비스 동작, 네트워킹 인프라에 대한 가시성을 투명한 방식으로 제공합니다.
아래의 Hubble UI는 실제 카카오페이증권에서 사용하고 있는 일부 서비스로 상단에서 서비스 연결 구조 확인이 가능하며 화면 하단에서는 서비스의 InBound/Outbound의 통신 상태를 실시간으로 확인이 가능합니다. 실시간 이상징후 탐지는 prometheus, grafana로 알림을 받고 있으며 이상징후 발생 시 Grafana 및 Hubble UI를 통해 이슈를 확인하고 있습니다.
Hubble UI
메트릭 및 모니터링
카카오페이증권에서 Cilium을 채택한 이유?
클러스터를 구성 당시 대표적인 CNI는 Cilium과 Calico가 있었으며, 아래는 간단하게 비교한 내용입니다.
기능 | Cilium | calico |
---|---|---|
Core Technology | eBPF 기반 | IP Tables 기반 (최근 버전에서는 eBPF를 지원) |
모니터링 가시성 | Hubble 지원 및 Prometheus, Garafana 추가 연동 가능 | Prometheus, Grafana 등과 연동을 해야만 가능 |
저희는 24시간 365일 서비스로 많은 서비스와 많은 트래픽을 안전하게 운영할 수 있는 환경을 원했습니다. 이에 따라 CNI를 채택할 때 Cilium의 eBPF 기반으로 잠재적 이슈를 차단하고 보다 좋은 성능을 발휘할 수 있다는 점과 Hubble을 통한 네트워크 가시성 및 메트릭을 통한 이상징후 감지로 보다 안정적인 서비스를 운영할 수 있다는 점이 큰 메리트였습니다.
또한 저희는 하이브리드 클라우드 구성으로 퍼블릭 클라우드와 프라이빗 클라우드를 모두 사용하고 있고 그에 따라 클러스터 내부 통신, 클러스터 간 통신, 대외 기관 연동 통신 등과 같은 많은 통신을 하고 있기 때문에 네트워크 정책 관리는 필수적이었습니다. Cilium의 eBPF의 특성으로 애플리케이션 코드나 컨테이너 구성을 변경하지 않고 네트워크 정책 적용이 가능하다는 점과 뒤에서 설명드릴 Egress Gateway 정책을 통해 대외 기관연동에 운영 편의성을 가질 수 있어 채택하게 되었습니다.
단 Cilium이 eBPF를 기반으로 동작하기 때문에 eBPF Maps의 상한이 존재합니다. 아래는 상한의 일부를 나타내며 이에 맞게 클러스터 및 서비스 구성을 해야 합니다.
Map Name | Scope | Default Limit | Scale Implications |
---|---|---|---|
Node | node | 16k | Max 16k distinct node IPs (IPv4 & IPv6) across all clusters. |
Load Balancer | node | 64k | Max 64k cumulative backends across all services across all clusters |
Policy | endpoint | 16k | Max 16k allowed identity + port + protocol pairs for specific endpoint |
Endpoints | node | 64k | Max 64k local endpoints + host IPs per node |
카카오페이증권 기존 시스템은 물리 서버를 사용하는 Gateway에서 확장성과 운영 효율성에 문제를 겪고 있었습니다. 이러한 문제를 해결하고, 나아가 네트워크 관리를 좀 더 효율적으로 하기 위해 Kubernetes 환경에 Cilium을 함께 도입했습니다.
Cilium Egress Gateway ?
Cilium은 Egress Gateway를 통해 egress NAT 정책을 설정할 수 있습니다. 이 말은 즉 서비스 Pod에서 트래픽이 나갈 때 동적으로 할당되어 IP를 Egress Gateway 정책을 통해 일관된 IP로 변환하여 나갈 수 있습니다. 장점은 아래와 같으며, 왜 장점인지에 대해서는 도입 배경에서 자세하게 설명 드리겠습니다.
- 특정 서비스에만 정책 적용이 가능하며 서비스 별 관리에 용이
- 일관된 IP로 트래픽이 나가기 때문에 방화벽에서 관리에 용이
- 외부 시스템과의 연결이 용이
카카오페이증권에서 Cilium Egress Gateway를 도입한 이유
이런 이유로 Gateway 통합 프로젝트에서 Cilium Egress Gateway를 선택하게 되었고, 이제 프로젝트 목표와 성과가 어땠는지 알아보겠습니다.
Gateway 통합 프로젝트
카카오페이증권은 다양한 외부기관과의 연동을 통해 고객들에게 편리한 금융 서비스를 제공하고 있습니다. 이러한 연동을 위해 Gateway 서버가 약 100여 대 정도 운영되고 있었으며 Gateway는 물리서버에 Nginx 등의 웹서버를 구성하여 트래픽을 처리했습니다.
IaC로 Gateway 구성 및 관리를 하며 몇 가지 불편한 점들이 생겼습니다. 대표적으로 확장 시마다 프로비저닝 작업으로 인한 인적 리소스 및 물리서버 비용 증가, 외부기관 또는 내부 환경 변경에 따른 프로비저닝 작업으로 운영의 비효율성이었습니다.
이와 같은 불편한 점을 해소하고자 저희는 Gateway 환경의 물리 서버들을 Kubernetes 환경으로 이관하여 관리 및 운영 효율성을 높이고, 서버 대수 감소를 통한 비용 절감을 목표로 프로젝트를 진행했습니다.
프로젝트 목표
- 효율적인 관리 및 운영: Kubernetes 기반 Gateway 관리 시스템 구축을 통해 자동화 및 표준화를 도모하여 관리 및 운영 효율성을 극대화합니다.
- 서버 대수 감소로 비용 효율 증대: 컨테이너 기반 Gateway를 운영하여 서버 대수를 최소화하고, 이를 통해 하드웨어 및 운영 비용을 절감합니다.
- 외부기관 변경 최소화: 기존 IP/NAT IP를 그대로 사용할 수 있도록 하여 외부기관 시스템 변경 작업을 최소화합니다.
Cilium Egress Gateway 도입 배경
기존 운영되던 Gateway는 외부기관과 연동하기 위하여 전용선 혹은 외부 통신을 하되 양측의 약속된 IP로 통신을 하고 있었습니다. 약속된 IP는 양측의 whitelist로 관리되고 있었으며 서버 추가 및 변경작업이 있는 경우 양측 합의 후 whitelist 반영 및 확인을 해야 했습니다. 그에 따라 내부요인에 의한 변경작업도 일정 합의, 변경, 확인 단계를 거쳐 반영해야 하므로 많은 커뮤니케이션과 작업이 필요했습니다.
이와 같은 복잡한 과정은 운영 효율성을 크게 저해하는 요인이었습니다. 이러한 문제를 해결하기 위해 저희는 Cilium Egress Gateway를 도입했습니다. 도입에 따른 이점은 아래와 같습니다.
- CNI(Container Network Interface)로 Cilium 사용: 이미 Kubernetes 환경에서 CNI로 Cilium을 사용하고 있어 별도의 CNI 도입 없이 Cilium Egress Gateway를 활용할 수 있습니다.
- 운영 리소스 절감: 기존에 사용하고 있던 Cilium 환경을 활용하기 때문에 추가적인 운영 리소스가 필요하지 않습니다.
- 외부기관 변경 최소화: Cilium Egress Gateway는 기존 IP/NAT IP를 그대로 사용할 수 있도록 지원하여 외부기관 시스템 변경 작업을 최소화합니다.
여기서 포인트는 내부 변경작업에 따른 외부기관 변경 최소화였습니다. 많은 Gateway들을 kubernetes 환경으로 이관하여 물리적 리소스 사용량을 줄이되, Gateway에 따라 Egress Gateway 정책 적용으로 프로젝트 진행으로 인한 외부기관의 변경작업은 없도록 하기 위함 이였습니다. 적용된 구성도는 4. EgressGateway 적용된 구성도에서 확인 가능합니다.
Cilium Egress Gateway 적용
1. Cilium Egress Gateway 활성화
현재 구성된 Cilium 은 helm chart로 구성되어 있어, 설정값 변경으로 간단하게 활설화를 합니다. 활성화 후 적용을 위해 Cilium 재시작합니다.
- bpf.masquerade: 클러스터에서 나가는 트래픽의 source IP를 노드로 설정합니다.
- kubeProxyReplacement: Cilium BPF 데이터 경로에서 kube-proxy 대체합니다.
- egressGateway.enabled: egressGateway의 활성화 여부입니다. 저희는 egressGateway를 사용하기 위해 true로 설정합니다.
- egressGateway.installRoutes: true를 설정하게 된다면 클러스터 내 모든 트래픽이 egressGateway를 통해 외부로 나가게 됩니다. 저희는 서비스별 정책을 적용하기 위해 false로 설정합니다.
- egressGateway.reconciliationTriggerInterval: 클러스터의 상태 변경을 감지하고 재조정하는 주기입니다. 기본 값으로 1초가 설정되어 있습니다.
(중략)
bpf:
masquerade: true
kubeProxyReplacement: true
egressGateway:
# -- Enables egress gateway to redirect and SNAT the traffic that leaves the
# cluster.
enabled: true
# -- Deprecated without a replacement necessary.
installRoutes: false
# -- Time between triggers of egress gateway state reconciliations
reconciliationTriggerInterval: 1s
# -- Maximum number of entries in egress gateway policy map
# maxPolicyEntries: 16384
(중략)
2. Egress Gateway에서 사용할 IP address 추가
Egress Gateway에서 사용할 IP address를 추가하는 작업이 필요하며, 추가하는 방법은 서버에 IP를 추가하는 방식과 Pod 내부에서 IP를 추가하는 방식 2가지가 존재합니다. 카카오페이증권에서는 서버와 IP를 관리하는 파트가 별도로 존재하기 때문에 Kubernetes 노드에 IP address 추가 방식을 사용하고 있습니다. IP address를 추가하지 않으면 사용자가 원하는 IP로 나가지 않게 됩니다. 따라서 Egress Gateway 사용 전 사용 할 IP에 대한 검토가 필요하며, 사전 작업이 필요합니다.
2.1. Kubernetes 노드에 IP address 추가
아래의 내용은 Cilium Egress Gateway 검증을 위한 테스트 내용으로, 네트워크 환경에 따라 달라집니다. 사용자 환경에 맞게 적용 부탁드립니다.
$ ip address add 192.168.1.2/24 dev eth0;
$ ip address show
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
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether d4:f5:ef:25:96:64 brd ff:ff:ff:ff:ff:ff
inet 192.168.1.240/24 brd 192.168.1.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet 192.168.1.2/24 brd 192.168.1.255 scope global secondary noprefixroute eth0:0
valid_lft forever preferred_lft forever
2.2. Container 환경에 IP address 추가
아래는 Container 환경에서 IP address 추가 확인하는 manifest입니다. 아래의 manifest를 참고하여 Gateway Container에 적용이 필요합니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: "egress-ip-assign"
labels:
name: "egress-ip-assign"
spec:
replicas: 1
selector:
matchLabels:
name: "egress-ip-assign"
template:
metadata:
labels:
name: "egress-ip-assign"
spec:
affinity:
# the following pod affinity ensures that the "egress-ip-assign" pod
# runs on the same node as the mediabot pod
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: class
operator: In
values:
- mediabot
- key: org
operator: In
values:
- empire
topologyKey: "kubernetes.io/hostname"
hostNetwork: true
containers:
- name: egress-ip
image: docker.io/library/busybox:1.31.1
command: ["/bin/sh","-c"]
securityContext:
privileged: true
args:
- "ip address add 192.168.1.2/24 dev eth0;"
lifecycle:
preStop:
exec:
command:
- "/bin/sh"
- "-c"
- "ip address del 192.168.1.2/24 dev eth0;"
3. CiliumEgressGatewayPolicy 생성
Cilium Egress Gateway 활성화와 사용할 IP address 추가 됐다면 CiliumEgressGatewayPolicy를 생성할 순서입니다.
아래의 CiliumEgressGatewayPolicy는 내부 정보를 비식별화한 설정입니다. 추가로 궁금한 부분이 있다면 댓글로 문의 부탁드립니다.
- spec.selectors를 사용하여 적용될 Pod를 지정합니다.
- spec.egressGateway를 통하여 node와 egressIP를 지정합니다.
apiVersion: cilium.io/v2
kind: CiliumEgressGatewayPolicy
metadata:
name: proxy-egress-policy
spec:
# Specify which pods should be subject to the current policy.
# Multiple pod selectors can be specified.
selectors:
- podSelector:
matchLabels:
wallga/app: production-nginx-forward-proxy
wallga/namespace: proxy
# Specify which destination CIDR(s) this policy applies to.
# Multiple CIDRs can be specified.
destinationCIDRs:
- "0.0.0.0/0"
# Configure the gateway node.
egressGateway:
# Specify which node should act as gateway for this policy.
nodeSelector:
matchLabels:
kubernetes.io/hostname: node01.hostname
egressIP: 192.168.1.2
---
apiVersion: cilium.io/v2
kind: CiliumEgressGatewayPolicy
metadata:
name: fep-egress-policy
spec:
# Specify which pods should be subject to the current policy.
# Multiple pod selectors can be specified.
selectors:
- podSelector:
matchLabels:
wallga/app: production-nginx-forward-proxy
wallga/namespace: fep
# Specify which destination CIDR(s) this policy applies to.
# Multiple CIDRs can be specified.
destinationCIDRs:
- "0.0.0.0/0"
# Configure the gateway node.
egressGateway:
# Specify which node should act as gateway for this policy.
nodeSelector:
matchLabels:
kubernetes.io/hostname: node01.hostname
egressIP: 192.168.1.1
4. EgressGateway 적용된 구성도
- 내부 서비스에서 외부 대외 기관, Publish 저장소 등에 접근하기 위해서는 Gateway를 통해야 합니다.
- Gateway는 각각의 용도에 따라 분리되어 있습니다.
- 대외기관 1에 대한 트래픽은 Gateway Pod에서 192.168.1.1 IP 주소를 통해 전송됩니다.
- Public 저장소에 대한 트래픽은 Gateway Pod에서 192.168.1.2 IP 주소를 통해 전송됩니다.
- 방화벽에서는 Source IP 를 192.168.1.1 / 192.168.1.2 에 따라 특정 NAT IP로 변경하여 전송됩니다.
- Egress Gateway Policy로 Source IP가 변경되지 않기때문에 방화벽 정책에 대한 추가 및 변경 작업은 하지 않아도 됩니다.
앞으로의 고도화 방향성
카카오페이증권에서는 생산성플랫폼인 wecan을 자체 구축 및 운영하고 있습니다. 개발자가 Wecan을 통한 목적지, 사용될 IP를 입력하여 Gateway를 생성하여 사용 및 관리할 수 있도록 작업 중에 있습니다.
- 개발자가 생산성 플랫폼을 통한 Gateway 구성을 자동화하여 개발 및 연동 테스트에 소요되는 시간을 단축합니다.
- 개발자가 Gateway를 직접 생성 및 관리하여 불필요한 커뮤니케이션 비용을 줄입니다.
- 개발자가 외부의 변경으로 인한 내부 변경에 대해 직접 대응이 가능합니다.
프로젝트 수행 이후의 변화
Gateway 통합 프로젝트 수행 이후 가장 큰 변화는 약 100여 대의 서버가 약 40여 대로 감소한 점입니다. 관리 대상서버가 반 이상으로 줄어 서버 장비에 대한 비용과 운영에 들어가는 인적 비용이 크게 감소됐습니다.
또 다른 큰 변화는 바로 Gateway를 kubernetes 환경으로 이관된 점입니다. 이관된 후의 장점은 아래와 같이 정리해 보았습니다.
- Gateway 환경을 위해 따로 운영되면 로깅 및 모니터링이 기존에 사용하던 kubernetes 환경의 로깅 및 모니터링으로 통합되어 운영 리소스가 감소하였습니다.
- Gateway에 config 변경이 필요할 때 Configmap Object로 적용 및 관리하여 편의성이 증대 됐습니다.
- 기존에 운영하던 Argo UI를 통해 각각의 Object 확인 및 제어가 가능하여 운영에 대한 편의성이 증대 됐습니다.
- Cilium Egress Gateway 적용으로 내부 작업으로 인해 외부 기관과의 커뮤니케이션이 불필요해졌습니다.
마치며
카카오페이증권은 현재 대부분의 서비스를 Kubernetes 환경에서 운영하고 있으며, Gateway 통합 프로젝트 이후 운영 서버가 약 50% 감소하고, 운영에 들어가는 인적 리소스가 크게 감소하는 효과를 보았습니다. 또한, Cilium과 같은 eBPF 기반 기술을 도입함으로써 실시간 네트워크 모니터링과 보안을 강화하는 데 성공했습니다.
저희와 유사한 환경에서 운영 효율성, 비용 절감, 그리고 네트워크 관리의 단순화를 고민하시는 분들이라면, Gateway를 Kubernetes 환경으로 이관하고 Cilium Egress Gateway를 검토해 보시길 권장합니다.
카카오페이증권은 앞으로도 이러한 프로젝트를 통해 기술력을 더욱 향상시키고자 합니다. 추가적인 최적화를 고려하고 계신다면, 저희 카카오페이증권의 사례를 참고하여 eBPF 기반의 다양한 솔루션을 탐색해 보시는 것도 좋은 방법일 것입니다. 이것으로 글을 마치겠습니다. 감사합니다.