-
[Kubernetes] 구성 - ConfigMaps, secrets공부/데이터 2025. 2. 1. 23:42
ConfigMaps
ConfigMap은 key-value 쌍으로 데이터를 저장하는 데 사용되는 API 객체입니다. 파드는 ConfigMap을 환경 변수, 명령줄 인자 또는 볼륨의 구성 파일 형태로 사용할 수 있습니다.
ConfigMap을 사용하면 컨테이너 이미지에서 환경별 설정을 분리할 수 있으므로 애플리케이션을 쉽게 이식할 수 있습니다.
예를 들어, 개인 컴퓨터(개발용)와 클라우드(실제 트래픽 처리용)에서 실행할 수 있는 애플리케이션을 개발한다고 합니다.
DATABASE_HOST
라는 환경 변수를 찾도록 코드를 작성합니다. 로컬에서는 해당 변수를localhost
로 설정하고 클라우드에서는 데이터베이스 구성 요소를 클러스터에 노출하는 Kubernetes Service를 참조하도록 설정합니다. 이렇게 하면 클라우드에서 실행되는 컨테이너 이미지를 가져와 필요한 경우 로컬에서 정확히 동일한 코드를 디버깅할 수 있습니다.ConfigMap은 다른 객체가 사용할 설정을 저장할 수 있도록 하는 API 객체입니다. 대부분의 Kubernetes 객체에는
spec
이 있지만 ConfigMap에는data
와binaryData
필드가 있습니다. 이 필드들은 key-value 쌍을 값으로 허용합니다.data
필드와binaryData
필드는 모두 선택 사항입니다.data
필드는 UTF-8 문자열을 포함하도록 설계되었고,binaryData
필드는 base64로 인코딩된 바이너리 데이터를 포함하도록 설계되었습니다.data
또는binaryData
필드의 각 키는 영숫자,-
,_
또는.
로 구성되어야 합니다.data
에 저장된 키는binaryData
필드의 키와 겹치지 않아야 합니다.v1.19부터는 ConfigMap 정의에
immutable
필드를 추가하여 변경 불가능한 ConfigMap을 만들 수 있습니다.apiVersion: v1 kind: ConfigMap metadata: name: game-demo data: # property-like keys; each key maps to a simple value player_initial_lives: "3" ui_properties_file_name: "user-interface.properties" # file-like keys game.properties: | enemy.types=aliens,monsters player.maximum-lives=5 user-interface.properties: | color.good=purple color.bad=yellow allow.textmode=true
ConfigMap을 사용하여 파드 내의 컨테이너를 구성하는 네 가지 방법이 있습니다.
- 컨테이너 명령 및 인자 내부
- 컨테이너의 환경 변수
- 애플리케이션이 읽을 수 있도록 읽기 전용 볼륨에 파일 추가
- Kubernetes API를 사용하여 ConfigMap을 읽는 파드 내에서 실행되는 코드 작성
이러한 다양한 방법은 사용되는 데이터 모델링에 적합합니다. 처음 세 가지 방법의 경우,
kubelet
은 파드에 대한 컨테이너를 시작할 때 ConfigMap의 데이터를 사용합니다.네 번째 방법은 ConfigMap과 해당 데이터를 읽는 코드를 작성해야 함을 의미합니다. 그러나 Kubernetes API를 직접 사용하므로 ConfigMap이 변경될 때마다 업데이트를 구독하고 이에 대응할 수 있습니다. Kubernetes API에 직접 접근함으로써 이 기술을 사용하면 다른 네임스페이스의 ConfigMap에도 접근할 수 있습니다.
아래는 파드에서 game-demo를 사용하는 예시입니다.
apiVersion: v1 kind: Pod metadata: name: configmap-demo-pod spec: containers: - name: demo image: alpine command: ["sleep", "3600"] env: # Define the environment variable - name: PLAYER_INITIAL_LIVES # Notice that the case is different here # from the key name in the ConfigMap. valueFrom: configMapKeyRef: name: game-demo # The ConfigMap this value comes from. key: player_initial_lives # The key to fetch. - name: UI_PROPERTIES_FILE_NAME valueFrom: configMapKeyRef: name: game-demo key: ui_properties_file_name volumeMounts: - name: config mountPath: "/config" readOnly: true volumes: # You set volumes at the Pod level, then mount them into containers inside that Pod - name: config configMap: # Provide the name of the ConfigMap you want to mount. name: game-demo # An array of keys from the ConfigMap to create as files items: - key: "game.properties" path: "game.properties" - key: "user-interface.properties" path: "user-interface.properties"
ConfigMap은 단일 행 속성 값과 여러 행으로 된 파일과 유사한 값을 구분하지 않습니다. 중요한 것은 파드 및 기타 객체가 이러한 값을 어떻게 사용하는지입니다.
이 예제에서
demo
컨테이너 내부에/config
로 볼륨을 정의하고 마운트하면 ConfigMap에 4개의 키가 있음에도 불구하고/config/game.properties
와/config/user-interface.properties
두 개의 파일이 생성됩니다. 이는 파드 정의가volumes
섹션에items
배열을 지정하기 때문입니다.items
배열을 완전히 생략하면 ConfigMap의 모든 키는 키와 동일한 이름을 가진 파일이 되고 4개의 파일을 얻게 됩니다.사용 예시
파드의 파일로 사용
파드 내의 볼륨에서 ConfigMap을 사용하려면 다음 단계를 따르면 됩니다.
- ConfigMap을 만들거나 기존 ConfigMap을 사용합니다. 여러 파드가 동일한 ConfigMap을 참조할 수 있습니다.
- 파드 정의를 수정하여
spec.volumes[]
아래에 볼륨을 추가합니다. 볼륨 이름을 원하는 대로 지정하고spec.volumes[].configMap.name
필드를 설정하여 ConfigMap 객체를 참조하도록 합니다. - ConfigMap이 필요한 각 컨테이너에
spec.containers[].volumeMounts[]
를 추가합니다.spec.containers[].volumeMounts[].readOnly = true
와spec.containers[].volumeMounts[].mountPath
를 ConfigMap이 나타나도록 하려는 사용하지 않는 디렉터리 이름으로 지정합니다. - 이미지 또는 명령줄을 수정하여 프로그램이 해당 디렉터리의 파일을 찾도록 합니다. ConfigMap
data
맵의 각 키는mountPath
아래의 파일 이름이 됩니다.
다음은 볼륨에 ConfigMap을 마운트하는 파드의 예입니다.
apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mypod image: redis volumeMounts: - name: foo mountPath: "/etc/foo" readOnly: true volumes: - name: foo configMap: name: myconfigmap
사용하려는 각 ConfigMap은
spec.volumes
에서 참조해야 합니다.파드에 여러 컨테이너가 있는 경우 각 컨테이너에는 자체
volumeMounts
블록이 필요하지만 ConfigMap당 하나의spec.volumes
만 필요합니다.마운트된 ConfigMap은 자동으로 업데이트됨
볼륨에서 현재 사용 중인 ConfigMap이 업데이트되면 프로젝션된 키도 결국 업데이트됩니다. kubelet은 주기적인 동기화마다 마운트된 ConfigMap이 최신인지 확인합니다. 그러나 kubelet은 ConfigMap의 현재 값을 가져오기 위해 로컬 캐시를 사용합니다. 캐시 유형은
KubeletConfiguration
구조체의configMapAndSecretChangeDetectionStrategy
필드를 사용하여 구성할 수 있습니다. ConfigMap은 watch(기본값), ttl 기반 또는 모든 요청을 API 서버로 직접 리디렉션하는 방식으로 전파될 수 있습니다. 결과적으로 ConfigMap이 업데이트된 시점부터 새 키가 Pod에 프로젝션되는 시점까지의 총 지연 시간은 kubelet 동기화 주기 + 캐시 전파 지연 시간만큼 길어질 수 있으며, 캐시 전파 지연 시간은 선택한 캐시 유형에 따라 달라집니다(watch 전파 지연 시간, 캐시 ttl 또는 0에 해당).정리하자면 다음과 같은 순서로 진행됩니다.
- ConfigMap의 내용이 변경되면 Kubernetes API 서버에 변경 사항이 저장됩니다.
- 각 노드의 kubelet은 주기적으로 마운트된 ConfigMap이 최신 상태인지 확인합니다.
- kubelet은 ConfigMap의 변경 사항을 감지하면 로컬 캐시를 업데이트하고 파드 내부의 볼륨에 마운트된 ConfigMap 파일을 업데이트합니다.
- 컨테이너 반응
- 애플리케이션 내 설정: 컨테이너 내에서 실행되는 애플리케이션은 ConfigMap 파일의 변경 사항을 감지하고, 이에 따라 설정을 다시 로드하거나 업데이트합니다. 애플리케이션이 이러한 기능을 지원하도록 개발되었다면 컨테이너 재실행 없이도 변경 사항을 즉시 반영할 수 있습니다.
- 컨테이너 재실행: 만약 애플리케이션이 ConfigMap 변경에 자동으로 대응하지 못하도록 개발되었거나 특정 이유로 인해 컨테이너 재실행이 필요한 경우, kubelet은 해당 컨테이너를 재실행하여 변경 사항을 적용합니다. 이 경우에도 전체 파드가 재실행되는 것이 아니라 영향을 받는 컨테이너만 재실행됩니다.
환경 변수로 사용되는 ConfigMap은 자동으로 업데이트되지 않으며 파드를 재시작해야 하고 subPath 볼륨 마운트를 사용하는 컨테이너 또한 ConfigMap 업데이트를 받지 못합니다.
환경변수로 사용
파드의 환경 변수에서 ConfigMap을 사용하려면 다음 단계를 따르면 됩니다.
- 파드 사양의 컨테이너에서 사용하려는 ConfigMap 키에 대한 환경 변수를
env[].valueFrom.configMapKeyRef
필드에 추가합니다. - 이미지 나 명령줄을 수정하여 프로그램이 지정된 환경 변수의 값을 찾도록 합니다.
다음은 ConfigMap을 Pod 환경 변수로 정의하는 예입니다.
다음 ConfigMap(
myconfigmap.yaml
)은username
과access_level
두 가지 속성을 저장합니다.apiVersion: v1 kind: ConfigMap metadata: name: myconfigmap data: username: k8s-admin access_level: "1"
다음 파드는 위 컨피그맵의 콘텐츠를 환경 변수로 사용합니다.
apiVersion: v1 kind: Pod metadata: name: env-configmap spec: containers: - name: app command: ["/bin/sh", "-c", "printenv"] image: busybox:latest envFrom: - configMapRef: name: myconfigmap
envFrom
필드는 Kubernetes에게 해당 필드 내에 중첩된 소스에서 환경 변수를 생성하도록 지시합니다. 내부의configMapRef
는 ConfigMap을 이름으로 참조하고 모든 키-값 쌍을 선택합니다. 파드를 클러스터에 추가한 다음 로그를 검색하여printenv
명령의 출력을 확인합니다. 이렇게 하면 ConfigMap의 두 키-값 쌍이 환경 변수로 설정되었는지 확인할 수 있습니다.$ kubectl logs pod/ env-configmap ... username: "k8s-admin" access_level: "1" ...
예를 들어, ConfigMap의
username
값만 사용하는 다른 파드가 있을 때, ConfigMap의 개별 키를 선택할 수 있는env.valueFrom
구문을 대신 사용할 수 있습니다. 환경 변수의 이름은 ConfigMap 내의 키와 다를 수도 있습니다.apiVersion: v1 kind: Pod metadata: name: env-configmap spec: containers: - name: envars-test-container image: nginx env: - name: CONFIGMAP_USERNAME valueFrom: configMapKeyRef: name: myconfigmap key: username
이 매니페스트에서 생성된 파드에서 환경 변수
CONFIGMAP_USERNAME
가 ConfigMap의username
값으로 설정된 것을 확인할 수 있습니다. ConfigMap 데이터의 다른 키는 환경 변수에 복사되지 않습니다.파드의 환경 변수 이름에 허용되는 문자 범위는 제한적입니다. 키가 규칙을 충족하지 않으면 해당 키는 컨테이너에서 사용할 수 없지만 파드는 시작할 수 있습니다.
변경 불가능한 ConfigMap
apiVersion: v1 kind: ConfigMap metadata: ... data: ... immutable: true
ConfigMap이 변경 불가능으로 표시되면 이 변경 사항을 되돌리거나
data
또는binaryData
필드의 내용을 변경할 수 없습니다. ConfigMap을 삭제하고 다시 생성하는 방법밖에 없습니다. 기존 파드는 삭제된 ConfigMap에 마운트 지점을 유지하므로 이러한 파드를 다시 생성하는 것이 좋습니다.Secrets
Secret은 비밀번호, 토큰 또는 키와 같은 소량의 민감한 데이터를 포함하는 객체입니다. 이러한 정보는 그렇지 않으면 파드 사양이나 컨테이너 이미지에 포함될 수 있습니다. Secret을 사용하면 애플리케이션 코드에 기밀 데이터를 포함할 필요가 없습니다.
Secret은 이를 사용하는 파드와 독립적으로 생성할 수 있으므로 파드를 생성, 보고 편집하는 워크플로우 중에 Secret(및 해당 데이터)이 노출될 위험이 적습니다. Kubernetes와 클러스터에서 실행되는 애플리케이션은 민감한 데이터를 비휘발성 스토리지에 쓰지 않는 것과 같은 추가적인 예방 조치를 Secret에 대해 취할 수도 있습니다.
Secret은 ConfigMap과 유사하지만 특히 암호화 데이터를 저장하기 위한 것입니다.
.으로 시작하는 키를 정의하여 데이터를 숨길 수 있습니다. 이 키는 dotfile 또는 숨겨진 파일을 나타냅니다. 예를 들어, 다음 Secret이
secret-volume
이라는 볼륨에 마운트되면 볼륨에는.secret-file
이라는 단일 파일이 포함되고dotfile-test-container
는/etc/secret-volume/.secret-file
경로에 이 파일을 갖게 됩니다.apiVersion: v1 kind: Secret metadata: name: dotfile-secret data: .secret-file: dmFsdWUtMg0KDQo= --- apiVersion: v1 kind: Pod metadata: name: secret-dotfiles-pod spec: volumes: - name: secret-volume secret: secretName: dotfile-secret containers: - name: dotfile-test-container image: registry.k8s.io/busybox command: - ls - "-l" - "/etc/secret-volume" volumeMounts: - name: secret-volume readOnly: true mountPath: "/etc/secret-volume"
Secret 유형
Secret을 생성할 때 Secret 리소스의
type
필드 또는 (사용 가능한 경우) 특정kubectl
명령줄 플래그를 사용하여 Secret의 유형을 지정할 수 있습니다. Secret 유형은 Secret 데이터의 프로그래밍 방식 처리를 용이하게 하는 데 사용됩니다.Kubernetes는 몇 가지 일반적인 사용 시나리오를 위해 여러 가지 기본 제공 유형을 제공합니다. 이러한 유형은 수행되는 유효성 검사 및 Kubernetes가 적용하는 제약 조건 측면에서 다릅니다.
type Usage Opaque
임의의 사용자 정의 데이터 kubernetes.io/service-account-token
서비스 계정 토큰 kubernetes.io/dockercfg
직렬화된 ~/.dockercfg
파일kubernetes.io/dockerconfigjson
직렬화된 ~/.docker/config.json
파일kubernetes.io/basic-auth
기본 인증을 위한 자격 증명 kubernetes.io/ssh-auth
SSH 인증을 위한 자격 증명 kubernetes.io/tls
TLS 클라이언트 또는 서버에 대한 데이터 bootstrap.kubernetes.io/token
부트스트랩 토큰 데이터 Secret 객체의
type
값으로 비어 있지 않은 문자열을 할당하여 사용자 정의 Secret 유형을 정의하고 사용할 수 있습니다 (빈 문자열은Opaque
유형으로 처리됩니다).Kubernetes는 유형 이름에 어떠한 제약도 적용하지 않습니다. 그러나 기본 제공 유형 중 하나를 사용하는 경우 해당 유형에 대해 정의된 모든 요구 사항을 충족해야 합니다.
공용으로 사용할 Secret 유형을 정의하는 경우 규칙을 따르고 도메인 이름 뒤에
/
로 구분된 이름을 포함하도록 Secret 유형을 구성합니다. 예를 들어cloud-hosting.example.net/cloud-api-credentials
와 같이 지정할 수 있습니다.Opaque
명시적으로 Secret 매니페스트에 유형을 지정하지 않으면
Opaque
가 기본 Secret 유형입니다. 사용자 정의이므로 annotation을 필수로 작성하지 않아도 됩니다.ServiceAccount token Secrets
kubernetes.io/service-account-token
유형의 Secret은 ServiceAccount를 식별하는 토큰 자격 증명을 저장하는 데 사용됩니다.Kubernetes v1.22 이상에서는 TokenRequest API를 사용하여 수명이 짧고 자동으로 로테이션되는 ServiceAccount 토큰을 얻는 것이 권장되는 방법입니다. 이러한 수명이 짧은 토큰은 다음 방법을 사용하여 얻을 수 있습니다.
- TokenRequest API를 직접 호출하거나
kubectl
과 같은 API 클라이언트를 사용하여 호출합니다. 예를 들어kubectl create token
명령을 사용할 수 있습니다. - 파드 매니페스트의 프로젝션된 볼륨에서 마운트된 토큰을 요청합니다. Kubernetes는 토큰을 생성하여 파드에 마운트합니다. 토큰은 마운트된 파드가 삭제되면 자동으로 무효화됩니다.
이 Secret 유형을 사용할 때
kubernetes.io/service-account.name
어노테이션이 기존 ServiceAccount 이름으로 설정되었는지 확인해야 합니다. ServiceAccount와 Secret 객체를 모두 생성하는 경우 ServiceAccount 객체를 먼저 생성해야 합니다.Secret이 생성된 후 Kubernetes 컨트롤러는
kubernetes.io/service-account.uid
어노테이션과data
필드의token
키와 같은 다른 필드를 채웁니다. 이 키는 인증 토큰으로 채워집니다.다음은 ServiceAccount 토큰 Secret을 선언하는 구성 예시입니다.
apiVersion: v1 kind: Secret metadata: name: secret-sa-sample annotations: kubernetes.io/service-account.name: "sa-name" type: kubernetes.io/service-account-token data: extra: YmFyCg==
Secret을 생성한 후 Kubernetes가
data
필드의token
키를 채울 때까지 기다리면 됩니다.Docker config Secrets
컨테이너 이미지 레지스트리에 접근하기 위한 자격 증명을 저장하는 Secret을 생성하는 경우, 해당 Secret에 대해 다음
type
값 중 하나를 사용해야 합니다.kubernetes.io/dockercfg
: Docker 명령줄 구성을 위한 레거시 형식인 직렬화된~/.dockercfg
를 저장합니다. Secretdata
필드에는 base64로 인코딩된~/.dockercfg
파일의 내용인.dockercfg
키가 포함되어 있습니다.kubernetes.io/dockerconfigjson
:~/.dockercfg
의 새로운 형식인~/.docker/config.json
파일과 동일한 형식 규칙을 따르는 직렬화된 JSON을 저장합니다. Secretdata
필드에는 base64로 인코딩된~/.docker/config.json
파일의 내용인.dockerconfigjson
키가 포함되어야 합니다.
아래는 kubernetes.io/dockercfg의 예시입니다.
apiVersion: v1 kind: Secret metadata: name: secret-dockercfg type: kubernetes.io/dockercfg data: .dockercfg: | eyJhdXRocyI6eyJodHRwczovL2V4YW1wbGUvdjEvIjp7ImF1dGgiOiJvcGVuc2VzYW1lIn19fQo=
매니페스트를 사용하여 Docker 구성 Secret을 생성할 때 API 서버는
data
필드에 키가 있는지 확인하고 제공된 값이 유효한 JSON으로 파싱될 수 있는지 확인합니다. API 서버는 JSON이 실제로 Docker 구성 파일인지 여부는 검증하지 않습니다.Docker 구성 파일이 없는 경우와 같이 컨테이너 레지스트리에 접근하기 위한 Secret을 생성하는 데
kubectl
을 사용할 수도 있습니다.$ kubectl create secret docker-registry secret-tiger-docker \ --docker-email=tiger@acme.example \ --docker-username=tiger \ --docker-password=pass1234 \ --docker-server=my-registry.example:5000
이 명령은
kubernetes.io/dockerconfigjson
유형의 Secret을 생성합니다.새로운 Secret에서
.data.dockerconfigjson
필드를 검색하고 데이터를 디코딩합니다.$ kubectl get secret secret-tiger-docker -o jsonpath='{.data.*}' | base64 -d
출력은 다음 JSON 문서(유효한 Docker 구성 파일이기도 함)와 동일합니다.
{ "auths": { "my-registry.example:5000": { "username": "tiger", "password": "pass1234", "email": "tiger@acme.example", "auth": "dGlnZXI6cGFzczEyMzQ=" } } }
Basic authentication
kubernetes.io/basic-auth
유형은 기본 인증에 필요한 자격 증명을 저장하는 데 제공됩니다. 이 Secret 유형을 사용할 때 Secret의data
필드에는 다음 두 키 중 하나가 포함되어야 합니다.username
: 인증에 사용되는 사용자 이름password
: 인증에 사용되는 비밀번호 또는 토큰
위 두 키의 값은 모두 base64로 인코딩된 문자열입니다. Secret 매니페스트에서
stringData
필드를 사용하여 일반 텍스트 콘텐츠를 대신 제공할 수도 있지만 서버 사이드에선 적합하지 않습니다.다음 매니페스트는 기본 인증 Secret의 예입니다.
apiVersion: v1 kind: Secret metadata: name: secret-basic-auth type: kubernetes.io/basic-auth stringData: username: admin # required field for kubernetes.io/basic-auth password: t0p-Secret # required field for kubernetes.io/basic-auth
SSH authentication
기본 제공 유형인
kubernetes.io/ssh-auth
는 SSH 인증에 사용되는 데이터를 저장하는 데 제공됩니다. 이 Secret 유형을 사용할 때data
(또는stringData
) 필드에 사용할 SSH 자격 증명으로ssh-privatekey
키-값 쌍을 지정해야 합니다.다음 매니페스트는 SSH 공개/개인 키 인증에 사용되는 Secret의 예입니다.
apiVersion: v1 kind: Secret metadata: name: secret-ssh-auth type: kubernetes.io/ssh-auth data: # the data is abbreviated in this example ssh-privatekey: | UG91cmluZzYlRW1vdGljb24lU2N1YmE=
TLS
kubernetes.io/tls
Secret 유형은 일반적으로 TLS에 사용되는 인증서와 연결된 키를 저장하는 데 사용됩니다.TLS Secret의 일반적인 용도 중 하나는 Ingress에 대한 전송 중 암호화를 구성하는 것이지만 다른 리소스와 함께 사용하거나 워크로드에서 직접 사용할 수도 있습니다. 이 유형의 Secret을 사용할 때
tls.key
와tls.crt
키는 Secret 구성의data
(또는stringData
) 필드에 제공되어야 하지만, API 서버는 각 키의 값을 실제로 검증하지 않습니다.stringData
를 사용하는 대신data
필드를 사용하여 base64로 인코딩된 인증서와 개인 키를 제공할 수 있습니다.다음 YAML은 TLS Secret에 대한 구성 예시를 포함합니다.
apiVersion: v1 kind: Secret metadata: name: secret-tls type: kubernetes.io/tls data: # values are base64 encoded, which obscures them but does NOT provide # any useful level of confidentiality tls.crt: | LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNVakNDQWJzQ0FnMytNQTBHQ1NxR1NJYjNE UUVCQlFVQU1JR2JNUXN3Q1FZRFZRUUdFd0pLVURFT01Bd0cKQTFVRUNCTUZWRzlyZVc4eEVEQU9C Z05WQkFjVEIwTm9kVzh0YTNVeEVUQVBCZ05WQkFvVENFWnlZVzVyTkVSRQpNUmd3RmdZRFZRUUxF dzlYWldKRFpYSjBJRk4xY0hCdmNuUXhHREFXQmdOVkJBTVREMFp5WVc1ck5FUkVJRmRsCllpQkRR VEVqTUNFR0NTcUdTSWIzRFFFSkFSWVVjM1Z3Y0c5eWRFQm1jbUZ1YXpSa1pDNWpiMjB3SGhjTk1U TXcKTVRFeE1EUTFNVE01V2hjTk1UZ3dNVEV3TURRMU1UTTVXakJMTVFzd0NRWURWUVFHREFKS1VE RVBNQTBHQTFVRQpDQXdHWEZSdmEzbHZNUkV3RHdZRFZRUUtEQWhHY21GdWF6UkVSREVZTUJZR0Ex VUVBd3dQZDNkM0xtVjRZVzF3CmJHVXVZMjl0TUlHYU1BMEdDU3FHU0liM0RRRUJBUVVBQTRHSUFE Q0JoQUo5WThFaUhmeHhNL25PbjJTbkkxWHgKRHdPdEJEVDFKRjBReTliMVlKanV2YjdjaTEwZjVN Vm1UQllqMUZTVWZNOU1vejJDVVFZdW4yRFljV29IcFA4ZQpqSG1BUFVrNVd5cDJRN1ArMjh1bklI QkphVGZlQ09PekZSUFY2MEdTWWUzNmFScG04L3dVVm16eGFLOGtCOWVaCmhPN3F1TjdtSWQxL2pW cTNKODhDQXdFQUFUQU5CZ2txaGtpRzl3MEJBUVVGQUFPQmdRQU1meTQzeE15OHh3QTUKVjF2T2NS OEtyNWNaSXdtbFhCUU8xeFEzazlxSGtyNFlUY1JxTVQ5WjVKTm1rWHYxK2VSaGcwTi9WMW5NUTRZ RgpnWXcxbnlESnBnOTduZUV4VzQyeXVlMFlHSDYyV1hYUUhyOVNVREgrRlowVnQvRGZsdklVTWRj UUFEZjM4aU9zCjlQbG1kb3YrcE0vNCs5a1h5aDhSUEkzZXZ6OS9NQT09Ci0tLS0tRU5EIENFUlRJ RklDQVRFLS0tLS0K # In this example, the key data is not a real PEM-encoded private key tls.key: | RXhhbXBsZSBkYXRhIGZvciB0aGUgVExTIGNydCBmaWVsZA==
kubectl
을 사용하여 TLS Secret을 생성하려면tls
하위 명령을 사용하면 됩니다.kubectl create secret tls my-tls-secret \ --cert=path/to/cert/file \ --key=path/to/key/file
공개/개인 키 쌍은 미리 존재해야 합니다.
--cert
에 대한 공개 키 인증서는 .PEM으로 인코딩되어야 하며--key
에 제공된 개인 키와 일치해야 합니다.사용 예시
선택적 사용
파드에서 Secret을 참조할 때 다음 예와 같이 Secret을 선택적(optional)으로 표시할 수 있습니다. 선택적 Secret이 존재하지 않으면 Kubernetes는 이를 무시합니다.
apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mypod image: redis volumeMounts: - name: foo mountPath: "/etc/foo" readOnly: true volumes: - name: foo secret: secretName: mysecret optional: true
기본적으로 Secret은 필수입니다. 모든 필수 Secret을 사용할 수 있을 때까지 파드의 어떤 컨테이너도 시작되지 않습니다.
파드가 필수 Secret의 특정 키를 참조하고 해당 Secret은 존재하지만 명명된 키가 누락된 경우 파드는 시작 중에 실패합니다.
파드의 파일로 사용
apiVersion: v1 kind: Pod metadata: name: secret-test-pod spec: containers: - name: test-container image: nginx volumeMounts: # name must match the volume name below - name: secret-volume mountPath: /etc/secret-volume readOnly: true # The secret data is exposed to Containers in the Pod through a Volume. volumes: - name: secret-volume secret: secretName: test-secret
ConfigMap과 동일하게 파일로 마운트된 Secret은 자동으로 업데이트되며 subPath 볼륨 마운트를 사용하는 컨테이너는 업데이트를 받지 못합니다.
환경변수로 사용
apiVersion: v1 kind: Pod metadata: name: env-single-secret spec: containers: - name: envars-test-container image: nginx env: - name: SECRET_USERNAME valueFrom: secretKeyRef: name: backend-user key: backend-username
변경 불가능한 Secret
apiVersion: v1 kind: Secret metadata: ... data: ... immutable: true
Secret이 변경 불가능으로 표시되면 이 변경 사항을 되돌리거나
data
또는binaryData
필드의 내용을 변경할 수 없습니다. Secret을 삭제하고 다시 생성하는 방법밖에 없습니다. 기존 파드는 삭제된 Secret에 마운트 지점을 유지하므로 이러한 파드를 다시 생성하는 것이 좋습니다.Secret 정보 보안
ConfigMap과 Secret은 유사하게 작동하지만 Kubernetes는 Secret 객체에 몇 가지 추가적인 보호 장치를 적용합니다.
Secret은 종종 중요도 스펙트럼에 걸쳐 있는 값을 보유하며 그 중 많은 값은 Kubernetes 내부(예: 서비스 계정 토큰) 및 외부 시스템으로의 권한 상승을 유발할 수 있습니다. 개별 앱이 상호 작용할 것으로 예상되는 Secret의 권한에 대해 추론할 수 있더라도 동일한 네임스페이스 내의 다른 앱은 이러한 가정을 무효화할 수 있습니다.
Secret은 해당 노드의 파드가 필요로 하는 경우에만 노드로 전송됩니다. Secret을 파드에 마운트하기 위해 kubelet은 데이터를
tmpfs
에 복사하여 저장하므로 기밀 데이터가 영구 저장소에 기록되지 않습니다. Secret에 의존하는 파드가 삭제되면 kubelet은 Secret의 로컬 복사본인 기밀 데이터를 삭제합니다.파드에는 여러 개의 컨테이너가 있을 수 있습니다. 기본적으로 정의하는 컨테이너는 기본 ServiceAccount와 관련 Secret에만 접근할 수 있습니다. 다른 Secret에 대한 접근 권한을 제공하려면 환경 변수를 명시적으로 정의하거나 볼륨을 컨테이너에 매핑해야 합니다.
동일한 노드에 여러 파드에 대한 Secret이 있을 수 있습니다. 그러나 파드가 요청한 Secret만 해당 컨테이너 내에서 잠재적으로 볼 수 있습니다. 따라서 한 파드는 다른 파드의 Secret에 접근할 수 없습니다.
궁금증
쿠버네티스가 ConfigMap, Secret의 변경을 감지하고 컨테이너가 자동 반영되도록 한다는데 github의 stakater/Reloader와 어떤 차이인지?
https://github.com/stakater/Reloader
Reloader의 주요 기능은 다음과 같습니다.
- 자동 롤링 업데이트: ConfigMap 또는 Secret이 변경되면 연결된 Deployment, StatefulSet, DaemonSet 등의 워크로드를 자동으로 롤링 업데이트하여 변경 사항을 반영합니다. Kubernetes의 기본 기능만으로는 수동으로 롤링 업데이트를 수행해야 하지만 Reloader를 사용하면 이러한 과정을 자동화할 수 있습니다.
- 특정 리소스 감지: 특정 ConfigMap 또는 Secret의 변경만 감지하여 롤링 업데이트를 트리거하도록 설정할 수 있습니다. 이를 통해 불필요한 업데이트를 방지하고, 보다 세밀한 제어가 가능합니다.
- 어노테이션 기반 설정: 워크로드에 어노테이션을 추가하는 간단한 방식으로 Reloader를 설정할 수 있습니다. 별도의 설정 파일이나 복잡한 구성 없이도 쉽게 사용할 수 있습니다.
기능 Kubernetes 기본 기능 Reloader 롤링 업데이트 수동으로 수행 자동으로 수행 특정 리소스 감지 불가능 가능 설정 방식 복잡한 구성 필요 어노테이션 기반으로 간편하게 설정 사용 예시
apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: replicas: 3 selector: matchLabels: app: my-app template: metadata: labels: app: my-app annotations: reloader.stakater.com/reload: "true" # Reloader 활성화 configmap.reloader.stakater.com/watch: "true" # ConfigMap 감지 spec: containers: - name: my-app image: my-app-image envFrom: - configMapRef: name: my-app-config
my-app-config의 ConfigMap이 변경되면 자동으로 롤링 업데이트를 하여 변경된 ConfigmAP 내용이 애플리케이션에 적용됩니다.
reloader.stakater.com/reload: "true"
만 활성화하게 된다면 리로더가 이 리소스를 관리 대상으로 삼겠다 라는 준비만 하고 자동 업데이트는 하지 않습니다.Kubernetes가 변경을 컨테이너에 알리고 자체 처리한댔는데 롤링 업데이트가 왜 필요한지?
다음 이유로 롤링 업데이트가 필요합니다.
- 애플리케이션이 ConfigMap/Secret 변경에 자동으로 대응하지 못하는 경우 변경 사항을 적용하기 위해 컨테이너를 재시작해야함
- ConfigMap/Secret 변경이 애플리케이션 로직 변경을 수반하는 경우
- 애플리케이션이 실행 환경 변화에 따라 설정을 변경해야 하는 경우
쿠버네티스 Secret 사용 대신 secret manager를 사용하면 되는거 아닌지?
쿠버네티스 환경의 결합 측면에선 Secret을 사용하는 것이 좋아 보인다고 합니다. AWS → GCP, GCP → AWS와 같이 secret manager 도구가 바뀌면 어플리케이션의 코드를 수정해야 합니다.
레퍼런스
https://kubernetes.io/docs/concepts/configuration/configmap/