Olá a todos neste blog! Este é o terceiro post de uma série onde mostramos como implantar aplicações web modernas no Red Hat OpenShift.

Nos dois posts anteriores, falamos sobre como implantar aplicações web modernas em apenas alguns passos e como utilizar a nova imagem S2I junto com uma imagem pronta de servidor HTTP, como o NGINX, com a ajuda de builds encadeados (chained builds) para organizar a implantação em produção.
Hoje, mostraremos como iniciar na plataforma OpenShift um servidor de desenvolvimento para sua aplicação e sincronizá-lo com o sistema de arquivos local, além de discutir o que são os OpenShift Pipelines e como podem ser aplicados como uma alternativa aos builds encadeados.
OpenShift como ambiente de desenvolvimento
Fluxo de trabalho de desenvolvimento
Como mencionado no , o processo típico de desenvolvimento para aplicações web modernas é simplesmente um "servidor de desenvolvimento" que monitora mudanças nos arquivos locais. Quando ocorrem, uma nova build da aplicação é iniciada e, em seguida, ela é atualizada no navegador.
Na maioria dos frameworks modernos, um "servidor de desenvolvimento" está embutido nas ferramentas de linha de comando apropriadas.
Exemplo local
Para começar, vamos ver como isso funciona no caso de uma execução local de aplicações. Como exemplo, usaremos a aplicação dos artigos anteriores, embora praticamente os mesmos conceitos de fluxo de trabalho se apliquem a todos os outros frameworks modernos.
Então, para iniciar o "servidor de desenvolvimento" em nosso exemplo com React, digitamos o seguinte comando:
$ npm run start
Então, na janela do terminal, veremos algo como o seguinte:

E nossa aplicação será aberta no navegador padrão:

Agora, se fizermos alterações no arquivo, a aplicação deverá ser atualizada no navegador.
OK, o desenvolvimento em modo local está claro, mas como obter o mesmo no OpenShift?
Servidor de desenvolvimento no OpenShift
Se você se lembra, no , discutimos a fase de execução (run phase) da imagem S2I e vimos que, por padrão, o módulo serve é responsável por atender nossa aplicação web.
No entanto, se olharmos mais de perto No exemplo, há a variável de ambiente $NPM_RUN, que permite executar seu próprio comando.
Por exemplo, podemos usar o módulo nodeshift para implantar nosso aplicativo:
$ npx nodeshift --deploy.env NPM_RUN="yarn start" --dockerImage=nodeshift/ubi8-s2i-web-app
Nota: o exemplo acima é apresentado de forma resumida para ilustrar a ideia geral.
Aqui, adicionamos à nossa implantação a variável de ambiente NPM_RUN, que informa à etapa de execução que deve iniciar o comando yarn start, que inicia o servidor de desenvolvimento React dentro do nosso pod no OpenShift.
Se olharmos os logs do pod em execução, veremos algo como:

Claro, isso não terá valor até que possamos sincronizar o código local com o código que também está sob controle de alterações, mas reside em um servidor remoto.
Sincronização do código remoto e local
Felizmente, a sincronização é facilitada pelo nodeshift, e para rastrear alterações, podemos usar o comando watch.
Assim, após executarmos o comando para implantar o servidor de desenvolvimento do nosso aplicativo, podemos usar o seguinte comando:
$ npx nodeshift watch
Como resultado, será estabelecida uma conexão com o pod em execução que criamos anteriormente, a sincronização de nossos arquivos locais com o cluster remoto será ativada e os arquivos em nosso sistema local começarão a ser monitorados quanto a alterações.
Portanto, se agora atualizarmos o arquivo src/App.js, o sistema reagirá a essas alterações, copiará para o cluster remoto e iniciará o servidor de desenvolvimento, que então atualizará nosso aplicativo no navegador.
Para completar o quadro, vamos mostrar como esses comandos se parecem na íntegra:
$ npx nodeshift --strictSSL=false --dockerImage=nodeshift/ubi8-s2i-web-app --build.env YARN_ENABLED=true --expose --deploy.env NPM_RUN="yarn start" --deploy.port 3000
$ npx nodeshift watch --strictSSL=false
O comando watch é uma abstração sobre o comando oc rsync; mais detalhes sobre como isso funciona podem ser encontrados. .
Este foi um exemplo para React, mas o mesmo método pode ser usado com outros frameworks, basta definir a variável de ambiente NPM_RUN corretamente.
Pipelines do OpenShift

A seguir, falaremos sobre uma ferramenta chamada OpenShift Pipelines e como ela pode ser usada como uma alternativa às compilações encadeadas.
O que são OpenShift Pipelines
OpenShift Pipelines é um sistema de CI/CD baseado na nuvem, projetado para organizar pipelines utilizando Tekton. Tekton é um framework CI/CD flexível, nativo do Kubernetes e de código aberto, que permite automatizar a implementação em várias plataformas (Kubernetes, serverless, máquinas virtuais etc.) ao abstrair o nível subjacente.
Para entender este artigo, são necessários alguns conhecimentos sobre Pipelines, portanto, recomendamos fortemente que você comece consultando o .
Configurando o ambiente de trabalho
Para experimentar os exemplos deste artigo, primeiro você precisa preparar o ambiente de trabalho:
- Instalar e configurar um cluster OpenShift 4. Em nossos exemplos, utilizamos o CodeReady Containers (CRD), cujas instruções de instalação podem ser encontradas .
- Depois que o cluster estiver pronto, você deve instalar o Pipeline Operator. Não se preocupe, é fácil, as instruções para instalação estão .
- Baixar (tkn) .
- Executar a ferramenta de linha de comando create-react-app para criar um aplicativo que será implantado depois (este é um aplicativo simples ).
- (Opcional) Clonar o repositório para executar localmente o exemplo do aplicativo com o comando npm install e, em seguida, npm start.
No repositório do aplicativo também haverá uma pasta k8s, onde estarão os YAMLs do Kubernetes/OpenShift usados para a implantação do aplicativo. Haverá Tasks, ClusterTasks, Resources e Pipelines que criaremos neste .
Vamos começar
Primeiramente, para nosso exemplo, precisamos criar um novo projeto no cluster OpenShift. Vamos chamar este projeto de webapp-pipeline e criar com o seguinte comando:
$ oc new-project webapp-pipeline
A partir de agora, esse nome de projeto aparecerá no código, então, se você decidir nomeá-lo de forma diferente, não se esqueça de ajustar o código dos exemplos apropriadamente. A partir daqui, iremos de baixo para cima: ou seja, primeiro criaremos todos os componentes do pipeline antes de criar o próprio.
Então, primeiro...
Tarefas Tasks
Vamos criar duas tarefas (tasks), que depois ajudarão a implantar o aplicativo dentro do nosso pipeline. A primeira tarefa – apply_manifests_task – é responsável por aplicar os recursos YAML do Kubernetes (service, deployment e route) que estão na pasta k8s do nosso aplicativo. A segunda tarefa – update_deployment_task – é responsável por atualizar a imagem já implantada para a que está sendo criada pelo nosso pipeline.
Não se preocupe se ainda não estiver muito claro. Na verdade, essas tarefas são como utilitários, e nós as exploraremos com mais detalhes mais tarde. Por enquanto, apenas vamos criá-las:
$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/tasks/update_deployment_task.yaml
$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/tasks/apply_manifests_task.yaml
Em seguida, usaremos o comando tkn CLI para verificar se as tarefas foram criadas:
$ tkn task ls
NOME IDADE
apply-manifests 1 minuto atrás
update-deployment 1 minuto atrás
Nota: estas são tarefas locais do seu projeto atual.
Tarefas do Cluster
Tarefas do Cluster são basicamente a mesma coisa que apenas tarefas. Ou seja, é uma coleção reutilizável de etapas que são combinadas de uma forma ou de outra ao executar uma tarefa específica. A diferença é que a tarefa do cluster está disponível em toda a extensão do cluster. Para ver a lista de tarefas do cluster que são criadas automaticamente ao adicionar o Pipeline Operator, novamente usaremos o comando tkn CLI:
$ tkn clustertask ls
NOME IDADE
buildah 1 dia atrás
buildah-v0-10-0 1 dia atrás
jib-maven 1 dia atrás
kn 1 dia atrás
maven 1 dia atrás
openshift-client 1 dia atrás
openshift-client-v0-10-0 1 dia atrás
s2i 1 dia atrás
s2i-go 1 dia atrás
s2i-go-v0-10-0 1 dia atrás
s2i-java-11 1 dia atrás
s2i-java-11-v0-10-0 1 dia atrás
s2i-java-8 1 dia atrás
s2i-java-8-v0-10-0 1 dia atrás
s2i-nodejs 1 dia atrás
s2i-nodejs-v0-10-0 1 dia atrás
s2i-perl 1 dia atrás
s2i-perl-v0-10-0 1 dia atrás
s2i-php 1 dia atrás
s2i-php-v0-10-0 1 dia atrás
s2i-python-3 1 dia atrás
s2i-python-3-v0-10-0 1 dia atrás
s2i-ruby 1 dia atrás
s2i-ruby-v0-10-0 1 dia atrás
s2i-v0-10-0 1 dia atrás
Agora vamos criar duas tarefas do cluster. A primeira irá gerar uma imagem S2I e enviá-la para o registro interno do OpenShift; a segunda irá realizar a compilação da nossa imagem baseada no NGINX, utilizando como conteúdo o aplicativo que já construímos.
Criando e enviando a imagem
Ao criar a primeira tarefa, iremos repetir o que já fizemos no artigo anterior sobre builds relacionados. Lembre-se de que utilizamos a imagem S2I (ubi8-s2i-web-app) para 'compilar' nosso aplicativo, e no final obtivemos uma imagem armazenada no registro interno do OpenShift. Agora, usaremos esta imagem S2I do aplicativo web para criar um DockerFile para nosso aplicativo e, em seguida, utilizaremos o Buildah para realizar a construção real e enviar a imagem resultante ao registro interno do OpenShift, pois é isso que o OpenShift faz ao implantar seus aplicativos com o NodeShift.
Pergunta-se de onde sabemos tudo isso? De , simplesmente copiamos e ajustamos para nossas necessidades.
Então, vamos criar a tarefa de cluster s2i-web-app:
$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/clustertasks/s2i-web-app-task.yaml
Não vamos analisar isso em detalhes, apenas nos deteremos no parâmetro OUTPUT_DIR:
params:
- name: OUTPUT_DIR
description: O local do diretório de saída da construção
default: build
Por padrão, este parâmetro é definido como build; é para lá que o React armazena o conteúdo compilado. Outros frameworks usam caminhos diferentes, por exemplo, no Ember é dist. A saída da nossa primeira tarefa de cluster será uma imagem contendo o HTML, JavaScript e CSS que compilamos.
Construindo uma imagem baseada no NGINX
Quanto à nossa segunda tarefa de cluster, ela deve compilar uma imagem baseada no NGINX, usando o conteúdo do aplicativo que já compilamos. Na verdade, esta é a parte da seção anterior onde discutimos builds encadeados.
Para isso, assim como fizemos acima, criaremos a tarefa de cluster webapp-build-runtime:
$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/clustertasks/webapp-build-runtime-task.yaml
Ao olhar o código dessas tarefas de cluster, é visível que não há especificação do repositório Git com o qual estamos trabalhando ou dos nomes das imagens que estamos criando. Apenas definimos o que exatamente estamos passando para o Git ou alguma imagem para a qual o resultado final deve ser enviado. É por isso que essas tarefas de cluster podem ser reutilizadas ao trabalhar com outros aplicativos.
E aqui elegantemente passamos para o próximo ponto...
Recursos
Assim, já que, como dissemos, as tarefas em cluster devem ser maximizadas em sua generalidade, precisamos criar recursos que serão utilizados na entrada (repositório Git) e na saída (imagens finais). O primeiro recurso que precisamos é o Git, onde nosso aplicativo está localizado, algo como isto:
# 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
Aqui o PipelineResource tem o tipo git. A chave url na seção params indica o repositório específico e define o ramo master (opcional, mas incluímos para completude).
Agora precisamos criar um recurso para a imagem, onde os resultados da execução da tarefa s2i-web-app serão salvos, isso é feito assim:
# 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
Aqui o PipelineResource tem o tipo image, e o valor do parâmetro url aponta para o registro de imagens interno do OpenShift, especificamente para aquele que está no namespace webapp-pipeline. Não se esqueça de alterar esse parâmetro se você estiver usando outro namespace.
E, finalmente, o último recurso que precisamos também terá o tipo image e será a imagem final do NGINX, que será utilizada durante a implantação:
# 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
E novamente, observe que este recurso salva a imagem no registro interno do OpenShift no namespace webapp-pipeline.
Para criar todos esses recursos de uma vez, usaremos o comando create:
$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/resources/resource.yaml
Você pode verificar se os recursos foram criados assim:
$ tkn resource ls
Pipeline
Agora que temos todos os componentes necessários, vamos montá-los em um pipeline, criando-o com o seguinte comando:
$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/pipelines/build-and-deploy-react.yaml
Mas, antes de executar esse comando, vamos analisar esses componentes. O primeiro é o nome:
apiVersion: tekton.dev/v1alpha1
kind: Pipeline
metadata:
name: build-and-deploy-react
Em seguida, na seção spec, vemos a especificação dos recursos que criamos anteriormente:
spec:
resources:
- name: web-application-repo
type: git
- name: built-web-application-image
type: image
- name: runtime-web-application-image
type: image
Depois criamos as tarefas que nosso pipeline deve executar. Primeiro, ele deve executar a tarefa s2i-web-app que já criamos:
tasks:
- name: build-web-application
taskRef:
name: s2i-web-app
kind: ClusterTask
Essa tarefa pega os parâmetros de entrada (recurso gir) e de saída (recurso built-web-application-image). Também passamos um parâmetro especial para que ela não verifique o TLS, uma vez que estamos usando certificados autoassinados:
recursos:
entradas:
- nome: fonte
recurso: repositório-de-aplicações-web
saídas:
- nome: imagem
recurso: imagem-de-aplicação-web-construída
parâmetros:
- nome: TLSVERIFY
valor: "false"
A próxima tarefa é quase a mesma, só que aqui chamamos a tarefa de cluster já criada, webapp-build-runtime:
nome: construir-imagem-runtime
referênciaTarefa:
nome: webapp-build-runtime
tipo: TarefaDeCluster
Assim como na tarefa anterior, passamos o recurso, mas agora é a imagem-de-aplicação-web-construída (saída da nossa tarefa anterior). E como saída, novamente especificamos a imagem. Como esta tarefa deve ser executada após a anterior, adicionamos o campo runAfter:
recursos:
entradas:
- nome: imagem
recurso: imagem-de-aplicação-web-construída
saídas:
- nome: imagem
recurso: imagem-de-aplicação-web-runtime
parâmetros:
- nome: TLSVERIFY
valor: "false"
runAfter:
- construir-aplicação-web
As duas próximas tarefas são responsáveis pela aplicação dos arquivos YAML do serviço, rota e implantação, que estão no diretório k8s da nossa aplicação web, bem como pela atualização dessa implantação ao criar novas imagens. Essas duas tarefas de cluster foram definidas no início do artigo.
Execução do pipeline
Então, todas as partes do nosso pipeline foram criadas, e nós o iniciaremos com o seguinte comando:
$ tkn pipeline start build-and-deploy-react
Nesta etapa, a linha de comando é usada em modo interativo e é necessário escolher os recursos correspondentes em resposta a cada solicitação: para o recurso git escolhemos repositório-de-aplicações-web, em seguida, para o recurso da primeira imagem – imagem-de-aplicação-web-construída, e, finalmente, para o recurso da segunda imagem – imagem-de-aplicação-web-runtime:
? 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
Agora vamos verificar o status do pipeline com o seguinte comando:
$ tkn pipeline logs -f
Após o início do pipeline e a aplicação ser implantada, solicitamos a rota publicada com o seguinte comando:
$ oc get route react-pipeline-example --template='http://{{.spec.host}}'
Para uma melhor visualização, podemos ver nosso pipeline no Modo Desenvolvedor do console web na seção Pipelines, como mostrado na Fig. 1.

Fig.1. Visão geral dos pipelines em execução.
Um clique no pipeline em execução exibe informações adicionais, como mostrado na Fig.2.

Fig. 2. Informações adicionais sobre o pipeline.
Após as informações adicionais, é possível ver as aplicações em execução na visão Topologia, como mostrado na Fig.3.

Fig 3. Pod em execução.
Um clique no círculo no canto superior direito do ícone abre nossa aplicação, como mostrado na Fig.4.

Fig. 4. Aplicação React em execução.
Conclusão
Assim, mostramos como iniciar um servidor de desenvolvimento para seu aplicativo no OpenShift e sincronizá-lo com o sistema de arquivos local. Também abordamos como simular um template de construção encadeada usando OpenShift Pipelines. Todo o código de exemplos deste artigo pode ser encontrado .
Recursos adicionais (EN)
- E-book gratuito
- Outros artigos sobre no site da Red Hat
Anúncios de webinars futuros
Iniciaremos uma série de webinars às sextas-feiras sobre a experiência nativa de uso da Red Hat OpenShift Container Platform e Kubernetes:
Fonte: habr.com
