개발/Docker

Dockerfile 내용 기반 Docker Image Build.

moonzoo 2024. 11. 27. 23:58

0. Docker를 사용하는 이유

도커 컨테이너를 통해 작업하는 가장 큰 장점은 애플리케이션의 실행 환경을 격리하고 일관성 있게 유지할 수 있다는 점입니다. Docker 환경에서 작업을 진행하면 다음과 같은 장점이 있습니다.

 

1. 실행 환경의 일관성

  • 컨테이너는 애플리케이션과 그 종속성을 패키지화하여 어떤 환경에서도 동일하게 동작하도록 보장합니다.
    → "내 로컬에서는 잘 작동하지만 서버에서는 오류가 난다" 같은 문제를 방지.

2. 격리된 환경 제공

  • 각 컨테이너는 독립적인 실행 환경을 제공하므로, 하나의 컨테이너에서 문제가 발생해도 다른 컨테이너나 호스트 시스템에 영향을 주지 않습니다.
    → 동일한 호스트에서 서로 다른 애플리케이션(예: Python 3.9과 3.8)을 충돌 없이 실행 가능.

3. 이동성(Mobility)

  • 도커 이미지를 사용하면 컨테이너를 어느 환경에서든 실행할 수 있습니다.
    → 로컬 개발 환경, 테스트 서버, 클라우드 서비스(AWS, GCP 등)에서 동일한 동작.

4. 빠른 배포 및 실행

  • 컨테이너는 이미지를 기반으로 매우 빠르게 생성되고 실행됩니다. → 서버를 초기화하거나 애플리케이션을 재배포하는 데 걸리는 시간을 대폭 단축.

이러한 Docker의 일관성과 이동성의 장점으로 저는 Docker 환경에서 작업하는 것을 선호합니다.

 


1. Docker build & run

Docker 컨테이너를 띄우는 과정은 크게 두 가지 Build Run이 있습니다.

  1. Build (이미지 생성):
    • Dockerfile을 활용하여 이미지(애플리케이션 실행 환경)를 만듭니다.
    • 도커 이미지는 애플리케이션 실행에 필요한 환경을 일관되게 제공하고, 효율적인 배포와 관리, 자동화 등을 위해 필수적입니다.
    • 도커 이미지를 한번 build 해두면 bulid된 도커 이미지를 새로 build하지 않아도 다른 컨테이너의 이미지로 사용할 수 있습니다.
  2. Run (이미지 실행):
    • 생성된 이미지를 기반으로 컨테이너를 실행하는 과정입니다.
    • 결과물: 실행 중인 컨테이너. (docker ps를 통해 확인 가능.)

2. Dockerfile 내용 기반 Docker image build

Dockerfile로 빌드하는 이유는 애플리케이션의 실행 환경을 코드로 정의하여 일관성, 효율성, 자동화를 제공하기 위함입니다. 이를 통해 운영 환경의 재현성을 보장하고, 애플리케이션의 배포 및 관리를 간소화할 수 있습니다.

 

이젠 Dockerfile로 TensorFlow 기반의 GPU 환경을 구축하고 필요한 패키지와 라이브러리를 설치한 뒤, Python 환경으로 실행하기 위한 이미지를 빌드해보도록 하겠습니다.

 

FROM tensorflow/tensorflow:2.11.0-gpu

WORKDIR /app

COPY . .

RUN apt update && apt install -y python3.9

RUN update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.9 

RUN dpkg -i cudnn-local-repo-ubuntu2204-9.1.0_1.0-1_amd64.deb
RUN cp /var/cudnn-local-repo-ubuntu2204-9.1.0/cudnn-*-keyring.gpg /usr/share/keyrings/
RUN apt-get update
RUN apt-get -y install cudnn

RUN apt install -y git \
    build-essential \
    wget \
    ffmpeg \
    python3.9-dev \
    && rm -rf /var/lib/apt/lists/*

RUN ln -s /usr/bin/python3 /usr/bin/python

RUN python -m pip install --upgrade pip

RUN pip install -r requirements.txt

ENV TZ=Asia/Seoul
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

RUN wget http://ftp.gnu.org/gnu/libc/glibc-2.34.tar.gz \
    && tar -xvf glibc-2.34.tar.gz \
    && cd glibc-2.34 \
    && mkdir build \
    && cd build \
    && ../configure --prefix=/usr/local/glibc-2.34 --disable-sanity-checks \
    && make -j$(nproc) \
    && make install \
    && cd / \
    && rm -rf /app/glibc-2.34 glibc-2.34.tar.gz

RUN ln -s /usr/local/cuda-11.2/targets/x86_64-linux/lib/libcublas.so.11 /usr/local/cuda-11.2/targets/x86_64-linux/lib/libcublas.so.12

COPY start_server.sh /app/start_server.sh
RUN chmod +x /app/start_server.sh
CMD ["/app/start_server.sh"]

 

1. FROM tensorflow/tensorflow:2.11.0-gpu

  • 기능: TensorFlow의 GPU 지원 이미지를 베이스 이미지로 사용.
  • 설명: TensorFlow 2.11.0 버전과 CUDA 및 cuDNN 지원이 포함된 공식 도커 이미지를 기반으로 작업을 시작합니다.
  • GPU가 필요한 딥러닝 작업을 실행하기 위함.

 

2. WORKDIR /app

  • 기능: 컨테이너 내 작업 디렉터리를 /app으로 설정.
  • 설명: 이후 명령어(COPY, RUN 등) 실행 시 기준 디렉터리가 /app이 됩니다.
  • 코드 및 데이터를 통일된 디렉터리에서 관리하기 위해 사용.

 

3. COPY . .

  • 기능: 현재 로컬 디렉터리(.)의 모든 파일을 컨테이너의 /app 디렉터리(.)로 복사.
  • 설명: Dockerfile이 위치한 디렉터리의 모든 파일을 컨테이너에 복사하여, 애플리케이션 코드와 관련 리소스를 컨테이너 내부에서 사용할 수 있게 합니다.

 

4. RUN apt update && apt install -y python3.9

  • 기능: apt 패키지 목록을 업데이트한 뒤 Python 3.9를 설치.
  • 설명: 최신 Python 버전을 사용하기 위해 설치하며, -y 옵션은 설치 과정 중 사용자의 확인을 자동으로 처리합니다.

 

5. RUN update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.9

  • 기능: Python 3 명령어를 Python 3.9로 기본 설정.
  • 설명: 컨테이너 내에서 python3 명령이 Python 3.9를 실행하도록 설정.

 

6. RUN dpkg -i cudnn-local-repo-ubuntu2204-9.1.0_1.0-1_amd64.deb

  • 기능: cuDNN 로컬 패키지를 설치.
  • 설명: CUDA 기반 GPU 연산 가속에 필요한 cuDNN 라이브러리를 설치하기 위해 .deb 패키지를 사용.

 

7. RUN cp /var/cudnn-local-repo-ubuntu2204-9.1.0/cudnn-*-keyring.gpg /usr/share/keyrings/

  • 기능: cuDNN 리포지토리의 인증 키를 복사.
  • 설명: cuDNN 패키지 설치를 위해 패키지 관리자가 리포지토리의 신뢰성을 확인할 수 있도록 키 파일을 복사합니다.

 

8. RUN apt-get update

  • 기능: 패키지 관리자의 소프트웨어 목록 업데이트.
  • 설명: cuDNN 리포지토리를 포함한 새로운 패키지 목록을 가져옵니다.

 

9. RUN apt-get -y install cudnn

  • 기능: cuDNN 설치.
  • 설명: 딥러닝 연산에 필수적인 CUDA 라이브러리 중 하나인 cuDNN을 설치합니다.

 

10. RUN apt install -y git build-essential wget ffmpeg python3.9-dev libasound2-dev gawk bison portaudio19-dev && rm -rf /var/lib/apt/lists/*

  • 기능: 여러 필수 패키지 설치.
    • git: 버전 관리 도구.
    • build-essential: 컴파일러 및 빌드 도구.
    • wget: 파일 다운로드 도구.
    • ffmpeg: 오디오 및 비디오 처리 도구.
    • python3.9-dev: Python 3.9 개발 헤더 파일.
    • libasound2-dev: 오디오 관련 라이브러리.
    • gawk, bison: GNU 도구 모음.
    • portaudio19-dev: 오디오 입출력 라이브러리.
  • 설명: 애플리케이션 실행 및 빌드에 필요한 도구와 라이브러리를 설치.
  • rm -rf /var/lib/apt/lists/*: 캐시를 삭제해 이미지 크기를 줄입니다.

 

11. RUN ln -s /usr/bin/python3 /usr/bin/python

  • 기능: /usr/bin/python 심볼릭 링크를 Python 3으로 설정.
  • 설명: python 명령어로 Python 3을 실행할 수 있도록 심볼릭 링크를 생성.

 

12. RUN python -m pip install --upgrade pip

  • 기능: Python의 패키지 관리자인 pip를 최신 버전으로 업그레이드.
  • 설명: 최신 pip 기능과 보안 패치를 적용하기 위함.

 

13. RUN pip install -r requirements.txt

  • 기능: requirements.txt 파일에 명시된 Python 패키지 설치.
  • 설명: 애플리케이션 실행에 필요한 모든 Python 종속성을 설치.

 

14. ENV TZ=Asia/Seoul

  • 기능: 환경 변수 TZ를 Asia/Seoul로 설정.
  • 설명: 컨테이너의 시간대를 한국 표준시(KST)로 설정.

 

15. RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

  • 기능: 시간대 설정을 $TZ 환경 변수(한국 표준시)로 반영.
  • 설명: 컨테이너 내 시간 설정을 올바르게 동기화.

 

16. RUN wget http://ftp.gnu.org/gnu/libc/glibc-2.34.tar.gz && ...

  • 기능: GLIBC 2.34 설치.
    • GLIBC: Linux에서 사용하는 C 라이브러리.
    • 최신 GLIBC 버전을 소스에서 빌드하고 설치.
  • 설명: 최신 버전의 C 라이브러리가 필요한 애플리케이션을 실행하기 위함.

 

17. RUN ln -s /usr/local/cuda-11.2/targets/x86_64-linux/lib/libcublas.so.11 /usr/local/cuda-11.2/targets/x86_64-linux/lib/libcublas.so.12

  • 기능: libcublas.so.11 파일을 libcublas.so.12로 심볼릭 링크 생성.
  • 설명: CUDA 라이브러리 버전 호환성을 맞추기 위해 사용.

 

18. COPY start_server.sh /app/start_server.sh

  • 기능: 로컬의 start_server.sh 스크립트를 컨테이너의 /app 디렉터리로 복사.
  • 설명: 서버 실행에 필요한 스크립트를 컨테이너로 옮김.

 

19. RUN chmod +x /app/start_server.sh

  • 기능: start_server.sh 파일에 실행 권한 부여.
  • 설명: 해당 파일이 실행 가능한 상태가 되도록 설정.

 

20. CMD ["/app/start_server.sh"]

  • 기능: 컨테이너 실행 시 /app/start_server.sh 스크립트를 기본 실행 명령으로 설정.
  • 설명: 컨테이너가 시작되면 자동으로 서버 스크립트를 실행.

이제 현재 디렉터리에 있는 Dockerfile을 사용해 Docker 이미지를 생성해보겠습니다.

docker build -t tensorflow/tensorflow:2.11.0-gpu_v1 .

 

  • -t tensorflow/tensorflow:2.11.0-gpu_v1:
    • -t 옵션은 생성할 이미지에 태그를 붙입니다.
    • tensorflow/tensorflow:2.11.0-gpu_v1은 이미지 이름과 태그를 정의하는 것입니다.
  • .: 현재 디렉터리를 빌드 컨텍스트로 사용합니다.
    • Dockerfile과 빌드에 필요한 파일들이 이 경로에 있어야 합니다.

이를 통해 tensorflow/tensorflow:2.11.0-gpu_v1이라는 이름으로 커스터마이즈된 Docker 이미지를 생성했습니다.

 


3. Docker image 기반 컨테이너 실행

docker run -itd -v /home/mz_moonzoo/voice_test/voice:/app --name=voice_test --gpus=all -p 5000:5000/udp tensorflow/tensorflow:2.11.0-gpu_v1 bash

 

 

docker run 

  • Docker 컨테이너를 생성하고 실행하기 위한 것입니다.

Options

-itd

  • -i (interactive): 표준 입력을 연결해 컨테이너와 상호작용할 수 있도록 설정합니다.
  • -t (tty): 컨테이너에 터미널(가상 콘솔)을 할당합니다.
  • -d (detached): 컨테이너를 백그라운드에서 실행합니다.
    • 즉, 이 명령을 실행한 후 터미널로 돌아오며, 컨테이너는 백그라운드에서 계속 동작합니다.

 

-v /home/mz_moonzoo/voice_test/voice:/app

  • -v (volume): 호스트와 컨테이너 간 디렉터리를 공유합니다.
  • 호스트의 /home/mz_moonzoo/voice_test/voice 디렉터리를 컨테이너의 /app 디렉터리로 마운트합니다.
    • 이로 인해 호스트에서 만든 파일을 컨테이너에서 접근 가능하고, 컨테이너에서 생성한 파일도 호스트에서 접근 가능해집니다.
    • 디렉터리 경로는 프로젝트 파일, 데이터셋, 로그 등을 공유하기 위해 사용됩니다.

 

--name=voice_test

  • 실행할 컨테이너의 이름을 voice_test로 지정합니다.
    • 이름을 지정하면, 컨테이너 ID 대신 이름을 통해 컨테이너를 관리할 수 있습니다.

 

--gpus=all

  • 컨테이너에서 GPU를 사용할 수 있도록 설정합니다.
  • all 옵션은 호스트의 모든 GPU를 컨테이너에서 접근 가능하게 합니다.
    • 이는 딥러닝 모델 훈련, 추론 등 GPU가 필요한 작업을 지원합니다.
    • NVIDIA Docker 런타임이 필요하며, 호스트 머신에 CUDA 드라이버가 설치되어 있어야 합니다.

 

-p 5000:5000/udp

  • 호스트와 컨테이너 간 네트워크 포트를 연결합니다.
  • 5000:5000: 호스트의 UDP 5000번 포트를 컨테이너의 UDP 5000번 포트와 연결합니다.
    • 컨테이너 내부에서 실행되는 서비스(음성 처리 서버)가 5000번 포트를 통해 네트워크 요청을 받을 수 있습니다.

 

tensorflow/tensorflow:2.11.0-gpu_v1

  • 컨테이너 생성에 사용할 Docker 이미지를 지정합니다.
  • tensorflow/tensorflow:2.11.0-gpu_v1은 직접 커스터마이징한 TensorFlow 기반 이미지입니다.

bash

  • 컨테이너가 시작되면 실행할 기본 명령어를 지정합니다.
  • bash를 실행하면 컨테이너 내부의 Bash 셸 환경에 진입할 수 있습니다.
    • 이 명령어는 기본적으로 대기 상태가 되어 컨테이너가 종료되지 않게 합니다.
  • docker run 명령어에 bash를 명시하면, CMD에서 설정된 start_server.sh는 무시됩니다. 그 이유는 CMD는 기본 실행 명령어로 사용되지만, docker run에서 명령어(bash)를 지정하면 이를 덮어쓰기 떄문입니다.

4. 마치며

위와 같은 방법으로 Dockerfile을 통해 원하는 특정 환경의 image를 빌드하고, 해당 이미지를 사용해 새 컨테이너를 생성하는 방법까지 작성했습니다.

 

이러한 방법을 통해 운영 환경의 재현성을 보장하고, 애플리케이션의 배포 및 관리를 간소화할 수 있습니다.