August 23, 2019

Docker - Dockerfile 작성 / Build (이미지 제작)

[Docker - Dockerfile Write]

인프라 구성을 관리 및 효율적으로 운영하기 위해 "Dockerfile"를 이용할 수 있으며,
Dockerfile를 작성하여 사용자가 원하는 설계 방향이나 설정된 내용으로 도커 이미지를 제작할 수 있습니다.

즉, 이미지를 작성할 수 있는 설정 파일입니다. 기존에 도커 컨테이너에 웹서버 구동을 위해 베이스 이미지 다운로드후 컨테이너에 접속하여 사용자가 수동으로 작업했던 반면, 자동으로 모든 걸 처리하여 이미지로 작성됩니다.


띠용!!
Dockerfile를 빌드할 때는 "Dockerfile"을 포함하고 있는 디렉터리의 서브디렉터리 까지 모두 Docker 데몬으로 보내 처리하기에 많이 느려집니다.

Dockerfile 기반으로 빌드시 하위 디렉터리에서 진행하며, 불필요한 파일을 포함하지 않도록 해주세요.





[Dockerfile 구문 및 옵션]

그러면 본격적으로 Dockerfile를 작성해보도록 하겠습니다.

Dockerfile은 텍스트 형식이며, 파일명 또한 "Dockerfile" 입니다. 확장자는 따로 존재하지 않습니다.

아래 내용은 Dockerfile에 작성되는 명령 옵션 입니다.

  • FROM : Docker Base Image (기반이 되는 이미지, <이미지 이름>:<태그> 형식으로 설정)

  • MAINTAINER : 메인테이너 정보 (작성자 정보)

  • RUN : Shell Script 또는 명령을 실행

  • CMD : 컨테이너가 실행되었을 때 명령이 실행

  • LABEL : 라벨 작성 (docker inspect 명령으로 label 확인할 수 있습니다.)

  • EXPOSE : 호스트와 연결할 포트 번호를 설정한다.

  • ENV : 환경변수 설정

  • ADD : 파일 / 디렉터리 추가

  • COPY : 파일 복사

  • ENTRYPOINT : 컨테이너가 시작되었을 때 스크립트 실행

  • VOLUME : 볼륨 마운트

  • USER : 명령 실행할 사용자 권한 지정

  • WORKDIR : "RUN", "CMD", "ENTRYPOINT" 명령이 실행될 작업 디렉터리

  • ARG : Dockerfile 내부 변수

  • ONBUILD : 다른 이미지의 Base Image로 쓰이는 경우 실행될 명령 수행

  • SHELL : Default Shell 지정





[Dockerfile 작성 - 1 ]

dongdonge@dongdonge$ vim Dockerfile
FROM ubuntu:16.04

RUN apt-get update && apt-get install -y vim apache2

COPY index.html /var/www/html/

CMD ["/usr/sbin/apachectl", "-D", "FOREGROUND"]

Dockerfile 예시 1


우선 임시로 "Dockerfile"를 생성하여 예시 1와 같이 작성 하였습니다.



  1. "FROM ubuntu:16.04" : 공식 이미지를 기반으로 이미지를 제작하며, 태그명이 생략되면 Base Image의 최신버전(Latest)로 기반됩니다.

  2. "RUN apt-get update && apt-get install -y vim apache2" : 컨테이너가 생성될 때 명령을 수행하며, vim와 Apache 웹서버를 설치한다.

  3. "COPY index.html /var/www/html/" : 컨테이너 내부에 파일을 복사한다. 현재 index.html 파일을 /var/www/html/ 경로에 복사한다.

  4. "CMD ["/usr/sbin/apachectl", "-D", "FOREGROUND"]" : 컨테이너가 매번 실행될 때 마다 명령이 실행된다.





[Dockerfile - Build, Docker Image Make ]

Dockerfile을 이미지로 제작하기 위해 Docker Build 작업을 하여야 합니다.


docker build <옵션> <Dockerfile 경로>

아래 옵션을 통해 확인해보도록 하겠습니다.




dongdonge@dongdonge$ docker build --help

Usage:	docker build [OPTIONS] PATH | URL | -

Build an image from a Dockerfile

Options:
      --add-host list           Add a custom host-to-IP mapping (host:ip)
      --build-arg list          Set build-time variables
      --cache-from strings      Images to consider as cache sources
      --cgroup-parent string    Optional parent cgroup for the container
      --compress                Compress the build context using gzip
      --cpu-period int          Limit the CPU CFS (Completely Fair Scheduler) period
      --cpu-quota int           Limit the CPU CFS (Completely Fair Scheduler) quota
  -c, --cpu-shares int          CPU shares (relative weight)
      --cpuset-cpus string      CPUs in which to allow execution (0-3, 0,1)
      --cpuset-mems string      MEMs in which to allow execution (0-3, 0,1)
      --disable-content-trust   Skip image verification (default true)
  -f, --file string             Name of the Dockerfile (Default is 'PATH/Dockerfile')
      --force-rm                Always remove intermediate containers
      --iidfile string          Write the image ID to the file
      --isolation string        Container isolation technology
      --label list              Set metadata for an image
  -m, --memory bytes            Memory limit
      --memory-swap bytes       Swap limit equal to memory plus swap: '-1' to enable unlimited swap
      --network string          Set the networking mode for the RUN instructions during build
                                (default "default")
      --no-cache                Do not use cache when building the image
      --pull                    Always attempt to pull a newer version of the image
  -q, --quiet                   Suppress the build output and print image ID on success
      --rm                      Remove intermediate containers after a successful build (default true)
      --security-opt strings    Security options
      --shm-size bytes          Size of /dev/shm
  -t, --tag list                Name and optionally a tag in the 'name:tag' format
      --target string           Set the target build stage to build.
      --ulimit ulimit           Ulimit options (default [])

해당 옵션 중 "-t <생성할 이미지명>:<태그명> <Dockerfile 위치>" 옵션을 사용하여 이미지를 제작해보도록 하겠습니다.




dongdonge@dongdonge$ docker build -t dongdonge_web:0.2 /root/docker_test/

Sending build context to Docker daemon  3.072kB
Step 1/4 : FROM ubuntu:18.04
18.04: Pulling from library/ubuntu
35c102085707: Pull complete 
251f5509d51d: Pull complete 
8e829fe70a46: Pull complete 
6001e1789921: Pull complete 
Digest: sha256:d1d454df0f579c6be4d8161d227462d69e163a8ff9d20a847533989cf0c94d90
Status: Downloaded newer image for ubuntu:18.04
 ---> a2a15febcdf3
Step 2/4 : RUN apt-get update && apt-get install -y vim nginx
 ---> Running in d969a5be3c53
Get:1 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB]
Get:2 http://archive.ubuntu.com/ubuntu bionic InRelease [242 kB] ....
.....
Removing intermediate container d969a5be3c53
 ---> 6ff7d429b509
Step 3/4 : COPY index.html /usr/share/nginx/html/
 ---> f845adeff3f9
Step 4/4 : CMD ["nginx", "-g", "daemon off;"]
 ---> Running in b3821cf26c2f
Removing intermediate container b3821cf26c2f
 ---> 291fcc71f9b1
Successfully built 291fcc71f9b1
Successfully tagged dongdonge_web:0.2

"build" 옵션을 통해 Base Image를 다운로드 받고, 이를 기반으로 이미지가 제작되고 있는걸 볼 수 있습니다.




dongdonge@dongdonge$ docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
dongdonge_web       0.2                 291fcc71f9b1        4 minutes ago       206MB
ubuntu              18.04               a2a15febcdf3        2 weeks ago         64.2MB

생성된 이미지





[Dockerfile - RUN ]

FROM 명령에서 설정한 베이스 이미지에 대해 실행하며, 패키지 설치 및 명령 실행에 사용될 수 있습니다.


RUN <명령어>

RUN 명령어는 두 가지 형식으로 쓸 수 있습니다.

  1. Shell 방식

RUN apt-get install apache2 vim -y




  1. Exec 방식

RUN ["/bin/bash", "-c", "apt-get install apache2 vim -y"]





[Dockerfile - CMD ]

이미지를 바탕으로 생성된 컨테이너 실행 시 매번 명령을 실행합니다. (Docker run / Docker start)

참고로 하나의 CMD만 작성할 수 있으며, 중복일 경우 맨 마지막 하나만 유효 됩니다.


CMD <명령어>

  1. Shell 방식

CMD apachectl -D FOREGROUND




  1. Exec 방식

CMD ["/usr/sbin/apachectl", "-D", "FOREGROUND"]





[Dockerfile - ENTRYPOINT ]

Dockerfile에서 빌드한 이미지를 컨테이너로 생성(Docker run)할때 단 한번만 실행합니다.


ENTRYPOINT <명령어>

ENTRYPOINT도 RUN 명령어 처럼 두 가지 형식으로 쓸 수 있습니다.

  1. Shell 방식

ENTRYPOINT apachectl -D FOREGROUND




  1. Exec 방식

ENTRYPOINT ["/usr/sbin/apachectl", "-D", "FOREGROUND"]





[Dockerfile - ONBUILD ]

다른 이미지의 Base Image로 쓰이는 경우 빌드시 해당 명령이 실행된다.


ONBUILD <명령어>

FROM ubuntu:16.04

RUN apt-get update && apt-get install apcahe2 -y

EXPOSE 80

ONBUILD ADD website.tar /var/www/html/

CMD ["/usr/sbin/apachectl", "-D", "FOREGROUND"]





[Dockerfile - ENV ]

Dockerfile을 통하여 환경변수를 컨테이너 안에 지정할 수 있습니다.
또한 Dockerfile 대신 "docker run" 명령의 "--env" 옵션을 통하여 사용할 수도 있습니다.


ENV <Key> <Value>

또는

ENV <Key> = <Value>

ENV 명령어는 아래와 같이 두 가지 방법을 이용할 수 있습니다.

  1. Key Value 형식

ENV ServerName "DongDongE"
ENV ServerPw toor




  1. Key = Value 형식

ENV ServerName="DongDongE" \
    ServerPw=toor

"Key = Value" 형식은 한 줄에 여러 값을 설정할 수 있습니다.





[Dockerfile - WORKDIR ]

Dockerfile 내부에서 사용되는 WORKDIR 명령은 작업용 디렉터리를 설정하기 위해 사용됩니다.
주로 "RUN", "CMD", "ENTRYPOINT", "COPY", "ADD" 등 명령에 같이 사용됩니다.


WORKDIR <경로>

WORKDIR /abcd
WORKDIR efgh
WORKDIR ijk

해당 경로가 디렉터리가 존재하지 않는다면 새로 생성되며, Dockerfile내에서 "WORKDIR" 명령을 여러 번 사용할 수 있습니다.




root@2d24bcaa30a3:/abcd/efgh/ijk# pwd
/abcd/efgh/ijk

Docker build -> 컨테이너 생성시





[Dockerfile - USER ]

Dockerfile 내에서 명령을 실행하기 위해 사용자(권한)를 지정할 수 있습니다.


USER <사용자명 또는 UID>

RUN ["useradd", "-m", "DongDongE"]

USER DongDongE
RUN ["touch", "/home/DongDongE/test123"]

우선 USER 명령으로 권한을 설정하기 전, "RUN" 명령을 통해 사용자 계정을 생성한 뒤 "USER" 명령으로 사용자를 지정하였습니다.




DongDongE@c3bf452076b1:~$ ls -la /home/DongDongE/
total 20
drwxr-xr-x 1 DongDongE DongDongE 4096 Sep  3 06:28 .
drwxr-xr-x 1 root      root      4096 Sep  3 06:28 ..
-rw-r--r-- 1 DongDongE DongDongE  220 Apr  4  2018 .bash_logout
-rw-r--r-- 1 DongDongE DongDongE 3771 Apr  4  2018 .bashrc
-rw-r--r-- 1 DongDongE DongDongE  807 Apr  4  2018 .profile
-rw-r--r-- 1 DongDongE DongDongE    0 Sep  3 06:28 test123

컨테이너 내부 권한 (DongDongE)


컨테이너 내부에서 Dockerfilr의 "USER" 명령을 통하여 "DongDongE" 사용자 권한으로 파일이 생성된 걸 볼 수 있습니다.





[Dockerfile - LABEL ]

Docker Image의 작성자 정보, 타이틀, 버전, 코맨드 등. 정보를 작성할때 사용됩니다.


LABEL <Key>=<Value>

LABEL maintainer "DongDongE <DongDongE@d0ngd0nge.xyz>"
LABEL title="Test Docker"
LABEL version="0.1"
LABEL description="Docker Test Label"

아래와 같이 Docker 빌드된 도커 이미지의 정보를 확인해보면 지정한 정보가 설정된걸 볼 수 있습니다.




root@dongdonge:/var/www/raonctf/training/test/label# docker inspect --format="{{ .Config.Labels }}" label

map[description:Docker Test Label maintainer:DongDongE <DongDongE@d0ngd0nge.xyz> title:Test Docker version:0.1]

Docker 이미지 정보 확인


현재 빌드된 컨테이너명을 "label"로 설정되어 있습니다. 아래 명령을 통해 확인 하시면 됩니다.
'docker inspect --format="{{ .Config.Labels }}" <컨테이너명>'





[Dockerfile - EXPOSE ]

Docker Container의 공개 포트를 호스트와 연결 (지정)할 때 사용됩니다.

EXPOSE <포트 번호>

EXPOSE 80
EXPOSE 443

나눠서 쓰기

또는

EXPOSE 80 443

한줄에 쓰기


Dockerfile의 EXPOSE 명령은 실행 중인 컨테이너와 호스트와 연결만 하고, 외부에 노출되지는 않습니다.

컨테이너 포트를 외부에 노출하여, 외부에서 접속할 수 있게 하려면 "docker run" 명령의 "-p" 옵션을 사용해야 합니다.





[Dockerfile - SHELL ]

Dockerfile 내부에서 명령을 실행할 때 Shell을 지정할 수 있으며, Default로 리눅스 경우 "/bin/sh"로 설정됩니다.

또한 "RUN", "CMD", "ENTRYPOINT" 명령을 사용할 때만 유효합니다.


SHELL ["SHELL 경로", "파라미터"]

SHELL ["/bin/bash", "-c"]

RUN echo "TEST"
bash Shell로 변경

위와 같이 "/bin/bash" Shell로 변경되어, "RUN" 명령을 실행합니다.





[Dockerfile - ADD ]

호스트 상에 존재하는 파일/디렉터리를 Docker Image에 추가할 때 사용합니다.


ADD <호스트의 파일 경로> <Docker Image의 파일 경로>

또는

ADD ["<호스트의 파일 경로>", "<Docker Image의 파일 경로>"]

예를 들어 웹서버 이미지를 만들기 위해 호스트의 "index.php" 파일을 도커 이미지의 "/var/www/html/"안에 추가하려면 아래와 같이 작성합니다.

ADD index.php /var/www/html/

또한, ADD 명령어는 파일/디렉터리를 호스트뿐만 아니라 URL처럼 원격에서 파일을 다운로드 받을 수 있습니다.





[Dockerfile - COPY ]

호스트 상에 존재하는 파일/디렉터리를 Docker Image에 복사할 때 사용합니다.


COPY <호스트의 파일 경로> <Docker Image의 파일 경로>

또는

COPY ["<호스트의 파일 경로>", "<Docker Image의 파일 경로>"]

COPY index.php /var/www/html/

"COPY" 명령어는 "ADD" 명령어와 비슷하지만, COPY 명령은 ADD처럼 URL이나 원격 파일의 다운로드를 하지 못하고, 순수히 파일 복사기능만 가지고 있습니다.





[Dockerfile - VOLUME ]

"VOLUME" 명령은 도커 컨테이너의 파일/디렉토리를 컨테이너에 저장하지 않고 호스트의 "/var/lib/docker/volumes/" 경로에 저장됩니다.


VOLUME <컨테이너 내부의 마운트 경로>

VOLUME /var/log

또한 "VOLUME" 명령을 사용함으로써 여러 개의 인수로 마운트할 수 있습니다.
영구적인 데이터를 컨테이너에 저장하지 않고 컨테이너 외부 스토리지인 호스트에 저장하기에 적합합니다.




root@dongdonge:# ls -la /var/lib/docker/volumes/283cbe5136bf789cc2954ce67a225d99f19bc7046e4ce34a36664c05c3de5435/_data/

total 184
drwxr-xr-x 4 root     root       4096 Sep  3 08:44 .
drwxr-xr-x 3 root     root       4096 Sep  3 08:44 ..
-rw-r--r-- 1 root     root       5088 Dec 29  2018 alternatives.log
drwxrwxrwx 2 www-data www-data   4096 Sep  3 08:44 apache2
drwxr-xr-x 2 root     root       4096 Sep  3 08:44 apt
-rw-rw---- 1 root     utmp          0 Dec 26  2018 btmp
-rw-r--r-- 1 root     root     126921 Dec 29  2018 dpkg.log
-rw-r--r-- 1 root     root       3232 Dec 26  2018 faillog
-rw-rw-r-- 1 root     utmp      29492 Dec 26  2018 lastlog
-rw-rw-r-- 1 root     utmp          0 Dec 26  2018 wtmp

호스트 스토리지에 저장된 파일 리스트