Asp-Net-Core開發筆記:FrameworkDependent搭配docker部署

2023-09-08 15:00:53

前言

之前我寫過一篇使用 docker 部署 AspNetCore 應用的文章,這種方式搭配 CICD 非常方便, build 之後 push 到私有的 dockerhub ,在生產伺服器上 pull 下來映象就可以直接執行了。

然而,有時需要一種更傳統的部署方式,比如在本地打包可執行檔案之後直接放到伺服器上執行。

.NetCore 打包可執行檔案有兩種方式

  • 獨立可執行檔案 - 不依賴任何執行時環境,直接執行就可以啟動
  • 框架依賴 - 需要先安裝對應版本的 dotnet-runtime 才可以執行

前者雖然方便,但打包出來比較大,據說在 .net8 版本會有優化,但後面的事後面再說,本文記錄第二種方式,框架依賴,搭配 docker 部署,這樣就無需在伺服器上安裝 runtime 了。

(PS:有點Java部署內味了)

這種方式設定完成之後,每次更新只需要重新本地重新 publish 後把可執行檔案上傳覆蓋伺服器上的版本即可,非常方便~

不生成 PDB

每次打包會生成一堆 pdb 偵錯檔案,但部署的時候我們不需要這些檔案,可以通過設定 .csproj 檔案關閉。

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
  <DebugType>none</DebugType>
  <DebugSymbols>false</DebugSymbols>
</PropertyGroup>

更好的方式是在解決方案的目錄下建立 common.props 檔案,把以上設定放在這個檔案中,然後每個 .csproj 都參照這個檔案,具體路徑根據實際情況而定。

<Import Project="../../common.props" />

打包

使用以下命令打包

dotnet publish -f net7.0 -c Release -p:PublishSingleFile=true

打包之後生成一個需要依賴 runtime 執行的可執行檔案,接下來準備一下 docker 的設定。

dockerfile

官方的 dockerfile 包含從原始碼構建到部署的整個流程,我們這裡只需要 basefinal ,也就是把可執行檔案放進去微軟的基礎映象裡執行。

FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM base AS final
WORKDIR /app
COPY . .
ENTRYPOINT ["./AIHub.Blazor"]

docker-compose

不想每次都打一堆 docker 的命令,或者不想寫 bash 指令碼的話,docker-compose 是最好的選擇,還可以很方便的和其他容器編排使用。

version: '3.6'

services:
  web:
    image: ${DOCKER_REGISTRY-}web
    container_name: aihub
    restart: always
    environment:
      - ASPNETCORE_ENVIRONMENT=Production
      - ASPNETCORE_URLS=http://+:80
    build:
      context: .
    volumes:
      - .:/app
    ports:
      - "12001:80"
    networks:
      - default
      - swag

networks:
  swag:
    name: swag
    external: true
  default:
    name: aihub

補充:

  • ports 節點對映了容器內的 80 埠
  • 我使用了 swag 來提供 web 服務,所以其實不需要使用 ports 對映埠
  • 後續再試用 candy / traefik 來替代 nginx (本專案沒有nginx,直接用 kestrel)

啟動!

使用命令列啟動!

docker compose up

如果沒有對映埠的話,還需要接著設定一下反向代理。

swag設定

直接上設定

/path/to/swag/config/nginx/proxy-confs/aihub.subdomain.conf

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name aihub.*;

    include /config/nginx/ssl.conf;

    client_max_body_size 0;

    # enable for ldap auth, fill in ldap details in ldap.conf
    #include /config/nginx/ldap.conf;

    # enable for Authelia
    #include /config/nginx/authelia-server.conf;

    location / {
        # enable the next two lines for http auth
        #auth_basic "Restricted";
        #auth_basic_user_file /config/nginx/.htpasswd;

        # enable the next two lines for ldap auth
        #auth_request /auth;
        #error_page 401 =200 /ldaplogin;

        # enable for Authelia
        #include /config/nginx/authelia-location.conf;

        include /config/nginx/proxy.conf;
        include /config/nginx/resolver.conf;

        set $upstream_app aihub;
        set $upstream_port 80;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;

        proxy_hide_header X-Frame-Options; # Possibly not needed after Portainer 1.20.0
    }
}