Create Spring Boot Images in Jenkins/CI in K8s, Part 1
Working out Jenkins/CI pipelines it is a common task to create Spring Boot Images. Doing this with kubernetes agents is a challenge since docker is no more available from inside of containers.
The task is quiet simple, create a spring boot image with `mvn spring-boot:build-image` inside a kubernetes pod.
By default this fails because spring try to execute 'buildpacks' but the needed docker service is not available. The docker service is needed to create the container image. With spring 2.6 and beneath it is not possible to use another service then docker. But it is possible to use buildpacks separately after creating the project jar file.
As replacement of docker it is possible to use podman as service. podman is compatible with docker and also supports the docker.sock. Looking forward to spring boot 2.7 which supports also podman as alternative to docker I did not try to use 'kaniko'.
Objectives of this post:
- Create a woking pod and script to create spring boot images inside of Kubernetes
- Prove how creation could be done in K8s
- Push the image to docker hub
- Creating the Jenkins pipeline
To do the task I create a 'pod.yaml' with container needed to create a spring boot image and a 'build.sh' containing all the commands executing at the pods containers.
To test the script a simple spring application will be used (https://github.com/mhus/sample-spring-service). - This files are included in the repository in '/test'.
So let's do it:
(0) First a management pod is needed to download the project. Usually this is done by Jenkins at the start of the pipeline. In this case I need to do it manually. I need an image which contains the command 'git' to clone the git repo. The image 'dockercore/docker' will do the job. As usually we need to start a dummy command to let the container alive. My name for the container is 'box'.
To simulate Jenkins I will share the folder '/home/jenkins/agent/' over all pods.
image: dockercore/docker
command:
- cat
tty: true
volumeMounts:
- name: workspace-volume
Now it is possible to clone the repository
"cd /home/jenkins/agent/;
Preparation is done.
(1) First pipeline step is to create the jar file using maven. This is a common task in Jenkins pipelines. Using the 'maven' image and execute `mvn package` for the project.
image: maven:3.8-openjdk-11
command:
- cat
tty: true
volumeMounts:
- name: workspace-volume
and execute
/bin/bash -c "cd /home/jenkins/agent/sample-spring-service;
(2) More complicated is to execute the buildpack command. To create the image the command is
But the image do not include a bash or sh command and it is not possible to start the container doing nothing and wait for exec commands - wtf. Therefore I was forced to create a separate image containing buildpacks AND a shell.
Dockerfile
RUN set +x \
&& apt update \
&& apt install -y curl git \
&& (curl -sSL "https://github.com/buildpacks/pack/releases/download/v0.26.0/pack-v0.26.0-linux.tgz" | tar -C /usr/local/bin/ --no-same-owner -xzv pack) \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
ENTRYPOINT ["/usr/local/bin/pack"]
And I pushed the image to docker hub as 'mhus/buildpacks:0.26.0-0'. Adding the container specification to the pod I created a shared folder to share the docker socket from podman into buildpacks.
- name: buildpacksimage: mhus/buildpacks:0.26.0-0
command: ["/bin/bash","-c"]
args: ["cat"]
tty: true
volumeMounts:
- name: workspace-volume
mountPath: /home/jenkins/agent
- name: docker-socket
And the podman container as helper for the buildpacks command. To provide the socket it's important to start the podman as a service and set the path for the socket.
- name: podmanimage: quay.io/podman/stable
args: ["/usr/bin/podman","system","service","-t","0","--log-level=info", "unix:///var/run/docker.sock"]
tty: true
securityContext:
privileged: true
volumeMounts:
- name: workspace-volume
mountPath: /home/jenkins/agent
- name: docker-socket
"cd /home/jenkins/agent/sample-spring-service;
(3) Last step is to push the image to docker hub. To do this I need to tag the image, login to the hub and push the image. Since the podman container already exists I only need to call the command in the existing container.
kubectl exec -it -c podman agent -- /bin/bash -c \"podman tag sample-spring-service docker.io/$docker_user/sample-spring-service:$version;"
kubectl exec -it -c podman agent -- /bin/bash -c \
"podman login -u $docker_user -p '$docker_pass' docker.io/$docker_user"
kubectl exec -it -c podman agent -- /bin/bash -c \
Before execution set the variables
docker_user="mhus"
Let's test the new image with docker:
This proof could be more generic but I get the goal to create a spring boot image. Next this should be done all together to create a pipeline that works for this project and with parameters for all other projects too.
Kommentare
Kommentar veröffentlichen