私有化輕量級持續集成部署方案–03-部署web服務(上)
提示:本系列筆記全部存在於
Github,
可以直接在
Github 查看全部筆記
這一篇主要講述部署一個 Web 項目,項目是我曾經搞的一個 VUE 模板項目://github.com/orca-studio/vue-template/tree/vite-3.X

目前還沒有搭建鏡像私有倉庫和自動化部署流程。
只能本地打包 Docker 鏡像,上傳 DockerHub,再伺服器拉取鏡像,進行啟動。
本地打包 Docker 需要本地具有 Docker 環境。
Windows 或 Mac 的 Docker 環境,可以在網上查詢怎麼安裝。
構建鏡像
部署 Web 項目 的第一步是構建 鏡像(Image)。
鏡像(Image)是運行時所使用的文件資源。
Docker 提供了製作 鏡像(Image) 的方式:使用 build 命令執行 Dockerfile 文件。
構建 鏡像(Image) 的關鍵 就在於 Dockerfile 文件。 Dockerfile 配置了構建鏡像時所有的操作。
執行 build 時,需要提供一個 上下文目錄(Context)(一般上下文目錄為項目根目錄)。
Docker 會將上下文目錄(Context) 與子目錄結構發送到 Docker 引擎 ,Docker 引擎 根據這個目錄結構去構建 鏡像 (Image)。
在 Dockerfile 文件中,是不允許訪問 上下文目錄(Context) 之外的目錄。
這就是有些教程中會說不能在 Dockerfile 使用 ../ 原因。
默認情況下 Docker 會讀取 上下文目錄(Context) 中 Dockerfile 文件,所以一般都會將 Dockerfile 文件放在根目錄。
當然也可以放在其它目錄,執行 build 時使用參數指定 Dockerfile 文件
PS: 注意:在構建
鏡像時不允許訪問上下文目錄(Context)之外的目錄。
Dockerfile
為了管理方便,將所有的部署相關放在 deploy 目錄。
所以也將 Dockerfile 存放在 deploy 目錄。

FROM nginx:latest
# 將程式碼copy到鏡像
COPY ../dist /usr/share/nginx/html
# 將 nginx 配置文件 copy 到容器內配置文件的目錄下
COPY ../deploy/nginx.conf /etc/nginx
# 容器應用埠
EXPOSE 80
PS:
Dockerfile支援好多指令,在此只介紹使用到的指令,其它指令有興趣的朋友可以自行查詢
-
第一行 FROM 指令:表示使用的底層鏡像,製作應用級別鏡像,都需要依賴運行環境。web 項目的運行環境為
Nginx伺服器。PS: 之前說過, 鏡像是分層存儲的,構建鏡像可以簡單的理解為在現有鏡像上添加一層。
-
第二行 COPY 指令:表示 複製文件,將本地的目錄或者文件 複製到鏡像指定目錄下。
將 ./dist 目錄,也就是項目編譯生成的程式碼目錄複製到 鏡像中 /usr/share/nginx/html 目錄PS:所有相對目錄都是以
上下文目錄(Context)為基準,所以 dist 目錄訪問是 ./dist,而非 ../dist。 -
第三行 COPY 指令:表示將 nginx.conf 配置文件 複製到 /etc/nginx。
PS:所有相對目錄都是以
上下文目錄(Context)為基準,所以 nginx.conf 目錄訪問是 ./deploy/nginx.conf,而非 ./nginx.conf。web 項目
容器運行的是Nginx伺服器, 自己製作的 web 鏡像鏡像(Image)只是將生成的靜態文件掛載到Nginx伺服器上。nginx.conf 文件是用來配置
Nginx掛載路由等資訊。 -
第四行 EXPOSE 指令:暴露埠號,啟動容器時使用
ports映射容器內部的埠號就是此命令暴露的。
Nginx鏡像中,暴露了 80 埠運行Nginx伺服器,Dockerfile中只暴露 80 埠,在啟動時 80 埠直接啟動的是Nginx伺服器。
注意:不允許直接使用 ./nginx.conf 訪問,會被識別成以 上下文目錄(Context) 下的 nginx.conf

但是允許以 上下文(目錄)為相對目錄的基準目錄。
nginx.conf
在 deploy/nginx.conf 文件中編寫 Nginx 配置。 構建鏡像(Image)時會將此文件複製到鏡像
PS: 也可以使用類似上一篇中的將
nginx.conf掛載到宿主環境中。
events {
worker_connections 1024;
}
http {
include mime.types;
default_type text/html;
sendfile on;
keepalive_timeout 65;
charset utf-8;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
}
- root: 此屬性設置根目錄,當前根目錄設置為 /usr/share/nginx/html,靜態文件都存儲在此目錄。
- index: 此屬性指定網站初始頁面。 也就是 /usr/share/nginx/html/index.html
- try_files: 此屬性將所有的訪問都轉為 index.html 。單頁面程式的路由都是請求同一個
HTML,由JS內部判斷的路由頁面,
類似webpack-dev-server中 historyApiFallback 屬性
執行構建
執行構建 鏡像(Image) 使用的命令是 docker build。
為了執行方便,在 package.json 中添加 deploy 命令執行構建
每次構建 鏡像(Image) 前,先進行項目編譯。也就是執行 npm run build 命令。當編譯成功後才執行 docker build 。

PS:
npm-run-all是一個 NPM 包,用於執行多個腳本
PS:
Docker Hub沒有帳號的需要先進行註冊://hub.docker.com/
docker build 命令中使用了幾個參數
- -t 構建的鏡像名稱。 其中 yxs970707 是
Docker Hub中的用戶名稱。
當前沒有構建私庫,先推送到Docker Hub。將 yxs970707 改為自己用戶名稱或組織。
: 後的為當前鏡像的標籤(tag),一般情況下會設置版本號。
也可以使用多個 -t 設置多個版本號 - -f
Dockerfile文件地址,Dockerfile文件存在了 deploy 目錄,所以需要指定文件地址。 - 最後一個點 . 表示設置當前目錄為
上下文目錄(Context)。
PS:
標籤(tag)可以隨意設置,標籤(tag)可以根據實際情況使用版本號
PS: 構建鏡像時可以設置多
標籤(tag),添加多個 -t
此時,執行 npm run deploy 便可以構建鏡像(Image)。構建鏡像(Image)時,每一句命令都具有清晰的資訊。構建成功後就可以在本地 Docker 中看到此鏡像
PS:第一次構建可能會慢一些,因為本地沒有
Nginx鏡像,需要 pull。
PS:
鏡像(Image)的分層其實每一句命令都是一層。


測試鏡像
成功構建鏡像後可以先在本地測試

在此將本地 3333 埠號映射到了容器。可以根據情況隨意設置未被使用的埠號,
如果未出意外的話將會啟動一個 容器,容器狀態為 RUNNING。


如果啟動時出錯的話,可以點擊容器查看錯誤日誌進行分析

按照步驟理論上不會有什麼問題,如有未成功的可以查詢日誌嘗試解決,實在解決不了可以留言。
推送 Docker Hub
鏡像推送 Docker Hub 很簡單,只需要在 Docker Desktop 中登錄帳號點擊 push 即可
PS:之後部署私有倉庫之後可以推送到私有倉庫
push 成功後就可以在 Docker Hub 中搜到此鏡像



部署容器
最簡部署
容器的最簡部署方案是只設置埠號
拉取鏡像可能有些延遲,因為
Docker配置了中國源,需要時間來同步
version: '3.9'
services:
nginx:
image: yxs970707/deploy-web-demo:1.0.0
container_name: web
restart: always
ports:
- 7777:80
PS:
鏡像(Image)的標籤(tag)設置的為 1.0.0,拉取鏡像時需要指定
使用 Portainer 部署完畢後就可以訪問伺服器進行訪問。


volumes 掛載
在上面將所有文件都存放鏡像中,並沒有使用 volumes 將 /usr/share/nginx/html 目錄掛載到宿主機中。
接下來就實現這一操作,將數據掛載到宿主機中。
將數據掛載到宿主機中可以實現不更新鏡像和容器直接更新前端項目。
但是真實情況下並不推薦這樣做。這裡只是介紹下可以這樣做,在後續自動化部署時還是根據鏡像版本更新。
非具名 volumes 覆蓋問題
之前都是使用宿主目錄直接掛載容器內目錄。
直接使用宿主目錄掛載,在容器啟動時會使用宿主目錄覆蓋容器目錄。
version: '3.9'
services:
nginx:
image: yxs970707/deploy-web-demo:1.0.0
container_name: web
restart: always
ports:
- 7777:80
volumes:
- /volumes/web/html:/usr/share/nginx/html
更新 YMAL 文件,添加掛載 /usr/share/nginx/html 目錄。
使用此文件重新部署,訪問時 Nginx 會提示 403,也就是根本沒有找到該地址

/usr/share/nginx/html 目錄是存儲前端文件的目錄。
在伺服器查看會發現掛載目錄並沒有任何文件,進入容器內部查詢 /usr/share/nginx/html 也沒有任何文件
也就是說 Docker 在啟動容器時,使用宿主目錄(空目錄)覆蓋了容器內目錄。


docker exec -it web /bin/sh 進入容器
可以在宿主目錄創建一個文件測試,在此只貼出測試結果。有興趣的可以自行測試。

具名 Volumes
解決數據掛載問題,需要創建具名的 Volumes。
Docker 中 Volume 是一個完整的模組。具有很強大的功能。
甚至可以將數據掛載到其它機器上,在此只使用 Volume 完成目前的需求。
其它功能,有興趣的朋友可以自行查詢穩定。

Volume 可以使用命令先進行創建,然後在掛載時使用。當然可以在 Docker Compose 創建。
version: '3.9'
volumes:
web-html:
name: web-html
driver: local
driver_opts:
o: bind
type: none
device: /volumes/web/html
services:
nginx:
image: yxs970707/deploy-web-demo:1.0.0
container_name: web
restart: always
ports:
- 7777:80
volumes:
- web-html:/usr/share/nginx/html
YAML 文件中 volumes 就是創建具名的數據卷。
這個數據卷使用了本地數據卷,將數據卷綁定本地 /volumes/web/html 目錄
PS: 數據卷還具有其它綁定方式,比如使用 IP 綁定其它機器。
然後使用 數據卷名稱(web-html) 掛載容器 /usr/share/nginx/html
注意,使用數據卷名稱掛載時, /volumes/web/html 目錄必須存在,目錄下不允許有文件。
使用此 yml 部署便可以將數據掛載到 /volumes/web/html。


仔細觀察的情況下, Portainer 可視化工具中在 Volume 項此時具有一個 web-html 的數據卷

在其詳細資訊中可以看到具體詳情。
其中具有一個 Mount path 屬性,這個屬性值是此數據卷的目錄。
其實在 Docker 掛載數據卷時,會將此目錄與容器內進行掛載。
另外還有一個 device 屬性,這個數據是與數據卷綁定的目錄。Linux 具有一種可以將 Mount path 和 device 綁定為一個目錄方案
當然還可以使用其它綁定方案,將數據卷綁定到其它目錄。甚至可以綁定到其它機器



