Kubernetes를 배워보자 4일차 - ConfigMap과 Secret

0

kubernetes

목록 보기
4/13

ConfigMap과 Secret을 사용하여 pod들을 설정하기

이번 chapter에서는 ConfigMapsSecrets라는 kubernetes object에 대해서 알아보도록 한다.

ConfigMaps와 Secrets에 대한 이해

kubernetes에서는 configuration을 가장 중요한 요소로 생각하여 두 가지 resource를 만들어냈다. 하나는 ConfigMaps이고 하나는 Secrets이다.

application과 configuration을 분리하는 것은 매우 중요하다.

kubernetes를 사용할 때 우리는 application이 가능한 portable했으면 한다. 가장 좋은 방법은 application을 configuration으로부터 분리하는 것이다.

예전에는 application과 configuration을 하나로 묶어내어 application을 만들어냈었다. 이는 하나의 environment에서 배포가 이루어졌기 때문인데, 이러한 application의 경우 portability가 부족하다는 문제가 있다. 오늘 날에는 다양한 환경에서의 배포가 이루어지며, 환경에 따라 configuration을 자유자재로 바꾸고 업데이트하는 경우들이 많이 생겼다. 가령 다음의 상황을 보자

  1. 개발 환경에 테스트를 목적으로 java application을 배포했다고 하자.
  2. test 이후 해당 application은 production 환경에 배포되어야 하는데 production 환경에서의 MySQL endpoint가 test환경에서의 endpoint와 다르다.

여기에는 두 가지 가능성이 있다.

  • configuration과 application code가 decoupled되지 않았다. 즉, MySQL이 하드코딩되어있고 applicatio ncode에 번들링되어있을 가능성이 있다. 때문에 매 환경마다 application code를 새로 만들고 빌드해야한다.
  • configuration과 application이 decoupled되어있다면, configuration을 환경에 맞게 변경만하면 된다. 그러면 환경변수를 읽은 application이 환경에 따라 MySQL endpoint를 다르게 인식한다.

portablility의 핵심 개념은 application code는 application이 동작하는 infrastructure와 독립적이어야 한다. 이를 달성할 수 있는 가장 좋은 방법은 application code와 configuration을 분리하는 것이다.

kubernetes에서 application codepod가 되고, configuration이 바로 ConfigMapSecrets object가 된다. 이 둘은 모두 configuration data를 전달하기위해 설계되었으며, 이를 application codepod에 연결시켜주어야 한다.

configuration value를 docker images의 한 부분으로 포함시키지 말자. Dockerfile은 application code를 빌드할 뿐이지, 설정(configure)하는 것은 아니다. container를 빌드할 때 설정값들을 넣으면 application과 configuration 사이에 강한 relationship이 생긴다. 이는 container의 portability를 감소시킨다.

ConfigMap은 보안에 중요하지 않는 설정값들을 담는 기능을 한다. 반면에 Secrets는 global하게 같지만, 보안에 민감한 정보들을 담는다. 가령, database password 등이 있다.

즉, ConfigMapSecret은 key/value pair들로 이루어진 repository로 생각하면 된다. 따라서, pod가 생성될 때 ConfigMap 또는 Secret의 이름을 정하고 이를 pod에 링킹할 수 있다. 이를 통해, 해당 configuration 값들은 pod에 동작하는 container에 노출시킬 수 있는 것이다.

다음의 순서를 따르도록 하자.

  1. ConfigMap 또는 Secret을 만들도록 하자.
  2. 원하는 configuration value로 채우도록 하자.
  3. ConfigMap 또는 Secret을 참조하는 pod를 만들자.

다음을 따름으로서, pod를 환경에 따라 portable하게 만들 수 있는 것이다.

어떻게 pod가 ConfigMap과 Secret을 사용하는 지에 대한 이해

kubernetes외에 다른 현대의 containerized application은 다음의 두 가지 방식으로 configuration을 사용한다.

  • OS Environment variables
  • Configuration files

다음의 두 가지 방법을 선호하는 이유는 Docker와 같은 container 프로그램에서 configuration 값을 override하기 좋고, application이 configuration 값을 읽기 좋기 때문이다.

kubernetes world로 들어와서는 ConfigMapsSecrets로 configuration 설정을 할 수 있다. 위의 두 가지 방법을 그저 kubernetes의 ConfigMapSecret이 해주는 것일 뿐이다. 다음의 두 가지 방식으로 사용된다.

  • pod에서 동작하는 container안의 environment variable로 포함된다.
  • 다른 volume처럼 kubernetes volumes로 마운트된다.

즉, ConfigMapSecret의 하나 또는 그 이상의; configuration value는 환경 변수로 injected될 수 있다.

ConfigMapSecret은 또한 volume mounts와 같이 동작할 수 있다. ConfigMap을 volume으로 마운트하면 모든 configuration value를 container의 directory안에 포함되도록 할 수 있다. 만약 full configuration file들을 ConfigMap안에 저장한다면, 이 방법이 가장 좋다.

그러나, ConfigMapSecret은 서로 동작하는 방식이 다르다. 또한 ConfigMap은 보안에 민감하지 않는 정보를 담는 반면, Secret은 보안에 민감한 정보를 담는다는 차이도 있다. 이제 이들에 대해서 더 자세히 알아보도록 하자.

ConfigMaps를 사용하여 pod를 Configuration하기

먼저 현재 kubernetes cluster에서 ConfigMap을 가져오는 방법을 알아보자. kubectl get pod와 마찬가지로 kubectl get configmaps를 사용하면 된다.

kubectl get configmaps
kubectl get cm
kubectl get cm -A

configmaps라는 object이름이 너무 길다면 cm과 같은 축약어를 사용할 수 있다. -A옵션은 전체 namespace에 관계없이 모든 configmaps를 리스팅하라는 것이다. namespace에 대해서는 추후에 알아보도록 하자.

현재는 configmaps가 없기 때문에 위의 명령어를 실행해도 나오는 것이 없다. 이제 ConfigMap을 만들어보도록 하자.

다른 kubernetes object들과 마찬가지로 ConfigMaps도 imperatively 또는 declaratively하게 생성가능하다.

먼저, 명령어로 imperative하게 configmap을 생성하는 방법에 대해서 알아보자.

kubectl create configmap my-first-configmap
...
configmap/my-first-configmap created

kubectl create pod <pod-name>을 했듯이 kubectl create configmap <configmap-name>을 사용하면 된다.

일단, 해당 명령어가 실행되면 kubectl get cm으로 확인가능하다.

kubectl get cm
...
NAME                 DATA   AGE
my-first-configmap   0      56s

잘 만들어진 것을 볼 수 있다.

declarative하게 configmap을 생성하는 방법은 다음과 같다. 먼저 my-second-configmap.yaml 파일을 만들고 다음의 코드를 넣어주도록 하자.

  • my-second-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-second-configmap

kind부분에 pod가 아닌 ConfigMap으로 kubernetes object를 바꿔주면 된다. pod 생성시와 크게 다를바가 없다. 생성하는 부분도 pod를 만들 때와 크게 다를 바 없다.

kubectl create -f my-second-configmap.yaml 
...
configmap/my-second-configmap created

해당 명령어를 실행하면 성공적으로 ConfigMap이 만들어진 것이다. 리스팅 시에 잘 나오는 지 확인해보도록 하자.

kubectl get cm 
...
NAME                  DATA   AGE
my-first-configmap    0      6s
my-second-configmap   0      78s

ConfigMap모두 성공적으로 배포되었다. 그러나 DATA column을 보면 아무것도 없다는 것을 알 수 있다.
즉, configuration value가 없다는 것이다. 이는 우리가 생성 시에 데이터가 없는 빈 ConfigMap을 생성하였기 때문이다. 이제 데이터를 처음부터 가지고 있는 configmap을 만들어주도록 하자.

value가 없는 ConfigMap을 만드는 것은 매우 무의미한 일이다. value를 채운 ConfigMap을 만들어보도록 하자. 먼저 imperatively한 방식으로 value가 있는 ConfigMap을 만들어보도록 하자.

kubectl create cm <configmap-name> --from-literal=<key=value> 방식으로 사용하면 된다. --from-literalkey=value를 적어내면 되는 것이다.

다음과 같이 color라는 key는 blue라는 value를 갖도록 만들 수 있다.

kubectl create cm my-third-configmap --from-literal=color=blue
...
configmap/my-third-configmap created

또한, --from-literal을 여러번 써서 여러 개의 key=value를 저장할 수 있다.

kubectl create cm my-fourth-configmap --from-literal=color=blue --from-literal=version=1 -
-from-literal=environment=prod
...
configmap/my-fourth-configmap created

위는 3개의 configuration value를 만든 것이다.

이전에 kubectl get cm명령어에서 DATA column이 실제로 configmap이 가진 confiuguration value라고 하였다. 몇 개가 설정되어 있는 지 알아보도록 하자.

kubectl get cm 
NAME                  DATA   AGE
my-first-configmap    0      71m
my-fourth-configmap   3      109s
my-second-configmap   0      72m
my-third-configmap    1      3m25s

my-third-configmap은 1개, my-fourth-configmap은 3개인 것을 확인하였다.

declaratively하게 위와 동일한 configuration value를 가진 configmap을 만들 수 있다. 굉장히 간단한데, data 속성을 만들고 key:value로 만들어주면 된다.

  • my-fifth-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-fifth-configmap
data:
  color: "blue"
  version: "1"
  environment: "prod"

data.key: value 형식으로 써주면 되는 것이다. kubect create -f <filename>으로 배포해보도록 하자.

kubectl create -f my-fifth-configmap.yaml 
...
configmap/my-fifth-configmap created

다음으로 kubectl get cm으로 DATA가 의도한 대로 3개가 맞는 지 확인하도록 하자.

kubectl get cm
NAME                  DATA   AGE
my-fifth-configmap    3      5s
my-first-configmap    0      74m
my-fourth-configmap   3      4m50s
my-second-configmap   0      75m
my-third-configmap    1      6m26s

my-fifth-configmapDATA로 3개를 갖고있는 것을 볼 수 있다.

ConfigMap에 전체 configuration file을 저장하기

이전에 언급했듯이, ConfigMap에 파일 그 자체를 저장할 수 있다. 즉, literal value에만 국한되지 않는 것이다. kubectl 명령어에 file의 위치만 적어주면 된다. 그러면 해당 파일의 내용이 ConfigMapvalue에 적히게 낸다. 즉, key는 file이름이 되고, value는 해당 파일의 내용이 되는 것이다.

$HOME/configfile.txt 파일을 ConfigMap의 value로 가져오도록 해보자. 먼저 $HOME/configfile.txt를 만들어주도록 하자.

echo "I'm just a dummy config file" >> $HOME/configfile.txt && cat $HOME/configfile.txt 
I'm just a dummy config file

잘 저장된 것을 확인할 수 있다. 참고로 예제에서는 txt파일을 사용했지만, yaml, toml 등 상관없이 잘된다.

이제 해당 파일을 ConfigMap에 import해야한다. 새로운 ConfigMap을 만들고 --from-file flag를 사용해서 file을 적재하도록 하자.

kubectl create cm my-sixth-configmap --from-literal=color=yellow --from-file=$HOME/configfile.txt
configmap/my-sixth-configmap created

kubectl get cm 명령어를 사용하여 sixth configmap이 만들어졌는 지 확인해보도록 하자. 우리가 잘 만들었다면 2개의 DATA가 있을 것이다.

kubectl get cm
NAME                  DATA   AGE
my-fifth-configmap    3      15m
my-first-configmap    0      89m
my-fourth-configmap   3      19m
my-second-configmap   0      90m
my-sixth-configmap    2      47s
my-third-configmap    1      21m

my-sixth-configmap은 두 개의 DATA를 가진 것을 볼 수 있다. 특히 하나는 --from-file을 통해서 만든 file value이다.

imperatively하게 명령어를 사용하여 ConfigMap을 만들어냈으니 declaratively하게 ConfigMap을 만들어보도록 하자.

  • my-seventh-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-seventh-configmap
data:
  color: "green"
  configfile.txt: |
    I'm another configuration file.

다음과 같이 data부분에 file의 이름을 key로 하고 내용을 value로 하여 만들 수 있다.

그러나 다음과 같이 만들지는 말자

...
  configfile.txt: $HOME/configfile.txt

이렇게하면 $HOME/configfile.txt라는 경로가 configfile.txt에 그대로 저장되지 configfile.txt의 내용이 value에 들어가지 않는다.

kubectl get cm명령어로 DATA가 2개 만들어졌는 지 확인해보도록 하자

kubectl get cm
NAME                   DATA   AGE
my-fifth-configmap     3      23m
my-first-configmap     0      97m
my-fourth-configmap    3      28m
my-second-configmap    0      98m
my-seventh-configmap   2      79s
my-sixth-configmap     2      9m5s
my-third-configmap     1      29m

다음으로 ConfigMap을 생성하는 마지막 방법은 env파일로부터 ConfigMap을 만드는 방법을 알아보도록 하자.

env file로부터 ConfigMap만들기

imperatively한 방법으로 --from-env-file 옵션을 사용하면 env파일을 통해 ConfigMap`을 만들 수 있다.

env 파일은 key=value 형식의 파일로 각 key는 line break로 나누어져 있다. env파일은 kubernetes가 있기 전부터 많이 사용된 configuration 방식이기 때문에 kubernetes에서도 이를 가져와 ConfigMap으로 바꾸어 줄 수 있는 것이다.

다음의 env파일이 있다고 하자.

  • my-env-file.txt
hello=world
color=blue
release=1.0
production=true

kubernetes는 해당 env파일을 읽고 ConfigMap의 key-value 쌍을 만들어낼 것이다.

다음의 명령어를 사용하여 env파일을 읽고 이를 기반으로 ConfigMap을 만들어낼 수 있다.

kubectl create cm my-eigth-configmap --from-env-file=my-env-file.txt
...
configmap/my-eigth-configmap created

kubectl get cm을 통해서 잘 만들어졌는 지 확인해보도록 하자.

kubectl get cm my-eigth-configmap 
NAME                 DATA   AGE
my-eigth-configmap   4      7s

4개의 key-value 쌍이 잘 만들어졌음을 볼 수 있다.

ConfigMap에는 민감한 정보를 넣어서는 안된다. ConfigMap에 있는 데이터들은 보안과 관련된 정보가 없어야 하는데, 이는 kubectl describe cm명령어로 쉽게 ConfigMap에 있는 데이터를 볼 수 있기 때문이다. 보안과 관련된 민감한 정보는 Secret에 넣도록 하자.

그럼 데이터가 ConfigMap에 들어간 것은 알겠다만, 어떻게 읽을 수 있는가?

ConfigMap안에 있는 값들을 읽어오기

kubectl describe 명령어를 사용해서 ConfigMap에 있는 데이터를 가져올 수 있다. 예시로 my-fourth-configmap에 어떤 데이터들이 저장되어 있는 지 확인하도록 하자.

kubectl describe cm my-fourth-configmap 
Name:         my-fourth-configmap
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
color:
----
blue
environment:
----
prod
version:
----
1
Events:  <none>

굉장히 읽기 귀찮은 모습으로 나오지만 Data부분을 기점으로 keyvalue:----라인 사이로 번갈아 나온다.

이 처럼, ConfigMap은 굉장히 간단하게 data를 가져올 수 있으므로 절대로 민감한 정보를 포함해서는 안된다.

이제, 해당 데이터들을 pod들에서 사용하도록 링킹하는 방법에 대해서 알아보자.

ConfigMap을 environment variables로 연결하기

먼저, ConfigMap을 환경 변수(environment variables)로 삽입하는데 집중해보자. pod안의 container 환경 변수가 ConfigMap에 상응하도록 하자. 즉, 연결시키자는 것이다.

두 가지 방법이 있다.

  1. 한 개의 ConfigMap에 한 개의 값: 한 개 또는 여러 개의 ConfigMap들을 사용하여, pod안의 container 환경 변수 값을 설정 할 수 있다. 즉, 한개의 ConfigMap이 모든 환경 변수를 다 설정하는 것이 아니라, N개의 환경 변수를 M개의 ConfigMap으로 설정할 수 있다는 것이다. (N >= M)
  2. 모든 값들을 하나의 ConfigMap으로: 하나의 ConfigMap을 가져, 모든 값들을 한 번에 container의 환경 변수로 설정하는 것이다.

첫번째 방법은 관리에 있어 어려움은 있지만, 유연하다는 특징이 있다. 두 번째 방법은 하나의 pod 또는 하나의 application마다 하나의 ConfigMap을 만들어 pod 또는 application 배포 시에 ConfigMap을 배포 준비시킬 수 있다. 다만, 관리가 쉬운 장점이 있지만 유연하진 못하다.

하나씩 예제를 사용하여 알아보도록 하자.

ConfigMapPodkubectl의 imperative 방식으로는 연결시켜줄 수 없다. 왜냐하면 kubectl run 명령어로는 ConfigMap을 링킹하는 Pod를 만들 수 없기 때문이다. 때문에 podConfigMap를 사용하는 yaml파일을 만들어야만 한다.

위에서 우리는 my-third-configmap이라는 ConfigMap을 만들었는데, color=blue라는 데이터를 가졌었다. 이제 nginx:latest image를 가지는 pod를 만들어 my-third-configmap과 연결시켜 nginx container가 COLOR라는 환경변수로 blue라는 값을 갖도록 할 것이다. 다음의 YAML manifest를 집중해보자.

  • nginx-pod-with-configmap.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod-with-configmap
spec:
  containers:
    - name: nginx-container-with-configmap
      image: nginx:latest
      env:
        - name: COLOR # Any other name works here.
          valueFrom:
            configMapKeyRef:
              name: my-third-configmap
              key: color

env: 부분을 잘 보도록 하자. name부분은 nginx-container-with-configmap에서 가장 환경변수의 key이다. value는 valueFrom부분으로부터 연결시킬 수 있는데, configMapKeyRef에는 ConfigMap이름과 key를 적어주는데, 이 key에 해당하는 value이 COLOR에 연결되는 것이다. 참고로 해당 방법은 직접 data 하나하나마다 ConfigMap을 지정해줌으로 한 개의 ConfigMap에 한 개의 값에 해당한다.

pod를 생성시켜주도록 하자.

kubectl create -f nginx-pod-with-configmap.yaml
...
pod/nginx-pod-with-configmap created

이제 nginx pod가 만들어졌다. env command로 환경변수를 불러와보도록 하자. 이전에 배웠던 kubectl exec을 사용하면 된다.

kubectl exec nginx-pod-with-configmap -- env | grep "COLOR"
COLOR=blue

잘 설정된 것을 볼 수 있다.

이제, pod를 지우고 두 번째 방법(모든 값들을 하나의 ConfigMap으로)을 적용해보도록 하자.

kubectl delete pod nginx-pod-with-configmap 
pod "nginx-pod-with-configmap" deleted

이제 또 다른 ConfigMapmy-fourth-configmap을 연결시켜보도록 하자. 이번에는 하나하나씩 데이터를 환경변수에 설정하지 않고, ConfigMap에 있는 모든 환경 변수를 적용시키도록 하고싶다. 다음과 같이 manifest 파일을 만들도록 하자.

  • nginx-pod-with-configmap.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod-with-configmap
spec:
  containers:
    - name: nginx-container-with-configmap
      image: nginx:latest
      envFrom:
        - configMapRef:
            name: my-fourth-configmap

잘보면 이전과 달리 env를 사용하지 않고 envFrom을 사용하는 것을 볼 수 있다. 이는 env로 개별적인 환경변수 key를 설정하지 않기 때문이다.

pod를 만들어 잘 설정되었는 지를 확인해보도록 하자.

kubectl create -f nginx-pod-with-configmap.yaml
...
pod/nginx-pod-with-configmap created

pod가 만들어졌다면 my-fourth-configmap에 있는 환경변수가 잘 설정되었는지 보도록 하자. 참고로 이전에 kubectl describemy-fourth-configmap에 있는 환경변수를 가져왔었을 때 3가지로 이루어져있었다.

color=blue
version=1
environment=prod

다음의 3개가 pod에 설정되어 있는 지 확인하도록 한다.

kubectl exec nginx-pod-with-configmap -- env 
..
HOSTNAME=nginx-pod-with-configmap
environment=prod
version=1
color=blue
...

nginx-pod-with-configmap에 3개의 환경변수가 잘 설정되어있는 것을 볼 수 있다. 이 환경변수는 my-fourth-configmap에 있는 데이터들로 이 값들이 해당 pod의 환경변수로 설정된 것을 볼 수 있다.

단, 이 방법으로는 pod에 저장되는 환경변수의 key 이름을 지정하지 못하고 ConfigMap에 있는 데이터와 동일하게 간다는 것이 단점이다.

다음으로, ConfigMap을 container의 volume으로 마운트하는 방법에 대해서 알아보도록 하자.

ConfigMap을 volume mount로 마운팅하기

kubectl은 pod안에 volume으로 ConfigMap을 적재할 수 있도록 도와준다. 이는 ConfigMap이 container의 파일시스템 안에 삽입하고 싶은 파일 내용을 가지고 있다면 매우 유용하다.

환경 변수들을 삽입했을 때와 같이, 이 방법은 imperatively한 방법으로는 불가능하다. yaml manifest file을 만들어야한다. ConfigMapmy-sixth-configmap을 volume mount로 nginx-pod-with-configmap pod에 마운트시키도록 하자.

먼저 cluster에서 이전에 배포했던 pod를 삭제하고 시작하도록 하자.

kubectl delete pod nginx-pod-with-configmap
...
pod "nginx-pod-with-configmap" deleted

이제, 우리의 pod manifest file을 수정하여 ConfigMap을 volume mount로 nginx pod에 추가하도록 하자.

  • nginx-pod-with-configmap-volume.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod-with-configmap-volume
spec:
  volumes:
    - name: configuration-volume
      configMap:
        name: my-sixth-configmap # Configmap name goes here
  containers:
    - name: nginx-container-with-configmap
      image: nginx:latest
      volumeMounts:
        - name: configuration-volume
          mountPath: /etc/conf

configuration volume이라는 volume을 cotanienrs와 동일한 level에서 선언하였고, spec.volumes.configMap을 통해서 해당 volume은 my-sixth-configmap이라는 ConfigMap으로부터 만들어진다는 것을 알려주었다. 때문에 해당 manifest file을 적용할 때는 반드시 my-sixth-configmap이라는 ConfigMap이 먼저 kubernetes cluster에서 동작하고 있어야 한다.

마지막으로 해당 volumenginx-container-with-configmap container의 /etc/conf에 적재하도록 한다. ConfigMap에 있는 parameter는 반드시 특정 위치에 있어야함을 잊지말자.

이제 해당 manifest로 pod를 deploy해보도록 하자.

kubectl create -f nginx-pod-with-configmap-volume.yaml 
pod/nginx-pod-with-configmap-volume created

pod가 만들어졌다면, ls 명령어를 통해 해당 디렉터리가 container에 마운팅되었는 지 확인해보도록 하자.

참고로, my-sixth-configmap은 다음으로 이루어져있다.

kubectl describe cm my-sixth-configmap 
...
Name:         my-sixth-configmap
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
color:
----
yellow
configfile.txt:
----
I'm just a dummy config file

Events:  <none>

data로 yellowI'm just a dummy config file로 이루어져 있다.

kubectl exec nginx-pod-with-configmap-volume  -- ls /etc/conf
color
configfile.txt

확인한 결과 우리가 원한대로 /etc/confnginx-pod-with-configmap-volume에 적재되었고, 이 안에는 my-sixth-configmap의 data인 colorconfigfile.txt가 있다. 이들의 내부 데이터를 얻어오면 다음과 같다.

kubectl exec nginx-pod-with-configmap-volume  -- cat /etc/conf/color
yellow
...
kubectl exec nginx-pod-with-configmap-volume  -- cat /etc/conf/configfile.txt
I'm just a dummy config file

ConfigMap의 data가 volume의 key-value pair로 저장되게 되는 것이다. 이와 같은 기능을 통해서 특정 디렉터리 위치에 있는 configuration을 읽어서 환경에 따른 application 배포 및 구동이 가능하다. 즉, 디렉터리 위치라는 인터페이스로 환경 변수들이 환경과 독립적으로 설정될 수 있는 것이다.

다음으로, ConfigMap들을 삭제해보록 하자.

ConfigMap 삭제하기

ConfigMap 삭제는 이전의 pod삭제와 크게 다를바 없다. 그러나 한 가지 유의할 것은 ConfigMap의 value가 특정 pod에서 사용되어도 ConfigMap이 삭제된다는 것이다. 이는 pod가 시작되면 ConfigMap object와 독립적이기 때문이다.

kubectl delete cm my-first-configmap
configmap "my-first-configmap" deleted

container에 의해 ConfigMap의 value가 사용되고 있는 지와 상관없이, ConfigMap은 바로 삭제된다. 조심해야할 것은 ConfigMap을 삭제하면 이를 되돌릴 방법은 없다. 때문에 삭제할 때 두 번 정도 생각해서 결정하도록 하자.

또한, 동작중인 pod에서 사용중인 value가 있는 ConfigMap을 삭제하는 것은 조심해야한다. 만약 pod가 크러싱이 발생하면 manifest file을 수정하는 방법 외에는 다시 정상으로 되돌릴 방법이 없기 때문이다.

ConfigMap 수정

ConfigMap을 수정하는 특별한 명령어는 딱히 없지만, edit을 통해서 변경이 가능하다. 다만, 변경한다고 해서 pod에 반드시 적용되지 않을 수 있다. 가령, pod에서 환경변수를 읽어오는 특정 시점이 프로그램이 시작된 후 가장 첫 부분이라면 ConfigMap의 data를 변경해도 적용되지 않는다.

따라서, 이럴 때는 pod를 재시작시켜주는 방법 밖에 없다.

ConfigMap을 수정하는 방법은 다음과 같다.

kubectl edit cm my-third-configmap
(이후 `color` 데이터를 `blue`에서 `red`로 변경 후 :wq!로 저장)

my-third-configmap을 수정할 수 있게되고, value와 key를 변경할 수 있다. 위의 예시에서는 color key의 bluered로 변경하는 예이다.

앞서 이야기했듯이 이렇게 수정한다해서 pod에 반드시 적용된다는 보장이 없기때문에 pod를 삭제했다가 다시 올려야한다.

Secret object를 통해 민감한 configuration 관리하기

secret object는 kubernetes에서 동작 중인 applicatio을 configuration할 수 있다. 이는 ConfigMap과 동일하지만, Secret은 인코딩되며 민감한 데이터를 가질 수 있다. 가령, password나 token, 또는 private API key들이 있다. 반면에 ConfigMap은 민감하지 않는 configuration data을 가진다. 이 외에 이들은 사실상 거의 같다.

Secret을 리스팅하는 방법은 다음과 같다.

kubectl get secret

ConfigMap과 같이 DATA column은 Secret에 저장되고 해싱된 민감한 정보의 수를 표현한다.

이제 data를 가진 Secret을 만들도록 하자.

--from-literal을 통해 명령형 방식으로 Secret 만들기

Secret은 imperatively하게 만들수도 있고, declaratively하게 만들 수도 있다. 먼저 imperatively하게 Secret을 만드는 방법부터 알아보도록 하자. 우리는 database password인 my-db-passwordSecret object안에 저장하고 싶다면 --from-literal 플래그와 kubectl create secret 명령어를 사용하면 된다.

또한, kubectl create secret <secret-type> <secret-name>를 쓰게되는데, secret-type이 추가되었다. 이는 secret이 어떤 목적에 따라 사용되냐를 적은 것인데, generic이라고 적으면 Opaque type이 되고, 이는 사용자 정의 타입을 말한다.

kubectl create secret generic my-first-secret --from-literal=db_password=my-db-password

만들었다면, kubectl get secrets 명령어로 Secret의 list를 불러올 수 있다. 다음과 같이 나올 것이다.

kubectl get secrets 
NAME                  TYPE                                  DATA   AGE
my-first-secret       Opaque                                1      3m7s

이제 Secret을 declaratively하게 만드는 방법을 알아보도록 하자.

YAML file로 Secret 만들기

Secret을 declarative한 방법으로 만들 수도 있는데, 이 경우에 한 가지 주의해야할 것은 data를 base64로 인코딩한 다음 넣어야한다는 것이다. 이는 yaml file에 Secret정보가 노출되는데, 인코딩되지 않은 상태에서는 민감한 정보가 그대로 하드코딩되기 때문이다.

imperative한 방법으로 Secret을 만들 때는 --from-literal을 사용하였는데, 이 플래그가 실행되면 kubernetes는 자동적으로 string을 base64로 인코딩한다. 그러나, yaml manifest file을 통해서 Secret을 만드는 경우는 인코딩 단계를 따로 kubernetes에서 동작해주지 않는다.

따라서, 우리가 넣을 데이터인 db_password=my-db-passwordmy-db-password문자열을 base64로 인코딩해주도록 하자.

echo 'my-db-password' | base64
bXktZGItcGFzc3dvcmQK

bXktZGItcGFzc3dvcmQKmy-db-passwordbase64인코딩 결과이고, 이를 YAML file에 value로 써주면 된다.

  • secret-from-file.yaml
apiVersion: v1
kind: Secret
metadata:
  name: my-second-secret
type: Opaque
data:
  db_password: bXktZGItcGFzc3dvcmQK

secrettype을 가지는 데, type 필드는 Secret이 어떤 목적으로 이루어져 있냐는 것이다. 즉, tls인지 ssh-auth인지 사용자 정의 데이터인지 등에 따라 다르다. Opaque는 임의의 사용자 정의 데이터를 의미한다. https://kubernetes.io/ko/docs/concepts/configuration/secret/

data부분에 key-value형식으로 데이터를 넣어주면된다.

이제 Secret을 만들어보도록 하자.

kubectl create -f secret-from-file.yaml 
secret/my-second-secret created

잘 만들어졌는 지 확인하도록 하자.

kubectl get secret
NAME                  TYPE                                  DATA   AGE
my-first-secret       Opaque                                1      20m
my-second-secret      Opaque                                1      26s

my-second-secret이 잘 만들어졌음을 알 수 있다.

file의 내용을 가진 Secret만들기

file에서의 content을 기반으로 Secret을 만들 수 있다. file에 비밀번호를 넣고 이를 가져와 Secret을 만들도록 하자.

먼저 비밀번호를 가진 Secret을 만들도록 하자.

echo -n 'mypassword' > ./password.txt

해당 명령어를 실행하면 우리는 password.txt라는 파일을 얻게 된다. 해당 파일에는 string으로 mypassword라는 비밀번호를 가지고 있고 이는 Secret의 value가 된다. -n 옵션을 써서 password.txt가 어떠한 추가적인 blank line을 text의 끝에 갖지않도록 한다.

--from-file플래그를 통해서 password.txt의 위치를 넘겨줌으로서 kubectl create secret 명령어로 Secret을 만들어보도록 하자. 이는 mypassword 문자열의 base64 표현을 data로 갖게 될 것이다.

이제 kubectl create secret <secret-type> <secret-name> --from-literal명령어로 Secret을 만들어주도록 하자.

kubectl create secret generic my-password --from-file=password=./password.txt
secret/my-password created

keypassword이고 value./password.txt인 data를 my-password에 넣어 Secret을 만들었다.

잘 만들어졌는 지 확인하기 위해서 kubectl get secret 명령어를 사용해보도록 하자.

get secret
NAME                  TYPE                                  DATA   AGE
my-password           Opaque                                1      81s
my-second-secret      Opaque                                1      35m

잘 만들어진 것을 확인할 수 있다.

Secret 읽기

Secret은 보안상 민감한 데이터를 담고 있기 때문에 kubectl output으로 가져올 수 없다. 이는 보안상의 민감한 데이터가 터미널에 로깅되거나, 접근하지 않아야할 누군가가 이를 볼 수 있기 때문이다.

이러한 이유로 Secret의 data는 얻을 수 없다. 다만, 해당 data의 사이즈와 같은 정보들은 알 수 있따.

kubectl describe 명령어를 사용함으로서 Secret의 data를 불러올 수 있다. 단지 보안상의 이유로 일부 정보만 가져올 수 있는 것이다.

ubectl describe secrets my-password 
Name:         my-password
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
password:  10 bytes

Data부분의 password의 value가 단지 10 bytes로만 나온 것은 민감한 정보인 password의 value를 decoding하지 않기 때문이다. 물론 kubectl edit을 통해서 Secret자체에 접근하고 configuration value를 수정할 수 있지만, 이는 좋은 방법이 아니다.

이제, Secret을 environmet variable로 사용해보도록 하자.

Secret을 환경변수로서 사용하기

Secretmy-passwrod에서 password 값을 만들었었다. 이 값을 pod의 nginx-container container에 넣어주도록 하자.

  • nginx-pod-with-secret-env-variable.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod-with-secret-env-variable
spec:
  containers:
    - name: nginx-container
      image: nginx:latest
      env:
        - name: PASSWORD_ENV_VAR # name of env variable
          valueFrom:
            secretKeyRef:
              name: my-password # name of secret
              key: password # name of key in secret object 

spec.containers.env를 만들어주고 namecontainer에서 사용할 이름으로 설정해주면 된다. valueFrom을 통해 env의 값을 설정해주는데, secretKeyRefname으로 Secret의 이름을 정해주고, keySecret에서의 env이름을 정해주면 된다.

이제 pod를 만들어 실행해보도록 하자.

kubectl  create -f nginx-pod-with-secret-env-variable.yaml 
pod/nginx-pod-with-secret-env-variable created

실행이 되었다면 env가 잘 설정되었는지 확인해보도록 하자.

kubectl exec nginx-pod-with-secret-env-variable -- env | grep "PASS"
PASSWORD_ENV_VAR=mypassword

Secret에 있는 env가 잘 설정된 것을 볼 수 있다.

또 다른 방법은 envFrom을 사용하는 것인데, Secret에 있는 모든 env값들을 pod에 적용하는 것이다.

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod-with-secret-env-variable
spec:
  containers:
    - name: nginx-container
      image: nginx:latest
      envFrom:
        - secretRef:
            name: my-password # name of secret

이전보다 간단한데, env부분을 envFrom으로 변경하여 적용하면 secretRefname에 해당하는 Secret의 모든 값들이 pod에 적용된다.

실행시켜서 확인해보도록 하자.

kubectl delete pod nginx-pod-with-secret-env-variable 
pod "nginx-pod-with-secret-env-variable" deleted

kubectl exec nginx-pod-with-secret-env-variable -- env | grep "pass"
password=mypassword

password=mypassword가 잘 적용된 것을 볼 수 있다.

Secret을 volume mount로 사용하기

Secret을 pod에 volume으로 사용할 수도 있다. 다만, declareative하게 사용할 때만 가능하다.

mypassword라는 Secret을 pod container의 /etc/passwords-mounted-path/password에 적재하도록 하자.

  • nginx-pod-with-secret-volume.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod-with-secret-volume
spec:
  containers:
    - name: nginx-container
      image:  nginx:latest
      volumeMounts:
        - name: mysecret-volume
          mountPath: /etc/password-mounted-path
  volumes:
    - name: mysecret-volume
      secret:
        secretName: my-password

volumesmysecret-volume를 만들고 Secret으로 my-password를 타겟으로 한다. 그리고 이 volumenginx-containervolumeMounts로 마운팅하기만 하면 된다.

이제 pod를 만들어보고 volume이 잘 적재되었는 지 확인해보도록 하자.

kubectl create -f nginx-pod-with-secret-volume.yaml 
pod/nginx-pod-with-secret-volume created

kubectl exec nginx-pod-with-secret-volume -- ls /etc/password-mounted-path/
password

kubectl exec nginx-pod-with-secret-volume -- cat /etc/password-mounted-path/password
mypassword

password라는 이름의 파일로 mypassword값이 정확히 들어있는 것을 확인할 수 있다. 성공적으로 Secret이 volume으로 적재된 것을 볼 수 있다.

Secret 삭제하기

이전 kubernetes object들과 마찬가지로 kubectl delete명령어를 사용하면 된다.

kubectl delete secret my-first-secret
secret "my-first-secret" deleted

Secret 수정하기

Secret을 수정하기 위해서는 Secret을 edit으로 수정하고, 이와 관련된 pod를 재시작하면 된다. 그러나 추천하진 않는다.

0개의 댓글