Notice
Recent Posts
Recent Comments
Link
Gom3rye
Kubernetes- Config & Storage API 본문
728x90
반응형
Config & Storage API
- 컨테이너에 대한 설정 파일, 패스워드 같은 기밀 정보를 추가하거나 영구 볼륨을 제공하기 위한 리소스
- 내부에서 사용되는 것을 제외하면 사용자가 직접 사용하는 것은 3가지
- Secret
- ConfigMap
- 영구 볼륨 클레임
쿠버네티스의 환경 변수
- 환경 변수를 전달할 때는 파드 템플릿에 env 또는 envForm을 지정
- 환경 정보에는 다섯가지 정도의 정보를 변수에 포함시킴
- 정적 설정
- 파드 정보
- 컨테이너 정보
- 시크릿 리소스 기밀 정보
- ConfigMap 리소스 설정값 들이 저장된다.
정적 설정
- spec.containers[].env에 정적인 값을 설정하는 것
# sample-env.yaml
apiVersion: v1
kind: Pod
metadata:
name: sample-env
labels:
app: sample-app
spec:
containers:
- name: nginx-containe
image: nginx:1.16
env:
- name: MAX_CONNECTION
value: "100"
# 리소스 생성
kubectl apply -f sample-env.yaml
# 정말 환경 변수가 만들어졌는지 컨테이너 가서 확인해보기(컨테이너 내부의 환경 변수 확인:env)
# kubectl exec -it <pod-name> -- <command> (pod내 컨테이너가 한개인 경우)
# kubectl exec -it <pod-name> -c <container-name> -- <command> (컨테이너가 여러 개인 경우)
kubectl exec -it sample-env -- env
kubectl exec -it sample-env -- env | grep MAX_CONNECTION
## MAX_CONNECTION=100
# 타임존을 변경하고자 할 때 TZ 환경 변수에 필요한 값을 설정하면 된다.
env:
- name: TZ
value: Asia/Seoul
파드 정보
- 어떤 노드에서 파드가 기동하고 있는지와 파드 자신의 IP 주소, 기동 시간 등 파드에 관한 정보는 fieldRef를 사용하면 참조할 수 있다.
- 아래 명령어를 이용하면 파드에 대한 정보를 yaml 형태로 알 수 있다.
kubectl get pods sample-env -o yaml
- 이때 등록한 매니페스트 정보와 별도로 파드의 IP 주소나 호스트 정보와 같은 여러 정보가 추가되어 있는 것을 확인할 수 있다.
- 파드의 정보를 이용해서 환경 변수 설정 (spec.nodeName을 K8S_NODE에 저장)
# sample-env-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: sample-env-pod
labels:
app: sample-app
spec:
containers:
- name: nginx-container
image: nginx:1.16
env:
- name: K8S_NODE
valueFrom: # 이 파드(spec)를 어떤 노드(nodeName)에 스케줄링했는지"를 자동으로 가져오겠다
fieldRef:
fieldPath: spec.nodeName
# 리소스 생성
kubectl apply -f sample-env-pod.yaml
# 환경 변수 확인
kubectl exec -it sample-env-pod -- env | grep K8S_NODE
# K8S_NODE=workernode1
컨테이너 정보
- 파드의 정보와 마찬가지고 컨테이너 리소스에 대한 정보는 resourceFieldRef 사용하여 확인이 가능하다.
- 파드에는 여러 컨테이너 정보가 포함되어 있으므로 각 컨테이너에 대한 정보는 fieldRef에서 확인할 수 없다.
- 컨테이너 정보를 가져와서 환경 변수에 저장하는 리소스 매니페스트 작성
# sample-env-container.yaml
apiVersion: v1
kind: Pod
metadata:
name: sample-env-container
labels:
app: sample-app
spec:
containers:
- name: nginx-container
image: nginx:1.16
env:
- name: CPU_REQUESTS
valueFrom:
resourceFieldRef:
containerName: nginx-container
resource: requests.cpu
- name: CPU_LIMITS
valueFrom:
resourceFieldRef:
containerName: nginx-container
resource: limits.cpu
# 리소스 생성
kubectl apply -f sample-env-container.yaml
(파드는 불변 객체기 때문에 yaml 파일 수정하려면 delete pod 하고 수정해야 변경된 yaml로 파드가 생성된다.)
# 환경 변수 확인
kubectl exec -it sample-env-container -- env | grep -E 'CPU_REQUESTS|CPU_LIMITS'
# CPU_REQUESTS=0
# CPU_LIMITS=1
- 주의할 점
- kubernetes에서 command나 args로 실행 명령어를 지정할 때 파드 매니페스트 내부에 정의된 환경 변수는 ${ } 대신에 $( )를 이용해야 한다.
# sample-env-fail.yaml
apiVersion: v1
kind: Pod
metadata:
name: sample-env-fail
labels:
app: sample-app
spec:
containers:
- name: nginx-container
image: nginx:1.16
command: ["echo"] # 컨테이너 만들고 이 명령 수행
args: ["${TESTENV}", "${HOSTNAME}"] # echo ${TESTENV} 와 echo ${HOSTNAME} 수행
env:
- name: TESTENV
value: "100"
- name: HOSTNAME
value: "kyla"
# 리소스 생성
kubectl apply -f sample-env-fail.yaml
# echo 명령 확인은 logs
kubectl logs sample-env-fail
# ${TESTENV} ${HOSTNAME} 로 환경 변수 값이 안나온다. ${}로 해서
# $()로 수정하고 파드 지우고 다시 생성
kubectl logs sample-env-fail
kubectl logs sample-env-fail
# 100 kyla 로 환경 변수 값 잘 나온다.
Secret
- MySQL 같은 데이터베이스에 접속하려면 사용자 이름이나 패스워드 같은 기밀 정보가 필요하다.
- 쿠버네티스에서 애플리케이션을 실행할 때 이러한 기밀 정보를 컨테이너에 전달하는 방법
- 도커 빌드 시 컨테이너 이미지에 추가
- 이미지를 빌드할 때 애플리케이션 측이나 컨테이너 환경 변수 및 실행 인수 등에 패스워드 등을 추가
- 이미지 자체에 기밀 정보가 포함되어 있다면 도커 레지스트리에 기밀 정보도 업로드하게 되어 보안상 바람직하지 않다.
- 기밀 정보 내용을 변경하려면 이미지를 다시 빌드해야 한다.
- 파드나 디플로이먼트의 매니페스트를 이용해서 전달하기
- 매니페스트 자체에 기밀 정보가 포함되어 매니페스트 관리가 어려워진다.
- Git 저장소와 같은 외부 서버에서 기밀 정보를 포함한 매니페스트를 관리하면 보안상 위험하다. (지금은 Git이나 AWS 같은 곳에서 기밀 정보가 노출되면 에러를 발생시키기도 한다.)
- github action에서 비밀번호를 발견하면 빌드를 안 해버린다.
- aws code에 비밀번호 넣어버리면 계정이 막혀버린다.
- 사용자 명이나 패스워드 등의 기밀 정보를 별도의 리소스 파일로 만들고 파드에서 읽어서 설정할 수 있는데 이것을 리크릿 리소스라고 한다.
- 시크릿을 정의하고 있는 매니페스트는 base64로 인코드되어 있지만 암호화는 되어 있지 않는다. → 매니페스트를 Git 저장소 등에 업로드하는 것은 불가능하다.
- 이런 부분을 해결해주는 오픈 소스 솔루션이 있다.
- 도커 빌드 시 컨테이너 이미지에 추가
시크릿 분류
종류 개요
| Opaque | 일반적인 범용 용도 |
| kubernetes.io/tls | TLS 인증서 용 |
| kubernetes.io/basic-auth | 기본 인증서 용 |
| kubernetes.io/dockerconfigjson | 도커 레지스트리 인증 용 |
| kubernetes.io/ssh-auth | SSH 인증 정보 용 |
| kubernetes.io/service-account-token | 서비스 어카운트 토큰 용 |
| bootstrap.kubernetes.io/token | 부트스트랩 토큰 용 |
- Opaque를 제외하고는 형식이 정해져 있다.
- AWS에서 Secret 키 값으로 넣기
✅ 문제 상황 요약이걸 깃허브 같은 저장소에 올리면 안 되겠죠?그래서 AWS 같은 클라우드에서는 이런 걸 다른 안전한 방식으로 보관합니다.
🔐 "키값으로 집어넣는다"의 의미1. AWS Secrets Manager- 암호, API 키, DB 비밀번호 같은 민감한 정보를 안전하게 저장
- 애플리케이션이 API로 해당 값을 읽어오는 방식으로 사용
- Kubernetes와 연동 가능 (예: External Secrets, CSI Driver)
- 비슷하게 문자열 값을 키/값 형태로 저장
- 일반 변수와 SecureString(암호화된) 형태로 사용 가능
🔧 사용 흐름 예시 (Secrets Manager)- AWS 콘솔이나 CLI로 기밀 정보 등록:
- aws secretsmanager create-secret \\ --name mysql-secret \\ --secret-string '{"username":"admin","password":"my-password"}'
- Kubernetes에서 외부 Secret을 참조하도록 구성 (ExternalSecrets 사용):
- apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: mysql-secret spec: secretStoreRef: name: aws-secrets kind: SecretStore target: name: mysql-secret data: - secretKey: username remoteRef: key: mysql-secret property: username - secretKey: password remoteRef: key: mysql-secret property: password
- 이제 파드는 mysql-secret이라는 쿠버네티스 Secret을 쓰지만
- 실제 값은 AWS Secrets Manager에서 가져오는 거예요.
✅ 요약 정리항목 의미mysql-secret.yaml 직접 관리 기밀정보가 코드에 노출됨 (위험) AWS에 키값으로 저장 Secrets Manager나 SSM Parameter Store에 안전하게 저장 Kubernetes에선 ExternalSecret이나 CSI driver로 AWS에서 Secret을 가져와 사용 장점 코드에 기밀정보 없음, 안전한 권한 제어, 자동 갱신 가능 - 이건 보통 다음 두 가지 방식 중 하나입니다:
- → 기밀정보 노출 위험 때문입니다.
- 당신이 가진 mysql-secret.yaml 파일은 대개 이런 내용일 거예요:
- "AWS에 키값으로 집어넣는다"는 표현은 보통 기밀 정보를 직접 코드나 YAML에 쓰지 않고, AWS의 보안 서비스에 안전하게 저장해서 사용하는 방식을 말한다
- Github에 secret.yaml 파일 올라갔다면 해결방법
- 노출된 비밀번호 등 민감 정보 즉시 무효화
- GitHub 기록에서 mysql-secret.yaml 완전히 삭제 (히스토리 포함)
🧩 1단계: 기밀 정보 무효화 (가장 먼저 해야 해요)
그리고 쿠버네티스에서도 새 비밀번호로 Secret을 다시 생성해야 해요:-- MySQL 기준 ALTER USER 'your-username'@'%' IDENTIFIED BY '새로운강력한비밀번호';
🧩 2단계: GitHub에서 흔적 지우기- BFG 설치 (macOS 기준)Ubuntu/Debian이라면:
- sudo apt install openjdk-11-jre wget <https://repo1.maven.org/maven2/com/madgag/bfg/1.14.0/bfg-1.14.0.jar>
- brew install bfg
- Git 저장소를 미러로 복제
- git clone --mirror <https://github.com/your-username/your-repo.git> cd your-repo.git
- 파일 완전히 제거
- java -jar bfg-1.14.0.jar --delete-files mysql-secret.yaml
- 기록 정리하고 푸시
- git reflog expire --expire=now --all git gc --prune=now --aggressive git push --force
✅ 3단계: .gitignore로 다시 올리지 않게 막기
✅ 4단계 (선택): 안전하게 secret 관리하는 방법으로 전환방법 설명SealedSecrets (Bitnami) Git에 암호화된 secret을 올리고, K8s에서 복호화 AWS Secrets Manager + ExternalSecret 기밀정보는 AWS에 두고, K8s는 가져다 씀 Vault 보안에 특화된 secret 관리 도구 .env 파일 + Kustomize 개발 시 로컬에서만 사용하는 방식
😥 혹시 실수로 Public Repo에 올렸다면- GitHub에 비공개 전환해두세요.
- 이미 공개된 경우라면 GitHub Security나 API 제공 업체로 키 폐기 요청도 해야 합니다.
- AWS, DB, 혹은 기타 자격 증명은 반드시 회수 및 갱신하세요.
- 앞으로는 다음 중 하나로 관리하세요:
- echo "mysql-secret.yaml" >> .gitignore git rm --cached mysql-secret.yaml git commit -m "gitignore에 secret 파일 추가" git push
- ✅ 방법 1: BFG Repo-Cleaner 사용 (간단하고 빠름)
- kubectl delete secret mysql-secret kubectl create secret generic mysql-secret \\ --from-literal=username=your-username \\ --from-literal=password=새로운강력한비밀번호
- YAML에 들어 있던 DB 사용자명, 비밀번호 등을 이미 쿠버네티스에서 쓰고 있다면, 즉시 비밀번호를 바꿔주세요:
- 🎯 목표 요약
Opaque
일반적인 범용 용도의 시크릿
- 일반적인 스키마 리스 시크릿을 생성하는 경우 타입에 Opaque를 지정
- 생성 방법
- kubectl로 파일에서 값을 참조하여 생성(--from-file)
- kubectl로 envfile에서 값을 참조하여 생성(--from-env-file)
- kubectl로 직접 값을 전달하여 생성(--from-literal)
- 매니페스트에서 생성(-f)
- 시크릿 리소스에서는 하나의 시크릿 안에 여러 Key-Value 값이 저장되는데 하나의 시크릿 당 저장 가능한 데이터 크기는 1MB
- kubectl로 파일에서 값을 참조해서 생성(--from-file)
- 파일에서 값을 참조해서 생성하는 경우에는 --from-file 옵션을 이용한다.
- 파일명이 그대로 키가 되기 때문에 확장자는 붙이지 않는 것이 좋다.
- 파일을 생성할 때 개행(줄바꿈) 코드가 들어가지 않도록 주의해야 한다.
- 실습
- 시크릿 값을 저장할 2개의 파일을 생성 (웬만하면 확장자 붙이지 말자. username.txt (x), username (o))
# username root # password rootpassword # 파일 내용을 호출해서 sample-db-auth 시크릿 생성 kubectl create secret generic --save-config <이름> --from-file=<파일명> --from-file=<파일명> kubectl create secret generic --save-config sample-db-auth --from-file=./username --from-file=./password # secret/sample-db-auth created kubectl get secret ## # NAME TYPE DATA AGE # sample-db-auth Opaque 2 3m35s -> 2개가 잘 만들어진 걸 확인할 수 있다. # secret 확인 kubectl get secret sample-db-auth -o json | grep -E 'username|password' ## # "password": "cm9vdHBhc3N3b3JkCg==", # base64로 잘 인코딩 되었다. # "username": "cm9vdAo=" echo 'cm9vdHBhc3N3b3JkCg==' | base64 --decode # rootpassword echo 'cm9vdAo=' | base64 --decode # root - base64
- 바이너리 데이터로 문자 코드에 영향을 받지 않는 공통 ASCII 문자로 표현하기 위해 만들어진 인코딩
- ASCII 문자 하나가 64진법의 숫자 하나를 의미하기 때문이다.
- 8비트짜리 바이트 3개를 6비트씩 4개로 쪼개어 Base64 코드 4개로 바꾸어 표현한다.
- Base64 코드를 바이너리로 디코딩하기 편하게 하기 위해 Base64 코드를 무조건 4글자 단위로 만들고 빈 부분을 = 문자로 채워두기도 한다.
- 마지막에 = 들어간 파일 → Base64 코드구나!
- kubectl로 envfile에서 값을 참조하여 생성(--from-env-file)
- 하나의 파일에서 일괄적으로 생성하는 경우에는 envfile로 생성하는 것이 가능하다.
- 실습
- 데이터를 저장할 파일을 생성하고 작성
# env-secret username=root password=rootpassword # 시크릿 생성 (sample-db-auth가 이미 있으니 지우고 다시 생성) kubectl create secret generic --save-config sample-db-auth --from-env-file env-secret # --from-file 명령어와 큰 차이 없다. - 일반 파일은 파일 이름이 키가 되고 그 안에 작성한 것이 값이 된다.
- 파일 하나에 하나의 Config만 만들 수 있지만 env-file을 이용하면 여러 개의 데이터를 하나의 파일에 저장해서 사용 가능하다.
- 매니페스트(yaml) 파일에서 생성(-f)
- stringData: 사람이 쓰기 쉬움, 자동 base64 인코딩됨
- 실습
# sample-db-auth.yaml apiVersion: v1 kind: Secret metadata: name: sample-db-auth type: Opaque stringData: username: root password: rootpassword # 시크릿 생성 kubectl apply -f sample-db-auth.yaml kubectl get secret sample-db-auth -o json # username과 password base64인코딩 되어서 나온다.
ConfigMap
설정 정보 등을 Key-Value 값으로 저장할 수 있는 데이터 저장 리소스
- ConfigMap은 Generic 타입의 시크릿과 거의 동일한 방법으로 생성한다.
- nginx.conf나 httpd.conf 같은 설정 파일도 사용 가능
- 방법
- kubectl로 파일에서 값을 참조하여 생성(--from-file)
- kubectl로 직접 값을 전달해서 생성(--from-literal) → 쉽지 않음
- 매니페스트로 생성(-f)
# 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
}
# nginx.conf 파일을 이용해서 ConfigMap 생성
kubectl create configmap sample-configmap --from-file=nginx.conf # configmap/sample-configmap created
# 확인
kubectl get configmap sample-configmap -o json
- 리터럴(값을 직접 입력)을 이용한 ConfigMap 생성
kubectl create configmap --save-config web-config --from-literal=connection.max=100 --from-literal=connection.min=10
# 확인
kubectl describe configmap web-config
- 매니페스트를 이용한 설정
# 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;
pid /run/nginx.pid
test.sh: |
#! /bin/bash
echo "Hello Kubernetes"
sleep infinity
# 생성
kubectl apply -f sample-configmap.yaml
# 확인
kubectl describe configmap sample-configmap
사용
방법
- 환경 변수로 전달
- 컨피그맵의 특정 키만
- 컨피그맵의 전체 키
- 볼륨으로 마운트
- 컨피그맵의 특정 키만
- 컨피그맵의 전체 키
환경 변수로 전달
- 특정 키만을 전달하고자 할 때는 spec.containers[].env의 valueFrom.configMapKeyRef를 사용한다.
- configmap을 사용하기 위한 리소스 파일을 작성
# 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
# 리소스 생성
kubectl apply -f sample-configmap-single-env.yaml
# 확인
kubectl exec -it sample-configmap-single-env -- env | grep CONNECTION_MAX # CONNECTION_MAX=100
# sample-configmap-multi-env.yaml (key가 빠지면 된다.)
apiVersion: v1
kind: Pod
metadata:
name: sample-configmap-multi-env
spec:
containers:
- name: configmap-container
image: nginx:1.16
envFrom:
- configMapRef:
name: sample-configmap
# 리소스 생성
kubectl apply -f sample-configmap-multi-env.yaml
# 확인 (ConfigMap의 data 부분들이 다 들어가있다.)
kubectl exec -it sample-configmap-multi-env -- env
- 환경 변수로 사용할 때는 **.이나 -**가 포함된 경우에는 변수 참조가 어려우므로 사용하지 않는 것을 권장한다.
- YAML에서 사용하는 :나 | 등도 환경 변수에서는 사용하지 않는 것을 권장한다.
볼륨으로 마운트
- 특정 키만을 마운트 할 수도 있고 전체를 마운트 할 수도 있다.
- 특정 키만을 마운트 할 때는 spec.volumes[]의 secret.items[]를 이용한다.
# sample-configmap-single-volume.yaml (특정 키만을 가져오는 리소스 파일)
apiVersion: v1
kind: Pod
metadata:
name: sample-configmap-single-volume
spec:
containers:
- name: secret-container
image: nginx:1.16
volumeMounts:
- name: config-volume
mountPath: /config # /config/username.txt 에 저장
volumes:
- name: config-volume
secret:
secretName: sample-db-auth # sample-db-auth 라는 secret에 있는 username 키의 데이터를 가져와서
items:
- key: username
path: username
# 리소스 생성
kubectl apply -f sample-configmap-single-volume.yaml
# 확인 (파일을 만들었으니까 파일로 확인하기)
kubectl exec -it sample-configmap-single-volume -- cat /config/username
# 전부 다 가져오고 싶으면 items를 안 쓰면 된다.
apiVersion: v1
kind: Pod
metadata:
name: sample-configmap-multi-volume
spec:
containers:
- name: secret-container
image: nginx:1.16
volumeMounts:
- name: config-volume
mountPath: /config
volumes:
- name: config-volume
secret:
secretName: sample-db-auth # sample-db-auth라는 secret에 있는 username 키의 데이터를 가져와서
# 확인
kubectl exec -it sample-configmap-multi-volume -- ls /config # password username
# key 별로 파일이 생성, 이 경우 기본적으로 60초마다 내용을 확인해서 갱신합니다.
kubectl exec -it sample-configmap-multi-volume -- cat /config/username
728x90
반응형
'현대 오토에버 클라우드 스쿨' 카테고리의 다른 글
| Kubernetes- Volume API, Requests, Limits (1) | 2025.07.11 |
|---|---|
| Kubernetes- Volume API (3) | 2025.07.10 |
| Kubernetes- Session Affinity, Headless, ExternalName, None-Selector, Ingress (2) | 2025.07.08 |
| Kubernetes Service의 type (1) | 2025.07.07 |
| Kubernetes- Job, CronJob, Service (2) | 2025.07.04 |