Привет Хабр! Я продолжаю цикл статей о том, как построить свой облачный хостинг за 5 минут. В прошлой статье мы рассмотрели инструменты, которые помогут решить нам проблему обнаружения сервисов (Service Discovery). В это части мы приступим к практике, построим облако и посмотрим как эти инструменты ведут себя в реальной жизни.
Как и прежде, всю работу может выполнить обычный программист в течении 5 минут, просто запустив набор сценариев для Ansible, которые я подготовил специально для вас и выложил на GitHub.
Несмотря на то, что наше облако стало сложнее и теперь в нём используется бо́льшее число инструментов, построить его стало проще. Я полностью переписал набор сценариев из прошлых статей, удалил всё лишнее, остальное упростил настолько, насколько это вообще возможно.
Содержание
- Ansible, Docker, Docker Swarm
- Service Discovery
- Consul, Registrator, Consul-Template
- …
Приступаем
У вас на клиентской машине должен быть установлен Ansible и Docker. В наличии должно быть 3 сервера с авторизацией по ключу и Debian 8.1 x64 на борту (вы можете использовать любой другой дистрибутив, внеся небольшие изменения в сценарии).
Скачиваем набор сценариев или клонируем репозиторий:
» git clone https://github.com/vkozlovski/ansible-cloud-hosting » cd ansible-cloud-hosting » git checkout v2.x
IP адреса
Открываем файл stage и заменяем в нем IP адреса на IP своих серверов:
[dc1-cloud] 192.168.1.1 192.168.1.2 192.168.1.3
Если вы хотите построить облако в нескольких датацентрах, то просто добавьте дополнительные группы с соответствующими IP адресами (по аналогии с тем, как это уже сделано):
[dc1-cloud] 192.168.1.1 192.168.1.2 192.168.1.3 [dc2-cloud] 192.168.2.1 192.168.2.2 192.168.2.3 #--- in all DC ---# # cloud in all DC [cloud:children] dc1-cloud dc2-cloud #--- everything in DC ---# [dc1:children] dc1-cloud [dc2:children] dc2-cloud
Центр сертификации
Теперь надо сгенерировать ключи для нашего центра сертификации, которыми будут подписаны сертификаты клиентов и серверов Docker‘a (более подробно об этом написано в первой статье). Для этого я создал небольшой помощник, поэтому из корневой директории проекта выполняем команду:
» make gen-ca
Generating RSA private key, 4096 bit long modulus ...++ ................++ e is 65537 (0x10001) Enter pass phrase for certs/ca/ca-key.pem: Verifying - Enter pass phrase for certs/ca/ca-key.pem: Enter pass phrase for certs/ca/ca-key.pem: You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:US State or Province Name (full name) [Some-State]:California Locality Name (eg, city) []:Cupertino Organization Name (eg, company) [Internet Widgits Pty Ltd]:Ansible Cloud Hosting Organizational Unit Name (eg, section) []: Common Name (e.g. server FQDN or YOUR name) []:example.com Email Address []:postmaster@example.com
Отвечаем на вопросы (тут нет никаких конкретный требований, домен можете указать любой) и запоминаем пароль. Пароль необходимо присвоить переменной certs_ca_password в файле group_vars/all.yml.
--- common_packages: - sudo - htop - mc - git - apt-transport-https - python-setuptools # easy_install (necessary for install python pip) debian_release: jessie certs_ca_password: '1234' # ;)
Сертификаты
На этом шаге надо сгенерировать сертификаты для Consul. Для этого я тоже создал небольшой помощник, поэтому из корневой директории проекта просто выполняем команду:
» make gen-consul-certs
Generating a 2048 bit RSA private key ..........................+++ .................................................+++ writing new private key to 'privkey.pem' ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:US State or Province Name (full name) [Some-State]:California Locality Name (eg, city) []:Cupertino Organization Name (eg, company) [Internet Widgits Pty Ltd]:Ansible Cloud Hosting Organizational Unit Name (eg, section) []: Common Name (e.g. server FQDN or YOUR name) []:example.com Email Address []:postmaster@example.com Generating a 1024 bit RSA private key ...........................++++++ ..............++++++ writing new private key to 'consul.key' ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:US State or Province Name (full name) [Some-State]:California Locality Name (eg, city) []:Cupertino Organization Name (eg, company) [Internet Widgits Pty Ltd]:Ansible Cloud Hosting Organizational Unit Name (eg, section) []: Common Name (e.g. server FQDN or YOUR name) []:example.com Email Address []:postmaster@example.com Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []: Using configuration from myca.conf Check that the request matches the signature Signature ok The Subject's Distinguished Name is as follows countryName :PRINTABLE:'US' stateOrProvinceName :PRINTABLE:'California' localityName :PRINTABLE:'Cupertino' organizationName :PRINTABLE:'Ansible Cloud Hosting' commonName :PRINTABLE:'example.com' emailAddress :IA5STRING:'postmaster@example.com' Certificate is to be certified until Nov 22 16:25:08 2025 GMT (3650 days) Write out database with 1 new entries Data Base Updated ------------------------------------------------------------
Если вы хотите подробнее разобраться в том, что именно происходит на этом шаге, то можете ознакомиться с отличной статьёй на DigitalOcean.
Секретный ключ
Теперь нам надо сгенерировать секретный ключ, который Consul будет использовать для шифрования своего сетевого траффика. Для этого выполняем команду:
» docker run --rm --entrypoint "/bin/consul" progrium/consul:latest keygen L+3UkrkFeXHQBT97nTZI/g==
Ключ необходимо присвоить переменной docker_consul_encrypt в файле group_vars/cloud.yml.
--- # docker docker_api_version: 1.18 docker_key_server: "hkp://pgp.mit.edu:80" docker_key_id: "58118E89F3A912897C070ADBF76221572C52609D" # docker-consul docker_consul_encrypt: 'L+3UkrkFeXHQBT97nTZI/g==' docker_consul_start_join_wan: - "{{ hostvars[groups['dc1'][0]]['ansible_eth0']['ipv4']['address'] }}" # first host in DC1
Настройки для датацентра
Файл dc1.yml в директории group_vars содержит конфигурацию, специфичную для конкретного датацентра. Если у вас их больше одного, то можете создать dc2.yml, dc3.yml, … и заполнить их по аналогии.
--- # docker-consul # first host in "my_name_dc" DC docker_consul_join: '{{ hostvars[groups["my_name_dc"][0]]["ansible_eth0"]["ipv4"]["address"] }}' docker_consul_dc: 'dc1' # docker-swarm-manager # first host in "my_name_dc" DC docker_swarm_manager_ip: '{{ hostvars[groups["my_name_dc"][0]]["ansible_eth0"]["ipv4"]["address"] }}'
Consul
Если вы строите облако в нескольких центрах обработки данных, то у меня для вас хорошие новости – Consul поддерживает это «из коробки». Единственное, что вам необходимо сделать, это добавить под одному IP из каждого ЦОДа в переменную docker_consul_start_join_wan:
--- # docker docker_api_version: 1.18 docker_key_server: "hkp://pgp.mit.edu:80" docker_key_id: "58118E89F3A912897C070ADBF76221572C52609D" # docker-consul docker_consul_encrypt: 'L+3UkrkFeXHQBT97nTZI/g==' docker_consul_start_join_wan: - "{{ hostvars[groups['dc1'][0]]['ansible_eth0']['ipv4']['address'] }}" # first host in DC1 - "{{ hostvars[groups['dc2'][0]]['ansible_eth0']['ipv4']['address'] }}" # first host in DC2 ...
Запускаем
Если вы дошли до этого шага – вас ждёт вознаграждение. Запускаем помощник:
» make run
Теперь вы можете «откинуться на спинку кресла и отдохнуть».
Владельцы табуреток — берегите себя.
После того, как магия закончится, я рекомендую перезагрузить все машины.
Готово!
Consul UI
Открываем браузер и переходим по любому из IP адресов наших машин (http://192.168.1.1:8500/). Если вы настраивали несколько датацентров, то должны увидеть похожую картину:
Если центр обработки данных у вас один или вы выбрали его из списка выше:
Consul отображает список сервисов из которых состоит наше облако. Зелёным цветом отображаются «здоровые» сервисы, жёлтым цветом – проблемные (в прошлой статье я упоминал, что Consul умеет проверять здоровье сервисов).
Docker Swarm
Давайте проверим Docker Swarm (более подробно можете почитать о нём в первой статье). Docker Swarm Manager устанавливается на первый IP адрес каждого датацентра из списка в файле stage. Например из списка:
[dc1-cloud] 192.168.1.1 192.168.1.2 192.168.1.3 [dc2-cloud] 192.168.2.1 192.168.2.2 192.168.2.3 #--- in all DC ---# # cloud in all DC [cloud:children] dc1-cloud dc2-cloud #--- everything in DC ---# [dc1:children] dc1-cloud [dc2:children] dc2-cloud
это будут 192.168.1.1 и 192.168.2.1.
Для того, что бы подключиться к Docker Swarm Manager необходимо выполнить:
» docker -H tcp://192.168.1.1:8000 --tlsverify=true --tlscacert=certs/ca/ca.pem --tlscert=certs/docker/cert.pem --tlskey=certs/docker/key.pem info
Вы должны лицезреть что-то похожее:
Containers: 13 Images: 12 Role: primary Strategy: spread Filters: health, port, dependency, affinity, constraint Nodes: 3 debian1: 192.168.1.1:2376 └ Containers: 5 └ Reserved CPUs: 0 / 1 └ Reserved Memory: 0 B / 519.2 MiB └ Labels: executiondriver=native-0.2, kernelversion=3.16.0-4-amd64, operatingsystem=Debian GNU/Linux 8 (jessie), storagedriver=aufs debian2: 192.168.1.2:2376 └ Containers: 4 └ Reserved CPUs: 0 / 1 └ Reserved Memory: 0 B / 519.2 MiB └ Labels: executiondriver=native-0.2, kernelversion=3.16.0-4-amd64, operatingsystem=Debian GNU/Linux 8 (jessie), storagedriver=aufs debian3: 192.168.1.3:2376 └ Containers: 4 └ Reserved CPUs: 0 / 1 └ Reserved Memory: 0 B / 519.2 MiB └ Labels: executiondriver=native-0.2, kernelversion=3.16.0-4-amd64, operatingsystem=Debian GNU/Linux 8 (jessie), storagedriver=aufs CPUs: 3 Total Memory: 1.521 GiB Name: debian1
Если это так, а должно быть именно так, тогда остаётся только поздравить вас. Если возникли какие-то трудности – добро пожаловать в комментарии.
Тестируем
Пришло время что-нибудь запустить в нашем крутом облаке. И что же это может быть, если не Nginx? Вот именно!
Запускаем:
» docker -H tcp://178.62.232.38:8000 --tlsverify=true --tlscacert=certs/ca/ca.pem --tlscert=certs/docker/cert.pem --tlskey=certs/docker/key.pem run -d -p 80:80 -p 443:443 -e "SERVICE_80_NAME=http" -e "SERVICE_443_NAME=https" nginx
Подробнее о переменных окружения, которые мы передаём здесь, вы можете почитать в прошлой статье.
Смотрим на какой машине был запущен Nginx:
» docker -H tcp://192.168.1.1:8000 --tlsverify=true --tlscacert=certs/ca/ca.pem --tlscert=certs/docker/cert.pem --tlskey=certs/docker/key.pem ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e96b351a857e nginx "nginx -g 'daemon off" 3 minutes ago Up 3 minutes 192.168.1.2:80->80/tcp, 192.168.1.2:443->443/tcp debian2/fervent_dubinsky ...
Открываем в браузере http://192.168.1.2:80/:
Есть контакт. Теперь глянем появился ли наш сервис в панели Consul’а:
Появились 2 сервиса (по количеству портов): http и https (их названия мы передали в переменных SERVICE_80_NAME и SERVICE_443_NAME).
DNS
Давайте теперь проверим работу службы DNS, которую нам любезно предоставил Consul. Для этого запустим на какой-нибудь машине контейнер с Debian:
» docker -H tcp://192.168.1.1:8000 --tlsverify=true --tlscacert=certs/ca/ca.pem --tlscert=certs/docker/cert.pem --tlskey=certs/docker/key.pem run -ti debian:testing /bin/bash root@2e68749354b2:/#
Смотрим есть ли наша служба http:
root@2e68749354b2:/# ping http PING http.service.consul (172.17.0.6): 56 data bytes 64 bytes from 172.17.0.6: icmp_seq=0 ttl=64 time=0.076 ms 64 bytes from 172.17.0.6: icmp_seq=1 ttl=64 time=0.118 ms 64 bytes from 172.17.0.6: icmp_seq=2 ttl=64 time=0.075 ms ^C--- http.service.consul ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max/stddev = 0.075/0.090/0.118/0.000 ms
Полный адрес нашего сервиса http.service.consul, но мы можем обращаться и по короткому http (потому что Docker мы запустили с параметром —dns-search service.consul). Также мы можем использовать и более длинный вариант http.service.dc1.consul с указанием датацентра (если вы хотите достучаться до сервиса из другого ЦОДа, например). Более подробно об этом вы можете почитать в официальной документации.
Давайте запустим еще несколько копий Nginx. Откройте другую вкладку в консоли (контейнер с Debian нам понадобится) и выполните 2 раза команду:
» docker -H tcp://178.62.232.38:8000 --tlsverify=true --tlscacert=certs/ca/ca.pem --tlscert=certs/docker/cert.pem --tlskey=certs/docker/key.pem run -d -p 80:80 -p 443:443 -e "SERVICE_80_NAME=http" -e "SERVICE_443_NAME=https" nginx
Docker Swarm достаточно умён, что бы запустить все 3 сервиса на разных машинах (смотрит где есть свободные 80 и 443 порты). И если вы попробуете запустить больше копий Nginx, чем у вас машин, то он сообщит об этом:
Error response from daemon: unable to find a node with port 443 available
Теперь вернёмся в контейнер с Debian и поставим пакет:
root@2e68749354b2:/# apt-get update && apt-get install dnsutils --no-install-recommends
Посмотрим появились ли новые http сервисы:
root@866f410a5f18:/# dig http.service.dc1.consul. ANY ; <<>> DiG 9.9.5-12+b1-Debian <<>> http.service.dc1.consul. ANY ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 17731 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;http.service.dc1.consul. IN ANY ;; ANSWER SECTION: http.service.dc1.consul. 0 IN A 192.168.1.1 http.service.dc1.consul. 0 IN A 192.168.1.2 http.service.dc1.consul. 0 IN A 192.168.1.3 ;; Query time: 4 msec ;; SERVER: 172.17.0.1#53(172.17.0.1) ;; WHEN: Thu Nov 26 10:22:41 UTC 2015 ;; MSG SIZE rcvd: 158
Всё работает.
Если вы будете обращаться к вашему сервису по имени http, то нагрузка будет распределяться по алгоритму Round-robin. Если вы сейчас остановите один из контейнеров с Nginx и повторно выполните вышеуказанную команду, то заметите, что его уже нет в списке.
Таким образом нагрузка распределяется только между «живыми» сервисами. Также у вас есть возможность воспользоваться мониторингом здоровья, который предоставляет Consul, в таком случае вы можете распределить нагрузку только между «здоровыми» сервисами (не путайте с просто «живыми»).
Вы можете добавлять и удалять сервисы динамически и всё будет продолжать работать без вашего вмешательства.
Заключение
В этой статье я хотел рассказать вам, как поднять своё персональное облако.
Если вы были внимательны, а я уверен, что это так, то заметили, что мы не воспользовались Consul-Template. Я решил открыть для вас ещё одну часть своих наработок и описать процесс автоматического развёртывания проектов в наше облако в следующей статье. Понадобилось какое-то время, что бы найти подходящий вариант для этих целей и теперь это экономит нам массу времени.
Какими сервисами «наполнить» ваше облако – решать вам. Я поработал на этой конфигурации достаточно долго и не встретил каких-либо проблем.
На этом всё. Всем спасибо за внимание. Стабильных вам облаков и удачи!
P.S. Я ищу разработчиков в стартап, подробности у меня в профиле.
Также вы можете подписываться на меня в социальных сетях (указаны в профиле) и задавать там свои вопросы. Работы у меня всегда много, но в свободное время я стараюсь всем отвечать.
ссылка на оригинал статьи http://habrahabr.ru/post/264269/
Добавить комментарий