소소한 컴퓨터 이야기

Dockerfile 만들기

by Cori

지금까지 나는 Docker를 사용해오면서, docker commit을 통해 프로젝트 이미지를 생성 및 관리해왔다. 

초반에는 아무런 불편함이 없었지만, 점차 불편한점들이 체감되기 시작하면서, Dockerfile 공부를 뒤늦게 시작했다.

이 포스트는 RAG (Retriever Augmented Generation) 모델 아키텍처를 위한 Docker 이미지를 만드는 과정을 처음부터 다루고 있다.


0. Dockerfile 생성 

Dockerfile은 아무런 확장자가 없는 파일로, 파일명을 Dockerfile로 설정해서 하나 만들어주자. 

메모장으로 생성한 Dockerfile (좌)과 VSCode에서 열어본 Dockerfile (우)

1. Dockerfile Option

command explanation example
FROM 기본 이미지 지정 (Docker Hub 참고) FROM pytorch/pytorch
WORKDIR 작업 디렉토리 설정  WORKDIR /usr/src/app
ENV 환경 변수 설정 ENV LC_ALL C.UTF-8
COPY 호스트 파일 시스템의 파일/디렉토리 이미지로 복사 COPY app /usr/src/app
ADD COPY와 유사하며, URL로부터 파일을 다운로드하거나 압축을 푸는 등 추가 기능을 지원함 ADD https://~file.txt /usr/src/
RUN 컨테이너 내에서 실행할 명령어 정의 (패키지 설치 등) RUN apt-get update
EXPOSE 컨테이너가 개방할 포트 지정 EXPOSE 8888
CMD 컨테이너가 실행될 때 실행할 명령어 지정 CMD ["npm", "start"]
ENTRYPOINT 컨테이너가 실행될 때 항상 실행할 명령어 지정  ENTRYPOINT [" ", " "]
VOLUME 호스트와 컨테이너 간 볼륨을 공유 VOLUME /data

2. Dockerfile BUILD TEST

Test 과정에서, Dockerfile로 이미지 생성할 때 사용한 명령어는 'docker build -t dockerfile:test .' 로 통일했다. 생성한 Docker image 진입할 때에는 'docker run -i -t dockerfile:test'를 사용했다. 

 

WORKDIR

WORKDIR은 빌드한 이미지를 실행하고, 접속했을 때 나에게 보이는 경로이다. 

# 베이스 이미지 설정 
FROM pytorch/pytorch:latest 
WORKDIR /workspace # /rag

Docker 기본 작업 경로 설정

COPY

Docker 호스트의 파일이나 디렉토리를 Docker 이미지로 복사하는데 사용됨. 

* 로컬 파일 시스템에서만 동작하며, URL이나 다른 원격 소스에서 직접 파일을 복사할 수는 없음 

FROM pytorch/pytorch:latest  
WORKDIR /rag   
EXPOSE 8888 
RUN apt-get update && apt-get install -y vim
COPY . /rag/

COPY 명령어는 Dockerfile이 있는 디렉토리의 모든 파일을 도커 이미지로 복사하는 개념으로 사용하는게 편하다. 

절대 경로로 파일명 지정하고 하니까 계속 오류나면서 안 됌 ... 

Dockerfile 복사

도커 컨테이너 내부에서 Dockerfile을 수정하고 컨테이너를 빠져나오면 로컬 파일의 Dockerfile이 수정되는지 보자.

Dockerfile 수정

위처럼 파일을 수정하고 컨테이너를 종료했는데, 로컬 디렉토리의 Dockerfile은 수정 사항이 반영되지 않았다. 

실시간 반영을 원한다면 작업 내용을 commit 하거나, VOLUME을 사용하자. 

 

ADD

COPY와 유사하며, URL을 통해 파일 다운로드 및 압축된 파일을 자동으로 추출하는 등의 추가 기능을 가짐 

* 특정 상황에서 유용하게 사용될 수 있지만, 그 추가 기능들이 필요하지 않다면 COPY 명령어 사용할 것 

FROM pytorch/pytorch:latest  
WORKDIR /rag   
EXPOSE 8888 
ADD https://github.com/huggingface/transformers/blob/main/README.md /rag/

 

VOLUME

컨테이너 안에 있는 데이터는 컨테이너를 삭제하면 모든 데이터가 같이 삭제(휘발성 데이터)된다.

데이터를 보존하기 위해 VOLUME을 사용하고, VOLUME 명령은 설정한 컨테이너의 데이터를 호스트 OS에 저장하거나

컨테이너 간 데이터 공유가 가능하다.

 

* VOLUME은 ADD, COPY와 달리 Docker container 내부에 마운트 포인트를 만든다는 점에서 둘과 다르다.

도커 외부 혹은 내부에서 작업한 변경 사항이 바로 반영 되기에 빈번한 수정이 일어나는 개발 환경에서 특히 유용하다. 

 

방법 1. Dockerfile 이용 (추천 x) 

FROM pytorch/pytorch:latest  
WORKDIR /rag   
EXPOSE 8888 
VOLUME ["/rag"]

해당 Dockerfile을 Build하고, Build한 이미지를 실행하면 Volume이 생성된다. 

생성한 Docker Volume은 다음 명령어로 조회할 수 있다. 

docker volume ls

* 생성한 Volume들의 이름은 해시값으로 설정되어 있음. 한번 빌드할 때 마다 새로운 Volume들이 생성된다.

 

해당 컨테이너에서 파일을 생성하고 작업한 후, 빠져나오면 Volume에 작업 내용이 저장된다. 

생성한 Volume은 여러 컨테이너에서 공동으로 사용할 수 있다.

docker run -it -v [볼륨 이름]:[컨테이너 Volume 경로] dockerfile:test

* 이런저런 실험을 하다 알게 된 사실인데, 해당 Volume:/workspace 와 같이 다른 디렉토리로 연결 후 해당 디렉토리에서 파일을 생성하더라도, 생성한 파일들은 전부 '/rag' 경로로 저장된다.. 아마도 해당 Volume을 빌드할 때 사용한 Dockerfile에 VOLUME 값이 '/rag'로 설정되어 있기 때문 아닐까 추측해봄 .. 또한 위 방식으로 컨테이너 실행 시, 컨테이너 실행과 함께 VOLUME이 생성되는데, 이는 컨테이너 삭제 시 함께 삭제된다. 

 

도커 볼륨 정보는 다음과 같이 조회할 수 있다. 

docker inspect [volume 이름]

Mountpoint 에 데이터가 저장된다.

방법 2. 로컬 디렉토리 <-> 컨테이너 디렉토리 연동 

로컬 디렉토리 내 파일들을 컨테이너로 연동해서 사용할 때 사용하는 명령어로, 개인적으로 자주 사용하는 방법이다. 

해당 방법은 본인의 환경에 맞게 사용하기 좋지만, 디렉토리 관리가 좀 복잡해질 수 있다는 단점이 있다.

docker run -it -v [호스트 컴퓨터 디렉토리]:[컨테이너 볼륨 디렉토리] [이미지 이름]

# docker run -it -v C:/Users/user/Desktop/:/workspace pytorch/pytorch

 

3. tmps

호스트 시스템의 메모리에 저장되는 볼륨으로, 보안 혹은 비영구 상태 데이터를 작성할 때 유용하다. 

docker run -it --tmpfs [컨테이너 볼륨 경로]

 

CMD

도커 컨테이너가 시작될 때 실행되는 셀 명령어를 지정. CMD 명령어의 경우 하나의 Dockerfile에서 한 가지만 설정됨.

여러 개 작성했을 경우 맨 마지막에 설정한 CMD 명령어만 적용됨. CMD로 설정한 명령어는, docker run 명령어보다 우선

순위가 낮아 docker run 명령어를 통해 덮어씌웠을 경우 CMD 상 명령어는 무시된다. 

 

ENTRYPOINT

CMD와 ENTRYPOINT의 차이는 docker run 을 사용하며 새로운 명령을 지정한 경우 이 명령이 실행 되는지, 안되는지의 차이다. 

CMD: 컨테이너가 실행될 때 명령어 및 인자값 전달하여 실행, 단 docker run 명령에 쉘 명령어 및 인자값 전달할 경우 CMD에 작성된 명령어와 인자값은 무시 됩니다. (다른 명령어와 인자값을 사용한 예는 아래 이미지 확인)

 

CMD, ENTRYPOINT 두 명령어로 지정한 옵션은 docker run 명령어 뒤에 붙게 됨

FROM pytorch/pytorch:latest  
WORKDIR /rag   
EXPOSE 8888 
VOLUME [ "/rag" ]
ENTRYPOINT ["bin/echo", "this is cori's world"]

위와 같이 Dockerfile을 작성하고 이미지를 빌드했으면 이미지 실행 시 다음과 같은 형태로 동작함 

docker run -i -t dockerfile:test   # 도커 이미지 실행 명령어

ENTRYPOINT에 지정한 내용 출력하고 도커 종료

# 실제 적용되는 명령어 
docker run -i -t dockerfile:test /bin/echo "this is cori's world"

ENTRYPOINT 명령어 실제 동작 과정

CMD랑 ENTRYPOINT 개념이 생소해서 뭔 내용인가 싶기도 하고, 한번에 와 닿지 않았는데 이제는 얼추 알 것 같다.

컨테이너를 실행시켰는데 진입이 안 돼서 많이 당황 .. 알고보니 저런 형태로 붙어서 그런거였다. 당장 나한테는 필요 없을수도 .. ?

 

Retriever Augment Generation 아키텍처를 위한 Docker File

지금까지 배운 내용을 바탕으로 RAG 아키텍처 개발 환경을 생성해주는 Dockerfile을 작성해보았다. 

Llama Index, Langchain과 여러 Vector DB 관련 라이브러리가 기본으로 깔려 있다. 

RAG 연구를 지속하는 한, Dockerfile은 꾸준히 업데이트 할 것 같다.. 

requirements.txt
0.00MB

# 기본 Docker Image 설정 
FROM pytorch/pytorch:latest
LABEL maintainer='ojd9512@gmail.com'
LABEL version='1.0.0'
LABEL description='Docker image created for rag architecture'

# Docker 내 작업 경로 설정 
WORKDIR /rag  
COPY requirements.txt .

# 한글 입력을 위한 환경 변수 설정 
ENV LC_ALL ko_KR.UTF-8 

# 포트 오픈 
EXPOSE 8888 

# Anaconda Install  -  pass 

# 패키지 설치 (한글 입력을 위한 locale)
RUN apt-get update && apt-get install -y locales
RUN locale-gen ko_KR.UTF-8   
RUN apt-get install python3-pip -y
RUN pip install jupyter notebook
RUN jupyter notebook --generate-config 
RUN echo "c.NotebookApp.ip = '0.0.0.0'" >> /root/.jupyter/jupyter_notebook_conifg.py
RUN pip install -r requirements.txt

♣ Reference

Docker ADD vs COPY vs VOLUME

Docker VOLUME 사용법 

Docker Container 설정 파일 찾기 

https://0902.tistory.com/6

도커와 컨테이너의 이해 (2/3) - 볼륨과 네트워크

https://tech.cloudmt.co.kr/2022/06/29/%EB%8F%84%EC%BB%A4%EC%99%80-https://nirsa.tistory.com/66?category=868315

Dockerfile 명령어 정리 (RUN, CMD, ENTRYPOINT)

Anaconda, Jupyter Dockerfile 설정

블로그의 정보

코딩하는 오리

Cori

활동하기