Свій хмарний хостинг за 5 хвилин. Частина 3: Consul, Registrator, Consul-Template

Docker friends

Привіт Хабр! Я продовжую цикл статей про те, як побудувати свій хмарний хостинг за 5 хвилин. минулій статті ми розглянули інструменти, які допоможуть нам вирішити проблему виявлення сервісів (Service Discovery). В це ми приступимо до практики, побудуємо хмара і подивимося як ці інструменти ведуть себе в реальному житті.

Як і раніше, всю роботу може виконати звичайний програміст протягом 5 хвилин, просто запустивши набір сценаріїв для Ansible, які я підготував спеціально для вас і виклав на GitHub.

Незважаючи на те, що наше хмара стало складніше і тепер в ньому використовується більша кількість інструментів, побудувати його стало простіше. Я повністю переписав набір сценаріїв з минулих статей, видалив все зайве, решта спростив настільки, наскільки це взагалі можливо.

Зміст

  1. Ansible, Docker, Docker Swarm
  2. Service Discovery
  3. Consul, Registrator, Consul-Template
  4. ...
Приступаємо
У вас на клієнтській машині повинен бути встановлений 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 blank some
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.

Результат 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 blank some
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 blank some
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.

Секретний ключ

image
Тепер нам треба згенерувати секретний ключ, який Consul буде використовувати для шифрування свого мережевого трафіку. Для цього виконуємо команду:

» docker run --rm --entrypoint "/bin/consul" progrium/consul:latest keygen
L+3UkrkFeXHQBT97nTZI/g==

Ключ необхідно привласнити змінної docker_consul_encrypt у файлі group_vars/cloud.yml.

Результат 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:

Приклад 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
- "{{ 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 IMAGE ID 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. Я шукаю розробників в стартап, подробиці у мене в профілі.

Також ви можете підписуватися на мене в соціальних мережах (вказані в профілі) і ставити там свої питання. Роботи у мене завжди багато, але у вільний час я намагаюся всім відповідати.


Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.