Dockerfile make official Tomcat images and use detailed explanation

  • 2020-06-15 10:50:52
  • OfStack

I have learned Dockerfile these two days, and I think it is quite a lot of knowledge and very important. Therefore, I will add a little note today.

Official Tomcat mirror

Address: https: / / hub. docker. com / _ / tomcat /

In mirror Full Description, we can get a lot of information. Here are a few:

1.Supported tags and respective Dockerfile links

Supported tags and corresponding Dockerfile links. One Dockerfile can correspond to multiple tags, and we will analyze Dockerfile in 8.5.16-jre8 version.

2.How to use this image

How to use this image includes commands to run the container differently, as well as some of the main environment variables. I'm not going to go into detail here, but we'll go into more detail.

Preparation knowledge: APR mode of APR, Tomcat Native and Tomcat

APR, short for Apache Portable Runtime, is actually a set of dynamic link libraries written in C language. It provides the API interface of Unit 1 for accessing the bottom layer of the operating system. See: http: / / apr. apache. org /.

The primary purpose of Tomcat Native is to provide tomcat with access to local resources. In other words, APR library is used to access the network and generate random Numbers. Tomcat Native depends on APR, OpenSSL, JDK. See: http: / / tomcat. apache. org/native doc /.

After you have configured Tomcat Native, you can turn on APR mode in the tomcat configuration file. Once turned on, Tomcat will call the APR library directly to access the network, and no longer need to transfer via jvm.

Because APR and Tomcat Native are closely related to the specific operating system, they are not ready to be used across platforms as java applications are. Therefore, tomcat does not install these features by default. Instead, it manually compiles the source code installation according to the need as well as the specific operating system. According to some data, the performance of tomcat does not necessarily improve greatly when APR mode is turned on (and may even decline in some cases). Whether APR mode is enabled or not depends on the situation. In my opinion, in general, when it is time to mine the performance of Tomcat, using tomcat cluster will be a better solution, which will improve the performance, stability and reliability of the system.

Analysis of Dockerfile (tomcat:8.5.16-jre8)

Address: https: / / github com/docker - library/tomcat/blob/master / 8.5 / jre8 / Dockerfile

Note that the Dockerfile link on the master branch, for example, may not be the same as the Dockerfile link on DockerHub, but this will not affect our analysis. The following is the contents of Dockerfile, which I have annotated:


# The base image of this mirror. If you're interested, you can do it on your own DockerHub On the search openjdk , analyze the official openjdk The mirror Dockerfile File. Why not use it here oracle To provide the jdk ( jre )? In a nutshell, copyright. 
FROM openjdk:8-jre

# The statement CATALINA_HOME Environment variables, which you all know. 
ENV CATALINA_HOME /usr/local/tomcat
# will Tomcat Under the bin Path to PATH In the environment variable. 
ENV PATH $CATALINA_HOME/bin:$PATH
# create tomcat The path. 
RUN mkdir -p "$CATALINA_HOME"
# The specified RUN , CMD , ENTRYPOINT The current working path of the command. 
WORKDIR $CATALINA_HOME

#Tomcat Native Path configuration. 
ENV TOMCAT_NATIVE_LIBDIR $CATALINA_HOME/native-jni-lib
# will TOMCAT_NATIVE_LIBDIR To join the LD_LIBRARY_PATH In the environment variable, it looks like this Tomcat In finding Tomcat Native It will look for the relevant dynamic link library TOMCAT_NATIVE_LIBDIR The path specified by the environment variable. 
ENV LD_LIBRARY_PATH ${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$TOMCAT_NATIVE_LIBDIR

# Check and update OpenSSL I didn't go into that detail. 
ENV OPENSSL_VERSION 1.1.0f-3
RUN { \
  echo 'deb http://deb.debian.org/debian stretch main'; \
 } > /etc/apt/sources.list.d/stretch.list \
 && { \
  echo 'Package: *'; \
  echo 'Pin: release n=stretch'; \
  echo 'Pin-Priority: -10'; \
  echo; \
  echo 'Package: openssl libssl*'; \
  echo "Pin: version $OPENSSL_VERSION"; \
  echo 'Pin-Priority: 990'; \
 } > /etc/apt/preferences.d/stretch-openssl
RUN apt-get update && apt-get install -y --no-install-recommends \
  libapr1 \
  openssl="$OPENSSL_VERSION" \
 && rm -rf /var/lib/apt/lists/*

# from key Server import key , used for verification tomcat Compressed file signature, this is also not to go into detail. 
ENV GPG_KEYS 05AB33110949707C93A279E3D3EFE6B686867BA6 07E48665A34DCAFAE522E5E6266191C37C037D42 47309207D818FFD8DCD3F83F1931D684307A10A5 541FBE7D8F78B25E055DDEE13C370389288584E7 61B832AC2F1C5A90F0F9B00A1C506407564C17A3 713DA88BE50911535FE716F5208B0AB1D63011C7 79F7026C690BAA50B92CD8B66A3AD3F4F22C4FED 9BA44C2621385CB966EBA586F72C284D731FABEE A27677289986DB50844682F8ACB77FC2E86E29AC A9C5DF4D22E99998D9875A5110C01C5A2F6059E7 DCFD35E0BF8CA7344752DE8B6FB21E8933C60243 F3A04C595DB5B6A5F1ECA43E3B7BBB100D811BBE F7DA48BB64BCB84ECBA7EE6935CD23C10D498E23
RUN set -ex; \
 for key in $GPG_KEYS; do \
  gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; \
 done

#Tomcat The version of the relevant file. 
ENV TOMCAT_MAJOR 8
ENV TOMCAT_VERSION 8.5.16

#Tomcat Relevant file download address. 
ENV TOMCAT_TGZ_URL https://www.apache.org/dyn/closer.cgi?action=download&filename=tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz
ENV TOMCAT_ASC_URL https://www.apache.org/dist/tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz.asc

# Execute the command 
RUN set -x \
 \
 # download Tomcat The compressed file 
 && wget -O tomcat.tar.gz "$TOMCAT_TGZ_URL" \
 && wget -O tomcat.tar.gz.asc "$TOMCAT_ASC_URL" \
 # Perform signature verification 
 && gpg --batch --verify tomcat.tar.gz.asc tomcat.tar.gz \
 # Unpack the Tomcat
 && tar -xvf tomcat.tar.gz --strip-components=1 \
 #  Delete for Windows System used .bat file 
 && rm bin/*.bat \
 #  Delete compressed files 
 && rm tomcat.tar.gz* \
 \
 # The installation Tomcat Native
 && nativeBuildDir="$(mktemp -d)" \
 && tar -xvf bin/tomcat-native.tar.gz -C "$nativeBuildDir" --strip-components=1 \
 && nativeBuildDeps=" \
  dpkg-dev \
  gcc \
  libapr1-dev \
  libssl-dev \
  make \
  openjdk-${JAVA_VERSION%%[-~bu]*}-jdk=$JAVA_DEBIAN_VERSION \
 " \
 && apt-get update && apt-get install -y --no-install-recommends $nativeBuildDeps && rm -rf /var/lib/apt/lists/* \
 && ( \
  export CATALINA_HOME="$PWD" \
  && cd "$nativeBuildDir/native" \
  && gnuArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)" \
  && ./configure \
   --build="$gnuArch" \
   --libdir="$TOMCAT_NATIVE_LIBDIR" \
   --prefix="$CATALINA_HOME" \
   --with-apr="$(which apr-1-config)" \
   --with-java-home="$(docker-java-home)" \
   --with-ssl=yes \
  && make -j "$(nproc)" \
  && make install \
 ) \
 && apt-get purge -y --auto-remove $nativeBuildDeps \
 && rm -rf "$nativeBuildDir" \
 && rm bin/tomcat-native.tar.gz

# validation Tomcat Native Whether the installation is successful 
RUN set -e \
 && nativeLines="$(catalina.sh configtest 2>&1)" \
 && nativeLines="$(echo "$nativeLines" | grep 'Apache Tomcat Native')" \
 && nativeLines="$(echo "$nativeLines" | sort -u)" \
 && if ! echo "$nativeLines" | grep 'INFO: Loaded APR based Apache Tomcat Native library' >&2; then \
  echo >&2 "$nativeLines"; \
  exit 1; \
 fi

# exposed 8080 port 
EXPOSE 8080
# The command that is executed when the container is started. 
CMD ["catalina.sh", "run"]

The main functions of Dockerfile can be summarized as follows:

1. Build the image based on openjdk image.

2. Install Tomcat Native and its dependent libraries (APR, OpenSSL, etc.). Verify that the installation is correct.

3. Download Tomcat, check signature, unzip, remove unwanted files, etc.

4. Expose port 8080 and configure the entry command.

In general, the functions of THIS Dockerfile are relatively clear. If you want to build your own Tomcat image, you can refer to this Dockerfile. In addition, Dockerfile of Tomcat should be generated automatically rather than written manually, because there are many versions of Dockerfile of Tomcat 1, which requires a lot of manual maintenance. Second, there are some things that I don't think are very reasonable (e.g., getting a lot of key from key server). Therefore, when you are analyzing some official Dockerfile, don't be too confused if you encounter some unreasonable places.

How do I use official mirroring


$ docker run -d --name tomcat-test -p 8888:8080 tomcat:8.5.16-jre8

The above instructions will use this image to start a container and you can access Tomcat in the container via http:// native ip:8888. There's no application deployed, so it doesn't really make any sense.


$ docker run -d --name tomcat-test -p 8888:8080 \
-v /home/myWebApp:/usr/local/tomcat/webapps/ROOT \
-v /home/myWebAppLogs:/usr/local/tomcat/logs \
tomcat:8.5.16-jre8

Instructions by two volume above will/home/myWebApp mounted to the container/usr/local/tomcat/webapps/ROOT, will/home myWebAppLogs mounted to the container/usr/local/tomcat/logs path. When the container is started, the root application of tomcat will be myWebApp (accessed via http:// native ip:8888) and the log of tomcat will be output to the /home/myWebAppLogs path.
After that, if the container is deleted, the application and its log will not be deleted with container 1. To update the application, just update the /home/myWebApp path and restart the container.

If you don't want to hang the application to the root directory, you can change the volume configuration, such as: - v/home/myWebApp: / usr/local/tomcat/webapps/myWebApp, again through http: / / native ip: 8888 / myWebApp access.

Note: If you want to output the myWebApp internal log to the /home/myWebAppLogs path as well, configure the myWebApp log file output path to the Tomcat log path (relative path), for example: logs/ myLog.log. So myWebApp log files will be output to/usr local/tomcat/logs (because the mount volume, actually is the output to/home/myWebAppLogs path).

From a normative point of view, this approach to application deployment is not recommended, as the deployment is still context-dependent. In other words, the application directory and log directory must be specified before deployment. It is also difficult to load balance two identical applications on one machine (create two application and log directories, and modify container startup commands), making it difficult to automate deployment. But then again, I'm sure this deployment will be welcomed by most people. This pattern is now commonly used in our company's test environments so that multiple applications (Tomcat) can be deployed on one test server without any correlation or impact to each other.

If you want a completely environment-independent deployment, consider building a new image based on the official Tomcat image. Download and deploy myWebApp directly in the new image of Dockerfile, and use some tools or frameworks to upload and summarize the logs generated by Tomcat and myWebApp into a unified logging service. In this way, if I want to deploy the same application again, I just give me a machine with Docker and I execute one instruction (note port conflict with 1Docker). This approach facilitates automated deployment and is appropriate when there are a large number of servers. The trouble with this approach, of course, is that every time you release an application, you have to rebuild a new image.

For automatic deployment, you can also refer to Docker Compose and Kubernetes, which are not in-depth (mainly because I do not know enough about this area and its application).

Deficiency of official mirror image

In the actual use of this mirror, there are still 1 problems:

1. In order to take care of global mirror users, the official openjdk mirror and Tomcat mirror are not configured with custom time zones and default to UTC time (8 hours earlier than Beijing time). If there is no time zone configuration within the application, the system time acquired by the application will also be UTC time.

2. On some machines (or virtual machines), jdk's random number generator took too long to initialize, resulting in Tomcat taking too long to boot. This is the case with my Alicloud ECS.

These issues will be addressed later in the Tomcat image we build ourselves.


Related articles: