目前專案當中存有 .NET Framework 和 .NET Core 兩種型別的專案,但是都需要進行容器化將其分別部署在 Windows 叢集和 Linux 叢集當中。在 WCF 進行容器化的時候,遇到了以下幾個問題:
關於第一個問題,最開始我覺得只需要將 WCF 服務打包出來,暴露一個 HTTP 端點。然後在這個 WCF 服務的前面再加一層 NGINX,具體的證書由 NGINX 進行管理。大概的流程就是 API Caller --> (HTTPS)F5 --> (HTTPS)NGINX --> (HTTP)WCF
,按照這樣的方式部署之後,對應的伺服器端點無法存取,具體的錯誤提示的是 Schema 不匹配。因為 WSHttpBinding 強制使用 HTTPS,如果我僅暴露一個 HTTP 端點,是無法繞過 WSHttpBinding 的限制的。
隨後我又在網上找到了 這篇文章,該文章的思路就是實現一個 CustomBinding,然後在裡面忽略掉這塊驗證,經過我的測試無法滿足需求。
上述方法行不通就只有建立一個自籤 SSL 證書,並匯入到 IIS 當中,隨後在 NGINX 啟用 SSL 轉發,目前看來已經解決這個問題。下面是我的 Dockerfile 以及入口點的 PowerShell 指令碼,指令碼裡面包含了證書生成與匯入方法。
dockerfile:
FROM mcr.microsoft.com/dotnet/framework/sdk:4.8 AS build
WORKDIR /build
COPY . .
RUN cd ./src; nuget restore
WORKDIR /build/src/ProjectName
RUN msbuild Wcf.csproj /p:Configuration=Release -r:False
FROM mcr.microsoft.com/dotnet/framework/wcf:4.8-windowsservercore-ltsc2019 AS runtime
WORKDIR /WcfService
EXPOSE 443
COPY --from=build /build/wcf-entrypoint.ps1 .
COPY --from=build /build/src/ProjectName .
ENTRYPOINT ["powershell", ".\\wcf-entrypoint.ps1"]
entrypoint.ps1
$hostName = $env:HostName
$port = "443"
$password = "Your password."
$storeLocation = "Cert:\LocalMachine\My"
$certificate = New-SelfSignedCertificate -DnsName $hostName -CertStoreLocation $storeLocation
$thumbPrint = $certificate.Thumbprint
$certificatePath = ("cert:\localmachine\my\" + $certificate.Thumbprint)
$bindingInformation = "*:" + $port + ":" + $hostName
$securedString = ConvertTo-SecureString -String $password -Force -AsPlainText
Export-PfxCertificate -FilePath "C:\WcfService\temp.pfx" -Cert $certificatePath -Password $securedString
Import-PfxCertificate -FilePath "C:\WcfService\temp.pfx" -CertStoreLocation "Cert:\LocalMachine\Root" -Password $securedString
New-IISSite -Name "WcfService" -PhysicalPath C:\WcfService -BindingInformation $bindingInformation -CertificateThumbPrint $thumbPrint -CertStoreLocation $storeLocation -Protocol https
# Entry point for the application.
&C:\\ServiceMonitor.exe w3svc
由於 WCF 是託管在 IIS 裡面的,我們的紀錄檔資訊是無法輸出到標準輸出流的。所以我們就採取了一個曲線救國的方案,使用一個旁路程式,我們的紀錄檔輸出到檔案當中,由這個旁路程式監控檔案變動,然後將變動的內容輸出到標準輸出流裡面。
這個功能有點像 Logstash,你可能會說我們為什麼不直接用 Logstash 收集這些紀錄檔呢?因為我們所有專案的紀錄檔,都是由基礎架構團隊統一處理。規範就是我們紀錄檔必須輸出到標準輸出流,並且紀錄檔是結構化紀錄檔,還需帶上一些 ProjectId 之類的標記資訊。然後由注入的 Sidecar 容器統一收集、處理、上報到 Garylog 平臺。
回到正題,最開始我找到了微軟實現的一個開源工具,它的本意就是為一些 Windows 容器解決紀錄檔收集問題的。
專案的地址是: https://github.com/microsoft/windows-container-tools。
使用這個工具,指定好路徑與需要執行的程式,替換 Dockerfile 的入口點即可解決問題。微軟那個工具的核心,就是使用了系統提供的檔案監聽 API,在 .NET 裡面也有提供類似的 API,叫做 FileSystemWatcher,如果有興趣的話,也可以參考 C++ 的原始碼和思路自己實現。