Docker 설치와 실행 방법에 대해서 정리한 글입니다.


최근에 여러 환경에서 딥러닝 실험을 해야될 일이 있었습니다. 그때마다 가장 애먹는 부분이 바로 CUDA입니다. Hardware 마다 지원하는 driver도 다르고, driver마다 지원하는 cuda toolkit도 다릅니다. 또 pytorch version에 따라 AMP(Automatic Mixed Precision)가 안될 때도 있습니다. (벌써 머리가 지끈지끈)


이러한 변수를 다 고려해서 초기 환경 세팅을 하려면 시간도 많이 걸리고 매우 번거롭습니다. 이를 해결해준게 바로 도커입니다!! 정말 유용한 tool이라서 모두에게 소개시켜주고자 이 글을 쓰게 됐습니다. 어쨌든 “다들 도커 쓰세요!! 두번 쓰세요!”


Docker 란?

Docker는 애플리케이션을 신속하게 구축, 테스트 및 배포할 수 있는 소프트웨어 플랫폼입니다. Docker가 이런 장점을 가지는 이유는 애플리케이션을 실행하는 데 필요한 모든 것을 가지고 있기 때문입니다. 예를 들어 라이브러리, 미들웨어, OS, 네트워크 설정 등을 포함하고 있습니다. 평소에는 서비스 운영에 필요한 파일들을 이미지 형태로 묶어서 가지고 있습니다. 이미지는 불변성을 가지므로 바로 사용할 수 없습니다. 해당 이미지를 사용하기 위해서는 이미지를 실행시켜서 독립적인 컨테이너를 만들어야합니다.


이미지가 불변성을 가지고 있더라도 실제 환경에 적용하기 위해선 도커 이미지를 자기 입맛에 맞게 만드는 과정이 필요합니다. 이때 필요한 것이 Dockerfile입니다. Dockerfile은 Docker 이미지가 어떤 단계를 거쳐 build되어야 하는지를 담고있는 텍스트 파일입니다. 이 Dockerfile을 build하 원하는 이미지를 생성할 수 있습니다.


마지막으로 run 명령어를 사용해서 도커 이미지를 실행시켜 줍니다. Dockerfile을 사용해서 이미지를 입맛에 맞게 만들어주었지만, 어떻게 각자 환경에 맞게 컨테이너를 실행 시켜야하는지 고민이 됩니다. Dockerfile은 전체를 위한 세팅이지만, 여기서는 개인에 맞는 세팅을 해야됩니다. 각자 개발 환경에 맞추려면 run 명령어와 다양한 option들을 사용해야됩니다. docker-compose라는 파일로 실행 시킬 수 있지만, 이번 포스팅에서는 다루지 않겠습니다. 옵션은 local 환경에서 실행할 때 주로 사용하는 것을 다룰 예정입니다. 지금까지 설명한 내용을 그림으로 표현하면 아래와 같습니다.

img

딥러닝 실험 환경

딥러닝에서 실험은 매우 중요한 요소를 차지하고 있습니다. 가설을 설정하고 이를 증명하기 위해서는 많은 양의 실험이 필요합니다. 더군다나 이 모델의 성능을 높이고 여러 production에 적용해야 된다면 필요한 실험의 양은 점점 방대해집니다. 그렇기 때문에 실험을 혼자가 아닌 여러명이서 동일한 환경에서 작업해야 됩니다. 딥러닝 실험을 “실험 도구”, “실험 수행”, “실험 환경”에서 살펴보겠습니다.


딥러닝에서 실험 도구는 대표적으로 Tensorflow, Pytorch 등이 있습니다. 이러한 Framework는 연구자가 원하는 언어를 사용하면 됩니다. 저는 주로 pytorch와 pytorch-lightning을 사용합니다. 이에 대한 자세한 내용은 다음 포스팅에서 다뤄보겠습니다.


실험 도구가 정해졌다면 본격적으로 실험 수행을 합니다. 실험을 수행하다보면 다양한 산출물이 나오게 됩니다. 제 경우에 수십번, 수백번 정도 학습을 진행하다 보면 혼란스러워 질 때가 종종 있었습니다. 처음 진행하려던 방향과 달라지고, 이전 실험 결과가 떠오르지 않은 경우가 있었습니다. 그래서 log와 artifact를 기록할 수 있는 도구에 관심이 많아졌고, 최근에도 계속해서 공부 중입니다. 관련 글은 아래 링크에서 보실 수 있습니다.


WandB란? - 강력한 MLOps Tool

딥러닝에서 도커의 필요성

그 중에서도 딥러닝에서 실험 환경은 매우매우 중요합니다. 제가 중요하다고 생각한 이유는 3가지의 이유 때문입니다.

  1. 재현성
  2. 생산성
  3. 확장성

논문을 탐색하며 github 링크가 있을 때는 정말 기쁩니다. 논문의 코드를 직접 실행하는 것만으로도 인사이트를 얻을 수 있습니다. 가령 논문에서 생략되어있는 loss function, optimizer 등을 github 코드에서 찾아 볼 수 있습니다. 또한 실험 결과를 직접 비교해보면서 논문의 신뢰도를 판가름 할 수 있을 겁니다. 물론 논문의 저자가 거짓을 말하는 것은 아니지만 연구의 결과를 재현할 수 없다면 그 결과는 객관적인 지식으로 볼 수 없는 거죠. 이때 도커를 사용하면 동일한 환경에서 실험을 진행하기 때문에 실험의 주체가 누구인지에 상관없이 동일한 결과가 나올 확률이 높아집니다.


이에 더해서 동일한 환경을 세팅하는 데 Dockerfile만 있으면 되기 때문에 세팅 시간도 굉장히 절약됩니다. 물론 github 링크에 해당 논문에서 사용된 Dockerfile이 있어야 되지만요. Dockerfile과 이 파일을 실행시켜주는 docker-compose 파일이 있다면 무한한 감사가 생기게 됩니다. 하지만 논문 뿐만 아니라, 협업을 할 때 Dockerfile만 있다면 동일한 환경에서 실험을 진행할 수 있습니다.


이는 바로 확장성으로 이어지게 됩니다. 만일 Docker 없이 10명의 사람과 협업을 진행한다고 하면 일일히 동일하게 환경을 세팅해줘야 합니다. 가령 pytorch, numpy, opencv 등의 version을 맞춰주는 일이 있습니다. 물론 anaconda로 환경 세팅을 진행 할 수 있지만, cuda version이 안 맞는 경우 또 다른 문제에 봉착할 수 있습니다. docker를 사용하면 module의 vesion은 물론이고 동일한 os 환경에서 개발하는 것과 같은 이점을 가져다 줍니다.

도커 사용법

이제 본격적으로 도커 사용법에 대해서 알아봅시다. 이번 글은 개발 환경이 아닌, 우분투 ssh 서버 환경에서의 딥러닝 실험에 초점을 맞췄습니다. 그렇기 때문에 local gpu를 사용하기 위해 nvidia-docker를 설치하는 과정도 포함되어 있습니다.

도커 설치하기

  1. 이전 도커 제거
# docker 설치 확인
$ docker
# docker 제거
$ sudo apt purge docker-ce
  1. 도커 설치

    $ wget -qO- <https://get.docker.com> | sh -
    
    ...(중략)
    ================================================================================
    
    To run Docker as a non-privileged user, consider setting up the
    Docker daemon in rootless mode for your user:
    
        dockerd-rootless-setuptool.sh install
    
    Visit <https://docs.docker.com/go/rootless/> to learn about rootless mode.
    
    To run the Docker daemon as a fully privileged service, but granting non-root
    users access, refer to <https://docs.docker.com/go/daemon-access/>
    
    WARNING: Access to the remote API on a privileged Docker daemon is equivalent
             to root access on the host. Refer to the 'Docker daemon attack surface'
             documentation for details: <https://docs.docker.com/go/attack-surface/>
    
    ================================================================================
    
  2. 도커 설치 확인

    $ docker -v
    Docker version 20.10.12, build e91ed57
    
    • 도커의 버전을 확인합니다.
  3. Hello world

    $ sudo -i
    $ docker run hello-world
    
    • hello-world를 실행해서 도커가 정상적으로 설치된 것을 확인할 수 있습니다.
  4. Docker 권한 설정

    $ sudo usermod -aG docker $USER # 현재 접속중인 사용자에게 권한주기
    $ sudo usermod -aG docker pung  # pung 사용자에게 권한주기
    
    • 도커를 처음 설치하면 관리자 계정으로 컨트롤 해야됩니다.

    • 권한을 허용하기 위해서는 따로 권한을 부여해야됩니다.

    • 저는 pung이라는 사용자로 접속중이기 때문에 pung에게 권한을 줬습니다.

  5. Nvidia Toolkit 설치

    $ distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
    $ curl -s -L <https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.repo> |
    $ sudo tee /etc/yum.repos.d/nvidia-docker.repo
    $ 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 -y nvidia-container-toolkit
    $ sudo systemctl restart docker
    
    • 도커 컨테이너 내에서 GPU를 실행할 수 없습니다.
    • 그렇기 때문에 host gpu driver와 docker를 연동시켜주는 Nvidia-docker를 설치해야됩니다.
  • gpu 확인하기

    • CUDA 11 기준
    $ docker run --rm --gpus all nvidia/cuda:11.0-base nvidia-smi
    
    • 위의 명령어를 사용하면 정상적으로 gpu가 할당되는지 확인할 수 있습니다.

도커 컨테이너 조작하기

  1. 도커 이미지 가져오기

    img

    $ docker pull pytorch/pytorch:1.10.0-cuda11.3-cudnn8-devel
    
    • 자신의 환경과 맞는 도커 이미지를 선택해서 pull 수행합니다.
    • 도커 허브의 repository 내의 Tags를 클릭하면 원하는 version을 선택할 수 있습니다.
  2. 도커 실행하기

    제가 자주 사용하고 유용하다고 생각하는 옵션도 추가로 설명 드리겠습니다.

    $ docker run -d --name [NAME] --gpus all --ipc=host -v [LOCAL_DIR]:/[DOKER_DIR] [IMAGE_NAME] python -m http.server
    
    • 예시
    $ docker run \
    -d \
    --name torch \
    --gpus all \
     --ipc=host \
     -v $(pwd):/workspace \
    pytorch/pytorch:1.10.0-cuda11.3-cudnn8-devel \
    python -m http.server
    
    • docker 이미지를 실행 시키기 위해서는 docker run 명령어를 수행해야 됩니다.

      • -d 옵션: 백그라운드에서 실행
      • –name 옵션: 컨테이너 이름 지정
      • –gpus 옵션: 사용할 gpu 할당
      • –ipc 옵션: numworker 사용
      • -v 옵션: local 저장소를 컨테이너와 연동
      • python -m http.server: docker를 background에서 실행 시키기 위함
    • 이 외에도 다양한 명령어가 존재하지만, 해당 글에서는 다루지 않겠습니다.

    • run 명령어를 수행하면 다음과 같이 나옵니다

      img

  3. 컨테이너 확인하기

    $ docker ps
    

    img

    • docker ps를 사용해서 현재 가동중인 컨테이너를 확인할 수 있습니다.

    • -a 옵션을 추가하면 가동되지 않거나, 멈춘 컨테이너를 확인할 수 있습니다.

      $ docker ps -a
      

      img

  4. 도커 내부에 접속하기

    $ docker exec -it [CONTAINER_NAMES] bash
    

    img

    • docker exec 명령을 사용해서 컨테이너 내부로 들어가겠습니다.
    • 실행중인 컨테이너의 shell에 접속할 수 있습니다.
    • 이때 -it 옵션은 컨테이너의 shell이나 CLI 도구를 사용할 때 쓰는 옵션입니다.
  5. GPU 동작 확인

    $ python
       
    >>> import torch
    >>> torch.cuda.is_available()
    

    img

    • 이제 도커 컨테이너에 접속이 되면 local GPU와 호환이 되고 있는지 확인하는게 중요합니다.
    • torch.cuda.is_available() 결과 True로 나왔으니 gpu가 잘 실행되고 있는 것 같습니다!

Docker 업로드하기

  1. docker hub에 로그인하기

    $ docker login
    

    img

    • docker image를 docker hub로 올리기 위해서 login을 진행합니다.
    • docker hub는 github처럼 pull/push를 통해서 이미지를 공유할 수 있습니다.
  2. 이미지화 하기전에 컨테이너 중단하기

    $ docker stop [CONTAINER_NAMES]
    

    img

    • image로 만들기 전에 컨테이너를 중단시켜야합니다.
    • Stop 명령어 후에 실행중인 컨테이너가 2개에서 1개로 줄어든 모습을 볼 수 있습니다.
  3. 배포할 컨테이너를 이미지로 만들기

    $ docker commit [CONTAINER_NAMES] [hub ID]/[image명]:[tag]
    

    img

    • commit을 하면 자신의 docker Hub 아이디와 이미지명, tag명을 위와 같이 적은 대로 이미지가 생성됩니다.
  4. 이미지 업로드하기

    $ docker push [hub ID]/[image명]:[tag]
    

    img

    • push를 하면 정상적으로 업로드가 됩니다.
  • 배포 결과

    img

그외 다양한 TIP

  • 컨테이너에서 git 설치하기

    $ apt-get update
    $ apt-get install git
    
    • 현재 컨테이너에서 git을 설치하려면 apt-get을 먼저 업데이트 해야됩니다.
  • 변경사항 살펴보기

    $ docker diff [CONTAINER_NAMES]
    
    • 다운 받은 이미지로 부터 어떠한 변경사항이 있는지 보여줍니다.
  • 도커 이미지 검색하기

    $ docker search [IMAGE_NAME]
    
    • 원하는 이미지 명을 입력해서 검색할 수 있습니다.

    img

    • pytorch로 검색했을 때는 여러 이미지가 검색되고 star의 개수도 볼 수 있습니다.
  • docker 자동 접속

    docker run —restart=always
    
    • docker를 종료할 때 container 또한 자동으로 종료되는데, 이때 restart 옵션을 주게 되면 docker가 실행 될 때 바로 container 접속이 가능해 집니다.
  • local 드라이브 마운트하기

    docker run -v [Local Drive]:[Docker Drive]
    
    • 위와 같이 사용하고자 하는 local 드라이브의 경로와 작업을 수행할 Docker 드라이브의 경로를 설정하면 도커 환경에서 로컬의 데이터를 사용할 수 있습니다.

Reference

https://89douner.tistory.com/96?category=878197

https://www.daleseo.com/docker-volumes-bind-mounts/

https://soyoung-new-challenge.tistory.com/54

https://yangeok.github.io/devops/2019/01/19/git-in-docker-container.html

https://greeksharifa.github.io/references/2021/06/21/Docker/

https://losskatsu.github.io/it-infra/docker02/#