Усунення безладу маршрутизації сервісів за допомогою Docker

Усунення безладу маршрутизації сервісів за допомогою Docker
«Не труднощі „ламають“ вас, а те, як ви їх переносите» — Lou Holtz
У співавторстві з Emmet o'grady (засновником NimbleCI і Docker Ninja)
У книзі Франца Кафки «Перетворення» («Метаморфози») людина прокидається одного ранку і виявляє, що він перетворився в гігантську насекомоподобное істота. Як у інженерів DevOps, у нас є такі ж сюрреалістичні моменти в житті. Ми знаходимо екзотичні помилки «під килимком» (приховані в самих важкодоступних місцях) або буваємо атаковані хробаками або іншими небезпечними істотами. Якщо ви займаєтеся цим досить довго, у вас рано чи пізно з'явиться жахлива історія, чи навіть дві (поділіться ними з нами!). В такий момент ми не можемо сидіти і чекати, коли настане криза, ми повинні діяти швидко. Поспішаючи виправити це якомога раніше, ми повинні розгорнути (deploy) нову сутність і випустити нову версію нашого сервісу, усуваючи проблему.
Як щодо іншого сюрреалістичного моменту: ваш додаток отримує популярність в засобах масової інформації, багатолюдному Slack каналі (чаті) або вашої внутрішньої дошці оголошень. Користувачі прийдуть швидко і блискавично на ваш сайт, ваш сервіс буде переповнений ними, кількість користувачів досягне ліміту і навіть вийде за його межі. В шаленій гонці, намагаючись усунути помилку 502, ви повинні знайти сервери, запустити нові сутності, і переконфігурувати вашу мережу і ваші балансировщики навантаження. Ви судорожно намагаєтеся скласти всі шматочки разом. Ви відчуваєте себе, як ніби вам належить бій ложкою проти ножа. Мрійливо ви думаєте: «Це повинно бути автоматизовано», можливо тоді у мене буде більше часу, щоб розслабитися і почитати класику.
Не випробовуйте більше подібних почуттів! Docker 1.12 допоможе вам. Цей реліз поставляється з набором нових функцій, що забезпечують наступні умови:
  • Швидке розгортання і відкат сервісу
  • Автоматичне балансування навантаження
  • Включення масштабування послуг і інфраструктури, в якій вони працюють
  • Відновлення служби або відмовили вузлів автоматично
І, коли ви вивчите те, що пропонує Docker, він виявиться простий у використанні.
Сітка маршрутизації
Docker 1.12 надає повний набір нових визначень. Один з них — нова функція, звана «Сітка маршрутизації». Геометрія комп'ютерної мережі та її алгоритм маршрутизації не є чимось новим, геніальність інженерної команди Docker'а полягала в тому, щоб використовувати цей підхід для спрощення поставки змін програмного забезпечення і служби виявлення в Мікро-сервісній архітектурі. «Сітка» — це просто новий шлях маршрутизації і балансування трафіку в контейнерах Docker'а 1.12. Нова стратегія маршрутизації дозволяє сервісу досягти однакового порту на всіх вузлах у Swarm, навіть якщо вузол не має сервісу, розгорнутого на ньому. Сітка маршрутизації також прозоро розподіляє запити по всім доступним сервісів в Swarm, визначаючи збійні вузли.
Ваша мережа сьогодні виглядає також?
Новий підхід робить дуже простим налаштування балансування навантаження сервісів: уявіть три вузла Swarm з сімома різними сервісами запущеними в Swarm. Ззовні ми можемо послати запит на будь-який вузол і він буде переданий (маршрутизирован) випадковому сервісу автоматично, або ми завжди можемо послати запит одному вузлу і Docker внутрішньо розподілить баланс між сервісами. Таким чином ми отримуємо балансування навантаження сервісів своїми внутрішніми силами.
Сітка маршрутизації дозволяє нам обробляти контейнери по справжньому прозоро, в тому сенсі, що ми не хвилюємося, як багато контейнерів обслуговує наш додаток, кластер обробляє всю мережу і виробляє балансування навантаження. Якщо до цього ми повинні були підключити зворотний проксі-сервер перед сервісами, який повинен був діяти в якості балансувальника навантаження, тепер ми можемо розслабитися і дозволити Docker'у здійснювати балансування навантаження за нас. Оскільки Docker виконує всю брудну роботу за нас, відмінність між ситуаціями, коли у нас є один контейнер і 100 контейнерів тепер стало тривіально маленьким; це просто причина мати ще комп'ютерні (обчислювальні) ресурси, щоб бути в змозі масштабувати і потім запускати лише одну команду для збільшення масштабування. Нам більше не потрібно думати про архітектурному аналізі перед масштабуванням, з тих пір як все це виконує Docker. Коли він починає масштабування, ми можемо розслабитися, знаючи, що Docker виконає його прозоро, для одного контейнера також як і 100.
Вам може бути цікаво, чому ми використовуємо термінологію «сервіси», замість «контейнери». Це ще дещо нове в Docker'е 1.12, давайте подивимося.
Сервіси та завдання
Docker 1.12 вводить нову абстракцію — «сервіси». Сервіси визначають бажаний стан контейнерів у кластері. Внутрішнє ядро використовує цей новий концепт, щоб пересвідчитися, що контейнери запущені, обробляють помилки і маршрутизируют трафік до контейнерів.
Давайте зануримося трохи глибше і обговоримо нові концепції завдань. Сервіси складаються із завдань, які представляють одну сутність контейнера, який повинен бути запущений. Swarm створює розклад виконання цих завдань між вузлами. Сервіси здебільшого визначають запущені сутності контейнерів (завдань), які повинні бути запущені весь час, так само, як вони повинні працювати (конфігурації і прапори для кожного контейнера), а також їх оновлення (наприклад, плаваючі оновлення). Все це разом являє бажане стан сервісу і ядро Docker'а постійно контролює поточний стан кластера і вносить зміни, для того щоб переконатися, що вони збігаються з тим станом, який ви хочете.
Ось невелике превью сервісу redis, який буде розглянутий пізніше в цій статті. Щоб запустити його, ми повинні виконати команду, подібну до цієї:
$ docker service create --name redisdb --replicas=3 redis:alpine

Сітка маршрутизації в дії
Годі теорії, давайте побачимо все це у дії. Ми почнемо з невеликого nodejs-сервісу, який допоможе показати внутрішню роботу сітки маршрутизації. Ви знайдете код на GitHub тут. Давайте розглянемо найбільш важливий файл webapp.js:
// Приклад веб-сервера, який повертає свою версію, ім'я хоста, IP і кількість відвідувань
var http = require('http');
var os = require("os");
var redis = require('redis');

var server = http.createServer(function (request, response) {

// Починаємо створення і чекаємо на відповідь "OK"
response.writeHead(200, {"Content-Type": "text/plain"});

// а також записуємо в log змінні, які ми будемо використовувати в нашому відповіді
var version = "2.0";
var log = {};
log.header = 'webapp';
log.name = os.hostname();
log.version = version;

// Пройдемо через мережеві інтерфейси для отримання адрес IPv4
var interfaces = os.networkInterfaces();
var addresses = [];
for (var k in interfaces) {
for (var k2 in interfaces[k]) {
var address = interfaces[k][k2];
if (address.family === 'IPv4' && !address.internal) {
addresses.push(address.address);
}
}
}
log.nics = addresses;

// Постараємося отримати наш redis-сервер (redisdb) на ІМ'Я
var client = redis.createClient('6379', 'redisdb');
client.on('connect', function(err,reply) {
if (err) return next(err);
console.log('Connected to Redis server'); 
client.incr('counter', function(err, reply) {
if(err) return next(err);
console.log('This page has been viewed' + reply + ' times!');
console.log(JSON.stringify(log));
response.end(“ Hello, i'm version “+ log.version +".My hostname is “+ log.name +", this page has been viewed "+ reply +"\n and my ip addresses are " + log.nics + "\n" );

}); // client.incr
}); // client.on

}); // http.createHttpServer

// Давайте почекаємо http-відповіді на порт 8000
server.listen(8000);

Сервіс тільки повертає ім'я хоста, IP-адресу контейнера, що запустив його, і лічильник з кількістю візитів.
Ось і все наше додаток. Перед тим як зануритися в нього, ми повинні бути впевнені, що перейшли на Docker 1.12
$ docker version
Client:
Версія: 1.12.0
API версія: 1.24
Go version: go1.6.3
Git commit: 8eab29e
Built: Thu Jul 28 21:04:48 2016
OS/Arch: darwin/amd64
Experimental: true

Server:
Версія: 1.12.0
API версія: 1.24
Go version: go1.6.3
Git commit: 8eab29e
Built: Thu Jul 28 21:04:48 2016
OS/Arch: linux/amd64
Experimental: true

Ми почнемо з створення кластера з 3 вузлів, використовуючи Docker-машину:
$ docker-machine create --driver virtualbox swarm-1
Running pre-create checks...
Creating machine...
...
Setting Docker configuration on the remote daemon...
Checking connection to Docker...
Docker is up and running!
...

$ docker-machine create --driver virtualbox swarm-2
...
Docker is up and running!
$ docker-machine create --driver virtualbox swarm-3
...
Docker is up and running!

$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
swarm-1 — virtualbox Running tcp://192.168.99.106:2376 v1.12.0
swarm-2 — virtualbox Running tcp://192.168.99.107:2376 v1.12.0
swarm-3 — virtualbox Running tcp://192.168.99.108:2376 v1.12.0

Для ясності ми скоротили висновок деяких команд. Потім, ми налаштуємо наш Swarm. Docker 1.12 дозволяє зробити це дуже просто:
$ eval $(docker-machine env swarm-1)
$ docker swarm init --advertise-addr $(docker-machine ip swarm-1)
Swarm initialized: current node (bihyblm2kawbzd3keonc3bz0l) is now a manager.

To add a worker to this swarm, run the following command:
docker swarm join \
--token SWMTKN-1–1n7gtfmvvrlwo91pv4r59vsdf73bwuwodj3saq0162vcsny89l-5zige8u81ug5adk3o4bsx32fi \
192.168.99.106:2377
...

Тепер, ми скопіюємо і вставимо команду, яка була на виході попередньої команди для вузла «працівник», у двох інших вузлах
$ eval $(docker-machine env swarm-2)
$ docker swarm join \
--token SWMTKN-1–1n7gtfmvvrlwo91pv4r59vsdf73bwuwodj3saq0162vcsny89l-5zige8u81ug5adk3o4bsx32fi \
192.168.99.106:2377
This node joined a swarm as a worker.

$ eval $(docker-machine env swarm-3)
$ docker swarm join \
--token SWMTKN-1–1n7gtfmvvrlwo91pv4r59vsdf73bwuwodj3saq0162vcsny89l-5zige8u81ug5adk3o4bsx32fi \
192.168.99.106:2377
...
This node joined a swarm as a worker.

Зверніть увагу: коли ви инициализируете новий Swarm, команда виведе дві нові команди, які ви можете використовувати, щоб приєднати інші вузли до Swarm. Не турбуйтеся про «втрату» цих команд; ви можете отримати їх знову в будь-який час, запустивши «docker swarm join-token worker|manager».
Перед тим, як продовжити, давайте переконаємося в тому, що наш swarm-кластер функціонує. Зазначимо наш Docker-клієнт для керуючого вузла і перевіримо його статус:
$ eval $(docker-machine env swarm-1)
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
5jqsuf8hsemi7bfbwzfdxfcg5 swarm-2 Ready Active
93f0ghkpsh5ru7newtqm82330 swarm-3 Ready Active
b2womami9n2t8tti1acvz6v5j * swarm-1 Ready Active Leader

$ docker info
...
Swarm: active
NodeID: b2womami9n2t8tti1acvz6v5j
Is Manager: true
ClusterID: bimg9n2ti2tnsprkdjqg07tdm
Managers: 1
Nodes: 3
Orchestration:
Task History Retention Limit: 5
Raft:
Snapshot interval: 10000
Heartbeat tick: 1
Election tick: 3
Пошук:
Heartbeat period: 5 seconds
CA configuration:
Expiry duration: 3 months
Node Address: 192.168.99.106

Приступимо до створення нової мережі, яку ми будемо використовувати для наших прикладів:
$ docker network create --driver overlay webnet
a9j4al25hzhk2m7rdfv5bqt54

Таким чином, тепер ми готові запустити новий сервіс для Swarm. Ми почнемо з запуску бази даних redis і контейнера «lherrera/webapp», який зберігає сторінки відвідування в redis і виводить інші цікаві деталі, такі як ім'я хоста або IP-адресу контейнера.
Коли ми розгортаємо наш веб-додаток, для нього стає можливим з'єднатися з базою даних redis використовуючи сервіс Redis «redisdb». Нам не потрібно використовувати IP-адреси, тому що Swarm має внутрішній DNS, який автоматично присвоює кожній службі DNS запис. Все дуже просто!
Ми можемо тільки розгорнути сервіси з керуючих вузлів. Поки ваш клієнт Docker'а ще вказує на керуючий вузол, ми можемо лише надрукувати в командному рядку «docker service create»:
$ docker service create --name webapp --replicas=3 --network webnet --publish 80:8000 lherrera/webapp:1.0
avq41soybmtw2jamdus0m3pg

$ docker service create --name redisdb --network webnet --replicas 1 redis:alpine
bmotumdr8bcewcfj6zqkws97x

$ docker service ls 
ID NAME REPLICAS IMAGE COMMAND
avq41soybmtw webapp 3/3 lherrera/webapp:1.0
bmotumdr8bce redisdb 1/1 redis:alpine

В команді створення сервісу нам необхідно вказати щонайменше образ (у нашому випадку lherrera/webapp). За угодою, ми також вказуємо ім'я webapp. Ми повинні також задати команду, для того щоб здійснити запуск всередині контейнерів тільки після (підключення) образу. У попередній команді ми також вказуємо, що ми хочемо три репліки контейнера, запущеного в будь-поточний момент часу. Використання прапора "— replicas" передбачає, що ми не повинні турбуватися, на який вузол він потрапить, якщо ми хочемо один сервіс на сайт, ми можемо використовувати замість цього команду "— mode=global".
Ви можете побачити, що ми використовуємо мережа «webnet», яку ми створили раніше. Щоб можна було створити наш сервіс ззовні Swarm, нам потрібно вказати порт, по якому Swarm прослуховує веб-запити. У нашому прикладі, ми «поставили» порт 8000 всередині сервісу на порт 80 на всіх вузлах. Завдяки решітці маршрутизації він буде резервувати порт 80 на всіх вузлах маршрутизації і Docker Engine буде балансувати трафік між портом 8000 у всіх репліках контейнера.
Swarm буде використовувати опис цього сервісу як бажаний стан для вашого застосування і почнуть розгортання програми на сайтах для досягнення і підтримання цього бажаного стану. Ми могли б вказати додаткові параметри сервісу, щоб завершити наш опис, такі як правила перезавантаження, ліміти пам'яті і ресурсів центрального процесора, контейнери вузлів і т. д. Для повного списку всіх доступних прапорів ви можете використовувати команду «docker service create» (дивіться тут).
На цьому етапі, ми можемо бути впевнені, що наш веб-додаток коректно з'єдналося з webnet мережею
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
df19a5c87d90 bridge bridge local
7c5762c8c6ff docker_gwbridge bridge local
eb0bd5a4920b host local host
bqqh4te5f5tf ingress overlay swarm
3e06a1616b7b none null local
a9j4al25hzhk webnet overlay swarm

$ docker service inspect webapp
...
"VirtualIPs": [
{
"NetworkID": "7i9t9uhtr7x0hybsvnsheh92u",
"Addr": "10.255.0.6/16"
},
{
"NetworkID": "a9j4al25hzhk2m7rdfv5bqt54",
"Addr": "10.0.0.4/24"
}
]
},
...

Тепер давайте повернемося до нашого прикладу і переконаємося, що наш сервіс запущений і працює:
$ docker service ps webapp
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
bb8n4iagxcjv4rn2oc3dj6cvy webapp.1 lherrera/webapp:1.0 swarm-1 Running Preparing about a minute ago
chndeorlvglj45alr4vhy50vg webapp.2 lherrera/webapp:1.0 swarm-3 Running Preparing about a minute ago
4txay0gj6p18iuiknacdoa91x webapp.3 lherrera/webapp:1.0 swarm-2 Running Preparing about a minute ago

Одне питання, в курсі якої треба бути: хоча Docker-сервіс створює команду, яка швидко повертається з id, фактичне масштабування сервісу може зайняти деякий час, особливо, якщо образи повинні перебувати на вузлах. В такому випадку лише запустіть команду «docker service ps webapp» кілька разів, поки всі репліки не будуть надані сервісу.
Коли запущені сервіси (це може зайняти декілька хвилин, запасіться кави на цей час), ми можемо перевірити, що наші сервіси отримують у відповідь на запити.
Спочатку ми повинні отримати IP першого вузла:
$ NODE1=$(docker-machine ip swarm-1)

Тоді ми встановимо порт 80 для того IP-адреси, тому що ми опублікували сервіс на порт 80 в Swarm. Ми використовуємо curl у прикладі нижче, але ви також можете задати IP у вашому браузері, щоб отримати той же результат.

Тепер, ми готові протестувати наш новий сервіс:
$ curl $NODE1
Hello, i'm version 1.0.My hostname is 5a557d3ed474, this page has been viewed 1
and my ip addresses are 10.255.0.9,10.255.0.6,172.18.0.3,10.0.0.7,10.0.0.4

$ curl $NODE1
Hello, i'm version 1.0.My hostname is 4e128c8af4ae, this page has been viewed 2
and my ip addresses are 10.255.0.7,10.255.0.6,172.18.0.3,10.0.0.5,10.0.0.4

$ curl $NODE1
Hello, i'm version 1.0.My hostname is eaa73f01996c, this page has been viewed 3
and my ip addresses are 10.255.0.8,10.255.0.6,172.18.0.4,10.0.0.6,10.0.0.4

Ми можемо побачити, що перший запит був направлений до контейнера «5a557d3ed474». Якщо ви натиснете "оновити" кілька разів або викличете «curl» повторно з командного рядка, ви побачите запит, який був посланий на всі три репліки контейнерів, які ми створили.
Для демонстрації інших аспектів сітки маршрутизації, спробуйте «призначити» порт 80 для IP двох інших вузлів Docker'а. Ви побачите те ж саме, що раніше, з цього випливає, що не має значення, який сайт ви запросили; над запитом завжди буде здійснена внутрішня балансування навантаження між трьома контейнерами.
Плаваючі оновлення (Роллінг-оновлення)
В якості частини опису сервісу, ви можете задати стратегію оновлення вашого сервісу. Наприклад, ви можете використовувати прапор
update-delay
, щоб настроїти затримку між оновленнями для завдання сервісу (контейнера) або набору завдань. Або ви можете використовувати прапор
update-parallelism
, щоб змінити поведінку за замовчуванням: оновлення одного контейнера за раз. Ви можете встановити всі ці прапори в процесі створення сервісу або пізніше, використовуючи команду «docker update service», як ми побачимо в наступному прикладі. Команда оновлення вимагає майже однакові параметри з командою «docker service create», але деякі прапори мають різні імена з командою оновлення. Все, що ви можете встановити в команді створення (create), ви можете змінити в команді оновлення (update), таким чином, ви маєте повну свободу змінювати будь-яку частину опису сервісу в будь-який час.
Застосування роллінг-оновлень вручну: бігти вниз по схилу, розуміючи, що ви вийшли з-під контролю
Давайте поновимо наш сервіс webapp, щоб побачити, як працює механізм «rolling update». Команда розробників наполегливо працювала, щоб поліпшити webapp і ми випустили новий тег під назвою «2.0». Зараз ми оновимо наш новий сервіс цим новим чином:
$ docker service update --update-parallelism 1 --update-delay 5s --image lherrera/webapp:2.0 webapp

Зверніть увагу, ми також вказали, що ми хочемо, щоб оновлення відбувалося за раз і поставили інтервал в 5 секунд між кожним оновленням. Цей підхід означає, що у нас не буде ніяких простоїв!
Поки відбуваються оновлення, перегляньте їх в реальному часі, запускаючи «docker service ps webapp» кожні кілька секунд. Ви побачите старі образи, вимикає один за одним, і заміняються новими:
$ docker service ps webapp
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
7bdpfbbjok78zt32xd9e2mqlt webapp.1 lherrera/webapp:2.0 swarm-3 Running Running 43 seconds ago
bb8n4iagxcjv4rn2oc3dj6cvy \_ webapp.1 lherrera/webapp:1.0 swarm-1 
Shutdown Shutdown 44 seconds ago
af2rlu0laqhrj3uz8brym0f8r webapp.2 lherrera/webapp:2.0 swarm-2 Running Running 30 seconds ago
chndeorlvglj45alr4vhy50vg \_ webapp.2 lherrera/webapp:1.0 swarm-3
Shutdown Shutdown 30 seconds ago
0xjt6gib1hql10iqj6866q4pe webapp.3 lherrera/webapp:2.0 swarm-1 Running Running 57 seconds ago
4txay0gj6p18iuiknacdoa91x \_ webapp.3 lherrera/webapp:1.0 swarm-2
Shutdown Shutdown 57 seconds ago

Це просто щось неймовірне!
Якщо наше додаток також друкує версію образу, інший шлях побачити оновлення в реальному часі — натиснути багаторазово (кінцеву) сервісу протягом оновлення. Коли сервіс буде оновлено, ви повільно побачите все більше і більше запитів, повертають «version 2.0», до тих пір, поки оновлення на завершиться і всі сервіси не повернуть версію 2.0.
$ curl $NODE1
Hello, i'm version 1.0.My hostname is 5a557d3ed474, this page has been viewed 4
and my ip addresses are 10.255.0.9,10.255.0.6,172.18.0.3,10.0.0.7,10.0.0.4

$ curl $NODE1
Hello, i'm version 2.0.My hostname is e0899324d9df, this page has been viewed 5
and my ip addresses are 10.255.0.10,10.255.0.6,172.18.0.4,10.0.0.8,10.0.0.4

$ curl $NODE1
...

Зверніть увагу, що Redis вважає продовження неефективними (граф Рэдис-сервісу незмінний), так як ми не змінили сервіс Redis, тільки образ webapp.
Вирішення проблеми зростання
Рой медових бджіл є звичним видовищем на початку літа. Медові бджоли інстинктивно використовують виживання в колонії шляхом об'єднання в рій, коли їх стає багато. Та це ж ми робимо в наших кластерах контейнерів.
Давайте об'єднаємося в рій...
Давайте скажемо, що наш сайт досяг межі потужності і нам потрібно додати додатковий вузол до нашого кластеру. Це так просто, ви можете зробити це за допомогою всього 4 команд! Для ясності, ми збираємося використовувати декілька більше, щоб переконатися, що все добре зрозуміло.
$ docker-machine create -d virtualbox swarm-4
...
Docker is up and running!

Join the node the swarm as a worker as before:

$ eval $(docker-machine env swarm-4)
$ docker swarm join \
--token SWMTKN-1–1n7gtfmvvrlwo91pv4r59vsdf73bwuwodj3saq0162vcsny89l-5zige8u81ug5adk3o4bsx32fi \
192.168.99.106:2377
This node joined a swarm as a worker.

Перевіримо, що і новий вузол і webapp-сервіс запущено:
$ eval $(docker-machine env swarm-1)

$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
93f0ghkpsh5ru7newtqm82330 swarm-3 Ready Active
e9rxhj0w1ga3gz89g927qvntd swarm-4 Ready Active
5jqsuf8hsemi7bfbwzfdxfcg5 swarm-2 Ready Active
b2womami9n2t8tti1acvz6v5j * swarm-1 Ready Active Leader

$ docker service ps webapp
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
7bdpfbbjok78zt32xd9e2mqlt webapp.1 lherrera/webapp:2.0 swarm-3 Running Running 5 minutes ago
bb8n4iagxcjv4rn2oc3dj6cvy \_ webapp.1 lherrera/webapp:1.0 swarm-1 Shutdown Shutdown 5 minutes ago
af2rlu0laqhrj3uz8brym0f8r webapp.2 lherrera/webapp:2.0 swarm-2 Running Running 5 minutes ago
chndeorlvglj45alr4vhy50vg \_ webapp.2 lherrera/webapp:1.0 swarm-3 Shutdown Shutdown 5 minutes ago
0xjt6gib1hql10iqj6866q4pe webapp.3 lherrera/webapp:2.0 swarm-1 Running Running 6 minutes ago
4txay0gj6p18iuiknacdoa91x \_ webapp.3 lherrera/webapp:1.0 swarm-2 Shutdown Shutdown 6 minutes ago
luis@aurelio [13:14:27] [~/webapp] [2.0]

Тепер давайте активізуємо наш webapp-сервіс для чотирьох реплік:
$ docker service update --replicas=4 webapp

Ми повинні почекати кілька хвилин, щоб образ завантажився на нові вузли:
$ docker service ps webapp
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
7bdpfbbjok78zt32xd9e2mqlt webapp.1 lherrera/webapp:2.0 swarm-3 Running Running 10 minutes ago
bb8n4iagxcjv4rn2oc3dj6cvy \_ webapp.1 lherrera/webapp:1.0 swarm-1 Shutdown Shutdown 10 minutes ago
af2rlu0laqhrj3uz8brym0f8r webapp.2 lherrera/webapp:2.0 swarm-2 Running Running 10 minutes ago
chndeorlvglj45alr4vhy50vg \_ webapp.2 lherrera/webapp:1.0 swarm-3 Shutdown Shutdown 10 minutes ago
0xjt6gib1hql10iqj6866q4pe webapp.3 lherrera/webapp:2.0 swarm-1 Running Running 10 minutes ago
4txay0gj6p18iuiknacdoa91x \_ webapp.3 lherrera/webapp:1.0 swarm-2 Shutdown Shutdown 10 minutes ago
81xbk0j61tqg76wcdi35k1bxv webapp.4 lherrera/webapp:2.0 swarm-4 Running Running 20 seconds ago

Просто, так? Бджоли в рої завжди в гарному настрої!
Для глобальних сервісів (на відміну від реплікації, як ми бачили в прикладі), Swarm запускає нову задачу автоматично для сервісу на новому доступному вузлі.
Стійкість маршрутизації
Якщо щось відбувається не досить добре, кластер буде керувати станом цих сервісів (наприклад, запущених реплік) і в разі відмови відновлювати сервіс в бажаний стан. У цьому сценарії нові контейнери і IP-адреси з'являються і зникають. На щастя, новий вбудований механізм виявлення сервісів допоможе нам адаптувати наші сервіси до цих ситуацій і відмовами контейнерів і навіть зараз повна відмова вузла пройде непоміченим.
Маршрутизація мережі у традиційному колектор виконаний проти відмови оточенні (HA environment)
Щоб побачити це у дії, ми продовжимо розглядати наш приклад і просимулируем вузол нашого невеликого відмовив кластера.
Давайте переконаємося, що наше webapp все ще запущено на нашому кластері:
$ docker service ps webapp
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
7bdpfbbjok78zt32xd9e2mqlt webapp.1 lherrera/webapp:2.0 swarm-3 Running Running 10 minutes ago
bb8n4iagxcjv4rn2oc3dj6cvy \_ webapp.1 lherrera/webapp:1.0 swarm-1 Shutdown Shutdown 10 minutes ago
af2rlu0laqhrj3uz8brym0f8r webapp.2 lherrera/webapp:2.0 swarm-2 Running Running 10 minutes ago
chndeorlvglj45alr4vhy50vg \_ webapp.2 lherrera/webapp:1.0 swarm-3 Shutdown Shutdown 10 minutes ago
0xjt6gib1hql10iqj6866q4pe webapp.3 lherrera/webapp:2.0 swarm-1 Running Running 10 minutes ago
4txay0gj6p18iuiknacdoa91x \_ webapp.3 lherrera/webapp:1.0 swarm-2 Shutdown Shutdown 10 minutes ago
81xbk0j61tqg76wcdi35k1bxv webapp.4 lherrera/webapp:2.0 swarm-4 Running Running 20 seconds ago

Вузли:
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
21z5m0vik76msi90icrf8prvf swarm-3 Ready Active
7zyckxuwsruehcfosgymwiucm swarm-4 Ready Active
9aso727d8c4vc59cxu0e8g778 swarm-2 Ready Active
bihyblm2kawbzd3keonc3bz0l * swarm-1 Ready Active Leader

Тут починається саме веселе — хто не любить відключати працюють сайти, щоб подивитися, що станеться?
$ docker-machine stop swarm-2

Давайте подивимося, як наші служби відреагували:
$ docker service ps webapp
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
7bdpfbbjok78zt32xd9e2mqlt webapp.1 lherrera/webapp:2.0 swarm-3 Running Running 11 minutes ago
bb8n4iagxcjv4rn2oc3dj6cvy \_ webapp.1 lherrera/webapp:1.0 swarm-1 Shutdown Shutdown 11 minutes ago
af2rlu0laqhrj3uz8brym0f8r webapp.2 lherrera/webapp:2.0 swarm-4 Running Running 11 minutes ago
chndeorlvglj45alr4vhy50vg \_ webapp.2 lherrera/webapp:1.0 swarm-3 Shutdown Shutdown 11 minutes ago
0xjt6gib1hql10iqj6866q4pe webapp.3 lherrera/webapp:2.0 swarm-1 Running Running 11 minutes ago
4txay0gj6p18iuiknacdoa91x \_ webapp.3 lherrera/webapp:1.0 swarm-4 Shutdown Shutdown 11 minutes ago
15pxa5ccp9fqfbhdh76q78aza webapp.4 lherrera/webapp:2.0 swarm-3 Running Running 4 seconds ago
81xbk0j61tqg76wcdi35k1bxv \_ webapp.4 lherrera/webapp:2.0 swarm-2 Shutdown Running about a minute ago

Здорово! Docker розгорнув новий контейнер на сайті swarm-3, після того, як ми «вбили» вузол swarm-2. Як ви можете бачити, ми все ще маємо три запущені репліки (два у вузлі «swarm-3»)...
$ curl $NODE1
Hello, i'm version 2.0.My hostname is 0d49c828b675, this page has been viewed 7
and my ip addresses are 10.0.0.7,10.0.0.4,172.18.0.4,10.255.0.10,10.255.0.6

$ curl $NODE1
Hello, i'm version 2.0.My hostname is d60e1881ac86, this page has been viewed 8
and my ip addresses are 10.0.0.7,10.0.0.4,172.18.0.4,10.255.0.10,10.255.0.6

І трафік автоматично перенаправляється на знову створений контейнер!
Ріст і розвиток Swarm
Програмне забезпечення змінюється швидко. Відмови трапляються, і вони неминуче відбуваються, коли найменше очікуєш. Нова абстракція «сервіси» була введена в Docker 1.12, спрощуючи оновлення і запобігаючи простої відмови сервісу. До того ж, цей новий підхід робить планування і обслуговування довго працюють сервісів, таких як веб-сервера, набагато простіше. Тепер ви можете розгорнути реплицируемый, розподілений, збалансований по навантаженню сервіс в Swarm на Docker Engine за допомогою декількох команд. Кластер може керувати станом ваших сервісів і навіть призводить сервіс в бажаний стан у разі якщо вузол або контейнер відмовив.
Solomon Hykes добре описав, як ми сподіваємося зробити життя розробників простіше: «З розвитком у нашому оркестрационном (orchestration) інструментарії, мережах та безпеки, Docker підключає розробників, щоб побудувати більш комплексні програми, які можуть бути розвинені в масштабі від робочого комп'ютера до хмари, незалежно від базової інфраструктури.»
З релізом Docker 1.12 ми думаємо, він, безумовно, забезпечить свою обіцянку. Docker робить речі простішими, сподіваюся, це той момент, коли ці сюрреалістичні моменти, що ми згадали на початку, почнуть пропадати. У вас є які-небудь ще сюрреалістичні моменти в DevOps? Поділіться цим з нами!
Більше інформації та посилань на Docker 1.12
  • https://www.youtube.com/watch?v=dooPhkXT9yI — відмінне глибоке розгляд специфіки, як вузли Swarm'а працюють і обмінюються інформацією між собою.
  • https://www.youtube.com/watch?v=_F6PSP-qhdA — частина 2 глибокого розгляду, сфокусована на тому, як оркестрируются (orchestrated) сервіси і як обробляються відмови.
Джерело: Хабрахабр

0 коментарів

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