ТЛ; Д.
Р.
В этой статье мы развернем Docker-приложение, голосуя на Swarm, Kubernetes и Nomad от Hashicorp. Надеюсь, вам понравится читать эту статью так же, как и мне экспериментировать со всем этим.
Если вы работаете с технологиями, очень важно быть любознательным.
Это необходимо для того, чтобы постоянно учиться и быть в курсе того, что происходит на местах.
Все меняется слишком быстро.
Оркестровка контейнеров — настолько горячая тема, что даже если у вас есть любимый инструмент, все равно интересно посмотреть, как работают другие, и узнать о них что-то новое.
Приложение для голосования
В предыдущих статьях я использовал приложение для голосования.Приложение работает на микросервисной архитектуре и состоит из 5 сервисов.
- Голосование: интерфейс, позволяющий пользователю выбирать между собакой и кошкой
- Redis: база данных, в которой хранятся голоса
- Worker: сервис, который собирает голоса из Redis и сохраняет результаты в базе данных Postgres.
- БД: база данных Postgres, в которой хранятся результаты голосования.
- Результат: интерфейс показывает результаты голосования.
Вот сам файл:
Вообще в этом файле обозначено 6 сервисов, но в архитектуре приложения их всего 5. Дополнительный сервис — визуализатор, отличный инструмент, предоставляющий интерфейс, показывающий, где развернуты сервисы.version: "3" services: redis: image: redis:alpine ports: - "6379" networks: - frontend deploy: replicas: 1 update_config: parallelism: 2 delay: 10s restart_policy: condition: on-failure db: image: postgres:9.4 volumes: - db-data:/var/lib/postgresql/data networks: - backend deploy: placement: constraints: [node.role == manager] vote: image: dockersamples/examplevotingapp_vote:before ports: - 5000:80 networks: - frontend depends_on: - redis deploy: replicas: 2 update_config: parallelism: 2 restart_policy: condition: on-failure result: image: dockersamples/examplevotingapp_result:before ports: - 5001:80 networks: - backend depends_on: - db deploy: replicas: 1 update_config: parallelism: 2 delay: 10s restart_policy: condition: on-failure worker: image: dockersamples/examplevotingapp_worker networks: - frontend - backend deploy: mode: replicated replicas: 1 labels: [APP=VOTING] restart_policy: condition: on-failure delay: 10s max_attempts: 3 window: 120s placement: constraints: [node.role == manager] visualizer: image: dockersamples/visualizer:stable ports: - "8080:8080" stop_grace_period: 1m30s volumes: - "/var/run/docker.sock:/var/run/docker.sock" deploy: placement: constraints: [node.role == manager] networks: frontend: backend: volumes: db-data:
Докер Рой
Docker Swarm — инструмент для управления и создания кластеров контейнеров Docker. С помощью Swarm администраторы и разработчики могут создавать кластер узлов и управлять им как единой виртуальной системой.
Компоненты роя
Кластер Swarm состоит из нескольких нод, одни работают менеджерами, другие исполнителями:- Узлы-менеджеры отвечают за внутреннее состояние кластера.
- Узлы-исполнители выполняют задачи (= запускают контейнеры)
Менеджеры совместно используют внутреннее распределенное хранилище для поддержания согласованного состояния кластера.
Это обеспечивается благодаря бревнам Raft. В Swarm сервисы определяют, как следует развертывать приложения и как они должны работать в контейнерах.
Установка Докера
Если у вас еще не установлен Docker, вы можете скачать Docker CE (Community Edition) для вашей ОС.
Создание роя
После установки Docker мы находимся всего в одной команде от работающего Swarm. $ docker swarm init
Это все, что требуется для кластера Swarm. Хотя это кластер с одним узлом, это все равно кластер со всеми сопутствующими процессами.
Развертывание приложений
Среди файлов Compose, доступных в репозитории приложения на GitHub, нам нужен docker-stack.yml для развертывания приложения через Swarm. $ docker stack deploy -c docker-stack.yml app
Creating network app_backend
Creating network app_default
Creating network app_frontend
Creating service app_visualizer
Creating service app_redis
Creating service app_db
Creating service app_vote
Creating service app_result
Creating service app_worker
Поскольку стек работает на Docker для Mac, у меня есть доступ к приложению непосредственно с локального компьютера.
Выбрать кошек или собак можно с помощью интерфейса голосования (порт 5000) и просмотреть результаты через порт 5001.
Я не буду сейчас вдаваться в подробности, я просто хотел показать, насколько легко развернуть приложение с помощью Swarm.
Если вам нужен более подробный анализ того, как развернуть приложение через Swarm с несколькими узлами, вы можете прочитать Эта статья .
Кубернетес
Kubernetes — это платформа с открытым исходным кодом для автоматизации развертывания, масштабирования и управления контейнерными приложениями.
Концепция Кубернетеса
Кластер Kubernetes состоит из одного или нескольких мастеров и узлов.
- Мастер отвечает за управление кластером (управление состоянием кластера, планирование задач, реагирование на события в кластере и т.д.)
- Ноды (раньше их называли миньонами.
Да, как в мультфильме «Гадкий Я») предоставляют рантайм для запуска контейнера приложения (через Pods)
Интерфейс командной строки kubectl используется для ввода команд. Ниже мы рассмотрим несколько примеров его использования.
Чтобы понять, как развертываются приложения, вам необходимо знать о нескольких высокоуровневых объектах Kubernetes:
- Модуль — это наименьшая единица, которую можно развернуть на узле.
Это группа контейнеров, которые должны работать вместе.
Но довольно часто Pod содержит только один контейнер.
- ReplicaSet предоставляет определенное количество реплик модулей.
- Развертывание управляет ReplicaSet и позволяет выполнять последовательные обновления, синее/зеленое развертывание, тестирование и т. д.
- Сервис определяет логический набор модулей и политику получения к ним доступа.
Установка кубектла
Кубектл — это командная строка для развертывания и управления приложениями в Kubernetes. Для установки используем официальную документацию ( https://kubernetes.io/docs/tasks/tools/install-kubectl/ ).
Например, для установки на Mac вам необходимо ввести следующие команды: $ curl -LO https://storage.googleapis.com/kubernetes-release/release/$ (curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt )/bin/darwin/amd64/kubectl
$ chmod +x .
/kubectl $ sudo mv .
/kubectl /usr/local/bin/kubectl
Установка миникуба
Minicube — это комплексная установка Kubenetes. Он создает локальные виртуальные машины и запускает кластер узлов, на которых выполняются все процессы Kubernetes. Это определенно не тот инструмент, который следует использовать для настройки производственного кластера, но его действительно удобно использовать для разработки и тестирования.После установки Minicube для настройки кластера с одним узлом потребуется всего одна команда.
$ minikube start
Starting local Kubernetes v1.7.0 cluster…
Starting VM…
Downloading Minikube ISO
97.80 MB / 97.80 MB [==============================================] 100.00% 0s
Getting VM IP address…
Moving files into cluster…
Setting up certs…
Starting cluster components…
Connecting to cluster…
Setting up kubeconfig…
Kubectl is now configured to use the cluster.
Дескриптор Кубернетеса
В Kubernetes контейнеры запускаются через Набор реплик , который контролируется Развертывание .Ниже приведен пример файла .
yml, описывающего Развертывание .
Набор реплик обеспечивает запуск 2-х реплик Нгинкс .
// nginx-deployment.yml
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2 # tells deployment to run 2 pods matching the template
template: # create pods using pod definition in this template
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
Чтобы создать развертывание, необходимо использовать интерфейс командной строки kubectl.
Чтобы создать приложение, состоящее из микросервисов, необходимо создать файл развертывания для каждого сервиса.
Вы можете сделать это вручную или использовать Сочинять .
Использование Kompose для создания развертываний и сервисов
Kompose — это инструмент, который преобразует файлы компоновки Docker в файлы дескрипторов, используемые Kubernetes. Этот сервис делает его более удобным и ускоряет процесс миграции.Примечание: Kompose использовать не обязательно, все можно написать вручную, но это существенно ускоряет процесс развертывания.
Kompose не учитывает все параметры, используемые в файле Docker Compose. Kompose можно установить на Linux или Mac с помощью следующих команд:
# Linux
$ curl -L https://github.com/kubernetes/kompose/releases/download/v1.0.0/kompose-linux-amd64 -o kompose
# macOS
$ curl -L https://github.com/kubernetes/kompose/releases/download/v1.0.0/kompose-darwin-amd64 -o kompose
$ chmod +x kompose
$ sudo mv .
/kompose /usr/local/bin/kompose
Прежде чем запустить docker-stack.yml в Kompose мы его немного изменим и удалим ключ развертывания каждого сервиса.
Этот ключ не принимается и может вызвать ошибки при создании файлов дескрипторов.
Вы также можете удалить информацию о сетях.
В Kompose мы дадим новый файл, который назовем docker-stack-k8s.yml .
version: "3"
services:
redis:
image: redis:alpine
ports:
- "6379"
db:
image: postgres:9.4
volumes:
- db-data:/var/lib/postgresql/data
vote:
image: dockersamples/examplevotingapp_vote:before
ports:
- 5000:80
depends_on:
- redis
result:
image: dockersamples/examplevotingapp_result:before
ports:
- 5001:80
depends_on:
- db
worker:
image: dockersamples/examplevotingapp_worker
visualizer:
image: dockersamples/visualizer:stable
ports:
- "8080:8080"
stop_grace_period: 1m30s
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
volumes:
db-data:
Из файла docker-stack-k8s.yml Мы генерируем дескрипторы для приложения с помощью следующей команды: $ kompose convert --file docker-stack-k8s.yml
WARN Volume mount on the host "/var/run/docker.sock" isn't supported - ignoring path on the host
INFO Kubernetes file "db-service.yaml" created
INFO Kubernetes file "redis-service.yaml" created
INFO Kubernetes file "result-service.yaml" created
INFO Kubernetes file "visualizer-service.yaml" created
INFO Kubernetes file "vote-service.yaml" created
INFO Kubernetes file "worker-service.yaml" created
INFO Kubernetes file "db-deployment.yaml" created
INFO Kubernetes file "db-data-persistentvolumeclaim.yaml" created
INFO Kubernetes file "redis-deployment.yaml" created
INFO Kubernetes file "result-deployment.yaml" created
INFO Kubernetes file "visualizer-deployment.yaml" created
INFO Kubernetes file "visualizer-claim0-persistentvolumeclaim.yaml" created
INFO Kubernetes file "vote-deployment.yaml" created
INFO Kubernetes file "worker-deployment.yaml" created
Мы видим, что для каждого сервиса создается файл развертывания и сервиса.
Мы получили только одно предупреждение.
Это связано с визуализатор потому что сокет Docker не может быть подключен.
Мы не будем пытаться запустить этот сервис, а сосредоточимся на остальных.
Развертывание приложения
Через кубектл Создадим все компоненты, указанные в файле дескриптора.Укажем, что файлы расположены в текущей папке.
$ kubectl create -f .
persistentvolumeclaim "db-data" created deployment "db" created service "db" created deployment "redis" created service "redis" created deployment "result" created service "result" created persistentvolumeclaim "visualizer-claim0" created deployment "visualizer" created service "visualizer" created deployment "vote" created service "vote" created deployment "worker" created service "worker" created unable to decode "docker-stack-k8s.yml":.
Примечание: поскольку мы оставили измененный файл компоновки в текущей папке, мы получили ошибку, поскольку его невозможно проанализировать.
Но эту ошибку можно игнорировать без всякого риска.
С помощью этих команд вы можете просмотреть созданный Услуги И Развертывания .
Предоставляем доступ к приложению из внешнего мира
Чтобы получить доступ к интерфейсу голосование И результат вам нужно немного изменить созданные для них сервисы.
Вот сгенерированный дескриптор для голосование : apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
io.kompose.service: vote
name: vote
spec:
ports:
- name: "5000"
port: 5000
targetPort: 80
selector:
io.kompose.service: vote
status:
loadBalancer: {}
Мы изменим тип услуги и заменим КластерIP на НодПорт .
КластерIP делает услугу доступной внутри компании и НодПорт позволяет публиковать порт на каждом узле кластера и делает его доступным для всего мира.
Давайте сделаем то же самое для результат потому что мы хотим голосование , и чтобы результат был доступ снаружи.
apiVersion: v1
kind: Service
metadata:
labels:
io.kompose.service: vote
name: vote
spec:
type: NodePort
ports:
- name: "5000"
port: 5000
targetPort: 80
selector:
io.kompose.service: vote
После внесения изменений в обе службы ( голосование И результат ), вы можете воссоздать их.
$ kubectl delete svc vote
$ kubectl delete svc result
$ kubectl create -f vote-service.yaml
service "vote" created
$ kubectl create -f result-service.yaml
service "result" created
Доступ к приложению
Теперь мы получаем подробную информацию об услуге голосование И результат и получите порты, которые они предоставляют.голосование доступен через порт 30069 и результат – 31873. Теперь голосуем и видим результаты.
Как только мы поняли основные компоненты Kubernetes, мы смогли легко развернуть приложение.
И Kompose нам очень помог.
Кочевник Хашикорпа
Nomad — инструмент для управления кластером машин и запуска на них приложения.Он абстрагирует машины и точки размещения приложений и позволяет пользователям говорить, что они хотят запустить.
А Nomad отвечает за то, где и как он будет запущен.
Концепция кочевника
Кластер Nomad состоит из агенты (агенты), которые могут работать в режиме серверы (сервер) или клиент (клиент).
- Сервер отвечает за протокол консенсуса , что позволяет серверу выбирать лидера и осуществлять репликацию состояния.
- Клиенты очень легкие, поскольку они взаимодействуют с сервером, практически ничего не делая сами.
Задачи выполняются на клиентских узлах.
В кластере Nomad можно выполнять несколько типов задач.
Чтобы развернуть приложение, вам необходимо понимать основные концепции Nomad:
- Job – определяет, какие задачи должен выполнять Nomad. Это описано в файле задания (текстовый файл в формате hcl, язык конфигурации Hashicorp).
Задание может содержать одну или несколько групп задач.
- Группа содержит несколько задач, расположенных на одной машине.
- Task — запущенный процесс, в нашем случае это Docker-контейнер.
- Сопоставление задач с заданиями осуществляется с помощью распределения.
Распределение используется для обеспечения выполнения задач задания на определенном узле.
Монтаж
В этом примере мы запустим приложение на хосте Docker, созданном с помощью Docker Machine. Локальный IP – 192.168.1.100. Сначала давайте запустим Consul, который используется для обнаружения и регистрации сервисов.
Мы запустим Nomad и развернем приложение как задание в Nomad.
Консул по регистрации и открытию услуг
Для обнаружения и регистрации служб рекомендуется использовать такой инструмент, как Consul, который не будет работать так же, как Job в Nomad. Консул возможен скачать по ссылке .
Эта команда запускает сервер Consul локально: $ consul agent -dev -client=0.0.0.0 -dns-port=53 -recursor=8.8.8.8
Рассмотрим подробнее используемые опции:
- - разработчик — флаг, устанавливающий кластер Consul с сервером и клиентом.
Эту опцию следует использовать только в целях разработки и тестирования.
- -клиент=0.0.0.0 позволяет вам получить доступ к службам Consul (API и DNS-серверу) через любой интерфейс хоста.
Это необходимо, поскольку Nomad будет подключаться к Consul через интерфейс localhost, а контейнеры — через docker-bridge (что-то вроде 172.17.x.x).
- -dns-порт=53 определяет порт, который будет использовать DNS-сервер Consul (по умолчанию 8600).
Мы установим стандартный порт 53, чтобы DNS можно было использовать из контейнера.
- -рекурсор=8.8.8.8 определяет другой DNS-сервер, который будет обрабатывать запросы, которые Consul не может обработать.
Создать кластер с узлом
Мы загрузили Nomad и теперь можем запустить Агент со следующими настройками.
// nomad.hcl
bind_addr = "0.0.0.0"
data_dir = "/var/lib/nomad"
server {
enabled = true
bootstrap_expect = 1
}
client {
enabled = true
network_speed = 100
}
Агент будет работать и как сервер, и как клиент. Отметим, что связывание_адрес должен работать с любым интерфейсом, чтобы можно было получать задания из внешнего мира.
Запустим Nomad Agent со следующими настройками: $ nomad agent -config=nomad.hcl
==> WARNING: Bootstrap mode enabled! Potentially unsafe operation.
Loaded configuration from nomad-v2.hcl
==> Starting Nomad agent.
==> Nomad agent configuration:
Client: true
Log Level: INFO
Region: global (DC: dc1)
Server: true
Version: 0.6.0
==> Nomad agent started! Log data will stream in below:
Примечание.
По умолчанию Nomad подключается к вашему локальному экземпляру Consul. Мы только что установили кластер с одним узлом.
Вот информация об уникальном участнике: $ nomad server-members
Name Address Port Status Leader Protocol Build Datacenter Region
neptune.local.global 192.168.1.100 4648 alive true 2 0.6.0 dc1 global
Развертывание приложения
Чтобы развернуть приложение с помощью Swarm, вы можете напрямую использовать файл компоновки.Для развертывания через Kubernetes нужны дескрипторы из тех же файлов Compose. Как все это происходит через Nomad? Во-первых, для Hashicorp не существует такого инструмента, как Kompose, который мог бы упростить миграцию Compose на Nomad (кстати, неплохая идея для проекта с открытым исходным кодом).
Файлы с описанием Вакансии , группы , задания , вам придется написать это вручную.
Мы рассмотрим это более подробно, когда будем описывать вакансии в сфере услуг.
Редис И Голосование .
Для остальных сервисов это будет выглядеть примерно так же.
Определение задания для Redis
Этот файл определяет часть приложения Redis: // redis.nomad
job "redis-nomad" {
datacenters = ["dc1"]
type = "service"
group "redis-group" {
task "redis" {
driver = "docker"
config {
image = "redis:3.2"
port_map {
db = 6379
}
}
resources {
cpu = 500 # 500 MHz
memory = 256 # 256MB
network {
mbits = 10
port "db" {}
}
}
service {
name = "redis"
address_mode = "driver"
port = "db"
check {
name = "alive"
type = "tcp"
interval = "10s"
timeout = "2s"
}
}
}
}
}
Давайте посмотрим, что здесь написано:
- Имя работы — redis-nomad
- Тип работы – сервисная (т.е.
долгосрочная эксплуатация)
- Группе присваивается произвольное имя; содержит одну операцию
- Task Redis использует docker-driver, то есть он будет работать в контейнере.
- Задача будет использовать образ Redis:3.2.
- Блок ресурсов указывает ограничения на процессор и память.
- В сетевом блоке указано, что порт БД должен быть динамическим.
- Сервисный блок определяет, как будет происходить регистрация в Consul: имя сервиса, IP-адрес и определение проверки работоспособности.
$ nomad plan redis.nomad
+ Job: "nomad-redis"
+ Task Group: "cache" (1 create)
+ Task: "redis" (forces create)
Scheduler dry-run:
- All tasks successfully allocated.
Job Modify Index: 0
To submit the job with version verification run:
nomad run -check-index 0 redis.nomad
When running the job with the check-index flag, the job will only be run if the server side version matches the job modify index returned. If the index has changed, another user has modified the job and the plan's results are potentially invalid.
Кажется, все работает. Теперь расширим задачу этим заданием:
$ nomad run redis.nomad
==> Monitoring evaluation "1e729627"
Evaluation triggered by job "nomad-redis"
Allocation "bf3fc4b2" created: node "b0d927cd", group "cache"
Evaluation status changed: "pending" -> "complete"
==> Evaluation "1e729627" finished with status "complete"
Видим, что размещение создано.
Давайте проверим его статус: $ nomad alloc-status bf3fc4b2
ID = bf3fc4b2
Eval ID = 1e729627
Name = nomad-redis.cache[0]
Node ID = b0d927cd
Job ID = nomad-redis
Job Version = 0
Client Status = running
Client Description = <none>
Desired Status = run
Desired Description = <none>
Created At = 08/23/17 21:52:03 CEST
Task "redis" is "running"
Task Resources
CPU Memory Disk IOPS Addresses
1/500 MHz 6.3 MiB/256 MiB 300 MiB 0 db: 192.168.1.100:21886
Task Events:
Started At = 08/23/17 19:52:03 UTC
Finished At = N/A
Total Restarts = 0
Last Restart = N/A
Recent Events:
Time Type Description
08/23/17 21:52:03 CEST Started Task started by client
08/23/17 21:52:03 CEST Task Setup Building Task Directory
08/23/17 21:52:03 CEST Received Task received by client
Контейнер запустился корректно.
Проверим DNS-сервер Consul и убедимся, что сервис тоже зарегистрирован корректно: $ dig @localhost SRV redis.service.consul
; <<>> DiG 9.10.3-P4-Ubuntu <<>> @localhost SRV redis.service.consul
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 35884
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 2
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;redis.service.consul. IN SRV
;; ANSWER SECTION:
redis.service.consul. 0 IN SRV 1 1 6379 ac110002.addr.dc1.consul.
;; ADDITIONAL SECTION:
ac110002.addr.dc1.consul. 0 IN A 172.17.0.2
;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Wed Aug 23 23:08:36 CEST 2017
;; MSG SIZE rcvd: 103
Задача располагалась на IP 172.17.0.2, а ее порт, как мы указывали, был 6379.
Определение задания для голосования
Давайте определим задание для сервиса голосование .
Мы используем следующий файл: // job.nomad
job "vote-nomad" {
datacenters = ["dc1"]
type = "service"
group "vote-group" {
task "vote" {
driver = "docker"
config {
image = "dockersamples/examplevotingapp_vote:before"
dns_search_domains = ["service.dc1.consul"]
dns_servers = ["172.17.0.1", "8.8.8.8"]
port_map {
http = 80
}
}
service {
name = "vote"
port = "http"
check {
name = "vote interface running on 80"
interval = "10s"
timeout = "5s"
type = "http"
protocol = "http"
path = "/"
}
}
resources {
cpu = 500 # 500 MHz
memory = 256 # 256MB
network {
port "http" {
static = 5000
}
}
}
}
}
}
Но здесь есть несколько отличий от файла, который мы использовали для Redis:
- Голосование соединяется с Redis используя только имя операции.
Вот пример части файла app.py , используется в сервисе голосование :
// app.py
def get_redis():
if not hasattr(g, 'redis'):
g.redis = Redis(host="redis", db=0, socket_timeout=5)
return g.redis
В этом случае для получения IP-контейнера из Redis контейнер с голосование должен использовать DNS-сервер Consul. DNS-запрос от контейнера выполняется через Docker-мост (172.17.0.1).
dns_search_domains определяет, что Служба X зарегистрирована как X.service.dc1.consul в Consul
- Мы установили статический порт, чтобы сервис голосования на порту 5000 был доступен извне кластера.
Доступ к приложению
Когда все задания выполняются, вы можете проверить их статус и убедиться, что все работает.Мы также можем просмотреть это через интерфейс Consul.
С помощью IP узла (в нашем случае 192.168.1.100) мы получаем доступ к интерфейсам с голосование И результат .
Нижняя граница
Это приложение для голосования является отличным приложением с демонстрационной точки зрения.Мне было интересно узнать, можно ли его развернуть без каких-либо изменений кода, используя какой-нибудь оркестратор.
И да, можно, даже без особых танцев с бубном.
Надеюсь, эта статья поможет вам понять основы Swarm, Kubernetes и Nomad. Также было бы интересно узнать, что вы запускаете в Docker и какой оркестратор используете.
Теги: #docker #контейнеры #разработка #Kubernetes #swarm #nomad #Визуализация данных #Тестирование веб-сервисов #Сборка систем #Kubernetes
-
Основы Игрового Баланса: Ситуационный Баланс
19 Oct, 24 -
Исповедь Новичка...
19 Oct, 24 -
Как Я «Выжимал» Новый Ipad Из Re:store
19 Oct, 24 -
Джон Ресиг Для Usethis.com
19 Oct, 24 -
Вода И Лед
19 Oct, 24