본문 바로가기

Container/Docker

10. Docker Image 생성 (도커파일)

이번에는 Dockerfile 을 통해 처음부터 Docker 이미지를 생성하고
 
이를 Docker 레지스트리에 push 해보도록 하자.
 
 
Dockerfile
 
Dockerfile 은 GO 문법으로 작성된 Docker 이미지 설정파일이다.
 
Dockerfile 에 설정된 내용대로 이미지를 생성할 수 있다. 
 
Dockerfile 에서 주로 사용되는 키는 아래와 같다.  
 
FROM
어떤 이미지를 기반으로 할지 설정
<이미지 이름>:<태그> 형식으로 설정
 
MAINTAINER
이미지를 생성한 사람의 정보를 설정하며 형식은 자유
 
RUN
Shell 스크립트 혹은 명령을 실행
이미지 생성 중에는 사용자 입력을 받을 수 없으므로
apt-get install 명령에서 -y 옵션을 사용
 
VOLUME
호스트와 공유할 디렉터리 목록
 
WORKDIR
CMD, RUN, ENTRYPOINT 에서 설정한 실행 파일이 실행될 디렉터리
 
CMD
컨테이너가 시작되었을 때 실행할 실행 파일 또는 스크립트
 
ENTRYPOINT
컨테이너가 시작되었을 때 실행할 실행 파일 또는 스크립트 (CMD 와 차이 있음)
 
EXPOSE
호스트와 연결할 포트 번호
ENV
환경 변수를 설정
ADD
 파일을 이미지에 추가 ( 압축파일의 경우 압축을 풀어서 전달 )
COPY
 파일을 이미지에 추가
USER
 명령을 실행할 사용자 계정을 설정
 
MAINTAINER
 
이미지를 생성한 사람의 정보를 설정하며 형식은 자유롭게 입력하고 생략 가능하다.
 
MAINTAINER <작성자 정보>
 
FROM
 
Docker 이미지를 어떤 이미지 기반으로 생성할지 설정한다.
 
여기에 명시한 이름의 이미지를 Docker 의 Package Manager 를 통해 다운로드 받게 된다.
 
이는 리눅스의 apt-get 이나 yum 명령과 비슷하다.
 
Dockerfile 로 이미지를 생성할 때는
 
항상 도커 저장소에 있는 이미지를 기반으로 생성하기 때문에 FROM 은 반드시 설정해야 한다.
 
도커 <이미지 이름> 만 설정하면 태그로 latest 가 자동으로 들어가고 
 
<이미지이름>:<태그> 로 설정하면 해당 태그로 이미지를 생성한다.
 
#FROM <이미지이름>:<태그>
FROM ubuntu:14.04
FROM ubuntu
 
ENV
 
환경 변수를 설정한다.
 
환경 변수는 RUN, CMD, ENTRYPOINT 에 적용할 수 있다.
 
#ENV <VariableName> <Value>
ENV GOPATH /go
ENV HELLO 1234
CMD echo GOPATH/HELLO
 
RUN
 
RUN 명령은 FROM 에서 설정한 이미지 위에서 스크립트 혹은 명령을 실행한다. 
 
실행의 결과는 새 이미지에 포함되며 실행 내역은 이미지의 히스토리에 기록된다. 
 
( 각 RUN 이 하나하나 commit 된다 )
 
기술하는 방식으로는 Exec Form 과 Shell Form 을 지원한다.
 
# Shell Form
# RUN <command>
# 변수, 하위 명령, 파이프 출력, 명령 결합 및 기타 셸 편의를 확장하는 셸이 제공
 
RUN apt-get install -y nginx
RUN echo "Hello Docker" > /tmp/hello
RUN git clone https://github.com/docker/docker.git
 
# Exec Form ( 실행 파일을 찾아서 실행함 )
# RUN ["<executable", "<param 1>", "<param 2>"]
# bash 를 사용하고 싶다던지 아니면 bin/sh 의 편의 기능을 일부로 억제해야 하는 경우
 
RUN ["/bin/bash", "-c", "echo hello"]
RUN ["mysqld", "--datadir=/var/lib/mysql", "--user=mysql"]
 
CMD
 
docker run 명령으로 컨테이너를 생성하거나,  
 
docker start 명령으로 정지된 컨테이너를 시작할 때 실행될 명령이나 스크립트 혹은 서비스를 넣는다. 
 
CMD 는 Dockerfile 에서 한 번만 사용할 수 있다.
 
사용자가 docker Run 명령에서 다른 Command 를 지정하면 도커 파일에 지정한 CMD 명령은 모두 무시된다.
 
왜냐하면 docker run 에서 Command 를 넣으면 이 값이 CMD 로 배치하기 때문이다.
 
# Exec Form
# CMD ["<executable", "<param 1>", "<param 2>"]
CMD ["mysqld", "--detadir=/var/lib/mysql", "--user=mysql"]
 
# Shell Form
CMD <command>
CMD touch /home/hello/hello.txt
 
ENTRYPOINT 와 같이 사용되면 CMD 는 단순히 매개 변수 역할을 하게 된다.
 
ENTRYPOINT ["echo"]
CMD ["hello"]
 
$ sudo docker build --tag example
$ sudo docker run example
hello
 
ENTRYPOINT
 
docker run 명령으로 컨테이너를 생성하거나, 
 
docker start 명령으로 정지된 컨테이너를 시작할 때 실행할 명령이나 스크립트 혹은 서비스를 넣는다. 
 
ENTRYPOINT 도 Dockerfile 에서 한 번만 사용할 수 있다.
 
사용자가 docker Run 명령에서 다른 Command 를 지정하면 이 값이 CMD 로 배치되며 
 
ENTRYPOINT 에 파라미터로 제공되게 된다.
 
즉 ENTRYPOINT 에 넣은 내용은 항상 실행되며 입력으로 CMD 에 기술한 파라미터를 받게 된다. 
 
# Exec Form
# ENTRYPOINT ["<executable", "<param 1>", "<param 2>"]
 
ENTRYPOINT ["mysqld", "--detadir=/var/lib/mysql", "--user=mysql"]
 
# Shell Form
# ENTRYPOINT<command>
 
ENTRYPOINT touch /home/hello/hello.txt
 
EXPOSE
 
호스트와 연결할 포트 번호를 설정한다.
 
docker run 명령의 --expose 옵션과 동일하다.
 
EXPOSE 는 호스트와 연결만 할 뿐 외부에 노출은 되지 않는다.
 
포트를 외부에 노출하려면 docker run 명령의 -p 옵션을 사용해야 한다.
 
-p 옵션은 <HostPort>:<ContainerPort> 형식으로 주면 된다.
 
# EXPOSE <PORT>
EXPOSE 81
 
$ docker build -t example
$ docker run -p 80:81 example
 
ADD
 
ADD 는 파일이나 디렉토리를 이미지에 추가한다.
 
추가할 파일이나 디렉토리는 혹은 압축파일 등은
 
반드시 컨텍스트 내부의 데이터 또는 파일 URL 만 가능하다.
 
그리고 이미지상의 위치는 절대경로만 사용할 수 있다.
 
# ADD <SOURCE-FROM-CONTEXT><DEST-IN-IMAGE>
 
ADD entrypoint.sh /entrypoint.sh
ADD testDir /testDir
ADD hello.zip /
ADD http://example.com/hello.txt /hello.txt
 
컨텍스트 내부의 압축 파일의 경우는 압축이 풀려서 추가되고
 
파일 URL 내부의 압축파일은 tar 파일이 그대로 추가된다.
 
 
COPY
 
COPY 는 파일이나 디렉토리를 이미지에 추가한다.
 
ADD 와 다른점은 압축파일을 그냥 전달하며 URL 은 사용할 수 없는 점이다.
 
 
VOLUME
 
공유폴더를 설정한다.
 
설정한 폴더에 데이터를 저장하면 실제로는 호스트 위치에 저장이 되고 
 
이미지에서는 해당 폴더를 마운트하여 사용한다.
 
docker run 에서 -v 옵션을 사용하여 호스트에서 공유될 폴더를 지정해야 사용가능하다.
 
-v 옵션은 <HostDirectory>:<ContainerDirectory> 형식으로 주면 된다.
 
# VOLUME <ContainerDirectory>
VOLUME /data
 
$ docker build -t example
$ docker run -v /root/data:/data example
 
USER
 
USER 는 명령을 실행할 사용자 계정을 설정한다.
 
RUN, CMD, ENTRYPOINT 에 적용된다.
 
# USER <UserAccount>
 
USER root
RUN touch /hello.txt
 
WORKDIR
 
RUN, CMD, ENTRYPOINT 의 명령이 실행될 컨테이너 디렉토리를 설정한다.
 
도커파일 작성 중간에 working directory 를 수시로 바꿀수 있다.
 
최초 기준은 홈( / ) 이다.
 
# WORKDIR <경로> 
 
WORKDIR /root
RUN touch hello.txt
 
WORKDIR /tmp
RUN touch hello.txt
 
 
.dockerignore
 
Dockerfile 과 같은 디렉토리에 들어있는 모든 파일을 컨텍스트라고 한다.
 
이미지를 생성할 때 컨텍스트를 모두 Docker 데몬에 전송하므로
 
필요없는 파일은 제외해야 한다.
 
이때 컨텍스트로 .dockerignore 파일을 작성할 수 있다.
 
example/hello.txt
example/*.cpp
wo*
*.cpp
.git
.svn
 
 
 
Docker Build & Push
 
위의 키워드를 조합하여 Dockerfile 을 아래와 같이 만들었다고 하자.
 
FROM ubuntu
 
RUN apt-get update
RUN apt-get install python
 
RUN pip install flask
RUN pip install flask-mysql
 
COPY . /opt/source-code
 
ENTRYPOINT FLASK_APP=/opt/source-code/app.py flask run
 
그러면 docker build 명령으로 Dockerfile 기반으로 이미지를 생성하고 Docker 레지스트리에 push 하면 끝이다.
 
$ docker login
 ...
$ docker build Dockerfile -t kin3303/my-custom-app
$ docker image tag my-custom-app kin3303/my-custom-app
$ docker push kin3303/my-custom-app
 
 
Docker Layer
 
앞서 108. Docker Image Inspect 부분에서 Docker 레이어에 대해 설명하였는데
 
dockerfile 기반으로 확인하자면 각 라인이 하나의 레이어를 생성하게 된다.
 
 
 그리고 모든 레이어는 Docker 에 의해 캐시되므로 특정 단계가 실패했을 때
 
 
2단계 까지는 Cache 를 이용하고 나머지만 빌드 하므로 빠르다.
 
 
 
Exercise
 
간단히 아래 소스를 다운받고 이를 기준으로 Dockerfile 을 만들어 이를 실행해 보자.
 

kin3303/simple-webapp-flask

Simple Flask based web application. Contribute to kin3303/simple-webapp-flask development by creating an account on GitHub.

github.com

$ mkdir my-simple-webapp
 
$ cd my-simple-webapp/ 
 
$ cat > app.py
import os
from flask import Flask
app = Flask(__name__)
 
@app.route("/")
def main():
    return "Welcome!"
 
@app.route('/how are you')
def hello():
    return 'I am good, how about you?'
 
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8080)
^C
 
$ cat > Dockerfile
FROM ubuntu
 
RUN apt-get update
RUN apt-get install -y python python-setuptools python-dev build-essential python-pip python-mysqldb
RUN pip install flask
RUN pip install flask-mysql
 
COPY app.py /opt/app.py
 
ENTRYPOINT FLASK_APP=/opt/app.py flask run --host=0.0.0.0
^C
 
$ docker build . -t my-simple-webapp
 
$ docker images
 
$ docker run -p 5000:5000 my-simple-webapp
 
^C
 
$ docker image tag my-simple-webapp kin3303/my-simple-webapp
 
$ docker login
 
$ docker push kin3303/my-simple-webapp
 
 
 
 

'Container > Docker' 카테고리의 다른 글

12. Docker Compose  (0) 2020.01.14
11. Docker Container Life Cycle  (0) 2020.01.14
09. Docker Image 생성 (기존이미지 사용)  (0) 2020.01.14
08. Docker Image Inspect  (0) 2020.01.14
07. Docker Image  (0) 2020.01.14