IT_Study/Ops

[MLOps] AWS EC2 Ubuntu 환경에서 Kubeflow 세팅 방법

__Vivacé__ 2023. 11. 1. 15:06

 최근 AWS에서도 ML 최적화 환경(EKS cluster, sagemaker, ...)을 제공해주고 있다. 때문에 여러 ML 관련 tool들을 핸들링하기가 쉬워졌다.

 그래서인지 Kubeflow 관련 세팅을 찾아보면, 대다수가 Public Cloud에 의존적으로 아키텍쳐가 모델링이 되어있다.

 

 적용해보는 것도 나쁘지 않지만, low하게 구축해보는 것도 경험이라 생각해서, ubuntu image 위에서 활용할 수 있도록 진행해볼 예정이다. 

 

진행 스펙

 - AWS Instance Type : g4dn.xlarge
 - OS Image : Ubuntu Server 20.04 LTS (HVM), SSD Volume Type
 - Storage : 150GB, EBS, 범용 SSD(gp2)

 


1. cuDNN 설치

AWS 스펙 상 NVIDIA GPU(g4dn)을 사용하기 때문에, GPU 가속화를 위해 cuDNN을 설치한 후 nvidia Docker(2)를 이용해서 GPU 가속을 할 것이다.

 

Working Directory는 Home DIirectory에서 진행한다.

 

먼저 다음 Shell script를 실행한다.

#!/bin/bash

sudo apt-get -y update
sudo apt-get -y remove --purge '^nvidia-.*'
sudo apt-get -y remove --purge 'cuda-.*'
sudo apt-get -y install nvidia-cuda-tookit
sudo apt-get -y install nvidia-cuda-toolkit
nvcc -V
whereis cuda
mkdir ~/nvidia
cd ~/nvidia
CUDNN_TAR_FILE="cudnn-10.1-linux-x64-v7.6.5.32.tgz"
wget https://developer.download.nvidia.com/compute/redist/cudnn/v7.6.5/${CUDNN_TAR_FILE}
tar -xzvf ${CUDNN_TAR_FILE}

sudo cp cuda/include/cudnn.h /usr/lib/cuda/include/
sudo cp cuda/lib64/libcudnn* /usr/lib/cuda/lib64/
sudo chmod a+r /usr/lib/cuda/lib64/libcudnn*
sudo chmod a+r /usr/lib/cuda/include/cudnn.h
echo "export LD_LIBRARY_PATH=/usr/lib/cuda/lib64:$LD_LIBRARY_PATH" >> ~/.bashrc
export "LD_LIBRARY_PATH=/usr/lib/cuda/include:$LD_LIBRARY_PATH" >> ~/.bashrc
source ~/.bashrc
ubuntu-drivers devices
sudo apt install -y nvidia-driver-470
echo "reboot....."

 

Docker 설치

위 설치가 완료되면 다음 Shell script를 실행한다.

#!/bin/bash

sudo apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update -y
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
sudo docker run hello-world
sudo usermod -aG docker $USER && newgrp docker
sudo service docker restart

Docker 설치가 끝나면, 재부팅을 해준다.

$ sudo reboot

 


2. Nvidia Docker 설치

reboot를 완료했다면, 다음 shell script를 활용해서 nvidia docker를 설치해준다.

#!/bin/bash

distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt-get -y update
sudo apt-get -y install nvidia-docker2
sudo systemctl restart docker
sudo docker run --runtime nvidia nvidia/cuda:11.4.3-base-ubuntu20.04 /usr/bin/nvidia-smi
sudo bash -c 'cat <<EOF > /etc/docker/daemon.json
{
    "exec-opts": ["native.cgroupdriver=systemd"],
    "log-driver": "json-file",
    "log-opts": {
        "max-size": "100m"
    },
    "data-root": "/mnt/storage/docker_data",
    "storage-driver": "overlay2",
    "default-runtime" : "nvidia",
    "runtimes" : {
        "nvidia" : {
            "path": "/usr/bin/nvidia-container-runtime",
            "runtimeArgs" : []
        }
    }
}
EOF'
sudo systemctl restart docker

실행 완료 화면

nvidia-smi 명령어를 실행하게끔 해놨기 때문에, 해당 창이 떠야 한다.

 

추가로 docker hub의 tag가 업데이트가 계속 이어지기 때문에, 이미지를 잘 확인해야 한다

 

3. k8s 설치 및 초기화

nvidia-smi를 통해 지표가 동작함을 확인했다면, 다음 shell script를 실행시킨다.

#!/bin/bash

sudo swapoff -a
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab

sudo apt-get install -y iptables arptables ebtables
sudo apt-get update && sudo apt-get install -y apt-transport-https curl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF

sudo apt-get update
sudo apt-get install -y kubelet=1.21.10-00 kubeadm=1.21.10-00 kubectl=1.21.10-00 --allow-downgrades --allow-change-held-packages
sudo apt-mark hold kubelet kubeadm kubectl
kubeadm version
kubelet --version
kubectl version --client

설치 성공 시 뜨는 화면 / 설치 성공 시에는 version 정보를 확인할 수 있어야 한다.

설치가 완료되었다면, 다음 shell script를 실행한다.

#!/bin/bash
# init k8s
sudo kubeadm init --pod-network-cidr=10.217.0.0/16

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config


kubectl cluster-info

# CNI
kubectl create -f https://raw.githubusercontent.com/cilium/cilium/v1.6/install/kubernetes/quick-install.yaml
kubectl get pods -n kube-system --selector=k8s-app=cilium

kubectl taint nodes --all node-role.kubernetes.io/master-
kubectl apply -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/1.0.0-beta6/nvidia-device-plugin.yml


#test GPU
kubectl -n kube-system get pod -l name=nvidia-device-plugin-ds
kubectl -n kube-system logs  -l name=nvidia-device-plugin-ds

# default storageclass
kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml
kubectl get storageclass
kubectl patch storageclass local-path -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
kubectl get sc

# install kusomize 
# 
if [ ! -f /usr/local/bin/kusomize ]
  then
    echo "kustomize"
    wget https://github.com/kubernetes-sigs/kustomize/releases/download/v3.2.0/kustomize_3.2.0_linux_amd64
    mv ./kustomize_3.2.0_linux_amd64 kustomize
    sudo chmod 777 kustomize
    sudo mv kustomize /usr/local/bin/kustomize
fi


# autocomplete k8s
shellname=`echo $SHELL | rev | cut -d '/' -f1 | rev`
shellconf=`echo ~/.\${shellname}rc`
grep -n "kubectl completion" $shellconf

if [ $? = 1 ]
  then
    echo 'install autocomplete k8s'
    sudo apt-get install bash-completion -y
    echo 'source <(kubectl completion '$shellname')' >>$shellconf
    echo 'alias k=kubectl' >>$shellconf
    echo 'complete -F __start_kubectl k' >>$shellconf
fi
$SHELL

 CNI는 cilium 1.6 이상은 제대로 동작하지 않기 때문에 사용하지 않는 것을 추천 (안 되면 cilium말고 calico로 설치하면 잘 된다)

 kustomize는 3.2.0 이상 버전은 지원이 안되기 때문에, 이상의 버전 사용을 권장하지 않는다.

 

4. kubeflow 설치

kubeflow 설치를 위해 kubeflow github에 들어가서 manifests를 다운받아야 한다.

Home Directory에 clone을 받도록 하자

 

GitHub - kubeflow/manifests: A repository for Kustomize manifests

A repository for Kustomize manifests. Contribute to kubeflow/manifests development by creating an account on GitHub.

github.com

$ cd ~
$ git clone https://github.com/kubeflow/manifests.git

$ cd manifests
$ git checkout v1.5.1  # kubeflow 1.5.1 설치를 위해

일단 이전에 github에 써 있는 내용 중, cert-manager를 먼저 설치하고, 나머지는 single command로 설치할 것이다.

 

$ kustomize build common/cert-manager/cert-manager/base | kubectl apply -f -

# 확인
$ watch -n1 kubectl get pod -A

pod을 보았을 때, 모두 Running 상태면 다음 단계를 진행하면 된다.

$ kustomize build common/cert-manager/kubeflow-issuer/base | kubectl apply -f -

# 위 작업이 완료가 되면, 아래 싱글 커맨드를 진행
$ while ! kustomize build example | kubectl apply -f -; do echo "Retrying to apply resources"; sleep 10; done

# 다시 확인
$ watch -n1 kubectl get pod -A

이후 전체 pod가 running 상태가 될 때까지 대기한다.

 

 


5. Kubeflow 접속

이제 Kubeflow 설치가 완료가 되었고, Kubeflow에 접근하기 위해 port forwarding을 진행해주어야 한다.

# istio-system이 있는 지 확인
$ kubectl get namespaces

# istio-ingressgatewy PORT 확인
$ kubectl get svc -n istio-system

# 원하는 포트(8080)로 port-forwarding 진행
$ kubectl port-forward --address=0.0.0.0 svc/istio-ingressgateway -n istio-system 8080:80

forwarding 명령어 실행 중인 상태

그럼 지금 상태로는. http에 본인 public ip 주소와 8080포트로 kubeflow에 접근이 가능하다. 

Kubeflow 초기 화면

처음 이메일 및 패스워드는 다음과 같다.

 - Email Address : user@example.com

 - Password : 12341234

 - Namespace : kubeflow-user-example-com

로그인 성공 화면

 


6. Kubeflow 환경 설정

테스트하기 위해 notebook을 새로 만들어보자

 

해당 페이지에서, 노트북 이름과 이미지 설정만 한 다음, Launch 버튼을 누르면 다음과 같은 CSRF 오류가 난다.

아래 CSRF 오류가 난 모습

해결 방법은 2가지가 있다.

a. APP_SECURE_COOKIES를 false로 변경

 기본적으로 웹 애플리케이션 같은 경우는 APP_SECURE_COOKIES를 사용하고 있다.

 이 값을 false로 하면 접근을 할 수는 있지만 CSRF 공격을 막을 수는 없다. 그래서 권장하진 않는다.

 하는 방법은 다음과 같다.

$ kubectl get deployments.apps -n kubeflow | grep web

명령어 실행 시 보이는 화면

이 부분에서 app deployment 확인 후 설정을 바꿔주면 된다.

$ kubectl edit deployments.apps -n kubeflow jupyter-web-app-deployment

spec의 env 하단에 빨간색 박스 내용을 추가

 

b. HTTPS로 접속할 수 있도록 변경

해당 방법을 권장하며, 다음 페이지를 참고해서 진행하면 된다.

 

Securing the Kubeflow authentication with HTTPS

How to secure the Kubeflow authentication with HTTPS using the network load balancer

ibm.github.io

요약하면, 두 yaml 파일을 작성해서 배포하면 된다.

yaml 파일 내용

$ kubectl apply -f gateway.yaml
$ kubectl apply -f certificate.yaml

이렇게 두 파일을 적용을 해주면 https로 접근할 수가 있다.

 

 

# gateway가 443이 https로 되어있으므로, 443으로 port forwarding 진행
$ kubectl port-forward --address=0.0.0.0 svc/istio-ingressgateway -n istio-system 8080:443

 

이후에 아까와 같이 접속을 진행한다.

인증서가 자체 인증서기 때문에 실제로는 그냥 들어가지지는 않고, 안전하지 않음을 눌러 이동한다.

 

이제 노트북을 생성하면, CSRF 오류가 뜨지 않는다. 

Notebook 생성 완료

아, 그리고

본인은 requested CPUs를 0.1로 설정했는데, 자원 설정에 따라 status가 loading 상태에 머무를 수 있으니 잘 확인하자

 


7. Kubeflow 1.6.0 설치

kubeflow 1.6.0을 설치하기 위해서는 kubeflow 초기화를 해주어야 한다.

$ sudo kubeadm reset

config file(빨간 박스)까지 지워야 k8s가 초기화된다.

$ rm $HOME/.kube/config

 

이후 3번 과정에 있는 k8s initiation을 다시 진행한다.

그리고 후속 과정 중, v1.6.0 tag로 checkout 후 같은 과정을 진행하면 된다.

 

명령어만 간단하게 정리해보겠다.

# 1.6.0 tag로 이동
$ git checkout v1.6.0

# cert-manager 설치
$ kustomize build common/cert-manager/cert-manager/base | kubectl apply -f -

# pod이 모두 running 상태인 지 확인 후 진행
$ kubectl get pod -A
$ kustomize build common/cert-manager/kubeflow-issuer/base | kubectl apply -f -

# 이후 single command로 install
$ while ! kustomize build example | kubectl apply -f -; do echo "Retrying to apply resources"; sleep 10; done

# 이후 pod이 모두 running 상태인 지 확인
$ kubectl get pod -A

# 작성한 yaml 파일이 있는 디렉토리로 돌아가서 내용 배포
$ kubectl apply -f gateway.yaml
$ kubectl apply -f certificate.yaml

# 이후 kubeflow 접속
$ kubectl port-forward --address=0.0.0.0 svc/istio-ingressgateway -n istio-system 8080:443