使用內部 nuget url 編譯映像檔

公司內部大多都有建置內部使用的一些工具套件,但僅供內部使用

這邊會程現在 docker 盛行的年代,如何使用 ci/cd 自動建置,搭配自動拉取內部工具套件建置

之前有寫過怎麼自動化建置專案,並將相關的 nuget 推至內部 nuget server,可參考 這邊

不想要自己手動建 nuget server,用 docker 快速使用別人的也可以, liget / nexus 都是相當不錯的選擇

推送上的內部 nuget server 通常會被當作是 lib 集中管理的地方

通常我們再開發新的系統的時候,就會去透過設定內部 nuget url 的方式新增來源,這樣就能達到 lib 共用的效果

但是這些 lib 不適合被放至公開的 nuget server 上,那麼在內部環境在建置 docker images 的時候,就會需要在 docker file 上調整

假設 docker file 如下

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

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["nuget.config", "."]
COPY ["demo/demo.csproj", "demo/"]
RUN dotnet restore "demo/demo.csproj"
COPY . .
WORKDIR "/src/demo"
RUN dotnet build "demo.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "demo.csproj" -c Release -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "demo.dll", "--urls", "http://+:80"]

方法有很多種

  1. 在 server 上設定 global 使用的 nuget.config (較不偏好,因為之後要做 server migration 就要記得去做這些事)
  2. Docker build 的時候直接使用參考來源(這種較適用於沒有資安性質的)
    docker file 調整的部份,只需針對 dotnet restore 去調整就可以了 (這邊是使用 liget 在本機建置了一個 nuget 服務,並指定是用 9011 port)
    當 dotnet restore 找不到相關的 packages 時,就會往下一個找,所以內部的 nuget server 比較適合放在前面,也得小心自行開發的套件名稱有可能會跟 nuget.org 上的一樣
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["nuget.config", "."]
COPY ["demo/demo.csproj", "demo/"]
RUN dotnet restore -s "http://127.0.0.1:9011/api/v3/index.json" -s "https://api.nuget.org/v3/index.json"  "demo/demo.csproj"
COPY . .
WORKDIR "/src/demo"
RUN dotnet build "demo.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "demo.csproj" -c Release -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "demo.dll", "--urls", "http://+:80"]

3. 修改 nuget.config (可使用 user/pwd 登入的形式)

這邊使用的是 nexus 的方式進行拉取 package

這種修改形式不需要動到 docker file,只需要修改 nuget.config 就可以

這邊需要注意的是密碼是用明碼儲存,若不想使用明碼也可以參考其他型式

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="nuget" value="https://api.nuget.org/v3/index.json" />
    <add key="PrivateSource" value="http://internal.nexus.xxx/repository/nuget-hosted" />
  </packageSources>
  
   <packageSourceCredentials>
    <PrivateSource>
      <add key="Username" value="root" />
      <add key="ClearTextPassword" value="pwd" />
    </PrivateSource>
  </packageSourceCredentials>
</configuration>

如果覺得明碼太不安全,太不專業的話

可以先用 nuget 進行變更(如果 nuget 指令無法找到,得手動下載 nuget 的執行檔,並把執行檔的路徑加至 windows 的系統變數路徑下)

nuget sources update -Name "PrivateSource" -User root -Pass pwd

再去看 nuget.config 就可以發現密碼被加密了

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="nuget" value="https://api.nuget.org/v3/index.json" />
    <add key="PrivateSource" value="http://idc-pub-nexus.sportxxxr1pub.com/repository/nuget-hosted" />
  </packageSources>
  
   <packageSourceCredentials>
    <PrivateSource>
      <add key="Username" value="root" />
      <add key="Password" value="AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAA+Qylrq6BEUq+JW7FG0JMawAAAAACAAAAAAAQZgAAAAEAACAAAAChbuLBh+gUx/OBu1O1YsuS/dsozPGdhDEiXsZcMpuk7QAAAAAOgAAAAAIAACAAAAAAwqd8cBaIIpOS90sirp2noqjEDL06rezniInwfTbK6iAAAADJEun9ZJbddrov2sCPjgGlBt4KxASBrNUCBbVOrYdZoUAAAAAhw0ybI6IvrYjl3noER+7e9/XUmXxxhYqoPpL3+j/l8H4Hi6UaK0inboBmtrnSqI9JNk9eEBbcfBm7L17JT3wB" />
    </PrivateSource>
  </packageSourceCredentials>
</configuration>

4. 使用 api key 

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="nuget" value="https://api.nuget.org/v3/index.json" />
    <add key="PrivateSource" value="http://127.0.0.1:9011/api/v3/index.json" />
  </packageSources>
  
  <apikeys>
    <add key="http://127.0.0.1:9011/api/v3/index.json" value="NUGET-SERVER-API-KEY" />
  </apikeys>
</configuration>

也可以搭配 ci/cd 裡的變數增加安全性 (這裡使用的是 gitlab runner 做 ci/cd)


<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="nuget" value="https://api.nuget.org/v3/index.json" />
    <add key="PrivateSource" value="http://127.0.0.1:9011/api/v3/index.json" />
  </packageSources>
  
  <apikeys>
    <add key="http://127.0.0.1:9011/api/v3/index.json" value="$ligetApiKey" />
  </apikeys>
</configuration>

但抓取 nuget packages 似乎不能用 api key (目前只用來當 publish package 的用途),只能用其他方式,例如 user/pwd 的方式,請參考

參考資料

https://dotblogs.com.tw/AceLee/2020/05/11/200723

https://github.com/ai-traders/liget

https://learn.microsoft.com/en-us/nuget/reference/nuget-config-file#packagesourcecredentials

https://community.sonatype.com/t/why-does-authentication-not-working-with-nuget-in-nexus-3/1484/3