天天看点

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

1. 简介

最近项目中有一个搜集用户

feedback

的功能,用户通过回答一些问题给我们提供

feedback

feedback

的数据会以

json

文件的格式通过邮件发送给我们。但是这些

json

文件如何进行保存是一个问题。

于是后面我们又单独基于

MongoDB

liberity

(

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

    命令,构建自己的镜像
  2. 启动自己的应用容器

    由于应用的端口配置的是

    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
           
  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": "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

查看该网络的详细信息:

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

在启动容器的时候,使用

--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

,可以看见两个容器已经被加入到自定义的网络中。

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

这时候,直接访问我们的应用(应用中连接

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 // 进入容器命令()