FROM openjdk:8
RUN apt-get update && apt-get install -y maven
COPY . /usr/app
WORKDIR /usr/app
RUN mvn clean package
EXPOSE 8080
ENTRYPOINT ["java","-jar","/usr/app/target/learning-spring-boot-0.0.1.jar"]
Lets execute the build command:
$ docker build -t josephrodriguez:variant1 -f ./Dockerfile .
[+] Building 410.9s (10/10) FINISHED
=> [internal] load build definition from Dockerfile
=> => transferring dockerfile: 32B
=> [internal] load .dockerignore
=> => transferring context: 35B
=> [internal] load metadata for docker.io/library/openjdk:8
=> [internal] load build context
=> => transferring context: 9.89kB
=> [1/5] FROM docker.io/library/openjdk:8
=> CACHED [2/5] RUN apt-get update && apt-get install -y maven
=> CACHED [3/5] COPY . /usr/app
=> CACHED [4/5] WORKDIR /usr/app
=> [5/5] RUN mvn clean package
=> exporting to image
=> => exporting layers
=> => writing image sha256:ccce626033f48beb36087794b0664a97dc0e45ea95194310709c253b855449f0
=> => naming to docker.io/library/josephrodriguez:variant1
The image was created successfully, but there was some curiosity in me to inspect and see the properties.
$ docker inspect josephrodriguez:variant1
{ ... "Size": 1002195280, "VirtualSize": 1002195280, ... "RootFS": { "Type": "layers", "Layers": [ "sha256:799760671c382bd2492346f4c36ee4033cf917400be4354c8b096ecef88df34b", "sha256:4e61e63529c26e95bef3cf769d07847dee7590b37b6b685186ce5c37a509b06d", "sha256:d00da3cd77634730ab5bc8e98b784cda40259f8be6a9b7138b4eee24ca1226b3", "sha256:8555e663f65b2a41e3aa61c0440f73bc5fac86c94d1cc14331d86d1c699382bf", "sha256:00ef5416d927e1fe6332a3c71e73d9b99eb25f0606bc8ecb0cbec4322d113a6d", "sha256:9cb5eb95298cec190a4f823f82c5a12bbec227e25c9ea4f3a91c05a0c06988a3", "sha256:d9b6ea8e7d5f87f028ab876890fc4129544152138293a167c7697386d57b8a79", "sha256:a5e66608e40747d1a4aba9b933c609b3091fc4eb9796b55c9a121476f4edd364", "sha256:ebd00c77f600344c1e8934b6e69f6dbdf4ae8b2cec1b875a422595a074bce142", "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef", "sha256:cc22a4d2c89f478db3c784b65b1dd650a709a04456f971cecf41d20dac5f197e" ] } ... }
This information raised two major concerns:
- The image size is really big
- It´s contains too many layers
- We use a lighter image such as openjdk:8-jdk-alpine.
FROM openjdk:8-jdk-alpine
COPY . /usr/app
WORKDIR /usr/app
RUN chmod +x mvnw && ./mvnw clean package
COPY /target/*.jar /app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","app.jar"]
We are ready to rebuild our image with these new changes.
$ docker build -t josephrodriguez:variant2 -f ./Dockerfile .
[+] Building 482.1s (10/10) FINISHED
=> [internal] load build definition from Dockerfile
=> => transferring dockerfile: 262B
=> [internal] load .dockerignore
=> => transferring context: 35B
=> [internal] load metadata for docker.io/library/openjdk:8-jdk-alpine
=> [internal] load build context
=> => transferring context: 10.13kB
=> CACHED [basebuild 1/1] FROM docker.io/library/openjdk:8-jdk-alpine
=> [build 1/4] COPY . /usr/app
=> [build 2/4] WORKDIR /usr/app
=> [build 3/4] RUN chmod +x mvnw && ./mvnw clean package
=> [build 4/4] COPY /target/*.jar /app.jar
=> exporting to image
=> => exporting layers
=> => writing image sha256:67a39c7c6ace2c2dfdc81db9909f58c008fb56c19fe75eb09ecc5c19f896fc8a
=> => naming to docker.io/library/josephrodriguez:variant2
Controlling a little anxiety and excitement to inspect our image again, we repeat the same step:
$ docker inspect josephrodriguez:variant2 { "Size": 360337334, "VirtualSize": 360337334, ... "RootFS": { "Type": "layers", "Layers": [ "sha256:f1b5933fe4b5f49bbe8258745cf396afe07e625bdab3168e364daf7c956b6b81", "sha256:9b9b7f3d56a01e3d9076874990c62e7a516cc4032f784f421574d06b18ef9aa4", "sha256:ceaf9e1ebef5f9eaa707a838848a3c13800fcf32d7757be10d4b08fb85f1bc8a", "sha256:c16f37ef1693d02f9d1a938d965b131a3d9cd4f04de15a3b1cf000c251fb07bc", "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef", "sha256:ec3ae917e70014706981d1b58a02390d3d23b1fe5e94a0df5ecf2c73f04a2452", "sha256:eea9c1935243ee73b7d6952bf110f2dfe93868897c3ca53452f4acfb907e2f8b" ] } ... }
Wow, much better. We have now a lighter image from approximately 1GB we have now 360 MB and with less layers. We are moving forward.
Now I have another curiosity with our progress, we are going to check the file system of our image.
$ docker run -ti --entrypoint "/bin/sh" josephrodriguez:variant2
/usr/app # ls
Dockerfile app.jar data mvnw pom.xml src target
In this new version of our image we see that we are publishing with it the source code inside the src folder, the Java byte code .class files and our app.jar file on target folder. What if we could have a lighter image with just our final artifact, the application .jar file?
Variant 3
In this direction we can think, what if we could divide the image process building into two phases? In a first stage we compile our source code and generate our app.jar file, and in a second stage we copy our app.jar file for the final image. We can use the openjdk:8-jdk-alpine image as a base for the first stage, and in the second stage we can use the openjdk:8-jre-alpine image as a base, which is even lighter because it only contains the tools to run our application and not it contains all the development tools.
Here I present multi-stage builds as our definitive solution, the Dockerfile would be as follows:
1: FROM openjdk:8-jdk-alpine as build
2: COPY . /usr/app
3: WORKDIR /usr/app
4: RUN chmod +x mvnw && ./mvnw clean package
5:
6: FROM openjdk:8-jre-alpine
7: COPY --from=build /usr/app/target/*.jar app.jar
8: EXPOSE 8080
9:
10: ENTRYPOINT ["java","-jar","app.jar"]
The code block from lines 1 to 4 is what we already know, now the magic comes in the following blocks.
On line 6 we are declaring that our base image is openjdk:8-jre-alpine instead of openjdk:8-jdk-alpine image.
6: FROM openjdk:8-jre-alpine
In the next line, we are going to copy our app.jar file from our previous stage named build to our final image with the absolute path of the file.
7: COPY --from=build /usr/app/target/*.jar app.jar
Lets build now our image.
$ docker build -t josephrodriguez:variant3 -f ./Dockerfile .
[+] Building 0.3s (12/12) FINISHED
=> [internal] load build definition from Dockerfile
=> => transferring dockerfile: 282B
=> [internal] load .dockerignore
=> => transferring context: 35B
=> [internal] load metadata for docker.io/library/openjdk:8-jdk-alpine
=> [internal] load metadata for docker.io/library/openjdk:8-jre-alpine
=> [internal] load build context
=> => transferring context: 10.15kB
=> [build 1/4] FROM docker.io/library/openjdk:8-jdk-alpine
=> [stage-1 1/2] FROM docker.io/library/openjdk:8-jre-alpine
=> CACHED [build 2/4] COPY . /usr/app
=> CACHED [build 3/4] WORKDIR /usr/app
=> CACHED [build 4/4] RUN chmod +x mvnw && ./mvnw clean package
=> CACHED [stage-1 2/2] COPY --from=build /usr/app/target/*.jar app.jar
=> exporting to image
=> => exporting layers
=> => writing image sha256:601acb6abe23e60ca1fa6f1b11f03168f6581cd25df3ce58f378eb5a843b06c5
=> => naming to docker.io/library/josephrodriguez:variant3
$ docker run -ti --entrypoint "/bin/sh" josephrodriguez:variant3
/ # ls
app.jar bin dev etc home lib media mnt opt
proc root run sbin srv sys tmp usr var
$ docker inspect josephrodriguez:variant3
[
{
"Config": {
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/jvm/java-1.8-openjdk/jre/bin:/usr/lib/jvm/java-1.8-openjdk/bin",
"LANG=C.UTF-8",
"JAVA_HOME=/usr/lib/jvm/java-1.8-openjdk/jre",
"JAVA_VERSION=8u212",
"JAVA_ALPINE_VERSION=8.212.04-r0"
]
},
"Architecture": "amd64",
"Os": "linux",
"Size": 133549472,
"VirtualSize": 133549472,
...
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:f1b5933fe4b5f49bbe8258745cf396afe07e625bdab3168e364daf7c956b6b81",
"sha256:9b9b7f3d56a01e3d9076874990c62e7a516cc4032f784f421574d06b18ef9aa4",
"sha256:edd61588d12669e2d71a0de2aab96add3304bf565730e1e6144ec3c3fac339e4",
"sha256:0701526ec6789abb0b6b8454aaa6574edc5f8fd03bd27102ca51baf005e66425"
]
}
}
]
$ docker image ls | grep variant
josephrodriguez variant1 ccce626033f4 1GB
josephrodriguez variant2 67a39c7c6ace 360MB
josephrodriguez variant3 601acb6abe23 134MB
In the Docker Hub repository we can even see that our compressed image is even lighter!!!!!
Comments
Post a Comment