Docker Best Practices Tutorial
This tutorial talks about various best practices and examples around the docker containers.
1. Introduction
Docker containers are an essential part of containerization as we moved towards cloud-native applications. Since it is going to massive implementation of containers, it is vital to follow certain best practices based on our past experience, to bring out qualitative containers. The best practices for the docker are around the below classifications:
- Dockerfile best practices
- Docker security best practices
2. Dockerfile best practices
2.1 Keep in mind the caching and the layers
This section explains the tricks which make your builds lightweight using caching mechanisms. You need to write the Dockerfile in an efficient way to support appropriate caching. Each time the docker builds, it caches layers of the images. However, when it encounters the COPY/ADD instructions and if the folder or files under the operation have changed then it invalidates the caches the docker builds all the layer thereafter.
Check this example. Here ADD comes after FROM instruction. Let us run mvn clean install
and then docker build . --file Dockerfile.wrong_order --tag jcg_example:0.0.1
. Now without running the mvn install command again run the docker build command. It will not take much time as the earlier build.
However, run the install once again and then the docker build command, it would take the same time as new. That is because, the ADD jar file in the ADD command has changed and hence has invalidated the cache.
Dockefile.wrong_order
FROM ubuntu:18.04 ADD target/JCGJavaWithDocker-1.0-SNAPSHOT-jar-with-dependencies.jar java-docker.jar RUN apt-get update RUN apt-get install -y openjdk-8-jdk CMD ["java", "-jar", "java-docker.jar"]
Download the code and compile the java code using the instructions given in section 5, below. Execute the below command to generate an example image with version 0.0.1.
time docker build . --file Dockerfile.wrong_order --tag jcg_example:0.0.1 # Run Maven clean install again mvn clean install # Run docker image again time docker build . --file Dockerfile.wrong_order --tag jcg_example:0.0.1
Sample Output:
time docker build . --file Dockerfile.wrong_order --tag jcg_example:0.0.1 Sending build context to Docker daemon 128kB Step 1/5 : FROM ubuntu:18.04 ---> d27b9ffc5667 Step 2/5 : ADD target/JCGJavaWithDocker-1.0-SNAPSHOT-jar-with-dependencies.jar java-docker.jar ---> 37171c094f33 Step 3/5 : RUN apt-get update ---> Running in 20d2c01147c6 Get:1 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB] .. .. Step 5/5 : CMD ["java", "-jar", "java-docker.jar"] ---> Running in 469ccf6754a2 Removing intermediate container 469ccf6754a2 ---> aeb0816e2cdb Successfully built aeb0816e2cdb Successfully tagged jcg_example:0.0.1 real 1m55.505s user 0m0.091s sys 0m0.141s ~/projects/JCGJavaWithDocker$ mvn clean install WARNING: An illegal reflective access operation has occurred WARNING: Illegal reflective access by com.google.inject.internal.cglib.core.$ReflectUtils$1 (file:/usr/share/maven/lib/guice.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) WARNING: Please consider reporting this to the maintainers of com.google.inject.internal.cglib.core.$ReflectUtils$1 WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations WARNING: All illegal access operations will be denied in a future release [INFO] Scanning for projects... [INFO] [INFO] --------------------------------------- [INFO] Building JCGJavaWithDocker 1.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ JCGJavaWithDocker --- [INFO] Deleting /home/.../projects/JCGJavaWithDocker/target [INFO] [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ JCGJavaWithDocker --- [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] Copying 1 resource [INFO] [INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @ JCGJavaWithDocker --- [WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent! [INFO] Compiling 1 source file to /home/.../projects/JCGJavaWithDocker/target/classes [INFO] [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ JCGJavaWithDocker --- [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] skip non existing resourceDirectory /home/.../projects/JCGJavaWithDocker/src/test/resources [INFO] [INFO] --- maven-compiler-plugin:2.3.2:testCompile (default-testCompile) @ JCGJavaWithDocker --- [INFO] Nothing to compile - all classes are up to date [INFO] [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ JCGJavaWithDocker --- [INFO] No tests to run. [INFO] [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ JCGJavaWithDocker --- [INFO] Building jar: /home/.../projects/JCGJavaWithDocker/target/JCGJavaWithDocker-1.0-SNAPSHOT.jar [INFO] [INFO] --- maven-assembly-plugin:2.2-beta-5:single (default) @ JCGJavaWithDocker --- [INFO] Building jar: /home/.../projects/JCGJavaWithDocker/target/JCGJavaWithDocker-1.0-SNAPSHOT-jar-with-dependencies.jar [INFO] [INFO] --- maven-install-plugin:2.4:install (default-install) @ JCGJavaWithDocker --- [INFO] Installing /home/.../projects/JCGJavaWithDocker/target/JCGJavaWithDocker-1.0-SNAPSHOT.jar to /home/.../.m2/repository/org/example/JCGJavaWithDocker/1.0-SNAPSHOT/JCGJavaWithDocker-1.0-SNAPSHOT.jar [INFO] Installing /home/.../projects/JCGJavaWithDocker/pom.xml to /home/.../.m2/repository/org/example/JCGJavaWithDocker/1.0-SNAPSHOT/JCGJavaWithDocker-1.0-SNAPSHOT.pom [INFO] Installing /home/.../projects/JCGJavaWithDocker/target/JCGJavaWithDocker-1.0-SNAPSHOT-jar-with-dependencies.jar to /home/.../.m2/repository/org/example/JCGJavaWithDocker/1.0-SNAPSHOT/JCGJavaWithDocker-1.0-SNAPSHOT-jar-with-dependencies.jar [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 2.708 s [INFO] Finished at: 2020-07-23T12:27:55+01:00 [INFO] ------------------------------------------------------------------------ ~/projects/JCGJavaWithDocker$ time docker build . --file Dockerfile.wrong_order --tag jcg_example:0.0.1 Sending build context to Docker daemon 128kB Step 1/5 : FROM ubuntu:18.04 ---> d27b9ffc5667 Step 2/5 : ADD target/JCGJavaWithDocker-1.0-SNAPSHOT-jar-with-dependencies.jar java-docker.jar ---> d6274dbfcb70 Step 3/5 : RUN apt-get update ---> Running in def9d44a2262 ... Removing intermediate container e20b310b89f8 ---> 78c1ecdfc835 Step 5/5 : CMD ["java", "-jar", "java-docker.jar"] ---> Running in 67c9afd2ec59 Removing intermediate container 67c9afd2ec59 ---> 1aff615dd35d Successfully built 1aff615dd35d Successfully tagged jcg_example:0.0.1 real 1m57.550s user 0m0.041s sys 0m0.251s
Here is the right way of ordering the layers. In this way even we do change the compiled jar, it does not affect the build time of the docker image.
Dockefile.right_order
FROM ubuntu:18.04 RUN apt-get update RUN apt-get install -y openjdk-8-jdk ADD target/JCGJavaWithDocker-1.0-SNAPSHOT-jar-with-dependencies.jar java-docker.jar CMD ["java", "-jar", "java-docker.jar"]
Execute the below commands:
# Run Maven clean install again mvn clean install docker build . --file Dockerfile.right_order --tag jcg_example:0.0.2 # Run Maven clean install again mvn clean install # Run docker image again docker build . --file Dockerfile.right_order --tag jcg_example:0.0.2 # Examine it takes the lesser time as previous
Sample Output:
~/projects/JCGJavaWithDocker$ mvn clean install WARNING: An illegal reflective access operation has occurred WARNING: Illegal reflective access by com.google.inject.internal.cglib.core.$ReflectUtils$1 (file:/usr/share/maven/lib/guice.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) WARNING: Please consider reporting this to the maintainers of com.google.inject.internal.cglib.core.$ReflectUtils$1 WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations WARNING: All illegal access operations will be denied in a future release [INFO] Scanning for projects... [INFO] [INFO] --------------------------------------- [INFO] Building JCGJavaWithDocker 1.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- ... [INFO] Installing /home/.../projects/JCGJavaWithDocker/target/JCGJavaWithDocker-1.0-SNAPSHOT.jar to /home/.../.m2/repository/org/example/JCGJavaWithDocker/1.0-SNAPSHOT/JCGJavaWithDocker-1.0-SNAPSHOT.jar [INFO] Installing /home/.../projects/JCGJavaWithDocker/pom.xml to /home/.../.m2/repository/org/example/JCGJavaWithDocker/1.0-SNAPSHOT/JCGJavaWithDocker-1.0-SNAPSHOT.pom [INFO] Installing /home/.../projects/JCGJavaWithDocker/target/JCGJavaWithDocker-1.0-SNAPSHOT-jar-with-dependencies.jar to /home/.../.m2/repository/org/example/JCGJavaWithDocker/1.0-SNAPSHOT/JCGJavaWithDocker-1.0-SNAPSHOT-jar-with-dependencies.jar [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1.919 s [INFO] Finished at: 2020-07-23T12:31:21+01:00 [INFO] ------------------------------------------------------------------------ ~/projects/JCGJavaWithDocker$ time docker build . --file Dockerfile.right_order --tag jcg_example:0.0.2 Sending build context to Docker daemon 128kB Step 1/5 : FROM ubuntu:18.04 ---> d27b9ffc5667 Step 2/5 : RUN apt-get update ---> Using cache ---> 8818b118f8d4 Step 3/5 : RUN apt-get install -y openjdk-8-jdk ---> Using cache ---> 967e3b35c6ee Step 4/5 : ADD target/JCGJavaWithDocker-1.0-SNAPSHOT-jar-with-dependencies.jar java-docker.jar ---> 2c9aa1a06388 Step 5/5 : CMD ["java", "-jar", "java-docker.jar"] ---> Running in ea68774c0b30 Removing intermediate container ea68774c0b30 ---> 0e51dc5a27a9 Successfully built 0e51dc5a27a9 Successfully tagged jcg_example:0.0.2 real 0m0.436s user 0m0.033s sys 0m0.037s
~/projects/JCGJavaWithDocker$ mvn clean install WARNING: An illegal reflective access operation has occurred WARNING: Illegal reflective access by com.google.inject.internal.cglib.core.$ReflectUtils$1 (file:/usr/share/maven/lib/guice.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) WARNING: Please consider reporting this to the maintainers of com.google.inject.internal.cglib.core.$ReflectUtils$1 WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations WARNING: All illegal access operations will be denied in a future release [INFO] Scanning for projects... [INFO] [INFO] --------------------------------------- [INFO] Building JCGJavaWithDocker 1.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- ... [INFO] Installing /home/.../projects/JCGJavaWithDocker/target/JCGJavaWithDocker-1.0-SNAPSHOT.jar to /home/.../.m2/repository/org/example/JCGJavaWithDocker/1.0-SNAPSHOT/JCGJavaWithDocker-1.0-SNAPSHOT.jar [INFO] Installing /home/.../projects/JCGJavaWithDocker/pom.xml to /home/.../.m2/repository/org/example/JCGJavaWithDocker/1.0-SNAPSHOT/JCGJavaWithDocker-1.0-SNAPSHOT.pom [INFO] Installing /home/.../projects/JCGJavaWithDocker/target/JCGJavaWithDocker-1.0-SNAPSHOT-jar-with-dependencies.jar to /home/.../.m2/repository/org/example/JCGJavaWithDocker/1.0-SNAPSHOT/JCGJavaWithDocker-1.0-SNAPSHOT-jar-with-dependencies.jar [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1.919 s [INFO] Finished at: 2020-07-23T12:31:21+01:00 [INFO] ------------------------------------------------------------------------ ~/projects/JCGJavaWithDocker$ time docker build . --file Dockerfile.right_order --tag jcg_example:0.0.2 Sending build context to Docker daemon 128kB Step 1/5 : FROM ubuntu:18.04 ---> d27b9ffc5667 Step 2/5 : RUN apt-get update ---> Using cache ---> 8818b118f8d4 Step 3/5 : RUN apt-get install -y openjdk-8-jdk ---> Using cache ---> 967e3b35c6ee Step 4/5 : ADD target/JCGJavaWithDocker-1.0-SNAPSHOT-jar-with-dependencies.jar java-docker.jar ---> 88eabff6bcb3 Step 5/5 : CMD ["java", "-jar", "java-docker.jar"] ---> Running in c44ad221562f Removing intermediate container c44ad221562f ---> ce30673e6e80 Successfully built ce30673e6e80 Successfully tagged jcg_example:0.0.2 real 0m0.430s user 0m0.014s sys 0m0.063s
2.2 Avoid wild characters in ADD or COPY command – be specific
Whenever you issue wild charecter like * and dot (.) like the one in the below, it will end copy or adding a lot of files and it would copy a lot of files leading to cache bursts.
Dockefile.cacheburst
FROM ubuntu:18.04 RUN apt-get update RUN apt-get install -y openjdk-8-jdk ADD target/* / CMD ["java", "-jar", "JCGJavaWithDocker-1.0-SNAPSHOT-jar-with-dependencies.jar"]
2.3 Reduce Image size
# Tip 1: Use the right base image required for the container to work.
For the java based containers like the example above, instead of using ubuntu using jdk images such as openjdk:8-jdk-alpine and the size of the image becomes almost 10% the image generated. Check the size of the jcg_example:0.0.3 image;it must be in the order of 100s instead of 400+ for other images.
Dockerfile.lessersize
FROM openjdk:8-jdk-alpine ADD target/JCGJavaWithDocker-1.0-SNAPSHOT-jar-with-dependencies.jar java-docker.jar CMD ["java", "-jar", "java-docker.jar"]
docker build . --file Dockerfile.lessersize --tag jcg_example:0.0.3 # Check the size by executing the docker image and look for jcg_example docker image ls | grep jcg_example # Size jcg_example:0.0.3 should be in the order of 100s instead of 400+ for other images
Sample Output:
~/projects/JCGJavaWithDocker$ docker build . --file Dockerfile.lessersize --tag jcg_example:0.0.3 Sending build context to Docker daemon 128kB Step 1/3 : FROM openjdk:8-jdk-alpine ---> a3562aa0b991 Step 2/3 : ADD target/JCGJavaWithDocker-1.0-SNAPSHOT-jar-with-dependencies.jar java-docker.jar ---> ce842dafc94c Step 3/3 : CMD ["java", "-jar", "java-docker.jar"] ---> Running in 04dbfd1f9718 Removing intermediate container 04dbfd1f9718 ---> 80d8aec6f234 Successfully built 80d8aec6f234 Successfully tagged jcg_example:0.0.3 ~/projects/JCGJavaWithDocker$ docker image ls | grep jcg_example jcg_example 0.0.3 80d8aec6f234 57 seconds ago 105MB jcg_example 0.0.2 ce30673e6e80 5 minutes ago 490MB jcg_example 0.0.1 1aff615dd35d About an hour ago 490MB jcg_example 0.0.6 88614bba2d06 15 hours ago 105MB jcg_example 0.0.5 9b71834fad7a 19 hours ago 105MB
2.4 Use standard labels for better traceability
It is recomended to use OCI labels for standard images. Refer specification for list of labels that can be used.
Dockerfile.with_labels
FROM openjdk:8-jdk-alpine LABEL \ org.opencontainers.image.title=jcg_example \ org.opencontainers.image.vendor=Java Code Geeks \ org.opencontainers.image.version=0.0.5 ADD target/JCGJavaWithDocker-1.0-SNAPSHOT-jar-with-dependencies.jar java-docker.jar RUN apt-get update RUN apt-get install -y openjdk-8-jdk CMD ["java", "-jar", "java-docker.jar"]
docker build . --file Dockerfile.with_labels--tag jcg_example:0.0.4 # Check the labels in the image docker inspect jcg_example:0.0.4 | grep Label -A 4
Sample Output:
~/projects/JCGJavaWithDocker$ docker build . --file Dockerfile.with_labels --tag jcg_example:0.0.4 Sending build context to Docker daemon 128kB Step 1/4 : FROM openjdk:8-jdk-alpine ---> a3562aa0b991 Step 2/4 : LABEL org.opencontainers.image.title=jcg_example org.opencontainers.image.vendor="Java Code Geeks" org.opencontainers.image.version=0.0.5 ---> Using cache ---> d61342b6d696 Step 3/4 : ADD target/JCGJavaWithDocker-1.0-SNAPSHOT-jar-with-dependencies.jar java-docker.jar ---> Using cache ---> 2c433b6d996a Step 4/4 : CMD ["java", "-jar", "java-docker.jar"] ---> Running in 7b04d5c12198 Removing intermediate container 7b04d5c12198 ---> fdf0bc611bbe Successfully built fdf0bc611bbe Successfully tagged jcg_example:0.0.4 ~/projects/JCGJavaWithDocker$ docker inspect jcg_example:0.0.4 | grep Label -A 4 "Labels": { "org.opencontainers.image.title": "jcg_example", "org.opencontainers.image.vendor": "Java Code Geeks", "org.opencontainers.image.version": "0.0.5" } -- "Labels": { "org.opencontainers.image.title": "jcg_example", "org.opencontainers.image.vendor": "Java Code Geeks", "org.opencontainers.image.version": "0.0.5" }
2.5 Use ARGS wherever possible
Use ARGS for the dynamic content such as jar name, build date, commit hash etc.,.
Dockerfile
FROM openjdk:8-jdk-alpine ARG COMMIT ARG BUILD_DATE ARG APP_VERSION ARG JAR_NAME LABEL \ org.opencontainers.image.title=jcg_example \ org.opencontainers.image.created=$BUILD_DATE \ org.opencontainers.image.revision=$COMMIT \ org.opencontainers.image.vendor="Java Code Geeks" \ org.opencontainers.image.version=$APP_VERSION ADD target/$JAR_NAME java-docker.jar CMD ["java", "-jar", "java-docker.jar"]
# Build the docker time docker build --build-arg COMMIT=b34eab --build-arg BUILD_DATE=22-JUL-2020 --build-arg APP_VERSION=0.0.5 --build-arg JAR_NAME=JCGJavaWithDocker-1.0-SNAPSHOT-jar-with-dependencies.jar --file Dockerfile.with_args . --tag jcg_example:0.0.5 # Check the availability of images docker image ls | grep jcg_example
Sample Output:
~/projects/JCGJavaWithDocker$ time docker build --build-arg COMMIT=b34eab --build-arg BUILD_DATE=22-JUL-2020 --build-arg APP_VERSION=0.0.5 --build-arg JAR_NAME=JCGJavaWithDocker-1.0-SNAPSHOT-jar-with-dependencies.jar --file Dockerfile . --tag jcg_example:0.0.5 Sending build context to Docker daemon 128kB Step 1/8 : FROM openjdk:8-jdk-alpine ---> a3562aa0b991 Step 2/8 : ARG COMMIT ---> Using cache ---> 71c6a6a00594 Step 3/8 : ARG BUILD_DATE ---> Using cache ---> fb62a3145fea Step 4/8 : ARG APP_VERSION ---> Using cache ---> 8fc4365d0cbb Step 5/8 : ARG JAR_NAME ---> Using cache ---> 792d4dbee6b5 Step 6/8 : LABEL org.opencontainers.image.title=jcg_example org.opencontainers.image.created=$BUILD_DATE org.opencontainers.image.revision=$COMMIT org.opencontainers.image.vendor="Java Code Geeks" org.opencontainers.image.version=$APP_VERSION ---> Using cache ---> b6cfa98420eb Step 7/8 : ADD target/$JAR_NAME java-docker.jar ---> 230212c73cee Step 8/8 : CMD ["java", "-jar", "java-docker.jar"] ---> Running in 30d2a52ae47c Removing intermediate container 30d2a52ae47c ---> 9acb3c756cef Successfully built 9acb3c756cef Successfully tagged jcg_example:0.0.5 real 0m0.466s user 0m0.019s sys 0m0.034s ~/projects/JCGJavaWithDocker$ docker image ls | grep jcg_example jcg_example 0.0.5 9acb3c756cef About a minute ago 105MB jcg_example 0.0.4 fdf0bc611bbe 5 minutes ago 105MB jcg_example 0.0.3 80d8aec6f234 8 minutes ago 105MB jcg_example 0.0.2 ce30673e6e80 13 minutes ago 490MB jcg_example 0.0.1 1aff615dd35d About an hour ago 490MB jcg_example
3. Docker security best practices
These are the best practices to be followed while running the containers.
3.1 Mind the memory and CPU usage
Any application needs memory and CPU for running. Applications are prone to programming errors which may lead to over usage of available resources and may hinder the performance of other containers. Hence it is good to cap the resources used by the containers at the time execution. Here is an example of how to cap the resources. For more information check the docker documentation.
Reusing the docker image from the previous section.
docker run -m 10m --cpus 1.5 jcg_example:0.0.5
3.2 Run as non-root user
It is not at all a good practice to run a container as a root. When you do not mention any user to run, the container run by default as root. There are a couple of options to not to run as root.
One of the options is to set the user in the Dockerfile, so that when the image is run, it automatically run as specified user. Or alternatively, specify at the time of execution of the containers as per below example:
docker run --user $(id -u):$(id -g) -m 10m --cpus 1.5 jcg_example:0.0.5
3.3 Use only trusted Docker Registries
It is always good to use containers from a secure and trusted docker registries. In the industry, there are a lot of generally available docker images for commonly used images. For example, to run nginx, the image is available at hub.docker.com with the image name as nginx with label 1.19.1.
However, security experts at the enterprises, do no recommend using the global image. Instead, the image has to be downloaded, duly tested for security vulnerabilities, and to be uploaded into an industry-wide image repository. These repositories are protected by firewalls and role-based authentication mechanisms to percent unauthorized access.
3.4 Do not include sensitive information in the containers
I have seen many developers irresponsibly leave the sensitive information such user names, passwords, security tokens for the REST APIs they use in the containers. Some use AWS resources to upload information/files from the containers and they need AWS CLI tokens. It is bad to burn the image with tokens and distribute across the world.
Since it is not good to bake images with secrets (tokens, passwords, API keys). we have to design containers to accept injected secrets or containers must directly fetch the secret. Here are the various options to inject secrets into the container:
- Inject as environment variables: This is not a recommended way as the containers might be hacked and environment values might be inspected and easily secrets be retrieved
- Mount the folder containing files with secrets: This is better way than environmental variables. you can write all secrets into a file and mount that folder as volume as secrets. However, its not good from the maintenability perspective to write sensitive information on machine where the docker containers are run.
- Fetch the sensitive information from a centralized repository: In this method you can use a predefined side car to fetch the tokens dynamically from a centralised stored password manager such a vault.
4. Setup for Execution
In this section we will execute the programs and see how it is working.
Prerequisites:
- Java 1.8 installed in the system. Environment variables
JAVA_HOME
set to the Java location andPATH
set to the directory containing javac and java binaries (%JAVA_HOME%/bin
on windows or$JAVA_HOME/bin
on Linux machines) - Maven 3 installed. Refer documentation for instructions on how to install.
- Docker engine installed using the documentation from the docker site. For Linux OS, add user into the docker group using the steps (this might require a restart).
- Source code zip and unzipped to a location (say,
C:\JavaCodeGeeks
. This would be different for Linux) - Command-line is used for example
4.1 Execution using command line
Step 1: Open the command line
Step 2: Go the folder where examples are unzipped C:\JavaCodeGeeks
Step 3: Compile the project using the command mvn clean install
Sample Output:
~/projects/JCGJavaWithDocker$ mvn clean install WARNING: An illegal reflective access operation has occurred WARNING: Illegal reflective access by com.google.inject.internal.cglib.core.$ReflectUtils$1 (file:/usr/share/maven/lib/guice.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) WARNING: Please consider reporting this to the maintainers of com.google.inject.internal.cglib.core.$ReflectUtils$1 WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations WARNING: All illegal access operations will be denied in a future release [INFO] Scanning for projects... [INFO] [INFO] --------------------------------------- [INFO] Building JCGJavaWithDocker 1.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- ... [INFO] Installing /home/.../projects/JCGJavaWithDocker/target/JCGJavaWithDocker-1.0-SNAPSHOT.jar to /home/.../.m2/repository/org/example/JCGJavaWithDocker/1.0-SNAPSHOT/JCGJavaWithDocker-1.0-SNAPSHOT.jar [INFO] Installing /home/.../projects/JCGJavaWithDocker/pom.xml to /home/.../.m2/repository/org/example/JCGJavaWithDocker/1.0-SNAPSHOT/JCGJavaWithDocker-1.0-SNAPSHOT.pom [INFO] Installing /home/.../projects/JCGJavaWithDocker/target/JCGJavaWithDocker-1.0-SNAPSHOT-jar-with-dependencies.jar to /home/.../.m2/repository/org/example/JCGJavaWithDocker/1.0-SNAPSHOT/JCGJavaWithDocker-1.0-SNAPSHOT-jar-with-dependencies.jar [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1.919 s [INFO] Finished at: 2020-07-23T12:31:21+01:00 [INFO] ------------------------------------------------------------------------
Step 4: Generate the latest image and check if it is created.
# Generate the image time docker build --build-arg COMMIT=b34eab --build-arg BUILD_DATE=22-JUL-2020 --build-arg APP_VERSION=0.0.5 --build-arg JAR_NAME=JCGJavaWithDocker-1.0-SNAPSHOT-jar-with-dependencies.jar --file Dockerfile . --tag jcg_example:latest # Check the availability of image docker image ls | grep jcg_example | grep latest
Sample Output:
time docker build --build-arg COMMIT=b34eab --build-arg BUILD_DATE=22-JUL-2020 --build-arg APP_VERSION=0.0.5 --build-arg JAR_NAME=JCGJavaWithDocker-1.0-SNAPSHOT-jar-with-dependencies.jar --file Dockerfile . --tag jcg_example:latest Sending build context to Docker daemon 128kB Step 1/8 : FROM openjdk:8-jdk-alpine ---> a3562aa0b991 Step 2/8 : ARG COMMIT ---> Using cache ---> 71c6a6a00594 Step 3/8 : ARG BUILD_DATE ---> Using cache ---> fb62a3145fea Step 4/8 : ARG APP_VERSION ---> Using cache ---> 8fc4365d0cbb Step 5/8 : ARG JAR_NAME ---> Using cache ---> 792d4dbee6b5 Step 6/8 : LABEL org.opencontainers.image.title=jcg_example org.opencontainers.image.created=$BUILD_DATE org.opencontainers.image.revision=$COMMIT org.opencontainers.image.vendor="Java Code Geeks" org.opencontainers.image.version=$APP_VERSION ---> Using cache ---> b6cfa98420eb Step 7/8 : ADD target/$JAR_NAME java-docker.jar ---> Using cache ---> 230212c73cee Step 8/8 : CMD ["java", "-jar", "java-docker.jar"] ---> Using cache ---> 9acb3c756cef Successfully built 9acb3c756cef Successfully tagged jcg_example:latest real 0m0.119s user 0m0.039s sys 0m0.012s # Check the availability of images ~/projects/JCGJavaWithDocker$ docker image ls | grep jcg_example | grep latest jcg_example latest 9acb3c756cef 4 minutes ago 105MB
5. Download the Project
You can download the full source code of this example here: Docker Best Practices Tutorial