Kubernetes 환경 구축 ( Ubuntu ) - 3

2024. 1. 9. 13:29Technology[DevOps]

[ 이번 게시글에서 구현할 사항 ]

- springboot service를 kubernetes pod로 생성하고 해당 서비스를 호출할 수 있도록 NodePort service를 등록합니다.

- AutoScaling을 설정합니다.

 

1. namespace를 생성합니다.

kubectl craete namespace [만들고 싶은 namespace 이름]

 

2. springboot service를 kubernetes pod로 생성하는 deployment.yaml 파일을 작성합니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test
  namespace: [생성한 namespace 이름]
  labels:
    app: test
spec:
  replicas: 4
  revisionHistoryLimit: 0 # Default to 10 if not specified
  selector:
    matchLabels:
      app: test
  template:
    metadata:
      labels:
        app: test
    spec:
      terminationGracePeriodSeconds: 60
      containers:
      - name: test
        image: docker.io/[dockerHub ID]/[이미지명](:[태그명])
        imagePullPolicy: Always
        ports:
        - containerPort: [사용하고자 하는 PORT번호]
        resources:
          requests:
            memory: "350Mi"
            cpu: "350m"
          limits:
            memory: "700Mi"
            cpu: "700m"
        livenessProbe:
          tcpSocket:
            port: [사용하고자 하는 PORT번호]
          initialDelaySeconds: 60
          periodSeconds: 60
          failureThreshold: 60
          timeoutSeconds: 60
        readinessProbe:
          tcpSocket:
            port: [사용하고자 하는 PORT번호]
          initialDelaySeconds: 60
          periodSeconds: 60
          failureThreshold: 60
          timeoutSeconds: 60
        startupProbe:
          tcpSocket:
            port: [사용하고자 하는 PORT번호]
          initialDelaySeconds: 60
          periodSeconds: 60
          failureThreshold: 60
          timeoutSeconds: 60
        lifecycle:
            preStop:
              exec:
                command: ["/bin/sleep", "30"]

- 태그명은 별도로 설정하지 않는 경우 default로 :latest 가 붙게 됩니다.

- (ReplicaSet) spec.replicas 부분에 pod replica 개수를 입력하면 해당 개수만큼의 pod를 보장해주는 replicaSet을 구성합니다.

- (ReplicaSet Rollback) spec.revisionHistoryLimit 부분에 deployment Rollback을 위해 몇 개의 History를 저장할 지 지정할 수 있습니다. deployment를 update할 때 이전 버전의 History를 저장하고 이전 버전으로 Rollback 기능을 제공하기 위해 이전 버전의 ReplicaSet을 남겨두게 됩니다.

ReplicaSet으로 해당 개수만큼의 pod를 보장합니다.

- (Pod Resource Allocation) spec.template.spec.containers.resources 부분은 추후 autoscaling 할 때 리소스 할당량의 일정 비율 이상을 사용하게 되면 Scale Out을 하게 되는데 pod의 초기 리소스 할당량과 제한을 명시하는 부분입니다.

- (Pod Health Check - Scale Out에서의 트래픽 유실 방지)  spec.template.spec.containers.livenessProbe 부분은 주기적으로 해당 pod의 상태를 진단하여 정상이 아닌 상태일 때 종료 또는 재시작시키도록 동작합니다.

- (Pod Health Check - Scale Out에서의 트래픽 유실 방지)  spec.template.spec.containers.readinessProbe 부분은 트래픽이 해당 pod로 처음 유입될 때 pod의 상태를 진단하여 정상 상태일 때만 트래픽을 받도록 동작합니다.

- (Pod Health Check - Scale Out에서의 트래픽 유실 방지)  spec.template.spec.containers.startupProbe 부분은 pod의 상태를 진단하여 정상 상태일 때 livenessProbe와 readinessProbe를 동작시킵니다.

- (Scale In에서의 트래픽 유실 방지)  spec.terminationGracePeriodSeconds 부분은 pod를 종료하기 전에 특정 동작을 현재 수행하고 있다면 graceful shutdown을 위해 설정한 시간 동안 종료를 유예한 후 해당 시간이 지나도 동작 중이라면 pod를 강제종료하도록 동작합니다.

- (Scale In에서의 트래픽 유실 방지)  spec.template.spec.containers.lifecycle.preStop 부분은 pod가 Terminated되기 전에 trigger되는 이벤트를 정의할 수 있고 트래픽이 완전하게 차단된 후 종료되도록 시간적 여유를 제공하기 위해 설정하였습니다.

 

3. test Service를 호출할 수 있도록 NodePort service를 생성하는 nodeport.yaml 파일을 작성합니다.

apiVersion: v1
kind: Service
metadata:
  name: nodeport-service
  namespace: [생성한 namespace 이름]
spec:
  type: NodePort
  selector:
    app: test
  ports:
    - protocol: TCP
      port: [nodeport-service가 사용하는 PORT 번호]
      targetPort: [springBoot Service가 사용하는 PORT 번호]
      nodePort: [외부에서 접근할 PORT 번호]

사용자는 외부에 노출한 nodePort 로 접근하게 되고 해당 포트와 라우팅된 nodeport-service로 요청이 보내지고 해당 요청은 targetPort인 springBoot Service가 실행중인 포트로 가게 됩니다.

deployment.yaml 파일에서 작성한 동일한 namespace를 부여합니다.

 

4. 위 yaml 파일을 kubernetes 환경에 적용합니다.

kubectl apply -f deployment.yaml
kubectl apply -f nodeport.yaml

 

5. test Service pod와 nodeport-service가 정상적으로 실행되었는지 확인합니다.

test pod가 정상적으로 Running 상태임을 확인합니다.
nodeport-service가 80포트에서 실행되고 30000 외부포트와 라우팅되어 있음을 확인합니다.
외부에 오픈된 30000번 포트번호로 접근했을 때 정상적으로 해당 서비스가 호출됨을 확인합니다.

 

6. autoscaling을 위한 yaml파일을 작성합니다.

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: kubernetes-simple-app-hpa
  namespace: default
spec:
  maxReplicas: 8
  minReplicas: 4
  scaleTargetRef:
    apiVersion: [pod로 배포한 service의 version]
    kind: Deployment
    name: [pod로 배포한 service의 name]
  targetCPUUtilizationPercentage: 50

autoscaling을 실행할 HPA의 이름을 kubernetes-simple-app-hpa로 적용했고 네임스페이스는 default로 설정했습니다.

maxReplicas은 오토스케일링이 적용되서 포드 개수를 증가시킬때 최대 몇개까지 증가시킬 것인지에 대한 옵션입니다.

반대로 minReplicas은 포드 개수가 줄어들때 최소한 여기 지정된 개수 만큼은 포드가 실행되고 있게 지정한 값입니다.

실제 어떤 대상을 오토스케일링 할 것인지는 scaleTargetRef옵션에 있습니다.

targetCPUUtilizationPercentage은 CPU 사용률이 50%가 됐을때 오토스케일링을 적용하라는 내용입니다.

 

7. 작성한 yaml 파일을 kubernetes에 적용합니다.

kubectl apply -f autoscaling.yaml

 

8. HPA가 정상적으로 실행되고 있는지 확인합니다.

kubectl get hpa

이 때 TARGETS 부분에 <unknown> 이 떠서 해당 pod의 CPU 사용률을 얻어오지 못하고 있음을 알 수 있습니다.

이를 해결하기 위해서는 metrics-server가 필요합니다.

 

9. metrics-server yaml 파일을 kubernetes에 적용하고 오류를 수정합니다.

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

kuberctl describe pod metrics-server-xxx -n kube-system으로 해당 pod의 상태를 조회해보시면

Readiness probe failed: HTTP probe failed with statuscode: 500 오류로 정상작동이 되지 않음을 알 수 있습니다.

이를 해결하기 위해 아래 명령어 입력 후

kubectl edit deploy -n kube-system metrics-server

[ 아래 수정코드 복사 ]
        - --kubelet-insecure-tls
        
      hostNetwork: true

spec.containers.args 에 [ 추가 ] 부분을 추가하고,
spec.template.spec 라인에 [ 추가 ] 부분을 추가합니다.

 

10. metrics-server pod와 HPA가 정상적으로 실행되고 있는지 확인합니다.

kubectl get pods --all-namespaces

kubectl get hpa

metrics-server pod의 상태가 Ready 상태임을 확인할 수 있습니다.
HPA를 조회해보면 정상적으로 TARGETS 상태를 추적하고 있음을 확인할 수 있습니다.

 

참고

Kubernetes에서 HPA를 활용한 오토스케일링(Auto Scaling) (saramin.github.io)