Tech Blog
[MLOps] 4. Docker Image와 Dockerfile 본문
1️⃣ Docker Image란?
Docker Image는 어떤 애플리케이션에 대해서, 단순히 애플리케이션 코드 뿐만이 아니라, 그 애플리케이션과 dependent한 모든 것을 함께 패키징함으로써 어느 운영체제, 환경에서든지 실행해볼 수 있도록 만든 데이터입니다. 예를 들어, sklearn 패키지에서 svm 분류 모델을 파이썬 코드로 작성하였을 때, 파이썬 소스코드를 전달하는 것이 아니라 여기서 사용된 파이썬 버전이나, 패키지 (sklearn, numpy, pandas 등) 의 버전을 패키지화 하여 어디서든지 동일한 결과를 얻을 수 있도록 만드는 것입니다.
이번 글에서는 (1) 머신러닝 코드를 담은 도커 이미지를 만드는 방법은 무엇인가? (2) 이를 다른 사람들과 공유할 수 있는 방법은 무엇인가? 이 두 질문에 대한 답변을 얻을 수 있도록 합니다.
2️⃣ Dockerfile
Dockerfile은 사용자가 도커 이미지를 쉽게 만들 수 있도록 제공하는 템플릿을 말합니다.
1) Dockerfile 만들기
먼저, Dockerfile 이라는 이름으로 빈 파일을 하나 생성합니다.
# home 디렉토리로 이동
cd $HOME
# docker-practice 폴더 생성
mkdir docker-practice
# docker-practice 폴더로 이동
cd docker-practice/
# Dockerfile 이라는 빈 파일 생성
touch Dockerfile
# 현재 폴더의 파일 확인하기
ls
Dockerfile 이 정상적으로 생성되었음을 확인하였습니다.
2) Dockerfile 내부 기본 명령어
Dockerfile 에서 사용할 수 있는 기본적인 명령어에 대해서 간단히 알아보고, 추후에 필요한 경우에 구글링할 수 있을 정도로 키워드만 알아두는 것을 목표로 합니다.
▪️ FROM
Dockerfile 이 base image로 어떠한 이미지를 사용할 것인지를 명시하는 명령어입니다. base image란, 이 때 처음 사용할 도커 이미지를 말합니다. 도커 이미지를 만들 때는 항상 처음부터 끝까지를 모두 명시해서 만드는 것이 아니라, 처음 일부분은 이미 잘 만들어진 도커 이미지를 그대로 가져오고, 그 이후부터 이미지를 만들어나가게 되기 때문에 필요한 개념입니다. 여기서 어떤 base image를 사용할 것인가를 명시하는 명령어가 바로 FROM입니다. .
FROM <image> [:<tag>] [AS <name>]
# example
FROM ubuntu
FROM ubuntu:18.04
FROM nginx:latest AS ngx
▪️ COPY
<src>의 파일 혹은 디렉토리를 <dest> 경로에 복사하는 명령어입니다.
COPY <src> ... <dest>
# example
COPY a.txt /some-directory/b.txt
COPY my directory /some-directory-2
첫번째 예시처럼 파일을 카피하거나, 두번째 예시처럼 폴더를 카피할 수도 있습니다.
▪️ RUN
명시한 커맨드를 도커 컨테이너에서 실행하는 것을 명시하는 명령어입니다.
RUN <command>
RUN ["excutable-command", "parameter1", "parameter2"]
# example
RUN pip install torch
RUN pip install -r requirements.txt
위의 코드를 예로 들면, 첫번째는 컨테이너 내에서 torch 패키지를 설치, 두번째는 requirements.txt에 있는 모든 파이썬 패키지를 설치하라는 명령어가 됩니다.
▪️ CMD
명시한 커맨드를 도커 컨테이너가 시작될 때 (시작함과 동시에) 실행하는 것을 명시하는 명령어입니다. 추후에 배울 ENTRYPOINT 와 비슷한 역할을 합니다. 또, RUN 명령어와 다른 점은, 하나의 Docker Image에서 하나의 CMD 만 실행할 수 있다는 점 입니다.
CMD <command>
CMD ["excutable-command", "parameter1", "parameter2"]
CMD ["parameter1", "parameter2"] # ENTRYPOPINT 와 함께 사용될 때
# example
CMD python main.py
도커가 시작함과 동시에 main.py 파일을 실행시키라는 명령어입니다.
▪️ WORKDIR
이후 작성된 명령어를 컨테이너 내의 어떤 디렉토리에서 수행할 것인지를 설정해주는 명령어입니다. 해당 디렉토리가 없다면 자동으로 생성하게됩니다.
WORKDIR /path/to/workdir
# example
WORKDIR /home/demo
위의 코드 이후에 실행될 명령어들은 모두 /home/demo 폴더에서 수행이 되도록 하는 코드입니다.
▪️ ENV
컨테이너 내부에서 지속적으로 사용될 environment variable 의 값을 설정하는 명령어입니다.
ENV <key> <value>
ENV <key>=<value>
# example
# default 언어 설정
RUN locale-gen ko_KR.UTF-8
ENV LANG ko_KR.UTF-8
ENV LANGUAGE ko_KR.UTF-8
ENV LC_ALL ko_KR.UTF-8
보통은 ENV를 사용하여 default 언어 설정, 타임존 설정, 포트넘버, 그리고 패스워드 같은 시크릿한 정보를 담아두는 데 사용합니다.
▪️ EXPOSE
컨테이너에서 뚫어줄 포트/프로토콜을 지정할 수 있습니다.이때, protocol을 지정하지 않으면, TCP가 디폴트로 설정됩니다.
EXPOSE <port>
EXPOSE <port>/<protocol>
# example
EXPOSE 8080
이렇게 작성하면 해당 컨테이너는 8080 포트가 TCP 프로토콜로 열린 채로 실행됩니다.
3) 간단한 Dockerfile 작성 실습
vi, vim, nano 또는 vscode 등 본인이 사용하는 편집기를 사용해서 Dockerfile을 열어 작성하도록 합니다. 저는 vim 편집기를 사용하도록 하겠습니다.
vim Dockerfile
Dockerfile
# base image : ubuntu:18.04
FROM ubuntu:18.04
# apt-get update
RUN apt-get update
# DOCKER CONTAINER STARTING => "HELLO WORLD!"
CMD ["echo", "Hello World!"]
위와 같이 Dockerfile 안에 내용을 작성하도록 합니다. base image는 ubuntu:18.04로 설정하고, apt-get update 명령어를 실행하며, 도커가 실행됨과 동시에 echo Hello World! 명령어가 작동됩니다.
3️⃣ Docker build from Dockerfile
이제 위에서 생성한 Dockerfile 로 Docker image를 빌드하고, 해당 이미지로 Docker 컨테이너를 Run 해보는 실습까지 진행합니다.
▪️ docker build: Dockerfile 로부터 Docker image를 생성하는 명령어입니다.
docker build -t my-image:v1.0.0 .
이 코드는 현재 경로(.) 에 있는 Dockerfile로 부터 my-image라는 이름, v1.0.0 이라는 태그의 도커 이미지를 빌드하겠다는 의미입니다.
▪️ 도커 이미지가 정상적으로 빌드되었는지 확인
docker images | grep my-image
위와 같이 성공적으로 도커 이미지가 빌드된 것을 볼 수 있습니다.
▪️ 빌드한 my-image:v1.0.0 이미지로 docker 컨테이너 run 하기
docker run my-image:v1.0.0
직접 빌드한 도커 이미지로 도커 컨테이너를 run 해보면, 아까 Dockerfile에서 작성해놨던 echo Hello World! 가 정상적으로 실행되었습니다.
4️⃣ Docker Image 저장소
도커 이미지를 다른 사람들과 들과 공유하기 위해서는 저장소에 docker image를 저장해야 합니다. 도커 이미지가 저장되는 저장소는 registry라고 합니다. registry는 도커 이미지를 저장하고 관리하기 위한 중앙 저장소로, 도커 이미지는 애플리케이션과 해당 애플리케이션을 실행하는 데 필요한 모든 종속성을 포함하는 패키지입니다. 도커 레지스트리는 이러한 도커 이미지를 저장하고 공유하기 위한 목적으로 사용됩니다.
Docker Hub는 가장 널리 알려진 공개 Docker 레지스트리 중 하나압니다. Docker 이미지를 저장하고 공유하는 데 사용되며, 기본적으로 Docker 이미지를 푸시하고 풀하기 위한 공개 레지스트리입니다. Docker Hub는 Docker 레지스트리의 일종으로 볼 수 있으며, Docker 이미지의 저장소 및 공유 플랫폼으로 널리 사용됩니다.
큰 범위의 Docker registry와 그것의 일부인 Docker hub에 도커 이미지를 push하는 간단할 실습을 수행해보도록 하겠습니다.
1) Docker Registry
docker run -d -p 5000:5000 --name registry registry
먼저, registry 공식 이미지를 받아오고, 해당 이미지를 백그라운드로 실행시킵니다. -p 5000:5000은 호스트의 포트 5000과 컨테이너의 포트 5000을 매핑하여, 호스트의 5000 포트로 접속하면 컨테이너의 5000 포트로 연결되도록 합니다. 요약하자면, registry라는 도커 이미지를 받고, 백그라운드로 5000번 포트로 registry라는 이름의 도커 컨테이너를 실행하는 명령어입니다.
docker tag my-image:v1.0.0 localhost:5000/my-image:v1.0.0
my-image를 위에서 생성한 registry를 바라보도록 tag 합니다. 도커 레지스트리에서 이미지는 일반적으로 레지스트리주소/이미지이름:태그의 형식으로 사용합니다.
docker images | grep my-image
my-image 가 들어가는 도커 이미지를 출력해보았을 때 위와 같이 localhost:5000 레지스트리에 my-image가 잘 생성된 것을 볼 수 있습니다.
docker push localhost:5000/my-image:v1.0.0
마지막으로 my-image를 도커 레지스트리에 푸시 (업로드) 하는 명령어입니다.
# localhost:5000 이라는 registry 에 어떤 이미지가 저장되어 있는지 리스트를 출력하는 명령
curl -X GET http://localhost:5000/v2/_catalog
{"repositories":["my-image"]}
/v2/_catalog는 이미지가 저장되어 있는지 확인하는 api의 endpoint입니다. localhost:5000 레지스트리에 my-image가 잘 저장된 것을 확인하였습니다.
# my-image 라는 이미지 네임에 어떤 태그가 저장되어있는지 리스트를 출력하는 명령
curl -X GET http://localhost:5000/v2/my-image/tags/list
{"name":"my-image","tags":["v1.0.0"]}
태그의 저장도 위와 같은 endpoint로 확인할 수 있습니다.
2) Docker Hub
두번째로 Docker Hub 실습입니다. registry와 같은 방식으로 이루어집니다.
먼저, 도커 회원가입 을 진행합니다.
docker login
그 다음 터미널에서 로그인 합니다.
docker tag my-image:v1.0.0 {username}/my-image:v1.0.0
docker tag <image_name>:<tag_name> <user_name>/<image_name>:<tag> 의 형태로 이미지가 도커 허브를 바라보도록 tag를 생성합니다.
docker push {username}/my-image:v1.0.0
docker push <user_name>/<image_name>:<tag> 형태의 명령어로 Docker hub에 푸시합니다.
docker hub 사이트의 repositories에서 확인해보면, 위와 같이 이미지가 잘 업로드 된 것을 확인할 수 있습니다.
* 본 포스트는 패스트캠퍼스의 강의를 정리한 글 입니다.
'MLOps > 개념 정리' 카테고리의 다른 글
[MLOps] 6. VM에서 minikube 사용하기 (0) | 2023.02.25 |
---|---|
[MLOps] 5. 쿠버네티스의 기본 개념과 YAML (0) | 2023.02.25 |
[MLOps] 3. Docker의 기본적인 명령어 정리 (0) | 2023.02.22 |
[MLOps] 2. Docker 실습 환경 셋팅 (VirtualBox, Ubuntu) (0) | 2023.02.21 |
[MLOps] 1. MLOps와 컨테이너의 개념 (feat, 도커/쿠버네티스) (0) | 2023.02.20 |