1. 기타 Dockerfile 명령어
■ ENV
- Dockerfile에서 사용될 환경변수를 지정
- ENV test /home 은 test라는 환경변수에 /home 이라는 값을 설정
- run 명령어에서 -e옵션을 사용해 같은 이름의 환경변수를 사용하면 기존의 값은 덮어 쓰여짐
[root@localhost dockerfile]# vi dockerfile
FROM ubuntu:18.04
ENV test /home
WORKDIR $test
RUN touch $test/testfile
test라는 변수에 /home 이라는 값을 설정하여 dockerfile을 만들었습니다.
[root@localhost dockerfile]# docker build . -t test1:0.0
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM ubuntu:18.04
---> 81bcf752ac3d
Step 2/4 : ENV test /home
---> Running in da376e004799
Removing intermediate container da376e004799
---> 0911b98c5b8f
Step 3/4 : WORKDIR $test
---> Running in fc38e56029a4
Removing intermediate container fc38e56029a4
---> cd45fdb225b4
Step 4/4 : RUN touch $test/testfile
---> Running in 84f1cc26e886
Removing intermediate container 84f1cc26e886
---> 73d6e65b6285
Successfully built 73d6e65b6285
Successfully tagged test1:0.0
[root@localhost dockerfile]# docker run -ti --name env_test test1:0.0 /bin/bash
root@1a292e1be2f3:/home# echo $test
/home
위에서 만든 dockerfile 기반 이미지로 컨테이너생성 후 test라는 환경변수를 출력한 모습입니다.
[root@localhost dockerfile]# docker run -ti --name env_test2 -e test=myvalue test1:0.0 /bin/bash
root@5942c4739b20:/home# echo $test
myvalue
run 명령어에서 -e 옵션으로 동일한 환경변수값을 설정해 컨테이너를 만든 후 환경변수를 출력한 모습입니다.
dockerfile 에 설정되어있던 값은 /home이지만 -e 옵션에서 지정한 값으로 변경되었습니다.
[root@localhost dockerfile]# vi dockerfile
FROM ubuntu:18.04
ENV test value
RUN echo ${test:-A} / ${test:+A} / ${testt:-A} / ${testt:+A}
[root@localhost dockerfile]# docker build .
Sending build context to Docker daemon 2.048kB
Step 1/3 : FROM ubuntu:18.04
...
...
value / A / A /
...
...
Successfully built de1ce705bc99
[root@localhost dockerfile]#
${test:-A} : test라는 변수값이 선언되어있지 않으면 A라는 값 할당(변수값이 있다면 기존값 그대로 사용)
${test:+A} : test라는 변수값이 선언되어있으면 A라는 값 할당(변수값이 없다면 빈 문자열 사용)
즉, 위에선 test라는 변수값이 value로 선언되어져 있습니다.
RUN echo 다음 첫 번째 test:-A 에서는 test 변수값이 있기 때문에 A라는 값을 넣지 않고 기존값 그대로 나오게 되고
두 번째 test:+A 에서는 test 변수값이 있으므로 A라는 값이 들어갔습니다.
세 번째도 마찬가지로 testt라는 변수값이 할당되어있지 않으므로 A를 넣었고, 네 번째는 testt 값이 할당되지 않아 빈 문자열이 할당되었습니다.
■ VOLUME
- 빌드된 이미지로 컨테이너를 생성했을 때 호스트와 공유할 컨테이너 내부의 디렉토리 설정
- JSON 배열의 형식으로 여러 개를 사용하거나 VOLUME /home/a /home/b 식으로 사용할 수 있음
[root@localhost dockerfile]# vi dockerfile
FROM ubuntu:18.04
RUN mkdir /home/volume
RUN echo test >> /home/volume/testfile
VOLUME /home/volume
[root@localhost dockerfile]# docker run -tid --name volumetest myvolume:0.0
f8e71aabe24c049a3b783182bf49dd0640c198f4ec3ed867734c0866e48d51d1
위와같이 dockerfile 및 컨테이너를 생성했습니다.
[root@localhost dockerfile]# docker volume ls
DRIVER VOLUME NAME
local 1d26230fcd04028c3f23696d4d6afd2e1da0cdc037baf470bd71c3a4e9cc71d6
local 27fef6afad75e521fff5abccc75a5a38ff7fc8847432eef802e3f6b73260493c
local 44cf230404a81cbcb6880bbc001083ab5480f4d0f2d1469a24be8f313ad8e434
local 83a14ac554a19e24eaa7d155e57d1d70e175108f139f3086a85b90f61f42c299
local 85e3cfdfeef077c9b050ce1114ea559cff1c0801e9eaf437e8347f8f2618efd1
local 450fb14035417378f2efca10505104c737274e003213cd280518f71eb0cccc9d
local 883ce9c1a29df7503be69668f74a91c5aa0360cf1655286db99c6fcca6188d4f
local 9738a4b228ae284e8142dfc900819a7917d644d209e67091160f181726e1492a
local 7488539d2b57899aedb3da5d6c0f0377c23491b29bef83aa87a2eafb8ab13370
local aee07671fbf1f3b80078522516e631aef1a0d2fbce3f0b9c4bb6fadb176adf85
local b088b18514f8068165c4c65375e10519e58a8a417180b61cc6b3e2c0d9bcbc59
local b3771d00d147d31947d35e6be414b1400ea3cc4e80a3a1fd8cb722934eb40f9a
local c4b69ea7db233f0ca20144b275759d0bc725068cfdfd216aaf17e0faac82b8da
local c30e70bbaac62e517d7eba6347941ad1560aed8219c370fef6011f3dcc74af5f
local c49f5a5477058a576cefa0c473ed228a41df3f2f094f642ea2df579bd7fbb36d
local cd5588c29e6e0433eb3e86e009d187e6d9635747b6cb03aadc87140f0438a4b6
local daf9cfa19662725eaad41de31c5ba9e6f9fac4c596206d3d95b7b60a7a7661d1
local df7afbba858a4bf034e9a589d1efb2cb7075729aaa8fde3dab9275a25234eebf
local mysql
local myvolume
local wordpress
기존에 있던 volume들이 많아 다음과 같이 비교해보았습니다.
[root@localhost dockerfile]# docker volume ls >> volume_ls_1.txt
[root@localhost dockerfile]# docker volume ls >> volume_ls_2.txt
volume_ls_1.txt 은 컨테이너 생성 전 볼륨리스트이고 volume_ls_2.txt 는 컨테이너 생성 후 볼륨리스트 입니다.
[root@localhost dockerfile]# diff volume_ls_1.txt volume_ls_2.txt
14a15
> local c5b11549a2fd2634306978fba8bd725983423369ea485f98df5070aafb3f7907
두 파일을 비교해보니 15번째 라인에 위와 같이 local c5... 값이 추가되었다는 것을 확인할 수 있습니다.
즉, 위 볼륨정보가 새로 생성된 것임을 알 수 있고 c5b1로 시작하는 볼륨이 컨테이너 내부의 /home/volume 디렉토리를 호스트와 공유한다는 뜻입니다.
■ ARG
- 빌드명령어를 실행할 때 추가로 입력을 받아 Dockerfile 내에서 사용될 변수의 값을 설정
[root@localhost dockerfile]# vi dockerfile
FROM ubuntu:18.04
ARG test1
ARG test2=asdf
RUN touch ${test1}/testfile
[root@localhost dockerfile]# docker build --build-arg test1=/home -t arg_test:0.0 .
Sending build context to Docker daemon 6.144kB
Step 1/4 : FROM ubuntu:18.04
---> 81bcf752ac3d
Step 2/4 : ARG test1
---> Running in be068ee5b79c
Removing intermediate container be068ee5b79c
---> b65c95321c1f
Step 3/4 : ARG test2=asdf
---> Running in e89da317a6e8
Removing intermediate container e89da317a6e8
---> 5369b56decdb
Step 4/4 : RUN touch ${test1}/testfile
---> Running in 5da0f73d32f4
Removing intermediate container 5da0f73d32f4
---> 361a0b055874
Successfully built 361a0b055874
Successfully tagged arg_test:0.0
위와 같이 Dockerfile 생성 후 build 까지 진행했습니다.
dockerfile 에서 test1은 변수이름만 만들었지 값은 들어있지 않습니다.
build 시 --build-arg 옵션을 사용해서 dockerfile에서 사용될 ARG 값을 입력할 수 있습니다.
여기서는 test1=/home 이라는 ARG를 선언한 것 입니다.
[root@localhost dockerfile]# docker run -ti --name arg_test arg_test:0.0
root@e4f7a4854d84:/# ll /home/
total 0
drwxr-xr-x. 1 root root 22 Jun 2 00:15 ./
drwxr-xr-x. 1 root root 6 Jun 2 00:15 ../
-rw-r--r--. 1 root root 0 Jun 2 00:15 testfile
root@e4f7a4854d84:/# echo $test1
root@e4f7a4854d84:/# echo $test2
컨테이너 생성 후 진입하여 /home 하단 목록을 조회해보니 testfile이 생성된 것을 확인할 수 있습니다.
또한 dockerfile에서 ARG로 선언한 test1과 test2의 값은 실제 컨테이너 내의 환경에서는 적용되지 않습니다.
즉, Dockerfile 내에서만 사용되는 변수가 되는 것 입니다.
■ USER
- USER로 컨테이너에서 사용될 사용자계정의 이름이나 UID를 설정시 그 아래의 명령어는 해당사용자 권한으로 실행됨
- 일반적으로 RUN으로 사용자 그룹과 계정을 생성한 뒤 사용함
- root 권한이 필요하지 않다면 USER를 사용하는 것을 권장
...
RUN groupadd -r test1 && useradd -r -g test1 sotest
USER sotest
...
기본적으로 컨테이너는 root 사용자를 사용하도록 설정합니다.
이는 컨테이너가 호스트의 root권한을 가질 수 있다는 것을 의미하기에 보안측면에서 바람직하지 않습니다.
예를들면 root가 소유한 호스트의 디렉토리를 컨테이너에 공유했을 때, 컨테이너 내부에서 공유된 root 소유의 디렉토리를 마음대로 조작이 가능합니다.
docker run 명령어 자체에서도 --user 옵션을 지원하지만, 가급적 이미지 자체에 root가 아닌 다른사용자를 설정해 놓는 것이 좋습니다.
■ ONBUILD
- 빌드된 이미지를 기반으로 하는 다른 이미지가 Dockerfile로 생성될 때 실행할 명령어를 추가
이게 무슨말인지 예시로 확인하겠습니다.
[root@localhost dockerfile]# vi dockerfile
FROM ubuntu:18.04
RUN echo "ONBUILD test"
ONBUILD RUN echo "onbuild" >> /onbuild.txt
[root@localhost dockerfile]# docker build . -t onbuild:0.0
Sending build context to Docker daemon 6.144kB
Step 1/3 : FROM ubuntu:18.04
---> 81bcf752ac3d
Step 2/3 : RUN echo "ONBUILD test"
---> Running in 06d2e3ab5452
ONBUILD test
Removing intermediate container 06d2e3ab5452
---> 0bcae90a079d
Step 3/3 : ONBUILD RUN echo "onbuild" >> /onbuild.txt
---> Running in ee8f2a822626
Removing intermediate container ee8f2a822626
---> 7d7477ee04e9
Successfully built 7d7477ee04e9
Successfully tagged onbuild:0.0
위와 같이 Dockerfile 생성 후 이미지를 빌드했습니다.
ONBUILD RUN echo "onbuild" >> /onbuild.txt 명령은 Dockerfile 빌드 시 실행되지 않으며, 별도의 정보로 이미지에 저장됩니다.
[root@localhost dockerfile]# vi dockerfile2
FROM onbuild:0.0
RUN echo "child image"
[root@localhost dockerfile]# docker build . -f dockerfile2 -t onbuild:0.1
Sending build context to Docker daemon 7.168kB
Step 1/2 : FROM onbuild:0.0
# Executing 1 build trigger
---> Running in 6f4758fd792e
Removing intermediate container 6f4758fd792e
---> dcd601c038c7
Step 2/2 : RUN echo "child image"
---> Running in 4c4035caac44
child image
Removing intermediate container 4c4035caac44
---> ea18a162211a
Successfully built ea18a162211a
Successfully tagged onbuild:0.1
이번엔 위에서 만든 이미지를 기반으로 하는 dockerfile2를 생성하였고 빌드했습니다.
[root@localhost dockerfile]# docker run -ti --name onbuild_2 onbuild:0.1
root@260dda263a45:/# ll /
total 8
drwxr-xr-x. 1 root root 6 Jun 2 00:41 ./
drwxr-xr-x. 1 root root 6 Jun 2 00:41 ../
-rwxr-xr-x. 1 root root 0 Jun 2 00:41 .dockerenv*
drwxr-xr-x. 2 root root 4096 May 12 23:09 bin/
drwxr-xr-x. 2 root root 6 Apr 24 2018 boot/
drwxr-xr-x. 5 root root 360 Jun 2 00:41 dev/
drwxr-xr-x. 1 root root 66 Jun 2 00:41 etc/
drwxr-xr-x. 2 root root 6 Apr 24 2018 home/
drwxr-xr-x. 8 root root 96 May 23 2017 lib/
drwxr-xr-x. 2 root root 34 May 12 23:08 lib64/
drwxr-xr-x. 2 root root 6 May 12 23:05 media/
drwxr-xr-x. 2 root root 6 May 12 23:05 mnt/
-rw-r--r--. 1 root root 8 Jun 2 00:41 onbuild.txt
drwxr-xr-x. 2 root root 6 May 12 23:05 opt/
dr-xr-xr-x. 116 root root 0 Jun 2 00:41 proc/
drwx------. 2 root root 37 May 12 23:09 root/
drwxr-xr-x. 1 root root 21 May 19 19:44 run/
drwxr-xr-x. 1 root root 21 May 19 19:44 sbin/
drwxr-xr-x. 2 root root 6 May 12 23:05 srv/
dr-xr-xr-x. 13 root root 0 May 24 00:05 sys/
drwxrwxrwt. 2 root root 6 May 12 23:09 tmp/
drwxr-xr-x. 1 root root 18 May 12 23:05 usr/
drwxr-xr-x. 1 root root 17 May 12 23:09 var/
컨테이너 생성 후 / 디렉토리 확인 시 onbuild.txt 파일이 생성된 것을 확인할 수 있습니다.
이처럼 이미지가 빌드될 때 수행돼야 하는 Dockerfile 명령어를 나중에 빌드될 이미지를 위해 미리 저장 가능합니다.
■ STOPSIGNAL
- 컨테이너가 정지될 때 사용될 시스템 콜의 종류를 지정
- 아무것도 설정하지 않으면 기본적으로 SIGTERM
- Dockerfile에 STOPSIGNAL을 정의해 컨테이너가 종료되는 데 사용될 신호를 선택할 수 있음
[root@localhost dockerfile]# vi dockerfile
FROM ubuntu:18.04
STOPSIGNAL SIGKILL
[root@localhost dockerfile]# docker build . -t stopsignal:0.0
Sending build context to Docker daemon 6.144kB
Step 1/2 : FROM ubuntu:18.04
---> 81bcf752ac3d
Step 2/2 : STOPSIGNAL SIGKILL
---> Running in 9f306b316754
Removing intermediate container 9f306b316754
---> 1287022576a4
Successfully built 1287022576a4
Successfully tagged stopsignal:0.0
[root@localhost dockerfile]# docker run -tid --name stopsignal stopsignal:0.0
[root@localhost dockerfile]# docker inspect stopsignal | grep -i stop
"Name": "/stopsignal",
"Image": "stopsignal:0.0",
"StopSignal": "SIGKILL"
STOPSIGNAL을 SIGKILL로 설정한 후 빌드하였고 빌드한 이미지를 기반으로 컨테이너를 생성했습니다.
이후 inspect로 stopsignal 확인 시 SIGKILL로 설정된 것을 확인할 수 있습니다.
dockerfile 뿐만 아니라 docker run 명령에서 --stop-signal 옵션으로 컨테이너에 개별적 설정이 가능합니다.
■ HEALTHCHECK
- 이미지로부터 생성된 컨테이너에서 동작하는 애플리케이션의 상태를 체크하도록 설정
- 컨테언 내부에서 동작중인 애플리케이션의 프로세스가 종료되지는 않았으나 애플리케이션이 동작하고 있지 않은 상태를 방지하기 위해 사용될 수 있음
[root@localhost dockerfile]# vi dockerfile
FROM nginx
RUN apt-get update -y && apt-get install curl -y
HEALTHCHECK --interval=1m --timeout=3s --retries=3 CMD curl -f http://localhost || exit 1
[root@localhost dockerfile]# docker build . -t nginx:healthcheck
Sending build context to Docker daemon 6.144kB
Step 1/3 : FROM nginx
latest: Pulling from library/nginx
...
...
...
Successfully built beef57e4df3e
Successfully tagged nginx:healthcheck
[root@localhost dockerfile]#
위 dockerfile의 내용은 다음과 같습니다.
1분마다 curl -f 를 실행해 nginx 애플리케이션의 상태를 체크하며, 3초 이상이 소요되면 이를 한 번의 실패로 간주합니다. 3번 이상 타임아웃이 발생하면 해당 컨테이너는 unhealthy 상태가 됩니다.
CMD curl ~ 부분이 상태를 체크하는 명령어가 되고, --interval 주기마다 이를 실행합니다.
상태체크 명령이 --timeout에 설정한 시간을 초과하면 실패한 것으로 간주하고 --retries의 횟수만큼 명령을 반복합니다.
--retries에 설정된 횟수만큼 상태 체크에 실패하면 해당 컨테이너는 unhealthy 상태로 설정됩니다.
[root@localhost dockerfile]# docker run -d -P nginx:healthcheck
cf2a4638ba54c88921c21e166721b7da48115fd6571583a1bdfc675d1c1974a9
[root@localhost dockerfile]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cf2a4638ba54 nginx:healthcheck "/docker-entrypoint.…" 4 seconds ago Up 3 seconds (health: starting) 0.0.0.0:49154->80/tcp, :::49154->80/tcp infallible_faraday
[root@localhost dockerfile]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cf2a4638ba54 nginx:healthcheck "/docker-entrypoint.…" 20 seconds ago Up 19 seconds (health: starting) 0.0.0.0:49154->80/tcp, :::49154->80/tcp infallible_faraday
[root@localhost dockerfile]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cf2a4638ba54 nginx:healthcheck "/docker-entrypoint.…" 36 seconds ago Up 35 seconds (health: starting) 0.0.0.0:49154->80/tcp, :::49154->80/tcp infallible_faraday
[root@localhost dockerfile]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cf2a4638ba54 nginx:healthcheck "/docker-entrypoint.…" About a minute ago Up About a minute (healthy) 0.0.0.0:49154->80/tcp, :::49154->80/tcp infallible_faraday
이미지 빌드 후 해당 이미지로 컨테이너를 생성하였고 docker ps 출력 중 해당 컨테이너의 STATUS에 정보가 추가된 것을 확인할 수 있습니다.
[root@localhost dockerfile]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cf2a4638ba54 nginx:healthcheck "/docker-entrypoint.…" 2 minutes ago Up 2 minutes (healthy) 0.0.0.0:49154->80/tcp, :::49154->80/tcp infallible_faraday
[root@localhost dockerfile]# docker inspect cf2 | grep Status
"Status": "running",
"Status": "healthy",
■ SHELL
- Dockerfile에서 기본적으로 사용하는 쉘은 리눅스는 '/bin/sh -c' 이고 윈도우는 'cmd /S /C'
...
RUN echo "Hello"
...
위와 같은 dockerfile이 있다면 리눅스는 /bin/sh -c echo hello 로 실행될 것이고,
윈도우는 cmd /S /C echo hello 로 실행됩니다.
[root@localhost dockerfile]# vi dockerfile
FROM node
RUN echo Hello
SHELL ["/usr/local/bin/node"]
RUN -v
node.js 공식 이미지인 node 이미지를 사용했고 쉘을 node로 변경한 후 -v를 실행했습니다.
즉, /bin/sh -c -v 가 아닌, /usr/local/bin/node -v 가 되는 것 입니다.
[root@localhost dockerfile]# docker build . -t nodetest
Sending build context to Docker daemon 6.144kB
Step 1/4 : FROM node
latest: Pulling from library/node
...
...
...
Step 4/4 : RUN -v
---> Running in e73b4a1bc09f
v16.2.0
...
...
...
node -v 로써 버전명이 출력되는 것을 확인할 수 있습니다.
■ ADD, COPY
- COPY는 로컬 디렉토리에서 읽어 들인 컨텍스트로부터 이미지에 파일을 복사하는 역할을 함
COPY test.html /home/
COPY ["test.html", "/home/"]
ADD https://test.com/A/B/test.html /home
ADD test.tar /home
ADD와 사용하는 형식은 같으며 기능 그 자체만으로 봤을 땐 동일합니다.
하지만 COPY는 로컬의 파일만 이미지에 추가할 수 있으며, ADD는 외부 URL 및 tar파일도 추가가 가능합니다.
tar파일은 그대로 추가하는 것이 아닌 tar파일을 압축 해제해서 추가합니다.
즉, COPY의 기능이 ADD에 포함되는 셈입니다.
■ ENTRYPOINT, CMD
- CMD는 컨테이너가 시작될 때 실행할 명령어를 설정(docker run 명령어에서 맨 뒤에 입력하는 커맨드랑 같은역할)
- ENTRYPOINT도 CMD와 역할 자체는 비슷하나 차이점이 있음
[root@localhost dockerfile]# docker run -ti --name no_entrypoint ubuntu:18.04 /bin/bash
root@215b3f30c288:/#
[root@localhost dockerfile]# docker run -ti --entrypoint="echo" --name yes_entrypoint ubuntu:18.04 /bin/bash
/bin/bash
[root@localhost dockerfile]#
entrypoint 지정 시 마지막 명령이 entrypoint의 인자가 되어 실행됩니다.
즉, 위에선 컨테이너가 시작될 때 echo /bin/bash 가 실행된 것 입니다.
[root@localhost dockerfile]# vi entrypoint.sh
echo $1 $2
apachectl -DFOREGROUND
인자로 받은 두 개의 값을 echo로 출력하고 아파치 웹 서버를 실행하는 내용입니다.
[root@localhost dockerfile]# vi dockerfile
FROM ubuntu:18.04
RUN apt-get update
RUN apt-get install apache2 -y
ADD entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/bin/bash", "/entrypoint.sh"]
빌드 컨텍스트의 스크립트파일을 ADD로 이미지의 / 하단에 추가했고 이 파일을 실행가능하도록 권한을 부여했습니다.
그리고 이미지의 ENTRYPOINT로 entrypoint.sh를 지정했습니다.
[root@localhost dockerfile]# docker build -t entry:0.0 .
Sending build context to Docker daemon 20.99kB
Step 1/6 : FROM ubuntu:18.04
...
...
...
Successfully built 89916c2ced17
Successfully tagged entry:0.0
[root@localhost dockerfile]#
[root@localhost dockerfile]# docker run -d --name entry entry:0.0 first second
d9c94618011b27fbabccab323ea0e64418e83df44d2fc76a7449d91e91392646
[root@localhost dockerfile]# docker logs entry
first second
...
'docker' 카테고리의 다른 글
도커 컨테이너 다루기(10) - 도커데몬[1] (0) | 2021.06.05 |
---|---|
도커 컨테이너 다루기(9) - Dockerfile로 빌드할 때 주의할 점 (0) | 2021.06.04 |
도커 컨테이너 다루기(8) - 도커파일(Dockerfile)[1] (1) | 2021.06.01 |
도커 컨테이너 다루기(7) - 도커 이미지(Image) (0) | 2021.05.31 |
도커 컨테이너 다루기(6) - 컨테이너 자원 할당 제한 (1) | 2021.05.29 |