본문 바로가기
2023~/쿠버네티스 인 액션

Ch07 컨피그맵과 시크릿: 애플리케이션 설정

by 경아ㅏ 2024. 11. 21.


7.1 컨테이너화된 애플리케이션 설정

컨테이너 내 애플리케이션에 설정 사항을 전달하는 방법

* 컨테이너에 명령줄 인수 전달
* 각 컨테이너를 위한 환경 변수 설정
* 볼륨을 컨테이너에 마운트하여 설정


7.2 컨테이너에 명령줄 인자 전달

1) 도커 파일로 이미지를 띄울 때 인자 전달

fortuneloop.sh
: INTERNAL 변수 간격으로 /var/htdocs/index.html 에 fortune 문구를 저장

#!/bin/bash
trap "exit" SIGINT

INTERVAL=$1
echo Configured to generate new fortune every $INTERVAL seconds

mkdir -p /var/htdocs

while :
do
  echo $(date) Writing fortune to /var/htdocs/index.html
  /usr/games/fortune > /var/htdocs/index.html
  sleep $INTERVAL
done

 


Dockerfile
: fortune 명령어를 설치한 뒤 fortuneloop.sh 실행, 이 때 INTERVAL 인자를 10으로 전달

* 이제까지 CMD 는 인자가 아니라 명령어를 실행하는 역할인 줄 알았는데 아니라고 한다....!
- ENTRYPOINT ["node", "app.js" ]: EXEC 형식으로 명령 실행
- ENTRYPOINT node app.js: shell 형식으로 명령 실행
- CMD xx: 인자 전달

FROM ubuntu:latest

RUN apt-get update ; apt-get -y install fortune
ADD fortuneloop.sh /bin/fortuneloop.sh

ENTRYPOINT ["/bin/fortuneloop.sh"]
CMD ["10"]


docker run it -it fortune:args 15 와 같이 인자를 전달하면 재정의도 가능함


2) 쿠버네티스 파드 띄울 때 인자 전달

도커에서 ENTRYPOINT = 쿠버네티스 command
도커에서 CMD = 쿠버네티스 args

apiVersion: v1
kind: Pod
metadata:
  name: fortune2s
spec:
  containers:
  - image: luksa/fortune:args
    args: ["2"]
    name: html-generator
    volumeMounts:
    - name: html
      mountPath: /var/htdocs
  - image: nginx:alpine
    name: web-server
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html
      readOnly: true
    ports:
    - containerPort: 80
      protocol: TCP
  volumes:
  - name: html
    emptyDir: {}


fortune:args 이미지를 실행할 때 INTERVAL 인자를 2로 전달
(emptyDir 볼륨을 html-generator 컨테이너의 /var/htdocs, web-server 컨테이너의 /usr/share/nginx/html 위치로 마운트 하여 생성된 fortune html 을 공유)


7.3 컨테이너의 환경변수 설정

bash 파일에서 변수 정의를 제거하고 파드 yaml 정의 시 환경 변수 목록 추가

piVersion: v1
kind: Pod
metadata:
  name: fortune-env
spec:
  containers:
  - image: luksa/fortune:env
    env:
    - name: INTERVAL
      value: "30"
...


(env 에서 INTERVAL 값을 30으로 정의)

특정 변수 정의 값을 참조하여 다른 값을 정의하는 것도 가능

...
spec:
  containers:
  - image: luksa/fortune:env
    env:
    - name: FIRST_VAR
      value: "foo"
    - name: SECOND_VAR
      value: "$(FIRST_VAR)bar" // foobar
...



7.4 컨피그맵으로 설정 분리

configmap 리소스 생성하기

1) kubectl create configmap my-config1 --from-literal=keyname=value

apiVersion: v1
data:
  keyname: value
kind: ConfigMap
metadata:
  creationTimestamp: "2024-11-22T05:14:48Z"
  name: my-config1
  ...



2) kubectl create configmap my-config2 --from-file=foo.json

파일명(foo.json)을 key로 파일 내용을 value로 데이터 생성

apiVersion: v1
data:
  foo.json: "{\n\tfoo: bar\n\tbaz: 5\n}\n"
kind: ConfigMap
metadata:
  creationTimestamp: "2024-11-22T06:18:20Z"
  name: my-config2
...



3) kubectl create configmap my-config3 --from-file=bar=foobar.conf

직접 지정한 kyename 하위에 파일 내용을 value로 데이터 생성

apiVersion: v1
data:
  bar: |
    abc
kind: ConfigMap
metadata:
  creationTimestamp: "2024-11-22T06:25:46Z"
  name: my-config3
...

 


4) kubectl create configmap my-config4 --from-file=config-opts

폴더 안에 있는 파일들로 데이터 key, value 구성

apiVersion: v1
data:
  debug: |
    true
  foo.json: "{\n\tfoo: bar\n\tbaz: 5\n}\n"
  repeat: |
    10
kind: ConfigMap
metadata:
  creationTimestamp: "2024-11-22T06:48:27Z"
  name: my-config5
...



configmap 데이터를 컨테이너 내부에 환경변수로 전달하기

1) 한 개씩 환경 변수 설정

apiVersion: v1
kind: Pod
metadata:
  name: fortune-env-from-configmap
spec:
  containers:
  - image: luksa/fortune:env
    env:
    - name: INTERVAL
      valueFrom:
        configMapKeyRef:
          name: fortune-config
          key: sleep-interval
...


(컨테이너 내 환경변수 INTERVAL 값이 fortune-config 의 sleep-interval 값으로 셋팅)


2) configmap 내 여러 데이터를 한번에 환경 변수 등록

apiVersion: v1
kind: Pod
metadata:
  name: fortune-env-from-configmap
spec:
  containers:
  - image: luksa/fortune:env
    envFrom:
      - prefix: CONFIG_
        configMapRef:
          name: my-config4
...


(my-config 내 데이터에 prefix CONFIG_를 붙여 환경 변수 생성)


컨피그맵 항목을 명령줄 인자로 전달하기

apiVersion: v1
kind: Pod
metadata:
  name: fortune-env-from-configmap
spec:
  containers:
  - image: luksa/fortune:env
    env:
    - name: INTERVAL
      valueFrom:
        configMapKeyRef:
          name: fortune-config
          key: sleep-interval
    args: ["$(INTERVAL)"]
...



컨피그맵 볼륨을 사용해 컨피그맵 항목을 파일로 노출

1) 컨피그맵 생성

nginx 설정 관련 파일인 my-nginx-config.conf 파일을 포함한 컨피그맵 생성
(my-nginx-config.conf 파일은 압축 응답과 관련된 설정 사항 포함)


kubectl get configmap fortune-config -o yaml

apiVersion: v1
data:
  my-nginx-config.conf: |
    server {
        listen              80;
        server_name         www.kubia-example.com;

        gzip on;
        gzip_types text/plain application/xml;

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

    }
  sleep-interval: |
    25
kind: ConfigMap
metadata:



2) 파드 생성시 컨피그맵을 참조하는 볼륨 생성, 볼륨을 컨테이너에 마운트

apiVersion: v1
kind: Pod
metadata:
  name: fortune-configmap-volume
spec:
  containers:
...
  - image: nginx:alpine
    name: web-server
    volumeMounts:
    ...
    - name: config
      mountPath: /etc/nginx/conf.d
      readOnly: true
      ...
    ports:
      - containerPort: 80
        name: http
        protocol: TCP
  volumes:
...
  - name: config
    configMap:
      name: fortune-config


fortune-config 컨피그맵 설정 사항을 반영하는 볼륨 config 를 생성
web-server 컨테이너에서 /etc/nginx/conf.d 위치를 컨피그맵 볼륨으로 마운트

설정 사항이 잘 적용되었는지 확인해보면,

kubectl port-forward fortune-configmap-volume 8080:80 &

curl -H "Accept-Encoding: gzip" -I localhost:8080

HTTP/1.1 200 OK
Server: nginx/1.27.2
Date: Fri, 22 Nov 2024 08:48:37 GMT
Content-Type: text/html
Last-Modified: Fri, 22 Nov 2024 08:48:14 GMT
Connection: keep-alive
ETag: W/"6740454e-a2"
Content-Encoding: gzip // nginx 설정 사항이 반영되어 gzip 으로 응답이 오는 것 확인 가능

web-server 컨테이너에 들어가서 마운트 위치에 컨피그맵 설정 사항이 잘 저장되어있는지 확인하면,

kubectl exec fortune-configmap-volume -c web-server -- ls /etc/nginx/conf.d
my-nginx-config.conf
sleep-interval

my-nginx-config.conf 확인 가능



디렉터리 안에 다른 파일을 숨기지 않고 개별 컨피그맵 항목을 마운트

리눅스 시스템의 특정 디렉토리를 볼륨에 마운트하면 해당 디렉토리에 있던 원래의 파일들은 숨김 처리
이런 문제를 해결하기 위해서는 볼륨의 subPath를 특정 파일 위치로 마운트하기

 


애플리케이션을 재시작하지 않고 설정 업데이트

컨피그맵을 업데이트 하면 볼륨의 파일은 모두 업데이트가 되지만, 컨테이너 내에 반영되는지 여부는 해당 프로세스의 처리에 달려있음(자동적으로 해당 변경사항을 프로세스가 반영하지 않는다면 수동으로 반영해야 함)

e.g
nginx 설정 파일 my-nginx-config.conf 에서 gzip 설정을 off 로 변경하면,
(kubectl edit configmap fortune-config)

web-server 컨테이너에 접속해서 마운트된 설정 파일을 열어보았을 때 변경 사항 반영은 확인 가능
(kubectl exec fortune-configmap-volume -c web-server -- cat /etc/nginx/conf.d/my-nginx-config.conf)

server {
    listen              80;
    server_name         www.kubia-example.com;

    gzip off; //off는 반영됨
    gzip_types text/plain application/xml;

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

}


파일은 변경되었지만 port-forward 8080:80 실행한 뒤 curl 명령어로 접속해보면 gzip off 옵션은 반영이 안 되었다는 걸 알 수 있음

따라서 컨테이너 내부의 nginx 가 해당 파일의 변경사항을 반영할 수 있도록 수동으로 변경 사항 반영 필요
(kubectl exec fortune-configmap-volume -c web-server -- nginx -s reload)

curl -H "Accept-Encoding: gzip" -I localhost:8080
HTTP/1.1 200 OK
Server: nginx/1.27.2
Date: Sun, 24 Nov 2024 13:31:48 GMT
Content-Type: text/html
Content-Length: 48
Last-Modified: Sun, 24 Nov 2024 13:31:27 GMT
Connection: keep-alive
ETag: "67432aaf-30"
Accept-Ranges: bytes
(gzip off 확인)


단, 전체 볼륨 대신 단일 파일을 마운트 한 경우 파일 업데이트가 반영되지 않기 때문에 이러한 경우에는 다른 폴더를 만들어 마운트 하고 의도한 파일 경로와의 심볼릭 링크를 생성해야 함

애플리케이션이 실행되는 동안 설정사항을 변경하면, 해당 애플리케이션을 실행하는 파드 간 설정 사항이 구버전을 보고 있는지/신버전을 보고 있는지 차이가 날 수 있으므로 애플리케이션이 reload 를 지원하는지 잘 파악해야 함
(reload를 지원하더라도 시간 차이가 날 수 있다는 사실을 인지해야 함)


7.5 시크릿

컨피그맵과 비슷하나, 인증서/자격증명 등 보안이 필요한 시크릿 항목을 볼륨 파일로 노출
시크릿은 물리 디스크가 아닌 인메모리 형태로 저장(물리적 디스크에 저장되면 이를 삭제해야 보안이 이루어지므로)

시크릿 생성

개인키와 인증서를 생성하고 두 파일을 포함하는 시크릿 생성
시크릿을 확인해보면 Base64로 인코딩 되어있는 문자열 확인 가능

openssl genrsa -out https.key 2048
openssl req -new -x509 -key https.key -out https.cert -days 3650 -subj /CN=http://www.kubia-example.com


kubectl create secret generic fortune-https --from-file=https.key --from-file=https.cert --from-file=foo (시크릿 생성)

kubectl describe secret fortune-https


Name:         fortune-https
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
https.cert:  1127 bytes
https.key:   1679 bytes
foo:         4 bytes


파드에서 시크릿 사용

1) nginx(web-server) 컨테이너에서 사용하는 컨피그맵 수정(443 HTTPS)

kubectl describe configmap fortune-config


Name:         fortune-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
my-nginx-config.conf:
----
server {
    listen              80;
    listen              443 ssl;
    server_name         http://www.kubia-example.com;
    ssl_certificate     certs/https.cert;
    ssl_certificate_key certs/https.key;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;

    gzip off;
    gzip_types text/plain application/xml;

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

}
...

 

2) 파드 생성시 시크릿 관련 볼륨 생성 및 마운트

apiVersion: v1
kind: Pod
metadata:
  name: fortune-https
spec:
  containers:
  - image: luksa/fortune:env
    name: html-generator
    env:
    - name: INTERVAL
      valueFrom:
        configMapKeyRef:
          name: fortune-config
          key: sleep-interval
    volumeMounts:
    - name: html
      mountPath: /var/htdocs
  - image: nginx:alpine
    name: web-server
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html
      readOnly: true
    - name: config
      mountPath: /etc/nginx/conf.d
      readOnly: true
    - name: certs
      mountPath: /etc/nginx/certs/ # 시크릿 마운트
      readOnly: true
    ports:
    - containerPort: 80
    - containerPort: 443
  volumes:
  - name: html
    emptyDir: {}
  - name: config
    configMap:
      name: fortune-config
      items:
      - key: my-nginx-config.conf
        path: https.conf
  - name: certs # 시크릿 볼륨 생성
    secret:
      secretName: fortune-https



3) 443 HTTPS 연결 및 확인

kubectl port-forward fortune-https 8443:443 &
curl https://localhost:8443 -k -v
*   Trying 127.0.0.1:8443...
* Connected to localhost (127.0.0.1) port 8443 (#0)
* ALPN: offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
* (304) (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305
* ALPN: server accepted http/1.1
* Server certificate:
*  subject: CN=http://www.kubia-example.com
*  start date: Aug 16 18:43:13 2016 GMT
*  expire date: Aug 14 18:43:13 2026 GMT
 


도커 이미지 자격증명 시 시크릿 사용

도커 이미지를 pull 할 때 필요한 자격증명도 시크릿 설정을 통해 전달 가능