버전 비교

  • 이 줄이 추가되었습니다.
  • 이 줄이 삭제되었습니다.
  • 서식이 변경되었습니다.
목차

...

2. Resource Policies

2.1 Request / Limit (최소요구사항/최대 사용량)

  • 쿠버네티스에서 파드를 어느 노드에 배포할지 스케쥴링 할 때, 스케쥴링이 될 노드에 해당 파드가 동작할 수 있는 충분한 자원이 확보가 되어야 합니다.

  • 쿠버네티스에서 파드(컨테이너)에 필요한 리소스 양을 명시 할 수 있도록 설정을 지원합니다.

  • cpu/memory와 같은 컴퓨트 리소스 외에도 gpu/storage 리소스에 대한 쿼터도 지정 할 수 있습니다.

  • CPU는 m(밀리코어, 1코어=1000밀리코어) 단위로 지정하며, 해당 컨테이너에 어느정도의 CPU를 할당할 것인지를 지정합니다.

  • 메모리는 Mi(Mib)를 사용합니다.

코드 블럭
---
apiVersion: v1
kind: Pod
metadata:
  name: frontend
spec:
  containers:
  - name: app
    image: images.my-company.example/app:v4
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"
  - name: log-aggregator
    image: images.my-company.example/log-aggregator:v6
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"

metrics-server를 이용한 노드 별 리소스 모니터링

코드 블럭
root@k8s-master01:~# kubectl top nodes | sort -n -k 2
NAME           CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
k8s-worker02   114m         1%     4030Mi          25%
k8s-worker01   176m         2%     3196Mi          20%
k8s-master03   279m         3%     4727Mi          29%
k8s-master02   347m         4%     4144Mi          26%
k8s-master01   414m         5%     4557Mi          28%

metrics-server를 이용한 파드 별 리소스 모니터링

코드 블럭
root@k8s-master01:~# kubectl -n kube-system top pod | sort -n -k 2
NAME                                       CPU(cores)   MEMORY(bytes)
nginx-proxy-k8s-worker01                   1m           16Mi
nginx-proxy-k8s-worker02                   1m           17Mi
dns-autoscaler-59b8867c86-hjkvs            2m           7Mi
kube-controller-manager-k8s-master02       4m           19Mi
kube-controller-manager-k8s-master03       4m           19Mi
nodelocaldns-rdkbl                         4m           15Mi
coredns-588bb58b94-9qcvw                   5m           16Mi
kube-scheduler-k8s-master02                5m           20Mi
nodelocaldns-sd99v                         5m           10Mi
coredns-588bb58b94-zcnvc                   6m           14Mi
kube-proxy-h584h                           7m           22Mi
kube-scheduler-k8s-master03                7m           19Mi
nodelocaldns-9vlvr                         7m           9Mi
nodelocaldns-b8gpm                         7m           9Mi
metrics-server-6f77f96b88-v5jjs            8m           17Mi
nodelocaldns-r4sjf                         8m           16Mi
kube-scheduler-k8s-master01                9m           21Mi
kube-proxy-x8gcq                           12m          22Mi
calico-kube-controllers-75748cc9fd-gqdzw   13m          21Mi
kube-proxy-w87v4                           13m          15Mi
kube-proxy-96tsm                           20m          15Mi
kube-proxy-tj8pv                           24m          14Mi
kube-controller-manager-k8s-master01       36m          52Mi
calico-node-87g22                          42m          85Mi
calico-node-kk5vn                          51m          84Mi
calico-node-wckv7                          51m          85Mi
calico-node-8278d                          64m          91Mi
etcd-k8s-master02                          70m          89Mi
calico-node-4hzx4                          71m          109Mi
kube-apiserver-k8s-master02                77m          303Mi
etcd-k8s-master03                          81m          84Mi
kube-apiserver-k8s-master01                94m          349Mi
etcd-k8s-master01                          99m          95Mi
kube-apiserver-k8s-master03                111m         310Mi

2.2 ResourceQuota

  • 쿠버네티스 운영 시 특정 팀에서 많은 리소스를 요구할 경우 ResourceQuota를 이용하여 네임스페이스별로 사용할 수 있는 리소스의 양을 정하고, 컨테이너 마다 사용 할 수 있는 양을 지정할 수 있습니다.

Resource Name

Description

limits.cpu

Across all pods in a non-terminal state, the sum of CPU limits cannot exceed this value.

limits.memory

Across all pods in a non-terminal state, the sum of memory limits cannot exceed this value.

requests.cpu

Across all pods in a non-terminal state, the sum of CPU requests cannot exceed this value.

requests.memory

Across all pods in a non-terminal state, the sum of memory requests cannot exceed this value.

hugepages-<size>

Across all pods in a non-terminal state, the number of huge page requests of the specified size cannot exceed this value.

cpu

Same as requests.cpu

memory

Same as requests.memory

  • 쿼터 오브젝트를 생성하여 특정 우선 순위의 파드와 일치 시키며, "low(낮음)", "medium(중간)", "high(높음)"의 세 가지 우선 순위 클래스 중 하나를 가질 수도 있습니다.

코드 블럭
# quota-test.yaml
---
apiVersion: v1
kind: ResourceQuota
metadata:
  name: default
spec:
  hard:
    cpu: "1000"
    memory: 200Gi
    pods: "10"
#  scopeSelector:
#    matchExpressions:
#    - operator : In
#      scopeName: PriorityClass
#      values: ["high"]

코드 블럭
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.19
        ports:
        - containerPort: 80
        resources:
          requests:
            memory: "64Mi"
            cpu: "250m"
          limits:
            memory: "128Mi"
            cpu: "500m"

코드 블럭
root@k8s-master01:~# kubectl get pod
NAME                               READY   STATUS    RESTARTS   AGE
nginx-deployment-5bccc488d-bqkvz   1/1     Running   0          18h
nginx-deployment-5bccc488d-r4s5d   1/1     Running   0          18h
nginx-deployment-5bccc488d-z29wp   1/1     Running   0          18h

root@k8s-master01:~# kubectl get quota
NAME      AGE   REQUEST                                         LIMIT
default   32s   cpu: 750m/1k, memory: 192Mi/200Gi, pods: 3/10

2.3 LimitRange

  • ResourceQuota를 사용하면 네임스페이스의 리소스를 제한하고, LimitRange는 네임스페이스 내 파드(컨테이너)의 리소스를 제한합니다.

  • 사용자가 컨테이너 리소스를 너무 크게 사용하면 특정 컨테이너가 많은 리소스를 점유하는 것을 방지할 수 있기 때문에 LimitRange를 사용합니다.

코드 블럭
root@k8s-master01:~# cat LimitRange.yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: cpu-min-max-demo-lr
  namespace: default
spec:
  limits:
  - max:
      cpu: "800m"
    min:
      cpu: "200m"
    type: Pod #Container

코드 블럭
root@k8s-master01:~# cat LimitRange.yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: cpu-min-max-demo-lr
  namespace: default
spec:
  limits:
  - max:
      cpu: "800m"
    min:
      cpu: "200m"
    type: Pod #Container
root@k8s-master01:~# more nginx-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.19
        ports:
        - containerPort: 80
        resources:
          requests:
            memory: "64Mi"
            cpu: "1000m"
          limits:
            memory: "128Mi"
            cpu: "1500m"

경고

root@k8s-master01:~# kubectl get event --sort-by='lastTimestamp'
LAST SEEN TYPE REASON OBJECT MESSAGE
78s Warning FailedCreate replicaset/nginx-deployment-8579d7f98c Error creating: pods "nginx-deployment-8579d7f98c-mxw8q" is forbidden: maximum cpu usage per Pod is 800m, but limit is 1500m

...

2. Label & Selector

  • Label

    • Label은 Pod와 같은 객체에 연결된 키/값 쌍입니다.

    • 리소스를 논리적인 그룹으로 나누거나, 식별의 편의를 위해 붙이는 이름표입니다.

    • Label은 생성 시 객체에 첨부할 수 있으며 나중에 언제든지 추가 및 수정할 수 있습니다.

  • Selector

    • 특정 Label에 해당하는 객체를 식별하고 검색할 수 있습니다.

2.1 Node Label

...

코드 블럭
# Node Label 확인
kubectl get nodes --show-labels

# Node Label 추가
kubectl label nodes k8s-worker01 svc=web

2.2 Pod Selector

pod-label.yml

코드 블럭
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  nodeSelector:
    svc: web

...

3. 쿠버네티스 볼륨

  • PV(PersistentVolume): PV는 관리자가 프로비저닝했거나 스토리지 클래스를 사용해 동적으로 프로비저닝한 클러스터의 스토리지입니다. PV는 볼륨과 같은 볼륨 플러그인이지만 PV를 사용하는 개별 Pod와 독립적인 수명 주기를 가집니다.

  • PVC(PersistentVolumeClaim): PVC는 사용자가 볼륨을 사용하기 위해 PV에 하는 스토리지 요청입니다. Pod와 유사하게 Pod는 노드 리소스를 소비하고, PVC는 PV 리소스를 소비합니다.

3.1 PV의 Lifecycle

...

3.1.1 Provisioning

PV를 생성하는 단계로 프로비저닝 방법에는 두 가지가 있습니다.

  • 정적 프로비저닝

    • 정적 프로비저닝은 클러스터 관리자가 미리 적정 용량의 PV를 만들어 두고 사용자의 요청이 있을 시 미리 만들어 둔 PV를 할당하는 방식입니다.

    • 사용할 수 있는 스토리지 용량에 제한이 있을 때 유용합니다.

  • 동적 프로비저닝

    • 동적 프로비저닝은 사용자가 PVC를 거쳐서 PV를 요청했을 때 생성해 제공합니다.

    • 클러스터에 사용자가 원하는 만큼의 스토리지 용량이 있다면, 원하는 용량만큼을 생성해서 사용할 수 있습니다.

3.1.2 Binding

바인딩은 프로비저닝으로 생성된 PV를 PVC와 연결하는 단계입니다. PVC에서 원하는 스토리지 용량과 접근방법을 명시해서 용청하면 거기에 맞는 PV가 할당됩니다. PV와 PVC의 매핑은 1대1 관계입니다.

3.1.3 Using

PVC는 Pod에 설정되고, Pod는 PVC를 볼륨으로 인식해서 사용합니다. 클러스터는 PVC를 확인하여 바인딩된 PV를 찾고 해당 볼륨을 Pod에서 사용할 수 있도록 해줍니다. 할당된 PVC는 파드를 유지하는 동안 계속 사용되며, 시스템에서 임의로 삭제할 수 없습니다.

3.1.4 Reclaiming

사용이 끝난 PVC는 삭제되고, PV를 초기화(reclaim)하는 과정을 거칩니다. PV는 기존에 사용했던 PVC가 아니더라도 다른 PVC로 재활용이 가능합니다.

  • PV 초기화 정책

    • Retain: PV의 데이터를 그대로 보존합니다.

    • Recycle: 재사용하게 될 경우 기존의 PV 데이터들을 모두 삭제 후 재사용합니다.

    • Delete: 사용이 종료되면 해당 볼륨을 삭제합니다.

3.2 PV 생성

코드 블럭
apiVersion: v1
kind: PersistentVolume
metadata:
  name: test-pv
  labels:
    name: test-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
  - ReadWriteMany
  hostPath:
    path: "/test/volume"

# Value
- capacity: 사용할 용량을 설정합니다.
- accessModes:특정 접근 모드를 선택합니다.
- hostPath: 노드에 저장되는 디렉토리를 설정합니다.

# 적용하기
kubectl apply -f test-pv.yaml

# PV 조회
kubectl get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
test-pv   1Gi        RWX            Retain           Available                                   15s

3.3 PVC 생성

코드 블럭
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
     storage: 1Gi

kubectl apply -f test-pvc.yaml

# PV, PVC 조회
 kubectl get pv,pvc
NAME                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM              STORAGECLASS   REASON   AGE
persistentvolume/test-pv   1Gi        RWX            Retain           Bound    default/test-pvc                           2m22s

NAME                             STATUS   VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/test-pvc   Bound    test-pv   1Gi        RWX                           18s
=> PV와 PVC가 연결되어 PV가 Bound 상태로 변경된 것을 확인할 수 있습니다.

3.4 PVC를 사용할 Pod 생성

코드 블럭
apiVersion: v1
kind: Pod
metadata:
  name: test-nginx2
spec:
  containers:
  - name: test-nginx2
    image: nginx:1.19
    ports:
    - containerPort: 80
    volumeMounts:
      - mountPath: "/test/volume"
        name: test-pv
  volumes:
  - name: test-pv
    persistentVolumeClaim:
      claimName: test-pvc

# 옵션
- volumeMounts.mountPath: 볼륨 마운트할 컨테이너 안의 경로를 작성합니다.
- volumes:.persistentVolumeClaim: 컨테이너에서 사용할 PV의 이름을 가져오고, PV와 연결되어 있으며 요청을 보낼 PVC를 지정합니다.

# 적용하기
kubectl apply -f test-nginx2.yaml

# 확인해보기
# 외부에서 확인
# kubectl describe pod test-nginx2 | grep -A1 Mounts
    Mounts:
      /test/volume from test-pv (rw)

# 컨테이너 내부에서 확인
kubectl exec -it test-nginx2 -- bash
root@test-nginx2:/# df -Th | grep volume
/dev/vda1      xfs       50G  3.7G   47G   8% /test/volume
=> 지정한 경로에 볼륨이 마운트된 것을 확인할 수 있습니다.

# 컨테이너 내부에서 test용 파일 생성
root@test-nginx2:/# touch /test/volume/test.txt

# PV 생성 시 설정한 노드의 경로에서도 확인이 가능합니다.
[root@worker-node ~]# ls -al /test/volume/
total 0
drwxr-xr-x 2 root root 22 Mar 10 06:22 .
drwxr-xr-x 3 root root 20 Mar 10 06:18 ..
-rw-r--r-- 1 root root  0 Mar 10 06:22 test.txt

...

4. 컨피그맵

  • Key-Value 쌍으로 기밀이 아닌 데이터를 저장하는 데 사용하는 API 오브젝트입니다.

  • 컨테이너 이미지에서 환경 별 구성을 분리하여, 애플리케이션을 쉽게 이식할 수 있습니다.

  • 개발/운영 환경의 컨테이너는 동일하게 구성하고, 컨피그맵 설정을 다르게 적용하여 서비스를 관리할 수 있습니다.

  • 파드와 컨피그맵은 동일한 네임스페이스에 있어야 합니다.

4.1 컨피그맵 사용

4.1.1 컨피그맵을 생성합니다.

코드 블럭
apiVersion: v1
kind: ConfigMap
metadata:
  name: prod-account
  namespace: default
data:
  ID: prod-user
  PASSWORD: prod-pass
  LOG_LEVEL: info

4.1.2 컨테이너에서 prod-account 컨피그맵의 LOG_LEVEL값을 가지고 오도록 설정합니다.

코드 블럭
piVersion: apps/v1
kind: Deployment
metadata:
  name: configmap-test
  labels:
    app: prod
spec:
  replicas: 1
  selector:
    matchLabels:
      app: prod
  template:
    metadata:
      labels:
        app: prod
    spec:
      containers:
      - name: testapp
        image: nginx:1.19
        ports:
        - containerPort: 8080
        env:
          - name: LOG_LEVEL
            valueFrom:
              configMapKeyRef:
                 name: prod-account
                 key: LOG_LEVEL

4.1.3 설정이 제대로 되었는지 파드 안에서 확인합니다.

코드 블럭
root@k8s-master01:~/kb# kubectl get pod
NAME                              READY   STATUS    RESTARTS   AGE
configmap-test-779ff45747-f4969   1/1     Running   0          80s

root@k8s-master01:~/kb# kubectl exec -it configmap-test-779ff45747-f4969 -- bash

root@configmap-test-779ff45747-f4969:/# env | grep LOG_LEVEL
LOG_LEVEL=info

...

5. 시크릿

  • 비밀번호, OAuth 토큰, ssh 키와 같은 민감한 정보를 저장하는 용도로 사용됩니다.

  • 시크릿 생성 시 데이터는 base64로 인코딩되어 저장됩니다.

  • 컨피그맵은 보안/암호화를 제공하지 않기 때문에, 저장하려는 데이터가 기밀인 경우, Secret을 사용하여 데이터를 비공개로 유지합니다.

    • 시크릿은 ETCD에 암호화되지 않은 상태로 저장되기 때문에, API 접근 권한이 있는 모든 사용자는 시크릿을 조회/수정 할 수 있습니다.

  • TLS 인증서를 시크릿으로 저장하여 사용하는 경우도 많습니다.

  • secret 리소스의 type 필드로 타입을 명시 할 수 있습니다.

빌트인 타입

사용처

Opaque

임의의 사용자 정의 데이터

kubernetes.io/service-account-token

서비스 어카운트 토큰

kubernetes.io/dockercfg

직렬화 된(serialized) ~/.dockercfg 파일

kubernetes.io/dockerconfigjson

직렬화 된 ~/.docker/config.json 파일

kubernetes.io/basic-auth

기본 인증을 위한 자격 증명(credential)

kubernetes.io/ssh-auth

SSH를 위한 자격 증명

kubernetes.io/tls

TLS 클라이언트나 서버를 위한 데이터

bootstrap.kubernetes.io/token

부트스트랩 토큰 데이터

5.1 불투명(Opaque) 시크릿 사용

5.1.1 명령어로 시크릿 생성

코드 블럭
root@k8s-master01:~/kb# cat prod-user.txt
prod-user
root@k8s-master01:~/kb# cat prod-pass.txt
prod-pass


root@k8s-master01:~/kb# kubectl create secret generic prod-user --from-file=./prod-user.txt --from-file=./prod-pass.txt
secret/prod-user-secret created


root@k8s-master01:~/kb# kubectl get secrets
NAME               TYPE     DATA   AGE
prod-user-secret   Opaque   2      4s


root@k8s-master01:~/kb# kubectl get secrets prod-user-secret -o yaml
apiVersion: v1
data:
  prod-pass.txt: cHJvZC1wYXNzCg==
  prod-user.txt: cHJvZC11c2VyCg==
kind: Secret
metadata:
  creationTimestamp: "2023-03-13T02:35:54Z"
  name: prod-user-secret
  namespace: default
  resourceVersion: "1226226"
  uid: 41a2cb2d-97f2-41bc-824f-c0c2783ec678
type: Opaque


*원래 값 확인방
root@k8s-master01:~/kb# echo cHJvZC11c2VyCg== | base64 --decode
prod-user

5.1.2 yaml 파일로 시크릿 생성

  • yaml 파일로 생성시 필요 값들을 base64로 인코딩된 값을 넣어야 합니다.

코드 블럭
root@k8s-master01:~/kb# echo -n "prod-user" | base64
cHJvZC11c2Vy
root@k8s-master01:~/kb# echo -n "prod-pass" | base64
cHJvZC1wYXNz

  • 시크릿을 생성합니다.

코드 블럭
apiVersion: v1
kind: Secret
metadata:
  name: prod-user
type: Opaque
data:
  username: cHJvZC11c2Vy
  password: cHJvZC1wYXNz

  • 생성된 시크릿을 확인합니다.

코드 블럭
root@k8s-master01:~/kb# kubectl apply -f prod-user-secret.yaml


root@k8s-master01:~/kb# kubectl get secrets
NAME        TYPE     DATA   AGE
prod-user   Opaque   2      5s


root@k8s-master01:~/kb# kubectl get secrets prod-user -o yaml
apiVersion: v1
data:
  password: cHJvZC1wYXNz
  username: cHJvZC11c2Vy
kind: Secret
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","data":{"password":"cHJvZC1wYXNz","username":"cHJvZC11c2Vy"},"kind":"Secret","metadata":{"annotations":{},"name":"prod-user","namespace":"default"},"type":"Opaque"}
  creationTimestamp: "2023-03-13T02:49:45Z"
  name: prod-user
  namespace: default
  resourceVersion: "1228228"
  uid: a5eff12c-2329-4697-92f7-f252a4f724ba
type: Opaque

5.1.3 시크릿 사용

코드 블럭
apiVersion: apps/v1
kind: Deployment
metadata:
  name: secretapp
  labels:
    app: secretapp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: secretapp
  template:
    metadata:
      labels:
        app: secretapp
    spec:
      containers:
      - name: testapp
        image: nginx:1.19
        ports:
        - containerPort: 8080
        env:
          - name: SECRET_USERNAME
            valueFrom:
              secretKeyRef:
                name: prod-user
                key: username
          - name: SECRET_PASSWORD
            valueFrom:
              secretKeyRef:
                name: prod-user
                key: password

코드 블럭
root@k8s-master01:~/kb# kubectl exec -it secretapp-69d4797f86-7r95g -- bash

root@secretapp-69d4797f86-7r95g:/# env | grep SECRET
SECRET_USERNAME=prod-user
SECRET_PASSWORD=prod-pass