使用docker創建只讀文件系統
容器化部署對應用的運維帶來了極大的方便,同時也帶來一些新的安全問題需要考慮.比如黑客入侵到容器內,對容器內的系統級別或者應用級別文件進行修改,會造成難以估量的損失.(比如修改hosts文件導致dns解析異常,修改web資源導致網站被嵌入廣告,后端邏輯被更改導致權限驗證失效等,由於是分布式部署,哪些容器內的資源被修改也很難以發現).解決這個問題的辦法就是創建創建一個具有只讀文件系統的容器.下面介紹使用docker run命令和docker compose來創建具有只讀文件系統的容器.
使用docker run命令創建只讀文件系統
比如說要創建一個只讀文件系統的redis容器,可以執行以下命令
docker run --read-only redis
docker compose/swarm創建只讀文件系統
yaml編排文件示例如下
version: '3.3'
services:
redis:
image: redis:4.0.1-alpine
networks:
- myoverlay
read_only: true
networks:
myoverlay:
問題:創建只讀文件系統看起來很不錯,但是實際上往往會有各種各樣的問題,比如很多應用要寫temp文件或者寫日志文件,如果對這樣的應用創建只讀容器則很可能導致應用無法正常啟動.對於需要往固定位置寫入日志或者臨時文件的應用,可以掛載宿主機的存儲卷,雖然容器是只讀的,但是掛載的盤仍然是可讀寫的.
創建只讀的asp.net core容器
上面一節我們講到了創建容器只讀文件系統以增加安全性,以及如何解決需要寫入日志文件或者臨時文件這樣常見的問題.我們嘗試創建一個只讀的asp.net應用時,即便不使用任何log組件(即不寫入日志),仍然無法正常啟動鏡像.解決這個問題其實也非常簡單,只需要把環境變量COMPlus_EnableDiagnostics
的值設置為0
即可.
FROM microsoft/dotnet:2.2-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 52193
FROM microsoft/dotnet:2.2-sdk AS build
WORKDIR /src
COPY . .
WORKDIR "/src"
RUN dotnet build "ReadOnlyTest.csproj" -c Release -o /app
FROM build AS publish
RUN dotnet publish "ReadOnlyTest.csproj" -c Release -o /app
FROM base AS final
WORKDIR /app
ENV DOTNET_RUNNING_IN_CONTAINER=true
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
ENV COMPlus_EnableDiagnostics=0
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "ReadOnlyTest.dll"]
我們對這些環境變量進行簡單介紹
-
DOTNET_RUNNING_IN_CONTAINER
值設置為true時則表示應用運行在容器內,方便我們獲取程序的運行環境,然后根據環境做出不同決策(比如單元測試的時候,可能要根據項目是運行在windows,linux或者linux容器做出不同的測試策略).當然,你也可以設置其它的環境變量來方便自己使用,比如你鍵名稱設置為IsRunningInDocker
,但是DOTNET_RUNNING_IN_CONTAINER
-
DOTNET_CLI_TELEMETRY_OPTOUT
是否輸出遙測信息,如果設置為1則是關閉,這樣dotnet.exe就不會向調試窗口輸出遙測信息. -
COMPlus_EnableDiagnostics
目前沒有找到太多關於這個參數的詳細信息,只是查閱資源發現這開啟這項配置可以創建只讀權限 aspnet 應用程序.
微軟官方基礎鏡像里還包含一項名稱叫作
ASPNETCORE_VERSION
的環境變量,我們可以直接讀取它,這樣使用公共的環境變量一來避免息手動設置和更新的麻煩,二來便於和社區交流(自己定義約束的只能用於內部團隊交流)
我們如何使用這些環境變量呢,其它可以在程序里面暴露一個helper方法,比如
private bool InDocker { get { return Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") == "true";} }
這樣我們就可以根據實際的需求來使用它.
上面我們介紹了如何使用docker run命令以及docker-compose創建只讀文件系統.然而在kubernetes集群里,我們需要使用k8s的編排方法來創建只讀文件系統.那么在k8s里如何創建只讀文件系統.其實這里涉及到了另一個高級主題:那就是k8s的安全策略(Pod Security Policies)我們將在下一節介紹它.