Kubernetes Reflection Pattern.

Original : https://www.magalix.com/blog/kubernetes-patterns-the-reflection-pattern

“Reflection”이란 무엇입니까?

Reflection은 대부분의 프로그래밍 언어에서 사용할 수있는 개념입니다. 단순히 어떤 유형의 개체가 자신에 대한 중요한 정보를 드러내는 능력을 나타냅니다. 예를 들어 이름, 상위 클래스 및 포함되는 모든 메타 데이터가 있습니다. 클라우드 및 DevOps 분야에서도 동일한 개념이 적용됩니다. 예를 들어, AWS EC2 인스턴스에 로그인 한 경우, 인스턴스 자체 내에서 http://169.254.169.254/latest/meta-data/에서 GET 요청을 실행하여 특정 인스턴스에 대한 풍부한 정보 (Reflection)를 쉽게 얻을 수 있습니다.

Reflection Pattern이 필요한 이유는 무엇입니까?

여기서 개체는 작업 단위를 나타내는 일반적인 용어로 사용됩니다. 따라서 프로그래밍 언어에서 객체는 클래스의 인스턴스이고 온 프레미스 인프라에서 객체는 물리적 또는 가상 호스트 일 수 있으며 클라우드 환경에서는 인스턴스이고 Kubernetes에서는 포드입니다. .

이 기사에서는 Kubernetes에 관심이 있으므로 Pod와 객체를 서로 바꿔서 사용할 수 있습니다.

포드의 메타 데이터가 필요한 많은 사용 사례가 있습니다. 특히 포드가 본질적으로 동적 인 상태 비 추적 애플리케이션의 일부인 경우 특히 그렇습니다. 몇 가지 가능한 시나리오를 살펴 보겠습니다.

  • 네트워크에서 감지 된 의심스러운 트래픽의 소스인지 여부를 식별하려면 포드의 IP 주소가 필요합니다.
  • 컨테이너 내부에서 실행되는 애플리케이션은 Pod가 실행중인 네임 스페이스를 알아야합니다. 아마도 네임 스페이스가 전달하는 실행중인 환경에 따라 다르게 동작하도록 프로그래밍 되었기 때문일 수 있습니다.
  • 컨테이너에 적용되는 현재 리소스 제한 (CPU 및 메모리)을 알아야합니다. 
    예를 들어, 이 데이터를 사용하여 Java 애플리케이션이 시작될 때 자동으로 힙 크기를 조정할 수 있습니다.

다행히 Kubernetes는 Downward API를 사용하여이 작업을 비교적 쉽게 만들었습니다.

Downward API는 어떻게 작동합니까?

Downward API는 환경 변수 및 파일을 통해 컨테이너에 메타 데이터를 삽입합니다. configMaps 및 Secrets를 사용하여 외부 정보를 애플리케이션으로 전달하는 것과 동일한 방식으로 사용됩니다. 그러나 Downward API는 사용 가능한 모든 메타 데이터를 컨테이너에 주입하지 않습니다. 대신 컨테이너에서 사용할 수 있어야하는 변수를 선택합니다.

이것이 무엇인지 이해하기 위해 예를 들어 보겠습니다. 다음 정의 파일은 bash 이미지에서 컨테이너를 실행하는 포드를 만듭니다. Downward API를 사용하여 사용 가능한 세 가지 변수 인 Pod의 IP 주소,이 Pod가 실행되는 네임 스페이스, 여기에 부과 된 현재 메모리 제한을 삽입합니다. 이 시나리오는 다음 그림에서 설명 할 수 있습니다.

반사

K8s 클러스터를 지속적으로 최적화하는 방법 알아보기

그리고 정의 파일은 다음과 같습니다.

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - image: bash
    name: mycontainer
    command: ['bash','-c','sleep 1000000']
    env:
    - name: MY_IP
      valueFrom:
        fieldRef:
          fieldPath: status.podIP
    - name: MY_NAMESPACE
      valueFrom:
        fieldRef:
          fieldPath: metadata.namespace
    - name: MY_MEMORY_LIMIT
      valueFrom:
        resourceFieldRef:
          containerName: mycontainer
          resource: limits.memory
          divisor: 1Mi

kubectl apply -f filename 을 사용하여이 정의를 실행 한 다음 Pod 내부의 컨테이너에 액세스하고 메타 데이터를 사용할 수 있는지 확인합니다.

$ kubectl exec -it mypod bash
bash-5.0# echo MY_IP
MY_IP
bash-5.0# echo $MY_IP
172.17.0.4
bash-5.0# echo $MY_NAMESPACE
default
bash-5.0# echo $MY_MEMORY_LIMIT
1900

따라서 MY_IP, MY_NAMESPACE 및 MY_MEMORY_LIMIT와 같은 각 환경 변수를 쿼리하여이 포드가 실행중인 IP 주소와 네임 스페이스를 가져올 수있었습니다.

FieldRef 매개 변수

첫 번째 예에서는 fieldRef 매개 변수를 사용하여 fieldPath를 통해 Pod에 삽입해야하는 정보를 선택했습니다. 참고로 다음은 fieldRef를 통해 사용할 수있는 가능한 값 목록입니다.

이름기술
spec.nodename포드가 실행중인 노드의 이름입니다.
status.hostIP포드가 실행중인 노드의 IP 주소입니다.
metadata.name포드 이름 (컨테이너의 이름과 다릅니다. 포드에 컨테이너가 두 개 이상있을 수 있음)
metadata.namespace포드의 네임 스페이스
status.podIP포드의 IP 주소
spec.serviceAccountNamePod와 함께 사용 된 서비스 계정입니다.
metadata.uid실행중인 포드의 UID
metadata.labels [ ‘label ‘]포드에있는 라벨의 값입니다. 예를 들어 포드가 env = prod로 라벨이 지정되면 metadata.labels [ ‘env’]는 ‘prod’를 반환합니다.
metadata.annotations [ ‘annotation’]레이블과 유사하게 지정된 주석의 값을 가져옵니다.

ResourceFieldRef 매개 변수

fieldRef 매개 변수를 사용하면 Pod에 대한 메타 데이터를 삽입 할 수 있습니다. Pod가 사용하는 리소스, 즉 CPU 및 메모리에 대한 데이터가 필요한 경우 resourceFieldRef를 사용해야합니다. 다음은이 데이터를 가져 오는 데 사용할 수있는 옵션 목록입니다.

이름기술
requests.cpu포드 정의의 요청 필드에 지정된 CPU 양
requests.memory포드 정의의 요청 필드에 지정된 메모리 양
limits.cpu포드의 CPU 제한
limits.memory포드의 메모리 제한

요청 및 제한은 정의 파일 내의 포드에 부과 될 수 있습니다. 둘 다 주어진 Pod가 소비 할 수있는 리소스 양의 하드 및 소프트 제한을 제어 할 수 있습니다. 또한 스케줄러가 리소스 요청 및 제한에 따라 적절한 노드에 포드를 할당하는 데 도움이됩니다. 이 항목에 대한 자세한 내용은 용량 계획 문서를 참조하십시오.

수정 후 포드 메타 데이터 가져 오기

Kubernetes 사용자는 포드가 실행되는 동안 포드의 일부 메타 데이터를 변경할 수 있습니다. 따라서 리소스 요청 및 제한과 같은 필드는 포드를 삭제하고 다시 생성하지 않는 한 변경할 수 없지만 포드 라벨은 변경할 수 있습니다. 사용자가 kubectl edit pod pod_name 명령을 실행 한 경우 필드에서 허용하는 한 Pod 정의를 동적으로 수정할 수 있습니다.

Pod의 메타 데이터가 동적으로 변경된 경우 컨테이너를 다시 시작해야하므로 환경 변수를 통해 컨테이너에 다시 삽입 할 수 없습니다. 그러나 컨테이너에 데이터를 주입하는 다른 방법 인 볼륨을 사용하여 이러한 변경 사항을 모니터링하고 가져올 수 있습니다.

다음 정의는 컨테이너가 데이터에 액세스 할 수 있도록 configMaps 및 Secrets와 함께 사용하는 것과 동일한 방식으로 볼륨을 사용할 수있는 방법을 보여줍니다.

apiVersion: v1
kind: Pod
metadata:
  name: mypod
  labels:
    env: prod
spec:
  containers:
  - image: bash
    name: mycontainer
    command: ['bash','-c','sleep 1000000']
    volumeMounts:
    - name: mypod-vol
      mountPath: /mypod-metadata
  volumes:
  - name: mypod-vol
    downwardAPI:
      items:
      - path: labels
        fieldRef:
          fieldPath: metadata.labels
      - path: annotations
        fieldRef:
          fieldPath: metadata.annotations

이 정의를 적용하고 Pod에 로그인하면 관련 데이터와 함께 볼륨이 마운트 된 것을 확인할 수 있습니다.

$ kubectl exec -it mypod bash
bash-5.0# cat /mypod-metadata/labels  && echo
env="prod"
bash-5.0# cat /mypod-metadata/annotations && echo
kubectl.kubernetes.io/last-applied-configuration="{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"labels\":{\"env\":\"prod\"},\"name\":\"mypod\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"command\":[\"bash\",\"-c\",\"sleep 1000000\"],\"image\":\"bash\",\"name\":\"mycontainer\",\"volumeMounts\":[{\"mountPath\":\"/mypod-metadata\",\"name\":\"mypod-vol\"}]}],\"volumes\":[{\"downwardAPI\":{\"items\":[{\"fieldRef\":{\"fieldPath\":\"metadata.labels\"},\"path\":\"labels\"},{\"fieldRef\":{\"fieldPath\":\"metadata.annotations\"},\"path\":\"annotations\"}]},\"name\":\"mypod-vol\"}]}}\n"
kubernetes.io/config.seen="2019-09-07T09:06:35.812284937Z"
kubernetes.io/config.source="api"

보시다시피 환경 변수가 아닌 볼륨에 저장된 파일을 통해 데이터를 얻습니다. 이를 통해 컨테이너를 다시 시작할 필요없이 정보가 변경 될 때마다 동적으로 검색 할 수 있습니다. 그러나 실행중인 응용 프로그램은 레이블 또는 주석 파일 (해당 값을 사용하는 경우)의 변경 사항을 감지하고 수정이 발생하면 그에 따라 작동하도록 구성해야합니다.

TL; DR

  • 많은 경우 애플리케이션이 실행중인 인프라의 일부 메타 데이터를 인식해야합니다. 애플리케이션은이 정보를 사용하여 지능적인 결정을 내리거나 수동 작업을 자동화 할 수 있습니다.
  • Kubernetes는이 메타 데이터 중 일부를 Pod에 삽입하고 내부 컨테이너에 액세스 할 수 있도록하는 Downward API를 제공합니다.
  • Downward API를 사용하면 API 서버에서 여러 메타 데이터 항목과 리소스 요청 및 제한을 쿼리 할 수 ​​있습니다.
  • 환경 변수 또는 마운트 볼륨을 통해 필요한 정보를 Pod에 삽입 할 수 있습니다.
  • 환경 변수 사용의 단점은 라벨 및 주석과 같은 Pod의 메타 데이터에 대한 동적 변경 사항을 반영 할 수 없다는 것입니다. 해결 방법으로 볼륨을 사용할 수 있습니다.
  • Downward API는 Pod 리플렉션을 달성하는 우아한 방법이지만 제공 할 수있는 데이터의 양은 여전히 ​​제한적입니다. 필요할 수 있지만 Downward API를 통해 제공되지 않는 다른 Pod 측면이 있습니다. 이 단점에 대한 대답은 애플리케이션이 API 서버에 직접 쿼리하여 누락 된 데이터를 가져 오도록하는 것입니다. 코드를 통해 API 서버를 쿼리 할 수있는 많은 프로그래밍 언어로 된 많은 클라이언트 측 라이브러리가 있습니다.

Author: zepirox

Leave a Reply

Your email address will not be published. Required fields are marked *