Skip to content

Commit fbd6099

Browse files
gfraiteurclaude
andcommitted
Migrate Docker image caching from GHCR to Azure Container Registry
Replace GHCR_REGISTRY/GHCR_TOKEN with DOCKER_REGISTRY/DOCKER_USERNAME/DOCKER_PASSWORD env vars, add local image check before pulling from registry, remove GHCR label from Dockerfiles, and mark McpApprovalServer as non-packable. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 05d7d1a commit fbd6099

File tree

13 files changed

+612
-595
lines changed

13 files changed

+612
-595
lines changed

DockerBuild.ps1

Lines changed: 60 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
- Collects environment variables and generates Init.g.ps1 for container startup
1414
- Mounts the source directory, NuGet cache, source-dependencies, and sibling repos
1515
- Handles non-C: drive letters on Windows via subst
16-
- Supports GHCR image caching for faster CI builds
16+
- Supports registry image caching for faster CI builds
1717
1818
.PARAMETER Interactive
1919
Opens an interactive PowerShell session inside the container.
@@ -554,8 +554,8 @@ try
554554
# Dictionary to track volume mounts with "writable wins" logic
555555
$script:VolumeMountDict = @{ }
556556

557-
# Background job for async GHCR push (if applicable)
558-
$script:GhcrPushJob = $null
557+
# Background job for async registry push (if applicable)
558+
$script:RegistryPushJob = $null
559559

560560
function Add-VolumeMount
561561
{
@@ -643,13 +643,13 @@ try
643643

644644
# Generate content-based hash for image tag
645645
$contentHash = Get-ContentHash -DockerfilePath $dockerfileFullPath -ContextDirectory $dockerContextDirectory
646-
$ghcrRegistry = $env:GHCR_REGISTRY
646+
$dockerRegistry = $env:DOCKER_REGISTRY
647647

648-
if ($ghcrRegistry)
648+
if ($dockerRegistry)
649649
{
650-
# GHCR mode: use registry URL with content hash
651-
$ImageTag = "${ghcrRegistry}:${contentHash}"
652-
Write-Host "GHCR image tag: $ImageTag" -ForegroundColor Cyan
650+
# Registry mode: use registry URL with image name and content hash
651+
$ImageTag = "${dockerRegistry}/build-${contentHash}:${contentHash}"
652+
Write-Host "Registry image tag: $ImageTag" -ForegroundColor Cyan
653653
}
654654
elseif ([string]::IsNullOrEmpty($ImageName))
655655
{
@@ -1410,50 +1410,57 @@ $envVarAssignments$gitConfigCommands$postInitCommands
14101410
}
14111411
}
14121412

1413-
# GHCR authentication and pull logic
1413+
# Registry authentication and pull logic
14141414
$builtNewImage = $false
14151415
$dockerConfigArg = @()
14161416

1417-
if ($ghcrRegistry -and -not $NoBuildImage -and -not $existingContainerId)
1417+
if ($dockerRegistry -and -not $NoBuildImage -and -not $existingContainerId)
14181418
{
1419-
# Extract registry host from full URL (e.g., ghcr.io from ghcr.io/owner/repo)
1420-
$registryHost = ($ghcrRegistry -split '/')[0]
1421-
1422-
# Create a temporary Docker config directory to avoid credential helper issues
1423-
# (e.g., docker-credential-desktop not found when using Docker Engine without Desktop)
1424-
$tempDockerConfig = Join-Path $env:TEMP "docker-config-$( New-Guid )"
1425-
New-Item -ItemType Directory -Path $tempDockerConfig -Force | Out-Null
1426-
@{ auths = @{ } } | ConvertTo-Json | Set-Content (Join-Path $tempDockerConfig "config.json")
1427-
$dockerConfigArg = @("--config", $tempDockerConfig)
1428-
1429-
# Authenticate to GHCR
1430-
$ghcrToken = $env:GHCR_TOKEN
1431-
if ($ghcrToken)
1432-
{
1433-
Write-Host "Authenticating to GHCR..." -ForegroundColor Gray
1434-
# GHCR accepts any username when using a PAT, commonly 'github' is used
1435-
$ghcrToken | docker @dockerConfigArg login $registryHost --username github --password-stdin 2> $null
1436-
if ($LASTEXITCODE -ne 0)
1437-
{
1438-
Write-Host "Warning: GHCR authentication failed. Pull/push may fail." -ForegroundColor Yellow
1439-
}
1440-
}
1441-
else
1442-
{
1443-
Write-Host "Warning: GHCR_TOKEN not set. GHCR pull/push may fail." -ForegroundColor Yellow
1444-
}
1445-
1446-
# Try to pull the image
1447-
Write-Host "Checking GHCR for existing image: $ImageTag" -ForegroundColor Cyan
1448-
docker @dockerConfigArg pull $ImageTag 2> $null
1419+
# Check if image already exists locally before pulling from registry
1420+
docker image inspect $ImageTag *> $null
14491421
if ($LASTEXITCODE -eq 0)
14501422
{
1451-
Write-Host "Using cached image from GHCR." -ForegroundColor Green
1423+
Write-Host "Using locally cached image: $ImageTag" -ForegroundColor Green
14521424
$NoBuildImage = $true
14531425
}
14541426
else
14551427
{
1456-
Write-Host "Image not found in GHCR, will build locally." -ForegroundColor Yellow
1428+
# Create a temporary Docker config directory to avoid credential helper issues
1429+
# (e.g., docker-credential-desktop not found when using Docker Engine without Desktop)
1430+
$tempDockerConfig = Join-Path $env:TEMP "docker-config-$( New-Guid )"
1431+
New-Item -ItemType Directory -Path $tempDockerConfig -Force | Out-Null
1432+
@{ auths = @{ } } | ConvertTo-Json | Set-Content (Join-Path $tempDockerConfig "config.json")
1433+
$dockerConfigArg = @("--config", $tempDockerConfig)
1434+
1435+
# Authenticate to registry
1436+
$dockerPassword = $env:DOCKER_PASSWORD
1437+
$dockerUsername = $env:DOCKER_USERNAME
1438+
if ($dockerPassword -and $dockerUsername)
1439+
{
1440+
Write-Host "Authenticating to registry..." -ForegroundColor Gray
1441+
$dockerPassword | docker @dockerConfigArg login $dockerRegistry --username $dockerUsername --password-stdin 2> $null
1442+
if ($LASTEXITCODE -ne 0)
1443+
{
1444+
Write-Host "Warning: Registry authentication failed. Pull/push may fail." -ForegroundColor Yellow
1445+
}
1446+
}
1447+
else
1448+
{
1449+
Write-Host "Warning: DOCKER_USERNAME/DOCKER_PASSWORD not set. Registry pull/push may fail." -ForegroundColor Yellow
1450+
}
1451+
1452+
# Try to pull the image
1453+
Write-Host "Checking registry for existing image: $ImageTag" -ForegroundColor Cyan
1454+
docker @dockerConfigArg pull $ImageTag 2> $null
1455+
if ($LASTEXITCODE -eq 0)
1456+
{
1457+
Write-Host "Using cached image from registry." -ForegroundColor Green
1458+
$NoBuildImage = $true
1459+
}
1460+
else
1461+
{
1462+
Write-Host "Image not found in registry, will build locally." -ForegroundColor Yellow
1463+
}
14571464
}
14581465
}
14591466

@@ -1534,12 +1541,12 @@ RUN if [ -n "`$MOUNTPOINTS" ]; then \
15341541

15351542
$builtNewImage = $true
15361543

1537-
# Auto-push to GHCR after successful build (async)
1544+
# Auto-push to registry after successful build (async)
15381545
$pushJob = $null
1539-
if ($ghcrRegistry)
1546+
if ($dockerRegistry)
15401547
{
1541-
Write-Host "Starting async push to GHCR: $ImageTag" -ForegroundColor Cyan
1542-
$script:GhcrPushJob = Start-Job -ScriptBlock {
1548+
Write-Host "Starting async push to registry: $ImageTag" -ForegroundColor Cyan
1549+
$script:RegistryPushJob = Start-Job -ScriptBlock {
15431550
docker @using:dockerConfigArg push $using:ImageTag 2>&1
15441551
$LASTEXITCODE
15451552
}
@@ -1802,14 +1809,14 @@ RUN if [ -n "`$MOUNTPOINTS" ]; then \
18021809
Write-Host "Skipping container run (BuildImage specified)." -ForegroundColor Yellow
18031810
}
18041811

1805-
# Check async GHCR push status if one was started
1806-
if ($script:GhcrPushJob)
1812+
# Check async registry push status if one was started
1813+
if ($script:RegistryPushJob)
18071814
{
18081815
Write-Host ""
1809-
Write-Host "Checking GHCR push status..." -ForegroundColor Cyan
1816+
Write-Host "Checking registry push status..." -ForegroundColor Cyan
18101817

18111818
# Wait for the job to complete with a timeout
1812-
$pushJob = $script:GhcrPushJob
1819+
$pushJob = $script:RegistryPushJob
18131820
$completed = Wait-Job -Job $pushJob -Timeout 300 # 5 minute timeout
18141821

18151822
if ($completed)
@@ -1820,11 +1827,11 @@ RUN if [ -n "`$MOUNTPOINTS" ]; then \
18201827

18211828
if ($exitCode -eq 0)
18221829
{
1823-
Write-Host "GHCR push completed successfully" -ForegroundColor Green
1830+
Write-Host "Registry push completed successfully" -ForegroundColor Green
18241831
}
18251832
else
18261833
{
1827-
Write-Host "GHCR push failed with exit code $exitCode" -ForegroundColor Yellow
1834+
Write-Host "Registry push failed with exit code $exitCode" -ForegroundColor Yellow
18281835
if ($output)
18291836
{
18301837
Write-Host "Push output: $output" -ForegroundColor Gray
@@ -1833,7 +1840,7 @@ RUN if [ -n "`$MOUNTPOINTS" ]; then \
18331840
}
18341841
else
18351842
{
1836-
Write-Host "GHCR push timed out (still running in background)" -ForegroundColor Yellow
1843+
Write-Host "Registry push timed out (still running in background)" -ForegroundColor Yellow
18371844
Stop-Job -Job $pushJob
18381845
}
18391846

eng/docker/Dockerfile

Lines changed: 79 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,79 @@
1-
# escape=`
2-
3-
# This file is auto-generated by PostSharp.Engineering.
4-
5-
FROM mcr.microsoft.com/windows/servercore:ltsc2025
6-
7-
# The initial shell is Windows PowerShell (use full path to avoid HCS issues)
8-
SHELL ["C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", "-Command"]
9-
10-
# Prepare environment
11-
ENV PSExecutionPolicyPreference=Bypass
12-
ENV POWERSHELL_UPDATECHECK=Off
13-
ENV TEMP=C:\Temp
14-
ENV TMP=C:\Temp
15-
ENV RUNNING_IN_DOCKER=TRUE
16-
17-
# Set locale for consistent behavior regardless of host locale
18-
ENV LANG=C.UTF-8
19-
ENV LC_ALL=C.UTF-8
20-
ENV DOTNET_CLI_UI_LANGUAGE=en
21-
ENV VSLANG=1033
22-
23-
# Set base PATH explicitly to avoid issues with expansion
24-
ENV PATH="C:\Windows\System32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0"
25-
26-
# Enable long path support
27-
RUN Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' -Value 1
28-
29-
30-
31-
# Install Git
32-
RUN Invoke-WebRequest -Uri https://github.com/git-for-windows/git/releases/download/v2.50.0.windows.1/PortableGit-2.50.0-64-bit.7z.exe -OutFile PortableGit.exe; `
33-
Start-Process -FilePath .\PortableGit.exe -ArgumentList '-o"C:\git"', '-y' -Wait; `
34-
Remove-Item PortableGit.exe
35-
36-
# Add git to PATH using ENV directive (persists across shell switches)
37-
ENV PATH="C:\git\cmd;C:\git\bin;C:\git\usr\bin;${PATH}"
38-
39-
RUN git config --system core.longpaths true; git config --system core.autocrlf false
40-
41-
# Set CLAUDE_CODE_GIT_BASH_PATH for Claude Code
42-
ENV CLAUDE_CODE_GIT_BASH_PATH=C:\git\bin\bash.exe
43-
44-
45-
# Install PowerShell 7
46-
RUN Invoke-WebRequest -Uri https://github.com/PowerShell/PowerShell/releases/download/v7.5.2/PowerShell-7.5.2-win-x64.msi -OutFile PowerShell.msi; `
47-
$process = Start-Process msiexec.exe -Wait -PassThru -ArgumentList '/I PowerShell.msi /quiet'; `
48-
if ($process.ExitCode -ne 0) { exit $process.ExitCode }; `
49-
Remove-Item PowerShell.msi
50-
51-
ENV PATH="C:\Program Files\PowerShell\7;${PATH}"
52-
53-
54-
# Download .NET Installer
55-
RUN Invoke-WebRequest -Uri https://dot.net/v1/dotnet-install.ps1 -OutFile dotnet-install.ps1
56-
57-
# Add .NET to PATH using ENV directive (persists across shell switches)
58-
ENV PATH="C:\Program Files\dotnet;${PATH}"
59-
60-
61-
# Install .NET Sdk 9.0.310
62-
RUN & .\dotnet-install.ps1 -Version 9.0.310 -InstallDir 'C:\Program Files\dotnet'
63-
64-
65-
# Epilogue
66-
# Link to private repository for GHCR visibility
67-
LABEL org.opencontainers.image.source=https://github.com/postsharp/PostSharp.Engineering.Images
68-
69-
# Create directories for mountpoints
70-
ARG MOUNTPOINTS
71-
RUN if ($env:MOUNTPOINTS) { `
72-
$mounts = $env:MOUNTPOINTS -split ';'; `
73-
foreach ($dir in $mounts) { `
74-
if ($dir) { `
75-
Write-Host "Creating directory $dir`."; `
76-
New-Item -ItemType Directory -Path $dir -Force | Out-Null; `
77-
} `
78-
} `
79-
}
80-
81-
# Configure .NET SDK
82-
ENV DOTNET_NOLOGO=1
1+
# escape=`
2+
3+
# This file is auto-generated by PostSharp.Engineering.
4+
5+
FROM mcr.microsoft.com/windows/servercore:ltsc2025
6+
7+
# The initial shell is Windows PowerShell (use full path to avoid HCS issues)
8+
SHELL ["C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", "-Command"]
9+
10+
# Prepare environment
11+
ENV PSExecutionPolicyPreference=Bypass
12+
ENV POWERSHELL_UPDATECHECK=Off
13+
ENV TEMP=C:\Temp
14+
ENV TMP=C:\Temp
15+
ENV RUNNING_IN_DOCKER=TRUE
16+
17+
# Set locale for consistent behavior regardless of host locale
18+
ENV LANG=C.UTF-8
19+
ENV LC_ALL=C.UTF-8
20+
ENV DOTNET_CLI_UI_LANGUAGE=en
21+
ENV VSLANG=1033
22+
23+
# Set base PATH explicitly to avoid issues with expansion
24+
ENV PATH="C:\Windows\System32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0"
25+
26+
# Enable long path support
27+
RUN Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' -Value 1
28+
29+
30+
31+
# Install Git
32+
RUN Invoke-WebRequest -Uri https://github.com/git-for-windows/git/releases/download/v2.50.0.windows.1/PortableGit-2.50.0-64-bit.7z.exe -OutFile PortableGit.exe; `
33+
Start-Process -FilePath .\PortableGit.exe -ArgumentList '-o"C:\git"', '-y' -Wait; `
34+
Remove-Item PortableGit.exe
35+
36+
# Add git to PATH using ENV directive (persists across shell switches)
37+
ENV PATH="C:\git\cmd;C:\git\bin;C:\git\usr\bin;${PATH}"
38+
39+
RUN git config --system core.longpaths true; git config --system core.autocrlf false
40+
41+
# Set CLAUDE_CODE_GIT_BASH_PATH for Claude Code
42+
ENV CLAUDE_CODE_GIT_BASH_PATH=C:\git\bin\bash.exe
43+
44+
45+
# Install PowerShell 7
46+
RUN Invoke-WebRequest -Uri https://github.com/PowerShell/PowerShell/releases/download/v7.5.2/PowerShell-7.5.2-win-x64.msi -OutFile PowerShell.msi; `
47+
$process = Start-Process msiexec.exe -Wait -PassThru -ArgumentList '/I PowerShell.msi /quiet'; `
48+
if ($process.ExitCode -ne 0) { exit $process.ExitCode }; `
49+
Remove-Item PowerShell.msi
50+
51+
ENV PATH="C:\Program Files\PowerShell\7;${PATH}"
52+
53+
54+
# Download .NET Installer
55+
RUN Invoke-WebRequest -Uri https://dot.net/v1/dotnet-install.ps1 -OutFile dotnet-install.ps1
56+
57+
# Add .NET to PATH using ENV directive (persists across shell switches)
58+
ENV PATH="C:\Program Files\dotnet;${PATH}"
59+
60+
61+
# Install .NET Sdk 9.0.310
62+
RUN & .\dotnet-install.ps1 -Version 9.0.310 -InstallDir 'C:\Program Files\dotnet'
63+
64+
65+
# Epilogue
66+
# Create directories for mountpoints
67+
ARG MOUNTPOINTS
68+
RUN if ($env:MOUNTPOINTS) { `
69+
$mounts = $env:MOUNTPOINTS -split ';'; `
70+
foreach ($dir in $mounts) { `
71+
if ($dir) { `
72+
Write-Host "Creating directory $dir`."; `
73+
New-Item -ItemType Directory -Path $dir -Force | Out-Null; `
74+
} `
75+
} `
76+
}
77+
78+
# Configure .NET SDK
79+
ENV DOTNET_NOLOGO=1

0 commit comments

Comments
 (0)