Linux Docker 0.9 - краткое практическое руководство
Docker - это open-source решение для максимально автоматизированного создания и управления самодостаточными легковесными контейнерами выполняющими приложения в изолированном окружении. Изоляция контейнеров базируется на технологиях ядра Linux - Linux Namespaces и Linux Control Groups.
Docker прост в установке и настройке, может использоваться практически в любых системах, начиная от субноутбуков, и заканчивая кластерами.
Благодаря централизованному хранилищу репозиториев пользователь может обмениваться своими образами с другими, а так же сохранять свои наработки на сервере центрального реестра Docker для возможности последующей загрузки их с различных машин.
Сам по себе Docker не привносит в мир виртуализации и контейнеризации новые фундаментальные технологии, но он делает другую немаловажную вещь. Docker вместо нас выполняет всю рутинную работу по предварительной настройке и разворачиванию изолированных окружений, а так же по их сборке и обновлению (благодаря Dockerfile)
Достаточно неплохо ситуацию характеризуют эта и вот эта картинки.
В данной статье рассматривается Docker версии 0.9 (последняя на данный момент).
Содержание
- Требования к ядру Linux
- Запуск Docker
- Запуск контейнеров
- Базовая работа с контейнерами
- Ctrl+P, Ctrl+Q - отключение от контейнера
- run -d - запуск контейнера в фоне
- attach - подключение к контейнеру
- stop - остановка контейнера
- ps - просмотр всех созданных контейнеров
- images - просмотр доступных образов
- inspect - получение конфигурации контейнера, определение IP адреса
- tag - переименование образа
- logs - просмотр логов контейнера
- help - справка
- Возможные значения IMAGE для run
- Настройка hostname
- Возможность chroot
- Прочие команды
- Сохранение состояния контейнера - commit в отдельный образ
- Самостоятельная сборка образа - build. Dockerfile
- Общие каталоги (Share Directories)
- Изменение размера хранилища и виртуального диска
- Переконфигурирование контейнера "на ходу"
- Docker и возможности CGroups
- Создание собственного репозитория. Docker Central Registry
- Выводы
- Полезные ссылки
Требования к ядру 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'
Параметры:
--graph=/home/docker
- корень "рабочей директрии" по умолчанию располагается в/var/lib/docker/
, туда же загружаются и скачиваемые шаблоны образов контейнеров, там же разворачиваются (с применением Device Mapper) и созданные контейнеры. Потому этот каталог может занимать много места. Вместо него я использую каталог в разделе/home
.--exec-driver=lxc
- сообщает docker о необходимости использовать драйвер lxc для доступа к интерфейсу cgroups. Раньше он использовался по умолчанию, но начиная с версии 0.9 разработчики Docker сменили драйвер по умолчанию на native драйвер docker. Пока native драйвер не умеет всего того что умеет lxc, потому используется драйвер lxc.- По умолчанию адрес 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.
В целом - хочется пожелать разработчикам успехов, т.к. продукт у них получается вроде бы хороший и удобный для использования.