Overlay / Tunneling Network
aws에서 리눅스 인스턴스를 만드는 상황에서..
또는, 가상화를 사용하는 곳에서는 Overlay / Tunneling Network를 사용하게 된다.
가상컴퓨터를 만들기 위한 Host가 있다.
물리서버가 어떻게 구성되어 있는지에 대해서는 모르지만
BareMetal이 여러 대가 있을 것이고 가용영역, 리전으로 나누어져 있을 것이다. 저 세세하게는 Rack이라는 형태로 Baremetal들이 존재 할 것이다.
그 위에 VM이 올라가는 형태가 될 것이다.
AWS의 경우를 생각해보면 VPC를 만들고 Subnet을 만들 것이다.
결론적으로 VPC는 논리적으로 여러 BM에 걸쳐서 만들어 질 것이다. 이게 논리적 Network, Virtual Network가 여러 가상 머신에 걸쳐서 만들어 질 것이다.
이 때 만약 a subnet을 만들었다고 하면, 어떤 Baremetal들에게 이 서브넷이 형성이 될 텐데 그림으로 그려보면..
결국에는 내부적으로는 각 baremetal에 Virtual switch가 만들어진다.
이 virtual switch는 Network에 연결이 될것이다.
이때 주의할 점은
가상의 네트워크가 존재를 할 것이고 그 라우터를 기준으로 서로 다른 네트워크 대역이 연결 되어 있을 것이다.
이것을 단순하게 그리면 이렇게 될 것이다.
그리고 이렇게는 안돼고
이렇게 Router를 각각에 만들어주는 식으로 되는 것이다.
실제로는 각각의 VM마다 다른 네트워크인것이고 같은 네트워크 인것 처럼 작동을 하게 만드는 것이다.
만약 진짜 같은 네트워크로 만드다고 가정을 하면 Switch로 VM들을 물리적으로 연결하는 것 처럼 구성을 하면 되기는 하겠지만 당연히 이런 구성은 현실적으로 불가능하다.
그래서 여기서 나오는 개념이 보통 각 3개의 VM에 각 3개의 Router들과 Switch로 연결 되어있는 이 개념이 Underlay Network이다.
그리고 이 위에다가 가상의 네트워크를 구성하는 것을 Overlay, Tunneling Network라고 한다.
이런 전체적인 Underlay구성속에서 나만 사용할 수 있는 Network를 뚫어놓는 것이 Overlay Network라고 한다.
다른 관점에서 생각해보면..
docker0를 기준으로 컨테이너를 사용하는 것을 생각해보자.
이렇게 tunneling, overlay를 하는 방법은 아주 많고
보통 이야기하는 VPN Virtual Private Network 또는 Private Link라는 개념이 있다.
인터넷 망은 Public Network이고 이때 우리만 사용할 수 있는 네트워크를 만드는 것을 생각해보자.
이것이 VPN이고 SSL/TLS프로토콜을 이용해서 암호화를 통해 Tunneling을 하는 방법이 있다.
만약 DB는 우리 회사에 놨다고 하더라도 네트워크를 하는 도중에 누군가가 물리적으로 도청을 할 수 있다
이 때도 SSL TLS로 이용해 터널링을 만든다.
물론 터널링을 구성하는 것과
암호화를 구성하는것은 별개이다. 하지만 비슷하게 VPN이나 Private Link에서 취급되기는 한다.
터널링을 구성하는 방법으로는 IPIP, VxLAN, GRE, GEMEVEm VLAN이 있다.~~ VLAN과 VxLAN은 전혀 관계없음~~
Calico도 IPIP와 VxLAN방식으로 터널을 뚫는다.
node1 node2를 생각해보자..
service가 사용하는 네트워크와
pod/container가 사용하는 네트워크 대역이 달랐다
이렇게 같은 네트워크에 있는것 처럼 구성이 된다.
그리고 10.0.0.10에서 10.0.0.11으로 통신을 한다고 생각해보자
SRC = 10
DST = 11
인데 라우터에서 알고있는 네트워크 정보는 192.168.100.100밖에 모르지만 10.0.0.11로 라우팅을 어떻게 할것인가에 대한 문제가 생긴다.
그래서 실제로 가상의 인터페이스에 TUN0라는 인터페이스가 있다.
이때 이 방식이
IPIP와
VxLAN방식이 있다.
IPIP는 IP를 IP에 캡슐화하는 것이다.
이렇게 IP헤더 위에 IP헤더를 만들어서 전송을 하게 되는 것이다.
그리고 이 IP헤더 위에 Ethernet 헤더가 올라가서 SW이 가능하게 된ㄴ 것이다.
그리고 VxLAN은 어떤 방식이냐면
똑같이 IP헤더를 만들고 UDP방식의 VxLAN헤더가 붙는다.
이런 차이점은 있음. VxLAN이 헤더가 더 붙어서 overhead가 있긴하지만 대규모환경에서는 조금 더 잘 작동하는 장점이 있다.
가장 기본적인 개념으로 Encaptulization을 통한 IP통신이라고 생각하면 된다.
Ipaddr show 에 보면
이 cali라는 인터페이스는 컨테이너에 연결하기 위한 인터페이스이다.
veth가 있었는데 지금은 그게 cali임
tunl이게 터널링 인터페이스임
이렇게 볼 수 있고
이게 실제 가상의 네트워크임
이렇게도 구성을 확인할 수 있다.
pidns networkns
ipcns mountns 임
하나는 pod 하나는 서비스 네트워크 네임스페이스임
Pod용 네트워크가 있고 Service용 네트워크가 있어서 Router를 통해 둘이 통신이 되는 것이다.
Kubeproxy를 통해서 Nat table을 만들게 됨
각 노드에도 당연히 이런 구성을 확인할 수 있다.
https://www.youtube.com/watch?v=J1VbZR7j4sI&list=PLoWxE_5hnZUZMWrEON3wxMBoIZvweGeiq
이곳에 보면 calico 의 동작원리를 알려줌
https://velog.io/@200ok/Kubernetes-Calico-CNI-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0
이곳에도 설명을 잘 해놨음
BGP는 대규모 네트워크를 구성할때 사용함
https://kubernetes.io/docs/concepts/cluster-administration/networking/#how-to-implement-the-kubernetes-networking-model
쿠버네티스의 자료에서는..
CNI들의 종류에 대해서 설명이 되어있음
네트워크는 여기까지 간단하게 알아보는 것으로 하고
결국 Vertiual Switch가 같은 네트워크에 있는 것 처럼 사용해야하는데 직접적으로 는 불가능하다보니 Header를 추가적으로 구성하면서 Overlay네트워크를 구성하게 된다.
옛날에 쿠키기반으로 로드밸런싱했던거를 기억해보자
물론 DB에 로그인 정보를 가져다 놓을 수 있지만 너무 DB에 부하가 많이 걸림
그래서 Memcahed와 redis를 사용하기도함
인증정보를 이곳에 저장함
하지만 여기서는 이런 구성이 없기 때문에
여기서는 sessionAffinity를 이용해서 가능하게 함
기본값은 None임 ClientIP라고 하면 IP에 따라서 세션을 고정시켜줌
apiVersion: v1
kind: Service
metadata:
name: myweb-svc-ses
spec:
type: ClusterIP
sessionAffinity: ClientIP
selector:
app: web
ports:
- port: 80
targetPort: 8080
kubectl get svc,rs
kubectl create -f myweb-svc-ses.yaml -f myweb-rs.yaml
kubectl get svc,ep,rs,pod
이렇게하면 exit했을 때 pod가 사라짐
kubectl run nettool -it --image ghcr.io/c1t1d0s7/network-multitool --rm
이렇게 똑같은 Pod로만 연결이 되는 것을 확인 할 수 있다.
이것이 바로 sessionAffinity이다.
이름을 가지고 참조가 가능하다 !
이렇게 포트를 이름으로 참조하는것을 namedport
라고 함
이미지를 만들 때 Web같은 경우 http를 위한 80 https를 위한 443포트를 두 개 열어놓을 수가 있다
이런 구성을 multiport라고 함
kubectl create...
kubectl get svc,ep
kubectl describe svc myweb-svc-multi
kubectl describe ep myweb-svc-multi
기존에 있던 것을 안지워서 이렇게 되어버림
다시 기존은 다 지우고..
하나의 Pod에 svc는 여러 개 연결 될 수 있다.
클라이언트가 있고 서버가 있을 때 서버가 autoscaling을 통해서 확장과 축소를 하는데 이걸 어플리케이션이 어떻게 알것인가? 이 때 로드밸런서에 의해서 연결이 되는데
이런 형태 즉, App이 서버를 찾는 형태를 말함
wp는 mysql을 찾는데
kubectl create -f myweb-rs.yaml -f myweb-svc.yaml
kubectl run nettool -it --image ghcr.io/c1t1d0s7/network-multitool --rm
env
env | grep MYWEB
nettool을 띄움과 동시에 이런 환경변수가 자동으로 추가됨
Pod가 start될 때의 시점에 환경변수를 반영하고 이 후에 만들어진 서비스에 대해서는 반영이 안됨
어플리케이션이 서비스를 찾을 수 있다. 이걸 디스커버리라고 한다.
환경변수를 이용한 Service Discovery..
이거보다 많이 사용하는 것은
DNS를 이용한 Service Discovery
host 커맨드는 dns서버에 질의를 하는거임
DNS에 대해서는 꼭 공부해보세요 - 장성균 강사님
-v
옵션
이 정보는 DNS protocol의 정보이다.
;;는 주석
;는 의미가 있는거
우리는 myweb-svc를 물어봤는데
FQDN fully qulified domain name으로 정제되서 나옴
회사 내부에서 사용하는 도메인 이름은 관습적으로 local을 뒤에 붙인다.
kube-dns(coredns-X 파드)
Service 생성하면 해당 이름으로 FQDN을 DNS 서버에 등록
[서비스 이름].[네임스페이스].[타입].[도메인]
myweb-svc.default.svc.cluster.local
다 같은 결과를 보여줌
이유는
search라는 설정이 있음
myweb-svc만 가지고는 FQDN을 질의할 수 없지만
이런식으로 여러 번의 쿼리를 통해 도메인 이름을 받아오게 된다.
또 한 가지 예시를 보면..
dafault NS에
myweb-svc 가 있는데
dev NS를 만들어서
nettool Pod를 띄워보시오
nettool Pod(dev NS) --> myweb-svc SVC(default NS)
kubectl run nettool -it --image ghcr.io/c1t1d0s7/network-multitool --rm -n dev
1.22버전부터는 이렇게 가능해졌다
이렇게 버전에 따라 다르기 때문에 권장하는 것은
host myweb-svc.default
이렇게 최소한 네임스페이스까지는 써줘야함
같은 이름이 다른 네임스페이스마다 있는 경우엔..
맨 첫 번째 본인의 네임스페이스 먼저 질의를 한다.
가장 좋은 방법은 아무래도 풀네임을 써주는 것이다.
마지막의 .
은 Root Hint라고 한다.
전세계 root hint를 볼 수 있다.
https://www.iana.org/domains/root/files
https://www.internic.net/domain/named.root
이것도 무기임..
똑같은 IP가 여러 개 있는데 그 중에 가장 가까운 것과 연결하는 것
IPv6는 broadcast가 없다고한다...
https://en.wikipedia.org/wiki/Root_name_server
모든 Pod에는 기본적으로 /etc/resov.conf
node local interface가 다 있다
Pod --dns -> 169.254.25.10(node-cache): DNS Cache Server
알고있지는 않지만 다시 재 질의를 보낸다 그러면 응답을 받아서 로컬에 기록을 한다고 한다.
이거를 Cache 서버 또는 DNS Forwarding한다고 한다.
https://kubernetes.io/docs/tasks/administer-cluster/nodelocaldns/
Cache는 TTL만큼만 저장한다.
실제에서는 Kt를 사용하면 168.126.63.1 DNS를 사용한다. 이것도 KT DNS는 Cache서버이다.
또는 DNS forwarder라고 한다.
cd /tc/kubernetes
sudo more coredns-config.yml
cd ..
kubectl get po -A
kubectl get po -A -wide?
kubectl get po -n kube-system nodelocaldns-46r7c -o yaml | more
kubectl get po -A #coredns가 실제dns역학을하고
kubectl get svc -n kube-system
kubectl get ep -n kube-system
정리를 해보면 DNS Cache Server는 conredns SVC(kube-system NS) -> coredns Pod로 질의를 한다..
nodelocal DNS는 애드온이다
만약 노드가 매우 많다면, 그리고 Pod가 1000개씩 된다면..
하지만 controll plane에 coredns는 몇 개 없는데 모든 요청을 direct로 받아야 하니까 이걸 로컬에 캐시에 두고 사용하게 된다.
IT기술의 핵심은 어쩌면 부하분산이 아닐까..?
환경변수를 이용한것과 DNS를 이용한것을 비교해보면 결국 DNS를 사용하는 것이 더 유용하다..
오후에는 외부로 노출시키는 것에 대해서 배울 예정
apiVersion: v1
kind: Service
metadata:
name: myweb-svc-np
spec:
type: NodePort
selector:
app: web
ports:
- port: 80
targetPort: 8080
서비스 지우기 이후
kubectl get rs,po.svc
노드포트의 사용할 포트범위이다
kubespray 또는 kubeadm으로 이 노드포트의 범위를 지정할 수 있다.
다만 기본적으로 0~1023은 well known port이라서 포트가 충돌될 수 있음
https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml
포트 범위에 대해서 3가지로 분류해놨음
외부에 노출 시킬 수있는 포트는 결국 2768개이지만 이건 변경 가능하다
30000-32767
sudo ss -tnlp
sudo ss -tnlp | grep proxy
ssh node2 sudo ss -tnlp | grep proxy
ssh node3 sudo ss -tnlp | grep proxy
이걸 그림으로 그려보면..
NodePort = NodePort + Cluster IP
kubectl get svc
curl 192.168.100.100:31772
curl 192.168.101.100:31772
curl 192.168.102.100:31772
kubectl delete...svc..
vi myweb-svc-np.yaml
kubect .... # 아래 그림
curl 192.168.100.100:31313
이렇게 해서 외부에서 접근이 가능!
중요한거는 우리 고객들에게 우리 서비스는요 192.168.100.100:31313에 들어오세요 하면 아무도 안들어옴
핸드폰의 어플리케이션으로는 상관이 없음
그래서 외부에 로드밸런서를 하나 둘 것이다.
다만 쿠버네티스는 내부에 있는것들을 세팅하지 외부에 있는 것들에 대해서는 세팅하지 못한다.
그래서..
apiVersion: v1
kind: Service
metadata:
name: myweb-svc-lb
spec:
type: LoadBalancer
selector:
app: web
ports:
- port: 80
targetPort: 8080
nodePort: 31313
kubectl get svc
아무리 기다려도 pending이라는 것은 바뀌지 않는다 원래는 여기에 IP가 찍혀야함
Linux밖에 LB이 있어야 제대로 동작할 수 있다.
AWS에서는 ALB나 NLB를 만들어서 백엔드에 해당되는 포트를 연결을 하고 여기에 LB에 부여되는 IP가 EXTERNAL-IP에 찍히게 된다
그래서 못하는거냐?
아님
ㄷㄷ 연기력 무엇
https://metallb.universe.tf/
그래서 사용하는 것이 MTEALLB임
내부의 Pod로 외부의 로드밸런서기능을 하는 것을 띄우는 것이다.
아직 stable버전은 없지만 실제 프로덕션 환경에서 많이 사용하고있음
installation
을 보면 설치하는 방법이 잘 나와있음
그래서 이걸 해도 되고
kubespray에 이미 이 기능이 있다.
이렇게 하고 다시 플레이북을 돌리면 됨
~/kubespray/inventory/mycluster/group_vars/k8s-cluster/addons.yml
...
139 metallb_enabled: true
140 metallb_speaker_enabled: true
141 metallb_ip_range:
142 - "192.168.100.240-192.168.100.249"
...
168 metallb_protocol: "layer2"
...
ansible-playbook -i inventory/mycluster/inventory.ini cluster.yml -b
수정사항 더 있음
이렇게 ip가 부여가 됨
접속을 해보면..
크롬에도 접속을 해보면..
LB=LB+NP+CI
NP=NP+CI
CI=CI
이런식으로 기능이 누적이 되는 형태이다.
다시한 번 간단하게 그림을 그려보면
EKS에서는 ALB나 NLB구성을 할 수 가 있도다..
L7LB를 구현하기 위해 Nginx를 이용할 예정이다
만약 BGP모드로 작동을 시킬려면..
쿠버네티스 외부에 실제 스위치가 있어야한다.
L2.SW
라우터에 ip가 있을것이고 이 ip를 치고 들어오면 speaker가 받고 이후는 똑같음
L2 는 소규모 10대 이하
BGP는 그 이상의 규모에서 사용함..
https://velog.io/@youwins/MetalLB
중국에서 거의 똑같이 따라했다고 추정..
나중에 보겠지만 이 상태로 두면 알아서 ip가 배정되서 크롬으로 접속이 가능해진다고 하심
curl -s 'wttr.in/Seoul?foramt=1'
이런 서비스가 있는데
이런 형태가 REST_API이다
apiVersion: v1
kind: Service
metadata:
name: weather-ext-svc
spec:
type: ExternalName
externalName: wttr.in
kubectl get svc
kubectl run nettool -it --image ghcr.io/c1t1d0s7/network-multitool --rm
host weather-ext-svc
여기에 -v옵션을 붙이면 더 상세하게 알려줌
만약 주소가 바뀌면..
어플리케이션에서는 바꿀 필요가 없어진다.
externalName을 사용하지 않으면 코드를 뒤집어 까야하는데
사용을 하면 그 RDS이름만 나중에 수정해주면 되기때문에 사용한다고 한다..
셀렉터가 없으면 endpoint가 만들어지지 않아서 직접 endpoint를 만들어주어야함
왜 사용하냐하면
svc자체만 만들고 svc가 바라보는 백앤드가 Pod가 없는 다른 무언가 ip와 port를 가지고 있는것은 다 가능하다.
거의 쓸일은 없다..
나중에 볼예정
statefulset이라는 컨트롤러와 같이 쓰이는 서비스이다.
Nodeport를 거치지 않고 바로 svc로 들어가게 함
externalIPs라는 설정이 있다.
svc에 물려져있는 스위치가 있을것이고 직접적으로 연결시키는 것임
이러면 LB와 NP가 필요 없지만 쿠버네티스가 관리하지는 못하는 영역에서 작동하는 것이기 때문에 보안상 위험할 수 있다. 그래서 실제 서비스에서 사용하기에는 무리가 있다고 한다.
다음 주부터는 Ingress L7 loadbalacer를 다룰 예정
그리고 addon 미리 설치를 해오기
한 가지 더
이친구가 LB를 구현해주는 커널의 기능이라고 함
보면 최종적으로 Pod로 라우팅을 시켜준다.
실제로 리눅스의 가상의 네트워크들이 어떻게 구성이 되는지를 볼 수 가 있다....
결국 쿠버네티스도 리눅스 커널을 이용해서 이렇게 동작하는것이기 때문에..