AI TECH

Docker

prefer_all 2022. 11. 11. 14:22
<목차>
1. 가상화
- VM VS Docker
2. Docker
- image, container

 

 

가상화

(문제) 개발을 진행한 Local 환경과 Production 서버 환경이 다른 경우,

Local 환경과 서버가 같은 OS를 사용해도, 서버에서 올바르게 작동하지 않을 수 있다.

(해결) 특정 소프트웨어 환경을 만들고, Local, Production 서버에서 그대로 활용할 수 있도록 한다.

즉, 서버 환경까지도 모두 한번에 소프트웨어화하는 것이다.

 

Docker 등장 전에는 VM(Virtual Machine)을 사용하였다. 

앞서 사용한 GCP의 Compute Engine 또는 AWS EC2가 이런 개념을 활용한다.

즉, 클라우드 회사에서 미리 만든 이미지를 바탕으로, Computing 서비스를 통해 사용자에게 동일한 컴퓨팅 환경을 제공한다.

 

VM이란

VM은 호스트 머신이라고 하는 실제 물리적인 컴퓨터 위에, OS를 포함한 가상화 소프트웨어를 두는 방식이다.
ex. 호스트 머신은 Window(Mac)인데, Window에서 Linux를 실행

 

(문제) VM의 단점은 OS 위에 OS를 하나 더 실행시키기 때문에, 굉장히 리소스를 많이 사용한다는 것이다. (무겁다)

(해결) VM의 무거움을 크게 덜어주면서, 가상화를 좀 더 경량화된 프로세스의 개념으로 만든 기술인 Container가 등장했다. Container을 통해 빠르고 가볍게 가상화를 구현할 수 있다.

Docker가 Container 기술을 쉽게 사용할 수 있는 도구이다.


Docker

 

- Docker Image로 만들어두고, 재부팅하면 Docker Image의 상태로 실행을 한다.

- 다른 사람이 만든 소프트웨어도 Docker Image로 가져와서 사용할 수 있다.

 

Docker Image VS Docker Container

Docker Image
- 컨테이너를 실행할 때 사용할 수 있는 “템플릿”
- Read Only

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

Docker 사용하기

도커 다운로드 후 cmd 창에 아래와 같이 입력

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

 

다운받은 이미지 확인

docker images

 

도커 실행하기

이미지를 기반으로 컨테이너를 생성한다

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

컨테이너 이름 지정 안하면 랜덤으로 생성된다.

 

데몬(백그라운드)모드 : 컨테이너를 백그라운드 현태로 실행한다.

이 설정을 하지 않으면 현재 실행하는 셀 위에서 컨테이너가 실행된다.

컨테이너의 로그를 바로 볼 수 있으나, 컨테이너를 나가면 실행이 종료된다.

 

포트 지정 : 로컬 포트(내 컴퓨터) 3306 접근시 컨테이너 포트(컨테이너 이미지 내부) 3306으로 연결되도록 설정했다.

(mysql은 기본적으로 3306 포트를 통해 통신한다)


Docker 기본  명령어

 

실행중인 컨테이너 확인하기

docker ps

 

컨테이너 진입하기 (Compute Engine에서 SSH와 접속하는 것과 유사)

docker exec -it “컨테이너 이름(ID)" /bin/bash

 

작동이 멈춘 컨테이너까지 확인하기

docker ps -a

 

실행 중인 컨테이너를 중지하기

docker stop “컨테이너 이름(ID)”

 

멈춘(중지된) 컨테이너 삭제하기

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

 

실행중인 컨테이너 삭제하기

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

 

도커가 실행중일 때 파일을 공유하는 방법

 

(문제) Docker Container 내부는 특별한 설정이 없으면 컨테이너를 삭제할 때 파일이 사라짐
           =Host와 Container와 파일 공유가 되지 않음
(해결책) 만약 파일을 유지하고 싶다면 Host(우리의 컴퓨터)와 Container의 저장소를 공유해야 함

(해결) Volume Mount

- Volume Mount를 진행하면 Host와 Container의 폴더가 공유됨
-v 옵션을 사용하며, -p(Port)처럼 사용함.
    -v Host_Folder:Container_Folder


Docker - MySQL 실행하기

 

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

docker exec -it “컨테이너 이름(혹은 ID)” /bin/bash

MySQL 프로세스로 들어가면 MySQL 쉘 화면이 보인다 

mysql -u root -p


Docker Image 만들기

간단한 FastAPI 애플리케이션을 실행하는 서버를 Docker Image 생성하는 실습을 해보자
(아래 정리는 별희웅니 블로그)

 

가상환경 생성

$ python -V

User@DESKTOP-FEQ0UC5 MINGW64 ~/Desktop/docker_project_setting
$ python -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
pip list --not-required --format=freeze # 의존성에 따라 설치된 라이브러리는 보이지 않음

 

Dockerfile 작성

Dockerfile에는 Docker 이미지를 빌드하기 위한 정보가 담긴다

 

  • 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로 실행시킬 수 있다.
    && \ → 한번에 실행할 명령어가 여러개인 경우 이어주는 역할 
    (docker 파일 한 줄을 layer라고 하는데 &&는 두 개의 layer을 하나로 묶어줌)
  • 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 이미지 생성

 

-t “이미지 이름:태그” 옵션으로 이미지 이름과 태그 지정할 수 있음

태그는 미 지정시 “latest”로 채워짐

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)

 

 

'AI TECH' 카테고리의 다른 글

MRC  (0) 2022.12.20
언어모델 실습  (1) 2022.11.24
Linux, Shell  (0) 2022.11.10
ML Ops  (0) 2022.11.07
N21, N2N, N2M  (0) 2022.10.25