DOCKER. CENTOS7

Thank you for reading this post, don't forget to subscribe!

Для уста­нов­ки Docker тре­бу­ет­ся 64-х раз­ряд­ная опе­ра­ци­он­ная систе­ма и ядро вер­сии 3.10 и выше.
Docker не отно­сит­ся ни к какой вир­ту­а­ли­за­ции. Это ско­рее контейнеризация.

Установка docker

установка Docker Compose на CentOS 7

Термины

Образ - это ста­ти­че­ский билд на осно­ве опре­де­лен­ной OS.

Кон­тей­нер - это запу­щен­ный инстанс образа.

Права на запуск docker

Что­бы запус­кать Docker кон­тей­не­ры под сво­им поль­зо­ва­те­лем (без sudo), нуж­но доба­вить­ся в соот­вет­ству­ю­щую группу:

Сервис Docker

Управ­ле­ние сер­ви­сом 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

 

Импорт/экспорт

Выполнение команд

В резуль­та­те будет создан файл /tmp/execWorks.

Загру­зить ubuntu с тегом latest:

Ска­чать все теги обра­за ubuntu:

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

Оста­но­вить все кон­тей­не­ры и потом уда­лить все кон­тей­не­ры:

Уда­лить образ:

docker rmi IMAGE_ID

Уда­лить все образы:

Создадим/запустим кон­тей­нер с 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 порта:

Создать и запу­стить кон­тей­нер с после­ду­ю­щим уда­ле­ни­ем это­го кон­тей­не­ра после оста­нов­ки (полез­но для отладки):


Внимание!

После запус­ка Docker кон­тей­не­ра сервисы/демоны (как-то SSH, Supervisor и про­чие) не будут запус­кать­ся авто­ма­ти­че­ски! Я потра­тил несколь­ко часов на отлад­ку ошиб­ки: "ssh_exchange_identification: read: Connection reset by peer", при попыт­ке под­клю­чить­ся к кон­тей­не­ру по SSH. А ока­за­лось, что все­го-то не запус­кал­ся демон sshd. Вы долж­ны буде­те вруч­ную запус­кать нуж­ные демо­ны или супер­ви­зор после стар­та контейнера:

Сохра­ня­ем локаль­но новое состо­я­ние кон­тей­не­ра, тем самым созда­вая новый Docker-образ
Сохра­ня­ем изме­не­ния делая commit, пред­ва­ри­тель­но посмот­рим ID-контейнера
docker ps -a | grep debian

docker commit -m "Installed Apache" -a "Eugene Kamenev" 4aa0534b3129 kamaok/debian8_apache2

-m – сообщение,которое будет инфор­ми­ро­вать дру­гих поль­зо­ва­те­лей о том, какие изме­не­ния были сделаны(аналогично опции -m
при исполь­зо­ва­нии систе­му управ­ле­ния версиями)
-a - автор коммита
4aa0534b3129 – ID-контейнера
kamaok –имя поль­зо­ва­те­ля, с кото­рым была про­из­ве­де­на реги­стра­ция на Docker Hub
debian8_apache2– имя ново­го Docker-образа

 

Про­ве­ря­ем нали­чие ново­го Docker-образа
# docker images | grep debian

Теперь этот образ мож­но исполь­зо­вать при запуске/создании контейнера
# docker run -tid kamaok/debian8_apache2 /bin/bash

 Заливаем новый образ на Docker Hub

Пред­ва­ри­тель­но зало­ги­ним­ся на Docker Hub с команд­ной стро­ки, исполь­зуя имя поль­зо­ва­те­ля и пароль,указанные при регистрации

# docker login -u kamaok

Password:
Login Succeeded
[root@centos71 ~]#

Зали­ва­ем

# docker push kamaok/debian8_apache2

The push refers to a repository [docker.io/kamaok/debian8_apache2]
adbce29d8581: Pushed
142a601d9793: Mounted from library/debian
latest: digest: sha256:d419b767a54d503fb4c42b2cd7a4d1d5d0b92cb1f88971b7626cc358b4ffb978 size: 741

Про­ве­рим нали­чие наше­го ново­го обра­за на Docker Hub
https://hub.docker.com/

Для запус­ка ново­го кон­тей­не­ра с ново­го обра­за исполь­зу­ем команды:

# docker pull kamaok/debian8_apache2

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

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

Настройка сети в Docker

После уста­нов­ки Doсker авто­ма­ти­че­ски созда­ет­ся 3 сети автоматически

docker network ls

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-интер­фей­сом, при этом на ноде будет созда­ва­вать­ся новый интер­фейс для каж­до­го контейнера

Про­смотр сети типа bridge на ноде

docker network inspect bridge | less

Про­ве­ря­ем настрой­ки сети контейнера

Для пер­во­го кон­тей­не­ра docker-debian8-apache2

docker inspect docker-debian8-apache2 | less

В самом контейнере,например, docker-mydebian8, сете­вые настрой­ки име­ют вид
# docker attach docker-debian8-apache2

# ip addr show

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

# ip route show

default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.2

Cоздание пользовательских сетей типа Bridge

По умолчанию,контейнеры име­ет доступ друг к дру­гу через хосто­вый Bridge-интер­фейс docker0
Для изо­ля­ция кон­тей­не­ров друг от дру­га мож­но созда­вать пользовательский/свои сети типа Bridge
Напри­мер, созда­дим новую сеть типа Bridge с име­нем isolated_network
# docker network create --driver bridge isolated_network

c2fcfb10c69962c9c890a3caecdb6270b5befd02a0a25bda1ebaf1406601d74d

Про­вер­ка нали­чия новой сети

# docker network ls | grep -Ei 'isolated|name'

NETWORK ID NAME DRIVER SCOPE
c2fcfb10c699 isolated_network bridge local

Про­смот­рим харак­те­ри­сти­ки этой сети

# docker network inspect isolated_network

[
{
"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": {}
}
]

Видно,что в этой сети исполь­зу­ет­ся дру­гая под­сеть 172.18.0.0/16 отлич­ная от сети по умолчанию,которая исполь­зу­ет­ся для всех осталь­ных контейнеров(172.17.0.0./16)

На ноде появил­ся новый 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

Теперь созда­дим новый кон­тей­нер с debian8 для рабо­ты с новой сетью.

# docker run -dit --name docker-mydebian8-isolated --hostname="docker-mydebian8-isolated" --network=isolated_network debian:latest /bin/bash

# docker ps -a | grep debian8-isolated

d2940fb8eaf8 debian:latest "/bin/bash" About a minute ago Up About a minute docker-mydebian8-isolated

Про­ве­рим нали­чие под­со­еди­нен­но­го к сети с име­нем isolated_network запу­щен­но­го кон­тей­не­ра docker-mydebian8-isolated

# docker network inspect isolated_network

[
{
"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": {}
}
]

Под­клю­чим­ся к ново­му кон­тей­не­ру и про­ве­рим доступ­ность с него дру­гих кон­тей­не­ров и досту­па в Интернет
# docker attach docker-mydebian8-isolated

root@docker-mydebian8-isolated:/#

# ip addr show

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
Доступ в Интер­нет есть бла­го­да­ря ново­му интер­фей­су на ноде

# ping i.ua

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

Ожи­да­е­мо, что доступ к сосед­не­му кон­тей­не­ру отсутствует

root@docker-mydebian8-isolated:/# ping 172.17.0.3

PING 172.17.0.3 (172.17.0.3): 56 data bytes

Создание/построение образа из Dockerfile

Созда­дим образ с Ubuntu 16.04, кото­рый впо­след­ствии может быть исполь­зо­ван для созда­ния контейнера

Для это­го созда­дим Dockerfile, в кото­ром про­пи­шем необ­хо­ди­мые инструкции

# mkdir -p /root/ubuntu16.04 && cd /root/ubuntu16.04

# nano Dockerfile

# This is a comment
FROM ubuntu:16.04
MAINTAINER Eugene Kamenev <username@mydomain.com>
RUN apt-get update && apt-get install -y apache2

Фор­мат Dockerfile име­ет вид

INSTRUCTION statement
Ком­мен­та­ри­ям пред­ше­ству­ет символ #
Назва­ние инструк­ции пишут­ся с боль­шой буквы
В Dockerfile были исполь­зо­ва­ны сле­ду­ю­щие инструкции
FROM - опре­де­ля­ет какой источ­ник исполь­зо­вать для наше­го обра­за – уста­нав­ли­ва­ем Ubuntu 16.04
MAINTAINER – имя и E-mail лица, обслу­жи­ва­ю­ще­го этот образ
RUN - коман­ды, кото­рые необ­хо­ди­мо выпол­нить внут­ри обра­за – обнов­ля­е­мый локаль­ный кеш паке­тов и уста­нав­ли­ва­ем Apache

CMD  ука­зы­ва­ет, какую коман­ду необ­хо­ди­мо запу­стить, когда кон­тей­нер запу­щен. В отли­чие от коман­ды RUN ука­зан­ная коман­да испол­ня­ет­ся не во вре­мя постро­е­ния обра­за, а во вре­мя запус­ка контейнера.

Важ­но пом­нить, что вы може­те пере­гру­зить коман­ду CMD, исполь­зуя docker run.

ENTRYPOINT

Часто коман­ду CMD пута­ют с ENTRYPOINT. Раз­ни­ца в том, что вы не може­те пере­гру­жать ENTRYPOINT при запус­ке контейнера.

При запус­ке кон­тей­не­ра пара­мет­ры пере­да­ют­ся коман­де, ука­зан­ной в ENTRYPOINT.

Мож­но ком­би­ни­ро­вать ENTRYPOINT и CMD.

В этом слу­чае коман­да в ENTRYPOINT выпол­нит­ся в любом слу­чае, а коман­да в CMD выпол­нит­ся, если не пере­да­но дру­гой коман­ды при запус­ке кон­тей­не­ра. Если тре­бу­ет­ся, вы все-таки може­те пере­гру­зить коман­ду ENTRYPOINT с помо­щью фла­га --entrypoint.

WORKDIR

С помо­щью WORKDIR мож­но уста­но­вить рабо­чую дирек­то­рию, отку­да будут запус­кать­ся коман­ды ENTRYPOINT и CMD.

Вы може­те пере­гру­зить рабо­чую дирек­то­рию кон­тей­не­ра в ран­тай­ме с помо­щью фла­га -w.

USER

Спе­ци­фи­ци­ру­ет поль­зо­ва­те­ля, под кото­рым дол­жен быть запу­щен образ. Мы можем ука­зать имя поль­зо­ва­те­ля или UID и груп­пу или GID.

Вы може­те пере­гру­зить эту коман­ду, исполь­зуя глаг -u при запус­ке кон­тей­не­ра. Если поль­зо­ва­тель не ука­зан, исполь­зу­ет­ся root по-умолчанию.

VOLUME

Инструк­ция VOLUME добав­ля­ет тома в образ. Том — пап­ка в одном или более кон­тей­не­рах или пап­ка хоста, про­бро­шен­ная через Union File System (UFS).
Тома могут быть рас­ша­ре­ны или повтор­но исполь­зо­ва­ны меж­ду кон­тей­не­ра­ми. Это поз­во­ля­ет добав­лять и изме­нять дан­ные без ком­ми­та в образ.

В при­ме­ре выше созда­ет­ся точ­ка мон­ти­ро­ва­ния /opt/project для любо­го кон­тей­не­ра, создан­но­го из обра­за. Таким обра­зом вы може­те ука­зы­вать и несколь­ко томов в массиве.

ADD

Инструк­ция ADD добав­ля­ет фай­лы или пап­ки из наше­го билд-окру­же­ния в образ, что полез­но напри­мер при уста­нов­ке приложения.

Источ­ни­ком может быть URL, имя фай­ла или директория.

ADD latest.tar.gz /var/www/wordpress/

В послед­нем при­ме­ре архив tar.gz будет рас­па­ко­ван в /var/www/wordpress. Если путь назна­че­ния не ука­зан — будет исполь­зо­ван пол­ный путь вклю­чая директории.

COPY

Инструк­ция COPY отли­ча­ет­ся от ADD тем, что пред­на­зна­че­на для копи­ро­ва­ния локаль­ных фай­лов из билд-кон­тек­ста и не под­дер­жи­ва­ет рас­па­ков­ки файлов:

 

ONBUILD

Инструк­ция ONBUILD добав­ля­ет триг­ге­ры в обра­зы. Триг­гер испол­ня­ет­ся, когда образ исполь­зу­ет­ся как базо­вый для дру­го­го обра­за, напри­мер, когда исход­ный код, нуж­ный для обра­за еще не досту­пен, но тре­бу­ет для рабо­ты кон­крет­но­го окружения.

 

Коммуникация между контейнерами

Eсли при­ло­же­ни­ям нуж­но свя­зы­вать­ся друг с дру­гом. Есть 2 спо­со­ба: связь через про­брос пор­тов и лин­ков­ку контейнеров.

Про­брос портов
Такой спо­соб свя­зи уже был пока­зан ранее. Посмот­рим на вари­ан­ты про­бро­са пор­тов чуть шире.
Когда мы исполь­зу­ем EXPOSE в Dockerfile или пара­метр -p номер_порта – порт кон­тей­не­ра при­вя­зы­ва­ет­ся к про­из­воль­но­му пор­ту хоста. Посмот­реть этот порт мож­но коман­дой docker ps или docker port имя_контейнера номер_порта_в_контейнере. В момент созда­ния обра­за мы можем не знать, какой порт будет сво­бо­ден на машине в момент запус­ка контейнера.

Ука­зать, на какой кон­крет­ный порт хоста мы при­вя­жем порт кон­тей­не­ра мож­но пара­мет­ром docker run -p порт_хоста: порт_контейнера
По-умол­ча­нию порт исполь­зу­ет­ся на всех интер­фей­сах маши­ны. Мож­но, напри­мер, при­вя­зать к localhost явно:

Мож­но при­вя­зать UDP пор­ты, ука­зав /udp:

 

Лин­ков­ка контейнеров

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

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

Допу­стим у вас есть 2 кон­тей­не­ра: web и db. Что­бы создать связь, уда­ли­те кон­тей­нер web и пере­со­здай­те с исполь­зо­ва­ни­ем коман­ды --link name:alias.

Исполь­зуя docker -ps мож­но уви­деть свя­зан­ные контейнеры.

Что на самом деле про­ис­хо­дит при лин­ков­ке? Созда­ет­ся кон­тей­нер, кото­рый предо­став­ля­ет инфор­ма­цию о себе кон­тей­не­ру-полу­ча­те­лю. Это про­ис­хо­дит дву­мя способами:

  • Через пере­мен­ные окружения
  • Через /etc/hosts

Пере­мен­ные окру­же­ния мож­но посмот­реть, выпол­нив коман­ду env:

Пре­фикс DB_ был взят из alias контейнера.

Мож­но про­сто исполь­зо­вать инфор­ма­цию из hosts, напри­мер коман­да ping db (где db – alias) будет работать.

 

Запу­стим сборку/создание образа
# docker build -t kamaok/ubuntu16.04 .
kamaok - имя пользователя,которому при­над­ле­жит образ
ubuntu16.04 – имя образа
. (Точ­ка) – раз­ме­ще­ние Dockerfile – в теку­щем ката­ло­ге. (так­же мож­но опре­де­лять пол­ный путь к Dockerfile)

Про­ве­ря­ем нали­чие создан­но­го обра­за с име­нем kamaok/ubuntu16.04

# docker images | grep -E 'ubuntu16|REPOSITORY'

REPOSITORY TAG IMAGE ID CREATED SIZE
kamaok/ubuntu16.04 latest 11e09ab98db5 3 minutes ago 265.4 MB

Теперь созда­ем кон­тей­не­ра из это­го образа

# docker run -dit --name docker-ubuntu16.04 --hostname="ubuntu16.04" kamaok/ubuntu16.04 /bin/bash

Про­ве­ря­ем нали­чие кон­тей­не­ра запу­щен­но­го из ново­го образа

# docker ps -a | grep -E 'ubuntu16.04|IMAGE'

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b4ecdc0b1e2f kamaok/ubuntu16.04 "/bin/bash" 26 seconds ago Up 23 seconds docker-ubuntu16.04

Под­клю­ча­ем­ся к кон­тей­не­ру и про­ве­ря­ем вер­сию опе­ра­ци­он­ной системы

# docker attach docker-ubuntu16.04

root@ubuntu16:/# cat /etc/issue

Ubuntu 16.04.1 LTS \n \l

Как пробросить порт в созданном контейнере Docker?

$ iptables -t nat -A DOCKER -p tcp --dport 8002 -j DNAT --to-destination 192.168.103.193:80

Заме­ча­ние: Нуж­но стар­та­нуть тот кон­тей­нер на кото­ром нуж­но про­бро­сить порт и запус­ка­ем коман­ду что выше. Она откро­ет порт «80» на 192.168.103.193 ИП.

ПРИМЕР.

Я постав­лю уже гото­вый кон­тей­нер толь­ко с одной про­грам­мой — 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 — это порт на кото­ром рабо­та­ет докер.

Если не ука­зать IP адрес, то он будет слу­шать все ИП адреса.

Про­бро­сить кон­крет­ные пор­ты (при­мер - 80 локаль­ный порт на 8080 в мир, 443 на 4443 порт в мир)

Про­бро­сить все пор­ты сразу

Связь контейнера с локальной файловой системой

Что­бы заме­нить какой-нибудь файл в кон­тей­не­ре, исполь­зу­ет­ся коман­да docker cp. Она копи­ру­ет файл из локаль­ной фай­ло­вой систе­мы в кон­тей­нер. В нашем при­ме­ре, мы можем изме­нить кон­фи­гу­ра­ци­он­ный файл nginx сле­ду­ю­щей командой:

Где web  и /home/  - имя кон­тей­не­ра и путь к заме­ня­е­мо­му фай­лу или дирек­то­рию внут­ри контейнера,

а /etc/hosts путь до фай­ла в теку­щей опе­ра­ци­он­ной системе.

 

При­мон­ти­ро­вать хосто­вую дирек­то­рию /doesnt/exist в /foo. Если на хосте нету /doesnt/exist - то будет авто­матиче­ски создана:

 

Docker так­же поз­во­ля­ет ссы­лать­ся на фай­лы и ката­ло­ги в локаль­ной фай­ло­вой систе­ме с помо­щью опции -v при запус­ке кон­тей­не­ра.

Для демон­стра­ции про­бро­сим кор­не­вую дирек­то­рию, в кото­рой лежат ресур­сы сай­та nginx.

Пере­хо­дим в пап­ку tmp и созда­ем там дирек­то­рию /nginx/content:

Теперь созда­ем пустой html файл:

Откры­ва­ем его на редактирование:

И встав­ля­ет в него сле­ду­ю­щий текст:

Нажи­ма­ем в редак­то­ре соче­та­ние кла­виш Ctrl+x, согла­ша­ем­ся с сохра­не­ни­ем и нажи­ма­ем Enter.

Что­бы про­бро­сить эту дирек­то­рию в кон­тей­нер с nginx, необ­хо­ди­мо уда­лить сна­ча­ла ста­рый контейнер

И выпол­нить сле­ду­ю­щую команду:

то изме­не­ния в локаль­ной дирек­то­рии повле­кут за собой изме­не­ния в контейнере.

Создать кон­тей­нер с дирек­то­ри­ей баз (/var/lib/mysql) и при­мон­ти­ро­вать этот раз­дел баз в дру­гой контейнер

Docker Compose

Docker Compose упро­ща­ет жизнь если у вас боль­ше одно­го кон­тей­не­ра. С помо­щью одно­го, а ино­гда несколь­ких фай­лов, мы опи­сы­ва­ем какие кон­тей­не­ры запус­кать, их настрой­ки и свя­зи меж­ду кон­тей­не­ра­ми. Начи­ная со вто­рой вер­сии docker compose под­дер­жи­ва­ет насле­до­ва­ние и мож­но с его помо­щью опи­сы­вать раз­ные кон­фи­гу­ра­ции для раз­ных окру­же­ний. команды не только похожи на команды от docker, они и предоставляют аналогичный функционал.
Единственная разница состоит в том,
что применяются они не к отдельному контейнеру, а ко всей группе, определенной в конфигурационном файле docker-compose.yml

  • Коман­ды для рабо­ты с обра­за­ми: savesearchimagesimportexporttaghistory
  • Коман­ды для вза­и­мо­дей­ствия с поль­зо­ва­те­лем: attachexecrun -iloginwait

Отдель­но сто­ит запом­нить коман­ду 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 кон­тей­нер 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

Доба­вим в автозапуск
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


docker attach web.mysql

yum -y install epel-release nano less net-tools wget

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