记一次docker部署web应用实战(Docker + MongoDB + Liberity)

1. 简介

最近项目中有一个搜集用户feedback的功能,用户通过回答一些问题给我们提供feedbackfeedback的数据会以json文件的格式通过邮件发送给我们。但是这些json文件如何进行保存是一个问题。
于是后面我们又单独基于MongoDBliberity(Web应用服务器,相当于Tomcat)开发了一个简单的应用,提供了文件的上传、导出、查看等功能。当我们收到这些json文件后,通过上传功能,将json文件中的数据,存储在MongoDB中。同时可以从mongodb中以文件的形式导出feedback数据。MongoDB是文档型数据库,非常适合用于存储JSON数据。最终使用docker部署应用。

2.步骤

  1. 将自己的应用制作成镜像
    1)编写Dockerfile
    基础镜像使用的是open-liberty:21.0.0.2-full-java8-openj9
    主要做的工作是将自己编写的应用导出成war包(Eclipse可以直接将应用导出成war包),然后复制到liberity服务器的基础镜像中,并且将服务器的配置文件以及应用需要的一些jar包也一起复制到liberity基础镜像中。

    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
    

    2)运行docker build 命令,构建自己的镜像

     docker build -f Dockerfile -t feedbackdata:1.0 .
    
  2. 启动自己的应用容器
    由于应用的端口配置的是xxxx, 所以用-p将其暴露在主机的xxxx端口,这样,通过主机的ip或者域名 + 端口号xxxx的方式就能够访问我们的应用。
    --restart unless-stopped : 容器不正常退出的情况下,自动重启。例如直接机器重启的情况

docker run -d -p xxxx:xxxx --name feedbackdata-liberity-1.0 --restart unless-stopped feedbackdata:1.0
  1. 启动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": "xxxx",
                    "EndpointID": "xxxx",
                    "Gateway": "xxxxx",
                    "IPAddress": "xxxxx",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "xxxxx",
                    "DriverOpts": null
                }
            }

将源代码中的数据库连接地址修改成容器的ip地址之后,确实能够正常的连接上mongodb了,但是如果容器重启,ip地址发生了变化怎么办?难道还要再改一次代码,重新制作应用镜像吗?
思考:
能不能通过容器名来进行连接(在应用源码中,数据库连接地址url直接写成mongodb容器的名字)???我们只需要保证容器名不变化就可以,即使mongodb容器的ip地址发生了变化也没关系。这样就不需要一直更改应用源代码中的数据库连接地址ip了。

所以又去研究了容器互联的办法。
1)第一种办法是使用--link 。已经不推荐使用,它是直接修改的/etc/hosts文件,将ip地址和容器名的映射加入到了hosts文件中。这样一来,通过容器名访问的时候,就能解析得到容器ip,就能够访问容器了。
在启动应用容器的时候使用--link参数,连接mongodb容器.

docker run -d -p xxxx:xxxx --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.0ip地址的映射。

docker exec -it feedbackdata-liberity-1.0 /bin/bash
default@63a5d087d6a7:/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 可以查看到自己创建的网络。

simple@simples-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 查看该网络的详细信息:
在这里插入图片描述
在启动容器的时候,使用--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 xxxx:xxxx --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容器被删除,然后重新启动一个新的容器,也会自动同步宿主机上的数据。
最终使用下面的命令将logsmongoDB的数据挂载到了宿主机的logs目录和databackup目录。
通过-v进行卷挂载。

docker run -d -p xxxx:xxxx --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的副本集模式 ==> 由于项目目前不需要配置,后面如果有需要再扩展。

备注:
MongoDBauth配置:

1. 进入正在运行的mongodb容器: docker exec -it mongo /bin/bash
2.执行下面的命令
1)mongo  // 进入mongodb
2)use admin // 创建admin数据库
3)db.createUser({ user:'xxxxx',pwd:'xxxx',roles:[ { role:'userAdminAnyDatabase', db: 'admin'},"readWriteAnyDatabase"]}); // 创建一个admin用户,后面用来创建其它的普通用户。如果开启了权限认证,只能第一次创建admin的时候会成功创建,第二次如果再直接创建另一个admin会直接失败,报错如下:
	db.createUser({ user:'xxxx',pwd:'xxxx',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 :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
DB.prototype.createUser@src/mongo/shell/db.js:1413:11
4)进行认证操作
db.auth("xxxxx", "xxxx") // 认证操作,只有认证之后才能操作数据库,才能进行后面的操作

5). 
use feedbackdb // 创建feedbackdata数据库
db.createUser({ user: "xxxxx", pwd: "xxxxx", roles: [{ role: "readWrite", db: "feedbackdb" }] }); // 创建一个普通用户feedbackdb数据库有读写权限
// db.auth("xxxx", "xxxxx")
使用java程序连接feedbackdb,用户名是xxxx,密码是xxxx

docker exec -it feedbackdata-liberity-1.0 /bin/bash // 进入容器命令()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值