Using Docker containers to develop microservices

duration 20 minutes

Prerequisites:

Learn how to use Docker containers for iterative development.

What you’ll learn

You will learn how to set up, run, and iteratively develop a simple REST application in a container with Open Liberty and Docker.

The implementation of the REST application can be found in the start/src directory. To learn more about this application and how to build it, read Creating a RESTful web service.

To iteratively develop your application in a container, first build it with Maven and add it to the servers of your choice. Second, create a Docker image that contains an Open Liberty runtime. Third, run this image and mount a single server directory or the directory that contains all of your servers to the container’s file system. Finally, run one of the mounted servers inside of a container.

What is Docker?

Docker is a tool that you can use to deploy and run applications with containers. You can think of Docker like a virtual machine that runs various applications. However, unlike a typical virtual machine, you can run these applications simultaneously on a single system and independent of one another.

Learn more about Docker on the official Docker page.

Learn how to install Docker on the official instructions page.

What is a container?

A container is a lightweight, stand-alone package that contains a piece of software that is bundled together with the entire environment that it needs to run. Containers are small compared to regular images and can run on any environment where Docker is set up. Moreover, you can run multiple containers on a single machine at the same time in isolation from each other.

Learn more about containers on the official Docker page.

Why use containers?

Consider a scenario where you need to deploy your application on another environment. Your application works on your local machine, but when you try to run it on a different environment, it breaks. You do some debugging and discover that you built your application with Python 3, but this new environment has only Python 2.7 installed. Although this issue is generally easy to fix, you don’t want your application to be missing dozens of version-specific dependencies. You can create a virtual machine specifically for testing your application, but VM images generally take up a huge amount of space and are slow to run.

To solve the problem, you can containerize your application by bundling it together with the entire environment that it needs to run. You can then run this container on any machine that is running Docker regardless of how that machine’s environment is set up. You can also run multiple containers on a single machine in isolation from one another so that two containers that have different versions of Python do not interfere with each other. Containers are quick to run compared to individual VMs, and they take up only a fraction of the memory of a single image.

Getting started

The fastest way to work through this guide is to clone the Git repository and use the projects that are provided inside:

git clone https://github.com/openliberty/guide-docker.git
cd guide-docker

The start directory contains the starting project that you will build upon.

The finish directory contains the finished project that you will build.

Building your application

Before you begin, build your application. To do this, navigate to the start directory and run the Maven install goal:

mvn install

Your pom.xml file is already configured to add your REST application to the defaultServer. But you can tweak this configuration or add your own for another server by updating the <execution/> element.

The install-apps goal copies the application into the specified directory of the specified server. In this case, the goal copies the rest.war file into the apps directory of the defaultServer server.

Learn more about this goal on the official Maven Liberty plug-in repository.

pom.xml

  1<?xml version='1.0' encoding='utf-8'?>
  2<project xmlns="http://maven.apache.org/POM/4.0.0"
  3xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4xsi:schemaLocation=
  5"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  6
  7    <modelVersion>4.0.0</modelVersion>
  8
  9    <groupId>io.openliberty.guides</groupId>
 10    <artifactId>rest</artifactId>
 11    <version>1.0-SNAPSHOT</version>
 12    <packaging>war</packaging>
 13
 14    <properties>
 15        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 16        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
 17        <maven.compiler.source>1.8</maven.compiler.source>
 18        <maven.compiler.target>1.8</maven.compiler.target>
 19        <app.name>LibertyProject</app.name>
 20        <testServerHttpPort>9080</testServerHttpPort>
 21        <testServerHttpsPort>9443</testServerHttpsPort>
 22        <warContext>${app.name}</warContext>
 23        <package.file>${project.build.directory}/${app.name}.zip</package.file>
 24        <packaging.type>usr</packaging.type>
 25    </properties>
 26
 27    <dependencyManagement>
 28        <dependencies>
 29            <dependency>
 30                <groupId>io.openliberty.features</groupId>
 31                <artifactId>features-bom</artifactId>
 32                <version>RELEASE</version>
 33                <type>pom</type>
 34                <scope>import</scope>
 35            </dependency>
 36        </dependencies>
 37    </dependencyManagement>
 38
 39    <dependencies>
 40        <dependency>
 41            <groupId>io.openliberty.features</groupId>
 42            <artifactId>jaxrs-2.1</artifactId>
 43            <type>esa</type>
 44            <scope>provided</scope>
 45        </dependency>
 46        <dependency>
 47            <groupId>io.openliberty.features</groupId>
 48            <artifactId>jsonp-1.1</artifactId>
 49            <type>esa</type>
 50            <scope>provided</scope>
 51        </dependency>
 52        <dependency>
 53            <groupId>junit</groupId>
 54            <artifactId>junit</artifactId>
 55            <version>4.12</version>
 56            <scope>test</scope>
 57        </dependency>
 58        <dependency>
 59            <groupId>org.apache.cxf</groupId>
 60            <artifactId>cxf-rt-rs-client</artifactId>
 61            <version>3.2.6</version>
 62            <scope>test</scope>
 63        </dependency>
 64        <dependency>
 65            <groupId>org.apache.cxf</groupId>
 66            <artifactId>cxf-rt-rs-extension-providers</artifactId>
 67            <version>3.2.6</version>
 68            <scope>test</scope>
 69        </dependency>
 70        <dependency>
 71            <groupId>org.glassfish</groupId>
 72            <artifactId>javax.json</artifactId>
 73            <version>1.0.4</version>
 74            <scope>test</scope>
 75        </dependency>
 76        <dependency>
 77            <groupId>io.openliberty.features</groupId>
 78            <artifactId>jaxrs-2.1</artifactId>
 79            <type>esa</type>
 80            <scope>provided</scope>
 81        </dependency>
 82        <dependency>
 83            <groupId>io.openliberty.features</groupId>
 84            <artifactId>jsonp-1.1</artifactId>
 85            <type>esa</type>
 86            <scope>provided</scope>
 87        </dependency>
 88        <!-- Support for JDK 9 and above -->
 89        <dependency>
 90            <groupId>javax.xml.bind</groupId>
 91            <artifactId>jaxb-api</artifactId>
 92            <version>2.3.1</version>
 93            <scope>test</scope>
 94        </dependency>
 95        <dependency>
 96            <groupId>com.sun.xml.bind</groupId>
 97            <artifactId>jaxb-core</artifactId>
 98            <version>2.3.0.1</version>
 99            <scope>test</scope>
100        </dependency>
101        <dependency>
102            <groupId>com.sun.xml.bind</groupId>
103            <artifactId>jaxb-impl</artifactId>
104            <version>2.3.2</version>
105            <scope>test</scope>
106        </dependency>
107        <dependency>
108            <groupId>javax.activation</groupId>
109            <artifactId>activation</artifactId>
110            <version>1.1.1</version>
111            <scope>test</scope>
112        </dependency>
113    </dependencies>
114
115    <build>
116        <plugins>
117            <plugin>
118                <groupId>org.apache.maven.plugins</groupId>
119                <artifactId>maven-war-plugin</artifactId>
120                <version>3.2.2</version>
121                <configuration>
122                    <failOnMissingWebXml>false</failOnMissingWebXml>
123                    <packagingExcludes>pom.xml</packagingExcludes>
124                </configuration>
125            </plugin>
126            <!-- Plugin to run unit tests -->
127            <plugin>
128                <groupId>org.apache.maven.plugins</groupId>
129                <artifactId>maven-surefire-plugin</artifactId>
130                <version>2.18.1</version>
131                <executions>
132                    <execution>
133                        <phase>test</phase>
134                        <id>default-test</id>
135                        <configuration>
136                            <excludes>
137                                <exclude>**/it/**</exclude>
138                            </excludes>
139                            <reportsDirectory>
140                                ${project.build.directory}/test-reports/unit
141                            </reportsDirectory>
142                        </configuration>
143                    </execution>
144                </executions>
145            </plugin>
146            <!-- Enable liberty-maven plugin -->
147            <plugin>
148                <groupId>net.wasdev.wlp.maven.plugins</groupId>
149                <artifactId>liberty-maven-plugin</artifactId>
150                <version>2.6.1</version>
151                <configuration>
152                    <assemblyArtifact>
153                         <groupId>io.openliberty</groupId>
154                         <artifactId>openliberty-runtime</artifactId>
155                         <version>RELEASE</version>
156                        <type>zip</type>
157                    </assemblyArtifact>
158                    <configFile>src/main/liberty/config/server.xml</configFile>
159                    <packageFile>${package.file}</packageFile>
160                    <include>${packaging.type}</include>
161                    <bootstrapProperties>
162                        <default.http.port>${testServerHttpPort}</default.http.port>
163                        <default.https.port>${testServerHttpsPort}</default.https.port>
164                        <app.context.root>${warContext}</app.context.root>
165                    </bootstrapProperties>
166                </configuration>
167                <executions>
168                    <!-- Install the OL runtime -->
169                    <execution>
170                        <id>install-liberty</id>
171                        <phase>prepare-package</phase>
172                        <goals>
173                            <goal>install-server</goal>
174                        </goals>
175                    </execution>
176                    <!-- Create defaultServer -->
177                    <execution>
178                        <id>create-server</id>
179                        <phase>prepare-package</phase>
180                        <goals>
181                            <goal>create-server</goal>
182                        </goals>
183                    </execution>
184                    <!-- Install the app into the apps/ directory of defaultServer -->
185                    <execution>
186                        <id>install-app</id>
187                        <phase>package</phase>
188                        <goals>
189                            <goal>install-apps</goal>
190                        </goals>
191                        <configuration>
192                            <appsDirectory>apps</appsDirectory>
193                            <stripVersion>true</stripVersion>
194                            <installAppPackages>project</installAppPackages>
195                        </configuration>
196                    </execution>
197                    <!-- Test start and stop server -->
198                    <execution>
199                        <id>start-server</id>
200                        <phase>pre-integration-test</phase>
201                        <goals>
202                            <goal>test-start-server</goal>
203                        </goals>
204                    </execution>
205                    <execution>
206                        <id>stop-server</id>
207                        <phase>post-integration-test</phase>
208                        <goals>
209                            <goal>test-stop-server</goal>
210                        </goals>
211                    </execution>
212                </executions>
213            </plugin>
214            <!-- Plugin to run functional tests -->
215            <plugin>
216                <groupId>org.apache.maven.plugins</groupId>
217                <artifactId>maven-failsafe-plugin</artifactId>
218                <version>2.18.1</version>
219                <executions>
220                    <execution>
221                        <phase>integration-test</phase>
222                        <id>integration-test</id>
223                        <goals>
224                            <goal>integration-test</goal>
225                        </goals>
226                        <configuration>
227                            <includes>
228                                <include>**/it/**</include>
229                            </includes>
230                            <systemPropertyVariables>
231                                <liberty.test.port>
232                                    ${testServerHttpPort}
233                                </liberty.test.port>
234                                <war.name>${warContext}</war.name>
235                            </systemPropertyVariables>
236                        </configuration>
237                    </execution>
238                    <execution>
239                        <id>verify-results</id>
240                        <goals>
241                            <goal>verify</goal>
242                        </goals>
243                    </execution>
244                </executions>
245                <configuration>
246                    <summaryFile>
247                        ${project.build.directory}/test-reports/it/failsafe-summary.xml
248                    </summaryFile>
249                    <reportsDirectory>
250                        ${project.build.directory}/test-reports/it
251                    </reportsDirectory>
252                </configuration>
253            </plugin>
254        </plugins>
255    </build>
256</project>

Creating the Dockerfile

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.

Navigate to the start directory to begin.

Create the Dockerfile.
Dockerfile

The FROM instruction initializes a new build stage and indicates the parent image from which your image is built. If you don’t need a parent image, then use FROM scratch, which makes your image a base image.

In this case, you’re using the openliberty/open-liberty:javaee8 image as your parent image, which comes with the latest Open Liberty runtime.

The RUN instruction executes various shell commands in a new layer on top of the current image. In this case, you create a symlink between the /opt/ol/wlp/usr/servers directory and the /servers directory. This way, you can mount your servers more easily because you don’t need to use long path names. Note that since the Open Liberty Docker image runs by default with user 1001 (which is a non-root user), you must temporarily switch to the root user to create the symlink. This is done by using the USER instruction.

The ENTRYPOINT and CMD instructions define a default command that executes when the image runs as a container. These two instructions function the same way, except that the CMD instruction is overridden with any arguments that are passed at the end of the docker run command. In contrast, the ENTRYPOINT instruction requires the --entrypoint flag to be overridden. In this case, you use the ENTRYPOINT instruction to start an Open Liberty server and the CMD instruction to indicate which server to start. Because the CMD instruction is easily overridden, starting any server is convenient.

For a complete list of available instructions, see the Docker documentation.

Dockerfile

 1# Start with OL runtime.
 2FROM open-liberty
 3
 4USER root
 5# Symlink servers directory for easier mounts.
 6RUN ln -s /opt/ol/wlp/usr/servers /servers
 7USER 1001
 8
 9# Run the server script and start the defaultServer by default.
10ENTRYPOINT ["/opt/ol/wlp/bin/server", "run"]
11CMD ["defaultServer"]

Optional: Writing a .dockerignore file

When Docker runs a build, it sends all of the files and directories that are located in the same directory as the Dockerfile to its build context, making them available for use in instructions like ADD and COPY. To make image building faster, add all files and directories that aren’t necessary for building your image to a .dockerignore file. This excludes them from the build context.

A .dockerignore file is available to you in the start directory. This file includes the src directory, the pom.xml file, and some system files. Feel free to add anything else that you want to exclude.

.dockerignore

1.DS_Store
2src/
3pom.xml

pom.xml

  1<?xml version='1.0' encoding='utf-8'?>
  2<project xmlns="http://maven.apache.org/POM/4.0.0"
  3xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4xsi:schemaLocation=
  5"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  6
  7    <modelVersion>4.0.0</modelVersion>
  8
  9    <groupId>io.openliberty.guides</groupId>
 10    <artifactId>rest</artifactId>
 11    <version>1.0-SNAPSHOT</version>
 12    <packaging>war</packaging>
 13
 14    <properties>
 15        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 16        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
 17        <maven.compiler.source>1.8</maven.compiler.source>
 18        <maven.compiler.target>1.8</maven.compiler.target>
 19        <app.name>LibertyProject</app.name>
 20        <testServerHttpPort>9080</testServerHttpPort>
 21        <testServerHttpsPort>9443</testServerHttpsPort>
 22        <warContext>${app.name}</warContext>
 23        <package.file>${project.build.directory}/${app.name}.zip</package.file>
 24        <packaging.type>usr</packaging.type>
 25    </properties>
 26
 27    <dependencyManagement>
 28        <dependencies>
 29            <dependency>
 30                <groupId>io.openliberty.features</groupId>
 31                <artifactId>features-bom</artifactId>
 32                <version>RELEASE</version>
 33                <type>pom</type>
 34                <scope>import</scope>
 35            </dependency>
 36        </dependencies>
 37    </dependencyManagement>
 38
 39    <dependencies>
 40        <dependency>
 41            <groupId>io.openliberty.features</groupId>
 42            <artifactId>jaxrs-2.1</artifactId>
 43            <type>esa</type>
 44            <scope>provided</scope>
 45        </dependency>
 46        <dependency>
 47            <groupId>io.openliberty.features</groupId>
 48            <artifactId>jsonp-1.1</artifactId>
 49            <type>esa</type>
 50            <scope>provided</scope>
 51        </dependency>
 52        <dependency>
 53            <groupId>junit</groupId>
 54            <artifactId>junit</artifactId>
 55            <version>4.12</version>
 56            <scope>test</scope>
 57        </dependency>
 58        <dependency>
 59            <groupId>org.apache.cxf</groupId>
 60            <artifactId>cxf-rt-rs-client</artifactId>
 61            <version>3.2.6</version>
 62            <scope>test</scope>
 63        </dependency>
 64        <dependency>
 65            <groupId>org.apache.cxf</groupId>
 66            <artifactId>cxf-rt-rs-extension-providers</artifactId>
 67            <version>3.2.6</version>
 68            <scope>test</scope>
 69        </dependency>
 70        <dependency>
 71            <groupId>org.glassfish</groupId>
 72            <artifactId>javax.json</artifactId>
 73            <version>1.0.4</version>
 74            <scope>test</scope>
 75        </dependency>
 76        <dependency>
 77            <groupId>io.openliberty.features</groupId>
 78            <artifactId>jaxrs-2.1</artifactId>
 79            <type>esa</type>
 80            <scope>provided</scope>
 81        </dependency>
 82        <dependency>
 83            <groupId>io.openliberty.features</groupId>
 84            <artifactId>jsonp-1.1</artifactId>
 85            <type>esa</type>
 86            <scope>provided</scope>
 87        </dependency>
 88        <!-- Support for JDK 9 and above -->
 89        <dependency>
 90            <groupId>javax.xml.bind</groupId>
 91            <artifactId>jaxb-api</artifactId>
 92            <version>2.3.1</version>
 93            <scope>test</scope>
 94        </dependency>
 95        <dependency>
 96            <groupId>com.sun.xml.bind</groupId>
 97            <artifactId>jaxb-core</artifactId>
 98            <version>2.3.0.1</version>
 99            <scope>test</scope>
100        </dependency>
101        <dependency>
102            <groupId>com.sun.xml.bind</groupId>
103            <artifactId>jaxb-impl</artifactId>
104            <version>2.3.2</version>
105            <scope>test</scope>
106        </dependency>
107        <dependency>
108            <groupId>javax.activation</groupId>
109            <artifactId>activation</artifactId>
110            <version>1.1.1</version>
111            <scope>test</scope>
112        </dependency>
113    </dependencies>
114
115    <build>
116        <plugins>
117            <plugin>
118                <groupId>org.apache.maven.plugins</groupId>
119                <artifactId>maven-war-plugin</artifactId>
120                <version>3.2.2</version>
121                <configuration>
122                    <failOnMissingWebXml>false</failOnMissingWebXml>
123                    <packagingExcludes>pom.xml</packagingExcludes>
124                </configuration>
125            </plugin>
126            <!-- Plugin to run unit tests -->
127            <plugin>
128                <groupId>org.apache.maven.plugins</groupId>
129                <artifactId>maven-surefire-plugin</artifactId>
130                <version>2.18.1</version>
131                <executions>
132                    <execution>
133                        <phase>test</phase>
134                        <id>default-test</id>
135                        <configuration>
136                            <excludes>
137                                <exclude>**/it/**</exclude>
138                            </excludes>
139                            <reportsDirectory>
140                                ${project.build.directory}/test-reports/unit
141                            </reportsDirectory>
142                        </configuration>
143                    </execution>
144                </executions>
145            </plugin>
146            <!-- Enable liberty-maven plugin -->
147            <plugin>
148                <groupId>net.wasdev.wlp.maven.plugins</groupId>
149                <artifactId>liberty-maven-plugin</artifactId>
150                <version>2.6.1</version>
151                <configuration>
152                    <assemblyArtifact>
153                         <groupId>io.openliberty</groupId>
154                         <artifactId>openliberty-runtime</artifactId>
155                         <version>RELEASE</version>
156                        <type>zip</type>
157                    </assemblyArtifact>
158                    <configFile>src/main/liberty/config/server.xml</configFile>
159                    <packageFile>${package.file}</packageFile>
160                    <include>${packaging.type}</include>
161                    <bootstrapProperties>
162                        <default.http.port>${testServerHttpPort}</default.http.port>
163                        <default.https.port>${testServerHttpsPort}</default.https.port>
164                        <app.context.root>${warContext}</app.context.root>
165                    </bootstrapProperties>
166                </configuration>
167                <executions>
168                    <!-- Install the OL runtime -->
169                    <execution>
170                        <id>install-liberty</id>
171                        <phase>prepare-package</phase>
172                        <goals>
173                            <goal>install-server</goal>
174                        </goals>
175                    </execution>
176                    <!-- Create defaultServer -->
177                    <execution>
178                        <id>create-server</id>
179                        <phase>prepare-package</phase>
180                        <goals>
181                            <goal>create-server</goal>
182                        </goals>
183                    </execution>
184                    <!-- Install the app into the apps/ directory of defaultServer -->
185                    <execution>
186                        <id>install-app</id>
187                        <phase>package</phase>
188                        <goals>
189                            <goal>install-apps</goal>
190                        </goals>
191                        <configuration>
192                            <appsDirectory>apps</appsDirectory>
193                            <stripVersion>true</stripVersion>
194                            <installAppPackages>project</installAppPackages>
195                        </configuration>
196                    </execution>
197                    <!-- Test start and stop server -->
198                    <execution>
199                        <id>start-server</id>
200                        <phase>pre-integration-test</phase>
201                        <goals>
202                            <goal>test-start-server</goal>
203                        </goals>
204                    </execution>
205                    <execution>
206                        <id>stop-server</id>
207                        <phase>post-integration-test</phase>
208                        <goals>
209                            <goal>test-stop-server</goal>
210                        </goals>
211                    </execution>
212                </executions>
213            </plugin>
214            <!-- Plugin to run functional tests -->
215            <plugin>
216                <groupId>org.apache.maven.plugins</groupId>
217                <artifactId>maven-failsafe-plugin</artifactId>
218                <version>2.18.1</version>
219                <executions>
220                    <execution>
221                        <phase>integration-test</phase>
222                        <id>integration-test</id>
223                        <goals>
224                            <goal>integration-test</goal>
225                        </goals>
226                        <configuration>
227                            <includes>
228                                <include>**/it/**</include>
229                            </includes>
230                            <systemPropertyVariables>
231                                <liberty.test.port>
232                                    ${testServerHttpPort}
233                                </liberty.test.port>
234                                <war.name>${warContext}</war.name>
235                            </systemPropertyVariables>
236                        </configuration>
237                    </execution>
238                    <execution>
239                        <id>verify-results</id>
240                        <goals>
241                            <goal>verify</goal>
242                        </goals>
243                    </execution>
244                </executions>
245                <configuration>
246                    <summaryFile>
247                        ${project.build.directory}/test-reports/it/failsafe-summary.xml
248                    </summaryFile>
249                    <reportsDirectory>
250                        ${project.build.directory}/test-reports/it
251                    </reportsDirectory>
252                </configuration>
253            </plugin>
254        </plugins>
255    </build>
256</project>

Building the image

To build your image, make sure that your Docker daemon is running and execute the Docker build command from the command line. If you execute your build from the same directory as your Dockerfile, you can use the period character (.) notation to specify the location for the build context. Otherwise, use the -f flag to point to your Dockerfile:

docker build -t ol-runtime .

Use the -t flag to give the image an optional name. In this case, ol-runtime is the name of your image.

The first build usually takes much longer to complete than subsequent builds because Docker needs to download all dependencies that your image requires, including the parent image.

If your build runs successfully, you’ll see an output similar to the following:

Sending build context to Docker daemon  148.9MB
Step 1/4 : FROM open-liberty
latest: Pulling from library/open-liberty
7b8b6451c85f: Pull complete
ab4d1096d9ba: Pull complete
e6797d1788ac: Pull complete
e25c5c290bde: Pull complete
27b2fbbc72b1: Pull complete
aa35dfd74487: Pull complete
1ade56d64661: Pull complete
3493ef172f60: Pull complete
cd6dff6d245d: Pull complete
82450af30afc: Pull complete
Digest: sha256:b7576e4278030537765d4185c4641ee2769194226263f979109ed4fa0e1aa4e4
Status: Downloaded newer image for open-liberty:latest
 ---> 45d4b67ace5b
Step 2/4 : RUN ln -s /opt/ol/wlp/usr/servers /servers
 ---> Running in cbeb275770ab
Removing intermediate container cbeb275770ab
 ---> 937183f8460b
Step 3/4 : ENTRYPOINT ["/opt/ol/wlp/bin/server", "run"]
 ---> Running in 856a4bdec82b
Removing intermediate container 856a4bdec82b
 ---> 6cf732381877
Step 4/4 : CMD ["defaultServer"]
 ---> Running in 1a543a9e37d8
Removing intermediate container 1a543a9e37d8
 ---> 8fdcad065d25
Successfully built 8fdcad065d25
Successfully tagged ol-runtime:latest

Each step of the build has a unique ID, which represents the ID of an intermediate image. For example, step 2 has the ID 937183f8460b, and step 4 has the ID 8fdcad065d25, which is also the ID of the final image. During the first build of your image, Docker caches every new layer as a separate image and reuses them for future builds for layers that didn’t change. For example, if you run the build again, Docker reuses the images that it cached for steps 2 - 4. However, if you make a change in your Dockerfile, Docker would need to rebuild the subsequent layer since this layer also changed.

However, you can also completely disable the caching of intermediate layers by running the build with the --no-cache=true flag:

docker build -t ol-runtime --no-cache=true .

Learn more about the image build process on the Docker documentation.

Running your application in Docker container

Now that your image is built, execute the Docker run command with the absolute path to this guide:

docker run -d --name rest-app -p 9080:9080 -p 9443:9443 -v <absolute path to guide>/start/target/liberty/wlp/usr/servers:/servers ol-runtime

Use the -u flag to override the default user within the container to match the user id on your host machine. This is to ensure the default user has correct permissions to the server directory.

docker run -d --name rest-app -p 9080:9080 -p 9443:9443 -v <absolute path to guide>/start/target/liberty/wlp/usr/servers:/servers -u `id -u` ol-runtime

Alternatively, you can also execute the run command to mount a single server instead of the whole servers directory:

docker run -d --name rest-app -p 9080:9080 -p 9443:9443 -v <absolute path to guide>/start/target/liberty/wlp/usr/servers/defaultServer:/servers/defaultServer ol-runtime
docker run -d --name rest-app -p 9080:9080 -p 9443:9443 -v <absolute path to guide>/start/target/liberty/wlp/usr/servers/defaultServer:/servers/defaultServer -u `id -u` ol-runtime

Let’s break down the flags:

FlagDescription

-d

This flag tells Docker to run the container in the background. Without this flag, Docker runs the container in the foreground.

--name

This flag specifies a name for the container.

-p

This flag maps the container ports to the host ports.

-v

This flag mounts a directory or file to the file system of the container.

You can pass in an optional server name at the end of the run command to override the defaultServer server in the CMD instruction. For example, if your servers directory also contains a server called testServer, then it can be started as shown in the following example:

docker run -d --name rest-app -p 9080:9080 -p 9443:9443 -v <absolute path to guide>/start/target/liberty/wlp/usr/servers:/servers ol-runtime testServer

Learn more about running containers on the official Docker page

Testing the container

Before you access your application from the browser, run the docker ps command from the command line to make sure that your container is running and didn’t crash:

$ docker ps
CONTAINER ID        IMAGE               CREATED             STATUS              NAMES
2720cea71700        ol-runtime          2 seconds ago       Up 1 second         rest-app

To view a full list of all available containers, run the docker ps -a command from the command line.

If your container is running without problems, point your browser to http://localhost:9080/LibertyProject/System/properties, where you can see a JSON file that contains the system properties of the JVM in your container.

Update the PropertiesResource class.
src/main/java/io/openliberty/guides/rest/PropertiesResource.java

Change the endpoint of your application from properties to properties-new by changing the @Path annotation to "properties-new".

To see these changes reflected in the container, run the following command from the command line to rebuild your application and point your browser to http://localhost:9080/LibertyProject/System/properties-new.

mvn package

You see the same JSON file that you saw previously.

To stop your container, run the following command from the command line.

docker stop rest-app

If a problem occurs and your container exits prematurely, the container won’t appear in the container list that the docker ps command displays. Instead, your container appears with an Exited status when you run the docker ps -a command. Run the docker logs rest-app command to view the container logs for any potential problems and double-check that your Dockerfile is correct. When you find the cause of the issue, remove the faulty container with the docker rm rest-app command, rebuild your image, and start the container again.

PropertiesResource.java

 1package io.openliberty.guides.rest;
 2
 3import java.util.Properties;
 4import java.util.Map;
 5
 6import javax.ws.rs.Path;
 7import javax.ws.rs.core.MediaType;
 8import javax.ws.rs.GET;
 9import javax.ws.rs.Consumes;
10import javax.ws.rs.Produces;
11
12import javax.json.JsonObject;
13import javax.json.JsonObjectBuilder;
14import javax.json.JsonArray;
15import javax.json.Json;
16import javax.json.JsonNumber;
17
18@Path("properties")
19public class PropertiesResource {
20
21    @GET
22    @Produces(MediaType.APPLICATION_JSON)
23    public JsonObject getProperties() {
24
25        JsonObjectBuilder builder = Json.createObjectBuilder();
26
27        System.getProperties()
28              .entrySet()
29              .stream()
30              .forEach(entry -> builder.add((String)entry.getKey(),
31                                            (String)entry.getValue()));
32
33       return builder.build();
34    }
35}

Great work! You’re done!

You have learned how to set up, run, iteractively develop a simple REST application in a container with Open Liberty and Docker. Whenever you make changes to your application code, they will now reflect automatically on the Open Liberty server running in a container when the application rebuilds.

Guide Attribution

Using Docker containers to develop microservices by Open Liberty is licensed under CC BY-ND 4.0

Copied to clipboard
Copy code block
Copy file contents

Prerequisites:

Nice work! Where to next?

What did you think of this guide?

Extreme Dislike Dislike Like Extreme Like

What could make this guide better?

Raise an issue to share feedback

Create a pull request to contribute to this guide

Need help?

Ask a question on Stack Overflow

Like Open Liberty? Star our repo on GitHub.

Star