Docker

J. Hwang·2024년 12월 18일
0

Docker는 컨테이너 (Container) 기술을 기반으로 애플리케이션을 개발, 배포, 실행할 수 있도록 지원하는 오픈 소스 플랫폼이다. 일단 컨테이너란 무엇이고, 왜 사용하는 것일까?

개발할 때의 서버와 배포하려는 서버는 OS, 환경변수, 퍼미션 등 환경이 다를 수 있다. 그러나 설정들을 일일이 기록하는 것은 번거롭고, 혹시 하나라도 누락된다면 에러가 발생하며 제대로 작동하지 않을 것이다. 이런 문제를 해결하기 위해, 개발한 프로그램 뿐만 아니라 프로그램이 구동되는 서버 환경까지도 소프트웨어화하려는 시도들이 생겨났다.

기존에는 이를 virtual machine으로 구현했다. virtual machine은 호스트 머신이라고 하는 실제 물리적인 컴퓨터 위에 OS를 포함한 가상화 소프트웨어를 두는 방식이다. 그러나 virtual machine은 OS 위에 OS를 하나 더 실행시키는 것이기 때문에 리소스를 많이 사용한다는 단점이 있다. 컨테이너는 이러한 가상화를 경량화하여 더 빠르고 가볍게 가상 환경을 구동할 수 있게 해준다.

컨테이너 기술을 이용하는 Docker를 활용하면 Docker image를 생성할 수 있는데, 이는 컨테이너를 실행할 때 사용하는 "템플릿"이다. (Read only) 그리고 Docker image를 실행한 instance를 Docker container라고 한다. (write 가능)

이제 Docker 사용법을 배워 어느 환경에서나 동일한 환경으로 프로그램을 실행시킬 수 있도록 연습해보자.


기본 명령어 정리

  • $ docker pull image_name:tag : image_name:tag라는 docker image를 docker hub에서 다운로드
  • $ docker images : 다운 받은 docker image의 목록을 출력
  • $ docker run image_name:tag : image_name:tag라는 docker image를 기반으로 docker container를 만들고 실행
    • --name : 컨테이너 이름을 지정하는 옵션. 지정하지 않으면 랜덤으로 생성된다.
    • -e : 환경 변수 설정. docker image에 따라 다르다.
      MySQL의 예를 들자면, -e MYSQL_ROOT_PASSWORD=1234와 같이 root 계정의 비밀번호를 설정할 수 있다.
    • -d : demon (백그라운드) 모드. 이 옵션을 주지 않으면 현재 실행 중인 shell 위에서 컨테이너가 실행된다.
    • -p host_port:container_port : -p 8000:8000와 같이 지정했다면, 로컬 호스트 포트 8000으로 접근했을 때 컨테이너 포트 8000으로 연결되도록 설정한 것이다.
    • -v host_directory:container_directory : volume mount 설정. host 컴퓨터와 컨테이너의 저장소를 공유하기 위한 옵션이다.
  • $ docker ps : 현재 실행중인 docker 컨테이너 목록 출력
    • -a : 작동을 멈춘 docker container 목록 출력
  • $ docker exec -it "CONTAINER_ID" /bin/bash : (현재 실행중인 CONTAINER_ID의) docker 컨테이너 내부로 진입
  • $ docker stop "CONTAINER_ID : CONTAINER_ID docker 컨테이너 중지
  • $ docker rm "CONTAINER_ID" : (중지된 CONTAINER_ID의) docker 컨테이너 삭제
    • -f : 실행중인 docker container를 강제 삭제

설치

Docker 공식 홈페이지에서 자신의 운영체제에 맞는 Docker Desktop 설치

(Docker 설치 완료까지는 시간이 좀 걸리는 편)


dockerhub

dockerhub는 Docker image를 저장, 공유, 배포할 수 있는 클라우드 기반 레지스트리 서비스이다. Docker의 공식 이미지 저장소이자 널리 사용되는 컨테이너 이미지 관리 플랫폼으로, 개발자가 컨테이너화된 애플리케이션을 쉽게 배포하고 공유할 수 있다. 여기에서 원하는 이미지를 받아서 사용하면 된다.

github처럼 자신이 만든 이미지를 pubic/private repository에 업로드하거나 받아올 수 있다. 먼저 https://hub.docker.com/signup에서 docker hub 계정을 만든다. 그리고 $ docker login으로 로그인을 하고, docker tag my-image:latest dockerhubid/my-repo-name:latest로 내 이미지를 태그한다. 그 후 docker push mydockerhubid/my-repo-name:latest로 push하면 내 저장소로 이미지를 업로드할 수 있다. 무료 계정은 1개의 private repository를 제공한다고 한다.


Docker image 생성

Docker image를 생성하기 위해서는 먼저 Dockerfile을 생성해야 한다. Dockerfile은 docker image를 빌드하기 위한 정보를 저장하는 파일이다.

  • FROM image_name:tag : image_name:tag를 베이스 이미지로 사용. 보통 0에서부터 만들기 보다는 이미 존재하는 이미지를 기반으로 만들게 됨.
  • COPY host_directory:container_directory : host 디렉토리에 있는 파일들을 container 디렉토리로 복사
  • WORKDIR container_directory : dockerfile 내의 CMD, RUN 등의 명령어를 실행할 컨테이너의 경로
  • ENV 환경변수_이름=값 : 컨테이너 내의 환경 변수를 지정. ENV PYTHONPATH=/app이면 컨테이너 내의 파이썬 경로를 /app으로 지정하겠다는 의미이다.
  • RUN 리눅스_명령어 : docker image를 빌드할 때 실행할 명령어. image를 생성하기 위해 필요한 소프트웨어 설치, 설정 변경 등 영구적으로 적용되는 설정을 저장한다. 실행할 명령어가 여러 개인 경우 && \로 연결
RUN pip install pip==23.0.1 && \
    pip install -r requirements.txt
  • CMD ["명령어", "인자"] : docker run으로 컨테이너를 실행할 때 실행할 명령어를 지정. CMD ["python", "main.py"]로 설정하면 docker image가 실행되었을 때 main.py가 실행된다.

여기서는 이전에 만들어 둔 간단한 웹 API 하나를 Docker image로 만드는 실습을 해보겠다. 만들어 둔 웹 API가 있는 디렉토리에서 Dockerfile이라는 이름의 도커파일을 만들자.

FROM python:3.9.13-slim     # 베이스 이미지

WORKDIR /code
COPY ./requirements.txt /code/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
COPY . /code
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]

이 파일을 저장하고 아래 명령어를 실행하면 docker image가 생성된다. 명령어의 형태는 docker build -t image_name:tag_name /dockerfile_director와 같다.

$ docker build -t APIweb:first .

docker image가 잘 만들어졌는지 확인하려면 $ docker images를 입력하면 된다.

그리고 만들어진 docker image가 잘 동작하는지 확인해보기 위해, docker run을 해보자. $ docker run -p 8000:8000 APIweb:first 하면 방금 만든 docker image를 실행시킬 수 있다. 그리고 브라우저에서 localhost:8000 에 접속하면 웹 페이지가 잘 동작하는지 확인할 수 있다.


Docker image push

만든 docker image를 docker hub나 container registry에 업로드해보자. 이를 push라고 한다.
여기서는 docker hub을 이용해서 push 해보겠다. 먼저 docker hub에 가입되어 있지 않다면 계정을 먼저 만들고, $ docker login으로 로그인하자. 그리고 $ docker tag image_name:tag_name my_id/image_name:tag_name를 한 뒤에 $ docker push my_id/image_name:tag_name를 하면 docker hub에 이미지가 업로드된다.


image size 최적화하기

보통 ML 모델이 들어간 docker image는 크기가 매우 크다. docker image는 용량이 클수록 메모리 용량을 많이 차지하고, 빌드 속도가 느려진다. 따라서 image size를 최적화하는 과정이 필요하다. image size를 최적화하기 위해서는 1) 용량이 작은 base image를 선정해서 사용하고, 2) multi stage build를 활용하고, 3) container를 잘 패키징해야 한다.

용량이 작은 base image 선택하기

python image에는 표준, slim, alpine 이미지가 있다. slim은 Debian 이미지를 기반으로 하여 보다 가볍고 production 환경에 적합하다. alpine 이미지는 alpine linux 기반으로 크기가 작은 대신 종속성은 수동 설치해야 할 수도 있다.
(ex) FROM python:3.9.13-slim)

Multi stage build

Multi stage build는 빌드에는 필요하지만 최종 컨테이너 이미지에는 필요 없는 내용을 제외하며 컨테이너 이미지를 생성하는 방법이다. 하나의 docker file에 여러 이미지를 빌드하고, 베이스 이미지를 바꾸며 사용한다. (예시)

container 패키징

  • .dockerignore로 필요없는 파일 제거
  • .pt, .pth과 같이 사이즈가 큰 파일들은 빌드에서 포함하지 않고, 빌드 타임 혹은 컨테이너 시작하는 스크립트에서 다운로드 하도록 설정
  • dockerfile에서 변경 가능성이 낮은 명령어를 위로, 변경 가능성이 높은 명령어는 아래에 위치시킴으로서 캐싱을 최대한 이용하도록 한다.

docker compose 사용하기

docker image 여러 개를 동시에 실행해야 할 때가 있다. 예를 들어 A 이미지는 database, B 이미지는 웹 서비스여서 둘을 동시에 실행하려고 할 경우이다. 이럴 때 docker compose를 사용하면 여러 컨테이너를 한 번에 실행시키면서 여러 컨테이너의 실행 순서와 의존도를 관리할 수 있다.
docker compose는 아래와 같이 docker-compose.yml 파일을 작성함으로써 실행시킬 수 있다. 아래는 db 컨테이너와 app 컨테이너를 함께 실행시키는 파일이다.

version: '3'    # docker compose 버전

services:
  db:
  	image: mysql.5.7.12
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: my_database
    ports:
      - 3306:3306
  app:
    build:
      context: .
    environment:
      DB_URL: mysql+mysqldb://root:root@db:3306/my_database?charset=utf8mb4
    ports:
      - 8000:8000
    depends_on:      # app은 db가 실행된 이후에 실행
      - db
    restart: always

이 docker-compose.yml 파일을 저장하고 $ docker-compose up을 하면 여러 컨테이너를 한 번에 실행할 수 있다.

profile
Let it code

0개의 댓글