가장 쉬운 딥러닝 코딩환경 구축 방식 - docker & vscode

가장 쉬운 딥러닝 코딩환경 구축 방식 - docker & vscode

환경 구축을 못해서 딥러닝 코딩을 못한다?

ChatGPT의 영향으로 많은 사람들이 인공지능을 공부한다. 이제는 학부 수업에도 인공지능 코딩이 들어가고, 졸업 작품도 인공지능에 기반한 프로젝트를 하는 것 같다. 그만큼 많은 사람들이 관심을 가지고 딥러닝 코딩에 도전하고 있다.

그들 대부분은 jupyter notebook으로 딥러닝 코딩을 시작하게 될 것이다. 그리고 어느 순간 좀 더 진지한 연구를 위해 오리지널 python으로 눈을 돌리게 된다. 이때 처음 난관을 마주하게 되는데, 그것은 바로 딥러닝 코드가 돌아가는 환경을 구축하는 일이다.

연구소에서 다른 사람들 환경 설정해주느라 정신이 없다.

석사 후 연구소에서 근무하던 친구가 한 말이다. 인터넷에 나와 있는대로 따라했는데 pytorch가 안깔린다는 둥, 그래픽 카드 드라이버가 안잡힌다는 둥, 환경 구축은 정말로 짜증나는 일이다.

이는 딥러닝 코딩을 위해 설치해야할 것들이 굉장히 많고 그 과정에 호환성도 생각해야하기 때문이다. 간단히 생각나는 것들을 적어보면 이렇다.

  1. Nvidia graphic card driver: 내가 가진 graphic card와 호환되는 버전
  2. python과 파이썬 패키지 관리툴(conda 혹은 pip)
  3. Deep learning package: Nvidia graphic card driver와 호환되는 버전의 pytorch/tensorflow
  4. Cuda: graphic card driver 및 pytorch/tensorflow와 호환되는 버전의 cuda 패키지
  5. 코딩을 위한 editor: vscode

항목 수만 해도 많은데, 진짜 문제는 이들 간 상호 호환성을 고려해야한다는 것이다. 예를들어, 내 그래픽카드 기종에 따라 설치할 수 있는 driver의 버전이 다르고, 설치된 driver 버전에 따라 설치할 수 있는 pytorch나 tensorflow의 버전이 다르다. 하나라도 어긋나면 제대로 동작하지 않는 상황이 발생할 수 있다. 이러니 사람들이 딱 한번 구성에 성공하면, 그 환경을 A, B, 그리고 C 프로젝트까지 모든 프로젝트에 사용하게 된다.

그러나 이건 또다른 문제를 낳는다. A 프로젝트의 파이썬 패키지들 버전이 너무 낮아서 B에서 버전을 업그레이드 했는데, 다시 C에서 낮은 버전이 필요한 경우가 있을 수도 있다. 그래서 가능하면 각 프로젝트 별로 환경을 따로 쓰는 방식이 필요해진다. (보통은 conda나 venv로 가상환경을 잡아서 이런 구분을 한다.)

문제는 이게 끝이 아니다. 더 심각한 문제가 있다. 하드웨어가 달라지더라도 개발한 모델이 동작하는 환경을 그대로 재현할 수 있을까? 그러니까, 각 프로젝트 별로 구동할 pc의 그래픽카드가 다를 수 있고 그에 따라 설치된 드라이버가 달라질텐데, 이들에 맞출 수 있느냔 것이다.

이런 고민은 개발자들이 이미 했던 것이다. 최근의 개발자들은 도커를 통해 가상환경을 구축하여 하드웨어가 달라져도 동일하게 구동할 수 있는 방식을 채택함으로써 이걸 해결하는 것 같다.

그래서 나는 딥러닝 환경구축에 이 방식을 적용했고, 실제 이 환경에서 딥러닝 코딩을 하고 있다. 이번 포스팅은 이 방식의 튜토리얼이 되겠다.

우리가 구축할 환경

우리는 다음처럼 딥러닝 코딩 환경을 구축하게 될 것이다.

  1. Host PC (서버 혹은 코딩용 개인 pc)
    1. nvidia driver
    2. docker
    3. nvidia container tookit
    4. vscode
    5. git
    6. docker-compose
  2. 도커 컨테이너 인스턴스
    1. nvidia driver
    2. cuda
    3. python
    4. pytorch
    5. pip (conda)

가능하면 host pc는 리눅스 환경이면 좋을 것 같다. 윈도우 환경에서는 WSL을 깔고 그 위에 docker가 가동되는 것 같더라. 그만큼 나중에 가서 문제가 발생할 가능성이 커진다. (나도 문제가 발생해서 결국 리눅스로 옮겨왔다.) 이 포스트는 host pc가 리눅스 환경이라 가정한다.

host PC 설정하기

먼저 host PC를 설정한다. 여기서는 그래픽카드 driver 설치 여부를 확인하고 docker, docker-compose, vscode, 그리고 git을 설치한다.

그래픽카드 드라이버 설치 확인

터미널을 열고 터미널에 다음의 명령어를 통해 드라이버가 설치되었나 확인한다.

bash
nvidia-smi
result of nvidia-smi
will@lab:~$ nvidia-smi
Wed Jun 18 12:57:46 2025       
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 575.57.08              Driver Version: 575.57.08      CUDA Version: 12.9     |
|-----------------------------------------+------------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  NVIDIA GeForce GTX 1070 Ti     Off |   00000000:01:00.0  On |                  N/A |
|  0%   50C    P0             40W /  180W |     824MiB /   8192MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+
                                                                                         
+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI              PID   Type   Process name                        GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
|    0   N/A  N/A            1262      G   /usr/lib/Xorg                           565MiB |
|    0   N/A  N/A            3111      G   kitty                                     9MiB |
|    0   N/A  N/A            3418      G   ...9122beb8ae4e68e83c12556f44b66         80MiB |
|    0   N/A  N/A            3827      G   ...ess --variations-seed-version         77MiB |
|    0   N/A  N/A            3904      G   /usr/lib/zotero/zotero-bin               11MiB |
|    0   N/A  N/A            4046      G   kitty                                    15MiB |
|    0   N/A  N/A           39356      G   kitty                                     9MiB |
|    0   N/A  N/A           69915      G   kitty                                     9MiB |
|    0   N/A  N/A           70005      G   kitty                                    19MiB |
|    0   N/A  N/A           71685      G   kitty                                     9MiB |
+-----------------------------------------------------------------------------------------+

위와 같이 결과가 잘 출력된다면 드라이버가 설치되어 있단 것이다. 혹시 이 명령어가 동작하지 않는다면, 각 리눅스 배포판에 맞는 방식으로 driver를 설치해야 한다. 설치 방법은 아래의 링크를 참고하자.

도커 설치하기

도커 설치는 공식 가이드에 따라서 이뤄져야 한다. 각 리눅스 배포판별로 공식 가이드가 제공 되고 있으니 이를 참고하자. 이왕이면 Post-installation steps까지 수행해서 docker를 수행할 때 sudo를 붙이지 않아도 작동할 수 있도록 만들어주자.

arch linux는 공식 가이드에 없으니, arch wiki 페이지 를 참고하면 된다.

nvidia container toolkit 설치하기

guest인 컨테이너가 host의 gpu 자원에 접근하려면 nvidia container toolkit이 필요하다. 이것 또한 공식 가이드 에 따라 설치해주자.

arch linux는 arch wiki 페이지 를 참고하면 된다.

도커와 nvidia container toolkit 작동 확인하기

다음 단계는 도커와 nvidia container toolkit이 정상적으로 동작하는지 sample 컨테이너를 만들어서 확인하는 것 이다.

다음을 실행하여 앞서 host에서와 같이 출력되는지 확인하자. 혹시 실패했다면 앞 과정을 차근차근 다시 수행해보자.

bash
docker run --rm --gpus all ubuntu nvidia-smi
will@lab:~$ sudo docker run --rm --gpus all ubuntu nvidia-smi
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
d9d352c11bbd: Pull complete 
Digest: sha256:b59d21599a2b151e23eea5f6602f4af4d7d31c4e236d22bf0b62b86d2e386b8f
Status: Downloaded newer image for ubuntu:latest
Wed Jun 18 04:14:30 2025       
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 575.57.08              Driver Version: 575.57.08      CUDA Version: 12.9     |
|-----------------------------------------+------------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  NVIDIA GeForce GTX 1070 Ti     Off |   00000000:01:00.0  On |                  N/A |
|  0%   47C    P8              9W /  180W |     815MiB /   8192MiB |      1%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+
                                                                                         
+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI              PID   Type   Process name                        GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
+-----------------------------------------------------------------------------------------+

이 결과는 앞서 봤던 결과와 별로 달라보이지 않는다. 그러나 엄청난 차이가 있다.

이 결과는 사실 1)ubuntu 컨테이너를 생성하고, 2)생성된 그 컨테이너 내부에서 nvidia-smi를 수행하고 3)그 결과를 반환받은 것이다. 자세히 보면 아까와는 달리 Processes에 아무것도 없다. 앞서 본 결과의 processes들은 내 host pc가 gpu에게 동작시키던 것이기 때문에, 컨테이너에서는 그것을 볼 수 없는거다.

이제부터 컨테이너는 host pc의 GPU를 사용할 수 있게 되었다. (물론, docker container를 생성할 때 gpu를 사용하도록 명시해줘야 한다)

필요한 패키지들 설치하기

도커에 기반한 딥러닝 코딩에 필요한 패키지들을 설치한다. 각 패키지는 다음처럼 활용된다.

  • git은 각 컨테이너마다 설치할 수도 있으나, 그 경우 모든 컨테이너의 ssh public key를 등록해줘야하는 번거로움이 있다. 그래서, 나는 여러 컨테이너를 관리하기 위해 host pc에서만 git을 사용한다. 이후에 다루겠지만, 컨테이너와 연결된 volume 폴더 자체를 git directory로 쓴다.
  • docker-compose는 컨테이너 생성을 좀 더 명시적이고 재현가능하도록 하는데 필요하다.
  • vscode는 컨테이너에 원격 접속하여 코드를 작성, 실행, 그리고 디버깅 하는데 사용한다.

arch linux는 다음의 코드로 설치하면 된다. 다른 배포판에서는 그에 맞는 방식으로 설치해주자. (요즘은 gpt한테 아래 설치 스크립트를 보여주고 debian(혹은 다른 배포판)에 맞게 바꿔달라고 하면 기가막히게 바꿔준다.)

bash
sudo pacman -S git docker-compose
sudo paru -S visual-studio-code-bin

여기까지 잘 따라왔다면 host PC에 대한 작업은 완료되었다. 다음은 실제 코딩을 할 코딩용 컨테이너를 구축한다.

코딩용 컨테이너 설정하기

도커 이미지와 패러다임 전환

도커를 사용하면 환경 설정의 패러다임이 바뀐다. 기존에는 설치된 graphic card driver에 적합한 cuda도 설치하고, 그에 맞는 python, python 패키지 관리툴을 설치하고, 호환이 되는 pytorch를 설치해야 했다.

그러나 우리는 이제 그걸 직접 할 필요가 없다. 그냥 pytorch 공식팀(혹은 nvidia팀)에서 그들을 다 설치하고 호환성 검사를 마친 컨테이너 이미지를 가져다 사용하기만 하면 된다.

docker hub를 방문해서 pytorch/pytorch를 검색해보자. 이건 pytorch 팀에서 만든 공식 컨테이너 이미지다. Tags 탭을 누르면 여러 버전의 이미지들이 있다. (여기서 도커 이미지는 그냥 가상머신 틀이라고 생각하면 된다.) pytorch/pytorch 도커 이미지들은 (debian + conda + cuda + pytorch) 환경을 만들고 호환성 검사까지 마친 상태로 배포된다. 그래서 우리는 이들 중 내 pc 하드웨어에 맞는 것을 가져다 쓰기만 하면 된다.

docker compose 방식의 이점

일반적인 도커 이미지 사용 방식으로 이미지를 pulling하고 터미널 명령어로 직접 컨테이너를 만들어 써도된다. 그러나 시간이 한참 지나면 어떤 도커 이미지를 사용했는지, 어떤 폴더를 연결했는지, 그래픽카드는 몇 개를 연결했는지, 어떤 패키지를 설치했는지 등 자세한 설정이 기억나지 않을 수 있다.

반면, docker compose 방식을 사용하면 그런 세부 설정들 또한 파일로 남아있기 때문에 나중에 분명히 도움을 받는 때가 온다. 그러니 본 포스팅에서는 docker-compose dockerfile 을 활용하여 컨테이너 구성을 향후 재현 가능한 형태로 진행한다.

requirements.txt 작성하기

파이썬 패키지들 중 필요한 것들을 미리 목록으로 만들어주자. 파일 이름은 나는 requirements.txt라고 저장했다. 이 파일은 나중에 Dockerfile에서 pip을 사용하여 자동으로 도커 이미지 내부에 설치하게 될 것이다.

requirements.txt
matplotlib
haversine
wandb
scikit-learn
pandas
pyarrow
cartopy
pot
hydra-core
omegaconf
pyyaml
tqdm

Dockerfile 작성하기

Dockerfile은 원하는 도커 이미지를 pulling 해와서 커스텀 이미지를 만드는 파일이다. 여기서 커스텀 작업이란 리눅스 수준에서 필요한 작업들을 의미한다. 작성 방식은 ChatGPT나 공식 문서 를 참고하자.

우리는 리눅스 수준에서 필요한 작업들(e.g., time zone 설정)을 수행하고, 필요한 리눅스 패키지들(e.g., python, pip, git) 설치하며, 앞서 작성한 requirements.txt의 파이썬 패키지들을 pip을 사용하여 설치하도록 정의한다. 이름은 Dockerfile로 하고 requirements.txt와 동일한 directory에 두도록 하자.

나는 pytorch/pytorch 이미지를 사용하지 않았다. 왜냐면, pytorch의 공식 도커 이미지들은 모두 conda 기반인데, 이게 pip 기반으로 설치해야 하는 huggingface 패키지들과의 충돌이 발생하는 경우가 있었다. 그래서 그냥 nvidia/cuda 이미지를 가져와서 pip으로 직접 torch를 설치하는 방식으로 Dockerfile을 정의했다. (이 이미지는 리눅스에 cuda만 설치되어있다.) pytorch/pytorch 이미지를 쓸 사람은 그에 맞게 Dockerfile을 작성하면 된다.

Dockerfile
# 나는 nvidia/cuda 이미지를 사용하였다. 취향에 따라 가져올 이미지를 선택하면 된다.
FROM nvidia/cuda:11.7.1-cudnn8-runtime-ubuntu22.04

# 컨테이너의 time zone 설정 및 필요 패키지 설치(python 등)
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
    echo $TZ > /etc/timezone && \
    echo "ttf-mscorefonts-installer msttcorefonts/accepted-mscorefonts-eula select true" | debconf-set-selections && \
    DEBIAN_FRONTEND=noninteractive apt-get update && \
    apt-get install -y \
        git \
        tzdata \
        fontconfig \
        ttf-mscorefonts-installer \
        python3.10 \
        python3-pip \
        python3.10-venv && \
    ln -sf /usr/bin/python3.10 /usr/bin/python && \
    ln -sf /usr/bin/pip3 /usr/bin/pip && \
    fc-cache -f -v && \
    apt-get clean && rm -rf /var/lib/apt/lists/*


# pip 최신화 및 빌드 도구 설치
RUN pip install --upgrade pip setuptools wheel

# PyTorch 설치 (pip)
RUN pip install torch==2.0.1 torchvision torchaudio --index-url https://download.pytorch.org/whl/cu117 && pip install "numpy<2.0"

# Python 패키지 설치
COPY requirements.txt /tmp/requirements.txt
RUN pip install -r /tmp/requirements.txt

docker-compose.yml 작성하기

다음으로 docker-compose.yml을 작성해준다. 이름은 필히 docker-compose.yml로 작성해주자. 이 파일은 docker-compose 명령어가 컨테이너를 생성할 때 참고하는 지침 같은 것이다. 여기에는 생성할 컨테이너가 어떤 이미지에 기반할 것인지, 어떤 이름으로 인스턴스를 만들 것인지, 그리고 어떤 volume을 host와 연결해줄 것인지 등을 정의하게 된다.

나는 다음처럼 작성했다. 개인의 필요에 따라 수정하여 사용하면 된다. 자세한 설명은 주석처리된 부분을 읽어보자.

docker-compose.yml
services:
  engine:
    build: 
      context: .
      dockerfile: Dockerfile # 도커 이미지 build에 사용할 Dockerfile
    image: myimg:latest # Dockerfile로 직접 빌드한 커스텀 이미지
    container_name: dl_coding # 생성될 컨테이너 인스턴스의 이름
    shm_size: '4g' # default 256M에서 4G로 늘려줌
    deploy:
      resources:
        reservations:
          devices: # gpu 1개에 대한 접근 허용
            - driver: nvidia
              count: 1
              capabilities: [gpu]
    volumes:
      - /home/will/docker-shared/dl_coding:/dl_coding # host PC와 컨테이너 인스턴스 사이에 연결할 폴더 지정. 앞쪽에 쓰인 부분이 host PC의 directory, 뒷쪽에 쓰인 부분이 컨테이너 인스턴스의 directory임. 이 폴더는 vscode의 workspace와 git directory로 쓰인다.
    stdin_open: true # 컨테이너를 interactive 모드로 실행
    tty: true # 컨테이너가 종료되지 않도록 터미널을 할당

컨테이너 인스턴스 생성하기 (with docker-compose)

자, 이제 컨테이너 인스턴스를 생성할 준비가 끝났다. 앞서 작성한 requirements.txt, Dockerfile, docker-compose.yml이 있는 directory로 이동하고 docker compose 명령어를 실행해주자. (나는 모든 파일들을 volume으로 연결했던 /home/will/docker-shared/dl_coding에 저장해뒀다.)

bash
cd /home/will/docker-shared/dl_coding
docker compose up --build # 반드시 docker-compose.yml 파일이 있는 경로에서 실행

오류없이 잘 작동되었다면, 다음의 명령어를 수행했을 때 실행된 상태에 있는 컨테이너를 확인할 수 있다.

bash
docker ps
result of docker ps
will@lab:~$ docker ps
CONTAINER ID   IMAGE           COMMAND                  CREATED        STATUS       PORTS     NAMES
717685f2243e   myimg:latest   "/opt/nvidia/nvidia_…"   2 months ago   Up 4 hours             dl_coding

한번 생성된 컨테이너는 계속 존재하지만, host PC를 재부팅한 경우에는 다시 start를 해줘야 한다.

bash
docker start dl_coding

vscode로 컨테이너 내에서 코딩하기

터미널에서 직접 코딩을 한다면 다음처럼 터미널을 컨테이너에 연결하여 수행하면 된다.

bash
docker exec -it dl_coding bash

그러나 대부분은 vscode와 같은 에디터를 사용할 것이다. 그러니 지금부터 차근차근 vscode로 생성해둔 컨테이너 내부로 들어가서 코딩하는 방법을 알아보자.

remote development 패키지 설치하기

우리는 vscode의 도커 연동 패키지를 통해 우리가 만든 dl_coding 컨테이너에 원격접속하여 코딩을 할 것이다. vscode에서 이걸 가능하게 하는 것이 remote development 패키지다. 이걸 설치해주자.

Remote Development를 검색해서 설치해주자
Remote Development를 검색해서 설치해주자

도커 컨테이너에 접속하기

설치하고 나면 vscode의 좌측 상단에 그림의 1과 같이 처음보는 아이콘이 하나 생긴다. 눌러보면 remote explorer 탭이 나온다.

Remote development 버튼과 각 항목들
Remote development 버튼과 각 항목들

그림의 2를 누르면 여러 선택지가 있는데, 그 중 우리는 Dev Containers를 선택한다. 그러면 그림의 3과 같이 실행중 혹은 꺼져있는 컨테이너들의 목록이 보인다.

앞서 docker-compose.yml에 따라 컨테이너를 생성했다면 dl_coding이 있을 것이다. (나의 경우, 이미 작업하고 있는 engine이라는 컨테이너가 떠있다.)

이제 컨테이너로 접속하기 위해 아래 그림의 버튼을 눌러주자.

컨테이너로 접속하는 화살표 버튼
컨테이너로 접속하는 화살표 버튼

그러면 짜잔, 우리는 컨테이너 내부와 연결된 vscode 창으로 이동하게 된다. (처음 접속할 땐 시간이 조금 걸린다.)

그 증거로, 좌측 하단에 다음과 같이 원격접속하고 있다는 표시가 생긴다. (나는 engine으로 나오지만, 순서대로 따라왔다면 dl_coding이라고 표시될 것이다.)

원격 접속중임을 알리는 표시
원격 접속중임을 알리는 표시

workspace 열고 작업하기

이제 코딩을 위한 workspace를 열어야 한다. 앞서 docker-compose.yml에서 정의한 volume directory인 /dl_coding을 workspace로 쓰면 된다. 그러면 host PC에서도 작성된 코드 파일과 결과 파일들에 바로 접근이 가능하다.

아래 그림의 1을 누르면 2의 창이 뜨는데, 여기에 아까 연결해둔 volume인 /dl_coding을 입력하여 선택하면 된다. 그러면 vscode가 해당 폴더를 workspace로 열게 되고, 그 폴더에서 코딩하면 된다.

추가로 파이썬 패키지를 설치해야 한다면, vscode에 연동된 터미널 창에서 수행하면 된다. (pip이든 conda든 다 여기에서 처리하면 된다.)

vscode의 터미널은 컨테이너 내부와 연결되어있는 터미널이다.
vscode의 터미널은 컨테이너 내부와 연결되어있는 터미널이다.

도커에 연결된 vscode 창에서 실행되는 파이썬 코드는 gpu를 사용할 수 있다. 다시 확인하고 싶다면 vscode 터미널에 nvidia-smi을 입력해보자. (혹은 torch를 활용하여 gpu 접근 권한을 출력하는 python 파일을 하나 만들고 실행해보자)

vscode 터미널에서 nvidia-smi 실행 결과
vscode 터미널에서 nvidia-smi 실행 결과

마치며

이번 포스팅에서는 하드웨어가 달라져도 재현이 가능한 형태로 딥러닝 환경을 구축하는 방식에 대해 알아보았다. 복잡해 보이지만 한번 해보면 그렇게 어렵지 않은 것을 알 수 있다.

그럼 유용하게 사용해주시길.

Last updated on