私有化輕量級持續集成部署方案–03-部署web服務(上)


提示:本系列筆記全部存在於
Github
可以直接在
Github 查看全部筆記

這一篇主要講述部署一個 Web 項目,項目是我曾經搞的一個 VUE 模板項目://github.com/orca-studio/vue-template/tree/vite-3.X

目前還沒有搭建鏡像私有倉庫和自動化部署流程。

只能本地打包 Docker 鏡像,上傳 DockerHub,再伺服器拉取鏡像,進行啟動。

本地打包 Docker 需要本地具有 Docker 環境。

WindowsMacDocker 環境,可以在網上查詢怎麼安裝。

構建鏡像

部署 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-serverhistoryApiFallback 屬性

執行構建

執行構建 鏡像(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 構建的鏡像名稱。 其中 yxs970707Docker 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。

DockerVolume 是一個完整的模組。具有很強大的功能。

甚至可以將數據掛載到其它機器上,在此只使用 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 pathdevice 綁定為一個目錄方案

當然還可以使用其它綁定方案,將數據卷綁定到其它目錄。甚至可以綁定到其它機器

Tags: