Inputs binarios para builds de Jenkins en OpenShift
Sumergirse en la plataforma de contenedores OpenShift (OCP en sus siglas en inglés) es un desafío. Uno de los principales objetivos de nuestro cliente era alojar una arquitectura de microservicios (Spring Boot) en una plataforma de microservicios. Así fue como OpenShift fue adquirido.
OpenShift junto con el CI de Jenkins proporciona una solución alternativa para una infraestructura ya existente. Empezar a construir tu propio software en OCP conlleva múltiples desafíos. Se necesita mucho conocimiento de base para OpenShift (Docker y Kubernetes) y Jenkins, lo que puede ser un poco abrumador debido a la extensa documentación.
Este artículo quiere demostrar cómo construir artefactos de software (Spring Boot ejecutable JAR/WAR) con Jenkins y cómo luego vincularlos a contenedores Docker. OpenShift proporciona múltiples configuraciones de construcción.
Para nosotros, es esencial distinguir entre dos tipos de builds:
- El build del pipeline de Jenkins como un archivo Jenkins escrito en Groovy. Esta es la consutrcción del artefacto.
- El build de la imagen de Docker.
Ten en cuenta que éste es un ejemplo complejo con muchas variables. Nuestro objetivo es darte una visión del problema y nuestra solución. Puedes usalo como punto inicial para resolver o implementar builds con OpenShift y Jenkins. Para nuestro ejemplo hemos usado una instancia persistente de Jenkins en OpenShift.
Empezando con builds de OpenShift
En nuestro primer acercamiento, construimos el artefacto y lo desplegamos en JFrog Artifactory como un servicio de la nube. En OpenShift, en la build de Docker, hacemos una consulta a Artifactory y recuperamos el URL de descarga del Artefacto.
Este enfoque tiene las siguientes desventajas:
- Los builds no estaban relacionadas.
- El build de Docker tuvo que recuperar el artefacto. Esto requiere lógica extra y sólo recuperó el último artefacto construido.
- La lógica de reestablecimiento fue escrita en el contenedor.
- Este enfoque es propenso a errores ya que el artefacto no debe coincidir con la construcción anterior.
El siguiente Dockerfile ha sido usado para construir la imagen de Docker.
FROM redhat-openjdk-18/openjdk18-openshift
ENV ARTIFACTORY_SERVER="https://demo.jfrog.io/repo" GROUP_ID="com.mimacom.ocp" ARTIFACT_ID="demo-app"
ARG USERNAME
ARG PASSWORD
ARG ARTIFACT_VERSION="1074.1-SNAPSHOT"
ARG JAVA_OPTS="-Xms384m -Xmx384m"
USER root
RUN yum install wget -y && yum clean all -y
RUN wget -O /usr/bin/jq https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64 && chmod a+rx /usr/bin/jq
RUN mkdir -p /srv/app/
RUN curl "$ARTIFACTORY_SERVER/api/search/gavc?g=$GROUP_ID&a=$ARTIFACT_ID&v=$ARTIFACT_VERSION&repos=libs-snapshots-local" -s > output.txt
RUN wget -O download.txt $(cat output.txt | /usr/bin/jq -r '.results[0].uri')
RUN wget -O /srv/app/micro-service.jar $(cat download.txt | /usr/bin/jq -r '.downloadUri')
WORKDIR /
ADD bootstrap.sh /
ADD logback-spring.xml /srv/app/
RUN chmod 755 /bootstrap.sh && chmod g=u /etc/passwd && chown -R 1001:0 /srv/app
EXPOSE 8080
# OpenShift requires images to run as non-root by default
USER 1001
ENTRYPOINT ["/bootstrap.sh"]
Como ves, hay demasiada lógica fea en este Dockerfile
.
Nuevo enfoque
Necesitamos:
- Una correlación uno a uno entre el artefacto y la imagen de Docker.
- Evitar la descarga del artefacto.
- Tener menos tráfico de red y asegurar la funcionalidad de la construcción de la imagen de Docker.
- Desacoplar el despliegue del artefacto del build de la imagen de Docker.
- Que un despliegue fallido a Artifactory no afecte al build de la imagen de Docker.
Nuestro nuevo enfoque pasa el artefacto directamente al build de Docker, que es lo que necesitamos.
Solución
La solución es fácil si conoces todas las posibilidades.
- La configuración del build de Docker acepta
git
obinary
como fuente de entrada. - Nuestro primer error fue usar "git" como fuente de entrada.
- ¿Por qué? Porque son mutuamente excluyentes.
- En lugar de
git
, usamos ahora elbinary
como fuente de entrada.
A continuación puedes ver el ejemplo de configuración:
kind: BuildConfig
apiVersion: build.openshift.io/v1
metadata:
name: micro-service-docker
namespace: development
labels:
build: micro-service
app: micro-service
spec:
source:
binary: {}
output:
to:
kind: ImageStreamTag
name: micro-service:latest
namespace: development
postCommit: {}
resources: {}
strategy:
dockerStrategy:
dockerfilePath: ./openshift/Dockerfile
type: Docker