강의 정보
- 러닝스푼스에서 2023년 4월 ~ 6월 간 강의한 쿠버네티스 딥다이브 2기 를 듣고 정리한 내용입니다.
강의 필기록 원본이라 글이 좀 어수선할 수 있습니다.
CNI
- pod ip 할당, pod - pod 통신 관장
- 로그 등의 작업물들은 모두
/var/lib/cni
에 저장함
CoreDNS
ExternalName
: ns 별로 dns 레코드 설정하기는 기능이 있는 것 같다.- CoreDNS 가 장난질 ExternalName 을 설정해서 coredns 가 cname 처리하게하는 것도 가능한 것 같다.
Kube-proxy
역사
1. Userspace mode
- 처음에는 그냥 프록시서버로 시작했다
- 처음에는 pod -> iptables 가 보고 clusterip 면 kube-proxy로 보내서 그놈이 처리하게 했음
- kube-proxy 는 nginx 나 haproxy 와 거의 유사하게 동작
- userspace 모드라고 부르고, 현재는 비활성화되어있다
- pod process 와 kube-proxy process 간의 CPU context switching 때문에 패킷 전송에 딜레이가 걸려 퍼포먼스가 안나왔기 때문
- 이게 그 이슈다: Github/kubernetes: Issue 12682
2. iptables mode
- 이거는 이제 userprocess 를 사용하지 않기 위해 kube-proxy는 iptables 룰만 설정하고, 모든 proxy 작업을 iptables 에게 맡겨버림
- 하지만 이것도 문제가 많다: 노드가 많아지면 많아질수록 iptables rule 이 너무 많아져서 kernelspace 가 너무 커진다
3. IPVS mode
- 이놈이 애초에 lb 용으로 개발된 커널모듈이기 때문에 rule 이 많아도 처리속도가 빠르다
- iptables 에는 svc 로 가는 패킷이면 SNAT 을 해서 iptables 로 보내는 룰만 추가
- kube-proxy 는 iptables 의 위의 룰 하나랑 ipvs 룰들을 추가한다
4. Cilium: kube-proxy-less mode
- Kube-proxy 가 하는일이 너무 많기에 cilium의 간판인 bpf 로 이것을 대체하는 것
잡담
- kube-proxy 가 가지는 node-proxier role (rbac)
- endpoint 와 svc 에 대한 list, watch 권한이 있음
- svc 에 labelselector 를 기입하지 않고 ep 를 수동으로 생성해서 원하는 곳으로 lb 되게 할 수도 있다
- clusterip 를 none 으로 주면 headless 가 되고, 이것은 kube-proxy 의 iptables, ipvs 룰들을 bypass 해서 단순히 “통신” 만 되게 한다
NodePort
- onprem 과 aws elb 에서 모두 유용하게 쓰일 수 있기에 개발됨
- 어찌보면 당연: nodeport 가 있기에 외부 LB 가 그곳으로 패킷을 찌를 수 있음
- iptables rule: kube-service, kube-postrouting
- (kube-service) 트래픽 들어왔을 때 nodeport / hostport 이면 마킹
LOCAL_IN
: k8s 쪽에서 장난치지 않음 (디폴트)externalTrafficPolicy: Local
:LOCAL_IN
-> local process
- externalIP:
- linux 가 하나의 router 니까
- ip 에 맞게 routing 을 하는데
- externalip 가 달려있으면 라우팅을 하지 않고 자기가 직접 처리한다 (L4 로 올려보낸다 인듯)
CNI
VXLAN, IPIP: Overlay Network
- VXLAN: UDP 사용
- 원래 패킷에 VXLAN 패킷을 달고 그 앞에다가 ip, mac 을 새로 다시 설정해서 실제 node 차원에서의 서브넷 네트워크를 사용할 수 있게 (VXLAN Tunneling)
- 하지만 이것은 물리적인 라우터를 조작할 수가 없을 때 사용 (거의 대부분 그렇제 근데)
- 장점은
- 거의 모든 네트워크 환경에서 사용 가능
- 단점은
- daemonset 을 띄워야 한다는 것
- 그리고 encap / decap 비용 + 노드간의 정보 동기화
- daemonset 에 버그가 생기면 tcpdump 하는 것 말고는 답이 없다
Routing table 건들기
- 물리적인 라우터의 RT 를 조작할 수 있으면 이런 것 없이 테이블만 건드려준다
- AWS 가 이짓을 한다
- 어차피 Overlay network 위에 ec2 를 띄우고 거기에 k8s 를 띄우는데 거기에까지 overlay 를 하나 더 깔 이유가 없다
- 그래서 VPC 로 router 들을 직접 조작하되 k8s 에는 overlay 를 깔지 않음
잡담
- 요즘은 kube-proxy 를 다른것으로 대체하는 것이 인기
- Cilium 때문인듯
- 이놈이 nodeport 를 처리하는 기능도 있다고 한다.
- 대역폭?
- CPU 와 MEM 이 합쳐서 25.6Gb/s 대역폭을 제공하는데
- 만약에 10Gb/s 의 대역폭을먹는 작업을 하면
- 예를들어 ssd 에서 뭔가를 가져온다 한다면
- ssd 에서 읽어서 mem에서 cpu로 보내는데 10Gb/s
- cpu -> mem 10Gb/s
- mem -> NIC 10Gb/s
- NIC -> mem 10Gb
- 이렇게 40 을 먹는다고 한다.
- CPU <- 25.6Gb/s -> MEM <-> NIC <-> 인터넷
- ndot:
- 가령 aaa 로 nslookup 을 때리면
- aaa
- aaa.{NAMESPACE}
- aaa.{NAMESPACE}.svc
- aaa.{NAMESPACE}.svc.{CLUSTER}
- aaa.{NAMESPACE}.svc.{CLUSTER}.local
- 이렇게 계층적으로 질의를 하게 되는 시스템
- 가령 aaa 로 nslookup 을 때리면
- 하지만 계층적으로 질의하기 때문에 불필요한 네트워크를 먹게 된다
- 따라서 FQDN 으로 마지막에
.
을 찍어줌으로써 계층적 질의를 막을 수 있고 - 이를 위해 처음부터 FQDN 으로 url 을 지정해주면 효율을 높일 수 있다
- 따라서 FQDN 으로 마지막에
Network 관련 트러블슈팅
ingress-nginx
- annotation 잘못 설정해주면 디버깅하기 힘들다: ic pod 도 정상이고 로그도 별거 없는데 갑자기 welcome to ingress 가 뜨던가 아니면 변경한 설정이 반영이 안되는 등
- 이놈의 rbac: endpoint 를 추적하여 be 로 보낸다
- kube-proxy 가 망가져도 ingress-nginx 는 작동한다
Container network
- Linux 에서 network namespace 를 나눠서 container 의 namespace 를 나누면
- namespace 안에서 가상의 랜카드인
eth0
가 생성되고 - namespace 밖에서는 저
eth0
와 통신할veth
가 생성된다 - 따라서 eth0 와 veth 가 쌍으로 생성되어 트래픽이 namespaced network 밖으로 나온다
- 그래서 tcpdump 를 뜨고 싶을 때 호스트딴에서 veth 에 dump 를 뜨거나
- pod 에서 tcpdump ephermeral container 를 띄워서 (pod 의 container 들은 network namespace 를 공유하고 있으니까) tcpdump 프로세스를 돌릴 수 있다.
- 이건 경장한 꿀팁이다: 뭐라하면 tcpdump 떠서 network 문제가 아님을 확인한 후 network 문제가 아니라 application 문제면 니탓이오를 시전할 수 있다