Migre um aplicativo Spring Boot para o OpenShift – IBM Developer

Migre um aplicativo Spring Boot para o OpenShift

Visão geral

Imagine que haja um aplicativo existente que precise ser migrado para um cluster do OpenShift®. Também há um requisito para mudar o tempo de execução sem modificar o código-fonte original nem usar servidores de aplicativos diferentes. Este tutorial mostrará como migrar para um cluster do OpenShift e executar um aplicativo Spring Boot existente, que é executado com o Apache Tomcat integrado, e como substituir o Tomcat pelo Open Liberty. O desafio aqui é que o aplicativo Spring Boot não deve ser modificado. O motivo para isso poderia ser que ele não deve ter uma relação direta com o tempo de execução, para que seja fácil mudar a carga de trabalho entre diferentes provedores de nuvem, como o IBM Cloud, o OpenShift ou um cluster do vanilla Kubernetes.

Este tutorial cobre a migração de um aplicativo Spring Boot existente para um cluster do OpenShift com um tempo de execução diferente, como um servidor Open Liberty. O empacotamento e a implementação serão manipulados com o OpenShift Source-to-Image (S2I). Há um exemplo com o Spring Boot e a configuração completa no GitHub (ramificação: OpenShift).

Primeiro analisaremos as etapas relevantes para executar o aplicativo Spring Boot no Open Liberty. O conhecimento adquirido será usado para preparar um construtor do OpenShift S2I, que será usado para implementar o aplicativo Spring Boot no OpenShift Container Platform com o Open Liberty.

Pré-requisitos

Tempo estimado

A conclusão deste tutorial deve levar cerca de 60 minutos.

Introdução ao OpenShift

O OpenShift é um tempo de execução de contêiner baseado no Kubernetes com recursos corporativos adicionais, incluindo o Source-to-Image (S2I).

O Source-to-Image é um conceito do OpenShift para desenvolver e implementar um aplicativo usando uma imagem de construtor para compilar o aplicativo. O resultado é uma nova imagem do Docker, que será usada para implementar o novo aplicativo. O benefício é que a imagem do construtor pode assumir atividades complexas e recorrentes, como a compilação ou a preparação do ambiente (em um contêiner do Docker). Com o S2I, também é possível separar da fonte principal do aplicativo quaisquer atividades específicas do ambiente ou do produto.

Instale o oc e o s2i na máquina local. Considere que, em geral, na IU da web do OpenShift em “About” há um link para fazer download do artefato oc. Também é possível usar o login oc com um token genérico para efetuar login no cluster do OpenShift:

oc login https://c100-e.eu-de.containers.cloud.ibm.com:30019 --token=<your-token-value>

O s2i será usado para gerar localmente a imagem do construtor do S2I.

Etapas

Etapa 1. Migração para o Open Liberty

Esta etapa aborda a modificação necessária para executar o aplicativo Spring Boot em um servidor Open Liberty. O Open Liberty fornece suporte para o Spring Boot. Esse recurso desativará o contêiner da web integrado no aplicativo Spring e usará o Liberty.

No Open Liberty, implemente um aplicativo ao incluir uma entrada para no server.xml de configuração do servidor ou a usar a abordagem dinâmica e coloque o aplicativo em um diretório de dropins definido. Como no nosso caso, o aplicativo contém a configuração completa, e quando não se deseja sempre modificar o server.xml, a solução de inserções é a preferencial.

Para a migração, usaremos uma imagem oficial do Open Liberty Docker com um tipo de Spring Boot 2 (open-liberty:springBoot2). A característica especial é que o server.xml incluído contém algumas configurações relacionadas ao Spring Boot:

<!-- Enable features for Spring Boot 2.0 -->
<featureManager>
  <feature>springBoot-2.0</feature>
  <feature>servlet-4.0</feature>
  <!-- ... -->
</featureManager>

<!-- Configure HTTP endpoint -->
<httpEndpoint id="defaultHttpEndpoint" host="*" httpPort="9080" />

Além disso, o springBootUtility é incluído, que separa as dependências integradas do fat jar do aplicativo Spring do código do aplicativo. Isso otimiza o uso e a transferência de dados durante o envio por push da imagem de contêiner ao registro. O springBootUtility permite que o código do aplicativo seja colocado em uma camada separada, acima da camada com as dependências. O springBootUtility é um recurso do Open Liberty e do WebSphere® Liberty (saiba mais na documentação do WebSphere Liberty).

Extraia as bibliotecas do aplicativo Spring Boot original e coloque o código do aplicativo no diretório de inserções do Liberty:

<wlp>/bin/springBootUtility thin \
    --sourceAppPath=hellospringboot.jar \
    --targetLibCachePath=<wlp>/usr/shared/resources/lib.index.cache \
    --targetThinAppPath=<wlp>/usr/servers/helloserver/dropins/spring/hellospringboot.jar

Etapa 2. Criar a imagem do Docker com o Open Liberty

Um Dockerfile modificado, que usa o Open Liberty e separa um aplicativo Spring Boot, tem a seguinte forma:

# Open Liberty example with Spring (Boot) application
# use springBootUtility to split the embedded libs from the main logic
ARG IMAGE=open-liberty:springBoot2
FROM ${IMAGE} as staging

USER root
# Symlink servers directory for easier mounts.
RUN ln -s /opt/ol/wlp/usr/servers /servers

ARG JAR_FILE
COPY ${JAR_FILE} /staging/app.jar

# Extract the libs
RUN springBootUtility thin \
 --sourceAppPath=/staging/app.jar \
 --targetThinAppPath=/staging/appThin.jar \
 --targetLibCachePath=/staging/lib.index.cache

# New image using the separated application (cache and main logic)
FROM ${IMAGE}
COPY --from=staging /staging/lib.index.cache /lib.index.cache
COPY --from=staging /staging/appThin.jar /config/dropins/spring/appThin.jar

USER 1001

# Run the server script and start the defaultServer by default.
ENTRYPOINT ["/opt/ol/wlp/bin/server", "run"]
CMD ["defaultServer"]

Após a compilação e a execução do Docker, o aplicativo em http://localhost:8099/swagger-ui.html fica acessível:

$ docker build --rm -t service-playground-liberty -f DockerfileLiberty --build-arg=JAR_FILE=target/service-playground-0.0.1-SNAPSHOT.jar .
$ docker run -d -p 8099:9080 service-playground-liberty:latest

Para verificar os parâmetros de configuração e de execução, use o terminal Actuator Env em http://localhost:8099/actuator/env.

Etapa 3. Migração para o OpenShift

Agora temos um aplicativo Spring Boot em execução em um contêiner do Docker com o Open Liberty. A próxima etapa é fornecer a base para criar e implementar um aplicativo Spring Boot em um cluster do OpenShift. Para isso, usamos o mecanismo OpenShift Source-to-Image (S2I). O S2I ajuda a cumprir o requisito de não modificar o código-fonte do aplicativo, de reduzir a configuração e de acoplar fortemente ao OpenShift.

A base é uma nova imagem do construtor, que processa as etapas necessárias:

  • Compilação do aplicativo (do repositório de origem)
  • Extração das bibliotecas
  • Inserção dos artefatos nos diretórios certos do Open Liberty

O resultado é uma nova imagem do Docker com o Open Liberty e a nova versão do aplicativo.

Etapa 4. Compilar uma imagem do construtor do S2I

A imagem do construtor do S2I é uma imagem do Docker, que espera arquivos s2i:

  1. assemble — script para compilar e montar a nova imagem do Docker, usando a origem
  2. run — para executar a nova imagem do Docker criada
  3. usage — para manter as informações de uso

Com a ajuda do s2i, a estrutura inicial pode ser criada com s2i create s2i-openliberty-springapp s2i-builder, que resulta na estrutura de diretório e nos arquivos a seguir.

s2i-builder> tree
.
├── Dockerfile
├── Makefile
├── README.md
├── s2i
│   └── bin
│       ├── assemble
│       ├── run
│       ├── save-artifacts
│       └── usage
└── test
    ├── run
    └── test-app
        └── index.html

4 directories, 9 files

Nas próximas etapas, os arquivos são adaptados às nossas necessidades.

O Dockerfile da imagem do construtor do Spring Boot tem a seguinte forma:

# OpenShift S2I Builder Image for
# Open Liberty example with Spring (Boot) application
# use springBootUtility to split the embedded libs from the main logic
ARG IMAGE=open-liberty:springBoot2
FROM ${IMAGE} as staging

LABEL io.k8s.description="Used for building and running Spring Boot application on Open Liberty" \
      io.k8s.display-name="SpringApp-In-OpenLiberty" \
      io.openshift.expose-services="9080:http" \
      io.openshift.tags="builder,liberty,open-liberty" \
      io.openshift.s2i.destination="/tmp" \
      io.openshift.s2i.scripts-url="image:///opt/s2i/"

USER root
RUN   apt-get update \
      && apt-get -y install maven \
      && apt-get -y install openjdk-8-jdk \
      && apt-get clean

# Copy Scripts to build s2i
COPY ./s2i/bin/assemble /opt/s2i/
COPY ./s2i/bin/run /opt/s2i/
COPY ./s2i/bin/usage /opt/s2i/

# Create some dir and change permissions
RUN mkdir -p /home/default/.m2/repository \
    && mkdir -p /config/dropins/spring/ \
    && chown -R 1001:0 /opt/s2i/ && chmod -R +x /opt/s2i/ \
    && chown -R 1001:0 /home/default/.m2 && chmod g=u /home/default/.m2 \
    && chown -R 1001:0 /config/dropins/spring && chmod g=u /config/dropins/spring

# change JAVA_HOME to have JDK during maven build
ENV JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64

USER 1001

Etapa 5. Criar o script de montagem

O script de montagem compila e empacota o código-fonte. O aplicativo Spring Boot criado será extraído com o springBootUtility e os arquivos serão movidos para os caminhos do Open Liberty.

Script de montagem do S2I:

# compile and package application
cd /tmp/src
mvn clean package

# split libraries from the main logic
mkdir -p /tmp/artifacts
cp /tmp/src/target/*.jar /tmp/artifacts/app.jar

springBootUtility thin \
 --sourceAppPath=/tmp/artifacts/app.jar \
 --targetThinAppPath=/tmp/artifacts/appThin.jar \
 --targetLibCachePath=/tmp/artifacts/lib.index.cache

# place the files for Open Liberty in the right dirs
cp -r /tmp/artifacts/lib.index.cache/* /lib.index.cache
cp -r /tmp/artifacts/appThin.jar /config/dropins/spring/appThin.jar

Etapa 6. Criar o script de execução

O script de execução do S2I é muito simples e contém somente o comando para executar o servidor Open Liberty:

# run the application
/opt/ol/wlp/bin/server run defaultServer

Etapa 6. Compilar a imagem do construtor do S2I

Os comandos a seguir compilam a imagem do construtor s2i-openliberty-springapp. Em seguida, testamos a imagem do construtor com o repositório local do aplicativo Spring Boot e compilamos uma nova imagem do Docker do aplicativo, test-s2i-springapp.

s2i-builder> docker build -t s2i-openliberty-springapp -f DockerfileS2IBuilderImage .

spring-example-repo> s2i build . s2i-openliberty-springapp test-s2i-springapp

spring-example-repo> docker run -d -p 8099:9080 -u 7887 test-s2i-springapp

Agora o aplicativo na mesma URL está acessível: http://localhost:8099/. A grande diferença aqui é somente o processo de compilação e implementação. O código-fonte do aplicativo não contém nenhum conhecimento de que o tempo de execução é o Open Liberty ou o cluster do OpenShift. Tudo isso é manipulado durante o processo de implementação, que também inclui a recompilação e o empacotamento do aplicativo.

Para implementar o aplicativo em um cluster do OpenShift, é necessário publicar a nova imagem do construtor do S2I no OpenShift e criar um novo aplicativo.

Etapa 7. Publicar a imagem do construtor do S2I

Para implementar o aplicativo no OpenShift, é necessário registrar a nova imagem do construtor do S2I no OpenShift, para que seja possível enviar por push a imagem do Docker para o registro de contêiner interno do OpenShift em um projeto geral chamado comum. O OpenShift cria automaticamente um ImageStream, que agora está disponível e pode ser usado a qualquer momento para criar um novo aplicativo, caso esse tipo de construtor do S2I seja necessário:

# Login and create common project
$ oc login https://c100-e.eu-de.containers.cloud.ibm.com:30488 --token=dct7....

$ oc new-project common

# Create tag and push to OpenShift Registry
$ docker tag s2i-openliberty-springapp:v1.0.0 docker-registry-default.article-cluser-123456789abcdefgh-0001.eu-de.containers.appdomain.cloud/common/s2i-openliberty-springapp:v1.0.0

$ docker login -u token -p $(oc whoami -t) docker-registry-default.article-cluser-123456789abcdefgh-0001.eu-de.containers.appdomain.cloud

$ docker push docker-registry-default.article-cluser-123456789abcdefgh-0001.eu-de.containers.appdomain.cloud/common/s2i-openliberty-springapp:v1.0.0
The push refers to repository [docker-registry-default.article-cluser-123456789abcdefgh-0001.eu-de.containers.appdomain.cloud/common/s2i-openliberty-springapp]
5d0d868c79e0: Pushed
965d6a798d5e: Pushed
7d11cd4a4782: Pushed
f9725c11f15d: Pushed
350befc62911: Pushed
db75ce8a74ec: Pushed
126d273c10f4: Pushed
b75afb1bc4ce: Pushed
69f2bba0832b: Pushed
895c7b09f601: Pushed
bd4b24484dda: Pushed
4ce08090970e: Pushed
e79142719515: Pushed
aeda103e78c9: Pushed
2558e637fbff: Pushed
f749b9b0fb21: Pushed
v1.0.0: digest: sha256:0773401a2c231dc0b7cd811fba244adedcba4315437778ba828e9bc2ff516304 size: 3660

$ oc get is -n common
NAME                        IMAGE REPOSITORY                                                                    TAGS     UPDATED
s2i-openliberty-springapp   image-registry.openshift-image-registry.svc:5000/common/s2i-openliberty-springapp   v1.0.0   2 minutes ago

Após o push do Docker para o registro de contêiner do OCP, temos um ImageStream chamado common/s2i-openliberty-springapp. Esse ImageStream pode ser usado para qualquer aplicativo Spring Boot a ser executado com um servidor Open Liberty.

Etapa 8. Instalar o aplicativo

Esta seção aborda a instalação do aplicativo usando a nova imagem do construtor do S2I, que está em um namespace comum. Primeiro, o acesso deve ser concedido a partir do novo projeto test-s2i:

$ oc adm policy add-role-to-user -n common system:image-puller system:serviceaccount:test-s2i:builder

Agora é possível criar o novo projeto test-s2i e implementar o novo aplicativo usando um repositório Git que contém o código-fonte e referenciar a imagem do construtor do S2I (fluxo) common/s2i-openliberty-springapp:

$ oc new-project test-s2i

$ oc new-app --name test-s2i-springapp -i common/s2i-openliberty-springapp:v1.0.0 https://github.com/IBM/spring-microservice

--> Found image 2706284 (2 months old) in image stream "common/s2i-openliberty-springapp" under tag "v1.0.0" for "common/s2i-openliberty-springapp:v1.0.0"

    SpringApp-In-OpenLiberty
    ------------------------
    Used for building and running Spring Boot application on Open Liberty

    Tags: builder, liberty, open-liberty

    * The source repository appears to match: jee
    * A source build using source code from https://github.com/IBM/spring-microservice will be created
      * The resulting image will be pushed to image stream tag "test-s2i-springapp:latest"
      * Use 'oc start-build' to trigger a new build
    * This image will be deployed in deployment config "test-s2i-springapp"
    * Ports 9080/tcp, 9443/tcp will be load balanced by service "test-s2i-springapp"
      * Other containers can access this service through the hostname "test-s2i-springapp"

--> Creating resources ...
    imagestream.image.openshift.io "test-s2i-springapp" created
    buildconfig.build.openshift.io "test-s2i-springapp" created
    deploymentconfig.apps.openshift.io "test-s2i-springapp" created
    service "test-s2i-springapp" created
--> Success
    Build scheduled, use 'oc logs -f bc/test-s2i-springapp' to track its progress.
    Application is not exposed. You can expose services to the outside world by executing one or more of the commands below:
     'oc expose svc/test-s2i-springapp'
    Run 'oc status' to view your app.

Observamos que o fluxo de imagem common/s2i-openliberty-springapp é usado e a compilação inicial é acionada.

O log da configuração do construtor fornece alguns insights sobre o processo de compilação:

$ oc logs -f bc/test-s2i-springapp

...
[INFO] Replacing main artifact with repackaged archive
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 37.270 s
[INFO] Finished at: 2019-10-27T18:20:42+00:00
[INFO] Final Memory: 49M/2298M
[INFO] ------------------------------------------------------------------------
Creating a thin application from: /tmp/artifacts/app.jar
Library cache: /tmp/artifacts/lib.index.cache
Thin application: /tmp/artifacts/appThin.jar

Pushing image docker-registry.default.svc:5000/test-s2i/test-s2i-springapp:latest ...
Pushed 0/17 layers, 0% complete
Pushed 1/17 layers, 6% complete
Pushed 2/17 layers, 12% complete
Pushed 3/17 layers, 18% complete
...
Pushed 16/17 layers, 94% complete
Pushed 17/17 layers, 100% complete
Push successful

Nos logs, observamos:

  • Que a imagem do construtor é usada para a compilação
  • Que o projeto de origem foi compilado e criado com sucesso
  • Que o SpringBootUtility foi usado para criar o aplicativo thin
  • A compilação e o envio por push da imagem do Docker recém-criada

Depois de um tempo, tempo um pod em execução:

$ oc get pods
NAME                          READY   STATUS      RESTARTS   AGE
test-s2i-springapp-1-build    0/1     Completed   0          4m2s
test-s2i-springapp-1-hhwv6    1/1     Running     0          81s

$ oc get svc
NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
test-s2i-springapp   ClusterIP   172.30.178.69   <none>        9080/TCP,9443/TCP   4m6s

Para acessar o aplicativo externamente, temos que expor o serviço:

$ oc expose svc test-s2i-springapp
route.route.openshift.io/test-s2i-springapp exposed

$ oc get routes
NAME                 HOST/PORT                                                              PATH   SERVICES             PORT       TERMINATION   WILDCARD
test-s2i-springapp   test-s2i-springapp-test-s2i.article-cluser-123456789abcdefgh-0001.eu-de.containers.appdomain.cloud          test-s2i-springapp   9080-tcp                 None

A página principal do Spring Boot está acessível agora:

$ curl test-s2i-springapp-test-s2i.article-cluser-123456789abcdefgh-0001.eu-de.containers.appdomain.cloud

Resumo

Este tutorial mostrou como migrar um aplicativo Spring Boot existente para a nuvem. O uso do recurso Source-to-Image do OpenShift permite uma migração perfeita sem nenhuma mudança no código-fonte do aplicativo. Além disso, o aplicativo continua sem um acoplamento mais próximo ao ambiente de tempo de execução (nuvem). Em geral, essa é uma boa abordagem técnica para migrar uma carga de trabalho existente para o ambiente de nuvem certo.

Aviso

O conteúdo aqui presente foi traduzido da página IBM Developer US. Caso haja qualquer divergência de texto e/ou versões, consulte o conteúdo original.