1. 程式人生 > >teprunner測試平臺部署到Linux系統Docker

teprunner測試平臺部署到Linux系統Docker

本文是一篇過渡,在進行用例管理模組開發之前,有必要把入門篇開發完成的程式碼部署到Linux系統Docker中,把部署流程走一遍,這個過程對後端設計有決定性影響。 # 本地執行 通過在Vue專案執行`npm run serve`和在Django專案執行`python manage.py runserver`,我們把專案在本地跑起來了,示意圖如下: ![](https://img2020.cnblogs.com/blog/1629545/202103/1629545-20210312101820644-719768010.png) 前端在本地啟了個Node伺服器,後端在本地啟了個Django伺服器,分別使用`8080`和`8000`埠。瀏覽器有個同源策略:域名、埠、協議三者一致才能進行訪問,否則會由於跨域訪問而被瀏覽器攔截。圖中前後端的埠不一致,出現了跨域,前端是無法直接請求後端的。解決辦法是在`vue.config.js`中配置`devServer`: ![](https://img2020.cnblogs.com/blog/1629545/202103/1629545-20210312101821046-304392242.png) 這是Node開的一個代理伺服器,當前端請求後端時,會先發向Node代理伺服器,Node代理伺服器以相同的引數向真正的後端伺服器進行請求,再把響應返回給前端。在本專案中,前端請求仍然是發給`http://127.0.0.1:8080`,瀏覽器不會攔截,Node代理伺服器會幫你把請求轉發給後端`8000`埠。 # Nginx部署 搞懂了本地執行代理轉發,再來看看Nginx部署。Nginx本身是個伺服器,就像Node伺服器一樣,也可以看做Apache Tomcat。Vue專案使用`npm run build`命令把程式碼構建為`dist`目錄靜態檔案,放到Nginx伺服器中加載出來,結合Docker示意圖如下: ![](https://img2020.cnblogs.com/blog/1629545/202103/1629545-20210312101821252-1554974419.png) 相比於本地執行,Nginx部署時,前端變化比較大,一:`dist`靜態檔案拷貝到了`/usr/share/nginx/html`目錄中,二:對`/`路徑來說,Nginx會監聽`80`埠,三:對`/api`路徑來說,Nginx會把請求轉發到後端伺服器埠,這也叫做反向代理。後端沒有什麼變化,為了和本地執行看著有點區別,把埠稍微改了下,Docker內部使用`80`埠。 這裡比較關鍵的是理解`Docker teprunner-frontend`、`Docker teprunner-backend`、`Linux`三者之間的關係。如果不知道Docker,那麼應該聽說過虛擬機器,Docker從概念上理解就像是虛擬機器,這三者可以看做是三臺主機。`Linux`的IP是`172.16.25.131`,`80`埠對映到了`Docker teprunner-frontend`的`80`埠,`8099`埠對映到了`Docker teprunner-backend`的`80`埠,如圖中下方雙向箭頭所示。在`Linux`上訪問`http://127.0.0.1`,能開啟登入頁面,但是無法向後端發起請求,因為從`80`埠直接請求`8099`埠,跨域了。解決辦法是在`Docker teprunner-frontend`藉助Nginx進行反向代理,把請求先發送到Nginx伺服器,再轉發給`Linux`的`8099`埠。 > 不能在`Docker teprunner-frontend`中把`/api`的代理設定為`http://127.0.0.1:8099`,因為這個Docker容器的`8099`埠並沒有啟用,啟用的是`Linux`這臺機器上的`8099`埠,所以需要通過`IP`來指定。 整體思路明確了,接下來就開始動手操作。 # 編寫deploy指令碼 **前端** 開啟`teprunner-frontend`資料夾,新建`deploy/nginx.conf`檔案: ![](https://img2020.cnblogs.com/blog/1629545/202103/1629545-20210312101821485-697363193.png) `/`路徑從`user/share/nginx/html`讀檔案,入口為`index.html`,`/api`轉發到`http://172.16.25.131:8099`。這個檔案會拷貝到Docker映象中。新建`Dockerfile`檔案: ![](https://img2020.cnblogs.com/blog/1629545/202103/1629545-20210312101821660-2057597317.png) `FROM`定義了基礎映象,可以理解為作業系統,前端專案基於`nginx`來構建。`WORKDIR`定義了映象當前工作目錄,意思是在執行後面`COPY`操作時,映象目錄用哪一個。`COPY`分別把`dist`靜態檔案和`nginx.conf`配置檔案拷貝到映象中,`COPY`指令第一個引數是本機目錄,第二個引數是映象目錄。映象目錄通過`WORKDIR`來指定,本機目錄通過Docker上下文來指定,新建`build.sh`檔案: ![](https://img2020.cnblogs.com/blog/1629545/202103/1629545-20210312101821882-1092806003.png) `DockerContext`指定了Docker上下文為`teprunner-frontend`根目錄。這裡的Shell指令碼有兩個階段,第1階段是使用`node`編譯: ``` docker run # 執行映象 --rm # 執行後刪除容器 -v $(pwd)/../:/data/src # $(pwd)指當前工作目錄,把根目錄掛載到data/src -v /root/.npm/_logs:/root/.npm/_logs # 掛載日誌檔案 -w /data/src/ # 映象當前工作目錄 $BUILDER_IMAGE # 執行映象為node:latest,用node編譯前端程式碼 /bin/sh -c "npm install && npm run build" # /bin/sh是shell可執行程式,呼叫執行npm命令 ``` 第2階段是打包成Docker映象: ``` docker build # 構建映象 -f $Dockerfile # 指定Dockerfile檔案位置 -t $PkgName # 映象包名 $DockerContext # Docker上下文 ``` **後端** 後端也是類似的,先新建`deploy/Dockerfile`檔案: ![](https://img2020.cnblogs.com/blog/1629545/202103/1629545-20210312101822132-1779978375.png) 後端專案基於`python:3.8`來構建,接著設定了時區,`COPY . .`把Django原始檔直接複製到了映象目錄`/app/release`中,`RUN`指令執行`pip install`命令安裝依賴包,`CMD`和`RUN`有點區別,`RUN`指令在`docker build`時就執行,`CMD`指令在`docker run`時才執行,預定義啟動命令。 > 這裡簡化了遷移資料庫`migrate`等啟動命令,伺服器資料庫和本地用的同一個。 再新建`build.sh`檔案: ![](https://img2020.cnblogs.com/blog/1629545/202103/1629545-20210312101822349-897920151.png) Python程式碼不需要編譯,打包成Docker映象就可以了。 # 部署到Ubuntu系統Docker Linux系統是核心版本,它有很多發行版本,比如CentOS、Ubuntu,本文采用了Ubuntu,只有一個原因,它長的好看。 > 大學室友曾經衝動地把Windows系統換成了Ubuntu,還天天跟我們炫耀有多酷炫有多牛逼,過了兩三天發現Office不好用,也玩不了遊戲,就又換回來了。哈哈,Ubuntu平時玩玩就好了,除非是做Linux核心開發。 下載軟體: - VMware 破解版 - Ubuntu Desktop 20.04 安裝過程此處不再另加贅述。開啟虛擬機器的Ubuntu: ![](https://img2020.cnblogs.com/blog/1629545/202103/1629545-20210312101822560-444960660.png) 開啟Terminal,輸入`su`,輸入密碼,切換到`root`: ![](https://img2020.cnblogs.com/blog/1629545/202103/1629545-20210312101822744-586228980.png) > 發現缺少許可權就`su`一下。 安裝`curl`: ```shell apt-get install curl ``` 安裝`docker`: ```shell curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun ``` 使用`ifconfig`查詢虛擬機器IP: ![](https://img2020.cnblogs.com/blog/1629545/202103/1629545-20210312101822977-1389635193.png) 不要選擇`.git`和`node_modules`資料夾,把`teprunner-frontend`打成壓縮包。不要選擇`.git`和`__pycache__`資料夾,把`teprunner-backend`打成壓縮包。複製前後端壓縮包到虛擬機器Documents解壓: ![](https://img2020.cnblogs.com/blog/1629545/202103/1629545-20210312101823231-672100138.png) Ubuntu Desktop的好處是提供了影象化操作介面,適合我這種小白使用者。使用命令列編輯工具`vi`或者圖形編輯工具`gedit`編輯`teprunner-frontend/deploy/nginx.conf`檔案中`/api`轉發地址為你的虛擬機器實際IP地址: ![](https://img2020.cnblogs.com/blog/1629545/202103/1629545-20210312101823424-14226177.png) 開啟兩個Terminal,分別`cd`到`teprunner-frontend/deploy`和`teprunner-backend/deploy`,執行`./build.sh`命令。 > 如果執行提示`^M`之類報錯,那是因為在Windows編輯後複製到Linux格式不一致,使用`apt-get install dos2unix`命令安裝工具後進行格式轉化,比如`dos2unix build.sh`、`dos2unix Dockerfile`。 前端構建截圖: ![](https://img2020.cnblogs.com/blog/1629545/202103/1629545-20210312101823754-1591589648.png) 第一次因為要下載node依賴包和拉取nginx映象,會比較慢,第二次就快很多了。 後端構建截圖: ![](https://img2020.cnblogs.com/blog/1629545/202103/1629545-20210312101824018-777429168.png) 第一次因為要拉取python映象,會比較慢,第二次就快多了。 都構建完成後,輸入`docker images`命令就能看到打包好的Docker映象了: ![](https://img2020.cnblogs.com/blog/1629545/202103/1629545-20210312101824267-2000499849.png) 啟動前端映象: ```shell docker run -p 80:80 teprunner-frontend ``` 啟動後端映象: ```shell docker run -p 8099:80 teprunner-backend ``` > 映象啟動後就變成了Docker容器,可以理解為一臺虛擬主機。`-p`引數用於對映Ubuntu埠和Docker埠。可以新增`-d`引數讓容器在後臺執行。`docker ps -a`檢視容器,`docker kill CONTAINER`或`docker stop CONTAINER`退出容器。 最後可以在虛擬機器中訪問`http:127.0.0.1`進行登入了,本地機器想要訪問的話,需要把`127.0.0.1`改為你的虛擬機器實際IP,比如`http://172.16.25.131`。 # 小結 本文先介紹了本地執行和Nginx部署的示意圖,涉及到跨域訪問和反向代理。接著編寫deploy指令碼,編譯程式碼,構建映象。最後部署到Ubuntu系統的Docker中執行起來。在使用過程中,也感受到了Docker這一劃時代技術的魅力,如果沒有Docker,我們需要在Ubuntu上面安裝nginx、node、python等軟體,有了Docker,我們只需要安裝Docker,其他都基於Docker映象構建就可以了。teprunner測試平臺的用例採用的是程式碼形式,這就涉及到了程式碼存放位置的問題,為了讓pytest能呼叫執行,肯定是存放到檔案裡面的。本文實踐給了個重要提醒,如果後端把程式碼直接寫入磁碟檔案,每次打包映象部署後,就會把已儲存的用例程式碼抹掉。解決這個問題的第一個辦法是用K8S,第二個辦法是把程式碼存資料庫。學習版採用了第二個辦法存資料庫,執行時動態從資料庫拿程式碼生成檔案。第一個辦法思路借鑑: ![](https://img2020.cnblogs.com/blog/1629545/202103/1629545-20210312101824502-2066592383.png) 最後,簡單聊下Docker和K8S,Docker是Docker公司的,K8S是Google的,Docker是家小公司搞的,在建立之初,並沒有考慮到“容器編排”這個功能,2014年 Google推出Kubernetes用於解決大規模場景下Docker容器編排的問題,2016年Kubernetes釋出CRI統一介面,雖然Docker也在2016年釋出了Docker Swarm,帶來了Docker在多主機多容器的編排解決方案,但是已經無法阻擋K8S取得這場容器編排戰爭的勝利。 > 參考資料: > > https://www.cnblogs.com/riwang/p/11883332.html > > https://zhuanlan.zhihu.com/p/334787180 > > https://testerhome.com/topi