[Kubernetes] ConfigMap & Secret ( + 환경변수)
✔️ 환경변수
vagrant@k8s-node1 ~ kubectl explain pods.spec.containers.env
name
: 환경변수의 이름value
: 환경변수의 값
myweb.yaml
apiVersion: v1
kind: Pod
metadata:
name: myweb-env
spec:
containers:
- name: myweb
image: ghcr.io/c1t1d0s7/go-myweb:alpine
env:
- name: MESSAGE # 환경변수명
value: "Customized Hello World"
vagrant@k8s-node1 ~/configure/env kubectl create -f myweb.yaml
pod/myweb-env created
vagrant@k8s-node1 ~/configure/env kubectl get po
NAME READY STATUS RESTARTS AGE
myweb-env 1/1 Running 0 3s
nfs-client-provisioner-758f8cd4d6-wpjbt 1/1 Running 0 53m
vagrant@k8s-node1 ~/configure/env kubectl exec -it myweb-env -- sh
/ # env
KUBERNETES_PORT=tcp://10.233.0.1:443
KUBERNETES_SERVICE_PORT=443
HOSTNAME=myweb-env
SHLVL=1
HOME=/root
TERM=xterm
KUBERNETES_PORT_443_TCP_ADDR=10.233.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.233.0.1:443
MESSAGE=Customized Hello World
KUBERNETES_SERVICE_HOST=10.233.0.1
PWD=/
컨테이너 내부에 MESSAGE=Customized Hello World
의 환경변수를 제공한다.
vagrant@k8s-node1 ~/configure/env kubectl port-forward pod/myweb-env 8080:8080
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080
Handling connection for 8080
vagrant@k8s-node1 ~ curl localhost:8080
Customized Hello World
myweb-env
포트 포워딩을 걸어놓고 접속하면 Customized Hello World
가 출력된다.
원래 Hello World
만 출력되지만 해당 App안에는 MESSAGE
환경변수가 있으면
그 값을 리턴 시키는 기능을 가지고 있기 때문이다.
✔️ ConfigMap & Secret 사용 이유
ConfigMap과 Secret 오브젝트를 사용하는 이유를 생각해보자
우리가 서비스를 배포할 때는 개발환경과 상용환경의 차이가 있을 것이다.
그 이유는, 대부분 설정 정보나 보안 접근에서 차이가 있기 때문이다.
따라서, 상용환경과 개발환경에서 배포를 한다면 값이 바뀌어야한다는 것을 의미한다.
이러한 값은 컨테이너의 이미지 값이기 때문에 값을 바꾼다는 것은 개발환경과 상용환경에서 사용하는 이미지를 각각 관리해야한다는 것을 말한다.
하지만 상용환경과 개발환경에 사용되는 컨테이너는 같아야한다. 그래야만 개발과 서비스 사이의 환경적 차이에서 오는 문제점을 방지할 수 있다.
그러므로, 변하는 값들을 외부에서 결정이 가능하도록 도움을 주는 Object인 ConfigMap과 Secret을 사용한다.
즉, 컨테이너에 필요한 환경 설정을 컨테이너와 분리해서 제공하는 방식을 택하는 것이다.
분리해야 하는 일반적인 상수들을 모아서 ConfigMap으로 만들고 Key와 같은 보안적인 관리가 필요한 것을 모아서 Secret으로 만들고 Pod 생성시 환경변수로서 연결해 사용한다.
데이터만 바꿔주면서 똑같은 이미지로 개발환경과 상용환경에서 사용이 가능하게 된다.
✔️ ConfigMap
컨피그맵은 키-값 쌍으로 기밀이 아닌 데이터를 저장하는 데 사용하는 API 오브젝트이다.
파드는 볼륨에서 환경 변수, 커맨드-라인 인수 또는 구성 파일로 컨피그맵을 사용할 수 있다.
컨피그맵을 사용하면 컨테이너 이미지에서 환경별 구성을 분리하여, 애플리케이션을 쉽게 이식할 수 있다.
주의: 컨피그맵은 보안 또는 암호화를 제공하지 않는다. 저장하려는 데이터가 기밀인 경우, 컨피그맵 대신 시크릿(Secret) 또는 추가(써드파티) 도구를 사용하여 데이터를 비공개로 유지하자.
vagrant@k8s-node1 ~/configure/cm kubectl api-resources | grep configmap
configmaps cm v1 true ConfigMap
vagrant@k8s-node1 ~/configure/cm kubectl explain cm.data
FIELD: data <map[string]string>
DESCRIPTION:
Data contains the configuration data. Each key must consist of alphanumeric
characters, '-', '_' or '.'. Values with non-UTF-8 byte sequences must use
the BinaryData field. The keys stored in Data must not overlap with the
keys in the BinaryData field, this is enforced during validation process.
data
는 해시 방식으로 key : value
를 지정한다.
CM
: 기밀이 아닌 데이터Secret
: 기밀 데이터
CM
과 Secret
모두 기본적으로 key : value
를 저장한다.
파드에서 두가지 형식으로 사용 가능하다.
1) 환경 변수 : key, value를 환경 변수로 사용 가능
2) 파일로 제공 가능 : key가 파일명이 되며 value가 파일의 내용이 된다.
→ 그래서 볼륨의 종류 중에 CM
과 Secret
이 있는 것이다.
파일을 제공하지만 데이터를 쓰거나 하기는 어려워서 읽기 전용으로 제공하는 것이 일반적이다.
파일 제공의 목적은 설정 파일 (즉, 읽기만 하는 용도), 인증서, 암호화 키를 제공하는 것이다.
✔️ 환경변수로 제공하는 방법
mymessage.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mymessage
data:
MESSAGE: Customized Hello ConfigMap
vagrant@k8s-node1 ~/configure/cm kubectl create -f mymessage.yaml
configmap/mymessage created
vagrant@k8s-node1 ~/configure/cm kubectl get cm
NAME DATA AGE
kube-root-ca.crt 1 7d22h
mymessage 1 3s
vagrant@k8s-node1 ~/configure/cm kubectl describe cm mymessage
Name: mymessage
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
MESSAGE:
----
Customized Hello ConfigMap
BinaryData
====
Events: <none>
key
역할을 하는 MESSAGE
가 있고 구분자가 있고 바로 아래에 value
가 있다.
key : value
는 세트이기 때문에 현재 Data
가 한개 존재하는 것이다.
vagrant@k8s-node1 ~/configure/cm kubectl explain pods.spec.containers.envFrom
FIELDS:
configMapRef <Object>
The ConfigMap to select from
prefix <string>
An optional identifier to prepend to each key in the ConfigMap. Must be a
C_IDENTIFIER.
secretRef <Object>
The Secret to select from
configMapRef
: configMap
을 참조한다.secretRef
: secret
을 참조한다.
vagrant@k8s-node1 ~/configure/cm kubectl explain pods.spec.containers.envFrom.configMapRef
FIELDS:
name <string>
Name of the referent. More info:
https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
optional <boolean>
Specify whether the ConfigMap must be defined
name
: configMap
의 이름
myweb.yaml
apiVersion: v1
kind: Pod
metadata:
name: myweb-env
spec:
containers:
- name: myweb
image: ghcr.io/c1t1d0s7/go-myweb:alpine
envFrom:
- configMapRef:
name: mymessage
vagrant@k8s-node1 ~/configure/cm kubectl exec -it myweb-env -- sh
/ # env
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.233.0.1:443
HOSTNAME=myweb-env
SHLVL=1
HOME=/root
TERM=xterm
KUBERNETES_PORT_443_TCP_ADDR=10.233.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.233.0.1:443
MESSAGE=Customized Hello ConfigMap
KUBERNETES_SERVICE_HOST=10.233.0.1
PWD=/
MESSAGE=Customized Hello ConfigMap
이라는 환경변수가 있다.configMap
에서 Customized Hello ConfigMap
를 가져와서 등록시킨 것을 볼 수 있다.
myweb.yaml
의 envFrom.configMapRef.name
이 mymessage.yaml
의 name
을 가리킨다.
그래서 mymessage.yaml
의 MESSAGE: Customized Hello ConfigMap
가 key : value
형태로 시스템의 환경변수로 설정된다.
vagrant@k8s-node1 ~/configure/cm cat ../env/myweb.yaml
apiVersion: v1
kind: Pod
metadata:
name: myweb-env
spec:
containers:
- name: myweb
image: ghcr.io/c1t1d0s7/go-myweb:alpine
env:
- name: MESSAGE
value: "Customized Hello World"
환경변수를 직접 작성하는 방식과 비교해서 선택적으로 사용하면 된다.
✔️ 파일로 제공하는 방법
vagrant@k8s-node1 ~/configure/cm kubectl explain pods.spec.volumes.configMap
name <string>
Name of the referent. More info:
https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
myweb-cmvol.yaml
apiVersion: v1
kind: Pod
metadata:
name: myweb-cm-vol
spec:
containers:
- name: myweb
image: ghcr.io/c1t1d0s7/go-myweb:alpine
volumeMounts:
- name: cmvol
mountPath: /myvol
volumes:
- name: cmvol
configMap:
name: mymessage
vagrant@k8s-node1 ~/configure/cm kubectl exec -it myweb-cm-vol -- sh
/ # ls
bin dev etc home lib media mnt myvol myweb opt proc root run sbin srv sys tmp usr var
/ # cd myvol
/myvol # ls
MESSAGE
/myvol # cat MESSAGE
Customized Hello ConfigMap/myvol #
key
가 파일명이 되며 안에있는 데이터가 내용이된다.
✔️ env.valueFrom을 사용하는 방법
apiVersion: v1
kind: Pod
metadata:
name: myweb-env
spec:
containers:
- name: myweb
image: ghcr.io/c1t1d0s7/go-myweb:alpine
env:
valueFrom:
configMapKeyRef:
name: mymessage
key: MESSAGE
envFron
을 사용하는 방식과 env.valueFrom
을 사용하는 방식을 비교해보면
전자는 configMap
이 가진 데이터(key : value
형식)의 개수와 상관없이 다 등록하는 것이고
후자는 key를 직접 지정하므로 여러개의 데이터 중에 한개만 등록하고 싶을 때 사용할 수 있다.
즉, 특정 key
를 지칭하고 싶을 때는 후자 방식을 사용하면 된다.
✔️ Secret
시크릿은 암호, 토큰 또는 키와 같은 소량의 중요한 데이터를 포함하는 오브젝트이다.
이를 사용하지 않으면 중요한 정보가 파드 명세나 컨테이너 이미지에 포함될 수 있다.
시크릿을 사용한다는 것은 사용자의 기밀 데이터를 애플리케이션 코드에 넣을 필요가 없음을 뜻한다.
시크릿은 시크릿을 사용하는 파드와 독립적으로 생성될 수 있기 때문에, 파드를 생성하고, 확인하고, 수정하는 워크플로우 동안 시크릿(그리고 데이터)이 노출되는 것에 대한 위험을 경감시킬 수 있다.
쿠버네티스 및 클러스터에서 실행되는 애플리케이션은 기밀 데이터를 비휘발성 저장소에 쓰는 것을 피하는 것과 같이, 시크릿에 대해 추가 예방 조치를 취할 수도 있다.
시크릿은 컨피그맵과 유사하지만 특별히 기밀 데이터를 보관하기 위한 것이다.
기본적인 원리는 configMap
과 같이 key : value
를 제공하는 것이다.
value + base64 → encoded database64
는 암호화가 아니다. key
없이도 얼마든지 decoding
시킬 수 있다.secret
은 민감한 데이터를 저장하기 위해 만들어놨지만 인코딩만 할 뿐 암호화를 하지 않아 안전하지 않다.
AWS의 KMS와 연동해서 암호화할 수 있다.
또는 vault 라는 서비스와 base64를 연동해서 암호화할 수 있다.
보통 on-prem에서 사용할 때는 vault를 연동시켜 사용하고 클라우드 서비스를 사용할 때는 Key Managed Service를 연동해서 암호화한다.
vagrant@k8s-node1 ~/configure/secret kubectl api-resources | grep secret
secrets v1 true Secret
vagrant@k8s-node1 ~/configure/secret kubectl explain secret.type
📌 Secret type
key : value
를 저장할 때 value
가 어떤 형태인지 타입을 지정해야 한다.
✔️ 환경변수로 제공하는 방법
mydata.yaml
apiVersion: v1
kind: Secret
metadata:
name: mydata
type: Opaque
data:
id: admin
pwd: P@ssw0rd
다음 YAML 파일은 정상적으로 동작하지 않을 것이다.
vagrant@k8s-node1 ~/configure/secret kubectl create -f mydata.yaml
Error from server (BadRequest): error when creating "mydata.yaml": Secret in version "v1" cannot be handled as a Secret: v1.Secret.Data: decode base64: illegal base64 data at input byte 4, error found in #10 byte of ...|d":"admin","pwd":"P@|..., bigger context ...|{"apiVersion":"v1","data":{"id":"admin","pwd":"P@ssw0rd"},"kind":"Secret","metadata":{"na|...
역시 동작하지 않는다. base64로 값을 인코딩해야 한다.
vagrant@k8s-node1 ~/configure/secret echo "admin" | base64
YWRtaW4K
vagrant@k8s-node1 ~/configure/secret echo "P@ssw0rd" | base64
UEBzc3cwcmQK
인코딩
apiVersion: v1
kind: Secret
metadata:
name: mydata
type: Opaque
data:
id: YWRtaW4K
pwd: UEBzc3cwcmQK
처음 YAML 파일의 data의 id와 pwd를 인코딩한 값으로 변경한다.
vagrant@k8s-node1 ~/configure/secret kubectl get secret
NAME TYPE DATA AGE
default-token-h87sc kubernetes.io/service-account-token 3 7d23h
mydata Opaque 2 13s
nfs-client-provisioner-token-xzr7h kubernetes.io/service-account-token 3 91m
vagrant@k8s-node1 ~/configure/secret kubectl describe secret mydata
Name: mydata
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
id: 6 bytes
pwd: 9 bytes
secret
은 Data
의 내용을 보여주지 않는다.
vagrant@k8s-node1 ~/configure/secret kubectl get secret mydata -o yaml
apiVersion: v1
data:
id: YWRtaW4K
pwd: UEBzc3cwcmQK
kind: Secret
metadata:
creationTimestamp: "2022-05-24T06:41:38Z"
name: mydata
namespace: default
resourceVersion: "883840"
uid: 8cb72ad1-0cdb-45d9-b913-00596e058fba
type: Opaque
인코딩된 형태로 볼 수 있긴 하지만 암호화가 되지않아 안전하지 않다.
vagrant@k8s-node1 ~/configure/secret kubectl explain pod.spec.containers.envFrom.secretRef
FIELDS:
name <string>
Name of the referent. More info:
https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
optional <boolean>
Specify whether the Secret must be defined
myweb.yaml
apiVersion: v1
kind: Pod
metadata:
name: myweb-secret
spec:
containers:
- name: myweb
image: ghcr.io/c1t1d0s7/go-myweb:alpine
envFrom:
- secretRef:
name: mydata
key까지 설정하는 방법
apiVersion: v1
kind: Pod
metadata:
name: myweb-env
spec:
containers:
- name: myweb
image: ghcr.io/c1t1d0s7/go-myweb:alpine
env:
valueFrom:
secretKeyRef:
name: mydata
key: id
✔️ 파일로 제공하는 방법
apiVersion: v1
kind: Pod
metadata:
name: myweb-sec-vol
spec:
containers:
- name: myweb
image: ghcr.io/c1t1d0s7/go-myweb:alpine
volumeMounts:
- name: secvol
mountPath: /secvol
volumes:
- name: secvol
secret:
secretName: mydata