새소식

부스트캠프 AI Tech 4기

[Product Serving Part.3] Docker

  • -

가상화

  • 개발을 진행한 Local 환경과 Production 서버 환경이 다른 경우,
    OS가 다르기 때문에 라이브러리, 파이썬 등 설치할 때 다르게 진행해야 한다.
    Local: 윈도우 ↔ Production 서버: Linux
  • Local과 Production 서버가 같은 OS를 사용해도, Local의 환경 변수와 Production 서버의 환경 변수등이 달라서 올바르게 작동하지 않을 수 있다.
  • 개발환경 설정을 README에 기록하고 실행하도록 하면 사람이 진행하는 일이라 Human Error가 발생하거나 번거롭다.
    또 운영하는 서버가 1000대이고, 특정 서버 업데이트가 진행되었다면 나머지 서버에도 다 업데이트가 필요한데 일일이 하기에는 너무 오래걸린다.

⇒ 서버 환경까지도 모두 소프트웨어화 할 수 없을까? ⇒ 가상화

특정 소프트웨어 환경을 만들고, Local/Production 서버에서 그대로 활용할 수 있다.

 

Docker 등장 전에는 가상화 기술로 VM을 사용하였다.

VM : 호스트 머신이라고 하는 실제 물리적인 컴퓨터 위에, OS를 포함한 가상화 소프트웨어를 두는 방식

ex) 호스트 머신은 Window인데, Window에서 Linux를 실행

→ GCP의 Compute Engine 또는 AWS의 EC2
     클라우드 회사에서 미리 만든 이미지를 바탕으로 Computing 서비스를 통해 사용자에게 동일한 컴퓨팅 환경 제공

https://img.vembu.com/wp-content/uploads/2019/02/VM-vs-Containers_02.png

 

그러나 OS 위에 OS를 하나 더 실행시키는 것은 리소스를 굉장히 많이 사용하는 일이다.

이를 해결하기 위해 등장한 기술이 Container 이다.

Container : VM의 무거움을 크게 덜어주면서, 가상화를 좀 더 경량화된 프로세스의 개념으로 만든 기술

 

 

Docker

이런 Container 기술을 쉽게 사용할 수 있도록 나온 도구 

 

Docker Image

  • 컨테이너를 실행할 때 사용할 수 있는 "템플릿"
  • Read Only
  • 다른 사람이 만든 소프트웨어라고 생각할 수 있다.
    • OS, 설정을 포함한 실행환경
    • Linux, Window, Mac 어디에서나 동일하게 실행할 수 있다.

Docker Container

  • Docker Image를 활용해 실행된 인스턴스
  • Write 가능

 

Docker로 할 수 있는 일

  • 자신만의 이미지를 만들고 원격저장소(Container Registry)에 저장하면 어디서나 사용할 수 있다.

 


Docker로 MySQL 실행하기

이미지 다운로드

docker pull "이미지 이름:태그"

docker pull mysql:8

 

다운받은 이미지 확인

docker images

 

컨테이너 실행

docker run --name mysql_practice -e MYSQL_ROOT_PASSWORD=1234 -d -p 3306:3306 mysql:8
  • --name : 컨테이너 이름 설정
    지정하지 않으면 랜덤설정
  • -e : 환경변수 설정
    MYSQL root 계정 비밀번호 설정
  • -d : 데몬(백그라운드) 모드
    이 설정을 하지 않으면 현재 실행하는 셸 위에서 컨테이너가 실행되어 컨테이너의 로그를 바로 확인할 수는 있지만 컨테이너를 나가면 실행이 종료된다.
  • -p : 포트 지정 (로컬 호스트 포트:컨테이너 포트) 
    로컬 포트 3306으로 접근 시 컨테이너 포트 3306으로 연결되도록 설정
    mysql은 기본적으로 3306 포트를 통해 통신
  • mysql:8
    아까 다운받은 이미지

실행된 컨테이너 확인

docker ps

중지된 컨테이너까지 확인

docker ps -a

 

MySQL이 실행되고 있는지 확인하기 위해 컨테이너 진입

User@DESKTOP-FEQ0UC5  /usr/bin
$ docker exec -it mysql_practice bash

MySQL 프로세스로 진입

User@DESKTOP-FEQ0UC5  /usr/bin
$ docker exec -it mysql_practice bash

bash-4.4# mysql -u root -p
Enter password:

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 8.0.31 MySQL Community Server - GPL

Copyright (c) 2000, 2022, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>


컨테이너 중지

docker stop "컨테이너 이름(ID)"


멈춘 컨테이너 삭제

docker rm "컨테이너 이름(ID)"

 

실행 중인 컨테이너 삭제

docker rm "컨테이너 이름(ID)" -f

 

Volume Mount

Host와 Container간의 파일 공유가 되지 않는다.

만일 파일을 유지하고 싶다면 Host와 Container의 저장소를 공유해야한다.

→ -v 옵션

-p 처럼 사용할 수 있다.

-v Host_Folder:Container_Folder

docker run -it -p 8888:8888 -v Host_folder:Container_folder

 


프로젝트를 위한 Docker Image 만들기

가상환경 생성

User@DESKTOP-FEQ0UC5 MINGW64 ~/Desktop/docker_project_setting
$ py -3.8 -m venv venv

User@DESKTOP-FEQ0UC5 MINGW64 ~/Desktop/docker_project_setting
$ source venv/Scripts/activate

(venv) 
User@DESKTOP-FEQ0UC5 MINGW64 ~/Desktop/docker_project_setting
$ pip install pip --upgrade

User@DESKTOP-FEQ0UC5 MINGW64 ~/Desktop/docker_project_setting
$ pip install "fastapi[all]"

 

FastAPI 코드 작성

#main.py
from fastapi import FastAPI
import uvicorn

app = FastAPI()

@app.get("/hello")
def hello():
    return {
        "message" : "World!"
    }

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

 

사용 라이브러리 requirements.txt에 저장

pip freeze > requirements.txt

 

Dockerfile 작성

 

  • FROM <baseImage:tag> : 이미지 빌드에 사용할 베이스 이미지를 지정
    FROM python:3.8.7-slim-buster
  • COPY <로컬 디렉토리(파일)> <컨테이너 내 디렉토리(파일)> 
    컨테이너는 자체적인 파일 시스템과 디렉토리를 가짐
    COPY 명령어는  Dockerfile이 존재하는 경로 기준 로컬 디렉토리를 컨테이너 내부의 디렉토리로 복사
    COPY . /app → 로컬 프로젝트 폴더 최상위에 존재하는 모든 파일을 컨테이너 내부 /app 디렉토리로 복사
  • WORKDIR <컨테이너 내 디렉토리>
    Dockerfile의 RUN, CMD 등의 명령어를 실행할 컨테이너 경로 지정
    WORKDIR /app → 이 라인 뒤의 등장하는 명령어는 컨테이너 내부의 /app 에서 실행
  • ENV <환경변수 이름=값>
    컨테이너 내 환경변수를 지정
    ENV PYTHONPATH=/app
    ENV PYTHONBUFFERED=1 → 파이썬 애플리케이션의 경우 통상 위 두 값을 지정함
  • RUN <실행할 리눅스 명령어>
    RUN pip install pip==22.3.1 && \
    pip install -r requirements.txt
    이전 라인에서 COPY와 WORKDIR이 실행되었기 때문에 container 내에 requirements.txt가 존재하고 이를 pip install -r로 실행시킬 수 있다.

    && \ → 한번에 실행할 명령어가 여러개인 경우 이어주는 역할
  • CMD [<"실행할 명령어">, <"인자">, ... ]
    CMD ["python", "main.py"]
    docker run으로 이 이미지 기반 컨테이너를 만들 때 실행할 명령어를 담는다.
    CMD는 띄어쓰기를 사용하지 않는다.
RUN과 CMD의 차이는?

RUN 명령어
: 도커파일로부터 도커 이미지를 빌드하는 순간에 실행이 되는 명령어


Docker는 Container를 실행할 때 도커 이미지가 필요하다.
이 이미지를 만들때는 보통 도커 허브의 이미 만들어진 이미지를 베이스 이미지로 놓고,
이 베이스 이미지에 Docker 명령어를 가지고 자신에게 맞는 환경을 하나하나 얹는다. (layer를 더한다고 표현함)
RUN 명령어는 명령을 실행한 결과를 새로운 layer를 더하는 과정으로 볼 수 있다.

CMD 명령어
:  RUN 명령어는 이미지를 작성하기 위해 실행하는 명령어라면, CMD는 이미지를 바탕으로 생성된 컨테이너 안에서 명령을 실행하기 위한 명령어

ENTRYPOINT 명령어
: CMD와 마찬가지로 컨테이너 안에서 명령을 실행하기 위한 명령어
그러나 ENTRYPOINT로 정의하는 명령어는 컨테이너가 수행될 때 변경되지 않는다.

Example)
# Dockerfile
FROM ubuntu:latest
CMD ["echo", "hello"]

prac이라는 이름의 이미지를 빌드
빌드한 이미지 컨테이너로 실행하면서 echo world 명령까지 실행해보면
기존 도커 파일은 "hello"로 실행되도록 되었지만 "world"라고 출력됨을 알 수 있다.
⇒ parser argument의 default값이라고 생각하면 될 것 같다.

$ sudo docker build --tag prac .
$ sudo docker run prac echo world
world​

FROM ubuntu:latest
ENTRYPOINT ["echo", "hello"]

ENTRYPOINT로 지정하면 명령 인자를 무엇을 주든 무조건 ENTRYPOINT 값이 실행된다.
그리고 뒤에 추가로 실행한 명령어인 echo world 는 매개변수로 처리되어 뒤에 함께 처리된다.

$ sudo docker build --tag prac .
$ sudo docker run prac echo world
hello echo world

 


그래서 CMD 명령어는 ENTRYPOINT 명령어로 지정된 커맨드에 디폴트로 넘길 파라미터를 지정할 때 사용한다.

ENTRYPOINT ["python"]
CMD ["helloworld.py"]

 

Docker 이미지 생성

docker build <Dockerfile이 위치한 경로> -t <이미지 이름:태그>

docker build . -t my-fastapi

생성된 이미지를 확인해보면 잘 생성된 것을 알 수 있음

User@DESKTOP-FEQ0UC5 MINGW64 ~/Desktop/docker_project_setting
$ docker images
REPOSITORY                                            TAG       IMAGE ID       CREATED              SIZE    
my-fastapi                                            latest    bebcf58eb45c   About a minute ago   253MB   
mysql                                                 8         2a04bf34fdf0   5 days ago           535MB

 

Docker 이미지를 이용해 컨테이너 실행

docker run -p 8000:8000 my-fastapi:latest
User@DESKTOP-FEQ0UC5 MINGW64 ~/Desktop/docker_project_setting
$ docker run -p 8000:8000 my-fastapi:latest
INFO:     Started server process [1]      
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

다른 터미널을 열어 curl로 애플리케이션 동작 확인해보면 정상동작함

User@DESKTOP-FEQ0UC5 MINGW64 ~/Desktop/docker_project_setting
$ curl localhost:8000/hello
{"message":"World!"}(venv)
728x90
Contents