Kubernetes4

열공하는웅2·2025년 11월 13일

클라우드

목록 보기
10/13

📌 ConfigMap에 데이터를 저장해두고 필요한 값을 불러 올려서 사용하기

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개 값 중 하나만 사용

📌 추가 설명

  • ConfigMap에 저장된 데이터는 nginx.confmysql.conf 파일에서도 값으로 사용 가능함.


📌 ConfigMap

  • ConfigMap에 저장된 데이터를 마운트시켜서 nginx.confmysql.conf 파일에서 값으로 사용

  • ConfigMap의 값이 Pod 내부로 올라오는 것을 투영(Projection) 이라고 한다.
    👉 --from-literal 옵션으로 값을 불러옴

  • ConfigMap을 외부 저장공간에 파일로 두고 여러 파드에서 공통으로 불러올 때 사용
    👉 --from-file 옵션으로 값을 불러옴


📌 Secret

  • Secret은 ConfigMap과 사용법이 유사하지만, ConfigMap에서는 평문 그대로 불러오고 보여주지만
    Secret에서는 Base64 방식으로 인코딩해서 보이기 때문에
    SSH 키나 비밀번호 등 민감한 정보를 저장할 때 사용

  • Secret은 네임스페이스에 종속된 객체

  • 생성 시 다음 옵션들을 사용할 수 있음

    • --from-literal
    • --from-file
    • --from-env-file
  • 여러 번 --from-file 사용하여 여러 파일을 동시에 지정해서 불러올 수도 있음



📌 Secret 타입과 생성 방식 정리

  • kubectl create secret --help 를 보면 docker-registry, generic, tls 등의 타입을 사용할 수 있다.

✔️ Secret 타입 설명

  • docker-registry 타입

    • container registry에 접근할 때 사용되는 비밀키(인증 정보)
  • generic 타입

    • Opaque 타입의 비밀키(일반적인 key-value 기반 Secret)
  • tls 타입

    • TLS 인증서와 그에 관련된 키를 가지고 있는 Secret

📌 Secret 생성 형식

kubectl create secret (docker-registry | generic | tls) [OPTIONS]
  • Secret Type을 generic으로 지정하면 Opaque 타입을 사용하며
    로컬 파일, 디렉터리, 혹은 문자열 값을 지정하여 Secret 생성 가능


1. 전체 흐름 요약

지금까지 실행한 명령어들의 흐름은 대략 이렇게 흘러가요.

  1. ConfigMap을 Pod에 volume으로 마운트해서 /etc/config 에 파일로 보는 실습

  2. index.html 파일을 만들어서 ConfigMap 두 가지 방식(키 = 파일이름 / 키 = 임의이름)으로 생성

  3. Secret

    • 하나는 --from-literal 로 단일 비밀번호
    • 하나는 --from-file 로 두 개의 파일(pw1, pw2)을 읽어서 생성
  4. 생성된 Secret 값을 kubectl get secret -o yaml로 확인하고,
    Base64로 인코딩된 값을 base64 -d 로 디코딩해 실제 비밀번호 확인

  5. Secret을

    • envFrom 으로 전체를 환경변수로 넣는 Pod
    • env.valueFrom.secretKeyRef 로 특정 key만 환경변수로 넣는 Pod
    • volume 마운트로 /etc/secret에 파일로 붙이는 Pod
    • 그 중에서 특정 key만 선택적으로 마운트하는 Pod
      까지 단계별로 실습한 흐름입니다.

2. 명령어 하나씩 분석

(1) ConfigMap을 volume으로 마운트하는 Pod

nano volume-mount-configmap.yaml
  • volume-mount-configmap.yaml 매니페스트 파일을 작성/수정.
kubectl apply -f volume-mount-configmap.yaml 
  • 위 YAML을 적용해서 ConfigMap을 /etc/config 에 마운트하는 Pod 생성/업데이트.
kubectl get po -o wide
  • Pod 목록을 넓은 정보(IP, 노드 등)까지 확인.
kubectl exec configmap-volume-pod -- ls /etc/config
  • configmap-volume-pod 컨테이너 안에 들어가서 /etc/config 디렉터리 목록 확인
    → 마운트된 ConfigMap의 key들이 파일 이름으로 나타남.
### 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 가 맞겠죠.


(2) 파일로부터 ConfigMap 생성

echo "Hello, ITKOREA" > index.html
  • 현재 디렉터리에 index.html 파일 생성, 내용은 Hello, ITKOREA.
kubectl create configmap index-file-value --from-file index.html 
  • index-file-value 라는 ConfigMap 생성.
  • 이때 key 이름 = 파일 이름(index.html),
    value = 파일 내용("Hello, ITKOREA").
kubectl create configmap index-file-key --from-file index_key=index.html 
  • 또 다른 ConfigMap index-file-key 생성.

  • 이번에는 key 이름을 index_key 로 직접 지정,
    value는 index.html 파일 내용.

  • 두 명령의 차이:

    • 앞은 key=index.html
    • 뒤는 key=index_key.
kubectl describe configmap index-file-key
  • index-file-key ConfigMap 상세 정보 확인
    → key 이름이 index_key 로 들어갔는지 확인하는 단계.

(3) Secret 생성 (literal, file 방식)

kubectl create secret generic my-sec-passwd --from-literal password=rootoor
  • my-sec-passwd 라는 generic(Opaque 타입) Secret 생성.

  • password=rootoor 라는 key-value 1개를 가짐.

    • key: password
    • value: rootoor (저장 시에는 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
  • 현재 네임스페이스의 Secret 목록 확인
    (default 토큰 + 위에서 만든 my-sec-passwd, our-sec-passwd 등).
kubectl get secret my-sec-passwd -o yaml 
kubectl get secret our-sec-passwd -o yaml 
  • 각각의 Secret을 YAML 형태로 출력.
  • data: 아래에 값들이 Base64 인코딩 되어 들어 있는 걸 확인.

(4) Base64 디코딩으로 실제 비밀번호 확인

echo bXlwYXNzd2QK | base64 -d 
  • bXlwYXNzd2QK 문자열을 Base64 디코딩.
  • 결과: mypasswd (뒤에 개행 문자 포함).
  • 위 값은 아마 pw1 (mypasswd)가 Base64로 인코딩된 결과.

(5) Secret을 envFrom으로 넣는 Pod

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처럼 자동으로 만들어서 컨테이너에 주입.


(6) Secret에서 특정 key만 env로 사용하는 Pod

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 라는 환경변수에 주입.


(7) Secret을 volume 으로 마운트하는 Pod

nano volume-mount-secret.yaml
kubectl apply -f volume-mount-secret.yaml 
  • Secret을 /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 출력될 것.

(8) Secret 선택적 마운트 Pod

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)이 출력됨.

3. 정리 포인트

  • ConfigMap

    • --from-file 로 파일 내용을 key-value로 저장하고
    • volume으로 마운트하면 키 이름 = 파일 이름(또는 지정한 path)인 파일로 노출.
  • Secret

    • 데이터는 항상 Base64 인코딩 상태로 저장 (kubectl get secret -o yaml).
    • --from-literal : 문자열 직접 입력.
    • --from-file : 파일 내용 통째로 저장.
  • Pod에서 사용하는 방식 3가지

    1. envFrom.secretRef → Secret 전체를 env 로 가져오기
    2. env.valueFrom.secretKeyRef → Secret의 특정 key만 env 로 가져오기
    3. volumes[].secret + volumeMounts[] → Secret을 파일로 마운트

지금 한 흐름이면 ConfigMap/Secret 기본 개념 + env/volume 활용법은 거의 다 돈 거라서, 시험이나 실무에서 나오는 대부분 패턴은 다 커버했다고 보면 됩니다 👍


1. 비공개 레지스트리 접근 인증용 Secret

1-1. 상황 정리

  • 지금까지는 퍼블릭 Docker Hub 이미지만 써서 docker login 없이 잘 됐는데,
  • 사설 레지스트리 / Private repo / GCR / ECR 등을 쓰면
    이미지를 pull 할 때 인증 정보(아이디/비번) 이 필요합니다.
  • 쿠버네티스에서는 이 정보를 Secret에 저장하고,
    Deployment.spec.template.spec.imagePullSecrets 에 연결해서 사용합니다.

1-2. 방법 A : docker login 후 config.json으로 Secret 만들기

  1. 노드(또는 마스터)에서 우선 docker 로그인
docker login
# Username, Password 입력

로그인에 성공하면 ~/.docker/config.json 파일에 credential 이 저장됩니다.

  1. 이 파일을 그대로 이용해서 Secret 생성
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 용 스페셜 타입

1-3. 방법 B : 명령어에서 직접 아이디/비번 적어서 Secret 만들기

  1. 도커 허브(기본 레지스트리) 용
kubectl create secret docker-registry registry-auth-by-cmd \
  --docker-username=hopus627 \
  --docker-password=rootoor
  1. 사설 레지스트리 서버 주소까지 지정하고 싶을 때
kubectl create secret docker-registry registry-auth-registry \
  --docker-username=hopus627 \
  --docker-password=rootoor \
  --docker-server=alicek106.registry.com
  • --docker-server 를 생략하면 기본 Docker Hub.
  • 사설 레지스트리면 반드시 주소나 도메인 적어줘야 함.
  1. Secret 확인
kubectl get secrets
kubectl get secret registry-auth-registry -o yaml

1-4. Private 레지스트리 이미지를 쓰는 Deployment 예제

이제 위에서 만든 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

2. TLS 타입 Secret (HTTPS, 공개키/개인키용)

2-1. 개념 정리

  • generic(Opaque) Secret도 있지만,
    HTTPS / TLS 인증서는 쿠버네티스에서 전용 타입인 tls Secret을 지원합니다.
  • 보통 Nginx Ingress, HTTPS 웹 서버 등에서
    tls.crt(인증서) + tls.key(개인키)를 Secret에 넣고 사용합니다.

2-2. openssl 로 개인키/인증서 생성

현재 디렉터리에서 아래 명령 실행:

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 파일 있는지 확인

2-3. TLS Secret 생성

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 두 개가 들어 있습니다.


2-4. Nginx HTTPS Pod에서 TLS Secret 사용하는 예시

(실습 확장용 예시 – 필요하면 수정해서 사용)

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란? (쿠버네티스 L7 진입점)

Ingress는 쿠버네티스에서 외부 → 내부(Pod) 로 들어오는 HTTP/HTTPS 트래픽을
L7(Application Layer) 수준에서 라우팅하는 엔트리 포인트(Entry Point)이다.


📦 Ingress의 역할

✔ 1) L7 라우팅 수행

  • URL 경로 기반 라우팅
  • 도메인(가상 호스트) 기반 라우팅
  • HTTP/HTTPS 트래픽 제어

✔ 2) SSL/TLS 처리

  • HTTPS 인증서를 Ingress에만 설정해 두고
    여러 서비스(Pod) 앞에서 단일 위치에서 SSL 처리 가능

✔ 3) 여러 Service를 하나의 엔드포인트로 묶음

  • NodePort / LoadBalancer Service를 여러 개 만들 필요 없음
  • Ingress 하나로 여러 Deployment를 하나의 URL 통해 제공 가능

🏗 왜 Ingress가 필요한가?

❌ Ingress가 없을 때

예를 들어 Nginx 앱이 3개의 Deployment로 각각 운영 중이라면,

  • Service(NodePort/LoadBalancer) 3개 생성 필요
  • 각 서비스에 도메인, SSL 설정 모두 따로 해야 함

➡️ 복잡함 + 관리 비용 증가


✔ Ingress를 사용할 때

  • 단 하나의 URL(or 도메인)만 노출
  • SSL/TLS 설정도 한 곳에서 끝
  • path/host 기반으로 서비스 라우팅

➡️ 구조 간단 + 관리 쉬움 + 확장성 높음


🔎 Ingress의 위치

[ 외부 사용자 ]
        ↓
  (L7 Ingress)
┌──────────────────┐
│  Ingress Control  │  ← SSL/TLS 처리, URL/도메인 라우팅
└──────────────────┘
    ↓        ↓
Service A   Service B
    ↓        ↓
 Pod들      Pod들

Ingress는 Service 위에 존재하는 상위 개념이며
Pod 앞의 “단일 진입점(Entry Point)” 역할을 한다.


Ingress 구성 요소

Ingress를 사용하려면 YAML이 2개 필요하다:

📄 1) Ingress 규칙 정의 파일

(host/path → 어떤 Service로 전달할지 명시)

📄 2) Ingress Controller

  • 실제로 트래픽을 처리하는 실행 엔진
  • 대표적: Nginx Ingress Controller

⚠ 쿠버네티스에는 기본 Ingress Controller가 없음 → 직접 설치해야 함.


🧩 Ingress 예시 규칙

예: /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

📌 요약 (한눈에 보기)

구성 요소역할
IngressL7 라우터. URL·도메인 기반 트래픽 분배
Ingress Rule"이 요청은 어떤 서비스로 보낼까?" 라우팅 규칙
Ingress Controller실제 트래픽 처리 엔진(Nginx, Traefik 등)
ServicePod 앞의 L4 로드밸런서
Pod애플리케이션 컨테이너


📌 Ingress-rule의 의미와 역할 정리

✔ Ingress-rule은 트래픽을 직접 처리하는 서버가 아니다

ingress-rule 객체는 요청을 실제로 처리하는 엔진이 아니라,
단지 "규칙(Rule)"만 정의하는 설정 파일이다.

즉,

Ingress-rule = “이 URL은 어느 서비스로 보낼지” 정해둔 지도(Map)


⚡ 그럼 누가 실제로 트래픽을 받을까?

Ingress가 외부 요청을 받기 위해서는
Ingress Controller 서버가 반드시 필요하다.

✔ Ingress Controller 역할

  • L7 트래픽 수신
  • host/path 기반 라우팅
  • SSL/TLS 처리
  • rewrite, proxy 설정 실행

즉,

Ingress Controller = 실제로 요청을 받아 처리하는 웹 서버(Load Balancer)


🌐 대표적인 Ingress Controller 종류

🔹 Nginx Ingress Controller (가장 널리 사용됨)

🔹 Kong API Gateway (엔터프라이즈 기능 제공)

🔹 GKE(Google Kubernetes Engine) Ingress Controller

(클라우드에서 제공하는 관리형 Ingress)

🔹 Traefik Ingress

🔹 HAProxy Ingress

즉,

Ingress-rule은 “규칙 파일”이고
Ingress Controller는 “실제 일하는 서버”라고 보면 쉽다.


🎯 한 줄 요약

Ingress = 규칙
Ingress Controller = 규칙을 실제로 실행하는 서버

Ingress-rule만 만들어서는 외부 요청을 받을 수 없고,
반드시 Ingress Controller가 배포되어 있어야 한다.


아래는 너가 올린 TLS + Ingress + Nginx Ingress Controller 실습을 완전히 해석 + 정리하고
모든 명령어를 바로 복붙 가능하게 만들어준 버전이야.

형식은 다음 순서로 정리했어:

  1. 실습 목적
  2. 핵심 흐름 요약
  3. 단계별 명령어 + 설명
  4. TLS Ingress YAML (/ 완전 정상 버전 제공)
  5. 마지막 curl 테스트까지 정리

🌐 [실습 목적]

외부 HTTPS 요청 → Nginx Ingress Controller → TLS 인증 → Flask(5000) 웹앱 전달
이라는 구조를 직접 만들어 보는 실습이다.


🚀 [핵심 흐름 요약]

  1. openssl 로 TLS 인증서(cert.crt, tls.key) 생성
  2. kubectl create secret tls 로 K8s TLS Secret 생성
  3. Deployment + Service 구성
  4. TLS HTTPS 라우팅이 있는 Ingress(TLS rule) 생성
  5. Ingress Controller Pod IP 또는 노드 포트로 curl 테스트

🧩 [1. TLS 인증서 생성]

✔ 명령어 그대로 복붙

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

🔐 [2. TLS Secret 생성]

kubectl create secret tls tls-secret1 \
  --cert=tls.crt \
  --key=tls.key

확인:

kubectl get secret tls-secret1 -o yaml

🏗 [3. TLS 옵션을 포함한 Ingress 생성]

✔ 완전 정상 들여쓰기 + 에러 없는 정식 버전

(너가 올린 이미지의 오류, 줄바꿈, 잘못된 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

🏗 [4. Deployment + Service 만들기]

✔ Deployment (hostname-deployment.yaml)

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

✔ Service (hostname-service.yaml)

apiVersion: v1
kind: Service
metadata:
  name: hostname-service
spec:
  type: ClusterIP
  selector:
    app: webserver
  ports:
    - name: web-port
      port: 80
      targetPort: flask-port

📦 [5. 생성 명령어 순서] (그대로 복붙 가능)

kubectl apply -f hostname-deployment.yaml
kubectl apply -f hostname-service.yaml
kubectl apply -f ingress-tls-k8s-latest.yaml

🔎 [6. Ingress Controller 확인]

kubectl get po -n ingress-nginx -o wide
kubectl get svc -n ingress-nginx

여기서 중요한 정보:

  • Ingress Controller Pod IP → 예: 10.244.5.16
  • NodePort 값 → 예: 30080 (80 포트의 NodePort 매핑)

🌐 [7. HTTPS/TLS 테스트]

✔ 방법 1 — Controller Pod IP 직접 접근 (테스트용)

curl -k https://10.244.5.16/echo-hostname \
  -H "Host: alicek106.example.com"

-k : self-signed 인증서 허용


✔ 방법 2 — 도메인 기반 접근 테스트

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 강제로 매핑


✔ 방법 3 — NodePort 이용 (가장 정상적)

노드 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"

📌 정리

✔ Ingress 자체는 규칙(Rule)만 정의

✔ 실제 HTTPS 트래픽은 Ingress Controller가 처리

✔ TLS Secret → Ingress의 tls 항목에서 사용

✔ curl 테스트 시 Host 헤더와 resolve 매핑이 매우 중요



📌 PV(Persistent Volume)와 PVC(Persistent Volume Claim)

✔ Stateful vs Stateless 차이

  • Stateless Pod

    • Pod가 생성/교체되어도 임의의 이름·ID가 주어짐
    • 외부에 데이터를 저장하지 않으면 상태와 무관
    • Replica로 여러 개가 생성되는 일반 웹 서버 등이 여기에 속함
  • Stateful Pod

    • Pod가 생성/교체되어도 고유한 순번·이름·ID를 유지해야 함
    • 자신만의 데이터가 반드시 유지되어야 하는 Pod
    • 예: DB Pod 등
      → 이러한 Pod는 반드시 PVC(PersistentVolumeClaim) 과 연결됨

📦 PV, PVC 개념

✔ PV(Persistent Volume)

  • 클러스터 내부의 실제 스토리지 공간
  • 관리자가 제공 (NFS, AWS EBS, HostPath 등)

✔ PVC(Persistent Volume Claim)

  • Pod가 요청하는 스토리지 요구사항(인터페이스)

    • Pod는 직접 PV를 알지 않고 PVC만 참조함

✔ 관계 정리

사용자(Pod) → PVC → PV(실제 스토리지)

✔ Pod의 동작

  • Pod는 PVC를 직접 마운트하여 데이터를 지속적으로 저장한다.


📌 쿠버네티스에서의 Persistent Volume 개념

쿠버네티스에서는 외부 노드나 특정 스토리지에 위치한 디렉터리를
Pod에 공유시켜서 Pod가 생성하는 데이터를 노드에 저장할 수 있다.

하지만 특정 노드 A에만 데이터를 저장하게 되면 문제가 발생한다:

  • Pod가 노드 A에서 실행 중일 때는 문제가 없지만
  • Pod가 재시작되며 다른 노드 B로 이동하면,
    A 노드에 저장된 데이터는 네트워크 주소가 달라져서 접근 불가
  • 이러한 구조는 Stateful 워크로드에 치명적임

✔ PV가 필요한 이유

이 문제를 해결하기 위해 쿠버네티스는
Pod가 특정 노드에 종속되지 않고,
어느 노드에서든 동일한 데이터를 저장·사용할 수 있도록
네트워크 기반 스토리지(PV)를 제공한다.


📦 PV의 정체: 네트워크 드라이브

PV(퍼시스턴트 볼륨)는 쉽게 말해:

NFS, NAS 같은 네트워크 드라이브를 쿠버네티스가 공식적으로 제공하는 형태

  • 어떤 노드에서든 동일한 네트워크 스토리지를 마운트할 수 있음
  • Pod가 장애로 다른 노드로 이동해도 같은 PV에 계속 접근 가능

즉,

노드에 종속되지 않는 영구 스토리지가 PV이다.


📌 PV의 구현 기술 예시

Kubernetes PV는 다양한 스토리지 백엔드를 지원한다:

  • NFS (Network File System)
  • NAS
  • AWS EBS
  • GCE Persistent Disk
  • Ceph, GlusterFS
  • HostPath(개발용)

아래 텍스트를 깔끔하게 정리한 버전으로 만들어줄게.
문단 나누기 + 용어 강조 + 흐름 정리 형태로 재구성했어.
(너가 자주 요청하는 정리 스타일 그대로 적용함.)


PV와 PVC를 이용한 볼륨 관리

쿠버네티스에서 지원하는 대부분의 볼륨 타입은 PodDeployment의 YAML 파일에서 직접 정의하여 사용할 수 있다.
이 때문에 YAML 파일 안에 nfs 항목을 함께 넣어 NFS 서버를 직접 정의해 사용하는 방식이 가능했다.

하지만 이러한 구조에는 다음과 같은 문제가 있다.

  • 예를 들어 데이터가 많이 발생하는 MySQL을 Pod 내부에서 NFS로 마운트해 데이터를 저장할 경우
    여러 Pod이 동시에 하나의 NFS 공간을 사용하면서 병목·분리 문제가 발생함.
  • MySQL은 반드시 특정 전용 스토리지 공간을 필요로 하는데
    YAML 안에 직접 NFS 서버 정보를 넣는 방식은 재사용이나 독립성이 떨어짐.
  • 그래서 실제 운영환경에서는 NFS 대신 iSCSI, GlusterFS 등 다양한 타입의 스토리지를 사용하며,
    이런 스토리지 역시 YAML 안에서 직접 정의하는 방식은 구조적으로 비효율적이다.

이 문제를 해결하기 위해 영속적(Persistent) 볼륨인 PV
그 볼륨을 Pod에서 요청하는 PVC(Persistent Volume Claim) 개념이 등장한다.


PV, PVC의 개념

🔹 PV (Persistent Volume)

  • 관리자가 미리 생성해두는 영구 스토리지 영역.
  • 쿠버네티스 클러스터가 사용할 수 있도록 미리 할당된 저장소.

🔹 PVC (Persistent Volume Claim)

  • Pod가 필요한 스토리지 요구사항을 적어 제출하는 스토리지 요청서.
  • Pod는 직접 스토리지를 지정하지 않고 “이 정도 크기, 이 정도 조건의 저장소를 주세요”라고 PVC를 통해 요청함.

🔹 예시 구조

  • 사용자는 Deployment나 Pod YAML 안에서 PVC 이름만 적음
  • PVC가 자동으로 조건에 맞는 PV매칭(binding)
  • Pod는 그 PV를 마치 로컬 디스크처럼 사용 가능

왜 필요한가?

❗ Pod가 직접 NFS 등을 지정하면 생기는 문제점

  1. 스토리지 정보가 Pod에 강하게 결합됨 (재사용성 ↓)
  2. 스토리지 종류 변경 시 YAML 파일 모두 수정 필요
  3. 여러 Pod이 하나의 NFS를 공유하면 동시성·데이터 충돌 문제 발생
  4. 운영 환경에서 다양한 스토리지 타입(iSCSI, NFS, GlusterFS 등)을 단일 구조로 관리 불가

✔ PV/PVC 도입 시 이점

  1. 스토리지 추상화
    Pod는 단지 “필요한 용량/접근 방식”만 명시 → 어디에 저장되든 상관 없음

  2. 재사용 가능
    동일 PVC 스펙이면 다른 Pod에서도 그대로 사용 가능

  3. 교체 용이
    내부 스토리지 타입(NFS, iSCSI 등)을 변경해도 Pod YAML 수정 필요 없음

  4. 관리 효율성
    스토리지 담당자와 애플리케이션 팀의 역할이 분리됨


요약

개념역할
PV (Persistent Volume)관리자가 미리 만들어 두는 실제 저장소 공간
PVC (Persistent Volume Claim)Pod가 필요한 저장소를 요청하는 Claim 객체
PodPVC를 통해 PV를 간접적으로 사용함
이점스토리지 관리 분리, 추상화, 확장성↑, 유지보수 용이


🔵 "외부 디렉터리를 마운트하면 A 파드 내부로는 들어오지만, A 파드에서 생성한 데이터는 외부 디렉터리로 나가지 못한다"의 의미

이 문장은 hostPath의 잘못된 사용 방식을 설명하는 예시이거나,
혹은 마운트 경로를 readOnly로 사용했을 때 발생하는 현상을 말하는 것에 가깝다.

하지만 가장 정확한 해석은 아래야 👇


정확한 의미

호스트의 디렉터리를 Pod 내부(A 파드)에 마운트하면, 호스트에 이미 존재하는 내용은 Pod 안에서 보이지만,
Pod 내부에서 새로 생성한 파일이 호스트 디렉터리로 반영되지 않는 경우가 생긴다
는 뜻이다.

즉,

  • 호스트 → Pod 방향은 동기화됨
  • Pod → 호스트 방향은 동기화되지 않음

이 현상은 다음과 같은 상황에서 발생할 수 있어.


🧩 왜 이런 일이 생기는가? (발생 원인)

① readOnly 마운트일 때

volumeMounts:
  - name: host-volume
    mountPath: /data
    readOnly: true
  • 호스트의 /data는 Pod에서 보이지만
  • Pod에서 파일 생성해도 호스트에 쓰기(writing) 불가 → 생성 내용 반영 안 됨

② 컨테이너 이미지가 mountPath 경로에 이미 파일을 가지고 있을 때

예:

  • Pod에서 /var/log 를 호스트에 마운트했는데
  • 컨테이너 이미지 자체에도 /var/log 기본 디렉터리가 있음

→ 컨테이너의 rootfs 레이어가 hostPath 위에 오버레이(overlay) 로 덮어쓰면서
호스트로 데이터가 올라가지 못하는 문제가 발생할 수 있음


③ 권한 문제 (Permission denied)

  • Pod에서 쓰기 권한이 없는 host 디렉터리에 마운트 → 읽기만 됨
  • 쓰려고 하면 컨테이너 내부에 임시 레이어에 생성되어 호스트로 가지 않음

④ SELinux / AppArmor 등의 보안 정책

  • 쓰기 제한 때문에 외부 디렉터리에 반영되지 않음

🟦 핵심 요약

👉 hostPath를 단순히 외부 디렉터리처럼 생각하고 마운트하면,
Pod 내부에서 발생한 변경사항이 항상 외부로 반영되는 것은 아니며 사용 시 주의가 필요하다.

즉,

  • 외부 파일은 Pod가 볼 수 있음
  • Pod에서 만든 파일이 외부 저장소에 안 남는 경우가 있음

그래서 운영에서는 hostPath를 거의 안 씀
→ 커플링이 너무 강하고 예상 불가능한 동작 많음


profile
훌륭한 it 엔지니어 꿈나무

0개의 댓글