-
Notifications
You must be signed in to change notification settings - Fork 86
Linux CI + Dockerfile + nightly container image (#1804 stage 3) #2049
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| # Keep the Darling image build context lean (#1804): the Dockerfile copies source and publishes | ||
| # inside the build stage, so nothing prebuilt, versioned-binary, or platform-foreign belongs in it. | ||
| .git | ||
| .github | ||
| **/bin | ||
| **/obj | ||
| **/publish | ||
| releases | ||
| Darling/artifacts | ||
| deprecated | ||
| docs | ||
| *.md | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -728,3 +728,64 @@ jobs: | |||||||||||||
| ${{ runner.temp }}/darling-pg.log | ||||||||||||||
| TestResults/ | ||||||||||||||
| if-no-files-found: ignore | ||||||||||||||
|
|
||||||||||||||
| # ── Linux service build + container image (#1804) ──────────────────────────────────────────────── | ||||||||||||||
| # The Darling service is cross-platform .NET on purpose, but until this job nothing PROVED it on | ||||||||||||||
| # every PR — the linux-x64 publish and the container image both built for the first time at release | ||||||||||||||
| # time or never. Same path-filter shape as darling-pg above: only runs the expensive work when | ||||||||||||||
| # Darling/service code (or this workflow, or the Dockerfile) changed, always reports a result so it | ||||||||||||||
| # can be a required check. No tests run here — the test projects are net10.0-windows (they reference | ||||||||||||||
| # the WPF apps); the cross-platform behavior they pin is exercised by the Windows jobs, and the | ||||||||||||||
| # container smoke lives in the compose quickstart. This job answers exactly two questions: does the | ||||||||||||||
| # service still publish for linux-x64, and does the image still build. | ||||||||||||||
| darling-linux: | ||||||||||||||
| name: Darling Linux build | ||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||
| timeout-minutes: 30 | ||||||||||||||
| permissions: | ||||||||||||||
| contents: read | ||||||||||||||
|
|
||||||||||||||
| steps: | ||||||||||||||
| - uses: actions/checkout@v7 | ||||||||||||||
|
|
||||||||||||||
| - name: Detect changed paths | ||||||||||||||
| id: filter | ||||||||||||||
| if: github.event_name != 'release' | ||||||||||||||
| uses: dorny/paths-filter@v4 | ||||||||||||||
| with: | ||||||||||||||
| base: ${{ github.event_name == 'push' && github.event.before || '' }} | ||||||||||||||
| filters: | | ||||||||||||||
| darling: | ||||||||||||||
| - 'Darling/**/!(*.md)' | ||||||||||||||
| - 'PerformanceMonitor.Common/**' | ||||||||||||||
| - 'PerformanceMonitor.Collectors/**' | ||||||||||||||
| - 'PerformanceMonitor.Analysis/**' | ||||||||||||||
|
Comment on lines
+760
to
+762
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These three lines are missing the The comment block above the Suggest matching the established convention:
Suggested change
|
||||||||||||||
| - '.github/workflows/build.yml' | ||||||||||||||
|
|
||||||||||||||
| - name: Report the Linux gate decision | ||||||||||||||
| shell: bash | ||||||||||||||
| run: | | ||||||||||||||
| set -euo pipefail | ||||||||||||||
| if [ "${{ github.event_name }}" = "release" ]; then | ||||||||||||||
| echo "::notice title=Darling Linux build skipped::Release event - the dev push that produced this commit already ran it." | ||||||||||||||
| elif [ "${{ steps.filter.outputs.darling }}" = "true" ]; then | ||||||||||||||
| echo "::notice title=Darling Linux build running::Darling/service code (or this workflow) changed." | ||||||||||||||
| else | ||||||||||||||
| echo "::notice title=Darling Linux build skipped::No Darling/service code changed." | ||||||||||||||
| fi | ||||||||||||||
|
|
||||||||||||||
| - name: Setup .NET 10.0 | ||||||||||||||
| if: steps.filter.outputs.darling == 'true' | ||||||||||||||
| uses: actions/setup-dotnet@v6 | ||||||||||||||
| with: | ||||||||||||||
| global-json-file: global.json | ||||||||||||||
| cache: true | ||||||||||||||
| cache-dependency-path: '**/packages.lock.json' | ||||||||||||||
|
|
||||||||||||||
| - name: Publish service (linux-x64) | ||||||||||||||
| if: steps.filter.outputs.darling == 'true' | ||||||||||||||
| run: dotnet publish Darling/PerformanceMonitor.Darling.Service/PerformanceMonitor.Darling.Service.csproj -c Release -r linux-x64 --self-contained false -o publish/DarlingService-linux | ||||||||||||||
|
|
||||||||||||||
| - name: Build container image | ||||||||||||||
| if: steps.filter.outputs.darling == 'true' | ||||||||||||||
| run: docker build -f Darling/Dockerfile -t performancemonitor-darling:pr . | ||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,8 @@ on: | |
|
|
||
| permissions: | ||
| contents: write | ||
| # #1804: the linux job pushes the nightly container image to ghcr. | ||
| packages: write | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This adds |
||
|
|
||
| jobs: | ||
| # Scheduled workflows always execute the DEFAULT branch's copy of this file, while nightly | ||
|
|
@@ -389,3 +391,66 @@ jobs: | |
| ${{ runner.temp }}/darling-pg.log | ||
| TestResults/ | ||
| if-no-files-found: ignore | ||
|
|
||
| # ── Linux artifact + container image (#1804) ───────────────────────────────────────────────────── | ||
| # Runs AFTER the windows build job so the nightly release exists to upload into. Publishes the | ||
| # linux-x64 service tar.gz with its own checksum file (the windows job owns SHA256SUMS.txt; a | ||
| # cross-job rewrite of one file is a race), and pushes the service image to ghcr tagged :nightly. | ||
| # The bundled pg-runtime is deliberately absent from the linux artifact — the compose distribution | ||
| # pairs the service with the official timescale/timescaledb image, and managed mode stays Windows. | ||
| linux: | ||
| needs: build | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 30 | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| with: | ||
| ref: dev | ||
|
|
||
| - name: Setup .NET 10.0 | ||
| uses: actions/setup-dotnet@v6 | ||
| with: | ||
| global-json-file: global.json | ||
| cache: true | ||
| cache-dependency-path: '**/packages.lock.json' | ||
|
|
||
| - name: Set nightly version | ||
| id: version | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
| base=$(grep -oPm1 '(?<=<Version>)[^<]+' Lite/PerformanceMonitorLite.csproj) | ||
| date=$(date +%Y%m%d) | ||
| echo "VERSION=${base}-nightly.${date}" >> "$GITHUB_OUTPUT" | ||
| echo "Nightly version: ${base}-nightly.${date}" | ||
|
|
||
| - name: Publish service (linux-x64) | ||
| run: dotnet publish Darling/PerformanceMonitor.Darling.Service/PerformanceMonitor.Darling.Service.csproj -c Release -r linux-x64 --self-contained false -o publish/DarlingService-linux | ||
|
|
||
| - name: Package linux artifact + checksum | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
| version="${{ steps.version.outputs.VERSION }}" | ||
| mkdir -p releases | ||
| tar -C publish/DarlingService-linux -czf "releases/PerformanceMonitorDarling-linux-x64-${version}.tar.gz" . | ||
| (cd releases && sha256sum "PerformanceMonitorDarling-linux-x64-${version}.tar.gz" > SHA256SUMS-linux.txt && cat SHA256SUMS-linux.txt) | ||
|
|
||
| - name: Upload linux artifact to the nightly release | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: gh release upload nightly releases/PerformanceMonitorDarling-linux-x64-*.tar.gz releases/SHA256SUMS-linux.txt --clobber | ||
|
|
||
| - name: Build and push container image (ghcr, :nightly) | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
| version="${{ steps.version.outputs.VERSION }}" | ||
| image="ghcr.io/${{ github.repository_owner }}/performancemonitor-darling" | ||
| echo "$GH_TOKEN" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin | ||
| docker build -f Darling/Dockerfile -t "${image}:nightly" -t "${image}:${version}" . | ||
| docker push "${image}:nightly" | ||
| docker push "${image}:${version}" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| # The Darling service container (#1804) — builds from source so `docker build` works from any checkout: | ||
| # | ||
| # docker build -f Darling/Dockerfile -t performancemonitor-darling . | ||
| # | ||
| # Build context is the REPO ROOT (the service references PerformanceMonitor.Common / .Collectors / | ||
| # .Analysis / Darling.Storage by project). The runtime stage is the official aspnet image (the service | ||
| # hosts the web dashboard + MCP endpoint on Kestrel) and sets DOTNET_RUNNING_IN_CONTAINER, which is what | ||
| # the bind ladder's container gate keys on — network exposure with the mandatory token/CIDR works here | ||
| # under postgres.managed = false, because the compose port mapping is the boundary. | ||
| # | ||
| # The bundled zero-admin store is Windows-only BY DESIGN and never runs in this image: pair the container | ||
| # with the official timescale/timescaledb image (see the compose file) and keep postgres.managed = false. | ||
| # Secrets never land in darling.json — use env:/file: references (#1804 stage 1), which are compose | ||
| # `secrets:`-friendly. | ||
|
|
||
| FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build | ||
| WORKDIR /src | ||
| COPY . . | ||
| RUN dotnet publish Darling/PerformanceMonitor.Darling.Service/PerformanceMonitor.Darling.Service.csproj \ | ||
| -c Release -o /app/publish | ||
|
|
||
| FROM mcr.microsoft.com/dotnet/aspnet:10.0 | ||
| # Microsoft.Data.SqlClient probes the Kerberos GSSAPI library at connect time on Linux — even for SQL | ||
| # auth — and the aspnet base image does not carry it. Found the hard way in the #1804 container smoke. | ||
| RUN apt-get update \ | ||
| && apt-get install -y --no-install-recommends libgssapi-krb5-2 \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
| WORKDIR /app | ||
| COPY --from=build /app/publish . | ||
|
|
||
| # The config mount point the compose file uses; override DARLING_CONFIG to relocate. | ||
| ENV DARLING_CONFIG=/config/darling.json | ||
|
|
||
| # Web dashboard + MCP (both opt-in via darling.json; exposed here only behind their token gates). | ||
| EXPOSE 5153 5152 | ||
|
|
||
| ENTRYPOINT ["dotnet", "PerformanceMonitor.Darling.Service.dll"] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -232,10 +232,14 @@ internal static IReadOnlyList<string> GetNetworkStartupWarnings(DarlingConfig co | |
| "postgres.network.* is set but postgres.managed is false — it is IGNORED in bring-your-own mode; your own PostgreSQL governs its network exposure (pg_hba / listen_addresses / TLS)."); | ||
| } | ||
|
|
||
| if (config.Mcp.Network?.IsConfigured == true) | ||
| /* #1804: in a container the mcp/web network blocks ARE honored (the bind ladder's container | ||
| gate), so this notice would be a lie there — the smoke test caught it warning IGNORED in | ||
| the same breath as 'Starting MCP server on 0.0.0.0'. The postgres.network notice above | ||
| stays: the bundled store never runs in BYO mode, container or not. */ | ||
| if (config.Mcp.Network?.IsConfigured == true && !Hosting.DarlingHostBinding.IsRunningInContainer) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Compare with the established pattern for exactly this problem elsewhere in the same PR/area: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This new suppression branch reads This is also a departure from the pattern Right now the container-suppression behavior is only verified by the manual live-container smoke described in the PR body, not by CI. |
||
| { | ||
| warnings.Add( | ||
| "mcp.network.* is set but postgres.managed is false — the MCP network endpoint is managed-mode only, so it is IGNORED; the MCP server stays loopback-only."); | ||
| "mcp.network.* is set but postgres.managed is false — the MCP network endpoint is managed-mode (or container, #1804) only, so it is IGNORED; the MCP server stays loopback-only."); | ||
| } | ||
|
|
||
| return warnings; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the build context is the raw filesystem (not
git),.dockerignoredoesn't inherit.gitignore's exclusions — and the root.gitignoreexplicitly calls outappsettings.jsonas "Sensitive configuration (connection strings)" that's never committed but commonly present in a dev's working tree. The Dockerfile'sCOPY . .(repo root context) would pick up any such locally-present, git-ignored secret-bearing file on a plain localdocker build, and since the service project isSdk="Microsoft.NET.Sdk.Worker", a same-directoryappsettings*.jsonis copied into the publish output too.Worth mirroring the sensitive-file exclusions from
.gitignorehere (appsettings.jsonat minimum) as defense-in-depth, even though CI's checkout is always clean.