[Retry, k8s] 22. 컨피그 & 스토리지 API - 컨피그맵

Date:     Updated:

카테고리:

태그:


🔔 컨피그맵


쿠버네티스 컨피그맵은 컨테이너와 분리해서 키-값 쌍으로 환경설정 값을 저장하는데 사용하는 API 오브젝트

  • 키-밸류 형식 외에도 nginx.conf, httpd.conf 같은 설정 파일 자체도 저장할 수 있다.

  • 컨피그맵을 사용하면 동일한 컨테이너 이미지에 다른 설정 값을 이식해서 사용할 수 있다.

  • 컨피그맵은 네임스페이스 별로 존재하며, 파드는 환경 변수, 커맨드-라인 인수 또는 구성 파일로 컨피그맵을 사용할 수 있다.

  • 컨피그맵은 기밀이 아닌 데이터를 저장하도록 설계되었으므로, 저장하려는 데이터가 기밀인 경우 시크릿이나 다른 도구를 사용해야 한다.


(1) 컨피그맵 생성

  • 컨피그맵 리소스는 하나의 컨피그맵 안에 여러 키-밸류 값이 저장된다.

  • 하나의 컨피그맵마다 저장할 수 있는 사이즈는 총 1MB이다.


📜 kubectl로 파일에서 값을 참조하여 생성(–from-file)

# 파일로 컨피그맵 생성
$  kubectl create configmap --save-config sample-configmap --from-file=./nginx.conf
configmap/sample-configmap created


# 컨피그맵에 등록된 데이터 확인
$ kubectl get configmap sample-configmap -o json | jq .data
{
  "nginx.conf": "user  nginx;\nworker_processes  1;\n\nerror_log  /var/log/nginx/error.log warn;\n\npid        /var/run/nginx.pid;\n\n\nevents {\n    worker_connections  1024;\n}\n\n\nhttp {\n    include       /etc/nginx/mime.types;\n    \n    default_type  application/octet-stream;\n\n    log_format  main  '$remote_addr - $remote_user [$time_local] \"$request\" '\n                      '$status $body_bytes_sent \"$http_referer\" '\n                      '\"$http_user_agent\" \"$http_x_forwarded_for\"';\n\n    access_log  /var/log/nginx/access.log  main;\n\n    sendfile        on;\n    #tcp_nopush     on;\n\n    keepalive_timeout  65;\n\n    #gzip  on;\n    \n    include /etc/nginx/conf.d/*.conf\n}\n"
}


# 컨피그맵에 등록된 데이터 확인
$ kubectl describe configmap sample-configmap
Name:         sample-configmap
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
nginx.conf:
----
user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;

pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;

    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf
}


BinaryData
====

Events:  <none>
  • 컨피그맵 매니페스트는 data가 아닌 binaryData 필드를 사용하여 UTF-8 이외의 데이터를 포함하는 바이너리 데이터를 저장할 수 있다.

  • 쿠버네티스에 직접 등록하는 것이 아니라 매니페스트 파일로 저장하려면 “–dry-run=client -o yaml 옵션”을 사용한다.

$ kubectl create configmap sample-configmap-binary \
--from-file image.jpg \
--from-literal=index.html="Hello, Kubernetes" \
--dry-run=client -o yaml \
> sample-configmap-binary.yaml
$ cat sample-configmap-binary.yaml
apiVersion: v1
binaryData:
  image.jpg: iVBORw0KGgoAAAANSUhEUgAAAxcAAAGXCAYA ~(생략)~
data:
  index.html: Hello, Kubernetes
kind: ConfigMap
metadata:
  creationTimestamp: null
  name: sample-configmap-binary
cat <<EOF > sample-configmap-binary-webserver.yaml
apiVersion: v1
kind: Pod
metadata:
  name: sample-configmap-binary-webserver
spec:
  containers:
  - name: nginx-container
    image: nginx:1.16
    volumeMounts:
    - name: config-volume
      mountPath: /usr/share/nginx/html
  volumes:
  - name: config-volume
    configMap:
      name: sample-configmap-binary
EOF


$ kubectl exec -it sample-configmap-binary-webserver -- ls -la /usr/share/nginx/html
total 12
drwxrwxrwx 3 root root 4096 Apr  8 11:05 .
drwxr-xr-x 3 root root 4096 Apr 23  2020 ..
drwxr-xr-x 2 root root 4096 Apr  8 11:05 ..2023_04_08_11_05_18.1453186303
lrwxrwxrwx 1 root root   32 Apr  8 11:05 ..data -> ..2023_04_08_11_05_18.1453186303
lrwxrwxrwx 1 root root   16 Apr  8 11:05 image.jpg -> ..data/image.jpg
lrwxrwxrwx 1 root root   17 Apr  8 11:05 index.html -> ..data/index.html


📜 kubectl로 직접 값을 전달하여 생성(–from-literal)

# 인수에 직접 값을 전달하여 컨피그맵 생성
$ kubectl create configmap --save-config web-config \
--from-literal=connection.max=100 --from-literal=connection.min=10


📜 매니페스트로 생성 (-f)

cat <<EOF > sample-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: sample-configmap
data:
  thread: "16"
  connection.max: "100"
  connection.min: "10"
  sample.properties: | 
    property.1=value-1
    property.2=value-2
    property.3=value-3
  nginx.conf: |
    user nginx;
    worker_processes auto;
    error_log /var/log/nginx/error.log;
    pid /run/nginx.pid;
  test.sh: |
    #!/bin/bash
    echo "Hello, Kubernetes"
    sleep infinity
EOF




(2) 컨피그맵 사용

  1. 환경 변수로 전달

    • 컨피그맵의 특정 키만

    • 컨피그맵의 전체 키

  2. 볼륨으로 마운트

    • 컨피그맵의 특정 키만

    • 컨피그맵의 전체 키


📜 환경 변수로 전달

# 컨피그맵의 한 개 키를 환경 변수를 전달하는 파드
$ cat <<EOF > sample-configmap-single-env.yaml
apiVersion: v1
kind: Pod
metadata:
  name: sample-configmap-single-env
spec:
  containers:
  - name: configmap-container
    image: nginx:1.16
    env:
    - name: CONNECTION_MAX
      valueFrom:
        configMapKeyRef:
          name: sample-configmap
          key: connection.max
EOF


# 파드의 CONNECTION_MAX 환경 변수 내용 확인
$ kubectl exec -it sample-configmap-single-env -- env | grep CONNECTION_MAX
CONNECTION_MAX=100
# 컨피그맵의 전체 키를 환경 변수로 전달하는 파드 예제
$ cat <<EOF > sample-configmap-multi-env.yaml
apiVersion: v1
kind: Pod
metadata:
  name: sample-configmap-multi-env
spec:
  containers:
  - name: configmap-container
    image: nginx:1.16
    envFrom:
    - configMapRef:
        name: sample-configmap
EOF


# 파드의 환경 변수 내용 확인
$ kubectl exec -it sample-configmap-multi-env -- env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=sample-configmap-multi-env
TERM=xterm
nginx.conf=user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

sample.properties=property.1=value-1
property.2=value-2
property.3=value-3

test.sh=#!/bin/bash
echo "Hello, Kubernetes"
sleep infinity

thread=16
connection.max=100
connection.min=10
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT=tcp://10.96.0.1:443
NGINX_VERSION=1.16.1
NJS_VERSION=0.3.8
PKG_RELEASE=1~buster
HOME=/root


📜 볼륨으로 마운트

# 컨피그맵의 한 개 키를 볼륨 마운트하는 파드 예제
$ cat <<EOF > sample-configmap-single-volume.yaml
apiVersion: v1
kind: Pod
metadata:
  name: sample-configmap-single-volume
spec:
  containers:
  - name: configmap-container
    image: nginx:1.16
    volumeMounts:
    - name: config-volume
      mountPath: /config
  volumes:
  - name: config-volume
    configMap:
      name: sample-configmap
      items:
      - key: nginx.conf
        path: nginx-sample.conf
EOF

# 파일로 저장된 컨피그맵 확인
$ kubectl exec -it sample-configmap-single-volume -- cat /config/nginx-sample.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# 컨피그맵의 전체 키를 볼륨 마운트하는 파드 예제
$ cat <<EOF > sample-configmap-multi-volume.yaml
apiVersion: v1
kind: Pod
metadata:
  name: sample-configmap-multi-volume
spec:
  containers:
  - name: configmap-container
    image: nginx:1.16
    volumeMounts:
    - name: config-volume
      mountPath: /config
  volumes:
  - name: config-volume
    configMap:
      name: sample-configmap
EOF

# 파드에 마운트된 /config 아래 파일 확인
$ kubectl exec -it sample-configmap-multi-volume -- ls /config
connection.max  connection.min  nginx.conf  sample.properties  test.sh  thread




(3) 시크릿과 컨피그맵의 공통 주제


📜 시크릿과 컨피그맵의 사용 구분

시크릿과 컨피그맵은 비슷하게 사용할 수 있지만, 가장 큰 차이는 시크릿은 기밀 정보를 취급하기 위한 리소스라는 점에 있다.

  • 시크릿 데이터는 쿠버네티스 마스터의 etcd라는 분산 KVS(Key-Value Store)에 저장된다.

  • 실제 시크릿을 사용하는 파드가 있는 경우에만 etcd에서 쿠버네티스 노드에 데이터를 보낸다.

  • 이때 쿠버네티스 노드상에 영구적으로 데이터가 남지 않도록 시크릿 데이터 tmpfs 영역(메모리상에 구축된 임시 파일 시스템)에 저장되게 되어 있다.

  • 쿠버네티스 버전과 환경에 따라서는 etcd에 저장된 시크릿이 암호화되지 않을 수 있으므로, etcd에 접근할 수 있는 권한을 제한해야 합니다.

22313


📜 컨피그맵과 시크릿의 데이터 마운트 시 퍼미션 변경

컨피그맵에 저장된 스크립트를 파드에서 실행하는 경우 컨피그맵 데이터에서 볼륨을 생성할 때 실행 권한을 부여할 수 있다.

  • 시크릿도 저장된 기밀 데이터를 파드에 마운트하는 경우 시크릿 데이터에서 볼륨을 생성할 때 퍼미션을 부여할 수 있다.

  • 컨피그맵과 시크릿 모두 기본값 0644로 마운트된다. (퍼미션은 8진수 표기에서 10진수 표기로 변환한 형태를 사용하여 기술해야 한다.)

    • 예시) 256 -> 0400 -> r– — — 493 -> 0755 -> rwx- r-x r-x 420 -> 0644 -> rw- r– r–
# 예제에서는 컨피그맵 내부의 test.sh를 0755로 마운트하고 이 스크립트를 그대로 실행할 수 있다.
$ cat <<EOF > sample-configmap-scripts.yaml
apiVersion: v1
kind: Pod
metadata:
  name: sample-configmap-scripts
spec:
  containers:
  - name: configmap-container
    image: nginx:1.16
    command: ["/config/test.sh"]
    volumeMounts:
    - name: config-volume
      mountPath: /config
  volumes:
  - name: config-volume
    configMap:
      name: sample-configmap
      items:
      - key: test.sh
        path: test.sh
        mode: 493
EOF

# 작동 확인
$ kubectl logs sample-configmap-scripts
Hello, Kubernetes
# 시크릿 내부의 모든 데이터를 0400으로 마운트한다.
$ cat <<EOF > sample-configmap-secure.yaml
apiVersion: v1
kind: Pod
metadata:
  name: sample-secret-secure
spec:
  containers:
  - name: secret-container
    image: nginx:1.16
    volumeMounts:
    - name: config-volume
      mountPath: /config
  volumes:
  - name: config-volume
    secret:
      secretName: sample-db-auth
      defaultMode: 256
EOF


# 실제로 파일을 확인해보면 기본값 0644에 0400으로 변경되어 마운트된 것을 확인할 수 있다.
$ kubectl exec -it sample-secret-secure -- ls -l /config
total 0
lrwxrwxrwx 1 root root 15 Apr  8 13:20 password -> ..data/password
lrwxrwxrwx 1 root root 15 Apr  8 13:20 username -> ..data/username

$ kubectl exec -it sample-secret-secure -- ls -l /config/..data/
total 8
-r-------- 1 root root 12 Apr  8 13:20 password
-r-------- 1 root root  5 Apr  8 13:20 username


📜 동적 컨피그맵 업데이트

볼륨 마운트를 사용한 컨피그맵에서는 일정 시간마다 kube-apiserver로 변경을 확인하고 변경이 있을 경우에는 파일을 교체한다.

  • 업데이트 간격은 60초로 설정되어 있고, 이 간격을 조정할 경우에는 kubelet의 –sync-frequency 옵션을 설정한다.

  • 환경 변수를 사용한 컨피그맵은 기동할 때 환경 변수가 정해지기 때문에 동적으로 업데이트 할 수 없다.

23131313123

# 컨피그맵이 마운트되어 있는 디렉터리 확인
$ kubectl exec -it sample-configmap-multi-volume -- ls -al /config
total 12
drwxrwxrwx 3 root root 4096 Apr  8 11:47 .
drwxr-xr-x 1 root root 4096 Apr  8 11:47 ..
drwxr-xr-x 2 root root 4096 Apr  8 11:47 ..2023_04_08_11_47_17.2283803633
lrwxrwxrwx 1 root root   32 Apr  8 11:47 ..data -> ..2023_04_08_11_47_17.2283803633
lrwxrwxrwx 1 root root   21 Apr  8 11:47 connection.max -> ..data/connection.max
lrwxrwxrwx 1 root root   21 Apr  8 11:47 connection.min -> ..data/connection.min
lrwxrwxrwx 1 root root   17 Apr  8 11:47 nginx.conf -> ..data/nginx.conf
lrwxrwxrwx 1 root root   24 Apr  8 11:47 sample.properties -> ..data/sample.properties
lrwxrwxrwx 1 root root   14 Apr  8 11:47 test.sh -> ..data/test.sh
lrwxrwxrwx 1 root root   13 Apr  8 11:47 thread -> ..data/thread


# 파드의 /config/thread 파일 내용 확인
$ kubectl exec -it sample-configmap-multi-volume -- cat /config/thread
16


# 컨피그 맵 변경 전의 경과 시간(AGE) 확인
$ kubectl get pod sample-configmap-multi-volume
NAME                            READY   STATUS    RESTARTS   AGE
sample-configmap-multi-volume   1/1     Running   0          109m
  • 이번 예제에서는 컨피그맵 내용을 thread만으로 kubectl apply 했기 때문에 그 외의 파일(nginx.conf 등)이 삭제된 점에도 주의하자.

  • 단, 처음에 컨피그맵을 생성할 때 “kubectl apply” 나 “kubectl craete –save-config”를 사용하여 생성하지 않을 경우 매니페스트 병합처리가 불완전하여 결과가 달라진다.

# 컨피그맵 업데이트
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
  name: sample-configmap
data:
  thread: "32"
EOF
# 컨피그맵이 마운트되어 있는 디렉터리 확인
$ kubectl exec -it sample-configmap-multi-volume -- ls -al /config
total 12
drwxrwxrwx 3 root root 4096 Apr  8 13:38 .
drwxr-xr-x 1 root root 4096 Apr  8 11:47 ..
drwxr-xr-x 2 root root 4096 Apr  8 13:38 ..2023_04_08_13_38_03.285047011
lrwxrwxrwx 1 root root   31 Apr  8 13:38 ..data -> ..2023_04_08_13_38_03.285047011
lrwxrwxrwx 1 root root   13 Apr  8 11:47 thread -> ..data/thread


# 16에서 32로 변경된 내용 확인
$ kubectl exec -it sample-configmap-multi-volume -- cat /config/thread
32


# 동적 파일이 변경된 후의 결과 시간(AGE) 확인
$ kubectl get pod sample-configmap-multi-volume
NAME                            READY   STATUS    RESTARTS   AGE
sample-configmap-multi-volume   1/1     Running   0          113m


📜 시크릿이나 컨피그맵의 데이터 변경 거부

시크릿이나 컨피그맵의 “immutable” 설정을 변경하면 데이터가 변경되는 것을 방지하고 예상치 못한 시스템 변경도 방지할 수 있다.

  • 변경이 거부된 시크릿이나 컨피그맵의 데이터를 변경하는 경우에는 리소스를 삭제하고 나서 다시 생성해야 한다.

  • 또 볼륨으로 마운트하고 있는 경우는 파드 재생성도 필요하다.

  • 장점으로는 리소스 변경을 감시할 필요가 없어지므로 쿠버네티스의 시스템적 성능 문제를 해결할 수도 있다는 것을 들 수 있다.

# 변경할 수 없는 시크릿 생성
$ cat <<EOF > sample-secret-immutable.yaml
apiVersion: v1
kind: Secret
metadata:
  name: sample-secret-immutable
type: Opaque
data:
  username: cm9vdA==
  password: cm9vdHBhc3N3b3Jk
immutable: true
EOF


# username을 root에서 hoge로 변경 시도
$  kubectl patch secret sample-secret-immutable -p '{"data": {"username": "aG9nZQ=="}}'
The Secret "sample-secret-immutable" is invalid: data: Forbidden: field is immutable when `immutable` is set


KUBERNETES 카테고리 내 다른 글 보러가기

댓글 남기기