Multi-stage Docker Build
Demonstrating
docker multi-stage builds
which helps to build smaller docker images. This process also referred as Docker’sBUILDER PATTERN
One of the most challenging things about building images is keeping the image size down.
Multi-stage builds are a new feature requiring Docker 17.05 or higher on the daemon and client.
It was actually very common to have one Dockerfile to use for development (which contained everything needed to build your application), and a slimmed-down one to use for production, which only contained your application and exactly what was needed to run it.
How Multi-stage Build Works
With multi-stage builds, you use multiple FROM
statements in your Dockerfile.
Each FROM
instruction can use a different base, and each of them begins a new stage of the build.
You can selectively copy artifacts from one stage to another, leaving behind everything you don’t want in the final image.
Create Docker Image with SpringBoot Gradle Project
Lets build Docker Image for SpringBoot application using Gradle
Source code available at Gradle SpringBoot MultiStageBuild
STAGE-1: Copy required files(src, gradle wrapper, gradlew,build.gradle, gradle.properties
) into docker image and build a final SpringBoot FAT JAR.
We are compiling our source inside docker image with specified JDK version, JENKINS server need not required JDK & Gradle installed in it. |
STAGE-2: Copy Final FAT JAR from STAGE-1
, Build Docker image which uses JRE (No JDK required for runtime)
#Stage - #1
FROM openjdk:8 AS GENERATE_FAT_FILE
# create folder inside docker env
ENV APP_HOME=/root/dev/app/
# make src folder to put source code
RUN mkdir -p $APP_HOME/src
#change your working directory
WORKDIR $APP_HOME
#copy required files to build final executable Jar
COPY build.gradle settings.gradle gradle.properties gradlew gradlew.bat $APP_HOME
#copy gradle wrapper
COPY gradle $APP_HOME/gradle
#copy main source code folder ( test folder not required inside the docker)
COPY src/main $APP_HOME/src/main
# skip test stage , bootJar will create executable Jar in gradle which is FAT Jar
# (-x for skip stage, -i for INFO mode to see all stages)
RUN ./gradlew build -x test -i
#Stage - #2
#We need JRE now to run the app , NO JDK not required
FROM openjdk:8-jre
LABEL maintainer="tvajjala.in"
# create folder inside docker env
ENV HOTBOX=/root
WORKDIR $HOTBOX
#Copy FAT JAR from previous stage to create final docker image
COPY --from=GENERATE_FAT_FILE /root/dev/app/build/libs/* .
#copy wiremock contracts (this is specific to my app)
COPY contracts $HOTBOX/contracts
EXPOSE 8080
#since root folder have one FAT JAR , make sure the final jar name
# java -jar *.jar working inside image but not outside need to debug
CMD ["java","-jar","spring-boot-wiremock-1.0.jar"]
CMD java -cp /root/ org.springframework.boot.loader.JarLauncher not working . need to check the root cause, which avoid jar file name hard-coding.
|
Label each stage (in my case GENERATE_FAT_FILE) with some string to refer in next stage, which also improves readability. |
Use below command to check the content inside the docker image
$ docker run -it <image_name> sh
Check the image history which contains only stage-2 history
docker image history --no-trunc <IMAGE_NAME> > image_history.txt
Inspect docker as JSON
$ docker image inspect <IMAGE_ID>
This approach also helps your Jenkins server to handover dockerize stage to slave pods. That means your Jenkins server doesn’t required to install any kind of environment setups(JDK, Gradle, Maven etc) to compile code.
|
Finally, run the below command from root folder of this project
docker build . -t tvajjala/wiremock
Once image is ready run below command to start
docker run -p 80:8080 tvajjala/wiremock
Open your browser http://localhost , make sure your machines 80 port not used by other service or change to different port
Remove all stopped images
docker rm $(docker ps -a -q)
Remove all Intermediate images
docker rmi $(docker images | grep "^<none>" | awk "{print $3}")
View local docker images and container
docker system df
Remove all dangling images and stopped container
docker system prune
Comments
Post a Comment