Aplicativos OpenShift modernos, parte 2: compilações encadeadas

Olá! Este é o segundo post de nossa série em que mostramos como implantar aplicativos da web modernos no Red Hat OpenShift.







No post anterior, falamos um pouco sobre os recursos da nova imagem do construtor S2I (source-to-image), que é projetada para construir e implantar aplicativos da web modernos na plataforma OpenShift. Então estávamos interessados ​​no tópico de implementação rápida de aplicativos, mas hoje veremos como usar uma imagem S2I como uma imagem de construtor "limpa" e combiná-la com assemblies OpenShift relacionados.



Imagem limpa do construtor



Como mencionamos na primeira parte, a maioria dos aplicativos da web modernos tem um chamado estágio de construção, que geralmente executa operações como transpilação de código, concatenação de vários arquivos e minificação. Os arquivos resultantes - HTML estático, JavaScript e CSS - são adicionados à pasta de saída. A localização desta pasta geralmente depende de quais ferramentas de construção são usadas, e para React será a pasta ./build (voltaremos a isso com mais detalhes abaixo).



Source-to-Image (S2I)



Este post não é realmente sobre o que é S2I e como usá-lo (você pode ler mais sobre isso aqui ), mas é importante deixar claro sobre as duas etapas neste processo para entender o que a imagem do Web App Builder faz.



Fase de montagem



A etapa de montagem é inerentemente muito semelhante ao que acontece quando você executa o docker build e acaba com uma nova imagem do Docker. Da mesma forma, este estágio ocorre ao iniciar uma construção na plataforma OpenShift.



No caso de uma imagem do Web App Builder, o script assemble é responsável por instalar as dependências do seu aplicativo e executar o build . Por padrão, a imagem do construtor usa a construção npm run build, mas pode ser substituída por meio da variável de ambiente NPM_BUILD.



Como dissemos antes, a localização do aplicativo acabado e já construído depende de quais ferramentas você usa. Por exemplo, no caso do React, esta será a pasta. / Build, e para aplicativos Angular, a pasta project_name / dist. E, como mostrado na última postagem, a localização do diretório de saída, que é definido para construir por padrão, pode ser substituída por meio da variável de ambiente OUTPUT_DIR. Bem, como a localização da pasta de saída difere de estrutura para estrutura, você simplesmente copia a saída gerada para a pasta padrão na imagem, ou seja, / opt / apt-root / output. Isso é importante para entender o restante deste artigo, mas por enquanto vamos dar uma olhada rápida no próximo estágio - a execução (fase de execução).



Fase de execução



Este estágio ocorre quando a docker run é chamada em uma nova imagem criada durante o estágio de montagem. Isso também acontece durante a implantação na plataforma OpenShift. Por padrão, o script de execução usa o módulo serve para servir conteúdo estático localizado no diretório de saída padrão acima.



Este método é bom para implantar aplicativos rapidamente, mas geralmente não é recomendado servir conteúdo estático dessa forma. Bem, uma vez que servimos apenas conteúdo estático, o Node.js instalado dentro de nossa imagem não é necessário - um servidor web é suficiente.



Em outras palavras, precisamos de uma coisa durante a montagem e outra durante a execução. É aqui que as compilações encadeadas são úteis.



Construções encadeadas



Aqui está o que eles escrevem sobre compilações encadeadas na documentação do OpenShift:



"Dois assemblies podem ser vinculados um ao outro, com um gerando uma entidade compilada e o outro hospedando essa entidade em uma imagem separada que é usada para executar essa entidade."



Em outras palavras, podemos usar a imagem do Web App Builder para executar nosso build e, em seguida, usar a imagem do servidor da Web, NGINX, para servir nosso conteúdo.



Portanto, podemos usar a imagem do Web App Builder como um construtor puro e ainda ter uma pequena imagem de tempo de execução.



Agora vamos ver isso com um exemplo específico.



Para este tutorial, usaremos um aplicativo React simples construído com a ferramenta de linha de comando create-react-app.



O arquivo de modelo OpenShift nos ajudará a colocar tudo junto .



Vamos dar uma olhada neste arquivo e começar com a seção de parâmetros.



parameters:
  - name: SOURCE_REPOSITORY_URL
    description: The source URL for the application
    displayName: Source URL
    required: true
  - name: SOURCE_REPOSITORY_REF
    description: The branch name for the application
    displayName: Source Branch
    value: master
    required: true
  - name: SOURCE_REPOSITORY_DIR
    description: The location within the source repo of the application
    displayName: Source Directory
    value: .
    required: true
  - name: OUTPUT_DIR
    description: The location of the compiled static files from your web apps builder
    displayName: Output Directory
    value: build
    required: false


Tudo está bem claro aqui, mas você deve prestar atenção ao parâmetro OUTPUT_DIR. Para o aplicativo React do nosso exemplo, não há nada com que se preocupar, já que o React usa o valor padrão como pasta de saída, mas no caso do Angular ou outro, esse parâmetro precisará ser alterado conforme necessário.



Agora vamos dar uma olhada na seção ImageStreams.



- apiVersion: v1
  kind: ImageStream
  metadata:
    name: react-web-app-builder  // 1 
  spec: {}
- apiVersion: v1
  kind: ImageStream
  metadata:
    name: react-web-app-runtime  // 2 
  spec: {}
- apiVersion: v1
  kind: ImageStream
  metadata:
    name: web-app-builder-runtime // 3
  spec:
    tags:
    - name: latest
      from:
        kind: DockerImage
        name: nodeshift/ubi8-s2i-web-app:10.x
- apiVersion: v1
  kind: ImageStream
  metadata:
    name: nginx-image-runtime // 4
  spec:
    tags:
    - name: latest
      from:
        kind: DockerImage
        name: 'centos/nginx-112-centos7:latest'


Dê uma olhada na terceira e quarta imagens. Ambas são definidas como imagens Docker e você pode ver claramente de onde elas vêm.



A terceira imagem é web-app-builder e vem de nodeshift / ubi8-s2i-web-app com tag 10.x no hub Docker .



A quarta é uma imagem NGINX (versão 1.12) com a tag mais recente no hub Docker .



Agora vamos dar uma olhada nas duas primeiras imagens. Ambos estão vazios no início e são criados apenas na fase de construção. A primeira imagem, react-web-app-builder, será o resultado de uma etapa de montagem que irá mesclar a imagem web-app-builder-runtime e nosso código-fonte. É por isso que colocamos "-builder" no nome desta imagem.



A segunda imagem - react-web-app-runtime - será o resultado da combinação do nginx-image-runtime e alguns arquivos da imagem react-web-app-builder. Essa imagem também será usada durante a implantação e conterá apenas o servidor da web e o HTML estático, JavaScript, CSS de nosso aplicativo.



Confuso? Agora vamos dar uma olhada nas configurações de construção e isso ficará um pouco mais claro.



Existem duas configurações de construção em nosso modelo. Aqui está o primeiro, e é bastante padrão:



  apiVersion: v1
  kind: BuildConfig
  metadata:
    name: react-web-app-builder
  spec:
    output:
      to:
        kind: ImageStreamTag
        name: react-web-app-builder:latest // 1
    source:   // 2 
      git:
        uri: ${SOURCE_REPOSITORY_URL}
        ref: ${SOURCE_REPOSITORY_REF}
      contextDir: ${SOURCE_REPOSITORY_DIR}
      type: Git
    strategy:
      sourceStrategy:
        env:
          - name: OUTPUT_DIR // 3 
            value: ${OUTPUT_DIR}
        from:
          kind: ImageStreamTag
          name: web-app-builder-runtime:latest // 4
        incremental: true // 5
      type: Source
    triggers: // 6
    - github:
        secret: ${GITHUB_WEBHOOK_SECRET}
      type: GitHub
    - type: ConfigChange
    - imageChange: {}
      type: ImageChange


Como você pode ver, a linha identificada como 1 diz que o resultado dessa construção será colocado na mesma imagem react-web-app-builder que vimos anteriormente na seção ImageStreams.



A linha identificada como 2 informa de onde obter o código. No nosso caso, este é um repositório git, e a localização, ref e pasta de contexto são definidos pelos parâmetros que já vimos acima.



A linha identificada como 3 já é vista na seção de parâmetros. Ele adiciona a variável de ambiente OUTPUT_DIR, que é construída em nosso exemplo.

A linha identificada como 4 diz para usar a imagem web-app-builder-runtime que já vimos na seção ImageStream.



A linha rotulada como 5 diz que queremos usar uma construção incremental se a imagem S2I suportar e a imagem do Web App Builder sim. Na primeira inicialização, após concluir o estágio de montagem, a imagem salvará a pasta node_modules em um arquivo. Em seguida, nas execuções subsequentes, a imagem simplesmente descompactará essa pasta para reduzir o tempo de construção.



E, finalmente, a linha rotulada 6 é apenas alguns gatilhos para que o build seja iniciado automaticamente, sem intervenção manual, quando algo muda.



Em suma, esta é uma configuração de construção bastante padrão.



Agora vamos dar uma olhada na segunda configuração de compilação. É muito semelhante ao primeiro, mas há uma diferença importante.



apiVersion: v1
  kind: BuildConfig
  metadata:
    name: react-web-app-runtime
  spec:
    output:
      to:
        kind: ImageStreamTag
        name: react-web-app-runtime:latest // 1
    source: // 2
      type: Image
      images:                              
        - from:
            kind: ImageStreamTag
            name: react-web-app-builder:latest // 3
          paths:
            - sourcePath: /opt/app-root/output/.  // 4
              destinationDir: .  // 5
             
    strategy: // 6
      sourceStrategy:
        from:
          kind: ImageStreamTag
          name: nginx-image-runtime:latest
        incremental: true
      type: Source
    triggers:
    - github:
        secret: ${GITHUB_WEBHOOK_SECRET}
      type: GitHub
    - type: ConfigChange
    - type: ImageChange
      imageChange: {}
    - type: ImageChange
      imageChange:
        from:
          kind: ImageStreamTag
          name: react-web-app-builder:latest // 7


Portanto, a segunda configuração de compilação é react-web-app-runtime e começa bem padrão.



A linha identificada como 1 não é nova - apenas diz que o resultado da compilação está sendo colocado na imagem react-web-app-runtime.



A linha identificada como 2, como na configuração anterior, indica de onde obter o código-fonte. Mas observe que aqui dizemos que é tirado da imagem. Além disso, a partir da imagem que acabamos de criar - do react-web-app-builder (indicado na linha rotulada 3). Os arquivos que queremos usar estão localizados dentro da imagem e sua localização é especificada na linha rotulada 4, no nosso caso é / opt / app-root / output /. Se você se lembra, é aqui que os arquivos gerados a partir dos resultados da construção de nosso aplicativo são colocados.



A pasta de destino especificada na linha rotulada 5 é apenas o diretório atual (lembre-se, tudo isso está girando dentro de alguma coisa mágica chamada OpenShift, não no seu computador local).



A seção de estratégia - linha rotulada 6 - também é semelhante à primeira configuração de construção. Só que desta vez vamos usar o nginx-image-runtime, que já vimos na seção ImageStream.



Finalmente, a linha rotulada como 7 é a seção de gatilhos que dispara esta compilação toda vez que a imagem react-web-app-builder muda.



Caso contrário, este modelo contém uma configuração de implantação razoavelmente padrão, bem como coisas relacionadas a serviços e rotas, mas não entraremos nisso. Observe que a imagem que será implantada é a imagem react-web-app-runtime.



Implantar o aplicativo



Então, depois de dar uma olhada no modelo, vamos ver como usá-lo para implantar o aplicativo.



Podemos usar uma ferramenta cliente OpenShift chamada oc para implantar nosso modelo:



$ find . | grep openshiftio | grep application | xargs -n 1 oc apply -f

$ oc new-app --template react-web-app -p SOURCE_REPOSITORY_URL=https://github.com/lholmquist/react-web-app


O primeiro comando na captura de tela acima é uma maneira deliberada de engenharia para encontrar o modelo. / Openshiftio / application.yaml.



O segundo comando simplesmente cria um novo aplicativo com base neste modelo.



Depois que esses comandos forem executados, veremos que temos dois assemblies:







E, voltando à tela Visão geral, veremos o pod lançado:







Clique no link e seremos direcionados ao nosso aplicativo, que é a página padrão do React App:







Apêndice 1



Para os amantes do Angular, também temos um aplicativo de amostra .



O modelo é o mesmo aqui, exceto para a variável OUTPUT_DIR.



Apêndice 2



Neste artigo, utilizamos como servidor web o NGINX, mas é bastante fácil substituí-lo pelo Apache, basta trocar o arquivo template da imagem NGINX no caminho do Apache .



Conclusão



Na primeira parte desta série, mostramos como implantar rapidamente aplicativos da web modernos na plataforma OpenShift. Hoje vimos o que torna uma imagem de aplicativo da Web e como ela pode ser combinada com um servidor da Web puro como o NGINX usando compilações encadeadas para criar uma compilação de aplicativo mais pronta para produção. No próximo artigo final desta série, mostraremos como executar um servidor de desenvolvimento para seu aplicativo no OpenShift e manter os arquivos locais e remotos sincronizados.



Conteúdo desta série de artigos










All Articles