Web 服务器与应用
Nginx
我的Nginx Docker镜像
## 设置继承自己创建的 sshd 镜像
FROM caseycui/ubuntu-sshd
## 维护者
LABEL maintainer="CaseyCui [email protected]"
## 安装 nginx
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends \
nginx \
geoip-bin \
fcgiwrap \
ssl-cert \
&& rm -rf /var/lib/apt/lists/* \
&& chown -R www-data:www-data /var/lib/nginx
## 添加脚本,并设置权限
COPY run-nginx.sh /run-nginx.sh
##RUN chmod 755 /run-nginx.sh
## 定义工作目录
WORKDIR /etc/nginx
## 添加挂载点 /var/www
VOLUME /var/www
## forward request and error logs to docker log collector
RUN ln -sf /dev/stdout /var/log/nginx/access.log \
&& ln -sf /dev/stderr /var/log/nginx/error.log
## 定义输出端口
EXPOSE 80
EXPOSE 443
## 定义输出命令
CMD ["/run-nginx.sh"]
run-nginx.sh 脚本:
## nginx 以 daemon off 形式启动
/usr/sbin/nginx -g "daemon off;"
为什么需要
daemon off;
?想象这样的场景:
如果没有 daemon off, nginx 后台运行, 这时 nginx 并不是 pid 为 1 的程序, 而是执行的其他(如 bash), 这个 bash 执行了 nginx 指令后就结束了, 容器也会随之退出.
或直接修改/etc/nginx/nginx.conf 文件:
echo -e "\ndaemon off;" >> /etc/nginx/nginx.conf
Tomcat
Tomcat 最初是由 Sun 的软件架构师詹姆斯.邓肯.戴维森 开发的, 后来在他的帮助下称为开源项目, 并由 Sun 贡献给 Apache 软件基金会.
Tomcat主要功能: 运行 JSP 页面和 Servlet.
JAVA
企业通常使用 Sun JDK 6 或 Oracle JDK 7+. Dockerfile 如下:
FROM caseycui/ubuntu-sshd
LABEL maintainer="CaseyCui [email protected]"
## 创建 /java 目录
RUN mkdir /java
## 解压jdk压缩包到/java目录
ADD jdk-7u80-linux-x64.tar.gz /java
## 1. 删除 src.zip,减少镜像size
## ~~2. 配置JAVA环境变量~~
## ~~3. 使生效~~
## 下面为几种不同的 echo 写法(配置ENV则不需要手动在/etc/profile里添加)
## =======================================================
## echo -e "\nexport JAVA_HOME=/java/jdk1.7.0_80\nexport PATH=/java/jdk1.7.0_80/bin:$PATH\nexport CLASSPATH=.:/java/jdk1.7.0_80/lib/dt.jar:/java/jdk1.7.0_80/lib/tools.jar" >> /etc/profile
## =======================================================
## RUN { \
## echo; \
## echo 'export JAVA_HOME=/java/jdk1.7.0_80'; \
## echo 'export PATH=$JAVA_HOME/bin:$PATH'; \
## echo 'export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar'; \
## } >> /etc/profile \
## && source /etc/profile \
## && rm -f /java/jdk1.7.0_80/src.zip
## =======================================================
RUN rm -f /java/jdk1.7.0_80/src.zip
## 配置ENV
## > The environment variables set using `ENV` will persist when a container is run from the resulting image.
ENV JAVA_HOME /java/jdk1.7.0_80
ENV JAVA_VERSION 7u80
ENV PATH $JAVA_HOME/bin:$PATH
ENV CLASSPATH .:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
备注:
- JDK的压缩包来自 Oracle Support 网站.
- JAVA环境变量直接在
ENV
里配置即可, 无需手动写入 /etc/profile 中- 如何把多行, 且含有多种特殊字符的字符串写入文件? - 用大括号
Tomcat 8
基于 Oracle JDK 7 的 Tomcat 8.0.X 的Dockerfile如下:
FROM caseycui/jdk7:7u80
LABEL maintainer='CaseyCui [email protected]'
ENV CATALINA_HOME /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
## runtime dependencies for Tomcat Native Libraries
## Tomcat Native 1.2+ requires a newer version of OpenSSL than debian:jessie has available
## > checking OpenSSL library version >= 1.0.2...
## > configure: error: Your version of OpenSSL is not compatible with this version of tcnative
## see http://tomcat.10.x6.nabble.com/VOTE-Release-Apache-Tomcat-8-0-32-tp5046007p5046024.html (and following discussion)
## and https://github.com/docker-library/tomcat/pull/31
ENV OPENSSL_VERSION 1.0.2g-1ubuntu4.8
## RUN set -ex; \
## if ! grep -q stretch /etc/apt/sources.list; then \
## # only add stretch if we're not already building from within stretch
## { \
## echo 'deb http://deb.debian.org/debian stretch main'; \
## } > /etc/apt/sources.list.d/stretch.list; \
## { \
## # add a negative "Pin-Priority" so that we never ever get packages from stretch unless we explicitly request them
## echo 'Package: *'; \
## echo 'Pin: release n=stretch'; \
## echo 'Pin-Priority: -10'; \
## echo; \
## # ... except OpenSSL, which is the reason we're here
## echo 'Package: openssl libssl*'; \
## echo "Pin: version $OPENSSL_VERSION"; \
## echo 'Pin-Priority: 990'; \
## } > /etc/apt/preferences.d/stretch-openssl; \
## fi
RUN apt-get update && apt-get install -y --no-install-recommends \
libapr1 \
openssl="$OPENSSL_VERSION" \
&& rm -rf /var/lib/apt/lists/*
## 安装跟 tomcat 用户认证相关的软件
RUN apt-get update && \
DIBIAN_FRONTEND=noninteractive \
apt-get install -yq --no-install-recommends \
wget \
pwgen \
ca-certificates && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
## 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
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.0.46
ENV TOMCAT_TGZ_URL http://mirrors.tuna.tsinghua.edu.cn/apache/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
## 复制 tomcat 到镜像中
RUN set -x \
\
&& 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 \
&& tar -xvf tomcat.tar.gz --strip-components=1 \
&& rm bin/*.bat \
&& rm tomcat.tar.gz* \
\
&& nativeBuildDir="$(mktemp -d)" \
&& tar -xvf bin/tomcat-native.tar.gz -C "$nativeBuildDir" --strip-components=1 \
&& nativeBuildDeps=" \
dpkg-dev \
gcc \
libapr1-dev \
libssl-dev \
make \
" \
&& 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="/java/jdk1.7.0_80" \
--with-ssl=yes \
&& make -j "$(nproc)" \
&& make install \
) \
&& apt-get purge -y --auto-remove $nativeBuildDeps \
&& rm -rf "$nativeBuildDir" \
&& rm bin/tomcat-native.tar.gz
## 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
## 创建 tomcat 用户脚本
COPY create_tomcat_admin_user.sh /create_tomcat_admin_user.sh
## 创建 tomcat 运行脚本
COPY run-tomcat.sh /run-tomcat.sh
RUN chmod +x /*.sh && \
chmod +x /tomcat/bin/*.sh
## 挂载点
## 日志文件
VOLUME $CATALINA_HOME/logs
## 程序文件
VOLUME $CATALINA_HOME/webapps
EXPOSE 8080
CMD ["/run-tomcat.sh"]
创建 Tomcat 用户和密码脚本文件 create_tomcat_admin_user.sh
, 内容如下:
##!/bin/bash
if [ -f /.tomcat_admin_created ]; then
echo "Tomcat 'admin' user already created"
exit 0
fi
## generate password
PASS=${TOMCAT_PASS:-$(pwgen -s 12 1)}
_word=$( [ ${TOMCAT_PASS} ] && echo "preset" || echo "random")
echo "=> Creating and admin user with a ${_word} password in Tomcat"
##sed -i -r 's/<\/tomcat-user>//' ${CATALINA_HOME}/conf/tomcat-users.xml
## 这句的主要用法就是原本的`tomcat-users.xml`里存在一个空的``到` `的字段,直接用sed删除最后一行,即``
## 然后补上我们生成的密码的相关内容,最后再加上``
sed -i '$d' ${CATALINA_HOME}/conf/tomcat-users.xml
echo ' ' >> ${CATALINA_HOME}/conf/tomcat-users.xml
echo ' ' >> ${CATALINA_HOME}/conf/tomcat-users.xml
echo ' ' >> ${CATALINA_HOME}/conf/tomcat-users.xml
echo ' ' >> ${CATALINA_HOME}/conf/tomcat-users.xml
echo ' ' >> ${CATALINA_HOME}/conf/tomcat-users.xml
echo " " >> ${CATALINA_HOME}/conf/tomcat-users.xml
echo '' >> ${CATALINA_HOME}/conf/tomcat-users.xml
echo "=> Done!"
touch /.tomcat_admin_created
echo "======================================================"
echo "You can now configure to this Tomcat server using:"
echo ""
echo " admin:${PASS}"
echo ""
echo "======================================================"
Tomcat 启动脚本 run-tomcat.sh
:
##!/bin/bash
if [ ! -f /.tomcat_admin_created ]; then
/create_tomcat_admin_user.sh
fi
exec ${CATALINA_HOME}/bin/catalina.sh run
tomcat 密码脚本最后生成的 tomcat-users.xml
文件:
本章小结
中间件服务器是 Docker 容器应用的最佳实践, 理由如下:
- 中间件服务器是除数据库服务器外的主要计算节点, 很容易成为性能瓶颈, 所以通常需要大批量部署, 而Docker 对于批量部署有着许多的先天优势
- 中间件服务器结构清晰, 在剥离了配置文件 日志 代码目录 之后, 容器几乎可以处于零增长状态, 这使得容器的迁移和批量部署更加方便.
- 中间件服务器很容易实现集群, 在使用硬件的F5, 软件的Nginx 等负载均衡后, 中间件服务器集群变得非常容易
在使用中间件容器的时候, 需要事先规划好容器的用途和可能开放的网络端口等资源.
对于程序代码 程序的资源目录 日志 数据库文件 等需要实时更新的数据一定要通过 -v
参数映射到宿主主机的目录中来, 使用 Docker 的 AUFS 文件格式, 会产生较大的性能问题.
IBM研究院关于Docker各项性能的测试报告