우분투에 Docker 설치하기

Ubuntu Bionic 18.04 (LTS) 에 도커 설치하기

사전 확인

이전 버전 삭제하기

만약 이전 버전의 도커가 설치되어 있다면 먼저 삭제해야합니다. 패키지명은 docker, docker.io 또는 docker-engine 입니다

sudo apt-get remove docker docker-engine docker.io containerd runc

도커 설치하기

리포지토리를 이용하여 설치하기

새로운 호스트 시스템에, 처음으로 도커 엔진을 설치하기 위해서는, 도커 리포지토리를 설정해야 합니다. 설정 후후 리포지토리를 이용하여 도커를 설치하고 업데이트할 수 있습니다.

리포지토리 설정하기

https를 통해 리포지토리를 사용할 수 있도록, 적절한 패키지 인덱스 및 설치 패키지 업데이트 합니다.

sudo apt-get update

sudo apt-get install \\
    apt-transport-https \\
    ca-certificates \\
    curl \\
    gnupg-agent \\
    software-properties-common

도커의 공식 GPG key를 추가합니다

curl -fsSL <https://download.docker.com/linux/ubuntu/gpg> | sudo apt-key add -

도커를 설치하기 위한 리포지토리를 추가합니다.

sudo add-apt-repository \\
   "deb [arch=amd64] <https://download.docker.com/linux/ubuntu> \\
   $(lsb_release -cs) \\
   stable"

도커 설치하기

apt 패키지 인덱스를 업데이트하고, 도커 엔진과, containerd 를 설치합니다.

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli 

도커 확인하기

docker 를 일반 사용자 계정에서 사용하려면, docker 그룹에 사용자 계정을 추가해 줘야합니다.

sudo usermod -aG docker <your-username>

로그 아웃을 한 다음, 다시 접속을 해야 설정이 적용됩니다.

docker info 명령어를 실행하여, 설치된 도커의 정보를 확인할 수 있습니다.

docker info

정상적으로 실행되면, 다음과 같은 결과를 확인할 수 있습니다.

Client:
 Debug Mode: false

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 0
 Server Version: 19.03.12
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Native Overlay Diff: true
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc version: dc9208a3303feef5b3839f4323d9beb36df0a9dd
 init version: fec3683
 Security Options:
  apparmor
  seccomp
   Profile: default
 Kernel Version: 4.15.0-76-generic
 Operating System: Ubuntu 18.04.4 LTS
 OSType: linux
 Architecture: x86_64
 CPUs: 1
 Total Memory: 3.852GiB
 Name: magi
 ID: 53WF:R22P:ZLLX:5564:H5MV:2WDA:S7UK:CK5Y:G647:TH6W:D74Z:UPDZ
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Registry: <https://index.docker.io/v1/>
 Labels:
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false

WARNING: No swap limit support

우분투 18.04에 네트워크 카드 추가하기

우분투 18.04 부터는 네트워크 카드를 설정하려면, netplan을 사용해야 합니다.

네트워크 인터페이스 추가

네트워크 인터페이스를 추가한 다음, ifconfig 명령어를 실행해 봅니다. 별다른 옵션을 주기 않았기 때문에, 추가된 네트워크 인터페이스가 보이지 않습니다.

ifconfig
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 944  bytes 67408 (67.4 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 944  bytes 67408 (67.4 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

추가한 네트워크 인터페이스 확인

ifconfig -a 명령어를 이용하여, 추가한 네트워크 인터페이스를 확인할 수 있습니다.

ifconfig -a

eth0 이 추가된 것을 확인할 수 있습니다.

eth0: flags=4098<BROADCAST,MULTICAST>  mtu 1500
        ether 00:15:5d:15:0e:00  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 944  bytes 67408 (67.4 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 944  bytes 67408 (67.4 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

설정에 네트워크 인터페이스를 추가하기

/etc/netplan/*.yaml 파일에 네트워크 설정을 추가해 줘야 합니다

cat /etc/netplan/*.yaml
# This file is generated from information provided by the datasource.  Changes
# to it will not persist across an instance reboot.  To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
    ethernets: {}
    version: 2

현재 설정된 네트워크 인터페이스가 없기 때문에, ethernets 필드에 아무런 값이 없습니다.

/etc/netplan/*.yaml 파일에 네트워크 설정을 추가합니다.

sudo vi /etc/netplan/*.yaml

ifconfig -a 명령어를 통해서 확인한 네트워크 인터페이스 이름을 ethernets 필드에 추가하고, 설정값을 지정해줍니다. 아래 예제에서는 dhcp 를 사용하기 때문에, IP 직접 명시하지 않았습니다.

# This file is generated from information provided by the datasource.  Changes
# to it will not persist across an instance reboot.  To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
    ethernets:
        eth0:
            addresses: []
            dhcp4: true
    version: 2

만약 고정 IP를 사용한다면 아래처럼 설정할 수 있습니다.

# This file is generated from information provided by the datasource.  Changes
# to it will not persist across an instance reboot.  To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
    ethernets:
        eth0:
            addresses: [192.168.21.100/24]
            gateway4: 192.168.56.1
            nameservers:
                    addresses: [8.8.8.8,8.8.4.4]
            dhcp4: no
            dhcp6: no
    version: 2

설정 적용하기

다음 명령어를 실행하여, 변경한 설정을 적용합니다.

sudo netplan apply

설정이 적용되면 ifconfig 명령어를 실행하여, 적용한 내용을 확인할 수 있습니다.

ifconfig

정상적으로 적용되었다면, 추가한 eth0 을 확인할 수 있습니다.

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.21.39  netmask 255.255.255.0  broadcast 192.168.21.255
        inet6 fe80::215:5dff:fe15:e00  prefixlen 64  scopeid 0x20<link>
        ether 00:15:5d:15:0e:00  txqueuelen 1000  (Ethernet)
        RX packets 47668  bytes 70216376 (70.2 MB)
        RX errors 0  dropped 6  overruns 0  frame 0
        TX packets 9362  bytes 772780 (772.7 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 120  bytes 9592 (9.5 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 120  bytes 9592 (9.5 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

PC에 kubeflow 설치하기 – 3부 kubeflow 설치하기

Service Account Token Volume Projection 활성화

kubeflow에서는 인증/권한 기능을 위해서 istio 를 사용합니다. 그래서 istio-system 이라는 네임스페이스에 istio 관련 컴포넌트가 설치됩니다. 그 중에 하나인 istio-ingressgateway 포드의 내용을 보면 다음과 같은 부분을 발견할 수 있습니다.

...
  volumes:
  - name: istio-token
    projected:
      defaultMode: 420
      sources:
      - serviceAccountToken:
          audience: istio-ca
          expirationSeconds: 43200
          path: istio-token
...

바로 Service Account Token Volume Projection 이라는 것입니다. 이 기능은 쿠버네티스 1.15에서 비활성화 되어 있습니다. 그래서 해당 기능을 사용하기 위해서는 활성화 해줘야 합니다.

기능을 활성화 하기 위해서는, 다음과 같이 kube-apiserver 매니페스트에 몇 가지 플래그를 추가해야합니다. 매니페스트 파일은 /etc/kubernetes/manifests/kube-apiserver.yaml에 위치합니다.

$ sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml
...
        - --service-account-signing-key-file=/etc/kubernetes/pki/sa.key
        - --service-account-issuer=api
        - --service-account-api-audiences=api,vault

매니페스트 파일을 수정하고, kube-apiserver 포드가 자동으로 다시 시작됩니다.

dynamic volume provisioner 설치

kubeflow를 쉽게 설치하기 위해서는 동적 볼륨 프로비져너(dynamic volume provisioner)가 필요합니다. 이 글에는 로컬 디렉토리를 이용하는 Local Path Provisioner 를 사용하겠습니다.

다음은 Local Path Provisioner 를 설치하는 명령어입니다.

$ kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml

namespace/local-path-storage created
serviceaccount/local-path-provisioner-service-account created
clusterrole.rbac.authorization.k8s.io/local-path-provisioner-role created
clusterrolebinding.rbac.authorization.k8s.io/local-path-provisioner-bind created
deployment.apps/local-path-provisioner created
storageclass.storage.k8s.io/local-path created
configmap/local-path-config created

스토리지 클래스(storage class)를 조회해 보겠습니다.

$ kubectl get storageclass
NAME         PROVISIONER             AGE
local-path   rancher.io/local-path   63s

kubeflow는 기본 스토리지 클래스를 사용하기 때문에, local-path 스토리지 클래스를 기본 클래스로 설정해야합니다..

다음은 기본 스토리지 클래스를 설정하는 명령어입니다.

$ kubectl patch storageclass local-path -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

storageclass.storage.k8s.io/local-path patched

다시 스토리지 클래스를 조회해 보면, 기본 클래스가 설정된 것을 확인할 수 있습니다.

$ kubectl get sc
NAME                   PROVISIONER             AGE
local-path (default)   rancher.io/local-path   11m

kubeflow 설치하기

kubeflow를 설치하기 위해서, kftctl 릴리즈 페이지에서 다운로드 합니다. 이 글을 쓰는 시점에서는 v1.0버전이 최신이므로, v1.0 버전을 기준으로 설명하겠습니다.

$ mkdir ~/kubeflow
$ cd ~/kubeflow

$ curl -L -O https://github.com/kubeflow/kfctl/releases/download/v1.0/kfctl_v1.0-0-g94c35cf_linux.tar.gz

다운 받은 tar ball 을 풉니다.

$ tar -xvf kfctl_v1.0-0-g94c35cf_linux.tar.gz

kubflow 배포를 쉽게 하기 위해서, 다음과 같은 환경 변수들을 생성합니다. 환경 변수들의 자세한 내용은 해당 페이지를 확인 하시기 바랍니다.

export PATH=$PATH:"/home/kangwoo/kubeflow"

export CONFIG_URI="https://raw.githubusercontent.com/kubeflow/manifests/v1.0-branch/kfdef/kfctl_istio_dex.v1.0.1.yaml"


export KF_NAME=kf-test

export BASE_DIR=/home/kangwoo/kubeflow
export KF_DIR=${BASE_DIR}/${KF_NAME}

kfctl_existing_arrikto.yaml 설정 파일을 가지고, kubeflow를 배포하겠습니다. 해당 파일에는 다중 유저와 권한/인증 기능을 지원하는 부분이 정의 되어 있습니다.

mkdir -p ${KF_DIR}
cd ${KF_DIR}

# Download the config file and change the default login credentials.
wget -O kfctl_istio_dex.yaml $CONFIG_URI
export CONFIG_FILE=${KF_DIR}/kfctl_istio_dex.yaml

kfctl apply -V -f ${CONFIG_FILE}

kfctl apply 명령어를 실행하면, kubeflow가 설치되기 시작합니다.

다음은 kubeflow 네임스페이스와, istio-system 네임스페이스의 포드를 조회해 본 것입니다.

$ kubectl -n kubeflow get pod
NAME                                                           READY   STATUS      RESTARTS   AGE
admission-webhook-deployment-7b7888fc9b-9dlj9                  1/1     Running     0          2d23h
application-controller-stateful-set-0                          1/1     Running     0          2d23h
argo-ui-7ffb9b6577-xqcxc                                       1/1     Running     0          2d23h
centraldashboard-6944c87dd5-sfqc7                              1/1     Running     0          2d23h
jupyter-web-app-deployment-679d5f5dc4-6278n                    1/1     Running     0          2d23h
katib-controller-7f58569f7d-62pgx                              1/1     Running     1          2d23h
katib-db-manager-54b66f9f9d-wsxv5                              1/1     Running     5          2d23h
katib-mysql-dcf7dcbd5-4fpmj                                    1/1     Running     0          2d23h
katib-ui-6f97756598-dk8fz                                      1/1     Running     0          2d23h
metadata-db-65fb5b695d-b92zm                                   1/1     Running     0          2d23h
metadata-deployment-65ccddfd4c-242t7                           1/1     Running     1          2d23h
metadata-envoy-deployment-7754f56bff-6vftm                     1/1     Running     0          2d23h
metadata-grpc-deployment-7557fdc6bb-n7jd7                      1/1     Running     7          2d23h
metadata-ui-7c85545947-wwkh9                                   1/1     Running     0          2d23h
minio-69b4676bb7-zglc6                                         1/1     Running     0          2d23h
ml-pipeline-5cddb75848-tjbh9                                   1/1     Running     1          2d23h
ml-pipeline-ml-pipeline-visualizationserver-7f6fcb68c8-pw529   1/1     Running     0          2d23h
ml-pipeline-persistenceagent-6ff9fb86dc-ghj74                  1/1     Running     3          2d23h
ml-pipeline-scheduledworkflow-7f84b54646-mztnf                 1/1     Running     0          2d23h
ml-pipeline-ui-6758f58868-qc72b                                1/1     Running     0          2d23h
ml-pipeline-viewer-controller-deployment-745dbb444d-2xwdn      1/1     Running     0          2d23h
mysql-6bcbfbb6b8-6qb6p                                         1/1     Running     0          2d23h
notebook-controller-deployment-54f455c5c9-rpv8s                1/1     Running     0          2d23h
profiles-deployment-6fcb86d54c-9pdrs                           2/2     Running     0          2d23h
pytorch-operator-cf8c5c497-lntsm                               1/1     Running     0          2d23h
seldon-controller-manager-6b4b969447-b4gcj                     1/1     Running     0          2d23h
spark-operatorcrd-cleanup-knfpw                                0/2     Completed   0          2d23h
spark-operatorsparkoperator-76dd5f5688-2689x                   1/1     Running     0          2d23h
spartakus-volunteer-5dc96f4447-6ss4g                           1/1     Running     0          2d23h
tensorboard-5f685f9d79-7d8kp                                   1/1     Running     0          2d23h
tf-job-operator-5fb85c5fb7-vxkgv                               1/1     Running     0          2d23h
workflow-controller-689d6c8846-lmmdz                           1/1     Running     0          2d23h
k -n istio-system get pod
NAME                                                         READY   STATUS      RESTARTS   AGE
authservice-0                                                1/1     Running     0          2d23h
istio-citadel-79b5b568b-kqjw9                                1/1     Running     0          3d
istio-galley-756f5f45c4-kxkhr                                1/1     Running     0          3d
istio-ingressgateway-77f74c944c-z5frv                        1/1     Running     0          3d
istio-nodeagent-478g7                                        1/1     Running     0          3d
istio-nodeagent-rmbc5                                        1/1     Running     0          3d
istio-nodeagent-z49bb                                        1/1     Running     0          3d
istio-pilot-55f7f6f6df-k5mdm                                 2/2     Running     0          3d
istio-policy-76dbd68445-vskkp                                2/2     Running     0          3d
istio-security-post-install-release-1.3-latest-daily-2j5tr   0/1     Completed   0          3d
istio-sidecar-injector-5d9f474dcb-l5qjj                      1/1     Running     0          3d
istio-telemetry-697c8fd794-9hz9q                             2/2     Running     0          3d
prometheus-b845cc6fc-d7cq6                                   1/1     Running     0          3d

kubeflow 접속하기

kubeflow GUI에 접속해 보겠습니다. istio-ingressgateway 를 통해서 접속합니다. 여기서는 편의를 위해서 노드 포트(NodePort)를 사용하겠습니다.

다음은 istio-ingressgateway 서비스를 조회해 본 결과입니다.

$ kubectl -n istio-system get service istio-ingressgateway
NAME                   TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)                                                                                                                                      AGE
istio-ingressgateway   NodePort   172.30.86.239   <none>        15020:30113/TCP,80:31380/TCP,443:31390/TCP,31400:31400/TCP,15029:31134/TCP,15030:31251/TCP,15031:32398/TCP,15032:30455/TCP,15443:32764/TCP   3d

서비스 타입이 NodePort 이고, 80번 포트가 31380이라는 노드 포트로 열려있습니다. 브라우저를 실행하고, 해당 포트로 접속해보겠습니다.

기본 설정을 바꾸지 않았다면, 사용자 이름은 admin@kubeflow.org 이고, 비밀번호는 12341234 입니다.

로그인이 성공적으로 되면, 다음과 같이 사용할 네임스페이스를 생성하는 화면이 나옵니다. 원하는 이름을 입력하시면 됩니다. 기본값을 admin 으로 되어있습니다.

네임스페이스가 생성되면, kubeflow 대시보드 화면을 볼 수 있습니다.

참고

PC에 kubeflow 설치하기 – 2부 kubernetes, nvidia device-plugin 설치하기

swap 비활성화 하기

쿠버네티스(kubernetes)를 설치 하기 위해서 swap을 비활성화 합니다.

$ sudo swapoff -a

그리고 재부팅 하였을때 swap이 다시 활성화되는 것을 막기 위해서, /etc/fstab 에 있는 swap 관련 부분을 주석 처리하거나, 제거해 줍니다.

$ sudo vi /etc/fstab
 
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
/dev/mapper/ubuntu--vg-root /               ext4    errors=remount-ro 0       1
# /boot/efi was on /dev/nvme0n1p1 during installation
UUID=D21A-9B89  /boot/efi       vfat    umask=0077      0       1
# /dev/mapper/ubuntu--vg-swap_1 none            swap    sw              0       0

iptables 설치하기

iptables을 설치하고, 필요에 따라서 iptables tooling을 legacy 모드로 변경합니다.

# ensure legacy binaries are installed
$ sudo apt-get install -y iptables arptables ebtables

# switch to legacy versions
sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
sudo update-alternatives --set arptables /usr/sbin/arptables-legacy
sudo update-alternatives --set ebtables /usr/sbin/ebtables-legacy

kubelet, kubeadm, kubectl 설치하기

쿠버네티스 설치에 필요한 kubelet, kubeadm, kubectl을 설치합니다. 버전을 명시해 주지 않으면, 최선 버전으로 설치됩니다. kubeflow 문서에 따르면 현재 권장하는 쿠버네티스 버전은 1.14 입니다. 1.15 버전도 호환이 되기 때문에, 이 글에서는 1.15.10-00 버전으로 설치 하였습니다.

$ 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.15.10-00 kubeadm=1.15.10-00 kubectl=1.15.10-00
$ sudo apt-mark hold kubelet kubeadm kubectl

쿠버네티스 설치하기

kubeadm을 사용해서 쿠버네티스를 설치합니다. 포드 네트워크 애드온을 cilium을 사용할 것이기 때문에 --pod-network-cidr=10.217.0.0/16 옵션을 사용하겠습니다.

다음 명령어를 실행해서 쿠버네티스를 설치합니다.

$ sudo kubeadm init --pod-network-cidr=10.217.0.0/16

설치가 완료되면, kubectl을 사용하기 위해서 관리자 설정 파일을 유저 디렉토리로 복사합니다.

$ 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
Kubernetes master is running at https://192.168.21.36:6443
KubeDNS is running at https://192.168.21.36:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

이제 Cilium을 쿠버네티스에 설치합니다.

$ kubectl create -f https://raw.githubusercontent.com/cilium/cilium/v1.6/install/kubernetes/quick-install.yaml

cilim 포드의 READY가 1/1이 되면, 쿠버네티스 클러스터를 사용할 수 있습니다.

$ kubectl get pods -n kube-system --selector=k8s-app=cilium
NAME           READY   STATUS    RESTARTS   AGE
cilium-k4l5b   1/1     Running   0          70s

Control plane 노드 격리 해제하기

기본적으로 쿠버네티스 클러스터의 컨트롤 플레인(control-plane) 노드에는 보안상의 이유로 노드가 격리되어 있어서, 포드가 스케줄링되지 않습니다. 이 문서에는 1대의 머신만을 사용하기 때문에 노드 격리를 해제하겠습니다.

다음 명령어로 노드 격리를 해제 시킵니다.

$ kubectl taint nodes --all node-role.kubernetes.io/master-
node/mortar untainted

nvidia plugin 설치하기

쿠버네티스에서 GPU를 사용하기 위해서, nvidia k8s-device-plugin 을 설치합니다. 이 문서를 작성하는 시점에서는 1.12가 최신버전이라서 1.12로 설치하겠습니다.

$ kubectl apply -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v1.12/nvidia-device-plugin.yml

daemonset.extensions/nvidia-device-plugin-daemonset-1.12 created

참고로, 쿠버네티스 1.15 버전을 설치했을 경우에는 문제가 없을 건데, 1.16 버전 이상을 설치 했을 경우, 다음과 같은 에러가 발생할 것입니다. 자세한 사항은 해당 페이지를 참고 바랍니다.

error: unable to recognize "https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v1.12/nvidia-device-plugin.yml": no matches for kind "DaemonSet" in version "extensions/v1beta1"

쿠버네티스 버전이 올라가면서, Daemonsetextensions/v1beta1 버전을 더 이상 지원하지 않아서 입니다. 버전을 apps/v1 으로 변경하고 selector를 추가한 후, k8s-device-plugin 을 다시 설치합니다.

다음은 변경한 1.17 버전에 맞게 변경한 메니페스트 파일입니다.

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nvidia-device-plugin-daemonset-1.12
  namespace: kube-system
spec:
  updateStrategy:
    type: RollingUpdate
  selector:
    matchLabels:
      name: nvidia-device-plugin-ds
  template:
    metadata:
      # Mark this pod as a critical add-on; when enabled, the critical add-on scheduler
      # reserves resources for critical add-on pods so that they can be rescheduled after
      # a failure.  This annotation works in tandem with the toleration below.
      annotations:
        scheduler.alpha.kubernetes.io/critical-pod: ""
      labels:
        name: nvidia-device-plugin-ds
    spec:
      tolerations:
      # Allow this pod to be rescheduled while the node is in "critical add-ons only" mode.
      # This, along with the annotation above marks this pod as a critical add-on.
      - key: CriticalAddonsOnly
        operator: Exists
      - key: nvidia.com/gpu
        operator: Exists
        effect: NoSchedule
      containers:
      - image: nvidia/k8s-device-plugin:1.11
        name: nvidia-device-plugin-ctr
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop: ["ALL"]
        volumeMounts:
          - name: device-plugin
            mountPath: /var/lib/kubelet/device-plugins
      volumes:
        - name: device-plugin
          hostPath:
            path: /var/lib/kubelet/device-plugins
EOF

device-plugin 포드가 정상적으로 작동했는지 확인해 봅니다.

$ kubectl -n kube-system get pod -l name=nvidia-device-plugin-ds
NAME                                        READY   STATUS    RESTARTS   AGE
nvidia-device-plugin-daemonset-1.12-4kt95   1/1     Running   0          24s

$ kubectl -n kube-system logs  -l name=nvidia-device-plugin-ds
2020/02/09 09:05:10 Loading NVML
2020/02/09 09:05:10 Fetching devices.
2020/02/09 09:05:10 Starting FS watcher.
2020/02/09 09:05:10 Starting OS watcher.
2020/02/09 09:05:10 Starting to serve on /var/lib/kubelet/device-plugins/nvidia.sock
2020/02/09 09:05:10 Registered device plugin with Kubelet

GPU 테스트 하기

다음은 텐서플로를 이용해서, GPU를 테스트 해 보는 예제입니다. 단순한 테스트이기 때문에 무시하고 넘어가도 됩니다.

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: tf-gpu-jupyter
  name: tf-gpu-jupyter
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tf-gpu-jupyter
  template:
    metadata:
      labels:
        app: tf-gpu-jupyter
    spec:
      containers:
      - image: tensorflow/tensorflow:2.1.0-gpu-py3-jupyter
        imagePullPolicy: IfNotPresent
        name: tf-gpu-jupyter
        ports:
        - containerPort: 8888
          protocol: TCP
        resources:
          limits:
            nvidia.com/gpu: "1"
EOF

tf-gpu-jupyter 라는 이름을 가진 GPU를 사용할 수 있는 텐서플로 주피터(jupyter)를 생성하였습니다. 포드가 정상적으로 작동했는지 확인해 봅니다.

$ kubectl get pod -l app=tf-gpu-jupyter
NAME                              READY   STATUS    RESTARTS   AGE
tf-gpu-jupyter-66f89b64cd-vrllc   1/1     Running   0          5m58s

주피터 접속에 필요한 토큰 정보를 얻기 위해서 로그를 조회해 보겠습니다.

$ kubectl logs -l app=tf-gpu-jupyter
[I 09:15:25.009 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[C 09:15:25.012 NotebookApp] 
    
    To access the notebook, open this file in a browser:
        file:///root/.local/share/jupyter/runtime/nbserver-1-open.html
    Or copy and paste one of these URLs:
        http://tf-gpu-jupyter-66f89b64cd-vrllc:8888/?token=6527214998b8d895f6f14a8901a39ba6d8420c43e68f6919
     or http://127.0.0.1:8888/?token=6527214998b8d895f6f14a8901a39ba6d8420c43e68f6919
[I 09:17:20.916 NotebookApp] 302 GET / (127.0.0.1) 0.53ms
[I 09:17:20.926 NotebookApp] 302 GET /tree? (127.0.0.1) 0.65ms

포드에 접속하기 위해서 port-forward를 사용하겠습니다.

$ kubectl port-forward pod/tf-gpu-jupyter-66f89b64cd-vrllc 8888:8888
Forwarding from 127.0.0.1:8888 -> 8888
Forwarding from [::1]:8888 -> 8888

kubectl delete deployment tf-gpu-jupyter
deployment.apps "tf-gpu-jupyter" deleted

포트 포워드가 활성화 되면, 브라우저에서 주피터 주소를 입력합니다. 포드 로그에서 봤던 주소를 입력하면 됩니다. 이 예제에서 주소는 http://127.0.0.1:8888/?token=6527214998b8d895f6f14a8901a39ba6d8420c43e68f6919 입니다.

정상적으로 접속이 되면, 다음과 같은 화면을 보실 수 있습니다.

사용 가능한 GPU 갯수를 확인하겠습니다. 파이썬3 노트북을 생성한 후, 다음 코드를 입력합니다.

from __future__ import absolute_import, division, print_function, unicode_literals

import tensorflow as tf
print("Num GPUs Available: ", len(tf.config.experimental.list_physical_devices('GPU')))

코드를 실행하면 다음과 같이 사용 가능한 GPU 개수가 출력될 것입니다.

확인을 다 했으면, 브라우저를 종료하고, 자원 낭비를 막기 위해서 디플로이먼트를 삭제하도록 하겠습니다. 우리의 GPU는 소중하니까요.

$ kubectl delete deploy tf-gpu-jupyter

참고

  • https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
  • https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/
  • https://github.com/NVIDIA/k8s-device-plugin
  • https://hub.docker.com/r/tensorflow/tensorflow/
  • https://www.tensorflow.org/guide/gpu

PC에 kubeflow 설치하기 – 1부 nvidia 드라이버, docker 설치하기

이 글은 지적 유희를 위해서 작성하였습니다. kubeflow 자체가 목적이신 분들은, miniKFGCP를 사용하시길 추천드립니다.

시스템 사항

다음은 이 글에서 사용한 PC의 사양입니다. kubeflow를 원활하게 설치하기 위해서는 램이 16GB 이상, CPU는 4코어 이상을 추천합니다. GPU를 사용하기 위해서 nvidia 그래픽 카드도 필요합니다.

프로세서amd 라이젠 5 3600
RAM32GB
그래픽 카드RTX-2060
스토리지 공간 다다익선

설치 목록

  • ubuntu 18.04 LTS
  • nvidia driver 435
  • docker CE 18.9
  • nvidia-docker2
  • kubernetes 1.15.10
  • cilium 1.6
  • nvidia-device-plugin-daemonset 1.12
  • kubeflow 1.0RC4 with istio 1.3

전체 목록

우분투 설치하기

우분투는 데스크탑 18.04 LTS 버전을 사용합니다. 설치 방법은 다른곳에 많이 나와있기 때문에 생략합니다. 다만 nvidia 그래픽 카드를 사용할 경우 문제가 생기기 때문에, 그 부분만 다루겠습니다.

nvidia driver 설치하기

우분투 18.04 환경에서 RTX-2060을 사용할 경우 nouveau 문제가 있습니다. RTX-2060가 장착되어 있는 장비에서 우분투를 설치할 경우 nouveau로 자동 설정되기 때문이다. 그래서 nouveau 를 제거하는 작업이 필요합니다.

우분투 설치 화면이 깨져서 보이지 않는다면, 설치 전에 nomodset 옵션을 추가해줘야 정상적인 화면을 볼 수 있습니다.

우분투를 설치 하기 전 GRUB 메뉴 화면에서 e 키를 누룹니다.

e 키를 누르면, 다음과 같이 파라메터를 편집할 수 있는 화면이 나옵니다.

quiet splash 뒤에 nomodeset 을 추가해 줍니다. 그리고 F10 키를 눌러서 부팅 합니다.

정상적으로 화면이 보일 것입니다. 우분투를 설치하는 나머지 과정은 생략하겠습니다.

nouveau 설치 확인 하기

우분투가 정상적으로 설치되었다면, 재부팅 후 nouveau 확인 작업을 합니다. 시스템이 다시 시작되면, 앞서 한 것과 동일한 방법으로, nomodset 옵션을 추가해줘야 정상적인 화면을 볼 수 있을것입니다.

부팅이 완료되면 터미널을 열어서 작업을 시작합니다.

터미널에서 다음 명령어를 실행한 후, 결과가 보이면 nouveau가 설치되어 있는 것입니다. nvidia 드라이버 설치를 위해서 제거해야 합니다.

$ lsmod | grep nouveau
nouveau              1863680  0
mxm_wmi                16384  1 nouveau
video                  49152  1 nouveau
i2c_algo_bit           16384  1 nouveau
ttm                   102400  1 nouveau
drm_kms_helper        180224  1 nouveau
drm                   479232  3 drm_kms_helper,ttm,nouveau
wmi                    28672  3 wmi_bmof,mxm_wmi,nouveau

/etc/modprobe.d/ 경로에 blacklist 파일을 생성합니다.

$ sudo vi /etc/modprobe.d/blacklist-nouveau.conf

blacklist nouveau
options nouveau modset=0

다음 명령어를 실행 한 후, 재부팅 합니다.

$ sudo update-initramfs -u
$ sudo service gdm stop

Nvidia 드라이버 설치하기

컨테이너(Container)를 이용해서 GPU를 사용할 예정이기 때문에, Nvidia 드라이버가 설치합니다.

$ sudo add-apt-repository ppa:graphics-drivers/ppa
$ sudo apt-get update

$ sudo apt-get install nvidia-driver-435
$ sudo reboot

재부팅 후, nvidia-smi 명령어를 실행해서, 드라이버가 정상적으로 설치되어 있는지 확인해 볼 수 있습니다.

$ nvidia-smi
Sun Feb 16 17:26:22 2020       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 435.21       Driver Version: 435.21       CUDA Version: 10.1     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce RTX 2060    Off  | 00000000:26:00.0  On |                  N/A |
| 32%   45C    P8     9W / 190W |    189MiB /  5931MiB |      1%      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|    0       975      G   /usr/lib/xorg/Xorg                            96MiB |
|    0      1123      G   /usr/bin/gnome-shell                          91MiB |
+-----------------------------------------------------------------------------+

docker 설치하기

apthttps저장소를 사용할 수 있도록 패키지를 추가합니다.

$ sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common

도커의 GPG 키를 추가합니다.

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

저장소를 추가합니다

$ sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

apt 패키지의 인덱스를 업데이트합니다.

$ sudo apt-get update

이 문서를 작성할 당시(2020-02-08)에 도커의 최선 버전은 19.03이였습니다. 19.03 버전 부터 GPU 관련한 내용이 변경되었습니다. 쿠버네티스상에서 GPU 관련 작업을 하라면, k8s-device-plugin이 필요한데, 아직 19.03 버전을 지원하지 않는 것 같습니다. 그래서 18.9 버전을 설치하였습니다.

도커 엔진 18.9 버전을 설치합니다.

$ sudo apt-get install docker-ce=5:18.09.9~3-0~ubuntu-bionic docker-ce-cli=5:18.09.9~3-0~ubuntu-bionic containerd.io

$ sudo apt-mark hold docker-ce docker-ce-cli

설치 가능한 도커 버전을 보려면 다음 명령어를 실행하면 됩니다.

$ apt-cache madison docker-ce
 docker-ce | 5:19.03.5~3-0~ubuntu-bionic | https://download.docker.com/linux/ubuntu bionic/stable amd64 Packages
 docker-ce | 5:19.03.4~3-0~ubuntu-bionic | https://download.docker.com/linux/ubuntu bionic/stable amd64 Packages
 docker-ce | 5:19.03.3~3-0~ubuntu-bionic | https://download.docker.com/linux/ubuntu bionic/stable amd64 Packages
 docker-ce | 5:19.03.2~3-0~ubuntu-bionic | https://download.docker.com/linux/ubuntu bionic/stable amd64 Packages
 docker-ce | 5:19.03.1~3-0~ubuntu-bionic | https://download.docker.com/linux/ubuntu bionic/stable amd64 Packages
 docker-ce | 5:19.03.0~3-0~ubuntu-bionic | https://download.docker.com/linux/ubuntu bionic/stable amd64 Packages
 docker-ce | 5:18.09.9~3-0~ubuntu-bionic | https://download.docker.com/linux/ubuntu bionic/stable amd64 Packages
 docker-ce | 5:18.09.8~3-0~ubuntu-bionic | https://download.docker.com/linux/ubuntu bionic/stable amd64 Packages
 docker-ce | 5:18.09.7~3-0~ubuntu-bionic | https://download.docker.com/linux/ubuntu bionic/stable amd64 Packages
...

도커가 정상적으로 설치되었는지 확인해 보기 위해서 hello-world 이미지를 실행합니다.

$ sudo docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete 
Digest: sha256:9572f7cdcee8591948c2963463447a53466950b3fc15a247fcad1917ca215a2f
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.
...

nvidia-docker2 설치하기

컨테이너에서 GPU를 사용하기 위해서 nvidia-docker2 을 설치합니다. 그리고 도커를 재시작 합니다.

# Add the package repositories
$ 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 update
$ sudo apt-get install nvidia-docker2
$ sudo systemctl restart docker

nvidia-docker2 가 정상적으로 설치되었는지 확인해 보기 위해서, 다음 명령어를 실행합니다.

$ sudo docker run --runtime nvidia nvidia/cuda:10.0-base nvidia-smi
Sat Feb  8 11:19:15 2020       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 435.21       Driver Version: 435.21       CUDA Version: 10.1     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce RTX 2060    Off  | 00000000:26:00.0  On |                  N/A |
| 29%   40C    P8     9W / 190W |    229MiB /  5931MiB |      1%      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
+-----------------------------------------------------------------------------+

도커의 기본 런타임을 변경해 줍니다. /etc/docker/daemon.json 파일이 생성되었을 것입니다. 해당 파일을 열여서 "default-runtime": "nvidia"을 추가해주면 됩니다.

$ sudo vi /etc/docker/daemon.json

    {
      "default-runtime": "nvidia", 
      "runtimes": {
        "nvidia": {
          "path": "nvidia-container-runtime",
          "runtimeArgs": []
        }
      }
    }

파일을 수정한 후, 도커를 재시작합니다.

$ sudo systemctl restart docker

참고

  • https://docs.docker.com/install/linux/docker-ce/ubuntu/
  • https://github.com/NVIDIA/nvidia-docker