Application에서 pod의 metadata에 접근하기

Jiyoon·2022년 1월 25일
1

Kubernetes

목록 보기
7/10

Accessing pod metadata / other resources from application

Overview

Pod에 대한 정보 (pod의 이름,..) 등은 pod를 생성할 때 사용하는 manifest를 통해 미리 알 수 있지만, pod가 생성된 이후 알 수 있는 정보들이 있다. (Pod의 IP, host node의 이름, ReplicaSet으로 생성된 pod의 이름..) 등

실행 시점까지 알려지지 않은 데이터가 pod내에 배포된 application단에서 필요한 경우, Pod의 metadata에 접근해야한다.
이때 사용 가능한 방법이

  • Downward API를 사용하는 방법
  • K8S API Server와 통신해 내장된 정보를 이용하는 방법
  • Application단에서 Client Library를 이용해 API Server와 통신하는 방법 이렇게 3가지가 있다.

1. Downward API를 사용하는 방법

1.1 접근 가능한 metadata에 대한 이해

pod 자체의 metadata를 해당 pod내에서 실행 중인 프로세스에 노출할 수 있는 metadata 종류

  • metadata.name
  • metadata.namespace
  • metadata.uid
  • metadata.labels
  • metadata.annotations

Resource에 대한 정보

  • Container’s CPU limit / request
  • Container’s Memory limit / request
  • Container’s hugepages limit / request
  • Container’s ephemeral-storage limit / request

note)

  • hugepages: node 커널이 기본 페이지 크기보다 훨씬 큰 메모리 블록을 할당하는 리눅스 관련 기능
  • ephemeral-storage: 임시 저장소 라는 뜻으로, 컨테이너 환경에서는 volume을 mount하지 않는 이상 data가 휘발성이 되고, 그 휘발성 data를 위한 저장 공간을 의미한다. 이 ephemeral volume의 용량이 부족해지면 pod의 상태가 evicted (강제 종료) 되고, 그렇다면 이걸 increase하는 방법은? -> increase he size in the VM configuration or cloud provider!
  • status.podIP
  • spec.serviceAccountName
  • spec.nodeName
  • status.hostIP

1.2 환경변수를 사용해 접근하기

Pod를 배포할 때

apiVersion: v1
kind: Pod
metadata:
  name: downward
spec:
  containers:
  - name: main
    image: busybox
    command: ["sleep", "9999999"]
    resources:
      requests:
        cpu: 15m
        memory: 100Ki
      limits:
        cpu: 100m
        memory: 4Mi
    env:
    - name: POD_NAME. ###### POD_NAME라는 환경변수로 저장하겠다
      valueFrom:
        fieldRef:
          fieldPath: metadata.name.  ###### 이 fieldpath에서 가져온 값을!
    - name: POD_NAMESPACE
      valueFrom:
        fieldRef:
          fieldPath: metadata.namespace
    - name: POD_IP
      valueFrom:
        fieldRef:
          fieldPath: status.podIP
    - name: NODE_NAME
      valueFrom:
        fieldRef:
          fieldPath: spec.nodeName
    - name: SERVICE_ACCOUNT
      valueFrom:
        fieldRef:
          fieldPath: spec.serviceAccountName
    - name: CONTAINER_CPU_REQUEST_MILLICORES
      valueFrom:
        resourceFieldRef:
          resource: requests.cpu
          divisor: 1m

위의 값을 확인하는 pod를 임시로 하나 만들어서


apiVersion: v1
kind: Pod
metadata:
  name: print-greeting
spec:
  containers:
  - name: env-print-demo
    image: bash
    env:
    - name: GREETING
      value: "Warm greetings to"
    - name: HONORIFIC
      value: "The Most Honorable"
    - name: NAME
      value: "Kubernetes"
    command: ["echo"]
    args: ["$(GREETING) $(HONORIFIC) $(NAME)"] #### HERE!
  • 컨테이너 내부에서 실행되는 프로세스는 해당 변수를 읽고, 필요한 대로 사용할 수 있다.
  • 환경 변수는 서로를 참조할 수 있는데, 이 때 순서에 주의해야한다. 동일한 context에서 정의된 다른 변수를 참조하는 변수는 목록의 뒤쪽에 나와야 한다.

1.3 downwardAPI 전용 downwardAPI type의 volume을 통해 files로 내보내기해서 접근하기

apiVersion: v1
kind: Pod
metadata:
  name: downward
  labels:
    foo: bar
  annotations:
    key1: value1
    key2: |
      multi
      line
      value
spec:
  containers:
  - name: main
    image: busybox
    command: ["sleep", "9999999"]
    resources:
      requests:
        cpu: 15m
        memory: 100Ki
      limits:
        cpu: 100m
        memory: 4Mi
    volumeMounts: ## (pod에 volume 형태로 downwardAPI를 사용하도록 mount)
    - name: downward
      mountPath: /etc/downward.  ### (이 pod의 etc/downward라는 경로에다가)
  volumes: 
  - name: downward
    downwardAPI:  ###### downwardAPI용 볼륨으로 딱 지정
      items:
      - path: "podName"
        fieldRef:
          fieldPath: metadata.name
      - path: "podNamespace"
        fieldRef:
          fieldPath: metadata.namespace
      - path: "labels"
        fieldRef:
          fieldPath: metadata.labels

실제 출력은 pod에 접속해서 etc/downward라는 경로에서 file을 열어서 확인한다.

# k exec -it —/bin/bash kubernetes-downwardapi-volume-example 
# cat /etc/downward

kubectl.kubernetes.io/last-applied-configuration="{\"apiVersion\":\"
v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{\"build\":\"two\",
\"builder\":\"john-doe\"},\"labels\":{\"cluster\":\"test-cluster1\",\"
rack\":\"rack-22\",\"zone\":\"us-est-coast\"},\"name\":\"kubernetes-
downwardapi-volume-example\",\"namespace\":\"default\"},\"spec\":{\"
containers\":[{\"args\":[\"while true; do if [[ -e /etc/podinfo/labels
]]; then echo -en '\\\\n\\\\n'; cat /etc/podinfo/labels; fi; if [[ -e
/etc/podinfo/annotations ]]; then echo -en '\\\\n\\\\n'; cat /etc
/podinfo/annotations; fi; sleep 5; done;\"],\"command\":[\"sh\",\"-c\"],
\"image\":\"k8s.gcr.io/busybox\",\"name\":\"client-container\",\"
volumeMounts\":[{\"mountPath\":\"/etc/podinfo\",\"name\":\"
podinfo\"}]}],\"volumes\":[{\"downwardAPI\":{\"items\":[{\"fieldRef\":
{\"fieldPath\":\"metadata.labels\"},\"path\":\"labels\"},{\"fieldRef\":
{\"fieldPath\":\"metadata.annotations\"},\"path\":\"annotations\"}]},\"
name\":\"podinfo\"}]}}\n"

언제 환경변수를 사용하고 언제 downwardAPI 볼륨을 사용하는가?

  • 환경변수로는 pod의 label이나 annotaion을 노출할 수 없음. 이 경우 downwardAPI volume방식 적합

참고) https://kubernetes.io/ko/docs/tasks/inject-data-application/downward-api-volume-expose-pod-information/

2. K8S API server에 접근하기

2.1 pod에서 직접 접근 -> 결론부터 말하자면 실패함

예상 시나리오 : kubectl cluster-info 로 master가 running하고 있는 node IP를 찾아서, 직접 curl request를 통해 metadata에 접근한다.

 k  cluster-info
Kubernetes master is running at <https://192.168.64.3:8443>
KubeDNS is running at <https://192.168.64.3:8443/api/v1/namespaces/kube-
system/services/kube-dns:dns/proxy>
curl <https://192.168.64.3:8443> -k
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {
  },
  "status": "Failure",
  "message": "forbidden: User \"system:anonymous\" cannot get path \"
/\"",
  "reason": "Forbidden",
  "details": {
},
  "code": 403
}%

API서버는 HTTPS를 사용하고 인증이 필요하기 때문에 직접 통신할 수 없다. -k 옵션을 줘서 서버 인증서 확인을 건너뛰는걸 시도해도 원하는 응답을 얻지 못한다.
그대신
Kubectl proxy로 서버와 통신할 수 있다.

note) kubectl proxy
Proxy 서버를 실행해서 로컬에서 HTTP연결을 수행하고, 이 연결을 인증을 관리하면서 API server로 전달하기 때문에, 요청할 때 token을 전달할 필요가 없다. 또 각 요청마다 서버의 인증서를 확인해 중간자가 아닌 실제 API server와 통신하는 것을 담당한다.

k proxy
Starting to serve on 127.0.0.1:8001
curl localhost:8001

2.2 ambassador containers를 이용해 API server와 통신하기

API server와 application이 직접 통신하는 대신에, main container 옆에 ambassador container를 통해 kubectl proxy를 실행하고, API server와 통신할 수 있다.

지난번 세미나에서 했던 내용처럼 pod의 모든 container는 동일한 loopback network interface를 공유하므로 (플랫 네트워크, localhost로 access 가능) application은 localhost의 port로 proxy server에 access할 수 있다.

3. Client library를 이용해 API server와 통신하기

https://github.com/kubernetes-client/python

Quiz

1) 클지니회사의 DevOps 주니어 징니씨는 The node was low on resource: ephemeral-storage. Container oooo was using 28Ki, which exceeds its request of 0 라는 메시지를 받게 되었다. 이 때, 징니가 ephemeral-storage의 request를 확인하기 위해 해야할 action과 해결사항은?

2) 클지니회사의 DevOps 주니어 징니씨는 동료 DevOps 시니어 쥬니씨가 단 pod의 label을 pod 내부에 배포된 application에서 확인하고 싶다. 이 때 징니씨는 어떻게 해야할까?

profile
Jiyoon in cloud valley, Change the world Why Not? / 오픈소스 생태계를 잘 이해하는 Cloud engineer가 되고 싶은 지윤

0개의 댓글