# Default arguments ARG gitWindowsComponent='https://github.com/git-for-windows/git/releases/download/v2.54.0.windows.1/MinGit-2.54.0-64-bit.zip' ARG gitWindowsComponentSHA256='04f937e1f0918b17b9be6f2294cb2bb66e96e1d9832d1c298e2de088a1d0e668' ARG jdkServerWindowsComponent='https://corretto.aws/downloads/resources/21.0.10.7.1/amazon-corretto-21.0.10.7.1-windows-x64-jdk.zip' ARG jdkServerWindowsComponentMD5SUM='403888fc1d84a8d7a823ad7ff3ecc589' ARG nanoserverImage='mcr.microsoft.com/windows/nanoserver:ltsc2022' ARG powershellImage='mcr.microsoft.com/powershell:nanoserver-ltsc2022' ARG windowsBuild='2022' # The list of required arguments # ARG powershellImage # ARG jdkServerWindowsComponent # ARG jdkServerWindowsComponentMD5SUM # ARG gitWindowsComponent # ARG gitWindowsComponentSHA256 # ARG windowsBuild # ARG powershellImage # PowerShell FROM ${powershellImage} AS base # On some agents, Windows 2022 requires administrator permissions to modify "C:/" folder within ... # ... PowerShell container. USER ContainerAdministrator COPY scripts/*.cs /scripts/ SHELL ["pwsh", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] # JDK ARG jdkServerWindowsComponent ARG jdkServerWindowsComponentMD5SUM # Git ARG gitWindowsComponent ARG gitWindowsComponentSHA256 RUN [Net.ServicePointManager]::SecurityProtocol = 'tls12, tls11, tls' ; \ $code = Get-Content -Path "scripts/Web.cs" -Raw ; \ # Use basic parsing to prevent errors in Windows Server 2022 $Global:ProgressPreference = 'SilentlyContinue' ; \ $Global:UseBasicParsing = $true ; \ # Download actual target files Add-Type -IgnoreWarnings -TypeDefinition "$code" -Language CSharp ; \ $downloadScript = [Scripts.Web]::DownloadFiles($Env:jdkServerWindowsComponent + '#MD5#' + $Env:jdkServerWindowsComponentMD5SUM, 'jdk.zip', $Env:gitWindowsComponent + '#SHA256#' + $Env:gitWindowsComponentSHA256, 'git.zip') ; \ iex $downloadScript ; \ Expand-Archive jdk.zip -DestinationPath $Env:ProgramFiles\Java ; \ Get-ChildItem $Env:ProgramFiles\Java | Rename-Item -NewName "OpenJDK" ; \ Remove-Item -Force jdk.zip ; \ Remove-Item $Env:ProgramFiles\Java\OpenJDK\lib\src.zip -Force ; \ Expand-Archive git.zip -DestinationPath $Env:ProgramFiles\Git ; \ # https://youtrack.jetbrains.com/issue/TW-73017 (Get-Content 'C:\Program Files\Git\etc\gitconfig') -replace 'path = C:/Program Files/Git/etc/gitconfig', '' | Set-Content 'C:\Program Files\Git\etc\gitconfig' ; \ Remove-Item -Force git.zip # Prepare TeamCity server distribution ARG windowsBuild COPY TeamCity /TeamCity RUN New-Item C:/TeamCity/webapps/ROOT/WEB-INF/DistributionType.txt -type file -force -value "docker-windows-$Env:windowsBuild" | Out-Null COPY run-server.ps1 /TeamCity/run-server.ps1 USER ContainerUser # Workaround for https://github.com/PowerShell/PowerShell-Docker/issues/164 ARG nanoserverImage FROM ${nanoserverImage} ENV ProgramFiles="C:\Program Files" \ # set a fixed location for the Module analysis cache PSModuleAnalysisCachePath="C:\Users\ContainerUser\AppData\Local\Microsoft\Windows\PowerShell\docker\ModuleAnalysisCache" \ # Persist %PSCORE% ENV variable for user convenience PSCORE="$ProgramFiles\PowerShell\pwsh.exe" COPY --from=base ["C:/Program Files/PowerShell", "C:/Program Files/PowerShell"] # In order to set system PATH, ContainerAdministrator must be used USER ContainerAdministrator RUN setx /M PATH "%PATH%;%ProgramFiles%\PowerShell" USER ContainerUser # intialize powershell module cache RUN pwsh -NoLogo -NoProfile -Command " \ $stopTime = (get-date).AddMinutes(15); \ $ErrorActionPreference = 'Stop' ; \ $ProgressPreference = 'SilentlyContinue' ; \ while(!(Test-Path -Path $env:PSModuleAnalysisCachePath)) { \ Write-Host "'Waiting for $env:PSModuleAnalysisCachePath'" ; \ if((get-date) -gt $stopTime) { throw 'timout expired'} \ Start-Sleep -Seconds 6 ; \ }" COPY --from=base ["C:/Program Files/Java/OpenJDK", "C:/Program Files/Java/OpenJDK"] COPY --from=base ["C:/Program Files/Git", "C:/Program Files/Git"] ENV JAVA_HOME="C:\Program Files\Java\OpenJDK" \ TEAMCITY_DIST="C:\TeamCity" \ TEAMCITY_ENV=container \ CATALINA_TMPDIR="C:\TeamCity\temp" \ TEAMCITY_LOGS="C:\TeamCity\logs" \ TEAMCITY_DATA_PATH="C:\ProgramData\JetBrains\TeamCity" \ TEAMCITY_SERVER_MEM_OPTS="-Xmx2g -XX:ReservedCodeCacheSize=640m" EXPOSE 8111 COPY --from=base $TEAMCITY_DIST $TEAMCITY_DIST CMD ["pwsh", "C:/TeamCity/run-server.ps1"] # Use ContainerAdministrator to update permissions and PATH USER ContainerAdministrator # Grant Permissions for ContainerUser (Default Account), OI - Object Inherit, CI - Container Inherit, ... # ... F - full control, /T - apply to subfolders & files RUN setx /M PATH "%PATH%;%JAVA_HOME%\bin;C:\Program Files\Git\cmd" && \ cmd /c icacls.exe C:\\TeamCity /reset /T && \ cmd /c icacls.exe C:\\TeamCity /grant:r DefaultAccount:(OI)(CI)F /grant:r Users:(OI)(CI)F /T && \ pwsh -Command "& { <# Canonicalizing ACLs to prevent issues such as TW-100061 #> $acl = Get-Acl 'C:\TeamCity'; Set-Acl 'C:\TeamCity' $acl; Get-ChildItem 'C:\TeamCity' -Recurse -Force | ForEach-Object { $a = Get-Acl $_.FullName; Set-Acl $_.FullName $a }; $acl = Get-Acl 'C:\TeamCity'; if (-not $acl.AreAccessRulesCanonical) { throw 'ACLs are not canonical after Set-Acl on C:\TeamCity' } }" && \ cmd /c icacls.exe C:\\TeamCity\\* USER ContainerUser VOLUME $TEAMCITY_DATA_PATH \ $TEAMCITY_LOGS \ $CATALINA_TMPDIR