CS

Deep learning 개발자를 위한 Docker [2]

bono. 2021. 6. 27. 20:44

대충 도커가 어떻게 동작하고 있는지는 그려진다. 이번 포스트에서는 Docker를 사용 할 때, 주로 사용하는 커멘드에 대해서 알아보려한다.

 

일단 시키는데로 docker 커멘드를 치고는 있는데...

  • 우리는 누군가 만들어 놓은 모델을 돌리고자 할 때 도커를 찾는다.
  • 정확히는 그 사람이 만든 도커파일을 찾는다.
    - 환경 세팅 하기 싫어...
  • 그리고 기계적으로 build하고 run 한다...
  • README에 docker 관련해서 문서화를 잘 해놨길 바랄 뿐이다...
  • 이렇게 끝나면 좋은데 때로는 몇가지 설정을 해줘야 할 때가 있다.
  • 그런 몇가지 설정에 대해 먼저 이야기 해보려 한다.

그림 1. Tensorflow object detection api docker

Local 디렉토리에 있는 dataset을 연동하고 싶은데...

  • 우리의 로컬 호스트와 도커 컨테이너 간의 공유 디렉토리를 연결 (디렉토리 마운트)하는 방법에 대해 말하려 한다.
  • 도커 컨테이너는 종료되면 컨테이너 내부 변경사항이 모두 소실된다.
    - 그래서 로컬 호스트에 존재하는 디렉토리를 컨테이너에 마운트시켜 컨테이너가 종료되더라도 변경사항이 소실되지 않도록 한다.
  • 도커 호스트에 -v, —volume 혹은 —mount 옵션을 이용하여 로컬 호스트의 디렉토리를 마운트 시킬 수 있다.
  • 다음 명령어 처럼 run 할 때 명령어를 추가하여 마운트 시켜준다.
$ docker run -d \
  --name devtest \
  -v myvol2:/app \
  nginx:latest


-v myvol2:/app \

-v "$(pwd)"/target:/app
  • 밑에 -v 명령어를 두개의 스타일로 작성했다.
  • 하나는 절대 경로를 주고, 하나는 주지 않았다.
  • 놀랍게도 이 두 명령어는 다르게 동작한다.

Volume vs Bind mount

  • Bind mount와 volume이라는 개념이 등장한다.
  • 여기까지 알기 싫으면 그냥 volume 쓰면 된다.
  • 마운트 할 때 호스트 시스템의 절대 경로를 이용하면 bind mount, 그렇지 않으면 volume이다.
  • 다음의 7가지 이유를 대면서 이왕이면 volume을 쓰라고 권장하고 있다. 그래.... volume 쓰자.
    1. Volume으로 관리하는것이 back up하거나 migrate 하기 쉽다.
    2. Volume쓰면 docker cli나 docker api를 이용하여 관리가 가능하다.
    3. Linux, windows os 모두에서 사용 가능하다.
    4. 여러 컨테이너 간의 sharing을 할 때, volume이 더 safe 하다.
    5. Volume 드라이버가 볼륨의 내용을 암호화하거나 다른 기능을 추가 할 수 있게 해준다.
    6. 새 volume 생성시 컨테이너에 의해 content가 채워 질 수 있다.
    7. Volumes on Docker Desktop이 더 좋은 성능을 낸다.
  • 밑의 그림 보면 더 잘 이해가 간다. 호스트 파일 시스템 내부에 존재하는 docker area에서 관리되는것이 volume, 그냥 호스트 파일 시스템 어딘가에서 관리되는것이 bind mount이다.

그림 2. 왼쪽이 Volume, 오른쪽이 bind mount

Volume

# volume
$ docker run -d \
  --name devtest \
  -v myvol2:/app \
  nginx:latest
  • 공식문서에는 다음과 같은 설명이 있다.
    - While bind mounts are dependent on the directory structure and OS of the host machine, volumes are completely managed by Docker.
    - 어쨋든간에 bind mount와 다르게 volume은 docker에 의해 잘 관리된다는 의미같다.
  • 호스트 시스템의 Docker 스토리지 내부에 새 디렉토리가 생성되고 Docker가 해당 디렉토리를 관리한다.
  • 위의 그림과 같이 호스트 파일 시스템 내부에 docker area라는 영역 (디렉토리로 이해하면 편하다) 이 존재해서 컨테이너는 해당 영역을 참조한다.

Bind mount

# Bind mount
$ docker run -d \
  -it \
  --name devtest \
  -v "$(pwd)"/target:/app \
  nginx:latest
  • Volume에 비해 기능이 제한적이다.
  • 로컬 호스트 (호스트 시스템)의 파일이나 디렉토리가 container에 마운트 된다.
    - 마운트 된 파일이나 디렉토리는 호스트의 절대 경로로 참조된다.
  • 성능은 좋지만 호스트의 파일 시스템에 의존한다.
  • 위의 그림처럼 호스트 파일 시스템 내 어딘가에 존재하고, 그 영역을 참조하게 된다. (No docker area)

Docker에서 포트 포워딩하기

docker run -it --rm --name myTensorflow -p 8000:8888 tensorflow/tensorflow:latest-gpu-jupyter

위의 커멘드는 docker에서 jupyter notebook을 실행 시기기 위하여 사용한 커맨드이다. https://softtone-someday.tistory.com/5

나는 그동안 기계적으로 블로그 포스트를 따라치며 jupyter notebook을 실행해왔다.

그런데 문득, 저 -p가 뭔지 포트라는게 뭔지 알고싶었다.

먼저 Port 개념을 말하고 싶었다.

  • Port 라는 것은 OSI 7계층 중 4계층인 transport layer에서 사용되는 기술이다.
  • Port 번호란 컴퓨터가 데이터를 어느 프로세스에게 전달해야 되는지를 알려주는 유니크한 번호이다.
  • 송신자는 데이터를 보낼 때, 데이터를 받을 수신자 컴퓨터에 있는 프로세스의 port 번호를 붙혀 보낸다.
  • 이 port 번호를 이용하여 어느 프로세스가 데이터를 받아야 하는지 알 수 있게 된다.
  • OSI 7계층에 대해 자세히 알고 싶다면 이 링크를 추천한다 : https://youtu.be/1pfTxp25MA8

Container networking

  • container도 ip주소, 게이트웨이, routing table, DNS 서비스와 같은 네트워크 인터페이스를 가지고 있다.
  • 따라서 container를 통해 네트워킹이 가능하다.

Published Port

  • 아무래도 포트를 제일 많이 쓰는거 같아 앞에다 두었다.
  • docker run / docker create로 컨테이너를 생성하면 default로 포트가 publish 되지는 않는다. 따로 설정해줘야한다.
  • —publish, -p 플래그를 통하여 설정 할 수 있다.
  • 일반적으로 -p <host port> : <container port> 의 형태로 container의 포트번호를 명시한 host 포트 번호로 매핑하여 사용한다.
  • 다음은 플래그 설정 예시와 설명이다.
Flag value Description
-p 8080:80 컨테이너의 TCP 포트 80을 도커 호스트의 포트 8080에 매핑시킨다.
-p 192.168.1.100:8080:80 컨테이터 TCP 포트 80을 192.168.1.100 라는 host ip의 포트 8000에 매핑시킨다.
-p 8080:80/udp 컨테이너의 udp 포트 80을 도커 호스트의 포트 8080에 매핑시킨다.
-p 8080:80/tcp -p 8080:80/udp 컨테이너의 TCP 포트 80을 도커 호스트의 TCP 포트 8080에 매핑하고 컨테이너의 UDP 포트 80을 도커 호스트의 UDP 포트 8080에 매핑한다.

DockerFile 에 있는 명령어들은 뭔가요

FROM tensorflow/tensorflow:2.2.0-gpu

ARG DEBIAN_FRONTEND=noninteractive

# Install apt dependencies
RUN apt-get update && apt-get install -y \
    git \
    gpg-agent \
    python3-cairocffi \
    protobuf-compiler \
    python3-pil \
    python3-lxml \
    python3-tk \
    wget

# Install gcloud and gsutil commands
# https://cloud.google.com/sdk/docs/quickstart-debian-ubuntu
RUN export CLOUD_SDK_REPO="cloud-sdk-$(lsb_release -c -s)" && \
    echo "deb http://packages.cloud.google.com/apt $CLOUD_SDK_REPO main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list && \
    curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \
    apt-get update -y && apt-get install google-cloud-sdk -y

# Add new user to avoid running as root
RUN useradd -ms /bin/bash tensorflow
USER tensorflow
WORKDIR /home/tensorflow

# Copy this version of of the model garden into the image
COPY --chown=tensorflow . /home/tensorflow/models

# Compile protobuf configs
RUN (cd /home/tensorflow/models/research/ && protoc object_detection/protos/*.proto --python_out=.)
WORKDIR /home/tensorflow/models/research/

RUN cp object_detection/packages/tf2/setup.py ./
ENV PATH="/home/tensorflow/.local/bin:${PATH}"

RUN python -m pip install -U pip
RUN python -m pip install .

ENV TF_CPP_MIN_LOG_LEVEL 3

FROM

  • 베이스 이미지를 지정한다.
  • 위의 경우 tensorflow/tensorflow:2.2.0-gpu 라는 이미지가 베이스 이미지가 된다.

RUN

  • 명령어를 그대로 실행한다.
  • 터미널에 입력하는것과 같다고 보면 된다.
  • 내부적으로 /bin/sh -c 뒤에 명령어를 실행하는 방식이다.

WORKDIR

  • RUN, CMD, ADD, COPY등과 같은 명령어가 실행 될 디렉토리를 지정한다.
  • 위의 코드를 보면 중간 중간 WORKDIR를 지정해준다.
  • WORKDIR /home/tensorflow/models/research/ → RUN cp object_detection/packages/tf2/setup.py ./ 하면 해당 디렉토리에서 저 명령어가 실행된다.

ENV

  • 컨테이너에서 사용 할 환경변수를 지정한다.

VOLUME

  • 컨테이너 외부의 파일 시스템을 마운트 할 때 사용한다.

COPY

  • 파일이나 디렉토리를 이미지로 복사한다.

Reference