[k8s] Cilium: Egress Gateway (with kube-vip)
Egress Gateway๋ cilium์ ์ฃผ์ ํ์ฅ ๊ธฐ๋ฅ ์ค ํ๋๋ค.
Egress, ๊ทธ๋ฌ๋๊น ์์๋ฐ์ด๋ ํธ๋ํฝ์ ์ด๋ค IP๋ก ๋๊ฐ๊ฒ ํ ์ง ์ง์ ํ ์ ์๊ฒ ํด์ฃผ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค.
๊ธฐ๋ณธ ์๋ฆฌ
๊ธฐ๋ณธ์ ์ธ ๋ ผ๋ฆฌ๋ ๊ทธ๋ค์ง ๋ณต์กํ ๊ฒ์ ์๋ค.
๊ฒ์ดํธ์จ์ด ๋
ธ๋๋ฅผ ํ๋ ์ก์๋์ผ๋ฉด, ๊ทธ๋์ ํตํด ํธ๋ํฝ์ ๊ฒฝ์ ํด์ ๋๊ฐ๊ฒ ํ๋ ๊ฒ์ด๋ค.
๊ตฌ์ฑํ๊ธฐ์ ๋ฐ๋ผ์ ๋ค์ํ ํ๋ฆ์ผ๋ก ์ ๊ฐ๋ฅผ ํ ์ ์์ง๋ง, ์ผ๋จ ๊ธฐ๋ณธ ๋ ผ๋ฆฌ๋ ํ๋์ด ๊ฐ๊ณ ์๋ IP๋ก SNAT์ ๋๋ฆฌ๋ ๊ฒ์ด๋ค. ๊ทธ๋ฆฌ๊ณ ํด๋น IP๋ฅผ ํน์ WAN์ ๋ฌผ๋ ค์ ๋ด๋ณด๋ด๋ฉด ๋๋ค.
๊ทธ๋์ ๊ธฐ๋ณธ ๊ตฌ์กฐ์์๋ ์ด๊ฒ ๋ค์ดํ์์ด ํญ์ ์๊ธธ ์๋ฐ์ ์๊ธฐ๋ ํ๋ค. ์ผ๋จ์ ํ๋์ ๋ ธ๋๊ฐ IP๋ฅผ ๋ฌผ๊ณ ๋ํ์ ํด์ค์ผ ํ๊ธฐ ๋๋ฌธ์, ๋ถํ์ ๋ฌธ์ ๋ ์๊ณ , ํด๋น ๋ ธ๋๊ฐ ์ฃฝ์์ ๋๋ ๋ค์ดํ์์ด ๋ฐ์ํ ์ ์๋ค.
cilium egress์๋ ๊ณ ๊ฐ์ฉ์ฑ ์ต์ ์ด ์๊ธด ํ๋ฐ, ์ด๊ฑด cilium ์ํฐํ๋ผ์ด์ฆ์์๋ง ์ ๊ณต๋๋ ๊ธฐ๋ฅ์ด๊ณ , ์ง์ ๊ตฌ์ฑํ๋ ค๋ฉด ์์ ์ข ์จ์ผํ๋ค.
์ฌ์ ์กฐ๊ฑด
์ด๊ฑธ ์ฌ์ฉํ๋ ค๋ฉด cilium์ ์ค์นํ ๋ ํน์ ์ต์
์ ์ผ์ค์ผ ํ๋ค. ๊ธฐ๋ณธ๊ฐ์ด ์๋๋ค.
cilium CLI๋ฅผ ํตํด ์ค์นํ ๊ฒฝ์ฐ ๊ธฐ๋ณธ๊ฐ์ ์ด๊ฒ ํฌํจ๋์ด์์ง ์๊ธฐ ๋๋ฌธ์ ๊ทธ๋ฅ ๊น์๋ค๊ฐ ๋์น ์ ์๋ค.
helm์ ํตํด ์ค์นํ ๊ฒฝ์ฐ์๋ ๋ค์๊ณผ ๊ฐ์ด ์ต์ ์ ๋ฃ์ด์ ์ค์นํ ์ ์๋ค.
# Egress Gateway ์ ์ ์กฐ๊ฑด. BPF ๋ก Service โ Backend ๋ก๋๋ฐธ๋ฐ์ฑ ์ํ.
kubeProxyReplacement: true
egressGateway:
enabled: true
์ด๊ฑฐ 2๊ฐ์ง๊ฐ ํต์ฌ์ด๋ค.
์ด 2๊ฐ์ง ๊ฐ์ ๋ค์ดํ์์ด ์๋ฐ๋๋ ๋ณ๊ฒฝ์ด๋ผ์, ๊ฐ๊ธ์ ์ด๋ฉด ์ฒ์๋ถํฐ ๋ฃ์ด์ฃผ๋๊ฒ ์ข๋ค.
Egress Gateway ์ฌ์ฉํด๋ณด๊ธฐ
์ผ๋จ ์ด๋ฐ์ ๋ฐ ๋ถ๊ฐ ์ต์ ๋นผ๊ณ ๊ทธ๋ฅ ๋์์ ์ฐ๋๊ฒ ๋ชฉ์ ์ด๋ผ๋ฉด, ์ธํ ์ ๋งค์ฐ ๊ฐ๋จํ๋ค.
๋ค์๊ณผ ๊ฐ์ด ์ ์ฑ ๋ง ํ๋ ์ ์ํด์ฃผ๋ฉด ๋์ธ ๊ฒ์ด๋ค.
apiVersion: cilium.io/v2
kind: CiliumEgressGatewayPolicy
metadata:
name: egress-wan4
spec:
selectors:
- podSelector:
matchLabels:
egress.myyrakle.io/profile: wan4
destinationCIDRs:
- 0.0.0.0/0
excludedCIDRs:
- 10.42.0.0/16
- 10.43.0.0/16
- 192.168.88.0/24
egressGateway:
nodeSelector:
matchLabels:
egress.myyrakle.io/pool: default
egressIP: 192.168.88.222
์ด ์ ์๋ ๋ค์๊ณผ ๊ฐ์ ์๋ฏธ๋ฅผ ๊ฐ์ง๋ค.
- "egress.myyrakle.io/profile: wan4"๊ฐ ๋ถ์ด์๋ pod์ ๋ํด์ ์ ์ฉํ๋ค.
- "egress.myyrakle.io/pool: default"๊ฐ ๋ถ์ด์๋ node๋ฅผ gateway ๋ ธ๋๋ก ์ ํํ๋ค.
- ๋ด๋ณด๋ด๋ ์ต์ข IP๋ 192.168.88.222๋ค. (SNAT)
๊ทธ๋ฆฌ๊ณ pod๋ฅผ ์ ์ํ ๋ ์ ์กฐ๊ฑด์ ๋ง์ถฐ์ ๋ผ๋ฒจ๋ง ๋ฌ์์ฃผ๋ฉด ๋๋ค.
spec:
...
template:
metadata:
labels:
...
egress.myyrakle.io/profile: wan4
๊ทธ๋ฆฌ๊ณ ํ ์คํธํด๋ณผ๋๋ ์ด๋ฐ ์์ผ๋ก ํ๋ฉด ๋๋ค.
kubectl run egress-test-wan4 --image=alpine:3.20 \
--labels=egress.myyrakle.io/profile=wan4 --restart=Never \
--command -- sh -c 'sleep 5; for i in 1 2 3; do wget -qO- -T 8 http://ifconfig.me/ip; echo " rc=$?"; done'
kubectl logs egress-test-wan4
๊ทธ๋ผ ์ค์ ํ๋๋ก wan4์ ๋ถ์ด์๋ ๊ณต์ธ IP๋ก ๋๊ฐ ๊ฒ์ ๋ณผ ์ ์๋ค.
kube-vip์ ๊ณ ๊ฐ์ฉ์ฑ
๊ทผ๋ฐ ์ ๋ฐฉ์์๋ ๋ฌธ์ ๊ฐ ์๋ค.
๋
ธ๋๊ฐ ํผ์ ๋ชธ๋นตํ๋ ๊ฒ๋ ๋ฌธ์ ๋ผ๋ฉด ๋ฌธ์ ์ธ๋ฐ, ์ผ๋จ ๊ฒ์ดํธ์จ์ด ์ญํ ์ ๋งก์ ๋
ธ๋๊ฐ ๋ป์ผ๋ฉด ์ ์ฒด ์ฅ์ ๊ฐ ๋ฐ์ํ๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ด๋ค.
์ด๋ด๋ ํ์ฉํ๊ธฐ ์ข์ ๊ฒ์ด kube-vip๋ค.
https://blog.naver.com/sssang97/224428580085
์ด๊ฑธ ์ฌ์ฉํ๋ฉด ๋ด๋ณด๋ผ IP ์์ฒด๋ฅผ ํน์ ๋
ธ๋์ ์ข
์์ํค๊ธฐ ์๊ณ , ๋ค๋ฅธ ๋
ธ๋์ ์ธ๊ณํด์ ์ฅ์ ๊ฐ ์๋์ผ๋ก ํ๋ณต๋๋๋ก ๋ง๋ค ์ ์๋ค.
ํ๋์ ๋ ธ๋์ ๋ถํ๊ฐ ๊ณผ์ค๋๋๊ฑด ๊ทธ๋ฅ IP ์์ฒด๋ฅผ ๋ถ์ฐํด๋๊ณ ๋์ผ WAN์ ๋ผ์ฐํ ํ๋ฉด ๋๋ ๊ฒ์ด๊ณ , ๊ฐ์ฉ์ฑ์ ์ฑ๊ธฐ๋๊ฑด ์ด vip๋ฅผ ํ์ฉํ๋ ๊ฒ์ด ๊ฐ์ฅ ๊ด์ฐฎ๋ค.
์ฌ๊ธฐ์๋ kube-vip๋ฅผ ํ์ฉํด์ ๊ตฌ์ฑํ๋ ๋ฐฉ๋ฒ์ ๋ค๋ค๋ณธ๋ค.
๋ด ๊ฒฝ์ฐ์๋ wan์ด 8๊ฐ๊ฐ ๋๋๋ฐ, ์ด๊ฑธ ๋ค ์ฐ๋ํด์ผํด์ ๊ตฌ์ฑ์ด ์กฐ๊ธ ๋ณต์กํ๋ค.
๊ทธ๋ฆฌ๊ณ vip๋ฅผ ์ฐ๊ธฐ ๋๋ฌธ์ ๊ฐ์ ip๋ก ์ฌ์ฉํ ip ๋ชฉ๋ก์ ๋ฏธ๋ฆฌ ์ ํด๋๊ณ DHCP ๋ฒ์์์ ๋นผ๋๋ ํธ์ด ์ข๋ค.
๋ด ๊ฒฝ์ฐ์๋ 192.168.88.200~๋ฅผ ์ฌ์ฉํ๊ธฐ๋ก ํ๋ค.
๊ฒ์ดํธ์จ์ด์ฉ ๋ผ๋ฒจ ๋ถ์ด๊ธฐ
์, ์ผ๋จ Egress Gateway๋ก ์ฌ์ฉํ ํ๋ณด๊ตฐ์ ๋ผ๋ฒจ๋ก ์ ๋ถ ๋ถ์ฌ์ค๋ค.
kubectl label node ๋
ธ๋๋ช
egress.myyrakle.io/pool=default --overwrite
kubectl get nodes -L egress.myyrakle.io/pool
์ ์ผ๋ฉด ์ด์ฉ ์ ์๊ณ , 2๊ฐ ์ด์์ผ๋ก ํด๋์ผ๋ฉด ์๋์ผ๋ก ํ๋ณต๋๋๋ก ํ๋ ๊ฒ์ด ๊ฐ๋ฅํ๋ค.
kube-vip ๋ฐ๋ชฌ์ ๋ง๋ค๊ธฐ
๊ทธ๋ฆฌ๊ณ kube-vip์ฉ ๊ธฐ๋ณธ ๋ฐ๋ชฌ์
์ ํ๋ ์ ์ํด์ค๋ค.
์ด๊ฑด ์๊น ๋ผ๋ฒจ์ ๋ถ์ธ ๋
ธ๋์๋ง ์คํ๋๋ฉฐ, ํต์ฌ ์ปดํฌ๋ํธ๊ฐ ๋ ๊ฒ์ด๋ค. wan์ ์ฌ๋ฌ๊ฐ ๋ถ์ด๋๋ผ๋ ์ด๊ฑด ํ๋ฒ๋ง ๋ง๋ค์ด๋ ๋๋ค.
# kube-vip egress VIP (services mode) โ WAN ํ๋๋น LoadBalancer Service ํ๋ (04-vips/)
apiVersion: v1
kind: Namespace
metadata:
name: kube-vip-egress
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: kube-vip-egress-svc
namespace: kube-system
labels:
app.kubernetes.io/name: kube-vip-egress
app.kubernetes.io/instance: svc
spec:
selector:
matchLabels:
name: kube-vip-egress-svc
template:
metadata:
labels:
name: kube-vip-egress-svc
app.kubernetes.io/name: kube-vip-egress
app.kubernetes.io/instance: svc
spec:
hostNetwork: true
serviceAccountName: kube-vip
nodeSelector:
egress.myyrakle.io/pool: default
tolerations:
- operator: Exists
effect: NoSchedule
containers:
- name: kube-vip
image: ghcr.io/kube-vip/kube-vip:v1.2.4
args: [manager]
env:
# Node name ์ ๋ฐ๋์ downwardAPI ๋ก ๋๊ฒจ์ผ kube-vip ๊ฐ ์ฌ๋ฐ๋ฅธ k8s ๋
ธ๋์ label ํจ์น ๊ฐ๋ฅ
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: vip_nodename
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- { name: vip_arp, value: "true" }
- { name: vip_cidr, value: "32" }
- { name: cp_enable, value: "false" }
- { name: lb_enable, value: "false" }
- { name: svc_enable, value: "true" }
- { name: svc_election, value: "true" }
- { name: svc_namespace, value: kube-vip-egress }
- { name: lb_class_name, value: myyrakle.io/egress-vip }
- { name: lb_class_only, value: "true" }
- { name: lb_class_legacy_handling, value: "false" }
- { name: vip_leaseduration, value: "5" }
- { name: vip_renewdeadline, value: "3" }
- { name: vip_retryperiod, value: "1" }
- { name: enable_node_labeling, value: "true" }
# hostNetwork ๋ผ :2112 ๋ control-plane kube-vip ๊ฐ ์ด๋ฏธ ์ ์
- { name: prometheus_server, value: ":2113" }
securityContext:
capabilities:
add: [NET_ADMIN, NET_RAW]kube-vip ์๋น์ค ๋ง๋ค๊ธฐ
์ด๊ฑด wan๋ง๋ค ํ๋์ฉ ๋ง๋ค๋ฉด ๋๋ค.
wan4๋ง ๋จผ์ ๋ง๋ค์ด๋ณด๊ฒ ๋ค.
apiVersion: v1
kind: Service
metadata:
name: egress-wan4
namespace: kube-vip-egress
labels:
app.kubernetes.io/name: kube-vip-egress
annotations:
kube-vip.io/loadbalancerIPs: "192.168.88.222"
kube-vip.io/allow-reconcile-without-endpoints: "true"
spec:
type: LoadBalancer
loadBalancerClass: myyrakle.io/egress-vip
externalTrafficPolicy: Cluster
ports:
- name: unused
port: 65535
protocol: TCP
---
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
name: egress-wan4
namespace: kube-vip-egress
labels:
kubernetes.io/service-name: egress-wan4
addressType: IPv4
endpoints: []
์ ๋นํ ๋ง๋ค์ด์ฃผ๊ณ , ์ฌ๊ธฐ๊น์ง ๋์ผ๋ฉด ์ด์ ๋ผ์ฐํฐ์ ๋ค์ด๊ฐ์ ์ค์ ํด์ฃผ๋ฉด ๋๋ค.
๋ผ์ฐํฐ ์ค์ (microtik)
์. ์ด์ ํด์ผํ ๊ฒ์ ์๊น ๋งคํํด๋์ vip๋ฅผ ํน์ wan๋ก ๋๊ฐ๋๋ก ์ต์ข
๋งคํ์ ํด์ฃผ๋ ๊ฒ์ด๋ค.
์ด๊ฑด microtik์ ์์์ด๊ธด ํ๋ฐ, ์ด๋ค ๋ผ์ฐํฐ๋ ๊ฑฐ์ ๋น์ทํ๊ฒ ์ฒ๋ฆฌํ ์ ์์ ๊ฒ์ด๋ค.
# ๋ผ์ฐํ
ํ
์ด๋ธ ๋ง๋ค๊ธฐ
/routing table add fib name=egress-wan4
# 192.168.88.222์์ ์์๋ ์ฐ๊ฒฐ์ ๋งํน
/ip firewall mangle add chain=prerouting src-address=192.168.88.222 action=mark-connection new-connection-mark=egress-wan4 passthrough=yes comment="egress VIP .222 to wan4 conn"
/ip firewall mangle add chain=prerouting src-address=192.168.88.222 connection-mark=egress-wan4 action=mark-routing new-routing-mark=egress-wan4 passthrough=no comment="egress wan4 routing-mark"
# egress-wan4 ๋ผ์ฐํ
ํ
์ด๋ธ์ ๊ฒฝ๋ก ์ถ๊ฐ => wan4๋ก ๋๊ฐ๋๋ก
/ip route add dst-address=0.0.0.0/0 gateway=61.74.171.254%wan4 routing-table=egress-wan4 distance=1 comment="egress wan4 route"
# ์ต์ข
NAT ์ฒ๋ฆฌ
/ip firewall nat add chain=srcnat out-interface=wan4 action=masquerade comment="egress SNAT via wan4"
์ค๋ฅ ์์ด ์ ๋๋ฉด ๋ ๊ฒ์ด๋ค.
๊ฒ์ดํธ์จ์ด ์ ์ฑ ์์ฑ
์ด์ ๋ค์ ์ ์ ํ ๋ง์ถฐ์ ๊ฒ์ดํธ์จ์ด ์ ์ฑ ์ ๋ง๋ค์ด์ฃผ๋ฉด ๋์ด๋ค.
apiVersion: cilium.io/v2
kind: CiliumEgressGatewayPolicy
metadata:
name: egress-wan4
spec:
selectors:
- podSelector:
matchLabels:
egress.myyrakle.io/profile: wan4
destinationCIDRs:
- 0.0.0.0/0
excludedCIDRs:
- 10.42.0.0/16
- 10.43.0.0/16
- 192.168.88.0/24
egressGateway:
nodeSelector:
matchLabels:
egress.myyrakle.io/pool: default
service-provided.kube-vip.io/egress-wan4.kube-vip-egress: "192.168.88.222"
egressIP: 192.168.88.222
์ด๋ฌ๋ฉด ์ vip๋ฅผ ๋ค๊ณ ์๋ ๋์ ๊ฒ์ดํธ์จ์ด๋ก ์ผ์์ ๋์ ์ผ๋ก ๊ฐ๋ฆฌํฌ ์ ์๋ค.
์ฌ๊ธฐ๊น์ง ํ๋ฉด ๋์ด๋ค. ํ์ํ๋งํผ wan ์ธํธ๋ฅผ ์ถ๊ฐํ๊ณ , ๊ฒ์ดํธ์จ์ด ๋ ธ๋๋ก ์ ํ๋ ๋ ์์ ํฐ๋จ๋ ค์ ๋ณต๊ตฌ๊ฐ ๋๋์ง ํ์ธ๊น์ง ํด๋ณด๋ฉด ๋๋ค.
ํ๊ณ
์ด ๋ฐฉ์์๋ ๋ช๊ฐ์ง ํ๊ณ์ ๋ค์ด ์กด์ฌํ๋ค. ๋ช๊ฐ์ง๋ Cilium Egress์ ๊ทผ๋ณธ์ ์ธ ํ๊ณ์ ์ด๊ธฐ๋ ํ๋ค.
๋ค์ดํ์
๊ฒ์ดํธ์จ์ด ๋
ธ๋๊ฐ ์ฃฝ์ผ๋ฉด, vip๋ฅผ ํตํด์ ๊ณ์น๋ฐ๊ณ ๋ณต๊ตฌ๋๊ธฐ๊น์ง ๋ณดํต ๋ช์ด ์ ๋์ ๋ค์ดํ์์ด ๋ฐ์ํ๋ค.
์ด๊ฑด ์์ ํ ์์ ๊ธฐ ์ด๋ ต๋ค. ๋ณต๊ตฌ๋ฅผ ๋น ๋ฅด๊ฒ, ์๋์ผ๋ก ์ฒ๋ฆฌํด์ค ๋ฟ์ด๋ค.
๋ ธ๋ ๊ณผ๋ถํ
์ผ๋จ Egress Gateway Policy๊ฐ ์ฌ์ฉํ๋ ์ต์ข ๊ฒ์ดํธ์จ์ด ๋ ธ๋๋ ํ๋๋ค. ๊ทธ๋์ ๋ถํ๊ฐ ๊ณผ๋ํ๊ฒ ๋ชฐ๋ฆฌ๋ ๊ฒ ์์ฒด๋ฅผ ๊น๋ํ๊ฒ ํด๊ฒฐํ์ง ์๋๋ค.
๊ฐ์ฅ ๋จ์ํ ์ํ ๋ฐฉ๋ฒ์, ๊ฐ์ WAN์ผ๋ก ๋ผ์ฐํ ๋๋ ๋ด๋ถ IP๋ฅผ ์ฌ๋ฌ๊ฐ ๋ง๋ค๊ณ , ๊ฐ๊ฐ ํ๋์ฉ Egress Gateway๋ฅผ ๋ง๋ค์ด์ ์ง์ ๋ถ์ฐ์ ์ํค๋ ๊ฒ์ด๋ค.
์ด๋ฐ ์์ผ๋ก ๋ง์ด๋ค.
192.168.88.222 โ gateway-1 โ WAN4
192.168.88.223 โ gateway-2 โ WAN4
192.168.88.224 โ gateway-3 โ WAN4
๋์ ๊ด๋ฆฌ๋ ์ฌ์ฉ์ด ์ข ๋ณต์กํด์ง๋ค.
Egress ๋๋ ์ด
cilium egress ๋ผ์ฐํ ์์ฒด์๋ ๋๋ ์ด๊ฐ ์๋ค. ์ด๊ฒ ์ฌ์ค Pod๊ฐ ๋ฐ๋ ๋ฐ๋ก ๋ถ๋๊ฒ ์๋๋ผ, ๋น๋๊ธฐ์ ์ผ๋ก ๋์ค์ ๋ถ๋๋ค.
๊ทธ๋์ ์ปจํ ์ด๋๊ฐ ์์๋๊ณ ๋ช์ด ์ ๋๋ ์๋์ IP๋ก ๋๊ฐ ์ ์๋ค. ์ด๊ฑธ ๋ฐฉ์งํ๋ ค๋ฉด ๊ทธ๋ฅ ์ปจํ ์ด๋์ ์์ ๋๊ธฐ์๊ฐ์ ๋ฃ๊ฑฐ๋, ์ํ๋ IP๊ฐ ๋ถ์๋๊น์ง ํ๋ก๊ทธ๋จ ์์์ ์ง์ฐ์ํค๋ ์คํฌ๋ฆฝํธ๋ฅผ ๋ฐ๊ฑฐ๋ ํด์ผํ๋ค.
์ฐธ์กฐ
https://christianhuth.de/a-highly-available-egress-gateway-for-kubernetes-with-cilium-and-kube-vip/
https://tech.kakaopay.com/post/cilium-egress-gateway/
https://docs.cilium.io/en/stable/network/egress-gateway/egress-gateway/
https://cilium.io/use-cases/egress-gateway/
https://blog.naver.com/sssang97/224428580085
https://blog.naver.com/sssang97/224428274080
https://blog.naver.com/sssang97/224425032860