Russell Bateman
May 2021
last update:
I installed Docker via the Software Manager on Linux Mint. I'm doing this to create a container in which a lone web application, for generating HL7v3 (CDA) documents, will run taking POST requests from HTTP clients.
I have another "Docker experience" packaging up a custom NAR for use in an Apache NiFi container Apache NiFi and Docker notes.
~/dev/hl7v3-generator/src/main/docker $ cat Dockerfile
...produces:
FROM tomcat:jdk8-openjdk-slim
LABEL maintainer="[email protected]"
ADD hl7v3-generator.war /usr/local/tomcat/webapps
EXPOSE 8080
CMD [ "catalina.sh", "run" ]
Keyword | Explanation |
---|---|
1. FROM | Let's use the Tomcat container that is the most widely downloaded. Of that container, let's use specifically jdk8-openjdk-slim because it's one of the smaller containers yet has everthing we need. |
2. LABEL | Always have a plan to seek out and punish the guilty! |
3. ADD | Make certain the hl7v3-generator WAR is in our local subdirectory alongside this Dockerfile. |
4. EXPOSE | This is more documentary than effectual, but we'll add it. It means basically that port 8080 inside our container will be the one Tomcat listens on. The way this really happens though is via the -p option on the docker run command. |
5. CMD | /usr/local/tomcat/bin/catalina.sh is how Tomcat gets launched; don't really know what "run" does: it's just always there. |
The first time we ran Docker's hello-world to prove Docker installed correctly, we discovered that we had never inducted ourselves into the docker group. We were denied permission to run docker. We fix that, but then we have to log out, then back in. (If I do that, I'm going to have to set up all my workspaces all over again, so I'll just pick a console and re-log in as myself which will implement the group change.)
Though we used a browser pointed to Docker Hub to find our Tomcat Docker container, let's take a look from the command line—that's always more pleasant.
~ $ sudo usermod -aG docker russ ~ $ su - russ Password: ~ $ cd ~/dev/hl7v3-generator/src/main/docker ~/dev/hl7v3-generator/src/main/docker $ docker search tomcat NAME DESCRIPTION STARS OFFICIAL AUTOMATED tomcat Apache Tomcat is an open source implementati... 3036 [OK] tomee Apache TomEE is an all-Apache Java EE certif... 87 [OK] dordoka/tomcat Ubuntu 14.04, Oracle JDK 8 and Tomcat 8 base... 57 [OK] bitnami/tomcat Bitnami Tomcat Docker Image 37 [OK] kubeguide/tomcat-app Tomcat image for Chapter 1 3 consol/tomcat-7.0 Tomcat 7.0.57, 8080, "admin/admin" 18 [OK] cloudesire/tomcat Tomcat server, 6/7/8 15 [OK] aallam/tomcat-mysql Debian, Oracle JDK, Tomcat & MySQL 13 [OK] arm32v7/tomcat Apache Tomcat is an open source implementati... 11 rightctrl/tomcat CentOS , Oracle Java, tomcat application ssl... 6 [OK] unidata/tomcat-docker Security-hardened Tomcat Docker container. 5 [OK] arm64v8/tomcat Apache Tomcat is an open source implementati... 3 fabric8/tomcat-8 Fabric8 Tomcat 8 Image 2 [OK] jelastic/tomcat An image of the Tomcat Java application serv... 2 cfje/tomcat-resource Tomcat Concourse Resource 2 oobsri/tomcat8 Testing CI Jobs with different names. 2 amd64/tomcat Apache Tomcat is an open source implementati... 2 picoded/tomcat7 tomcat7 with jre8 and MANAGER_USER / MANAGER... 1 [OK] camptocamp/tomcat-logback Docker image for tomcat with logback integra... 1 [OK] chenyufeng/tomcat-centos tomcat基于centos6的镜像 1 [OK] ppc64le/tomcat Apache Tomcat is an open source implementati... 1 99taxis/tomcat7 Tomcat7 1 [OK] s390x/tomcat Apache Tomcat is an open source implementati... 0 softwareplant/tomcat Tomcat images for jira-cloud testing 0 [OK] secoresearch/tomcat-varnish Tomcat and Varnish 5.0 0 [OK]
We're in gear now...
From Dockerfile above, let's build our new image. It's a copy of the image from the standard Tomcat Docker container at Docker Hub augmented with our servlet, hl7v3-generator.
Note that creating a symbolic link to the WAR file in the Docker build directory isn't adequate. It must be (at least a copy of) the file. I'm sure there's a clever way around this, but we're in a hurry to get this working.
~/dev/hl7v3-generator/src/main/docker $ cp ../../../target/hl7v3-generator.war ~/dev/hl7v3-generator/src/main/docker $ ll total 12 drwxrwxr-x 2 russ russ 4096 May 27 14:06 . drwxrwxr-x 6 russ russ 4096 May 27 12:40 .. -rw-rw-r-- 1 russ russ 184 May 27 13:57 Dockerfile lrwxrwxrwx 1 russ russ 32 May 27 14:06 hl7v3-generator.war -> ../../../target/hl7v3-generator.war ~/dev/hl7v3-generator/src/main/docker $ docker build -t hl7v3-generator . Sending build context to Docker daemon 80.41MB Step 1/5 : FROM tomcat:jdk8-openjdk-slim ---> f1acc0fc1a93 Step 2/5 : LABEL maintainer="[email protected]" ---> Using cache ---> a6a71000a3c5 Step 3/5 : ADD hl7v3-generator.war /usr/local/tomcat/webapps ---> 4d1bd0381328 Step 4/5 : EXPOSE 8080 ---> Running in 3b7f868e0351 Removing intermediate container 3b7f868e0351 ---> 10da1c9e37d7 Step 5/5 : CMD [ "catalina.sh", "run" ] ---> Running in 02af5504f4c4 Removing intermediate container 02af5504f4c4 ---> 46c97152277e Successfully built 46c97152277e Successfully tagged hl7v3-generator:latest
Notice that this launches the servlet—the proof is the bit in bold below.
~/dev/hl7v3-generator/src/main/docker $ docker run -p 9999:8080 hl7v3-generator 27-May-2021 20:17:03.327 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version name: Apache Tomcat/9.0.46 27-May-2021 20:17:03.328 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built: May 8 2021 17:35:52 UTC 27-May-2021 20:17:03.328 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version number: 9.0.46.0 27-May-2021 20:17:03.328 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name: Linux 27-May-2021 20:17:03.328 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version: 5.4.0-73-generic 27-May-2021 20:17:03.328 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture: amd64 27-May-2021 20:17:03.328 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home: /usr/local/openjdk-8/jre 27-May-2021 20:17:03.328 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version: 1.8.0_292-b10 27-May-2021 20:17:03.329 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor: Oracle Corporation 27-May-2021 20:17:03.329 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE: /usr/local/tomcat 27-May-2021 20:17:03.329 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME: /usr/local/tomcat 27-May-2021 20:17:03.329 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties 27-May-2021 20:17:03.329 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager 27-May-2021 20:17:03.329 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djdk.tls.ephemeralDHKeySize=2048 27-May-2021 20:17:03.329 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.protocol.handler.pkgs=org.apache.catalina.webresources 27-May-2021 20:17:03.329 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 27-May-2021 20:17:03.330 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dignore.endorsed.dirs= 27-May-2021 20:17:03.330 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=/usr/local/tomcat 27-May-2021 20:17:03.330 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=/usr/local/tomcat 27-May-2021 20:17:03.330 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=/usr/local/tomcat/temp 27-May-2021 20:17:03.332 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent Loaded Apache Tomcat Native library [1.2.28] using APR version [1.6.5]. 27-May-2021 20:17:03.332 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true]. 27-May-2021 20:17:03.332 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent APR/OpenSSL configuration: useAprConnector [false], useOpenSSL [true] 27-May-2021 20:17:03.334 INFO [main] org.apache.catalina.core.AprLifecycleListener.initializeSSL OpenSSL successfully initialized [OpenSSL 1.1.1d 10 Sep 2019] 27-May-2021 20:17:03.525 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"] 27-May-2021 20:17:03.540 INFO [main] org.apache.catalina.startup.Catalina.load Server initialization in [323] milliseconds 27-May-2021 20:17:03.557 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina] 27-May-2021 20:17:03.557 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/9.0.46] 27-May-2021 20:17:03.572 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/usr/local/tomcat/webapps/hl7v3-generator.war] 27-May-2021 20:17:06.740 INFO [main] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time. SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/usr/local/tomcat/webapps/hl7v3-generator/WEB-INF/lib/slf4j-simple-1.7.7.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: Found binding in [jar:file:/usr/local/tomcat/webapps/hl7v3-generator/WEB-INF/lib/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation. SLF4J: Actual binding is of type [org.slf4j.impl.SimpleLoggerFactory] [main] INFO com.windofkeltia.servlet.RestletInitializer - ############################################################# [main] INFO com.windofkeltia.servlet.RestletInitializer - Initializing hl7v3-generator application context... [main] INFO com.windofkeltia.servlet.RestletInitializer - The HL7v3 Generator servlet is up. Manifest-Version: 1.0 Implementation-Title: hl7v3-generator Implementation-Version: 3.0.0 Specification-Title: hl7v3-generator Implementation-Vendor-Id: com.windofkeltia.mdht Build-Time: 2021-05-26T11:34:56Z Created-By: Apache Maven 3.6.3 Build-JDK: 11.0.10 Specification-Version: 3.0 Generates documents for CCDA, QRDA I or QRDA III from IXML. Copyright (c) 2018-2021 by Etretat Logiciels, LLC. Proprietary and confidential. All rights reserved. 27-May-2021 20:17:06.767 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/usr/local/tomcat/webapps/hl7v3-generator.war] has finished in [3,194] ms 27-May-2021 20:17:06.769 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"] 27-May-2021 20:17:06.773 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [3233] milliseconds ^C 27-May-2021 20:22:09.023 INFO [Thread-4] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["http-nio-8080"] 27-May-2021 20:22:09.029 INFO [Thread-4] org.apache.catalina.core.StandardService.stopInternal Stopping service [Catalina] [Thread-4] INFO com.windofkeltia.servlet.RestletInitializer - Discarded hl7v3-generator application context! 27-May-2021 20:22:09.035 INFO [Thread-4] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["http-nio-8080"] 27-May-2021 20:22:09.076 INFO [Thread-4] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler ["http-nio-8080"]
Let's run it in the background with the -d option instead (like grown-ups)...
~/dev/hl7v3-generator/src/main/docker $ docker run -d -p 9999:8080 hl7v3-generator e1fd372624037302ba96364b476a6e8062399052c6534fd0517b87c3799addc6 ~/dev/hl7v3-generator/src/main/docker $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e1fd37262403 hl7v3-generator "catalina.sh run" About a minute ago Up About a minute 8080/tcp, 0.0.0.0:80->9999/tcp relaxed_beaver ~/dev/hl7v3-generator/src/main/docker $ docker inspect e1fd372624037302ba96364b476a6e8062399052c6534fd0517b87c3799addc6 [ { "Id": "e1fd372624037302ba96364b476a6e8062399052c6534fd0517b87c3799addc6", "Created": "2021-05-27T20:23:51.541855236Z", "Path": "catalina.sh", "Args": [ "run" ], . . . . . . "Networks": { "bridge": { "IPAMConfig": null, "Links": null, "Aliases": null, "NetworkID": "251a9fa5fd324147d105b6a12fc8b652b6c199b201005f4875569bcb713f123c", "EndpointID": "85fc7643288b3934735543c55d61cdcc79d2747d04f8d35a872f31365ee5a456", "Gateway": "172.17.0.1", "IPAddress": "172.17.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "02:42:ac:11:00:02", "DriverOpts": null } } } } ] ~/dev/hl7v3-generator/src/main/docker $ docker stop e1fd37262403 e1fd37262403 ~/dev/hl7v3-generator/src/main/docker $ docker rm e1fd37262403 e1fd37262403
We stop Docker and removed the image from Docker's list to show ourselves how Docker is (tediously) managed. Then, let's run it again and check in practical ways to see if hl7v3-generator is healthy.
~/dev/hl7v3-generator/src/main/docker $ docker run -d -p 9999:8080 hl7v3-generator 8cddb5e484a00f7370090001bdc20ceee8359f080b3190b7603e651f01aabbbb
Let's fail in order to show how not to do it. These failures are because what curl is in essence asked to do is access Tomcat's splash page, but we've never set that up to work, so it fails. I say this because, on the face of it, it kind of looks like what we've done isn't working, but we need to be careful about jumping to conclusions.
What are the two different commands here?
The first one is us trying to reach Tomcat in the Docker container directly. We told Docker we want Tomcat inside the container to run on its default port which is 8080. The second one is us reaching it via the port mapped from our host's port 9999 inside to the container's port 8080.
~/dev/hl7v3-generator/src/main/docker $ curl 172.17.0.2:8080 <!doctype html><html lang="en"><head><title>HTTP Status 404—Not Found</title>... ~/dev/hl7v3-generator/src/main/docker $ curl localhost:9999 -# | head <!doctype html><html lang="en"><head><title>HTTP Status 404—Not Found</title>...
Conversely, if we ask hl7v3-generator about its state, status and other manifest particulars, it should work if it's up. Of course, the only other thing we can do with hl7v3-generator is POST it an IXML document (an input document to the generator), which isn't part of what we care about here.
~/dev/hl7v3-generator/src/main/docker $ curl 172.17.0.2:8080/hl7v3-generator -# | head { "status" : "The HL7v3 Generator servlet is up.", "manifest" : " Manifest-Version: 1.0 Implementation-Title: hl7v3-generator Implementation-Version: 3.0.0 Specification-Title: hl7v3-generator Implementation-Vendor-Id: com.windofkeltia.mdht Build-Time: 2021-05-26T11:34:56Z ~/dev/hl7v3-generator/src/main/docker $ curl localhost:9999/hl7v3-generator -# | head { "status" : "The HL7v3 Generator servlet is up.", "manifest" : " Manifest-Version: 1.0 Implementation-Title: hl7v3-generator Implementation-Version: 3.0.0 Specification-Title: hl7v3-generator Implementation-Vendor-Id: com.windofkeltia.mdht Build-Time: 2021-05-26T11:34:56Z
The output above demonstrates clearly that we are up and running on a successful container. 95% of the time this took was refreshing our Docker memories and doing this write-up.
Here are some extra notes...
Assumes, as I'm going to do, that you put your image into a tar file to make it very convenient to distribute.
~/dev/hl7v3-generator $ ll *.tar -rw------- 1 russ russ 335291904 Feb 16 15:53 hl7v3-generator.tar ~/dev/hl7v3-generator $ docker load --input hl7v3-generator.tar 7d0ebbe3f5d2: Loading layer [==================================================>] 83.88MB/83.88MB 7da834c1ebd3: Loading layer [==================================================>] 5.177MB/5.177MB aaecf84c9a25: Loading layer [==================================================>] 3.584kB/3.584kB dbc38e354e15: Loading layer [==================================================>] 211MB/211MB fa1218e69a17: Loading layer [==================================================>] 3.072kB/3.072kB 903e73c9f59a: Loading layer [==================================================>] 20.91MB/20.91MB 6d95f0a50001: Loading layer [==================================================>] 2.048kB/2.048kB db8daaa4113e: Loading layer [==================================================>] 14.3MB/14.3MB Loaded image: hl7v3-generator:master.official ~/dev/hl7v3-generator $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE hl7v3-generator master.official 63d6255b17e7 7 days ago 330MB
Done. Now you can run it, but to make later steps easier, let's give it a name:
$ docker run -d --name hl7v3-generator -p 6666:8080 hl7v3-generator:master.official 8ddabb0621accddc8c3c9a932821d7adb139d42a55708d7f3677a23914c2c828
This is a little off-topic, but it's a great addition illustrating the flexibility of the Docker run command. In this case, it happens that the Tomcat 9 Docker image we used is set up to accept environment variables to configure Tomcat rather than using bin/catalina.sh, /etc/systemd/system/tomcat.services, etc.
Modify the Docker run command as shown here:
$ docker run -d --name hl7v3-generator -e CATALINA_OPTS="-D-Xmx=8192"1 -p 6666:8080 hl7v3-generator:master.official ... INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version name: Apache Tomcat/9.0.58 ... INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built: Jan 15 2022 14:37:38 UTC ... INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version number: 9.0.58.0 ... INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name: Linux ... INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version: 5.4.0-139-generic ... INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture: amd64 ... INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home: /usr/local/openjdk-8/jre ... INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version: 1.8.0_322-b06 ... INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor: Oracle Corporation ... INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE: /usr/local/tomcat ... INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME: /usr/local/tomcat ... INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.confi... ... INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manag... ... INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djdk.tls.ephemeralDHKeyS... ... INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.protocol.handler.p... ... INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dorg.apache.catalina.sec... ... INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -D-Xmx=8192M ... INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dignore.endorsed.dirs= ... INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=/usr/loca... ... INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=/usr/loca... ... INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=/usr/loc... ... ...INFO c.i.s.RestletInitializer.contextInitialized:48 - ############################################################... ...INFO c.i.s.RestletInitializer.contextInitialized:49 - Initializing hl7v3-generator application context... ...INFO c.i.s.RestletInitializer.contextInitialized:50 - HL7v3 CDA on-demand generation service using Model-driven He... ... ...INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/usr/local/tomc... ...INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"] ...INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [1241] milliseconds
1 Yes, the -D is a little surprising, but essential! See answer in Docker + Tomcat + .properties −− Environment Variables.
With the Docker image running, it's sometimes useful, at very least for debugging purposes, to get inside and look around. For instance, I want to check out to see how the Tomcat service has been set up and whether I can pre-modify its heap size. Let's start a shell in the running container:
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8ddabb0621ac hl7v3-generator:master.official "catalina.sh run" 4 seconds ago Up 3 seconds 0.0.0.0:6666->8080/tcp, :::6666->8080/tcp hl7v3-generator $ docker exec -it hl7v3-generator bash root@8ddabb0621ac:/usr/local/tomcat#
Want to wipe your local Docker repository and start over?
$ docker rm -f $(docker ps -qa) $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
$ docker rmi -f $(docker images -aq) $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE