Docker作業一筆記
此作業完整的程式碼有放在Github上。
一、作業內容
以下為老師作業的題目:
透過任一IDE啟動一個pipenv的專案資料夾,並在pipfile內安裝pymongo套件。
建置docker-compose.yml,裡面需有mongo資料庫,且帶有ports,volume, container_name 及官方所必須的Environment。
編寫一個app.py,裡面需要對mongo的collection(資料表)的document(文件),進行CRUD等核心操作。
為能夠做更多Docker練習,此處我將第一點的Python環境,由本機端改為在docker-compose.yml內以Jupyter Notebook建立。
二、作業執行環境說明
- 採用VMware Workstation 16 Pro建立虛擬機器
- 主體作業系統:Windows 10
- 客體作業系統:CentOS7
Docker部署在虛擬機CentOS7作業系統上。
三、編寫docker-compose.yml
1. MongoDB
首先我到Docker Hub內尋找有沒有MongoDB的Image,經查詢官方有提供MongoDB的Image(點我連結)。
官方文件的docker-compose.yml範例如下:
# Use root/example as user/password credentials
version: '3.1'
services:
mongo:
image: mongo
restart: always
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: example
mongo-express:
image: mongo-express
restart: always
ports:
- 8081:8081
environment:
ME_CONFIG_MONGODB_ADMINUSERNAME: root
ME_CONFIG_MONGODB_ADMINPASSWORD: example
若按官方提供的文件,會多安裝mongo-express,這個軟體是讓使用者可透過前端畫面來操作mongoDB資料庫,但這邊我們不需要,所以我將官方的docker-compose.yml修改如下:
version: '3.1'
services:
mongo:
image: mongo
container_name: mongo
restart: always
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: example
ports:
- 27017:27017
volumes:
- ./mongo_db:/data/db
主要修改有:
- 拿掉mongo-express的部分
- 增加port設定
- 增加volume設定
./mongo_db:/data/db
:主要是儲存mongoDB的資料庫,參考自官網的Where to Store Data章節說明
在environment部分,MONGO_INITDB_ROOT_USERNAME
為root的帳號,MONGO_INITDB_ROOT_PASSWORD
為root的密碼。
上述的docker-compose.yml即可建立mongoDB且可順利連線。
但此處我不想要直接以root權限來連接資料庫,想要建立其他帳號讓Python連線,並且我想讓建立帳號這件事情,讓Docker在部署時可以直接幫我設置好。參考官網的Initializing a fresh instance章節說明,要先撰寫程式腳本.js
或.sh
檔案,放到容器內的docker-entrypoint-initdb.d
資料夾底下,這樣Docker在部署時即會按照腳本進行相關設定。
此處我撰寫的js腳本內容新增一個user叫做user1,對world資料庫具有讀寫權限:
db.createUser(
{
user: 'user1',
pwd: 'user1pw',
roles: [{
role: 'readWrite',
db: 'world'
}
]
}
);
MongoDB創立使用者的roles設定寫法可參考MongoDB官網說明手冊(點此連結)。
而在docker-compose.yml內,需要在environment部分多設定一個環境變數MONGO_INITDB_DATABASE: user1
,並且在volumes部分將剛寫好的js檔案放到容器內。
version: '3.1'
services:
mongo:
image: mongo
container_name: mongo
restart: always
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: example
MONGO_INITDB_DATABASE: world
ports:
- 27017:27017
volumes:
- ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js
- ./mongo_db:/data/db
設定好後執行,即可在剛部署好的MongoDB內,直接在world
資料庫底下,使用user1帳號登入。
-
其他參考資料:
-
踩到的坑:
- 在測試不同的腳本前,需要先把
volumes
在本地端建立的資料庫資料夾(以我這邊的設定為例是mongo_db
)刪除,否則mongoDB會直接沿用資料庫資料夾的內容直接啟用,意即忽略初始化腳本,直接沿用舊的設定。
- 在測試不同的腳本前,需要先把
2. Jupyter Notebook(Python)
Jupyter Notebook的docker-compose.yml則參考自老師上課講義,此處為節省篇幅只先將Jupyter的部分列出來:
version: '3.1'
services:
jupyter:
build:
context: ./dockerfile
dockerfile: dockerfile-jupyter
container_name: jupyter
restart: always
tty: true
stdin_open: true
depends_on:
- mongo
ports:
- 8888:8888
volumes:
- ./code:/home/jovyan/work
command: start.sh jupyter notebook --NotebookApp.token=''
此處是用dockerfile客製化映像檔,主要是安裝pymongo
套件,dockerfile-jupyter的內容如下:
FROM jupyter/base-notebook
RUN pip install pymongo
- 踩到的坑:
在volumes設定部分,我是將本機端的code資料夾映射到容器內的/home/jovyan/work資料夾。如果本機端沒有先建立好code資料夾,則在執行Jupyter時,於work資料夾內新增python檔案時,會發生下圖的錯誤:
這是因為如果Jupyter若偵測不到本地端有code資料夾,便會以root身份建立,導致非root使用者無法寫入此資料夾。解法有兩個:一個是直接對該資料夾調整擁有者(chown
指令),第二個是在docker-compose
前先行建立好資料夾,這樣資料夾的擁有者就會是使用者的。
3. 部署架構彙整
- Docker部署前資料夾內容:
其中code資料夾底下有一個main.ipynb
檔案,這是待會要在Jupyter內用Python操作MongoDB的程式碼。
- 完整的docker-compose.yml:
version: '3.1'
services:
mongo:
image: mongo
container_name: mongo
restart: always
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: example
MONGO_INITDB_DATABASE: world
ports:
- 27017:27017
volumes:
- ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js
- ./mongo_db:/data/db
jupyter:
build:
context: ./dockerfile
dockerfile: dockerfile-jupyter
container_name: jupyter
restart: always
tty: true
stdin_open: true
depends_on:
- mongo
ports:
- 8888:8888
volumes:
- ./code:/home/jovyan/work
command: start.sh jupyter notebook --NotebookApp.token=''
4. 開始執行部署
在docker-compose.yml檔案路徑下,執行linux指令:
# 啟動docker-compose開始部署
docker-compose up -d
# 執行後 查詢docker運行狀況
docker ps -a
執行成功的畫面如下圖所示:
四、Jupyter內執行MongoDB的CRUD操作
Docker於虛擬機部署好後,接下來在主體作業系統(Windows環境),輸入虛擬機IP及Port連入Jupyter Notebook。
接下來進入到work資料夾內,打開main.py
檔案,即可開始測試pymongo套件
。
1. 建立連線
由於在部署時已有安裝pymongo套件,此處就不需要在進行安裝,可以直接載入套件。
另外在登入帳號時,不是用root帳號,而是在docker部署時,自動幫我們讀取mongoDB初始化腳本(mongo-init.js
)建立好的user1帳號。
# 讀取套件
from pymongo import MongoClient
# 連線相關設定
host = 'mongo'
port = '27017'
user = 'user1'
passwd = 'user1pw'
dbName = 'world'
# 建立mongoDB連線
client = MongoClient('mongodb://' + user + ':' + passwd + '@' + host + ':' + port + '/' + dbName)
# 連入資料庫
db = client['world']
collection = db['people']
2. Insert(新增)
# 匯入資料(單筆匯入寫法)
for i in range(100):
doc = {"age": i, "name": "user_" + str(i)}
collection.insert_one(doc)
# 匯入資料(多筆匯入寫法)
docs = list()
for i in range(100):
docs.append({"age": i, "name": "user_" + str(i)})
collection.insert_many(docs)
# 查詢資料表總資料數
collection.estimated_document_count()
3. Select(查詢)
# 查詢資料
docs = collection.find({"age": {"$gt":95}})
for doc in docs:
print(doc)
4. Update(修改)
# 修改資料
targetDocs = {"age": 0}
newValues = {"$set": {"age": 100}}
result = collection.update_many(targetDocs, newValues)
print(result.modified_count, " documents updated.")
# 確認是否有修改成功
docs = collection.find({"age": 100})
for doc in docs:
print(doc)
5. Delete(刪除)
# 刪除指定資料
collection.delete_many({"age":{"$gt":95}})
# 確認是否有刪除
collection.count_documents({"age":{"$gt":95}})
# 刪除所有資料
collection.drop()
# 確認是否有刪除
collection.estimated_document_count()
6. 指令參考來源
pymongo套件的操作指令主要參考兩個來源:
五、心得
本篇作業筆記說明如何以docker-compose部署MongoDB與Jupyter,並在Jupyter內以Python程式碼對MongoDB進行「增刪改查」。
這次的作業讓我對於Docker的部署流程更加熟悉,了解docker-compse.yml的撰寫方式和架構,也學習到一些要注意的細節。
在MongoDB部分,藉此作業熟悉基本的「增刪改查」操作。且上課時老師並未說明如何建立使用者帳號以及權限的設定,這部分是靠自己去Google學習,並應用到Docker內。
這份作業進行很多次的測試,在每次測試錯誤的結果中去找出解法,每找出一次錯誤的解決方式,就感覺自己功力又更進一步。程式要進步果然是要從實作中學習最快!
comments powered by Disqus