컨테이너와 Docker (5) - 도커 이미지 생성 - export - Docker Compose

Share

Last Updated on 1월 5, 2024 by Jade(정현호)

안녕하세요 
이번 포스팅에서는 도커 이미지의 생성, Export 를 통한 이관, Docker Compose 등을 살펴보도록 하겠습니다. 

아래 글에서 이어지는 포스팅입니다. 

       

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]


연관된 다른 글

 

 

 



0
글에 대한 당신의 생각을 기다립니다. 댓글 의견 주세요!x