이번에는 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 을 만들어 이를 실행해 보자.
$ 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 |