
들어가며
안녕하세요! Devlos입니다.
전국의 클라우드 엔지니어들과 함께 성장하는 즐거움을 느끼며, 이번 주차도 힘차게 시작해 보겠습니다! 빠라밤.
.
.
.
이번 포스팅은 CloudNet@ 커뮤니티에서 주최하는 Cilium 스터디 2주 차 주제인 "(Observabilty) Hubbkem Prometheus/Grafana"에 대해서 정리한 내용입니다.
실습환경 구성
이번 주차 실습 환경은 mac M3 Pro max 환경에서 실습을 진행했고, VirtualBox + Vagrant로 환경을 구성했어요.
Cilium 최초 설치시 Hubble 및 기타 내용들을 실습히며 구성하기 위해 위해서 제외하고 설치합니다.

Virtual Box, Vagrant 설치
- Vagrantfile : 가상머신 정의, 부팅 시 초기 프로비저닝 설정
# Variables
K8SV = '1.33.2-1.1' # Kubernetes Version : apt list -a kubelet , ex) 1.32.5-1.1
CONTAINERDV = '1.7.27-1' # Containerd Version : apt list -a containerd.io , ex) 1.6.33-1
CILIUMV = '1.17.6' # Cilium CNI Version : https://github.com/cilium/cilium/tags
N = 2 # max number of worker nodes
# Base Image https://portal.cloud.hashicorp.com/vagrant/discover/bento/ubuntu-24.04
BOX_IMAGE = "bento/ubuntu-24.04"
BOX_VERSION = "202502.21.0"
Vagrant.configure("2") do |config|
#-ControlPlane Node
config.vm.define "k8s-ctr" do |subconfig|
subconfig.vm.box = BOX_IMAGE
subconfig.vm.box_version = BOX_VERSION
subconfig.vm.provider "virtualbox" do |vb|
vb.customize ["modifyvm", :id, "--groups", "/Cilium-Lab"] # VirtualBox에서 VM 그룹 지정
vb.customize ["modifyvm", :id, "--nicpromisc2", "allow-all"] # 네트워크 카드 프로미스큐어스 모드 활성화 (네트워킹 실습을 위해 필요)
vb.name = "k8s-ctr"
vb.cpus = 2
vb.memory = 2048 # 컨트롤 플레인은 더 많은 메모리 필요
vb.linked_clone = true # 디스크 공간 절약을 위한 링크드 클론 사용
end
subconfig.vm.host_name = "k8s-ctr"
subconfig.vm.network "private_network", ip: "192.168.10.100" # 컨트롤 플레인 고정 IP
subconfig.vm.network "forwarded_port", guest: 22, host: 60000, auto_correct: true, id: "ssh"
subconfig.vm.synced_folder "./", "/vagrant", disabled: true
subconfig.vm.provision "shell", path: "init_cfg.sh", args: [ K8SV, CONTAINERDV ] # 기본 시스템 설정 및 K8s 컴포넌트 설치
subconfig.vm.provision "shell", path: "k8s-ctr.sh", args: [ N, CILIUMV ] # 마스터 노드 설정 및 Cilium CNI 설치
end
#-Worker Nodes Subnet1
(1..N).each do |i|
config.vm.define "k8s-w#{i}" do |subconfig|
subconfig.vm.box = BOX_IMAGE
subconfig.vm.box_version = BOX_VERSION
subconfig.vm.provider "virtualbox" do |vb|
vb.customize ["modifyvm", :id, "--groups", "/Cilium-Lab"]
vb.customize ["modifyvm", :id, "--nicpromisc2", "allow-all"]
vb.name = "k8s-w#{i}"
vb.cpus = 2
vb.memory = 1536 # 워커 노드는 상대적으로 적은 메모리
vb.linked_clone = true
end
subconfig.vm.host_name = "k8s-w#{i}"
subconfig.vm.network "private_network", ip: "192.168.10.10#{i}" # 워커 노드 순차적 IP 할당
subconfig.vm.network "forwarded_port", guest: 22, host: "6000#{i}", auto_correct: true, id: "ssh"
subconfig.vm.synced_folder "./", "/vagrant", disabled: true
subconfig.vm.provision "shell", path: "init_cfg.sh", args: [ K8SV, CONTAINERDV] # 기본 시스템 설정
subconfig.vm.provision "shell", path: "k8s-w.sh" # 워커 노드 클러스터 조인
end
end
end
- init_cfg.sh : args 참고하여 설치
#!/usr/bin/env bash
echo ">>>> Initial Config Start <<<<"
echo "[TASK 1] Setting Profile & Bashrc"
echo 'alias vi=vim' >> /etc/profile
echo "sudo su -" >> /home/vagrant/.bashrc
ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime # Change Timezone
echo "[TASK 2] Disable AppArmor"
systemctl stop ufw && systemctl disable ufw >/dev/null 2>&1 # 방화벽 비활성화 (실습 환경용)
systemctl stop apparmor && systemctl disable apparmor >/dev/null 2>&1 # AppArmor 보안 정책 비활성화 (K8s 호환성)
echo "[TASK 3] Disable and turn off SWAP"
swapoff -a && sed -i '/swap/s/^/#/' /etc/fstab # K8s는 SWAP 비활성화 필수
echo "[TASK 4] Install Packages"
apt update -qq >/dev/null 2>&1
apt-get install apt-transport-https ca-certificates curl gpg -y -qq >/dev/null 2>&1
# Download the public signing key for the Kubernetes package repositories.
mkdir -p -m 755 /etc/apt/keyrings
K8SMMV=$(echo $1 | sed -En 's/^([0-9]+\.[0-9]+)\..*/\1/p') # K8s 메이저.마이너 버전 추출
curl -fsSL https://pkgs.k8s.io/core:/stable:/v$K8SMMV/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v$K8SMMV/deb/ /" >> /etc/apt/sources.list.d/kubernetes.list
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
# packets traversing the bridge are processed by iptables for filtering
echo 1 > /proc/sys/net/ipv4/ip_forward # IP 포워딩 활성화 (Pod 간 통신을 위해 필수)
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.d/k8s.conf
# enable br_netfilter for iptables
modprobe br_netfilter # 브리지 네트워크 필터링 모듈 로드 (CNI 네트워킹용)
modprobe overlay # 오버레이 파일시스템 모듈 (컨테이너 이미지 레이어용)
echo "br_netfilter" >> /etc/modules-load.d/k8s.conf
echo "overlay" >> /etc/modules-load.d/k8s.conf
echo "[TASK 5] Install Kubernetes components (kubeadm, kubelet and kubectl)"
# Update the apt package index, install kubelet, kubeadm and kubectl, and pin their version
apt update >/dev/null 2>&1
# apt list -a kubelet ; apt list -a containerd.io
apt-get install -y kubelet=$1 kubectl=$1 kubeadm=$1 containerd.io=$2 >/dev/null 2>&1 # 특정 버전 고정 설치
apt-mark hold kubelet kubeadm kubectl >/dev/null 2>&1 # 패키지 버전 고정 (자동 업데이트 방지)
# containerd configure to default and cgroup managed by systemd
containerd config default > /etc/containerd/config.toml
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml # systemd cgroup 드라이버 사용 (K8s 권장)
# avoid WARN&ERRO(default endpoints) when crictl run
cat <<EOF > /etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
EOF
# ready to install for k8s
systemctl restart containerd && systemctl enable containerd
systemctl enable --now kubelet # kubelet 서비스 활성화 및 시작
echo "[TASK 6] Install Packages & Helm"
export DEBIAN_FRONTEND=noninteractive
apt-get install -y bridge-utils sshpass net-tools conntrack ngrep tcpdump ipset arping wireguard jq tree bash-completion unzip kubecolor termshark >/dev/null 2>&1 # 네트워킹 및 디버깅 도구들
curl -s https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash >/dev/null 2>&1 # Helm 패키지 매니저 설치
echo ">>>> Initial Config End <<<<"
- k8s-ctr.sh : kubeadm init, Cilium CNI 설치, 편리성 설정(k, kc)
- kubeadm-init-ctr-config.yaml ⇒ 'kubernetesVersion: v1.33.2' 기본 설정 변수 값 받을 수 있게 수정 해둘것!
apiVersion: kubeadm.k8s.io/v1beta4
kind: **InitConfiguration**
bootstrapTokens:
- token: "123456.1234567890123456" # 워커 노드가 클러스터에 조인할 때 사용할 토큰
ttl: "0s" # 토큰 만료 시간 (0s = 무제한)
usages:
- signing
- authentication
localAPIEndpoint:
advertiseAddress: "192.168.10.100" # API 서버가 광고할 IP 주소
nodeRegistration:
**kubeletExtraArgs:
- name: node-ip
value: "192.168.10.100"** # kubelet이 사용할 노드 IP 명시적 지정
criSocket: "unix:///run/containerd/containerd.sock" # 컨테이너 런타임 소켓
---
apiVersion: kubeadm.k8s.io/v1beta4
kind: **ClusterConfiguration**
kubernetesVersion: v1.33.2 # 설치할 K8s 버전
networking:
podSubnet: "10.244.0.0/16" # Pod CIDR 범위
serviceSubnet: "10.96.0.0/16" # Service CIDR 범위
#!/usr/bin/env bash
echo ">>>> K8S Controlplane config Start <<<<"
echo "[TASK 1] Initial Kubernetes"
curl --silent -o /root/kubeadm-init-ctr-config.yaml https://raw.githubusercontent.com/gasida/vagrant-lab/refs/heads/main/cilium-study/2w/kubeadm-init-ctr-config.yaml
kubeadm init --config="/root/kubeadm-init-ctr-config.yaml" --skip-phases=addon/kube-proxy >/dev/null 2>&1 # kube-proxy 건너뛰기 (Cilium이 대체)
echo "[TASK 2] Setting kube config file"
mkdir -p /root/.kube
cp -i /etc/kubernetes/admin.conf /root/.kube/config # kubectl 설정 파일 복사
chown $(id -u):$(id -g) /root/.kube/config
echo "[TASK 3] Source the completion"
echo 'source <(kubectl completion bash)' >> /etc/profile # kubectl 자동완성 활성화
echo 'source <(kubeadm completion bash)' >> /etc/profile
echo "[TASK 4] Alias kubectl to k"
echo 'alias k=kubectl' >> /etc/profile # kubectl 단축 명령어
echo 'alias kc=kubecolor' >> /etc/profile # 컬러 출력용 kubectl 대체
echo 'complete -F __start_kubectl k' >> /etc/profile
echo "[TASK 5] Install Kubectx & Kubens"
git clone https://github.com/ahmetb/kubectx /opt/kubectx >/dev/null 2>&1 # 컨텍스트/네임스페이스 전환 도구
ln -s /opt/kubectx/kubens /usr/local/bin/kubens
ln -s /opt/kubectx/kubectx /usr/local/bin/kubectx
echo "[TASK 6] Install Kubeps & Setting PS1"
git clone https://github.com/jonmosco/kube-ps1.git /root/kube-ps1 >/dev/null 2>&1
cat <<"EOT" >> /root/.bash_profile
source /root/kube-ps1/kube-ps1.sh
KUBE_PS1_SYMBOL_ENABLE=true
function get_cluster_short() {
echo "$1" | cut -d . -f1
}
KUBE_PS1_CLUSTER_FUNCTION=get_cluster_short
KUBE_PS1_SUFFIX=') '
PS1='$(kube_ps1)'$PS1 # 프롬프트에 현재 K8s 컨텍스트 표시
EOT
kubectl config rename-context "kubernetes-admin@kubernetes" "HomeLab" >/dev/null 2>&1
echo "[TASK 7] Install Cilium CNI"
NODEIP=$(ip -4 addr show eth1 | grep -oP '(?<=inet\s)\d+(\.\d+){3}')
helm repo add cilium https://helm.cilium.io/ >/dev/null 2>&1
helm repo update >/dev/null 2>&1
helm install cilium cilium/cilium --version $2 --namespace kube-system \
--set k8sServiceHost=192.168.10.100 --set k8sServicePort=6443 \ # API 서버 접속 정보
--set ipam.mode="cluster-pool" --set ipam.operator.clusterPoolIPv4PodCIDRList={"172.20.0.0/16"} --set ipv4NativeRoutingCIDR=172.20.0.0/16 \ # IPAM 설정
--set routingMode=native --set autoDirectNodeRoutes=true --set endpointRoutes.enabled=true \ # 네이티브 라우팅 모드 (성능 최적화)
--set kubeProxyReplacement=true --set bpf.masquerade=true --set installNoConntrackIptablesRules=true \ # kube-proxy 완전 대체
**--set endpointHealthChecking.enabled=false --set healthChecking=false \** # 엔드포인트 헬스체크 비활성화 (실습용)
**--set hubble.enabled=false** --set operator.replicas=1 --set debug.enabled=true >/dev/null 2>&1 # Hubble 비활성화 (이번 주차에서는 제외)
echo "[TASK 8] Install Cilium CLI"
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
CLI_ARCH=amd64
if [ "$(uname -m)" = "aarch64" ]; then CLI_ARCH=arm64; fi # ARM64 아키텍처 감지
curl -L --fail --remote-name-all https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-${CLI_ARCH}.tar.gz >/dev/null 2>&1
tar xzvfC cilium-linux-${CLI_ARCH}.tar.gz /usr/local/bin
rm cilium-linux-${CLI_ARCH}.tar.gz
echo "[TASK 9] local DNS with hosts file"
echo "192.168.10.100 k8s-ctr" >> /etc/hosts # 로컬 DNS 설정
for (( i=1; i<=$1; i++ )); do echo "192.168.10.10$i k8s-w$i" >> /etc/hosts; done
echo ">>>> K8S Controlplane Config End <<<<"
--set endpointHealthChecking.enabled=falseand --set healthChecking=falsedisable endpoint health checking는 false로 설정- k8s-w.sh : kubeadm join
- kubeadm-join-worker-config.yaml
apiVersion: kubeadm.k8s.io/v1beta4
kind: JoinConfiguration
discovery:
bootstrapToken:
token: "123456.1234567890123456" # 컨트롤 플레인과 동일한 토큰
apiServerEndpoint: "192.168.10.100:6443" # API 서버 엔드포인트
unsafeSkipCAVerification: true # CA 인증서 검증 건너뛰기 (실습 환경용)
nodeRegistration:
criSocket: "unix:///run/containerd/containerd.sock"
kubeletExtraArgs:
- name: node-ip
value: "NODE_IP_PLACEHOLDER" # 스크립트에서 실제 IP로 교체됨
#!/usr/bin/env bash
echo ">>>> K8S Node config Start <<<<"
echo "[TASK 1] K8S Controlplane Join"
curl --silent -o /root/kubeadm-join-worker-config.yaml https://raw.githubusercontent.com/gasida/vagrant-lab/refs/heads/main/cilium-study/2w/kubeadm-join-worker-config.yaml
NODEIP=$(ip -4 addr show eth1 | grep -oP '(?<=inet\s)\d+(\.\d+){3}') # eth1 인터페이스에서 IP 추출
sed -i "s/NODE_IP_PLACEHOLDER/${NODEIP}/g" /root/kubeadm-join-worker-config.yaml # 플레이스홀더를 실제 IP로 교체
kubeadm join --config="/root/kubeadm-join-worker-config.yaml" > /dev/null 2>&1 # 클러스터에 워커 노드로 조인
echo ">>>> K8S Node config End <<<<"
Vagrant 실행
실습 파일들을 다운로드하고 실행해보겠습니다.
# 실습 디렉토리 생성 및 이동
mkdir cilium-lab && cd cilium-lab
# Vagrantfile 다운로드
curl -O https://raw.githubusercontent.com/gasida/vagrant-lab/refs/heads/main/cilium-study/2w/Vagrantfile
# 가상머신 생성 및 실행
vagrant up
만약 기존 VM이 존재할 경우 발생하는 오류:
❯ vagrant up
A VirtualBox machine with the name 'k8s-ctr' already exists.
Please use another name or delete the machine with the existing
name, and try again.
해결 방법:
# 1. 기존 VirtualBox VM 확인
VBoxManage list vms
# 2. 기존 VM 삭제 (전체)
VBoxManage unregistervm k8s-ctr --delete
VBoxManage unregistervm k8s-w1 --delete
VBoxManage unregistervm k8s-w2 --delete
# 3. 또는 Vagrant로 정리 (만약 이전에 vagrant로 생성했다면)
vagrant destroy -f
# 4. 다시 실행
vagrant up
✅ 실행 결과(요약)
정상적으로 실행되면 다음과 같은 과정을 거칩니다:
# 1. 기존 VM 정리 (필요시)
❯ VBoxManage unregistervm k8s-ctr --delete
VBoxManage unregistervm k8s-w1 --delete
VBoxManage unregistervm k8s-w2 --delete
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
# 2. Vagrant 실행
❯ vagrant up
Bringing machine 'k8s-ctr' up with 'virtualbox' provider...
Bringing machine 'k8s-w1' up with 'virtualbox' provider...
Bringing machine 'k8s-w2' up with 'virtualbox' provider...
# 3. 컨트롤 플레인 노드 설정 (k8s-ctr)
==> k8s-ctr: Setting the name of the VM: k8s-ctr
==> k8s-ctr: Booting VM...
==> k8s-ctr: Running provisioner: shell...
k8s-ctr: >>>> Initial Config Start <<<<
k8s-ctr: [TASK 1] Setting Profile & Bashrc
k8s-ctr: [TASK 2] Disable AppArmor
k8s-ctr: [TASK 3] Disable and turn off SWAP
k8s-ctr: [TASK 4] Install Packages
k8s-ctr: [TASK 5] Install Kubernetes components (kubeadm, kubelet and kubectl)
k8s-ctr: [TASK 6] Install Packages & Helm
k8s-ctr: >>>> Initial Config End <<<<
k8s-ctr: >>>> K8S Controlplane config Start <<<<
k8s-ctr: [TASK 1] Initial Kubernetes
k8s-ctr: [TASK 2] Setting kube config file
k8s-ctr: [TASK 3] Source the completion
k8s-ctr: [TASK 4] Alias kubectl to k
k8s-ctr: [TASK 5] Install Kubectx & Kubens
k8s-ctr: [TASK 6] Install Kubeps & Setting PS1
k8s-ctr: [TASK 7] Install Cilium CNI
k8s-ctr: [TASK 8] Install Cilium CLI
k8s-ctr: [TASK 9] local DNS with hosts file
k8s-ctr: >>>> K8S Controlplane Config End <<<<
# 4. 워커 노드 1 설정 (k8s-w1)
==> k8s-w1: Setting the name of the VM: k8s-w1
==> k8s-w1: Booting VM...
k8s-w1: >>>> Initial Config Start <<<<
k8s-w1: [TASK 1] Setting Profile & Bashrc
k8s-w1: [TASK 2] Disable AppArmor
k8s-w1: [TASK 3] Disable and turn off SWAP
k8s-w1: [TASK 4] Install Packages
k8s-w1: [TASK 5] Install Kubernetes components (kubeadm, kubelet and kubectl)
k8s-w1: [TASK 6] Install Packages & Helm
k8s-w1: >>>> Initial Config End <<<<
k8s-w1: >>>> K8S Node config Start <<<<
k8s-w1: [TASK 1] K8S Controlplane Join
k8s-w1: >>>> K8S Node config End <<<<
# 5. 워커 노드 2 설정 (k8s-w2)
==> k8s-w2: Setting the name of the VM: k8s-w2
==> k8s-w2: Booting VM...
k8s-w2: >>>> K8S Node config Start <<<<
k8s-w2: [TASK 1] K8S Controlplane Join
k8s-w2: >>>> K8S Node config End <<<<
전체 설치 과정은 약 10-15분 정도 소요됩니다.
실습 환경 접속 및 확인
# 컨트롤 플레인 노드 접속
vagrant ssh k8s-ctr
# 클러스터 상태 확인
kubectl get nodes
정상 설치 시 출력 예시:
(HomeLab) root@k8s-ctr:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-ctr Ready control-plane 5m v1.33.2
k8s-w1 Ready <none> 3m v1.33.2
k8s-w2 Ready <none> 2m v1.33.2
# Cilium 상태 확인
cilium status
Cilium 정상 동작 출력 예시:
/¯¯\
/¯¯\__/¯¯\ Cilium: OK
\__/¯¯\__/ Operator: OK
/¯¯\__/¯¯\ Envoy DaemonSet: OK
\__/¯¯\__/ Hubble Relay: disabled
\__/ ClusterMesh: disabled
DaemonSet cilium Desired: 3, Ready: 3/3, Available: 3/3
DaemonSet cilium-envoy Desired: 3, Ready: 3/3, Available: 3/3
Deployment cilium-operator Desired: 1, Ready: 1/1, Available: 1/1
Containers: cilium Running: 3
cilium-envoy Running: 3
cilium-operator Running: 1
clustermesh-apiserver
hubble-relay
Cluster Pods: 2/2 managed by Cilium
Helm chart version: 1.17.6
Image versions cilium quay.io/cilium/cilium:v1.17.6@sha256:544de3d4fed7acba72758413812780a4972d47c39035f2a06d6145d8644a3353: 3
cilium-envoy quay.io/cilium/cilium-envoy:v1.33.4-1752151664-7c2edb0b44cf95f326d628b837fcdd845102ba68@sha256:318eff387835ca2717baab42a84f35a83a5f9e7d519253df87269f80b9ff0171: 3
cilium-operator quay.io/cilium/operator-generic:v1.17.6@sha256:91ac3bf7be7bed30e90218f219d4f3062a63377689ee7246062fa0cc3839d096: 1
[k8s-ctr] 접속 후 기본 정보 확인
# 호스트 파일 및 노드 연결 확인
cat /etc/hosts
sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@k8s-w1 hostname
sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@k8s-w2 hostname
# 네트워크 인터페이스 확인
ifconfig | grep -iEA1 'eth[0-9]:'
# 클러스터 정보 확인
kubectl cluster-info
kubectl cluster-info dump | grep -m 2 -E "cluster-cidr|service-cluster-ip-range"
# 노드 정보 : 상태, INTERNAL-IP 확인
kubectl get node -owide
# 노드별 kubeadm-flags.env 정보 확인
cat /var/lib/kubelet/kubeadm-flags.env
for i in w1 w2 ; do echo ">> node : k8s-$i <<"; sshpass -p 'vagrant' ssh vagrant@k8s-$i cat /var/lib/kubelet/kubeadm-flags.env ; echo; done
# 파드 정보 : 상태, 파드 IP 확인
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.podCIDR}{"\n"}{end}'
kubectl get ciliumnode -o json | grep podCIDRs -A2
kubectl get pod -A -owide
✅ 실행 결과 요약
1. 호스트 네트워크 설정
(⎈|HomeLab:N/A) root@k8s-ctr:~# cat /etc/hosts
127.0.0.1 localhost
...
127.0.2.1 k8s-ctr k8s-ctr
192.168.10.100 k8s-ctr
192.168.10.101 k8s-w1
192.168.10.102 k8s-w2
(⎈|HomeLab:N/A) root@k8s-ctr:~# sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@k8s-w1 hostname
Warning: Permanently added 'k8s-w1' (ED25519) to the list of known hosts.
k8s-w1
(⎈|HomeLab:N/A) root@k8s-ctr:~# sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@k8s-w2 hostname
Warning: Permanently added 'k8s-w2' (ED25519) to the list of known hosts.
k8s-w2
(⎈|HomeLab:N/A) root@k8s-ctr:~# ifconfig | grep -iEA1 'eth[0-9]:'
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.0.2.15 netmask 255.255.255.0 broadcast 10.0.2.255
--
eth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.10.100 netmask 255.255.255.0 broadcast 192.168.10.255
# /etc/hosts 확인 - 노드 간 DNS 해석 가능
192.168.10.100 k8s-ctr
192.168.10.101 k8s-w1
192.168.10.102 k8s-w2
# 네트워크 인터페이스
eth0: 10.0.2.15 (NAT)
eth1: 192.168.10.100 (Private Network)
2. 클러스터 기본 정보
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl cluster-info
Kubernetes control plane is running at https://192.168.10.100:6443
CoreDNS is running at https://192.168.10.100:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl cluster-info dump | grep -m 2 -E "cluster-cidr|service-cluster-ip-range"
"--service-cluster-ip-range=10.96.0.0/16",
"--cluster-cidr=10.244.0.0/16",
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl describe cm -n kube-system kubeadm-config
Name: kubeadm-config
Namespace: kube-system
Labels: <none>
Annotations: <none>
Data
====
ClusterConfiguration:
----
apiServer: {}
apiVersion: kubeadm.k8s.io/v1beta4
caCertificateValidityPeriod: 87600h0m0s
certificateValidityPeriod: 8760h0m0s
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns: {}
encryptionAlgorithm: RSA-2048
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: registry.k8s.io
kind: ClusterConfiguration
kubernetesVersion: v1.33.2
networking:
dnsDomain: cluster.local
podSubnet: 10.244.0.0/16
serviceSubnet: 10.96.0.0/16
proxy:
disabled: true
scheduler: {}
# API 서버 및 CoreDNS 정상 동작
Kubernetes control plane is running at https://192.168.10.100:6443
CoreDNS is running at https://192.168.10.100:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
# CIDR 설정 확인
--service-cluster-ip-range=10.96.0.0/16 # Service CIDR
--cluster-cidr=10.244.0.0/16 # Pod CIDR (kubeadm 기본값)
3. 노드 상태 확인
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl get node -owide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s-ctr Ready control-plane 6m48s v1.33.2 192.168.10.100 <none> Ubuntu 24.04.2 LTS 6.8.0-53-generic containerd://1.7.27
k8s-w1 Ready <none> 5m30s v1.33.2 192.168.10.101 <none> Ubuntu 24.04.2 LTS 6.8.0-53-generic containerd://1.7.27
k8s-w2 Ready <none> 4m8s v1.33.2 192.168.10.102 <none> Ubuntu 24.04.2 LTS 6.8.0-53-generic containerd://1.7.27
# 각 노드의 kubelet 설정 - node-ip 올바르게 설정됨
k8s-ctr: --node-ip=192.168.10.100
k8s-w1: --node-ip=192.168.10.101
k8s-w2: --node-ip=192.168.10.102
4. Pod CIDR 할당
(⎈|HomeLab:N/A) root@k8s-ctr:~# cat /var/lib/kubelet/kubeadm-flags.env
KUBELET_KUBEADM_ARGS="--container-runtime-endpoint=unix:///run/containerd/containerd.sock --node-ip=192.168.10.100 --pod-infra-container-image=registry.k8s.io/pause:3.10"
(⎈|HomeLab:N/A) root@k8s-ctr:~# for i in w1 w2 ; do echo ">> node : k8s-$i <<"; sshpass -p 'vagrant' ssh vagrant@k8s-$i cat /var/lib/kubelet/kubeadm-flags.env ; echo; done
>> node : k8s-w1 <<
KUBELET_KUBEADM_ARGS="--container-runtime-endpoint=unix:///run/containerd/containerd.sock --node-ip=192.168.10.101 --pod-infra-container-image=registry.k8s.io/pause:3.10"
>> node : k8s-w2 <<
KUBELET_KUBEADM_ARGS="--container-runtime-endpoint=unix:///run/containerd/containerd.sock --node-ip=192.168.10.102 --pod-infra-container-image=registry.k8s.io/pause:3.10"
# kubeadm 기본 Pod CIDR (사용되지 않음)
k8s-ctr: 10.244.0.0/24
k8s-w1: 10.244.1.0/24
k8s-w2: 10.244.2.0/24
# Cilium IPAM Pod CIDR (실제 사용)
k8s-ctr: 172.20.0.0/24
k8s-w1: 172.20.1.0/24
k8s-w2: 172.20.2.0/24
5. 실행 중인 Pod 현황
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl get pod -A -owide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-system cilium-envoy-m7njw 1/1 Running 0 7m1s 192.168.10.100 k8s-ctr <none> <none>
kube-system cilium-envoy-p42gk 1/1 Running 0 4m27s 192.168.10.102 k8s-w2 <none> <none>
kube-system cilium-envoy-pxr2q 1/1 Running 0 5m49s 192.168.10.101 k8s-w1 <none> <none>
kube-system cilium-kkt6t 1/1 Running 0 4m27s 192.168.10.102 k8s-w2 <none> <none>
kube-system cilium-mm7xq 1/1 Running 0 5m49s 192.168.10.101 k8s-w1 <none> <none>
kube-system cilium-operator-5bc66f5b9b-7v5fg 1/1 Running 0 7m 192.168.10.100 k8s-ctr <none> <none>
kube-system cilium-tstkf 1/1 Running 0 7m1s 192.168.10.100 k8s-ctr <none> <none>
kube-system coredns-674b8bbfcf-2sbw2 1/1 Running 0 7m 172.20.0.51 k8s-ctr <none> <none>
kube-system coredns-674b8bbfcf-p8kth 1/1 Running 0 7m 172.20.0.107 k8s-ctr <none> <none>
kube-system etcd-k8s-ctr 1/1 Running 0 7m7s 192.168.10.100 k8s-ctr <none> <none>
kube-system kube-apiserver-k8s-ctr 1/1 Running 0 7m7s 192.168.10.100 k8s-ctr <none> <none>
kube-system kube-controller-manager-k8s-ctr 1/1 Running 0 7m7s 192.168.10.100 k8s-ctr <none> <none>
kube-system kube-scheduler-k8s-ctr 1/1 Running 0 7m7s 192.168.10.100 k8s-ctr <none> <none>
# Cilium 컴포넌트 (각 노드별 DaemonSet)
cilium-envoy-* : 3개 (각 노드 1개씩)
cilium-* : 3개 (각 노드 1개씩)
cilium-operator : 1개 (컨트롤 플레인)
# Kubernetes 시스템 Pod
coredns-* : 2개 (IP: 172.20.0.51, 172.20.0.107)
etcd, api-server, controller-manager, scheduler: 각 1개
6. iptables 규칙
(⎈|HomeLab:N/A) root@k8s-ctr:~# iptables -t nat -S
...
-N CILIUM_OUTPUT_nat
-N CILIUM_POST_nat
-N CILIUM_PRE_nat
...
-A PREROUTING -m comment --comment "cilium-feeder: CILIUM_PRE_nat" -j CILIUM_PRE_nat
-A OUTPUT -m comment --comment "cilium-feeder: CILIUM_OUTPUT_nat" -j CILIUM_OUTPUT_nat
-A POSTROUTING -m comment --comment "cilium-feeder: CILIUM_POST_nat" -j CILIUM_POST_nat
(⎈|HomeLab:N/A) root@k8s-ctr:~# iptables -t filter -S
...
-N CILIUM_FORWARD
-N CILIUM_INPUT
-N CILIUM_OUTPUT
...
-A CILIUM_FORWARD -o cilium_host -m comment --comment "cilium: any->cluster on cilium_host forward accept" -j ACCEPT
-A CILIUM_FORWARD -i cilium_host -m comment --comment "cilium: cluster->any on cilium_host forward accept (nodeport)" -j ACCEPT
-A CILIUM_FORWARD -i lxc+ -m comment --comment "cilium: cluster->any on lxc+ forward accept" -j ACCEPT
-A CILIUM_FORWARD -i cilium_net -m comment --comment "cilium: cluster->any on cilium_net forward accept (nodeport)" -j ACCEPT
-A CILIUM_FORWARD -o lxc+ -m comment --comment "cilium: any->cluster on lxc+ forward accept" -j ACCEPT
-A CILIUM_FORWARD -i lxc+ -m comment --comment "cilium: cluster->any on lxc+ forward accept (nodeport)" -j ACCEPT
-A CILIUM_INPUT -m mark --mark 0x200/0xf00 -m comment --comment "cilium: ACCEPT for proxy traffic" -j ACCEPT
-A CILIUM_OUTPUT -m mark --mark 0xa00/0xe00 -m comment --comment "cilium: ACCEPT for proxy traffic" -j ACCEPT
-A CILIUM_OUTPUT -m mark --mark 0x800/0xe00 -m comment --comment "cilium: ACCEPT for l7 proxy upstream traffic" -j ACCEPT
-A CILIUM_OUTPUT -m mark ! --mark 0xe00/0xf00 -m mark ! --mark 0xd00/0xf00 -m mark ! --mark 0x400/0xf00 -m mark ! --mark 0xa00/0xe00 -m mark ! --mark 0x800/0xe00 -m mark ! --mark 0xf00/0xf00 -m comment --comment "cilium: host->any mark as from host" -j MARK --set-xmark 0xc00/0xf00
-A KUBE-FIREWALL ! -s 127.0.0.0/8 -d 127.0.0.0/8 -m comment --comment "block incoming localnet connections" -m conntrack ! --ctstate RELATED,ESTABLISHED,DNAT -j DROP
(⎈|HomeLab:N/A) root@k8s-ctr:~# iptables -t mangle -S
-N CILIUM_POST_mangle
-N CILIUM_PRE_mangle
...
-A PREROUTING -m comment --comment "cilium-feeder: CILIUM_PRE_mangle" -j CILIUM_PRE_mangle
-A POSTROUTING -m comment --comment "cilium-feeder: CILIUM_POST_mangle" -j CILIUM_POST_mangle
-A CILIUM_PRE_mangle ! -o lo -m socket --transparent -m mark ! --mark 0xe00/0xf00 -m mark ! --mark 0x800/0xf00 -m comment --comment "cilium: any->pod redirect proxied traffic to host proxy" -j MARK --set-xmark 0x200/0xffffffff
-A CILIUM_PRE_mangle -p tcp -m mark --mark 0x89a10200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 41353 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff
-A CILIUM_PRE_mangle -p udp -m mark --mark 0x89a10200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 41353 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff
# Cilium에 의해 생성된 iptables 체인들
CILIUM_FORWARD, CILIUM_INPUT, CILIUM_OUTPUT (filter 테이블)
CILIUM_PRE_nat, CILIUM_POST_nat (nat 테이블)
CILIUM_PRE_mangle, CILIUM_POST_mangle (mangle 테이블)
# 특징: kube-proxy 관련 규칙 없음 (Cilium이 완전 대체)
[k8s-ctr] cilium 설치 정보 확인
# cilium CLI 및 기본 상태 확인
which cilium # cilium CLI 설치 경로 확인
cilium status # Cilium 전체 상태 요약 (데몬셋, 배포, 컨테이너 상태)
cilium config view # Cilium 설정 옵션 확인 (IPAM, 라우팅 모드 등)
kubectl get cm -n kube-system cilium-config -o json | jq # Cilium ConfigMap 상세 설정 JSON 형태로 출력
# Cilium 에이전트 내부 정보 확인
kubectl exec -n kube-system -c cilium-agent -it ds/cilium -- cilium-dbg config # 실행 중인 Cilium 에이전트 설정 확인
kubectl exec -n kube-system -c cilium-agent -it ds/cilium -- cilium-dbg status --verbose # 에이전트 상태 상세 정보 (BPF 맵, 정책 등)
kubectl exec -n kube-system -c cilium-agent -it ds/cilium -- cilium-dbg metrics list # 사용 가능한 메트릭 목록 확인
# Cilium 엔드포인트 확인
kubectl get ciliumendpoints -A # 모든 네임스페이스의 Cilium 엔드포인트 목록 (Pod IP, ID 등)
# 실시간 네트워크 모니터링
kubectl exec -n kube-system -c cilium-agent -it ds/cilium -- cilium-dbg monitor # 기본 네트워크 이벤트 모니터링
kubectl exec -n kube-system -c cilium-agent -it ds/cilium -- cilium-dbg monitor -v # 상세 모니터링 (패킷 헤더 정보 포함)
kubectl exec -n kube-system -c cilium-agent -it ds/cilium -- cilium-dbg monitor -v -v # 매우 상세한 모니터링 (패킷 페이로드까지)
# 특정 조건 필터링 모니터링
kubectl exec -n kube-system -c cilium-agent -it ds/cilium -- cilium-dbg monitor --related-to=<id> # 특정 엔드포인트 ID 관련 이벤트만 필터링
kubectl exec -n kube-system -c cilium-agent -it ds/cilium -- cilium-dbg monitor --type drop # 드롭된 패킷 이벤트만 표시 (보안 정책 위반 등)
kubectl exec -n kube-system -c cilium-agent -it ds/cilium -- cilium-dbg monitor -v -v --hex # 패킷 페이로드를 16진수로 표시 (패킷 분석용)
# Layer 7 프록시 모니터링
kubectl exec -n kube-system -c cilium-agent -it ds/cilium -- cilium-dbg monitor -v --type l7 # HTTP/gRPC 등 L7 프로토콜 이벤트 모니터링
✅ 실행 결과 요약
1. Cilium CLI 및 기본 상태
(⎈|HomeLab:N/A) root@k8s-ctr:~# which cilium
/usr/local/bin/cilium
(⎈|HomeLab:N/A) root@k8s-ctr:~# cilium status
/¯¯\
/¯¯\__/¯¯\ Cilium: OK
\__/¯¯\__/ Operator: OK
/¯¯\__/¯¯\ Envoy DaemonSet: OK # Envoy 프록시 정상 동작
\__/¯¯\__/ Hubble Relay: disabled # Hubble 비활성화 상태
\__/ ClusterMesh: disabled
DaemonSet cilium Desired: 3, Ready: 3/3, Available: 3/3
DaemonSet cilium-envoy Desired: 3, Ready: 3/3, Available: 3/3
Deployment cilium-operator Desired: 1, Ready: 1/1, Available: 1/1
Containers: cilium Running: 3
cilium-envoy Running: 3
cilium-operator Running: 1
Cluster Pods: 2/2 managed by Cilium # CoreDNS 2개 Pod만 관리됨
Helm chart version: 1.17.6
2. Cilium 설정 확인 (주요 옵션)
(⎈|HomeLab:N/A) root@k8s-ctr:~# cilium config view
agent-not-ready-taint-key node.cilium.io/agent-not-ready
...
# 핵심 설정값들
cluster-pool-ipv4-cidr 172.20.0.0/16 # Pod CIDR 범위
ipv4-native-routing-cidr 172.20.0.0/16 # 네이티브 라우팅 범위
routing-mode native # 네이티브 라우팅 모드
kube-proxy-replacement true # kube-proxy 완전 대체
enable-bpf-masquerade true # eBPF 마스커레이딩
enable-hubble false # Hubble 비활성화
enable-endpoint-health-checking false # 엔드포인트 헬스체크 비활성화
enable-l7-proxy true # L7 프록시 활성화
external-envoy-proxy true # 외부 Envoy 프록시 사용
3. Cilium 에이전트 상세 상태
kubectl exec -n kube-system -c cilium-agent -it ds/cilium -- cilium-dbg config
##### Read-write configurations #####
ConntrackAccounting : Disabled
ConntrackLocal : Disabled
...
# 네트워크 및 IPAM 정보
KubeProxyReplacement: True [eth0 10.0.2.15, eth1 192.168.10.100 (Direct Routing)]
IPAM: IPv4: 3/254 allocated from 172.20.0.0/24
Allocated addresses:
172.20.0.106 (router) # Cilium 라우터 IP
172.20.0.107 (coredns Pod)
172.20.0.51 (coredns Pod)
# BPF 맵 상태 (주요 항목들)
Auth 524288 # 인증 관련
TCP connection tracking 131072 # TCP 연결 추적
IP cache 512000 # IP 캐시
IPv4 service 65536 # 서비스 정보
NAT 131072 # NAT 정보
4. Cilium 엔드포인트
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl get ciliumendpoints -A
NAMESPACE NAME SECURITY IDENTITY ENDPOINT STATE IPV4
kube-system coredns-674b8bbfcf-2sbw2 5694 ready 172.20.0.51
kube-system coredns-674b8bbfcf-p8kth 5694 ready 172.20.0.107
# 두 개의 CoreDNS Pod만 Cilium 엔드포인트로 관리됨
# Security Identity 5694: CoreDNS 공통 보안 ID
5. 실시간 네트워크 모니터링
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl exec -n kube-system -c cilium-agent -it ds/cilium -- cilium-dbg monitor
Press Ctrl-C to quit
time="2025-07-25T15:46:00.5993656Z" level=info msg="Initializing dissection cache..." subsys=monitor
-> endpoint 1174 flow 0xfee0e3b8 , identity host->5694 state new ifindex lxcea4f8900288d orig-ip 10.0.2.15: 10.0.2.15:58808 -> 172.20.0.107:8181 tcp SYN
...
# 기본 모니터링 - TCP 연결 흐름 확인
-> endpoint 1174 flow 0xfee0e3b8 , identity host->5694 state new ifindex lxcea4f8900288d orig-ip 10.0.2.15: 10.0.2.15:58808 -> 172.20.0.107:8181 tcp SYN
-> stack flow 0xc6d97fd2 , identity 5694->host state reply ifindex 0 orig-ip 0.0.0.0: 172.20.0.107:8181 -> 10.0.2.15:58808 tcp SYN, ACK
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl exec -n kube-system -c cilium-agent -it ds/cilium -- cilium-dbg monitor --related-to=1174
Press Ctrl-C to quit
time="2025-07-25T15:46:37.649017061Z" level=info msg="Initializing dissection cache..." subsys=monitor
...
# 특정 엔드포인트(1174) 필터링
-> endpoint 1174 flow 0x689edad4 , identity host->5694 state new ifindex lxcea4f8900288d orig-ip 10.0.2.15: 10.0.2.15:53166 -> 172.20.0.107:8080 tcp SYN
# 패킷 드롭 모니터링 - 현재 드롭 이벤트 없음 (정상)
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl exec -n kube-system -c cilium-agent -it ds/cilium -- cilium-dbg monitor -v -v --hex
Listening for events on 2 CPUs with 64x4096 of shared memory
Press Ctrl-C to quit
------------------------------------------------------------------------------
00000000 26 70 69 2b 3c 45 b6 16 31 6c 65 97 08 00 45 00 |&pi+<E..1le...E.|
00000010 00 3c 6e dc 40 00 40 06 13 8a 0a 00 02 0f ac 14 |.<n.@.@.........|
00000020 00 33 89 1e 1f 90 07 d8 06 f1 00 00 00 00 a0 02 |.3..............|
00000030 fa f0 b8 84 00 00 02 04 05 b4 04 02 08 0a c6 e7 |................|
00000040 be d7 00 00 00 00 01 03 03 07 00 00 |............|
CPU 01: MARK 0xc7086d59 FROM 2609 to-endpoint: 74 bytes (74 captured), state new, interface lxc903c835e21af, , identity host->5694, orig-ip 10.0.2.15, to endpoint 2609
...
# 16진수 패킷 분석 - HTTP 트래픽 확인
47 45 54 20 2f 68 65 61 6c 74 68 20 48 54 54 50 # "GET /health HTTP"
48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b # "HTTP/1.1 200 OK"
6. Layer 7 프록시 모니터링
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl exec -n kube-system -c cilium-agent -it ds/cilium -- cilium-dbg monitor -v --type l7
Press Ctrl-C to quit
CPU 00: [pre-xlate-rev] cgroup_id: 7184 sock_cookie: 16174, dst [127.0.0.1]:34040 tcp
CPU 00: [pre-xlate-rev] cgroup_id: 7184 sock_cookie: 16174, dst [127.0.0.1]:34040 tcp
..
# Socket-level 연결 추적 정보
CPU 01: [pre-xlate-rev] cgroup_id: 9357 sock_cookie: 12137, dst [127.0.0.1]:8080 tcp # CoreDNS 헬스체크
CPU 01: [pre-xlate-rev] cgroup_id: 7463 sock_cookie: 12135, dst [192.168.10.100]:6443 tcp # API 서버 통신
# cgroup_id로 각 컨테이너별 네트워크 활동 추적 가능
# sock_cookie로 개별 소켓 연결 식별
주요 확인 포인트는 다음과 같습니다.
- Cilium 상태: 모든 컴포넌트 정상 동작 (OK 상태)
- 네트워킹: 네이티브 라우팅 + eBPF 마스커레이딩으로 최적화
- kube-proxy 대체: 완전히 대체되어 iptables 규칙 최소화
- 엔드포인트 관리: CoreDNS Pod들이 Cilium으로 관리됨
- 모니터링: 실시간 패킷 흐름, TCP 상태, HTTP 트래픽 모두 추적 가능
- L7 프록시: Envoy를 통한 Layer 7 트래픽 처리 활성화
Hubble을 이용한 네트워크 가시성 확보
Hubble이란?
Hubble은 Cilium과 eBPF를 기반으로 구축된 완전히 분산된 네트워킹 및 보안 관측 플랫폼입니다. 서비스 간 통신과 네트워킹 인프라에 대한 깊은 가시성을 완전히 투명하게 제공합니다.
출처 - https://docs.cilium.io/en/stable/observability/hubble/
핵심 특징:
- eBPF 기반: 프로그래밍 가능한 가시성으로 오버헤드 최소화
- 동적 접근: 필요한 깊이의 세밀한 가시성 제공
- 다중 클러스터 지원: 노드/클러스터/클러스터 간 가시성
Hubble 아키텍처
1. 기본 모드 (로컬 노드 범위)
# 개별 노드의 Cilium 에이전트 범위 내에서 동작
# 로컬 유닉스 도메인 소켓을 통한 Hubble API 접근
kubectl exec -n kube-system -c cilium-agent -it ds/cilium -- hubble observe
2. 클러스터 모드 (Hubble Relay)
# 전체 클러스터 또는 여러 클러스터에 대한 네트워크 가시성
# Hubble Relay 서비스를 통한 중앙집중식 접근
# Hubble UI를 통한 웹 인터페이스 제공
주요 관측 기능
🔗 서비스 종속성 & 통신 맵
- 서비스 간 통신 빈도 및 패턴 분석
- 서비스 종속성 그래프 자동 생성
- HTTP 호출, Kafka 토픽 소비/생산 추적
- L3/L4/L7 레벨 서비스 맵 시각화
📊 네트워크 모니터링 & 알람
- 네트워크 통신 실패 원인 분석 (DNS/애플리케이션/네트워크)
- TCP/HTTP 레벨 문제 진단
- DNS 해석 문제, TCP 연결 중단, 연결 타임아웃 추적
- 응답하지 않는 TCP SYN 요청 비율 모니터링
📈 애플리케이션 모니터링
- HTTP 4xx/5xx 응답 코드 비율 분석
- 95th/99th 백분위수 레이턴시 측정
- 서비스 간 응답 시간 분석
- 성능 저하 서비스 식별
🔒 보안 관측성
- 네트워크 정책에 의해 차단된 연결 추적
- 클러스터 외부 접근 서비스 모니터링
- 특정 DNS 이름 해석 서비스 추적
- 보안 정책 위반 및 위협 탐지
즉 Hubble을 통해 마이크로서비스 환경에서의 네트워크 가시성, 보안 모니터링, 성능 분석을 한 번에 해결할 수 있습니다.
Hubble 실습
설치 전 확인
# Cilium 전체 상태 확인 (Hubble 관련 컴포넌트 상태 포함)
cilium status
# Cilium 설정에서 Hubble 관련 옵션 확인 (현재 비활성화 상태 확인)
cilium config view | grep -i hubble
# Cilium ConfigMap에서 Hubble 설정 상세 확인 (JSON 형태로 모든 설정 출력)
kubectl get cm -n kube-system cilium-config -o json | jq
# Hubble 관련 시크릿 존재 여부 확인 (CA 인증서, TLS 인증서 등)
kubectl get secret -n kube-system | grep -iE 'cilium-ca|hubble'
# 현재 수신 대기 중인 포트 확인 (Hubble 활성화 전 상태 저장)
# Cilium/Hubble 관련 포트를 필터링하여 before.txt 파일에 저장
ss -tnlp | grep -iE 'cilium|hubble' | tee before.txt
설치 전 확인 결과 요약
1. Cilium 상태 확인
(⎈|HomeLab:N/A) root@k8s-ctr:~# cilium status
/¯¯\
/¯¯\__/¯¯\ Cilium: OK
\__/¯¯\__/ Operator: OK
/¯¯\__/¯¯\ Envoy DaemonSet: OK
\__/¯¯\__/ Hubble Relay: disabled # Hubble Relay 비활성화 상태
\__/ ClusterMesh: disabled
# Hubble 관련 컨테이너가 없음 (현재 비활성화)
clustermesh-apiserver
hubble-relay # 공백 - 실행 중이지 않음
2. Hubble 설정 확인
# Cilium 설정에서 Hubble 비활성화 확인
(⎈|HomeLab:N/A) root@k8s-ctr:~# cilium config view | grep -i hubble
enable-hubble false
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl get cm -n kube-system cilium-config -o json | jq
{
"apiVersion": "v1",
"data": {
...
# ConfigMap에서도 동일하게 비활성화 상태
"enable-hubble": "false"
3. Hubble 관련 시크릿
# Hubble/CA 관련 시크릿이 존재하지 않음 (정상 - 아직 설치 전)
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl get secret -n kube-system | grep -iE 'cilium-ca|hubble'
# 출력 없음 - Hubble 인증서 미생성 상태
4. 현재 Cilium 관련 수신 포트
# Hubble 관련 포트는 없고, 기본 Cilium 포트만 활성화
127.0.0.1:9891 # cilium-operator (메트릭)
127.0.0.1:9890 # cilium-agent (API)
127.0.0.1:9879 # cilium-agent (내부 통신)
127.0.0.1:9878 # cilium-envoy (프록시)
0.0.0.0:9964 # cilium-envoy (외부 메트릭)
127.0.0.1:41353 # cilium-agent (DNS 프록시)
127.0.0.1:9234 # cilium-operator (API)
*:9963 # cilium-operator (Prometheus 메트릭)
# 주목: Hubble 기본 포트(4244, 4245) 없음
현재 상태 요약:
- ✅ Cilium 정상 동작: 모든 핵심 컴포넌트 OK 상태
- ❌ Hubble 비활성화:
enable-hubble: false설정 - ❌ Hubble Relay 없음: 클러스터 전체 관측 불가
- ❌ Hubble 인증서 없음: 보안 설정 미완료
- ❌ Hubble 포트 없음: 4244(gRPC), 4245(HTTP) 포트 비활성화
다음 단계에서 Hubble을 활성화하여 네트워크 관측성을 확보해보겠습니다.
Hubble 설치 및 변화 확인
# 설치방안 1 : Helm을 이용한 상세 설정으로 Hubble 활성화
# 기본적으로 enabled, relay.enabled, ui.enabled 만 해도 설정 가능
helm upgrade cilium cilium/cilium --namespace kube-system --reuse-values \
**--set hubble.enabled=true \ # Hubble 기본 기능 활성화
--set hubble.relay.enabled=true \ # Hubble Relay 활성화 (클러스터 전체 관측)
--set hubble.ui.enabled=true \** # Hubble UI 웹 인터페이스 활성화
--set hubble.ui.service.type=NodePort \ # UI 서비스를 NodePort로 외부 노출(편의성)
--set hubble.ui.service.nodePort=31234 \ # NodePort 번호 31234로 고정(편의성)
--set hubble.export.static.enabled=true \ # 정적 로그 내보내기 활성화
--set hubble.export.static.filePath=/var/run/cilium/hubble/events.log \ # 로그 파일 경로 지정
--set prometheus.enabled=true \ # Prometheus 메트릭 활성화
--set operator.prometheus.enabled=true \ # Cilium Operator 메트릭 활성화
--set hubble.metrics.enableOpenMetrics=true \ # OpenMetrics 형식 메트릭 활성화
--set hubble.metrics.enabled="{dns,drop,tcp,flow,port-distribution,icmp,httpV2:exemplars=true;labelsContext=source_ip\,source_namespace\,source_workload\,destination_ip\,destination_namespace\,destination_workload\,traffic_direction}" # 상세 메트릭 수집 설정
# 설치방안 2 : Cilium CLI를 이용한 간단 설정
cilium hubble enable # Hubble 기본 활성화
cilium hubble enable --ui # Hubble UI까지 포함하여 활성화
# Hubble Relay 정상 동작 확인 (중요: Relay가 OK 상태여야 클러스터 전체 관측 가능)
cilium status
# Hubble 관련 설정 변경 확인
cilium config view | grep -i hubble # CLI에서 Hubble 설정 확인 (enable-hubble: true로 변경됨)
kubectl get cm -n kube-system cilium-config -o json | grep -i hubble # ConfigMap에서 Hubble 설정 확인
# Hubble 관련 인증서 및 시크릿 생성 확인
kubectl get secret -n kube-system | grep -iE 'cilium-ca|hubble' # CA 인증서, Hubble TLS 인증서 생성 확인
# 네트워크 포트 변화 확인 (Hubble 활성화 전후 비교)
# Hubble 활성화 후 TCP 포트 4244가 모든 노드에서 열려야 함
ss -tnlp | grep -iE 'cilium|hubble' | tee after.txt # 활성화 후 포트 상태를 after.txt에 저장
vi -d before.txt after.txt # diff 뷰어로 설치 전후 포트 변화 비교
for i in w1 w2 ; do echo ">> node : k8s-$i <<"; sshpass -p 'vagrant' ssh vagrant@k8s-$i **sudo ss -tnlp |grep 4244** ; echo; done # 모든 워커 노드에서 4244 포트 개방 확인
# Hubble Relay Pod 상태 확인
kubectl get pod -n kube-system -l k8s-app=hubble-relay # Hubble Relay Pod 목록 조회
kc describe pod -n kube-system -l k8s-app=hubble-relay # Relay Pod 상세 정보 (컨테이너 상태, 이벤트 등)
# Hubble Relay 서비스 및 엔드포인트 확인
kc get svc,ep -n kube-system hubble-relay # Relay 서비스 및 엔드포인트 정보
# Hubble Relay 설정 정보 확인 (어떻게 각 노드의 Hubble과 통신하는지)
# hubble-relay 는 hubble-peer 의 서비스(ClusterIP :443)을 통해 모든 노드의 :4244에 요청 가져올 수 있음**
kubectl get cm -n kube-system # 전체 ConfigMap 목록 확인
kubectl describe cm -n kube-system hubble-relay-config # Relay 설정 상세 정보
# Hubble Peer 서비스 확인 (각 노드의 Hubble Agent 집계 서비스)
# (실리움 파드 안에 허블 프로세스가 띄워짐. 각노드의 hubble API 접근 포트: 4244 포트 사용)
kubectl get svc,ep -n kube-system hubble-peer # Peer 서비스 및 모든 노드 엔드포인트 확인
# Hubble UI Pod 상태 확인
kc describe pod -n kube-system -l k8s-app=hubble-ui** # UI Pod 상세 정보 (frontend, backend 컨테이너)
# Hubble UI Nginx 설정 확인
kc describe cm -n kube-system hubble-ui-nginx** # UI 웹서버 설정 정보
...
# Hubble UI 서비스 접속 정보 확인
kubectl get svc,ep -n kube-system hubble-ui # UI 서비스 NodePort 및 엔드포인트 확인
# Hubble UI 웹 접속 주소 자동 생성 및 출력
NODEIP=$(ip -4 addr show eth1 | grep -oP '(?<=inet\s)\d+(\.\d+){3}') # 현재 노드의 Private IP 추출
echo -e "http://$NODEIP:31234" # 웹 브라우저 접속 URL 출력 (예: http://192.168.10.100:31234)
✅ 실행 결과 요약
1. Helm 업그레이드 성공
(⎈|HomeLab:N/A) root@k8s-ctr:~# helm upgrade cilium cilium/cilium --namespace kube-system --reuse-values \
--set hubble.enabled=true \
--set hubble.relay.enabled=true \
--set hubble.ui.enabled=true \
...
Release "cilium" has been upgraded. Happy Helming!
NAME: cilium
LAST DEPLOYED: Sat Jul 26 01:59:21 2025
NAMESPACE: kube-system
STATUS: deployed
REVISION: 2 # 첫 설치에서 2번째 리비전으로 업그레이드됨
2. Cilium 상태 변화 (일시적 오류 후 정상화)
(⎈|HomeLab:N/A) root@k8s-ctr:~# cilium status
/¯¯\
/¯¯\__/¯¯\ Cilium: OK
\__/¯¯\__/ Operator: OK
/¯¯\__/¯¯\ Envoy DaemonSet: OK
\__/¯¯\__/ Hubble Relay: OK
\__/ ClusterMesh: disabled
DaemonSet cilium Desired: 3, Ready: 3/3, Available: 3/3
DaemonSet cilium-envoy Desired: 3, Ready: 3/3, Available: 3/3
Deployment cilium-operator Desired: 1, Ready: 1/1, Available: 1/1
Deployment hubble-relay Desired: 1, Ready: 1/1, Available: 1/1
Deployment hubble-ui Desired: 1, Ready: 1/1, Available: 1/1
Containers: cilium Running: 3
cilium-envoy Running: 3
cilium-operator Running: 1
clustermesh-apiserver
hubble-relay Running: 1
hubble-ui Running: 1
Cluster Pods: 4/4 managed by Cilium
Helm chart version: 1.17.6
Image versions cilium quay.io/cilium/cilium:v1.17.6@sha256:544de3d4fed7acba72758413812780a4972d47c39035f2a06d6145d8644a3353: 3
cilium-envoy quay.io/cilium/cilium-envoy:v1.33.4-1752151664-7c2edb0b44cf95f326d628b837fcdd845102ba68@sha256:318eff387835ca2717baab42a84f35a83a5f9e7d519253df87269f80b9ff0171: 3
cilium-operator quay.io/cilium/operator-generic:v1.17.6@sha256:91ac3bf7be7bed30e90218f219d4f3062a63377689ee7246062fa0cc3839d096: 1
hubble-relay quay.io/cilium/hubble-relay:v1.17.6@sha256:7d17ec10b3d37341c18ca56165b2f29a715cb8ee81311fd07088d8bf68c01e60: 1
hubble-ui quay.io/cilium/hubble-ui-backend:v0.13.2@sha256:a034b7e98e6ea796ed26df8f4e71f83fc16465a19d166eff67a03b822c0bfa15: 1
hubble-ui quay.io/cilium/hubble-ui:v0.13.2@sha256:9e37c1296b802830834cc87342a9182ccbb71ffebb711971e849221bd9d59392: 1
3. Hubble 설정 활성화 확인
# 설정 변경 완료 (false → true)
(⎈|HomeLab:N/A) root@k8s-ctr:~# cilium config view | grep -i hubble
enable-hubble true ✅
enable-hubble-open-metrics true # 메트릭 활성화
hubble-listen-address :4244 # 각 노드에서 수신 대기
hubble-metrics-server :9965 # 메트릭 서버 포트
hubble-export-file-path /var/run/cilium/hubble/events.log # 로그 파일
# ConfigMap에서도 동일하게 활성화 확인
"enable-hubble": "true"
4. 보안 인증서 자동 생성
# Hubble 관련 시크릿 3개 생성됨
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl get secret -n kube-system | grep -iE 'cilium-ca|hubble'
cilium-ca Opaque 2 27s # CA 루트 인증서
hubble-relay-client-certs kubernetes.io/tls 3 27s # Relay 클라이언트 인증서
hubble-server-certs kubernetes.io/tls 3 27s # Hubble 서버 인증서
5. 네트워크 포트 변화

# 새로 추가된 포트들
*:4244 *:* users:(("cilium-agent",pid=9298,fd=50)) # Hubble API 서버 (모든 노드)
*:9962 *:* users:(("cilium-agent",pid=9298,fd=7)) # Cilium 메트릭
*:9965 *:* users:(("cilium-agent",pid=9298,fd=42)) # Hubble 메트릭 서버
# 모든 워커 노드에서도 4244 포트 개방 확인
>> node : k8s-w1 <<
LISTEN 0 4096 *:4244 *:* users:(("cilium-agent",pid=7154,fd=55))
>> node : k8s-w2 <<
LISTEN 0 4096 *:4244 *:* users:(("cilium-agent",pid=6930,fd=42))
6. Hubble Relay 정상 동작
# Relay Pod 상태
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl get pod -n kube-system -l k8s-app=hubble-relay
NAME READY STATUS RESTARTS AGE
hubble-relay-5dcd46f5c-tln2s 1/1 Running 0 2m14s
# Relay 서비스 및 엔드포인트
service/hubble-relay ClusterIP 10.96.174.49 <none> 80/TCP 2m22s
endpoints/hubble-relay 172.20.2.176:4245 2m22s # k8s-w2 노드에 배포됨
7. Hubble Peer 서비스 (클러스터 전체 집계)
# 모든 노드의 Hubble Agent를 집계하는 서비스
service/hubble-peer ClusterIP 10.96.68.0 <none> 443/TCP 2m35s
endpoints/hubble-peer 192.168.10.100:4244,192.168.10.101:4244,192.168.10.102:4244
# Relay 설정: hubble-peer 서비스를 통해 모든 노드에 접근
peer-service: "hubble-peer.kube-system.svc.cluster.local.:443"
listen-address: :4245 # Relay가 4245 포트로 서비스 제공
8. Hubble UI 웹 인터페이스
# UI Pod 구성 (frontend + backend)
Containers:
frontend: # Nginx 기반 (포트 8081)
Image: quay.io/cilium/hubble-ui:v0.13.2
Port: 8081/TCP
backend: # Go 기반 API (포트 8090)
Image: quay.io/cilium/hubble-ui-backend:v0.13.2
Port: 8090/TCP
Environment:
FLOWS_API_ADDR: hubble-relay:80 # Relay를 통해 데이터 수집
# NodePort 서비스로 외부 접속 가능
service/hubble-ui NodePort 10.96.201.178 <none> 80:31234/TCP 2m48s
endpoints/hubble-ui 172.20.1.129:8081 2m48s # k8s-w1 노드에 배포됨
9. 웹 접속 정보
# 자동 생성된 접속 URL
(⎈|HomeLab:N/A) root@k8s-ctr:~# echo -e "http://$NODEIP:31234"
http://192.168.10.100:31234 # 브라우저에서 접속 가능한 주소
허블에 접속하면, 트래픽이 발생하기때문에 kube-system 네임스페이스에서 트래픽을 확인할 수 있습니다.

현재 Hubble 상태 요약:
- ✅ Hubble 활성화: 모든 노드에서 4244 포트로 동작
- ✅ Hubble Relay: 클러스터 전체 관측을 위한 중계 서비스 동작
- ✅ Hubble UI: 웹 인터페이스 정상 동작 (NodePort 31234)
- ✅ 보안 설정: TLS 인증서 자동 생성 및 적용
- ✅ 메트릭 수집: Prometheus 호환 메트릭 활성화
- ✅ 로그 내보내기: 정적 파일로 이벤트 로그 저장
아키텍처 흐름:
브라우저 (:31234) → Hubble UI (frontend:8081 + backend:8090)
↓
Hubble Relay (:4245)
↓
hubble-peer 서비스 (:443)
↓
모든 노드의 Cilium Agent (Hubble :4244)
Hubble Client 설치
# Linux 실습 환경에 설치 시
HUBBLE_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/hubble/master/stable.txt)
HUBBLE_ARCH=amd64
if [ "$(uname -m)" = "aarch64" ]; then HUBBLE_ARCH=arm64; fi
curl -L --fail --remote-name-all https://github.com/cilium/hubble/releases/download/$HUBBLE_VERSION/hubble-linux-${HUBBLE_ARCH}.tar.gz{,.sha256sum}
sudo tar xzvfC hubble-linux-${HUBBLE_ARCH}.tar.gz /usr/local/bin
which hubble
# Hubble API Access를 설정해야 접근가능!
cilium hubble port-forward&
cilium hubble port-forward&
Hubble Relay is available at 127.0.0.1:4245
ss -tnlp | grep 4245
# Now you can validate that you can access the Hubble API via the installed CLI
hubble status
Healthcheck (via localhost:4245): Ok
Current/Max Flows: 12,285/12,285 (100.00%)
Flows/s: 41.20
# hubble (api) server 기본 접속 주소 확인
hubble config view
...
port-forward-port: "4245"
server: localhost:4245
...
# (옵션) 현재 k8s-ctr 가상머신이 아닌, 자신의 PC에 kubeconfig 설정 후 아래 --server 옵션을 통해 hubble api server 사용해보자!
hubble help status | grep 'server string'
--server string Address of a Hubble server. Ignored when --input-file or --port-forward is provided. (default "localhost:4245")
# You can also query the flow API and look for flows
kubectl get ciliumendpoints.cilium.io -n kube-system # SECURITY IDENTITY
hubble observe
hubble observe -h
hubble observe -f
✅ 실행 결과 요약
1. Hubble Client 설치 성공
# 최신 버전 자동 다운로드 및 설치
(⎈|HomeLab:N/A) root@k8s-ctr:~# HUBBLE_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/hubble/master/stable.txt)
(⎈|HomeLab:N/A) root@k8s-ctr:~# curl -L --fail --remote-name-all https://github.com/cilium/hubble/releases/download/$HUBBLE_VERSION/hubble-linux-${HUBBLE_ARCH}.tar.gz
% Total % Received % Xferd Average Speed Time Time Time Current
100 22.3M 100 22.3M 0 0 13.9M 0 0:00:01 0:00:01 --:--:-- 33.0M
(⎈|HomeLab:N/A) root@k8s-ctr:~# which hubble
/usr/local/bin/hubble # 설치 완료 확인
2. 초기 연결 실패 → Port-Forward 설정
# 초기 상태: Hubble API 접근 불가
(⎈|HomeLab:N/A) root@k8s-ctr:~# hubble status
failed getting status: rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing: dial tcp 127.0.0.1:4245: connect: connection refused"
# Port-Forward 활성화
(⎈|HomeLab:N/A) root@k8s-ctr:~# cilium hubble port-forward&
[1] 10570
ℹ️ Hubble Relay is available at 127.0.0.1:4245 # 성공 메시지
# 로컬 포트 4245 개방 확인
(⎈|HomeLab:N/A) root@k8s-ctr:~# ss -tnlp | grep 4245
LISTEN 0 4096 127.0.0.1:4245 0.0.0.0:* users:(("cilium",pid=10570,fd=7))
LISTEN 0 4096 [::1]:4245 [::]:* users:(("cilium",pid=10570,fd=8))
3. Hubble API 정상 연결 확인
# 연결 성공 후 상태 확인
(⎈|HomeLab:N/A) root@k8s-ctr:~# hubble status
Healthcheck (via localhost:4245): Ok ✅
Current/Max Flows: 11,282/12,285 (91.84%) # 플로우 버퍼 91% 사용 중
Flows/s: 35.22 # 초당 35개 플로우 처리
Connected Nodes: 3/3 # 모든 노드(3개) 연결됨
# Hubble 클라이언트 설정 확인
(⎈|HomeLab:N/A) root@k8s-ctr:~# hubble config view
server: localhost:4245 # 기본 서버 주소
port-forward-port: "4245" # Port-Forward 포트
timeout: 5s # 요청 타임아웃
tls: false # TLS 비활성화 (내부 통신)
4. 실시간 네트워크 플로우 관측
# 실시간 트래픽 모니터링 시작
(⎈|HomeLab:N/A) root@k8s-ctr:~# hubble observe
# 주요 관측된 트래픽 패턴들:
# 1) Hubble UI → Relay 통신
Jul 25 17:13:13.125: kube-system/hubble-ui-76d4965bb6-hcgj6:55468 (ID:7661)
→ kube-system/hubble-relay-5dcd46f5c-tln2s:4245 (ID:11581)
to-endpoint FORWARDED (TCP Flags: ACK, PSH)
# 2) Hubble Relay → 각 노드 Agent 통신
Jul 25 17:13:13.125: kube-system/hubble-relay-5dcd46f5c-tln2s:42624 (ID:11581)
← 192.168.10.101:4244 (remote-node) to-endpoint FORWARDED
Jul 25 17:13:13.125: kube-system/hubble-relay-5dcd46f5c-tln2s:37400 (ID:11581)
← 192.168.10.102:4244 (host) to-endpoint FORWARDED
# 3) API Server 통신
Jul 25 17:13:17.280: kube-system/hubble-ui-76d4965bb6-hcgj6:47432 (ID:7661)
→ 192.168.10.100:6443 (kube-apiserver) to-network FORWARDED
# 4) CoreDNS 헬스체크
Jul 25 17:13:17.649: 10.0.2.15:55892 (host)
→ kube-system/coredns-674b8bbfcf-p8kth:8080 (ID:5694)
to-endpoint FORWARDED
# 5) 로컬 통신 (Pod 내부)
Jul 25 17:13:16.197: 127.0.0.1:8090 (world)
<> kube-system/hubble-ui-76d4965bb6-hcgj6 (ID:7661)
pre-xlate-rev TRACED
5. 관측된 네트워크 아키텍처
| 컴포넌트 | IP/Port | Security Identity | 역할 |
|---|---|---|---|
| hubble-ui | 172.20.1.129:8081 | ID:7661 | 웹 인터페이스 |
| hubble-relay | 172.20.2.176:4245 | ID:11581 | 클러스터 중계 |
| coredns | 172.20.0.51/107:8080 | ID:5694 | DNS 서비스 |
| k8s-ctr (192.168.10.100) | :4244 | kube-apiserver | 컨트롤 플레인 |
| k8s-w1 (192.168.10.101) | :4244 | remote-node | 워커 노드 1 |
| k8s-w2 (192.168.10.102) | :4244 | host | 워커 노드 2 |
현재 Hubble 관측 상태:
- ✅ CLI 접근: localhost:4245를 통한 API 접근 가능
- ✅ 실시간 모니터링: 초당 35개 플로우 처리 중
- ✅ 클러스터 커버리지: 3개 노드 모두 연결됨
- ✅ 플로우 버퍼: 12,285개 중 11,282개 사용 (91% 활용)
- ✅ 트래픽 가시성: UI↔Relay↔Agent 통신 체인 완전 관측
주요 관측 포인트:
- 데이터 플로우: UI → Relay → 각 노드 Agent (4244 포트)
- Security Identity: 각 Pod/서비스별 고유 ID 부여 (5694, 7661, 11581)
- 통신 방향: to-endpoint, to-network, to-stack 등 명확한 방향성
- 프로토콜 세부사항: TCP Flags (ACK, PSH, RST) 레벨까지 추적
Cilium Network Policy 실습
Cilium Agent 단축키 지정
# cilium 파드 이름
export CILIUMPOD0=$(kubectl get -l k8s-app=cilium pods -n kube-system --field-selector spec.nodeName=k8s-ctr -o jsonpath='{.items[0].metadata.name}')
export CILIUMPOD1=$(kubectl get -l k8s-app=cilium pods -n kube-system --field-selector spec.nodeName=k8s-w1 -o jsonpath='{.items[0].metadata.name}')
export CILIUMPOD2=$(kubectl get -l k8s-app=cilium pods -n kube-system --field-selector spec.nodeName=k8s-w2 -o jsonpath='{.items[0].metadata.name}')
echo $CILIUMPOD0 $CILIUMPOD1 $CILIUMPOD2
# 단축키(alias) 지정
alias c0="kubectl exec -it $CILIUMPOD0 -n kube-system -c cilium-agent -- cilium"
alias c1="kubectl exec -it $CILIUMPOD1 -n kube-system -c cilium-agent -- cilium"
alias c2="kubectl exec -it $CILIUMPOD2 -n kube-system -c cilium-agent -- cilium"
alias c0bpf="kubectl exec -it $CILIUMPOD0 -n kube-system -c cilium-agent -- bpftool"
alias c1bpf="kubectl exec -it $CILIUMPOD1 -n kube-system -c cilium-agent -- bpftool"
alias c2bpf="kubectl exec -it $CILIUMPOD2 -n kube-system -c cilium-agent -- bpftool"
# endpoint
c0 endpoint list
c0 endpoint list -o json
c1 endpoint list
c2 endpoint list
c1 endpoint get <id>
c1 endpoint log <id>
## Enable debugging output on the cilium-dbg monitor for this endpoint
c1 endpoint config <id> Debug=true
# monitor
c1 monitor
c1 monitor -v
c1 monitor -v -v
## Filter for only the events related to endpoint
c1 monitor --related-to=<id>
## Show notifications only for dropped packet events
c1 monitor --type drop
## Don't dissect packet payload, display payload in hex information
c1 monitor -v -v --hex
## Layer7
c1 monitor -v --type l7
# Manage IP addresses and associated information - IP List
c0 ip list
# IDENTITY : 1(host), 2(world), 4(health), 6(remote), 파드마다 개별 ID
c0 ip list -n
# Retrieve information about an identity
c0 identity list
# 엔드포인트 기준 ID
c0 identity list --endpoints
# 엔드포인트 설정 확인 및 변경
c0 endpoint config <엔트포인트ID>
# 엔드포인트 상세 정보 확인
c0 endpoint get <엔트포인트ID>
# 엔드포인트 로그 확인
c0 endpoint log <엔트포인트ID>
# Show bpf filesystem mount details
c0 bpf fs show
# bfp 마운트 폴더 확인
tree /sys/fs/bpf
# Get list of loadbalancer services
c0 service list
c1 service list
c2 service list
## Or you can get the loadbalancer information using bpf list
c0 bpf lb list
c1 bpf lb list
c2 bpf lb list
## List reverse NAT entries
c1 bpf lb list --revnat
c2 bpf lb list --revnat
# List connection tracking entries
c0 bpf ct list global
c1 bpf ct list global
c2 bpf ct list global
# Flush connection tracking entries
c0 bpf ct flush
c1 bpf ct flush
c2 bpf ct flush
# List all NAT mapping entries
c0 bpf nat list
c1 bpf nat list
c2 bpf nat list
# Flush all NAT mapping entries
c0 bpf nat flush
c1 bpf nat flush
c2 bpf nat flush
# Manage the IPCache mappings for IP/CIDR <-> Identity
c0 bpf ipcache list# Display cgroup metadata maintained by Cilium
c0 cgroups list
c1 cgroups list
c2 cgroups list
# List all open BPF maps
c0 map list
c1 map list --verbose
c2 map list --verbose
c1 map events cilium_lb4_services_v2
c1 map events cilium_lb4_reverse_nat
c1 map events cilium_lxc
c1 map events cilium_ipcache
# List all metrics
c1 metrics list
# List contents of a policy BPF map : Dump all policy maps
c0 bpf policy get --all
c1 bpf policy get --all -n
c2 bpf policy get --all -n
# Dump StateDB contents as JSON
c0 statedb dump
#
c0 shell -- db/show devices
c1 shell -- db/show devices
c2 shell -- db/show devices
Getting Started with the Star Wars Demo & Hubble/UI

출처 - https://docs.cilium.io/en/stable/gettingstarted/demo/
- 스타워즈에서 영감을 받은 예제에서는 데스스타, 타이파이터, 엑스윙의 세 가지 마이크로서비스 애플리케이션이 있습니다.
- 데스스타는 포트 80에서 HTTP 웹서비스를 실행하며, 이 서비스는 두 개의 포드 복제본에 걸쳐 데스스타에 대한 요청을 로드 밸런싱하는 Kubernetes 서비스로 노출됩니다.
- 데스스타 서비스는 제국의 우주선에 착륙 서비스를 제공하여 착륙 포트를 요청할 수 있도록 합니다.
- 타이파이터 포드는 일반적인 제국 선박의 착륙 요청 클라이언트 서비스를 나타내며, 엑스윙은 동맹 선박의 유사한 서비스를 나타냅니다.
- 데스스타 착륙 서비스에 대한 접근 제어를 위한 다양한 보안 정책을 테스트할 수 있도록 존재합니다.
실습 환경 설정
#
kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/1.17.6/examples/minikube/http-sw-app.yaml
# 파드 라벨 labels 확인
kubectl get pod --show-labels
kubectl get deploy,svc,ep deathstar
kubectl get ciliumendpoints.cilium.io -A
kubectl get ciliumidentities.cilium.io
# in a multi-node installation, only the ones running on the same node will be listed
kubectl exec -it -n kube-system ds/cilium -c cilium-agent -- **cilium endpoint list**
c0 endpoint list
c1 endpoint list
c2 endpoint list
# 현재 ingress/egress 에 정책(Policy) 없음! , Labels 정보 확인
# 엔드포인트 라벨별로 정책이 설정되기 때문에 라벨을 확인하는것이 중요하다. (예: k8s:class=deathstart)
✅ 실행 결과 요약
1. Star Wars 데모 애플리케이션 배포 성공
# 4개 Pod 정상 배포 완료
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
deathstar-8c4c77fb7-m8q2b 1/1 Running 0 32s app.kubernetes.io/name=deathstar,class=deathstar,org=empire,pod-template-hash=8c4c77fb7
deathstar-8c4c77fb7-nnzkt 1/1 Running 0 32s app.kubernetes.io/name=deathstar,class=deathstar,org=empire,pod-template-hash=8c4c77fb7
tiefighter 1/1 Running 0 32s app.kubernetes.io/name=tiefighter,class=tiefighter,org=empire
xwing 1/1 Running 0 32s app.kubernetes.io/name=xwing,class=xwing,org=alliance
# DeathStar 서비스 및 엔드포인트
service/deathstar ClusterIP 10.96.41.44 <none> 80/TCP 38s
endpoints/deathstar 172.20.1.167:80,172.20.2.219:80 # 2개 Pod로 로드밸런싱
2. Cilium Security Identity 체계
# 각 애플리케이션별 고유 Security Identity 할당
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl get ciliumendpoints.cilium.io -A
NAMESPACE NAME SECURITY IDENTITY IPV4
default deathstar-8c4c77fb7-m8q2b 15933 172.20.1.167 # Empire - DeathStar
default deathstar-8c4c77fb7-nnzkt 15933 172.20.2.219 # Empire - DeathStar (동일 ID)
default tiefighter 9225 172.20.2.9 # Empire - TieFighter
default xwing 7207 172.20.1.160 # Alliance - X-Wing
kube-system coredns-674b8bbfcf-2sbw2 5694 172.20.0.51 # System - CoreDNS
kube-system coredns-674b8bbfcf-p8kth 5694 172.20.0.107 # System - CoreDNS (동일 ID)
kube-system hubble-relay-5dcd46f5c-tln2s 11581 172.20.2.176 # System - Hubble Relay
kube-system hubble-ui-76d4965bb6-hcgj6 7661 172.20.1.129 # System - Hubble UI
# Identity 요약
kubectl get ciliumidentities.cilium.io
NAME NAMESPACE AGE
15933 default # DeathStar (2개 Pod 공유)
9225 default # TieFighter
7207 default # X-Wing
11581 kube-system # Hubble Relay
7661 kube-system # Hubble UI
5694 kube-system # CoreDNS (2개 Pod 공유)
3. 노드별 엔드포인트 분산 현황
| 노드 | 엔드포인트 | Identity | 애플리케이션 | IP 주소 |
|---|---|---|---|---|
| k8s-ctr | 703 | 1 | Host | - |
| k8s-ctr | 1174 | 5694 | CoreDNS | 172.20.0.107 |
| k8s-ctr | 2609 | 5694 | CoreDNS | 172.20.0.51 |
| k8s-w1 | 808 | 1 | Host | - |
| k8s-w1 | 1782 | 7661 | Hubble UI | 172.20.1.129 |
| k8s-w1 | 2885 | 7207 | X-Wing (Alliance) | 172.20.1.160 |
| k8s-w1 | 3615 | 15933 | DeathStar (Empire) | 172.20.1.167 |
| k8s-w2 | 93 | 11581 | Hubble Relay | 172.20.2.176 |
| k8s-w2 | 1041 | 15933 | DeathStar (Empire) | 172.20.2.219 |
| k8s-w2 | 2090 | 9225 | TieFighter (Empire) | 172.20.2.9 |
| k8s-w2 | 2374 | 1 | Host | - |
4. 중요한 레이블 체계 분석
조직별 분류:
- org=empire: DeathStar, TieFighter (제국군)
- org=alliance: X-Wing (반군 연합)
클래스별 분류:
- class=deathstar: 웹 서비스 (포트 80)
- class=tiefighter: 제국 클라이언트
- class=xwing: 연합 클라이언트
네임스페이스별 분류:
- default: Star Wars 애플리케이션들
- kube-system: Cilium 시스템 컴포넌트들
5. 현재 보안 정책 상태
# 모든 엔드포인트에서 정책 비활성화 상태
POLICY (ingress) POLICY (egress)
Disabled Disabled
# 의미: 현재 모든 Pod 간 통신이 제한 없이 허용됨
# 향후 네트워크 정책을 통해 Empire vs Alliance 간 접근 제어 가능
Star Wars 데모 아키텍처 완성:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ k8s-ctr │ │ k8s-w1 │ │ k8s-w2 │
├─────────────────┤ ├─────────────────┤ ├─────────────────┤
│ CoreDNS (2개) │ │ Hubble UI │ │ Hubble Relay │
│ (5694) │ │ (7661) │ │ (11581) │
│ │ │ │ │ │
│ │ │ X-Wing │ │ TieFighter │
│ │ │ (7207) Alliance │ │ (9225) Empire │
│ │ │ │ │ │
│ │ │ DeathStar │ │ DeathStar │
│ │ │ (15933) Empire │ │ (15933) Empire │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │
└───────┬───────────────┘
│
┌─────────────┐
│ DeathStar │
│ Service │
│ (ClusterIP) │
│ 10.96.41.44 │
└─────────────┘
준비 완료 상태:
- ✅ Star Wars 데모: 4개 애플리케이션 정상 배포
- ✅ Security Identity: 각 역할별 고유 ID 할당
- ✅ 네트워크 분산: 3개 노드에 균등 분산
- ✅ 서비스 노출: DeathStar HTTP 서비스 준비
- ✅ 정책 대기: 현재 모든 통신 허용 (정책 실습 준비)
현재 접근 전체 허용 테스트
- 데스스타 서비스의 관점에서 보면, org= empire 라벨이 부착된 선박만 연결하여 착륙을 요청할 수 있습니다.
- 규칙을 시행하지 않기 때문에 Xwing과 타이파이터 모두 착륙을 요청할 수 있습니다.
# 아래 출력에서 xwing 와 tiefighter 의 IDENTITY 메모
c1 endpoint list | grep -iE 'xwing|tiefighter|deathstar'
c2 endpoint list | grep -iE 'xwing|tiefighter|deathstar'
XWINGID=17141
TIEFIGHTERID=56716
DEATHSTARID=8113
# 모니터링 준비 : 터미널 3개, 단축키 설정
## 각각 monitor 확인
c0 monitor -v -v
c1 monitor -v -v
c2 monitor -v -v
# 모니터링 준비 : 터미널 1개
hubble observe -f
XWINGID=7207
TIEFIGHTERID=9225
DEATHSTARID=15933
hubble observe -f --from-identity $XWINGID
hubble observe -f --protocol udp --from-identity $XWINGID
hubble observe -f --protocol tcp --from-identity $XWINGID
hubble observe -f --protocol tcp --from-identity $DEATHSTARID
# 호출 시도 1
kubectl exec xwing -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing
while true; do kubectl exec xwing -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing ; sleep 5 ; done
# 호출 시도 2
kubectl exec tiefighter -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing
while true; do kubectl exec tiefighter -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing ; sleep 5 ; done
✅ 실행 결과 요약
호출 시도 1
(⎈|HomeLab:N/A) root@k8s-ctr:~# hubble observe -f --from-identity $XWINGID
Jul 25 17:44:03.781: default/xwing (ID:7207) <> 10.96.0.10:53 (world) pre-xlate-fwd TRACED (UDP)
Jul 25 17:44:03.781: default/xwing (ID:7207) <> kube-system/coredns-674b8bbfcf-2sbw2:53 (ID:5694) post-xlate-fwd TRANSLATED (UDP)
Jul 25 17:44:03.782: default/xwing:56514 (ID:7207) -> kube-system/coredns-674b8bbfcf-2sbw2:53 (ID:5694) to-network FORWARDED (UDP)
Jul 25 17:44:03.782: default/xwing:56514 (ID:7207) -> kube-system/coredns-674b8bbfcf-2sbw2:53 (ID:5694) to-endpoint FORWARDED (UDP)
Jul 25 17:44:03.783: default/xwing:56514 (ID:7207) <> kube-system/coredns-674b8bbfcf-2sbw2 (ID:5694) pre-xlate-rev TRACED (UDP)
Jul 25 17:44:03.783: default/xwing:56514 (ID:7207) <> kube-system/coredns-674b8bbfcf-2sbw2 (ID:5694) pre-xlate-rev TRACED (UDP)
Jul 25 17:44:03.806: default/xwing (ID:7207) <> 10.96.0.10:53 (world) pre-xlate-fwd TRACED (UDP)
Jul 25 17:44:03.806: default/xwing (ID:7207) <> kube-system/coredns-674b8bbfcf-p8kth:53 (ID:5694) post-xlate-fwd TRANSLATED (UDP)
Jul 25 17:44:03.806: default/xwing:53575 (ID:7207) -> kube-system/coredns-674b8bbfcf-p8kth:53 (ID:5694) to-network FORWARDED (UDP)
Jul 25 17:44:03.806: default/xwing:53575 (ID:7207) -> kube-system/coredns-674b8bbfcf-p8kth:53 (ID:5694) to-endpoint FORWARDED (UDP)
Jul 25 17:44:03.807: default/xwing:53575 (ID:7207) <> kube-system/coredns-674b8bbfcf-p8kth (ID:5694) pre-xlate-rev TRACED (UDP)
Jul 25 17:44:03.807: default/xwing:53575 (ID:7207) <> kube-system/coredns-674b8bbfcf-p8kth (ID:5694) pre-xlate-rev TRACED (UDP)
Jul 25 17:44:03.809: default/xwing (ID:7207) <> 10.96.0.10:53 (world) pre-xlate-fwd TRACED (UDP)
Jul 25 17:44:03.809: default/xwing (ID:7207) <> kube-system/coredns-674b8bbfcf-2sbw2:53 (ID:5694) post-xlate-fwd TRANSLATED (UDP)
Jul 25 17:44:03.809: default/xwing:33253 (ID:7207) -> kube-system/coredns-674b8bbfcf-2sbw2:53 (ID:5694) to-network FORWARDED (UDP)
Jul 25 17:44:03.810: default/xwing:33253 (ID:7207) <> kube-system/coredns-674b8bbfcf-2sbw2 (ID:5694) pre-xlate-rev TRACED (UDP)
Jul 25 17:44:03.810: default/xwing:33253 (ID:7207) <> kube-system/coredns-674b8bbfcf-2sbw2 (ID:5694) pre-xlate-rev TRACED (UDP)
Jul 25 17:44:03.810: default/xwing:33253 (ID:7207) -> kube-system/coredns-674b8bbfcf-2sbw2:53 (ID:5694) to-endpoint FORWARDED (UDP)
Jul 25 17:44:03.810: default/xwing (ID:7207) <> 10.96.0.10:53 (world) pre-xlate-fwd TRACED (UDP)
Jul 25 17:44:03.811: default/xwing (ID:7207) <> kube-system/coredns-674b8bbfcf-p8kth:53 (ID:5694) post-xlate-fwd TRANSLATED (UDP)
Jul 25 17:44:03.811: default/xwing:35900 (ID:7207) -> kube-system/coredns-674b8bbfcf-p8kth:53 (ID:5694) to-network FORWARDED (UDP)
Jul 25 17:44:03.812: default/xwing:35900 (ID:7207) -> kube-system/coredns-674b8bbfcf-p8kth:53 (ID:5694) to-endpoint FORWARDED (UDP)
Jul 25 17:44:03.812: default/xwing:35900 (ID:7207) <> kube-system/coredns-674b8bbfcf-p8kth (ID:5694) pre-xlate-rev TRACED (UDP)
Jul 25 17:44:03.812: default/xwing:35900 (ID:7207) <> kube-system/coredns-674b8bbfcf-p8kth (ID:5694) pre-xlate-rev TRACED (UDP)
Jul 25 17:44:03.815: default/xwing (ID:7207) <> 10.96.41.44:80 (world) pre-xlate-fwd TRACED (TCP)
Jul 25 17:44:03.815: default/xwing (ID:7207) <> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) post-xlate-fwd TRANSLATED (TCP)
Jul 25 17:44:03.815: default/xwing:43318 (ID:7207) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-network FORWARDED (TCP Flags: SYN)
Jul 25 17:44:03.816: default/xwing:43318 (ID:7207) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-endpoint FORWARDED (TCP Flags: SYN)
Jul 25 17:44:03.816: default/xwing:43318 (ID:7207) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-network FORWARDED (TCP Flags: ACK)
Jul 25 17:44:03.816: default/xwing:43318 (ID:7207) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-network FORWARDED (TCP Flags: ACK, PSH)
Jul 25 17:44:03.817: default/xwing:43318 (ID:7207) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-endpoint FORWARDED (TCP Flags: ACK)
Jul 25 17:44:03.817: default/xwing:43318 (ID:7207) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-endpoint FORWARDED (TCP Flags: ACK, PSH)
Jul 25 17:44:03.817: default/xwing:43318 (ID:7207) <> default/deathstar-8c4c77fb7-nnzkt (ID:15933) pre-xlate-rev TRACED (TCP)
Jul 25 17:44:03.819: default/xwing:43318 (ID:7207) <> default/deathstar-8c4c77fb7-nnzkt (ID:15933) pre-xlate-rev TRACED (TCP)
Jul 25 17:44:03.819: default/xwing:43318 (ID:7207) <> default/deathstar-8c4c77fb7-nnzkt (ID:15933) pre-xlate-rev TRACED (TCP)
Jul 25 17:44:03.820: default/xwing:43318 (ID:7207) <> default/deathstar-8c4c77fb7-nnzkt (ID:15933) pre-xlate-rev TRACED (TCP)
Jul 25 17:44:03.820: default/xwing:43318 (ID:7207) <> default/deathstar-8c4c77fb7-nnzkt (ID:15933) pre-xlate-rev TRACED (TCP)
Jul 25 17:44:03.821: default/xwing:43318 (ID:7207) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-network FORWARDED (TCP Flags: ACK, FIN)
Jul 25 17:44:03.821: default/xwing:43318 (ID:7207) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-network FORWARDED (TCP Flags: ACK)
Jul 25 17:44:03.822: default/xwing:43318 (ID:7207) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-endpoint FORWARDED (TCP Flags: ACK, FIN)
Jul 25 17:44:03.822: default/xwing:43318 (ID:7207) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-endpoint FORWARDED (TCP Flags: ACK)
(⎈|HomeLab:N/A) root@k8s-ctr:~# hubble observe -f --protocol udp --from-identity $XWINGID
Jul 25 17:47:06.358: default/xwing (ID:7207) <> 10.96.0.10:53 (world) pre-xlate-fwd TRACED (UDP)
Jul 25 17:47:06.358: default/xwing (ID:7207) <> kube-system/coredns-674b8bbfcf-p8kth:53 (ID:5694) post-xlate-fwd TRANSLATED (UDP)
Jul 25 17:47:06.359: default/xwing:44290 (ID:7207) -> kube-system/coredns-674b8bbfcf-p8kth:53 (ID:5694) to-network FORWARDED (UDP)
Jul 25 17:47:06.359: default/xwing:44290 (ID:7207) -> kube-system/coredns-674b8bbfcf-p8kth:53 (ID:5694) to-endpoint FORWARDED (UDP)
Jul 25 17:47:06.360: default/xwing:44290 (ID:7207) <> kube-system/coredns-674b8bbfcf-p8kth (ID:5694) pre-xlate-rev TRACED (UDP)
Jul 25 17:47:06.360: default/xwing:44290 (ID:7207) <> kube-system/coredns-674b8bbfcf-p8kth (ID:5694) pre-xlate-rev TRACED (UDP)
Jul 25 17:47:06.360: default/xwing (ID:7207) <> 10.96.0.10:53 (world) pre-xlate-fwd TRACED (UDP)
Jul 25 17:47:06.360: default/xwing (ID:7207) <> kube-system/coredns-674b8bbfcf-p8kth:53 (ID:5694) post-xlate-fwd TRANSLATED (UDP)
Jul 25 17:47:06.360: default/xwing:34714 (ID:7207) -> kube-system/coredns-674b8bbfcf-p8kth:53 (ID:5694) to-network FORWARDED (UDP)
Jul 25 17:47:06.361: default/xwing:34714 (ID:7207) -> kube-system/coredns-674b8bbfcf-p8kth:53 (ID:5694) to-endpoint FORWARDED (UDP)
Jul 25 17:47:06.361: default/xwing:34714 (ID:7207) <> kube-system/coredns-674b8bbfcf-p8kth (ID:5694) pre-xlate-rev TRACED (UDP)
Jul 25 17:47:06.361: default/xwing:34714 (ID:7207) <> kube-system/coredns-674b8bbfcf-p8kth (ID:5694) pre-xlate-rev TRACED (UDP)
Jul 25 17:47:06.361: default/xwing (ID:7207) <> 10.96.0.10:53 (world) pre-xlate-fwd TRACED (UDP)
Jul 25 17:47:06.361: default/xwing (ID:7207) <> kube-system/coredns-674b8bbfcf-2sbw2:53 (ID:5694) post-xlate-fwd TRANSLATED (UDP)
Jul 25 17:47:06.362: default/xwing:39701 (ID:7207) -> kube-system/coredns-674b8bbfcf-2sbw2:53 (ID:5694) to-network FORWARDED (UDP)
Jul 25 17:47:06.362: default/xwing:39701 (ID:7207) -> kube-system/coredns-674b8bbfcf-2sbw2:53 (ID:5694) to-endpoint FORWARDED (UDP)
Jul 25 17:47:06.362: default/xwing:39701 (ID:7207) <> kube-system/coredns-674b8bbfcf-2sbw2 (ID:5694) pre-xlate-rev TRACED (UDP)
Jul 25 17:47:06.362: default/xwing:39701 (ID:7207) <> kube-system/coredns-674b8bbfcf-2sbw2 (ID:5694) pre-xlate-rev TRACED (UDP)
Jul 25 17:47:06.363: default/xwing (ID:7207) <> 10.96.0.10:53 (world) pre-xlate-fwd TRACED (UDP)
Jul 25 17:47:06.363: default/xwing (ID:7207) <> kube-system/coredns-674b8bbfcf-p8kth:53 (ID:5694) post-xlate-fwd TRANSLATED (UDP)
Jul 25 17:47:06.363: default/xwing:60690 (ID:7207) -> kube-system/coredns-674b8bbfcf-p8kth:53 (ID:5694) to-network FORWARDED (UDP)
Jul 25 17:47:06.364: default/xwing:60690 (ID:7207) -> kube-system/coredns-674b8bbfcf-p8kth:53 (ID:5694) to-endpoint FORWARDED (UDP)
Jul 25 17:47:06.364: default/xwing:60690 (ID:7207) <> kube-system/coredns-674b8bbfcf-p8kth (ID:5694) pre-xlate-rev TRACED (UDP)
Jul 25 17:47:06.364: default/xwing:60690 (ID:7207) <> kube-system/coredns-674b8bbfcf-p8kth (ID:5694) pre-xlate-rev TRACED (UDP)
(⎈|HomeLab:N/A) root@k8s-ctr:~# hubble observe -f --protocol tcp --from-identity $XWINGID
Jul 25 17:47:29.583: default/xwing (ID:7207) <> 10.96.41.44:80 (world) pre-xlate-fwd TRACED (TCP)
Jul 25 17:47:29.583: default/xwing (ID:7207) <> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) post-xlate-fwd TRANSLATED (TCP)
Jul 25 17:47:29.584: default/xwing:40112 (ID:7207) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-network FORWARDED (TCP Flags: SYN)
Jul 25 17:47:29.584: default/xwing:40112 (ID:7207) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-network FORWARDED (TCP Flags: ACK)
Jul 25 17:47:29.584: default/xwing:40112 (ID:7207) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-endpoint FORWARDED (TCP Flags: SYN)
Jul 25 17:47:29.585: default/xwing:40112 (ID:7207) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-network FORWARDED (TCP Flags: ACK, PSH)
Jul 25 17:47:29.585: default/xwing:40112 (ID:7207) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-endpoint FORWARDED (TCP Flags: ACK)
Jul 25 17:47:29.585: default/xwing:40112 (ID:7207) <> default/deathstar-8c4c77fb7-nnzkt (ID:15933) pre-xlate-rev TRACED (TCP)
Jul 25 17:47:29.585: default/xwing:40112 (ID:7207) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-endpoint FORWARDED (TCP Flags: ACK, PSH)
Jul 25 17:47:29.586: default/xwing:40112 (ID:7207) <> default/deathstar-8c4c77fb7-nnzkt (ID:15933) pre-xlate-rev TRACED (TCP)
Jul 25 17:47:29.586: default/xwing:40112 (ID:7207) <> default/deathstar-8c4c77fb7-nnzkt (ID:15933) pre-xlate-rev TRACED (TCP)
Jul 25 17:47:29.586: default/xwing:40112 (ID:7207) <> default/deathstar-8c4c77fb7-nnzkt (ID:15933) pre-xlate-rev TRACED (TCP)
Jul 25 17:47:29.586: default/xwing:40112 (ID:7207) <> default/deathstar-8c4c77fb7-nnzkt (ID:15933) pre-xlate-rev TRACED (TCP)
Jul 25 17:47:29.586: default/xwing:40112 (ID:7207) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-network FORWARDED (TCP Flags: ACK, FIN)
Jul 25 17:47:29.587: default/xwing:40112 (ID:7207) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-network FORWARDED (TCP Flags: ACK)
Jul 25 17:47:29.587: default/xwing:40112 (ID:7207) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-endpoint FORWARDED (TCP Flags: ACK, FIN)
Jul 25 17:47:29.587: default/xwing:40112 (ID:7207) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-endpoint FORWARDED (TCP Flags: ACK)
(⎈|HomeLab:N/A) root@k8s-ctr:~# hubble observe -f --protocol tcp --from-identity $DEATHSTARID
Jul 25 17:47:52.956: default/xwing:60920 (ID:7207) <- default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-endpoint FORWARDED (TCP Flags: SYN, ACK)
Jul 25 17:47:52.956: default/xwing:60920 (ID:7207) <- default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-network FORWARDED (TCP Flags: SYN, ACK)
Jul 25 17:47:52.956: default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) <> default/xwing (ID:7207) pre-xlate-rev TRACED (TCP)
Jul 25 17:47:52.956: default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) <> default/xwing (ID:7207) pre-xlate-rev TRACED (TCP)
Jul 25 17:47:52.958: default/xwing:60920 (ID:7207) <- default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-endpoint FORWARDED (TCP Flags: ACK, PSH)
Jul 25 17:47:52.958: default/xwing:60920 (ID:7207) <- default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-network FORWARDED (TCP Flags: ACK, PSH)
Jul 25 17:47:52.959: default/xwing:60920 (ID:7207) <- default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-endpoint FORWARDED (TCP Flags: ACK, FIN)
Jul 25 17:47:52.959: default/xwing:60920 (ID:7207) <- default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-network FORWARDED (TCP Flags: ACK, FIN)
(⎈|HomeLab:N/A) root@k8s-ctr:~# hubble observe -f --protocol tcp --from-identity $TIEFIGHTERID
kubectl exec tiefighter -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing
Jul 25 17:51:18.026: default/tiefighter (ID:9225) <> 10.96.41.44:80 (world) pre-xlate-fwd TRACED (TCP)
Jul 25 17:51:18.026: default/tiefighter (ID:9225) <> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) post-xlate-fwd TRANSLATED (TCP)
Jul 25 17:51:18.027: default/tiefighter:48532 (ID:9225) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-endpoint FORWARDED (TCP Flags: SYN)
Jul 25 17:51:18.027: default/tiefighter:48532 (ID:9225) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-endpoint FORWARDED (TCP Flags: ACK)
Jul 25 17:51:18.027: default/tiefighter:48532 (ID:9225) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-endpoint FORWARDED (TCP Flags: ACK, PSH)
Jul 25 17:51:18.027: default/tiefighter:48532 (ID:9225) <> default/deathstar-8c4c77fb7-nnzkt (ID:15933) pre-xlate-rev TRACED (TCP)
Jul 25 17:51:18.027: default/tiefighter:48532 (ID:9225) <> default/deathstar-8c4c77fb7-nnzkt (ID:15933) pre-xlate-rev TRACED (TCP)
Jul 25 17:51:18.027: default/tiefighter:48532 (ID:9225) <> default/deathstar-8c4c77fb7-nnzkt (ID:15933) pre-xlate-rev TRACED (TCP)
Jul 25 17:51:18.028: default/tiefighter:48532 (ID:9225) <> default/deathstar-8c4c77fb7-nnzkt (ID:15933) pre-xlate-rev TRACED (TCP)
Jul 25 17:51:18.028: default/tiefighter:48532 (ID:9225) <> default/deathstar-8c4c77fb7-nnzkt (ID:15933) pre-xlate-rev TRACED (TCP)
Jul 25 17:51:18.028: default/tiefighter:48532 (ID:9225) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-endpoint FORWARDED (TCP Flags: ACK, FIN)
Jul 25 17:51:18.029: default/tiefighter:48532 (ID:9225) -> default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-endpoint FORWARDED (TCP Flags: ACK)
X윙~! 호출시

타이파이터 호출시

보안정책 적용

- Cilium을 사용할 때 보안 정책을 정의할 때 엔드포인트 IP 주소는 중요하지 않습니다. 대신 포드에 할당된 레이블을 사용하여 보안 정책을 정의할 수 있습니다. 정책은 클러스터 내에서 실행 중이거나 실행 중인 위치에 관계없이 레이블을 기반으로 올바른 포드에 적용됩니다.
- 데스스타 착륙 요청을 라벨이 있는 선박(org=empire)으로만 제한하는 기본 정책부터 시작하겠습니다. 이렇게 하면 org=empire 라벨이 없는 선박은 데스스타 서비스와 연결조차 할 수 없습니다. 이 정책은 IP 프로토콜(네트워크 계층 3)과 TCP 프로토콜(네트워크 계층 4)에만 적용되는 간단한 정책이므로 흔히 L3/L4 네트워크 보안 정책이라고 합니다.
- 참고: 실리움은 상태별 연결 추적을 수행합니다. 이는 정책이 프론트엔드가 백엔드에 도달할 수 있도록 허용하면, 동일한 TCP/UDP 연결 내에서 백엔드 응답의 일부인 모든 필수 응답 패킷이 자동으로 프론트엔드에 도달하도록 허용한다는 것을 의미합니다. → 리턴 패킷 자동 허용!
# CiliumNetworkPolicy
## CiliumNetworkPolicys는 "endpointSelector"를 사용하여 팟 레이블에서 정책이 적용되는 소스와 목적지를 식별합니다.
## 아래 정책은 TCP 포트 80에서 레이블(org=empire)이 있는 모든 팟에서 레이블(org=empire, class=deathstar)이 있는 데스스타 팟으로 전송되는 트래픽을 화이트리스트로 작성합니다.
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "rule1"
spec:
description: "L3-L4 policy to restrict deathstar access to empire ships only"
endpointSelector:
matchLabels:
org: empire
class: deathstar
ingress:
- fromEndpoints:
- matchLabels:
org: empire
toPorts:
- ports:
- port: "80"
protocol: TCP
kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/1.17.6/examples/minikube/sw_l3_l4_policy.yaml
#CNP -> Cilium Network Policy
kubectl get cnp
kubectl get cnp -o json | jq
# 모니터링
hubble observe -f --type drop
# 호출 시도 1
kubectl exec xwing -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing --connect-timeout 2
# 모니터링
hubble observe -f --protocol tcp --from-identity $DEATHSTARID
# 호출 시도 2
kubectl exec tiefighter -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing
✅ 실행 결과 요약
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/1.17.6/examples/minikube/sw_l3_l4_policy.yaml
ciliumnetworkpolicy.cilium.io/rule1 created
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl get cnp
NAME AGE VALID
rule1 9s True
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl get cnp -o json | jq
{
"apiVersion": "v1",
"items": [
{
"apiVersion": "cilium.io/v2",
...
"spec": {
"description": "L3-L4 policy to restrict deathstar access to empire ships only",
"endpointSelector": {
"matchLabels": {
"class": "deathstar",
"org": "empire"
}
},
"ingress": [
{
"fromEndpoints": [
{
"matchLabels": {
"org": "empire"
}
}
],
"toPorts": [
{
"ports": [
{
"port": "80",
"protocol": "TCP"
}
]
}
]
}
]
},
"status": {
"conditions": [
{
"lastTransitionTime": "2025-07-25T18:01:50Z",
"message": "Policy validation succeeded",
"status": "True",
"type": "Valid"
}
]
}
}
],
"kind": "List",
"metadata": {
"resourceVersion": ""
}
}
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl exec xwing -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing --connect-timeout 2
command terminated with exit code 28
#Death Start 모니터링시 타이파이터만 랜딩됨
(⎈|HomeLab:N/A) root@k8s-ctr:~# hubble observe -f --protocol tcp --from-identity $DEATHSTARID
Jul 25 18:04:28.190: default/tiefighter:56672 (ID:9225) <- default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-endpoint FORWARDED (TCP Flags: SYN, ACK)
Jul 25 18:04:28.190: default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) <> default/tiefighter (ID:9225) pre-xlate-rev TRACED (TCP)
Jul 25 18:04:28.190: default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) <> default/tiefighter (ID:9225) pre-xlate-rev TRACED (TCP)
Jul 25 18:04:28.191: default/tiefighter:56672 (ID:9225) <- default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-endpoint FORWARDED (TCP Flags: ACK, PSH)
Jul 25 18:04:28.191: default/tiefighter:56672 (ID:9225) <- default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933) to-endpoint FORWARDED (TCP Flags: ACK, FIN)
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl exec tiefighter -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing
Ship landed
# 네트워크 정책을 보면 각각의 노드 중 워커노드 1,2에 k8s:app.kubernetes.io/name=deathstar 정책이 Enabled 된 것을 확인할 수 있다.
(⎈|HomeLab:N/A) root@k8s-ctr:~# c0 endpoint list
ENDPOINT POLICY (ingress) POLICY (egress) IDENTITY LABELS (source:key[=value]) IPv6 IPv4 STATUS
ENFORCEMENT ENFORCEMENT
703 Disabled Disabled 1 k8s:node-role.kubernetes.io/control-plane ready
k8s:node.kubernetes.io/exclude-from-external-load-balancers
reserved:host
1174 Disabled Disabled 5694 k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=kube-system 172.20.0.107 ready
k8s:io.cilium.k8s.policy.cluster=default
k8s:io.cilium.k8s.policy.serviceaccount=coredns
k8s:io.kubernetes.pod.namespace=kube-system
k8s:k8s-app=kube-dns
2609 Disabled Disabled 5694 k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=kube-system 172.20.0.51 ready
k8s:io.cilium.k8s.policy.cluster=default
k8s:io.cilium.k8s.policy.serviceaccount=coredns
k8s:io.kubernetes.pod.namespace=kube-system
k8s:k8s-app=kube-dns
(⎈|HomeLab:N/A) root@k8s-ctr:~# c1 endpoint list
ENDPOINT POLICY (ingress) POLICY (egress) IDENTITY LABELS (source:key[=value]) IPv6 IPv4 STATUS
ENFORCEMENT ENFORCEMENT
808 Disabled Disabled 1 reserved:host ready
1782 Disabled Disabled 7661 k8s:app.kubernetes.io/name=hubble-ui 172.20.1.129 ready
k8s:app.kubernetes.io/part-of=cilium
k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=kube-system
k8s:io.cilium.k8s.policy.cluster=default
k8s:io.cilium.k8s.policy.serviceaccount=hubble-ui
k8s:io.kubernetes.pod.namespace=kube-system
k8s:k8s-app=hubble-ui
2885 Disabled Disabled 7207 k8s:app.kubernetes.io/name=xwing 172.20.1.160 ready
k8s:class=xwing
k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=default
k8s:io.cilium.k8s.policy.cluster=default
k8s:io.cilium.k8s.policy.serviceaccount=default
k8s:io.kubernetes.pod.namespace=default
k8s:org=alliance
3615 Enabled Disabled 15933 k8s:app.kubernetes.io/name=deathstar 172.20.1.167 ready
k8s:class=deathstar
k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=default
k8s:io.cilium.k8s.policy.cluster=default
k8s:io.cilium.k8s.policy.serviceaccount=default
k8s:io.kubernetes.pod.namespace=default
k8s:org=empire
(⎈|HomeLab:N/A) root@k8s-ctr:~# c2 endpoint list
ENDPOINT POLICY (ingress) POLICY (egress) IDENTITY LABELS (source:key[=value]) IPv6 IPv4 STATUS
ENFORCEMENT ENFORCEMENT
93 Disabled Disabled 11581 k8s:app.kubernetes.io/name=hubble-relay 172.20.2.176 ready
k8s:app.kubernetes.io/part-of=cilium
k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=kube-system
k8s:io.cilium.k8s.policy.cluster=default
k8s:io.cilium.k8s.policy.serviceaccount=hubble-relay
k8s:io.kubernetes.pod.namespace=kube-system
k8s:k8s-app=hubble-relay
1041 Enabled Disabled 15933 k8s:app.kubernetes.io/name=deathstar 172.20.2.219 ready
k8s:class=deathstar
k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=default
k8s:io.cilium.k8s.policy.cluster=default
k8s:io.cilium.k8s.policy.serviceaccount=default
k8s:io.kubernetes.pod.namespace=default
k8s:org=empire
2090 Disabled Disabled 9225 k8s:app.kubernetes.io/name=tiefighter 172.20.2.9 ready
k8s:class=tiefighter
k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=default
k8s:io.cilium.k8s.policy.cluster=default
k8s:io.cilium.k8s.policy.serviceaccount=default
k8s:io.kubernetes.pod.namespace=default
k8s:org=empire
2374 Disabled Disabled 1 reserved:host
Http Aware L7 레이어 정책 실습
L3~L4 정책은 ebpf가 처리하지만, L7 레이어는 cilium-envoy 데몬셋이 처리합니다.
이는 Userspace Policy를 거치기 때문에 속도가 느려질 수 있습니다. 하지만, ebpf와 userspace와 연결되기 때문에 nginx 기반 L7 보다는 효율이 좋습니다.
Cilium을 설치하면 기본적으로 L7 정책이 사용가능하도록 설정되어 있습니다.

- 위의 간단한 시나리오에서는 tiefighter / xwing에게 데스스타 API에 대한 전체 액세스 권한을 부여하거나 아예 액세스 권한을 부여하지 않는 것으로 충분했습니다. 그러나 마이크로서비스 간에 가장 강력한 보안(즉, 최소 권한 격리를 강제하는 것)을 제공하기 위해서는 데스스타 API를 호출하는 각 서비스가 합법적인 운영에 필요한 HTTP 요청 세트만 수행하도록 제한해야 합니다.
- 예를 들어, 데스스타 서비스가 임의의 제국 선박이 호출해서는 안 되는 일부 유지보수 API를 노출한다고 가정해 보겠습니다.
정책 설정 전
# 모니터링 >> Layer3/4 에서는 애플리케이션 상태를 확인 할 수 없음!
hubble observe -f --protocol tcp --from-identity $DEATHSTARID
# 호출해서는 안 되는 일부 유지보수 창륙장 API를 노출
kubectl exec tiefighter -- curl -s -XPUT deathstar.default.svc.cluster.local/v1/exhaust-port
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl exec tiefighter -- curl -s -XPUT deathstar.default.svc.cluster.local/v1/exhaust-port
Panic: deathstar exploded
goroutine 1 [running]:
main.HandleGarbage(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5, 0xa)
/code/src/github.com/empire/deathstar/
temp/main.go:9 +0x64
main.main()
/code/src/github.com/empire/deathstar/
temp/main.go:5 +0x85
# L3/4 레이어에서는 L7 정책을 알 수 없고, L7 정책도 설정되어 있지 않기 때문에, 착륙이 된다.
(⎈|HomeLab:N/A) root@k8s-ctr:~# hubble observe -f --protocol tcp --from-identity $DEATHSTARID
Jul 25 18:15:44.184: default/tiefighter:58932 (ID:9225) <- default/deathstar-8c4c77fb7-m8q2b:80 (ID:15933) to-network FORWARDED (TCP Flags: SYN, ACK)
Jul 25 18:15:44.184: default/tiefighter:58932 (ID:9225) <- default/deathstar-8c4c77fb7-m8q2b:80 (ID:15933) to-endpoint FORWARDED (TCP Flags: SYN, ACK)
Jul 25 18:15:44.185: default/deathstar-8c4c77fb7-m8q2b:80 (ID:15933) <> default/tiefighter (ID:9225) pre-xlate-rev TRACED (TCP)
Jul 25 18:15:44.185: default/deathstar-8c4c77fb7-m8q2b:80 (ID:15933) <> default/tiefighter (ID:9225) pre-xlate-rev TRACED (TCP)
Jul 25 18:15:44.185: default/tiefighter:58932 (ID:9225) <- default/deathstar-8c4c77fb7-m8q2b:80 (ID:15933) to-network FORWARDED (TCP Flags: ACK, PSH)
Jul 25 18:15:44.185: default/tiefighter:58932 (ID:9225) <- default/deathstar-8c4c77fb7-m8q2b:80 (ID:15933) to-endpoint FORWARDED (TCP Flags: ACK, PSH)
Jul 25 18:15:44.187: default/tiefighter:58932 (ID:9225) <- default/deathstar-8c4c77fb7-m8q2b:80 (ID:15933) to-network FORWARDED (TCP Flags: ACK, FIN)
Jul 25 18:15:44.187: default/tiefighter:58932 (ID:9225) <- default/deathstar-8c4c77fb7-m8q2b:80 (ID:15933) to-endpoint FORWARDED (TCP Flags: ACK, FIN)
Cilium Network Policy를 통해 L7 Policy 설정
기존 cnp rule1을 업데이트 하여 네트워크 정책을 허용합니다.
# 기존 rule1 정책을 업데이트 해서 사용
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "rule1"
spec:
description: "L7 policy to restrict access to specific HTTP call"
endpointSelector:
matchLabels:
org: empire
class: deathstar
ingress:
- fromEndpoints:
- matchLabels:
org: empire
toPorts:
- ports:
- port: "80"
protocol: TCP
rules:
http:
- method: "POST"
path: "/v1/request-landing"
# Update the existing rule to apply L7-aware policy to protect deathstar using:
kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/1.17.6/examples/minikube/sw_l3_l4_l7_policy.yaml
kubectl get cnp
kc describe cnp
c0 policy get
# 모니터링 : 파드 이름 지정
hubble observe -f --pod deathstar --protocol http
# We can now re-run the same test as above, but we will see a different outcome
kubectl exec tiefighter -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing
✅ 실행 결과 요약
1. L7 네트워크 정책 적용 성공
# 정책 배포 및 검증 완료
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/1.17.6/examples/minikube/sw_l3_l4_l7_policy.yaml
ciliumnetworkpolicy.cilium.io/rule1 configured
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl get cnp
NAME AGE VALID
rule1 20m True ✅ 정책 유효성 검증 성공
2. 상세 정책 규칙 분석
(⎈|HomeLab:N/A) root@k8s-ctr:~# kc describe cnp
# L7 HTTP 레벨 정책 세부사항
Name: rule1
Description: L7 policy to restrict access to specific HTTP call
# 대상 선택자: DeathStar (Empire)
Endpoint Selector:
Match Labels:
Class: deathstar # DeathStar 서비스만 대상
Org: empire # Empire 조직 소속
# 접근 허용 규칙
Ingress:
From Endpoints:
Match Labels:
Org: empire # Empire 조직에서만 접근 허용
To Ports:
Ports:
Port: 80 # HTTP 포트
Protocol: TCP
Rules:
Http:
Method: POST # POST 메서드만 허용
Path: /v1/request-landing # 특정 경로만 허용
# 정책 상태
Status: True (Policy validation succeeded)
3. Cilium Agent 정책 변환
# Kubernetes CNP → Cilium 내부 정책 변환 결과
(⎈|HomeLab:N/A) root@k8s-ctr:~# c0 policy get
{
"endpointSelector": {
"matchLabels": {
"any:class": "deathstar",
"any:org": "empire",
"k8s:io.kubernetes.pod.namespace": "default"
}
},
"ingress": [{
"fromEndpoints": [{
"matchLabels": {
"any:org": "empire",
"k8s:io.kubernetes.pod.namespace": "default"
}
}],
"toPorts": [{
"ports": [{"port": "80", "protocol": "TCP"}],
"rules": {
"http": [{"path": "/v1/request-landing", "method": "POST"}]
}
}]
}],
"enableDefaultDeny": {
"ingress": true, # Ingress 기본 거부 활성화
"egress": false # Egress는 제한 없음
}
}
Revision: 3 # 정책 리비전 번호
4. Empire 조직 간 통신 테스트 (성공)
# TieFighter → DeathStar 접근 허용 확인
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl exec tiefighter -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing
Ship landed ✅ 성공적인 착륙 요청
# 허용 조건 만족:
# ✅ org=empire (TieFighter도 Empire 소속)
# ✅ method=POST (정책에서 허용된 메서드)
# ✅ path=/v1/request-landing (정책에서 허용된 경로)
# ✅ port=80 (정책에서 허용된 포트)
실습 자원 삭제
# 다음 실습을 위해 리소스 삭제
kubectl delete -f https://raw.githubusercontent.com/cilium/cilium/1.17.6/examples/minikube/http-sw-app.yaml
kubectl delete cnp rule1
# 삭제 확인
kubectl get cnp
✅ 실행 결과 요약
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl delete -f https://raw.githubusercontent.com/cilium/cilium/1.17.6/examples/minikube/http-sw-app.yaml
service "deathstar" deleted
deployment.apps "deathstar" deleted
pod "tiefighter" deleted
pod "xwing" deleted
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl delete cnp rule1
ciliumnetworkpolicy.cilium.io "rule1" deleted
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl get cnp
No resources found in default namespace.
5. Hubble HTTP 트래픽 실시간 모니터링
# L7 HTTP 레벨 트래픽 관측
(⎈|HomeLab:N/A) root@k8s-ctr:~# hubble observe -f --pod deathstar --protocol http
# 실시간 HTTP 요청/응답 추적
Jul 25 18:23:15.877: default/tiefighter:52296 (ID:9225)
→ default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933)
http-request FORWARDED
(HTTP/1.1 POST http://deathstar.default.svc.cluster.local/v1/request-landing)
Jul 25 18:23:15.878: default/tiefighter:52296 (ID:9225)
← default/deathstar-8c4c77fb7-nnzkt:80 (ID:15933)
http-response FORWARDED
(HTTP/1.1 200 1ms (POST http://deathstar.default.svc.cluster.local/v1/request-landing))
# 관측 포인트:
# 🔍 Security Identity: 9225 (TieFighter) → 15933 (DeathStar)
# 🔍 HTTP 세부사항: POST 메서드로 변경되었음, 특정 경로, 1ms 응답시간
# 🔍 상태 코드: 200 OK (성공)
# 🔍 정책 적용: FORWARDED (정책 조건 만족하여 허용)
hubble ui 에서 확인해보면, 기존과 다르게 Http가 추가된 80이 표시되고, L7 info에 어떤 uri로 접근했는지까지 내용이 나옵니다.
이전 cnf L3/4 레이어 테스트 후 캡쳐

현재 cnp L7 레이어 테스트 후 캡쳐

정책 효과 분석:
| 항목 | Before 정책 | After 정책 | 변화 |
|---|---|---|---|
| 모든 조직 | 모든 접근 허용 | Empire만 허용 | 🔒 조직 기반 제한 |
| 모든 HTTP 메서드 | GET/POST/PUT 모두 허용 | POST만 허용 | 🔒 메서드 제한 |
| 모든 경로 | 모든 URL 허용 | /v1/request-landing만 허용 | 🔒 경로 제한 |
| 엔드포인트 정책 | Disabled | Enabled | ✅ 정책 활성화 |
L7 정책의 강력함:
- ✅ 조직 기반 접근제어: Empire vs Alliance 분리
- ✅ HTTP 메서드 제한: POST만 허용, GET/PUT 차단
- ✅ URL 경로 제한: 특정 API 엔드포인트만 허용
- ✅ 실시간 모니터링: Hubble로 L7 트래픽 완전 가시화
- ✅ 세밀한 제어: 포트, 프로토콜, 헤더 레벨까지 제어 가능
Empire 조직은 DeathStar의 착륙 서비스를 안전하게 이용할 수 있지만, Alliance는 접근이 차단되어 완벽한 Zero Trust 네트워크 환경이 구현되었습니다.
Hubble Exporter 설정 실습
hubble의 가시성 출력을 활용하여 모니터링 환경을 구축할 때 Exporter 설정이 필요합니다.
# 설정 : 아래 설정할 필요 없음 (처음 실습환경 구축시 적용해놓았기 때문입니다.)
helm upgrade cilium cilium/cilium --namespace kube-system --reuse-values \
--set hubble.enabled=true \
--set hubble.export.static.enabled=true \
--set hubble.export.static.filePath=/var/run/cilium/hubble/events.log
kubectl -n kube-system rollout status ds/cilium
# 확인
kubectl get cm -n kube-system cilium-config -o json | grep hubble-export
cilium config view | grep hubble-export
# Verify that flow logs are stored in target files
kubectl -n kube-system exec ds/cilium -- tail -f /var/run/cilium/hubble/events.log
kubectl -n kube-system exec ds/cilium -- sh -c 'tail -f /var/run/cilium/hubble/events.log' | jq
✅ 실행 결과 요약
1. Hubble Export 설정 확인 성공
# ConfigMap에서 Export 관련 설정 확인
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl get cm -n kube-system cilium-config -o json | grep hubble-export
"hubble-export-allowlist": "", # 허용 목록 (빈 값 = 모든 플로우 허용)
"hubble-export-denylist": "", # 거부 목록 (빈 값 = 차단 없음)
"hubble-export-fieldmask": "", # 필드 마스크 (빈 값 = 모든 필드 포함)
"hubble-export-file-max-backups": "5", # 최대 백업 파일 개수
"hubble-export-file-max-size-mb": "10", # 로그 파일 최대 크기 (10MB)
"hubble-export-file-path": "/var/run/cilium/hubble/events.log", # 로그 파일 경로
# Cilium CLI에서 Export 설정 확인
(⎈|HomeLab:N/A) root@k8s-ctr:~# cilium config view | grep hubble-export
hubble-export-allowlist # 허용 목록 (공백)
hubble-export-denylist # 거부 목록 (공백)
hubble-export-fieldmask # 필드 마스크 (공백)
hubble-export-file-max-backups 5 # 백업 파일 5개까지 보관
hubble-export-file-max-size-mb 10 # 파일당 10MB 제한
hubble-export-file-path /var/run/cilium/hubble/events.log # 저장 경로
2. 실시간 플로우 로깅 동작 확인
# 각 Cilium Agent에서 실시간으로 생성되는 플로우 로그 확인
# JSON 형태로 모든 네트워크 이벤트가 상세히 기록됨
주요 로깅 내용:
📋 **기본 정보**: time, uuid, verdict, node_name
🌐 **네트워크 계층**: IP 주소, 포트, 프로토콜, TCP 플래그
🔐 **보안 정보**: Security Identity, 레이블, 네임스페이스
📊 **상세 메타데이터**: Pod 이름, Workload 정보, CGroup ID
🔍 **추적 정보**: Traffic Direction, Observation Point, Interface
실시간 이벤트 예시:
- CoreDNS 헬스체크 (SOCK 레벨 추적)
- API Server ↔ CoreDNS 통신 (L3/L4 레벨)
- TCP 연결 수립/종료 (SYN, ACK, FIN 플래그)
- Socket 레벨 번역 포인트 추적
3. Export 기능 동작 원리
💾 파일 저장 방식:
- 경로: /var/run/cilium/hubble/events.log
- 형식: JSON Lines (각 줄이 하나의 플로우 이벤트)
- 순환: 10MB 도달 시 자동 로테이션
- 보관: 최대 5개 백업 파일 유지
🔄 실시간 처리:
- 모든 네트워크 플로우가 실시간으로 기록
- eBPF에서 캡처한 패킷 정보를 JSON으로 변환
- SOCK, L3_L4 레벨의 다양한 이벤트 포착
- Security Identity 기반 정책 적용 결과 추적
📊 모니터링 활용:
- 외부 로그 수집 시스템 연동 가능 (Fluentd, Logstash 등)
- SIEM 도구와 통합하여 보안 분석
- 네트워크 트래픽 패턴 분석 및 이상 탐지
- 성능 모니터링 및 트러블슈팅 지원
기타 기능
1. 성능 최적화 (Performance Tuning)
- 공식 문서: Hubble Export 성능 최적화
Hubble Exporter의 성능에 영향을 주는 주요 설정 옵션들:
# 허용 목록 설정 (특정 플로우만 내보내기)
--set hubble.export.static.allowList='[{"source_pod":["kube-system"]}]'
# 거부 목록 설정 (특정 플로우 제외)
--set hubble.export.static.denyList='[{"verdict":["DROPPED"]}]'
# 필드 마스킹 (불필요한 필드 제거로 성능 향상)
--set hubble.export.static.fieldMask='flow.source,flow.destination,flow.verdict'
성능 최적화 효과:
- 📈 디스크 사용량 감소: 필요한 플로우만 저장
- ⚡ 처리 속도 향상: 불필요한 데이터 필터링
- 💾 메모리 최적화: 선택적 필드 처리
2. 동적 설정 관리 (Dynamic Exporter Configuration)
- 공식 문서: 동적 내보내기 설정
- 실습 상태: 생략 (고급 기능)
정적 설정 vs 동적 설정 비교:
| 구분 | 정적 내보내기 | 동적 내보내기 |
|---|---|---|
| 필터 개수 | 단일 필터 세트만 가능 | 여러 필터 동시 적용 |
| 출력 파일 | 하나의 파일만 생성 | 필터별 개별 파일 생성 |
| 설정 변경 | Pod 재시작 필요 | 실시간 변경 가능 |
| 복잡도 | 간단한 설정 | 고급 설정 필요 |
동적 내보내기의 장점:
- 실시간 설정 변경: Cilium Pod를 재시작하지 않고도 설정 변경 가능
- 다중 출력 파일: 용도별로 로그 파일을 분리하여 저장
- 세밀한 제어: 각 필터를 독립적으로 관리 가능
동적 설정 활성화 방법:
# ConfigMap을 통한 동적 설정 경로 지정
--set hubble.export.static.enabled=false
--set hubble.export.dynamic.config.configMapName=hubble-flowlogs-config
--set hubble.export.dynamic.config.createConfigMap=true
3. 현재 실습 환경에서 사용한 설정
# 실습에서 적용된 기본 설정
hubble-export-allowlist: "" # 모든 플로우 허용 (필터링 없음)
hubble-export-denylist: "" # 차단할 플로우 없음
hubble-export-fieldmask: "" # 모든 필드 포함
hubble-export-file-max-backups: 5 # 최대 5개 백업 파일 보관
hubble-export-file-max-size-mb: 10 # 파일당 최대 10MB 크기 제한
운영 환경 권장 설정:
# 실제 운영 환경에서 권장하는 최적화된 설정
--set hubble.export.static.allowList='[{"source_namespace":["default","production"]}]'
--set hubble.export.static.denyList='[{"verdict":["TRACED"],"source_pod":["kube-system"]}]'
--set hubble.export.static.fieldMask='flow.time,flow.verdict,flow.source,flow.destination,flow.l4'
--set hubble.export.static.fileMaxSizeMb=50 # 더 큰 파일 크기
--set hubble.export.static.fileMaxBackups=10 # 더 많은 백업 파일
설정별 상세 설명:
- allowList: 지정된 조건에 맞는 플로우만 로그에 기록
- denyList: 지정된 조건에 맞는 플로우는 로그에서 제외
- fieldMask: 로그에 포함할 필드만 선택하여 파일 크기 최적화
Hubble Exporter와 Prometheus & Grafana 연동
Prometheus & Grafana에 대한 설명은 이전 스터디 글을 참고하시기 바랍니다!
링크 - https://devlos.tistory.com/63
샘플 애플리케이션 배포 및 확인
# 샘플 애플리케이션 배포
cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: webpod
spec:
replicas: 2
selector:
matchLabels:
app: webpod
template:
metadata:
labels:
app: webpod
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- sample-app
topologyKey: "kubernetes.io/hostname"
containers:
- name: webpod
image: traefik/whoami
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: webpod
labels:
app: webpod
spec:
selector:
app: webpod
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
EOF
# k8s-ctr 노드에 curl-pod 파드 배포
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: curl-pod
labels:
app: curl
spec:
nodeName: k8s-ctr
containers:
- name: curl
image: nicolaka/netshoot
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
EOF
# 배포 확인
kubectl get deploy,svc,ep webpod -owide
kubectl get endpointslices -l app=webpod
kubectl get ciliumendpoints
kubectl exec -it -n kube-system ds/cilium -c cilium-agent -- cilium-dbg endpoint list
# 통신 확인
kubectl exec -it curl-pod -- curl webpod | grep Hostname
kubectl exec -it curl-pod -- sh -c 'while true; do curl -s webpod | grep Hostname; sleep 1; done'
✅ 실행 결과 요약
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl get deploy,svc,ep webpod -owide
Warning: v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment.apps/webpod 2/2 2 2 54s webpod traefik/whoami app=webpod
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/webpod ClusterIP 10.96.166.184 <none> 80/TCP 54s app=webpod
NAME ENDPOINTS AGE
endpoints/webpod 172.20.1.179:80,172.20.2.207:80 54s
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl get endpointslices -l app=webpod
NAME ADDRESSTYPE PORTS ENDPOINTS AGE
webpod-97xpr IPv4 80 172.20.1.179,172.20.2.207 58s
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl get ciliumendpoints
NAME SECURITY IDENTITY ENDPOINT STATE IPV4 IPV6
curl-pod 10292 ready 172.20.0.241
webpod-697b545f57-b2xst 2460 ready 172.20.2.207
webpod-697b545f57-ntmqj 2460 ready 172.20.1.179
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl exec -it -n kube-system ds/cilium -c cilium-agent -- cilium-dbg endpoint list
ENDPOINT POLICY (ingress) POLICY (egress) IDENTITY LABELS (source:key[=value]) IPv6 IPv4 STATUS
ENFORCEMENT ENFORCEMENT
703 Disabled Disabled 1 k8s:node-role.kubernetes.io/control-plane ready
k8s:node.kubernetes.io/exclude-from-external-load-balancers
reserved:host
1174 Disabled Disabled 5694 k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=kube-system 172.20.0.107 ready
k8s:io.cilium.k8s.policy.cluster=default
k8s:io.cilium.k8s.policy.serviceaccount=coredns
k8s:io.kubernetes.pod.namespace=kube-system
k8s:k8s-app=kube-dns
1475 Disabled Disabled 10292 k8s:app=curl 172.20.0.241 ready
k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=default
k8s:io.cilium.k8s.policy.cluster=default
k8s:io.cilium.k8s.policy.serviceaccount=default
k8s:io.kubernetes.pod.namespace=default
2609 Disabled Disabled 5694 k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=kube-system 172.20.0.51 ready
k8s:io.cilium.k8s.policy.cluster=default
k8s:io.cilium.k8s.policy.serviceaccount=coredns
k8s:io.kubernetes.pod.namespace=kube-system
k8s:k8s-app=kube-dns
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl exec -it curl-pod -- curl webpod | grep Hostname
Hostname: webpod-697b545f57-b2xst
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl exec -it curl-pod -- sh -c 'while true; do curl -s webpod | grep Hostname; sleep 1; done'
Hostname: webpod-697b545f57-ntmqj
Hostname: webpod-697b545f57-ntmqj
...
Prometheus & Grafana 설치
참고: Docs
Prometheus와 Grafana를 단일 배포로 포함하는 예제 배포입니다. - Youtube
- Grafana: Cilium 대시보드가 미리 로드된 시각화 대시보드입니다.
- Prometheus: 시계열 데이터베이스 및 모니터링 시스템입니다.
- 이 Prometheus와 Grafana 예제 배포는 Cilium 및 Hubble 메트릭을 자동으로 수집합니다.
kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/1.17.6/examples/kubernetes/addons/prometheus/monitoring-example.yaml
kubectl get deploy,pod,svc,ep -n cilium-monitoring
kubectl get cm -n cilium-monitoring
# 프로메테우스 서버 설정
kc describe cm -n cilium-monitoring prometheus
# 그라파나 서버 설정
kc describe cm -n cilium-monitoring grafana-config
# 그파라나 대시보드들 주입을 위한 설정
kc describe cm -n cilium-monitoring grafana-cilium-dashboard
kc describe cm -n cilium-monitoring grafana-hubble-dashboard
✅ 실행 결과 요약
1. Prometheus & Grafana 모니터링 스택 배포 성공
# 모니터링 관련 모든 리소스가 cilium-monitoring 네임스페이스에 배포됨
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl get deploy,pod,svc,ep -n cilium-monitoring
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/grafana 1/1 1 1 2m45s # Grafana 웹 인터페이스
deployment.apps/prometheus 1/1 1 1 2m45s # Prometheus 시계열 DB
NAME READY STATUS RESTARTS AGE
pod/grafana-59957b9549-x7k2h 1/1 Running 0 2m45s # Grafana Pod 정상 동작
pod/prometheus-7c8c9cbd7-mp8vz 1/1 Running 0 2m45s # Prometheus Pod 정상 동작
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/grafana ClusterIP 10.96.89.156 <none> 3000/TCP 2m45s # Grafana 웹 서비스
service/prometheus ClusterIP 10.96.143.199 <none> 9090/TCP 2m45s # Prometheus API 서비스
NAME ENDPOINTS AGE
endpoints/grafana 172.20.1.45:3000 2m45s # Grafana 엔드포인트
endpoints/prometheus 172.20.2.97:9090 2m45s # Prometheus 엔드포인트
2. ConfigMap 구성 현황
# 총 4개의 ConfigMap으로 모니터링 설정 관리
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl get cm -n cilium-monitoring
NAME DATA AGE
grafana-cilium-dashboard 1 3m12s # Cilium 대시보드 JSON 설정
grafana-config 1 3m12s # Grafana 기본 설정 (데이터소스, 대시보드 경로)
grafana-hubble-dashboard 1 3m12s # Hubble 대시보드 JSON 설정
prometheus 1 3m12s # Prometheus 스크래핑 설정
3. Prometheus 설정 분석
- 스크래핑 대상: Cilium Agent (9965), Cilium Operator (9963), Hubble (9965) 메트릭
- 수집 간격: 기본 15초마다 메트릭 수집
- 서비스 디스커버리: Kubernetes API를 통한 자동 타겟 발견
- 레이블 설정: Pod, 네임스페이스, 노드별 레이블 자동 할당
4. Grafana 설정 분석
- 데이터소스: Prometheus (http://prometheus:9090) 자동 연결
- 대시보드: Cilium 및 Hubble 대시보드 사전 구성
- 프로비저닝: 시작 시 자동으로 대시보드 로드
- 접속 포트: 3000번 포트로 웹 인터페이스 제공
5. 주요 대시보드 구성
Cilium 대시보드:
- 📊 네트워크 정책: 허용/차단된 연결 통계
- 🔄 로드밸런싱: 서비스별 트래픽 분산 현황
- 🛡️ 보안 상태: Security Identity별 정책 적용 상태
- 📈 성능 메트릭: BPF 맵 사용률, 엔드포인트 상태
Hubble 대시보드:
- 🌐 HTTP 트래픽: 요청/응답 통계, 레이턴시 (p50, p99)
- 🔍 DNS 모니터링: 쿼리/응답 대칭성, 오류율, Top 10 쿼리
- 📊 프로토콜 분석: HTTP/gRPC 프로토콜 사용 분포
- ⚠️ 오류 추적: DNS 오류, 응답 누락, 문제가 있는 Pod 식별
아키텍처 흐름:
Grafana (:3000) ← Prometheus (:9090) ← Cilium/Hubble 메트릭 (:9965, :9963)
↓ ↓ ↓
웹 대시보드 시계열 데이터베이스 실시간 메트릭 수집
시각화 인터페이스 메트릭 저장 및 쿼리 eBPF 기반 관측
준비 완료 상태:
- ✅ Prometheus: Cilium/Hubble 메트릭 자동 수집 중
- ✅ Grafana: 사전 구성된 대시보드로 즉시 모니터링 가능
- ✅ ConfigMap: 모든 설정이 분리되어 관리 용이
- ✅ 서비스: ClusterIP로 클러스터 내부 접근 준비
Cilium과 Hubble metrics enabled 설정
- Cilium, Hubble, and Cilium Operator는 기본적으로 메트릭을 노출하지 않습니다.
- 이러한 서비스에 대한 메트릭을 활성화하면 이러한 구성 요소가 실행 중인 클러스터의 모든 노드에 각각 9962, 9965, 9963 포트가 열립니다.
- Cilium, Hubble, and Cilium Operator의 메트릭은 모두 다음 헬름 값으로 서로 독립적으로 활성화할 수 있습니다
prometheus.enabled=true: Enables metrics forcilium-agent.operator.prometheus.enabled=true: Enables metrics forcilium-operator.hubble.metrics.enabled: Enables the provided list of Hubble metrics.- For Hubble metrics to work, Hubble itself needs to be enabled with
hubble.enabled=true. - See Hubble exported metrics for the list of available Hubble metrics.
- For Hubble metrics to work, Hubble itself needs to be enabled with
- → Refer to Monitoring & Metrics for more details about the individual metrics.*
설정
# 이미 설정되어 있음
helm install cilium cilium/cilium --version 1.17.6 \
--namespace kube-system \
--set prometheus.enabled=true \
--set operator.prometheus.enabled=true \
--set hubble.enabled=true \
--set hubble.metrics.enableOpenMetrics=true \
--set hubble.metrics.enabled="{dns,drop,tcp,flow,port-distribution,icmp,httpV2:exemplars=true;labelsContext=source_ip\,source_namespace\,source_workload\,destination_ip\,destination_namespace\,destination_workload\,traffic_direction}"
# 호스트에 포트 정보 확인
ss -tnlp | grep -E '9962|9963|9965'
for i in w1 w2 ; do echo ">> node : k8s-$i <<"; sshpass -p 'vagrant' ssh vagrant@k8s-$i sudo ss -tnlp | grep -E '9962|9963|9965' ; echo; done
# 모니터링 네암스페이스의 서비스들 확인
kubectl get svc -n cilium-monitoring
# NodePort 설정
kubectl patch svc -n cilium-monitoring prometheus -p '{"spec": {"type": "NodePort", "ports": [{"port": 9090, "targetPort": 9090, "nodePort": 30001}]}}'
kubectl patch svc -n cilium-monitoring grafana -p '{"spec": {"type": "NodePort", "ports": [{"port": 3000, "targetPort": 3000, "nodePort": 30002}]}}'
# 확인
kubectl get svc -n cilium-monitoring
# 접속 주소 확인
echo "http://192.168.10.100:30001" # prometheus
echo "http://192.168.10.100:30002" # grafana
✅ 실행 결과 요약
# 각 노드별 익스포터 포트 구성 확인
# 오퍼레이터 레플리카가 1이라 Control Plane에 만 배포되어 있음
(⎈|HomeLab:N/A) root@k8s-ctr:~# ss -tnlp | grep -E '9962|9963|9965'
LISTEN 0 4096 *:9962 *:* users:(("cilium-agent",pid=9298,fd=7)) # cilium 메트릭
LISTEN 0 4096 *:9963 *:* users:(("cilium-operator",pid=5512,fd=7)) # cilium-opeator 메트릭
LISTEN 0 4096 *:9965 *:* users:(("cilium-agent",pid=9298,fd=42)) # hubble 메트릭
(⎈|HomeLab:N/A) root@k8s-ctr:~# for i in w1 w2 ; do echo ">> node : k8s-$i <<"; sshpass -p 'vagrant' ssh vagrant@k8s-$i sudo ss -tnlp | grep -E '9962|9963|9965' ; echo; done
>> node : k8s-w1 <<
LISTEN 0 4096 *:9965 *:* users:(("cilium-agent",pid=7154,fd=48)) # hubble 메트릭
LISTEN 0 4096 *:9962 *:* users:(("cilium-agent",pid=7154,fd=7)) # cilium 메트릭
>> node : k8s-w2 <<
LISTEN 0 4096 *:9965 *:* users:(("cilium-agent",pid=6930,fd=32)) # hubble 메트릭
LISTEN 0 4096 *:9962 *:* users:(("cilium-agent",pid=6930,fd=7)) # cilium 메트릭
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl get svc -n cilium-monitoring
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
grafana ClusterIP 10.96.103.7 <none> 3000/TCP 10m
prometheus ClusterIP 10.96.210.3 <none> 9090/TCP 10m
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl patch svc -n cilium-monitoring prometheus -p '{"spec": {"type": "NodePort", "ports": [{"port": 9090, "targetPort": 9090, "nodePort": 30001}]}}'
service/prometheus patched
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl patch svc -n cilium-monitoring grafana -p '{"spec": {"type": "NodePort", "ports": [{"port": 3000, "targetPort": 3000, "nodePort": 30002}]}}'
service/grafana patched
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl get svc -n cilium-monitoring
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
grafana NodePort 10.96.103.7 <none> 3000:30002/TCP 10m
prometheus NodePort 10.96.210.3 <none> 9090:30001/TCP 10m
Prometheus: http://192.168.10.100:30001 접속

Prometheus > Target 확인

Prometheus > 쿼리 예제(hubble_drop_total)

Grafana: http://192.168.10.100:30002 접속

Grafana > Cilium Metrics

Grafana > Operator

Grafana > Hubble

Grafana Hubble L7 HTTPS MEtrics By Workload

Cilium Metrics 설정 및 수집 방법 - Docs
- Cilium metrics은 Cilium 자체의 상태, 즉 Cilium Agent, Cilium envoy, Cilium operator 프로세스에 대한 인사이트를 제공합니다.
- 프로메테우스 메트릭이 활성화된 Cilium을 실행하려면
prometheus.enabled=trueHelm 값 집합을 사용하여 Cilium을 배포하세요. - Cilium metrics are exported under the
cilium_Prometheus namespace. - Envoy metrics are exported under the
envoy_Prometheus namespace, of which the Cilium-defined metrics are exported under theenvoy_cilium_namespace. - Kubernetes에서 실행 및 수집할 때 포드 이름과 네임스페이스로 태그가 지정됩니다.
Layer 7 Protocol Visibility 실습
- Monitoring Datapath State는 datapath state에 대한 성찰을 제공하지만, 기본적으로 L3/L4 패킷 이벤트에 대한 가시성만 제공합니다.
- L7 프로토콜 가시성을 원한다면 L7 Cilium Network Policies 을 사용할 수 있습니다(레이어 7 예제 참조).
- L7 트래픽에 대한 가시성을 활성화하려면 L7 규칙을 지정하는 CiliumNetworkPolicy를 만드세요.
- CiliumNetworkPolicy에서 L7 규칙과 일치하는 트래픽 흐름이 Cilium에 표시되므로 최종 사용자에게 노출될 수 있습니다.
- L7 네트워크 정책은 가시성을 가능하게 할 뿐만 아니라 포드에 들어오고 나가는 트래픽을 제한한다는 점을 기억하는 것이 중요합니다.
실습
# 반복 접속 해둔 상태
kubectl exec -it curl-pod -- sh -c 'while true; do curl -s webpod | grep Hostname; sleep 1; done'
# default 네임스페이스에 있는 Pod들의 egress(출방향) 트래픽을 제어하며, L7 HTTP 및 DNS 트래픽에 대한 가시성과 제어를 설정
## method/path 기반 필터링은 안 하지만, HTTP 요청 정보는 Envoy를 통해 기록/관찰됨
## cilium-envoy를 경유하게 됨 (DNS + HTTP 모두 L7 처리 대상)
## 이 정책이 적용되면, 명시된 egress 외의 모든 egress 트래픽은 차단됩니다 (Cilium 정책은 default-deny 모델임)
cat <<EOF | kubectl apply -f -
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "l7-visibility"
spec:
endpointSelector:
matchLabels:
"k8s:io.kubernetes.pod.namespace": default # default 네임스페이스 안의 모든 Pod에 대해 egress 정책이 적용
egress:
- toPorts: # 첫번째 정책!
- ports:
- port: "53"
protocol: ANY # TCP, UDP 둘 다 허용
rules:
dns:
- matchPattern: "*" # 모든 도메인 조회 허용, L7 가시성 활성화
- toEndpoints:
- matchLabels:
"k8s:io.kubernetes.pod.namespace": default
toPorts: # 두번째 정책!
- ports:
- port: "80" # default 다른 파드의 HTTP TCP 80 요청 허용
protocol: TCP
- port: "8080" # default 다른 파드의 HTTP TCP 8080 요청 허용
protocol: TCP
rules:
http: [{}] # 모든 HTTP 요청을 허용, L7 가시성 활성화
EOF
kubectl get cnp -o yaml
# 호출 확인 : cilium-envoy 경유 확인
kubectl exec -it curl-pod -- curl -s webpod
# 가시성 확인
hubble observe -f -t l7 -o compact
...
혹은 cilium nonitor ~
✅ 실행 결과 요약
1. L7 가시성 네트워크 정책 적용 성공
# CiliumNetworkPolicy 생성 및 검증 완료
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl apply -f -
ciliumnetworkpolicy.cilium.io/l7-visibility created
# 정책 상태 확인
Status:
Conditions:
Last Transition Time: 2025-07-25T19:47:41Z
Message: Policy validation succeeded
Status: True
Type: Valid
2. 정책 세부 규칙 분석
(⎈|HomeLab:N/A) root@k8s-ctr:~# cat <<EOF | kubectl apply -f -
# 적용된 정책 구조
endpointSelector:
matchLabels:
k8s:io.kubernetes.pod.namespace: default # default 네임스페이스 모든 Pod 대상
egress:
# DNS 트래픽 허용 (L7 가시성 활성화)
- toPorts:
- ports: [{"port": "53", "protocol": "ANY"}] # TCP/UDP 모두 허용
rules:
dns: [{"matchPattern": "*"}] # 모든 도메인 조회 허용
# HTTP 트래픽 허용 (L7 가시성 활성화)
- toEndpoints:
- matchLabels: {"k8s:io.kubernetes.pod.namespace": "default"}
toPorts:
- ports: [{"port": "80"}, {"port": "8080"}] # HTTP 포트들
rules:
http: [{}] # 모든 HTTP 요청 허용하되 가시성 확보
3. L7 Proxy 경유 확인
# HTTP 요청이 Envoy 프록시를 경유함을 확인
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl exec -it curl-pod -- curl -s webpod
Hostname: webpod-697b545f57-b2xst
...
# Envoy 관련 헤더 추가됨
X-Envoy-Expected-Rq-Timeout-Ms: 3600000
X-Envoy-Internal: true
X-Forwarded-Proto: http
X-Request-Id: 6fe4abf7-aafb-48f8-9837-d597c3d806ff
4. L7 트래픽 실시간 가시성 확보
# DNS 및 HTTP 트래픽의 상세한 L7 정보 관측 가능
Jul 25 19:48:16.851: default/curl-pod:38330 (ID:10292)
→ kube-system/coredns-674b8bbfcf-p8kth:53 (ID:5694)
dns-request proxy FORWARDED
(DNS Query webpod.default.svc.cluster.local. A)
Jul 25 19:48:16.852: default/curl-pod:38330 (ID:10292)
← kube-system/coredns-674b8bbfcf-p8kth:53 (ID:5694)
dns-response proxy FORWARDED
(DNS Answer "10.96.166.184" TTL: 30)
Jul 25 19:48:16.855: default/curl-pod:52252 (ID:10292)
→ default/webpod-697b545f57-b2xst:80 (ID:2460)
http-request FORWARDED
(HTTP/1.1 GET http://webpod/)
Jul 25 19:48:16.859: default/curl-pod:52252 (ID:10292)
← default/webpod-697b545f57-b2xst:80 (ID:2460)
http-response FORWARDED
(HTTP/1.1 200 4ms)
5. L7 가시성의 핵심 기능
DNS 레벨 가시성:
- 🔍 쿼리 추적: 도메인 조회 패턴 분석 (A, AAAA 레코드)
- ⏱️ TTL 모니터링: DNS 캐시 수명 추적 (TTL: 30초)
- 📊 응답 분석: 성공/실패 DNS 응답 구분
HTTP 레벨 가시성:
- 🌐 요청/응답 쌍: HTTP 메서드, URL, 상태코드 추적
- ⏱️ 레이턴시 측정: 응답 시간 정밀 측정 (2-4ms)
- 🔗 연결 추적: Request ID를 통한 요청 상관관계 분석
- 📋 헤더 분석: Envoy 프록시 메타데이터 포함
L7 정책의 중요한 특징:
- ✅ Zero Trust: 명시되지 않은 egress 트래픽은 모두 차단
- ✅ 프록시 경유: 모든 L7 트래픽이 cilium-envoy를 통과
- ✅ 실시간 관측: DNS/HTTP 트랜잭션의 완전한 가시성
- ✅ 성능 측정: 마이크로초 단위 레이턴시 측정
- ✅ 보안 강화: L7 레벨에서의 세밀한 접근 제어
L3/L4 vs L7 가시성 비교:
| 구분 | L3/L4 모니터링 | L7 가시성 |
|---|---|---|
| DNS | IP:53 연결만 보임 | 도메인명, 쿼리타입, TTL 상세 |
| HTTP | IP:80 연결만 보임 | URL, 메서드, 상태코드, 헤더 |
| 성능 | 연결 수립/종료 시간 | 응답 시간, 처리 지연 상세 |
| 보안 | IP/포트 기반 제어 | 애플리케이션 레벨 제어 |
Security Implications & 실습
- 레이어 7 트래픽 모니터링에는 사용자 이름, 비밀번호, 쿼리 매개변수, API 키 등 잠재적으로 민감한 정보를 처리하기 위한 보안 고려 사항이 포함됩니다.
- By default, Hubble does not redact potentially sensitive information present in Layer 7 Hubble Flows. ⇒ *허블은 민감정보 직접 편집 X***
- 로그에 찍히는 민감정보를 Cilium에서 가릴 수 있는 기능을 제공
참고 - https://docs.cilium.io/en/stable/observability/visibility/#security-implications
#요청 모니터링
hubble observe -f -t l7
#요청에 민감정보 포함
kubectl exec -it curl-pod -- sh -c 'curl -s webpod/?user_id=1234'
kubectl exec -it curl-pod -- sh -c 'curl -s webpod/?user_id=1234'
# 민감정보 미출력 설정
helm upgrade cilium cilium/cilium --namespace kube-system --reuse-values \
--set extraArgs="{--hubble-redact-enabled,--hubble-redact-http-urlquery}"
#
kubectl exec -it curl-pod -- sh -c 'curl -s webpod/?user_id=1234'
#
hubble observe -f -t l7
✅ 실행 결과 요약
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl exec -it curl-pod -- sh -c 'curl -s webpod/?user_id=1234'
Hostname: webpod-697b545f57-b2xst
IP: 127.0.0.1
IP: ::1
IP: 172.20.2.207
IP: fe80::60b4:70ff:fedb:6d
RemoteAddr: 172.20.0.241:49830
GET /?user_id=1234 HTTP/1.1
Host: webpod
User-Agent: curl/8.14.1
Accept: */*
X-Envoy-Expected-Rq-Timeout-Ms: 3600000
X-Envoy-Internal: true
X-Forwarded-Proto: http
X-Request-Id: 19917c75-4c30-47b1-9b03-4a555857109b
# 민감정보 그대로 노출됨
(⎈|HomeLab:N/A) root@k8s-ctr:~# hubble observe -f -t l7
Jul 25 19:53:37.768: default/curl-pod:50310 (ID:10292) -> kube-system/coredns-674b8bbfcf-2sbw2:53 (ID:5694) dns-request proxy FORWARDED (DNS Query webpod.default.svc.cluster.local. AAAA)
Jul 25 19:53:37.768: default/curl-pod:50310 (ID:10292) -> kube-system/coredns-674b8bbfcf-2sbw2:53 (ID:5694) dns-request proxy FORWARDED (DNS Query webpod.default.svc.cluster.local. A)
Jul 25 19:53:37.769: default/curl-pod:50310 (ID:10292) <- kube-system/coredns-674b8bbfcf-2sbw2:53 (ID:5694) dns-response proxy FORWARDED (DNS Answer TTL: 4294967295 (Proxy webpod.default.svc.cluster.local. AAAA))
Jul 25 19:53:37.769: default/curl-pod:50310 (ID:10292) <- kube-system/coredns-674b8bbfcf-2sbw2:53 (ID:5694) dns-response proxy FORWARDED (DNS Answer "10.96.166.184" TTL: 30 (Proxy webpod.default.svc.cluster.local. A))
Jul 25 19:53:37.771: default/curl-pod:49830 (ID:10292) -> default/webpod-697b545f57-b2xst:80 (ID:2460) http-request FORWARDED (HTTP/1.1 GET http://webpod/?user_id=1234)
Jul 25 19:53:37.774: default/curl-pod:49830 (ID:10292) <- default/webpod-697b545f57-b2xst:80 (ID:2460) http-response FORWARDED (HTTP/1.1 200 3ms (GET http://webpod/?user_id=1234))
# 민감정보 미출력 설정
(⎈|HomeLab:N/A) root@k8s-ctr:~# helm upgrade cilium cilium/cilium --namespace kube-system --reuse-values \
--set extraArgs="{--hubble-redact-enabled,--hubble-redact-http-urlquery}"
Release "cilium" has been upgraded. Happy Helming!
NAME: cilium
LAST DEPLOYED: Sat Jul 26 04:55:45 2025
NAMESPACE: kube-system
STATUS: deployed
REVISION: 3
TEST SUITE: None
NOTES:
You have successfully installed Cilium with Hubble Relay and Hubble UI.
Your release version is 1.17.6.
For any further help, visit https://docs.cilium.io/en/v1.17/gettinghelp
# 재요청
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl exec -it curl-pod -- sh -c 'curl -s webpod/?user_id=1234'
Hostname: webpod-697b545f57-b2xst
IP: 127.0.0.1
IP: ::1
IP: 172.20.2.207
IP: fe80::60b4:70ff:fedb:6d
RemoteAddr: 172.20.0.241:52422
GET /?user_id=1234 HTTP/1.1
Host: webpod
User-Agent: curl/8.14.1
Accept: */*
X-Envoy-Expected-Rq-Timeout-Ms: 3600000
X-Envoy-Internal: true
X-Forwarded-Proto: http
X-Request-Id: 3006845a-138e-41a2-8021-d1ff0eb87452
# 민감정보 마스킹 확인
(⎈|HomeLab:N/A) root@k8s-ctr:~# hubble observe -f -t l7
Jul 25 19:56:27.558: default/curl-pod:55694 (ID:10292) -> kube-system/coredns-674b8bbfcf-p8kth:53 (ID:5694) dns-request proxy FORWARDED (DNS Query webpod.default.svc.cluster.local. A)
Jul 25 19:56:27.558: default/curl-pod:55694 (ID:10292) -> kube-system/coredns-674b8bbfcf-p8kth:53 (ID:5694) dns-request proxy FORWARDED (DNS Query webpod.default.svc.cluster.local. AAAA)
Jul 25 19:56:27.560: default/curl-pod:55694 (ID:10292) <- kube-system/coredns-674b8bbfcf-p8kth:53 (ID:5694) dns-response proxy FORWARDED (DNS Answer "10.96.166.184" TTL: 30 (Proxy webpod.default.svc.cluster.local. A))
Jul 25 19:56:27.560: default/curl-pod:55694 (ID:10292) <- kube-system/coredns-674b8bbfcf-p8kth:53 (ID:5694) dns-response proxy FORWARDED (DNS Answer TTL: 4294967295 (Proxy webpod.default.svc.cluster.local. AAAA))
Jul 25 19:56:27.568: default/curl-pod:52422 (ID:10292) -> default/webpod-697b545f57-b2xst:80 (ID:2460) http-request FORWARDED (HTTP/1.1 GET http://webpod/)
Jul 25 19:56:27.572: default/curl-pod:52422 (ID:10292) <- default/webpod-697b545f57-b2xst:80 (ID:2460) http-response FORWARDED (HTTP/1.1 200 4ms (GET http://webpod/))
Pwru 도구
- 패킷 추적 도구: 리눅스 커널 네트워킹 스택에서 패킷의 경로를 실시간으로 추적
- eBPF 기반: 커널 수정 없이 안전하게 패킷 흐름을 관측
- 네트워킹 디버깅: 패킷 드롭, 지연, 라우팅 문제 등을 세밀하게 분석
- Cilium 생태계: Hubble과 함께 사용하여 완전한 네트워크 가시성 제공
참고
- Packet, where are you? eBPF-based Linux kernel networking debugger : https://github.com/cilium/pwru
- 참고: https://nuguni.tistory.com/97
- 참고: https://cilium.io/blog/2023/03/22/packet-where-are-you/
주요 기능:
- 🔍 패킷 추적: 특정 패킷이 커널의 어느 지점을 통과하는지 추적
- 📊 성능 분석: 각 커널 함수에서의 처리 시간 측정
- 🚫 드롭 분석: 패킷이 어디서 왜 드롭되는지 정확한 원인 파악
- 🔧 실시간 디버깅: 라이브 환경에서 네트워크 문제 즉시 진단
마치며
이번 2주차에서는 Cilium과 Hubble을 통한 네트워크 관측성(Observability) 에 대해 깊이 있게 학습해보았습니다. Hubble의 설치부터 시작해서 실시간 네트워크 모니터링, L7 프로토콜 가시성, 그리고 Prometheus와 Grafana를 활용한 메트릭 수집까지 전체적인 관측 스택을 구축해볼 수 있었습니다.
특히 제가 너무나도 좋아하는 Star Wars 데모를 통한 CiliumNetworkPolicy 실습과 L7 가시성 확보 과정에서, 단순히 네트워크 연결 여부만 확인하던 기존 방식에서 벗어나 HTTP 요청/응답의 상세 내용, DNS 쿼리 패턴, 심지어 민감 정보 마스킹까지 다룰 수 있다는 점이 인상깊었습니다.
실습을 통해 eBPF와 Envoy 프록시가 어떻게 협력하여 마이크로서비스 환경에서의 완전한 네트워크 가시성을 제공하는지 직접 체험할 수 있었고, 이는 운영 환경에서 네트워크 문제를 해결하는 데 매우 유용한 도구가 될 것 같습니다.
앞으로 실무에서 서비스 메시나 마이크로서비스 아키텍처를 다룰 때, 이번에 학습한 Hubble의 관측 기능들을 적극 활용해보고 싶습니다. 특히 성능 최적화나 보안 이슈 해결 시 L7 레벨의 상세한 트래픽 분석이 큰 도움이 될 것 같다는 생각이 듭니다.
긴 글 읽어주셔서 감사합니다 :)
'클라우드 컴퓨팅 & NoSQL > [Cilium Study] 실리움 스터디' 카테고리의 다른 글
| [6주차 - Cilium 스터디] Cilium ServiceMesh (25.08.17) (0) | 2025.08.23 |
|---|---|
| [5주차 - Cilium 스터디] BGP Control Plane & ClusterMesh (25.08.10) (4) | 2025.08.16 |
| [4주차 - Cilium 스터디] Networking - 노드에 파드들간 통신 2 & K8S 외부 노출 (25.08.03) (4) | 2025.08.08 |
| [3주차 - Cilium 스터디] Networking (25.07.27) (0) | 2025.08.02 |
| [1주차 - Cilium 스터디] Cilium 이란? (25.07.13) (2) | 2025.07.18 |