회사 기술블로그에 작성한 내용입니다.
안녕하세요 오픈소스컨설팅 한철희 과장입니다.
이번에는 개발자, 시스템 운영자 등등 IT 업계에 계신다면 많이 들어본 Docker 에 대해 포스팅 해보려고 합니다.
Docker 의 기초적인 내용부터 활용까지 알아보도록 하겠습니다.
이미지 출처 : flickr
위 사진을 보면 항구에 정박되있는 배가 있습니다. 해외 수출, 수입을 위해 많은 컨테이너를 적재한 모습입니다.
위키백과에서는 컨테이너를 이렇게 정의 하고 있습니다.
재미있게도 지금부터 알아볼 컨테이너의 기술은 위키백과에 설명된 내용과 비슷합니다!
Container 란?
컨테이너란 어플리케이션이 동작하기 위해서 필요한 요소(실행 파일, 어플리케이션 엔진등) 을 패키지화하고 격리 하는 기술을 말합니다.
이를 통해 전체 인프라를 쉽고 빠르게 관리 할 수 있게 됩니다.
아래 동영상은 컨테이너에 대해 쉽게 설명된 동영상입니다.
(자막이 포함되어 있습니다!)
출처 : RedHat Videos
Container 의 작동 원리
컨테이너는 Cgroup 와 namespace 와 같은 커널 기반의 기술을 이용해서 프로세스를 완벽하게 격리하여 분리된 환경을 만들고 실행하도록 만듭니다.
컨테이너의 사용법을 알기전에 Cgroup 과 namespace에 대해 먼저 보도록 하겠습니다.
Cgroup
Cgroup 이란 Control Group 의 약자로, 시스템의 CPU 시간, 시스템 메모리, 네트워크 대역폭과 같은 자원을 제한하고 격리 할 수 있는 커널 기능입니다.
" CentOS 7 - Cgroup 내용" # /sys/fs/cgroup # ls -la 합계 0 drwxr-xr-x 13 root root 340 7월 6 23:23 . drwxr-xr-x 5 root root 0 7월 6 23:23 .. drwxr-xr-x 5 root root 0 7월 6 23:23 blkio lrwxrwxrwx 1 root root 11 7월 6 23:23 cpu -> cpu,cpuacct drwxr-xr-x 5 root root 0 7월 6 23:23 cpu,cpuacct lrwxrwxrwx 1 root root 11 7월 6 23:23 cpuacct -> cpu,cpuacct drwxr-xr-x 3 root root 0 7월 6 23:23 cpuset drwxr-xr-x 5 root root 0 7월 6 23:23 devices drwxr-xr-x 3 root root 0 7월 6 23:23 freezer drwxr-xr-x 3 root root 0 7월 6 23:23 hugetlb drwxr-xr-x 5 root root 0 7월 6 23:23 memory lrwxrwxrwx 1 root root 16 7월 6 23:23 net_cls -> net_cls,net_prio drwxr-xr-x 3 root root 0 7월 6 23:23 net_cls,net_prio lrwxrwxrwx 1 root root 16 7월 6 23:23 net_prio -> net_cls,net_prio drwxr-xr-x 3 root root 0 7월 6 23:23 perf_event drwxr-xr-x 3 root root 0 7월 6 23:23 pids drwxr-xr-x 5 root root 0 7월 6 23:23 systemd
위 내용을 보면 Cgroup은 많은 시스템 자원을 제한하고 격리를 할 수 있습니다.
해당 서브시스템에 대한 설명은 아래와 같습니다.
서브시스템 | 설 명 |
---|---|
blkio |
Block Device 의 입출력 접근 제한 |
cpu |
CPU에 cgroup 작업 액세스를 제공하기 위해 스케줄러 |
cpuacct |
cgroup의 작업에 사용된 CPU 자원에 대한 보고서를 자동으로 생성 |
cpuset |
개별 CPU (멀티코어 시스템에서) 및 메모리 노드를 cgroup의 작업에 할당 |
devices | cgroup의 작업 단위로 장치에 대한 액세스를 허용하거나 거부 |
freezer | cgroup의 작업을 일시 중지하거나 다시 시작 |
net_cls | 특정 cgroup에서 발생하는 패킷을 식별하기 위해 태그를 지정 |
net_prio | cgroup의 작업에서 생성되는 네트워크 트래픽의 우선순위 지정 |
memory | cgroup의 작업에서 사용되는 메모리에 대한 제한을 설정 |
cgroup를 쉽게 이해하기 위해서 devices 서브시스템 자원을 제한하는 것을 보여드리겠습니다.
# cd /sys/fs/cgroup/devices # mkdir shell # cd shell/ # ls cgroup.clone_children cgroup.procs devices.deny notify_on_release cgroup.event_control devices.allow devices.list tasks # cat tasks # cat devices.list a *:* rwm " 모든 권한 활성화 " # cat tasks # " 다른 세션 PID: 8403 을 cgroup으로 지정 " # echo "8403" > tasks # cat tasks 8403 # echo "cgroup test \ > Hello Cgroup! \ > end" > /dev/pts/2 #
# echo $$ 8403 # w 15:24:14 up 54 days, 16:00, 4 users, load average: 0.00, 0.01, 0.05 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT root tty1 06 7월18 16days 0.04s 0.04s -bash root pts/0 192.168.0.83 14:38 14.00s 0.04s 0.02s ssh root@192.168.13.131 root pts/2 192.168.0.83 15:24 4.00s 0.00s 0.00s w root pts/3 192.168.13.131 15:23 14.00s 0.01s 0.01s -bash # cgroup test Hello Cgroup! end
위와 같이 pid : 8403 세션에 echo 명령으로 넣은 내용이 나오는 것을 보실 수 있습니다.
Cgroup을 이용해서 시스템 자원을 제한 해보도록 하겠습니다.
# echo "a *:* rwm" > devices.deny
pid : 8403 세선에 모든 장치에 대해 deny 하는 내용을 선언 합니다.
# echo $$ 8403 # echo "Dent test" > /dev/pts/2 -bash: /dev/pts/2: 명령을 허용하지 않음 # echo "Dent test" > /dev/pts/2 -bash: /dev/pts/2: 명령을 허용하지 않음
위와 같이 pid : 8403 세션에 대해 모든 장치 가 deny 된 것을 확인 할 수 있습니다.
이처럼 프로세스의 장치를 제한하고 격리하는 것이 바로 Cgroup 입니다.
namespace
namespace 란, 시스템 리소스를 프로세스의 전용 자원처럼 보이게 하고, 다른 프로세스와 격리시키는 기능입니다.
namespace 에는 총 6가지 namespace 가 있습니다.
- Mount namespacaes : 파일시스템의 Mount 를 분할하고 격리합니다.
- PID namespacaes : 프로세스를 분할 관리합니다.
- Network namespacaes : Network 관련된 정보를 분할 관리합니다.
- IPC namespacaes : 프로세스간 통신을 격리합니다.
- UTS namespacaes : 독립적인 hostname 할당합니다
- USER namespacaes : 독립적인 UID를 할당합니다.
이와 같이 namespace 를 이용하여 각 프로세스를 격리 할 수 있습니다.
간단하게 Mount namespaces 를 통해 namespace에 대해 알아보겠습니다.
# echo $$ 6467 # mkdir /imsi # ls -la /proc/6467/ns/mnt lrwxrwxrwx 1 root root 0 8월 30 16:48 /proc/6467/ns/mnt -> mnt:[4026531840] "신규 Mount Namespace 생성" # unshare -m /bin/bash # echo $$ 6523 # mount -t tmpfs tmpfs /imsi # mount | grep imsi tmpfs on /imsi type tmpfs (rw,relatime) # df | grep imsi tmpfs 1941000 0 1941000 0% /imsi # ls -la /proc/6523/ns/mnt lrwxrwxrwx 1 root root 0 8월 30 16:50 /proc/6523/ns/mnt -> mnt:[4026532457] " 다른 세션에서 Mount 확인 " # echo $$ 21889 # mount | grep imsi # df | grep imsi
namespace 를 통해 프로세스가 시스템 자원을 전용으로 사용하는것을 확인 할 수 있습니다.
이처럼 컨테이너는 Cgroup 와 namespace 의 기술을 이용한 프로세스 격리 기술입니다.
이를 이용하여 프로세스별로 각각의 가상머신을 운영하는 것과 같은 격리 효과를 볼 수 있는 것입니다.
이것이 바로 컨테이너 입니다!!!
그럼 Docker 는 뭔가요!?
Docker 란, 리눅스 컨테이너 기술을 기반으로 하는 오픈 소스 소프트웨어 플랫폼입니다.
로고를 보면 마치 항구에서 컨테이너를 관리하는 것처럼 Docker는 컨테이너를 환경에 구애받지 않고 애플리케이션을 신속하게 배포 및 확장 있는 플랫폼입니다.
컨테이너에서도 잠깐 설명한것처럼 Docker 는 가상화 환경과 비교를 많이하는데
위 비교 자료 및 성능 자료는 기존에 포스팅된 내용 참고 하시면 됩니다.
이렇게 좋은 Docker 한번 설치해보겠습니다.
Docker 설치
Test Information
Test OS 정보 : CentOS Linux release 7.5.1804 (Core)
Docker Install Version : docker-ce-18.06.1.ce-3.el7
Install Repository
docker-ce Yum Repository를 등록합니다.
# wget https://download.docker.com/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo # yum repolist
Install docker-ce
docker-ce 를 설치합니다.
# yum install docker-ce
docker 서비스 시작
docker 서비스 시작 합니다.
# systemctl enable docker;systemctl start docker
docker 서비스 확인
docker 가 정상적으로 설치가 되고 문제없이 사용이 가능한지 확인합니다.
" docker 컨테이너 확인 " # docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES " docker 컨테이너 실행 " # docker run hello-world Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world 9db2ca6ccae0: Pull complete Digest: sha256:4b8ff392a12ed9ea17784bd3c9a8b1fa3299cac44aca35a85c90c5e3c7afacdc Status: Downloaded newer image for hello-world:latest Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://hub.docker.com/ For more examples and ideas, visit: https://docs.docker.com/engine/userguide/ " dockerd 정보 " # docker info Containers: 1 Running: 0 Paused: 0 Stopped: 1 Images: 1 Server Version: 18.06.1-ce Storage Driver: overlay2 Backing Filesystem: xfs Supports d_type: true Native Overlay Diff: true Logging Driver: json-file Cgroup Driver: cgroupfs Plugins: Volume: local Network: bridge host macvlan null overlay Log: awslogs fluentd gcplogs gelf journald json-file logentries splunk syslog Swarm: inactive Runtimes: runc Default Runtime: runc Init Binary: docker-init containerd version: 468a545b9edcd5932818eb9de8e72413e616e86e runc version: 69663f0bd4b60df09991c08812a60108003fa340 init version: fec3683 Security Options: seccomp Profile: default Kernel Version: 3.10.0-693.el7.x86_64 Operating System: CentOS Linux 7 (Core) OSType: linux Architecture: x86_64 CPUs: 2 Total Memory: 3.702GiB Name: container.local ID: FC6G:U5RT:3F6H:4KTL:MX7I:7NND:F42S:FYXI:OFH2:XDSE:DFFC:Z6F2 Docker Root Dir: /var/lib/docker Debug Mode (client): false Debug Mode (server): false Registry: https://index.docker.io/v1/ Labels: Experimental: false Insecure Registries: 127.0.0.0/8 Live Restore Enabled: false
Docker Command
docker 사용을 위해 기본적인 명령어들을 알아보겠습니다.
1) List containers
현재 활성화되거나 중지된 컨테이너 목록을 보는 명령어입니다.
컨테이너의 상태 및 가동 시간등을 보여줍니다.
# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
032759e31d4c hello-world "/hello" 10 days ago Exited (0) 10 days ago jovial_lovelace
2) List images
Local 에 저장된 image 목록을 보여줍니다.
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest 2cb0d9787c4d 2 months ago 1.85kB
3) Pull image
Public Repository 혹은 Private Repository에 있는 container image 를 Local 로 pull 합니다. ( 일종의 다운로드 )
# docker pull [OPTIONS] NAME[:TAG|@DIGEST]
# docker pull httpd "pull http image "
Using default tag: latest
latest: Pulling from library/httpd
f189db1b88b3: Pull complete
ba2d31d4e2e7: Pull complete
23a65f5e3746: Pull complete
5e8eccbd4bc6: Pull complete
4c145eec18d8: Pull complete
1c74ffd6a8a2: Pull complete
1421f0320e1b: Pull complete
Digest: sha256:8631904c6e92918b6c7dd82b72512714e7fbc3f1a1ace2de17cb2746c401b8fb
Status: Downloaded newer image for httpd:latest
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
httpd latest d595a4011ae3 5 days ago 178MB
han0495/hello-world latest 2cb0d9787c4d 2 months ago 1.85kB
hello-world latest 2cb0d9787c4d 2 months ago 1.85kB
4) Push images
Local 에 있는 container image 를 Public Repository 혹은 Private Repository 로 push 합니다. ( 일종의 업로드 )
# docker push [OPTIONS] NAME[:TAG]
# docker push han0495/hello-world
The push refers to repository [
docker.io/han0495/hello-world
]
ee83fc5847cb: Mounted from library/hello-world
latest: digest: sha256:aca41a608e5eb015f1ec6755f490f3be26b48010b178e78c00eac21ffbe246f1 size: 524
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
han0495/hello-world latest 2cb0d9787c4d 2 months ago 1.85kB
hello-world latest 2cb0d9787c4d 2 months ago 1.85kB
위와 같이 docker hub 의 Public Repository 로 push 된 것을 확인 할 수 있습니다.
5) Tag image
Container image 에 태그를 작성합니다.
# docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
# docker tag hello-world han0495/hello-world
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
han0495/hello-world latest 2cb0d9787c4d 2 months ago 1.85kB
hello-world latest 2cb0d9787c4d 2 months ago 1.85kB
6) Container 실행
Container 를 실행 하는 명령 입니다.
# docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
# docker run httpd
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
[Mon Sep 10 06:43:19.002515 2018] [mpm_event:notice] [pid 1:tid 140466418673536] AH00489: Apache/2.4.34 (Unix) configured -- resuming normal operations
[Mon Sep 10 06:43:19.002612 2018] [core:notice] [pid 1:tid 140466418673536] AH00094: Command line: 'httpd -D FOREGROUND'
7) Container 제거
현재 실행 중이거나 실행이 종료된 Container 를 제거하는 명령 입니다.
현재 실행 중인 Container 를 강제로 제거 하기 위해서는 -f 옵션을 사용합니다.
# docker rm [OPTIONS] CONTAINER [CONTAINER...]
# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c89632a2eede httpd "httpd-foreground" 2 minutes ago Exited (0) 2 minutes ago fervent_wiles
032759e31d4c hello-world "/hello" 10 days ago Exited (0) 10 days ago jovial_lovelace
# docker rm c89632a2eede
c89632a2eede
# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
032759e31d4c hello-world "/hello" 10 days ago Exited (0) 10 days ago jovial_lovelace
8) Containers Image 삭제
Local 에 저장된 Container Image 를 삭제합니다.
# docker rmi [OPTIONS] IMAGE [IMAGE...]
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
httpd latest d595a4011ae3 5 days ago 178MB
hello-world latest 2cb0d9787c4d 2 months ago 1.85kB
han0495/hello-world latest 2cb0d9787c4d 2 months ago 1.85kB
# docker rmi hello-world
Untagged: hello-world:latest
Untagged: hello-world@sha256:4b8ff392a12ed9ea17784bd3c9a8b1fa3299cac44aca35a85c90c5e3c7afacdc
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
httpd latest d595a4011ae3 5 days ago 178MB
han0495/hello-world latest 2cb0d9787c4d 2 months ago 1.85kB
이처럼 Docker 에서 사용되는 기본적인 명령들을 확인하였습니다.
추가적인 명령들은 아래 문서를 참고합니다.
( https://docs.docker.com/engine/reference/commandline/cli/ )
Docker를 이용해서 Web 서비스를 실행해보자!
위 명령어 예제에서 httpd image 를 이용하여 contanier를 실행하는 예제를 보여드렸습니다.
그런데 container 만 작동된다고 Web 서비스가 구동되는 것은 아니죠!
docker 를 이용해서 Web 서비스를 해보도록 하겠습니다.
먼저, httpd container image 를 pull 합니다.
# docker pull httpd Using default tag: latest latest: Pulling from library/httpd Digest: sha256:8631904c6e92918b6c7dd82b72512714e7fbc3f1a1ace2de17cb2746c401b8fb Status: Image is up to date for httpd:latest # docker images REPOSITORY TAG IMAGE ID CREATED SIZE httpd latest d595a4011ae3 5 days ago 178MB han0495/hello-world latest 2cb0d9787c4d 2 months ago 1.85kB
http container 를 위에서 배운것처럼 실행해봅니다.
Container 가 Foreground 로 작동하면서 Shell 을 사용을 못할 뿐더러, Shell 이 종료가 되면 httpd Container 도 중지가 됩니다.
위와 같이 되면, 전혀 서비스에 적용 할 수가 없습니다.
그리하여 아래와 같이 background 로 container 를 실행하면 됩니다.
# docker run -d httpd 3c9764e9b79a058b0dedda07312679d6cafc0779c3e66ae04d9d1034a2b29ee1 # docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3c9764e9b79a httpd "httpd-foreground" 11 seconds ago Up 10 seconds 80/tcp stupefied_rama
위와 같이 Shell 에서 다른 명령도 가능하고 서비스가 계속 실행되는 것을 확인 할 수 있습니다.
그럼 실제로 서비스가 작동하는지 확인해 보겠습니다.
# curl http://127.0.0.1 curl: (7) Failed connect to 127.0.0.1; 연결이 거부됨
서비스가 안되고 있습니다! 이유가 뭘까요?
현재 container 가 어떤 상황인지 이해 하시면 왜 네트워크가 안되는지 이해가 쉽습니다.
위에 도식화된 내용은 Host OS 위에 docker 엔진이 설치가 되고 container 들의 네트워크가 어떤식으로 연결되어 있는지 쉽게 볼 수 있습니다.
지금 보면 HTTP 는 Host Network 와 연결이 안되어 있습니다. 이러면 docker 내부에서 container 간 통신은 되지만 docker 외부와 통신이 불가능합니다. 그래서 외부 서비스가 안되는 것입니다.
그럼 서비스가 되기 위해서는 아래와 같은 연결이 필요합니다. 그 연결은 port mapping 을 통해 진행합니다.
그리하면 위와 같은 구성이 될 것입니다. 실제로 적용해보겠습니다.
# docker stop 3c9764e9b79a " 기존에 실행중이던 docker 중지 " 3c9764e9b79a # docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3c9764e9b79a httpd "httpd-foreground" 18 minutes ago Exited (0) 3 seconds ago stupefied_raman # docker run -d -p 80:80 httpd dee5fb60c083564d6095b1b9811b3e634c017caf9788f5fce57a0dcb309e4e76 # docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES dee5fb60c083 httpd "httpd-foreground" 3 seconds ago Up 2 seconds 0.0.0.0:80->80/tcp goofy_sammet 3c9764e9b79a httpd "httpd-foreground" 19 minutes ago Exited (0) 18 seconds ago stupefied_raman # curl http://127.0.0.1 <html><body><h1>It works!</h1></body></html>
위와 같이 포트 80 을 통해 외부로 서비스를 하는 것을 확인 할 수 있습니다.
웹 브라우져에서 확인해보겠습니다.
이렇게 쉽게 Web 서비스를 구성 할 수 있습니다.
하지만 이런 Web Page 를 쓸수는 없습니다. Web Page 를 바꿔보겠습니다.
# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES dee5fb60c083 httpd "httpd-foreground" 3 seconds ago Up 2 seconds 0.0.0.0:80->80/tcp goofy_sammet 3c9764e9b79a httpd "httpd-foreground" 19 minutes ago Exited (0) 18 seconds ago stupefied_raman # docker exec -ti dee5fb60c083 /bin/bash "container 내부로 들어가서 http index.html 을 수정합니다." root@dee5fb60c083:/usr/local/apache2# root@dee5fb60c083:/usr/local/apache2# ls bin build cgi-bin conf error htdocs icons include logs modules root@dee5fb60c083:/usr/local/apache2# cd htdocs/ root@dee5fb60c083:/usr/local/apache2/htdocs# ls index.html root@dee5fb60c083:/usr/local/apache2/htdocs# cat index.html <html><body><h1>It works!</h1></body></html> root@dee5fb60c083:/usr/local/apache2/htdocs# echo "<html><body><h1>Docker Test Page</h1></body></html>" > index.html root@dee5fb60c083:/usr/local/apache2/htdocs# cat index.html <html><body><h1>Docker Test Page</h1></body></html> root@dee5fb60c083:/usr/local/apache2/htdocs# exit exit # curl http://192.168.13.131 <html><body><h1>Docker Test Page</h1></body></html>
이처럼 container 내부의 index.html 을 수정하면 Web Page를 변경 할 수 있습니다.
그럼 이제 완벽하게 Web 서비스를 할 수 있게 되었습니다.
하지만 이런 방식은 운영자 입장에서 보면 container 가 종료가 되거나, 삭제가 되면 매번 container를 실행하기 위해 Port 를 결정해서 입력해야되고, 수정된 index 파일을 다시 수정해야됩니다.
또한 운영하면서 발생한 로그 및 기타 증분 데이터는 container 가 종료가 되면 전부 삭제가 됩니다.
이런 귀차니즘을 해결하기 위해서
두가지의 방법을 적용해야 합니다.
바로
DockerFile
Docker-compose
입니다.
DockerFile 이란?
DockerFile 이란, 나만의 Container image를 Build 할 수 있게 해주는 Docker image 파일 입니다.
Docker Hub 에 없는 이미지도 DockerFile 을 이용하면 특별한 image 도 생성 할 수 있습니다.
# cat dockerfile FROM httpd:latest MAINTAINER chhan <chhan@osci.kr> RUN echo "<html><body><h1>Docker File Test Page</h1></body></html>" > /usr/local/apache2/htdocs/index.html EXPOSE 80
간단히 위에 사용된 구문에 대해 설명하겠습니다.
- FROM
Docker Hub 에서 어떤 이미지를 가지고와서 작업할지 선언합니다. 작성법은 <이미지명>:<태그> 로 작성합니다.
- MAINTAINER
DockerFile 제작한 사람의 정보를 기입합니다.
- RUN
docker image 가 실행되고 container 내에서 실행될 명령어입니다.
해당 내용은 적으면 적을수록 container label 이 적게 생성되어 image 를 compact 하게 생성 할 수 있습니다.
- EXPOSE
Host 에 연결될 Port를 지정합니다.
위와 같은 DockerFile 구문을 자세히 확인하려면 아래 문서를 참고하시면 됩니다.
( https://docs.docker.com/engine/reference/builder/ )
그럼 작성한 DockerFile 을 Build 하고 실행해 보겠습니다.
# pwd /root/http # ls dockerfile # docker build -t myhttpd . Sending build context to Docker daemon 2.048kB Step 1/4 : FROM httpd:latest ---> d595a4011ae3 Step 2/4 : MAINTAINER chhan <chhan@osci.kr> ---> Running in 176d94e63272 Removing intermediate container 176d94e63272 ---> 282d30eba8fe Step 3/4 : RUN echo "<html><body><h1>Docker File Test Page</h1></body></html>" > /usr/local/apache2/htdocs/index.html ---> Running in 2f16f1ef9d1c Removing intermediate container 2f16f1ef9d1c ---> df135d6e6dbd Step 4/4 : EXPOSE 80 ---> Running in 12cdc41b8546 Removing intermediate container 12cdc41b8546 ---> 52c07f2bfb38 Successfully built 52c07f2bfb38 Successfully tagged myhttpd:latest # docker images REPOSITORY TAG IMAGE ID CREATED SIZE myhttpd latest 52c07f2bfb38 3 seconds ago 178MB httpd latest d595a4011ae3 5 days ago 178MB han0495/hello-world latest 2cb0d9787c4d 2 months ago 1.85kB # docker run -d -p 80:80 --name=myweb myhttpd 1afd260265923828f88eeae9bc7083985b66eef2d9c588d35ee08e05198470a0 # docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1afd26026592 myhttpd "httpd-foreground" 5 seconds ago Up 5 seconds 0.0.0.0:80->80/tcp myweb # curl http://192.168.13.131 <html><body><h1>Docker File Test Page</h1></body></html>
이처럼 DockerFile 을 통해 작성한 container image 를 통해 매번 index File 이 수정된 Web 서비스를 실행 할 수 있습니다.
docker-compose 로 Container 통합 관리
docker-compose 란, 한번에 여러개의 container 을 통합 관리 할 수 있게 하는 툴입니다.
주로 서비스는 하나만으로 작동하는 것은 없습니다.
예를 들면
wordpress 같은 것이 있습니다.
DB 서비스와
wordpress
서비스가 동시에 실행되고 서로 연결되어 있습니다.
위와 같은 서비스를 편하게 통합 관리하기 위해 docker-compose 를 사용하는 것입니다.
그럼 docker-compose 를 사용해보겠습니다.
docker-compose 설치
아래와 같이 docker-compose 명령어를 설치해야합니다.
# curl -L "https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 617 0 617 0 0 558 0 --:--:-- 0:00:01 --:--:-- 559 100 11.2M 100 11.2M 0 0 2186k 0 0:00:05 0:00:05 --:--:-- 3668k # chmod +x /usr/local/bin/docker-compose # ls -l /usr/local/bin/docker-compose -rwxr-xr-x 1 root root 11750136 9월 10 17:26 /usr/local/bin/docker-compose # docker-compose --version docker-compose version 1.22.0, build f46880fe
docker-compose 사용법
아래 예제는 DB 서비스와 wordpress 서비스를 구동하는 docker-compose 파일입니다.
해당 docker-compose.yml 을 이용해서 wordpress 서비스를 구동해 보겠습니다.
version: '3.3' services: db: image: mysql:5.7 volumes: - /var/lib/mysql:/var/lib/mysql restart: always environment: MYSQL_ROOT_PASSWORD: passwordpress MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpress wordpress: depends_on: - db image: wordpress:latest ports: - "8000:80" restart: always environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: wordpress
* 위 예제는 docker docs 에서 발췌 했습니다. ( https://docs.docker.com/compose/overview/ )
* docker-compose 에 선언되는 각각의 environment는 아래 URL과 같이 docker docs 에서 확인이 가능합니다.
( https://docs.docker.com/samples/library/mysql/ )
이제 위 docker-compose.yml 을 실행해보겠습니다.
# docker-compose -f docker-compose.yml up -d(-f [File] , -d background 실행)
# ls -la /root/wordpress/docker-compose.yml -rw-r--r-- 1 root root 537 9월 10 17:35 /root/wordpress/docker-compose.yml # docker-compose -f docker-compose.yml up -d Creating network "wordpress_default" with the default driver Pulling db (mysql:5.7)... 5.7: Pulling from library/mysql 802b00ed6f79: Pull complete 30f19a05b898: Pull complete 3e43303be5e9: Pull complete 94b281824ae2: Pull complete 51eb397095b1: Pull complete 54567da6fdf0: Pull complete bc57ddb85cce: Pull complete c7c0a9c25d8a: Pull complete cce6c47ac3fc: Pull complete 499b9c7376c8: Pull complete 6c5e08e005ea: Pull complete Digest: sha256:1d8f471c7e2929ee1e2bfbc1d16fc8afccd2e070afed24805487e726ce601a6d Status: Downloaded newer image for mysql:5.7 Pulling wordpress (wordpress:latest)... latest: Pulling from library/wordpress 802b00ed6f79: Already exists 59f5a5a895f8: Pull complete 6898b2dbcfeb: Pull complete 8e0903aaa47e: Pull complete 2961af1e196a: Pull complete 71f7016f79a0: Pull complete 5e1a48e5719c: Pull complete 7ae5291984f3: Pull complete 725b65166f31: Pull complete 3823a607a5d4: Pull complete 1bcfa4198e39: Pull complete f1c79da21110: Pull complete 18903f439956: Pull complete 5eda25fffde3: Pull complete 3800dac98824: Pull complete 951fbb644962: Pull complete 5b91123e33c5: Pull complete 71250bb070e7: Pull complete 0363e75875b5: Pull complete 3bcb3cbf244a: Pull complete Digest: sha256:e30aed2d17b33758544f0eaebee763a452b41ff5bc926d723566338b0137dd81 Status: Downloaded newer image for wordpress:latest Creating wordpress_db_1 ... done Creating wordpress_wordpress_1 ... done # docker-compose ps Name Command State Ports ------------------------------------------------------------------------------------- wordpress_db_1 docker-entrypoint.sh mysqld Up 3306/tcp, 33060/tcp wordpress_wordpress_1 docker-entrypoint.sh apach ... Up 0.0.0.0:8000->80/tcp [root@container wordpress]# docker-compose top wordpress_db_1 UID PID PPID C STIME TTY TIME CMD ------------------------------------------------------------- polkitd 10737 10716 0 17:41 ? 00:00:00 mysqld wordpress_wordpress_1 UID PID PPID C STIME TTY TIME CMD ------------------------------------------------------------------------ root 10997 10977 0 17:41 ? 00:00:00 apache2 -DFOREGROUND 33 14530 10997 0 17:41 ? 00:00:00 apache2 -DFOREGROUND 33 14531 10997 0 17:41 ? 00:00:00 apache2 -DFOREGROUND 33 14533 10997 0 17:41 ? 00:00:00 apache2 -DFOREGROUND 33 14534 10997 0 17:41 ? 00:00:00 apache2 -DFOREGROUND 33 14535 10997 0 17:41 ? 00:00:00 apache2 -DFOREGROUND
이처럼 명령어 한줄로 두 종류의 서비스를 한번에 실행 할 수 있었습니다.
정상적으로 서비스가 작동하는지 확인해볼까요?
정상적으로 실행된 것을 확인 할 수 있었습니다.
지금까지 배운 명령어를 통해 docker-compose 가 어떤 내용을 실행했는지 한번 더 확인해 보겠습니다.
# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 25c5e75bb07d wordpress:latest "docker-entrypoint.s…" 4 minutes ago Up 4 minutes 0.0.0.0:8000->80/tcp wordpress_wordpress_1 f52a5d2495e4 mysql:5.7 "docker-entrypoint.s…" 4 minutes ago Up 4 minutes 3306/tcp, 33060/tcp wordpress_db_1 # docker images REPOSITORY TAG IMAGE ID CREATED SIZE myhttpd latest 52c07f2bfb38 About an hour ago 178MB wordpress latest 63b422244491 2 days ago 409MB mysql 5.7 563a026a1511 5 days ago 372MB httpd latest d595a4011ae3 5 days ago 178MB han0495/hello-world latest 2cb0d9787c4d 2 months ago 1.85k
- Local 에 없던 image를 자동으로 Download 했습니다.
- docker container 를 실행했습니다.
- /var/lib/mysql 를 영구적 볼륨으로 할당하였습니다.
- docker 내부 포트를 외부 포트와 Mapping 하였습니다.
- container 를 순서대로 실행했습니다.
간단히 만든 docker-compose.yml 인데....
명령어 한줄인데....
많은 작업을 한번에 해줬습니다.
잘만든 docker-compose.yml ....
운영자들은 행복해합니다. ^ㅡ^
마치며
지금까지 docker 에 대한 기초부터 응용법까지 간단히 포스팅해보았습니다.
이 포스팅이 많은 운영자, 개발자, 엔지니어 분들이 도움이 되셨으면 합니다.
Docker 의 원리와 구조를 잘 이해하고, 고객사의 서비스 환경에 맞는 container 를 구성하여 쉽고 편한 운영을 할 수 있는 좋은 세상이 될 수 있었으면 합니다!!
참고 자료
docker : https://docs.docker.com/