Note
|
This repository contains the guide documentation source. To view the guide in published form, view it on the Open Liberty website. |
Learn how to build a docker image. == What you’ll learn
You will learn how to write Dockerfiles
, how to use the docker build
to create Docker images and how to run instances of the images in Docker containers using docker run
.
The application that you will be working with is an inventory
service,
which stores the information about various JVMs that run on different systems.
Whenever a request is made to the inventory
service to retrieve the JVM
system properties of a particular host, the inventory
service communicates with the system
service on that host to get these system properties. The system properties are then stored and returned.
The starting Java project, which you can find in the start
directory, is a multi-module Maven project that’s made up of the system
and inventory
microservices. Each microservice resides in its own directory, start/system
and start/inventory
, respectively.
If you want to learn more about RESTful web services and how to build them, see
Creating a RESTful web service for details about how to build the system
service.
The inventory
service is built in a similar way.
To try out the application using Maven, first, navigate to the start
directory and then run the following Maven goals to build the application and run it inside Open Liberty:
cd start
mvn install
mvn liberty:start-server
The starting point of the inventory
service can be found at the http://localhost:9081/inventory/systems URL. It displays the current contents of the inventory.
The system
service shows the system properties of your local JVM and can be found at the http://localhost:9080/system/properties URL.
The system
can be added to the inventory
by visiting the http://localhost:9081/inventory/systems/localhost URL.
After you are done checking out the application, stop the Open Liberty server:
mvn liberty:stop-server
A Docker image is a binary file, made up of multiple layers, used to execute code in a Docker container. Images are built from
instructions, called Dockerfiles
, to create a containerized version of the application.
A Dockerfile is a collection of instructions for building a Docker image that can then be run as a container. Every Dockerfile begins with a parent or base image on top of which various commands are run. For example, you can start your image from scratch and execute commands that download and install Java, or you can start from an image that already contains a Java installation.
Learn more about Docker on the official Docker page.
Install Docker on the official instructions page.
You will be creating two Docker images to run the inventory
service and system
service. The first step is to create Dockerfiles for both services.
Create theinventory/Dockerfile
.inventory/Dockerfile
inventory/Dockerfile
link:finish/inventory/Dockerfile[role=include]
The FROM
instruction initializes a new build stage, which indicates the parent image of the
image that has been built. If you don’t need a parent image, then you can use FROM scratch
, which makes your image a
base image.
In this case, you’re using the open-liberty
image as your parent
image, which comes with the latest Open Liberty runtime by default. You can find all different official images at the open-liberty DockerHub. To pull different open-liberty image, like kernel
, you may define the FROM
instructions as FROM open-liberty:kernel
.
There are three different Open Liberty Docker image sets available on Docker Hub. You can learn more about them on the OpenLiberty Docker Images repository.
The ADD
instruction copies local files and directories into the destination within your Docker image. It is structured as ADD <source> <destination>
.
In this case, the source is a tar.gz
file that was created from running mvn install
and the destination is a directory called /opt/ol
where the server will be started.
The ADD
instruction unpacks local tar
archives into the destination directory specified in the Dockerfile
. This is one of the aspects that makes it different from the COPY
instruction. The COPY
instruction would keep a layer of the zipped archive as well as the unzipped contents of the archive, whereas ADD
only keeps the unzipped contents of the archive.
This server is started in the open-liberty Dockerfile.
The ADD
instruction needs to use the user id 1001
and group 0
because the OpenLiberty
image runs by default with the USER 1001
(non-root). Without this, the files and directories copied over would be owned by root.
Finally, the *.tar.gz
files are copied over into /opt/ol
.
The Dockerfile
for the system
service follows the same instructions as inventory
service.
Create thesystem/Dockerfile
.system/Dockerfile
system/Dockerfile
link:finish/system/Dockerfile[role=include]
Now that your microservices are complete and you have written your Dockerfiles, you will build your Docker images.
To build your image, you need Docker installed. For installation instructions, see the Official Docker Docs.
You will build your Docker image using the docker build
command.
To build and containerize the application, start your Docker daemon and run the following commands:
docker build -t system system/.
docker build -t inventory inventory/.
The -t
flag in the docker build
command allows the docker images to be in name:tag
format.
The tag for an image describes the specific image version.
To verify that the images are built, run the docker images
command to list all local Docker images:
docker images
Your two images inventory
and system
should appear in the list of all Docker images:
REPOSITORY TAG IMAGE ID CREATED SIZE
inventory latest 08fef024e986 4 minutes ago 471MB
system latest 1dff6d0b4f31 5 minutes ago 470MB
Now that you have your two images built, you will run your microservices in Docker containers:
docker run -d --name system -p 9080:9080 system
docker run -d --name inventory -p 9081:9081 inventory
The flags are described in the table below:
Flag | Description |
---|---|
-d |
Runs the container in the background. |
--name |
Specifies a name for the container. |
-p |
Maps the container ports to the host ports. |
Next, run the docker ps
command to verify that your containers are started:
docker ps
Make sure that your container is running and shows Up x seconds
as its status:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2b584282e0f5 inventory:latest "/opt/ol/helpers/run…" 2 seconds ago Up 1 second 9080/tcp, 9443/tcp, 0.0.0.0:9081->9081/tcp inventory
99a98313705f system:latest "/opt/ol/helpers/run…" 3 seconds ago Up 2 seconds 0.0.0.0:9080->9080/tcp, 9443/tcp system
To access the application, point your browser to the http://localhost:9081/inventory/systems URL. An empty list is expected because no system properties are stored in the inventory yet.
Point your browser to the http://localhost:9080/system/properties URL. The system
service shows the system properties of the system
container JVM.
Next, you will retrieve the system
containers IP address. When you start Docker, a default bridge network is created for running containers to be able to communicate.
Run the following command to retrieve the system
IP address:
docker network inspect bridge
You will find the address corresponding to IPv4Address:
"99a98313705fc9f8c21b8110900b8bee0427412373f8c3ef2d733c96d96ffb5f": {
"Name": "system",
"EndpointID": "e30b640eb214435c9bf08b23d7c3f851c88e909e4feffd1a893f14ae4d2f35a4",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
In this case, the address for system
is 172.17.0.2
. Note down the [system-ip-address] in order to add the system properties to the inventory service.
Point your browser to the http://localhost:9081/inventory/systems/[system-ip-address]
URL by replacing the [system-ip-address]
with the value you obtained.
You see a result in JSON format with the system properties of your local JVM. When you visit this URL, these system
properties are automatically stored in the inventory. Go back to http://localhost:9081/inventory/systems and
you see a new entry for [system-ip-address]
. As you can see, the os.name
is Linux
because the base image was pulled from a Linux
image.
If a problem occurs and your containers exit prematurely, the containers won’t appear in the container
list that the docker ps
command displays. Instead, your containers appear with an Exited
status when running the docker ps -a
command. Run the docker logs system
and docker logs inventory
commands to view the
container logs for any potential problems and double-check that your Dockerfiles are correct. When you
find the cause of the issue, remove the faulty containers with the docker rm system
and docker rm inventory
commands, rebuild
your image, and start the containers again.
You can test your application manually or with automated tests that test the microservices running locally and against the docker container.
Create theSystemEndpointTest
class.system/src/test/java/it/io/openliberty/guides/system/SystemEndpointTest.java
SystemEndpointTest.java
link:finish/system/src/test/java/it/io/openliberty/guides/system/SystemEndpointTest.java[role=include]
The testGetProperties()
method checks for a 200
response status from the system
service endpoint.
Create theInventoryEndpointTest
class.inventory/src/test/java/it/io/openliberty/guides/inventory/InventoryEndpointTest.java
InventoryEndpointTest.java
link:finish/inventory/src/test/java/it/io/openliberty/guides/inventory/InventoryEndpointTest.java[role=include]
-
The
testEmptyInventory()
method checks that theinventory
service has a total of 0 systems before anything is added to it. -
The
testHostRegistration()
method checks that thesystem
service was added toinventory
properly. -
The
testSystemPropertiesMatch()
checks that thesystem
properties match what was added into theinventory
. -
The
testUnknownHost()
checks that an error is raised if an unknown host name is being added into theinventory
service. -
The
systemServiceIp
is the same value that you retrieved in the previous section to manually add thesystem
service into theinventory
service. This value will also be passed in when you run the tests.
Run the Maven verify
goal to test the services running in the docker containers by replacing the [system-ip-address]
with the value determined in the previous section.
mvn verify -Ddockerfile.skip=true -Dsystem.ip=[system-ip-address]
If the tests pass, you will see a similar output as the following:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running it.io.openliberty.guides.system.SystemEndpointTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.653 s - in it.io.openliberty.guides.system.SystemEndpointTest
Results:
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running it.io.openliberty.guides.inventory.InventoryEndpointTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.935 s - in it.io.openliberty.guides.inventory.InventoryEndpointTest
Results:
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
When you are finished with the services, run the following commands to stop your containers.
docker stop inventory system
docker rm inventory system
You have just built Docker images for two microservices in Open Liberty.