728x90
반응형
쿠버네티스 인 액션: 그림과 상세한 설명으로 명확하게 이해하는
ch08. 애플리케이션에서 파드 메타데이터와 그 외의 리소스 액세스
Downward API로 메타데이터 전달
- Pod 내부에서 Kubernetes 리소스의 정보를 접근할 수 있게 해주는 기능
- 환경변수 또는 파일에 파드의 스펙 또는 상태값이 채워지도록 하는 방식 (REST API 같은 엔드포인트가 아님)
- 메타데이터
- 파드 이름
- 파드 IP
- 파드가 속한 네임스페이스
- 파드가 실행 중인 노드 이름
- 파드가 실행 중인 서비스 어카운트 이름
- 각 컨테이너의 CPU와 메모리 request/limit
- 파드의 레이블, 어노테이션 (볼륨으로만 노출 가능)
환경변수로 메타데이터 전달
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
valueFrom:
fieldRef:
fieldPath: metadata.name
...
- name: CONTAINER_CPU_REQUEST_MILLICORES
valueFrom:
resourceFieldRef: // resourceFieldRef 사용
resource: requests.cpu
divisor: 1m // 리소스 필드의 경우 필요한 단위의 값을 얻으려면 divisor을 정의
$ k exec downward -- env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=downward
CONTAINER_MEMORY_LIMIT_KIBIBYTES=4096
POD_NAME=downward
POD_NAMESPACE=default
POD_IP=10.88.1.12
NODE_NAME=gke-kubia-default-pool-a9ec92c1-pnv0
...
파일로 메타데이터 전달
- downwardAPI 볼륨을 정의해 컨테이너에 마운트
- 레이블과 어노테이션은 파드 실행중 수정되면 쿠버네티스가 이 값을 가지고 있는 파일도 업테이트 함
- 환경변수로 노출될 경우 값이 변경되어도 수정할 방법이 없음
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"]
...
volumeMounts:
- name: downward
mountPath: /etc/downward
volumes:
- name: downward
downwardAPI:
items:
- path: "podName"
fieldRef:
fieldPath: metadata.name
...
- path: "containerMemoryLimitBytes"
resourceFieldRef:
containerName: main
resource: limits.memory
divisor: 1
$ k exec downward -- ls -lL /etc/downward
total 24
-rw-r--r-- 1 root root 1343 Nov 10 12:23 annotations
-rw-r--r-- 1 root root 2 Nov 10 12:23 containerCpuRequestMilliCores
-rw-r--r-- 1 root root 7 Nov 10 12:23 containerMemoryLimitBytes
-rw-r--r-- 1 root root 9 Nov 10 12:23 labels
-rw-r--r-- 1 root root 8 Nov 10 12:23 podName
-rw-r--r-- 1 root root 7 Nov 10 12:23 podNamespace
$ k label pod downward foo=bor --overwrite
pod/downward labeled
$ k exec downward -- cat /etc/downward/labels
foo="bor"
Downward API의 사용법은 단순하나 사용 가능한 메타데이터가 상당히 제한적임
쿠버네티스 API 서버와 통신
- 애플리케이션에서 클러스터에 정의된 다른 파드나 리소스에 관한 더 많은 정보가 필요할 수 있음
kubectl 프록시로 API 서버 액세스
- 프록시 서버를 실행해 로컬에서 HTTP 연결을 수신하고, 인증을 관리하여 API 서버로 전달함
$ k proxy
Starting to serve on 127.0.0.1:8001
$ curl localhost:8001
{
"paths": [
"/.well-known/openid-configuration",
"/api",
"/api/v1",
"/apis",
"/apis/",
"/apis/apps/v1",
...
$ curl localhost:8001/apis/batch/v1/jobs
{
"kind": "JobList",
"apiVersion": "batch/v1",
"metadata": {
"resourceVersion": "3321063"
},
"items": []
}
파드 내에서 API 서버와 통신
파드 실행
apiVersion: v1
kind: Pod
metadata:
name: curl
spec:
containers:
- name: main
image: curlimages/curl
command: ["sleep", "9999999"]
서버의 아이덴티티 검증
$ k exec -it curl -- sh
$ curl
curl: (60) SSL peer certificate or SSH remote key was not OK
More details here: <https://curl.se/docs/sslcerts.html>
curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the webpage mentioned above.
- 인증서 서명
- 7장의 시크릿에서 등장한 /var/run/secrets/kubernetes.io/serviceaccount/에 마운트 되는 default-token 시크릿 사용 (p.339)
$ curl --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt <https://kubernetes>
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "forbidden: User \\\\"system:anonymous\\\\" cannot get path \\\\"/\\\\"",
"reason": "Forbidden",
"details": {},
"code": 403
}
$ export CURL_CA_BUNDLE=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
- API 서버로 인증
- default-token 시크릿의 token 사용
$ TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
$ curl -H "Authorization: Bearer $TOKEN" <https://kubernetes>
{
"paths": [
"/.well-known/openid-configuration",
"/api",
"/api/v1",
"/apis",
"/apis/",
...
]
}
RBAC이 활성화된 쿠버네티스 클러스터를 사용할 경우, 서비스 어카운트가 API 서버에 액세스할 권한이 없기 때문에
RBAC을 우회하는 명령어 실행해야 위의 실습 가능 (p. 76)
프로덕션에서는 금지!
- 동일 네임스페이스의 모든 파드 조회하기
- default-token 시크릿의 namespace 사용
$ NS=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
$ curl -H "Authorization: Bearer $TOKEN" <https://kubernetes/api/v1/namespaces/$NS/pods>
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"resourceVersion": "3359769"
},
"items": [
{
"metadata": {
"name": "curl",
"namespace": "default",
...
- 정리
앰배서더 컨테이너를 이용한 API 통신 간소화
- 메인 컨테이너 애플리케이션 -> HTTP로 앰배서더 연결 -> 앰배서더 프록시 -> HTTPS로 API 서버 연결
apiVersion: v1
kind: Pod
metadata:
name: curl-with-ambassador
spec:
containers:
- name: main
image: curlimages/curl
command: ["sleep", "9999999"]
- name: ambassador
image: luksa/kubectl-proxy:1.6.2
- 인증없이 잘 되는지 확인
$ k exec -it curl-with-ambassador -c main -- sh
$ curl localhost:8001
{
"paths": [
"/.well-known/openid-configuration",
"/api",
...
- curl -> http -> 프록시 -> https -> api 서버
- 메인 애플리케이션 언어에 상관없이 여러 애플리케이션에서 재사용이 가능
- 단점은 추가 프로세스가 실행되며, 추가 리소스 소비
클라이언트 라이브러리 사용해 API 서버 통신
https://kubernetes.io/docs/reference/using-api/client-libraries/
$ pip install kubernetes
파이썬 예제
from kubernetes import client, config
from time import sleep
# Kubernetes 클라이언트 구성 로드 (kubeconfig 사용)
config.load_kube_config()
# Kubernetes 클라이언트 생성
v1 = client.CoreV1Api()
# 기본(default) 네임스페이스의 모든 Pod 목록 가져오기
print("Listing pods in namespace 'default'")
pods = v1.list_namespaced_pod(namespace="default")
for pod in pods.items:
print(f"Found pod: {pod.metadata.name}")
# 새로운 Pod 생성
print("Creating a pod")
pod_body = client.V1Pod(
metadata=client.V1ObjectMeta(name="programmatically-created-pod"),
spec=client.V1PodSpec(
containers=[
client.V1Container(
name="main",
image="busybox",
command=["sleep", "99999"]
)
]
)
)
created_pod = v1.create_namespaced_pod(namespace="default", body=pod_body)
print(f"Created pod: {created_pod.metadata.name}")
# Pod 편집 (라벨 추가)
print("Editing pod to add label foo=bar")
patch_body = {
"metadata": {
"labels": {
"foo": "bar"
}
}
}
v1.patch_namespaced_pod(name="programmatically-created-pod", namespace="default", body=patch_body)
print("Added label foo=bar to pod")
# 1분 대기 후 Pod 삭제
print("Waiting 1 minute before deleting pod...")
sleep(60)
print("Deleting the pod")
v1.delete_namespaced_pod(name="programmatically-created-pod", namespace="default")
print("Deleted the pod")
$ python main.py
Listing pods in namespace 'default'
Found pod: kubia-fcbrx
Found pod: kubia-mdhv4
Found pod: kubia-sk8hb
Creating a pod
Created pod: programmatically-created-pod
Editing pod to add label foo=bar
Added label foo=bar to pod
Waiting 1 minute before deleting pod...
Deleting the pod
Deleted the pod
- po 조회 결과
$ k get po
NAME READY STATUS RESTARTS AGE
kubia-fcbrx 1/1 Running 0 11m
kubia-mdhv4 1/1 Running 0 11m
kubia-sk8hb 1/1 Running 0 11m
programmatically-created-pod 1/1 Terminating 0 79s
728x90
반응형
'Programming-[Infra] > Kubernetes' 카테고리의 다른 글
쿠버네티스 인 액션: ch7. 컨피그맵과 시크릿 (0) | 2024.11.24 |
---|---|
쿠버네티스 인 액션: ch6. 볼륨 (0) | 2024.11.23 |
쿠버네티스 인 액션: ch5. 서비스 (0) | 2024.11.22 |
쿠버네티스 인 액션: ch4. 레플리케이션과 그 밖의 컨트롤러: 관리되는 파드 배포 (1) | 2024.11.21 |
쿠버네티스 인 액션: ch3. 파드: 쿠버네티스에서 컨테이너 실행 (0) | 2024.11.20 |