전자책 출간 알림 [마이크로서비스패턴 쉽게 개발하기]

티스토리 뷰

10. 환경변수 컨피그맵과 시크릿

컨피그맵과 시크릿의 공통점은 파드 내에서 참조할 환경변수를 생성하는 리소스라는 것이고 차이점은 컨피그맵은 평문으로 저장되나 시크릿은 base64로 인코딩되고 추가적인 보안 수단이 있어 더 보안성이 뛰어나다는 것입니다.
사실 base64는 너무나 쉽게 디코딩되어 보안이라고 말할 수 없고 추가적인 보안 수단이 있기 때문에 민감한 정보는 시크릿으로 반드시 만들어야 합니다.
시크릿은 환경변수를 생성하는 기능뿐 아니라 이미지 레지스트리 자격증명과 TLS인증서도 만들 수 있습니다.

컨피그맵과 시크릿을 생성하는 방법에는 Literal, 한줄 컨피그 파일 이용 방식, 여러줄 컨피그 파일 이용 방식이 있습니다.
각 방식을 예제를 통해 배워보도록 하겠습니다.
그리고 파드안에서 컨피그맵과 시크릿을 참조하는 두가지 방법을 실습 하겠습니다.
또한 컨피그맵과 시크릿을 파드 안에 볼륨 마운트 하는 방법도 학습 하겠습니다.
마지막으로 시크릿을 이용하여 관리할 수 있는 다양한 종류의 데이터 유형에 대해 학습하겠습니다.

생성방식 ConfigMap Secret
Literal kubectl create configmap {name} --from-literal {key}={value} kubectl create secret generic<name> --from-literal {key}={value}
환경설정 파일 이용 kubectl create configmap {name} --from-env-file={file path} kubectl create secret generic {name} --from-env-file={file path}
일반 파일 이용 kubectl create configmap {name} --from-file={file path} kubectl create secret generic {name} --from-file={file path}
사용 예 envFrom:
 - configMapRef:
      name: myconfig
envFrom:
  - secretRef:
       name: mysecret
env:
  - name: PW_USER
     valueFrom:
         configMapKeyRef:
             name: myconfig
             key: PW_USER
env:
  - name: PW_USER
     valueFrom:
         secretKeyRef:
             name: mysecret
             key: PW_USER
‘--from-file’로 만든 컨피그맵은 ‘key’가 파일명이 됨
env:
  - name: CONFIG
    valueFrom:
        configMapKeyRef:
            name: myconfig
            key: config.ini
‘--from-file’로 만든 시크릿은 ‘key’가 파일명이 됨
env:
  - name: CONFIG
    valueFrom:
        secretKeyRef:
            name: mysecret
            key: config.ini


<팁>
시크릿 데이터도 쿠버네티스 데이터 저장소인 etcd에 저장됩니다.
평문으로 저장되기 때문에 루트 권한을 가지거나 쿠버네티스 클러스터의 인증서를 취득한 사용자는 모든 시크릿 데이터를 볼 수 있습니다.
이를 보완하기 위해 쿠버네티스에서는 시크릿 데이터를 암호화해서 etcd에 저장하는 방법을 제공 합니다.
개발을 위해서 알아야 할 정보는 아니지만 궁금하신 분들은 아래 글을 참고 하십시오.

https://happycloud-lee.tistory.com/243
</>

10.1 Literal, 환경설정 파일 이용, 일반 파일 이용 방식

컨피그맵과 시크릿을 만드는 3가지 방법을 이용하여 오브젝트들을 만들어 보겠습니다.

1) Literal
Literal 방식은 kubectl의 파라미터로 환경변수를 지정해서 컨피그맵이나 시크릿을 만드는 방법입니다.
‘--from-literal’ 파라미터를 여러번 사용하여 복수의 환경변수를 지정할 수 있습니다.
kubectl create cm {name} --from-literal {key}={value} [--from-literal {key}={value} …]
kubectl create secret generic {name} --from-literal {key}={value} [--from-literal {key}={value} …]

Literal 방식으로 컨피그맵 ‘cm1’을 만듭니다.

k create cm cm1 --from-literal dbhost=member --from-literal dbname=members
​​[root@osboxes yaml]# k describe cm cm1

Data
====
dbhost:
----
member
dbname:
----
members


Literal 방식으로 시크릿 ‘secret1’을 만듭니다. ‘k create secret’ 뒤에 ‘generic’을 반드시 붙여야 합니다.

[root@osboxes yaml]# k create secret generic secret1 --from-literal dbid=admin --from-literal dbpw=happy@cloud
[root@osboxes yaml]# k describe secret secret1
...
Data
====
dbid:  5 bytes
dbpw:  11 bytes


‘kubectl describe’명령으로 보면 컨피그맵은 내용이 나오나 시크릿은 키만 나오고 값은 안 보이것을 확인할 수 있습니다.

2) 환경설정 파일 이용 방식
Literal 방식은 적은 수의 환경변수를 만들때는 편하지만 정의할 환경변수가 많다면 명령줄이 너무 길어져서 불편합니다.
환경설정 파일 이용 방식은 파일에 키와 밸류로 구성된 환경변수들을 정의하고 그 파일을 이용하여 컨피그맵이나 시크릿을 만드는 방식입니다.
아래와 같이 컨피그맵 생성을 위한 파일 ‘cm-file.properties’를 만듭니다. 파일명과 확장자는 어떤 것이든 상관 없습니다.
‘tbl_a’, ‘tbl-b’, ‘tbl.c’는 환경변수를 만들때 언더바, 대시, 점을 사용할 수 있는지 테스트 하기 위해 정의했습니다.
미리 말씀 드리면 환경변수에서는 언더바를 쓰시는게 제일 안전합니다.

dbport=3306
tbl_a=a
tbl-b=b
tbl.c=c


환경설정 파일 이용 방식으로 컨피그 파일을 만들때는 ‘--from-env-file’파라미터를 사용 합니다.
컨피그맵 오브젝트 ‘cm2’를 위 파일을 이용하여 생성 합니다.

[root@osboxes yaml]# k create cm cm2 --from-env-file=cm-file.properties
[root@osboxes yaml]# k describe cm cm2


시크릿 생성을 위한 파일 ‘secret-file.properties’를 만듭니다.

auth_token=!@#$%
enc_key=^&*


시크릿 오브젝트 ‘secret2’를 위 파일을 이용하여 만듭니다.

[root@osboxes yaml]# k create secret generic secret2 --from-env-file=secret-file.properties
[root@osboxes yaml]# k describe secret secret2



3) 일반 파일 이용 방식

파일 내용을 컨피그맵으로 만들어 파드 안에 파일로 마운트 시켜야 하는 경우 일반 파일 이용방식을 사용합니다.

예를 들어 웹서버 설정 파일(httpd.conf)같은 것을 컨피그맵으로 관리할 때 사용할 수 있습니다. 

컨피그맵을 만들기 위한 일반 파일 ‘cm.conf’를 아래 예제처럼 만드십시오. 사실 내용은 어떤거든 상관 없습니다.

{
  name: "busybox"
  description: "test config"
}

‘imgreg.conf’파일도 아래 예제처럼 만드십시오.

registry=docker.io
organization=hiondal
repo=member


컨피그맵 ‘cm3’를 일반 파일 이용 방식으로 만듭니다. 파라미터는 ‘--from-file’을 사용합니다.
생성된 결과를 보면 키가 파일명인 ‘cm.conf’이고 값은 그 파일 내용이라는 걸 알 수 있습니다.

[root@osboxes yaml]# k create cm cm3 --from-file=cm.conf --from-file=imgreg.conf
configmap/cm3 created
[root@osboxes yaml]# k describe cm cm3

Data
====
cm.conf:
----
{
  name: "busybox"
  description: "test config"
}

imgreg.conf:
----
registry=docker.io
organization=hiondal
repo=member


시크릿을 만들기 위한 여러줄 컨피그 파일 ‘secret.conf’를 아래 예제처럼 만드십시오. 역시 파일 내용은 아무렇게나 하셔도 됩니다. 특히 각 키의 값은 아래 처럼 안하셔도 됩니다

{
  ca.crt: !@#$%
  ca.key: ^&*
}


시크릿 ‘secret3’를 여러줄 컨피그 파일 이용 방식으로 만듭니다.
역시 키는 파일명으로 만들어지고 값은 보이지 않습니다.

[root@osboxes yaml]# k create secret generic secret3 --from-file=secret.conf
secret/secret3 created
[root@osboxes yaml]# k describe secret secret3
...

Data
====
secret.conf:  96 bytes



4) 야믈 파일을 이용한 컨피그맵/시크릿 생성
위에서는 kubectl 명령을 이용하여 컨피그맵과 시크릿을 생성했습니다.
컨피그맵과 시크릿도 당연히 다른 쿠버네티스 오브젝트들처럼 야믈 파일로도 만들 수 있습니다.
생성된 오브젝트 중 cm1과 secret1의 야믈 파일을 추출해서 어떻게 정의하는지 알아 보겠습니다.
‘-o yaml’파라미터로 야믈 내용을 추출하고 ‘ > ‘을 이용해서 파일로 만듭니다.

[root@osboxes yaml]# k get cm cm1 -o yaml > cm1.yaml
[root@osboxes yaml]# k get secret secret1 -o yaml > secret1.yaml


‘cm1.yaml’을 열고 ‘creationTimestamp’, ‘resourceVersion’, ‘uid’를 제거합니다. 각 항목의 순서는 안 바꿔도 되지만 보기 좋게 kind, apiVersion, metadata, type, data 순서로 조정 합니다.
테스트를 위해 ‘dbkind’를 추가 합니다.

kind: ConfigMap
apiVersion: v1
metadata:
  name: cm1
  namespace: ott
data:
  dbhost: member
  dbname: members
  dbkind: mysql


기존의 컨피그맵 ‘cm1’을 지우고 이 파일을 이용해서 다시 만듭니다.
이번에는 ‘kubectl replace’명령으로 해 보십시오. 동일한 기능입니다.
아래와 같이 잘 생성된것을 확인할 수 있습니다.

[root@osboxes yaml]# k replace -f cm1.yaml
configmap/cm1 replaced
[root@osboxes yaml]# k describe cm cm1
...

Data
====
dbhost:
----
member
dbkind:
----
mysql
dbname:
----
members


이번에는 ‘secret1.yaml’ 파일을 열고 동일하게 있으면 안되는 항목들을 지우고 위치를 조정 합니다.
시크릿 야믈은 아래와 같이 값을 base64로 인코딩하여 정의해야 합니다.

kind: Secret
apiVersion: v1
metadata:
  name: secret1
  namespace: ott
data:
  dbid: YWRtaW4=
  dbpw: aGFwcHlAY2xvdWQ=
type: Opaque

<팁>
base64로 인코딩하는 가장 간단한 방법은 ‘echo’명령을 이용하시면 됩니다.
echo {인코딩할 값} | base64
예) echo members | base64

디코딩은 echo {디코딩할 값} | base64 -d 입니다.

파일을 인코딩할때는 base64 -w 0 {파일명}을 사용하십시오. ‘-w 0’은 줄바꿈 없이 만드는 옵션입니다.
</>

값을 base64 인코딩 값이 아닌 평문으로 지정하여 시크릿을 만들 수도 있습니다.
아래와 같이 데이터를 정의할 때 ‘stringData’를 이용하면 됩니다.

kind: Secret
apiVersion: v1
metadata:
  name: secret1
  namespace: ott
stringData:
  dbid: admin
  dbpw: happy@cloud
type: Opaque




컨피그맵 ‘cm3’은 야믈 내용이 다른 것과 조금 다를 겁니다.
‘--from-file’파라미터로 생성한 컨피그맵은 파일명이 키가 되고 그 내용이 값이 됩니다.

[root@osboxes yaml]# k get cm cm3 -o yaml
apiVersion: v1
apiVersion: v1

data:
  cm.conf: |
    {
      name: "busybox"
      description: "test config"
    }
  imgreg.conf: |+
    registry=docker.io
    organization=hiondal
    repo=member
kind: ConfigMap

<팁>
‘|’ 기호는 값이 여러줄일때 사용합니다. 제일 끝에 새로운 줄이 여러개 있을때 ‘|+’는 유지하라는 뜻이고 ‘|-’는 없애라는 뜻입니다. 기본 값은 ‘|-’입니다.
</>

지금까지 컨피그맵 cm1, cm2, cm3와 시크릿 secret1, secret2, secret3를 만들었습니다.
각 오브젝트의 키는 아래와 같습니다.

리소스 오브젝트명
컨피그맵 cm1 dbhost, dbname, dbkind
cm2 dbport, tbl_a, tbl-b, tbl.c
cm3 cm.conf, imgreg.conf
시크릿 secret1 dbid, dbpw
secret2 auth_token, enc_key
secret3 secret.conf


이제 컨피그맵과 시크릿을 파드에서 참조하는 방법을 배워 보도록 하겠습니다.

10.2 파드에서 컨피그맵과 시크릿 참조하기

컨피그맵과 시크릿을 파드에서 참조하려면 아래와 같이 두가지 방법으로 정의할 수 있습니다.
‘configMapRef’는 오브젝트의 내용을 모두 환경변수로 만드는 방법이고 ‘configMapKeyRef’는 특정 키 값만 환경변수로 생성하는 방법입니다.
그럼 각 방법을 예제를 통해 실습해 보겠습니다.

ConfigMap Secret
envFrom:
 - configMapRef:
      name: myconfig
envFrom:
  - secretRef:
       name: mysecret
env:
  - name: PW_USER
     valueFrom:
         configMapKeyRef:
             name: myconfig
             key: PW_USER
env:
  - name: PW_USER
     valueFrom:
         secretKeyRef:
             name: mysecret
             key: PW_USER


먼저 테스트를 위한 파드를 생성하겠습니다.
테스트로 많이 사용하는 busybox 컨테이너를 사용하겠습니다.
아래와 같이 busybox 파드를 스테이트풀셋으로 실행 합니다.

[root@osboxes]# cd ~/k8s/yaml
[root@osboxes yaml]# wget https://hiondal.github.io/k8s-yaml/3.10/sts-busybox.yaml
[root@osboxes yaml]# k apply -f sts-busybox.yaml
[root@osboxes yaml]# k get po
NAME                         READY   STATUS    RESTARTS       AGE
busybox-0                    1/1     Running   0              4h48m



1) 오브젝트 전체 키를 환경변수로 생성
컨피그맵 ‘cm1’, ‘cm2’, ‘cm3’을 읽어 ‘configMapRef’로 파드 내에 환경변수를 생성 합니다.
‘sts-busybox.yaml’파일을 열어 아래와 같이 항목을 추가 합니다.

...
    spec:
      serviceAccount: sa-ott
      containers:
      - name: busybox
        ...
        imagePullPolicy: IfNotPresent
        envFrom:
        - configMapRef:
            name: cm1
        - configMapRef:
            name: cm2
        - configMapRef:
            name: cm3


변경된 내용을 파드에 적용 합니다. 적용 후 파드의 목록을 확인하여 파드가 정상 실행될때까지 기다립니다.
‘-w’옵션을 붙이면 실시간으로 파드의 상태가 바뀌는 것을 볼 수 있습니다. 파드가 잘 실행이 되면 CTRL-C로 중단 합니다.

[root@osboxes yaml]# k apply -f sts-busybox.yaml
statefulset.apps/busybox configured

[root@osboxes yaml]# k get po -w


‘env’명령을 이용하여 파드 안의 환경변수를 봅니다. 아래와 같이 잘 생성이 되었습니다.

[root@osboxes yaml]# k exec busybox-0 -it -- env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

TERM=xterm
HOSTNAME=busybox-0
dbhost=member
dbkind=mysql
dbport=3306
tbl_a=a
cm.conf={
  name: "busybox"
  description: "test config"
}
dbid=admin
dbname=members
imgreg.conf=registry=docker.io
organization=hiondal
repo=member

tbl-b=b
tbl.c=c


그럼 언더바, 대시, 점을 사용한 환경변수가 제대로 읽히는지 테스트 해 보겠습니다.
파드 안으로 들어가서 테스트 해 봅니다. 언더바를 사용한 환경변수만 값이 제대로 읽힙니다.

[root@osboxes yaml]# k exec busybox-0 -it -- sh
/ # echo $tbl_a

a
/ # echo $tbl-b
-b
/ # echo $tbl.c
.c


이번에는 시크릿 ‘secret1’, ‘secret2’, ‘secret3’를 읽어 ‘configMapRef’로 파드 내에 환경변수를 생성 합니다.
‘sts-busybox.yaml’파일을 열어 아래와 같이 항목을 추가 합니다.

...
    spec:
      serviceAccount: sa-ott
      containers:
      - name: busybox
        ...
        imagePullPolicy: IfNotPresent
        envFrom:
        - configMapRef:
            name: cm1
        - configMapRef:
            name: cm2
        - configMapRef:
            name: cm3

        - secretRef:
            name: secret1

        - secretRef:
            name: secret2

        - secretRef:
            name: secret3


다시 파드에 적용하고 생성된 환경변수를 확인해 봅니다. 파드가 정상 실행할때까지 기다렸다가 확인 하십시오.
역시 잘 생성이 되었고 값도 디코딩되어 보입니다.

[root@osboxes yaml]# k apply -f sts-busybox.yaml
[root@osboxes yaml]# k get po
[root@osboxes yaml]# k exec busybox-0 -it -- env

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

enc_key=^&*
auth_token=!@#$%
dbhost=member
dbkind=mysql
dbport=3306
tbl_a=a
cm.conf={
  name: "busybox"
  description: "test config"
}
imgreg.conf=registry=docker.io
organization=hiondal
repo=member

dbid=admin
secret.conf={
  ca.crt: dkfjasdfjslkdfjkalsdfjkdsjflsdajf
  ca.key: dfjksdjfksdjfsdlkfjskdfskdfkjkfdkfdfs
}

dbname=members
tbl-b=b
tbl.c=c
dbpw=happy@cloud



2) 오브젝트의 특정 키만 환경변수로 생성
이번에는 특정 키만 선택적으로 환경변수로 만들어 보겠습니다.
아래 키만 환경변수로 만들도록 정의해 보겠습니다.

리소스 오브젝트명 환경변수명
컨피그맵 cm1 dbhost DBHOST
cm2 tbl-b TBL_B
tbl.c TBL_C
시크릿 secret1 dbpw DBPW
secret2 auth_token AUTH_TOKEN


‘sts-busybox.yaml’의 내용을 아래와 같이 수정 합니다.
‘envFrom’에서는 ‘cm3’와 ‘secret3’만 남기고 ‘env’항목 밑에 위 표대로 필요한 키만 정의 합니다.
파드 내에 생성될 환경변수는 모두 대문자로 지정 합니다. 소문자로 지정해도 상관은 없습니다.
그리고 ‘tbl-b’와 ‘tbl.c’의 환경변수명을 대문자와 언더바로 정의 하였습니다.

...
    spec:
      serviceAccount: sa-ott
      containers:
      - name: busybox
        ...
        imagePullPolicy: IfNotPresent
        envFrom:

        - configMapRef:
            name: cm3
        - secretRef:
            name: secret3
        env:
        - name: DBHOST
          valueFrom:
            configMapKeyRef:
              name: cm1
              key: dbhost
        - name: TBL_B
          valueFrom:
            configMapKeyRef:
              name: cm2
              key: tbl-b
        - name: TBL_C
          valueFrom:
            configMapKeyRef:
              name: cm2
              key: tbl.c
        - name: DBPW
          valueFrom:
            secretKeyRef:
              name: secret1
              key: dbpw
        - name: AUTH_TOKEN
          valueFrom:
            secretKeyRef:
              name: secret2
              key: auth_token


파드에 적용하고 생성된 환경변수명을 확인 합니다.
아래와 같이 지정된 환경변수명으로 잘 생성이 되는걸 볼 수 있습니다.

[root@osboxes yaml]# k apply -f sts-busybox.yaml
[root@osboxes yaml]# k get po -w
[root@osboxes yaml]# k exec busybox-0 -it -- env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
TERM=xterm
HOSTNAME=busybox-0
DBPW=happy@cloud
AUTH_TOKEN=!@#$%
cm.conf={
  name: "busybox"
  description: "test config"
}

secret.conf={
  ca.crt: !@#$%
  ca.key: ^&*
}

DBHOST=member
TBL_B=b
TBL_C=c




10.3 볼륨 마운트 하기

우리는 워커노드 VM의 특정 디렉토리를 퍼시스턴트 볼륨 클레임 오브젝트를 이용하여 파드 안에 마운트 해 봤습니다.
‘member’ 파드의 명세 부분에 아래와 같이 정의해서요.

...
    spec:
      …
      containers:
      - name: member
        ...
        volumeMounts:

        - name: data
          mountPath: /home/docker/data
      volumes:
      - name: data
        persistentVolumeClaim: 
          cliamName: ott


컨피그맵이나 시크릿을 이용하여 파드 안에 볼륨 마운트 할 수도 있습니다.
여러분이 만든 컨피그맵 ‘cm3’와 시크릿 ‘secret3’는 그 내용이 여러 줄입니다.
보통 이런 여러줄의 내용을 담고 있는 오브젝트들은 파드 안에 마운트하여 사용 합니다.

이번에는 컨피그맵과 시크릿을 파드안에 마운트하는걸 해 보겠습니다.
그리고 컨피그맵과 시크릿의 내용이 변경되었을때 자동으로 파드내의 데이터도 변경되는 것을 실습해 보겠습니다.

1) 컨피그맵/시크릿 볼륨 마운트
자 그럼 컨피그맵 ‘cm3’와 시크릿 ‘secret3’를 파드 안에 마운트 해 봅시다.

‘sts-busybox.yaml’파일을 열고 끝에 아래와 같이 ‘volumeMounts’와 ‘volumes’항목을 추가 합니다.

...
    spec:
      serviceAccount: sa-ott
      containers:
      - name: busybox
        ...
        imagePullPolicy: IfNotPresent
        envFrom:

        …
        env:
        …
        volumeMounts:
        - name: myconfig
          mountPath: /home/config
        - name: mysecret
          mountPath: /home/secret/secret.conf
          subPath: secret.conf
        
      volumes:
      - name: myconfig
        configMap:
          name: cm3
      - name: mysecret
        secret:
          secretName: secret3        




파드 내에 마운트할 위치는 디렉토리로 지정하는 방법과 파일로 지정하는 방법이 있습니다.
‘cm3’는 디렉토리에 마운트하고 ‘secret3’는 파일로 마운트 합니다.

첫번째 컨피그맵 ‘cm3’를 마운트 하는 원리를 살펴 봅시다.
❶ ‘volumeMounts’의 ‘name’에 지정한 ‘myconfig’와 동일한 이름을 ‘volumes’에서 찾습니다. 컨피그맵 ‘cm3’와 연결이 됩니다.
❷ 컨피그맵 ‘cm3’의 키인 ‘cm.conf’라는 파일명으로, 지정된 디렉토리 ‘/home/config’에 마운트 합니다. 즉 ‘/home/config/cm.conf’라는 파일이 파드 안에 생성이 됩니다. 마운트할 디렉토리는 없으면 자동으로 만들어 집니다.


두번째 시크릿 ‘secret3’는 디렉토리가 아닌 파일로 마운트 하도록 정의 했습니다.
❶ ‘volumeMounts’의 ‘name’에 지정한 ‘mysecret’과 동일한 이름을 ‘volumes’에서 찾습니다. 시크릿 ‘secret3’와 연결이 됩니다.
❷ 시크릿 오브젝트에서 키가 ‘secret.conf’인 데이터를 찾습니다. ‘secret3’는 파일명인 ‘secret.conf’가 키로 되어 있습니다. 한 파일에 여러개의 키가 있는 컨피그맵이나 시크릿이 있을 수 있으므로 어떤 키에 해당하는 데이터를 마운트할 지 지정해 줘야 합니다.
❸ 찾은 키에 해당하는 데이터를 ‘mountPath’에 지정한 ‘/home/secret/secret.conf’로 마운트 합니다.


위와 같이 정의하면 파드 안에 ‘/home/config/cm.conf’와 ‘/home/secret/secret.conf’파일이 생성되어야 합니다.
파드에 야믈 파일을 적용하고 파드 안으로 들어가서 확인해 봅시다.
아래와 같이 컨피그맵과 시크릿의 내용이 정의된 위치에 잘 마운트 된 걸 확인할 수 있습니다.

[root@osboxes yaml]# k apply -f sts-busybox.yaml
[root@osboxes yaml]# k get po -w
[root@osboxes yaml]# k exec busybox-0 -it -- sh
/ # cd /home/config

/home/config # ls -al

lrwxrwxrwx    1 root     root            14 Jan 20 03:58 cm.conf -> ..data/cm.conf
lrwxrwxrwx    1 root     root            18 Jan 20 03:58 imgreg.conf -> ..data/imgreg.conf

/home/config # cat cm.conf
{
  name: "busybox"
  description: "test config"
}
/home/config # cat imgreg.conf
registry=docker.io
organization=hiondal
repo=membe

/home/config # cd /home/secret
/home/secret # ls -al

-rw-r--r--    1 root     root            96 Jan 19 08:32 secret.conf
/home/secret # cat secret.conf
{
  ca.crt: !@#$%
  ca.key: ^&*
}


<주의>
디렉토리 마운트와 파일 마운트가 같이 정의 되어 있을때 디렉토리의 경로가 똑같으면 안됩니다.
위 예에서 마운트 경로가 ‘/home/config’나 ‘/home/secret’으로 똑같으면 안됩니다.
</>



2) 컨피그맵/시크릿 변경 데이터의 동적 반영
볼륨 마운트된 컨피그맵과 시크릿의 내용이 변경되면 파드 안에도 동적으로 반영 됩니다.
이러한 특성을 활용하면 파드를 재시작하지 않아도 되기 때문에 무중단 서비스가 가능합니다.
반영되는 시간 지연이 몇 초정도 있기 때문에 서비스의 지연 시간은 조금 있을 수 있습니다.
예를 들어 DB의 호스트나 포트가 변경되었을 때 파드를 재시작하지 않아도 반영이 되기 때문에 서비스 중단이 없습니다.
볼륨 마운트가 아닌 환경변수 생성을 위해 참조한 컨피그맵과 시크릿은 내용이 바뀌어도 동적으로 반영되지 않고
바뀐 값을 반영하려면 파드를 재시작 해야 합니다.

진짜로 동적으로 반영이 되는지 테스트 해 봅시다.
먼저 디렉토리로 마운트한 컨피그맵 ‘cm3’부터 테스트 합니다.
‘kubectl edit’를 이용해 ‘cm3’의 내용을 아무거나 바꿔 봅니다. 저는 ‘description’의 내용을 아래와 같이 바꿨습니다.

[root@osboxes yaml]# k edit cm cm3
apiVersion: v1
data:
  cm.conf: |
    {
      name: "busybox"
      description: "test dynamic config provisioning"
    }
...


아래 명령으로 파드 안의 파일 내용을 봅니다.

[root@osboxes yaml]# k exec -it busybox-0 -- cat /home/config/cm.conf
{
  name: "busybox"
  description: "test config1"
}


즉시 반영되지는 않습니다. 약 10초 이상 기다렸다가 다시 한번 확인 합니다.
아래와 같이 값이 변경된 것을 볼 수 있습니다.

[root@osboxes yaml]# k exec -it busybox-0 -- cat /home/config/cm.conf
{
  name: "busybox"
  description: "test dynamic config provisioning"
}


이번에는 파일로 마운트한 시크릿 ‘secret3’를 테스트 합니다.
변경할 값을 base64로 인코딩해야 하니 아래와 같이 그 값을 구합니다. 클립보드에 복사 합니다.

[root@osboxes yaml]# echo test secret dynamic provisioning | base64
dGVzdCBzZWNyZXQgZHluYW1pYyBwcm92aXNpb25pbmcK


‘kubectl edit’명령으로 시크릿 오브젝트를 편집합니다.
secret.conf의 값을 위에서 구한 base64 값으로 바꿉니다.

[root@osboxes yaml]# k edit secret secret3
apiVersion: v1
data:
  secret.conf: dGVzdCBzZWNyZXQgZHluYW1pYyBwcm92aXNpb25pbmcK
kind: Secret
...


아래 명령으로 현재 파드 안에 마운트된 파일 내용을 봅니다.

[root@osboxes yaml]# k exec -it busybox-0 -- cat /home/secret/secret.conf
{
  ca.crt: !@#$%
  ca.key: ^&*
}


이번에도 약 10초 이상 기다리면 값이 바뀔까요 ?
아닙니다. 아무리 한참 이따 해도 계속 값이 안 바뀝니다.
파일로 마운트한 컨피그맵이나 시크릿은 내용이 변경되어도 동적 반영이 되지 않습니다.
변경한 내용을 반영하려면 파드를 재시작 해야 합니다.
아래와 같이 파드를 지워서 재시작 하십시오.
아시다시피 파드를 지우면 스테이트풀셋 워크로드 컨트롤러가 새로운 파드를 생성합니다.

[root@osboxes yaml]# k delete po busybox-0
pod "busybox-0" deleted


새 파드에 마운트된 ‘secret.conf’파일의 내용을 확인 해 보십시오.
이제는 바뀐 내용이 반영이 되어 있을 겁니다.

[root@osboxes yaml]# k exec -it busybox-0 -- cat /home/secret/secret.conf
test secret dynamic provisioning


이와 같이 파드내에서 참조하는 컨피그맵이나 시크릿의 변경 내용이 동적으로 반영되려면 디렉토리로 마운트 해야 합니다. 환경변수 생성을 위해 참조하거나 파일로 마운트 된 경우는 변경 내용이 동적으로 반영되지 않고 파드를 재시작해야 합니다.

컨피그맵/시크릿의 내용 변경을 동적으로 반영할 필요 없는데 디렉토리로 마운트 해야 하는 경우 아래와 같이
‘immutable: true’ 항목을 추가 하십시오.
이 항목이 true로 되어 있는 컨피그맵과 시크릿은 내용 변경 모니터링에서 제외 되어 클러스터의 부하를 줄여 줍니다.

kind: ConfigMap
apiVersion: v1
metadata:
  name: cm3
  namespace: ott
data:
  cm.conf: |
    {
      name: "busybox"
      description: "test config"
    }
immutable: true


3) 프로젝티드 볼륨Projected Volumes으로 한 디렉토리로 마운트 하기
디렉토리로 마운트하는 방법에는 ‘프로젝티드 볼륨Projected volumes’이라는 방법도 있습니다.
프로젝티드 볼륨이란 동일한 디렉토리 밑으로 여러개의 파드 외부 볼륨을 마운트하는 방법입니다.
컨피그맵과 시크릿을 프로젝티드 볼륨 방식으로 동일한 디렉토리 밑으로 마운트 할 수 있습니다.
<팁>
프로젝티드 볼륨에서 ‘Projected’라는 의미는 동일한 목적으로 관련된 것을 묶었다는 의미로 이해하시면 됩니다.
</>

‘sts-busybox.yaml’에 아래와 같이 ‘projected’라는 볼륨을 ‘/home/projected’디렉토리로 마운트 하는 설정을 추가 하십시오.

...
    spec:
      serviceAccount: sa-ott
      containers:
      - name: busybox
        ...
        imagePullPolicy: IfNotPresent
        envFrom:

        …
        env:
        …
        volumeMounts:
        …
        - name: projected
          mountPath: /home/projected
        
      volumes:
      …
      - name: projected
        projected:
          sources:
          - configMap:
              name: cm3
              items:
              - key: cm.conf
                path: cm/cm.conf
              - key: imgreg.conf
                path: cm/imgreg.conf
          - secret:
              name: secret3
              items:
              - key: secret.conf
                path: secret/secret.conf       


프로젝티드 볼륨의 동작 방식은 아래와 같습니다.
❶ ‘volumeMounts’의 ‘name’에 지정한 ‘projected’와 동일한 이름을 ‘volumes’에서 찾습니다. 볼륨 ‘projected’와 연결이 됩니다.
❷ 컨피그맵에서 키가 ‘cm.conf’인 데이터와 키가 ‘imgreg.conf’인 데이터를 찾습니다. 또한 시크릿에서 키가 ‘secret.conf’인 데이터를 찾습니다.
❸ 찾은 키에 해당하는 데이터를 ‘mountPath’에 지정한 ‘/home/projected’로 마운트 합니다. 이때 각 데이터의 ‘items.path’에 지정한 디렉토리와 파일명으로 마운트 합니다. 마운트 되는 파일명은 각 오브젝트의 키와 달라도 됩니다. ‘items.path’에 파일명만 지정해도 됩니다.


‘sts-busybox.yaml’을 적용하여 새로 파드를 실행하고 파드 안으로 진입합니다.

[root@osboxes yaml]# k apply -f sts-busybox.yaml
[root@osboxes yaml]# k get po -w
[root@osboxes yaml]# k exec busybox-0 -it -- sh


‘/home/projected’디렉토리로 이동하고 리스트를 보면 디렉토리 ‘cm’과 ‘secret’이 보입니다.

/ # cd /home/projected/
/home/projected # ls -al
total 8
drwxrwxrwt    3 root     root           120 Jan 20 04:57 .
drwxr-xr-x    1 nobody   nobody        4096 Jan 20 03:58 ..
drwxr-xr-x    4 root     root            80 Jan 20 04:57 ..2022_01_20_04_57_51.1678785706
lrwxrwxrwx    1 root     root            32 Jan 20 04:57 ..data -> ..2022_01_20_04_57_51.1678785706
lrwxrwxrwx    1 root     root             9 Jan 20 03:58 cm -> ..data/cm
lrwxrwxrwx    1 root     root            13 Jan 20 03:58 secret -> ..data/secret


컨피그맵과 시크릿 오브젝트가 지정한대로 잘 마운트 되었는지 확인해 보십시오.

/home/projected # cat cm/cm.conf
{
  name: "busybox"
  description: "test config"
}
/home/projected # cat cm/imgreg.conf
registry=docker.io
organization=hiondal
repo=member
/home/projected # cat secret/secret.conf
{
  ca.crt: !@#$%
  ca.key: ^&*
}


이와 같이 프로젝티드 볼륨 방식으로 관련된 오브젝트들을 하나의 디렉토리로 마운트 할 수 있습니다.
또한 디렉토리로 마운트 했기 때문에 오브젝트 내용의 변화도 동적으로 적용 됩니다.
이건 여러분이 직접 한번 해 보시기 바랍니다.



10.4 시크릿으로 관리되는 데이터 유형

시크릿은 환경변수 생성 뿐 아니라 보안이 필요한 다양한 종류의 데이터를 관리하기 위해서도 사용됩니다.

시크릿으로 관리되는 데이터의 종류는 아래와 같습니다.
시크릿을 만들때 각 사용용도에 맞게 정확한 시크릿 타입을 지정해 주는 것이 좋습니다.

사용용도 시크릿 타입
환경변수 Opaque
서비스 어카운트 토큰Service Account Token kubernetes.io/service-account-token
이미지 레지스트리 로그인 자격 증명Image Registry Login Credential kubernetes.io/dockercfg
이미지 레지스트리 접근 자격 증명Image Registry Access Credential kubernetes.io/dockerconfigjson
ID/PW 방식의 기본 인증 자격 증명Basic Authentication Credential kubernetes.io/basic-auth
SSH 방식의 인증 자격 증명SSH Authentication Credential kubernetes.io/ssh-auth
TLS 인증서TLS Certificate kubernetes.io/tls


여러분은 이 중에 환경변수, 이미지 레지스트리 접근 자격 증명, TLS 인증서 유형의 시크릿은 이미 만들어 보셨습니다.
위 3가지 유형이 가장 많이 사용하는 시크릿 유형이므로 나머지에 대해서는 간략히만 설명하겠습니다.

1) 이미지 레지스트리 접근 자격 증명 유형
이미지 레지스트리를 접근하기 위한 아래 예와 같은 데이터를 갖고 있는 시크릿입니다.
{"auths":{"docker.io":{"username":"hiondal","password":"passw0rd","auth":"aGlvb…G92ZSQ="}}}

‘docker.io’가 이미지 레지스트리의 주소입니다.
‘auth’에는 그 앞에 있는 사용자명과 암호를 ‘{사용자명}:{암호}’형식으로 base64 인코딩하여 지정 합니다.

아래와 같이 만들 수 있습니다.

kubectl create secret docker-registry {시크릿명} \
--docker-server={이미지 레지스트리 주소} \
--docker-username={이미지 레지스트리 로그인 사용자명} \
--docker-password={이미지 레지스트리 로그인 사용자 암호} [-n ${네임스페이스명}]

예) kubectl create secret docker-registry dockerhub \
--docker-server=docker.io \
--docker-username=hiondal \
--docker-password=11111 -n ott



2) TLS 인증서 유형
TLS인증서 유형의 시크릿은 인그레스의 TLS통신을 실습할 때 만들었습니다.
웹브라우저에서 HTTPS를 이용하기 위해서는 이 유형의 시크릿이 필요 합니다.
‘tls.crt’ 항목에 인증서 데이터가 있고 ‘tls.key’항목에는 개인키 데이터가 있습니다.

kubectl을 이용해서 만들 수 있습니다.

kubectl create secret tls {name} \
--key {개인키 파일 절대 경로} \
--cert {인증서 파일 절대 경로} [-n ${네임스페이스명}]

예제) kubectl create secret tls ott --key ott.key --cert ott.crt -n ott



3) 서비스 어카운트 토큰 유형
서비스 어카운트 토큰 유형의 시크릿은 서비스 어카운트를 생성하면 자동으로 쿠버네티스 컨트롤러 매니저에 의해 생성됩니다. 따라서 여러분이 직접 만들 일은 없을 겁니다.

실습에서 사용하고 있는 서비스 어카운트 ‘sa-ott’의 토큰을 갖고 있는 시크릿을 찾아서 그 내용을 보시기 바랍니다.
‘ca.crt’는 서비스 어카운트가 쿠버네티스 클러스터를 접근하기 위한 인증서 데이터이고 ‘token’은 클러스터를 로그인하는 인증 토큰 입니다.

[root@osboxes yaml]# k get secret | grep sa-ott
sa-ott-token-rlbgj    kubernetes.io/service-account-token   3      26h
[root@osboxes yaml]# k get secret sa-ott-token-rlbgj -o yaml
apiVersion: v1
data:
  ca.crt: LS0tLS1…tLS0tCg==
  namespace: b3R0
  token: ZXlKaGJH…RqSWxuNHVB
kind: Secret
metadata:
  …
  name: sa-ott-token-rlbgj
  namespace: ott
  resourceVersion: "213435"
  uid: 57722509-91ab-4163-ab67-307e70d449cd
type: kubernetes.io/service-account-token

k8s 1.25부터는 Service Account생성 시 자동으로 Secret이 만들어지지 않습니다.

아래 예제와 같이 수동으로 Secret을 생성해줘야 합니다. 

apiVersion: v1
kind: Secret
metadata:
  name: sa-ott-secret
  namespace: ott
  annotations:
    kubernetes.io/service-account.name: sa-ott
type: kubernetes.io/service-account-token



4) 이미지 레지스트리 로그인 자격 증명 유형
이미지 레지스트리 로그인 자격 증명 유형의 시크릿은 이미지 레지스트리를 로그인 했을 때 $HOME/.docker/config.json에 저장되는 로그인 정보를 담고 있습니다.

예를 들면 아래와 같은 데이터를 담고 있습니다.
{ "auths": { "https://index.docker.io/v1/": { "auth": "aGl...2ZSQ=" } } }

https://index.docker.io/v1/’이 이미지 레지스트리의 API Server 주소입니다.
‘auth’는 ‘{유저명}:{로그인암호}’ 값을 base64로 인코딩한 값입니다.

배천 노드에서 아래 예를 참고해서 만들어 보고 생성된 시크릿의 야물을 확인해 보시기 바랍니다.

kubectl create secret generic {name} \
--from-file=.dockercfg={config.json의 절대경로} \
--type=kubernetes.io/dockercfg [-n ${네임스페이스명}]

예) kubectl create secret generic imgreg-login \
--from-file=.dockercfg=/root/.docker/config.json \
--type=kubernetes.io/dockercfg -n ott


5) ID/PW 방식의 기본 인증 자격 증명
ID/PW방식의 기본 인증 자격 증명은 ‘username’과 ‘password’를 키로 각각 사용자명과 암호를 담은 시크릿입니다.

Literal 방식으로 아래와 같이 간단히 만들 수 있습니다.

kubectl create secret generic {name} \
--from-literal username={username} \
--from-literal password={password} \
--type=kubernetes.io/basic-auth [-n ${네임스페이스명}]

예제) kubectl create secret generic basic-auth \
--from-literal username=admin \
--from-literal password=t0p-Secret \
--type=kubernetes.io/basic-auth -n ott


6) SSH 방식의 인증 자격 증명
SSH 방식의 인증 자격 증명은 프라이빗 키를 갖고 있는 시크릿입니다.
SSH 방식은 여러분들이 배천노드에서 컨트롤 플레인이나 워커 노드를 암호 없이 로그인할 때 사용한 방식입니다.

배천 노드의 ‘/root/.ssh/id_rsa’파일이 SSH 프라이빗 키입니다.
예제를 참고해서 아래와 같이 말들고 그 야믈 내용을 보시기 바랍니다.

kubectl create secret generic {name} \
--from-file=ssh-privatekey={SSH private key 파일의 절대 경로} \
--type=kubernetes.io/ssh-auth [-n ${네임스페이스명}]

예제)
kubectl create secret generic sshkey \
--from-file=ssh-privatekey=/root/.ssh/id_rsa \
--type=kubernetes.io/ssh-auth -n ott

 

쿠버네티스 쉽게 이해하기 시리즈 목차

[쿠버네티스 쉽게 이해하기 1] 쿠버네티스 설치하기
[쿠버네티스 쉽게 이해하기 2] 쿠버네티스 아키텍처
[쿠버네티스 쉽게 이해하기 3] 한장으로 이해하는 쿠버네티스 리소스
[쿠버네티스 쉽게 이해하기 4] 쿠버네티스 개발에서 배포까지 실습
[쿠버네티스 쉽게 이해하기 5] 쿠버네티스 오브젝트 정의 파일 쉽게 만들기
[쿠버네티스 쉽게 이해하기 6] 꼭 알아야 할 쿠버네티스 주요 명령어
[쿠버네티스 쉽게 이해하기 7] 파드 실행 및 통제를 위한 워크로드 컨트롤러
[쿠버네티스 쉽게 이해하기 8] 파드 로드 밸런서 서비스
[쿠버네티스 쉽게 이해하기 9] 서비스 로드 밸런서 인그레스
[쿠버네티스 쉽게 이해하기 10] 환경변수 컨피그맵과 시크릿
[쿠버네티스 쉽게 이해하기 11] 데이터 저장소 사용을 위한 PV/PVC
[쿠버네티스 쉽게 이해하기 12] 헬스 체크를 위한 스타트업 프로브, 라이브니스 프로브, 레디니스 프로브
[쿠버네티스 쉽게 이해하기 13] 통합 로깅을 위한 EFK 스택
[쿠버네티스 쉽게 이해하기 14] 인증Authentication과 알백RBAC 방식의 인가Authorization
[쿠버네티스 쉽게 이해하기 15] 더 알면 좋을 주제들: 무중단 배포, 모니터링, HPA

댓글

전자책 출간 알림 [마이크로서비스패턴 쉽게 개발하기]