Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chapter 8. 애플리케이션에서 파드 메타데이터와 그 외의 리소스에 액세스하기 #9

Open
kmg28801 opened this issue Dec 11, 2022 · 3 comments
Assignees

Comments

@kmg28801
Copy link
Owner

No description provided.

@thesun4sky
Copy link

thesun4sky commented Jan 5, 2023

8. 애플리케이션에서 파드 메타데이터와 그 외의 리소스에 액세스하기

8.1 Downward API로 메타데이터 전달

  • 7장에서는 환경변수 또는 configMap과 시크릿 볼륨으로 설정 데이터를 애플리케이션에 전달하는법을 배웠다.
    • 파드가 노드에 스케줄링돼 실행되기 이전에 이미 알고 있는 데이터
  • 8장에서는 파드의 IP, 노드의 이름 등 실행시점에 결정되는 데이터를 전달하는 법을 배운다. 또는 반복설정도 해결한다. 이는 downwardAPI로 해결할 수 있다.
    • 레플리카셋과 같은 컨트롤러에 의해 파드가 생성되는 경우 등...
    • 환경변수 또는 downwardAPI 볼륨내의 파일로 파드와 해당 환경의 메타데이터를 전달할 수 있다.
    • 아래 그림과 같이 환경변수 또는 파일에 파드의 스펙 또는 상태값이 채워지도록 하는 방식
      image

8.1.1 사용 가능한 메타데이터 이해

Downward API를 이용해 다음 정보를 컨테이너에 전달할 수 있다.

  • 파드의 이름, IP주소, 네임스페이스, 노드의이름, 서비스 어카운트 이름, 레이블, 어노테이션
  • 컨테이너의 CPU와 메모리 요청값(request), 메모리 제한값(limit)

여기서 레이블과 어노테이션은 볼륨으로만 노출될 수 있다.

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

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:                      # 특정 값을 설정하는 대신 파드 매니페스트의 metadata.name을 참조한다.
        fieldRef:
          fieldPath: metadata.name
    - name: POD_NAMESPACE
      valueFrom:                      # 특정 값을 설정하는 대신 파드 매니페스트의 metadata.namespace을 참조한다.
        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:       # 컨테이너의 CPU등은 filedRef대신 resourceFieldRef를 사용한다.
          resource: requests.cpu      
          divisor: 1m                 # 나눔수(제수)가 1m 이기때문에 15m 설정한경우 15 값이 들어간다.
    - name: CONTAINER_MEMORY_LIMIT_KIBIBYTES
      valueFrom:
        resourceFieldRef:
          resource: limits.memory
          divisor: 1Ki                 # 나눔수(제수)가 1Ki 이기때문에 4Mi 설정한경우 4096 값이 들어간다.

기본적으로 filedRef로 설정하고, 컨테이너의 CPU/메모리 요청/제한값은 filedRef대신 resourceFieldRef를 사용한다.

아그래 그림과 같이 환경변수를 이용해 파드의 메타데이터와 속성을 파드에 노출한다.
image

파드를 만든 후에 아래와 같이 kubectl exec 를 사용해서 컨테이너의 모든 환경변수를 확인

$ kubectl 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.0.0.10
NODE_NAME=gke-kubia-default-pool-32a2cac8-sgl7
SERVICE_ACCOUNT=default
CONTAINER_CPU_REQUEST_MILLICORES=15
KUBERNETES_SERVICE_HOST=10.3.240.1
KUBERNETES_SERVICE_PORT=443
...

8.1.3 downward API 볼륨에 파일로 메타데이터 전달

-환경변수가 아닌 파일로 메타데이터를 노출하기위해 downwardAPI 볼륨을 정의하고 컨테이너에 마운트한다.

apiVersion: v1
kind: Pod
metadata:
  name: downward
  labels:                         # 이 레이블과 어노테이션은 downward API 볼륨으로 노출된다.
    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:            # downward 볼륨은 /etc/downward아래에 마운트
    - name: downward
      mountPath: /etc/downward
  volumes:
  - name: downward         # downwardAPI 볼륨은 downward 이름으로 정의
    downwardAPI:                
      items:
      - path: "podName"         # 파드의 이름(매니페스트에 있는 metadata.name 필드)은 podName파일에 기록된다.
        fieldRef:
          fieldPath: metadata.name
      - path: "podNamespace"
        fieldRef:
          fieldPath: metadata.namespace
      - path: "labels"               # 파드의 레이블은  /etc/downward/labels 파일에 기록된다.
        fieldRef:
          fieldPath: metadata.labels
      - path: "annotations"       # 파드의 어노테이션을  /etc/downward/annotations 파일에 기록된다.
        fieldRef:
          fieldPath: metadata.annotations
      - path: "containerCpuRequestMilliCores"
        resourceFieldRef:
          containerName: main
          resource: requests.cpu
          divisor: 1m
      - path: "containerMemoryLimitBytes"
        resourceFieldRef:
          containerName: main
          resource: limits.memory
          divisor: 1
  • 환경변수 대신 downward 라는 볼륨을 정의하고 컨테이너의 /Etc/downward 아래에 마운트한 것이다.
    image

  • 파일을 조회하면 아래와 같이 확인할 수 있다.

    • 각 파일은 볼륨 정의의 항목에 해당한다.
$ kubectl exec downward ls -l /etc/downward
error: unknown shorthand flag: 'l' in -l
See 'kubectl exec --help' for usage.
$ kubectl exec downward ls /etc/downward
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
annotations
containerCpuRequestMilliCores
containerMemoryLimitBytes
labels
podName
podNamespace
$ kubectl exec downward cat /etc/downward/labels
foo="bar"

$kubectl exec downward cat /etc/downward/annotations
key1="value1"
key2="multi\nline\nvalue\n"
kubernetes.io/config/seen="2023-01-06T00:04:45.6381834014Z"
kubernetes.io/config.source="api"
  • 파드가 실행되고 있을때도 파일을 업데이트하면 레이블과 어노테이션이 수정되어 반영된다.
  • 환경변수의 값은 나중에 업데이트할 수 없기 때문에 파드의 환경변수로 노출된 레이블 또는 어노테이션은 업데이트 될 수 없다.

@thesun4sky
Copy link

thesun4sky commented Jan 7, 2023

8.2 쿠버네티스 API 서버와 통신하기

  • Downward API가 특정 파드와 컨테이너의 메타데이터를 전달하는것을 보았다.
  • 그러나 클러스터에 정의된 다른 파드나 리소스에대한 더많은 정보가 필요할 땐, API서버와 직접 소통해야한다.
    image

8.2.1 쿠버네티스 REST API 살펴보기

  • API서버의 URL얻기
$ kubectl cluster-info
Kubernetes control plane is running at https://34.68.118.85
GLBCDefaultBackend is running at https://34.68.118.85/api/v1/namespaces/kube-system/services/default-http-backend:http/proxy
KubeDNS is running at https://34.68.118.85/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
KubeDNSUpstream is running at https://34.68.118.85/api/v1/namespaces/kube-system/services/kube-dns-upstream:dns/proxy
Metrics-server is running at https://34.68.118.85/api/v1/namespaces/kube-system/services/https:metrics-server:/proxy
  • 접속하려면 인증서가 필요하다.
$ curl https://34.68.118.85 -k
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "forbidden: User \"system:anonymous\" cannot get path \"/\"",
  "reason": "Forbidden",
  "details": {},
  "code": 403
}
  • 하지만 프록시 명령으로 인증서없이 통신할 수 있다.

kubectl proxy 명령은 프록시 서버를 실행해 로컬 컴퓨터에서 HTTP연결을 수신하고, 이 연결 인증을 관리하면서 API 서버로 전달하기 때문에, 요청할 때마다 인증 토큰을 전달할 필요가 없다.

$ kubectl proxy
Starting to serve on 127.0.0.1:8001
  • 해당 주소로 연결하면 된다.

kubectl은 필요한 모든 것(API 서버 URL, 인증 토큰 등)을 이미 알고 있으므로 프록시 되고있는 8001번 포트를 통해 연결을 수신하기 시작한다.
proxy > API 서버 > proxy
아래 경로들은 파드, 서비스 등과 같은 리소스를 생성할 때 리소스 정의에 지정한 API 그룹과 버전에 해당한다 .

$ curl http://localhost:8001
{
  "paths": [
    "/.well-known/openid-configuration",      
    "/api",              # 리소스 타입들
    "/api/v1",
    "/apis",
    "/apis/",
    "/apis/admissionregistration.k8s.io",
    "/apis/admissionregistration.k8s.io/v1",
    "/apis/apiextensions.k8s.io",
    "/apis/apiextensions.k8s.io/v1",
    "/apis/apiregistration.k8s.io",
    "/apis/apiregistration.k8s.io/v1",
    "/apis/apps",
    "/apis/apps/v1",
    ...
    "/apis/batch",        # 배치 API 그룹
    "/apis/batch/v1",
    ...
  • 배치 api 그룹
$ curl http://localhost:8001/apis/batch
{
  "kind": "APIGroup",
  "apiVersion": "v1",
  "name": "batch",
  "versions": [          # 배치 API 그룹은 2가지 버전을 갖는다.
    {
      "groupVersion": "batch/v1",
      "version": "v1"
    },
    {
      "groupVersion": "batch/v1beta1",
      "version": "v1beta1"
    }
  ],
  "preferredVersion": {            # 클라이언트는 v1 버전을 사용해야 한다.
    "groupVersion": "batch/v1",
    "version": "v1"
  }
  • 배치 api 내 리소스 유형

아래와 같이 batch/v1 API 그룹에서 노출된 리소스 유형 및 REST 엔드포인트 목록을 반환한다.

$ curl http://localhost:8001/apis/batch/v1
{
  "kind": "APIResourceList",        # batch/v1 API 그룹내의 API 리소스 목록
  "apiVersion": "v1",
  "groupVersion": "batch/v1",
  "resources": [
    {
      "name": "cronjobs",             # 네임스페이스 지정된(true로 설정된) 잡 리소스에 관한 설명 (/apis/batch/v1/cronjobs)
      "singularName": "",
      "namespaced": true,
      "kind": "CronJob",
      "verbs": [                              # 사용할 수 있는 동사(동작)
        "create",
        "delete",
        "deletecollection",
        "get",
        "list",
        "patch",
        "update",
        "watch"
      ],
    },
    {
      "name": "cronjobs/status",         # cronjobs 의 상태만 변경 가능한 API 엔드포인트
      "singularName": "",
      "namespaced": true,
      "kind": "CronJob",
      "verbs": [
        "get",
        "patch",
        "update"
      ]
    },
     ....
    }
  ]
  • 클러스터에 있는 모든 잡 인스턴스를 나열해보자
$ curl http://localhost:8001/apis/batch/v1/jobs
{
  "kind": "JobList",
  "apiVersion": "batch/v1",
  "metadata": {
    "resourceVersion": "449081"
  },
  "items": []

처음엔 아무 잡도 없기 때문에 items 가 비어있다.
아래와 같이 my-job.yaml 으로 잡을 띄우고 다시 조회해보자.

apiVersion: batch/v1
kind: Job
metadata:
  name: my-job
spec:
  template:
    metadata:
      labels:
        app: batch-job
    spec:
      restartPolicy: OnFailure
      containers:
      - name: main
        image: luksa/batch-job       # 교재에서 제공해주는 샘플 잡
$ kubectl apply -f my-job.yaml
Warning: Autopilot set default resource requests for Job default/my-job, as resource requests were not specified. See http://g.co/gke/autopilot-defaults
job.batch/my-job created

$ curl http://localhost:8001/apis/batch/v1/jobs
{
  "kind": "JobList",
  "apiVersion": "batch/v1",
  "metadata": {
    "resourceVersion": "451356"
  },
  "items": [
    {
      "metadata": {
        "name": "my-job",       # 방금 띄워준 my-job 이 Items에 조회된다.
        "namespace": "default",
        "uid": "0268927a-5050-480f-9423-826c1545f06e",
        "resourceVersion": "451332",
        "generation": 1,
        "creationTimestamp": "2023-01-07T15:06:31Z",
        "labels": {
          "app": "batch-job"
        },
        ....
     ]
}
  • 엔드포인트에 이름을 설정하여 특정 잡 인스턴스를 검색할 수 있다.

namespaces/{namespaces}/jobs/{job-name}

$ curl http://localhost:8001/apis/batch/v1/namespaces/default/jobs/my-job
{
  "kind": "Job",
  "apiVersion": "batch/v1",
  "metadata": {
    "name": "my-job",
    "namespace": "default",
    "uid": "0268927a-5050-480f-9423-826c1545f06e",
    "resourceVersion": "454271",
    "generation": 1,
    "creationTimestamp": "2023-01-07T15:06:31Z",
    "labels": {
      "app": "batch-job"
    },
   ...
}
  • 아래 명령어로도 동일하게 JSON 형태로 정보를 얻을 수 있다.
$ kubectl get job my-job -o json
{
    "apiVersion": "batch/v1",
    "kind": "Job",
    "metadata": {
        "annotations": {
            "autopilot.gke.io/resource-adjustment": "{\"input\":{\"containers\":[{\"name\":\"main\"}]},\"output\":{\"containers\":[{\"limits\":{\"cpu\":\"500m\",\"ephemeral-storage\":\"1Gi\",\"memory\":\"2Gi\"},\"requests\":{\"cpu\":\"500m\",\"ephemeral-storage\":\"1Gi\",\"memory\":\"2Gi\"},\"name\":\"main\"}]},\"modified\":true}",
            "batch.kubernetes.io/job-tracking": "",
            "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"batch/v1\",\"kind\":\"Job\",\"metadata\":{\"annotations\":{},\"name\":\"my-job\",\"namespace\":\"default\"},\"spec\":{\"template\":{\"metadata\":{\"labels\":{\"app\":\"batch-job\"}},\"spec\":{\"containers\":[{\"image\":\"luksa/batch-job\",\"name\":\"main\"}],\"restartPolicy\":\"OnFailure\"}}}}\n"
        },
        "creationTimestamp": "2023-01-07T15:06:31Z",
        "generation": 1,
        "labels": {
            "app": "batch-job"
        },
        "name": "my-job",
        "namespace": "default",
        "resourceVersion": "454271",
        "uid": "0268927a-5050-480f-9423-826c1545f06e"
    },
    ...
}

image

8.2.2 파드 내에서 API 서버와 통신

  • 8.2.1 에서는 kubectl proxy를 사용해 로컬에서 API 서버와 통신하는 방법을 배웠다.

  • kubectl이 없는 파드내에서 통신하는방법을 알아보자. 🔢

    1. API서버 위치 찾기
    2. API서버와 통신하고 있는지 확인 (가짜 API서버가 아닌것을 확인)
    3. API서버로 인증
  • API통신을 위한 파드실행

apiVersion: v1
kind: Pod
metadata:
  name: curl
spec:
  containers:
  - name: main
    image: tutum/curl          # 컨테이너에서 curl을 사용해야 하기 때문에 tutum/curl 이미지 사용
    command: ["sleep", "9999999"]      # 컨테이너가 계속 실행되도록 하려고 지연 시간이 길게 sleep 커맨드를 실행한다.

위와 같이 띄우면 Docker Image 를 pulling 해올때 아래와 같이 에러가 발생한다.

kubectl get pods
NAME       READY   STATUS             RESTARTS   AGE
curl       0/1     ImagePullBackOff   0          4m1s
  • 도커 허브 이슈 #1672 를 보면 tutum/curl 이미지는 삭제되었고 대신에 curlimages/curl 이미지를 사용하라고 가이드 되어있다.
$ kubectl exec -it curl bash
root@curl:/#

위와 같이 bash 명령을 날리면 $PATH 경로를 찾을 수 없다고 나와서(아마도 환경변수 설정이 안되있는듯) /bin/sh 로 명령을 날려야 한다.

$ kubectl exec -it curl /bin/sh
/ $ 
  • API서버 주소찾기
$ kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.8.128.1   <none>        443/TCP   11h
/ $ env | grep KUBERNETES_SERVICE
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_SERVICE_HOST=10.8.128.1
  • 각 서비스마다 DNS 엔트리가 있기 때문에 환경변수 조회할 필요없이, 단순시 curl에서 https://kubernetes 을 조회하기만 하면 된다.
$ kubectl exec -it curl /bin/sh
/ $ curl https://kubernetes
curl: (60) SSL certificate problem: unable to get local issuer certificate
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 web page mentioned above.

하지만 조회하려고 하면 위와 같이 서버 인증서 확인이 안되었기 때문에 조회가 실패한다.

  • 서버의 아이덴티티 검증 (서버 인증서 확인하기)
    7장에서 시크릿을 설명했던 내용중에, 각 컨테이너의 /var/run/secrets/kubernetes.io/service/account 에 마운트되는 자동생성된 default-token-xyz 라는 이름의 시크릿이 있다. 이걸로 시크릿의 내용을 살펴본다.
/ $ ls /var/run/secrets/kubernetes.io/serviceaccount/
ca.crt     namespace  token

위 파일중 ca.crt 파일이 API 서버의 인증서를 서명하는 데 사용되는 인증 기관(CA)의 인증서이다.
2. API 서버와 통신확인 을 위해서 서버의 인증서가 CA로 서명됐는지 확인하면 된다.

/ $ 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
}

아직 인증에 실패한다.

  • 우선 아래 명령을 통해 --cacert 지정을 환경변수로 대신해준다.
/$ export CURL_CA_BUNDLE=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt

아래와 같이 동일한 명령을 간단하게 요청할 수 있다. (아직 인증은 안됨)

/ $ curl https://kubernetes
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "forbidden: User \"system:anonymous\" cannot get path \"/\"",
  "reason": "Forbidden",
  "details": {},
  "code": 403
}
  • API서버로 인증
    이제 인증을 제대로 해보자....
    먼저 아래와 같이 토큰을 환경변수에 로드하고, 이를 사용해 API 서버에 액세스한다.
/$ TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)

환경변수 토큰을 활용해서 API 서버에 억세스 해본다.

/ $ curl -H "Authorization: Bearer $TOKEN" https://kubernetes
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "forbidden: User \"system:serviceaccount:default:default\" cannot get path \"/\"",
  "reason": "Forbidden",
  "details": {},
  "code": 403
}

여전히 실패한다....

  • RBAC가 활성화 된 쿠버네티스에서는 서비스어카운트 등록해야 한다.(기본적으로 활성화 되어있음)
    아래 명령어로 모든 서비스 어카운트(모든 파드)에 클러스터 관리자 권한이 부여돼 원하는 대로 액세스 할 수 있다.

이 방법은 위험하지만 테스트 목적으로는 괜찮다. 12장에서 RBAC에 대해서 배우면서 정상적인 방법을 알려 줄 것이다.

$ kubectl create clusterrolebinding permissive-binding --clusterrole=cluster-admin --group=system:serviceaccounts
clusterrolebinding.rbac.authorization.k8s.io/permissive-binding created

이제 아래와 같이 모든 API 서버를 정상 조회할 수 있다. 👍

/ $ curl -H "Authorization: Bearer $TOKEN" https://kubernetes
{
  "paths": [
    "/.well-known/openid-configuration",
    "/api",
    "/api/v1",
    "/apis",
    "/apis/",
    "/apis/admissionregistration.k8s.io",
    "/apis/admissionregistration.k8s.io/v1",
    "/apis/apiextensions.k8s.io",
    "/apis/apiextensions.k8s.io/v1",
    "/apis/apiregistration.k8s.io",
    "/apis/apiregistration.k8s.io/v1",
    "/apis/apps",
    "/apis/apps/v1",
    ...
    ]
}
  • 파드가 실행중인 네임스페이스 얻기
    • 파드가 어떤 네임스페이스에서 실행중인지 알아보자
    • 시크릿 볼륨에 있는 3개의 파일을 모두 사용하여 동일한 네임스페이스에서 실행중인 모든 파드를 나열한다.
/ $ 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": "489452"
  },
  "items": [
    {
      "metadata": {
        "name": "curl",
        "namespace": "default",
        ...
     },
    ...실행중인 모든 파드...
}

위와 같은 방식으로 다른 API 오브젝트를 검색하고 GET, PUT, PATCH 를 전송해 업데이트도 할 수 있다. 💯

  • 파드각 쿠버네티스와 통신하는 방법 정리 🔢
    • 애플리케이션은 API 서버의 인증서가 인증 기관으로부터 서명됐는지를 검증해야하며, 인증 기관의 인증서는 ca.cart파일에 있다.
    • 애플리케이션은 token 파일의 내용을 Authorization HTTP 헤더에 Bearer 토큰으로 넣어 전송해서 자신을 인증해야 한다.
    • namespace 파일은 파드의 네임스페이스 안에 있는 API 오브젝트의 CRUD 작업을 수행할 때 네임스페이스를 API 서버로 전달하는 데 사용해야 한다.
      image

8.2.3 앰배서더 컨테이너를 이용한 API 서버 통신 간소화

  • 인증서의 유효성검사를 조금더 간단히 해보자. API서버로 직접 요청을 보내는 대신 프록시로 요청을 보내 검증을 처리하게 하자.

  • 이건 보안을 유지하면서 통신을 간단하게 만드는 방법이다.

  • kubectl proxy 와 동일한 기능을 수행하는 메인 컨테이너 옆에 앰배서더 컨테이너가 HTTPS 연결 처리 및 시크릿 설정을 대신하도록 한다.

  • 이를 통해 메인 컨테이너는 HTTP 로 인증서 절차 없이 액세스 할 수 있다.
    image

  • 아래와 같이 앰배서더를 포함한 2개의 컨테이너가 존재하는 파드를 배포 하자

apiVersion: v1
kind: Pod
metadata:
  name: curl-with-ambassador
spec:
  containers:
  - name: main
    image: curlimages/curl     # 여기도 curlimages/curl 로 바꿔준다
    command: ["sleep", "9999999"]
  - name: ambassador
    image: luksa/kubectl-proxy:1.6.2    # kubectl-rpoxy 이미지를 실행하는 앰버서더 컨테이너 이미지

bash 명령도 /bin/sh 로 바꿔서 실행해본다.

$ kubectl exec -it curl-with-ambassador -c main /bin/sh
/ $

위처럼 컨테이너가 두개여서 -c옵션을 통해 main 컨테이너라는걸 명시해줘야 한다.

  • 이제 localhost 로 그냥 조회할 수 있다. 👍
/ $ curl localhost:8001
{
  "paths": [
    "/.well-known/openid-configuration",
    "/api",
    "/api/v1",
    "/apis",
    "/apis/",
    "/apis/admissionregistration.k8s.io",
    "/apis/admissionregistration.k8s.io/v1",
    "/apis/apiextensions.k8s.io",
    "/apis/apiextensions.k8s.io/v1",
    "/apis/apiregistration.k8s.io",
    "/apis/apiregistration.k8s.io/v1",
    "/apis/apps",
    "/apis/apps/v1",
    ...
  ]
}

복잡성을 숨기고, 메인컨테이너를 단순화시킬 수 있고 여러 어플리케이션에서 재사용 할 수 있지만, 추가프로세스와 추가리소스를 소비한다는것이 단점이다.

8.2.4 클라이언트 라이브러리를 사용해 API 서버와 통신

  • 단순한 API요청 이상의 수행하려면 라이브러리를 사용하는것이 좋다.
  • 공식적으로 지원하는 Golang, Python 외에도 Java, Node.js 등.. 다양한 라이브러리가 있다.
  • 아래처럼 Java 라이브러리로 복잡한기능을 만들 수 있다.
import java.util.Arrays;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.PodList;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClient;

public class Test {
  public static void main(String[] args) throws Exception {
    KubernetesClient client = new DefaultKubernetesClient();

    // list pods in the default namespace
    PodList pods = client.pods().inNamespace("default").list();
    pods.getItems().stream()
      .forEach(s -> System.out.println("Found pod: " +
               s.getMetadata().getName()));

    // create a pod
    System.out.println("Creating a pod");
    Pod pod = client.pods().inNamespace("default")
      .createNew()
      .withNewMetadata()
        .withName("programmatically-created-pod")
      .endMetadata()
      .withNewSpec()
        .addNewContainer()
          .withName("main")
          .withImage("busybox")
          .withCommand(Arrays.asList("sleep", "99999"))
        .endContainer()
      .endSpec()
      .done();
    System.out.println("Created pod: " + pod);

    // edit the pod (add a label to it)
    client.pods().inNamespace("default")
      .withName("programmatically-created-pod")
      .edit()
      .editMetadata()
        .addToLabels("foo", "bar")
      .endMetadata()
      .done();
    System.out.println("Added label foo=bar to pod");

    System.out.println("Waiting 1 minute before deleting pod...");
    Thread.sleep(60000);

    // delete the pod
    client.pods().inNamespace("default")
      .withName("programmatically-created-pod")
      .delete();
    System.out.println("Deleted the pod");
  }
}
  • 그외에도 스웨거 API를 활성화 시켜서 사용하는 방법도 있다. (REST API를 탐색하는 더 좋은 방법)

@thesun4sky
Copy link

thesun4sky commented Jan 7, 2023

8.3 요약

image

  • 파드의 이름, 네임스페이스 및 기타 메타데이터가 환경변수 또는 downward API 볼륨의 파일로 컨테이너 내부의 프로세스에 노출되는 방법
  • CPU와 메모리의 요청 및 제한이 필요한 단위로 애플리케이션에 전달되는 방법
  • 파드에서 downward API 볼륨을 사용해 파드가 살아있는 동안 변경될 수 있는 최신 메타데이터를 얻는 방법(레이블과 어노테이션)
  • kubectl proxy로 쿠버네티스 REST API를 탐색하는 방법
  • 쿠버네티스에 정의된 다른 서비스와 같은 방식으로 파드가 환경변수 또는 DNS로 API 서버의 위치를 찾는 방법
  • 파드에서 실행되는 애플리케이션이 API서버와 통신하는지 검증하고, 자신을 인증하는 방법
  • 앰배서더 컨테이너를 사용해 애플리케이션 내에서 API 서버와 훨씬 간단하게 통신하는방법
  • 클라이언트 라이브러리로 쉽게 쿠버네티스와 상호작용할 수 있는 방법

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants