# 2. 네임스페이스, 컨피그맵, 시크릿, 인그레스

# namespace

  • 리소스들을 구분 지어 관리할 수 있는 논리적인 그룹 → namespace라는 오브젝트 제공
  • 쿠버네티스 리소스들이 묶여 있는 하나의 가상 공간 / 그룹
  • kubectl get namespaces, kubectl get ns 로 확인 가능
  • kubectl get pods --namespace default : --namespace or -n 옵션으로 특정 네임스페이스에 생성된 리소스 확인 가능
    • default는 기본적으로 쿠버네티스 리소스가 생성되는 네임스페이스

# namespace vs label

  • 라벨의 경우 kubectl get pods -l app=webserver 이런식으로 검색 가능
  • 네임스페이스는 라벨보다 더 넓은 용도로 사용 가능
    • 특정 네임스페이스에서 생성되는 포드의 자원 사용량 제한
    • 특정 네임스페이스에서 생성되는 포드에는 항상 사이드카 컨테이너가 붙도록 설정 가능
    • 사용 목적에 따라 리소스를 격리함으로써 편리하게 구분 가능

# 네임스페이스 생성

  1. yaml
apiVersion: v1
kind: Namespace
metadata:
  name: production
  1. 명령어
kubectl create namespace production
  • 특정 네임스페이스에 리소스 생성 시 yaml 파일에서 metadata.namespace를 설정하면 됨
apiVersion: v1
kind: Pod
metadata:
  name: my-nginx-pod
  namespace: production
spec:
  containers:
    - name: my-nginx-container
      image: nginx:latest
      ports:
        - containerPort: 80
          protocol: TCP

# 하나의 yaml 파일에서 여러 리소스 정의

  • ---를 사용하여 하나의 yaml 파일에서 여러 개의 리소스 정의 가능
apiVersion: v1
kind: Namespace
metadata:
  name: production

---
apiVersion: v1
kind: Pod
metadata:
  name: my-nginx-pod
  namespace: production
spec:
  containers:
    - name: my-nginx-container
      image: nginx:latest
      ports:
        - containerPort: 80
          protocol: TCP
  • kubectl get 명령어에 --all-namespaces 옵션을 사용하면 모든 네임스페이스의 리소스 확인 가능

# 네임스페이스 서비스 접근

  • 서비스 이름 만으로는 같은 네임스페이스 내의 서비스끼리만 접근 가능
  • <서비스 이름>.<네임스페이스 이름>.svc 로 다른 네임스페이스의 서비스에도 접근 가능

# 네임스페이스 삭제

  • kubectl delete -f <yaml 파일명>
  • kubectl delete namespace
  • 로 삭제 가능하지만 해당 네임스페이스에 존재하는 리소스도 모두 삭제되기 때문에 조심해야 함

# 네임스페이스에 종속되는 오브젝트

  • kubectl api-resources --namespaced=true로 네임스페이스에 속하는지 확인 가능
  • false로 설정하면 네임스페이스에 속하지 않는 오브젝트들 확인 가능
    • node, namespace, persistent volume 등

# Configmap, Secret

  • 애플리케이션의 설정값 지정하려면
  1. yaml 파일에 환경 변수 직접 적어놓기 → 상황에 따라서는 환경 변수 값만 다른 동일한 여러 개의 yaml이 존재할 수 있음
    • ex) 운영 / 개발 환경 분리
  2. Configmap, Secret 오브젝트 사용
    • 컨피그맵에는 설정값, 시크릿에는 비밀값 저장

# 컨피그맵

  • 일반적인 설정값 담아 저장
  • 네임스페이스에 속함

# 컨피그맵 생성

  1. yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-config
data:
  MYSQL_ROOT_PASSWORD: test123
  MYSQL_DATABASE: test
  1. 명령어 사용
  • kubectl create configmap <컨피그맵 이름> <각종 설정값들>
`kubectl create configmap mysql-config --from-literal MYSQL_ROOT_PASSWORD=test123 \
  --from-literal MYSQL_DATABASE=test`

# 컨피그맵 확인

dgh0001@rpi4b:~$ kubectl get cm
NAME                DATA   AGE
kube-root-ca.crt    1      34d
mysql-config        2      5s
prometheus-config   1      28d
web-config          9      29d

dgh0001@rpi4b:~$ kubectl describe cm mysql-config
Name:         mysql-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
MYSQL_DATABASE:
----
test

MYSQL_ROOT_PASSWORD:
----
test123


BinaryData
====

Events:  <none>

# 컨피그맵 값 가져오기

# 용도

  1. 컨피그맵의 값을 컨테이너의 환경 변수로 사용
  • 애플리케이션이 시스템 환경 변수로부터 설정값을 가져오는 경우
  • ex) LOG_LEVEL
apiVersion: v1
kind: Pod
metadata:
  name: mysql-container
spec:
  containers:
    - name: my-container
      image: mysql:8.0
      envFrom:
        - configMapRef:
            name: mysql-config

실행 결과

dgh0001@rpi4b:~$ kubectl exec -it mysql-container -- bash

bash-5.1# mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 8.0.43 MySQL Community Server - GPL

Copyright (c) 2000, 2025, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| test               |
+--------------------+
5 rows in set (0.00 sec)
  1. 컨피그맵의 값을 포드 내부의 파일로 마운트해 사용
  • 애플리케이션이 특정 파일을 통해 설정값을 읽어오는 경우
  • ex) nginx → nginx.conf를 통해 설정값을 읽어옴

# deploy-prometheus.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: prometheus
spec:
  replicas: 1
  selector:
    matchLabels:
      app: prometheus
  template:
    metadata:
      labels:
        app: prometheus
    spec:
      containers:
        - name: prometheus
          image: prom/prometheus
          args:
            - --config.file=/etc/prometheus/prometheus.yml
          ports:
            - containerPort: 9090
          resources:
            requests:
              cpu: "250m"
              memory: "256Mi"
            limits:
              cpu: "500m"
              memory: "512Mi"
          volumeMounts:
            - name: prometheus-config # volumes에서 정의한 컨피그맵 볼륨 이름
              mountPath: /etc/prometheus # 컨피그맵의 데이터가 위치할 경로
      volumes:
        - name: prometheus-config # 컨피그맵 볼륨 이름
          configMap:
            name: prometheus-config # 컨피그맵 이름

# config-prometheus.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-config
data:
  prometheus.yml: |
    global:
      scrape_interval: 5s
      evaluation_interval: 5s

    scrape_configs:
      - job_name: "spring-boot-app"
        metrics_path: "/actuator/prometheus"
        static_configs:
          - targets: [ "svc-clusterip:80" ]
  • 키:값 에 대해 파일명이 키, 파일 내용이 값으로 만들어짐
  • 원하는 특정 값만 가져올 수도 있음
        volumeMounts:
        - name: prometheus-config
          mountPath: /etc/prometheus
      volumes:
      - name: prometheus-config
        configMap:
          name: prometheus-config
          items:
          - key: prometheus.yml # prometheus.yml 라는 키에 대응하는 값 가져오기
            path: new-proemetheus.yml # 최종 파일 이름

# 파일로부터 컨피그맵 생성

  • --from-file 옵션 사용
  • 자동으로 파일명이 키, 파일 내용이 값이 되어 컨피그맵으로 생성됨
dgh0001@rpi4b:~$ echo helo world > index.html
dgh0001@rpi4b:~$ kubectl create configmap index-file --from-file index.html
configmap/index-file created
dgh0001@rpi4b:~$ kubectl describe configmap index-file
Name:         index-file
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
index.html:
----
helo world



BinaryData
====

Events:  <none>
  • --from-env-file 옵션으로 여러 개의 키-값 형태의 내용으로 구성된 설정파일을 한번에 컨피그맵으로 가져올 수 있음
dgh0001@rpi4b:~$ cat keyval
mykey1=myval1
mykey2=myval2
mykey3=myval3
dgh0001@rpi4b:~$ kubectl create configmap from-envfile --from-env-file keyval
configmap/from-envfile created
dgh0001@rpi4b:~$ kubectl get cm from-envfile -o yaml
apiVersion: v1
data:
  mykey1: myval1
  mykey2: myval2
  mykey3: myval3
kind: ConfigMap
metadata:
  creationTimestamp: "2025-10-22T02:49:37Z"
  name: from-envfile
  namespace: default
  resourceVersion: "1265915"
  uid: dc388e38-603e-45fd-9897-4be2ea1ef9b8

# 쉽게 컨피그맵 yaml 정의하기

  • --dry-run 과 -o yaml 옵션으로 쉽게 yaml 생성 가능
dgh0001@rpi4b:~$ kubectl create configmap easy-configmap \
> --from-literal mykey=myval --dry-run=client -o yaml
apiVersion: v1
data:
  mykey: myval
kind: ConfigMap
metadata:
  name: easy-configmap

# dry run

  • 특정 작업의 실행 가능 여부 확인
  • --dry-run=client 옵션으로 실행 가능 여부를 확인할 수 있으며 실제로 리소스를 생성하진 않음

# 시크릿

  • ssh 키, 비밀번호 등과 같은 민감한 정보를 저장하기 위한 용도
  • 네임스페이스에 종속
  • 컨피그맵처럼 --from-literal, --from-file, --from-env-file 옵션으로 생성 가능
dgh0001@rpi4b:~$ kubectl create secret generic \
> my-password --from-literal password=1q2w3e4r
secret/my-password created

dgh0001@rpi4b:~$ kubectl describe secret my-password
Name:         my-password
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
password:  8 bytes

dgh0001@rpi4b:~$ kubectl get secret my-password -o yaml
apiVersion: v1
data:
  password: MXEydzNlNHI=
kind: Secret
metadata:
  creationTimestamp: "2025-10-22T03:31:17Z"
  name: my-password
  namespace: default
  resourceVersion: "1267015"
  uid: 362d7fc4-8400-486a-8914-5f6e1463f6fe
type: Opaque
  • 시크릿에 값 저장 시 쿠버네티스가 기본적으로 base64로 값 인코딩
dgh0001@rpi4b:~$ echo MXEydzNlNHI= | base64 -d
1q2w3e4r
  • 디코딩하면 원래 값 나오는 모습

# 사용 방법

...
spec:
  containers:
    envFrom:
    - secretRef:
        name: my-password

---

      env:
    - name: PASSWORD
      valueFrom:
        secretKeyRef:
          name: my-password
          key: password

---

      volumeMounts:
      - name: secret-volume
        mountPath: /etc/config
  volumes:
  - name: secret-volume
    secret:
      secretName: my-password

---

      volumeMounts:
      - name: secret-volume
        mountPath: /etc/config
  volumes:
  - name: secret-volume
    secret:
      secretName: my-password # 시크릿 이름
      items: # 시크릿에서 가져올 키-값 목록
      - key: password # 키
        path: new-password # 최종 파일은 /etc/config/new-password 가 됨

# 시크릿 종류

  1. Opaque
  • 별도로 종류를 명시하지 않으면 자동으로 설정되는 타입
dgh0001@rpi4b:~$ kubectl create secret generic \
> my-password --from-literal password=1q2w3e4r
secret/my-password created
  • 여기서 사용한 generic이 Opaque 타입
  1. docker-registry
  • 프라이빗 레지스트리 접근 시 사용
  • ex) 사설 레지스트리, 도커 허브, GCR, ECR 등을 사용하는 경우
  1. tls
  • tls 연결에 사용되는 공개키, 비밀키 등을 쿠버네티스에 자체적으로 저장 가능
dgh0001@rpi4b:~$ openssl req -new -newkey rsa:4096 -days 365 -nodes \
> -x509 -subj "/CN=example.com" -keyout cert.key -out cert.crt
...

dgh0001@rpi4b:~$ ls cert.*
cert.crt  cert.key

dgh0001@rpi4b:~$ kubectl create secret tls my-tls-secret \
> --cert cert.crt --key cert.key
secret/my-tls-secret created
dgh0001@rpi4b:~$ kubectl get secrets my-tls-secret -o yaml
apiVersion: v1
data:
  tls.crt: LS0tLS1CRUdJ...
  tls.key: LS0tLS1CRUdJ...
kind: Secret
metadata:
  creationTimestamp: "2025-10-22T03:49:23Z"
  name: my-tls-secret
  namespace: default
  resourceVersion: "1267502"
  uid: b0fa1bfa-3faf-4ad0-8cbb-8ff78c3dad27
type: kubernetes.io/tls
dgh0001@rpi4b:~$

# Ingress

  • 외부에서 오는 요청을 어떻게 처리할 것인지 네트워크 7계층 레벨(응용 계층)에서 정의하는 쿠버네티스 오브젝트
  • 외부 요청 라우팅, 가상 호스트 기반 요청 처리, ssl/tls 보안 연결 처리 등에 사용

# 인그레스 사용하는 이유

  • 디플로이먼트에 레플리카 3개 두고 nodePort로 외부 노출하는 경우 → 3개 포드 일일히 다 ssl/tls 보안 설정 해줘야 함
  • 인그레스 사용하면 앞단에 인그레스 오브젝트 하나 두고 한번만 보안 설정해주면 됨
  • 즉, 하나의 설정 지점에서만 처리 규칙을 정의해주면 됨

# 인그레스 생성

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-knuchat-bot
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true" # http 요청을 자동으로 https로 리다이렉트
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - knu-chatbot.o-r.kr
      secretName: knu-chatbot-tls
  rules:
    - host: knu-chatbot.o-r.kr
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: svc-clusterip
                port:
                  number: 80

# Ingress Controller

  • 실제 외부 요청을 받아들이는 인그레스 컨트롤러에 인그레스 규칙을 로드해 사용 가능
  • 근데 인그레스 컨트롤러를 설치해도 nginx 웹 서버를 외부로 노출하기 위한 서비스를 생성해주지는 않음
  • 정리하자면 인그레스 컨트롤러 설치 + 인그레스 규칙 정의 + 인그레스 컨트롤러를 외부로 노출하기 위한 서비스 생성
apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
spec:
  type: NodePort
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
  ports:
    - name: http
      port: 80
      targetPort: http
      nodePort: 32080
    - name: https
      port: 443
      targetPort: https
      nodePort: 32443

# 인그레스 세부 기능 - annotation

  • 위에서 사용한 nginx.ingress.kubernetes.io/ssl-redirect 옵션처럼 annotation을 사용하여 다양한 옵션 적용 가능
  • ex
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-knuchat-bot
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true" # http 요청을 자동으로 https로 리다이렉트
    nginx.ingress.kubernetes.io/rewrite-target: / # /test 경로로 들어온 요청은 /로 전달
      paths:
      - path: /test
    kubernetes.io/ingress.class: "nginx" # 해당 인그레스 규칙을 어떤 인그레스 컨트롤러에 적용할 것인지