Обзор задачи
В статье рассматривается выкат приложения в Kubernetes с помощью werf. Для деплоя приложений в Kubernetes werf использует Helm (с некоторыми изменениями и дополнениями). В статье мы создадим простое web-приложение, соберем все необходимые для него образы, создадим Helm-шаблоны и выкатим приложение в кластер Kubernetes.
Требования
- Работающий кластер Kubernetes. Для выполнения примера вы можете использовать как обычный Kubernetes-кластер, так и Minikube. Если вы решили использовать Minikube, прочитайте статью о настройке Minikube, чтобы запустить Minikube и Docker registry.
- Работающий Docker registry.
- Доступ от хостов Kubernetes с правами на push образов в Docker registry.
- Доступ от хостов Kubernetes с правами на pull образов в Docker registry.
- Установленные зависимости werf.
- Установленный multiwerf.
- Установленный и сконфигурированный
kubectl
для доступа в кластер Kubernetes (https://kubernetes.io/docs/tasks/tools/install-kubectl/).
Внимание! Далее в качестве адреса репозитория будет использоваться значение :minikube
. Если вы используете собственный кластер Kubernetes и Docker registry, то указывайте репозиторий проекта в Docker registry вместо аргумента :minikube
.
Выбор версии werf
Перед началом работы необходимо выбрать версию werf. Для выбора актуальной версии werf в канале stable, релиза 1.0, выполним следующую команду:
. $(multiwerf use 1.1 stable --as-file)
Архитектура приложения
Пример представляет собой простейшее web-приложение, для запуска которого нам нужен только web-сервер. Архитектуру приложения в Kubernetes можно представить следующим образом:
.----------------------.
| backend (Deployment) |
'----------------------'
|
|
.--------------------.
| frontend (Ingress) |
'--------------------'
Здесь backend
— web-сервер с приложением, frontend
— прокси-сервер, который выступает точкой входа и используется для перенаправления внешнего трафика.
Файлы приложения
Создадим пустую директорию проекта и перейдём в неё для выполнения следующих шагов:
mkdir myapp
cd myapp
werf ожидает, что все файлы, необходимые для сборки и развертывания приложения, находятся в папке приложения (папке проекта) вместе с исходным кодом, если он имеется. В нашем примере в этой директории будут храниться только конфигурации.
Подготовка образа
Необходимо подготовить образ приложения с web-сервером внутри.
Для этого создадим файл werf.yaml
в папке приложения со следующим содержимым:
project: myapp
configVersion: 1
---
image: ~
from: python:alpine
ansible:
install:
- file:
path: /app
state: directory
mode: 0755
- name: Prepare main page
copy:
content:
<!DOCTYPE html>
<html>
<body>
<h2>Congratulations!</h2>
<img src="https://flant.com/images/logo_en.png" style="max-height:100%;" height="76">
</body>
</html>
dest: /app/index.html
Web-приложение состоит из единственной статической HTML-страницы, которая задаётся в инструкциях и добавляется при сборке образа. Содержимое этой страницы будет отдавать Python HTTP-сервер.
Соберём образ приложения и загрузим его в Docker registry:
werf build-and-publish --stages-storage :local --tag-custom myapp --images-repo :minikube
Название собранного образа приложения состоит из адреса Docker registry (REPO
) и тега (TAG
).
При указании :minikube
в качестве адреса Docker registry werf использует адрес werf-registry.kube-system.svc.cluster.local:5000/myapp
.
Так как в качестве тега был указан myapp
, werf загрузит в Docker registry следующий образ werf-registry.kube-system.svc.cluster.local:5000/myapp:myapp
.
Подготовка конфигурации деплоя
werf использует встроенный Helm для применения конфигурации в Kubernetes.
Для описания объектов Kubernetes werf использует конфигурационные файлы Helm: шаблоны и файлы с параметрами (например, values.yaml
).
Помимо этого, werf поддерживает дополнительные файлы, такие как — файлы секретами и с секретными значениями (например secret-values.yaml
), а также дополнительные Go-шаблоны для интеграции собранных образов.
Backend
Создадим файл конфигурации backend .helm/templates/010-backend.yaml
(далее мы рассмотрим его подробнее):
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Chart.Name }}-backend
spec:
replicas: 4
template:
metadata:
labels:
service: {{ .Chart.Name }}-backend
spec:
containers:
- name: backend
workingDir: /app
command: [ "python3", "-m", "http.server", "8080" ]
{{ werf_container_image . | indent 8 }}
livenessProbe:
httpGet:
path: /
port: 8080
scheme: HTTP
readinessProbe:
httpGet:
path: /
port: 8080
scheme: HTTP
ports:
- containerPort: 8080
name: http
protocol: TCP
env:
{{ werf_container_env . | indent 8 }}
---
apiVersion: v1
kind: Service
metadata:
name: {{ .Chart.Name }}-backend
spec:
clusterIP: None
selector:
service: {{ .Chart.Name }}-backend
ports:
- name: http
port: 8080
protocol: TCP
В конфигурации описываются Deployment myapp-backend
и сервис для доступа к pod’ам. Особое внимание стоит уделить функциям werf werf_container_image
и werf_container_env
.
Функция werf_container_image
позволяет добавить поле image
с корректным именем образа в конфигурацию, используя контекст и опциональное имя из werf.yaml
в качестве параметров.
В нашем случае образ безымянный (~
), поэтому функция принимает только контекст без имени.
Функция добавит тег на основе используемой схемы тегирования.
В зависимости от схемы тегирования функция также может вернуть поле imagePullPolicy
с определённым значением.
Более подробно о функции можно прочитать в соответствующей статье.
Функция werf_container_env
позволяет сгенерировать служебные значения в секции env
, которые влияют на перезапуск pod’ов при изменении образа.
В качестве аргументов также принимаются контекст и имя образа из werf.yaml
.
Подробнее про логику работы и особенности можно прочитать в статье).
Frontend
Создадим файл конфигурации frontend .helm/templates/090-frontend.yaml
со следующим содержимым:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: myapp-frontend
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
rules:
- host: myapp.local
http:
paths:
- path: /
backend:
serviceName: myapp-backend
servicePort: 8080
Эта конфигурация описывает Ingress и настраивает NGINX прокси-сервер.
По описанному правилу трафик для хоста myapp.local
будет перенаправляться на backend-сервер myapp-backend
.
Деплой
При использовании minikube
перед деплоем необходимо включить ingress-модуль:
minikube addons enable ingress
Наконец, запустим деплой:
werf deploy --stages-storage :local --images-repo :minikube --tag-custom myapp --env dev
После запуска команды, werf создаст соответствующие ресурсы в Kubernetes и будет отслеживать статус Deployment myapp-backend
до его готовности (готовности всех pod’ов) либо ошибки.
Для того чтобы сформировать правильные имя Helm-релиза и namespace требуется указать окружение с помощью параметра --env
.
В результате будет создан Helm-релиз с именем myapp-dev
.
Название Helm-релиза состоит из имени проекта myapp
(указанного в werf.yaml
) и переданного названия окружения — dev
.
Более подробно про формирование имен Helm-релизов можно посмотреть в документации.
При создании объектов Kubernetes будет использоваться namespace myapp-dev
.
Имя namespace также по умолчанию состоит из имени проекта myapp
(указанного в werf.yaml
) и переданного названия окружения — dev
.
Более подробно про формирование namespace в Kubernetes можно посмотреть в документации.
Проверка работы приложения
Самое время узнать ip-адрес кластера. Если используется minikube, то узнать ip-адрес можно следующим способом (обычно это 192.168.99.100
):
minikube ip
Убедитесь, что имя myapp.local
разрешается в полученный IP-адрес кластера на вашей машине. Например, добавьте соответствующую запись в файл /etc/hosts
:
192.168.99.100 myapp.local
Проверим работу приложения, открыв адрес http://myapp.local
.
Удаление приложение из кластера
Для полного удаления из кластера развернутого приложения запустим следующую команду:
werf dismiss --env dev --with-namespace
Читайте также
Более подробно об особенностях и возможностях деплоя приложений с помощью werf, например, об использовании секретов читайте в руководстве.