Study/K8s

[Kubernetes] ConfigMap과 Secret

Omoknooni 2023. 12. 25. 23:46

컨테이너 설정파일을 관리하는 방법으로는 컨테이너 이미지를 빌드할때에 복사하거나, 컨테이너를 실행했을 때에 외부 호스트에서 파일을 연결해주는 방법이 있다. 

쿠버네티스에서는 ConfigMap 리소스를 통해 설정파일을 관리하는 방법을 제공한다.

 

ConfigMap

컨테이너의 환경설정 값을 저장하기 위한 리소스 키-값 쌍의 데이터를 저장한다.

ConfigMap에는 주로 Application의 설정값, 컨테이너의 환경변수, 설정파일과 같은 데이터를 저장한다.

 

아래는 ConfigMap을 정의하는 Manifest이다.

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  NGINX_PORT: "8080"
  NGINX_SERVER_NAME: "my-nginx"
  NGINX_ROOT: "/usr/share/nginx/html"

 

 

위와 같이 키-값 형태로 정의된 상태로 YAML 파일을 작성해 ConfigMap을 작성할 수 있다.

파드를 생성할 때, ConfigMap을 환경변수로 컨테이너에 전달하는 Manifest이다.

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  containers:
    - name: nginx
      image: nginx
      env:				# 컨테이너의 환경변수를 설정
        - name: PORT			# PORT 환경변수 설정
          valueFrom:
            configMapKeyRef:		# configMap에서 키를 가져옴
              name: nginx-config	# configMap의 이름
              key: NGINX_PORT		# 해당 configMap에서 키 값을 가져옴
        - name: SERVER_NAME
          valueFrom:
            configMapKeyRef:
              name: nginx-config
              key: NGINX_SERVER_NAME
        - name: ROOT
          valueFrom:
            configMapKeyRef:
              name: nginx-config
              key: NGINX_ROOT

 

환경변수가 아닌 설정파일을 넣어주어야하는 경우가 있다. 이 경우 ConfigMap에 설정파일의 내용을 넣어서 생성하고 파드에 Volume으로 ConfigMap을 주입해 줄 수 있다.

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  nginx.conf: |
    server {
      listen 80;
      server_name localhost;

      location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
      }
    }

 

 

아래는 파드를 생성할때, 정의된 ConfigMap을 Volume으로 주입하는 Manifest이다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
          volumeMounts:
            - name: nginx-config-volume
              mountPath: /etc/nginx/conf.d		# Volume을 해당 경로에 마운트
      volumes:
        - name: nginx-config-volume
          configMap:					# ConfigMap을 volume으로 사용
            name: nginx-config

 

 

 

Secret

Password, SSH Key와 같은 민감한 정보를 저장하기 위한 목적을 가진 리소스

Secret도 ConfigMap과 동일하게 키-값 쌍의 데이터를 저장하지만, 데이터가 base64로 인코딩되어 저장된다는 점이 있다.

아래는 Secret을 생성하는 Manifest이다.

apiVersion: v1
kind: Secret
metadata:
  name: mariadb-secret
data:
  password: cGFzc3dvcmQ=
  userpass: dXNlcnBhc3M=

 

 

이렇게 생성한 Secret을 환경변수로 불러오는 Manifest는 아래와 같다.

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mariadb
...
    spec:
      containers:
      - name: mariadb
        image: mariadb
        env:
          - name: MYSQL_ROOT_PASSWORD
            valueFrom:
              secretKeyRef:			# Secret의 키를 참조하여 가져옴
                name: mariadb-secret		# Secret의 이름
                key: password			# 해당 Secret의 키(password)를 가져옴
          - name: MYSQL_USER
            valueFrom:
                secretKeyRef:
                  name: mariadb-secret
                  key: userpass
       ...

 

env 항목으로 환경변수를 생성하는데, valueFrom으로 SecretKeyRef를 통해 Secret의 특정 키를 참조한다.

반대로 Secret의 모든 내용을 한번에 불러오는 방법은 아래와 같다.

...
    spec:
      containers:
      - name: mariadb
        image: mariadb
        envFrom:
          - secretRef:			# mariadb-secret의 내용을 모두 로드
              name: mariadb-secret
...

 

 

여기서 알아두어야하는 것이 Secret이라는 이름에 무색하게 내용이 암호화되지 않는다는 것이다.

인코딩은 결코 암호화가 될 수 없다.

 

워커노드나 etcd에 접근할 수 있는 경우, Secret을 별 다른 노력없이 바로 읽을 수 있다.

그리고 Secret 내용을 yml 파일에 바로 담아서 사용하는 선언식 관리의 경우, git과 같은 버전관리 시스템에 포함하기에 적절하지 않다

따라서, 안전하게 민감정보를 주입하고 사용하기위해서는 Secret과 etcd를 암호화하거나 다른 3rd party 솔루션이나 오픈소스 등을 사용하는 방법이 존재한다.

 

이렇게 쿠버네티스에서 설정파일을 파드에 배포하는 리소스인 ConfigMap과 Secret에 대해 알아보았다.