Развертывание и масштабирование микросервисов Kubernetes

Kubernetes – открытый инструмент для оркестровки и управления контейнерными приложениями. В предыдущем мануале этой серии — Основы работы с Kubernetes — вы узнали об основных компонентах Кубернетеса.

В этом мануале вы сможете применить полученные знания из предыдущих руководств для создания, развертывания и управления комплексного микросервиса в Kubernetes. Тестовое веб-приложение, которое вы будете использовать в этом мануале, представляет собой простой список дел, написанный в Node.js, который использует БД MongoDB. Ранее это же приложение вы использовали в мануале Создание контейнеризированного приложения Docker.

Требования

1: Создание образа с помощью Dockerfile

Для начала нужно создать контейнер для приложения, упаковав его в образ Docker.

Перейдите в домашний каталог, а затем используйте Git, чтобы клонировать тестовое приложение из официального репозитория GitHub:

cd ~
git clone https://github.com/janakiramm/todo-app.git

Создайте образ контейнера из Dockerfile. Используйте флаг -t, чтобы добавить к образу метку, которая включает имя пользователя реестра, имя образа и (опционально) описательный тег.

docker build -t 8host/todo .

Результат сообщает, что образ было успешно собран и помечен соответствующим образом.

Sending build context to Docker daemon  8.238MB
Step 1/7 : FROM node:slim
---> 286b1e0e7d3f
Step 2/7 : LABEL maintainer = "jani@janakiram.com"
---> Using cache
---> ab0e049cf6f8
Step 3/7 : RUN mkdir -p /usr/src/app
---> Using cache
---> 897176832f4d
Step 4/7 : WORKDIR /usr/src/app
---> Using cache
---> 3670f0147bed
Step 5/7 : COPY ./app/ ./
---> Using cache
---> e28c7c1be1a0
Step 6/7 : RUN npm install
---> Using cache
---> 7ce5b1d0aa65
Step 7/7 : CMD node app.js
---> Using cache
---> 2cef2238de24
Successfully built 2cef2238de24
Successfully tagged 8host/todo-app:latest

Убедитесь, что образ был собран правильно.

docker images

Вы увидите размер образа и время его создания.

REPOSITORY                                       TAG                 IMAGE ID            CREATED             SIZE
8host/todo-app                                   latest              81f5f605d1ca        9 minutes ago       236MB

Затем загрузите образ в публичный реестр на Docker Hub. Для этого войдите в учетную запись Docker Hub:

docker login

После того, как вы предоставите свои учетные данные, пометьте образ, указав имя пользователя Docker Hub:

docker tag your_docker_hub_username/todo-app

Теперь загрузите образ:

docker push

Вы можете убедиться, что новый образ появился в реестре, выполнив поиск по Docker Hub в веб-браузере.

Когда образ Docker переместится в реестр, упакуйте приложение для Kubernetes.

2: Развертывание пода MongoDB в Kubernetes

Приложение использует MongoDB для хранения списков дел, созданных пользователем. Чтобы запустить MongoDB в Kubernetes, нужно упаковать его как под. Когда вы запустите этот под, он запустит один экземпляр MongoDB.

Создайте новый файл YAML db-pod.yaml:

nano db-pod.yaml

Добавьте следующий код, который определяет под с одним контейнером на основе MongoDB. Откройте порт 27017, стандартный порт MongoDB. Обратите внимание, определение содержит метки name и app. Вы сможете использовать эти метки для определения и настройки определенных подов.

apiVersion: v1
kind: Pod
metadata:
name: db
labels:
name: mongo
app: todoapp
spec:
containers:
- image: mongo
name: mongo
ports:
- name: mongo
containerPort: 27017
volumeMounts:
- name: mongo-storage
mountPath: /data/db
volumes:
- name: mongo-storage
hostPath:
path: /data/db

Данные хранятся в томе под названием mongo-storage, который связан с каталогом /data/db ноды. Дополнительную информацию о томах можно найти в документации Kubernetes.

Выполните следующую команду для создания пода.

kubectl create -f db-pod.yml
pod "db" created

Проверьте под:

kubectl get pods

В выводе вы увидите, что под существует и работает.

NAME      READY     STATUS    RESTARTS   AGE
db   1/1       Running   0          2m

Сделайте этот под доступным для внутренних потребителей кластера.

Создайте новый файл db-service.yaml, который содержит такой код сервиса для MongoDB:

apiVersion: v1
kind: Service
metadata:
name: db
labels:
name: mongo
app: todoapp
spec:
selector:
name: mongo
type: ClusterIP
ports:
- name: db
port: 27017
targetPort: 27017

Сервис обнаруживает в пространстве имен все поды, которые соответствуют метке name: db. Раздел selector явно определяет эту ассоциацию.

Сервис виден внутри кластера через декларацию type: ClusterIP.

Сохраните файл и закройте редактор. Затем добавьте файл в кластер:

kubectl create -f db-service.yml

Если сервис успешно добавлен в кластер, вы увидите:

service "db" created

Узнайте порт, по которому доступен под.

kubectl get services
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)     AGE
db           ClusterIP   10.109.114.243   <none>        27017/TCP   14s
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP     47m

Согласно выводу сервис использует порт 27017. Веб-приложение может получить доступ к MongoDB через этот сервис. Когда он использует имя хоста db, DNS-сервис Kubernetes будет разрешать адрес ClusterIP, связанный с сервисом. Этот механизм позволяет подам обнаруживать друг друга и взаимодействовать.

3: Развертывание приложения Node.JS как пода

Упакуйте созданный ранее образ Docker в качестве пода и разверните его в кластере. Он будет работать как фронт-энд приложения, доступный конечным пользователям.

Создайте новый файл YAML по имени web-pod.yaml:

nano web-pod.yaml

Добавьте следующий код, который определяет опд с одним контейнером на основе образа Docker 8host/todo-app. Он работает по порту 3000 и протоколу TCP.

apiVersion: v1
kind: Pod
metadata:
name: web
labels:
name: web
app: todoapp
spec:
containers:
- image: 8host/todo-app
name: myweb
ports:
- containerPort: 3000

Обратите внимание, определение содержит метки name и app. Сервис будет использовать эти метки для маршрутизации входящего трафика на соответствующие порты.

Выполните следующую команду для создания пода:

kubectl create -f web-pod.yaml
pod "web" created

Проверьте новый под:

kubectl get pods
NAME      READY     STATUS    RESTARTS   AGE
db        1/1       Running   0          8m
web       1/1       Running   0          9s

Обратите внимание, что в списке есть и под базы данных MongoDB, и под веб-приложения.

Теперь нужно сделать под приложения web доступным в интернете.

Сервисы позволяют открывать к подам как внешний, так и внутренний доступ. Определите сервис, который сделает под web доступным. Откройте его через NodePort, схему, которая сделает поды доступными через произвольный порт, открытый на каждой ноде кластера.

Создайте новый файл web-service.yaml и добавьте в него определение сервиса:

apiVersion: v1
kind: Service
metadata:
name: web
labels:
name: web
app: todoapp
spec:
selector:
name: web
type: NodePort
ports:
- name: http
port: 3000
targetPort: 3000
protocol: TCP

Сервис обнаруживает в пространстве имен все поды, которые соответствуют метке web. Раздел selector явно определяет эту ассоциацию.

Сервис имеет тип NodePort, который объявляется строкой type: NodePort.

Передайте сервис в кластер:

kubectl create -f web-service.yml
service "web" created

Теперь узнайте, какой порт использует под:

kubectl get services
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
db           ClusterIP   10.109.114.243   <none>        27017/TCP        12m
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP          59m
web          NodePort    10.107.206.92    <none>        3000:30770/TCP   12s

Сервис доступен по порту 30770. Попробуйте подключиться к одной из рабочих нод.

Получите открытый IP-адрес рабочей ноды, связанной с кластером Kubernetes, используя консоль хостинг-провайдера.

Узнав IP-адрес, используйте команду curl, чтобы отправить HTTP-запрос одной из нод на порт 30770:
curl http://your_worker_ip_address:30770

Вы получите примерно такой вывод:

<!DOCTYPE html>
<html>
<head>
<title>Containers Todo Example</title>
<link rel='stylesheet' href='/stylesheets/screen.css' />
<!--[if lt IE 9]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<div id="layout">
<h1 id="page-title">Containers Todo Example</h1>
<div id="list">
<form action="/create" method="post" accept-charset="utf-8">
<div class="item-new">
<input class="input" type="text" name="content" />
</div>
</form>
</div>
<div id="layout-footer"></div>
</div>
<script src="/javascripts/ga.js"></script>
</body>
</html>

4: Масштабирование веб-приложения

Набор реплик гарантирует, что в кластере будет работать минимальное количество подов. Если под упакован как набор реплик, Kubernetes всегда будет поддерживать минимальное количество подов, определенное в спецификации.

Удалите текущий под и воссоздайте два пода через набор реплик. Если вы оставите этот под в работе, он не будет частью набора реплик. Потому нужно запускать поды через наборы реплик, даже если в наборе будет только один под.

Удалите существующий под:

kubectl delete pod web
pod "web" deleted

Теперь создайте новую декларацию набора реплик. Определение набора реплик идентично определению пода. Ключевое отличие состоит в том, что оно содержит элемент replica, который определяет количество подов, которое нужно запустить. Как и под, набор также содержит метки в качестве метаданных, которые помогают в обнаружении сервисов.

Создайте файл web-rs.yaml и вставьте в него код:

apiVersion: extensions/v1beta1
kind: ReplicaSet
metadata:
name: web
labels:
name: web
app: todoapp
spec:
replicas: 2
template:
metadata:
labels:
name: web
spec:
containers:
- name: web
image: 8host/todo-app
ports:
- containerPort: 3000

Сохраните и закройте файл.

Создайте набор реплик:

kubectl create -f web-rs.yaml
replicaset "web" created

Проверьте количество подов:

kubectl get pods
NAME        READY     STATUS    RESTARTS   AGE
db          1/1       Running   0          18m
web-n5l5h   1/1       Running   0          25s
web-wh6nf   1/1       Running   0          25s

Когда вы обращаетесь к сервису через NodePort, запрос отправляется на один из подов, управляемых набором реплик.

Давайте проверим функциональность набора реплик, удалив один из подов, и посмотрим, что произойдет:

kubectl delete pod web-wh6nf
pod "web-wh6nf" deleted

Снова проверьте поды:

kubectl get pods
NAME        READY     STATUS              RESTARTS   AGE
db          1/1       Running             0          19m
web-n5l5h   1/1       Running             0          1m
web-wh6nf   1/1       Terminating         0          1m
web-ws59m   0/1       ContainerCreating   0          2s

Как только под удаляется, Kubernetes создает новый под, чтобы поддерживать заданное минимальное количество подов.

Вы можете масштабировать набор реплик для запуска дополнительных подов.

Выполните следующую команду, чтобы масштабировать веб-приложение до 10 подов.

kubectl scale rs/web --replicas=10
replicaset "web" scaled

Проверьте количество подов:

kubectl get pods
NAME        READY     STATUS              RESTARTS   AGE
db          1/1       Running             0          22m
web-4nh4g   1/1       Running             0          21s
web-7vbb5   1/1       Running             0          21s
web-8zd55   1/1       Running             0          21s
web-f8hvq   0/1       ContainerCreating   0          21s
web-ffrt6   1/1       Running             0          21s
web-k6zv7   0/1       ContainerCreating   0          21s
web-n5l5h   1/1       Running             0          3m
web-qmdxn   1/1       Running             0          21s
web-vc45m   1/1       Running             0          21s
web-ws59m   1/1       Running             0          2m

Kubernetes инициировал процесс масштабирования пода web. Когда запрос приходит на сервис через NodePort, он маршрутизируется на один из подов в наборе реплик.

Когда трафик и загрузка снижаются, вы можете вернуться к исходной конфигурации из двух подов.

kubectl scale rs/web --replicas=2
replicaset "web" scaled

Эта команда прерывает работу всех подов, оставляя только два из них:

kubectl get pods
NAME        READY     STATUS        RESTARTS   AGE
db          1/1       Running       0          24m
web-4nh4g   1/1       Terminating   0          2m
web-7vbb5   1/1       Terminating   0          2m
web-8zd55   1/1       Terminating   0          2m
web-f8hvq   1/1       Terminating   0          2m
web-ffrt6   1/1       Terminating   0          2m
web-k6zv7   1/1       Terminating   0          2m
web-n5l5h   1/1       Running       0          5m
web-qmdxn   1/1       Terminating   0          2m
web-vc45m   1/1       Terminating   0          2m
web-ws59m   1/1       Running       0          4m

Чтобы проверить доступность набора реплик, попробуйте удалить один из подов и проверить их количество.

kubectl delete pod web-ws59m
pod "web-ws59m" deleted
kubectl get pods
NAME        READY     STATUS              RESTARTS   AGE
db          1/1       Running             0          25m
web-n5l5h   1/1       Running             0          7m
web-ws59m   1/1       Terminating         0          5m
web-z6r2g   0/1       ContainerCreating   0          5s

Как только количество подов уменьшилось, Kubernetes восстановил его, чтобы соответствовать требованиям файла YAML. Когда один из подов в наборе реплик удаляется, создается другой под. Это обеспечивает высокую доступность приложения, гарантируя работу установленного в параметрах количества подов.

Удалите все объекты, созданные в этом мануале:

kubectl delete -f db-pod.yaml -f db-service.yaml -f web-rs.yaml -f web-service.yaml
pod "db" deleted
service "db" deleted
replicaset "web" deleted
service "web" deleted

Заключение

Теперь вы умеете работать с микросервисами.

В следующем мануале этой серии вы узнаете, как настроить высокую доступность MongoDB с помощью StatefulSet.

Tags: , , ,