文章目录
使用Docker-compose 编排Maximo容器环境
1. 写在前面
前期公司针对Maximo测试系统项目进行容器化改造有一段时间,迭代Weblogic镜像中增加了自动部署目录下的JAVA项目功能,解决了Java中文字库显示、JVM时区等问题。公司基于Weblogic带域的docker镜像也迭代到了V3.2的大版本。基本上Weblogic的镜像已经满足Maximo的生产环境使用。
随着Maximo上开发的业务逐渐增多,关联的容器也逐渐增加。从原来单一的Weblogic+Oracle DB容器架构,变成了双Weblogic+Tomcat+Nginx+Oracle DB的架构。这就意味着原来搭建测试环境只用敲两个docker命令,变成了现在需要敲5个docker命令启动容器,每个Docker镜像还得使用Link命令进行关联。这就增加了单个容器镜像变更时,运维操作的复杂度。
为了减少docker link命令的操作次数,规范Maximo容器环境的代码化,采用Docker-compose组件对Maximo容器环境进行编排。
2. 前期准备
2.1 Maximo业务组件拆解
公司原有Maximo容器化的组件有Weblogic和Oracle,仅适合单体业务测试开发使用,并不适用于生产环境,如下图。
原生的Maximo环境中采用的是WebSphere 集群+Apache组件组成。但WAS组件、WAS集群容器化难度较大,一方面Linux的WAS版本(JDK1.6)网络上并不好下载,另一方面WAS许多配置需要图形化操作,相比之下Weblogic可以使用WLTS工具在命令行下进行配置。此外公司Maximo正式系统业务中还有Tomcat业务,JDK版本与weblogic不同,若不采用容器化部署,需要另外部署一台含JDK1.7环境的虚拟机进行隔离。
容器化Maximo采用Weblogic搭建集群,但若使用Weblogic原生的方式搭建集群,势必会增加容器镜像和网络的复杂度。最终采用Nginx+Weblogic搭建集群的方式进行生产环境的容器化编排,两个Weblogic节点,可以满足正式系统灰度发布更新。
2.2 业务组件版本
软件 | 版本 |
---|---|
docker-ce | >=17.05 |
docker-compose | >=1.23.2 |
jdk | 1.6 |
weblogic | 11g |
Oracle Database | 11g |
Oracle instantclient | 10c |
Weblogic镜像(自建) | harbor.gdphdc.com/weblogic/wls-11g-jdk6:v3.0 |
Tomcat镜像(JDK7) | tomcat:7 |
Oracle Database镜像(自建) | harbor.gdphdc.com/oracle/oracle-11g:latest |
Oracle instantclient镜像(自建) | harbor.gdphdc.com/oracle/database-instantclient:10.2.0.5 |
Nginx镜像 | nginx:stable |
2.3 项目目录架构
── docker-compose-maximo
│ ├── database //数据库持久化目录
│ ├── dmp //数据库dump文件存放目录
│ ├── init //数据库初始化存放脚本目录
│ ├── doclinks //数据库dump文件存放目录
│ ├── logs //日志目录
│ ├── images //项目镜像存放目录
│ ├── weblogic01 //Weblogic 节点1 APP目录
│ │ └── maximo.ear
│ ├── weblogic02 //Weblogic 节点2 APP目录
│ │ └── maximo.ear
│ ├── nginx //Nginx配置目录
│ │ └── default.conf
│ └── tomcat //Tomcat,巡点检适配项目
│ └── cxfservice.war
│ ├── docker-compose-without-oracle.yaml //生产用docker-compose.yaml
│ ├── docker-compose.yaml //测试用docker-compose.yaml
│ ├── clean.sh //重置项目脚本
│ ├── export-images.sh //导出镜像脚本
│ ├── import-images.sh //导入镜像脚本,供无docker仓库环境使用
│ ├── import.sh //同步生产数据库到测试环境脚本
│ ├── install.sh
│ ├── README.MD
│ ├── start.sh
│ ├── stop.sh
3. 再次重构Weblogic镜像
3.1 减小镜像体积
在Maximo容器化初试的文章里,我曾经打造过一个Weblogic镜像,但是由于经验不足,Dockerfile写的不规范,最终导致生成的Weblogic镜像高达5G多,在pull 新镜像的时候时间非常的长,后来根据网上的文章了解,Docker AUFS的每一层用于保存镜像的上一版本和当前版本之间的差异。即使在Dockerfile进行了删除操作,上一层的文件仍然会占用空间,镜像拥有的层越多,最终的镜像就越大。
起初优化镜像体积的方法通过&&合并命令来减少RUN语句、删除apt更新缓存等操作减少相关层。采用这种方法优化,Weblogic镜像从5G减少到了2.7G,但是效果依然不太理想。此时还有一部分没有必要存在于镜像的文件被包含到了镜像中。比如在安装Weblogic时,首先需要COPY Weblogic安装包到镜像中,形成一个层约600Mb,然后使用RUN命令进行安装,这又形成了一个大约为700Mb的镜像层,在这之后,无论怎么删除掉安装包,其600Mb安装包依然占据了镜像空间,这一部分无法使用&&合并来进行优化
好在自从Docker 17.05.0-ce 开始Docker 官方提供了简便的多阶段构建 (multi-stage build) 方案,这就可以将jdk的环境,Weblogic安装的环境解耦,将安装完成后的二进制文件复制到最终的镜像中,从而减少安装的空间。
此时优化过的Weblogic镜像,仅有900多M,加上全部的Windows字体文件、Weblogic域文件等层最终只有1.34G,空间足足少了一半有多,最终的dockerfile构建示意图如下。
3.2 自动部署项目脚本
Weblogic基础镜像编制完后,若直接做成镜像启动容器,还需要手动进入到:7001/console页面中对项目进行部署,部署的相关配置保存在容器文件系统当中。这样一来有个缺点,一旦容器被销毁,所有的部署配置将被清空,不利于运维。解决方案有两种:
- 在Dockerfile中ADD项目文件,并引用WLTS脚本将项目文件离线部署在weblogic域当中中。
- 将APP项目作为目录映射在docker外,使其持久化,在Dockerfile的ADD一个entrypoint脚本,每次启动容器时先调用脚本部署离线部署项目文件夹下的文件。再启动Weblogic
两种方案各有利弊,方案1优点在于启动快,适用于项目直接以镜像的方式进行交付,但通用性较差。方案2通用性较好,但每次启动调用WTLS离线部署会占用容器启动时间。这里我们采用了方案2,编写一套启动脚本和WLST部署APP脚本。
entrypoint.sh
#!/bin/bash
echo $APP_NAME
echo $APP_PKG_FILE
echo $APP_PKG_LOCATION
if [[ ! $APP_PKG_LOCATION ]] ; then
echo "部署环境变量为空或不合法,跳过自动部署"
else
echo "启动离线部署"
wlst.sh -skipWLSModuleScanning /u01/oracle/app-deploy.py
fi
startWebLogic.sh
app-deploy.py
import os
# Deployment Information 从环境变量中获取部署变量信息
# ==============================================
domainhome = os.environ.get('DOMAIN_HOME', '/u01/oracle/weblogic/user_projects/domains/base_domain/')
admin_name = os.environ.get('ADMIN_NAME', 'AdminServer')
appdir = os.environ.get('APP_PKG_LOCATION', '/u01/app')
filetypes=[".jar",".war",".ear"]
files=os.listdir(appdir)
# Read Domain in Offline Mode 离线读取Weblogic域
# ==============================================
readDomain(domainhome)
# Create Application 部署APP
# ===============================================
cd('/')
for file in files:
for types in filetypes:
if os.path.splitext(file)[-1] == types:
try:
appname=file.rstrip(os.path.splitext(file)[-1])
app = create(appname, 'AppDeployment')
app.setSourcePath(appdir + '/' + file)
app.setStagingMode('nostage')
# Assign application to AdminServer
# ================================
assign('AppDeployment', appname, 'Target', admin_name)
print(file,"Deploy Sucessed!")
break
except Exception:
print(file,"Deploy failed!")
break
# Update Domain, Close It, Exit
# ==========================
updateDomain()
closeDomain()
exit()
3.2 环境变量规划
由于采用Docker-compose组件进行编排,可以先在Weblogic基础镜像中设置环境变量的默认值,后续再由不同的Docker-compose脚本传入Weblogic容器中。
1、不可变环境变量
这部分不可变的环境变量如JAVA_HOME、CLASSPATH、BEA_HOME、DOMAIN_HOME等直接在Dockerfile内写入。
2、可变环境变量
这部分可变的环境变量可以在Dockerfile内写入空值或默认值,也可以不写,但在实际的docker-compose文件中必须指定,如JVM启动参数USER_MEN_ARGS、以及3.2中提到的APP_PKG_LOCATION(APP包文件位置)
3.3 持久化数据规划
持久化数据意味着这部分文件数据,不随着容器的生命周期结束而消失。这部分文件需要使用docker-compose映射到相关的目录,需要规划持久化数据有
-
Weblogic 中相关的日志文件,用于故障排查这部分文件位于
/u01/oracle/weblogic/user_projects/domains/base_domain/servers/AdminServer/logs/
-
Weblogic 中APP部署目录,这部分文件位于
/u01/app
-
Maximo 中上传附件Doclinks的目录
/u01/app/maximo/doclinks
4. Nginx容器配置
4.1 持久化数据规划
为了方便调试,Nginx镜像采用官方镜像,并没有另外构建,默认配置文件default.conf映射在了容器外,方便日后拓展修改。同时,需要读取Weblogic中共享出来的doclinks的目录,作为下载服务器。
4.2 Doclinks文件下载服务器及负载均衡配置
Nginx在此项目有两个作用,第一是作为Apache的替代,作为doclinks附件的下载。另外一个作用则是作为Weblogic的前端负载均衡。这里有几个要注意的地方,由于官方Nginx镜像默认的编码没有设置,而Maximo中部分用户上传的文件名是采用中文命名。在Windows机器请求Url时不能命中,会显示404,需要增加相关编码配置。
...
server {
listen 80;
server_name maximo;
charset utf-8,gbk;
...
在负载均衡的配置中,由于Maximo项目并没有第三方组件对Session进行存储,为了不让请求在多个节点跳跃(具体表现为Maximo会话超时,请重新登录),需要采用ip_hash的算法方式进行负载均衡,同时需要在应用weblogic.xml 中配置Session复制
<?xml version="1.0" encoding="GBK"?>
<weblogic-web-app xmlns="http://www.bea.com/ns/weblogic/90">
<session-descriptor>
<persistent-store-type>replicated</persistent-store-type>
<sharing-enabled>true</sharing-enabled>
</session-descriptor>
</weblogic-web-app>
4.3 完整配置
#上游服务器设置,这里服务器应该采用docker-compose中的服务名而不是ip
upstream maximo {
server weblogic01:7001;
server weblogic02:7001;
ip_hash;
}
server {
listen 80;
server_name maximo;
#设置编码
charset utf-8,gbk;
#文件下载服务器,转发/doclinks请求
location /doclinks {
root /usr/share/nginx/html;
index index.html index.htm;
}
#转发/maximo请求到weblogic
location /maximo {
proxy_pass http://maximo;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_max_temp_file_size 512m;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
5. Tomcat容器及数据库容器配置
由于tomcat仅仅作为一个resultful风格的适配器,较为简单,除持久化webapps目录外没有额外配置,略。
Oracle 11g-ee的容器的构建参照了网上的项目,https://github.com/ufoscout/docker-oracle-11g ,此处略
6. Oracle数据库导出及脚本
6.1 Oracle工具镜像
由于生产系统的Oracle数据库版本较低,为了方便开发人员导出数据库数据而不需要另外再安装Oracle,这里构造了一个Oracle导出工具的镜像。需要从网上下载oracle-instantclient-basic-10.2.0.5-1.x86_64.rpm,oracle-instantclient-devel-10.2.0.5-1.x86_64.rpm,oracle-instantclient-sqlplus-10.2.0.5-1.x86_64.rpm几个文件,并构建镜像,镜像脚本如下
From centos
COPY /install /install
WORKDIR /install
RUN rpm -ivh oracle-instantclient-basic-10.2.0.5-1.x86_64.rpm && \
rpm -ivh oracle-instantclient-devel-10.2.0.5-1.x86_64.rpm && \
rpm -ivh oracle-instantclient-sqlplus-10.2.0.5-1.x86_64.rpm && \
echo /usr/lib/oracle/10.2.0.5/client64/lib > /etc/ld.so.conf.d/oracle-instantclient10.2.0.5.conf && ldconfig && \
cp exp /usr/lib/oracle/10.2.0.5/client64/bin/exp && \
cp imp /usr/lib/oracle/10.2.0.5/client64/bin/imp && chmod -R 775 /usr/lib/oracle/10.2.0.5/client64/bin/ && \
mkdir -p /usr/lib/oracle/10.2.0.5/rdbms/mesg/ && \
cp expus.msb /usr/lib/oracle/10.2.0.5/rdbms/mesg/expus.msb && \
cp expus.msb /usr/lib/oracle/10.2.0.5/rdbms/mesg/impus.msb
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/oracle/10.2.0.5/client64/bin
ENV ORACLE_HOME=/usr/lib/oracle/10.2.0.5/
ENV NLS_LANG='simplified chinese_china.ZHS16GBK'
CMD ['/bin/bash']
6.2 Oracle数据导入导出脚本
bash写的比较乱,将就着用,关键的数据已用【】替代
DATABASE=`docker ps |grep harbor.gdphdc.com/oracle/oracle-11g:latest | awk '{print $1}'`
echo "获取数据库容器名"
echo $DATABASE
echo "1.生产同步数据到dmp文件夹"
echo "2.导入数据(导入dmp文件夹下pheam.dmp phuser1.dmp)"
echo "3.导入Maximo工程文件"
echo "4.同步doclinks"
echo -n "请选择操作:"
read num
if [[ $num =~ ^-?[1-4]+$ ]]; then
if [[ $num = 2 ]]; then
echo "-------导入数据------"
docker exec -u root -it $DATABASE bash -c "chown oracle:oracle -R /dumpfile";
docker exec -u oracle -it $DATABASE bash -c "imp maximo/maximo@localhost:1521/EE.oracle.docker fromuser=【正式系统用户】 touser=【测试系统用户】 file=/dumpfile/pheam.dmp log=/dumpfile/pheam.imp.log"
exit;
fi
if [[ $num = 1 ]]; then
echo "------清空数据-------"
echo "Oracle用户名:"
read USERNAME
echo "Oracle密码:"
read PASSWORD
echo "Oracle IP:"
read IP
echo "SID名称:"
read SID
echo "端口:"
read PORT
echo "链接: $USERNAME/$PASSWORD@$IP:$PORT/$SID"
#导出pheam
docker run --rm --privileged=true -v $PWD/dmp:/tmp harbor.gdphdc.com/oracle/database-instantclient:10.2.0.5 \
exp $USERNAME/$PASSWORD@$IP:$PORT/$SID file=/tmp/pheam.dmp log=/tmp/pheam.exp.log owner=pheam grants=Y indexes=Y compress=Y buffer=1064000 rows=Y
#导出phuser1
docker run --rm --privileged=true -v $PWD/dmp:/tmp harbor.gdphdc.com/oracle/database-instantclient:10.2.0.5 \
exp $USERNAME/$PASSWORD@$IP:$PORT/$SID file=/tmp/phuser1.dmp log=/tmp/phuser1.exp.log owner=phuser1 grants=Y indexes=Y compress=Y buffer=1064000 rows=Y
exit;
fi
if [[ $num = 3 ]]; then
echo "-----复制工程文件------"
scp -r root@【正式系统】:/docker-compose-maximo/maximo/MAXIMO.ear $PWD/maximo/MAXIMO.ear
exit;
fi
if [[ $num = 4 ]]; then
echo "-----复制文档文件------"
rsync -avP 【正式系统】:/docker-compose-maximo/doclinks $PWD/
exit;
fi
else
echo "输入错误"
fi
7. 业务编排
重点来了,使用docker-compose业务编排,要求在数据库启动后,weblogic才开始启动,同时,使用服务名,各个容器都可以访问对方
7.1 docker-compose安装及配置
yum install epel-release -y
yum install docker-compose -y
7.2 docker-compose.yaml
version: "3"
services:
##节点1
weblogic01:
image: harbor.gdphdc.com/weblogic/wls-11g-jdk6:v3.2
ports:
- "7001:7001"
- "13400:13400"
networks:
- maximo
environment:
- "USER_MEM_ARGS=-Xms1024m -Xmx4096m -XX:MaxPermSize=512m"
- "JAVA_OPTIONS=$JAVA_OPTIONS -Dfile.encoding=utf-8 "
- "APP_PKG_LOCATION=/u01/app"
volumes:
- ./weblogic01:/u01/app
- ./logs/weblogic01:/u01/oracle/weblogic/user_projects/domains/base_domain/servers/AdminServer/logs/
- ./doclinks:/u01/app/maximo/doclinks
deploy:
replicas: 1
update_config:
parallelism: 1
delay: 10s
restart_policy:
condition: on-failure
depends_on:
- db
##节点2
weblogic02:
image: harbor.gdphdc.com/weblogic/wls-11g-jdk6:v3.2
ports:
- "7002:7001"
- "13401:13400"
networks:
- maximo
environment:
- "USER_MEM_ARGS=-Xms1024m -Xmx4096m -XX:MaxPermSize=512m"
- "JAVA_OPTIONS=$JAVA_OPTIONS -Dfile.encoding=utf-8 "
- "APP_PKG_LOCATION=/u01/app"
volumes:
- ./weblogic02:/u01/app
- ./logs/weblogic02:/u01/oracle/user_projects/domains/base_domain/servers/AdminServer/logs/
- ./doclinks:/u01/app/maximo/doclinks
deploy:
replicas: 1
update_config:
parallelism: 1
delay: 10s
restart_policy:
condition: on-failure
depends_on:
- db
nginx:
image: nginx:stable
environment:
- "LANG=en_US.UTF-8"
ports:
- "80:80"
volumes:
- ./doclinks:/usr/share/nginx/html/doclinks:ro
- ./nginx:/etc/nginx/conf.d:ro
links:
- weblogic01
- weblogic02
networks:
- maximo
tomcat:
image: tomcat:7
ports:
- "8080:8080"
networks:
- maximo
volumes:
- ./tomcat:/usr/local/tomcat/webapps
- ./doclinks:/doclinks
- ./logs/tomcat:/usr/local/tomcat/logs
- /etc/localtime:/etc/localtime:ro
environment:
- "JAVA_OPTS=$JAVA_OPTS -Dfile.encoding=UTF8 -Duser.timezone=GMT+08"
db:
image: harbor.gdphdc.com/oracle/oracle-11g:latest
volumes:
- ./database:/u01/app/oracle/
- ./init:/docker-entrypoint-initdb.d/
- ./dmp:/dumpfile
networks:
- maximo
ports:
- "1521:1521"
environment:
- "CHARACTER_SET=ZHS16GBK"
networks:
maximo:
driver: overlay
8.环境基本操作
8.1 第一次启动
进入项目文件夹运行命令:
docker-compose up -d
或运行脚本
sh install.sh
启动后可以通过docker-compose logs命令查看日志或使用以下命令查看容器日志
8.2 停止
进入项目文件夹运行命令:
docker-compose stop
或运行脚本
sh stop.sh
8.3 启动
进入项目文件夹运行命令:
docker-compose start
或运行脚本
sh start.sh
8.4 清除
进入项目文件夹运行命令
docker-compose down
rm -rf database/*
9.导入数据
9.1 Oracle数据导入&初始化
数据库初始化的脚本位于 init/init.sql 该脚本在第一次启动数据库时被调用。
数据库导入导出脚本为import.sh
数据库导出文件位于dmp/文件夹下,导出文件为pheam.dmp phuser.dmp。
由于生产数据库的版本为Oracle 10g 版本较低,需要使用database-instantclient-10g的版本导出。可以调用import.sh 按照提示操作。将会在文件夹下生成pheam.dmp phuser.dmp两个文件,也可自行使用Oracle 10g的 imp exp工具进行导出后放置dmp/文件夹下,命名为pheam.dmp phuser.dmp
9.2 Maximo部署
maximo部署文件夹位于maximo/下,该文件夹在weblogic容器中映射目录为/u01/app/maximo/
将生产上的MAXIMO.ear文件夹拷贝至此,部署前需修改MAXIMO.ear/properties.jar/maximo.properties文件修改如下:
mxe.system.reguser=MAXREG
mxe.system.regpassword=maxreg
mxe.db.driver=oracle.jdbc.OracleDriver
#修改Oracle链接
mxe.db.url=jdbc:oracle:thin:@db:1521/EE.oracle.docker
mxe.encrypted=false
mxe.rmi.port=0
#修改Oracle数据库拥有者
mxe.db.schemaowner=maximo
mxe.adminuserid=MAXADMIN
mxe.adminuserloginid=maxadmin
#修改Oracle数据库账户
mxe.db.user=maximo
#修改Oracle数据库密码
mxe.db.password=maximo
mxe.registry.port=13400
mxe.name=MaximoServer
mxe.int.dfltuser=MXINTADM
maximo.int.dfltuserpassword=mxintadm
mxe.encrypted=false
启动环境,MAXIMO.ear自动部署并运行。
10.日志查看
整个docker-compose日志可使用docker-compose logs查看
实时查看各个容器日志
#查看数据库日志
docker logs -f docker-compose-maximo_db_1
#查看weblogic日志
docker logs -f docker-compose-maximo_weblogic_1
#查看tomcat日志
docker logs -f docker-compose-maximo_tomcat_1
查看从某一时刻开始的各个容器日志时可以使用docker logs --since 和 --until参数
11.镜像导入导出
镜像文件备份位于images/文件夹下
镜像导出,运行export-images.sh
镜像导入,运行import-images.sh