반응형

Metric server 설치

 

원래는 아래 github에서 CLI 한줄이면 설치가 가능하지만
이 글에서는 kind cluster로 학습하고 있기 때문에 설치가 불가능하다
https://github.com/kubernetes-sigs/metrics-server

전체파일로 설치하자

# metrics-server.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    k8s-app: metrics-server
    rbac.authorization.k8s.io/aggregate-to-admin: "true"
    rbac.authorization.k8s.io/aggregate-to-edit: "true"
    rbac.authorization.k8s.io/aggregate-to-view: "true"
  name: system:aggregated-metrics-reader
rules:
- apiGroups:
  - metrics.k8s.io
  resources:
  - pods
  - nodes
  verbs:
  - get
  - list
  - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    k8s-app: metrics-server
  name: system:metrics-server
rules:
- apiGroups:
  - ""
  resources:
  - nodes/metrics
  verbs:
  - get
- apiGroups:
  - ""
  resources:
  - pods
  - nodes
  verbs:
  - get
  - list
  - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server-auth-reader
  namespace: kube-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: extension-apiserver-authentication-reader
subjects:
- kind: ServiceAccount
  name: metrics-server
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server:system:auth-delegator
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:auth-delegator
subjects:
- kind: ServiceAccount
  name: metrics-server
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  labels:
    k8s-app: metrics-server
  name: system:metrics-server
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:metrics-server
subjects:
- kind: ServiceAccount
  name: metrics-server
  namespace: kube-system
---
apiVersion: v1
kind: Service
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server
  namespace: kube-system
spec:
  ports:
  - name: https
    port: 443
    protocol: TCP
    targetPort: https
  selector:
    k8s-app: metrics-server
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server
  namespace: kube-system
spec:
  selector:
    matchLabels:
      k8s-app: metrics-server
  strategy:
    rollingUpdate:
      maxUnavailable: 0
  template:
    metadata:
      labels:
        k8s-app: metrics-server
    spec:
      containers:
      - args:
        - --cert-dir=/tmp
        - --secure-port=4443
        - --kubelet-insecure-tls
        - --kubelet-preferred-address-types=InternalIP
        - --kubelet-use-node-status-port
        - --metric-resolution=15s
        image: k8s.gcr.io/metrics-server/metrics-server:v0.6.2
        imagePullPolicy: IfNotPresent
        livenessProbe:
          failureThreshold: 3
          httpGet:
            path: /livez
            port: https
            scheme: HTTPS
          periodSeconds: 10
        name: metrics-server
        ports:
        - containerPort: 4443
          name: https
          protocol: TCP
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /readyz
            port: https
            scheme: HTTPS
          initialDelaySeconds: 20
          periodSeconds: 10
        resources:
          requests:
            cpu: 100m
            memory: 200Mi
        securityContext:
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: true
          runAsNonRoot: true
          runAsUser: 1000
        volumeMounts:
        - mountPath: /tmp
          name: tmp-dir
      nodeSelector:
        kubernetes.io/os: linux
      priorityClassName: system-cluster-critical
      serviceAccountName: metrics-server
      volumes:
      - emptyDir: {}
        name: tmp-dir
---
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
  labels:
    k8s-app: metrics-server
  name: v1beta1.metrics.k8s.io
spec:
  group: metrics.k8s.io
  groupPriorityMinimum: 100
  insecureSkipTLSVerify: true
  service:
    name: metrics-server
    namespace: kube-system
  version: v1beta1
  versionPriority: 100

아래 명령어를 적용해서 설치한 후 확인하고 진행하자

kubectl apply -f metrics-server.yaml

kubectl get pod -n kube-system

# 결과
NAME                                                READY   STATUS    RESTARTS   AGE
coredns-7c65d6cfc9-j7xg8                            1/1     Running   0          2d17h
coredns-7c65d6cfc9-l76fn                            1/1     Running   0          2d17h
etcd-dev-cluster-control-plane                      1/1     Running   0          2d17h
kindnet-kqh8m                                       1/1     Running   0          2d17h
kindnet-rvdl9                                       1/1     Running   0          2d17h
kindnet-x9xlp                                       1/1     Running   0          2d17h
kube-apiserver-dev-cluster-control-plane            1/1     Running   0          2d17h
kube-controller-manager-dev-cluster-control-plane   1/1     Running   0          2d17h
kube-proxy-dpnls                                    1/1     Running   0          2d17h
kube-proxy-nsq78                                    1/1     Running   0          2d17h
kube-proxy-xk7vs                                    1/1     Running   0          2d17h
kube-scheduler-dev-cluster-control-plane            1/1     Running   0          2d17h
metrics-server-7b445dfdc-jhnv8                      0/1     Running   0          29s # 이 부분이 1/1 이 되어야 한다.

아래 명령어를 통해 memory와 cpu 사용량을 볼 수 있다.

# 파드 사용량 (현재는 pod가 없음)
kubectl top pod

# 결과
No resources found in default namespace.

# 노드에서의 사용량
kubectl top nodes

# 결과
NAME                        CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
dev-cluster-control-plane   206m         1%     848Mi           10%
dev-cluster-worker          28m          0%     265Mi           3%
dev-cluster-worker2         32m          0%     292Mi           3%

리소스의 단위는 아래와 같다.

Memory 1M, 50M, 1G 1Mi, 50Mi, 1Gi
CPU 1 (하나의 CPU), 100m (CPU 1/10), 500m (CPU 1/5) (실제로는 이렇지 않지만 이렇게 생각해도 무방하다.)

 

만약 컨테이너가 memory나 cpu가 한도를 초과하면 어떻게 될까?
memory의 경우 kubelet이 컨테이너를 죽이고 재시작한다.
CPU의 경우 컨테이너가 죽지 않고 쓰로틀링이 걸린다. (성능이 저하될 수 있다.)

Pod pending

# 01-deploy-cpu-memory_usage.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deploy
spec:
  selector:
    matchLabels:
      app: my-app
  replicas: 3
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: nginx
          image: nginx
          resources:
            requests:
              cpu: 2
              memory: 100Mi
            limits:
              cpu: 2
              memory: 100Mi

파일을 만들고 실행한 후 top으로 확인해보자
위의 파일에서 request 보다 더 많은 리소스를 사용할 수 있도록 허용하고
limit은 limit 보다 더 많은 리소스를 사용할 수는 없다.

kubectl apply -f 01-deploy-cpu-memory_usage.yaml

kubectl top pods
# 15초 간격으로 확인하기 때문에 pod를 실행하고 조금 기다린 후 다시 실행하자
error: metrics not available yet

kubectl top pods

# 결과
NAME                         CPU(cores)   MEMORY(bytes)
my-deploy-6bcdc9d88f-chvvm   0m           15Mi
my-deploy-6bcdc9d88f-hwvw8   0m           15Mi
my-deploy-6bcdc9d88f-xsdh4   0m           15Mi

아래 파일처럼 CPU 수를 늘리고 replicaSet도 늘려서 적용해보자
이 숫자는 worker CPU에 따라서 변경이 가능하다
아래 예시는 CPU가 부족할때를 보기 위함이다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deploy
spec:
  selector:
    matchLabels:
      app: my-app
  replicas: 5
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: nginx
          image: nginx
          resources:
            requests:
              cpu: 10
              memory: 100Mi
            limits:
              cpu: 10
              memory: 100Mi

확인해보면 일부 pod가 pending 상태인걸 확인할 수 있다.
describe로 확인해보자

 kubectl describe pod/my-deploy-6598fd5d9-q5frf

# 결과
...
Events:
  Type     Reason            Age                  From               Message
  ----     ------            ----                 ----               -------
  Warning  FailedScheduling  111s (x4 over 2m1s)  default-scheduler  0/3 nodes are available: 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }, 2 Insufficient cpu. preemption: 0/3 nodes are available: 1 Preemption is not helpful for scheduling, 2 No preemption victims found for incoming pod.

pod에 CPU를 할당해야하지만 모든 CPU가 사용중이라서 불가능하다.
해결방법은 실제로 노드를 늘리거나 pod를 줄이는 방법이다.

 

HPA template

2개의 파일을 만들자

# 02-deploy-for-hpa.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deploy
spec:
  selector:
    matchLabels:
      app: my-app
  replicas: 1
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: nginx
          image: nginx
          startupProbe:
            httpGet:
              path: /
              port: 80
            periodSeconds: 1
            failureThreshold: 30
          readinessProbe:
            httpGet:
              path: /
              port: 80
            periodSeconds: 5
            failureThreshold: 3
          resources:
            requests:
              cpu: 50m
              memory: 10Mi
            limits:
              cpu: 50m
              memory: 10Mi
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  selector:
    app: my-app
  ports:
    - port: 80
      targetPort: 80
---
apiVersion: v1
kind: Pod
metadata:
  name: demo-pod
spec:
  terminationGracePeriodSeconds: 1
  containers:
    - name: demo
      image: vinsdocker/util
      args:
        - "sleep"
        - "3600"

위의 파일은 deployment와 데모를 위한 pod 그리고 외부 접속을 위한 service이다.
nginx version에 따라서 cpu나 memory가 더 필요하면 pod가 켜지지 않을 수도 있다. 적당히 조절해주자

# 03-hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: my-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-deploy
  minReplicas: 1
  maxReplicas: 3
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 10
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 10

이 파일은 deployment를 감시하며 autoscaling을 할 HPA 파일이다
이제 적용해보자

kubectl apply -f 02-deploy-for-hpa.yaml
kubectl apply -f 03-hpa.yaml

이제 demo pod로 접속한 후 부하 테스트를 진행해서 pod가 auto scaling이 되는지 확인해보자

kubectl exec -it demo-pod -- bash

root@demo-pod:/# ab -n 20000 -c 5 http://nginx/

그러면 CPU가 더 사용됨에 따라 auto scaling이 되는것을 확인할 수 있다.

이 후 작업이 완료되면 다시 1개로 돌아온다

 

HPA - Without Probe

이전 2번에서 probe를 주석 처리 하자

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deploy
spec:
  selector:
    matchLabels:
      app: my-app
  replicas: 1
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: nginx
          image: nginx
#          startupProbe:
#            httpGet:
#              path: /
#              port: 80
#            periodSeconds: 1
#            failureThreshold: 30
#          readinessProbe:
#            httpGet:
#              path: /
#              port: 80
#            periodSeconds: 5
#            failureThreshold: 3
          resources:
            requests:
              cpu: 50m
              memory: 20Mi
            limits:
              cpu: 50m
              memory: 20Mi
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  selector:
    app: my-app
  ports:
    - port: 80
      targetPort: 80
---
apiVersion: v1
kind: Pod
metadata:
  name: demo-pod
spec:
  terminationGracePeriodSeconds: 1
  containers:
    - name: demo
      image: vinsdocker/util
      args:
        - "sleep"
        - "3600"

이제 적용해보자

kubectl apply -f 02-deploy-for-hpa.yaml
kubectl apply -f 03-hpa.yaml

데모 파드로 접속한 후 요청을 보내보자

kubectl exec -it demo-pod -- bash

ab -n 20000 -c 5 http://nginx/

중간에 connection이 거절당하는 것을 확인할 수 있다.

Benchmarking nginx (be patient)
Completed 2000 requests
Completed 4000 requests
Completed 6000 requests
Completed 8000 requests
Completed 10000 requests
Completed 12000 requests
apr_socket_recv: Connection refused (111)
Total of 12928 requests completed

왜 이런일이 발생할까?
오토스케일링은 발생한다. 하지만 Probe가 있으면 컨테이너가 준비 된 후에 요청을 받지만
Probe가 없으면 컨테이너가 준비되기 전에도 요청을 받기 때문에 연결이 거부되는 상황이 생긴다.

반응형

'Kubernetes' 카테고리의 다른 글

[Kubernetes] Ingress  (0) 2024.12.30
[Kubernetes] Persistent Volume & StatefulSet  (0) 2024.12.30
[Kubernetes] Secret  (0) 2024.12.19
[Kubernetes] ConfigMap  (0) 2024.12.19
[Kubernetes] Probes  (0) 2024.12.19
얼은펭귄