當前位置: 妍妍網 > 碼農

基於.NetCore開發部落格計畫 StarBlog - (31) 釋出和部署【領紅包封面】

2024-02-09碼農

前言

StarBlog 第一期規劃的功能基本完成了,我想著在春節前應該可以把第一期的系列文章完結掉,那麽在差缺補漏階段就剩下開發計畫的最後一個環節——部署了。

PS: 事實上,還有一個很重要但又經常被略過的測試環節我們沒有提到,因為時間關系,第一期規劃我沒有寫單元測試和整合測試,在開發中,測試環節是必備的,我也立個flag會在之後補充這部份測試的程式碼。

關於 dotnet 的測試,可以看看我之前的這篇文章,有余力的同學可以先自行編寫測試程式碼。

文章傳送門:

C# 現在已經全面擁抱雲原生跨平台,部署方式多種多樣,特別是 dotnet8 出來之後大大加強了 AOT 功能,可以獲得和 go 差不多的方便 AOT 能力,本文介紹幾種常見的部署方式,可供讀者靈活選擇。

釋出

釋出就是把程式編譯+打包成一個可執行檔的過程,一般使用 dotnet publish 或者 msbuild 命令,本文使用 dotnet publish

然後編譯又有多種模式,一般分成這幾種

  • Framework dependent (框架依賴) - 需要先安裝對應版本的 runtime 才能執行,跟 Java 的 jar 包差不多

  • Self contained (自包含) - 內建執行時,可以直接執行,但跟框架依賴相比沒有本質區別

  • AOT (Ahead of time) - 生成二進制檔,不需要執行時可以直接執行

  • 第三種 AOT 是跟隨著 dotnet8 結束新釋出的(之前的不完善),目前對於 AspNetCore 計畫來說還需要一些修改,本計畫開發的時候還沒有 AOT ,所以我們只用前兩種方法,後續我會研究一下將 StarBlog 使用 AOT 方式釋出。

    框架依賴釋出

    使用命令

    dotnet publish -r linux-x64 -c Release -p:PublishSingleFile=true -p:PublishTrimmed=true --self-contained false

    參數說明:

  • -r linux-x64 - 表示使用 linux-x64 的 runtime ,如果要釋出到其他平台,需要修改為對應的執行時,比如 win-x64

  • -c Release - 使用 Release 配置生成,相對的還有 Debug 模式,但只有開發才用

  • -p:PublishSingleFile=true - 生成單個檔,如果沒有配置的話,會把計畫裏的依賴都帶上,一大堆dll檔

  • -p:PublishTrimmed=true - 裁剪生成的檔,雖然計畫的依賴很多,但使用到的 class 和 method 沒有那麽多,沒用到的這部份就可以去掉,但如果計畫裏面大量用到反射,就要慎用這個功能,編譯器可能沒法檢查到動態呼叫的方法

  • 自包含釋出

    使用命令

    dotnet publish -r linux-x64 -c Release -p:PublishSingleFile=true -p:PublishTrimmed=true --self-contained true

    會生成這些檔

     publish
     ├─ wwwroot
     ├─ words.json
     ├─ StarBlog.Web.xml
     ├─ StarBlog.Web
     ├─ SQLite.Interop.dll
     ├─ package.json
     ├─ package-lock.json
     ├─ Magick.Native-Q8-x64.dll.so
     ├─ Magick.Native-Q8-x64.dll.dylib
     ├─ Magick.Native-Q8-x64.dll
     ├─ libe_sqlite3.so
     ├─ appsettings.json
     ├─ appsettings.Development.json
     └─ appsettings-email.json
    1 directory, 13 files

    其中可執行檔就是 StarBlog.Web 這個,也就是我們的計畫名稱。

    其他的都是一些配置啥的,然後還可以看到幾個 dll,前面不是說把 dll 都打包到可執行檔裏了嗎,怎麽還有?錯啦,打包到一起的是那些純 C# 實作的 dll ,裏面是 IL 程式碼,而這裏的 SQLite.Interop.dll Magick.Native-Q8-x64.dll 實際上是 C/C++ 之類開發的第三方庫(native library),是二進制的形式,這部份預設不會包含到可執行檔裏。

    當然也可以整合到一起,加個參數就行 -p:IncludeNativeLibrariesForSelfExtract=true

    本機部署 (supervisor)

    最直接的部署方式,把程式釋出為可執行檔,直接在伺服器上執行,搭配 supervisor 等行程監控工具,也是我的部落格目前使用的部署方式。

    我之前已經寫過關於部署的文章,可以參考一下:

    使用 supervisor 來管理行程

    首先安裝

    pip install supervisor

    /etc/supervisord.d/ 下建立個配置,比如 star_blog.ini

    內容如下,可以參考一下,執行起來後在 8080 埠存取

    [program:star_blog]
    # 指令碼目錄
    directory = /home/apps/StarBlog
    # 指令碼執行命令
    command = /home/apps/StarBlog/StarBlog.Web --urls "http://*:8080;"
    # supervisor啟動的時候是否隨著同時啟動,預設True
    # 當程式exit的時候,這個program不會自動重新開機,預設unexpected,設定子行程掛掉後自動重新開機的情況,
    # 有三個選項,false,unexpected和true。
    # 如果為false的時候,無論什麽情況下,都不會被重新啟動,如果為unexpected,只有當行程的結束碼不在下面的exitcodes裏面定義的autorestart = true
    autostart = true
    # 這個選項是子行程啟動多少秒之後,此時狀態如果是running,則我們認為啟動成功了。預設值為1
    startsecs = 1
    # 指令碼執行的使用者身份
    user = hello

    然後啟動 supervisor

    systemctl start supervisord.service

    設定自啟動

    systemctl enable supervisord.service

    不同的Linux發行版命令有所差別,可以自行查閱文件: https://github.com/Supervisor/supervisor

    docker 部署

    docker 部署的方式很靈活,可以在本地打包了映像之後上傳到倉庫,伺服器上 docker pull 拉下來部署,後續搭配流水線也很方便;也可以用我這種方式,docker 作為 runtime 環境,然後本地打包個框架依賴的可執行檔上傳上去執行。

    這裏參考官方的樣版裏的 docker 部署方式,具體可以看我之前寫的這篇文章:

    根據前面的框架依賴釋出,然後準備好 docker 配置,以後每次更新只需要上傳可執行檔去覆蓋就行了。

    dockerfile

    FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
    WORKDIR /app
    EXPOSE80
    EXPOSE443
    FROM base AS final
    WORKDIR /app
    COPY . .
    ENTRYPOINT ["./StarBlog.Web"]

    docker-compose.yaml

    version:'3.6'
    services:
    web:
    image:${DOCKER_REGISTRY-}web
    container_name:starblog
    restart:always
    environment:
    -ASPNETCORE_ENVIRONMENT=Production
    -ASPNETCORE_URLS=http://+:80
    build:
    context:.
    volumes:
    -.:/app
    ports:
    -"8080:80"
    networks:
    -default
    networks:
    default:
    name:starblog

    啟動

    docker compose up

    之後在 8080 埠可以存取

    流水線部署

    流水線可以實作自動部署,解放雙手。

    關於這部份本文就不贅述了,具體的我之前也寫過文章,感興趣的同學可以看看

  • 使用 GitHub Action -

  • 使用 Gitlab CICD -

  • 其他註意事項

    使用 Nginx 反向代理或者在 docker 內部正確獲取 IP

    本計畫具有存取記錄功能,如果使用了 nginx 反向代理或者在 docker 部署且沒有正確配置的話,訪客的IP地址會是 127.0.0.1 ,需要配置一下。

    Nginx配置

    server {
    listen 80;
    server_name example.com *.example.com;
    location / {
    proxy_pass http://127.0.0.1:5000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection keep-alive;
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    }
    }

    後端配置中介軟體

    app.UseForwardedHeaders(new ForwardedHeadersOptions {
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
    });

    搞定

    小結

    部署這塊老生常談了,多種方式各有優劣,這次急著收拾東西就不寫太多了~

    參考資料

  • https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-publish

  • https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx