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