ProHoster > Блог > Администрирование > Современные приложения на OpenShift, часть 3: OpenShift как среда разработки и конвейеры OpenShift Pipelines
Современные приложения на OpenShift, часть 3: OpenShift как среда разработки и конвейеры OpenShift Pipelines
Привет всем в этом блоге! С вами третий пост из серии, в которой мы показываем, как развертывать современные веб-приложения на Red Hat OpenShift.
В двух предыдущих постах мы рассказали, как развертывать современные веб-приложения всего за несколько шагов и как использовать новый образ S2I вместе с готовым образом HTTP-сервера, например, NGINX с помощь связанных сборок chained builds для организации продакшн-развертывания.
Сегодня мы покажем, как запустить на платформе OpenShift сервер разработки для своего приложения и синхронизировать его с локальной файловой системой, а также поговорим о том, что такое OpenShift Pipelines и как можно применять в качестве альтернативы связанным сборкам.
OpenShift как среда разработки
Рабочий процесс разработки (development workflow)
Как уже говорилось в первом посте, типовой процесс разработки для современных веб-приложений – это просто некий «сервер разработки», который отслеживает изменения в локальных файлах. Когда они происходят, запускается сборка приложения, а затем оно обновляется в браузер.
В большинстве современных фреймворков такой «сервер разработки» встроен в соответствующие инструменты командной строки.
Локальный пример
Для начала посмотрим, как это работает в случае локального запуска приложений. В качестве примера возьмем приложение React из предыдущих статей, хотя практически те же концепции рабочего процесса применяются и во всех других современных фреймворках.
Итак, чтобы запустить «сервер разработки» в нашем примере с React, введем следующую команду:
$ npm run start
Тогда в окне терминала мы увидим примерно следующее:
А наше приложение откроется в браузере по умолчанию:
Теперь, если мы внесем изменения в файл, то приложение должно обновиться в браузере.
OK, с разработкой в локальном режиме все ясно, а как добиться такого же на OpenShift?
Сервер разработки на OpenShift
Если помните, в предыдущем посте, мы разбирали так называемый этап запуска (run phase) образа S2I и увидели, что по умолчанию обслуживанием нашего веб-приложения занимается модуль serve.
Однако если внимательнее взглянуть run script из того примера, то в нем есть переменная окружения $NPM_RUN, которая позволяет выполнить и свою команду.
Например, можно использовать модуль nodeshift, чтобы развернуть наше приложение:
Примечание: пример выше приводится в сокращенном виде для того, чтобы проиллюстрировать общую идею.
Здесь мы добавили в наше развертывание переменную окружения NPM_RUN, которая говорит этапу исполнения, что он должен запустить команду yarn start, которая стартует сервер разработки React внутри нашего pod-а OpenShift.
Если посмотреть лог работающего pod-а, то там будет примерно следующее:
Конечно, это все будет ни о чем до тех пор, пока мы не сможем синхронизировать локальный код с кодом, который тоже контролируется на предмет изменений, но живет на удаленном сервере.
Синхронизация удаленного и локального кода
К счастью, с синхронизацией легко поможет nodeshift, а для отслеживания изменений можно воспользоваться командой watch.
Так что после того, как мы выполнили команду для развертывания сервера разработки для нашего приложения, мы можем смело использовать вот такую команду:
$ npx nodeshift watch
В результате будет проведено подключение к запущенному pod’у, который мы создали чуть ранее, активируется синхронизация наших локальных файлов с удаленным кластером, а файлы на нашей локальной системе начнут отслеживаться на предмет изменений.
Поэтому, если теперь обновить файл src/App.js, то система среагирует на эти изменения, скопирует их на удаленный кластер и запустить сервер разработки, который затем обновит наше приложение в браузере.
Для полноты картины покажем, как выглядят эти команды целиком:
Команда watch – это абстракция поверх команды oc rsync, подробнее узнать о том, как это работает можно здесь.
Это был пример для React, но точно такой же метод можно использовать и с другими фреймворками, просто пропишите нужным образом переменную окружения NPM_RUN.
Конвейеры Openshift Pipelines
Дальше мы поговорим про такой инструмент, как OpenShift Pipelines, и о том, как его можно использовать в качестве альтернативы связанным сборкам chained build.
Что такое OpenShift Pipelines
OpenShift Pipelines – это облачно-ориентированная CI/CD-система непрерывной интеграции и доставки, предназначенная для организации конвейеров с использованием Tekton. Tekton – это гибкий Kubernetes-нативный CI/CD-фреймворк с открытым кодом, позволяющий автоматизировать развертывание на различных платформах (Kubernetes, serverless, виртуальные машины и т.д.) за счет абстрагирования от нижележащего уровня.
Для понимания этой статьи нужны определенные знания по Pipelines, поэтому мы настоятельно советуем вначале ознакомиться с официальным учебником.
Настройка рабочей среды
Чтобы поиграться с примерами из этой статьи, сначала надо подготовить рабочую среду:
Установить и настроить кластер OpenShift 4. В наших примерах для этого используются CodeReady Containers (CRD), инструкции по установке которого можно найти здесь.
После того, как кластер будет готов, на него надо установить Pipeline Operator. Не бойтесь, это легко, инструкции по установке здесь.
Запустить инструмент командной строки create-react-app, чтобы создать приложение, которое потом будет развертываться (это простое приложение React).
(Опционально) Клонировать репозиторий, чтобы локально запускать пример приложения командой npm install и затем npm start.
В репозитории приложения также будет папка k8s, где будут лежать YAML’ы Kubernetes/OpenShift, используемые для развертывания приложения. Там будут Tasks, ClusterTasks, Resources и Pipelines, которые мы создадим в этом репозитории.
Приступаем
Первым делом для нашего примера надо создать новый проект в кластере OpenShift. Назовем этот проект webapp-pipeline и создадим его следующей командой:
$ oc new-project webapp-pipeline
Дальше это имя проекта будет фигурирует в коде, так что, если решите назвать его как-то иначе, не забывайте соответствующим образом править код из примеров. Начиная с этого места, мы пойдем не сверху-вниз, а снизу-вверх: то есть, вначале создадим все составляющие конвейера, и лишь затем его самого.
Итак, первым делом…
Задачи Tasks
Создадим пару задач (tasks), которые затем помогут развертывать приложение в рамках нашего конвейера pipeline. Первая задача – apply_manifests_task – отвечает за применение YAML тех Kubernetes-ресурсов (service, deployment и route), которые находятся в папке k8s нашего приложения. Вторая задача – update_deployment_task – отвечает за обновление уже развернутого образа на тот, который создается нашим конвейером.
Не переживайте, если пока не очень понятно. На самом деле, эти задачи – что-то вроде утилит, и мы подробнее разберем их чуть позже. А пока что просто создадим их:
Затем с помощью команды tkn CLI проверим, что задачи создались:
$ tkn task ls
NAME AGE
apply-manifests 1 minute ago
update-deployment 1 minute ago
Примечание: это локальные задачи вашего текущего проекта.
Кластерные задачи Cluster tasks
Кластерные задачи – это в общем-то то же самое, что и просто задачи. То есть, это повторно используемая коллекция шагов, которые комбинируются тем или и иным образом при запуске конкретной задачи. Отличие в том, что кластерная задача доступна везде в пределах кластера. Чтобы увидеть список кластерных задач, которые автоматически создаются при добавлении Pipeline Operator, опять воспользуемся командой tkn CLI:
$ tkn clustertask ls
NAME AGE
buildah 1 day ago
buildah-v0-10-0 1 day ago
jib-maven 1 day ago
kn 1 day ago
maven 1 day ago
openshift-client 1 day ago
openshift-client-v0-10-0 1 day ago
s2i 1 day ago
s2i-go 1 day ago
s2i-go-v0-10-0 1 day ago
s2i-java-11 1 day ago
s2i-java-11-v0-10-0 1 day ago
s2i-java-8 1 day ago
s2i-java-8-v0-10-0 1 day ago
s2i-nodejs 1 day ago
s2i-nodejs-v0-10-0 1 day ago
s2i-perl 1 day ago
s2i-perl-v0-10-0 1 day ago
s2i-php 1 day ago
s2i-php-v0-10-0 1 day ago
s2i-python-3 1 day ago
s2i-python-3-v0-10-0 1 day ago
s2i-ruby 1 day ago
s2i-ruby-v0-10-0 1 day ago
s2i-v0-10-0 1 day ago
А теперь создадим две кластерные задачи. Первая будет генерировать образ S2I и отправлять его во внутренний реестр OpenShift; вторая – выполнять сборку нашего образа на базе NGINX, используя в качестве содержимого уже собранное нами приложение.
Создаем и отправляем образ
При создании первой задачи мы повторим то, что уже делали в предыдущей статье про связанные сборки. Напомним, что мы использовали образ S2I (ubi8-s2i-web-app), чтобы «собрать» наше приложение, и в итоге получали образ, хранящийся во внутреннем реестре OpenShift. Теперь мы будем используем этот S2I-образ веб-приложения, чтобы создать DockerFile для нашего приложения, а затем задействуем Buildah, чтобы провести реальную сборку и отправить полученный образ во внутренний реестр OpenShift, поскольку это именно то, что OpenShift делает, когда вы развертываете свои приложения с помощью NodeShift.
Мы не будем подробно разбирать это, а лишь остановимся на параметре OUTPUT_DIR:
params:
- name: OUTPUT_DIR
description: The location of the build output directory
default: build
По умолчанию этот параметр равен build, именно туда React складывает собранный контент. В других фреймворках используются другие пути, например, в Ember это dist. Вывод нашей первой кластерной задачи будет представлять собой образ, содержащий собранные нами HTML, JavaScript и CSS.
Собираем образ на базе NGINX
Что касается нашей второй кластерной задачи, то она должна собирать нам образ на основе NGINX, используя контент уже собранного нами приложения. По сути, эта та часть предыдущего раздела, где мы рассматривали связанные сборки chained builds.
Для этого мы – точно так же, как чуть выше – создадим кластерную задачу webapp-build-runtime:
Если посмотреть код этих кластерных задач, то видно, что там не конкретизируется репозиторий Git, с которым мы работаем, или имена образов, которые мы создаем. Мы только задаем, что именно мы передаем в Git, или некий образ, куда надо вывести итоговый образ. Именно поэтому эти кластерные задачи можно повторно использовать и при работе с другими приложениями.
И тут мы изящно переходим к следующему пункту…
Ресурсы
Итак, поскольку, как мы только что сказали, кластерные задачи должны быть максимально обобщенными, нам надо создать ресурсы, которые будут использоваться на входе (репозиторий Git) и на выходе (итоговый образы). Первый ресурс, который нам нужен –это Git, где находится наше приложение, что-то вроде такого:
# This resource is the location of the git repo with the web application source
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
name: web-application-repo
spec:
type: git
params:
- name: url
value: https://github.com/nodeshift-starters/react-pipeline-example
- name: revision
value: master
Здесь PipelineResource имеет тип git. Ключ url в секции params указывает на конкретный репозиторий и задает ветку master (это опционально, но пишем ее для полноты).
Теперь нам надо создать ресурс для образа, куда будут сохраняться результаты выполнения задачи s2i-web-app task, это делается так:
# This resource is the result of running "npm run build", the resulting built files will be located in /opt/app-root/output
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
name: built-web-application-image
spec:
type: image
params:
- name: url
value: image-registry.openshift-image-registry.svc:5000/webapp-pipeline/built-web-application:latest
Здесь PipelineResource имеет тип image, а значение параметра url pуказывает на внутренний OpenShift Image Registry, конкретно на тот, что находится в пространстве имен webapp-pipeline. Не забудьте поменять этот параметр, если используете другое пространство имен.
И, наконец, последний ресурс, который нам понадобится, тоже будет иметь тип image и это будет итоговый образ NGINX, который затем будет использоваться при развертывании:
# This resource is the image that will be just the static html, css, js files being run with nginx
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
name: runtime-web-application-image
spec:
type: image
params:
- name: url
value: image-registry.openshift-image-registry.svc:5000/webapp-pipeline/runtime-web-application:latest
И снова обратите внимание, что этот ресурс сохраняет образ во внутреннем реестре OpenShift в пространстве имен webapp-pipeline.
Чтобы разом создать все эти ресурсы, воспользуемся командой create:
Эта задача берет входные (gir-ресурс) и выходные (ресурс built-web-application-image) параметры. Мы также передаем ей специальный параметр, чтобы она не верифицировала TLS, поскольку мы используем самоподписанные сертификаты:
Как и с предыдущей задачей, мы передаем ресурс, но теперь это built-web-application-image (вывод нашей предыдущей задачи). И в качестве вывода мы опять задаем образ. Поскольку эта задач должна выполняться после предыдущей, то добавляем поле runAfter:
Следующие две задачи отвечают за применение YAML-файлов сервиса, маршрута и деплоймента, которые живут в каталоге k8s нашего веб приложения, а также за то, чтобы обновлять этот деплоймент при создании новых образов. Эти две кластерные задачи мы задали еще в начале статьи.
Запуск конвейера
Итак, все части нашего конвейера созданы, и мы запустим его следующей командой:
$ tkn pipeline start build-and-deploy-react
На этом этапе командная строка используется в интерактивном режиме и надо выбирать соответствующие ресурсы в ответ на каждый её запрос: для ресурса git выбираем web-application-repo, затем для ресурса первого образа – built-web-application-image, и, наконец, для ресурса второго образа –runtime-web-application-image:
? Choose the git resource to use for web-application-repo: web-application-repo (https://github.com/nodeshift-starters/react-pipeline-example)
? Choose the image resource to use for built-web-application-image: built-web-application-image (image-registry.openshift-image-registry.svc:5000/webapp-pipeline/built-web-
application:latest)
? Choose the image resource to use for runtime-web-application-image: runtime-web-application-image (image-registry.openshift-image-registry.svc:5000/webapp-pipeline/runtim
e-web-application:latest)
Pipelinerun started: build-and-deploy-react-run-4xwsr
Теперь проверим статус конвейера с помощью следующей команды:
$ tkn pipeline logs -f
После того, как конвейер запустится и приложение будет развернуто, запросим опубликованный маршрут следующей командой:
$ oc get route react-pipeline-example --template='http://{{.spec.host}}'
Для большей визуальности можно посмотреть наш конвейер в Developer-режиме веб-консоли в разделе Pipelines, как показано на Рис. 1.
Рис.1. Обзор запущенных конвейеров.
Щелчок по запущенному конвейеру отображает дополнительные сведения, как показано на Рис.2.
Рис. 2. Дополнительные сведения о конвейере.
После дополнительных сведений можно посмотреть запущенные приложения в представлении Topology, как показано на Рис.3.
Рис 3. Запущенный pod.
Щелчок по кружочку в правом верхнем углу значка открывает наше приложение, как показано на Рис.4.
Рис. 4. Запущенное приложение React.
Заключение
Итак, мы показали, как запустить на OpenShift сервер разработки для своего приложения и синхронизировать его с локальной файловой системой. Также мы рассмотрели, как сымитировать chained-build template с помощью OpenShift Pipelines. Все коды примеров из этой статьи можно найти здесь.