1. 简介
最近项目中有一个搜集用户
feedback
的功能,用户通过回答一些问题给我们提供
feedback
。
feedback
的数据会以
json
文件的格式通过邮件发送给我们。但是这些
json
文件如何进行保存是一个问题。
于是后面我们又单独基于
MongoDB
和
liberity
(
Web
应用服务器,相当于
Tomcat
)开发了一个简单的应用,提供了文件的上传、导出、查看等功能。当我们收到这些
json
文件后,通过上传功能,将
json
文件中的数据,存储在
MongoDB
中。同时可以从
mongodb
中以文件的形式导出
feedback
数据。
MongoDB
是文档型数据库,非常适合用于存储
JSON
数据。最终使用
docker
部署应用。
2.步骤
-
将自己的应用制作成镜像
1)编写
基础镜像使用的是Dockerfile
open-liberty:21.0.0.2-full-java8-openj9
。
主要做的工作是将自己编写的应用导出成
包(war
可以直接将应用导出成Eclipse
包),然后复制到war
服务器的基础镜像中,并且将服务器的配置文件以及应用需要的一些liberity
包也一起复制到jar
基础镜像中。liberity
2)运行FROM open-liberty:21.0.0.2-full-java8-openj9 # Add server configuration COPY --chown=1001:0 server.xml /config/ COPY --chown=1001:0 bootstrap.properties /config/ # This script will add the requested XML snippets to enable Liberty features and grow image to be fit-for-purpose using featureUtility. # Only available in 'kernel-slim'. The 'full' tag already includes all features for convenience. # RUN features.sh # Add the application COPY --chown=1001:0 FeedbackData.war /config/ COPY --chown=1001:0 ./lib/ /config/lib/ # This script will add the requested server configurations, apply any interim fixes and populate caches to optimize runtime. RUN configure.sh
命令,构建自己的镜像docker build
-
启动自己的应用容器
由于应用的端口配置的是
, 所以用9443
将其暴露在主机的-p
端口,这样,通过主机的9443
或者域名 + 端口号ip
的方式就能够访问我们的应用。9443
: 容器不正常退出的情况下,自动重启。例如直接机器重启的情况--restart unless-stopped
docker run -d -p 9443:9443 --name feedbackdata-liberity-1.0 --restart unless-stopped feedbackdata:1.0
- 启动
为了安全,MongoDB
不映射主机端口。镜像使用的是MongoDB
中的dockerhub
版本。mongo:4.2
, 启动--auth
的验证功能,简单理解就是只有登录的用户才能操作数据库mongodb
docker run -d --name feedbackdata-mongo-1.0 --restart unless-stopped mongo:4.2 --auth
在启动了
MongoDB
之后,通过浏览器去访问自己的应用,发现怎么也连接不上
MongoDB
数据库。在
log
中看见有很多连接数据库超时的信息。
经过调查,发现在连接
mongodb
的时候,代码中
host
地址写的是
localhost
。需要改成
MongoDB
容器的
ip
地址。可以通过下面的命令查看容器的
ip
地址:
docker inspect 容器ID或容器名
在Networks中的IPAddress字段就是该容器的IP。
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "c99291dfd481359090d02d66c902a4f15ea3d87209c094b730ddd9d891b8a9eb",
"EndpointID": "50f4b59e18d68c1a09b61cb8509394dc911a3df6b4f8bb2e5bdae4532ba1841d",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
}
}
将源代码中的数据库连接地址修改成容器的
ip
地址之后,确实能够正常的连接上
mongodb
了,但是如果容器重启,
ip
地址发生了变化怎么办?难道还要再改一次代码,重新制作应用镜像吗?
思考:
能不能通过容器名来进行连接(在应用源码中,数据库连接地址
url
直接写成
mongodb
容器的名字)???我们只需要保证容器名不变化就可以,即使
mongodb
容器的
ip
地址发生了变化也没关系。这样就不需要一直更改应用源代码中的数据库连接地址
ip
了。
所以又去研究了容器互联的办法。
1)第一种办法是使用
--link
。已经不推荐使用,它是直接修改的
/etc/hosts
文件,将
ip
地址和容器名的映射加入到了
hosts
文件中。这样一来,通过容器名访问的时候,就能解析得到容器
ip
,就能够访问容器了。
在启动应用容器的时候使用
--link
参数,连接
mongodb
容器.
docker run -d -p 9443:9443 --name feedbackdata-liberity-1.0 --restart unless-stopped --link feedbackdata-mongo-1.0 feedbackdata:1.0
上面这种方式也能够成功通过容器名的方式连接
mongodb
,但是已经不推荐使用。
执行下面的命令进入
feedbackdata-liberity-1.0
容器,
cat
输出
hosts
文件的内容,可以发现,
hosts
文件中加入了容器名
feedbackdata-mongo-1.0
和
ip
地址的映射。
docker exec -it feedbackdata-liberity-1.0 /bin/bash
[email protected]:/logs$ cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3 feedbackdata-mongo-1.0 0fe311efc84f
172.17.0.2 63a5d087d6a7
2)第二种办法是可以自定义网络。推荐使用。
使用下面的命令创建一个自定义网络,将容器都加入同一个自定义网络中,这样就能够通过容器名相互访问了。
--driver bridge
: 使用的是桥接模式,
docker
默认的
docker0
网络,也是使用的桥接模式,但是
docker0
有一些限制,例如通过容器
在这里插入代码片
名不能直接访问容器。
--subnet 192.168.0.0/16
: 指定子网范围
--gateway 192.168.0.1
: 指定网关,所有的网络都从这里进出,相当于路由器
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway
192.168.0.1 feedbackdata-net-1.0
执行
docker network ls
可以查看到自己创建的网络。
[email protected]-MBP FeedbackData $ docker network ls
NETWORK ID NAME DRIVER SCOPE
c99291dfd481 bridge bridge local
4f2aefc1c976 feedbackdata-net-1.0 bridge local
6cce3158d195 host host local
0945e49d3f44 none null local
执行
docker network inspect feedbackdata-net-1.0
查看该网络的详细信息:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiclRnblN2XjlGcjAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL9EFVPl3aq50dFRVT3V1MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLwITN2IzNwUTMwETNwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
在启动容器的时候,使用
--net
参数将容器加入到自定义的网络中。执行下面的命令分别启动
mongodb
容器和应用容器。
docker run -d --name feedbackdata-mongo-1.0 --restart unless-stopped --net feedbackdata-net-1.0 mongo:4.2 --auth
docker run -d -p 9443:9443 --name feedbackdata-liberity-1.0 --restart unless-stopped --net feedbackdata-net-1.0 feedbackdata:1.0
再次运行
docker network inspect feedbackdata-net-1.0
,可以看见两个容器已经被加入到自定义的网络中。
这时候,直接访问我们的应用(应用中连接
mongodb
数据库的地址写的是容器名
feedbackdata-mongo-1.0
),发现
mongodb
也是可以直接通过容器名进行访问的。
说明了自定义网络可以帮助我们直接通过容器名的方式进行容器间的访问。
思考:
应用程序生成了一些
log
,这些
log
必须进入到容器里面才能进行查看,很不方便。如何解决???
如何去备份
mongodb
的数据???
使用
docker
的卷挂载技术,于是又去研究了容器卷相关的技术。
容器卷挂载:将容器中的目录或文件映射到宿主机的某个目录或文件。容器中的目录或文件的改变,会直接同步更新到宿主机上。反之也是一样。但是如果容器中的目录被删除,宿主机上的该目录是不会被删除的。即使
mongodb
容器被删除,然后重新启动一个新的容器,也会自动同步宿主机上的数据。
最终使用下面的命令将
logs
和
mongoDB
的数据挂载到了宿主机的
logs
目录和
databackup
目录。
通过
-v
进行卷挂载。
docker run -d -p 9443:9443 --name feedbackdata-liberity-1.0 --restart unless-stopped --net feedbackdata-net-1.0 -v /home/gqdeng/logs/:/logs/ feedbackdata:1.0
docker run -d --name feedbackdata-mongo-1.0 --restart unless-stopped --net feedbackdata-net-1.0 -v /home/gqdeng/databackup/:/data/db/ mongo:4 --auth
思考:每次应用的镜像都是自己手动
build
出来的,首先要
build angular
前端的工程代码,然后将
build
出来的
dist
目录放在后端的
Webcontent
目录中,然后还需要手动从
eclipse
中导出一个
war
包;最后还有通过
docker build
命令,将
war
包构建成自己的应用镜像。非常麻烦。能不能自动化?将这些过程串起来。
经过研究,最终通过
Jenkins
将这一切都串起来。只要
GitHub
上代码有变化,就会自动
build
一个新的镜像,替换掉老的镜像,并且停止旧的应用容器,启动一个新的应用容器。
思考:
mongodb
只起了一个容器,如果它挂掉了,我们的应用是不是也就不能正常使用了?所以又去研究了
mongodb
的高可用。它有一个副本集模式。可以参考https://www.cnblogs.com/littleatp/p/8562842.html
打算配置
mongodb
的副本集模式 ==> 由于项目目前不需要配置,后面如果有需要再扩展。
备注:
MongoDB
的
auth
配置:
1. 进入正在运行的mongodb容器: docker exec -it mongo /bin/bash
2.执行下面的命令
1)mongo // 进入mongodb
2)use admin // 创建admin数据库
3)db.createUser({ user:'admin',pwd:'2342342',roles:[ { role:'userAdminAnyDatabase', db: 'admin'},"readWriteAnyDatabase"]}); // 创建一个admin用户,后面用来创建其它的普通用户。如果开启了权限认证,只能第一次创建admin的时候会成功创建,第二次如果再直接创建另一个admin会直接失败,报错如下:
db.createUser({ user:'admin2',pwd:'453453',roles:[ { role:'userAdminAnyDatabase', db: 'admin'},"readWriteAnyDatabase"]});
2021-04-11T10:19:46.215+0000 E QUERY [js] uncaught exception: Error: couldn't add user: command createUser requires authentication :
[email protected]/mongo/shell/utils.js:25:13
DB.prototype.[email protected]/mongo/shell/db.js:1413:11
4)进行认证操作
db.auth("admin", "2342342") // 认证操作,只有认证之后才能操作数据库,才能进行后面的操作
5).
use feedbackdb // 创建feedbackdata数据库
db.createUser({ user: "gqdeng", pwd: "23424234", roles: [{ role: "readWrite", db: "feedbackdb" }] }); // 创建一个普通用户feedbackdb数据库有读写权限
// db.auth("gqdeng", "23424234")
使用java程序连接feedbackdb,用户名是gqdeng,密码是23424234
docker exec -it feedbackdata-liberity-1.0 /bin/bash // 进入容器命令()