Docker

쿠버네티스 리소스의 관리와 설정 (네임스페이스, 컨피그맵, 시크릿)

쿠와와 2021. 1. 31. 19:00

이번 장에서는 네임스페이스, 컨피그맵, 시크릿의 사용 방법을 알아보겠다. 

 

네임스페이스

쿠버네티스는 리소스를 존리적으로 구분하기 위해 네임스페이스라는 오브젝트를 제공한다. (포드, 페플리카셋, 디플로이먼트, 서비스 등과 같은 쿠버네티스 리소스들이 묶여 있는 하나의 가상 공간 또는 그룹이라고 이해하자.)

 

보통 namespace를 ns라고 줄려서 사용 가능하다. 

# default에 존재하는 포드를 확인하려면 이때 --namespace 대신 -n 사용가능
kubectl get pods --namespace default
kubectl get pods -n kube-system

default 는 우리가 쿠버네티스를 성치하면 자동으로 사용하도록 설정되는 네임스페이스로 kubectl 명령어로 쿠버네티스 리소스를 사용할 때 기본적으로 default 네임스페이스를 사용한다. 즉 --namespace 옵션을 명시하지 않으면 기본적으로 default 네임스페이스를 사용하는 것이다. 

kube-system은 쿠버네티스 클러스터 구성에 필수적인 컴포넌트들과 설정값 등이 존재하는 네임스페이스이다. default 네임스페이스와는 논리적으로 구분돼 있다. 

 

각 네임스페이스의 리소스들은 논리적으로만 구분된 것이지, 물리적으로 격리된 것은 아니다. 즉 서로 다른 네임스페이스의 포드가 같은 노드에 존재할 수도 있다는 것이다. 

namespace와 label의 차이점
네임스페이스는 라벨처럼 리소스를 분류하고 구분하는 것 뿐만 아니라 더욱 넓은 용도로 사용할 수 있다. 
특정 네임스페이스에서 생성되는 포드의 자원 사용량을 제한, 애드미션 컨트롤러를 이용해 특정 네임스페이스에 생성되는 포드에 항상 사이트카 컨테이너를 붙이도록 설정할 수 있다. 

 

YAML을 이용해 정의해보자

production-namespace.yaml

apiVersion: v1
kind: Namespace
metadata:
  name: production

 

# 생성 명령어
kubectl apply -f production-namespace.yaml 
kubectl create namespace production

둘 중에 하나를 사용하자

# 삭제 명령어
kubectl delete namespace production
kubectl delete -f <YAML 파일명>

 

이제 이 특정 네임스페이스에 리소스를 생성해보자. YAML에 metadata.namespace 항목을 설정해주면 된다. 

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hostname-deployment-ns
  namespace: production
spec:
  replicas: 1
  selector:
    matchLabels:
      app: webserver
  template:
    metadata:
      name: my-webserver
      labels:
        app: webserver
    spec:
      containers:
      - name: my-webserver
        image: alicek106/rr-test:echo-hostname
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: hostname-svc-clusterip-ns
  namespace: production
spec:
  ports:
    - name: web-port
      port: 8080
      targetPort: 80
  selector:
    app: webserver
  type: ClusterIP

 

kubectl get pods, services -n production 명령어를 사용해서 확인해보자 

kubectl get 명령어에 --all-namespaces 옵션을 사용하면 모든 네임스페이스의 리소스를 확인할 수 있다.
kubectl get pods --all-namespaces

 

서비스 오브젝트를 설명할 때, 쿠버네티스 클러스터 내부에는 서비스 이름을 통해 포드에 접근할 수 있다고 설명했었다. 이는 정확히 말하자면  같은 네임스페이스 내의 서비스에 접근할 때에는 서비스 이름만으로 접근할 수 있다는 뜻이다. 다르게 말하면 같은 네임스페이스가 아니라면 이름만으로 접근할 수 없다는 뜻이다. 

 

<서비스 이름>.<네임스페이스 이름>.svc 처럼 서비스 이름 뒤에 네임스페이스 이름을 붙이면 다른 네임스페이스의 서비스에도 접근할 수 있다. 

ex. curl <서비스 이름>.<네임스페이스 이름>.svc:8080 --silent | grep hello

서비스의 DNS 이름에 대한 FQDN은 일반적으로 다름과 같은 형식으로 구성돼 있다. 

<서비스 이름>.<네임스페이스 이름>.svc.cluster.local

 

 

네임스페이스에 종속되는 쿠버네티스 오브젝트와 독립적인 오브젝트 

A라는 네임스페이스에서 포드를 만들면 B 네임스페이스에서는 보이지 않을 것이다. 이런 경우 '오브젝트가 네임스페이스에 속한다.' 라고 표현한다.

# 네임스페이스에 속하는 오브젝트의 종류는 다음 명령어로 확인할 수 있다.
kubecrl api-resources --namespaced=true

 

이와 반대로 네임스페이스에 속하지 않는 오브젝트도 있다. 노드(nodes) 또한 쿠버네티스의 오브젝트 중 하나이지만, 네임스페이스에 속하지 않는 대표적인 오브젝트 중 하나이다. 

노드처럼 네임스페이스에 속하지 않는 오브젝트들은 보통 네임스페이스에서 관리되지 않아야 하는, 클러스터 전반에 걸쳐 사용되는 경우가 많다.

# 네임스페이스에 속하지 않는 오브젝트의 종류는 다음 명령어로 확인 할 수 있다. 
kubectl api-resources --namespaced=false

 

당장은 어떤 오브젝트가 네임스페이스에 속했는지 알 필요는 없다. 내부분의 오브젝트가 네임스페이스에 속해 있을 것이다. 하지만 클러스터의 관리를 위한 저수준의 오브젝트들이 네임스페이스에 없을 수도 있다는 것을 알아두자.

 

컨피그맵, 시크릿 : 설정값을 포드에 전달

우리가 개발한 애플리케이션에는 설정값이 있을 것이다. 이러한 설정값은 도커 이미지 내부에 설정값 또는 설정 파일을 정적으로 저장해 놓는 것이 좋다. 하지만 도커는 이 설정값을 유연하게 변경할 수 없다. 

 

이에 대한 대안으로 포드를 정의하는 YAML 파일에 환경 변수를 직접 적어 놓는 하드 코딩 방식을 사용할 수 있다. 이러한 환경 변수를 템플릿에 직접 명시하는 방식도 나쁘지는 않지만, 상황에 따라서는 환경 변수의 값만 다른, 동일한 여러 개의 YAML이 존재할 수도 있다. 

 

쿠버네티스는 YAML 파일과 설정값을 분리할 수 있는 컨피그맵과 시크릿이라는 오브젝트를 제공한다. 

컨피그맵 : 설정값을 담아 저장

시크릿 : 노출되서는 안되는 비밀 값 저장

 

컨피그맵

# 생성 방법 
kebectl create configmap <컨피그맵 이름> <각종 설정값들>
#ex
kebectl create configmap log-level-configmap --from-literal LOG_LEVEL=DEBUG --from-literal container=docker
# --from-literal를 여러번 사용해서 여러 개의 키-값을 컨피그맵에서 사용하도록 설정 가능 
kubectl get cm 		# configmap = cm도 가능

# 저장된 설정 값 확인 아래의 두 명령어 중 아무거나 사용
kubectl describe configmap log-level-configmap
kubectl get configmap log-level-configmap -o yaml

 

이제는 컨피그맵을 포드에서 사용해보자. 그 방법은 2가지가 있다.

1. 컨피그맵의 값을 컨테이너의 환경변수로 사용

1. all-env-from-configmap.yaml

apiVersion: v1
kind: Pod
metadata:
  name: container-env-example
spec:
  containers:
    - name: my-container
      image: busybox
      args: ['tail', '-f', '/dev/null']
      envFrom:		# 이 부분부터 중요 
      - configMapRef:
          name: log-level-configmap
      - configMapRef:
          name: start-k8s

 

이때 하나의 컨피그맵에서 여러개의 키-값 쌍이 존재하더라도 모두 환경 변수로 가져오도록 설정 

# 생성
kubectl apply -f all-env-from-configmap.yaml

# 환경 변수 출력 명령어
kubectl exec container-env-example env

 

2. selective-env-from-configmap.yaml

apiVersion: v1
kind: Pod
metadata:
  name: container-selective-env-example
spec:
  containers:
    - name: my-container
      image: busybox
      args: ['tail', '-f', '/dev/null']
      env:
      - name: ENV_KEYNAME_1     # (1.1) 컨테이너에 새롭게 등록될 환경 변수 이름
        valueFrom: 
          configMapKeyRef:
            name: log-level-configmap
            key: LOG_LEVEL
      - name: ENV_KEYNAME_2  # (1.2) 컨테이너에 새롭게 등록될 환경 변수 이름
        valueFrom: 
          configMapKeyRef:
            name: start-k8s      # (2) 참조할 컨피그맵의 이름
            key: k8s             # (3) 가져올 데이터 값의 키
                                 # 최종 결과 -> ENV_KEYNAME_2=$(k8s 키에 해당하는 값)
                                 #              ENV_KEYNAME_2=kubernetes

[1] 포드의 컨테이너에서 새롭게 설정될 환경 변수의 이름

[2] 어떠한 컨피그 맵으로부터 값을 가져올 것인지 입력

[3] 해당 컨피그맵의 키-값 데이터중, 어떠한 키의 값을 가져올 것인지 명시

 

2. 컨피그맵의 값을 포드 내부의 파일로 마운트해 사용

volume-mount-configmap.yaml

apiVersion: v1
kind: Pod
metadata:
  name: configmap-volume-pod
spec:
  containers:
    - name: my-container
      image: busybox
      args: [ "tail", "-f", "/dev/null" ]
      volumeMounts:
      - name: configmap-volume          # volumes에서 정의한 컨피그맵 볼륨 이름 
        mountPath: /etc/config             # 컨피그맵의 데이터가 위치할 경로

  volumes:
    - name: configmap-volume            # 컨피그맵 볼륨 이름
      configMap:
        name: start-k8s

spec.volumes : YAML 파일에서 사용할 볼륨의 목록을 정의

spec.containers.volumeMounts : volumes 항목에서 정의된 볼륨을 컨테이너 내부의 어떤 디렉터리에 마운트할 것인지 명시 

 

컨피그맵에 저장돼 있던 키-쌍 데이터가 마운트된다. 

이때 모든 키-쌍 데이터를 포드에 마운트하는 것이 아닌, 원하는 키-쌍 데이터만 선택해서 포드에 파일로 가져올 수 도 있다. 

apiVersion: v1
kind: Pod
metadata:
  name: selective-cm-volume-pod 
spec:
  containers:
    - name: my-container
      image: busybox
      args: [ "tail", "-f", "/dev/null" ]
      volumeMounts:
      - name: configmap-volume
        mountPath: /etc/config       # 마운트되는 위치는 변경되지 않았습니다.
  volumes:
    - name: configmap-volume
      configMap:
        name: start-k8s
        items:                       # 컨피그맵에서 가져올 키-값의 목록을 나열합니다.
        - key: k8s                    # k8s라는 키에 대응하는 값을 가져옵니다.
          path: k8s_fullname         # 최종 파일 이름은 k8s_fullname이 됩니다

 

 

위의 YAMl 파일과 비교했을 때 volumes 항목이 약간 달라졌다. 

- items 항목 : 컨피그맵에서 가져올 키-값의 목록을 의미하며, k8s라는 키만 가져오도록 명시

- path 항목 : 최종적으로 디렉터리에 위치할 파일의 이름을 입력하는 항목, k8s_fullname이라는 값을 입력했다.

 

파일로부터 컨피그맵 생성하기

컨피그맵을 볼륨으로 포드에 제공할 때는 대부분 설정 파일 그 자체를 컨피그맵으로 사용하는 경우가 많다. 이러한 경우를 위해 쿠버네티스는 컨피그맵을 파일로부터 생성하는 기능 또한 제공한다. 

kubectl create configmap <컨피그맵 이름> --from-file <파일 이름>
# 이 때 별도의 키를 지정하지 않으면 파일 이름이 키로, 파일의 내용이 값으로 저장된다. 

파일 내용에 해당되는 키의 이름을 직접 정할 수도 있다. 
# ex
kubectl create configmap <컨피그맵 이름> --from-file myindex=<파일 이름>

여러 개의 키-값 형태의 내용으로 구성된 설정 파일을 한꺼번에 컨피그맵으로 가져올 수도 있다.
--from-env-file을 사용해서 

 

YAML 파일로 컨피그맵 정의하기 

컨피그맵은 위의 방법처럼 반드시 명령어를 통해 생성해야 하는 것은 아니다. kubectl create 명령어에서

--dry-run
-o yaml 

옵션을 사용하면 컨피그맵을 생성하지 않은 채로 YAML 파일의 내용을 출력할 수 있다. 

이러면 출력된 내용을 YAML 파일로 사용하면서 컨피그맵 또한 YAML파일로 배포해 사용할 수 있다. 

 

1.

ex
kubectl create configmap my-configmap --from-literal mykey=myvalue --dry-run -o yaml

2. 

출력된 내용을 YAMl파일로 저장한 뒤, kubectl apply명령어로 컨피그맵을 생성하면 된다. 

출력된 내용 YAML파일로 생성

그후 
kubectl apply -f my-configmap.yaml

이 방법의 단점은 키-값 데이터가 너무 많아지면 YAML 파일의 길이가 너무 길어진다는 것이다. 이럴 때 kubectl 명령어 1.14버전부터 사용할 수 있는 kustomize 기능을 사용하면 더욱 편하게 생성할 수 있다. 

 

시크릿

시크릿은 SSH 키, 비밀번호 등과 같이 민감한 정보를 저장하기 위한 용도로 사용되며, 네임스페이스에 종속되는 오브젝트이다.

시크릿과 컨피그맵은 사용 방법이 매우 비슷하다. 다만 시크릿은 민감한 정보를 저장하기 위해 컨피그맵보다 좀 더 세분화된 사용 방법을 제공한다. 

 

다음 명령어는 my-password 라는 시크릿을 생성하며, password=1q2w3e4r 이라는 key-value를 저장

kubectl create secret generic \
my-password --from-literal password=1q2w3e4r

또는 --from-literal 대신 --from-file 이나 --from-env-file 옵션을 이용해 파일로부터 값을 읽어 올수도 있다.

echo mypassword > pw1 && echo yourpassword > pw2
kubectl create secret generic \
our-password --form-file pw1 --from-file pw2


생성된 시크릿 확인
kubectl get secrets
kubectl describe secret my-password
kubectl get secret my-password -o yaml

generic -> 시크릿은 컨피그맵과 달리 데이터의 사용 목적에 따라 몇 가지 종류로 나뉘기 때문

 

생성된 시크릿을 확인해보면 키-값 쌍에서 값에 해당하는 부분이 이상한 값으로 변형돼 있는 것을 확인할 수 있다. (이것은 base64로 인코딩한 값이다. 


이렇게 생성된 시크릿은 컨피그맵과 비슷하게 사용할 수도 있다. 환경 변수로 사용할 수 있고, 특정 경로의 파일로 포드 내에 마운트할 수도 있다. 

env-from-secret.yaml

apiVersion: v1
kind: Pod
metadata:
  name: secret-env-example
spec:
  containers:
    - name: my-container
      image: busybox
      args: ['tail', '-f', '/dev/null']
      envFrom:
      - secretRef:
          name: my-password

selective-env-from-secret.yaml

apiVersion: v1
kind: Pod
metadata:
  name: selective-secret-env-example
spec:
  containers:
  - name: my-container
    image: busybox
    args: ['tail', '-f', '/dev/null']
    env:
    - name: YOUR_PASSWORD
      valueFrom:
        secretKeyRef:
          name: our-password
          key: pw2

 

위의 코드를 보면 secretRef name

밑에 코드에서 valueFrom secretKeyRef key

같이 정의하여 사용 가능하다. 

 

또는 시크릿의 키-값 데이터를 파일로 포드의 볼륨에 마운트하거나 선택해서 사용할 수 있다. 

apiVersion: v1
kind: Pod
metadata:
  name: secret-volume-pod
spec:
  containers:
    - name: my-container
      image: busybox
      args: [ "tail", "-f", "/dev/null" ]
      volumeMounts:
      - name: secret-volume          #  volumes에서 정의한 시크릿 볼륨 이름
        mountPath: /etc/secret             # 시크릿의 데이터가 위치할 경로
  volumes:
  - name: secret-volume            # 시크릿 볼륨 이름
    secret:
      secretName: our-password                  # 키-값 쌍을 가져올 컨피그맵 이름
apiVersion: v1
kind: Pod
metadata:
  name: selective-volume-pod
spec:
  containers:
  - name: my-container
    image: busybox
    args: [ "tail", "-f", "/dev/null" ]
    volumeMounts:
    - name: secret-volume
      mountPath: /etc/secret
  volumes:
  - name: secret-volume
    secret:
      secretName: our-password          # our-password 라는 시크릿을 사용
      items:                       # 시크릿에서 가져올 키-값의 목록
      - key: pw1                    # pw1라는 키에 대응하는 값이 사용됨.
        path: password1           # 최종 파일은 /etc/config/password1이 됨

 

단, 시크릿을 생성할 때 YAML 파일에 base64로 인코딩한 값을 입력했더라도 시크릿을 포드의 환경 변수나 볼륨 파일로써 가져오면 base64로 디코딩된 원래의 값을 사용하게 된다. 

 

이미지 레지스트리 접근을 위한 docker-registry타입의 시크릿 

시크릿은 컨피그맵처럼 단순 문자열이나 설정 파일 등을 저장할 때 사용할 수도 있지만, 사용 목적에 따라 여러 종류의 시크릿을 사용할 수 있다. 

 

지금까지 우리가 생성해봤던 시크릿의 타입은 모두 Opaque이다. 

Opaque = 사용자가 별도의 시크릿 종류를 명시하지 않으면 자동으로 설정되는 타입, 사용자가 정의하는 데이터를 저장할 수 있는 일반적인 목적의 시크릿이다. 

 

쿠버네티스에서는 docker login 명령어 대신 레지스트리의 인증 정보를 저장하는 별도의 시크릿을 생성해 사용한다. 

1. docker login 명령어로 로그인을 성공했을 때 도커 엔진이 자동으로 생성하는 ~/.docker/config.json 파일 사용하는 방법 
kubectl create secret generic registry-auth \
--from-file=.dockerconfigjson=/root/.docker/config.json \
--type=kubenetes.io/dockerconfigjson

2. 시크릿을 생성하는 명령어에서 직접 로그인 인증 정보를 명시 
kubectl create secret docker-registry registry-auth-by-cmd \
--docker-username=alicek106 \
--dcoker-password=1q2w3e4r

 

--docker-server 은 필수는 아니며 사용하지 않으면 기본적으로 docker.io를 사용하도록 설정된다. (사설에서 사용할때 쓰자)

kubectl create secret docker-registry registry-auth-by-cmd \
--docker-username=alicek106 \
--dcoker-password=1q2w3e4r \
--docker-server=alick106.registry.com

이 같이 설정하면 생성된 시크릿은 kubernetes.io/<사설 레지스트리 이미지>의 타입이 된다. 

 

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-from-prvate-repo
spec:
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      name: mypod
      labels:
        app: myapp
    spec:
      containers:
      - name: test-container
        image: alicek106.ipdisk.co.kr/busybox:latest
        args: ['tail', '-f', '/dev/null']
      imagePullSecrets:
      - name: registry-auth-registry

사용법은 imagePulSecrets: 에 항목을 정의해서 사용하면 된다. 

 

TLS 키를 저장할 수 있는 tls 타입 시크릿 

시크릿은 tls 연결에 사용되는 공개키, 비밀키 등을 자체적으로 저장할 수 있도록 tls 타입을 지원한다. 

보안 연결에 사용되는 키 페이거 미리 준비돼 있다면 

kubectl create secret tls <생성될 키 이름>명령어로 쉽게 생성가능

 

 

kustomize 기능 사용해보기

YAML 파일 작성할 때 데이터를 분리할 수 있는 기능으로 kubectl 명령어 1.14 버전부터 사용가능 

시크릿과 컨피그맵을 좀 더 쉽게 쓰지위한 용도이다. 

 

kustomization.yaml

secretGenerator:                # 시크릿을 생성하기 위한 지시문
- name: kustomize-secret
  type: kubernetes.io/tls       # tls 타입의 시크릿을 생성 
  files:
  - tls.crt=cert.crt            # tls.crt 라는 키에 cert.crt 파일의 내용을 저장
  - tls.key=cert.key            # tls.key 라는 키에 cert.key 파일의 내용을 저장

 

 

생성하기 전에 미리 정보를 확인하려면
kubectl kustomize 

작성한 파일로부터 시크릿을 생성하려면 해당 파일이 위치한 곳에서 
kubectl apply -k ./ 명령어 사용 

또한 컨피그맵을 생성하고 싶으면 
secretGenerator 대신 configmapGenerator 사용하기 

 

kustomize로부터 생성된 컨피그맵이나 시크릿 이름 뒤에는 저장된 데이터로부터 추출된 해시값이 자동으로 추가됨 kubectl 명령어를 사용할 때도 --append-hasj 옵션을 사용해 리소스의 이름 뒤에 해시값을 추가할 수 있다. 

 

 

컨피그맵이나 시크릿 업데이트로 인한 설정값 변경

1. kubectl edit 명령어로 수정
2. YAML 파일을 변경한 뒤 다시 kubectl apply 명령어 사용
3. kubectl patch 명령어 사용 

 

 

리소스 정리 

kubectl delete deplyment --all
kubectl delete pod --all
kubectl delete configmap --all
kubectl delete secret --all