使用.NET 6開發TodoList應用(30)——實現Docker打包和部署


系列導航及源代碼

需求

.NET 6 Web API應用使用最多的場景是作為后端微服務應用,在實際的項目中,我們一般都是通過將應用程序打包成docker鏡像進行發布,以便更好地進行部署,包括基於Kubernetes平台的微服務項目部署。

一般來說作為微服務部署的應用程序,都是位於某個虛擬子網下的,也就是說它們不直接暴露給外部用戶,請求都是走的內部網絡,所以很少會有HTTPS的需求,但是作為演示,在本文中我們還是會介紹如何實現HTTPS訪問docker中的應用程序。

目標

實現應用程序的docker鏡像打包運行,包括實現基於HTTPS的訪問。

原理與思路

應用程序docker鏡像打包的實現思路很簡單,准備一個正確的dockerfile,再根據需要進行HTTPS配置,最后正確構建鏡像就可以了。

實現

實現Docker鏡像打包

Api項目中新建dockerfile文件,一般我們構建應用程序都是通過兩步構建:第一步進行編譯發布,第二步將發布的文件拷貝到運行時環境中,這樣可以減少鏡像的大小。

如果你是使用Visual Studio或者Rider開發項目,可以在創建項目的時候就將是否使用Docker支持選上,選擇容器環境為Linux即可,項目模版會為我們自動生成正確的Dockerfile。或者我們也可以在項目上右擊,選擇添加Docker支持

下面是我們手寫的dockerfile的文件內容,對於編寫dockerfile經驗不多的小伙伴來說,最容易出錯的地方就是路徑的問題。因為我們將dockefile文件生成在了Api項目中了,所以單從文件內容里的路徑來看,是有問題的,但是不要緊,我們在打包鏡像的時候可以指定dockefile文件執行的上下文,只要在解決方案目錄下執行docker build就沒問題了。

ARG NET_IMAGE=6.0-bullseye-slim
FROM mcr.microsoft.com/dotnet/aspnet:${NET_IMAGE} AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
ENV ASPNETCORE_ENVIRONMENT=Development

FROM mcr.microsoft.com/dotnet/sdk:${NET_IMAGE} AS build
WORKDIR /src
COPY ["src/TodoList.Api/TodoList.Api.csproj", "TodoList.Api/"]
COPY ["src/TodoList.Application/TodoList.Application.csproj", "TodoList.Application/"]
COPY ["src/TodoList.Domain/TodoList.Domain.csproj", "TodoList.Domain/"]
COPY ["src/TodoList.Infrastructure/TodoList.Infrastructure.csproj", "TodoList.Infrastructure/"]
RUN dotnet restore "TodoList.Api/TodoList.Api.csproj"
COPY ./src .
WORKDIR "/src/TodoList.Api"
RUN dotnet build "TodoList.Api.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish --no-restore "TodoList.Api.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "TodoList.Api.dll"]

在構建鏡像之前,有幾個小坑需要注意一下:

  • 暫時刪除Program中的UseHttpsRedirection中間件,因為我們還沒有配置HTTPS證書;
  • Api項目的csproj文件中,將TodoList.Api.xml文件在Debug模式下的配置復制到Release中,否則會報錯Could not find file '/app/TodoList.Api.xml
  • 修改對應appsettings.{env}.json中的數據庫連接字符串,使用docker網絡模型獲取其他容器的方式,將localhost改為mssql,這個名字是在本地運行sql server docker的容器名稱,我們將使用docker網絡允許應用程序連接到數據庫docker容器。

下面我們就來構建一下這個鏡像,確保位於解決方案目錄下,注意最后那.指明了當前選擇的dockerfile文件執行的上下文路徑,即解決方案目錄:

$ docker build -t todo-list -f src/TodoList.Api/Dockerfile .

生成的鏡像:

image

運行起來,把80端口暴露出來,使用--link參數指出需要將當前應用容器連接到數據庫容器所在的網絡,並使用API客戶端去驗證登陸請求:

$ docker run -p 80:80 --name=todo_list_in_docker --link=mssql -d todo-list
4733f35c2c9558b78e3c7b9281536d8891f19bf87b18fa0ad953e94f7b984184

image

請求認證:
image

實現HTTPS訪問

接下來我們為容器添加HTTPS支持,為了實現這一點,我們當然還是需要繼續使用UseHttpsRedirection中間件,然后需要添加一個證書,並在啟動容器的時候添加這個證書。

dotnet dev-certs https -ep ${HOME}/.aspnet/https/aspnetapp.pfx -p Test@Password
dotnet dev-certs https --trust

重新build並運行容器,這次我們使用HTTPS的5001端口去訪問容器中的API,需要將HTTPS容器內的443端口暴露到host上的端口(我選擇的是5001端口)並制定相關的HTTPS的環境變量,證書的指定並將host上保存證書的路徑掛載到容器內可以訪問到。

docker run \
    -p 80:80 \
    -p 5001:443 \
    --name=todo_list_in_docker \
    --link=mssql \
    -e ASPNETCORE_URLS="https://+;http://+" \
    -e ASPNETCORE_HTTPS_PORT=5001 \
    -e ASPNETCORE_Kestrel__Certificates__Default__Password="Test@Password" \
    -e ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx \
    -v ${HOME}/.aspnet/https:/https/ \
    -d \
    todo-list

image

增加docker-compose功能

到這里我們發現了一個比較麻煩的地方在於我們需要記住這些配置,並且每次需要手動分別啟動數據庫容器和應用容器,我們完全可以通過docker-compose來完成,所以我們先把應用容器和數據庫容器都停止並刪除掉,開始在解決方案目錄下新建docker-compose文件:

version: '3.4'

services:
  todo-list:
    image: todo-list
    # 配置端口轉發
    ports:
      - "80:80"
      - "5001:443"
    # 配置容器環境變量
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_URLS=https://+;http://+
      - ASPNETCORE_HTTPS_PORT=5001
      - ASPNETCORE_Kestrel__Certificates__Default__Password=Test@Password
      - ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx
    # 掛載證書路徑
    volumes:
      - ~/.aspnet/https:/https:ro
    # 需要先啟動數據庫容器
    depends_on:
      - mssql
    # todo-list通過public網絡響應請求,通過private網絡連接數據庫容器
    networks:
      - private
      - public

  mssql:
    image: mcr.microsoft.com/mssql/server:2019-latest
    # 配置端口轉發,這是為從主機直接訪問數據庫需要的,如果沒有從主機直接訪問數據庫的需求,只需要聲明容器端口1433不做轉發即可
    ports:
      - "1433:1433"
    environment:
      - SA_PASSWORD=StrongPwd123
      - ACCEPT_EULA=Y
    # 掛載數據目錄實現持久化
    volumes:
      - mssqldata:/var/opt/mssql
    networks:
      - private
      - public

# 因為mssqldata路徑之前已經創建了,所以需要在這里聲明使用已有的
volumes:
  mssqldata:

networks:
  private:
  public:

運行起來以后繼續請求認證:

$ docker-compose up --build
Creating network "todolist_private" with the default driver
Creating network "todolist_public" with the default driver
Recreating todolist_mssql_1 ... done
Recreating todolist_todo-list_1 ... done
Attaching to todolist_mssql_1, todolist_todo-list_1
// 省略后面的日志....

請求結果:
image

到此為止如何使用容器去進行應用程序打包和部署的演示就結束了,關於如何在Kubernetes和CI/CD中應用這些步驟,會在后面將微服務的系列中再次涉及到。

總結

docker打包應用程序比較容易出錯的地方在於dockerfile路徑,除此之外如果在容器中還需要有其他操作比如安裝一些第三方的agent(比如splunk agent),也需要仔細操作,關於如何進行Docker Build的Debug,可以參考其他人寫的文章,例如這篇:Debugging Docker builds

參考資料

  1. Hosting ASP.NET Core images with Docker over HTTPS
  2. Hosting ASP.NET Core images with Docker Compose over HTTPS
  3. Debugging Docker builds


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM