Kubernetes 기반 nuclio function 배포 과정

서준교·2022년 4월 15일
0
post-thumbnail

해당 문서에서는 Kubernetes 클러스터에서 nuclio function을 배포하는 과정을 기술합니다.

1. 쿠버네티스 클러스터 구조

nuclio function을 배포한 쿠버네티스 클러스터의 구조는 다음과 같습니다.

작업을 진행한 클러스터는 마스터 노드 3개, 워커 노드 3개로 구성되어 있습니다. 1번 마스터 노드에는 포트포워딩이 되어 있기 때문에 32222번 포트를 통해 외부에서 접속이 가능하지만, 나머지 노드에는 접근이 불가하기에 VDI (Virtual Desktop Infra)를 통해 접속하여 작업을 진행했습니다. VDI는 쿠버네티스 클러스터 내부에 설치되어 있는 노드들과 동일한 대역의 네트워크를 제공합니다. 이외에도 포트포워딩이 설정된 nuclio dashboard나 nexus repository는 외부에서 접근이 가능하였고, cvat dashboard는 ingress에 설정된 URL 규칙에 따라 VDI에서 cvat.example.com:30000로 접근할 수 있습니다.

2. nuclio function 배포 과정

nuclio function의 배포 과정은 공식 문서를 참고하여 순서대로 기술하였습니다.

1) Docker registry 구축

nuclio function을 배포하기 위해 해야 할 첫 번째 작업은 이미지를 저장할 도커 레지스트리를 구축하는 것입니다. nuclio function은 function.yaml 에 정의된 메타 데이터를 기반으로 빌드된 일종의 이미지입니다. 배포 과정에서 이미지를 해당 레지스트리에 push하고 pull하는 작업을 거치게 되는데, 해당 작업을 하기 위해서는 도커 레지스트리가 필수적입니다.

기본적으로 도커 레지스트리를 구축하는 방식은 두 가지가 있습니다.

  • Registry 이미지를 기반으로 로컬 환경에서 Docker Registry를 구축하는 방식
  • Nexus를 활용하여 Private Docker Registry를 구축하는 방식

처음에 첫 번째 방식으로 도커 레지스트리를 구축하였으나, 모델 배포 과정에서 다음과 같은 에러가 발생하였습니다.

로컬 레지스트리에 이미지를 push하기 위해서는 localhost:5000/<image>:<tag> 와 같은 형식으로 이미지의 이름을 변경해야 합니다. local 환경에서 nuclio function을 배포하는 경우에는 nuclio 컨테이너가 동일한 docker network에 연결되어 있어 로컬 레지스트리를 인식할 수 있기 때문에 첫 번째 방식으로 레지스트리를 구축해도 정상적으로 배포가 가능합니다. 하지만 쿠버네티스 환경에서는 실제로 nuclio function의 deployment를 통해 생성된 pod가 특정 워커 노드에 할당되기 때문에, 모든 워커 노드에서 도커 레지스트리를 인식할 수 있는 환경을 구축해야 합니다.

따라서 localhost:5000으로 태깅된 이미지는 동일한 워커 노드에 레지스트리 컨테이너가 존재하지 않는 경우에는 레지스트리를 인식할 수 없기 때문에 위와 같은 오류가 발생하는 것입니다. (예를 들어, 레지스트리 컨테이너가 1번 워커 노드에서 실행중이고, 2번 워커 노드에 nuclio function pod가 할당된 경우 localhost는 2번 워커 노드를 가리키기 때문에 1번 워커 노드에서 실행중인 도커 레지스트리에 접근할 수 없습니다.)

하지만 nexus를 기반으로 구축한 레지스트리는 해당 레지스트리가 구축된 노드의 ClusterIP를 통해 접근할 수 있기 때문에 컨테이너가 없는 노드에서도 접근이 가능한 것입니다.

2) Credential 생성

쿠버네티스 클러스터에서 private docker registry를 구축한 경우에는 해당 레지스트리에 접근하기 위해 필요한 개인 정보를 secret 오브젝트로 생성해야 합니다. 실제로 nuclio function deployment의 spec.container.imagePullSecrets에 어떤 secret 오브젝트를 바탕으로 레지스트리에 접근하는지 명시되어 있습니다.

따라서 registry-credential 이라는 이름의 secret 오브젝트를 생성해야 합니다. secret 오브젝트를 생성하는 과정은 다음과 같습니다.

read -s mypassword
<enter your password>

kubectl create secret docker-registry registry-credential \
    --namespace nuclio \
    --docker-username <username> \
    --docker-password $mypassword \
    --docker-server <URL> \
    --docker-email ignored@nuclio.io

unset mypassword

nexus 레지스트리의 계정과 비밀번호와 이메일 주소, 그리고 레지스트리의 url을 입력합니다. url은 레지스트리가 동작하는 컨테이너의 ClusterIP와 포트번호로 이루어져 있습니다. ex) 172.30.45.153:5000

모든 옵션을 입력하였다면, 해당 정보는 base-64로 인코딩되어 secret 오브젝트로 저장됩니다. 주의해야 할 점은, 공식 문서에는 registry-credentials 로 되어있는데, 이를 꼭 registry-credential 로 변경해서 생성해야 합니다. 이름이 일치하지 않으면 deployment 오브젝트에 명시된 secret을 참조하지 못하기 때문에 다음과 같이 no basic auth credentials 오류가 발생합니다.

3) Nuclio helm package 설치

nuclio dashboard, controller를 helm chart를 통해 설치합니다.

먼저, nuclio helm chart를 저장소에 추가합니다.

helm repo add nuclio https://nuclio.github.io/nuclio/charts

이전에 입력했던 도커 레지스트리의 URL과 secret을 각각의 옵션에 추가합니다.

helm install nuclio \
--set registry.pushPullUrl=<URL> nuclio/nuclio \
--set registry.secretName=registry-credential -n nuclio

kubernetes의 nuclio namespace에 다음과 같이 deployment가 생성되었으면 정상적으로 설치가 완료된 것입니다.

nuclio dashboard를 외부로 노출시키기 위한 service 오브젝트를 생성합니다. yaml 파일을 작성해서 kubectl apply 명령을 통해 리소스를 생성하거나 kubectl expose 명령을 사용합니다. service type은 NodePort로 지정합니다.

  • kubectl expose 명령을 통해 deployment를 클러스터 외부에 노출
kubectl expose deployment -n nuclio nuclio-dashboard --type=NodePort --name=nuclio-nodeport
  • service object 생성
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/managed-by: Helm
  name: nuclio-nodeport
  namespace: nuclio
spec:
  clusterIP: 10.99.69.2
  clusterIPs:
  - 10.99.69.2
  externalTrafficPolicy: Cluster
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - nodePort: 32002
    port: 8070
    protocol: TCP
    targetPort: 8070
  selector:
    app: nuclio
    nuclio.io/app: dashboard
    nuclio.io/class: service
    nuclio.io/name: nuclio-dashboard
    release: nuclio
  sessionAffinity: None
  type: NodePort
status:
  loadBalancer: {}

4) Nuclio CLI 기반 프로젝트 생성 및 function 배포

이제 nuclio function을 배포하기 위한 환경은 모두 구축되었습니다. nuclio CLI인 nuctl 을 통해 function을 배포할 프로젝트를 생성합니다.

nuctl create project cvat -n nuclio

다음 명령을 통해 nuclio function을 배포합니다. git clone 을 통해 복제한 cvat 폴더 내부에서 작업한다고 가정하였습니다.

nuctl deploy --project-name cvat \
--path `pwd`/serverless/tensorflow/faster_rcnn_inception_v2_coco/nuclio \
--volume `pwd`/serverless/common:/opt/nuclio/common \
--platform kube \
--namespace nuclio \
--kubeconfig /etc/kubernetes/admin.conf \
--registry 172.16.156.21:5000 \
--http-trigger-service-type NodePort

각 옵션에 대한 설명은 다음과 같습니다.

OptionDescription
path배포할 nuclio function이 정의되어 있는 폴더의 경로
volumenuclio function 컨테이너의 볼륨에 마운트할 경로를 정의합니다.
platformnuclio function을 배포하는 환경 (kube, local)
namespace배포할 nuclio project의 namespace
kubeconfigkubernetes의 kubeconfig 파일 (admin.conf)
registrydocker registry의 URL
http-trigger-service-typenuclio function의 pod에 적용할 service의 type

클러스터 외부에서 nuclio function에 접근할 수 있게 하기 위해서는 nuclio function의 type을 NodePort로 설정하여 임의의 포트로 노출시켜야 합니다. NodePort는 30000 - 32767 범위 내에서 사용 가능한 포트가 임의로 지정됩니다.

5) function 배포 결과

위에서 작성한 명령을 통해 function이 정상적으로 배포되었다면, 최종적으로 Function deploy complete 메시지가 출력됩니다.
nuctl get functions 명령을 통해 배포된 nuclio function 리스트를 확인할 수 있습니다. NODE PORT가 지정되고, STATE가 ready면 정상적으로 배포된 것입니다.
해당 function은 쿠버네티스에서 deployment로 실행되며 (replicaset의 default 값은 1입니다.) 해당 deployment를 통해 생성된 pod 또한 확인할 수 있습니다.

nuclio dashboard와 cvat에서도 해당 function이 정상적으로 동작하고 있는 것을 확인할 수 있습니다.

3. 오류 사항

1. frame 단위 auto labeling은 정상적으로 진행되나, task 단위로 진행할 때 오류 발생

  • Postman으로 basic auth로 RestAPI를 보냈을 땐 정상적으로 응답이 오지만, 동일한 RestAPI가 Auto Annotation 버튼 클릭을 통해 송신되었을 때 500 Error 발생합니다. 따라서 인증 관련 이슈로 파악됩니다.

2. Nuclio Dashboard를 통해 모델을 배포했을 때 오류 발생

  • NodePort 옵션을 지정하지 않았을 땐 (ClusterIP) Dashboard에서도 정상적으로 배포가 되나, NodePort로 변경한 뒤 배포하면 배포 과정에서 오류가 발생함
  • nuclio CLI (nuctl)을 통해 배포할 때는 NodePort type으로도 정상적으로 배포됨
CaseClusterIP Type (Dashboard)NodePort Type (Dashboard)
모델 배포성공오류 발생
Auto Annotation (Frame 단위)오류 발생성공
Auto Annotation (Job 단위)오류 발생성공 (5장 내외의 image에 한함)

또한, nuctl을 통해 배포한 function의 로그를 nuclio dashboard를 통해 확인하면, 에러 메시지가 출력되나 모델 자체는 정상적으로 running됩니다.

profile
매일 성장하는 개발자가 되고 싶습니다. 😊

2개의 댓글

comment-user-thumbnail
2024년 2월 20일

유익한 내용 감사합니다. 혹시 마지막에 보이는 cvat ui는 어떻게 띄우신 건가요??

1개의 답글