Docker(도커), 쿠버네티스 관련 재직자 지원 수업의 두 번째 강의 내용을 정리한다.

2023-04-08 강의 노트

04. Docker 실습 이어서

시작 전에 Network 문제가 없는지 확인한다.

  • NetworkManager로 확인하는 방법
    $ sudo yum install NetworkManager-tui
    $ sudo mntui
    
  • ping을 보내는 방법
    $ ping 8.8.8.8
    PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
    64 bytes from 8.8.8.8: icmp_seq=1 ttl=114 time=54.4 ms
    64 bytes from 8.8.8.8: icmp_seq=2 ttl=114 time=38.4 ms
    64 bytes from 8.8.8.8: icmp_seq=3 ttl=114 time=34.5 ms
    64 bytes from 8.8.8.8: icmp_seq=4 ttl=114 time=35.8 ms
    

잘 되는 것을 확인했다.
Docker 의 bridge network type을 Host 로 하는 것을 해보자

$ docker network create -d host myhost
Error response from daemon: only one instance of "host" network is allowed

“host”는 하나밖에 쓰지 못 하며, 삭제도 하지 못 한다.
만들어진 host 를 사용한다.

$ docker run -it --network host --name centos8 centos:8 /bin/bash

05. Docker image 생성 : Container

컨테이너로 docker 이미지 커밋

apache 컨테이너를 사용해서 실습해본다.

$ docker run --name new_apache -d httpd:2.4
$ docker exec -it new_apache /bin/bash

컨테이너 내부에서 파일을 편집하려고 하는데, 만약 편집기가 없다면 설치한 뒤 진행한다.
apache 서버는 debian 계열이므로, apt update 후 install vim 실행한다.

$ vi /usr/local/apache2/htdocs/index.html 
$ cat /usr/local/apache2/htdocs/index.html

위에서 수정한 내용은 컨테이너 삭제 시 사라진다.

docker stop $(docker ps -q); docker rm $(docker ps -aq)
94f2fea86c41
94f2fea86c41
b8fb32487b6b

다시 apache 이미지를 올려서 확인을 하면, 이전 컨테이너에서 수정한 내용이 없다는 것을 알 수 있다.
컨테이너 내에서 수정한 내역을 계속 사용하고 싶다면, 컨테이너를 커밋해서 이미지로 생성한다.

$ docker run --name new_apache -d httpd:2.4
$ docker exec -it new_apache /bin/bash

#컨테이너 내부에서 필요 패키지를 다시 설치한다
$ apt update
$ apt install vim
$ apt install net-tools
$ vi /usr/local/apache2/htdocs/index.html 
$ exit

#컨테이너 커밋
# docker container commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
$ docker container commit new_apache test_image:v1.0
$ docker images
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
test_image    v1.0      1cef1b917867   6 seconds ago   200MB
mysql         5.7       3f3447deacaa   12 hours ago    455MB
httpd         2.4       192d41583429   9 days ago      145MB
httpd         latest    192d41583429   9 days ago      145MB
hello-world   latest    feb5d9fea6a5   18 months ago   13.3kB
centos        8         5d0da3dc9764   18 months ago   231MB

원하는 이미지가 생성된 것을 알 수 있다.
이미지를 실행 후 접속해서, 수정된 컨테이너 설정이 잘 저장되었는지 확인한다.

$ docker run --name test_image -d test_image:v1.0
$ docker exec -it test_image /bin/bash

#컨테이너 내부 설정 파일 확인
$ cat /usr/local/apache2/htdocs/index.html 
<html><body><h1>Hello This is my Apache Server</h1></body></html>

이전 수정 내역이 남아있는 것을 확인했다.
만든 이미지를 본인의 Dockerhub에 업로드 할 수도 있다.

컨테이너를 tar 파일로 출력

실행 중인 docker 컨테이너를 tar 파일로 저장하는 방법도 있다.

#일단 컨테이너를 실행한다
$ docker run --name new_apache2 -d httpd:2.4
$ docker container export new_apache2 -o httpd.tar
$ ll
total 143164
-rw-rw-r--. 1 vagrant vagrant 146595328 Apr  1 21:23 httpd.tar

#tar -tf로 tar 파일 확인한다. 
$ tar -tf httpd.tar

.tar 형식 파일이 저장된 것을 확인 가능하다.
이 tar 파일은 컨테이너를 백업한 것과 유사하다. 해당 파일을 이미지로 만들어서 실행한다.

$ cat httpd.tar | docker image import - test_image:v1.1
$ docker images
REPOSITORY    TAG       IMAGE ID       CREATED              SIZE
test_image    v1.1      55884d1eafbc   About a minute ago   142MB

tar파일을 표준 출력으로 넘겨서, docker image import를 사용하는 방식이다.
만들어진 이미지가 컨테이너로 실행 되는지 확인한다.

$ docker run -d --name test_image2 test_image:v1.1
docker: Error response from daemon: No command specified.

오… 안 된다.

오류 원인은 컨테이너 실행 시 command를 지정하지 않았기 때문이다.
컨테이너 실행 시 httpd 를 띄우는 커맨드를 뒤에 붙여서 확인해보자.

$ docker run --name test_image2 -d test_image:v1.1 /usr/local/apache2/bin/httpd -DFOREGROUND
#실행이 되었으면, apache 컨테이너의 ip 정보를 확인해서 접속 가능한지 확인한다
$ docker continer inspect test_image2 | grep 172
            "Gateway": "172.17.0.1",
            "IPAddress": "172.17.0.5",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.5",
$ curl http://172.17.0.5
<html><body><h1>It works!</h1></body></html>

정상적으로 동작하는 것을 확인하였다.

dockear image save

docker image 를 save 하는 방법이다.

$ docker image save -o mysql.tar mysql:5.7

저장된 docker 의 tar 파일로 부터 docker 이미지를 읽을 때는 아래와 같이 실행한다.

$ docker image load -i mysql.tar

06. Docker image 생성 : Dockerfile

주 사용 명령어

추후 정리 예정

Dockerfile 내 커맨드 예제

FROM, RUN

FROM으로는 베이스 이미지를 설정하고, RUN은 이미지 빌드 시 실행되는 명령어를 입력하는 부분이다.
예를 들어, CentOs8을 베이스 이미지로 사용하는 어떤 이미지를 아래와 같이 만들 수 있다.

FROM centos:8
RUN cal
RUN touch /tmp/test.txt
RUN touch /var/test2.txt
CMD sleep 500s

작성 후, Dockerfile이 존재하는 위치에서아래 명령어로 빌드한다.

#'t'는 tag이다
$ docker build -t sample .  
[+] Building 4.4s (8/8) FINISHED                                                        
 => [internal] load .dockerignore                                                  0.2s
 => => transferring context: 2B                                                    0.0s
 => [internal] load build definition from Dockerfile                               0.2s
 => => transferring dockerfile: 202B                                               0.0s
 => [internal] load metadata for docker.io/library/centos:8                        0.0s
 => [1/4] FROM docker.io/library/centos:8                                          0.0s
 => [2/4] RUN cal                                                                  2.2s
 => [3/4] RUN touch /tmp/test.txt                                                  0.8s
 => [4/4] RUN touch /var/test2.txt                                                 0.8s
 => exporting to image                                                             0.2s
 => => exporting layers                                                            0.2s
 => => writing image sha256:4d422c5e3d5a38356aa19fc11333126d91be7ac4a75ba3f0d39c4  0.0s
 => => naming to docker.io/library/sample
$ docker images
REPOSITORY    TAG       IMAGE ID       CREATED              SIZE
sample        latest    4d422c5e3d5a   About a minute ago   231MB

성공적으로 빌드된 것을 확인될 수 있다.

ENTRYPOINT, CMD

ENTRYPOINT, CMD는 빌드될 때 가장 마지막에 있는 하나만 Command로 실행이 된다.
단 ENTRYPOINT와 CMD는 각각 한 번씩 사용 가능하며, 이 경우 CMD가 ENTRYPOINT의 인수로 들어간다.

# CentOS 8 Images
FROM centos:8
RUN cal
RUN touch /tmp/test.txt
RUN touch /var/test2.txt

ENTRYPOINT cal
CMD 05 2023

과연 위와 같이 실행하면 “cal”에 대해 “05 2023” 변수가 들어갈까?

$ docker build -t sample .
[+] Building 0.1s (8/8) FINISHED                                           
 => [internal] load build definition from Dockerfile                  0.0s
 => => transferring dockerfile: 213B                                  0.0s
 => [internal] load .dockerignore                                     0.1s
 => => transferring context: 2B                                       0.0s
 => [internal] load metadata for docker.io/library/centos:8           0.0s
 => [1/4] FROM docker.io/library/centos:8                             0.0s
 => CACHED [2/4] RUN cal                                              0.0s
 => CACHED [3/4] RUN touch /tmp/test.txt                              0.0s
 => CACHED [4/4] RUN touch /var/test2.txt                             0.0s
 => exporting to image                                                0.0s
 => => exporting layers                                               0.0s
 => => writing image sha256:0f449c9acced44a57604b9e4559dfcd069c89a6d  0.0s
 => => naming to docker.io/library/sample                             0.0s
 $ docker run sample
     April 2023     
Su Mo Tu We Th Fr Sa
                   1
 2  3  4  5  6  7  8
 9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30                  

되지 않았다… 이유를 알아보자

$ /bin/sh -c cal 05 2023
     April 2023     
Su Mo Tu We Th Fr Sa
                   1
 2  3  4  5  6  7  8
 9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30

shell 형식으로 ENTRYPOINT와 CMD에 실행할 명령어를 주었더니, 마치 /bin/sh로 ‘cal’만 실행하는 것과 같은 결과를 얻은 것이다.

# CentOS 8 Images
FROM centos:8
RUN cal
RUN touch /tmp/test.txt
RUN touch /var/test2.txt

ENTRYPOINT ["cal"]
CMD ["05","2023"]
$ docker build -t sample .
[+] Building 0.1s (8/8) FINISHED                                            
 => [internal] load build definition from Dockerfile                   0.0s
 => => transferring dockerfile: 223B                                   0.0s
 => [internal] load .dockerignore                                      0.1s
 => => transferring context: 2B                                        0.0s
 => [internal] load metadata for docker.io/library/centos:8            0.0s
 => [1/4] FROM docker.io/library/centos:8                              0.0s
 => CACHED [2/4] RUN cal                                               0.0s
 => CACHED [3/4] RUN touch /tmp/test.txt                               0.0s
 => CACHED [4/4] RUN touch /var/test2.txt                              0.0s
 => exporting to image                                                 0.0s
 => => exporting layers                                                0.0s
 => => writing image sha256:f9471e0d469de730ac1ea42193bf1c1e91191e367  0.0s
 => => naming to docker.io/library/sample          
$ docker run sample
      May 2023      
Su Mo Tu We Th Fr Sa
    1  2  3  4  5  6
 7  8  9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31         

이제 원하던 결과를 얻었다.
CMD에 들어간 인자는 docker 컨테이너 실행 시 변경 가능하다.

$ docker run sample 07 2023
      July 2023     
Su Mo Tu We Th Fr Sa
                   1
 2  3  4  5  6  7  8
 9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31               

Dockerfile 내에 ENTRYPOINT [“cal”,”05”,”2023”]으로 작성해도 동일한 결과를 얻었을 테지만, 그런 경우에는 docker run 시에 다른 변수를 커맨드로 줄 수 없다.

ENTRYPOINT 내에 반드시 shell 형식으로 적어줘야 하는 명령어도 존재한다.
예를 들어 아래와 같은 경우이다.

# CentOS 8 Images
FROM centos:8
RUN cal
RUN touch /tmp/test.txt
RUN touch /var/test2.txt

#ENTRYPOINT ["cal"]
#CMD ["05","2023"]
ENTRYPOINT ps -e | head -n 2
$ docker build -t sample .
[+] Building 0.1s (8/8) FINISHED                                            
 => [internal] load build definition from Dockerfile                   0.1s
 => => transferring dockerfile: 256B                                   0.0s
 => [internal] load .dockerignore                                      0.0s
 => => transferring context: 2B                                        0.0s
 => [internal] load metadata for docker.io/library/centos:8            0.0s
 => [1/4] FROM docker.io/library/centos:8                              0.0s
 => CACHED [2/4] RUN cal                                               0.0s
 => CACHED [3/4] RUN touch /tmp/test.txt                               0.0s
 => CACHED [4/4] RUN touch /var/test2.txt                              0.0s
 => exporting to image                                                 0.0s
 => => exporting layers                                                0.0s
 => => writing image sha256:a6c4a269a1b30c9b1141bb4fc77ab419d2ee12dfd  0.0s
 => => naming to docker.io/library/sample   
$ docker run sample
  PID TTY          TIME CMD
    1 ?        00:00:00 sh
LABEL, ONBUILD

또, Dockerfile 내에 LABLE 지정 시 관리자, 이름 등을 지정할 수 있다.

ONBUILD 를 쓰면, 해당 Dockerfile 로 생성한 이미지를 베이스 이미지로 한 다른 Dockerfile을 빌드할 때 실행할 명령을 기술할 수 있다.

FROM ubuntu:18.04
RUN apt-get update \
    && apt-get install -y nginx
ONBUILD ADD ./src/website.tar  /var/www/html
CMD ["nginx","-g","daemon off;"]
$ docker build -t mynginx -f nginx_dockerfile .
#그냥 실행해본다. 이때는 ONBUILD에 정의한 website.tar이 보이지 않는다.
$ docker run -d -name=mynginx mynginx:latest

위에서 빌드한 mynginx 이미지를 베이스로 사용하여 다시 빌드한다.

FROM myngix

이제 ONBUILD에 정의한 website를 확인 가능하다.

차주에는 …

  • Docker-compose
  • 쿠버네티스 시작 (VM 이미지는 미리 올라올 예정으로, 예습 필요)