Implementation of Gitlab CI + Docker + Spring Boot

Posted on

Problem

i would really appreciate if anyone could invest a bit of time to review what i did. Basically this is first time i do this, and that is reason why i need another set of eyes.

I have Spring Boot application and i decided to use docker containers on my server to run applications across multiple environments (DEV, QA and PROD). I invested a lot of time to properly research everything and at the end i was able to achieve what i wanted from the beginning.

Basically my code is on GitLab and instead of using jenkins i wanted to take advantage of GitLab CI and simply automatize deployment of my app.

Lets begin, i will start from Dockerfile and it looks like this:

FROM maven:3.6.3-jdk-11-slim AS MAVEN_BUILD

ARG SPRING_ACTIVE_PROFILE

MAINTAINER jmj
COPY pom.xml /build/
COPY src /build/src/
WORKDIR /build/
RUN mvn clean install -Dspring.profiles.active=$SPRING_ACTIVE_PROFILE && mvn package -B -e -Dspring.profiles.active=$SPRING_ACTIVE_PROFILE
FROM openjdk:11-slim
WORKDIR /app

COPY --from=MAVEN_BUILD /build/target/storm-*.jar /app/storm.jar
ENTRYPOINT ["java", "-jar", "storm.jar"]

Dockerfile notes: I had one major issue here, and that is passing dynamically ARG in ENTRYPOINT, to be more specific i wanted to pass active profile, i was able to fix it by passing active profile when doing docker run, which you will see below.
Dockerfile question: I am using Java 11 on my project, because it is last LTS version of Java, what i have noticed compared when i used Java 8, is that docker image is really large, a lot of larger than when using Java 8. If i am correct, that is because there is no safe and tested Java 11 alpine image, which at the end produce smaller docker images. My actual question here is: Is my choice of images fine, and is it expected to have image size of ~450MB (on java 8 it was below ~200)

Next lets jump on my .gitlab-ci.yml file.

services:
  - docker:19.03.7-dind

stages:
  - build and push docker image
  - deploy

docker build:
  image: docker:stable
  stage: build and push docker image
  before_script:
    - source .${CI_COMMIT_REF_NAME}.env
  script:
    - docker build --build-arg SPRING_ACTIVE_PROFILE=$SPRING_ACTIVE_PROFILE -t $DOCKER_REPO .
    - docker login -u $DOCKER_USER -p $DOCKER_PASSWORD docker.io
    - docker push $DOCKER_REPO

deploy:
  image: ubuntu:latest
  stage: deploy
  before_script:
    - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d 'r' | ssh-add -
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - echo -e "Host *ntStrictHostKeyChecking nonn" > ~/.ssh/config
    - source .${CI_COMMIT_REF_NAME}.env
  script:
    - ssh root@$SERVER "docker stop $APP_NAME; docker system prune -a -f; docker pull $DOCKER_REPO; docker container run -d --name $APP_NAME -p $PORT:8080 -e SPRING_PROFILES_ACTIVE=$SPRING_ACTIVE_PROFILE $DOCKER_REPO"

Its important to mention that as extension for this file i also have 3 files, with names: .develop.env,.qa.env and .master.env. They represent dynamic variables that i need on different enviorements.

export SPRING_ACTIVE_PROFILE='development'
export DOCKER_REPO="$DOCKER_DEV_REPO"
export APP_NAME="$DEV_APP_NAME"
export PORT='8080'

That is basically it, if anyone can see something that i could improve please let me know.
Thank you all in advance.

Solution

So here’s some comments about the dockerfile. I don’t really want to comment on the gitlab-ci, since it’s completely unclear which version of gitlab you are running and what possible optimizations are available to you.

Builder Setup

The way your MAVEN_BUILD target is set up, it’s basically impossible for that target to do any form of caching, even if “only” source files changed.
You could be able to cache some things by reordering and splitting your setup a bit:

FROM maven:3.6.3-jdk-11-slim AS MAVEN_BUILD

ARG SPRING_ACTIVE_PROFILE

MAINTAINER jmj

COPY pom.xml /build/
WORKDIR /build/
RUN mvn clean install -Dspring.profiles.active=$SPRING_ACTIVE_PROFILE

# at this point dependencies are installed, but sources have not impacted the build process.
# This is where caching could kick in hard

COPY src /build/src
RUN mvn package -B -e -Dspring.profiles.active=$SPRING_ACTIVE_PROFILE

I am not quite sure how effective this change will be, but I presume it will be quite useful for day-to-day development, if you use the docker setup to run local tests.

You might have noticed that I am more generous with newlines in this file. I honestly did not even see the second FROM statement the first time I read this dockerfile.

The active profile

You might want to look into setting up environment variables using ENV to dynamically alter the ENTRYPOINT. Beware that the exec form of the entry point does not perform variable substitution, so you would need to use the shell form.

Leave a Reply

Your email address will not be published. Required fields are marked *