LabHub

블로그

CKA_9_Network

한국어English日本語

본 포스팅은 https://www.udemy.com/course/certified-kubernetes-administrator-with-practice-tests 강의와 https://kodekloud.com/의 내용을 공부하며 기록한 내용입니다.

201 Switching Routing

Switch는 동일 네트워크 안에있는 것들을 연결해준다.

Network

Router는 두 개 이상의 분리된 네트워크를 연결해준다. 하나의 network에서 다른 network로 패킷이 이동할 때는 Gateway라는 것을 거쳐가는데, 이 것은 Router에 연결된 주소를 의미한다.

Network

kernel route table은 아래와 명령어로 확인할 수 있다.

root@latte01:~# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.219.1   0.0.0.0         UG    100    0        0 enp2s0
169.254.0.0     0.0.0.0         255.255.0.0     U     1000   0        0 enp2s0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.219.0   0.0.0.0         255.255.255.0   U     100    0        0 enp2s0

접근하고자하는 모든 ipaddress를 명시하는 대신 0.0.0.0을 입력하여 모든 network를 표시할 수 있다.

Network

만약 외부로 나가는 것과, 내부 network로 나가는 router가 분리되어있다면 routing table에 별도로 지정할 수 있다.

Network

Linux machine을 router로 setup하려면 어떻게 해야하나? 하지만 아래와 같이 B의 2개의 network interface를 부여한 뒤, A에서 B로 ping을 하면 정상적으로 ping이 돌아오지 않는다. 그 이유는 Linux에서 보안 문제로, default로 packet을 forward하는 것을 막아두었기 떄문이다.

Network

B machine에서 echo 1 > /proc/sys/net/ipv4/ip_forward를 통해 forward를 하도록 설정할 경우 정상적으로 router처럼 동작하게 된다. reboot 해도 동일한 설정을 유지하려면 /etc/sysctl.conf에 이 net.ipv4.ip_forward =1을 설정하면 된다.

202 DNS

/etc/hosts에 Host B를 db라고 등록하면 ip대신 문자로 된 이름을 사용할 수 있게된다. /etc/hosts를 local nameserver(dns) server라고 부른다. 하지만, 실제로 db라고 불리는 서버의 hostname은 db가 아닐 수 있다. 또한 서버수가 많아지거나, ip 주소가 변경되는 상황이 생길 경우에는 더 관리가 어려워진다.

Network

ip주소와 hostname을 mapping하여 관리하는 서버를 DNS서버라 한다. 모든 서버는 /etc/resolv.conf라는 파일에 nameserver를 등록하고 사용한다.

Network

nameserver를 이용한다고 해서 local /etc/hosts파일을 이용하지 못하는 것은 아니고 동일하게 사용가능하다. ip -> hostname mapping정보를 찾을 때 dns서버보다 /etc/hosts파일 내용을 우선적으로 찾는다. 이 순서는 /etc/nsswitch.conf에 hosts 에 등록되어있다. files dns가 default로 되어있는데 이렇게 되어있다면 /etc/hosts를 먼저 찾는다는 의미다.

8.8.8.8 은 google에서 운영중인 유명한 nameserver이다. 다수의 nameserver를 이곳에 정의할 수 있다.

만약 DNS서버에서 apps.google.com을 찾는다고 하면 아래같은 과정으로 dns tree를 따라가서 ip주소를 가져오게 된다. 한번 가져왔다면 이를 local에 caching해두고 재사용한다.

Network

IP를 Hostname으로 바꾸는 것을 A type record라고 한다. Alias(별칭)을 갖도록 하는 것은 C name이라고 한다.

Network

nslookup <domain_name>을 통해서 nameserver와 ip를 알아낼 수 있는데 주의해야할 것은 nslookup은 /etc/hosts를 찾지 않는다는 것이다. 이 때문에 실제 local에서의 network동작은 달라질 수 있음을 명심해야한다.

dig도 nameserver를 찾는 좋은 tool이다.

nslookup www.google.com
dig www.google.com

204 Network Namespaces

Container에는 별도의 Routing Table과 ARP Table이 존재한다. network namespace가 별도로 존재하는 것이다.

Network

신규 network namespace를 생성하기 위해서는 ip netns add <namespace_name>을 입력하면 된다. ip ns명령어로 생성된 namespace를 확인할 수 있다.

Namespace 내부에서 ip 명령어를 사용하려면 아래와 같이 하면 된다. link명령어 입력시 host에서와 달리 loopback link 외에는 확인되지 않는다. arproute명령어도 동일하다.

Network

새로운 namespace는 외부로의 연결이 설정되어있지 않기 때문에, 다른 namespace와의 통신을 위해서는 network 연결을 설정해야하고 이 연결과정은 물리적인 cable을 연결하는 것(virtual cable)과 비슷하다.

Network

설정이 완료되면 아래처럼 arp table을 조회했을 때 상대방의 정보가 들어있다. 하지만 host의 arp table에는 이와 관련된 정보가 전혀없다.

Network

만약 2개가 아니라 그 이상의 Namespace가 존재하면 어떻게 해야하는가? 이 경우는 virtual switch를 만들어야한다. Linux Bridge나 Open vSwitch가 가장 유명하고, 이번에는 linux bridge를 알아본다.

Network

linux bridge를 생성하기 전에 이전에 생성했던 red와 blue의 virtual cable을 제거한다. ip -n red link del veth-red를 통해 제거할 수 있다.

아래와 같은 방법으로 linux bridge에 namespace를 연결하면 Namespace끼리 통신을 할 수 있다.

Network

Network

Bridge 와 Host 사이의 연결을 설정하려면 어떻게 해야할까? Bridge에 ip 를 부여하면 된다.

Network

이렇게 생성한 4 개의 namespace는 private한 network이기 때문에 바깥과 통신이 되지 않는다.

Network

아래와 같이 blue의 routing table에 gateway로 bridge network를 설정해준다.

Network

그리고 아래명령어로 192.168.15.0/24로 들어오는 packet을 host의 Packet인 것으로 설정하면 ping이 가능하다.

Network

마지막으로 default gateway까지 설정해주면 완료된다.

Network

외부에서 private network로 접근하려면 2가지 방법이 있다. NAT를 이용하거나 아니면, port fowarding을 이용하는 방법이다.

Network

206 Docker Networking

docker는 내부적으로 docker0라는 bridge를 만들어서 namespace간에 그리고 host machine과의 통신을 하는데 사용한다. 이는 docker network ls 명령어로 확인이 가능하다.

Network

Network

docker로 container를 띄우면 namespace가 하나 생긴다고 생각하면 된다. 그리고 그 namespace와 docker0 bridge는 이전에 살펴봤던 virtual cable로 연결된다.

Network

Network

port forwarding도 이전에 살펴봤던것과 비슷하게 iptable에 NAT Rule을 추가하여 수행한다.

Network

port forwarding이 설정된뒤 iptables -nvL -t nat명령어로 iptable을 확인하면 iptable에 DNAT이 추가된 것을 확인할 수 있다.

Network

207 CNI

이전에 Network Namespace를 생성해서 network를 연결하는 과정과 docker에서 Network를 연결하는 과정을 함꼐 알아봤다. 그리고 그 두가지는 매우 흡사하다. rkt, mosos, kubernetes도 동일한 문제를 해결해야한다. CNI(Container Network Interface)는 Kubernetes에서 container 간의 network 통신을 위해 구현해야할 것들을 정의한다. 따라서 CNI에 맞게 구현된 plugin은 어떤 runtime에 상관없이 잘 작동하게 된다.

Network

Docker는 CNI standard를 준수하지 않고 독자적인 CNM(Container Network Model)이란 것을 갖고있어서 CNI(flannel, weaveworks)를 사용할 수 없다.

Network

etcd가 Process가 사용중인 port 확인하는 법

$ netstat -anp | grep etcd
tcp        0      0 192.5.203.6:2379        0.0.0.0:*               LISTEN      3644/etcd           
tcp        0      0 127.0.0.1:2379          0.0.0.0:*               LISTEN      3644/etcd           
tcp        0      0 192.5.203.6:2380        0.0.0.0:*               LISTEN      3644/etcd  
...

2379 Port는 etcd가 모든 kubenetes Control Plain과 소통할 때 사용하는 포트고 2380은 peer connection을 위해 사용하는 port다.

212 Pod Networking

Kubernetes는 모든 pod에 고유한 IP address를 부여하고, 모든 pod 끼리 NAT 없이 통신이 가능한 model을 만들었다. 이 Network Model을 만들기 위해서 Kubernetes는 어떤 문제들을 해결해야 했을까? CNI standard를 준수하여 만들어진 다양한 network plugin들이 이것들을 해결했다.(Flannel, Weave net, Cilium)

Network

우선 모든 node에 bridge network를 만들고, pod가 생성될 때마다 network namespace와 bride로 연결되는 veth를 생성한다. 이렇게 하면 하나의 node 안에 있는 pod끼리는 통신이 가능한 상태가 된다. 하지만 다른 node에 있는 pod와의 통신은 불가능하다.

Network

각각의 node의 Routing Table에 gateway를 아래와 같이 설정하면 다른 node와의 network communication도 문제없는 상태가 된다.

Network

개념적으로는 크게 복잡하진 않지만, 이를 수백 수천대의 node가 있는 환경의 kubernetes cluster에 적용하려면 쉽지 않다. 하지만 CNI가 이를 해결해주기 때문에 크게 걱정하지 않아도 된다. CNI는 복잡한 script를 ADD, DELETE로 그룹화하여 관리하고 실행할 수 있도록 제공한다.

이 스크립트들은 /etc/cni/net.d/net-script.conflist/opt/cni/bin/net-script.sh 에 있고 사용자가 직접 이 script를 사용할 수도 있다.

Network

213 CNI in Kubernetes는

network-plugin은 kublet.service 에서 설정 가능하다. cni의 실행 binary들은 /opt/cni/bin에 위치해있고, 설정 파일은 /etc/cni/net.d 하위에 있다.

Network

실제로 bridge network를 구성하는데 사용되는 config 파일을 보면 아래와 같이 구성되어있다.

Network

Bridge network의 범위를 알고싶을 때는 ip link를 통해서 찾은 bridge network 이름을 ip addr show로 조사하면 된다.

master-node
$  ip addr show weave
4: weave: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1376 qdisc noqueue state UP group default qlen 1000
    link/ether be:b5:e6:4f:f0:c1 brd ff:ff:ff:ff:ff:ff
    inet 10.244.0.1/16 brd 10.244.255.255 scope global weave
       valid_lft forever preferred_lft forever
worker-node
$ ip addr show weave
4: weave: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1376 qdisc noqueue state UP group default qlen 1000
    link/ether aa:be:68:65:bf:37 brd ff:ff:ff:ff:ff:ff
    inet 10.244.192.0/16 brd 10.244.255.255 scope global weave
       valid_lft forever preferred_lft forever

223 Service Networking

Service가 배포되면 어떤 node에 배포되든 상관없이 다른 서비스에서 이용할 수 있어야한다. 이를 위해서 kubernetes에선 서비스에 Cluster IP 라는 것을 생성한다. 이로인해 실제 pod의 IP가 바뀌더라도 service를 사용하는 입장에서는 Cluster IP를 사용하기 때문에 Seamless하게 운영할 수 있는 것이다. 클러스터 외부에서 IP에 접근해야하는 경우, Cluster IP는 사용할 수 없는데, 이때는 Node Port라는 service를 통해 외부에 Endpoint를 제공할 수 있다. 이것을 가능하게 하는 것은 kube-proxy이다. 그리고 cluster-ip의 range는 kube-api-server를 시작할 때 argument로 입력하는 값이다.

Network

Network

그리고 실제로 iptable에서 service명을 조회해보면 cluster ip와 실제 pod의 ip가 DNAT로 설정되어있는 것을 확인할 수 있다.

Network

ip addr로 bridge의 Network Range를 확인할 수 있다.

226 DNS in kubernetes

Kubernetes 내부에서도 DNS를 이용가능하다. Serivce를 생성하면 Cluster IP가 생성되고 이 Cluster IP는 Kube DNS에 서비스 명으로 등록된다. 다른 pod에서 Cluster IP가 아닌 호스트명(web-service)으로 접근하여도 문제없이 접근 가능해진다. 물론 같은 namespace에 있는 경우를 말한 것이고, 다른 namespace에 있는 pod에서 접근한다면 web-service.apps로 접근하여야 한다.

Network

Network

Service가 아닌 pod는 DNS에 자동으로 등록되지 않는다. 설정을 통해 등록할 수 있는데 이 경우 hostname에 ip주소에서 .-로 치환한 것이 hostname으로 설정된다.

Network

227 Core DNS in kubernetes

core-dns는 kube-system namespace에 실행되는 Replica Set(Deployment)이다. /etc/coredns/Corefile에 core-dns에 관한 설정을 할 수 있다. core-dns의 설정 값은 configmap에 저장되는데 이 값 또한 수정 가능하다.

Network

core-dns는 kube-dns라는 name으로 cluster내부에서 접근가능한 endpoint를 만들고, 모든 pod의 /etc/resolv.conf에는 nameserver에 이 dns서버의 ip주소가 자동으로 기입된다.

Network

host명만 입력해도 FQDN(Fully Qualified Domain Name)을 얻을 수 있는데 그 이유는 이전에 살펴봤던 /etc/resolv.conf 내부에 있는 search에 설정된 상위 도메인 때문이다.

Network

pod 안에서 nslookup한 결과를 local에 복사하기

kubectl exec -it hr -- nslookup mysql.payroll > /root/CKA/nslookup.out

230 Ingress

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-ingress
  namespace: critical-space
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
  rules:
  - http:
      paths:
      - path: /pay
        pathType: Prefix
        backend:
          service:
           name: pay-service
           port:
            number: 8282

댓글

아직 댓글이 없습니다.

로그인하면 댓글을 쓸 수 있습니다