Вступление
Kubernetes - инструмент оркестровки контейнеров с открытым исходным кодом для управления контейнеризованными приложениями. В предыдущем уроке из этой серии A Более пристальный взгляд на Kubernetes вы изучили строительные блоки Kubernetes.
В этом руководстве вы будете применять концепции из предыдущих руководств для создания, развертывания и управления комплексным приложением микросервисов в Kubernetes. Пример веб-приложения, которое вы будете использовать в этом руководстве, представляет собой приложение «список задач», написанное на Node.js, которое использует MongoDB в качестве базы данных. Это то же самое приложение, которое мы использовали в учебном пособии Building Containerized Applications.
Вы создадите образ контейнера для этого приложения из Dockerfile, переместите образ в Docker Hub, а затем разверните его в своем кластере. Затем вы масштабируете приложение, чтобы удовлетворить возросший спрос.
Предпосылки
Для завершения этого урока вам понадобится:
-
Кластер Kubernetes, который вы можете настроить в третьей части этой серии руководств, Getting Started with Kubernetes.
-
Активная учетная запись Docker Hub для хранения изображения.
-
Git установлен на вашем локальном компьютере. Вы можете следовать учебному руководству Contributing для Open Source: Начало работы с Git, чтобы установить и настроить Git на вашем компьютере.
Шаг 1 - Создайте образ с помощью Dockerfile
Мы начнем с контейнера веб-приложения, упаковав его в образ Docker.
Начните с изменения вашего домашнего каталога, затем используйте Git для клонирования примера веб-приложения этого руководства из его официального репозитория на GitHub.
cd ~
git clone https://github.com/janakiramm/todo-app.git
Создайте образ контейнера из Dockerfile. Используйте ключ -t, чтобы пометить изображение именем пользователя реестра, именем изображения и необязательным тегом.
docker build -t sammy/todo .
Вывод подтверждает, что изображение было успешно построено и помечено соответствующим образом.
OutputSending build context to Docker daemon 8.238MB
Step 1/7 : FROM node:slim
---> 286b1e0e7d3f
Step 2/7 : LABEL maintainer = "[email protected]"
---> 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 sammy/todo-app:latest
Убедитесь, что образ создан, запустив команду docker images.
docker images
Вы можете увидеть размер изображения вместе со временем, с момента его создания.
OutputREPOSITORY TAG IMAGE ID CREATED SIZE
sammy/todo-app latest 81f5f605d1ca 9 minutes ago 236MB
Затем отправьте изображение в общедоступный реестр на Docker Hub. Для этого войдите в свою учетную запись Docker Hub:
docker login
После того, как вы предоставите свои учетные данные, отметьте свое изображение, используя имя пользователя Docker Hub:
docker tag /todo-app
Затем отправьте изображение в Docker Hub:
docker push
Вы можете убедиться, что новое изображение доступно, выполнив поиск Docker Hub в вашем веб-браузере.
Передав изображение Docker в реестр, давайте запакуем приложение для Kubernetes.
Шаг 2 - Разверните MongoDB Pod в Кубернетесе
Приложение использует MongoDB для хранения списков дел, созданных через веб-приложение. Чтобы запустить MongoDB в Kubernetes, нам нужно упаковать его как Pod. Когда мы запустим этот Pod, он запустит один экземпляр MongoDB.
Создайте новый файл YAML с именем db-pod.yaml:
nano db-pod.yaml
Добавьте следующий код, который определяет Pod с одним контейнером на основе MongoDB. Мы выставляем порт + 27017 +
, стандартный порт, используемый MongoDB. Обратите внимание, что определение содержит метки + name
и` + app`. Мы будем использовать эти ярлыки для идентификации и настройки конкретных модулей.
дб-pod.yaml
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.
Выполните следующую команду, чтобы создать Pod.
kubectl create -f db-pod.yml
Вы увидите этот вывод:
Outputpod "db" created
Теперь проверьте создание Pod.
kubectl get pods
Вывод показывает Pod и указывает, что он работает:
OutputNAME READY STATUS RESTARTS AGE
db 1/1 0 2m
Давайте сделаем этот Pod доступным для внутренних потребителей кластера.
Создайте новый файл с именем + db-service.yaml +
, содержащий этот код, который определяет Сервис для MongoDB:
дб-service.yaml
apiVersion: v1
kind: Service
metadata:
name: db
labels:
name: mongo
app:
spec:
selector:
name: mongo
type: ClusterIP
ports:
- name: db
port: 27017
targetPort: 27017
Служба обнаруживает все модули в одном и том же пространстве имен, которые соответствуют метке с + name: db +
. Раздел + selector +
файла YAML явно определяет эту связь.
Мы указываем, что Сервис виден внутри кластера через объявление + type: ClusterIP +
.
Сохраните файл и выйдите из редактора. Затем используйте + kubectl +
, чтобы отправить его в кластер.
kubectl create -f db-service.yml
Вы увидите этот вывод, указывающий, что Сервис был успешно создан:
Outputservice "db" created
Давайте получим порт, на котором доступен Pod.
kubectl get services
Вы увидите этот вывод:
OutputNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
db ClusterIP 10.109.114.243 <none> 14s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 47m
Из этого вывода вы можете видеть, что Сервис доступен на порту + 27017 +
. Веб-приложение может связаться с MongoDB через этот сервис. Когда он использует имя хоста + db +
, служба DNS, работающая в Kubernetes, преобразует адрес в ClusterIP, связанный с Сервисом. Этот механизм позволяет стручкам обнаруживать и общаться друг с другом.
Имея базу данных Pod и Service, давайте создадим Pod для веб-приложения.
Шаг 3. Разверните Node.JS Web App как модуль
Давайте упакуем образ Docker, созданный вами на первом шаге этого руководства, в виде Pod и развернем его в кластере. Это будет действовать как уровень интерфейсного веб-приложения, доступный для конечных пользователей.
Создайте новый файл YAML с именем + web-pod.yaml +
:
nano web-pod.yaml
Добавьте следующий код, который определяет Pod с одним контейнером на основе образа Docker + sammy / todo-app +
. Он выставлен на порт + 3000 +
по протоколу TCP.
веб-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: web
labels:
name: web
app:
spec:
containers:
- image: sammy/todo-app
name: myweb
ports:
- containerPort: 3000
Обратите внимание, что определение содержит метки + name
и` + app`. Сервис будет использовать эти метки для маршрутизации входящего трафика на соответствующие порты.
Выполните следующую команду, чтобы создать Pod:
kubectl create -f web-pod.yaml
Outputpod "web" created
Давайте проверим создание Pod:
kubectl get pods
OutputNAME READY STATUS RESTARTS AGE
1/1 Running 0 8m
1/1 Running 0 9s
Обратите внимание, что у нас есть и база данных MongoDB, и веб-приложение, работающее как Pod.
Теперь мы сделаем Pod + web +
общедоступным Интернетом.
Сервисы предоставляют набор модулей как внутри, так и снаружи. Давайте определим Сервис, который делает «+ web +» Pod общедоступным. Мы представим его через NodePort, схему, которая делает Pod доступным через произвольный порт, открытый на каждом узле кластера.
Создайте новый файл с именем + web-service.yaml +
, который содержит этот код, который определяет Сервис для приложения:
apiVersion: v1
kind: Service
metadata:
name: web
labels:
name: web
app:
spec:
selector:
name: web
type: NodePort
ports:
- name: http
port: 3000
targetPort: 3000
protocol: TCP
Служба обнаруживает все модули в одном и том же пространстве имен, которые соответствуют метке с именем + web +
. Раздел селектора файла YAML явно определяет эту связь.
Мы указываем, что Сервис имеет тип + NodePort +
через объявление + type: NodePort +
.
Используйте + kubectl +
для отправки этого в кластер.
kubectl create -f web-service.yml
Вы увидите этот вывод, указывающий, что Сервис был успешно создан:
Outputservice "web" created
Давайте получим порт, на котором доступен Pod.
kubectl get services
OutputNAME 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: 12s
Из этого вывода мы видим, что Сервис доступен через порт + 30770 +
. Давайте попробуем подключиться к одному из рабочих узлов.
Получите общедоступный IP-адрес для одного из рабочих узлов, связанных с вашим кластером Kubernetes, с помощью консоли DigitalOcean.
изображение: https: //assets.digitalocean.com/articles/webinar_3_kubernetes_stackpoint/w9acP7y.png [Консоль DigitalOcean, показывающая рабочие узлы]
Получив IP-адрес, используйте команду + curl +
, чтобы сделать HTTP-запрос к одному из узлов на порту + 30770 +
:
curl http://:30770
Вы увидите вывод, похожий на этот:
Output<!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>
Вы определили веб-Pod и Сервис. Теперь давайте рассмотрим масштабирование с помощью наборов реплик.
Шаг 5 - Масштабирование веб-приложения
Набор реплик гарантирует, что в кластере постоянно работает минимальное количество модулей. Когда модуль упакован как набор реплик, Kubernetes всегда запускает минимальное количество модулей, указанное в спецификации.
Давайте удалим текущий Pod и воссоздадим два Pod через набор реплик. Если мы оставим модуль запущенным, он не будет частью набора реплик. Таким образом, было бы неплохо запускать Pod через набор реплик, даже если счетчик всего один.
Сначала удалите существующий Pod.
kubectl delete pod web
Outputpod "web" deleted
Теперь создайте новое объявление набора реплик. Определение набора реплик идентично стручку. Основное отличие состоит в том, что он содержит элемент + replica +
, который определяет количество модулей, которые необходимо запустить. Как и Pod, он также содержит метки как метаданные, которые помогают в обнаружении служб.
Создайте файл + 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: sammy/todo-app
ports:
- containerPort: 3000
Сохраните и закройте файл.
Теперь создайте набор реплик:
kubectl create -f web-rs.yaml
Outputreplicaset "web" created
Затем проверьте количество стручков:
kubectl get pods
OutputNAME 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
Outputpod "web-wh6nf" deleted
Посмотрите на стручки еще раз:
kubectl get pods
OutputNAME 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=
Outputreplicaset "web" scaled
Проверьте количество стручков:
kubectl get pods
Вы увидите этот вывод:
OutputNAME 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 инициировал процесс масштабирования Pod + web +. Когда запрос поступает в Сервис через NodePort, он направляется к одному из модулей в наборе реплик.
Когда трафик и нагрузка уменьшатся, мы можем вернуться к исходной конфигурации двух модулей.
kubectl scale rs/web --replicas=
Outputreplicaset "web" scaled
Эта команда завершает все блоки, кроме двух.
kubectl get pods
OutputNAME 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
Outputpod "web-ws59m" deleted
kubectl get pods
OutputNAME 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
Outputpod "db" deleted
service "db" deleted
replicaset "web" deleted
service "web" deleted
Заключение
В этом руководстве вы применили все концепции, описанные в этой серии, для упаковки, развертывания и масштабирования приложений микросервисов.
В следующей части этой серии вы узнаете, как сделать MongoDB высокодоступным, запустив его как StatefulSet.