Основное

» Linux Docker 0.9 - краткое практическое руководство
Установка, настройка, запуск, основные моменты работы.

» Изучаем CGroups
Практический подход к изучению подсистемы ядра Linux

» db2dhcp - DHCP сервер на SQL СУБД
Сборка из исходников, настройка БД, запуск.

Последние записи

» Отличия синтаксиса C++ & Java и некоторые особенности Java
В рамках "заметок на полях" - краткий, очень поверхностный и слабо структурированный набор различий в...

» Восстановление старых разработок
Старые проекты по которым планируется восстановить работы

» Linux Docker 0.9 - краткое практическое руководство
Установка, настройка, запуск, основные моменты работы.

Linux Docker 0.9 - краткое практическое руководство

24 марта 2014

Docker - это open-source решение для максимально автоматизированного создания и управления самодостаточными легковесными контейнерами выполняющими приложения в изолированном окружении. Изоляция контейнеров базируется на технологиях ядра Linux - Linux Namespaces и Linux Control Groups.

Docker прост в установке и настройке, может использоваться практически в любых системах, начиная от субноутбуков, и заканчивая кластерами.

Благодаря централизованному хранилищу репозиториев пользователь может обмениваться своими образами с другими, а так же сохранять свои наработки на сервере центрального реестра Docker для возможности последующей загрузки их с различных машин.

Сам по себе Docker не привносит в мир виртуализации и контейнеризации новые фундаментальные технологии, но он делает другую немаловажную вещь. Docker вместо нас выполняет всю рутинную работу по предварительной настройке и разворачиванию изолированных окружений, а так же по их сборке и обновлению (благодаря Dockerfile)

Достаточно неплохо ситуацию характеризуют эта и вот эта картинки.

В данной статье рассматривается Docker версии 0.9 (последняя на данный момент).


Содержание


Требования к ядру Linux

Docker опирается на функционал предоставляемый ядром: Linux namespaces & Control groups, а значит ядро должно поддерживать эти возможности. В отношении cgroups моё ядро сконфирурировано так. В конфигурации для namespaces включено всё что есть:

 --- Namespaces support 
 [*]   UTS namespace    
 [*]   IPC namespace    
 [*]   User namespace   
 [*]   PID Namespaces   
 [*]   Network namespace

То же самое, но виде параметров для .config:

CONFIG_NAMESPACES=y
CONFIG_UTS_NS=y
CONFIG_USER_NS=y
CONFIG_PID_NS=y
CONFIG_NET_NS=y

Так же, для работы docker требуется достаточно широкая поддержка netfilter, в частности поддержка таблицы nat, включая цель MASQUERADE.

Запуск Docker

Для своего клона Debian (Crunchbang) я выполнял инсталляцию по документации для Ubuntu, там же можно посмотреть руководства по инсталяции для множества других дистрибутивов.

Шаги по обновлению ядра пропущены, т.к. моё ядро свежее использующегося в оригинальном руководстве.

# apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9
# echo deb http://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list
# apt-get update
# apt-get install lxc-docker
# aptitude install lxc

Примечание: lxc нужно только если при запуске контейнера требуется получить доступ ко всем возможностям современных cgroups, в противном случае, вместо него можно установить cgroup-lite (если нет в дистрибутиве, то можно взять например отсюда.

Отмечу: доступна "установка" бинарного файла, заключающаяся по сути в скачивании скомпилированного файла docker. Благодаря тому, что docker собран статически (и имеет размер 16M) - никакого дополнительного софта устанавливать не требуется.

Конфигурирование демона docker осуществляется через /etc/default/docker.

DOCKER_OPTS='--dns 10.7.7.7 --graph=/home/docker --exec-driver=lxc'

Параметры:

  1. --graph=/home/docker - корень "рабочей директрии" по умолчанию располагается в /var/lib/docker/, туда же загружаются и скачиваемые шаблоны образов контейнеров, там же разворачиваются (с применением Device Mapper) и созданные контейнеры. Потому этот каталог может занимать много места. Вместо него я использую каталог в разделе /home.
  2. --exec-driver=lxc - сообщает docker о необходимости использовать драйвер lxc для доступа к интерфейсу cgroups. Раньше он использовался по умолчанию, но начиная с версии 0.9 разработчики Docker сменили драйвер по умолчанию на native драйвер docker. Пока native драйвер не умеет всего того что умеет lxc, потому используется драйвер lxc.
  3. По умолчанию адрес DNS сервера в шаблоне предлагается задавать через -dns, но на данный момент это устарело и нужно использовать --dns.

Если у вас используются cgroups через утилиты пакета cgroup-bin, то их необходимо остановить:

# service cgconfig stop
Stopping cgconfig service...        Success.
# service cgred stop
Stopping CGroup Rules Engine Daemon...      Success

Запускаем Docker:

# service docker start
Starting Docker: docker.

Если все предварительные шаги выполнены верно, то:

# ps o pid,args -C docker 
  PID COMMAND
 3734 /usr/bin/docker -d -p /var/run/docker.pid --dns 10.7.7.7 --graph=/home/docker --exec-driver=lxc

В противном случае смотрим лог-файл:

# cat /var/log/docker.log

Там может быть примерно например такое:

[/var/lib/docker|1b28861b] +job serveapi(unix:///var/run/docker.sock)
[/var/lib/docker|1b28861b] +job initserver()
[/var/lib/docker|1b28861b.initserver()] Creating server
2014/03/13 20:32:15 Listening for HTTP on unix (/var/run/docker.sock)
[/var/lib/docker|1b28861b] +job init_networkdriver()
Unable to enable network bridge NAT: iptables failed: iptables -I POSTROUTING -t nat -s 
172.17.42.1/16 ! -d 172.17.42.1/16 -j MASQUERADE: iptables v1.4.14: 
can't initialize iptables table 'nat': Table does not exist (do you need to insmod?)
Perhaps iptables or your kernel needs to be upgraded.
 (exit status 3)

В принципе вывод сообщений об ошибках красноречиво рассказывает о проблеме. В моём случае изначально в ядре не было нормальной поддержки nat таблицы в netfilter.

После успешного запуска можно интереса ради посмотреть набор правил созданных docker при запуске:

# iptables -t nat -L -vn
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes  target  prot opt in     out            source       destination         
   0     0  DOCKER  all  --  *      *              0.0.0.0/0    0.0.0.0/0    ADDRTYPE match dst-type LOCAL
# iptables  -L -vn
Chain INPUT (policy ACCEPT 3733K packets, 8601M bytes)
pkts bytes target  prot opt in       out            source      destination         

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target  prot opt in       out            source      destination         
485K  716M ACCEPT  all  --  *        docker0        0.0.0.0/0   0.0.0.0/0  ctstate RELATED,ESTABLISHED
276K   16M ACCEPT  all  --  docker0  !docker0       0.0.0.0/0   0.0.0.0/0           
   0     0 ACCEPT  all  --  docker0  docker0        0.0.0.0/0   0.0.0.0/0           

Chain OUTPUT (policy ACCEPT 3184K packets, 2213M bytes)
 pkts bytes target     prot opt in     out     source               destination         

В корневом каталоге сразу же создаётся необходимая для работы демона структура каталогов:

# ls /home/docker
containers/  devicemapper/  graph/  init/  linkgraph.db  
lxc-start-unconfined  repositories-devicemapper  volumes/

Получить статус docker и используемые ресурсы можно командой:

# docker info 
Containers: 0
Images: 0
Driver: devicemapper
 Pool Name: docker-8:6-15335426-pool
 Data file: /home/docker/devicemapper/devicemapper/data
 Metadata file: /home/docker/devicemapper/devicemapper/metadata
 Data Space Used: 291.5 Mb
 Data Space Total: 102400.0 Mb
 Metadata Space Used: 0.7 Mb
 Metadata Space Total: 2048.0 Mb

Сеть в Docker

Docker пытается автоматически сконфигурировать сетевой интерфейс используемый для связи с созданными контейнерами. При этом используется следующий несложный алгоритм:

  • Создаётся сетевой мост docker0, если он не существует.
  • Выполняется поиск диапазона IP адресов не пересекающихся с существующими на хосте маршрутами.
  • Выбирается IP из заданного диапазона.
  • Выбранный адрес присваивается интерфейсу docker0.

Проверить что всё запустилось правильно можно выполнив:

# ip a sh docker0
5: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP 
    link/ether fe:00:eb:4f:7c:1f brd ff:ff:ff:ff:ff:ff
    inet 172.17.42.1/16 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::68c8:8aff:fe44:6d4a/64 scope link 
       valid_lft forever preferred_lft forever

Подробным образом процесс настройки сети, с возможностью ручного конфигурирования, описан в оригинальной документации.


Демон docker запущен и готов к работе. Теперь самое интересное.

Запуск контейнеров

В первую очередь - для удобства работы (во избежание постоянного sudo) добавляем пользователя в группу docker:

# usermod -aG docker roman

Примечание: фактически это эквивалентно добавлению пользователя в группу root

Теперь, от обычного пользователя запускаем контейнер. Docker в первую очередь проверит наличие образа для контейнера на локальной машине, если такового нет - автоматически выкачает его из репозитория Docker. В последнем случае это займёт достаточно много времени.

$ docker run -t -i base /bin/bash
Unable to find image 'base' locally
Pulling repository base
b750fe79269d: Download complete 
27cf78414709: Download complete 
root@5031aab0c5b8:/# 

Успех! После запуска docker производит монтирование разделов контейнера из образа средствами Device Mapper, в каталог <docker-root>/containers/<container-id>/root, что отображается в выводе mount.

Пара слов о параметрах запуска:

  • run - собственно команда запуска нового контейнера.
  • -t - при запуске приложения в контейнере ему необходимо выделить псевдо-терминал.
  • -i - оставить stdin открытым даже если не выполнено подключение (attach) к контейнеру (при запуске с ключём -d)
  • base - имя образа для запускаемого контейнера. В случае если таковой образ отсутствует локально - docker пытается найти образ с таким именем в индексе и скачать автоматически. (Кстати, делает он это от пользователя root что выглядит совсем не безопасно)
  • /bin/bash - программа запускаемая в контейнере. Важно понимать, что /bin/bash это путь к запускаемой программе внутри контейнера, а не на хост-машине. Т.е. перед тем как запускать что-либо в контейнере - необходимо убедиться что этот софт имеется в контейнере.

Но, может произойти например вот так:

# docker run -i -t ubuntu /bin/bash
[error] client.go:2315 Error resize: Error: bad file descriptor
# ps ax|fgrep dock
 7942 ?        Sl     0:00 /usr/bin/docker -d -p /var/run/docker.pid --dns 127.0.0.1
 8030 ?        Z      0:00 [.dockerinit] <defunct>
  • О том как исправить подобную ошибку написано тут, но если совсем коротко, то нужно отмонтировать все смонтированные cgroups подсистемы, а так же отмонтировать от /sys/fs/cgroups tmpfs если она там примонтирована. После этого перезапустить docker и проблема должна решиться.
  • Так же, подобное может произойти если вы не установили cgroup-lite или lxc. В этом случае docker не имеет инструментов что бы выполнять операции по монтированию подсистем cgroups.

Итак, возвращаемся к нашему успешно запущенному контейнеру. Посмотрим что в нём есть:

root@5031aab0c5b8:/# ps ax
  PID TTY      STAT   TIME COMMAND
    1 ?        S      0:00 /bin/bash
   14 ?        R+     0:00 ps ax
root@5031aab0c5b8:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
42: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 02:d1:90:5b:93:28 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.3/16 scope global eth0
       valid_lft forever preferred_lft forever
root@5031aab0c5b8:/# cat /etc/resolv.conf 
nameserver 10.7.7.7
root@5031aab0c5b8:/# hostname
5031aab0c5b8
root@5031aab0c5b8:/# ping ya.ru -c1
PING ya.ru (213.180.204.3) 56(84) bytes of data.
64 bytes from 213.180.204.3: icmp_req=1 ttl=57 time=7.29 ms
--- ya.ru ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 7.291/7.291/7.291/0.000 ms
root@5031aab0c5b8:/# cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=12.04
DISTRIB_CODENAME=precise
DISTRIB_DESCRIPTION="Ubuntu 12.04 LTS"
root@5031aab0c5b8:/# df -h /
df: Warning: cannot read table of mounted file systems: No such file or directory
Filesystem      Size  Used Avail Use% Mounted on
-               9.8G  245M  9.0G   3% /

Перед нами чистая "система" в которой можно устанавливать нужный софт и использовать как легковесную виртуальную машину.

Для сетевого взаимодействия с контейнерами на хост-системе создаются специальные сетевые интерфейсы.

Важно: Не следует путать команду создания нового контейнера run и команду запуска существующего контейнера start. run - создаёт новый контейнер из образа. start - запускает существующий но остановленный контейнер.


Базовая работа с контейнерами

Несколько наиболее типовых операций Docker.

Ctrl+P, Ctrl+Q - отключение от контейнера

Первый вопрос который у меня возник - отключение от контейнера без его остановки. Если нажать Ctrl+D (выполнить exit) в bash, то контейнер завершится, т.к. завершается процесс выполнявшийся в нём. Что бы этого не случилось, нужно нажать магическую комбинацию клавиш: Ctrl+P, Ctrl+Q

run -d - запуск контейнера в фоне

Если нам не нужен интерактивный доступ в контейнер, то можно запустить контейнер с ключём -d:

$ docker run -i -t -d b750fe79269d /bin/bash
c60c0e4bb0988dbfe93789b9c6526c1d35225b1a9a8925aba636a72d1669fd4e

При этом стоит учитывать, что для приложений вроде bash требующих псевдо-терминал и стандартный ввод (stdout) обязательно необходимо задавать ключи -i -t, в противном случае они сразу же завершатся и контейнер остановится. Для демонов (например sshd) этого не требуется.

Подключение к подобным образом запущенному контейнеру описано далее.

attach - подключение к контейнеру

От контейнера мы отключились успешно. Что бы подключиться, нужно выполнить листинг запущенных контейнеров:

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
5031aab0c5b8        ubuntu:12.04        /bin/bash           About an hour ago   Up 12 minutes                           sleepy_brown    

Взять CONTAINER ID, в нашем случае это 5031aab0c5b8, и выполнить:

$ docker attach 5031aab0c5b8
// приглашения командной строки не будет - система сразу же ждёт ввод, можно просто нажать Enter   
root@5031aab0c5b8:/# 

stop - остановка контейнера

Контейнер останавливается сам, когда завершается программа в нём запущенная. Либо его можно остановить принудително соответствующей командой:

$ docker stop 5031aab0c5b8
5031aab0c5b8

docker останавливает процессы в контейнере, сохраняет сделанные изменения на диске и отмонтирует
<docker-root>/containers/<container-id>/root После этого контейнер конечно же не исчезает "в никуда", а сохраняется доступным для повторного запуска.

ps - просмотр всех созданных контейнеров

Все контейнеры, включая остановленные, можно просмотреть командой:

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
c60c0e4bb098        base:latest         /bin/bash           4 minutes ago       Up 4 minutes                            kickass_lovelace    
5031aab0c5b8        ubuntu:12.04        /bin/bash           2 hours ago         Up 17 minutes                           sleepy_brown        
c6db7117ae18        base:latest         /bin/bash           2 hours ago         Exit 137                                sad_pike   

В поле STATUS отображается либо текущий аптайм контейнера, либо код возврата запущенного приложения, это значит что контейнер остановлен.

Выбрав соответствующее CONTAINER ID можно запускать/останавливать/удалять/и т.п. интересующий контейнер.

inspect - получение конфигурации контейнера, определение IP адреса

Конфигурацию созданных контейнеров можно просматривать при помощи команды inspect передав ей аргументом container id:

$ docker inspect c60c0e4bb098

Конфигурация выводится в JSON-формате, информация о IP адресе находится в блоке NetworkSettings:

$ docker inspect c60c0e4bb098 | fgrep NetworkSettings -A7
    "NetworkSettings": {
        "IPAddress": "172.17.0.2",
        "IPPrefixLen": 16,
        "Gateway": "172.17.42.1",
        "Bridge": "docker0",
        "PortMapping": null,
        "Ports": {}
    },

logs - просмотр логов контейнера

В ситуации когда с контейнером произошло "непонятно что", и он завершился, либо продолжает делать "непонятно что", может помочь команда logs, показывающая stdout контейнера

$ docker run -t -i -d ubuntu /bin/bash -c 'while : ; do echo -n "Now is: "; date; sleep 2; done'
3067f19a74a34181f64982162ae5a05c7bb28bb6bddd6b44e811e11bf2c2b67d
$ docker logs 3067f19a74a34181f64982162ae5a05c7bb28bb6bddd6b44e811e11bf2c2b67d
Now is: Sun Mar 23 21:10:39 UTC 2014
Now is: Sun Mar 23 21:10:41 UTC 2014
Now is: Sun Mar 23 21:10:43 UTC 2014
Now is: Sun Mar 23 21:10:45 UTC 2014
Now is: Sun Mar 23 21:10:47 UTC 2014

tags - переименование образа

Если вы создали образ или есть желание как-то особо выделить образ из уже имеющихся, то можно задать ему удобное имя, указав его в формате <repository:tag>:

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ubuntu              13.04               eb601b8965b8        6 weeks ago         170.2 MB
$ docker tag eb601b8965b8 ubuntu:best
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ubuntu              best                eb601b8965b8        6 weeks ago         170.2 MB

help - справка

Исполняемый файл docker содержит в себе достаточно подробную справку по всем ключам и командам доступную через:

$ docker help [command]

images - просмотр доступных образов

$ docker images

Отображает таблицу доступных локально образов. Первые три поля: REPOSITORY, TAG, IMAGE ID - могут быть использованы для указания в качестве аргумента команде run.

Обратите внимание на ключ -t, показывающий наследственную структуру доступных образов.

Возможные значения IMAGE для run

Указать образ для создания контейнера можно указав в качестве параметра IMAGE имя репозитория, имя и метку (TAG), или IMAGE ID полученные из вывода docker images. Честно говоря я не совсем понял по какому принципу выбирается образ если не указать метку, потому если необходимо создать контейнер из конкретного образа, то лучше указывать аргументом run параметры <имя:метка> образа или IMAGE ID однозначно идентифицирующий образ. Например:

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ubuntu              13.10               9f676bd305a4        6 weeks ago         182.1 MB
ubuntu              saucy               9f676bd305a4        6 weeks ago         182.1 MB
ubuntu              latest              9cd978db300e        6 weeks ago         204.7 MB
base                latest              b750fe79269d        12 months ago       175.3 MB
base                ubuntu-12.10        b750fe79269d        12 months ago       175.3 MB
$ docker run -i -t -d base:ubuntu-12.10 /bin/bash
7754b7799607f39fa8e4d042a495f5db9c234ede20c86012924b98c909a58770
$ docker run -i -t -d 9f676bd305a4 /bin/bash
624897576c1d1286cd2ae2a2517f87e597e528d3c44f522e33decfc82ded9940

Примечание: 64-х значные строки на выводе - "длинное" ID контейнера запущенного в фоновом режиме.

Настройка hostname

Для задания контейнеру осмысленного имени хоста, испольуется параметр hostname

$ docker run -t -i --hostname=ubuntu-box ubuntu /bin/bash
root@ubuntu-box:/# hostname 
ubuntu-box
root@ubuntu-box:/# uname -a
Linux ubuntu-box 3.13.3 #1 SMP Thu Mar 13 23:06:30 MSK 2014 x86_64 x86_64 x86_64 GNU/Linux

Возможность chroot

В случае если что-то пошло не так, и запущенный контейнер работает, но недоступен для конфигурирования (например в нём не запущен bash/sshd), можно сделать в него chroot и поправить ситуацию "вручную":

$ docker inspect c274c40dda3d | fgrep '"ID"' # Получаем "длинное" ID контейнера
    "ID": "c274c40dda3df96f1bf14a2d1c7ad835e0af8e77ce7013095fff6cbd0f97b070"
$ sudo chroot /home/docker/containers/c274c40dda3df96f1bf14a2d1c7ad835e0af8e77ce7013095fff6cbd0f97b070/root /bin/bash

Важный момент: /home/docker/ - рабочий каталог docker заданный при запуске через параметр --graph. См. пункт Запуск docker.

После выполнения chroot можно поправить какой-либо конфиг, перезадать пароль пользователя, или установить недостающий пакет.

Прочие команды

docker <command> <args>, где :

  • top <container_id> - показывает список процессов внутри контейнера
  • diff <container_id> - показывает изменения контейнера от оригинального образа из которого он был создан.
  • rm <container_id> - удаляет ненужный контейнер. Требует остановки контейнера либо запуска с ключём -f
  • rmi <image_id> - удаляет ненужный образ, будьте осторожны.

Сохранение состояния контейнера - commit в отдельный образ

Шаблонные/наиболее удачные конфигурации контейнеров можно сохранять в виде отдельных образов. Небольшой пример:

$ docker run --hostname=net-diag -i -t base:latest /bin/bash
root@net-diag:/# apt-get update
root@net-diag:/# apt-get install strace tcpdump nmap traceroute nload
# for i in strace tcpdump nmap traceroute nload; do which $i; done
/usr/bin/strace
/usr/sbin/tcpdump
/usr/bin/nmap
/usr/sbin/traceroute
/usr/bin/nload

Проверим работоспособность например strace:

root@net-diag:/# bash -c 'echo $$; while : ; do echo I $$ > /dev/null; sleep 1; done' &
[1] 296
root@net-diag:/# strace -e trace=open,close,read,write -p 296
Process 296 attached - interrupt to quit
--- SIGCHLD (Child exited) @ 0 (0) ---
open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
close(3)                                = 0
write(1, "I 296\n", 6)                  = 6
close(10)                               = 0
--- SIGCHLD (Child exited) @ 0 (0) ---
^CProcess 296 detached

Отключаемся от контейнера (Ctrl+P, Ctrl+Q) и оцениваем изменения:

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
1a8dc97804bd        base:latest         /bin/bash           23 minutes ago      Up 23 minutes                           romantic_newton     
roman@book.world ~ $ docker diff 1a8dc97804bd | head
C /etc
C /etc/ld.so.cache
A /etc/python
// Далее следует список установленных (A) и изменённых (C) файловов

Делаем "снимок" контейнера в новый образ, заодно укажем о необходимости сразу же запускать /bin/bash через параметр --run:

$ docker commit --run='{"Cmd": ["/bin/bash"]}'  1a8dc97804bd base:net-diag
d6079e6b738438d177817231fd2afb6bc1d24a62c23a6491ea810b12ac6be416

Просматриваем список образов и запускаем наш новый образ:

$ docker images | head -n 2
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
base                net-diag            d6079e6b7384        2 minutes ago       322.5 MB
$ docker run -i -t base:net-diag
root@74423b07d008:/# for i in strace tcpdump nmap traceroute nload; do which $i; done
/usr/bin/strace
/usr/sbin/tcpdump
/usr/bin/nmap
/usr/sbin/traceroute
/usr/bin/nload

Готово! Как и ожидалось - новый контейнер уже содержит установленные ранее пакеты.

Контрольная проверка. На новом контейнере выполняем:

root@74423b07d008:/# ip a sh eth0
107: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether c2:96:c0:e8:de:8b brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.3/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::c096:c0ff:fee8:de8b/64 scope link 
       valid_lft forever preferred_lft forever
root@74423b07d008:/# ping 172.17.0.2 -c1
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_req=1 ttl=64 time=0.212 ms

--- 172.17.0.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.212/0.212/0.212/0.000 ms

На контейнере-"родителе" получаем:

root@net-diag:/# tcpdump -ni eth0 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
13:40:11.047124 IP 172.17.0.3 > 172.17.0.2: ICMP echo request, id 11, seq 1, length 64
13:40:11.047207 IP 172.17.0.2 > 172.17.0.3: ICMP echo reply, id 11, seq 1, length 64

Эксперимент проведён удачно - всё работает ожидаемым образом.

Кроме прочего, команда commit позволяет изменять конфигурацию запуска (запускаемую программу, настройки DNS и т.п.) нового образа через ключ --run, подробный пример см. здесь


Самостоятельная сборка образа - build. Dockerfile

Вместо ручной настройки запущенного контейнера и создании на его основании нового образа для репозитория через commit, можно самому создать образ содержащий все необходимые инструменты. Для этого необходимо создать файл с командами для сборки образа: Dockerfile (аналог Makefile для make).

Так же, это можно использовать для автоматизированного обновления образа в репозитории - вместо запуска контейнера, выполнения в нём операций по обновлению системы и повтороного commit в новый образ, мы можем одной командой пересобрать образ на базе актуального программного обеспеченья.

Приведу пример создания образа с набором некоторых диагностических/служебных пакетов, парой файлов конфигурации и моим открытым ключём в /root/.ssh/authorized_keys. При необходимости, можно практически "с нуля" собрать базовый образ, через инструменты вроде Debootstrap.

Итак, записываем Dockerfile:

# Default server host
#
# VERSION               0.0.1

FROM     debian
MAINTAINER Roman Chebotarev "<my-e-mail>"

# Set update sources 
RUN echo "deb http://http.debian.net/debian wheezy main" > /etc/apt/sources.list
RUN echo "deb http://http.debian.net/debian wheezy-updates main" >> /etc/apt/sources.list
RUN echo "deb http://security.debian.org/ wheezy/updates main" >> /etc/apt/sources.list
# Get updates
RUN apt-get update

# Install software
RUN apt-get install --no-install-recommends -y ssh strace tcpdump nmap traceroute nload psmisc procps subversion file vim less bind9-host tmux

# Preconfigure for sshd
RUN mkdir /var/run/sshd 
RUN chown root.root /var/run/sshd
RUN chmod 755 /var/run/sshd
RUN mkdir /root/.ssh/

# Adding public key
ADD docker.pub /root/.ssh/authorized_keys
RUN chown -R root.root /root/.ssh/
RUN chmod 700 /root/.ssh/

# Configuring vim
ADD vimrc.local /etc/vim/vimrc.local

# Configuring tmux 
ADD .tmux.conf /root/.tmux.conf

# Configuring some bash settings
RUN echo '[ -r /etc/bash.bashrc.local ] && { . /etc/bash.bashrc.local; }' >> /etc/bash.bashrc
ADD bash.bashrc.local /etc/bash.bashrc.local

# Configuring timezone
RUN cp /usr/share/zoneinfo/Europe/Moscow /etc/localtime

# Sharing sshd port to host
EXPOSE 22

CMD ["/usr/sbin/sshd", "-D"]

Важно: файлы добавляемые в контейнер директивой ADD должны находиться внутри рабочей директории сборки, т.е. директории в которой находится Dockerfile. В противном случае вернётся ошибка "no such file or directory". Пояснения см. в описании команды ADD.

Удаляем образ созданный через commit:

$ docker rmi d6079e6b7384
Untagged: base:net-diag
Deleted: d6079e6b738438d177817231fd2afb6bc1d24a62c23a6491ea810b12ac6be416

Запускаем команду по сборке нового образа:

$ docker build --rm -t debian:server .
Uploading context 25.09 kB
Uploading context 
Step 0 : FROM     debian
 ---> b5fe16f2ccba
Step 1 : MAINTAINER Roman Chebotarev "<my-e-mail>"
 ---> Using cache
 ---> 0f498ee7c46e
Step 2 : RUN echo "deb http://http.debian.net/debian wheezy main" > /etc/apt/sources.list
 ---> Using cache
 ---> b6749b9716a6
// И т.д. для каждого шага в Dockerfile
Step 20 : CMD ["/usr/sbin/sshd", "-D"]
 ---> Running in 6278cadd9c54
 ---> 87d058512578
Successfully built 87d058512578
Removing intermediate container 814a63324637
Removing intermediate container 6278cadd9c54

Пояснения к параметрам build:

  • --rm - после сборки удалить все временные контейнеры созданные во время сборки.
    Примечание: если сборка останавливается из-за ошибки в Dockerfile, то временный контейнер не удаляется как сразу, так и после удачной сборки. Нужно выполнить docker ps -a что бы получить container id и удалить его вручную.
  • -t - задаёт имя (и метку) создаваемого образа - ubuntu:net-diag.
  • . - указывает каталог содержайший Dockerfile и другие необходимые файлы для сборки.

Если сборка данного образа производится первый раз, то она занимает относительно много времени, в ходе сборки возможен вывод ошибок о том что не удалось инициализировать конфигурационное окно для какого-либо пакета. Обычно это не страшно и пакет устанавливается в умолчальной конфигурации.

В случае же использования кэша (как в моём примере) пересборка образа занимает считанные секунды.

Проверяем наличие нашего образа в списке и запускаем:

$ docker images | head -n2
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
debian              server              87d058512578        4 minutes ago       242.9 MB
$ docker run -d --name vs0 --hostname vs0 -t -i -P debian:server
f2f6de189410a3eb2317b9a96e9a21badc77d54e12f115ed167e96e951fc4f84
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                   NAMES
f2f6de189410        debian:server       /usr/sbin/sshd -D   18 seconds ago      Up 16 seconds       0.0.0.0:49153->22/tcp   vs0

В выводе команды ps необходимо обратить внимание на значение поля PORTS: 0.0.0.0:49153->22/tcp - это сработала директива EXPOSE 22 из Dockerfile и ключ запуска -P, результатом чего явилась трансляция всех EXPOSE портов контейнера на локальный адрес (см. подробности).

Подключаемся:

$ ssh -i ~/.ssh/docker root@localhost -p 49153
Linux nameless 3.10.25-gentoo #2 SMP Tue Jan 7 17:41:42 MST 2014 x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sun Mar 23 22:41:33 2014 from 172.17.42.1
root@vs0 ~ # ps axf
  PID TTY      STAT   TIME COMMAND
    1 ?        S      0:00 /usr/sbin/sshd -D
   16 ?        Ss     0:00 sshd: root@pts/0    
   18 pts/0    Ss     0:00  \_ -bash
   24 pts/0    R+     0:00      \_ ps axf

Кроме того, можно использовать команду port что бы получить те же данные:

$ docker port vs0 22
0.0.0.0:49153

На всякий случай можно убедиться в этом через netstat:

$ sudo netstat -antp | fgrep 49153
tcp6       0      0 :::49153                :::*                    LISTEN      25692/docker

И конечно же можно получить конфигурацию сети контейнера через inspect, после чего подключиться на его IP адрес обычным образом:

$ ssh -i ~/.ssh/docker root@172.17.0.2 

Примечания к Dockerfile

1. В официальной документации, в примере по сборке образа с sshd, пропущена пара важных директив RUN:

RUN chown root.root /var/run/sshd
RUN chmod 755 /var/run/sshd

Если этого не сделать, то контейнер может не запуститься. Диагностировать проблему можно так:

$ docker run -d -P --name net-diag --hostname='net-diag' ubuntu:net-diag
dbae5da22ac6c5fb7510edd145ba7da41f0f2326a87d4933437b9e5a7c2cc236
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS               NAMES
dbae5da22ac6        ubuntu:net-diag     /bin/sh -c /usr/sbin   13 seconds ago      Exit 255                                net-diag            
$ docker logs dbae5da22ac6
/var/run/sshd must be owned by root and not group or world-writable.

Команда ps -a показывает что контейнер завершился с кодом 255, а вывод команды logs в последней строке достаточно красноречиво сообщает о причине этой беды. Лечится она пересборкой контейнера с выполнением chown & chmod.

2. Если ваша система поддерживает IPv6, то docker по умолчанию отображает порт на loopback адрес IPv6, см. выше вывод netstat. Потому подключиться на 127.0.0.1 или реальный IP адрес сетевой карты может не получиться, но получится на localhost, на ::1, или на IP адрес интерфейса docker0.

3. Строку запуска sshd:

CMD /usr/sbin/sshd -D

Лучше писать как:

CMD ["/usr/sbin/sshd", "-D"]

Т.к. если запускать в оригинальном виде, то директива разложится в запуск /bin/sh -c "/usr/sbin/sshd -D" и в вашем контейнере будет постоянно висеть один лишний ничего не делающий процесс sh ожидающий завершения sshd.


Общие каталоги (Share Directories)

Docker поддерживает удобный механизм томов общих каталогов: возможен вариант обмена данными через общие каталоги как строго внутри группы контейнеров, так и обмена данными между контейрами и хост-машиной. Важно отметить следующие особенности механизма Share Directories:

  • Изменения данных производятся непосредственно в файле тома общего каталога, без участия механизма копирования при записи (copy-on-write), потому изменения происходят быстро, что хорошо для работы с большими файлами.
  • Изменения данных в томах общих каталогов не учитываются командой commit, потому что они не записываются как изменения файловой системы контейнера.
  • Для использования общего тома - не обязательно что бы контейнер при котором был создан этот том был запущен, но запуск контейнера к которому "привязан" том может застраховать данные тома от случайного удаления командой rm.
  • Тома общих каталогов существуют пока сущетсвует хотя бы один контейнер подключенный к этому тому. Это значит что изначальный контейнер-владелец тома может быть удалён, но том будет существовать пока существуют контейнеры использующие его.
  • Вы не можете резервировать данные тома используя docker export/save/cp, т.к. том не является частью образа контейнера. Но вы можете создать контейнер подключенный к общему каталогу на хост-машине и к резервируемому контейнеру, после чего выгрузить содержимое резервируемого тома в хост-машину.

Работа с общими каталогами контейнеров

Создаём контейнер-"хранилище". Он не выполняет никаких функций кроме привязки к себе общего тома и в нормальном состоянии остановлен.

$ docker run -v /share --name DATA busybox true
roman@book.world docker $ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
b72047504197        busybox:latest      true                7 seconds ago       Exit 0                                  DATA                
fbe46cd580db        ubuntu:12.04        /bin/bash           34 seconds ago      Exit 0                                  data-client1    

Запускаем клиентов использующих созданный том. Ключ --volumes-from указывает docker на необходимость подключения к создаваемому контейнеру всех томов общих каталогов контейнера переданного аргументом ключа:

$ docker run -t -i --volumes-from DATA --name data-client1 --hostname data-client1 ubuntu /bin/bash
root@data-client1:/# cd /share/
root@data-client1:/share# ls
root@data-client1:/share# for i in hostname date; do $i > $i.txt; done
root@data-client1:/share# ls
date.txt  hostname.txt

Второй клиент:

$ docker run -t -i --volumes-from DATA --name data-client2 --hostname data-client2 ubuntu /bin/bash
root@data-client2:/# cd /share/
root@data-client2:/share# date
Sat Mar 22 06:53:00 UTC 2014
root@data-client2:/share# ls
date.txt  hostname.txt
root@data-client2:/share# cat date.txt 
Sat Mar 22 06:51:29 UTC 2014
root@data-client2:/share# cat hostname.txt 
data-client1
root@data-client2:/share# for i in hostname date; do $i > $i-2.txt; done

Таким образом можно подключить к тому /share из контейнера DATA любое необходимое число контейнеров-пользователей тома.

Уничтожим контейнер DATA, изначального владельца общего тома и проверим доступность данных после рестарта контейнеров-клиентов:

$ docker rm DATA
DATA
$ docker restart data-client1 data-client2
data-client1
data-client2
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
02ce97ca8cab        ubuntu:12.04        /bin/bash           2 minutes ago       Up 4 seconds                            data-client2        
3edb5038d466        ubuntu:12.04        /bin/bash           3 minutes ago       Up 15 seconds                           data-client1        
roman@book.world docker $ docker attach data-client1
root@data-client1:/# cd /share/
root@data-client1:/share# ls
date-2.txt  date.txt  hostname-2.txt  hostname.txt
root@data-client1:/share# cat date.txt hostname.txt 
Sat Mar 22 06:51:29 UTC 2014
data-client1
root@data-client1:/share# cat date-2.txt hostname-2.txt 
Sat Mar 22 06:53:44 UTC 2014
data-client2

Как и ожидалось, несмотря на уничтожение контейнера изначально владеющего томом /share, данные остались доступными для обоих контейнеров-клиентов.

Работа с томом хост-машины

Создание контейнера использующего каталог на диске:

$ docker run -t -i -v /tmp/docker_share:/share:ro ubuntu bash
root@26f0cbb9e413:/# cat /share/uname.txt 
Linux book 3.13.3 #1 SMP Thu Mar 13 23:06:30 MSK 2014 x86_64 GNU/Linux
root@26f0cbb9e413:/# 

В результате создан контейнер имеющий каталог /share подключенный в read-only режиме к каталогу хост-машины /tmp/docker_share.

Примечание: если на хост-машине отсутствует указанный каталог, то docker автоматически создаст его.

$ cd /tmp/docker_share/
$ for i in hostname date; do $i > $i.txt; done

Проверяем доступность данных из контейнера:

root@5f767b9c97fd:/share# cd /share/
root@5f767b9c97fd:/share# ls
date.txt  hostname.txt
root@5f767b9c97fd:/share# cat date.txt 
Сбт Мар 22 10:46:53 MSK 2014
root@5f767b9c97fd:/share# cat hostname.txt 
book

Примечание: в случае необходимости организовать доступ контейнера к файлам большого объёма можно использовать жёсткие ссылки, учитывая ограничения налагаемые системой на механизм жёстких ссылок. Символьные ссылки для этих целей использовать не выйдет, т.к. они будут указыват на файлы внутри ФС контейнера.


Изменение размера хранилища и виртуального диска

К сожалению, на данный момент в Docker не существует встроенного механизма по изменению как размера дискового пула (по умолчанию 100 Гб), так и размера "диска" каждого отдельного контейнера (по умолчанию 10 Гб).

Как можно изменить размер, и вообще заменить хранилище, подробно разобрано в этой статье.

Там же приведён метод изменения размера "диска" внутри контейнера средствами Device Mapper. По моему опыту он работает весьма условно: "на ходу", при запущенном контейнере, можно увеличить размер "диска", но если после этого остановить контейнер, то запустить его уже не удастся. Вероятно, причина в фактическом устаревании метаданных описывающих "диск" контейнера. Кроме того, есть подозрение что при ручном изменении размера диска одного из контейнеров можно повредить данные соседних контейнеров.


Переконфигурирование контейнера "на ходу"

На данный момент также недоступно. Единственный более-менее приемлемый метод, это создание снимка текущего образа контейнера командой commit с переданным ей ключём --run, аргументом которого может служить новая конфигурация контейнера упакованная в JSON формат, см. пример "Full -run example".

Отмечу, что некоторые параметры не сохраняются в новом образе, например задать Hostname через --run не получится т.к. это характеристика конкретного контейнера, а не образа служащего для запуска контейнеров (создаваемого commit).


Docker и возможности CGroups

Начиная с версии 0.9 Docker для работы с cgroups по умолчанию использует свой собственный драйвер. Но, на данный момент, он не поддерживает всю полноту конфигурирования cgroups, потому если нужно что-то большее чем ограничение по потреблению памяти или настройка пропорций использования процессора (cpu shares), то нужно по прежнему использовать lxc-драйвер (см. настройку демона docker).

Пример ограничения по процессору и памяти

Сперва проверим как загружает систему контейнер без установленных ограничений:

$ docker run -i -t base /bin/bash
root@12b353e21570:/# for i in {1..4}; do { while : ; do true; done & } ; done
[1] 20
[2] 21
[3] 22
[4] 23

Ожидаемый результат достигнут:

%Cpu0  :100,0 us
%Cpu1  :100,0 us
%Cpu2  : 96,8 us
%Cpu3  : 93,5 us

Остановим контейнер и запустим другой, которому доступно только 60% времени 3-го ядра процессора и 10 мегабайт памяти:

$ docker run --lxc-conf="lxc.cgroup.cpuset.cpus = 3" \
    --lxc-conf="lxc.cgroup.memory.limit_in_bytes = 10485760" \
    --lxc-conf="lxc.cgroup.cpu.cfs_period_us = 100000" \
    --lxc-conf="lxc.cgroup.cpu.cfs_quota_us = 60000" -i -t ubuntu /bin/bash
root@c5e54a218386:/# 

Проверяем ограничения по CPU, запускаем в контейнере:

root@c5e54a218386:/# for i in {1..4}; do { while : ; do true; done & } ; done
[1] 11
[2] 12
[3] 13
[4] 14

Оцениваем загрузку на хост-машине:

%Cpu0  :  6,2 us
%Cpu1  :  6,5 us
%Cpu2  :  6,5 us
%Cpu3  : 59,4 us

Загрузка 3го ядра колеблется вокруг 60% (± 1%). Теперь проверяем ограничение по памяти:

root@c5e54a218386:/# perl -e 'print "My PID: $$\n";
    while(1){$x.="x"x(1024**2); print "Len: ",length($x),"\n"; sleep 1}'
My PID: 20
Len: 1048576
Len: 2097152
Len: 3145728
Len: 4194304
Len: 5242880
Len: 6291456
Len: 7340032
Len: 8388608
Killed
root@c5e54a218386:/# dmesg | tail -n 2
[316136.457629] Memory cgroup out of memory: Kill process 29771 (perl) score 942 or sacrifice child
[316136.457632] Killed process 29771 (perl) total-vm:28816kB, anon-rss:9572kB, file-rss:0kB

Работает.

Подробней о настройке cgroups см. статью "CGroups - вводная. Базовые практические примеры ".

Docker и throttling дисковых операций

В настоящий момент в Docker нет встроенных средств (либо они очень хорошо спрятаны) для ограничения скорости ввода/вывода блочных устройств, в частности средствами cgroups через драйвер lxc.

Самый очевидный вариант приходящий в голову для решения этой задачи выглядит примерно так:

$ ls -l /dev/sda
brw-rw---T 1 root disk 8, 0 Мар 23 16:13 /dev/sda
$ docker run --lxc-conf='lxc.cgroup.blkio.throttle.read_bps_device = 8:0 5242880' -i -t base /bin/bash

Где 8:0 - номер устройства полученный через ls -l, а 5242880 - максимальная скорость чтения в байтах в секунду.

К сожалению этот вариант не работает. Объяснение тут достаточно простое - корневая файловая система контейнера расположена не на "обычном диске", а на создаваемом через Device Mapper устройстве. Потому процесс контейнера не попадает под налагаемое контрольной группой ограничение ввода вывода к физическому диску. Ситуация немного осложняется тем, что корневые виртуальные устройства для контейнеров существуют только когда контейнер уже запущен, потому невозможно заранее предугадать правильный номер устройства для написания его в правило cgroups, впрочем, система в любом случае не позволит создать правило для несуществующего устройства.

Но к счастью, эту проблему не так уж сложно и решить, запуская контейнер через простой скрипт-заглушку, вроде такого:

#!/bin/bash

read_iobps=$((1024 * 1024 * $1))
write_iobps=$((1024 * 1024 * $2))

echo Creating container...
ID=$(docker run $3)
echo New container ID: $ID

DEV=$(ls -l $(mount | egrep  -m 1 "$ID type" | cut -f 1 -d ' '))
DEV_NUMS=$(ls -l /dev/$(echo  $DEV | egrep -o '\s*\S*$' | cut -f 2 -d /)| awk '{gsub(/,/,":",$5); print $5 $6}')

echo 'Set read & write throttling'
echo "$DEV_NUMS $read_iobps" > /sys/fs/cgroup/blkio/lxc/$ID/blkio.throttle.read_bps_device || \
    { echo "Fail set blkio.throttle.read_bps_device"; exit -1; }
echo "$DEV_NUMS $write_iobps" > /sys/fs/cgroup/blkio/lxc/$ID/blkio.throttle.write_bps_device || \
    { echo "Fail set blkio.throttle.write_bps_device"; exit -1; }

echo Ok

Первый и второй параметры скрипта - ограничение скорости чтения и записи в Мб/с, третий - командная строка передаваемая docker для запуска контейнера. (скрипт страшен, но это временное решение только для теста :-) )

Запускаем контейнер:

# ./blkio-throttle.sh 10 10 '-t -i -d ubuntu /bin/bash'
Creating container...
New container ID: f8c9c67a389e9231b078adefd8dfac1a7787428366b7a84f73004cee6dae8c35
Set read & write throttling
Ok
# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
f8c9c67a389e        ubuntu:12.04        /bin/bash           8 seconds ago       Up 7 seconds                            berserk_fermi       

Теперь подключимся к контейнеру и проверим работоспособность ограничения:

$ docker attach f8c9c67a389e
root@f8c9c67a389e:/# cd /root/
root@f8c9c67a389e:/root# dd if=/dev/zero of=zeroes bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 12.1149 s, 88.6 MB/s
root@f8c9c67a389e:/root# pv -pterab zeroes > /dev/null
1GB 0:01:43 [9.94MB/s] [9.94MB/s] [=====================================>] 100%          

В случае с чтением всё получилось ожидаемым образом - скорость работы pv была ограниченна в 10 Мб/с.

В случае же с записью - ограничение не сработало, о чём красноречиво свидетельствует вывод dd: 88.6 MB/s. Объясняется это тоже достаточно просто - на данный момент cgroups не поддерживают регулировку скорости записи на блочное устройство в случае использования асинхронного буферизованного ввода/вывода. Официальная документация к cgroups сообщает по этому поводу:

Currently only sync IO queues are support. All the buffered writes are still system wide and not per group. Hence we will not see service differentiation between buffered writes between groups.

Следовательно - на данный момент, используя Docker можно управлять скоростью чтения блочных устройств из контейнера, но практически невозможно управлять скоростью записи.


Создание собственного репозитория. Docker Central Registry

Docker - это не только инструмент для управления контейнерами, это так же и инструмент для обмена Docker образами. Он предоставляет возможность загрузки созданных вами образов в центральный реестр (Central Registry), откуда они доступны для скачивания всем желающим. Разумеется, это можно использовать для сохранения своих наработок и быстрого их разворачивания в любом месте где доступен интернет. (Кроме того, поддерживаются частные закрытые репозитории, но они платные)

Вдобавок к этому - можно создать свой собственный реестр при помощи docker registry.

Создание собственного аккаунта в реестре Docker донельзя упрощено:

$ docker login
Username: romanch
Password: 
Email: <адрес-почты>
Account created. Please use the confirmation link we sent to your e-mail to activate it.

После этого на почту приходит письмо со ссылкой-подтверждением регистрации. Готово, можно пользоваться!

Например, при помощи команды build (но можно использовать и commit) мною был создан репозиторий (и образ) на базе debian репозитория, с некоторым комплектом софта и настроек. Для правильной работы с центральным реестром Docker (см. оф. доку) имя репозитория должно начинаться с вашего логина в реестре, через слеш - имя вашего репозитория. Если при сборке образа они не были заданы, их можно задать через:

$ docker tag <image-id> <registry-login>/<repository-name>

Загрузить свеже созданный образ и репозиторий в центральный реестр очень просто:

roman@book.world ~ $ docker push romanch/debian
The push refers to a repository [romanch/debian] (len: 1)
Sending image list
Pushing repository romanch/debian (1 tags)
511136ea3c5a: Image already pushed, skipping 
Image 584162d19e17 already pushed, skipping
Image b5fe16f2ccba already pushed, skipping
0f498ee7c46e: Image successfully pushed 
// Большой список "слоёв"-образов из которых состоит мой образ
41d703a438c7: Image successfully pushed 
Pushing tag for rev [41d703a438c7] on {https://registry-1.docker.io/v1/repositories/romanch/debian/tags/default-server}

Готово! Задать описание вашего репозитория можно в настройках профиля в реестре.

Для проверки можно попробовать поискать самого себя:

$ docker search romanch
NAME             DESCRIPTION                                     STARS     OFFICIAL   TRUSTED
romanch/debian   Images with some admin soft, eg: ssh strac...   0                    

Получить копию репозитория локально (например на другой машине) можно через:

$ docker pull romanch/debian

Выводы

На мой взгляд Docker - это очень удобная вещь для тестирования различного софта. Как минимум она решает два вопроса: спасает основную систему от "захламления", и даёт возможность "малой кровью" развернуть несколько виртуальных "хостов" если софт предполагает распределённую обработку данных.

С точки зрения безопасности - возможность удобного и быстрого запуска закрытых/непроверенных приложений тоже даёт ряд очевидных преимуществ.

Для решений вроде серьёзного хостинга на мой взгляд Docker применять ещё рано. Чего стоят одни только проблемы с изменением размера хранилища. Так же - явно не доработан механизм ограничения использования ресурсов, но разработчики обещают что возможности cgroups будут поддерживаться через собственный драйвер docker.

В целом - хочется пожелать разработчикам успехов, т.к. продукт у них получается вроде бы хороший и удобный для использования.


Полезные ссылки


comments powered by Disqus