[Devops] Docker image 생성 및 실행

황인용·2021년 5월 23일
0

Devops

목록 보기
6/7
post-thumbnail
post-custom-banner

docker image 란 어플리케이션과 해당 환경을 패키지화한 것
docker file은 자신의 docker image를 만드는데 필요한 개발환경과 패키지등을 DSL(Domain Specific Language)화 한 것

object

  • 간단하게 python-flask로 hello api를 응답해주는 application을 docker file로 image 만들어 보기
  • 만든 이미지를 확인하고 실행해보기

Create Application(Hello-api)

Development environment

  • python : v3.9.2
  • flask : v2.0.1
  • rootdir : ~/[your_path]/docker-app/api/

Create Development environment

[1] cd ~/[your_path]/docker-app/api/
[2] virtualenv venv
[3] . venv/bin/actiavte
[4] python -m pip install --upgrade pip
[5] pip install flask gunicorn
[6] pip freeze > requirements.txt

[1] directory 변경(api path)
[2] python 가상환경 생성
[3] 가상환경 활성화
[4] pip 업그레이드
[5] flask 및 gunicorn 설치
[6] pip list를 requirements.txt 로 작성

create app.py

[1] vi app.py
# ~/docker-app/api/app.py
from flask import Flask, make_response, jsonify, request
app = Flask(__name__)

@app.route('/')
def hello():
    return jsonify({
	'code': 200,
	'msg': 'Hello World!'
    })


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=80)
else:
    gunicorn_app = app
    gunicorn_app.debug = True
  • get 호출 시 "Hello World!" 응답하는 api 생성
  • gunicorn으로 실행시, "app:gunicorn_app" parameter로 넘겨서 실행해야함
  • ex) gunicorn -b 0:8080 app:gunicorn_app
  • gunicorn 사용법은 다음 포스트에...

flask run server

[1] python app.py
* Serving Flask app 'app' (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on all addresses.
   WARNING: This is a development server. Do not use it in a production deployment.
 * Running on http://172.30.82.223:80/ (Press CTRL+C to quit)

http request & response

[1] curl -v localhost
*   Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 80 failed: Connection refused
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.64.1
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Content-Type: application/json
< Content-Length: 34
< Server: Werkzeug/2.0.1 Python/3.9.2
< Date: Sun, 23 May 2021 04:16:33 GMT
<
{"code":200,"msg":"Hello World!"}
* Closing connection 0
  • client에서 curl로 http request 및 response 확인

Create DockerFile

vi Dockerfile

vi Dockerfile
  • 위 application을 ubuntu기반으로 dockerfile 작성
# api/Dockerfile
[1] FROM ubuntu:20.04
[2] WORKDIR /home/docker-app/api
[3] RUN apt update && apt-get install python3 python3-pip -y
[4] ADD . .
[5] RUN pip3 install -r requirements.txt
[6] EXPOSE 8080
[7] CMD gunicorn -b 0:8080 --access-logfile log/access.log --error-logfile log/error.log --threads 4 app:gunicorn_app
  • Dockerfile 내 내용은 각 옵션에 따라 Docker Container 내에서 실행된다.

[1] FROM 은 docker container의 운영체제를 지정함
또는 빌드환경을 지정함
[2] WORKDIR docker container 내 해당 application project main directory를 지정하여 만들고 이동함
[3] RUN docker container 내에서 실행하는 명령어로 container의 OS가 ubuntu로 지정하였음으로 apt 명령어로 업데이트 및 python3를 설치
(정확하게 위 api 와 같이 python v3.9.2 버전을 설치하고자 한다면, wget으로 별도로 설치해야함.)

[4] ADD 현재 host(내 PC)의 directory의 파일들을 container의 directory로 추가 (현재 ~/api/ 디렉토리에 api의 파일들(app.py, requirements.txt 등)을 container의 workdir로 이동 또는 directory를 지정가능 ex) ADD . /home/docker-app/api)

[5] (ubuntu에는 기본 python2가 설치 되어 있음으로..) pip3 로 requirements.txt 파일을 읽어서 application에 필요한 패키지 설치
[6] EXPOSE 는 container의 service port를 설정하는 것으로 8080포트를 열어줌
[7] CMD는 container 초기 구동 시 실행되는 명령어로 gunicorn 명령어로 프로젝트를 실행할 수 있는 명령어를 작성

create docker image

docker build

docker build --tag docker-app/api:1.0.0 .
[+] Building 283.9s (10/10) FINISHED
 => [internal] load build definition from Dockerfile                                                                                                                                                                                     0.0s
 => => transferring dockerfile: 765B                                                                                                                                                                                                     0.0s
 => [internal] load .dockerignore                                                                                                                                                                                                        0.0s
 => => transferring context: 2B                                                                                                                                                                                                          0.0s
 => [internal] load metadata for docker.io/library/ubuntu:20.04                                                                                                                                                                          1.2s
 => [1/5] FROM docker.io/library/ubuntu:20.04@sha256:cf31af331f38d1d7158470e095b132acd126a7180a54f263d386da88eb681d93                                                                                                                    0.0s
 => [internal] load build context                                                                                                                                                                                                        0.1s
 => => transferring context: 134.83kB                                                                                                                                                                                                    0.1s
 => CACHED [2/5] WORKDIR /home/docker-app/api                                                                                                                                                                                            0.0s
 => [3/5] RUN apt update && apt-get install -y  build-essential  zlib1g-dev  libncurses5-dev  libgdbm-dev  libnss3-dev  libssl-dev  libreadline-dev  libffi-dev  libsqlite3-dev  wget  libbz2-dev && wget https://www.python.org/ftp/  268.6s
 => [4/5] ADD . .                                                                                                                                                                                                                        0.4s
 => [5/5] RUN pip3 install -r requirements.txt                                                                                                                                                                                          10.1s
 => exporting to image                                                                                                                                                                                                                   3.5s
 => => exporting layers                                                                                                                                                                                                                  3.5s
 => => writing image sha256:902f310dd3ccf93901bd9398f964f46d1fe7ecde67eab676468517ea8a79cc17                                                                                                                                             0.0s
 => => naming to docker.io/docker-app/api:1.0.0
 
  • 작성한 dockerfile 기준으로 docker image를 만듬

  • build : docker image를 만들때 사용하는 옵션
    - --tag : tag를 달아서 이미지를 만들수 있음
    ex) [project이름]/[어플리케이션이름]:[버전]

  • . : Dockerfile의 위치를 옵션으로 넣어줌(현재는 ~/api/ 에 Dockerfile를 작성하고 docker build 명령어를 실행하기에 현재 디렉토리(.)로 옵션을 넣음)

docker images

docker images
(venv) ➜  api docker images
REPOSITORY                              TAG       IMAGE ID       CREATED          SIZE
docker-app/api                          1.0.0     902f310dd3cc   12 minutes ago   1.06GB
  • docker images 명령어를 통해 현재 만들어진 docker image를 확인

docker run

docker running

docker run -d -p 8080:8080 --name test-api docker-app/api:1.0.0
423b00d6a09f7b8f626b6054cf53dcb73ed2c57ee0c6e0fb85dc6aab026d9198
  • 생성한 docker images를 docker run 명령어로 실행
  • -d : daemon processor로 구동
  • -p : local에서 docker-container로 port forwarding 하는 옵션으로, local포트(8080)을 container포트(8080)으로 매핑하는 것
    ex) -p 80:8080 이면 local포트(80)을 container포트(8080)으로 매핑
  • --name : container의 이름(별칭)을 지어줌
  • [image_name] : 마지막으로 local에 해당되는 이미지가 있으면 가져와서 실행. 또는 docker-hub(또는 docker registry가 될수도 있음) 에서 image이름에 맞는 image를 pull 받아서 실행.

docker ps | docker ps -a

docker ps
CONTAINER ID   IMAGE                  COMMAND                  CREATED          STATUS          PORTS                    NAMES
423b00d6a09f   docker-app/api:1.0.0   "/bin/sh -c 'gunicor…"   24 minutes ago   Up 24 minutes   0.0.0.0:8080->8080/tcp   test-api

docker ps -a
CONTAINER ID   IMAGE                                         COMMAND                  CREATED          STATUS                      PORTS                    NAMES
423b00d6a09f   docker-app/api:1.0.0                          "/bin/sh -c 'gunicor…"   24 minutes ago   Up 24 minutes               0.0.0.0:8080->8080/tcp   test-api
9e3012c16905   xxx.xxx.xxx/test_api:1.0.0    "gunicorn -b 0:8080 …"   11 days ago      Exited (0) 40 minutes ago                            api
  • docker ps : 현재 구동중인 docker container의 process 이름, 상태, CMD등 정보를 출력
  • docker ps -a : -a를 추가 옵션을 넣을 경우, 구동중이거나 멈춰있거나 모든 상태의 docker container 정보를 출력

http request & response

curl -v localhost:8080
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: gunicorn
< Date: Sun, 23 May 2021 06:01:16 GMT
< Connection: keep-alive
< Content-Type: application/json
< Content-Length: 44
<
{
  "code": 200,
  "msg": "Hello World!"
}
* Connection #0 to host localhost left intact
* Closing connection 0

[참고] dockerfile with python v3.9.xx(특정버전)

python 3.9.xx(특정버전) 수동설치

  • 특정 python 버전으로 dockerfile을 만들고자 한다면, 특정 버전의 python을 wget으로 받아서 설치해야한다.
# dockerfile
FROM ubuntu:20.04
WORKDIR /home/docker-app/api
[1]RUN apt update \
&& apt-get install -y \
	build-essential \
	zlib1g-dev \
	libncurses5-dev \
	libgdbm-dev \
	libnss3-dev \
	libssl-dev \
	libreadline-dev \
	libffi-dev \
	libsqlite3-dev \
	wget \
	libbz2-dev \
[2]&& wget https://www.python.org/ftp/python/3.9.2/Python-3.9.2.tgz \
[3]&& tar -xf Python-3.9.2.tgz \
[4]&& cd Python-3.9.2 \
[5]&& ./configure --enable-optimizations \
[6]&& make -j 12 && make altinstall \
[7] update-alternatives --install /usr/bin/python3 python3 /usr/local/bin/python3.9 1
[8]&& apt-get install -y python3-pip
ADD . .
RUN pip3 install -r requirements.txt
EXPOSE 8080
CMD gunicorn -b 0:8080 --access-logfile log/access.log --error-logfile log/error.log --threads 4 app:gunicorn_app

[1] python 설치관련 필요한 패키지를 apt-get으로 설치
[2] wget으로 공식 python v3.9.2 repository의 파일들을 다운로드
[3] Python-3.9.2.tgz 압축해제
[4] Python-3.9.2 디렉토리 이동
[5] 설치 config 설정
[6] make 명령어로 컴파일 및 설치
[7] python3.9python3 링크로 업데이트
[8] python3-pip 설치

python:3.9.2-slim

  • 어느날 리서치해보니 수많은 docker hub 들 중 python - docker hub를 찾았다.
  • 그 중 docker image를 light하게 python을 구동할 수 있는 image를 찾았다.
[1]FROM python:3.9.2-slim
WORKDIR /home/docker-app/api
ADD . .
[2]RUN pip install -r requirements.txt
EXPOSE 8080
CMD gunicorn -b 0:8080 --access-logfile log/access.log --error-logfile log/error.log --threads 4 app:gunicorn_app

[1] python-docker hub에서 원하는 버전의 slim 태그 버전을 선택하여 설치
[2] 기존에는 python3를 별도로 설치했어야했지만, pip가 버전에 맞게 설치되어 있음

profile
dev_pang의 pang.log
post-custom-banner

0개의 댓글