AWS EKS, Cognito, Route53, ACM, VPC, EC2를 활용하여 KUBEFLOW를 구축해보자!

노하람·2021년 11월 16일
0

안녕하세요~!

오늘은 두달간의 삽질을 끝내고 AWS의 End To End Kubeflow install을 기록해보고자 합니다.
급하다고 하나라도 빼먹고 진행했다간 저처럼 끝없는 에러에 휘둘릴지 모르니,
모든 섹션을 정확히 따라하면서 진행하시기 바랍니다!!

시작하기에 앞서 aws에서 kubernetes 인프라를 다루고자 하신다면 아래의 툴들을 먼저 설치해놓으시기 바랍니다. 해당 툴 설치 방법은 다양한 곳에 자료가 많으니 참고하세요!

  • eksctl
  • kubectl
  • aws cli
  • istioctl
  • kfctl

EKS 쿠버네티스 클러스터 배포

클러스터가 아직 없으신 분은 먼저 배포를 진행하시기 바랍니다.

  • cluster.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: <클러스터명>
  region: <사용하고자 하는 aws 리전>

nodeGroups:
  - name: ng <노드 그룹명>
    desiredCapacity: 6
    instanceType: m5.xlarge
  • 클래스터 생성 : eksctl create cluster -f cluster.yaml
  • 노드 확인 : kubectl get nodes

저는 미리 구축된 p2.xlarge 사양의 노드 2개를 가진 클러스터를 이용하였습니다.
kubeflow 설치시 생성되는 총 파드 개수는 50개 이상이니 파드 생성 제한에 걸리지 않게 주의하세요.

  • 노드 그룹 조정 : eksctl scale nodegroup --cluster=<클러스터명> --nodes=4 ng

Route 53 도메인 생성

  1. AWS 콘솔 - Route 53 - 도메인 등록

  2. 원하는 도메인 등록 후 생성자 연락처 정보 기록 및 결제
    - .com 도메인의 경우 1년에 12달러입니다.

  3. 등록하면 아래와 같이 도메인 정보를 확인할 수 있습니다.

  4. Route 53 - 대시보드 - DNS 관리(호스팅 영역)

  5. 호스팅 영역 - 호스팅 영역 생성

  6. 도메인 이름 입력 후 호스팅 영역 생성 완료

  7. 처음엔 NS, SOA 타입으로 2개의 레코드가 존재합니다. 레코드 생성 버튼을 눌러 A 레코드를 임시로 생성합니다.

인증서 관리자(ACM, AWS Certificate Manager)

  1. AWS 콘솔 - AWS Certificate Manager - 요청 - 퍼블릭 인증서 요청

  2. .<도메인 이름>.com 으로 인증서 요청
    - 와일드카드를 이용해 하위 도메인에 대한 모든 인증을 대신합니다.
    - 예를 들어
    .musma.com이 작성하시면 됩니다.(위에서 생성한 도메인으로)

  3. 인증서 검증 대기 상태가 되면 인증서 ID를 클릭해서 세부사항으로 들어간 후, 생성된 CNAME을 기반으로 레코드를 생성해서 DNS 인증을 진행합니다.

  4. 인증서의 CNAME이 제대로 생성되었고, 검증 대기 중이라면 필터를 통해 자동으로 레코드 정보가 들어온 것을 볼 수 있습니다. 바로 레코드 생성을 클릭합니다.

  5. 시간이 어느정도 지나면(5~15분 정도) 인증서 발급이 완료됩니다.

    • 이 방식이 DNS 인증 방식입니다.
    • 1시간 이상 지나도 발급이 정상적으로 이루어지지 않으면 위 과정에서 잘못 설정한 것이 있는 것이니 다시 확인해주세요. 잘못된 부분이 있으면 아무리 시간이 지나도 발급되지 않습니다.
    • 가끔 아주 빨리 발급되고, 가끔 시간이 오래 소요될 때도 있습니다. aws에서 비동기식으로 처리하기 때문이라는데 답답하기 그지없습니다.
  6. (중요) 위의 1~6과정을 '버지니아 북부(us-east-1)' 리전에서 똑~같이 반복합니다.

    • 우리가 쓰려는 건 서울 리전인데 왜 버지니아 북부에 인증서를 발급하는지 궁금하시죠?
    • 버지니아 북부에 인증서가 없다면 추후에 Cognito에서 자체 도메인을 사용하려면 해당 리전에 인증서가 없다는 이유로 진행이 불가능합니다.(Cognito 인증서는 버지니아 북부만 인식하나 봅니다.)
    • 따로 이미지는 첨부하지 않겠으나 절대 빼먹지 않고 진행해주세요!! 방식은 위에서 설명한 것과 똑같습니다.
  7. 서울 리전의 인증서와 버지니아 리전의 인증서 모두 세부사항으로 들어가서 인증서 arn(ACM arn)을 기록해둡니다. 나중에 사용합니다.

Cognito에서 사용자 풀, 사용자 자격 증명 생성

  1. AWS 콘솔 - Cognito - 사용자 풀 관리 - 사용자 풀 생성

  2. 사용자 풀 이름 입력 후 기본값 검토
    - 풀 이름은 그다지 중요하지 않습니다.

  3. 별도의 설정은 하지 않고 그대로 생성하시면 됩니다.(물론 보안을 위해 다양한 설정을 추가할 수 있습니다.)

  4. 풀 생성 후 나오는 일반 설정 창에서 풀 ID와 풀 ARN은 중요하니 기록해두시길 바랍니다.

  5. 일반 설정 - 앱 클라이언트 항목에 들어가서 '앱 클라이언트' 추가를 진행합니다.

  6. 앱 클라이언트 이름은 중요하지 않으니 임의로 생성하고, 아래로 드래그하여 앱 클라이언트 생성을 누릅니다.
    - 앱 클라이언트 ID도 나중에 사용하니 따로 기록해두세요!

  7. 앱 통합 - 앱 클라이언트 설정에 들어가 아래와 같이 설정합니다.
    - 활성화된 자격 증명 공급자 : Cognito User Pool (추후에 OIDC, google 등 다양한 자격 증명 공급자도 추가할 수 있습니다. 로그인 및 회원가입에 이용하는 공급자를 의미합니다.)
    - 콜백 URL : https://kubeflow.<도메인 이름>/oauth2/idpresponse
    - 로그아웃 URL : https://auth.<도메인 이름>/logout?response_type=code&client_id=<클라이언트 ID>&redirect_uri=https://auth.<도메인 이름>/logout&state=STATE&scope=openid+profile+aws.cognito.signin.user.admin
    - 허용된 OAuth Flows : Authorization code grant
    - 허용된 OAuth Scopes : email, openid, aws.cognito.signin.user.admin, profile

  8. 앱 통합 - 도메인 이름 설정에 들어가 자체 도메인을 구성합니다.
    - 도메인 이름 : auth.<도메인 이름>
    - AWS 관리형 인증서(중요) : us-east-1에 인증서가 존재한다면 아래 이미지처럼 인증서가 선택됩니다. 아니라면 위 섹션에서 다시 버지니아 북부 리전에 인증서를 생성하세요.
    - 변경 내용 저장을 눌러 저장합니다. 다만 위 섹션에서 인증서 DNS 인증을 진행한 뒤로, 아직 발급되지 않은 상태라면(시간이 좀 걸릴 수도 있습니다.) 변경 내용이 저장되지 않습니다. 인증서 발급이 완료된 것을 확인한 후 진행해주시면 되겠습니다.

  9. 변경 사항이 적용되면 아래에 Alias Target DNS 주소가 생성됩니다. 해당 주소를 복사해서 위 섹션에서 임시로 생성한 Route 53의 A 레코드(127.0.0.1로 임시 지정해놨었죠?)를 별칭 사용으로 변경하여 해당 주소로 변경해주시면 됩니다.
    - 전 이미 해당 도메인을 하나 사용하고 있기 때문에 auth2.<도메인이름>으로 진행했습니다. 사실 같은 도메인에서 유저 풀만 다르게 해서 진행하고 싶은데 이렇게 두 번 생성하지 않고 기존의 도메인을 그대로 사용해도 될 것 같긴 합니다.
    - 트래픽 라우팅 대상을 CloudFront 배포에 대한 별칭으로 설정하고, 8번에서 복사한 별칭을 그대로 붙여넣기 하신 뒤 레코드를 생성해주시면 됩니다.

  10. 아래와 같이 자체 도메인이 Active 상태로 변경됐는지 확인해주세요!


Kubeflow 배포

  1. 지금까지 설정을 진행하면서 제가 기록해두라고 한 것들이 4개 있습니다. 같이 확인해볼까요? 추가로 아까 자체 도메인으로 등록한 도메인 주소는 당연히 기억하시겠죠??
    • 앱 클라이언트 ID(Cognito)
    • 사용자 풀 ID(Cognito) - 더 나중에 사용합니다.
    • 사용자 풀 ARN(Cognito)
    • 인증서 ARN(ACM, 서울 리전) - 버지니아 북부 리전의 ACM arn은 이제 사용하지 않습니다. 버지니아 북부로 설정해서 배포하면 오류나니 주의하세요.
    • 자체 도메인(Cognito)
  2. AWS cli에서 kubeflow를 배포할 것입니다. 터미널을 열고 진행해주세요.
    • aws configure, aws default profile 등을 확인해주세요. 해당 사항에 대한 자세한 내용은 이전 포스팅에 기록해두었으니 참고해주시면 됩니다.
    • export AWS_DEFAULT_PROFILE=<프로파일명>
    • kubectl config use-context <사용할 컨텍스트>
  3. Kubeflow with cognito 매니페스트 파일을 받아옵니다.
    • 해당 클러스터명으로 mkdir, cd를 하신 후 진행하셔야 합니다. (예를 들어 클러스터명이 env-kf라면 mkdir env-kr, cd env-kr, wget ~을 진행하시면 됩니다.
    • wget https://raw.githubusercontent.com/kubeflow/manifests/v1.2-branch/kfdef/kfctl_aws_cognito.v1.2.0.yaml
  4. 매니페스트 파일을 열어 수정합니다. KfAwsPlugin 섹션에 Cognito 관련 설정을 하는 부분이 있습니다. 위에서 기록해둔 4가지 파트에 대해서 수정을 진행합니다. region도 수정하고, eks의 IAM을 사용하려면 roles 부분은 주석처리하고 진행하시면 됩니다. roles를 작성하고 사용하면 노드그룹의 정책을 따라가니 주의하세요.
    - vim kfctl_aws_cognito.v1.2.0.yaml
    - 왜 kubeflow 1.4 버전도 있는데 1.2버전을 사용하는지 궁금하신가요? aws는 공식적으로 1.2.0 버전과 호환이 완벽하다고 공식문서에서 제안하고 있습니다.
    - certArn: 인증서 arn, cognitoAppClientId: 앱 클라이언트 ID, cognitoUserPoolArn: 사용자 풀 arn, cognitoUserPoolDomain: 자체 도메인(
    auth.<도메인이름>)
    -
  - kind: KfAwsPlugin
    metadata:
      name: aws
    spec:
      auth:
        cognito:
          certArn: arn:aws:acm:eu-west-1:xxxxx:certificate/xxxxxxxxxxxxx-xxxx
          cognitoAppClientId: xxxxxbxxxxxx
          cognitoUserPoolArn: arn:aws:cognito-idp:ap-northeast-2:xxxxx:userpool/eu-west-1_xxxxxx
          cognitoUserPoolDomain: auth.platform.domain.com
      region: ap-northeast-2
      #roles:
      #- eksctl-aiplatform-aws-nodegroup-ng-NodeInstanceRole-xxxxx

  1. Kubeflow를 배포합니다.
    • kfctl apply -V -f kfctl_aws_cognito.v1.2.0.yaml

설치 후 접속

  1. 배포 후 kubectl get ingress -n istio-system 명령을 실행하여 Address 파트에 DNS 주소가 정상적으로 나오는지 확인합니다. 설치후 3분 정도 소요될 수 있습니다.
    • DNS 주소가 나오지 않으면 아래 이슈 목록을 확인해주세요.
  2. 정상적으로 DNS 주소를 받았다면 Cognito의 콜백 URL에 추가해줍니다.
    • https://<받아온 주소>/oauth2/idpresponse
  3. Route 53 - 도메인 관리에 3개의 레코드을 추가할 것입니다.
    • 순서대로 레코드 이름, 유형, 값/트래픽 라우팅 대상입니다.
    • *.<도메인이름> / CNAME / <받아온 주소>
    • *.default.<도메인이름> / CNAME / <받아온 주소>
    • <도메인 이름> / A / 클래식 로드 밸런스에 뜨는 리소스(dualstack.<받아온 주소>
    • 제 최종 레코드 상태는 이렇습니다. 제가 작업 중에 임의로 추가한 레코드가 있을수도 있어서 여러분은 저보다 적은 수를 가지실 수 있습니다.
  4. 이제 kubeflow.<도메인이름> 으로 접속할 수 있습니다! 파이프라인이나 노트북, katib 등 자유롭게 쿠브플로를 활용해보세요!!

이슈 목록

ACM

  1. 인증서 DNS 인증이 계속 기다려도 안돼요!
    • 간혹 도메인의 이름 서버와 호스팅 영역의 자동 생성된 값/트래픽 라우팅 대상이 일치하지 않는 문제가 있습니다.
    • 예를 들어 도메인 이름 서버에 ns-546.awsdns-04.net가 있다면, 호스팅 영역의 라우팅 대상도 정확히 같은 값을 가지도록 복사/붙여넣기를 이용해 편집해주셔야 합니다.
    • 편집하고 기존에 인증을 위해 생성된 레코드(CNAME)을 삭제하고, 처음부터 다시 ACM에서 같은 방식으로 생성, 인증을 진행해보세요!
    • 72시간이 지나야 검증 시간 초과 상태가 된다는데.. 아직 72시간까진 기다려본 적이 없습니다.
    • 참고 : https://docs.aws.amazon.com/ko_kr/acm/latest/userguide/troubleshooting-DNS-validation.html

설치 중 발생하는 오류

  1. service 'istiod' not found : 다른 버전의 istio를 설치하지 마세요!

    • istioctl 및 istio 매니페스트 등 다양한 방법을 활용한 istio 설치를 추천드리지 않습니다. 경험상 더 많은 오류를 발생시킬 가능성이 농후하기 때문입니다. wget으로 다운받은 kubeflow_aws_cognito파일은 필요한 설정을 모두 포함하고 이습니다.
    • 대부분의 설치 문제는 삭제 과정에서 삭제되지 않는 리소스들이 남아있기 때문에 발생합니다. 아래에서 모든 리소스를 찾아 삭제하는 방법을 기재하겠습니다. 이미지를 보시면 istio-galley와 istiod-istio-system이 4일 전에 생성됐었는데, 삭제 과정을 거친 후에도 남아있기 때문에 오류 발생한 것을 볼 수 있습니다.
  2. failed calling webhook "webhook.cert-manager.io" : 웹훅을 불러오지 못하는 에러
    - 여러 문제는 기다리면 해결됩니다.(설치 중)
    - 두 세번 배포(kfctl apply)를 재시도해보시고 안되면 오류 메세지를 잘 확인해보세요.

  3. 오류 메세지 중 crd 관련 로그가 있다면, kubectl get crd -A 혹은 특정 네임스페이스 관련 crd kubectl get crd | grep <관련 기능> 으로 검색해서 삭제하시면 되겠습니다.

    • crd는 일반적으로 그냥 삭제되지 않기 때문에 patch 과정을 거친 후 삭제를 다시 한번 진행해주시면 됩니다.
    • 예를 들면 삭제코드는 아래와 같습니다.
    • kubectl patch crd/issuers.cert-manager.io -p '{"metadata":{"finalizers":[]}}' --type=merge
    • kubectl delete crd/issuers.cert-manager.io
  4. 설치/삭제 중 너무나 많은 오류가 발생하지만, 오류 기재하기엔 기록해놓은 것이 없네요. 여러분이 겪으실 대부분의 문제는 저도 겪어봤으니 댓글 남겨주시면 최선을 다해 도와드리도록 하겠습니다.

    • 대부분의 문제는 첫 설치에 실패하고, 삭제 후 설정을 변경해 재진행하려고 했을 때 이미 설치해둔 crd, clusterroles, clusterbindings, configmap, validatingwebhookconfiguration, mutatingwebhookconfiguration 등이 덜 삭제됐거나 Terminating 상태에 빠진 네임스페이스를 finalizers로 해제해주지 않았기 때문입니다. 밑의 삭제 방법에서 정리할테니 모든 리소스를 하나도 남기지 않고 다 삭제해주세요.

istio-ingress 관련 문제

  1. 모두 정상적으로 설치되었고 pod들도 다 작동하는데 DNS 주소를 받아오지 않는 경우
    • VPC의 서브넷에 설정이 필요할 수 있습니다.
    • AWS 콘솔 - VPC로 들어갑니다.
    • 가상 프라이빗 클라우드 - 서브넷에 들어갑니다.
    • 각 서브넷의 이름을 하나씩 확인하며 Public, Private 2 종류가 있는 것을 확인합니다.
    • 저는 클러스터가 2개 있기 떄문에 각 클러스터에 맞는 설정이 필요합니다. 클러스터 1개 뿐이시라면 해당 클러스터명만 사용해서 아래를 따라와주시면 됩니다.
    • 서브넷 이름에 Public이 포함되어 있다면 태그에 아래 2개가 있는지 확인하고 없다면 포함시킵니다.(모든 서브넷을 하나씩 다 작업하는 겁니다.), 순서대로 태그의 Key와 Value 입니다. kubernetes.io/cluster/<클러스터명>:shared, kubernetes.io/role/elb:1
    • 서브넷 이름에 Private이 포함되어 있다면 아래 태그를 확인하고 없다면 추가합니다. kubernetes.io/cluster/<클러스터명>:shared, kubernetes.io/role/internal-elb:1
    • 설치가 정상적으로 진행된 상태에서 Address가 들어오지 않는 문제는 이렇게 해결할 수 있는 가능성이 큽니다.
    • 이번 kubeflow 배포에서는 따로 external-dns를 활용하지 않으셔도 됩니다. 함께 설치되는 istio를 통해 진행됩니다.

kubeflow 삭제 방법

  1. 매니페스트 파일을 활용해서 1차로 삭제합니다.
    • kfctl delete -V -f kfctl_aws_cognito.v1.2.0.yaml
    • 설치 과정 중 클러스터 컨텍스트가 동일하지 않는다는 문제가 발생하면, 로그를 참고해서 매니페스트 파일 상단 metadata에 ClusterName: <컨텍스트명>을 추가해주시면 됩니다.
    • 물론 이걸로 다 끝나지 않습니다.
  2. 위 과정을 진행하고 kubectl get namespaces를 확인하면 kubeflow 관련한 모든 네임스페이스가 Terminating 상태에 빠졌을 겁니다. 아래 명령을 활용해서 하나씩 모두 해제해줍니다.
    • NAMESPACE=<네임스페이스명> 명령에 해제할 네임스페이스명을 바꿔 넣어주면서 반복 실행하시면 되겠습니다. proxy는 한번만 실행해도 됩니다.
$ kubectl proxy &
$ NAMESPACE=kubeflow
$ kubectl get namespace $NAMESPACE -o json |jq '.spec = {"finalizers":[]}' >temp.json
$ curl -k -H "Content-Type: application/json" -X PUT --data-binary @temp.json 127.0.0.1:8001/api/v1/namespaces/$NAMESPACE/finalize
  1. 그 후 아래 명령을 하나씩 실행해주세요.
    • kubectl delete clusterroles katib-controller katib-ui ml-pipeline-persistenceagent ml-pipeline-viewer-controller-role pipeline-runner
    • kubectl delete clusterrolebindings katib-controller katib-ui ml-pipeline-persistenceagent ml-pipeline-scheduledworkflow ml-pipeline-viewer-crd-role-binding pipeline-runner
    • kubectl delete validatingwebhookconfiguration istio-gallay istiod-system admission-webhook-mutating-webhook-configuration experiment-mutating-webhook-config istio-sidecar-injector mutating-webhook-configuration
    • kubectl delete crd applications.app.k8s.io
    • kubectl get configmap -o name -n kube-system | egrep 'cert-manager'|xargs kubectl delete -n kube-system
    • kubectl get mutatingwebhookconfiguration -o name | egrep 'kubeflow|katib'|xargs kubectl delete
    • kubectl get crd -o name| egrep 'kubeflow|istio|certmanager|cert-manager|applications.app.k8s.io'|xargs kubectl delete
    • kubectl get clusterrole -o name| egrep 'kubeflow|istio'|xargs kubectl delete
    • kubectl get clusterrolebinding -o name| egrep 'kubeflow|istio'|xargs kubectl delete
  2. 이제 모두 삭제되었는지 확인해볼 시간입니다. 아마 crd 파트에서 잔여 리소스가 남아있을 가능성이 큽니다. 설치 중 발생하는 오류-3번을 확인해서 crd도 모두 삭제해주세요.(방금 설치됐다고 뜨지 않는 오래된 crd는 상관없는 crd이니 놔두셔도 됩니다.)
    • kubectl get namespaces
    • kubectl get clusterroles -A
    • kubectl get crd -A
    • kubectl get pods -A
    • kubectl get validatingwebhookconfiguration -A
    • 이 외에 더 다양한 리소를 확인해도 좋겠지만, 이 정도 확인하고 모두 삭제된 것을 확인했으면 정상적으로 설치를 진행하실 수 있을겁니다.
profile
MLOps, MLE 직무로 일하고 있습니다😍

0개의 댓글