官方Tomcat镜像

地址:https://hub.docker.com/_/tomcat/

镜像的Full Description中,我们可以得到许多信息,这里简单介绍几个:

  1. Supported tags and respective Dockerfile links

    支持的标签,以及对应的Dockerfile链接。一个Dockerfile可以对应多个标签,我们将以8.5.16-jre8版本的Dockerfile进行分析。
  2. How to use this image

    如何使用本镜像,包括了以不同方式运行容器的命令,以及一些主要环境变量。这里讲的不够详细,我们会详细讲解。

准备知识:APR、Tomcat Native、Tomcat的APR模式

APR是Apache Portable Runtime的简写,其实就是一组用C语言编写的动态链接库,提供统一的API接口,用于访问操作系统底层。详见:http://apr.apache.org/

Tomcat Native的主要作用是为tomcat提供访问本地资源的功能。即利用APR库,访问网络、生成随机数等。Tomcat Native依赖于APR、OpenSSL、JDK。详见:http://tomcat.apache.org/native-doc/

在配置好Tomcat Native后,可以在tomcat配置文件中开启APR模式。开启之后,Tomcat就会直接调用APR库访问网络,不用再通过jvm中转。

因为APR和Tomcat Native是和具体的操作系统紧密关联的,并不像java应用那样编译好后就可以跨平台使用。所以tomcat默认不安装这些功能,而是根据需要,以及具体操作系统,手工编译源码安装。从一些资料上来看,开启tomcat的APR模式后,对tomcat的性能并不一定会有很大的提升(在某些情况下甚至可能下降)。是否开启APR模式要看具体的情况。个人认为,一般情况下,真到了要挖掘Tomcat性能的时候,使用tomcat集群将会是一种更好的解决方案,这对系统的性能、稳定性、可靠性都有提升。

分析Dockerfile(tomcat:8.5.16-jre8)

地址:https://github.com/docker-library/tomcat/blob/master/8.5/jre8/Dockerfile

注意,这里以master分支的Dockerfile链接为例,和DockerHub上的Dockerfile链接可能会不一致,不过不影响我们接下来的分析。以下就是这个Dockerfile的内容,我加了注释加以说明:

#本镜像的基础镜像。有兴趣的话,可以自行在DockerHub上搜索openjdk,分析官方的openjdk镜像的Dockerfile文件。这里为什么不用oracle提供的jdk(jre)?简单地讲,版权问题。
FROM openjdk:8-jre #声明CATALINA_HOME环境变量,这个变量大家都了解。
ENV CATALINA_HOME /usr/local/tomcat
#将Tomcat下的bin路径加入到PATH环境变量中。
ENV PATH $CATALINA_HOME/bin:$PATH
#创建tomcat路径。
RUN mkdir -p "$CATALINA_HOME"
#指定RUN、CMD、ENTRYPOINT命令的当前工作路径。
WORKDIR $CATALINA_HOME #Tomcat Native路径配置。
ENV TOMCAT_NATIVE_LIBDIR $CATALINA_HOME/native-jni-lib
#将TOMCAT_NATIVE_LIBDIR加入到LD_LIBRARY_PATH环境变量中,这样Tomcat在查找Tomcat Native相关的动态链接库时,会去查找TOMCAT_NATIVE_LIBDIR环境变量指定的路径。
ENV LD_LIBRARY_PATH ${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$TOMCAT_NATIVE_LIBDIR #检查、更新OpenSSL,这块的细节我没深究。
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/* #从key服务器导入key,用于验证tomcat压缩文件的签名,这块也没深究。
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相关文件的版本。
ENV TOMCAT_MAJOR 8
ENV TOMCAT_VERSION 8.5.16 #Tomcat相关文件下载地址。
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 #执行命令
RUN set -x \
\
#下载Tomcat压缩文件
&& wget -O tomcat.tar.gz "$TOMCAT_TGZ_URL" \
&& wget -O tomcat.tar.gz.asc "$TOMCAT_ASC_URL" \
#进行签名验证
&& gpg --batch --verify tomcat.tar.gz.asc tomcat.tar.gz \
#解压Tomcat
&& tar -xvf tomcat.tar.gz --strip-components=1 \
# 删除供Windows系统使用的.bat文件
&& rm bin/*.bat \
# 删除压缩文件
&& rm tomcat.tar.gz* \
\
#安装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 #验证Tomcat Native是否安装成功
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 #暴露8080端口
EXPOSE 8080
#容器启动时执行的命令。
CMD ["catalina.sh", "run"]

此Dockerfile的主要功能可归纳为:

  1. 以openjdk镜像为基础镜像进行构建。
  2. 安装Tomcat Native,及其依赖库(比如APR、OpenSSL等)。验证是否正确安装。
  3. 下载Tomcat,检查签名,解压、清除无用文件等。
  4. 暴露8080端口,配置入口命令。

总的来说,此Dockerfile的功能还是比较清晰的,如果要自己构建自己的Tomcat镜像,可以参考本Dockerfile。另外,Tomcat的Dockerfile应该是自动生成而非手工编写,因为第一,Tomcat的有很多版本的Dockerfile,手工维护工作量大;第二,存在一些我认为不是很很合理的地方(比如从key server上获取很多key)。所以大家在分析一些官方Dockerfile时,如果遇到一些感觉不是很合理的地方也别太纠结。

如何使用官方镜像

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

以上指令将使用本镜像启动一个容器,你可以通过http://本机ip:8888访问到容器中的Tomcat。这种方式并没有部署应用,所以其实也没什么实际意义。

$ 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

以上指令增加了两个volume,将/home/myWebApp挂载到容器中的/usr/local/tomcat/webapps/ROOT,将/home/myWebAppLogs挂载到容器中的/usr/local/tomcat/logs路径。容器启动后,tomcat的根应用将会是myWebApp(通过http://本机ip:8888访问),并且tomcat的日志将会输出到/home/myWebAppLogs路径下。

此后,如果容器被删除,应用和应用的日志也不会随容器一起删除。更新应用时,只需要更新/home/myWebApp路径,再重启容器即可。

如果不想把应用挂载到根目录下,可以更改volume配置,比如:-v /home/myWebApp:/usr/local/tomcat/webapps/myWebApp,再通过http://本机ip:8888/myWebApp访问。

注意:如果想把myWebApp内部的日志也输出到/home/myWebAppLogs路径下,请配置myWebApp的日志文件的输出路径为Tomcat日志路径(相对路径),例如:logs/myLog.log。这样,myWebApp的日志文件将会输出至/usr/local/tomcat/logs下(因为挂载了volume,其实是输出到/home/myWebAppLogs路径下)。

从规范的角度讲,其实这种应用部署方式并不值得推荐,因为部署还是出现了环境相关性。也就是说,必须先把应用目录、日志目录指定好,才能进行部署。而且如果要一台机上要部署两个相同的应用进行负载均衡也比较麻烦(要建两套应用和日志目录,并且修改容器启动命令),难以实现自动化部署。但话又说回来,我相信这种部署方式还是会受到大部分人欢迎的。目前我们公司在测试环境中也普遍使用这种模式,以便一台测试服务器部署多个应用(Tomcat),彼此之间完全没有关联和影响。

如果要做到完全环境无关性部署,可以考虑自己在官方Tomcat镜像的基础上,构建出一个新的镜像。在这个新镜像的Dockerfile中直接下载并部署myWebApp,并使用某些工具或框架,将Tomcat和myWebApp产生的日志,上传汇总到一个统一的日志服务中。这样,如果要再部署一个相同的应用,只要给我一台装有Docker环境的机器,我执行一条指令即可(同一Docker环境下注意端口冲突)。这种方式有利于自动化部署,在服务器数量较多的情况下比较合适。当然,这种方式也有比较麻烦的地方,就是每发布以一个应用版本,都要重新构建一个新的镜像。

关于自动化部署,还可以参考 Docker ComposeKubernetes ,这里不做深入(主要是本人对这块的了解和应用也不够多)。

官方镜像的不足

在本镜像的实际使用过程中,还是遇到了一些问题:

  1. 为了照顾到全球的镜像使用者,官方的openjdk镜像和Tomcat镜像都没对时区进行定制化配置,默认为UTC时间(比北京时间早八小时)。如果应用内部也没有进行时区配置,那么应用获取到的系统时间也将会是UTC时间。
  2. 在某些机器(或虚拟机)上,jdk的随机数生成器初始化用时过长,导致Tomcat启动用时过长。我用过的阿里云ECS就是这种情况。

这些问题将会在之后我们自己构建的Tomcat镜像中解决。

官方Tomcat镜像Dockerfile分析及镜像使用的更多相关文章

  1. docker社区的geodata/gdal镜像dockerfile分析

    对应从事遥感与地理信息的同仁来说,gdal应该是所有工具中使用频度最高的库了,那么在docker中使用gdal时,面临的第一步就是构建gdal基础镜像,社区中引用最多的就是geodata提供的gdal ...

  2. 使用Dockerfile文件制作centos6.8基础镜像,基于centos基础镜像的ssh远程登录镜像,jdk1.8镜像,tomcat镜像,elasticsearch镜像等等

    一.首先制作一个centos6.8的裸机镜像 创建一个干净的目录: [root@docker centos6.]# ls c68-docker.tar.xz Dockerfile Dockerfile ...

  3. Docker、Dockerfile、Docker镜像、容器这些都是什么鸟?

    老生常谈,再再再……普及一下: Docker:最早是dotCloud公司出品的一套容器管理工具,但后来Docker慢慢火起来了,连公司名字都从dotCloud改成Docker. Dockerfile: ...

  4. 实战docker,编写Dockerfile定制tomcat8镜像,实现web应用在线部署

    最初在tomcat上部署web应用的方式,是通过maven的maven-compiler-plugin插件先打成war包,再将war包复制到tomcat的webapps目录下,后来用上了tomcat7 ...

  5. Dockerfile构建私有镜像

    构建第一个镜像 镜像的定制实际上就是定制每一层所添加的配置,文件.我们可以把每一层修改,安装,构建,操作的命令都写入一个脚本,这个脚本就是Dockerfile.Dockerfile是一个文本文件,其内 ...

  6. Prometheus之Dockerfile编写、镜像构建、容器启动

    目录 从官方镜像启动:prom/prometheus 官方Dockerfile分析 编写自己的Dockerfile 构建镜像: 启动容器: 从官方镜像启动:prom/prometheus 拉取镜像 $ ...

  7. Docker dockerfile创建Eclipse镜像初试

    抽空初步阅读了Docker技术入门与实战 [Kindle电子书] http://www.cnblogs.com/2018/p/4600116.html 现在想首先在开发环境下引入统一的环境,由于开发中 ...

  8. Docker教程:镜像构建和自动镜像构建dockerfile

    http://blog.csdn.net/pipisorry/article/details/50805379 Docker透过Dockerfile来记录建立Container映象文件的每一个步骤,可 ...

  9. Dockerfile制作自定义镜像

    本文介绍最精简的Dockerfile文件构建镜像,Docker启动的时候可以启动一个shell脚本 1.首先编写Dockerfile文件 说明 1.启动的这个shell脚本一定是不退出的,比如服务器的 ...

随机推荐

  1. 浅谈 Java 主流开源类库解析 XML

    在大型项目编码推进中,涉及到 XML 解析问题时,大多数程序员都不太会选用底层的解析方式直接编码. 主要存在编码复杂性.难扩展.难复用....,但如果你是 super 程序员或是一个人的项目,也不妨一 ...

  2. Range Modular Queries

    Range Modular Queries 题意 给出一个数列,q个查询,问查询区间内有几个数 a[i] % x == y. 分析 其实裸的分块就能过了,跑的还特别快. 这里分块的作用就是排序. 在x ...

  3. Eclipse之文件【默认编码格式设置】,防止乱码等问题

    文件默认编码格式设置步骤如下: 这里显示的是workspace的视图 其他格式文件的视图如下:

  4. 关于echarts使用的常见问题总结

    关于echarts使用的问题总结1.legend图例不显示的问题: 在legend中的data为一个数组项,数组项通常为一个字符串,每一项需要对应一个系列的 name,如果数组项的值与name不相符则 ...

  5. 基于angular实现模拟微信小程序swiper组件

    这段时间的主业是完成一个家政类小程序,终于是过审核发布了.不得不说微信的这个小程序生态还是颇有想法的,抛开他现有的一些问题不说,其提供的组件系统乍一看还是蛮酷的.比如其提供的一个叫swiper的视图组 ...

  6. phpcms通过URL传参

    在PHPCMS中都会遇到通过URL传参数的问题,但是默认的只能取到$catid.$page等这类的值,特别是伪静态之后,想获得其他参数根本不可能,有的人用$_GET["参数"]这种 ...

  7. 实现UDP高效接收/响应

    环境Linux g++6.3.0 问题一:一个ip地址如何接收高并发请求 问题二:如何高并发响应消息 发送请求端只能通过ip地址+端口号向服务器发送请求码,所以服务器只能用一个UDP去绑定此ip以及端 ...

  8. 安装Mysql5.7并修改初始密码

    Centos 安装MySQL可以参考之前写的一篇文章 Centos7.3 安装Mysql5.7并修改初始密码 windows安装mysql5.7有两种方式 1.下载.msi安装文件直接根据界面提示进行 ...

  9. Eclipse汉化后如何还原为EN英文(实用技巧) --转

    自从那天脑袋短路后,下了个汉化包将Eclipse给汉化了,用的我真TMD的不习惯,一直想还原为EN文,试了好多办法,删文件,汉化包,改eclipse.ini文件中的"-nl zh" ...

  10. LoadRunner11_录制Oracle数据库脚本

    [oracle环境] ①oracle:无需在本地安装oracle,但是oracle的odbc驱动一定要装:(我的安装路径为 D:\oracle ).安装好后在环境变量 " Path &quo ...