tech/k8s

[쿠버네티스 인 액션] 파드 메타데이터와 그 외 리소스 접근하기

eumdengs 2025. 3. 27. 00:20
쿠버네티스 인 액션 8장

 
 
 
애플리케이션은 자신에 대한 상세 정보나 실행중인 환경 정보, 또는 클러스터 내 다른 구성요소의 정보가 필요할 수 있습니다.
일반적으로 애플리케이션 설정 데이터는 환경변수 또는 컨피그맵, 시크릿 봄륨으로 애플리케이션에 전달됩니다.
 
예를 들면 디비 접속정보나 특정 URL에 대한 정보가 컨피그맵 또는 시크릿으로 구성되어 파드에 마운트 되기도 합니다.
다만 이러한 데이터는 직접 설정했거나 파드가 스케줄링 되기 전 데이터입니다.
그렇다면 파드IP, 호스트 노드 이름, 자드 자체 이름 등 실행 시점까지 알려지지 않은 데이터는 어떻게 될까요?
 
이는 Downward API로 확인할 수 있습니다.
https://kubernetes.io/docs/concepts/workloads/pods/downward-api/

 

Downward API

There are two ways to expose Pod and container fields to a running container: environment variables, and as files that are populated by a special volume type. Together, these two ways of exposing Pod and container fields are called the downward API.

kubernetes.io

 
Downward API는 애플리케이션이 직접 호출하는 방식이 아닌 환경변수 또는 파일에 파드의 스펙/상태값을 채워넣는 방식입니다.
 

쿠버네티스 인 액션

 

사용 가능한 메타데이터

- 파드의 이름
- 파드의 IP 주소
- 파드가 속한 네임스페이스
- 파드가 실행 중인 서비스 어카운트 이름
- 각 컨테이너의 CPU와 메모리 requests
- 각 컨테이너의 CPU와 메모리 limits
- 파드의 레이블
- 파드의 어노테이션
 
대부분은 환경변수 또는 downwardAPI 볼륨으로 컨테이너에 전달이 가능하지만
레이블과 어노테이션은 downward API 볼륨으로만 노출될 수 있습니다.
 
 
 

환경변수로 메타데이터 노출하기

컨테이너 내부에 메타데이터를 환경변수로 노출하는 간단한 예제를 확인해보겠습니다.

apiVersion: v1
kind: Pod
metadata:
  name: env-example
spec:
  containers:
  - name: example-container
    image: busybox
    command: ["/bin/sh", "-c", "env && sleep 3600"]
    env:
      - name: POD_NAME
        valueFrom:
          fieldRef:
            fieldPath: metadata.name
      - name: SERVICE_ACCOUNT
        valueFrom:
          fieldRef:
            fieldPath: spec.serviceAccountName
      - name: CPU_LIMIT
        valueFrom:
          resourceFieldRef:
            containerName: example-container
            resource: limits.cpu

 
해당 예제에서는 POD_NAME, SERVICE_ACCOUNT, CPU_LIMIT 환경변수를 설정하였습니다.
이제 컨테이너에 제대로 적용되었는지 확인해봅니다.
 

kubectl exec env-example -- env

 

 
정상적으로 적용된 것을 확인할 수 있습니다.
 
 

downwardAPI 볼륨에 파일로 메타데이터 전달

환경변수 대신 파일로 메타데이터를 노출할 수도 있습니다.
레이블과 어노테이션을 포함하는 예제입니다.
중간에 볼륨에 downwardAPI: 부분을 확인 할 수 있습니다.
 

apiVersion: v1
kind: Pod
metadata:
  name: downward-api-volume-example
  labels:
    app: my-app
  annotations:
    description: "downward-api-volume"
    owner: "admin"
spec:
  containers:
  - name: example-container
    image: busybox
    command: ["/bin/sh", "-c", "cat /etc/pod-info/* && sleep 3600"]
    volumeMounts:
      - name: downward-api-volume
        mountPath: /etc/pod-info
  volumes:
    - name: downward-api-volume
      downwardAPI:
        items:
          - path: "labels"
            fieldRef:
              fieldPath: metadata.labels

          - path: "annotations"
            fieldRef:
              fieldPath: metadata.annotations

 
컨테이너 내부에 마운트된 볼륨 파일을 확인해보겠습니다.
정상적으로 내부 볼륨에 레이블 정보와 어노테이션 정보가 생성된 것을 확인할 수 있습니다.
 

 
왜 레이블과 어노테이션은 볼륨으로 마운트되는 것일까요?
그 이유는 파드의 레이블과 어노테이션은 파드가 실행되는 동안 수정이 가능하기 때문입니다.
환경변수 값은 나중에 업데이트를 할 수 없기 때문입니다.
 
그럼 현재 실행중인 파드의 레이블을 업데이트하고 볼륨을 확인해보겠습니다.
 

kubectl edit pod downward-api-volume-example

 
기존의 app: my-app을 수정합니다.

my-app -> my-app-new

 
 
다시 볼륨의 데이터를 확인해보면 my-app-new로 갱신된 것을 확인할 수 있습니다.

 
 
이로써 파드의 레이블과 어노테이션 메타데이터 정보는 볼륨으로 마운트하여 확인할 수 있다는 것을 보았습니다.
추가로 리소스 요청/제한 과 같은 컨테이너 수준의 메타데이터를 노출하는 경우에는 컨테이너 이름을 지정해주어야합니다.
파드는 하나 이상의 컨테이너를 가지고 있기 때문입니다.

  volumes:
    - name: downward-api-volume
      downwardAPI:
        items:
          - path: "cpu_limit"
            resourceFieldRef:
              containerName: example-container
              resource: limits.cpu

 
 

다른 클러스터나 파드 정보 확인하기

Downward API는 매우 유용해보이지만 단지 파드 자체의 메타데이터와 모든 파드의 데이터 중 일부만 노출합니다.
그외 다른 파드나 리소스의 정보는 어떻게 확인할까요?
이 경우 파드는 직접 API 서버와 통신을 해야 합니다.
 
잠깐 API 서버와는 어떻게 통신할까요?
API 서버의 REST 엔드포인트를 보고 실습을 해보겠습니다.
 

kubectl cluster-info

 
Kubernetes control plane is running at https://127.0.0.1:6443
 
저의 경우에는 로컬에서 간단하게 테스트 중으로 127.0.0.1:6443이 확인됩니다.
API 서버는 HTTPS 통신 인증이 필요합니다. 따라서 curl 의 --insecure 또는 -k 옵션으로는 인증이 어렵습니다.

https 통신이 필요합니다

 
이를 위해 kube proxy 명령어를 통해 HTTP 응답을 받아서 API 서버에 HTTPS 전달을 대신해주는 프록시 서버를 실행해보겠습니다.
프록시를 통해 요청마다 인증 토큰을 전달할 필요가 없어집니다.
 

 
실행하면 위와 같이 표시됩니다. 새로운 터미널을 키고 위에서 나온 프록시 주소로 curl 명령어를 다시 시도합니다.

 
프록시 서버가 대신해서 인증하고 API 서버가 반환하는 정보를 받아왔습니다.
 
apis/batch, apis/batch/v1, apis/batch/v1/jobs 와 같은 엔드포인트 목록을 불러와서 API 서버의 정보를 확인할 수 있습니다.
아래와 같이 정보를 준다면 실행중인 파드의 정보도 확인이 가능합니다.
 

curl http://localhost:8001/api/v1/namespaces/default/pods/env-example

 

 
해당 정보는 kubectl get pod env-example -o json 과 동일합니다.
 
 

파드 내에서 API 서버와 통신

프록시 없이 파드에서 어떻게 API 서버와 통신할 수 있을까요?
아래 세 가지가 필요합니다.
- API 서버의 위치
- API 서버와 통신하는지 확인
- API 서버 인증
 
로컬에서 curl https://127.0.0.1 을 해봐도 인증서가 없으므로 에러가 발생합니다.

 
 
인증서는 어디서 구해야할까요? 
간단한 해답은 실행중인 파드에 있습니다. 각 파드 내 컨테이너는 API 서버와 통신을 위해
/var/run/secrets/kubernetes.io/serviceaccount 내 통신을 위한 토큰, 인증서, 네임스페이스 정보를 가지고 있습니다.
 
우선 테스트를 위해 임시로 모든 서비스 어카운트에게 클러스터 관리자 권한을 부여하겠습니다.
(RBAC는 차후 다루겠습니다.)

kubectl create clusterrolebinding permissive-binding --clusterrole=cluster-admin --group=system:serviceaccounts

 
아까도 말했듯이 실행중인 파드에는 토큰, 인증서, 네임스페이스 정보가 있습니다.
API 서버 접근을 위해 curl 이 가능한 이미지로 파드하나를 만들고 내부로 들어가서 테스트해보겠습니다.

apiVersion: v1
kind: Pod
metadata:
  name: curl-test
  labels:
    app: curl-test
spec:
  containers:
  - name: curl-container
    image: curlimages/curl:latest
    command: ["sleep", "3600"]

 

kubectl apply -f curl.yaml
kubectl exec -it curl-test -- sh

 
인증을 위해 TOKEN 변수를 지정합니다.
파드의 서비스어카운트는 API 서버 인증을 위해 토큰을 사용합니다.

TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)

 
해당 토큰으로 인증을 시도하면 API 서버에서 응답을 확인할 수있습니다.

curl -H "Authorization: Bearer $TOKEN" --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt https://kubernetes

 

 
 
파드는 내부에서 위와 같은 API 서버와의 통신을 통해 필요한 정보를 조회할 수 있습니다.
 
 

정리..

파드가 자신의 메타데이터와 API 서버인증을 통해서 다른 정보를 가져올 수 있는 방법에 대해 확인해보았습니다.
위 과정에서 파드는 API 서버와 통신할 때 서비스어카운트를 가지고 인증을 시도하는 것을 확인했습니다.
 
 
 
 

매일 업데이트하는 식으로 포스팅합니다