Подготовка инфраструктуры (создание VPC, Master и Slave хостов и т.д.) – описаны в посте AWS: VPC – EC2 в public и private подсетях, NAT и Internet Gateway.
Ниже описан запуск Swarm-кластера по “старой” схеме, до выхода Docker 1.12 пару недель тому, в котором Docker Swarm был включен в Docker как “swarm mode“.
Отличное описание Docker Swarm есть на whatis.com.
“Старый” Swarm – документация тут>>>.
“Новый” Swarm – документация тут>>>.
- Создание инстансов EC2
- Установка Docker Engine
- Настройка нод
- Запуск Consul
- Запуск Swarm-master0
- Добавление нод в кластер
Содержание
Создание инстансов EC2
Нам требуется 2 Swarm-мастера, 2 Swarm-ноды и один EC2 – для Consul в роли service discovery.
Итого – два EC2 в публичной сети под мастер, 2 EC2 – под Swarm-ноды в приватной сети, 1 EC2 – для Consul, тоже в приватной сети.
Создаём ещё один Master в public сети:
$ aws ec2 run-instances --image-id ami-7615c901 --count 1 --instance-type t1.micro --key-name my-cluster --security-group-ids sg-cbbb9eac --subnet-id subnet-f6c35d92
И ещё две ноды в private сети:
$ aws ec2 run-instances --image-id ami-7615c901 --count 2 --instance-type t1.micro --key-name my-cluster --security-group-ids sg-cbbb9eac --subnet-id subnet-c3c35da7
Получаем новый Public IP для второго Master:
$ aws ec2 allocate-address --domain vpc { "PublicIp": "52.210.30.69", "Domain": "vpc", "AllocationId": "eipalloc-268dd343" }
Подключаем его к i-d8f93353
:
$ aws ec2 associate-address --public-ip 52.210.30.69 --instance-id i-d8f93353 { "AssociationId": "eipassoc-397f0a5f" }
Проверяем:
$ aws ec2 describe-instances --filters Name=vpc-id,Values=vpc-24279540 --query '[Reservations[*].Instances[*].{PrivateIP:PrivateIpAddress,InstanceId:InstanceId,PrivateDnsName:PrivateDnsName,PublicIpAddress:PublicIpAddress}]' [ [ [ { "InstanceId": "i-46e228cd", "PrivateDnsName": "ip-10-0-1-103.eu-west-1.compute.internal", "PublicIpAddress": "52.210.51.198", "PrivateIP": "10.0.1.103" } ], [ { "InstanceId": "i-f9e32972", "PrivateDnsName": "ip-10-0-2-33.eu-west-1.compute.internal", "PublicIpAddress": null, "PrivateIP": "10.0.2.33" } ], [ { "InstanceId": "i-d8f93353", "PrivateDnsName": "ip-10-0-1-245.eu-west-1.compute.internal", "PublicIpAddress": "52.210.30.69", "PrivateIP": "10.0.1.245" } ], [ { "InstanceId": "i-a3ff3528", "PrivateDnsName": "ip-10-0-2-185.eu-west-1.compute.internal", "PublicIpAddress": null, "PrivateIP": "10.0.2.185" }, { "InstanceId": "i-a2ff3529", "PrivateDnsName": "ip-10-0-2-186.eu-west-1.compute.internal", "PublicIpAddress": null, "PrivateIP": "10.0.2.186" } ] ] ]
Установка Docker Engine
Т.к. доступ к Swarm-нодам и Consul есть только из VPC – логинимся на один из swarm-master, и продолжаем оттуда.
Копируем ключ на master (если ещё не сделано):
$ scp -i my-cluster.pem my-cluster.pem [email protected]:/home/ubuntu swarm-cluster.pem 100% 1671 1.6KB/s 00:00
Подключаемся и продолжаем с него:
$ ssh [email protected] -i my-cluster.pem ... Last login: Thu Aug 11 07:40:42 2016 from 194.105.145.45 ubuntu@ip-10-0-1-103:~$
Устанавливаем Docker:
# apt-get update && curl -sSL https://get.docker.com/ | sh
Проверяем:
# docker info Containers: 0 Running: 0 Paused: 0 Stopped: 0 Images: 0 Server Version: 1.12.0 Storage Driver: aufs Root Dir: /var/lib/docker/aufs Backing Filesystem: extfs Dirs: 0 Dirperm1 Supported: false Logging Driver: json-file Cgroup Driver: cgroupfs Plugins: Volume: local Network: host bridge null overlay Swarm: inactive Runtimes: runc Default Runtime: runc Security Options: apparmor Kernel Version: 3.13.0-33-generic Operating System: Ubuntu 14.04.1 LTS OSType: linux Architecture: x86_64 CPUs: 1 Total Memory: 588.6 MiB Name: ip-10-0-1-103 ID: JDX3:OYHG:LQER:CGX5:5LKQ:ICCG:YEIM:NB4V:4YCS:Y2C3:4I23:A42U Docker Root Dir: /var/lib/docker Debug Mode (client): false Debug Mode (server): false Registry: https://index.docker.io/v1/ WARNING: No swap limit support Insecure Registries: 127.0.0.0/8
Для корректной работы Docker нам потребуется изменить на всех хостах ещё два файла – /etc/default/docker
и создать файл /etc/profile.d/docker_host.sh
.
По умолчанию Docker слушает только локальный сокет:
# ps aux | grep docker root 29260 0.0 3.6 492500 21976 ? Ssl 08:37 0:01 /usr/bin/dockerd --raw-logs root 29269 0.0 0.8 199676 5356 ? Ssl 08:37 0:00 docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --shim docker-containerd-shim --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --runtime docker-runc
Нам требуется слушать внешний TCP порт.
Редактируем /etc/default/docker
и добавляем DOCKER_OPTS
:
... DOCKER_OPTS="-H 10.0.1.103:2375" ...
Второй файл – /etc/profile.d/docker_host.sh
, потребуется для того, что бы не задавать переменную $
DOCKER_HOST
каждый раз:
# cat /etc/profile.d/docker_host.sh` export DOCKER_HOST=10.0.1.103:2375 # . /etc/profile.d/docker_host.sh
Перезапускаем, проверяем:
# service docker restart docker stop/waiting docker start/running, process 29833
# netstat -anp | grep 2375 tcp 0 0 10.0.1.103:2375 0.0.0.0:* LISTEN 29833/dockerd
Проверяем как работает сам Docker:
# docker run hello-world Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world c04b14da8d14: Pull complete Digest: sha256:0256e8a36e2070f7bf2d0b0763dbabdd67798512411de4cdcf9431a1feb60fd9 Status: Downloaded newer image for hello-world:latest Hello from Docker! This message shows that your installation appears to be working correctly. ...
Настройка нод
Находим Private IP остальных инстансов (с рабочей машины, где есть AWS CLI):
$ aws ec2 describe-instances --filters Name=vpc-id,Values=vpc-24279540 --query '[Reservations[*].Instances[*].PrivateIpAddress]' --output text 10.0.1.103 10.0.2.33 10.0.1.245 10.0.2.185 10.0.2.186
10.0.1.103 – Private IP нашего Master0, на который мы только что установили Docker Engine.
С помощью простого bash-скрипта docker_setup_multi_hosts.sh
– устанавливаем на все остальные ноды, добавив внутренние IP (кроме первого мастера) в переменную $IPS
:
#!/usr/bin/env bash IPS="10.0.2.33 10.0.1.245 10.0.2.185 10.0.2.186" USER="ubuntu" RSA_KEY="my-cluster.pem" docker_update () { echo -e "\nInstalling Docker to $1\n" ssh -t -t -oStrictHostKeyChecking=no -i "$RSA_KEY" "$USER@$1" "bash -c ' sudo apt-get update && curl -sSL https://get.docker.com/ | sh '" } copy_opts () { echo -e "\nCopy /etc/profile.d/docker_host.sh to $1\n" # subsctitute Master's IP to Node's IP sed -e 's/10.0.1.103/'"$1"'/g' /etc/profile.d/docker_host.sh > docker_host.sh scp -i "$RSA_KEY" docker_host.sh "$USER@$1":/home/$USER rm docker_host.sh echo -e "\nCopy /etc/default/docker to $1\n" # subsctitute Master's IP to Node's IP sed -e 's/10.0.1.103/'"$1"'/g' /etc/default/docker > docker scp -i "$RSA_KEY" docker "$USER@$1":/home/$USER rm docker } move_opts () { ssh -t -t -oStrictHostKeyChecking=no -i "$RSA_KEY" "$USER@$1" "bash -c ' sudo mv /home/$USER/docker /etc/default/docker sudo mv /home/$USER/docker_host.sh /etc/profile.d/docker_host.sh '" } docker_restart () { echo -e "\nRestarting Docker daemon.\n" ssh -t -t -oStrictHostKeyChecking=no -i "$RSA_KEY" "$USER@$1" "bash -c ' sudo service docker restart '" } for host in $IPS; do docker_update $host copy_opts $host move_opts $host docker_restart $host done
Запускаем и идём пить чай:
# ./docker_setup_multy_hosts.sh Installing Docker to 10.0.2.33 sudo: unable to resolve host ip-10-0-2-33 Ign http://eu-west-1.ec2.archive.ubuntu.com trusty InRelease Get:1 http://eu-west-1.ec2.archive.ubuntu.com trusty-updates InRelease [65.9 kB] ... Remember that you will have to log out and back in for this to take effect! Connection to 10.0.2.186 closed.
Готово.
Проверяем на любом хосте:
# ssh -i my-cluster.pem [email protected] ... $ docker info Containers: 0 Running: 0 Paused: 0 Stopped: 0 Images: 0 Server Version: 1.12.0 Storage Driver: aufs Root Dir: /var/lib/docker/aufs
Запуск Consul
Consul будет играть роль service discovery (см. тут>>> и тут>>>).
Ручная установка Consul описана в посте Consul: установка и базовые операции.
Подключаемся на ноду Consul0:
$ ssh [email protected] -i my-cluster.pem ... ubuntu@ip-10-0-2-186:~$
Запускаем Consul на порту 8500
:
$ sudo -s # docker run -d -p 8500:8500 --name=consul progrium/consul -server -bootstrap d1c0b41ca61f7276b79f58b675d2980dd8f04b4207dd501c6049c45c6bcc7053
Проверяем:
# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d1c0b41ca61f progrium/consul "/bin/start -server -" 18 seconds ago Up 17 seconds 53/tcp, 53/udp, 8300-8302/tcp, 8400/tcp, 8301-8302/udp, 0.0.0.0:8500->8500/tcp consul
Проверяем Consul – логинися в контейнер и выполняем consul members
:
# docker exec -ti d1c0b41ca61f consul members Node Address Status Type Build Protocol DC d1c0b41ca61f 172.17.0.2:8301 alive server 0.5.2 2 dc1
Запуск Swarm-master0
Возвращаемся к первому мастеру:
bash-4.3# exit ubuntu@ip-10-0-2-186:~$ logout Connection to 10.0.2.186 closed.
(хотя можно оставить октрытым во вкладке для дебага позже)
Запускаем первый Swarm-manager:
# docker run -d -p 4000:4000 swarm manage -H :4000 --replication --advertise 10.0.1.103:4000 consul://10.0.2.186:8500 Unable to find image 'swarm:latest' locally latest: Pulling from library/swarm 148ee29ca1ff: Pull complete 6059dedfee26: Pull complete 64a5b64b008f: Pull complete Digest: sha256:5ff2c5e085320680a1094fdd279d3420a9b240887287d4610810903e46a3ee50 Status: Downloaded newer image for swarm:latest b5c8f53123aa763998213383b901914d29353a03cd85a51397bdbcf8cf341655
Тут: 10.0.1.103 – IP мастера, 10.0.2.186 – адрес Consul-ноды в приватной подсети.
Проверяем:
# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 37e262e19cab swarm "/swarm manage -H :40" 19 seconds ago Up 18 seconds 2375/tcp, 0.0.0.0:4000->4000/tcp reverent_tesla
Повторяем на втором мастере:
# ssh [email protected] -i my-cluster.pem $ sudo -s # docker run -d -p 4000:4000 swarm manage -H :4000 --replication --advertise 10.0.1.245:4000 consul://10.0.2.186:8500 12a85ee872e4324c4605e23ee19fff78b3f119377729286880f4a4104757c56b
Возвращаемся на Мастер0:
root@ip-10-0-1-245:~# exit ubuntu@ip-10-0-1-245:~$ logout Connection to 10.0.1.245 closed. root@ip-10-0-1-103:~#
Добавление нод в кластер
Подключаем обе ноды.
Node0:
# ssh [email protected] -i my-cluster.pem $ sudo -s # docker run -d swarm join --advertise=10.0.2.33:2375 consul://10.0.2.186:8500 Unable to find image 'swarm:latest' locally latest: Pulling from library/swarm 148ee29ca1ff: Pull complete 6059dedfee26: Pull complete 64a5b64b008f: Pull complete Digest: sha256:5ff2c5e085320680a1094fdd279d3420a9b240887287d4610810903e46a3ee50 Status: Downloaded newer image for swarm:latest 3725c67a839bb13d5847dd97941b55107be94a69c4b03272073f7ef52570880e root@ip-10-0-2-33:~# exit ubuntu@ip-10-0-2-33:~$ logout Connection to 10.0.2.33 closed.
Node1:
# ssh [email protected] -i my-cluster.pem $ sudo -s # docker run -d swarm join --advertise=10.0.2.185:2375 consul://10.0.2.186:8500 Unable to find image 'swarm:latest' locally latest: Pulling from library/swarm 148ee29ca1ff: Pull complete 6059dedfee26: Pull complete 64a5b64b008f: Pull complete Digest: sha256:5ff2c5e085320680a1094fdd279d3420a9b240887287d4610810903e46a3ee50 Status: Downloaded newer image for swarm:latest 85febf58b870f10171a2406341f3f657e10c74c1f5bfa43bf637ba7b1e3b2822 root@ip-10-0-2-185:~# exit ubuntu@ip-10-0-2-185:~$ logout Connection to 10.0.2.185 closed.
Вернувшись в консоль Master0 – проверяем статус:
# docker -H :4000 info Containers: 10 Running: 2 Paused: 0 Stopped: 8 Images: 2 Server Version: swarm/1.2.4 Role: primary Strategy: spread Filters: health, port, containerslots, dependency, affinity, constraint Nodes: 2 ip-10-0-2-33: 10.0.2.33:2375 └ ID: 75JN:6IUX:VFEH:7WRA:LBUU:UZIU:P34I:VAJP:AALI:2G4I:QJXB:ETUE └ Status: Healthy └ Containers: 5 (1 Running, 0 Paused, 4 Stopped) └ Reserved CPUs: 0 / 1 └ Reserved Memory: 0 B / 618 MiB └ Labels: kernelversion=3.13.0-33-generic, operatingsystem=Ubuntu 14.04.1 LTS, storagedriver=aufs └ UpdatedAt: 2016-08-11T15:39:37Z └ ServerVersion: 1.12.0 ip-10-0-2-185: 10.0.2.185:2375 └ ID: MR63:UDFV:IH65:2ZWE:CR3B:UCLP:4YGC:FEY3:4ESN:WU2E:3MUJ:67DG └ Status: Healthy └ Containers: 5 (1 Running, 0 Paused, 4 Stopped) └ Reserved CPUs: 0 / 1 └ Reserved Memory: 0 B / 618 MiB └ Labels: kernelversion=3.13.0-33-generic, operatingsystem=Ubuntu 14.04.1 LTS, storagedriver=aufs └ UpdatedAt: 2016-08-11T15:40:04Z └ ServerVersion: 1.12.0 Plugins: Volume: Network: Swarm: NodeID: Is Manager: false Node Address: Security Options: Kernel Version: 3.13.0-33-generic Operating System: linux Architecture: amd64 CPUs: 2 Total Memory: 1.207 GiB Name: 80e595613215 Docker Root Dir: Debug Mode (client): false Debug Mode (server): false WARNING: No kernel memory limit support
И напрямую из Consul – смотрим ноды:
# docker run swarm list consul://10.0.2.186:8500 time="2016-08-11T09:48:54Z" level=info msg="Initializing discovery without TLS" 10.0.2.185:2375 10.0.2.33:2375
На сообщение “Initializing discovery without TLS” можно пока забить, т.к. всё работает по внутренней приватной сети без доступа снаружи, но потом лучше настроить TLS.
Обращаем внимание на строку:
... Role: primary ...
Если выполнить на втором мастере – то увидим:
# ssh -i my-cluster.pem [email protected] "bash -c 'sudo docker -H :4000 info | grep Role:'" sudo: unable to resolve host ip-10-0-1-245 WARNING: No kernel memory limit support Role: replica
Запускаем на ферме NGINX:
# docker -H :4000 run -d nginx dec406413b21052c5ce305c3f8485603dd951cb0487775c1027c716f591e899c
Проверяем:
# docker -H :4000 ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES dec406413b21 nginx "nginx -g 'daemon off" 4 seconds ago Up 3 seconds 80/tcp, 443/tcp ip-10-0-2-33/elegant_jepsen
Ссылки по теме:
Build a Swarm cluster for production (какой production…)
The Docker Ecosystem: Service Discovery and Distributed Configuration Stores
Set up Docker Swarm Cluster Using Consul
Running a Small Docker Swarm Cluster