SpringMVC开发的项目,打包后为.war文件,需要依托于Tomcat容器。

1. 问题

Tomcat容器在发布时会遇到两个问题:

  • 如果使用Nginx反向代理启用https,内嵌的js仍会使用http,导致页面显示不完整,且会浏览器标准不安全
  • Tomcat根目录为欢迎页面,部署的项目的路径为ip:8080/project,存在目录,并不美观

针对这两个问题,有如下解决方案。

1.1 不安全的JS

以前有写过解决方案:解决Nginx反代Tomcat Http、Https混合内容报错 - SPEX
简单来说就是需要Nginx与Tomcat均修改配置文件,Nginx还好说,但是对于Tomcat来说,必须修改server.xml,好消息是经过测试,修改此文件关于Forward的区域并不需要重启Tomcat即可生效。

1.2 项目目录

解决此问题有两个思路,一是Nginx反向代理时启用rewrite,但是这会带来两个缺点,地址栏仍可以看到目录以及token传递问题,很不推荐。
第二种是修改Tomcatserver.xml,这里有个过程需要讲一下,有兴趣可以看一下。

*根据我的测试,修改docBase需要重启Tomcat,这对于容器来说是不可以的,因为容器必须存在运行中的进程,而我们的Tomcat是使用CMD命令运行的,在docker中,CMD命令运行是使用PID 1的进程运行,当重启Tomcat即会造成容器直接关闭。
但是如果你在运行此容器的时候附加了--restart=always的话,容器会关闭后自动启动,这时候配置的docBase就生效了,但是显然我们不能说容器在启动后还要重启一下,那替换server.xml行不通。
而Endpoint运行方式则不会使用PID 1,可以尝试,不过也是需要重新构建Tomcat镜像。*

既然替换配置文件不行,那么就替换Tomcat默认的项目,在构建Tomcat镜像时直接删除webapps下的ROOT,在构建镜像时将自己的war包更名为ROOT.war,在server.xml中默认启用热更新,即可将默认项目替换为我们的项目。

所以,我们需要自己构建Tomcat镜像。


2. 构建镜像

刚刚的两个问题我们都可以解决,那么直接使用官方的Dockerfile,加上自己的定制参数即可。
参考:tomcat:8.5.43-openjdk8.Dockerfile
最终我们的Dockerfile文件为

FROM openjdk:8-jdk

ENV CATALINA_HOME /usr/local/tomcat
ENV PATH $CATALINA_HOME/bin:$PATH
RUN mkdir -p "$CATALINA_HOME"
WORKDIR $CATALINA_HOME

# let "Tomcat Native" live somewhere isolated
ENV TOMCAT_NATIVE_LIBDIR $CATALINA_HOME/native-jni-lib
ENV LD_LIBRARY_PATH ${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$TOMCAT_NATIVE_LIBDIR

# see https://www.apache.org/dist/tomcat/tomcat-$TOMCAT_MAJOR/KEYS
# see also "update.sh" (https://github.com/docker-library/tomcat/blob/master/update.sh)
ENV GPG_KEYS 05AB33110949707C93A279E3D3EFE6B686867BA6 07E48665A34DCAFAE522E5E6266191C37C037D42 47309207D818FFD8DCD3F83F1931D684307A10A5 541FBE7D8F78B25E055DDEE13C370389288584E7 61B832AC2F1C5A90F0F9B00A1C506407564C17A3 713DA88BE50911535FE716F5208B0AB1D63011C7 79F7026C690BAA50B92CD8B66A3AD3F4F22C4FED 9BA44C2621385CB966EBA586F72C284D731FABEE A27677289986DB50844682F8ACB77FC2E86E29AC A9C5DF4D22E99998D9875A5110C01C5A2F6059E7 DCFD35E0BF8CA7344752DE8B6FB21E8933C60243 F3A04C595DB5B6A5F1ECA43E3B7BBB100D811BBE F7DA48BB64BCB84ECBA7EE6935CD23C10D498E23

ENV TOMCAT_MAJOR 8
ENV TOMCAT_VERSION 8.5.43
ENV TOMCAT_SHA512 422eda76c5291a3d5ca5fbd679336997371eef913a6bcf95d17bb5b3ba41a3e033c022789cb61a56914be11251492f6c4fced72dbfefb33b31a3b5b0243335c5

RUN set -eux; \
    \
    savedAptMark="$(apt-mark showmanual)"; \
    apt-get update; \
    apt-get install -y --no-install-recommends \
        gnupg dirmngr \
        wget ca-certificates \
    ; \
    \
    ddist() { \
        local f="$1"; shift; \
        local distFile="$1"; shift; \
        local success=; \
        local distUrl=; \
        for distUrl in \
# https://issues.apache.org/jira/browse/INFRA-8753?focusedCommentId=14735394#comment-14735394
            'https://www.apache.org/dyn/closer.cgi?action=download&filename=' \
# if the version is outdated (or we're grabbing the .asc file), we might have to pull from the dist/archive :/
            https://www-us.apache.org/dist/ \
            https://www.apache.org/dist/ \
            https://archive.apache.org/dist/ \
        ; do \
            if wget -O "$f" "$distUrl$distFile" && [ -s "$f" ]; then \
                success=1; \
                break; \
            fi; \
        done; \
        [ -n "$success" ]; \
    }; \
    \
    ddist 'tomcat.tar.gz' "tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz"; \
    echo "$TOMCAT_SHA512 *tomcat.tar.gz" | sha512sum --strict --check -; \
    ddist 'tomcat.tar.gz.asc' "tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz.asc"; \
    export GNUPGHOME="$(mktemp -d)"; \
    for key in $GPG_KEYS; do \
        gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; \
    done; \
    gpg --batch --verify tomcat.tar.gz.asc tomcat.tar.gz; \
    tar -xf tomcat.tar.gz --strip-components=1; \
    rm bin/*.bat; \
    rm tomcat.tar.gz*; \
    command -v gpgconf && gpgconf --kill all || :; \
    rm -rf "$GNUPGHOME"; \
    \
    nativeBuildDir="$(mktemp -d)"; \
    tar -xf bin/tomcat-native.tar.gz -C "$nativeBuildDir" --strip-components=1; \
    apt-get install -y --no-install-recommends \
        dpkg-dev \
        gcc \
        libapr1-dev \
        libssl-dev \
        make \
    ; \
    ( \
        export CATALINA_HOME="$PWD"; \
        cd "$nativeBuildDir/native"; \
        gnuArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)"; \
        aprConfig="$(command -v apr-1-config)"; \
        ./configure \
            --build="$gnuArch" \
            --libdir="$TOMCAT_NATIVE_LIBDIR" \
            --prefix="$CATALINA_HOME" \
            --with-apr="$aprConfig" \
            --with-java-home="$JAVA_HOME" \
            --with-ssl=yes; \
        make -j "$(nproc)"; \
        make install; \
    ); \
    rm -rf "$nativeBuildDir"; \
    rm bin/tomcat-native.tar.gz; \
    \
# reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies
    apt-mark auto '.*' > /dev/null; \
    [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark > /dev/null; \
    find "$TOMCAT_NATIVE_LIBDIR" -type f -executable -exec ldd '{}' ';' \
        | awk '/=>/ { print $(NF-1) }' \
        | sort -u \
        | xargs -r dpkg-query --search \
        | cut -d: -f1 \
        | sort -u \
        | xargs -r apt-mark manual \
    ; \
    apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
    rm -rf /var/lib/apt/lists/*; \
    \
# sh removes env vars it doesn't support (ones with periods)
# https://github.com/docker-library/tomcat/issues/77
    find ./bin/ -name '*.sh' -exec sed -ri 's|^#!/bin/sh$|#!/usr/bin/env bash|' '{}' +; \
    \
# fix permissions (especially for running as non-root)
# https://github.com/docker-library/tomcat/issues/35
    chmod -R +rX .; \
    chmod 777 logs work

# verify Tomcat Native is working properly
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

EXPOSE 8080
RUN rm -rf /usr/local/tomcat/webapps/ROOT 
COPY ./server.xml /usr/local/tomcat/conf
CMD ["catalina.sh", "run"]

仅在EXPOSE 8080有定制:

  • 删除ROOT
  • 修改后的server.xml替换默认

然后将Dockerfile与server.xml放置在一个目录下,打包后上传:

# 打包
docker build -t harbor.s.com/library/tomcat:0.0.1 .

# 上传
docker push harbor.s.com/library/tomcat:0.0.1

现在我们已经有了合适的Tomcat镜像,再启动项目就简单了。


3. 启动项目

都打成docker镜像了,肯定是为了CI/CD准备的,但是这里还会先手动走通流程。
因为项目基于Maven,所以直接启用docker多阶段构建,一个Dockerfile完成。
这里假定我们在pom.xml中设定的包名为super.war,每个Dockerfile中可以有N个CMD,但只会运行最后一个,所以这里我们最后以CMD收尾。
在docker与K8s中还可以覆盖此命令。

FROM maven:3.6-alpine as BUILD

COPY src /usr/app/src
COPY pom.xml /usr/app

RUN mvn -f /usr/app/pom.xml clean package -Dmaven.test.skip=true

FROM harbor.s.com/library/tomcat:0.0.1
COPY --from=BUILD /usr/app/target/super.war /usr/local/tomcat/webapps/ROOT.war
CMD ["catalina.sh", "run"]

把Dockerfile文件放入项目根目录,打包:

docker build -t super:0.0.1 .

最后运行测试:

docker run -it --rm -p 8080:8080 super:0.0.1

确认8080没有被占用且防火墙已经放行,就可以打开网页测试了。

Last modification:September 5th, 2019 at 03:08 pm