PURPOSE: This chapter explains how to create a Docker image.
Docker build images by reading instructions from a Dockerfile. A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image. docker image build
command uses this file and executes all the commands in succession to create an image.
build
command is also passed a context that is used during image creation. This context can be a path on your local filesystem or a URL to a Git repository.
Dockerfile is usually called Dockerfile. The complete list of commands that can be specified in this file are explained at https://docs.docker.com/reference/builder/. The common commands are listed below:
Command | Purpose | Example |
---|---|---|
FROM |
First non-comment instruction in Dockerfile |
|
COPY |
Copies mulitple source files from the context to the file system of the container at the specified path |
|
ENV |
Sets the environment variable |
|
RUN |
Executes a command |
|
CMD |
Defaults for an executing container |
|
EXPOSE |
Informs the network ports that the container will listen on |
|
Create a new directory hellodocker
.
In that directory, create a new text file Dockerfile
. Use the following contents:
FROM ubuntu:latest
CMD ["/bin/echo", "hello world"]
This image uses ubuntu
as the base image. CMD
command defines the command that needs to run. It provides a different entry point of /bin/echo
and gives the argument “hello world”.
Build the image using the command:
docker image build . -t helloworld
.
in this command is the context for the command docker image build
. -t
adds a tag to the image.
The following output is shown:
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM ubuntu:latest
latest: Pulling from library/ubuntu
9fb6c798fa41: Pull complete
3b61febd4aef: Pull complete
9d99b9777eb0: Pull complete
d010c8cf75d7: Pull complete
7fac07fb303e: Pull complete
Digest: sha256:31371c117d65387be2640b8254464102c36c4e23d2abe1f6f4667e47716483f1
Status: Downloaded newer image for ubuntu:latest
---> 2d696327ab2e
Step 2/2 : CMD /bin/echo hello world
---> Running in 9356a508590c
---> e61f88f3a0f7
Removing intermediate container 9356a508590c
Successfully built e61f88f3a0f7
Successfully tagged helloworld:latest
List the images available using docker image ls
:
REPOSITORY TAG IMAGE ID CREATED SIZE
helloworld latest e61f88f3a0f7 3 minutes ago 122MB
ubuntu latest 2d696327ab2e 4 days ago 122MB
Other images may be shown as well but we are interested in these two images for now.
Run the container using the command:
docker container run helloworld
to see the output:
hello world
If you do not see the expected output, check your Dockerfile that the content exactly matches as shown above. Build the image again and now run it.
Change the base image from ubuntu
to busybox
in Dockerfile
. Build the image again:
docker image build -t helloworld:2 .
and view the images using docker image ls
command:
REPOSITORY TAG IMAGE ID CREATED SIZE
helloworld 2 7fbedda27c66 3 seconds ago 1.13MB
helloworld latest e61f88f3a0f7 5 minutes ago 122MB
ubuntu latest 2d696327ab2e 4 days ago 122MB
busybox latest 54511612f1c4 9 days ago 1.13MB
helloworld:2
is the format that allows to specify the image name and assign a tag/version to it separated by :
.
Note
|
If you are running OpenJDK 9,
because support for Java 5 was dropped in JDK9. You can add <properties>
<maven.compiler.source>1.6</maven.compiler.source>
<maven.compiler.target>1.6</maven.compiler.target>
</properties> to the generated |
Create a new Java project:
mvn archetype:generate -DgroupId=org.examples.java -DartifactId=helloworld -DinteractiveMode=false
Build the project:
cd helloworld
mvn package
Run the Java class:
java -cp target/helloworld-1.0-SNAPSHOT.jar org.examples.java.App
This shows the output:
Hello World!
Let’s package this application as a Docker image.
Run the OpenJDK container in an interactive manner:
docker container run -it openjdk
This will open a terminal in the container. Check the version of Java:
root@8d0af9da5258:/# java -version
openjdk version "1.8.0_141"
OpenJDK Runtime Environment (build 1.8.0_141-8u141-b15-1~deb9u1-b15)
OpenJDK 64-Bit Server VM (build 25.141-b15, mixed mode)
A different JDK version may be shown in your case.
Exit out of the container by typing exit
in the container shell.
Create a new Dockerfile in helloworld
directory and use the following content:
FROM openjdk:latest
COPY target/helloworld-1.0-SNAPSHOT.jar /usr/src/helloworld-1.0-SNAPSHOT.jar
CMD java -cp /usr/src/helloworld-1.0-SNAPSHOT.jar org.examples.java.App
Build the image:
docker image build -t hello-java:latest .
Run the image:
docker container run hello-java:latest
This displays the output:
Hello World!
This shows the exactly same output that was printed when the Java class was invoked using Java CLI.
Docker Maven Plugin allows you to manage Docker images and containers using Maven. It comes with predefined goals:
Goal | Description |
---|---|
|
Build images |
|
Create and start containers |
|
Stop and destroy containers |
|
Push images to a registry |
|
Remove images from local docker host |
|
Show container logs |
Complete set of goals are listed at https://github.com/fabric8io/docker-maven-plugin.
Clone the sample code from https://github.com/arun-gupta/docker-java-sample/.
Create the Docker image:
mvn -f docker-java-sample/pom.xml package -Pdocker
This will show an output like:
[INFO] Copying files to /Users/argu/workspaces/docker-java-sample/target/docker/hellojava/build/maven
[INFO] Building tar: /Users/argu/workspaces/docker-java-sample/target/docker/hellojava/tmp/docker-build.tar
[INFO] DOCKER> [hellojava:latest]: Created docker-build.tar in 87 milliseconds
[INFO] DOCKER> [hellojava:latest]: Built image sha256:6f815
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
The list of images can be checked using the command docker image ls | grep hello-java
:
hello-java latest ea64a9f5011e 5 seconds ago 643 MB
Run the Docker container:
mvn -f docker-java-sample/pom.xml install -Pdocker
This will show an output like:
[INFO] DOCKER> [hellojava:latest]: Start container 30a08791eedb
30a087> Hello World!
[INFO] DOCKER> [hellojava:latest]: Waited on log out 'Hello World!' 510 ms
This is similar output when running the Java application using java
CLI or the Docker container using docker container run
command.
The container is running in the foreground. Use Ctrl
+ C
to interrupt the container and return back to terminal.
Only one change was required in the project to enable Docker packaging and running. A Maven profile is added in pom.xml
:
<profiles>
<profile>
<id>docker</id>
<build>
<plugins>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.22.1</version>
<configuration>
<images>
<image>
<name>hello-java</name>
<build>
<from>openjdk:latest</from>
<assembly>
<descriptorRef>artifact</descriptorRef>
</assembly>
<cmd>java -cp maven/${project.name}-${project.version}.jar org.examples.java.App</cmd>
</build>
<run>
<wait>
<log>Hello World!</log>
</wait>
</run>
</image>
</images>
</configuration>
<executions>
<execution>
<id>docker:build</id>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
<execution>
<id>docker:start</id>
<phase>install</phase>
<goals>
<goal>start</goal>
<goal>logs</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
TL;DR CMD
will work for most of the cases.
Default entry point for a container is /bin/sh
, the default shell.
Running a container as docker container run -it ubuntu
uses that command and starts the default shell. The output is shown as:
> docker container run -it ubuntu
root@88976ddee107:/#
ENTRYPOINT
allows to override the entry point to some other command, and even customize it. For example, a container can be started as:
> docker container run -it --entrypoint=/bin/cat ubuntu /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
. . .
This command overrides the entry point to the container to /bin/cat
. The argument(s) passed to the CLI are used by the entry point.
TL;DR COPY
will work for most of the cases.
ADD
has all capabilities of COPY
and has the following additional features:
-
Allows tar file auto-extraction in the image, for example,
ADD app.tar.gz /opt/var/myapp
. -
Allows files to be downloaded from a remote URL. However, the downloaded files will become part of the image. This causes the image size to bloat. So its recommended to use
curl
orwget
to download the archive explicitly, extract, and remove the archive.