Last Updated on 1월 5, 2024 by Jade(정현호)
안녕하세요
이번 포스팅에서는 도커 이미지의 생성, Export 를 통한 이관, Docker Compose 등을 살펴보도록 하겠습니다.
아래 글에서 이어지는 포스팅입니다.
Contents
Docker 이미지 생성하기
도커 컨테이너 를 사용하다 보면 도커 허브 사이트 와 같이 Public Container Registry 에서 다운 받는 도커 이미지 외 필요한 정보(애플리케이션) 와 설정 등을 담아서 만들어서 사용해야 하는 경우는 많이 있습니다.
이전 포스팅에서 설명한 기존 컨테이너 에서의 변경사항을 COMMIT 을 통해 새로운 컨테이너 이미지를 생성할 수도 있으며 지금 설명할 도커 이미지를 생성하여 사용할 수 있습니다.
Dockerfile 작성하기
Docker 이미지를 생성을 위해서는 Dockerfile 이라는 Docker 이미지 설정파일을 먼저 작성을 해야 합니다.
별도의 작업 디렉토리를 생성하여 해당 디렉토리에서 파일을 생성하여 진행하도록 하겠습니다.
[devops@docker1 ~]$ mkdir work [devops@docker1 ~]$ cd work
다음 내용으로 Dockerfile로 생성합니다. 생성할 도커 이미지는 Ubuntu 18.04 OS를 Base 로 사용하며 Nginx 도커 이미지를 생성하도록 하겠습니다.
[devops@docker1 work]$ vi Dockerfile FROM ubuntu:18.04 LABEL maintainer="admin@hoing.io" #nginx RUN apt update RUN apt -y install nginx vim RUN chown -R www-data:www-data /usr/share/nginx/html VOLUME ["/usr/share/nginx/html", "/var/log/nginx"] WORKDIR /etc/nginx EXPOSE 80 CMD ["nginx","-g","daemon off;"]
컨테이너 생성 전에 위에서 작성한 Dockerfile 에서 각 항목을 간략하게 설명을 드리겠습니다.
• FROM: 도커 이미지의 생성은 기존의 도커 컨테이너를 통해서 생성을 하게 됩니다 FROM 에서는 어떤 이미지를 기반으로 할지 설정하며 <이미지 이름>:<태그> 형식으로 설정합니다.
• LABEL: Image의 작성자 정보, 타이틀, 버전, 코멘트 등 정보를 작성할 때 사용하며 LABEL <Key>=<Value> 으로 이루어집니다.
사용 예시)
LABEL maintainer "xxxxxx <xxxxx@xxxxx.com>"
LABEL title="xxxxx xxxxxx"
LABEL version="1.0"
LABEL description="xxxxxx xxxxxx Label"
• RUN: 셸 스크립트 혹은 명령을 실행합니다.
포스팅 예제에서는 nginx 와 vim 패키지를 설치하였으며, 설치된 이후 nginx 실행 유저인 www-data 로 /usr/share/nginx/html 디렉토리의 소유권을 변경하였습니다
• COPY 와 ADD : 둘 다 파일을 추가하는 용도로 사용되며 유사하게 동작 합니다
둘의 차이는 ADD 는 tar 와 같이 묶여 있거나 tar.gz 로 압축이 된 경우 풀어서 파일을 추가하게 되고, Remote-URL Copy 가 가능 합니다(wget 등)
COPY 는 호스트의 로컬 영역의 파일 또는 디렉토리에 대상으로 지정한 디렉토리나 파일을 그대로 복사하게 됩니다.
• VOLUME: 호스트와 공유할 디렉토리 목록입니다. docker run 명령에서는 -v 옵션으로 사용할 수 있는 Volume 옵션입니다.
여기서 지정한 볼륨은 호스트의 /var/lib/docker/volumes/ 아래 디렉토리와 공유됩니다.
• WORKDIR: OS의 cd 명령 처럼 컨테이너 상에서 작업 디텍토리로 전환을 위해서 사용됩니다.
디렉토리가 전환된 이후 사용되는 RUN, CMD, ENTRYPOINT, COPY, ADD 명령문은 해당 디렉터리를 기준으로 실행됩니다.
컨테이너 실행 후 exec -it /bin/bash 를 통해 컨테이너 안으로 진입하였을 때 시작하는 디렉토리 시작점이 되기도 합니다
• EXPOSE: 도커 이미지에서 사용하는 포트를 명시적으로 알려주기 위해서 사용합니다.
아래 2개의 컨테이너 중 컨테이너 ID 7a16ddc0c770 는 EXPOSE 를 사용한 도커 이미지이고, 컨테이너 ID cccb62061b88 는 EXPOSE 를 미사용 컨테이너 이미지입니다.
[devops@docker1 work]$ docker ps CONTAINER ID IMAGE PORTS NAMES cccb62061b88 mynginx2:1.0 admiring_shaw 7a16ddc0c770 mynginx:1.0 80/tcp mynginx1
* 가로 길이에 의해서 일부 컬럼은 편집되었습니다.
• CMD 와 ENTRYPOINT : CMD 와 ENTRYPOINT 는 둘다 컨테이너를 기동하면 실행(수행) 할 명령어를 정의 선언문입니다. 앞에서 컨테이너의 주 어플리케이션이 동작하기 위한 사전 작업(설치 등)이 완료된 후 최종적으로 애플리케이션 또는 데몬을 실행하여 기동하는 명령어 선언 단계입니다.
예제로 생성한 도커 이미지에서의 CMD 명령어는 Nginx 데몬이 계속 실행 중인 상태로 유지되기 위한 명령어 인자 입니다.
Docker Container 는 실행 시 계속 running 되는 명령이 없다면 해당 명령어 수행 완료 후 컨테이너도 종료되게 되게 됨으로 예제에서는 "-g","daemon off;" 를 사용하였습니다.
-g 는 Global Directive 설정으로 daemon off 을 적용함에 따라 foreground 로 동작을 의미하며 옵션 없이 run 으로 기동하면 foreground 로 동작하고 run -d 를 사용하면 background 로 실행하게 되며 해당 인자가 없게 되면 -d 를 사용하여도 background 로는 실행되지 않습니다.
CMD 와 ENTRYPOINT 둘의 차이점은 CMD 는 실행하는 시점에 실행 시 받은 인자로 대체하여 실행할 수 있습니다. 아래 실행 예제 결과는 nginx 이미지를 통해 컨테이너를 실행하지만 df -h 라는 실행 인자 값을 사용함으로써 실제는 df -h 가 실행되었습니다. (해당 이미지는 CMD 를 사용한 이미지 입니다.)
[devops@docker1 work]$ docker run mynginx:1.0 df -h Filesystem Size Used Avail Use% Mounted on overlay 46G 7.5G 38G 17% / tmpfs 64M 0 64M 0% /dev tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup shm 64M 0 64M 0% /dev/shm /dev/mapper/centos_docker1-root 46G 7.5G 38G 17% /etc/hosts tmpfs 1.9G 0 1.9G 0% /proc/asound tmpfs 1.9G 0 1.9G 0% /proc/acpi tmpfs 1.9G 0 1.9G 0% /proc/scsi tmpfs 1.9G 0 1.9G 0% /sys/firmware
ENTRYPOINT 는 작성된 이미지파일에서 정의된 명령어로만 실행이 됩니다 그래서 ENTRYPOINT 작성한 이미지의 컨테이너에서 위와 같이 실행을 하게 되면 에러가 발생되게 됩니다.
컨테이너의 목적, 즉 Apache, PHP-FPM, MySQL, Nginx 이와 같이 컨테이너의 사용 용도와 사용을 해야 하는 명령어가 정해져 있는 경우 이미지 작성시 작성된 의도대로 항상 실행될 수 있도록 ENTRYPOINT 를 사용하는 것이 좋을 수도 있습니다.
작성하는 형태에 따라서 ENTRYPOINT 와 CMD 를 혼용하여 사용할 수 있으며 이 경우 ENTRYPOINT 에서는 고정적인 명령어를, CMD 에서는 명령어의 추가 옵션이나 인자 값을 정의해주는 형태로 사용할 수도 있습니다.
Docker Image Layer
Docker 이미지를 생성하기 전에 레이어에 대해서 잠깐 살펴보도록 하겠습니다.
도커의 이미지 레이어가 중요하다고 강조되는 이유로는 Docker 이미지의 작성 방법에 따라서 레이어 수가 달라지고 레이어 수에 따라서 용량의 차이가 발생될 수 있다는 것입니다.
Best practices for writing Dockerfiles 지침을 따라서 이전 버전의 Docker 에서는 이미지의 레이어 수를 최소화하여 성능을 보장하는 것이 중요했습니다(지금도 레이어를 줄이는 것은 중요)
이러한 제한이나 중요점을 위해 추가된 기능으로 RUN, COPY, ADD 만 레이어를 만들 수 있습니다. 다른 명령(instructions) 은 temporary intermediate images 를 생성하고 용량을 늘리지는 않습니다.
이와 같은 내용으로 RUN, COPY, ADD 수를 줄이는 것 또는 많이 늘리지 않는 것도 중요 합니다. 그래서 아래와 같이 가능한 선에서 백슬래시(\) 를 통해서 1개 레이어에서 여러 명령어를 추가하여 작성하는 편이 좋습니다
RUN apt-get update && apt-get install -y \ bzr \ cvs \ git \ mercurial \ subversion \ && rm -rf /var/lib/apt/lists/*
Docker Build
이제 위해서 생성한 Dockerfile 을 통해서 새로운 도커 이미지를 생성해보도록 하겠습니다. build 명령어를 통해 진행하게 됩니다.
[devops@docker1 work]$ docker build --tag mynginx:1.0 . Sending build context to Docker daemon 4.608kB Step 1/9 : FROM ubuntu:18.04 ---> fbf60236a8e3 Step 2/9 : LABEL maintainer="admin@hoing.io" ---> Running in d6fe5eeb1cf5 Removing intermediate container d6fe5eeb1cf5 ---> d83a7f7a1dcb Step 3/9 : RUN apt update ---> Running in 43b13bec7255 < ... 중략 ... > Successfully built 7d749bc3b862 Successfully tagged mynginx:1.0 <-- 생성 완료
--tag(또는 -t) 옵션은 생성할 이미지 이름 과 버전 tag 을 지정하게 됩니다. 마지막 점(.) 은 build 에 사용할 Dockerfile 의 위치를 지정하는 것입니다.
생성된 도커 이미지 확인 및 실행을 하도록 하겠습니다.
[devops@docker1 work]$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE mynginx 1.0 7d749bc3b862 32 seconds ago 215MB [devops@docker1 work]$ docker run -d --name mynginx1 mynginx:1.0 [devops@docker1 work]$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7a16ddc0c770 mynginx:1.0 "nginx -g 'daemon of…" 6 seconds ago Up 6 seconds 80/tcp mynginx1
정상적으로 실행되는 것을 확인할 수 있습니다.
컨테이너 내부로 진입하여 몇 가지를 확인해보도록 하겠습니다.
[devops@docker1 work]$ docker exec -it mynginx1 /bin/bash -- Nginx 실행 유저 www-data root@7a16ddc0c770:/etc/nginx# more nginx.conf user www-data; <... 중략 ...> root@7a16ddc0c770:/etc/nginx# cd /usr/share/nginx/html -- 도커 이미지 작성시 chown 이 정상 실행되어서 소유권이 변경되어 있음 root@7a16ddc0c770:/usr/share/nginx/html# ls -al total 4 drwxr-xr-x 2 www-data www-data 24 Jul 15 15:03 . drwxr-xr-x 1 root root 18 Jul 15 15:01 .. -rw-r--r-- 1 www-data www-data 612 Apr 17 2018 index.html -- 패키지도 설치가 된 것이 확인 됨 root@7a16ddc0c770:/etc/nginx# which vim /usr/bin/vim
Dockerfile 에 정의한 내역이 정상적으로 반영된 것을 확인할 수 있습니다.
docker inspect 를 통해서 컨테이너 정보를 살펴보도록 하겠습니다.
-- Volume Mount 정보 [devops@docker1 work]$ docker inspect mynginx1 -f {{.Mounts}} [{volume 593fc9cf89d426b15239f24d66808462a8413c4615d7bf266153cd387bdee62e /var/lib/docker/volumes/593fc9cf89d426b15239f24d66808462a8413c4615d7bf266153cd387bdee62e/_data /usr/share/nginx/html local true } {volume f013c50e8bd379cc7110557c0a7a5d08f875f0ebccede37e667a749d9f5f798c /var/lib/docker/volumes/f013c50e8bd379cc7110557c0a7a5d08f875f0ebccede37e667a749d9f5f798c/_data /var/log/nginx local true }] -- LABEL [devops@docker1 work]$ docker inspect mynginx1 -f {{.Config.Labels}} map[maintainer:admin@hoing.io]
Dockerfile 에서 지정한 Volume 내역대로 마운트 되어있으며 LABEL 에서 지정한 maintainer 정보도 표시가 되고 있습니다.
이번에는 docker history 명령을 통해서 도커 이미지의 계층을 살펴보도록 하겠습니다. history 를 통해서 레이어 수, 각 레이어에서 사용되는 용량, 수행된 명령어나 선언 형태 등을 확인할 수 있습니다.
[devops@docker1 work]$ docker history 7d749bc3b862 IMAGE CREATED CREATED BY SIZE COMMENT 7d749bc3b862 40 minutes ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon… 0B 219308db6b97 40 minutes ago /bin/sh -c #(nop) EXPOSE 80 0B 6d9bbbcf080c 40 minutes ago /bin/sh -c #(nop) WORKDIR /etc/nginx 0B f62e05262a69 40 minutes ago /bin/sh -c #(nop) VOLUME [/usr/share/nginx/… 0B 94a742b42cea 40 minutes ago /bin/sh -c chown -R www-data:www-data /usr/s… 612B 3dc6d66946a4 40 minutes ago /bin/sh -c apt -y install nginx vim 115MB 8eb070ac06c8 41 minutes ago /bin/sh -c apt update 36.9MB f62550e042dc 41 minutes ago /bin/sh -c #(nop) LABEL maintainer=admin@ho… 0B fbf60236a8e3 44 hours ago /bin/sh -c #(nop) CMD ["bash"] 0B <missing> 44 hours ago /bin/sh -c #(nop) ADD file:7274ece1917848683… 63.1MB
포스팅에서는 예제로 간단하게 도커 이미지 생성을 확인하였으나 실제로는 요구 사항에 맞게 여러가지가 추가되고 변경되어 각각의 환경이나 업무 등에 맞게 만들어서 사용되고 있고 자주 사용되는 기능 이기도 합니다.
도커 이미지 컨테이너 이동하기
사용중인 도커 이미지나 컨테이너의 백업이 될 수도 있고, 보통은 다른 서버로의 이동을 위해서 export/import 또는 save/load 를 사용하게 됩니다.
둘의 차이는 아래의 공식 문서에서 명확하게 설명되어 있습니다.
• docker export
Export a container’s filesystem as a tar archive
• docker save
Save one or more images to a tar archive (streamed to STDOUT by default)
export 는 컨테이너의 파일시스템을 tar로 묶는(archive) 것이고, save 는 1개 이상의 image layer 를 tar 로 묶는(archive) 것 입니다. 둘의 차이는 아래 예제와 테스트를 통해 명확히 확인할 수 있습니다.
[참고] 테스트를 위해서 다른 서버로 파일을 전송하여 도커 컨테이너를 실행하도록 하겠습니다. 도커의 설치는 이전 포스팅에서 확인하시면 됩니다.
Docker export/import
export/import 부터 확인해보도록 하겠습니다.
작업 디렉토리는 mig 별도로 만들고 진행하도록 하겠습니다
[참고] 디렉토리 생성, 디렉토리 명은 필수는 아닙니다.
[devops@docker1 ~]$ mkdir mig [devops@docker1 ~]$ cd mig
실행 중인 컨테이너(mynginx1)는 위에서 docker build 로 생성하여 실행한 컨테이너입니다. 해당 컨테이너(mynginx1) 를 사용하여 export 를 하도록 하겠습니다.
-- 컨테이너 조회 [devops@docker1 mig]$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7a16ddc0c770 mynginx:1.0 "nginx -g 'daemon of…" 36 hours ago Up 36 hours 80/tcp mynginx1 -- 컨테이너에 대해서 export 수행 [devops@docker1 mig]$ docker container export mynginx1 > exp_mynginx.tar ------------------------------------------------------------------ -- Docker Image 조회 [devops@docker1 mig]$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE mynginx 1.0 7d749bc3b862 36 hours ago 215MB -- Docker image인 mynginx를 export 시도 [devops@docker1 mig]$ docker image export mynginx > exp_mynginx_img.tar Error response from daemon: No such container: mynginx -->> export 명령어는 Docker Container 에 사용해야 함
이제 export 된 파일을 다른 서버로 전송하도록 하겠습니다.
[devops@docker1 mig]$ rsync --progress \ exp_mynginx.tar docker-2:~/mig/
2번 서버(호스트네임 docker-2) 에서 import 를 진행하도록 하겠습니다.
-- import 실행 [devops@docker-2 mig]$ docker image import exp_mynginx.tar mynginx:1.0 sha256:bedbb68773df70577635592507529ad66b84b07eae17440b3d0479c263476656 -- images 조회 [devops@docker-2 mig]$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE mynginx 1.0 bedbb68773df 7 seconds ago 214MB -- 도커 이미지의 history 확인, 커맨드 등이 확인되지 않음 [devops@docker-2 mig]$ docker history bedbb68773df IMAGE CREATED CREATED BY SIZE COMMENT bedbb68773df 38 minutes ago 214MB Imported from -
참고로 import 는 위와 같이 import 옵션을 사용할 수 있고 아래와 같이 cat 을 사용할 수도 있습니다
]$ cat exp_mynginx.tar | docker image import - mynginx2:1.0
우선 2번 서버에서 export 된 파일을 해제 해보도록 하겠습니다.
-- 디렉토리 생성 [devops@docker-2 mig]$ mkdir -p tarfile_exp -- tar 수행 [devops@docker-2 mig]$ tar xvf exp_mynginx.tar -C tarfile_exp [devops@docker-2 mig]$ cd tarfile_exp/ -- 디렉토리 내역 조회 [devops@docker-2 tarfile_exp]$ ls -alrt total 12 drwxr-xr-x. 8 devops devops 96 May 23 2017 lib drwxr-xr-x. 2 devops devops 6 Apr 24 2018 sys drwxr-xr-x. 2 devops devops 6 Apr 24 2018 proc drwxr-xr-x. 2 devops devops 6 Apr 24 2018 home drwxr-xr-x. 2 devops devops 6 Apr 24 2018 boot drwxr-xr-x. 10 devops devops 105 Jul 3 04:30 usr drwxr-xr-x. 2 devops devops 6 Jul 3 04:30 srv drwxr-xr-x. 2 devops devops 6 Jul 3 04:30 opt drwxr-xr-x. 2 devops devops 6 Jul 3 04:30 mnt drwxr-xr-x. 2 devops devops 6 Jul 3 04:30 media drwxr-xr-x. 2 devops devops 34 Jul 3 04:31 lib64 drwxr-xr-x. 2 devops devops 4096 Jul 16 02:50 sbin drwxr-xr-x. 2 devops devops 4096 Jul 16 02:50 bin drwxr-xr-x. 12 devops devops 150 Jul 16 02:50 var drwxrwxr-x. 2 devops devops 6 Jul 16 02:50 tmp drwxr-xr-x. 5 devops devops 75 Jul 16 02:51 run drwxr-xr-x. 35 devops devops 4096 Jul 16 02:51 etc -rwxr-xr-x. 1 devops devops 0 Jul 16 02:51 .dockerenv drwxr-xr-x. 4 devops devops 43 Jul 16 02:51 dev drwx------. 2 devops devops 58 Jul 16 23:24 root drwxrwxr-x. 3 devops devops 45 Jul 17 10:36 .. drwxrwxr-x. 21 devops devops 242 Jul 17 10:41 .
위에서 보는 것처럼 컨테이너 내부의 파일이 그대로 tar 로 묶여서 추출된 것을 확인할 수 있습니다. 이제 import 된 도커 이미지를 실행해보도록 하겠습니다.
[devops@docker-2 tarfile_exp]$ cd .. -- 도커 컨테이너 실행 [devops@docker-2 mig]$ docker run -d --name exp_mynginx1 mynginx:1.0 docker: Error response from daemon: No command specified. See 'docker run --help'. <-- 에러 발생
import 된 이미지를 통해 컨테이너 기동을 하기 위해 실행하게 되면 에러가 발생될 것입니다
에러가 발생되는 이유는 export로 추출 후 로드한 docker image의 경우 docker container의 파일시스템을(파일을) 를 단순히 아카이빙 한 이미지입니다.
즉 파일을 압축한 파일 자체를 이미지가 로드 된 것으로 이 이미지를 사용하기 위해서는 이 이미지를 기반으로 새로운 Dockerfile을 새로 작성하거나 import 할 때 명령어도 같이 추가해서 로드 해야 합니다.
명령어를 추가하여 다시 import 후 실행해보도록 하겠습니다.
[devops@docker-2 mig]$ docker image import --change 'CMD ["nginx","-g","daemon off;"]' exp_mynginx.tar mynginx2:1.0 sha256:0b0c750b495637a9be017af9a6d67e99ac9760a9b39db4bb2e9a4a580ef905b1 [devops@docker-2 mig]$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE mynginx2 1.0 0b0c750b4956 6 seconds ago 214MB mynginx 1.0 bedbb68773df 5 hours ago 214MB -- history 는 동일하게 확인 되는 내용이 없음 [devops@docker-2 mig]$ docker history mynginx2:1.0 IMAGE CREATED CREATED BY SIZE COMMENT 0b0c750b4956 About a minute ago 214MB Imported from - -- 컨테이너 실행 [devops@docker-2 mig]$ docker run -d --name imp_nginx3 mynginx3:1.0 e3951aacace350495dc3eefbf9ca388c8810677c1c429572ba057c22f49b2a39 -- 컨테이너 정상 실행됨 [devops@docker-2 mig]$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e3951aacace3 mynginx2:1.0 "nginx -g 'daemon of…" 3 seconds ago Up 2 seconds imp_nginx2
CMD ["nginx","-g","daemon off;"] 를 추가로 입력하여 import 를 하였고, 이렇게 import 된 이미지는 정상적으로 실행된 것을 확인할 수 있습니다. export 는 매뉴얼에서 설명된 내용과 같이 컨테이너의 filesystem을 tar archive 를 한 형태입니다.
Docker save/load
save 와 load 에 대해서 확인해보도록 하겠습니다. 다시 계속 테스트를 진행한 첫 번째 서버에서 save 를 진행해보도록 하겠습니다.
save 에서 사용하는 이미지는 위와 동일하게 docker build 로 만든 이미지를 사용하도록 하겠습니다.
[devops@docker1 mig]$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7a16ddc0c770 mynginx:1.0 "nginx -g 'daemon of…" 36 hours ago Up 36 hours 80/tcp mynginx1 -- docker save 실행 [devops@docker1 mig]$ docker save mynginx:1.0 -o save_mynginx.tar -- --output , -o: 파일명을 명시합니다. [devops@docker1 mig]$ ls -alrt save_mynginx.tar -rw------- 1 devops devops 219806208 Jul 17 15:05 save_mynginx.tar -- 두번째 서버로 파일 전송 [devops@docker1 mig]$ rsync --progress \ save_mynginx.tar docker-2:~/mig/
이제 두번째 서버에서 파일을 load 하도록 하겠습니다 load 하기 전에 위에서 생성한 도커 이미지를 삭제하고 진행하겠습니다.
아래와 같이 수행하게 되면 실행, 생성된 모든 컨테이너의 종료 및 모든 도커 이미지가 삭제됩니다.
[devops@docker-2 mig]$ docker rm -f $(docker ps -q) [devops@docker-2 mig]$ docker rmi $(docker images -q)
Load 를 진행하겠습니다.
[devops@docker-2 mig]$ docker load -i save_mynginx.tar 878dab86cf0f: Loading layer [==================================================>] 65.51MB/65.51MB 015b884d7998: Loading layer [==================================================>] 36.9MB/36.9MB c3ab09f5a36c: Loading layer [==================================================>] 117.4MB/117.4MB c0182a141d30: Loading layer [==================================================>] 4.608kB/4.608kB Loaded image: mynginx:1.0
위와 같이 load -i 를 통해서 진행하여도 되고 아래와 같이 <(리다이렉션)을 통해서도 가능 합니다
$ sudo docker load < nginx-stable-image.tar
--input , -i 옵션은 불러올 파일명을 명시합니다
이번에는 도커 history 와 tar 파일 내용을 확인해보도록 하겠습니다.
[devops@docker-2 mig]$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE mynginx 1.0 7d749bc3b862 45 hours ago 215MB -- docker history 실행, history가 확인 됩니다. [devops@docker-2 mig]$ docker history 7d749bc3b862 IMAGE CREATED CREATED BY SIZE COMMENT 7d749bc3b862 45 hours ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon… 0B <missing> 45 hours ago /bin/sh -c #(nop) EXPOSE 80 0B <missing> 45 hours ago /bin/sh -c #(nop) WORKDIR /etc/nginx 0B <missing> 45 hours ago /bin/sh -c #(nop) VOLUME [/usr/share/nginx/… 0B <missing> 45 hours ago /bin/sh -c chown -R www-data:www-data /usr/s… 612B <missing> 45 hours ago /bin/sh -c apt -y install nginx vim 115MB <missing> 45 hours ago /bin/sh -c apt update 36.9MB <missing> 45 hours ago /bin/sh -c #(nop) LABEL maintainer=admin@ho… 0B <missing> 3 days ago /bin/sh -c #(nop) CMD ["bash"] 0B <missing> 3 days ago /bin/sh -c #(nop) ADD file:7274ece1917848683… 63.1MB -- 해제할 디렉토리 생성 [devops@docker-2 mig]$ mkdir -p tarfile_save -- tar 실행 [devops@docker-2 mig]$ tar xvf save_mynginx.tar -C tarfile_save 0dad86d100493aaf12efb7bda022cdaa726762010c93c2a5de316385044f1078/ 0dad86d100493aaf12efb7bda022cdaa726762010c93c2a5de316385044f1078/VERSION 0dad86d100493aaf12efb7bda022cdaa726762010c93c2a5de316385044f1078/json 0dad86d100493aaf12efb7bda022cdaa726762010c93c2a5de316385044f1078/layer.tar 602fd8163c337288e0e917291e902571c9823133fe9c24c5ccde9149c3fd67cc/ 602fd8163c337288e0e917291e902571c9823133fe9c24c5ccde9149c3fd67cc/VERSION 602fd8163c337288e0e917291e902571c9823133fe9c24c5ccde9149c3fd67cc/json 602fd8163c337288e0e917291e902571c9823133fe9c24c5ccde9149c3fd67cc/layer.tar 61d27a186eb59454d0e64f2bff599ea0e5ad612d26eaf9c33fc96e0bfb738ccd/ 61d27a186eb59454d0e64f2bff599ea0e5ad612d26eaf9c33fc96e0bfb738ccd/VERSION 61d27a186eb59454d0e64f2bff599ea0e5ad612d26eaf9c33fc96e0bfb738ccd/json 61d27a186eb59454d0e64f2bff599ea0e5ad612d26eaf9c33fc96e0bfb738ccd/layer.tar 7d749bc3b862cb40a94b814811eb83478171edd90ec549069c2f4e596b6ac5b0.json 7e8f06936c88e76d408347115ab8bec648e5886c36277c240372ade455dac7e0/ 7e8f06936c88e76d408347115ab8bec648e5886c36277c240372ade455dac7e0/VERSION 7e8f06936c88e76d408347115ab8bec648e5886c36277c240372ade455dac7e0/json 7e8f06936c88e76d408347115ab8bec648e5886c36277c240372ade455dac7e0/layer.tar manifest.json tar: manifest.json: implausibly old time stamp 1970-01-01 09:00:00 repositories tar: repositories: implausibly old time stamp 1970-01-01 09:00:00 -- 디렉토리 조회 [devops@docker-2 mig]$ ls -al tarfile_save total 16 drwxrwxr-x. 6 devops devops 4096 Jul 18 01:25 . drwxrwxr-x. 4 devops devops 89 Jul 18 01:25 .. drwxr-xr-x. 2 devops devops 50 Jul 16 02:50 0dad86d100493aaf12efb7bda022cdaa726762010c93c2a5de316385044f1078 drwxr-xr-x. 2 devops devops 50 Jul 16 02:50 602fd8163c337288e0e917291e902571c9823133fe9c24c5ccde9149c3fd67cc drwxr-xr-x. 2 devops devops 50 Jul 16 02:50 61d27a186eb59454d0e64f2bff599ea0e5ad612d26eaf9c33fc96e0bfb738ccd -rw-r--r--. 1 devops devops 2881 Jul 16 02:50 7d749bc3b862cb40a94b814811eb83478171edd90ec549069c2f4e596b6ac5b0.json drwxr-xr-x. 2 devops devops 50 Jul 16 02:50 7e8f06936c88e76d408347115ab8bec648e5886c36277c240372ade455dac7e0 -rw-r--r--. 1 devops devops 431 Jan 1 1970 manifest.json -rw-r--r--. 1 devops devops 87 Jan 1 1970 repositories
이전의 export/import 와 달리 history 를 통해 레이어 정보가 확인되며, tar 를 해제하면 도커 이미지 레이어 형태의 구성을 확인할 수 있습니다.
이제는 이미지를 실행하여 정상적으로 실행되는지 확인해보도록 하겠습니다.
[devops@docker-2 mig]$ docker run -d --name load_nginx_img mynginx:1.0 0d4f3c404f9da640859daca23a7337c182f7b7843d9312249d7b2859962e0a14 [devops@docker-2 mig]$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0d4f3c404f9d mynginx:1.0 "nginx -g 'daemon of…" 3 seconds ago Up 1 second 80/tcp load_nginx_img
정상적으로 실행이 되었습니다.
위에서 확인한 것 과 같이 두개의 명령어는 도커를 다른 곳으로 이동시킨다 의미로 사용이 가능하나 세부적으로는 차이가 있습니다. 그래서 사용하려는 용도나 목적에 따라서 명령어를 확인하여 사용해야 합니다.
docker-compose
docker-compose 는 1개 이상의 복수 개의 컨테이너를 실행시키는 도커 애플리케이션이 정의를 하기 위한 툴입니다.
Compose를 사용하면 yaml 파일을 사용하여 애플리케이션의 서비스를 구성할 수 있습니다.
docker-compose를 사용하면 컨테이너 실행에 필요한 옵션을 docker-compose.yaml(yml)이라는 파일에 설정해서 사용하며 컨테이너 간 실행 순서나 의존성도 관리할 수 있습니다.
Docker-compose 를 사용하기 위해서는 도커 엔진 과 도커 compose 가 특정 버전이상이 되어야 하나 최근에 설치했을 경우 버전은 모두 충족하게 됩니다.
docker-compose 설치
docker-compose 를 사용하기 위해서는 docker 이후에 별도로 설치를 해야 합니다.
설치는 아래와 같이 진행하시면 됩니다.
~]$ sudo yum -y install python3-pip \ python3-devel libffi-devel openssl-devel \ gcc glibc-devel rust cargo make ~]$ sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" \ -o /usr/local/bin/docker-compose ~]$ sudo chmod +x /usr/local/bin/docker-compose ~]$ sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
설치된 버전은 아래와 같이 확인할 수 있습니다.
[devops@docker1 ~]$ docker-compose version docker-compose version 1.29.2, build 5becea4c docker-py version: 5.0.0 CPython version: 3.7.10 OpenSSL version: OpenSSL 1.1.0l 10 Sep 2019
docker-compose.yaml 작성
docker-compose 사용하기 위해서는 yaml(yml) 파일을 작성해야 합니다.
docker-compose.yaml 파일의 예제는 인터넷에 원하는 구성으로 검색하면 각자의 상황에 맞게 다양하게 설정 내역이 공유 되어있기 때문에 공유된 yaml 파일을 참조하여 새로 작성하셔서 사용하시면 됩니다.
포스팅에서는 MySQL 과 WordPress 도커 이미지를 사용하여 작성을 해보도록 하겠습니다.
-- 디렉토리 생성 및 이동 [devops@docker1 ~]$ mkdir -p work [devops@docker1 ~]$ cd work -- docker-compose.yaml 파일명으로 작성 [devops@docker1 work]$ vi docker-compose.yaml version: "3.8" services: db: # 서비스명 image: mysql:5.7 restart: always container_name: wordpress_db # 컨테이너 이름 environment: # -e 옵션 MYSQL_ROOT_PASSWORD: 'mypass!@#' MYSQL_DATABASE: wordpress # 일반 유저 MYSQL_USER: wordpress_user MYSQL_PASSWORD: wordpress_pw command: # 명령어 실행 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --lower_case_table_names=1 volumes: - /var/lib/dbdata:/var/lib/mysql # -v 옵션 (다렉토리 마운트 설정) 과 동일 wordpress: # 서비스명 depends_on: - db image: wordpress container_name: wordpress_app # 컨테이너 이름 ports: - "8999:80" restart: always environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_NAME: wordpress WORDPRESS_DB_USER: wordpress_user WORDPRESS_DB_PASSWORD: wordpress_pw volumes: - /var/lib/wordpress:/var/www/html
들여쓰기와 공백 등을 맞춰야 합니다.
위에서 작성한 yaml 파일에서 설정한 내용을 확인해보도록 하겠습니다.
• version
version 은 작성한 yaml 파일의 파일 규격을 의미합니다. 입력한 버전에 따라서 지원하는 옵션이 달라지게 됩니다. compose 와 파일 버전의 호환성은 아래 링크에서 확인하시면 됩니다.
[devops@docker1 work]$ docker version Client: Docker Engine - Community Version: 20.10.7 API version: 1.41 Go version: go1.13.15 Git commit: f0df350 Built: Wed Jun 2 11:58:10 2021 OS/Arch: linux/amd64 Context: default Experimental: true <... 중략 ...>
지금 사용중인 버전이 20.10.7 로 확인되기 때문에 포스팅에서는 포스팅 시점에서 가장 높은 버전인 3.8을 입력하여 사용하였습니다.
• services
services 는 실행하는 컨테이너에 대해서 docker-compose 에서의 관리 단위입니다.
포스팅에서는 db 라는 이름의 서비스로 mysql:57 도커 이미지 사용하였고 wordpress 라는 서비스에서는 wordpress 도커 이미지를 사용하였습니다.
• image
image 는 사용할 도커 이미지를 입력합니다. 포스팅에서는 mysql:57 과 wordpress 를 사용하였습니다.
• restart
restart 는 무조건 필요한 옵션은 아니며, 포스팅에서는 추가적으로 사용한 옵션입니다.
always 로 설정하였기 때문에 docker 데몬의 재시작이나 비정상적으로 종료 시 재시작 되게 됩니다.
• container_name
docker run --name 과 동일한 옵션으로 컨테이너의 이름을 지정합니다.
• ports
docker run -p 와 동일한 옵션으로 외부에서 접속이 가능하도록 포트 포워딩을 설정을 하였습니다.
• depends_on
compose 의 특징이 서비스(컨테이너) 간의 순서 또는 의존성 등을 설정할 수 있습니다.
depends_on 을 통해 이와 같은 서비스 간의 순서 등을 설정할 수 있습니다.
예제에서 웹 서비스 와 DB를 사용하였기 때문에 DB 가 먼저 실행되어야 합니다.
그 후에 웹 서비스가 실행되어야 하는 순서가 있습니다.
그래서 wordpress 서비스에서 depends_on 을 사용하여 위의 db 서비스와의 의존성을 설정하였습니다.
• environment
서비스(컨테이너 별로) 추가 옵션(환경변수)를 설정합니다.
docker -e 을 사용하여 실행하는 것과 동일 하게 도커 이미지 별로 필수 또는 추가로 옵션(환경설정)을 지정하는 것입니다.
포스팅에서는 wordpress 에서 사용할 DB와 일반유저 정보를 다 같이 env 항목에 입력하였습니다.
그리고 wordpress 서비스에서도 env 를 설정하여 db 정보, 계정 정보를 입력하였습니다.
• command
dockerfile 을 통해 이미지 빌드시 사용한 run 과 같은 의미로 수행이 필요한 명령어를 입력하는 항목입니다.
mysql 이미지에서는 실행 시 파라미터 설정의 변경 항목으로 command 를 통해서 지정할 수 있습니다.
• volume
docker run -v 와 동일한 옵션으로 호스트 OS 디렉토리를 mount 합니다.
volume mount 를 하여 호스트 OS 디렉토리에 파일을 영구 저장 및 손쉬운 백업, 이관을 위해서 사용됩니다.
docker-compose up
이제 위에서 작성한 docker-compose.yaml 를 이용하여 docker-compose 를 실행하도록 하겠습니다.
[devops@docker1 work]$ docker-compose up -d Pulling wordpress (wordpress:)... latest: Pulling from library/wordpress b4d181a07f80: Already exists 78b85dd8f014: Pull complete 8589b26a90be: Downloading [==================> ] 28.4MB/76.68MB f5af5d641946: Download complete 614ec6f0b8d6: Download complete 12b28f3797fb: Download complete <... 중략 ...> e563e5b2630b: Waiting 10499c79181c: Waiting 7180626436df: Waiting 72df520dac82: Waiting ed2d407056b5: Waiting 7224b35f0930: Waiting
[참고] -d 옵션은 백그라운드 실행을 의미하며, 다른 여러 옵션도 있으며 -t 는 타임아웃에 관한 설정으로 기본 10초입니다.
로컬 캐시에 도커 이미지의 존재여부에 따라서 이미지 다운로드의 여부는 달라지게 됩니다. 포스팅 테스트 시스템에서는 wordpress 이미지가 없었기 때문에 다운로드를 받은 후 compose 가 실행되었습니다.
그럼 아래에서 컨테이너 등의 정보를 조회를 해보도록 하겠습니다.
-- 도커 컨테이너 조회 [devops@docker1 work]$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES bd2ff8b3f614 wordpress "docker-entrypoint.s…" 10 seconds ago Up 9 seconds 0.0.0.0:8999->80/tcp, :::8999->80/tcp wordpress_app 51b5d4a00dbb mysql:5.7 "docker-entrypoint.s…" 10 seconds ago Up 10 seconds 3306/tcp, 33060/tcp wordpress_db -- docker-compose image 조회 [devops@docker1 work]$ docker-compose images Container Repository Tag Image Id Size ------------------------------------------------------------- wordpress_app wordpress latest b77ea6f8ecf7 550.6 MB wordpress_db mysql 5.7 09361feeb475 447 MB -- docker-compose 컨테이너 조회 docker ps 와 유사(동일) [devops@docker1 work]$ docker-compose ps Name Command State Ports --------------------------------------------------------------------------------------------- wordpress_app docker-entrypoint.sh apach ... Up 0.0.0.0:8999->80/tcp,:::8999->80/tcp wordpress_db docker-entrypoint.sh --cha ... Up 3306/tcp, 33060/tcp -- config 내역 조회, yaml 파일의 정보 [devops@docker1 work]$ docker-compose config services: db: command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --lower_case_table_names=1 container_name: wordpress_db environment: MYSQL_DATABASE: wordpress MYSQL_PASSWORD: wordpress_pw MYSQL_ROOT_PASSWORD: mypass!@# MYSQL_USER: wordpress_user image: mysql:5.7 restart: always volumes: - /var/lib/dbdata:/var/lib/mysql:rw wordpress: container_name: wordpress_app depends_on: db: condition: service_started environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_NAME: wordpress WORDPRESS_DB_PASSWORD: wordpress_pw WORDPRESS_DB_USER: wordpress_user image: wordpress ports: - published: 8999 target: 80 restart: always volumes: - /var/lib/wordpress:/var/www/html:rw version: '3.8'
이와 같이 docker-compose 에서 몇 가지 정보 등을 조회해볼 수 있습니다. docker run -d 로 컨테이너 실행 시 문제나 특이사항을 확인하는 것처럼 docker-compose 도 로그를 확인할 수 있습니다.
아래와 같이 로그를 확인할 수 있으며 logs 위에서 docker-compose.yaml 에서 작성한 services 명을 입력해야 합니다.
[devops@docker1 work]$ docker-compose logs db [devops@docker1 work]$ docker-compose logs wordpress
접속 확인
docker-compose 는 1개 이상의 복수 개의 컨테이너를 유기적으로 실행 방법 등을 정의하고 실행하는 툴로 예제와 같이 연계적인 면이 있는 경우에도 많이 사용합니다. 그래서 예제로 wordpress 웹 서비스와 해당 웹 서비스에서 사용을 해야 하는 DB 컨테이너 를 같이 실행되도록 compose 파일이 작성되었습니다.
위에서 작성된 yaml 파일을 통해 정상적으로 실행된 것을 확인하였기 때문에 실제 웹 브라우저를 통해 사용이 가능한지 를 확인해보도록 하겠습니다
compose 설정의 ports 에서 외부에서 접속 가능한 포트를 8999 로 설정하였기 때문에 브라우저 에서 8999 포트로 접속합니다.
정상접속이 되었다면 처음에는 워드프레스 설치 화면이 보이게 됩니다. 언어를 먼저 선택하는 화면이 보이며 언어를 선택하였다면 하단의 계속을 눌러서 진행을 합니다.
그 외 워드프레스 설치는 생략하도록 하겠습니다.
워드프레스의 설치가 완료되면 아래와 같이 어드민 페이지의 접속 과 포스팅 첫 페이지가 정상적으로 접속되는 것을 확인할 수 있습니다.
docker-compose 명령어
docker-compose 명령어에 대해서 몇 가지 확인해보도록 하겠습니다.
버전 확인
docker-compose --version
컨테이너를 생성 및 실행
docker-compose up
-d 백그라운드 실행 / -t 타임아웃 시간을 지정(기본값 10초)
로그 확인
docker-compose logs 서비스명
시작/재시작
docker-compose start/restart
up 으로 컨테이너 이미지 생성 및 실행 이후에 stop 으로 중지된 경우 start 로 시작할 수 있습니다.
또는 사용 중에 restart 통해 재시작 할 수 있습니다.
명령어를 수행 할 때는 compose의 yaml 파일이 있는 디렉토리에서 실행해야 합니다.
정지
docker-compose stop
compose 명령으로 정지 할수도 있고 일반 docker stop 으로도 정지할 수 있습니다.
docker-compose stop 를 할 때는 compose의 yaml 파일이 있는 디렉토리에서 실행해야 합니다.
상태 확인
docker-compose ps
동작중인 컨테이너들의 상태를 확인할 수 있으며 docker ps 로도 유사한 정보를 확인 할수 있습니다.
삭제
docker-compose rm
docker-compose로 생성한 컨테이너들 삭제하는 명령어로 삭제 전에 컨테이너는 중지되어 있어야 합니다.
이번 포스팅은 여기까지 확인하도록 하겠습니다 다음 포스팅에서는 Private Registry 설정과 기타 내용을 확인해보도록 하겠습니다.
이어지는 다음 포스팅 글
Reference
Reference Link
docs.docker.com/compose/install [L]
docs.docker.com/dockerfile_best-practices [L]
docs.docker.com/storagedriver [L]
docs.docker.com/dockerfile_best-practices [L]
연관된 다른 글
Principal DBA(MySQL, AWS Aurora, Oracle)
핀테크 서비스인 핀다에서 데이터베이스를 운영하고 있어요(at finda.co.kr)
Previous - 당근마켓, 위메프, Oracle Korea ACS / Fedora Kor UserGroup 운영중
Database 외에도 NoSQL , Linux , Python, Cloud, Http/PHP CGI 등에도 관심이 있습니다
purityboy83@gmail.com / admin@hoing.io