From 5b232e529cd6e175be7895863e6bae89a721cbe5 Mon Sep 17 00:00:00 2001 From: idoyo7 Date: Mon, 6 Jan 2025 10:47:19 +0000 Subject: [PATCH] add cni & csi --- SUMMARY.md | 2 + posts/chapter5/EKS_Network.md | 200 ++++++++++++++++++++++++++++ posts/chapter6/EKS_Storage.md | 240 ++++++++++++++++++++++++++++++++++ posts/chapters.md | 2 + 4 files changed, 444 insertions(+) create mode 100644 posts/chapter5/EKS_Network.md create mode 100644 posts/chapter6/EKS_Storage.md diff --git a/SUMMARY.md b/SUMMARY.md index 4dc4fcc..e1d7fa3 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -6,6 +6,8 @@ * [Kubernetes란](posts/chapter2/About_Kubernetes.md) * [Terrform으로 EKS 생성하기](posts/chapter3/EKS_Terraform.md) * [Kuberentes 기본 리소스](posts/chapter4/Kuberentes_Resources.md) + * [Kubernetes & EKS 네트워크](chapter5/EKS_Network.md) + * [Kuberentes & EKS 스토리지](chapter6/EKS_Storage.md) * [TIPS](posts/tips.md) * [Docker 이미지 경량화](posts/tips/Docker_Optimization.md) diff --git a/posts/chapter5/EKS_Network.md b/posts/chapter5/EKS_Network.md new file mode 100644 index 0000000..0d2a4db --- /dev/null +++ b/posts/chapter5/EKS_Network.md @@ -0,0 +1,200 @@ + +### 네트워크 + + + +컨테이너 네트워크 인터페이스(CNI, Container Network Interface)는 컨테이너의 네트워크를 설정하고 관리하기 위한 표준입니다. CNI는 컨테이너 오케스트레이션 시스템(예: Kubernetes)과 다양한 네트워크 구현체 간의 인터페이스를 제공하여, 컨테이너가 네트워크에 연결될 수 있도록 합니다. + + + +사실 컨테이너 표준이 제정되면서, 네트워크의 표준인 + + + +Container Networking Interface 규격을 만족시키는경우 컨테이너간 네트워크를 광범위하게 활용할수있 방향으로 이어져갔습니다. + + + +https://github.com/containernetworking/cni + + + +## 서비스 + + + +쿠버네티스 POD을 내부/외부로 통신하기위해서 서비스라는 컴포넌트가 존재합니다. + + + +서비스는 ClusterIP, NodePort, LoadBalancer 가 있습니다. + + +![image.png](https://study.montkim.com/posts/chapter4/images/image.png) + + + + + +전에 간략하게 이야기했던, Probe같은 헬스체크들을 통해서 로드밸런싱 대상들을 특정 할 수 있습니다. + + +![image.png](https://study.montkim.com/posts/chapter4/images/image2.png) + + + + +### ClusterIP + + + + + +![image.png](https://apimin.montkim.com/cdn/blog/images/PKOS/2network/ClusterIP.png) + + + +ClusterIP는 service를 통해 내부 endpoint로 부하분산을 해줍니다. +외부노출은 없지만 core-dns 등을 통한 내부통신을 위한 서비스이거나, + +(thanos query의 endpoint로 내부 dns 등록된거 사진) + +ingress controller같은 서비스를 통해 외부 노출이 가능합니다. + +![image.png](https://study.montkim.com/posts/chapter4/images/image1.png) + +여기선 ingress controller만 어떻게든 외부노출이 되어있다면, 해당 규칙을 통해서 내부적으로 선언된 svc들을 ingress controller에 연결하여 배포한 파드들을 정해진 규칙으로 (ingress에 선언한) 외부로 노출 할 수 있습니다. + +아마도, Service 라는 컴포넌트가 ECS같은 컨테이너 자체를 실행만 하는것 이상으로, 쿠버네티스라는 플랫폼 내부적으로 컨테이너들을 더 잘 묶을수 있는 단위라고 생각합니다. + +꼭 Public 하게 오픈이 되어있지 않아도 Internal LB를 만드는것과 동일한 기능을 플랫폼에서 처리해주는 기능이라고 생각하시면 될것같습니다. + + +### NodePort + +![image.png](https://apimin.montkim.com/cdn/blog/images/PKOS/2network/NodePort.png) + + +NodePort는 pod가 할당되어있는 node의 특정 포트를 open하여 외부로 통신이 가능하게 하는 서비스 타입입니다. + +동작식방이 조금은 복잡하지만, 간단하게 설명하자면 +- 모든 노드가 정해진 노드포트 대역으로 open +- 클러스터 외부 -> NodePort로 요청을 전달할시, 정해진 Service 규칙에 의해 (알아서...?) 대상 Endpoint로 전달 + +쿠버네티스 클러스터 기준으로, 클러스터 외부 <-> 내부를 연결해주는 통로의 기본입니다. + +쿠버네티스의 Sercice 를 노출하는 입장에선, +아무 노드에 해당 NodePort로 던져도, 실제 Service 뒤에 연결된 Pod 까지 요청이 도달합니다! +그치만, 실제 pod가 배포되어있지 않은 노드로 네트워크 요청을 하게되면 실제 pod가 있는 노드에 요청을 재차 하는 방식으로 구성되어있어 추가 hop이 발생 될 수 있습니다. + +예시) 노드 2에 어플리케이션이 배포되어있음. +``` +graph LR +    Client[Client] +    subgraph Kubernetes Cluster +        subgraph Node1 +            direction TB +            NodePort1[NodePort:30001] +        end +        subgraph Node2 +            direction TB +            NodePort2[NodePort:30001] +            AppPod[Application Pod] +        end +    end + +    Client -->|Request| NodePort1 +    NodePort1 -->|Forward to Node2:30001| NodePort2 +    NodePort2 -->|Forward| AppPod +``` + +구체적으로 노드레벨 밑에서 일어나는 과정을 살펴보려면, CNI 자체의 동작방식을 보기도 해야하는데 +관심이 있으시다면 Life Of Packet 시리즈를 추천드립니다. + +커피고래님의 블로그에 잘 번역되어있는 수준 높은 게시글이 있으니 추천드립니다. +[패킷의삶1](]https://coffeewhale.com/packet-network1) +[패킷의삶2](https://coffeewhale.com/packet-network2) +[패킷의삶3](https://coffeewhale.com/packet-network3) +[패킷의삶4](https://coffeewhale.com/packet-network4) + + +### LoadBalancer + +![image.png](https://apimin.montkim.com/cdn/blog/images/PKOS/2network/LoadBalancer.png) + + +LoadBalancer는 일반적으로 클라우드에서 사용되는 방법으로 +서비스를 외부에 노출시키는 표준 방법입니다. + +Onpremise 에서는 MetalLB 나 LoxiLB같은 프로바이더들을 이용해서 SW LB를 생성하기도 합니다. +결국 인입점을 조금 더 깔끔하게 관리해준다는 차이로 이해를 하시면 될것같습니다. +- Service Type : Loadbalancer를 생성하면 ClusterIP, NodePort, LoadBalancer IP가 모두 부여됩니다. + +클러스터 기준으로 외부와의 인입점을 어떤식으로 갖게되는지에 대해 신경을 쓴 부분이라고 보입니다. + + +그치만 AWS 에서 사용하는 EKS의 CNI는 AWS VPC CNI라는 자체적인 CNI로, +클러스터 자체의 경계보다, VPC 내부에서 공통적으로 통신이 가능한 IP가 부여된다는 점이 특징이죠. + +![image.png](https://apimin.montkim.com/cdn/blog/images/AEWS/week2/EKS_Networking/Untitled.png) + + 바로 pod가 VPC와 동일한 대역의 주소를 갖는다는것입니다. + + +기존 CNI들은 POD들간 통신을 할 때 POD1에서 POD2로 통신을 시도할떄 +노드간 통신을 위해 패킷 오버레이가 발생해 한번의 오버헤드가 발생됩니다. + + +![image.png](https://apimin.montkim.com/cdn/blog/images/AEWS/week2/EKS_Networking/Untitled1.png) + +하지만 AWS VPC CNI의 경우 POD 에 물리적인 ENI에서 IP를 직접 할당받아 Pod의 네트워크 IP대역과 워커의 네트워크 IP대역이 동일하게 설정됩니다. + +이렇게될경우 pod들간 통신에서 오버헤드가 줄어듭니다. + +![image.png](https://apimin.montkim.com/cdn/blog/images/AEWS/week2/EKS_Networking/Untitled2.png) + + +구체적으로 동작을 다 까볼순 없겠지만, 이러한 방식을 채택한 후로 +생성하는 인스턴스의 사이즈에 적당히 비례한 POD IP 생성제한이 같이 걸리기도 합니다. +물론 그 규칙을 (합법적인 방법으로) 우회하는 방법이 있기야하지만, 그럴 이유는 없긴합니다. +노드에 POD를 많이 생성하고싶다면 더 큰 노드를 생성하라고 권장드릴것 같습니다. +(동작방식을 이해하고자 한다면, 다른 게시물의 내용을 참조) +[VPC CNI LIMIT](https://montkim.com/pkos-network) + + + +### AWS LB Controller + +AWS에서 아주 잘만들어 제공해주는 Manged 서비스(?) 인 LB입니다. + + +![image](https://apimin.montkim.com/cdn/blog/images/AEWS/week2/EKS_Networking/Untitled21.png) + +AWS의 ELB에 존재하는 컴포넌트중, ALB와 NLB를 메인으로 관리해주는 애드온입니다. + + +NLB : 쿠버네티스 관점에서의 L4로 관리하는 Service Type : Loadbalancer를 생성 +ALB : 다른 시스템과 잘 연계하여, HTTP (경로포함한 L7) 등의 정책을 설정하여 +쿠버네티스 관점에서 L7컴포넌트인 Ingress 로 생성, 관리 + + +#### 심화과정 + +Instance 모드 +- 경우 해당 노드로 트래픽이 도달 후 다시 POD를 찾아서 전달하는 방식으로 이를 위해서는 NodePort를 활용하며, LB에는 노드의 대표 IP가 등록됩니다. +IP 모드 +- 노드의 대표 IP를 거치지 않고, 바로 Pod의 IP로 트래픽을 전달하며, 따라서 Pod IP가 직접 LB에 등록됩니다. + +심화된 기능을 위해 LB -> [POD_IPs] 다이렉트로 호출하는 형태의 구조도 가능합니다. +점점 단순하게 네트워크 구조를 가져갈수록 빠르고 안전한 구조의 설계가 가능하죠 + +#### ALB 생성하기 +쿠버네티스의 정책인 `AdmissionControl`을 이용하여 +Ingress 생성 -> LB 생성 호출 -> 쿠버네티스의 리소스 - AWS ALB에 연결 +순서대로 연결이 됩니다. + +ALB 설정에 필요한 설정들은 Ingress 의 Annotation에 추가하여, AWS LBC에서 생성 호출하는 ALB에 관련 configuration들을 넣을 수 있습니다. + +[Configurations](https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.11/guide/ingress/annotations/) + + diff --git a/posts/chapter6/EKS_Storage.md b/posts/chapter6/EKS_Storage.md new file mode 100644 index 0000000..3020925 --- /dev/null +++ b/posts/chapter6/EKS_Storage.md @@ -0,0 +1,240 @@ + + +컨테이너는 종료되면 안에있던 파일 스토리지가 증발하는 ephemeral 한 스토리지를 갖고있습니다. + +하지만 상태의 저장을 위해 stateful 한 어플리케이션을 보장하기위해 파드의 라이프사이클과 무관하게 지속되는 스토리지가 필요했습니다. + +이를위해 컨테이너 표준이 적립되면서 컨테이너에서의 스토리지 표준에 대해 정립이된게 바로 CSI 입니다. + + + +### CSI란 + + +[CSI_SPEC](https://github.com/container-storage-interface/spec) + + + + +쿠버네티스에서는 볼륨에 대한 선언인 Persistent Volume Claim 과 실제 볼륨인 Persistent Volume 을 구분해서 사용합니다. + +이러한 각 스토리지에서 제공되는 CSI Driver를 이용하여 쿠버네티스 pod에서 디바이스들을 마운트 할 수 있습니다. + +![image](https://apimin.montkim.com/cdn/blog/images/AEWS/week3/EKS_Storage/Untitled.png) + +노드에 Daemonset에서 + + + +CSI에서 볼륨 생성하는 과정 + +![image](https://apimin.montkim.com/cdn/blog/images/CSI/Untitled1.png) + +볼륨이 필요한 어플리케이션의 스토리지 요청을 할때 다음과 같은 과정이 일어납니다. +1. PVC 생성 +2. 볼륨이 존재하지 않을경우 동적 프로비저닝 실행 +3. 외부 볼륨 프로바이더에서 볼륨 생성완료후 응답 +4. PV 형태로 리소스(세부 볼륨) 정보 생성완료 +5. PV를 어플리케이션이 구동될때 마운트 + +구체적인 연결관계는 차이가 있을 수 있지만, + + + +#### 동적 프로비저닝 +https://kubernetes.io/ko/docs/concepts/storage/dynamic-provisioning/ + +해당 Volume Controller에서 Storage Provider 측으로 스토리지 볼륨생성요청을 할 권한을 부여하는 정책 +볼륨 자체의 요구인 PVC 생성 후, PVC에서 사용할 PV가 없을경우 프로비저닝하는 역할 + +StorageClass라는 쿠버네티스 객체를 생성하여 해당 파라미터에 맞는 요청이 들어올때, 맞는 PV 생성을 Storage Service에 요청합니다. + + + +### Storage On AWS + +AWS의 Storage Service 를 호출해서 EKS에서 사용하는 형태는 다음과 같습니다. + +![image](https://apimin.montkim.com/cdn/blog/images/AEWS/week3/EKS_Storage/Untitled1.png) + +CSI 규격에 맞는 Controller와 볼륨을 붙이기 위한 Daemonset의 형태로, 이루어져있습니다. + + + + +#### EBS + +EBS CSI Driver의 형태로 제공되는 EKS Addon의 일부입니다. +해당 애드온을 이용해 AWS의 Block Storage 를 생성, 사용 할 수 있습니다. + +![image](https://apimin.montkim.com/cdn/blog/images/AEWS/week3/EKS_Storage/Untitled5.png) +출처 : https://malwareanalysis.tistory.com/598 + + +물론 CSI Controller에서 AWS측에 API 요청을할때, AWS 에서 필요로하는 적절한 권한을 가진 상태에서의 요청을 요구하기때문에 권한 설정이 필요합니다. + +- 이 부분의 설명은 별도 인증/인가 섹션에서 다룰 예정입니다. + + + +#### EBS StorageClass 설정 + +EBS CSI Driver를 설정하면 Default로 GP2 type의 Storageclass가 생성됩니다. + +이 Storageclass를 이용해 Block Storage를 생성 할수도 있지만, 조금 더 성능이 좋은 GP3을 이용한 StorageClass 를 만들어보겠습니다. + +``` +kind: StorageClass +apiVersion: storage.k8s.io/v1 +metadata: +  name: gp3 +allowVolumeExpansion: true +provisioner: ebs.csi.aws.com +volumeBindingMode: WaitForFirstConsumer +parameters: +  type: gp3 +  allowAutoIOPSPerGBIncrease: 'true' +  encrypted: 'true' +  fsType: xfs # 기본값이 ext4 +``` + + +기본적인 예시입니다. +이제 해당 StorageClass인 GP3 형태로 생성요청을 하게될경우 PV 가 GP3으로 생성이 됩니다. + + +``` +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: +  name: ebs-claim +spec: +  accessModes: +    - ReadWriteOnce +  resources: +    requests: +      storage: 4Gi +  storageClassName: gp3 +``` + +`나는 4Gi 의 GP3 볼륨이 필요해` 라는 요청에 대한 스토리지 명세파일입니다. + + +``` +apiVersion: v1 +kind: Pod +metadata: +  name: app +spec: +  terminationGracePeriodSeconds: 3 +  containers: +  - name: app +    image: centos +    command: ["/bin/sh"] +    args: ["-c", "while true; do echo \$(date -u) >> /data/out.txt; leep 5; done"] +    volumeMounts: +    - name: persistent-storage +      mountPath: /data +  volumes: +  - name: persistent-storage +    persistentVolumeClaim: +      claimName: ebs-claim +``` + +해당 Storage를 사용하는 임시 어플리케이션을 띄워보겠습니다. + +위에서 생성한 ebs-claim이라는 pvc의 정보에 맞는 볼륨을 마운트하면 된다는 의미인데, 실제로 생성된 pv 정보를 직접 어플리케이션 배포 코드에서 다루지 않고있습니다. + +[image](https://i.namu.wiki/i/XDVrtVbJXtd059R9AP5CZlgU20ADGGN5tgzuT30Fj393vb08IGrLDOxTOfIe15ZdU0nAVsvFcBiAPe3PeHi_aQ.webp) +실제로 PV 자체에 대한 정보는 알 필요 없다 +처럼 뒤에 쿠버네티스 플랫폼 - Storage 제공자 측에서 관리할 영역이지, 해당 배포파일에서 관리해야할건 또 아니라는 이야기이기도 합니다. + +### EFS + +efs 시스템은 AZ구분이 없는 스토리지로, 다중마운트를 제공하는 “공용 파일시스템” 에 적합한 종류의 파일시스템입니다. +[image](https://apimin.montkim.com/cdn/blog/images/AEWS/week3/EKS_Storage/Untitled16.png) + +Block 자체에 대한것이 아닌, 매니지드 File System에 대한 이야기이니, 동시성이나 확장에 대한 규약은 기본적으로 AWS 에서 제공하는 최대치와 동일합니다. + +결국 AWS에서 제공되는 볼륨을 그저 갖다 쓰는것 뿐이니깐요 + +EFS는 그중에서 NFS 기반으로 이루어진 Multi-AZ를 지원하는 파일시스템입니다. +쿠버네티스 관점에서 위의 EBS와 다른점은, 내부적으로 ReadWriteMany 형태로 선언해서 여러개의 Pod에 마운트 할 수 있다는 이야기기도 합니다. + + +[multi-pod-sample](https://github.com/kubernetes-sigs/aws-efs-csi-driver/tree/master/examples/kubernetes/multiple_pods) + +aws efs csi driver 에서 제공되는 example 코드를 기준으로 살펴보겠습니다. + +``` +kind: StorageClass +apiVersion: storage.k8s.io/v1 +metadata: + name: efs-sc +provisioner: efs.csi.aws.com +``` + + +storage class 자체의 구성은 굉장히 단촐합니다. +기존에 생성된 efs 를 그대로 이용하는것뿐 별도의 파라미터들이 필요로하진 않을테니깐요. + + +``` +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: efs-claim +spec: + accessModes: + - ReadWriteMany + storageClassName: efs-sc + resources: + requests: + storage: 5Gi +``` + +efs는 조금 다른형태의 볼륨을 사용하는데, +block storage provisioning 을 할 필요가 없기때문에, 동적 프로비저닝이 존재하지 않습니다. + +다만 일회성으로 쿠버네티스에 PV가 생성된다면, 그 이후에 PV는 모든 노드에서 프로토콜에 맞게 마운트가 가능하겠죠! + +기 생성되어 마운트 가능한 EFS 볼륨을 AWS CLI로 조회해봅니다. +``` +aws efs describe-file-systems --query "FileSystems[*].FileSystemId" --output text +``` + +Sample 코드에서 설정되어있는 PV 내용입니다. + +``` +apiVersion: v1 +kind: PersistentVolume +metadata: + name: efs-pv +spec: + capacity: + storage: 5Gi + volumeMode: Filesystem + accessModes: + - ReadWriteMany + persistentVolumeReclaimPolicy: Retain + storageClassName: efs-sc + csi: + driver: efs.csi.aws.com + volumeHandle: fs-4af69aab +``` + + +volumeHandle 부분에 위에서 AWS CLI로 획득한 EFS이름을 넣으면 해당 EFS를 마운트 할 수 있게 됩니다. + +해당 Git에 있는 pod 두개를 배포해봅니다. +두 pod는 동일한 pvc (pv)를 바라보고있지만, ReadWriteMany가 가능한 pod이기때문에, 생성이 완료됩니다. + +[image](https://apimin.montkim.com/cdn/blog/images/AEWS/week3/EKS_Storage/Untitled17.png) + +볼륨 사이즈가 8.0E 로 잡히긴하는데, +스토리지의 크기를 별도로 할당하지 않았기때문에 뜨는 값입니다만, 실제로 저 볼륨을 다 채울수 있을리는 없겠죠... + +온프레미스에서 NFS 로 볼륨을 연결하는것또한 동일합니다. +Block Storage아 아닐경우, NFS 자체만으로 공용볼륨을 조금씩 나눠쓰는 형태로 마운트를 한다면, 논리적인 볼륨의 최대치가 잡힙니다. + + diff --git a/posts/chapters.md b/posts/chapters.md index 903456f..c3b28ab 100644 --- a/posts/chapters.md +++ b/posts/chapters.md @@ -4,4 +4,6 @@ - [Kubernetes란](chapter2/About_Kubernetes.md) - [Terrform으로 EKS 생성하기](chapter3/EKS_Terraform.md) - [Kuberentes 기본 리소스](chapter4/Kuberentes_Resources.md) +- [Kubernetes & EKS 네트워크](chapter5/EKS_Network.md) +- [Kuberentes & EKS 스토리지](chapter6/EKS_Storage.md)