天天看點

記一次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 // 進入容器指令()