env:
- name: ENV_KEYNAME_1 # 컨테이너에 새롭게 등록될 환경 변수 이름
valueFrom:
configMapKeyRef: # 컨피그맵에 존재하는 키·값 중 값을 가져옴
name: log-level-configmap # 참조할 컨피그맵의 이름, 1개의 값이 있음
key: LOG_LEVEL # 이 키에 해당되는 값 1개만 사용
- name: ENV_KEYNAME_2 # 컨테이너에 새롭게 등록될 환경 변수 이름
valueFrom:
configMapKeyRef:
name: multi-configmap # 참조할 컨피그맵의 이름, 2개의 값이 있음
key: k8s # 2개 값 중 하나만 사용
nginx.conf나 mysql.conf 파일에서도 값으로 사용 가능함.ConfigMap에 저장된 데이터를 마운트시켜서 nginx.conf나 mysql.conf 파일에서 값으로 사용
ConfigMap의 값이 Pod 내부로 올라오는 것을 투영(Projection) 이라고 한다.
👉 --from-literal 옵션으로 값을 불러옴
ConfigMap을 외부 저장공간에 파일로 두고 여러 파드에서 공통으로 불러올 때 사용
👉 --from-file 옵션으로 값을 불러옴
Secret은 ConfigMap과 사용법이 유사하지만, ConfigMap에서는 평문 그대로 불러오고 보여주지만
Secret에서는 Base64 방식으로 인코딩해서 보이기 때문에
SSH 키나 비밀번호 등 민감한 정보를 저장할 때 사용
Secret은 네임스페이스에 종속된 객체
생성 시 다음 옵션들을 사용할 수 있음
--from-literal--from-file--from-env-file여러 번 --from-file 사용하여 여러 파일을 동시에 지정해서 불러올 수도 있음
kubectl create secret --help 를 보면 docker-registry, generic, tls 등의 타입을 사용할 수 있다.docker-registry 타입
generic 타입
tls 타입
kubectl create secret (docker-registry | generic | tls) [OPTIONS]
generic으로 지정하면 Opaque 타입을 사용하며



지금까지 실행한 명령어들의 흐름은 대략 이렇게 흘러가요.
ConfigMap을 Pod에 volume으로 마운트해서 /etc/config 에 파일로 보는 실습
index.html 파일을 만들어서 ConfigMap 두 가지 방식(키 = 파일이름 / 키 = 임의이름)으로 생성
Secret을
--from-literal 로 단일 비밀번호--from-file 로 두 개의 파일(pw1, pw2)을 읽어서 생성생성된 Secret 값을 kubectl get secret -o yaml로 확인하고,
Base64로 인코딩된 값을 base64 -d 로 디코딩해 실제 비밀번호 확인
Secret을
envFrom 으로 전체를 환경변수로 넣는 Podenv.valueFrom.secretKeyRef 로 특정 key만 환경변수로 넣는 Pod/etc/secret에 파일로 붙이는 Podnano volume-mount-configmap.yaml
volume-mount-configmap.yaml 매니페스트 파일을 작성/수정.kubectl apply -f volume-mount-configmap.yaml
kubectl get po -o wide
kubectl exec configmap-volume-pod -- ls /etc/config
configmap-volume-pod 컨테이너 안에 들어가서 /etc/config 디렉터리 목록 확인### kubectl configmap-volome-pod --cat /etc/configmap/k8s
주석처럼 남긴 메모 같은데,
kubectl configmap-volome-pod 는 잘못된 명령어이고
아마 의도는
kubectl exec configmap-volume-pod -- cat /etc/config/k8s
이런 식으로 마운트된 파일 내용 확인하려던 것 같아요.
경로도 /etc/configmap 이 아니라 /etc/config 가 맞겠죠.
echo "Hello, ITKOREA" > index.html
index.html 파일 생성, 내용은 Hello, ITKOREA.kubectl create configmap index-file-value --from-file index.html
index-file-value 라는 ConfigMap 생성.kubectl create configmap index-file-key --from-file index_key=index.html
또 다른 ConfigMap index-file-key 생성.
이번에는 key 이름을 index_key 로 직접 지정,
value는 index.html 파일 내용.
두 명령의 차이:
index.htmlindex_key.kubectl describe configmap index-file-key
index-file-key ConfigMap 상세 정보 확인index_key 로 들어갔는지 확인하는 단계.kubectl create secret generic my-sec-passwd --from-literal password=rootoor
my-sec-passwd 라는 generic(Opaque 타입) Secret 생성.
password=rootoor 라는 key-value 1개를 가짐.
passwordrootoor (저장 시에는 Base64로 인코딩됨).echo "mypasswd" > pw1 && echo "yourpasswd" > pw2
pw1 파일에 mypasswd,pw2 파일에 yourpasswd 저장.&& : 앞 명령이 성공하면 이어서 다음 명령 실행.kubectl create secret generic our-sec-passwd --from-file pw1 --from-file pw2
our-sec-passwd 라는 Secret 생성.--from-file pw1 → key=pw1, value=pw1 파일 내용 (mypasswd).--from-file pw2 → key=pw2, value=pw2 파일 내용 (yourpasswd).our-sec-passwd 는 key 두 개(pw1, pw2)를 가진 Secret.kubectl get secrets
my-sec-passwd, our-sec-passwd 등).kubectl get secret my-sec-passwd -o yaml
kubectl get secret our-sec-passwd -o yaml
data: 아래에 값들이 Base64 인코딩 되어 들어 있는 걸 확인.echo bXlwYXNzd2QK | base64 -d
bXlwYXNzd2QK 문자열을 Base64 디코딩.mypasswd (뒤에 개행 문자 포함).pw1 (mypasswd)가 Base64로 인코딩된 결과.nano env-from-secret.yaml
kubectl apply -f env-from-secret.yaml
kubectl get po -o wide
env-from-secret.yaml 작성/수정 후 apply.
이 파일에서는 대략 이런 형태였을 것:
envFrom:
- secretRef:
name: my-sec-passwd
즉 my-sec-passwd Secret 안의 모든 key(password)를
환경변수 PASSWORD처럼 자동으로 만들어서 컨테이너에 주입.
nano selective-env-from-secret.yaml
kubectl apply -f selective-env-from-secret.yaml
kubectl get po -o wide
selective-env-from-secret.yaml 수정 후 적용.
이 YAML에서는:
env:
- name: your_sec_passwd
valueFrom:
secretKeyRef:
name: our-sec-passwd
key: pw2
이런 식으로 our-sec-passwd Secret 중 pw2 키만 골라서
your_sec_passwd 라는 환경변수에 주입.
nano volume-mount-secret.yaml
kubectl apply -f volume-mount-secret.yaml
/etc/secret 같은 경로에 파일로 마운트하는 Pod YAML 작성 후 적용.kubectl exec secret-volume-pod -- ls /etc/secret
secret-volume-pod 안에서 /etc/secret 디렉터리 파일 목록 확인.pw1, pw2 같은 파일이 보일 것.kubectl exec secret-volume-pod -- cat /etc/secret/pw1
kubectl exec secret-volume-pod -- cat /etc/secret/pw2
mypasswd, yourpasswd 출력될 것.nano selective-mount-secret.yaml
kubectl apply -f selective-mount-secret.yaml
kubectl get po -o wide
Secret 중 특정 key만 선택적으로 파일로 마운트하는 YAML 작성 후 적용.
예를 들어 items 옵션을 쓰면:
volumes:
- name: secret-volume
secret:
secretName: our-sec-passwd
items:
- key: pw2
path: saved-password
kubectl exec selective-volume-pod -- cat /etc/secret/saved-password
selective-volume-pod 컨테이너에서 /etc/secret/saved-password 내용 확인.pw2 에 해당하는 값(yourpasswd)이 출력됨.ConfigMap
--from-file 로 파일 내용을 key-value로 저장하고Secret
kubectl get secret -o yaml).--from-literal : 문자열 직접 입력.--from-file : 파일 내용 통째로 저장.Pod에서 사용하는 방식 3가지
envFrom.secretRef → Secret 전체를 env 로 가져오기env.valueFrom.secretKeyRef → Secret의 특정 key만 env 로 가져오기volumes[].secret + volumeMounts[] → Secret을 파일로 마운트지금 한 흐름이면 ConfigMap/Secret 기본 개념 + env/volume 활용법은 거의 다 돈 거라서, 시험이나 실무에서 나오는 대부분 패턴은 다 커버했다고 보면 됩니다 👍
docker login 없이 잘 됐는데,Deployment.spec.template.spec.imagePullSecrets 에 연결해서 사용합니다.config.json으로 Secret 만들기docker login
# Username, Password 입력
로그인에 성공하면 ~/.docker/config.json 파일에 credential 이 저장됩니다.
kubectl create secret generic registry-auth \
--from-file=.dockerconfigjson=/root/.docker/config.json \
--type=kubernetes.io/dockerconfigjson
--from-file=.dockerconfigjson=... : key 이름은 .dockerconfigjson--type=kubernetes.io/dockerconfigjson : 이미지 pull 용 스페셜 타입kubectl create secret docker-registry registry-auth-by-cmd \
--docker-username=hopus627 \
--docker-password=rootoor
kubectl create secret docker-registry registry-auth-registry \
--docker-username=hopus627 \
--docker-password=rootoor \
--docker-server=alicek106.registry.com
--docker-server 를 생략하면 기본 Docker Hub.kubectl get secrets
kubectl get secret registry-auth-registry -o yaml
이제 위에서 만든 Secret을 이미지 가져올 때 사용합니다.
# deployment-from-private-repo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-from-private-repo
spec:
replicas: 1
selector:
matchLabels:
app: myapp
template:
metadata:
name: mypod
labels:
app: myapp
spec:
containers:
- name: test-container
image: alicek106.ipdisk.co.kr/busybox:latest # Private Registry 이미지
args: ['tail', '-f', '/dev/null']
imagePullSecrets:
- name: registry-auth-registry # 위에서 만든 Secret 이름
적용 & 확인:
kubectl apply -f deployment-from-private-repo.yaml
kubectl get pods -o wide
generic(Opaque) Secret도 있지만,tls Secret을 지원합니다.tls.crt(인증서) + tls.key(개인키)를 Secret에 넣고 사용합니다.현재 디렉터리에서 아래 명령 실행:
openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 \
-subj "/CN=kahn.edu" \
-keyout cert.key \
-out cert.crt
cert.key : 개인키cert.crt : 인증서확인:
ls
# cert.key cert.crt 파일 있는지 확인
kubectl create secret tls kahn-edu-tls-secret \
--cert=cert.crt \
--key=cert.key
Secret 확인:
kubectl get secrets
kubectl get secret kahn-edu-tls-secret -o yaml
YAML을 보면 data: 아래에 tls.crt, tls.key 두 개가 들어 있습니다.
(실습 확장용 예시 – 필요하면 수정해서 사용)
apiVersion: v1
kind: Pod
metadata:
name: nginx-https-pod
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 443
volumeMounts:
- name: tls-secret
mountPath: /etc/nginx/tls # 인증서/키 위치
readOnly: true
volumes:
- name: tls-secret
secret:
secretName: kahn-edu-tls-secret
이후에는 nginx.conf 에서 /etc/nginx/tls/tls.crt, /etc/nginx/tls/tls.key 를 참조하도록 설정하면 됩니다.
Ingress는 쿠버네티스에서 외부 → 내부(Pod) 로 들어오는 HTTP/HTTPS 트래픽을
L7(Application Layer) 수준에서 라우팅하는 엔트리 포인트(Entry Point)이다.
예를 들어 Nginx 앱이 3개의 Deployment로 각각 운영 중이라면,
➡️ 복잡함 + 관리 비용 증가
➡️ 구조 간단 + 관리 쉬움 + 확장성 높음
[ 외부 사용자 ]
↓
(L7 Ingress)
┌──────────────────┐
│ Ingress Control │ ← SSL/TLS 처리, URL/도메인 라우팅
└──────────────────┘
↓ ↓
Service A Service B
↓ ↓
Pod들 Pod들
Ingress는 Service 위에 존재하는 상위 개념이며
Pod 앞의 “단일 진입점(Entry Point)” 역할을 한다.
Ingress를 사용하려면 YAML이 2개 필요하다:
(host/path → 어떤 Service로 전달할지 명시)
⚠ 쿠버네티스에는 기본 Ingress Controller가 없음 → 직접 설치해야 함.
예: /api 요청은 service-api 로,
/web 요청은 service-web 으로 라우팅
/api → service-api
/web → service-web
예: admin.kahn.com 요청은 admin 서비스로,
user.kahn.com 요청은 user 서비스로 라우팅
admin.kahn.com → service-admin
user.kahn.com → service-user
| 구성 요소 | 역할 |
|---|---|
| Ingress | L7 라우터. URL·도메인 기반 트래픽 분배 |
| Ingress Rule | "이 요청은 어떤 서비스로 보낼까?" 라우팅 규칙 |
| Ingress Controller | 실제 트래픽 처리 엔진(Nginx, Traefik 등) |
| Service | Pod 앞의 L4 로드밸런서 |
| Pod | 애플리케이션 컨테이너 |
ingress-rule 객체는 요청을 실제로 처리하는 엔진이 아니라,
단지 "규칙(Rule)"만 정의하는 설정 파일이다.
즉,
Ingress-rule = “이 URL은 어느 서비스로 보낼지” 정해둔 지도(Map)
Ingress가 외부 요청을 받기 위해서는
Ingress Controller 서버가 반드시 필요하다.
즉,
Ingress Controller = 실제로 요청을 받아 처리하는 웹 서버(Load Balancer)
(클라우드에서 제공하는 관리형 Ingress)
즉,
Ingress-rule은 “규칙 파일”이고
Ingress Controller는 “실제 일하는 서버”라고 보면 쉽다.
Ingress = 규칙
Ingress Controller = 규칙을 실제로 실행하는 서버
Ingress-rule만 만들어서는 외부 요청을 받을 수 없고,
반드시 Ingress Controller가 배포되어 있어야 한다.
아래는 너가 올린 TLS + Ingress + Nginx Ingress Controller 실습을 완전히 해석 + 정리하고
모든 명령어를 바로 복붙 가능하게 만들어준 버전이야.
형식은 다음 순서로 정리했어:
외부 HTTPS 요청 → Nginx Ingress Controller → TLS 인증 → Flask(5000) 웹앱 전달
이라는 구조를 직접 만들어 보는 실습이다.
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout tls.key \
-out tls.crt \
-subj "/CN=alicek106.example.com/O=alicek106"
결과 파일:
tls.key
tls.crt
kubectl create secret tls tls-secret1 \
--cert=tls.crt \
--key=tls.key
확인:
kubectl get secret tls-secret1 -o yaml
(너가 올린 이미지의 오류, 줄바꿈, 잘못된 key 모두 수정함)
👉 ingress-tls-k8s-latest.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-example
annotations:
nginx.ingress.kubernetes.io/rewrite-target: "/"
kubernetes.io/ingress.class: "nginx"
spec:
tls:
- hosts:
- alicek106.example.com
secretName: tls-secret1
rules:
- host: alicek106.example.com
http:
paths:
- path: /echo-hostname
pathType: Prefix
backend:
service:
name: hostname-service
port:
number: 80
apiVersion: apps/v1
kind: Deployment
metadata:
name: hostname-deployment
spec:
replicas: 3
selector:
matchLabels:
app: webserver
template:
metadata:
name: my-webserver
labels:
app: webserver
spec:
containers:
- name: my-webserver
image: alicek106/ingress-annotation-test:0.0
ports:
- containerPort: 5000
name: flask-port
apiVersion: v1
kind: Service
metadata:
name: hostname-service
spec:
type: ClusterIP
selector:
app: webserver
ports:
- name: web-port
port: 80
targetPort: flask-port
kubectl apply -f hostname-deployment.yaml
kubectl apply -f hostname-service.yaml
kubectl apply -f ingress-tls-k8s-latest.yaml
kubectl get po -n ingress-nginx -o wide
kubectl get svc -n ingress-nginx
여기서 중요한 정보:
10.244.5.1630080 (80 포트의 NodePort 매핑)curl -k https://10.244.5.16/echo-hostname \
-H "Host: alicek106.example.com"
※ -k : self-signed 인증서 허용
curl -k https://alicek106.example.com/echo-hostname \
--resolve alicek106.example.com:443:10.244.5.16
의미:
alicek106.example.com:443 → 10.244.5.16 강제로 매핑
노드 IP 확인:
kubectl get nodes -o wide
예: 192.168.56.12
Ingress-controller NodePort 확인:
kubectl -n ingress-nginx get svc ingress-nginx-controller
예: 443 → 30443
curl:
curl -k https://alicek106.example.com/echo-hostname \
-H "Host: alicek106.example.com" \
--resolve alicek106.example.com:443:192.168.56.12
또는 더 단순하게:
curl -k https://192.168.56.12:30443/echo-hostname \
-H "Host: alicek106.example.com"
Stateless Pod
Stateful Pod
Pod가 요청하는 스토리지 요구사항(인터페이스)
사용자(Pod) → PVC → PV(실제 스토리지)
쿠버네티스에서는 외부 노드나 특정 스토리지에 위치한 디렉터리를
Pod에 공유시켜서 Pod가 생성하는 데이터를 노드에 저장할 수 있다.
하지만 특정 노드 A에만 데이터를 저장하게 되면 문제가 발생한다:
이 문제를 해결하기 위해 쿠버네티스는
Pod가 특정 노드에 종속되지 않고,
어느 노드에서든 동일한 데이터를 저장·사용할 수 있도록
네트워크 기반 스토리지(PV)를 제공한다.
PV(퍼시스턴트 볼륨)는 쉽게 말해:
NFS, NAS 같은 네트워크 드라이브를 쿠버네티스가 공식적으로 제공하는 형태
노드에 종속되지 않는 영구 스토리지가 PV이다.
Kubernetes PV는 다양한 스토리지 백엔드를 지원한다:


아래 텍스트를 깔끔하게 정리한 버전으로 만들어줄게.
문단 나누기 + 용어 강조 + 흐름 정리 형태로 재구성했어.
(너가 자주 요청하는 정리 스타일 그대로 적용함.)
쿠버네티스에서 지원하는 대부분의 볼륨 타입은 Pod나 Deployment의 YAML 파일에서 직접 정의하여 사용할 수 있다.
이 때문에 YAML 파일 안에 nfs 항목을 함께 넣어 NFS 서버를 직접 정의해 사용하는 방식이 가능했다.
하지만 이러한 구조에는 다음과 같은 문제가 있다.
이 문제를 해결하기 위해 영속적(Persistent) 볼륨인 PV와
그 볼륨을 Pod에서 요청하는 PVC(Persistent Volume Claim) 개념이 등장한다.
PVC 이름만 적음PV와 매칭(binding)스토리지 추상화
Pod는 단지 “필요한 용량/접근 방식”만 명시 → 어디에 저장되든 상관 없음
재사용 가능
동일 PVC 스펙이면 다른 Pod에서도 그대로 사용 가능
교체 용이
내부 스토리지 타입(NFS, iSCSI 등)을 변경해도 Pod YAML 수정 필요 없음
관리 효율성
스토리지 담당자와 애플리케이션 팀의 역할이 분리됨
| 개념 | 역할 |
|---|---|
| PV (Persistent Volume) | 관리자가 미리 만들어 두는 실제 저장소 공간 |
| PVC (Persistent Volume Claim) | Pod가 필요한 저장소를 요청하는 Claim 객체 |
| Pod | PVC를 통해 PV를 간접적으로 사용함 |
| 이점 | 스토리지 관리 분리, 추상화, 확장성↑, 유지보수 용이 |
이 문장은 hostPath의 잘못된 사용 방식을 설명하는 예시이거나,
혹은 마운트 경로를 readOnly로 사용했을 때 발생하는 현상을 말하는 것에 가깝다.
하지만 가장 정확한 해석은 아래야 👇
➡ 호스트의 디렉터리를 Pod 내부(A 파드)에 마운트하면, 호스트에 이미 존재하는 내용은 Pod 안에서 보이지만,
Pod 내부에서 새로 생성한 파일이 호스트 디렉터리로 반영되지 않는 경우가 생긴다는 뜻이다.
즉,
이 현상은 다음과 같은 상황에서 발생할 수 있어.
volumeMounts:
- name: host-volume
mountPath: /data
readOnly: true
/data는 Pod에서 보이지만예:
/var/log 를 호스트에 마운트했는데/var/log 기본 디렉터리가 있음→ 컨테이너의 rootfs 레이어가 hostPath 위에 오버레이(overlay) 로 덮어쓰면서
호스트로 데이터가 올라가지 못하는 문제가 발생할 수 있음
👉 hostPath를 단순히 외부 디렉터리처럼 생각하고 마운트하면,
Pod 내부에서 발생한 변경사항이 항상 외부로 반영되는 것은 아니며 사용 시 주의가 필요하다.
즉,
그래서 운영에서는 hostPath를 거의 안 씀
→ 커플링이 너무 강하고 예상 불가능한 동작 많음