本篇原创发布于 Flex 的我的博客:点击跳转java
在没有 docker 前,项目转测试是比较麻烦的一件事。首先会化较长的时间搭建测试环境,而后在测试过程当中又常常出现测试说是 bug,开发说没法复现的状况,致使撕逼。mysql
本篇记录了如何将一个 java 应用部署到 docker 中。主要讲述了如下几个部分:linux
项目架构以下:nginx
本系统中有三个主要模块 OMS,DAS 和一个 Eureka 注册中心。其中 OMS 和 DAS 使用有 activemq 消息队列,来进行大量数据的交互而后各自使用一个 mysql 数据库存储主要的业务数据。使用 elastricsearch 存储超大量的数据。sql
本项目在 windows 部署时是将其做为三个部分来进行安装的--ENV 环境包(保护 mysql,es 等),OMS 产品包,DAS 产品包。因此最初个人设想是一个容器中装 ENV 环境包所需的全部软件,一个容器装 DAS,一个容器装 OMS。而后再实践的过程当中愈来愈感受不对劲,环境配置比较复杂,并且也有种把容器当虚拟机用的感受,一点没有简化的感受。docker
遂停下了操做,开始学习一波 docker 究竟是怎么用的。用租房子来作比喻:数据库
使用 docker 推荐操做是一个进程放到一个容器中,作到更好的隔离性,同时也更容易进行管理。下面来使用容器技术部署咱们应用。仍是分为三部分,可是每一个进程使用一个容器,作到 0 配置启动容器。ubuntu
在此默认已经会安装 docker,且了解基本操做。如不了解的先看这两篇:安装,基本使用windows
环境包中诸如 elastricsearch,mysql 这样的数据存储工具,须要知足以下两个要求:tomcat
使用容器部署 mysql 过程以下:
docker pull mysql:5.7.24
复制代码
因为 mysql 是用来存数据的,数据不管什么状况都不能丢失,因此数据存在容器外部,经过映射操做,映射到容器内部,参数以下:
# 将宿主机的路径,映射到容器内部。这个路径既能够是文件夹,也能够是文件
-v hostPath:containerPath
复制代码
显然咱们经过这个桉树将外部的数据文件夹,配置文件映射到容器中。最后启动这个容器的命令以下:
# 假设在宿主机中数据存放路径为/opt/mysql/data,配置文件路径为:/opt/mysql/my.cnf
docker run --name=mysql -itd -p 3308:3306 -v /etc/localtime:/etc/localtime -v /etc/timezone:/etc/timezone -v /opt/mysql/data:/var/lib/mysql -v /opt/mysql/my.cnf:/etc/mysql/my.cnf -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7.25
复制代码
注意:若是 mysql 版本为 8.x,还须要映射容器中的/var/lib/mysql-files 目录,不然启动会报错
下面介绍具体参数含义:
可能大家会问为何要映射/etc/timezone
和/etc/timezone
,这是为了让容器的时间和时区与宿主机保持一致。默认状况下容器为 UTC 标准时间。/etc/timezone
让容器时间,时区和宿主机一致。可是若是不映射/etc/timezone
java 应用中的时区仍是错的,虽然使用date -R
命令查看时间和时区都正常。
es 和 activeMQ 都依赖 java 的运行环境,因此有两种部署方式:
这里以第二种方式为例进行说明。
这里不从 docker hub 中拉取镜像,经过 dockerfile 来制做一个自定义的镜像。因为只须要一个 java 运行环境,因此只要将一个 jre 运行环境加入到一个基础 linux 镜像中便可(这里选择 ubuntu)。制做过程以下:
首先建立一个文件夹dockerFileTest
存放依赖和 dockerfile 文件。
而后将下载加压后的 jre 运行环境放到dockerFileTest/jre
目录下。
接着在 dockerFileTest 目录中建立 Dockerfile 文件,内容以下:
#说明基础镜像,默认:latest
FROM ubuntu
#将当前路径下的jre文件夹复制到新镜像下的/opt/jre路径
COPY jre /opt/jre
#设置环境变量
ENV JAVA_HOME=/opt/jre CLASSPATH=/opt/jre/lib PATH=$PATH:/opt/jre/bin
复制代码
最后经过``命令生成新镜像 jre:v1
下载好 es,假设存放在/root/es1 中,经过如下命令建立一个 es 容器:
docker run --name=es1 -itd -p 9200:9200 -p 9300:9300 -v /etc/localtime:/etc/localtime -v /etc/timezone:/etc/timezone -v /root/es1:/opt/es -w /opt/es jre:v1 ./bin/elasticsearch -Des.insecure.allow.root=true
复制代码
参数含义以下:
上面的命令以 es1 为容器名,映射 9200,9300 到宿主机端口,以./bin/'elasticearch -Des.insecure.allow.root=true
建立 es 容器。最后加的参数为了让 es 可以以 root 在容器中启动。
将以前的 es1 复制一份命名为 es2 做为节点 2。要让两个 es 节点构成 es 集群,须要让节点间可以进行通讯,这里使用--link
参数来让 es2 可以连上 es1 构成集群。--link
用法以下:
--link containerName[:alias]
复制代码
es2 启动命令以下:
docker run --name=es2 -itd -p 9201:9200 -p 9301:9300 --link es1 -v /etc/localtime:/etc/localtime -v /etc/timezone:/etc/timezone -v /root/es2:/opt/es -w /opt/es jre:v1 ./bin/elasticsearch -Des.insecure.allow.root=true
复制代码
而后就能在 es2 中经过 es1 的容器名访问到 es1(实际是在 es2 的 host 中增长了一条记录,将 es1 指向 es1 的 IP,该 IP 是 docker 的虚拟网卡分配的 IP)。
可是使用--link 有一些局限,经过该参数联通的容器必须存在。所以该参数只能用在 B 依赖 A 的状况,若是同时 A 也依赖 B(也就是 A,B 要可以相互访问到),这种状况下就不能经过 link 来实现了,缘由你们应该可以想到。。。
在容器中启动 activeMQ 与启动 es 稍有不一样。activeMQ 默认是后台启动的,启动完成后启动程序就会退出,所以若是直接以./bin/activemq start
(假设当前目录在 activemq 中),启动容器会发如今 activemq 启动成功后容器就中止运行了。会出现这种状况是由于容器中启动的第一个进程结束后,容器就会被docker关闭掉
。因此呢咱们只需让第一个进程不结束就好了,所以须要咱们编写一个启动脚原本启动 activemq 并监测运行状况,一旦 activemq 进程挂掉,就结束启动脚本,不然一直运行。启动脚本代码以下:
#!/bin/bash
#使用sh脚本启动activemq,而后定时判断服务是否被关闭,关闭后退出脚本,不然一致循环。
#为避免docker容器在active自带的启动脚本运行结束后就关闭容器了。
#获取启动pid
out=`./bin/activemq start`
echo "$out"
pid=`echo $out | grep -Eo "pid '[0-9]+'" | grep -Eo "[0-9]+"`
echo "当前mq进程pid为:${pid}"
if [ ${#pid} = 0 ]; then
echo "启动失败"
exit 0
fi
while true; do
num=`ps -e | grep -cwE "$pid"`
if [ $num = 0 ]; then
echo "进程异常关闭"
exit 0
fi
sleep 1
done
复制代码
而后以该脚本做为启动脚原本启动容器便可。启动命令以下:(假设 activemq 目录为/opt/activemq,启动脚本路径为/opt/activemq/start.sh)
docker run --name=activemq -itd -p 8161:8161 -p 61616:61616 -v /etc/localtime:/etc/localtime -v /etc/timezone:/etc/timezone -v /root/activemq:/opt/activemq -w /opt/activemq jre:v1 /bin/bash ./start.sh
复制代码
仍是使用以前制做的 jar 镜像来启动 java 应用,这里以部署 jar 包为例,若是部署 war 包则须要在 tomcat 镜像上部署。特别注意下容器的时间和时区设置,不然 java 程序中没法获取到正确的时间和时区。这里经过映射宿主机的 localtime 和 timezone 文件来让容器时间和时区与宿主机相同。启动命令以下:
# 启动oms
docker run -itd --name=oms -p 8082:9090 -v /etc/localtime:/etc/localtime -v /etc/timezone:/etc/timezone -v /root/oms.jar:/opt/oms.jar -w /opt --link es1 --link activemq --link oms-mysql --link eureka-server jre:v1 java -jar oms.jar
# 启动das
docker run -itd --name=das -p 8083:9099 -v /etc/localtime:/etc/localtime -v /etc/timezone:/etc/timezone -v /root/das.jar:/opt/oms -w /opt --link es1 --link activemq --link oms-mysql --link eureka-server jre:v1 java -jar das.jar
复制代码
本篇只是记录了如何使用一容器一进程
的方式来部署 java 应用.
PS:不推荐这么直接手撸命令,建议使用 docker-compose
本篇原创发布于 Flex 的我的博客:点击跳转
扫码关注微信公众号:FleyX 学习笔记,获取更多干货