Notice
Recent Posts
Recent Comments
Link
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

Study_note

AEWS Study 2 주차 (네트워크) 본문

Terraform

AEWS Study 2 주차 (네트워크)

Study_note 2023. 5. 2. 17:29

1주차에 이어서 2주차를 정리해본다.
마찬가지로 구축 내용은 스킵하고 그 외 자세한 내용을 정리한다.
 
VPC CNI
 
네트워킹은 Kubernetes의 핵심 부분이지만 작동 방식을 정확히 이해하기 어렵다
크게 4가지로 고유한 네트워킹을 나타낼수 있으며 특정 리소스를 사용해서 통신을 지원한다..
 
1. 파드 내 컨테이너 통신 -> pause 컨테이너
2. 파드 간 통신 -> cni
3. 파드와 서비스간 통신 -> iptable, kube-proxy
4. 외부와 서비스 통신
 
위와 같이 Container Network Interface 는 k8s 내 파드 간 네트워크 통신 환경을 구성해준다
 
aws는 자체 cni인 AWS VPC CNI를 지원한다
 
AWS VPC CNI의 특징은 다음과 같다.

1. VPC ENI 에 미리 할당된 IP(=Local-IPAM Warm IP Pool)를 파드에서 사용할 수 있음
  -> 위 그림과 같이 vpc cni는 vpc eni를 할당하면서 미리 할당된 IP를 보조 ip로 사용하며 파드에게 바로 할당 가능하다
  -> 하지만 인스턴스 타입 별 eni가 할당 되는 수와 eni 별 할당되는 ip 개수가 다르기 때문에 따로 설정을 해줘야 한다 아래
      에서 추가로 설명한다
 
2. 파드의 IP를 할당해준다, 파드의 IP 네트워크 대역과 노드(워커)의 IP 대역이 같아서 직접 통신이 가능하다.
  -> 아래 그림을 보면 calico 같은 경우 파드와 노드의 ip 대역이 다르고 vpc cni같은 경우 eni자체를 할당 하기 때문에 대역        이 같다 

이렇듯 calico를 사용 시 ip 대역이 다르다면 파드간 통신 시 일반적으로는 헤더에 인캡슐레이션, 디캡슐레이션이 적용되는 오버레이(VXLAN, IP-IP 등) 통신을 하고,  AWS VPC CNI는 동일 대역으로 직접 통신을 하여 레이턴시가 단축되고 경로가 최적화되며 운영하기가 편하게 설정 가능하다. 

3. aws 리소스이기 때문에 aws 리소스와 호환이 가능하다 
예를들어 VPC 와 통합이 가능하여 VPC Flow logs , VPC 라우팅 정책, 보안 그룹(Security group) 을 사용 가능하다.
 
 
노드간 파드 통신은 아래와 같이 snat&dnat이 발생하지않고 별도의 overlay 또한 없이 파드간 직 접 통신이 가능하다

 
하지만 파드에서 외부 또는 외부에서 파드 통신 snat&dnat이 발생하여 xff에 client ip를 할당 받지 못한다.
(물론 ingress에 타겟 타입이나, externaltrafficpolicy: local 지정 시 client ip를 할당 받을수도 있다.)

 
vpc cni특징으로 ip pool에서 ip를 할당 받으면 단점으로는 인스턴스 타입별로 ip할당량이 정해져있어 많은 파드를 생성 하지 못한다라 설명했다. 이에 대한 해결 방안은 크게 두가지로 다음과 같다.
 
우선 deployment를 50개로 늘리면 아래와 같이 몇개는 pending되어 실행이 되지않고 describe 명령어를 통해 확인 시 노드에 파드들이 너무 많아 실행 가능한 노드가 없다라는 에러 문구가 나온다

 

 
1. Prefix Delegation
 
deamoset으로 생성된 aws-node를 확인해보면 Prefix Delegation 설정란이 있는데 현재 false로 구성되어있는걸 true로 변경하면 쉽게 활성화가 된다

 k get ds aws-node -o yaml -n kube-system | k neat

 
아래 명령어를 통해 접두사를 허용하여 더 많은 ip를 할당 가능

kubectl set env daemonset aws-node -n kube-system ENABLE_PREFIX_DELEGATION=true


2. Custom Network
(이 부분은 시도 했지만 먼가 오류가 있어서 정리하고 다시 올릴 예정)
 
---
 
ingress 및 service는 pkos에 정리했기 때문에 중요한 부분만 짚고 넘어가고 다른 2개의 namespace인 ingress를 하나에 ingress로 사용하는것을 정리해본다
 
우선 ingress, service는 iptable을 거치지 않고 바로 파드로 트래픽을 전송할 수 있다
아래와 같이  iptable을 거치지 않기 때문에 nat 발생하지 않고 client ip를 유지시킬수 있으며 조금 더 빠르게 트래픽을 전송할 수 있다.
 
해당 조건은 annotations.alb.ingress.kubernetes.io/target-type를 ip로 지정할 경우만 발생하고 instance로 지정할경우 패킷은 노드로 전송되기 때문에 iptable을 거쳐서 전송된다. 

 
아래와 같이 타겟이 노드가 아닌 파드의 ip인것을 확인 가능

 
다음으로 중요한것은 externalTrafficPolicy 설정이다
 
해당 설정의 특징은 다음과 같다
externalTrafficPolicy : ClusterIP ⇒ 2번 분산 및 SNAT으로 Client IP 확인 불가능 ← LoadBalancer 타입 (기본 모드) 동작externalTrafficPolicy : Local ⇒ 1번 분산 및 ClientIP 유지, 워커 노드의 iptables 사용함
 
즉 externalTrafficPolicy : Local로 설정한다면 아래와 같이 iptables을 사용하지 않고 ClientIP 유지 시키며 한번만 트래픽을 전송 한다.

 
아래와 같이 해당 파드가 없는 노드에 패킷을 전송 시킬수도있다.
앞서 설명한대로 한번만 트래픽을 전송하고 iptable을 거치지 않기 때문에 패킷 손실이 발생할 수 있다
하지만 aws에서 제공하는 alb는 헬스체크 기능이 있기 때문에 파드가 없는 노드는 unhealty 되어 해당 노드에 패킷을 전송하지 않아 패킷 손실 없이 externalTrafficPolicy : Local 특징을 제대로 사용 가능하다.

 
 
 
아래 yaml로 2개의 deployment, service, ingress를 생성해준다

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-tetris
spec:
  selector:
    matchLabels:
      app: tetris
  replicas: 3
  template:
    metadata:
      labels:
        app: tetris
    spec:
      containers:
      - name: webapp
        image: bsord/tetris
        ports:
        - containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  name: service-tetris
spec:
  selector:
    app: tetris
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  type: NodePort

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-tetris
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
spec:
  ingressClassName: alb
  rules:
    - http:
        paths:
        - path: /
          pathType: Prefix
          backend:
            service:
              name: service-tetris
              port:
                number: 80
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-mario
spec:
  selector:
    matchLabels:
      app: mario
  replicas: 2
  template:
    metadata:
      labels:
        app: mario
    spec:
      containers:
      - name: webapp
        image: pengbai/docker-supermario
        ports:
        - containerPort: 8080

---
apiVersion: v1
kind: Service
metadata:
  name: service-mario
spec:
  selector:
    app: mario
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
  type: NodePort

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-mario
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/group.name: "game"
spec:
  ingressClassName: alb
  rules:
    - http:
        paths:
        - path: /
          pathType: Prefix
          backend:
            service:
              name: service-mario
              port:
                number: 80

 
2개의 인그레스(alb)가 생성 된것을 확인 가능하다.

 
위에 yaml 파일에 alb.ingress.kubernetes.io/group.name이라는 설정을 추가해준다
필자는 값을 alb.ingress.kubernetes.io/group.name: "game"로 설정했다
 
하나의 ingress씩 적용해보면 아래와 같이 하나의 인그레서 dns주소가 default에서 game으로 변한게 보이고 2개다 적용이 된다면 alb는 하나로 합쳐지는것을 확인할 수 있다

 
여기서 해당 dns로 접속하면 mario 파드로 접속이되는것을 확인할 수 있다.

그럼 왜 tetris가 아니라 mario로 연결이 될까?
alb listener rule을 보면 아래와 같이 group-name이 설정 되기전에 dns네임으로 target group가 설정되어 있고
우선 순위가 mario가 1순위 tetris가 2순위다 해당 rule은 임의로 생성되어 적용되는것 같다

 
만약 tetris를 1순위로 하려면 어떻게 할까? 
alb.ingress.kubernetes.io/group.order라는 설정으로 우선 순위를 적용할 수 있다.
tetris를 0순위로 적용해보면 다음과 같다
 
우선 alb listener rule은 위와 다르게 tetris의 우선 순위가 더 높은것을 확인 할 수 있다.

해당 dns로 접근하면 mario가 아닌 tetris로 접근하는것을 확인 가능하다.

 
즉 아래 2개의 설정을 통해 2개의 인그레스를 하나의 인그레스로 사용가능하며 listener rule의 우선 순위 통해 더 다양하게 사용 라우팅 가능하다

    alb.ingress.kubernetes.io/group.name: "game"
    alb.ingress.kubernetes.io/group.order: '0'

 

Comments