Управление и доступ
По умолчанию, для безопасности, клиент общается с сервером через unix сокет (специльаный файл /var/run/socket.sock), а не через сетевой сокет. Дял работы через unix сокет можно использовать указать программе отправки запросов curl его использовать curl unix-socket /var/run/docker.sock http:/v1.24/containers/json, но это возможность поддерживается с версии curl 1.40, которая пока не поддерживается в CentOS. Для решения этой проблемы и взаимодействия между удалёнными серверами используем сетевой сокет. Для активации его останавливаем сервер systemctl stop docker и запускаем его с настройками dockerd H tcp://0.0.0.0:9002 & (слушать всех на порту 9002, что не допустимо для продакшна). После запуска команда docker ps не будет работать, а будет docker H 5.23.52.111:9002 ps или docker H tcp://geocode1.essch.ru:9202 ps. По умолчанию docker использует для http порт 2375, а для https 2376. Чтобы не менять везде код и каждый раз не указывать сокет, пропишем его в переменных окружения:
export DOCKER_HOST=5.23.52.111:9002
docker ps
docker info
unser DOCKER_HOST
Важно прописать export для обеспечения доступности переменной всем программам: дочерним процессам. Также не должно стоять пробелов вокруг =. Теперь мы так можем обращаться из любого места находящимся в одной сети сервером dockerd. Для управления удалёнными и локальными Docker Engine (Docker на хостах) разработана программа Docker Mashine. Взаимодействие с ней осуществляется с помощью команды docker-machine. Для начала установим:
base=https://github.com/docker/machine/releases/download/v0.14.0 &&
curl L $base/docker-machine-$(uname s)-$(uname m) >/usr/local/bin/docker-machine &&
chmod +x /usr/local/bin/docker-machine
Группа взаимосвязанных приложений
У нас уже есть несколько разных приложений, допустим, таких как Nginx, MySQL и наше приложение. Мы их изолировали в разных контейнерах, теперь она не конфликтуют между собой и Nginx и NySQL мы не стали тратить время и усилия на изготовление собственной конфигурации, а просто скачали: docker run mysql, docker run Nginx, а для приложения docker build.; docker run myapp p 80:80 bash. Как видно, казалось бы, всё очень просто, но есть два момента: управление и взаимосвязь.
Для демонстрации управления возьмём контейнер нашего приложения, и реализуем две возможности старт и создание (переборку). Для ручного старта, когда мы знаем, что контейнер уже создан, но просто остановлен, достаточно выполнить docker start myapp, но для автоматического режима этого недостаточно, а нам нужно написать скрипт, который бы учитывал, существует ли уже контейнер, существует ли для него образ:
if $(docker ps | grep myapp)
then
docker start myapp
else
if! $(docker images | grep myimage)
docker build.
fi
docker run d name myapp p 80:80 myimage bash
fi
А для создания нужно удалить контейнер, если он существует:
if $(docker ps | grep myapp)
docker rm f myapp
fi
if! $(docker images | grep myimage)
docker build.
fi
docker run d name myapp p 80:80 myimage bash
Понятно, что нужно общими параметры, название образа, контейнера вывести в переменные, проверить, что Dockerfile есть, он валидный и только после этого удалять контейнер и много другого. Для понимания реального масштаба, на вдаваясь во взаимодействие контейнеров, о клонировании (масштабирование) этих групп и тому подобного, а только упомяну, то что команда docker run может превышать один два десятка строк. Например, десяток проброшенных портов, монтируемых папок, ограничения на память и процессор, связи с другими контейнерами и ещё немного специфичных параметров. Да, это нехорошо, но делить в таком варианте на множество контейнеров сложно, из-за отсутствия карты взаимодействия контейнеров. Но возникает вопрос: Не много ли нужно делать, чтобы просто предоставить пользователю возможность стартовать контейнер или пересобрать? Зачастую ответ системного администратора сводится к тому, что давать доступы можно только избранным. Но и тут есть решение: docker-compose инструмент для работы с группой контейнеров:
#docker-compose
version: v1
services:
myapp:
container-name: myapp
images: myimages
ports:
80:80
build:.
Для старта docker-compose up d, а для переборки docker down; docker up d. Причём, при изменении конфигурации, когда не нужна полная переборка, произойдёт просто её обновление.
Теперь, когда мы упрости процесс управления одиночным контейнером, давайте поработаем с группой. Но тут, для нас изменится только сам конфиг:
#docker-compose
version: v1
services:
mysql:
images: mysql
Nginx:
images: Nginx
ports:
80:80
myapp:
container-name: myapp
build:.
depence-on: mysql
images: myimages
link:
db: mysql
Nginx: Nginx
Здесь мы видим всю картину в целом, контейнера связаны одной сетью, где приложение может обращаться к mysql и Nginx по хостам db и Nginx, соответственно, контейнер myapp будет создан, только когда после поднятия базы данных mysql, даже если это займёт некоторое время.
Для старта docker-compose up d, а для переборки docker down; docker up d. Причём, при изменении конфигурации, когда не нужна полная переборка, произойдёт просто её обновление.
Теперь, когда мы упрости процесс управления одиночным контейнером, давайте поработаем с группой. Но тут, для нас изменится только сам конфиг:
#docker-compose
version: v1
services:
mysql:
images: mysql
Nginx:
images: Nginx
ports:
80:80
myapp:
container-name: myapp
build:.
depence-on: mysql
images: myimages
link:
db: mysql
Nginx: Nginx
Здесь мы видим всю картину в целом, контейнера связаны одной сетью, где приложение может обращаться к mysql и Nginx по хостам db и Nginx, соответственно, контейнер myapp будет создан, только когда после поднятия базы данных mysql, даже если это займёт некоторое время.
Service Discovery
С ростом кластера вероятность падения нод вырастает и ручное обнаружение произошедшего усложняется, для автоматизации обнаружение вновь появившихся сервисов и их исчезновение предназначены системы Service Discovery. Но, чтобы кластер мог обнаруживать состояние но, учитывая, что система децентрализована ноды должны уметь обмениваться сообщениями с друг другом и выбирать лидера, примерами могут быть Consul, ETCD и ZooKeeper. Мы рассмотрим Consul исходя их следующих его особенностей: вся программа одни файл, крайне прост в работает и настройке, имеет высокоуровневый интерфейс (Zookiper его не имеет, полагается, что со временем должны появиться сторонние приложения, его реализующие), написан на не требовательном языке к ресурсам вычислительной машины (Consul Go, Zookeeper Java) и пренебрегли его поддержкой в других системах, такай как, например, ClickHouse (поддерживает по умолчанию ZooKeeper).
Проверим распределение информации между нодами с помощью распределенного key-value хранилища, то есть, если мы в одну ноду добавили записи, то они должны распространиться и на другие ноды, при этом жёстко заданного координирующего (Master) ноды у неё не должно быть. Поскольку Consul состоит из одного исполняемого файла скачиваем его с официального сайта по ссылке https://www.consul.io/downloads.html на каждой ноде:
wget https://releases.hashicorp.com/consul/1.3.0/consul_1.3.0_linux_amd64.zip O consul.zip
unzip consul.zip
rm f consul.zip
Теперь необходимо запустить одну ноду, пока, как master consul server ui, а другие как slave consul server ui и consul server ui. После чего остановим consul, находящийся в режиме master, и запускаем его как равного, в результате consul-ы переизберут временного лидера, а в случае иго падения, переизберут снова. Проверим работу нашего кластера consul members:
consul members;
И так проверим распределение информации нашего хранилища:
curl X PUT d 'value1 ..:8500/v1/kv/group1/key1
curl s..:8500/v1/kv/group1/key1
curl s..:8500/v1/kv/group1/key1
curl s..:8500/v1/kv/group1/key1
Настроим мониторинг сервисов, подробнее в документации https://www.consul.io/docs/agent/options.html#telemetry, для этого. https://medium.com/southbridge/monitoring-consul-with-statsd-exporter-and-prometheus-bad8bee3961b
Чтобы не настраивать, воспользуемся контейнером и режимом для разработки с уже настроенным IP-адресом на 172.17.0.2:
essh@kubernetes-master:~$ mkdir consul && cd $_
essh@kubernetes-master:~/consul$ docker run d name=dev-consul e CONSUL_BIND_INTERFACE=eth0 consul
Unable to find image 'consul: latest' locally
latest: Pulling from library/consul
e7c96db7181b: Pull complete
3404d2df15cb: Pull complete
1b2797650ac6: Pull complete
42eaf145982e: Pull complete
cef844389e8c: Pull complete
bc7449359c58: Pull complete
Digest: sha256:94cdbd83f24ec406da2b5d300a112c14cf1091bed8d6abd49609e6fe3c23f181
Status: Downloaded newer image for consul: latest
c6079f82500a41f878d2c513cf37d45ecadd3fc40998cd35020c604eb5f934a1
essh@kubernetes-master:~/consul$ docker inspect dev-consul | jq .[] |.NetworkSettings.Networks.bridge.IPAddress'
"172.17.0.4"
essh@kubernetes-master:~/consul$ docker run d name=consul_follower_1 e CONSUL_BIND_INTERFACE=eth0 consul agent dev join=172.17.0.4
8ec88680bc632bef93eb9607612ed7f7f539de9f305c22a7d5a23b9ddf8c4b3e
essh@kubernetes-master:~/consul$ docker run d name=consul_follower_2 e CONSUL_BIND_INTERFACE=eth0 consul agent dev join=172.17.0.4
babd31d7c5640845003a221d725ce0a1ff83f9827f839781372b1fcc629009cb
essh@kubernetes-master:~/consul$ docker exec t dev-consul consul members
Node Address Status Type Build Protocol DC Segment
53cd8748f031 172.17.0.5:8301 left server 1.6.1 2 dc1 < all>
8ec88680bc63 172.17.0.5:8301 alive server 1.6.1 2 dc1 < all>
babd31d7c564 172.17.0.6:8301 alive server 1.6.1 2 dc1 < all>
essh@kubernetes-master:~/consul$ curl X PUT d 'value1 172.17.0.4:8500/v1/kv/group1/key1
true
essh@kubernetes-master:~/consul$ curl $(docker inspect dev-consul | jq r .[] |.NetworkSettings.Networks.bridge.IPAddress'):8500/v1/kv/group1/key1
[
{
"LockIndex": 0,
"Key": "group1/key1",
"Flags": 0,
"Value": "dmFsdWUx",
"CreateIndex": 277,
"ModifyIndex": 277
}
]
essh@kubernetes-master:~/consul$ firefox $(docker inspect dev-consul | jq r .[] |.NetworkSettings.Networks.bridge.IPAddress'):8500/ui
С определением местоположения контенеров необходимо обеспечить авторизацию, для этого используются хранилища ключей.
dockerd H fd:// cluster-store=consul://192.168.1.6:8500 cluster-advertise=eth0:2376