一個完整的 Web 應用包含前端頁面、資料庫、後臺邏輯等,按照一般流程去構建需要配置 Nginx、MySQL,以及後臺伺服器,運維涉及到的部分十分複雜。而 Docker 可以將這些東西(數據+服務)封裝起來,雖然有些場合不建議數據和服務放在一起。本文就在一個 Docker 容器中完整部署整個 Web 應用的需求作詳細的介紹。
作者簡介:外號夫子,長於長江之上「梨花島」,總喜歡一個江湖的傳說,如果你偶然記起關於「桃花島」黃藥師的傳說,記得划船來找我。個人博客:fuzhii.com。其他博文《換個timeline看知乎》,《用機器學習的方法鑑別紅樓夢作者》。
本文舉例的 Web 應用為 『top-topic-Zhihu』(換個 timeline 看知乎),抓取「知乎」網站每天新提出的熱門 top10 問題聚合顯示,提供另一種看知乎的姿勢,不被紛繁的 timeline 所迷惑。
項目地址:https://github.com/Huangtuzhi/top-topic-Zhihu
Dockerfile 和依賴文件:https://github.com/Huangtuzhi/docker-toptopic
雲服務商選擇『靈雀雲』提供容器服務:http://www.alauda.cn/
鏡像地址:https://hub.alauda.cn/repos/huangtuzhi/docker-toptopic
Web頁面展示:http://toptopic-huangtuzhi.myalauda.cn:19991/
需要這幾步來完成目標:
抓取 ——> 存儲(數據持久化) ——> 分析 ——> 展示抓取:抓取部分主要是爬蟲,先手動輸入驗證碼獲取登錄 Cookie。然後帶著該 Cookie 模擬發出 Get 請求來獲得網頁數據。思路是從自己的個人主頁開始爬,先爬出現在主頁 timeline 上的所有人,再爬這些人主頁上的其他人...,直到數據量足夠大。把人的 ID 存儲在 people 中。接著繼續爬 people 中所有人主頁上提出的問題,並獲得問題的關注人數和提問時間。把抓取到的問題存儲在 question 中。
存儲:存儲可以把上面的 people,question 寫入文本或者 MySQL 資料庫。中間數據也應該放到資料庫中,不然內存會被無窮多的遞歸生成的中間數據填滿。本項目使用帶主鍵的 MySQL 表模擬內存 set 來存儲 people。
分析:網站目的是獲取每天或者一個時間段內新提出的 top10 熱門問題,所以需要對時間過濾,對關注人數排序。這都可以在 SQL 查詢中完成。
展示:展示包括後臺和前端兩部分,後臺需要在 DB 中取得數據構造成 JSON 格式以 CGI 的形式提供給前端調用。這裡使用 Python Flask 框架提供 CGI 後臺服務。前端頁面主要是跨域 AJax 請求後臺 CGI 來獲得數據,結合定義的模板來展示頁面。在版本 V1 中使用 AngularJS 來簡單的編寫模板及 AJax 請求的邏輯部分,在版本 V2 中使用 artTemplate 和封裝原生的 JS 來滿足需求。
整個 Web 應用的目錄結構如下所示:
Dockerfile 描述了容器的依賴和進行構建的步驟,下面會逐步解釋語句的含義。
MySQL 伺服器只需要用包管理器安裝 mysql-server-5.6,因為後臺使用 Python 作為伺服器語言,還需要安裝 MySQL 對 Python 語言的支持。需要使用 apt 安裝 python ,libmysqlclient-dev 和 python-dev,然後使用 pip 管理器安裝 MySQL-python。
MySQL 的默認字符集為 latin1,而網頁顯示一般是 utf8 字符集,需要將 MySQL 的配置文件的字符集置為 utf8。
使用命令
將本地已修改好的配置文件覆蓋 Docker 中的 MySQL 配置文件。查看字符集
若字符集如上所示,則說明已經修改成功。
在上面的 Dockerfile 中看到分別給'root'@'127.0.0.1'和'root'@'localhost'都加了權限,'root'@'localhost'的權限在 SQL 語句最後才加上。這是因為
Access denied for user 'root'@'localhost' (using password: No)
Access denied for user 'root'@'localhost' (using password: YES)
於是這裡用'root'@'127.0.0.1'來建資料庫和表,最後再用'root'@'localhost'來連接資料庫。
Nginx 在這裡作為靜態頁面的伺服器,安裝只需要用 apt 管理器安裝即可。
Nginx 需要配置 root 目錄來指定網站的文件位置,把本地的 global.conf和nginx.conf文件覆蓋到 Docker 中。
在 global.conf 中我們指明伺服器根目錄為/usr/share/nginx/html/www
在 Docker 中,我們將網站文件放到新建的 /home/toptopic/web/www目錄。這裡建立一個軟連結將它們關聯起來,便於修改和維護。
EXPOSE 在 Docker 中用來限制開放的埠。我們使用 Nginx 來提供靜態頁面訪問,使用 Flask 框架來提供動態頁面數據的獲取,所以需要開放兩個埠。
查詢埠狀態,可以看到宿主機 2333 埠被映射到 Docker 的 2333 埠,宿主機 5000 埠被映射到 Docker 的 5000 埠。
2223 埠與上節中的 Nginx 中設定的埠必須保持一致,因為 Nginx 使用 2223 埠提供服務,Docker 剛好必須把這個埠開放出去。
在基於 Flask 框架寫的後臺服務 dataCGI.py 中,伺服器對應的監聽地址為
host 必須設置為 0.0.0.0,表示監聽所有的 IP 地址。如果 host 使用 127.0.0.1,在容器外將無法訪問服務。同時,這裡的埠 5000 和 Dockerfile 中開放的另一個埠一致。
在 Dockerfile 中的 CMD 中可以指定 Docker 運行時執行一些命令。
這三行分別啟動 MySQL,Nginx 和後臺服務。
構建 Docker 容器
運行容器
需要注意的是若使用
無法啟動 CMD 中的腳本命令,這是因為在 docker run 後指定了 /bin/bash 後會覆蓋 CMD 中的命令。
在「靈雀雲」上部署一個 Docker 應用需要兩步:構建——創建服務。
點擊「構建」——「創建鏡像構建倉庫」,然後選擇 Github 倉庫源。需要把預先寫好的 Dockerfile 放在 Github中。
構建好倉庫之後,點擊「創建服務」。
進行服務的設置,高級設置中服務地址類型選為 tcp-endpoint 即可(外部用戶可以直接通過 TCP 方式訪問這個服務地址,服務地址的埠是隨機分配的,一般會大於 10000 小於 65535)。
最後點擊最下方的「創建服務」完成部署。新建的服務如下所示:
在瀏覽器中輸入http://toptopic-huangtuzhi.myalauda.cn:19991/ ,或點擊『閱讀原文』即可訪問網站。
www.alauda.cn