컨피그맵 (ConfigMap)과 시크릿 (Secret)

niyu·2022년 7월 29일
1

쿠버네티스 기초

목록 보기
9/15
post-thumbnail

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

# fortuneloop.sh
#!/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

INTERVAL 변수를 추가하고 첫 번째 명령줄 인자의 값으로 초기화한다.

# Dockerfile
FROM ubuntu:latest
RUN apt-get update ; apt-get -y install fortune
ADD fortuneloop.sh /bin/fortuneloop.sh
ENTRYPOINT ["/bin/fortuneloop.sh"]  # exec 형태의 ENTRYPOINT 명령
CMD ["10"]  # 실행할때 사용할 기본 인자

CMD 명령어를 사용해 기본 인터벌을 10초로 설정한다.

컨테이너의 사용자 정의 환경 변수 설정

어플리케이션은 설정 옵션을 제공하기 위해 환경 변수를 사용하는 경우가 많다. 파드의 각 컨테이너를 위한 환경변수 리스트를 지정할 수 있다.

컨테이너 각각의 환경 변수를 설정
컨테이너 각각의 환경 변수를 설정 (출처: github.com/sungsu9022/study-kubernetes-in-action/issues/7)

apiVersion: v1
kind: Pod
  containers:
  - image: luksa/fortune:env
    env:   # 환경변수 목록에 단일 변수 추가
    - name: INTERVAL
      value: "30"
    - name: FIRST_VAR
      value: "foo"
    - name: SECOND_VAR
      value: "${FIRST_VAR}bar"  # 다른 환경 변수 참조. foobar가 됨
    name: html-generator

컨테이너 정의에 환경 변수를 포함시킨 다음 스크립트에 이를 전달해 새 파드를 생성하고 실행할 수 있다. 파드 수준이 아닌 컨테이너 정의 내부에서 환경 변수를 설정한다.

이때 여러 환경에서 동일한 파드 정의를 재사용하려면 파드 디스크립터에서 설정을 분리하는 것이 좋다. 어플리케이션 설정의 주된 포인트는 환경 간의 다양한 부분이나 자주 변경되는 부분, 어플리케이션의 소스코드와 분리해야 하는 부분을 설정 옵션으로 유지하는 것이다. 이렇게 다른 설정으로 컨테이너를 실행해야 할 때 사용하는 것이 컨피그맵이다.

컨피그맵 (ConfigMap)

설정 데이터를 저장하는 k8s 리소스로, 컨테이너에서 필요한 환경설정 내용을 컨테이너와 분리해서 제공해주기 위한 기능이다.

k8s는 설정 옵션을 컨피그 맵이라는 별도의 객체로 분리할 수 있다. 이 객체는 간단한 문구부터 전체 설정 파일에 이르는 값을 갖는 키/값 쌍을 포함하는 맵이다.

파드는 환경 변수와 configMap 볼륨을 통해 ConfigMap을 사용
파드는 환경 변수와 configMap 볼륨을 통해 ConfigMap을 사용 (출처: github.com/sungsu9022/study-kubernetes-in-action/issues/7)

맵의 내용은 환경변수 또는 볼륨의 파일로 컨테이너에 전달된다.

서로 다른 환경에서 사용되는 동일한 이름을 가진 두 개의 다른 ConfigMap
서로 다른 환경에서 사용되는 동일한 이름을 가진 두 개의 다른 ConfigMap (출처: github.com/sungsu9022/study-kubernetes-in-action/issues/7)

어플리케이션이 컨피그맵을 사용하는 방식에 관계없이 이와 같은 분리된 독립 실행형 객체를 설정하면 동일한 이름의 컨피그맵에 대해 각각 다른 매니페스트(개발, 테스트, QA)의 유지가 가능해진다. 파드는 이름으로 컨피그맵을 참조하기 때문에 각 환경에서 서로 다른 설정을 사용할 수 있다.

컨피그맵 생성

apiVersion: v1
kind: ConfigMap
metadata:
  name: fortune-config
data:
  sleep-interval: "25"

sleep-interval=25를 갖는 fortune-config라는 컨피그맵이 생성된다.

컨피그맵 항목을 환경변수로 컨테이너에 전달

apiVersion: v1
kind: Pod
metadata:
  name: fortune-env-from-configmap
spec:
  containers:
  - image: luksa/fortune:env
    env:
    - name: INTERVAL  # INTERVAL 환경변수 설정
      valueFrom:
        configMapKeyRef:  # 컨피그맵 키에서 값을 가져와 초기화
          name: fortune-config  # 참조하는 컨피그맵 이름
          key: sleep-interval  # 컨피그맵에서 해당 키 아래에 저장된 값으로 변수 셋팅
    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: {} 

INTERVAL 환경 변수를 정의하고 fortune-config 컨피그맵의 sleep-interval 키에 저장된 값이 무엇이든 환경 변수에 그 값으로 설정된다.

환경변수로써 컨피그맵 항목을 컨테이너에 전달
환경변수로써 컨피그맵 항목을 컨테이너에 전달 (출처: github.com/sungsu9022/study-kubernetes-in-action/issues/7)

🔎 파드에 존재하지 않는 컨피그맵의 참조

파드를 생성할 때 참조했던 컨피그맵이 없으면, 컨피그맵을 참조하는 컨테이너는 시작되지 않지만 다른 컨테이너들은 정상적으로 시작된다. 누락된 컨피그맵을 생성하면 실패한 컨테이너는 파드를 다시 생성할 필요 없이 시작된다.

🔎 컨피그맵의 모든 항목을 한번에 환경변수로 전달

envFrom 속성을 사용해 환경 변수로 모든 것을 노출할 수 있다.

spec:
  containers:
  - image: some-image
    envForm:  # env 대신 envForm 사용
    - prefix: CONFIG_  # 모든 환경변수는 CONFIG_ prefix로 설정된다
        configMapRef:  # my-config-map 이름의 컨피그맵 참조
          name: my-config-map 
...

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

컨피그맵의 내용을 컨테이너의 환경변수로 주는 것뿐만 아니라 볼륨 형식으로 컨테이너에 붙여서 파일로 컨테이너에게 제공해줄 수 있다. 컨테이너에서 실행 중인 프로세스는 파일의 내용을 읽음으로써 항목의 값을 가져올 수 있다.

# 컨피그맵 내용
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:
   name: fortune-config
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
      ...
  volumes:
  ...
  - name: config
    configMap:  # 이 볼륨은 fortune-config 컨피그맵을 참조하는 볼륨
      name: fortune-config       

이 파드 정의에는 fortune-config 컨피그맵을 참조하는 볼륨이 포함돼 있다. Nginx가 사용할 수 있도록 /etc/nginx/conf.d 디렉토리에 볼륨을 마운트한다.

볼륨의 파일로 컨피그맵 엔트리 전달
볼륨의 파일로 컨피그맵 엔트리 전달 (출처: github.com/sungsu9022/study-kubernetes-in-action/issues/7)

🔎 어플리케이션 설정 업데이트

컨피그맵을 사용해 볼륨을 통해 노출시키면 파드를 다시 만들거나 컨테이너를 다시 시작하지 않고도 설정을 업데이트할 수 있다. 컨피그맵을 업데이트하면 참조하는 모든 볼륨의 파일이 업데이트된다. k8s는 컨피그맵이 업데이트되면 새 디렉토리를 만들고 모든 파일에 기록한 다음 심볼릭 링크를 새 디렉토리에 다시 연결해 모든 파일을 한 번에 변경한다.

시크릿 (Secret)

설정에는 보안 유지가 필요한 자격 증명 및 개인 암호화 키와 같은 중요한 정보가 포함될 수 있다. k8s는 중요한 정보를 저장하고 분류하기 위해 시크릿이라는 별도의 객체를 제공한다.

비밀번호, Oauth 토큰, SSH 키 같은 민감한 정보들을 저장하는 용도로 사용한다.

시크릿은 컨피그맵과 매우 비슷하며 키/값 쌍으로 사용할 수 있다. 컨피그맵과 차이점은 데이터가 base64로 저장된다는 것이다. 입력 내용을 설정하고 읽을 때 인코딩하고 디코딩해야 하기 때문에 YAML과 JSON 형태로 시크릿을 작성하는 것이 좀 더 어렵다.

기본 토큰 시크릿

모든 파드에는 자동으로 연결된 secret 볼륨이 있다. 기본적으로 default-token 시크릿은 모든 컨테이너에 마운트된다.

Volumes:
  default-token-cfee9:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-cfee9

시크릿에는 ca.crt, namespace, token 세 개의 항목이 있다.이 항목은 파드에서 k8s API 서버와 안전하게 통신하는 데 필요한 모든 것을 나타낸다.

default-token 시크릿이 자동으로 생성되고 해당 볼륨이 각 파드에 자동으로 마운트된다
default-token 시크릿이 자동으로 생성되고 해당 볼륨이 각 파드에 자동으로 마운트된다 (출처: github.com/sungsu9022/study-kubernetes-in-action/issues/7)

시크릿 생성

# 인증서와 개인키 생성
openssl genrsa -out https.key 2048
openssl req -new -x509 -key https.key -out https.cert -days 3650 -subj /CN=www.kubia-example.com

# secret 생성 
kubectl create secret generic fortune-https --from-file=https.key --from-file=https.cert --from-file=foo

fortune-https 이름을 가진 시크릿을 생성한다.

파드에서 시크릿 사용

볼륨으로 마운트해서 파일 형식으로 파드에 시크릿을 제공할 수 있다. 먼저 컨피그맵의 Nginx 설정에 https 인증서와 개인키를 추가해주고 시크릿을 파드에 마운트한다.

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  # nginx 서버가 인증서와 키를 /etc/nginx/certs에서 읽을수 있도록 해당 위치에 secret 마운트
      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

새로운 fortune-https 파드를 생성하고 인증서 및 키를 보유한 secret 볼륨을 웹 서버 컨테이너의 적절한 위치에 마운트한다.

파드를 운영하기 위한 컨피그맵과 시크릿의 결합
파드를 운영하기 위한 컨피그맵과 시크릿의 결합 (출처: github.com/sungsu9022/study-kubernetes-in-action/issues/7)

이미지 풀 시크릿

공용 이미지 레지스트리가 아닌 개인 레지스트리에 있는 컨테이너 이미지를 위한 파드를 배포할 때 k8s는 이미지를 가져오는 데 필요한 자격 증명을 알아야 한다. 이때 사용자 정보를 시크릿으로 저장해두고 사용할 수 있다.

# 도커 레지스트리용 시크릿 생성
$ kubectl create secret docker-registry mydockerhubsecret --docker-username=myusername --docker-password=mypassword --docker-email=my.email@providercom

도커 레지스트리 인증을 위한 시크릿을 생성한다. mydockerhubsecret이라는 docker-registry 시크릿을 작성하고 도커 허브 사용자 이름, 비밀번호, 이메일을 지정한다.

apiVersion: v1
kind: Pod
metadata:
  name: private-pod
spec:
  imagePullSecrets:  # 프라이빗 이미지 레지스트리에서 이미지를 가져올 수 있도록 설정
  - name: mydockerhubsecret
  containers:
  - image: username/private:tag
    name: main

파드 스펙에 시크릿의 이름을 지정한다.


References

0개의 댓글