Docker는 애플리케이션 영역에서 작동하는 가상화 플랫폼이다. 개발자와 시스템관리자는 docker를 이용해서 빠르고 쉽게 그들이 개발한 소프트웨어들을 격리된 운영체제 환경에서 테스트하고 배포할 수 있다.
물론 VM(가상머신)이라고 부르는 도구들을 이용해서 이런 일들을 할 수 있다. AWS와 같은 서비스를 이용한다면, (소프트웨어까지 모두 포함한)운영체제의 스냅샷을 떠서 배포할 수 있다. vagrant와 같은 가상화 기반 도구를 이용하면, 통합된 개발환경을 만들 수 있다.
실제 docker의 기본 개념의 기존의 가상화와 크게 다르지 않다. 단 접근방식에 있어 차이가 있다. 기존의 가상화라고 하면, 하드웨어와 그위에 올라가는 운영체제까지 한번에 띄우는 운영체제 가상화를 의미한다. 이런 방식의 가상화는 (기본적로 하드웨어+소프트웨어 조합이라서)이해하기가 쉽다는 장점과 (독립된 운영체제이기 때문에)격리가 매우 쉽다는 장점이 있다.
반면 단점도 있는데,
VM 방식의 경우 APM(Apache+PHP+Mysql)으로 구성된 간단한 웹서버를 배포하려면, 운영체제까지 전부 배포해야 한다. 3개의 소프트웨어와 약간의 하드디스크, 메모리 공간이 필요할 뿐인데, 운영체제를 모두 포함한 거대한 이미지를 배포해야 한다는 것은 상당한 낭비다. 운영체제를 실행하는 과정을 거쳐야 하기 때문에, 서비스 가동까지 꽤나 많은 시간이 걸리는 것도 단점이다.
도커는 하드웨어를 추상화하지 않는다. 운영체제의 자원을 모두 공유하며, 사실상 프로세스로 간주된다. 따라서 CPU, 메모리, 디스크 공간을 효율적으로 사용 할 수 있다. 운영체제를 가동할 필요가 없기 때문에, 매우 빨리 실행할 수 있다는 장점도 있다. 실제 실행해보면 일반 프로세스 실행하는 것과 별 차이가 없다.
그러면서도 가상화의 장점들인 네트워크, 디스크, 유저 격리를 할 수 있다. 사용자 입장에서는 컨테이너와 VM의 차이를 (거의)느낄 수 없다. 이런 도커의 특징은 특히 "애플리케이션의 서비스"에 아주 적합하다. Paas 혹은 Saas 애플리케이션의 개발과 배포에 유용하게 사용 할 수 있다.
컨테이너 vs VMs
Docker는 리눅스 컨테이너(Container) 시스템인 libcontainer
를 이용해서 하나의 운영체제위에서 격리된 컴퓨팅 환경을 운영할 수 있도록 도와주는 애플리케이션 레벨 가상화 소프트웨어다.
Docker는 AUFS라는 파일 시스템을 사용하는데, 읽기 전용 부분과 쓰기 부분이 따로 있고 이들을 병합할 수 있다. 해서 읽기 전용으로는 공통으로 배포되는 정보를 저장해서 다른 개발자들과 공유할 수 있다. 예를들어 Ruby on Rails 환경을 만들었다면, ROR은 읽기 전용 공간에 저장해서 다른 개발자들에게 배포한 후, 쓰기 공간을 이용해서 프로그래밍하는 식의 개발이 가능하다.
VM과 컨테이너 방식을 비교한 그림이다.
컨테이너 방식이 훨씬 효율적이라는 걸 예상할 수 있다. VM 보다 더 가볍고, 더 빠르고, 더 작은 공간만을 필요로 한다. 기본적으로 프로세스 단위로 작동하기 때문에, 수백개이상의 컨테이너를 별 어려움 없이 돌릴 수 있다. Full virtualized 방식의 가상화 시스템에서 VM을 실행하려면, 수분의 시간이 걸린다. 컨테이너 방식에서는 (운영체제가 올라오는게 아니기 때문에)수 초면 된다.
Dock 이미지 관리
한장의 그림으로 Dock 이미지 관리를 설명할 수 있다.
Docker Public Registery : 공개 Dock 이미지 저장소다. 다양한 종류의 애플리케이션을 탑재한 이미지들이 등록돼 있다.
Pull Image : 개발자는 공개 Dock 이미지 저장소로 부터, 원하는 이미지를 찾은(search)다음 개발 PC로 pull해서 개발한다.
Image commit : 개발하면서 변경된 부분이 있다면, commit을 한다.
Docker Private Registery : 개발이 끝난 이미지는 private dock 이미지 저장소에 Push 한다.
마지막으로 서비스 시스템에서 이미지를 pull해서 실행하면 배포가끝난다.
Git을 이용한 소프트웨어 개발/배포 과정과 매우 유사하다.
Docker 개발 Tutorial
환경
Ubuntu Linux 14.04가 설치된 개인 노트북에서 테스트를 진행했다.
프로젝트 시나리오
Docker 개발을 위한 나름대로의 간단한 시나리오를 만들었다. 이 시나리오에 따라서 Docker 테스트를 진행한다.
Apache+PHP5 기반의 웹서비스를 개발하기로 했다.
서비스의 이름은 "HelloWorld"로 Hello world를 출력하는 하는 php 파일을 하나 가지고 있다.
웹 서비스를 위해 필요한 것들만 배포하고 싶다. 해서 기본적인 기능만 담고 있는 작은 우분투 이미지를 pull해서 개발한다.
Apache, php5, Mysql을 설치하고 Commit한다. 이 이미지의 이름은 "my_app"이다.
my_app 이미지를 Docker private registery에 등록 한다.
이제 개발자들은 my_app을 pull해서, 애플리케이션을 개발할 수 있다.
HelloWorld API 개발을 끝냈다면, 서비스 서버에서 pull한다.
이 경우 Apache+PHP5 까지를 이미지로 떠서 배포를 하고, HelloWorld 애플리케이션은 "git"으로 관리하는 방법을 사용할 수 있겠으나, docker 사용성을 테스트하는게 목적이니 그냥 HelloWorld까지 이미지로 만든다음 pull해서 서비스 하기로 했다.
설치
docker 오피셜 사이트에서 설치할 수 있다. docker-ee(Enterprise Edition)와 docker-ce(Community Edition) 두개의 버전이 있다. 나는 CE 버전을 선택했다.
요즘 우분투 리눅스는 도커를 기본으로 배포하기는 한데, 좀 오래된 버전인 경우가 많다. 지금 설치돼 있는 도커를 삭제하고 새로 깔기로 했다.
$ docker info
Containers: 8
Running: 0
Paused: 0
Stopped: 8
Images: 121
Server Version: 17.06.0-ce
....
컨테이너 실행
프로젝트에 사용할 이미지를 선택하기 위해서 Docker public Registery에 등록된 공개 이미지를 검색했다. 우분투 기반운영체제로 찾을 거라서 ubuntu를 키워드로 검색
# docker search ubuntu
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
ubuntu Ubuntu is a Debian-based Linux operating s... 1713 [OK]
ansible/ubuntu14.04-ansible Ubuntu 14.04 LTS with ansible 51 [OK]
torusware/speedus-ubuntu Always updated official Ubuntu docker imag... 25 [OK]
ubuntu-upstart Upstart is an event-based replacement for ... 25 [OK]
tutum/ubuntu Ubuntu image with SSH access. For the root... 22 [OK]
sequenceiq/hadoop-ubuntu An easy way to try Hadoop on Ubuntu 17 [OK]
dorowu/ubuntu-desktop-lxde-vnc Ubuntu with openssh-server and NoVNC on po... 12 [OK]
....
NAME : 이미지의 이름
DESCRIPTION : 이미지에 대한 설명
STARTS : 인기도.
OFFICIAL : docker.com 에서 직접 지원하는 이미지.
AUTOMATED : Dockerfile를 이용 Docker Hub에서 자동으로 빌드한 이미지다. 일반적으로 Official 이미지를 기본 이미지로 해서 만들어진다.
나는 ubuntu 이미지를 다운로드 하기로 했다. pull로 이미지를 다운로드 할 수 있다.
# docker.io run -i -t ubuntu /bin/bash
WARNING: Local (127.0.0.1) DNS resolver found in resolv.conf and containers can't use it. Using default external servers : [8.8.8.8 8.8.4.4]
root@1e29e208fffe:/# cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04 LTS"
컨테이너 정보를 확인해보자.
# docker.io ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1e29e208fffe ubuntu:14.04 /bin/bash 35 seconds ago Up 35 seconds angry_albattani
컨테이너의 네트워크 정보를 확인했다.
root@1e29e208fffe:/# ifconfig
eth0 Link encap:Ethernet HWaddr 2e:8c:7a:2a:b5:a2
inet addr:172.17.0.2 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::2c8c:7aff:fe2a:b5a2/64 Scope:Link
UP BROADCAST RUNNING MTU:1500 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:10 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:648 (648.0 B) TX bytes:828 (828.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
172.17.0.2이라는 IP가 할당됐다.
컨테이너의 네트워크는 어떻게 관리되는 되는 건지 궁금해서 호스트 운영체제에서 확인해봤다.
# ifconfig
docker0 Link encap:Ethernet HWaddr be:bd:3e:84:50:83
inet addr:172.17.42.1 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::8494:5cff:fed3:640e/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:10 errors:0 dropped:0 overruns:0 frame:0
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:688 (688.0 B) TX bytes:648 (648.0 B)
# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.11.1 0.0.0.0 UG 0 0 0 wlan0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
이미지가 저장됐는지 확인해보자. 이미지의 이름은 my_app, 아이디 1f19ac8d36e3로 저장된걸 확인할 수 있다..
# docker.io images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
my_app latest 1f19ac8d36e3 14 seconds ago 323.1 MB
ubuntu utopic 58faa899733f 6 days ago 196 MB
...
내가 만든 이미지 my_app를 실행했다. 컨테이너 아이디가 e47eb44c6c99인 컨터이너가 실행됐다.
# docker.io run -i -t 1f19ac8d36e3 /bin/bash
WARNING: Local (127.0.0.1) DNS resolver found in resolv.conf and containers can't use it. Using default external servers : [8.8.8.8 8.8.4.4]
root@e47eb44c6c99:/#
다음으로 넘어가기 전에 내가 한일을 간단히 정리해 보자.
Public docker registry에서 ubuntu image를 pull 했다.
pull한 이미지로 부터 컨테이너를 만들었다.
깡통 컨테이너다. 적어도 ssh는 설치해야지..
변경사항(ssh 설치)를 적용한 새로운 이미지를 commit 했다.
이제 Apache와 PHP를 설치한 HelloWorld 프로젝트를 위한 이미지를 만들면 된다.
Image 목록을 확인해보면, my_app 이라는 이름으로 현재 컨테이너가 저장된걸 확인할 수 있을 거다.
# docker.io images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
my_app latest f6899ddd8576 45 seconds ago 316.2 MB
새로 만든 이미지로 컨테이너를 만들어보자.
# docker.io run -i -t my_app /bin/bash
WARNING: Local (127.0.0.1) DNS resolver found in resolv.conf and containers can't use it. Using default external servers : [8.8.8.8 8.8.4.4]
굳.. 잘 되네.. apache와 php까지 떠 있다. 이제 개발자들이 지금 만든 이미지를 공유해서 사용할 수 있도록 Private Registery에 등록하면 되겠다.
Private Registery를 이용한 docker 이미지 배포
Docker Registery에 등록하기
Register 서버를 만들기 위한 삽질을 또 어떻게 해야 하나 고민을 했는데, 다행히 public docker registery에 registy 이미지가 있었다.
# docker.io run --name private-registry -d -p 5000:5000 registry
WARNING: Local (127.0.0.1) DNS resolver found in resolv.conf and containers can't use it. Using default external servers : [8.8.8.8 8.8.4.4]
--name : 컨테이너의 이름은 private-registry다.
-d : 데몬모드로 실행했다.
-p : 포트포워딩. localhost:5000을 컨테이너:5000으로 포트포워딩 했다.
컨테이너 정보를 확인
# docker.io ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f3a4296938db registry:latest /bin/sh -c exec dock 3 seconds ago Up 3 seconds 0.0.0.0:5000->5000/tcp private-registry
~# curl -v localhost:5000
* Rebuilt URL to: localhost:5000/
* Hostname was NOT found in DNS cache
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 5000 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.35.0
> Host: localhost:5000
> Accept: */*
>
< HTTP/1.1 200 OK
* Server gunicorn/18.0 is not blacklisted
< Server: gunicorn/18.0
< Date: Mon, 07 Jul 2014 15:24:31 GMT
< Connection: keep-alive
< Expires: -1
< Content-Type: application/json
< Pragma: no-cache
< Cache-Control: no-cache
< Content-Length: 39
< X-Docker-Registry-Version: 0.7.3
< X-Docker-Registry-Config: dev
<
* Connection #0 to host localhost left intact
my_app 이미지를 push해보자. Push하기전에 이미지에 이름을 붙여줘야 한다. 이미지 이름은 my_app_demo로 설정했다.
# docker.io tag my_app localhost:5000/my_app_demo
# docker.io images | grep my_app_demo
localhost:5000/my_app_demo latest f6899ddd8576 About an hour ago 316.2 MB
Private registery에 이미지를 push 한다.
# docker.io push localhost:5000/my_app_demo
The push refers to a repository [localhost:5000/my_app_demo] (len: 1)
Sending image list
Pushing repository localhost:5000/my_app_demo (1 tags)
511136ea3c5a: Image successfully pushed
d7ac5e4f1812: Image successfully pushed
2f4b4d6a4a06: Image successfully pushed
83ff768040a0: Image successfully pushed
6c37f792ddac: Image successfully pushed
e54ca5efa2e9: Image successfully pushed
f6899ddd8576: Image successfully pushed
Pushing tag for rev [f6899ddd8576] on {http://localhost:5000/v1/repositories/my_app_demo/tags/latest}
# docker.io run -i -t localhost:5000/my_app_demo /bin/bash
WARNING: Local (127.0.0.1) DNS resolver found in resolv.conf and containers can't use it. Using default external servers : [8.8.8.8 8.8.4.4]
root@309eff26360d:/#
Contents
용어
Docker에 대해서
컨테이너 vs VMs
Dock 이미지 관리
Docker 개발 Tutorial
환경
프로젝트 시나리오
설치
컨테이너 실행
Apache, PHP5 설치
현재 컨테이너를 이미지로 commit 하기
Private Registery를 이용한 docker 이미지 배포
Docker Registery에 등록하기
Registery에 있는 이미지에서 컨테이너 만들기
앞으로 할일
참고
Recent Posts
Archive Posts
Tags