1 - 컨테이너를 위한 커맨드와 인자 정의하기

본 페이지는 파드 안에서 컨테이너를 실행할 때 커맨드와 인자를 정의하는 방법에 대해 설명한다.

시작하기 전에

쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.

버전 확인을 위해서, 다음 커맨드를 실행 kubectl version.

파드를 생성할 때 커맨드와 인자를 정의하기

파드를 생성할 때, 파드 안에서 동작하는 컨테이너를 위한 커맨드와 인자를 정의할 수 있다. 커맨드를 정의하기 위해서는, 파드 안에서 실행되는 컨테이너에 command 필드를 포함시킨다. 커맨드에 대한 인자를 정의하기 위해서는, 구성 파일에 args 필드를 포함시킨다. 정의한 커맨드와 인자들은 파드가 생성되고 난 이후에는 변경될 수 없다.

구성 파일 안에서 정의하는 커맨드와 인자들은 컨테이너 이미지가 제공하는 기본 커맨드와 인자들보다 우선시 된다. 만약 인자들을 정의하고 커맨드를 정의하지 않는다면, 기본 커맨드가 새로운 인자와 함께 사용된다.

이 예제에서는 한 개의 컨테이너를 실행하는 파드를 생성한다. 파드를 위한 구성 파일에서 커맨드와 두 개의 인자를 정의한다.

apiVersion: v1
kind: Pod
metadata:
  name: command-demo
  labels:
    purpose: demonstrate-command
spec:
  containers:
  - name: command-demo-container
    image: debian
    command: ["printenv"]
    args: ["HOSTNAME", "KUBERNETES_PORT"]
  restartPolicy: OnFailure
  1. YAML 구성 파일을 활용해 파드를 생성한다.

    kubectl apply -f https://k8s.io/examples/pods/commands.yaml
    
  2. 실행 중인 파드들의 목록을 조회한다.

    kubectl get pods
    

    출력은 command-demo라는 파드 안에서 실행된 컨테이너가 완료되었다고 표시할 것이다.

  3. 컨테이너 안에서 실행된 커맨드의 출력을 보기 위해, 파드의 로그를 확인한다.

    kubectl logs command-demo
    

    출력은 HOSTNAME과 KUBERNETES_PORT 환경 변수들의 값들을 표시할 것이다.

    command-demo
    tcp://10.3.240.1:443
    

인자를 정의하기 위해 환경 변수를 사용하기

이전 예제에서는, 문자열을 제공하면서 직접 인자를 정의해보았다. 문자열을 직접 제공하는 것에 대한 대안으로, 환경 변수들을 사용하여 인자들을 정의할 수 있다.

env:
- name: MESSAGE
  value: "hello world"
command: ["/bin/echo"]
args: ["$(MESSAGE)"]

이것은 컨피그 맵시크릿을 포함해, 환경 변수를 정의하는데 활용할 수 있는 모든 방법들을 활용해서 파드를 위한 인자를 정의할 수 있다는 것을 의미한다.

셸 안에서 커맨드 실행하기

일부 경우들에서는 커맨드를 셸 안에서 실행해야할 필요가 있다. 예를 들어, 실행할 커맨드가 서로 연결되어 있는 여러 개의 커맨드들로 구성되어 있거나, 셸 스크립트일 수도 있다. 셸 안에서 커맨드를 실행하려고 한다면, 이런 방식으로 감싸주면 된다.

command: ["/bin/sh"]
args: ["-c", "while true; do echo hello; sleep 10;done"]

다음 내용

2 - 종속 환경 변수 정의하기

본 페이지는 쿠버네티스 파드의 컨테이너를 위한 종속 환경 변수를 정의하는 방법에 대해 설명한다.

시작하기 전에

쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.

컨테이너를 위한 종속 환경 변수 정의하기

파드를 생성할 때, 파드 안에서 동작하는 컨테이너를 위한 종속 환경 변수를 설정할 수 있다. 종속 환경 변수를 설정하려면, 구성 파일에서 envvalue에 $(VAR_NAME)을 사용한다.

이 예제에서, 한 개의 컨테이너를 실행하는 파드를 생성한다. 파드를 위한 구성 파일은 일반적인 방식으로 정의된 종속 환경 변수를 정의한다. 다음은 파드를 위한 구성 매니페스트 예시이다.

apiVersion: v1
kind: Pod
metadata:
  name: dependent-envars-demo
spec:
  containers:
    - name: dependent-envars-demo
      args:
        - while true; do echo -en '\n'; printf UNCHANGED_REFERENCE=$UNCHANGED_REFERENCE'\n'; printf SERVICE_ADDRESS=$SERVICE_ADDRESS'\n';printf ESCAPED_REFERENCE=$ESCAPED_REFERENCE'\n'; sleep 30; done;
      command:
        - sh
        - -c
      image: busybox:1.28
      env:
        - name: SERVICE_PORT
          value: "80"
        - name: SERVICE_IP
          value: "172.17.0.1"
        - name: UNCHANGED_REFERENCE
          value: "$(PROTOCOL)://$(SERVICE_IP):$(SERVICE_PORT)"
        - name: PROTOCOL
          value: "https"
        - name: SERVICE_ADDRESS
          value: "$(PROTOCOL)://$(SERVICE_IP):$(SERVICE_PORT)"
        - name: ESCAPED_REFERENCE
          value: "$$(PROTOCOL)://$(SERVICE_IP):$(SERVICE_PORT)"
  1. YAML 구성 파일을 활용해 파드를 생성한다.

    kubectl apply -f https://k8s.io/examples/pods/inject/dependent-envars.yaml
    
    pod/dependent-envars-demo created
    
  2. 실행 중인 파드의 목록을 조회한다.

    kubectl get pods dependent-envars-demo
    
    NAME                      READY     STATUS    RESTARTS   AGE
    dependent-envars-demo     1/1       Running   0          9s
    
  3. 파드 안에서 동작 중인 컨테이너의 로그를 확인한다.

    kubectl logs pod/dependent-envars-demo
    
    
    UNCHANGED_REFERENCE=$(PROTOCOL)://172.17.0.1:80
    SERVICE_ADDRESS=https://172.17.0.1:80
    ESCAPED_REFERENCE=$(PROTOCOL)://172.17.0.1:80
    

위에서 보듯이, SERVICE_ADDRESS는 올바른 종속성 참조, UNCHANGED_REFERENCE는 잘못된 종속성 참조를 정의했으며 ESCAPED_REFERENCE는 종속성 참조를 건너뛴다.

환경 변수가 참조될 때 해당 환경 변수가 미리 정의되어 있으면 SERVICE_ADDRESS의 경우와 같이 참조를 올바르게 해석할 수 있다.

환경 변수가 정의되지 않았거나 일부 변수만 포함된 경우, 정의되지 않은 환경 변수는 UNCHANGED_REFERENCE의 경우와 같이 일반 문자열로 처리된다. 일반적으로 환경 변수 해석에 실패하더라도 컨테이너의 시작을 막지는 않는다.

$(VAR_NAME) 구문은 이중 $로 이스케이프될 수 있다. (예: $$(VAR_NAME)) 이스케이프된 참조는 참조된 변수가 정의되었는지 여부에 관계없이 해석을 수행하지 않는다. 이는 위의 ESCAPED_REFERENCE를 통해 확인할 수 있다.

다음 내용

3 - 컨테이너를 위한 환경 변수 정의하기

본 페이지는 쿠버네티스 파드의 컨테이너를 위한 환경 변수를 정의하는 방법에 대해 설명한다.

시작하기 전에

쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.

버전 확인을 위해서, 다음 커맨드를 실행 kubectl version.

컨테이너를 위한 환경 변수 정의하기

파드를 생성할 때, 파드 안에서 동작하는 컨테이너를 위한 환경 변수를 설정할 수 있다. 환경 변수를 설정하려면, 구성 파일에 envenvFrom 필드를 포함시켜야 한다.

이 예제에서, 한 개의 컨테이너를 실행하는 파드를 생성한다. 파드를 위한 구성 파일은 DEMO_GREETING 이라는 이름과 "Hello from the environment"이라는 값을 가지는 환경 변수를 정의한다. 다음은 파드를 위한 구성 매니페스트 예시이다.

apiVersion: v1
kind: Pod
metadata:
  name: envar-demo
  labels:
    purpose: demonstrate-envars
spec:
  containers:
  - name: envar-demo-container
    image: gcr.io/google-samples/node-hello:1.0
    env:
    - name: DEMO_GREETING
      value: "Hello from the environment"
    - name: DEMO_FAREWELL
      value: "Such a sweet sorrow"
  1. YAML 구성 파일을 활용해 파드를 생성한다.

    kubectl apply -f https://k8s.io/examples/pods/inject/envars.yaml
    
  2. 실행 중인 파드들의 목록을 조회한다.

    kubectl get pods -l purpose=demonstrate-envars
    

    출력은 아래와 비슷할 것이다.

    NAME            READY     STATUS    RESTARTS   AGE
    envar-demo      1/1       Running   0          9s
    
  3. 파드의 컨테이너 환경 변수를 나열한다.

    kubectl exec envar-demo -- printenv
    

    출력은 아래와 비슷할 것이다.

    NODE_VERSION=4.4.2
    EXAMPLE_SERVICE_PORT_8080_TCP_ADDR=10.3.245.237
    HOSTNAME=envar-demo
    ...
    DEMO_GREETING=Hello from the environment
    DEMO_FAREWELL=Such a sweet sorrow
    

설정 안에서 환경 변수 사용하기

파드의 구성 파일 안에서 정의한 환경 변수는 파드의 컨테이너를 위해 설정하는 커맨드와 인자들과 같이, 구성 파일 안의 다른 곳에서 사용할 수 있다. 아래의 구성 파일 예시에서, GREETING, HONORIFIC, 그리고 NAME 환경 변수들이 각각 Warm greetings to, The Most honorable, 그리고 Kubernetes로 설정되어 있다. 이 환경 변수들은 이후 env-print-demo 컨테이너에 전달되어 CLI 인자에서 사용된다.

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)"]

컨테이너가 생성되면, echo Warm greetings to The Most Honorable Kubernetes 커맨드가 컨테이너에서 실행된다.

다음 내용

4 - 환경 변수로 컨테이너에 파드 정보 노출하기

본 페이지는 파드에서 실행 중인 컨테이너에게 파드가 환경 변수를 사용해서 자신의 정보를 노출하는 방법에 대해 설명한다. 환경 변수는 파드 필드와 컨테이너 필드를 노출할 수 있다.

시작하기 전에

쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.

버전 확인을 위해서, 다음 커맨드를 실행 kubectl version.

다운워드(Downward) API

파드 및 컨테이너 필드를 실행 중인 컨테이너에 노출하는 두 가지 방법이 있다.

파드 및 컨테이너 필드를 노출하는 이 두 가지 방법을 다운워드 API라고 한다.

파드 필드를 환경 변수의 값으로 사용하자

이 연습에서는 하나의 컨테이너를 가진 파드를 생성한다. 다음은 파드에 대한 구성 파일이다.

apiVersion: v1
kind: Pod
metadata:
  name: dapi-envars-fieldref
spec:
  containers:
    - name: test-container
      image: k8s.gcr.io/busybox
      command: [ "sh", "-c"]
      args:
      - while true; do
          echo -en '\n';
          printenv MY_NODE_NAME MY_POD_NAME MY_POD_NAMESPACE;
          printenv MY_POD_IP MY_POD_SERVICE_ACCOUNT;
          sleep 10;
        done;
      env:
        - name: MY_NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        - name: MY_POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: MY_POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: MY_POD_IP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
        - name: MY_POD_SERVICE_ACCOUNT
          valueFrom:
            fieldRef:
              fieldPath: spec.serviceAccountName
  restartPolicy: Never

구성 파일에서 5개의 환경 변수를 확인할 수 있다. env 필드는 EnvVars의 배열이다. 배열의 첫 번째 요소는 MY_NODE_NAME 환경 변수가 파드의 spec.nodeName 필드에서 값을 가져오도록 지정한다. 마찬가지로 다른 환경 변수도 파드 필드에서 이름을 가져온다.

파드를 생성한다.

kubectl apply -f https://k8s.io/examples/pods/inject/dapi-envars-pod.yaml

파드의 컨테이너가 실행중인지 확인한다.

kubectl get pods

컨테이너의 로그를 본다.

kubectl logs dapi-envars-fieldref

출력은 선택된 환경 변수의 값을 보여준다.

minikube
dapi-envars-fieldref
default
172.17.0.4
default

이러한 값이 로그에 출력된 이유를 보려면 구성 파일의 commandargs 필드를 확인하자. 컨테이너가 시작되면 5개의 환경 변수 값을 stdout에 쓰며 10초마다 이를 반복한다.

다음으로 파드에서 실행 중인 컨테이너의 셸을 가져오자.

kubectl exec -it dapi-envars-fieldref -- sh

셸에서 환경 변수를 보자.

/# printenv

출력은 특정 환경 변수에 파드 필드 값이 할당되었음을 보여준다.

MY_POD_SERVICE_ACCOUNT=default
...
MY_POD_NAMESPACE=default
MY_POD_IP=172.17.0.4
...
MY_NODE_NAME=minikube
...
MY_POD_NAME=dapi-envars-fieldref

컨테이너 필드를 환경 변수의 값으로 사용하기

이전 연습에서는 파드 필드를 환경 변수의 값으로 사용했다. 이 다음 연습에서는 컨테이너 필드를 환경 변수의 값으로 사용한다. 다음은 하나의 컨테이너가 있는 파드의 구성 파일이다.

apiVersion: v1
kind: Pod
metadata:
  name: dapi-envars-resourcefieldref
spec:
  containers:
    - name: test-container
      image: k8s.gcr.io/busybox:1.24
      command: [ "sh", "-c"]
      args:
      - while true; do
          echo -en '\n';
          printenv MY_CPU_REQUEST MY_CPU_LIMIT;
          printenv MY_MEM_REQUEST MY_MEM_LIMIT;
          sleep 10;
        done;
      resources:
        requests:
          memory: "32Mi"
          cpu: "125m"
        limits:
          memory: "64Mi"
          cpu: "250m"
      env:
        - name: MY_CPU_REQUEST
          valueFrom:
            resourceFieldRef:
              containerName: test-container
              resource: requests.cpu
        - name: MY_CPU_LIMIT
          valueFrom:
            resourceFieldRef:
              containerName: test-container
              resource: limits.cpu
        - name: MY_MEM_REQUEST
          valueFrom:
            resourceFieldRef:
              containerName: test-container
              resource: requests.memory
        - name: MY_MEM_LIMIT
          valueFrom:
            resourceFieldRef:
              containerName: test-container
              resource: limits.memory
  restartPolicy: Never

구성 파일에서 4개의 환경 변수를 확인할 수 있다. env 필드는 EnvVars의 배열이다. 배열의 첫 번째 요소는 MY_CPU_REQUEST 환경 변수가 test-container라는 컨테이너의 requests.cpu 필드에서 값을 가져오도록 지정한다. 마찬가지로 다른 환경 변수도 컨테이너 필드에서 값을 가져온다.

파드를 생성한다.

kubectl apply -f https://k8s.io/examples/pods/inject/dapi-envars-container.yaml

파드의 컨테이너가 실행중인지 확인한다.

kubectl get pods

컨테이너의 로그를 본다.

kubectl logs dapi-envars-resourcefieldref

출력은 선택된 환경 변수의 값을 보여준다.

1
1
33554432
67108864

다음 내용

5 - 파일로 컨테이너에 파드 정보 노출하기

본 페이지는 파드가 DownwardAPIVolumeFile을 사용하여 파드에서 실행되는 컨테이너에 자신에 대한 정보를 노출하는 방법에 대해 설명한다. DownwardAPIVolumeFile은 파드 필드와 컨테이너 필드를 노출할 수 있다.

시작하기 전에

쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.

버전 확인을 위해서, 다음 커맨드를 실행 kubectl version.

다운워드(Downward) API

실행 중인 컨테이너에 파드 및 컨테이너 필드를 노출하는 방법에는 두 가지가 있다.

파드 및 컨테이너 필드를 노출하는 이 두 가지 방법을 "다운워드 API"라고 한다.

파드 필드 저장

이 연습에서는 하나의 컨테이너를 가진 파드를 생성한다. 다음은 파드에 대한 구성 파일이다.

apiVersion: v1
kind: Pod
metadata:
  name: kubernetes-downwardapi-volume-example
  labels:
    zone: us-est-coast
    cluster: test-cluster1
    rack: rack-22
  annotations:
    build: two
    builder: john-doe
spec:
  containers:
    - name: client-container
      image: k8s.gcr.io/busybox
      command: ["sh", "-c"]
      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;
      volumeMounts:
        - name: podinfo
          mountPath: /etc/podinfo
  volumes:
    - name: podinfo
      downwardAPI:
        items:
          - path: "labels"
            fieldRef:
              fieldPath: metadata.labels
          - path: "annotations"
            fieldRef:
              fieldPath: metadata.annotations

구성 파일에서 파드에 downwardAPI 볼륨이 있고 컨테이너가 /etc/podinfo에 볼륨을 마운트하는 것을 확인할 수 있다.

downwardAPI 아래의 배열을 살펴보자. 배열의 각 요소는 DownwardAPIVolumeFile이다. 첫 번째 요소는 파드의 metadata.labels 필드 값이 labels라는 파일에 저장되어야 함을 지정한다. 두 번째 요소는 파드의 annotations 필드 값이 annotations라는 파일에 저장되어야 함을 지정한다.

파드를 생성한다.

kubectl apply -f https://k8s.io/examples/pods/inject/dapi-volume.yaml

파드의 컨테이너가 실행 중인지 확인한다.

kubectl get pods

컨테이너의 로그를 본다.

kubectl logs kubernetes-downwardapi-volume-example

출력은 labels 파일과 annotations 파일의 내용을 보여준다.

cluster="test-cluster1"
rack="rack-22"
zone="us-est-coast"

build="two"
builder="john-doe"

파드에서 실행 중인 컨테이너의 셸을 가져온다.

kubectl exec -it kubernetes-downwardapi-volume-example -- sh

셸에서 labels 파일을 보자.

/# cat /etc/podinfo/labels

출력을 통해 모든 파드의 레이블이 labels 파일에 기록되었음을 확인할 수 있다.

cluster="test-cluster1"
rack="rack-22"
zone="us-est-coast"

마찬가지로 annotations 파일을 확인하자.

/# cat /etc/podinfo/annotations

etc/podinfo 디렉터리에 파일을 확인하자.

/# ls -laR /etc/podinfo

출력에서 labelsannotations 파일이 임시 하위 디렉터리에 있음을 알 수 있다. 이 예제에서는 ..2982_06_02_21_47_53.299460680이다. /etc/podinfo 디렉터리에서 ..data는 임시 하위 디렉토리에 대한 심볼릭 링크이다. /etc/podinfo 디렉토리에서 labelsannotations 또한 심볼릭 링크이다.

drwxr-xr-x  ... Feb 6 21:47 ..2982_06_02_21_47_53.299460680
lrwxrwxrwx  ... Feb 6 21:47 ..data -> ..2982_06_02_21_47_53.299460680
lrwxrwxrwx  ... Feb 6 21:47 annotations -> ..data/annotations
lrwxrwxrwx  ... Feb 6 21:47 labels -> ..data/labels

/etc/..2982_06_02_21_47_53.299460680:
total 8
-rw-r--r--  ... Feb  6 21:47 annotations
-rw-r--r--  ... Feb  6 21:47 labels

심볼릭 링크를 사용하면 메타데이터의 동적(dynamic) 원자적(atomic) 갱신이 가능하다. 업데이트는 새 임시 디렉터리에 기록되고, ..data 심볼릭 링크는 rename(2)을 사용하여 원자적(atomic)으로 갱신한다.

셸을 종료한다.

/# exit

컨테이너 필드 저장

이전 연습에서는 파드 필드를 DownwardAPIVolumeFile에 저장하였다. 이 다음 연습에서는 컨테이너 필드를 저장한다. 다음은 하나의 컨테이너를 가진 파드의 구성 파일이다.

apiVersion: v1
kind: Pod
metadata:
  name: kubernetes-downwardapi-volume-example-2
spec:
  containers:
    - name: client-container
      image: k8s.gcr.io/busybox:1.24
      command: ["sh", "-c"]
      args:
      - while true; do
          echo -en '\n';
          if [[ -e /etc/podinfo/cpu_limit ]]; then
            echo -en '\n'; cat /etc/podinfo/cpu_limit; fi;
          if [[ -e /etc/podinfo/cpu_request ]]; then
            echo -en '\n'; cat /etc/podinfo/cpu_request; fi;
          if [[ -e /etc/podinfo/mem_limit ]]; then
            echo -en '\n'; cat /etc/podinfo/mem_limit; fi;
          if [[ -e /etc/podinfo/mem_request ]]; then
            echo -en '\n'; cat /etc/podinfo/mem_request; fi;
          sleep 5;
        done;
      resources:
        requests:
          memory: "32Mi"
          cpu: "125m"
        limits:
          memory: "64Mi"
          cpu: "250m"
      volumeMounts:
        - name: podinfo
          mountPath: /etc/podinfo
  volumes:
    - name: podinfo
      downwardAPI:
        items:
          - path: "cpu_limit"
            resourceFieldRef:
              containerName: client-container
              resource: limits.cpu
              divisor: 1m
          - path: "cpu_request"
            resourceFieldRef:
              containerName: client-container
              resource: requests.cpu
              divisor: 1m
          - path: "mem_limit"
            resourceFieldRef:
              containerName: client-container
              resource: limits.memory
              divisor: 1Mi
          - path: "mem_request"
            resourceFieldRef:
              containerName: client-container
              resource: requests.memory
              divisor: 1Mi

구성 파일에서 파드에 downwardAPI 볼륨이 있고 컨테이너는 /etc/podinfo에 볼륨을 마운트하는 것을 확인할 수 있다.

downwardAPI 아래의 items 배열을 살펴보자. 배열의 각 요소는 DownwardAPIVolumeFile이다.

첫 번째 요소는 client-container라는 컨테이너에서 1m으로 지정된 형식의 limits.cpu 필드 값이 cpu_limit이라는 파일에 저장되어야 함을 지정한다. divisor 필드는 선택 사항이며 기본값인 1은 CPU에 대한 코어 및 메모리에 대한 바이트를 의미한다.

파드를 생성한다.

kubectl apply -f https://k8s.io/examples/pods/inject/dapi-volume-resources.yaml

파드에서 실행 중인 컨테이너의 셸을 가져온다.

kubectl exec -it kubernetes-downwardapi-volume-example-2 -- sh

셸에서 cpu_limit 파일을 확인한다.

/# cat /etc/podinfo/cpu_limit

비슷한 명령을 통해 cpu_request, mem_limitmem_request 파일을 확인할 수 있다.

다운워드 API의 기능

다음 정보는 환경 변수 및 downwardAPI 볼륨을 통해 컨테이너에서 사용할 수 있다.

  • fieldRef를 통해 다음 정보를 사용할 수 있다.

    • metadata.name - 파드의 이름
    • metadata.namespace - 파드의 네임스페이스(Namespace)
    • metadata.uid - 파드의 UID
    • metadata.labels['<KEY>'] - 파드의 레이블 <KEY> 값 (예를 들어, metadata.labels['mylabel'])
    • metadata.annotations['<KEY>'] - 파드의 어노테이션 <KEY> 값 (예를 들어, metadata.annotations['myannotation'])
  • resourceFieldRef를 통해 다음 정보를 사용할 수 있다.

    • 컨테이너의 CPU 한도(limit)
    • 컨테이너의 CPU 요청(request)
    • 컨테이너의 메모리 한도(limit)
    • 컨테이너의 메모리 요청(request)
    • 컨테이너의 hugepages 한도(limit) (DownwardAPIHugePages 기능 게이트(feature gate)가 활성화된 경우)
    • 컨테이너의 hugepages 요청(request) (DownwardAPIHugePages 기능 게이트(feature gate)가 활성화된 경우)
    • 컨테이너의 임시-스토리지 한도(limit)
    • 컨테이너의 임시-스토리지 요청(request)

downwardAPI 볼륨 fieldRef를 통해 다음 정보를 사용할 수 있다.

  • metadata.labels - 한 줄에 하나의 레이블이 있는 label-key="escaped-label-value" 형식의 모든 파드 레이블
  • metadata.annotations - 한 줄에 하나의 어노테이션이 있는 annotation-key="escaped-annotation-value" 형식의 모든 파드 어노테이션

환경 변수를 통해 다음 정보를 사용할 수 있다.

  • status.podIP - 파드의 IP 주소
  • spec.serviceAccountName - 파드의 서비스 계정 이름
  • spec.nodeName - 스케줄러가 항상 파드를 스케줄링하려고 시도할 노드의 이름
  • status.hostIP - 파드가 할당될 노드의 IP 주소

특정 경로 및 파일 권한에 대한 프로젝트 키

키(key)를 파드 안의 특정 경로에, 특정 권한으로, 파일 단위로 투영(project)할 수 있다. 자세한 내용은 시크릿(Secrets)을 참조한다.

다운워드 API에 대한 동기

컨테이너가 쿠버네티스에 과도하게 결합되지 않고 자체에 대한 정보를 갖는 것이 때때로 유용하다. 다운워드 API를 사용하면 컨테이너가 쿠버네티스 클라이언트 또는 API 서버를 사용하지 않고 자체 또는 클러스터에 대한 정보를 사용할 수 있다.

예를 들어 잘 알려진 특정 환경 변수에 고유 식별자가 있다고 가정하는 기존 애플리케이션이 있다. 한 가지 가능성은 애플리케이션을 래핑하는 것이지만 이는 지루하고 오류가 발생하기 쉬우며 낮은 결합 목표를 위반한다. 더 나은 옵션은 파드의 이름을 식별자로 사용하고 파드의 이름을 잘 알려진 환경 변수에 삽입하는 것이다.

다음 내용

  • 파드의 목표 상태(desired state)를 정의하는 PodSpec API 정의를 확인한다.
  • 컨테이너가 접근할 파드 내의 일반 볼륨을 정의하는 Volume API 정의를 확인한다.
  • 다운워드 API 정보를 포함하는 볼륨을 정의하는 DownwardAPIVolumeSource API 정의를 확인한다.
  • 다운워드 API 볼륨 내 파일을 채우기 위한 오브젝트 또는 리소스 필드로의 레퍼런스를 포함하는 DownwardAPIVolumeFile API 정의를 확인한다.
  • 컨테이너 리소스 및 이들의 출력 형식을 지정하는 ResourceFieldSelector API 정의를 확인한다.

6 - 시크릿(Secret)을 사용하여 안전하게 자격증명 배포하기

본 페이지는 암호 및 암호화 키와 같은 민감한 데이터를 파드에 안전하게 주입하는 방법을 설명한다.

시작하기 전에

쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.

시크릿 데이터를 base-64 표현으로 변환하기

사용자 이름 my-app과 비밀번호 39528$vdg7Jb의 두 가지 시크릿 데이터가 필요하다고 가정한다. 먼저 base64 인코딩 도구를 사용하여 사용자 이름과 암호를 base64 표현으로 변환한다. 다음은 일반적으로 사용 가능한 base64 프로그램을 사용하는 예제이다.

echo -n 'my-app' | base64
echo -n '39528$vdg7Jb' | base64

사용자 이름의 base-64 표현이 bXktYXBw이고 암호의 base-64 표현이 Mzk1MjgkdmRnN0pi임을 출력을 통해 확인할 수 있다.

시크릿 생성하기

다음은 사용자 이름과 암호가 들어 있는 시크릿을 생성하는 데 사용할 수 있는 구성 파일이다.

apiVersion: v1
kind: Secret
metadata:
  name: test-secret
data:
  username: bXktYXBw
  password: Mzk1MjgkdmRnN0pi
  1. 시크릿을 생성한다.

    kubectl apply -f https://k8s.io/examples/pods/inject/secret.yaml
    
  2. 시크릿에 대한 정보를 확인한다.

    kubectl get secret test-secret
    

    Output:

    NAME          TYPE      DATA      AGE
    test-secret   Opaque    2         1m
    
  3. 시크릿에 대한 자세한 정보를 확인한다.

    kubectl describe secret test-secret
    

    Output:

    Name:       test-secret
    Namespace:  default
    Labels:     <none>
    Annotations:    <none>
    
    Type:   Opaque
    
    Data
    ====
    password:   13 bytes
    username:   7 bytes
    

kubectl로 직접 시크릿 생성하기

Base64 인코딩 단계를 건너뛰려면 kubectl create secret 명령을 사용하여 동일한 Secret을 생성할 수 있다. 다음은 예시이다.

kubectl create secret generic test-secret --from-literal='username=my-app' --from-literal='password=39528$vdg7Jb'

이와 같이 더 편리하게 사용할 수 있다. 앞에서 설명한 자세한 접근 방식은 각 단계를 명시적으로 실행하여 현재 상황을 확인할 수 있다.

볼륨을 통해 시크릿 데이터에 접근할 수 있는 파드 생성하기

다음은 파드를 생성하는 데 사용할 수 있는 구성 파일이다.

apiVersion: v1
kind: Pod
metadata:
  name: secret-test-pod
spec:
  containers:
    - name: test-container
      image: nginx
      volumeMounts:
        # name must match the volume name below
        - name: secret-volume
          mountPath: /etc/secret-volume
  # The secret data is exposed to Containers in the Pod through a Volume.
  volumes:
    - name: secret-volume
      secret:
        secretName: test-secret
  1. 파드를 생성한다.

    kubectl apply -f https://k8s.io/examples/pods/inject/secret-pod.yaml
    
  2. 파드가 실행중인지 확인한다.

    kubectl get pod secret-test-pod
    

    Output:

    NAME              READY     STATUS    RESTARTS   AGE
    secret-test-pod   1/1       Running   0          42m
    
  3. 파드에서 실행 중인 컨테이너의 셸을 가져오자.

    kubectl exec -i -t secret-test-pod -- /bin/bash
    
  4. 시크릿 데이터는 /etc/secret-volume에 마운트된 볼륨을 통해 컨테이너에 노출된다.

    셸에서 /etc/secret-volume 디렉터리의 파일을 나열한다.

    # 컨테이너 내부의 셸에서 실행하자
    ls /etc/secret-volume
    

    두 개의 파일과 각 파일의 시크릿 데이터 조각을 확인할 수 있다.

    password username
    
  5. 셸에서 usernamepassword 파일의 내용을 출력한다.

    # 컨테이너 내부의 셸에서 실행하자
    echo "$( cat /etc/secret-volume/username )"
    echo "$( cat /etc/secret-volume/password )"
    

    사용자 이름과 비밀번호가 출력된다.

    my-app
    39528$vdg7Jb
    

시크릿 데이터를 사용하여 컨테이너 환경 변수 정의하기

단일 시크릿 데이터로 컨테이너 환경 변수 정의하기

  • 환경 변수를 시크릿의 키-값 쌍으로 정의한다.

    kubectl create secret generic backend-user --from-literal=backend-username='backend-admin'
    
  • 시크릿에 정의된 backend-username 값을 파드 명세의 SECRET_USERNAME 환경 변수에 할당한다.

    apiVersion: v1
       kind: Pod
       metadata:
         name: env-single-secret
       spec:
         containers:
         - name: envars-test-container
           image: nginx
           env:
           - name: SECRET_USERNAME
             valueFrom:
               secretKeyRef:
                 name: backend-user
                 key: backend-username
       
  • 파드를 생성한다.

    kubectl create -f https://k8s.io/examples/pods/inject/pod-single-secret-env-variable.yaml
    
  • 셸에서 SECRET_USERNAME 컨테이너 환경 변수의 내용을 출력한다.

    kubectl exec -i -t env-single-secret -- /bin/sh -c 'echo $SECRET_USERNAME'
    

    출력은 다음과 같다.

    backend-admin
    

여러 시크릿 데이터로 컨테이너 환경 변수 정의하기

  • 이전 예제와 마찬가지로 시크릿을 먼저 생성한다.

    kubectl create secret generic backend-user --from-literal=backend-username='backend-admin'
    kubectl create secret generic db-user --from-literal=db-username='db-admin'
    
  • 파드 명세에 환경 변수를 정의한다.

    apiVersion: v1
       kind: Pod
       metadata:
         name: envvars-multiple-secrets
       spec:
         containers:
         - name: envars-test-container
           image: nginx
           env:
           - name: BACKEND_USERNAME
             valueFrom:
               secretKeyRef:
                 name: backend-user
                 key: backend-username
           - name: DB_USERNAME
             valueFrom:
               secretKeyRef:
                 name: db-user
                 key: db-username
       
  • 파드를 생성한다.

    kubectl create -f https://k8s.io/examples/pods/inject/pod-multiple-secret-env-variable.yaml
    
  • 셸에서 컨테이너 환경 변수를 출력한다.

    kubectl exec -i -t envvars-multiple-secrets -- /bin/sh -c 'env | grep _USERNAME'
    

    출력은 다음과 같다.

    DB_USERNAME=db-admin
    BACKEND_USERNAME=backend-admin
    

시크릿의 모든 키-값 쌍을 컨테이너 환경 변수로 구성하기

  • 여러 키-값 쌍을 포함하는 시크릿을 생성한다.

    kubectl create secret generic test-secret --from-literal=username='my-app' --from-literal=password='39528$vdg7Jb'
    
  • envFrom을 사용하여 시크릿의 모든 데이터를 컨테이너 환경 변수로 정의한다. 시크릿의 키는 파드에서 환경 변수의 이름이 된다.

    apiVersion: v1
        kind: Pod
        metadata:
          name: envfrom-secret
        spec:
          containers:
          - name: envars-test-container
            image: nginx
            envFrom:
            - secretRef:
                name: test-secret
        
  • 파드를 생성한다.

    kubectl create -f https://k8s.io/examples/pods/inject/pod-secret-envFrom.yaml
    
  • usernamepassword 컨테이너 환경 변수를 셸에서 출력한다.

kubectl exec -i -t envfrom-secret -- /bin/sh -c 'echo "username: $username\npassword: $password\n"'

출력은 다음과 같다.

username: my-app
password: 39528$vdg7Jb

참고

다음 내용

  • 시크릿에 대해 더 배워 보기.
  • 볼륨에 대해 더 배워 보기.