Thank you for reading this post, don't forget to subscribe!
Для установки Docker требуется 64-х разрядная операционная система и ядро версии 3.10 и выше.
Docker не относится ни к какой виртуализации. Это скорее контейнеризация.
Установка docker
1 2 3 4 5 6 7 |
wget -qO- <a class="external free" href="https://get.docker.com/" rel="nofollow">https://get.docker.com/</a> | sh usermod -aG docker $(whoami) systemctl enable docker.service systemctl start docker или yum install -y yum-utils device-mapper-persistent-data lvm2 |
1 2 |
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo |
1 2 3 4 |
yum install docker-ce usermod -aG docker $(whoami) systemctl enable docker.service systemctl start docker |
установка Docker Compose на CentOS 7
1 2 3 4 5 |
yum install epel-release yum install -y python-pip pip install --upgrade pip pip install docker-compose |
1 2 3 4 |
Для проверки корректности установки Docker запустим тестовый образ в контейнере # yum list installed | grep docker docker-engine.x86_64 1.12.2-1.el7.centos @dockerrepo docker-engine-selinux.noarch 1.12.2-1.el7.centos @dockerrepo |
Термины
Образ - это статический билд на основе определенной OS.
Контейнер - это запущенный инстанс образа.
Права на запуск docker
Чтобы запускать Docker контейнеры под своим пользователем (без sudo), нужно добавиться в соответствующую группу:
1 |
sudo usermod -aG docker YOU_USER |
Сервис Docker
Управление сервисом Docker'а:
1 2 3 |
sudo service docker start|stop|restart|status sudo restart docker # алиас |
Основные команды по работе с контейнерами
- docker create
- создать контейнер, но не запускать его
- docker run
- создать и запустить контейнер
- docker stop
- остановить контейнер
- docker start
- запустить существующий остановленный контейнер
- docker restart
- перезапустить контейнер
- docker rm
- удалить контейнер
- docker kill
- отправить сигнал SIGKILL контейнеру
- docker attach
- подключиться к работающему контейнеру
- docker wait
- блокировать команду и ждать, пока контейнер не остановится
Информация о контейнерах
- docker ps
- показать работающие контейнеры (или вообще контейнеры, если использовать дополнительные опции)
- docker inspect
- показать всю информацию о контейнере, включая IP-адреса
- docker logs
- показать лог-вывод контейнера
В режиме tail -f:
docker logs -f
- docker events
- показать события контейнера
- docker port
- показать открытые наружу порты контейнера
- docker top
- показать процессы, работающие внутри контейнера
- docker stats
- показать статистику использования ресурсов контейнером
- docker diff
- показать изменённые файлы в файловой системе контейнера
Просмотреть конфигурацию контейнера в JSON-формате: docker inspect container_name
Просмотреть отдельную часть конфигурации/переменную: docker inspect -f '{{ .NetworkSettings.IPAddress }}' container_name
Импорт/экспорт
1 2 3 |
docker cp copies files or folders out of a container's filesystem. docker export turns container filesystem into tarball archive stream to STDOUT. |
Выполнение команд
1 |
docker exec to execute a command in container. |
1 2 |
docker exec -d ubuntu_bash touch /tmp/execWorks |
В результате будет создан файл /tmp/execWorks.
1 2 |
<strong>Поиск образа</strong> docker search |
Загрузить ubuntu с тегом latest:
1 |
docker pull ubuntu:latest |
Скачать все теги образа ubuntu:
1 |
# docker pull --all-tags ubuntu |
Получить список образов, которые есть на локальной машине:
1 |
# docker images |
Остановить все контейнеры и потом удалить все контейнеры:
1 2 |
# docker stop $(docker ps -a -q) # docker rm $(docker ps -a -q) |
Удалить образ:
docker rmi IMAGE_ID
Удалить все образы:
1 |
1 |
1 2 3 4 5 6 |
# docker rmi $(docker images -q) <strong>Просмотр существующих контейнеров(как запущенных, так и остановленных)</strong> # docker ps -a |
Создадим/запустим контейнер с Ubuntu14.04 (если образ предварительно не был скачан, то Docker сам автоматически его скачает с Docker public registry)
# docker run -dit --name docker-ubuntu14.04 --hostname="ubuntu14.04" ubuntu:14.04 /bin/bash
docker run [опции] образ [команда]
--name Имя контейнера вместо ID
-w Указать рабочую директорию (--workdir)
-e Установить переменную окружения в контейнере
-u Пользователь:группа под которым должен быть запущен контейнер
-v Смонтировать в контейнер файл или каталог хост-системы
-d – запускать контейнер в фоновом режиме
-p Пробросить порт(ы) контейнера - <порт хост-системы>:<порт контейнера> (--publish=[])
--entrypoint Заменить дефолтную команду из ENTRYPOINT файла Dockerfile
-t - запускать контейнер в интерактивном режиме
-i - выделить tty-терминал, который требуется для присоединения к контейнеру
--hostname – установить имя хоста внутри контейнера
Команда «run»- это команда для создания и запуска нового контейнера.
Создадим/запустим контейнер с Centos7
# docker run -dit --name docker-centos7 --hostname="centos7" centos:latest /bin/bash
Создадим/запустим контейнер с Debian8
# docker run -dit --name docker-debian8 --hostname="debian8" debian:latest /bin/bash
Создать и запустить Docker контейнер в режиме демона с пробросом SSH порта:
1 |
1 |
docker run -itd -p 127.0.0.1:221:22 ubuntu |
1 |
Создать и запустить контейнер с последующим удалением этого контейнера после остановки (полезно для отладки):
1 |
1 2 3 4 5 6 7 |
docker run -i -t --rm ubuntu bash <strong>Добавим контейнер в автозапуск(autorun)(укажем порт и внешнюю директорию)</strong> docker run -dti --restart=always --name=web2 --hostname="apach2" -p 80:80 -v /home/mid/html:/var/www/html centos7-ap-cron-nano <strong>Подключимся к контейнеру docker-ubuntu14.04 и выполним команду</strong> |
1 2 3 4 5 6 7 8 |
# docker attach docker-ubuntu14.04 root@ubuntu14:/# hostname ubuntu14.04 <strong>Отключиться от контейнера без его выключения</strong> <strong>CTRL+P+Q </strong> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<strong>Просмотр запущенных процессов внутри Docker-контейнера</strong> # docker top docker-ubuntu14.04 <strong>Использование ресурсов контейнером</strong> (процессорного времени, памяти, дисковой подсистемы, сетевой подсистемы) # docker stats docker-ubuntu14.04 <strong>Копирование файлов с Docker-контейнера на хостовую ноду</strong> (например,каталога /etc контейнера в каталог /root хостовой ноды) # mkdir /root/ubuntu14.04 # docker cp docker-ubuntu14.04:/etc /root/ubuntu14.04/ <strong>Остановка всех контейнеров</strong> # docker stop $(docker ps -q) |
1 2 3 4 |
<strong>Переименование контейнера</strong> # docker rename docker-ubuntu14.04 docker-myubuntu14.04 # docker rename docker-centos7 docker-mycentos7 # docker rename docker-debian8 docker-mydebian8 |
1 |
<strong>Запустить остановленный контейнер интерактивно:</strong> |
1 |
1 |
docker start -i CONTAINER_ID |
1 |
1 |
Внимание!
1 |
После запуска Docker контейнера сервисы/демоны (как-то SSH, Supervisor и прочие) не будут запускаться автоматически! Я потратил несколько часов на отладку ошибки: "ssh_exchange_identification: read: Connection reset by peer", при попытке подключиться к контейнеру по SSH. А оказалось, что всего-то не запускался демон sshd. Вы должны будете вручную запускать нужные демоны или супервизор после старта контейнера:
1 |
1 2 3 |
docker exec CONTAINER_ID bash -c "service ssh start" <strong style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif;">Сохранить состояние контейнера как образ: </strong></code>docker commit CONTAINER_ID IMAGE_NAME |
1 |
</code><code class="bash"> |
Сохраняем локально новое состояние контейнера, тем самым создавая новый Docker-образ
Сохраняем изменения делая commit, предварительно посмотрим ID-контейнера
docker ps -a | grep debian
1 |
# docker commit -m "Installed Apache" -a "Eugene Kamenev" 4aa0534b3129 kamaok/debian8_apache2
1 |
-m – сообщение,которое будет информировать других пользователей о том, какие изменения были сделаны(аналогично опции -m
при использовании систему управления версиями)
-a - автор коммита
4aa0534b3129 – ID-контейнера
kamaok –имя пользователя, с которым была произведена регистрация на Docker Hub
debian8_apache2– имя нового Docker-образа
Проверяем наличие нового Docker-образа
# docker images | grep debian
1 |
Теперь этот образ можно использовать при запуске/создании контейнера
# docker run -tid kamaok/debian8_apache2 /bin/bash
1 |
Заливаем новый образ на Docker Hub
1 |
Предварительно залогинимся на Docker Hub с командной строки, используя имя пользователя и пароль,указанные при регистрации
1 |
# docker login -u kamaok
1 |
Password:
Login Succeeded
[root@centos71 ~]#
1 |
Заливаем
1 |
# docker push kamaok/debian8_apache2
1 |
The push refers to a repository [docker.io/kamaok/debian8_apache2]
adbce29d8581: Pushed
142a601d9793: Mounted from library/debian
latest: digest: sha256:d419b767a54d503fb4c42b2cd7a4d1d5d0b92cb1f88971b7626cc358b4ffb978 size: 741
1 |
Проверим наличие нашего нового образа на Docker Hub
https://hub.docker.com/
1 |
Для запуска нового контейнера с нового образа используем команды:
1 |
# docker pull kamaok/debian8_apache2
1 |
Using default tag: latest
latest: Pulling from kamaok/debian8_apache2
Digest: sha256:d419b767a54d503fb4c42b2cd7a4d1d5d0b92cb1f88971b7626cc358b4ffb978
Status: Image is up to date for kamaok/debian8_apache2:latest
# docker images | grep debian
1 |
kamaok/debian8_apache2 latest d7a092cd2799 10 minutes ago 191.4 MB
debian latest ddf73f48a05d 3 weeks ago 123 MB
# docker run -dit --name docker-debian8-apache2 --hostname="debian8-apache2" kamaok/debian8_apache2
1 |
Настройка сети в Docker
1 |
После установки Doсker автоматически создается 3 сети автоматически
1 |
# docker network ls
1 |
NETWORK ID NAME DRIVER SCOPE
926f2f73b731 bridge bridge local
d5d2b9e299c8 host host local
0ba6c5dde459 none null local
Можно указать тип сети, который доkжен использовать контейнер при старте контейнера с помощью опции —network=
Именно сеть типа Bridge используется по умолчанию.
Docker использует Linux bridge для внутреннего межконтейнерного взаимодействия, а также для соединения контейнера с внешними сетями.
После установки Doсker автоматически создается bridge с именем docker0
Каждый контейнер будет соединяться с docker0 bridge-интерфейсом, при этом на ноде будет создававаться новый интерфейс для каждого контейнера
1 |
Просмотр сети типа bridge на ноде
1 |
# docker network inspect bridge | less
1 |
Проверяем настройки сети контейнера
1 |
Для первого контейнера docker-debian8-apache2
1 |
# docker inspect docker-debian8-apache2 | less
1 |
В самом контейнере,например, docker-mydebian8, сетевые настройки имеют вид
# docker attach docker-debian8-apache2
1 |
# ip addr show
1 |
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
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
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
6: eth0@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:3/64 scope link
valid_lft forever preferred_lft forever
1 |
# ip route show
1 |
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.2
1 |
Cоздание пользовательских сетей типа Bridge
1 |
По умолчанию,контейнеры имеет доступ друг к другу через хостовый Bridge-интерфейс docker0
Для изоляция контейнеров друг от друга можно создавать пользовательский/свои сети типа Bridge
Например, создадим новую сеть типа Bridge с именем isolated_network
# docker network create --driver bridge isolated_network
1 |
c2fcfb10c69962c9c890a3caecdb6270b5befd02a0a25bda1ebaf1406601d74d
1 |
Проверка наличия новой сети
1 |
# docker network ls | grep -Ei 'isolated|name'
1 |
NETWORK ID NAME DRIVER SCOPE
c2fcfb10c699 isolated_network bridge local
1 |
Просмотрим характеристики этой сети
1 |
# docker network inspect isolated_network
1 |
{
"Name": "isolated_network",
"Id": "c2fcfb10c69962c9c890a3caecdb6270b5befd02a0a25bda1ebaf1406601d74d",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1/16"
}
]
},
"Internal": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
1 |
1 |
1 |
1 |
На ноде появился новый Bridge-интерфейс
br-c2fcfb10c699: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.18.0.1 netmask 255.255.0.0 broadcast 0.0.0.0
ether 02:42:e8:cf:a2:65 txqueuelen 0 (Ethernet)
RX packets 11 bytes 830 (830.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 36 bytes 2560 (2.5 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
1 |
Теперь создадим новый контейнер с debian8 для работы с новой сетью.
1 |
# docker run -dit --name docker-mydebian8-isolated --hostname="docker-mydebian8-isolated" --network=isolated_network debian:latest /bin/bash
1 |
# docker ps -a | grep debian8-isolated
1 |
d2940fb8eaf8 debian:latest "/bin/bash" About a minute ago Up About a minute docker-mydebian8-isolated
1 |
Проверим наличие подсоединенного к сети с именем isolated_network запущенного контейнера docker-mydebian8-isolated
1 |
# docker network inspect isolated_network
1 |
{
"Name": "isolated_network",
"Id": "c2fcfb10c69962c9c890a3caecdb6270b5befd02a0a25bda1ebaf1406601d74d",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1/16"
}
]
},
"Internal": false,
"Containers": {
"d2940fb8eaf887229d1f188d8e423d58fb0227e673771d08b8e8e37a54cce86d": {
"Name": "docker-mydebian8-isolated",
"EndpointID": "ea317f7781df4c6822a568e578ce3c1ef2177dd8410b5e718098eaff0385e918",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
1 |
Подключимся к новому контейнеру и проверим доступность с него других контейнеров и доступа в Интернет
# docker attach docker-mydebian8-isolated
1 |
root@docker-mydebian8-isolated:/#
1 |
# ip addr show
1 |
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
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
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
15: eth0@if16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.2/16 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe12:2/64 scope link
valid_lft forever preferred_lft forever
Доступ в Интернет есть благодаря новому интерфейсу на ноде
1 |
# ping i.ua
1 |
PING i.ua (91.198.36.14): 56 data bytes
64 bytes from 91.198.36.14: icmp_seq=0 ttl=54 time=9.371 ms
^C--- i.ua ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max/stddev = 9.371/9.371/9.371/0.000 ms
Ожидаемо, что доступ к соседнему контейнеру отсутствует
1 |
root@docker-mydebian8-isolated:/# ping 172.17.0.3
1 |
PING 172.17.0.3 (172.17.0.3): 56 data bytes
1 |
1 |
Создание/построение образа из Dockerfile
1 |
Создадим образ с Ubuntu 16.04, который впоследствии может быть использован для создания контейнера
1 |
Для этого создадим Dockerfile, в котором пропишем необходимые инструкции
1 |
# mkdir -p /root/ubuntu16.04 && cd /root/ubuntu16.04
1 |
# nano Dockerfile
1 |
# This is a comment
FROM ubuntu:16.04
MAINTAINER Eugene Kamenev <username@mydomain.com>
RUN apt-get update && apt-get install -y apache2
1 |
Формат Dockerfile имеет вид
1 |
INSTRUCTION statement
Комментариям предшествует символ #
Название инструкции пишутся с большой буквы
В Dockerfile были использованы следующие инструкции
FROM - определяет какой источник использовать для нашего образа – устанавливаем Ubuntu 16.04
MAINTAINER – имя и E-mail лица, обслуживающего этот образ
RUN - команды, которые необходимо выполнить внутри образа – обновляемый локальный кеш пакетов и устанавливаем Apache
CMD указывает, какую команду необходимо запустить, когда контейнер запущен. В отличие от команды RUN указанная команда исполняется не во время построения образа, а во время запуска контейнера.
1 2 |
CMD [<span class="hljs-string">"/bin/bash"</span>, <span class="hljs-string">"-l"</span>] |
Важно помнить, что вы можете перегрузить команду CMD, используя docker run.
ENTRYPOINT
Часто команду CMD путают с ENTRYPOINT. Разница в том, что вы не можете перегружать ENTRYPOINT при запуске контейнера.
1 2 |
ENTRYPOINT [<span class="hljs-string">"/usr/sbin/nginx"</span>] |
При запуске контейнера параметры передаются команде, указанной в ENTRYPOINT.
1 2 |
docker run <span class="hljs-_">-d</span> trukhinyuri/static_web -g <span class="hljs-string">"daemon off"</span> |
Можно комбинировать ENTRYPOINT и CMD.
1 2 3 |
ENTRYPOINT [<span class="hljs-string">"/usr/sbin/nginx"</span>] CMD [<span class="hljs-string">"-h"</span>] |
В этом случае команда в ENTRYPOINT выполнится в любом случае, а команда в CMD выполнится, если не передано другой команды при запуске контейнера. Если требуется, вы все-таки можете перегрузить команду ENTRYPOINT с помощью флага --entrypoint.
WORKDIR
С помощью WORKDIR можно установить рабочую директорию, откуда будут запускаться команды ENTRYPOINT и CMD.
1 2 3 4 5 |
WORKDIR /opt/webapp/db RUN bundle install WORKDIR /opt/webapp ENTRYPOINT [<span class="hljs-string">"rackup"</span>] |
Вы можете перегрузить рабочую директорию контейнера в рантайме с помощью флага -w.
USER
Специфицирует пользователя, под которым должен быть запущен образ. Мы можем указать имя пользователя или UID и группу или GID.
1 2 3 4 5 6 7 |
USER user USER user:group USER uid USER uid:gid USER user:gid USER uid:group |
Вы можете перегрузить эту команду, используя глаг -u при запуске контейнера. Если пользователь не указан, используется root по-умолчанию.
VOLUME
Инструкция VOLUME добавляет тома в образ. Том — папка в одном или более контейнерах или папка хоста, проброшенная через Union File System (UFS).
Тома могут быть расшарены или повторно использованы между контейнерами. Это позволяет добавлять и изменять данные без коммита в образ.
1 2 |
VOLUME [<span class="hljs-string">"/opt/project"</span>] |
В примере выше создается точка монтирования /opt/project для любого контейнера, созданного из образа. Таким образом вы можете указывать и несколько томов в массиве.
ADD
Инструкция ADD добавляет файлы или папки из нашего билд-окружения в образ, что полезно например при установке приложения.
1 2 |
ADD software.lic /opt/application/software.lic |
Источником может быть URL, имя файла или директория.
1 2 |
ADD http://wordpress.org/latest.zip /root/wordpress.zip |
ADD latest.tar.gz /var/www/wordpress/
В последнем примере архив tar.gz будет распакован в /var/www/wordpress. Если путь назначения не указан — будет использован полный путь включая директории.
COPY
Инструкция COPY отличается от ADD тем, что предназначена для копирования локальных файлов из билд-контекста и не поддерживает распаковки файлов:
1 2 |
COPY conf.d/ /etc/apache2/ |
ONBUILD
Инструкция ONBUILD добавляет триггеры в образы. Триггер исполняется, когда образ используется как базовый для другого образа, например, когда исходный код, нужный для образа еще не доступен, но требует для работы конкретного окружения.
1 2 3 |
ONBUILD ADD . /app/src ONBUILD RUN <span class="hljs-built_in">cd</span> /app/src && make |
Коммуникация между контейнерами
Eсли приложениям нужно связываться друг с другом. Есть 2 способа: связь через проброс портов и линковку контейнеров.
Проброс портов
Такой способ связи уже был показан ранее. Посмотрим на варианты проброса портов чуть шире.
Когда мы используем EXPOSE в Dockerfile или параметр -p номер_порта – порт контейнера привязывается к произвольному порту хоста. Посмотреть этот порт можно командой docker ps или docker port имя_контейнера номер_порта_в_контейнере. В момент создания образа мы можем не знать, какой порт будет свободен на машине в момент запуска контейнера.
Указать, на какой конкретный порт хоста мы привяжем порт контейнера можно параметром docker run -p порт_хоста: порт_контейнера
По-умолчанию порт используется на всех интерфейсах машины. Можно, например, привязать к localhost явно:
1 2 |
docker run -p 127.0.0.1:80:80 |
Можно привязать UDP порты, указав /udp:
1 2 |
docker run -p 80:80/udp |
Линковка контейнеров
Связь через сетевые порты — лишь один способ коммуникации. Docker предоставляет систему линковки, позволяющую связать множество контейнеров вместе и отправлять информацию о соединении от одного контейнера другому.
Для установки связи нужно использовать имена контейнеров. Как было показано ранее, вы можете дать имя контейнеру при создании с помощью флага --name.
Допустим у вас есть 2 контейнера: web и db. Чтобы создать связь, удалите контейнер web и пересоздайте с использованием команды --link name:alias.
1 2 |
docker run <span class="hljs-_">-d</span> -P --name web --link db:db trukhinyuri/webapp python app.py |
Используя docker -ps можно увидеть связанные контейнеры.
Что на самом деле происходит при линковке? Создается контейнер, который предоставляет информацию о себе контейнеру-получателю. Это происходит двумя способами:
- Через переменные окружения
- Через /etc/hosts
Переменные окружения можно посмотреть, выполнив команду env:
1 2 3 4 5 6 7 8 9 |
$ sudo docker run --rm --name web2 --link db:db training/webapp env . . . DB_NAME=/web2/db DB_PORT=tcp://172.17.0.5:5432 DB_PORT_5432_TCP=tcp://172.17.0.5:5432 DB_PORT_5432_TCP_PROTO=tcp DB_PORT_5432_TCP_PORT=5432 DB_PORT_5432_TCP_ADDR=172.17.0.5 |
Префикс DB_ был взят из alias контейнера.
Можно просто использовать информацию из hosts, например команда ping db (где db – alias) будет работать.
1 |
Запустим сборку/создание образа
# docker build -t kamaok/ubuntu16.04 .
kamaok - имя пользователя,которому принадлежит образ
ubuntu16.04 – имя образа
. (Точка) – размещение Dockerfile – в текущем каталоге. (также можно определять полный путь к Dockerfile)
1 |
Проверяем наличие созданного образа с именем kamaok/ubuntu16.04
1 |
# docker images | grep -E 'ubuntu16|REPOSITORY'
1 |
REPOSITORY TAG IMAGE ID CREATED SIZE
kamaok/ubuntu16.04 latest 11e09ab98db5 3 minutes ago 265.4 MB
1 |
Теперь создаем контейнера из этого образа
1 |
# docker run -dit --name docker-ubuntu16.04 --hostname="ubuntu16.04" kamaok/ubuntu16.04 /bin/bash
1 |
Проверяем наличие контейнера запущенного из нового образа
1 |
# docker ps -a | grep -E 'ubuntu16.04|IMAGE'
1 |
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b4ecdc0b1e2f kamaok/ubuntu16.04 "/bin/bash" 26 seconds ago Up 23 seconds docker-ubuntu16.04
1 |
Подключаемся к контейнеру и проверяем версию операционной системы
1 |
# docker attach docker-ubuntu16.04
1 |
root@ubuntu16:/# cat /etc/issue
1 |
Ubuntu 16.04.1 LTS \n \l
1 |
Как пробросить порт в созданном контейнере Docker?
1 |
$ iptables -t nat -A DOCKER -p tcp --dport 8002 -j DNAT --to-destination 192.168.103.193:80
1 |
Замечание: Нужно стартануть тот контейнер на котором нужно пробросить порт и запускаем команду что выше. Она откроет порт «80» на 192.168.103.193 ИП.
1 |
ПРИМЕР.
1 |
Я поставлю уже готовый контейнер только с одной программой — nginx:
# docker run --name some-nginx -p 192.168.103.189:8080:80 -v /some/content:/var/nginx/docker.localhost.localdomain:ro -d nginx
192.168.103.189 — ИП адрес виртуальной машины.
8080 — это порт на котором будет работать nginx.
80 — это порт на котором работает докер.
1 |
Если не указать IP адрес, то он будет слушать все ИП адреса.
1 2 3 |
<strong>Запустим новый контейнер с уже проброшенным 80 портом</strong> docker run -dit -p 80:80 --name=web2 --hostname="webhost" centos7 Теперь при запросе к внешнему 80 порту, система будет автоматически перенаправлять запрос на 80 порт контейнера |
Пробросить конкретные порты (пример - 80 локальный порт на 8080 в мир, 443 на 4443 порт в мир)
1 |
1 2 |
# docker run -p 8080:80 -p 4443:443 … |
1 |
Пробросить все порты сразу
1 |
1 |
# docker -P … … |
1 |
1 2 |
Связь контейнера с локальной файловой системой
1 |
Чтобы заменить какой-нибудь файл в контейнере, используется команда docker cp. Она копирует файл из локальной файловой системы в контейнер. В нашем примере, мы можем изменить конфигурационный файл nginx следующей командой:
1 |
1 |
$ <strong>docker cp /etc/hosts web:/home/</strong> |
1 |
Где web и /home/ - имя контейнера и путь к заменяемому файлу или директорию внутри контейнера,
а /etc/hosts путь до файла в текущей операционной системе.
Примонтировать хостовую директорию /doesnt/exist в /foo. Если на хосте нету /doesnt/exist - то будет автоматически создана:
1 2 |
# docker run -v /doesnt/exist:/foo -w /foo -i -t ubuntu bash -v - volume (раздел) |
Docker также позволяет ссылаться на файлы и каталоги в локальной файловой системе с помощью опции -v при запуске контейнера.
Для демонстрации пробросим корневую директорию, в которой лежат ресурсы сайта nginx.
Переходим в папку tmp и создаем там директорию /nginx/content:
1 2 3 |
$ cd /tmp $ mkdir -p nginx/content $ cd nginx/content |
Теперь создаем пустой html файл:
1 |
$ >index.html |
Открываем его на редактирование:
1 |
$ nano index.html |
И вставляет в него следующий текст:
1 2 3 4 5 6 7 8 9 |
<!DOCTYPE html> <html> <head> <title>Vscale example</title> </head> <body> <h1>Hellow</h1> </body> </html> |
Нажимаем в редакторе сочетание клавиш Ctrl+x, соглашаемся с сохранением и нажимаем Enter.
Чтобы пробросить эту директорию в контейнер с nginx, необходимо удалить сначала старый контейнер
1 2 |
$ docker rm -f qa_nginx -f -позволяет удалить контейнер без его остановки |
И выполнить следующую команду:
1 2 |
$ docker run -dti --name=web --hostname="apach" -p 80:80 -v /home/mid/html:/var/www/html centos7 Заходим на 80 порт и видим, что главная страница поменялась. Так как мы не скопировали директорию, а сделали на неё ссылку, |
то изменения в локальной директории повлекут за собой изменения в контейнере.
1 |
Создать контейнер с директорией баз (/var/lib/mysql) и примонтировать этот раздел баз в другой контейнер
1 |
1 2 |
# docker create -v /var/lib/mysql --name dbname # docker run --volumes-from dbname … … |
1 |
Docker Compose
1 |
Docker Compose упрощает жизнь если у вас больше одного контейнера. С помощью одного, а иногда нескольких файлов, мы описываем какие контейнеры запускать, их настройки и связи между контейнерами. Начиная со второй версии docker compose поддерживает наследование и можно с его помощью описывать разные конфигурации для разных окружений. команды не только похожи на команды от
docker
, они и предоставляют аналогичный функционал.
Единственная разница состоит в том, что применяются они не к отдельному контейнеру, а ко всей группе, определенной в конфигурационном файле docker-compose.yml
- Команды для работы с образами:
save
,search
,images
,import
,export
,tag
,history
… - Команды для взаимодействия с пользователем:
attach
,exec
,run -i
,login
,wait
1 |
Отдельно стоит запомнить команду docker-compose up
. Она представляет собой упрощенный вызов docker-compose build && docker-compose run
Команды Docker Compose
Рассмотрим команды, которые поддерживает Docker Compose.
Команда docker-compose работает на уровне каталога. На одной машине можно иметь несколько групп контейнеров; для этого нужно создать отдельный каталог и отдельный файл docker-compose.yml для каждого контейнера.
Вы уже запускали команду docker-compose up и остановили процесс при помощи комбинации CTRL-C. Это выводит в окно терминала отладочные сообщения. Однако в среде производства инструмент docker-compose должен работать как сервис. Для этого достаточно добавить опцию –d:
docker-compose up -d
Эта команда запускает docker-compose в фоновом режиме.
Чтобы просмотреть группу контейнеров Docker (и запущенных, и отключенных), используйте следующую команду:
docker-compose ps
К примеру, вывод может иметь такой вид (этот вывод сообщает, что контейнер helloworld_my-test_1 отключен):
Name Command State Ports
-----------------------------------------------
helloworld_my-test_1 /hello Exit 0
Состояние запущенных контейнеров – Up:
Name Command State Ports
---------------------------------------------------------------
nginx_nginx_1 nginx -g daemon off; Up 443/tcp, 80/tcp
Чтобы остановить все контейнеры Docker в группе конкретного приложения, выполните следующую команду в каталоге, в котором находится файл docker-compose.yml, при помощи которого был запущена группа Docker:
docker-compose stop
Примечание: Также можно использовать команду docker-compose kill.
Иногда Docker хранит информацию во внутреннем томе. Чтобы вернуть среду в её исходное состояние, нужно использовать команду rm, которая удаляет все контейнеры, созданные группой:
docker-compose rm
Если запустить эту команду в другом каталоге (не в том, в котором хранится контейнер Docker и yml-файл), команда вернёт ошибку:
Can't find a suitable configuration file in this directory or any parent. Are you in the right directory?
Supported filenames: docker-compose.yml, docker-compose.yaml, fig.yml, fig.yaml
Ниже приведён пример подобного файла.
# Версия docker-compose
version: '2'
# Список наших сервисов (контейнеров)
services:
nginx:
# используем последний стабильный образ nginx
image: nginx:latest
# маршрутизируем порты
ports:
- "8000:80"
# монтируем директории, слева директории на основной машине, справа - куда они монтируются в контейнере
volumes:
- ./hosts:/etc/nginx/conf.d
- ./www:/var/www
- ./logs:/var/log/nginx
# nginx должен общаться с php контейнером
links:
- php
php:
# у нас свой образ для PHP, указываем путь к нему и говорим что его надо собрать
build: ./images/php
# этот образ будет общаться с mysql
links:
- mysql
# монтируем директорию с проектами
volumes:
- ./www:/var/www
mysql:
image: mariadb
ports:
- "3306:3306"
volumes:
- ./mysql:/var/lib/mysql
# задаем пароль для root пользователя
environment:
MYSQL_ROOT_PASSWORD: secret
pma:
# используем последний стабильный образ phpmyadmin
image: phpmyadmin/phpmyadmin
restart: always
links:
- mysql:mysql
ports:
- 8183:80
environment:
# прописываем название нашего MySQL хоста
PMA_HOST: mysql
MYSQL_USERNAME: root
MYSQL_ROOT_PASSWORD: secret
1 |
______________________________________________________________________________ |
Перейдём к полезному.
Поставим
на 1 контейнер httpd на 8080 порт(конфиг файлы будут браться с хоста на котором запущен docker путь /home/mid/virthost/httpd/) и php5.6
на 2 контейнер nginx на 80 порт(конфиг файлы будут браться с хоста на котором запущен docker путь /home/mid/virthost/nginx/)
на 3 контейнер mysql5.6
все контейнеры будут работать на образе centos7
docker run -dti --restart=always --name=web.httpd.php5.6 --hostname="centos7.httpd" -p 8080:8080 -v /home/mid/virthost/httpd/:/etc/httpd/conf.d/ centos
docker run -dti --restart=always --name=web.nginx --hostname="centos7.nginx" -p 80:80 -v /home/mid/virthost/nginx/:/etc/nginx/conf.d/ centos
docker run -dti --restart=always --name=web.mysql --hostname="centos7.mysql" -p 3306:3306 centos
docker attach web.httpd.php5.6
1 2 3 4 5 6 7 |
yum -y update yum -y install epel-release nano less net-tools wget httpd wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm wget https://centos7.iuscommunity.org/ius-release.rpm rpm -Uvh ius-release*.rpm yum -y update yum -y install php56u php56u-opcache php56u-xml php56u-mcrypt php56u-gd php56u-devel php56u-mysql php56u-intl php56u-mbstring php56u-bcmath |
1 |
Добавим в автозапуск
systemctl enable httpd.service
Created symlink /etc/systemd/system/multi-user.target.wants/httpd.service, pointing to /usr/lib/systemd/system/httpd.service.
Проверим
[root@centos7 ~]# systemctl list-unit-files | grep http
httpd.service enabled
[root@centos7 ~]# php -v
PHP 5.6.31 (cli) (built: Jul 7 2017 08:13:05)
Укажем 8080 порт
sed -i "s|Listen 80|Listen 8080|" /etc/httpd/conf/httpd.conf
/usr/sbin/httpd -k start
Проверим
[root@centos7 ~]# netstat -ntpl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 496/httpd
Выходим CTRL+P+Q
docker attach web.nginx
1 2 |
yum -y install epel-release nano less net-tools wget yum -y install nginx |
1 |
systemctl enable nginx |
1 2 |
<span class="pre">/usr/bin/nginx</span> <span class="pre">-s</span> <span class="pre">stop (если нужно остановить)</span> |
1 2 3 4 5 6 |
<span class="pre">/usr/bin/nginx (запуск) [root@centos7 ~]# netstat -ntpl Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 200/nginx: master p</span> |
1 2 |
<span class="pre"> Выходим </span></code><strong>CTRL+P+Q</strong> |
docker attach web.mysql
yum -y install epel-release nano less net-tools wget
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# добавляем репозиторий wget -q <a class="external-link" href="http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm" rel="nofollow">http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm</a> rpm -ivh mysql-community-release-el7-5.noarch.rpm обновляемся yum -y update # ставим mysql yum -y install mysql-server # создаём файлы базы данных mysql mysql_install_db --user=mysql --datadir=/var/lib/mysql # Запускаем mysql как фоновый процесс с использованием учетной записи пользователя "mysql" su mysql -c /usr/bin/mysqld_safe & # Указываем пароль для пользователя root /usr/bin/mysqladmin -u root password 'rootpass' <span class="pre">Выходим </span></code><strong>CTRL+P+Q </strong> Чтобы не заходить в каждый контейнер для запуска сервисов, можно использовать следующие команды: |
docker exec web.httpd.php5.5 "/usr/sbin/httpd"
docker exec web.mysql "/usr/bin/mysqld_safe"
docker exec web.nginx "/usr/sbin/nginx"
Так как изначально, мы забыли добавить внешний каталог, где будут храниться файлы сайтов, создадим образы контейнеров, и на их основе создадим корректные
контейнеры.
Остановим все контейнеры:
docker stop $(docker ps -a -q)
создадим образы:
docker commit -m "Apache" -a "MID" 2c76861f9723 centos7-apache
docker commit -m "Nginx" -a "MID" 6ab95025b643 centos7-nginx
Запустим создадим контейнеры:
docker run -dti --restart=always --name=web.httpd.php5.6 --hostname="centos7.httpd" -p 8080:8080 -v /home/mid/virthost/httpd/:/etc/httpd/conf.d/ -v /var/www/:/var/www/ centos7-apache
docker run -dti --restart=always --name=web.nginx. --hostname="centos7.nginx" -p 80:80 -v /home/mid/virthost/nginx/:/etc/nginx/conf.d/ -v /var/www/:/var/www/ centos7-nginx
удалим старые:
docker rm 2c76861f9723 6ab95025b643
Сейчас контейнеры выглядят следующим образом:
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
211b6f99498f centos7-nginx "/bin/bash" 10 minutes ago Up 10 minutes 0.0.0.0:80->80/tcp web.nginx.
c7d875f61bce centos7-apache "/bin/bash" 35 minutes ago Up 35 minutes 0.0.0.0:8080->8080/tcp web.httpd.php5.6
1808b9491a2a centos "/bin/bash" 14 hours ago Up 7 minutes 0.0.0.0:3306->3306/tcp web.mysql
добавим конфиги:
cat /home/mid/virthost/httpd/k.k.conf
<VirtualHost *:8080>
ServerAdmin webmaster@k.k
DocumentRoot /var/www/mid/html/
ServerName k.k
ServerAlias www.k.k
</VirtualHost>
Смотрим IP адрес у контейнера с apache
docker inspect web.httpd.php5.6 | grep IPAddress
"SecondaryIPAddresses": null,
"IPAddress": "172.17.0.2",
"IPAddress": "172.17.0.2",
cat /home/mid/virthost/nginx/k.k.conf
server {
listen 80;
server_name k.k;
#access_log /var/www/user1/logs/test.t.nginx.access.log combined;
#error_log /var/www/user1/logs/test.t.nginx.error.log error;
client_max_body_size 50m;
location ~* \.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|wav|bmp|rtf|swf|js|html|htm|)$ {
root /var/www/mid/html;
}
location / {
proxy_pass http://172.17.0.2:8080;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass_header Set-Cookie;
}
}
Обращаемся к сайту http://k.k
1 |