Add Windows deploy script
This commit is contained in:
167
scripts/deploy.ps1
Normal file
167
scripts/deploy.ps1
Normal file
@@ -0,0 +1,167 @@
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
function Require-Tool {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$Name
|
||||
)
|
||||
|
||||
if ($null -eq (Get-Command $Name -ErrorAction SilentlyContinue)) {
|
||||
throw "Required tool not found: $Name"
|
||||
}
|
||||
}
|
||||
|
||||
function Invoke-NativeCommand {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$Name,
|
||||
[Parameter(Mandatory = $true)][scriptblock]$Action
|
||||
)
|
||||
|
||||
Write-Host $Name
|
||||
& $Action
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Step failed: $Name"
|
||||
}
|
||||
}
|
||||
|
||||
function Get-RemoteScript {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$RemoteReleaseDir,
|
||||
[Parameter(Mandatory = $true)][string]$RemoteCurrentLink,
|
||||
[Parameter(Mandatory = $true)][string]$ContainerName,
|
||||
[Parameter(Mandatory = $true)][string]$ImageName,
|
||||
[Parameter(Mandatory = $true)][string]$ReleaseTimestamp,
|
||||
[Parameter(Mandatory = $true)][string]$RemoteDataDir,
|
||||
[Parameter(Mandatory = $true)][string]$ContainerPort,
|
||||
[Parameter(Mandatory = $true)][string]$HostPort
|
||||
)
|
||||
|
||||
$script = @'
|
||||
set -euo pipefail
|
||||
|
||||
remote_release_dir='__REMOTE_RELEASE_DIR__'
|
||||
remote_current_link='__REMOTE_CURRENT_LINK__'
|
||||
container_name='__CONTAINER_NAME__'
|
||||
image_name='__IMAGE_NAME__'
|
||||
release_timestamp='__RELEASE_TIMESTAMP__'
|
||||
remote_data_dir='__REMOTE_DATA_DIR__'
|
||||
container_port='__CONTAINER_PORT__'
|
||||
host_port='__HOST_PORT__'
|
||||
|
||||
previous_current_target=''
|
||||
if [ -L "${remote_current_link}" ]; then
|
||||
previous_current_target="$(readlink -f "${remote_current_link}")"
|
||||
fi
|
||||
|
||||
docker build -t "${image_name}:${release_timestamp}" -t "${image_name}:latest" "${remote_release_dir}"
|
||||
ln -sfn "${remote_release_dir}" "${remote_current_link}"
|
||||
|
||||
if docker ps -aq --filter "name=^/${container_name}$" | grep -q .; then
|
||||
docker rm -f "${container_name}" >/dev/null
|
||||
fi
|
||||
|
||||
if ! docker run -d \
|
||||
--name "${container_name}" \
|
||||
--restart unless-stopped \
|
||||
-p "127.0.0.1:${host_port}:${container_port}" \
|
||||
-e ASPNETCORE_ENVIRONMENT=Production \
|
||||
-e ASPNETCORE_URLS="http://+:${container_port}" \
|
||||
-e ConnectionStrings__RpgRoller="Data Source=/app/data/rpgroller.db" \
|
||||
-v "${remote_data_dir}:/app/data" \
|
||||
"${image_name}:${release_timestamp}" >/dev/null; then
|
||||
if [ -n "${previous_current_target}" ]; then
|
||||
ln -sfn "${previous_current_target}" "${remote_current_link}"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
'@
|
||||
|
||||
return $script.
|
||||
Replace("__REMOTE_RELEASE_DIR__", $RemoteReleaseDir).
|
||||
Replace("__REMOTE_CURRENT_LINK__", $RemoteCurrentLink).
|
||||
Replace("__CONTAINER_NAME__", $ContainerName).
|
||||
Replace("__IMAGE_NAME__", $ImageName).
|
||||
Replace("__RELEASE_TIMESTAMP__", $ReleaseTimestamp).
|
||||
Replace("__REMOTE_DATA_DIR__", $RemoteDataDir).
|
||||
Replace("__CONTAINER_PORT__", $ContainerPort).
|
||||
Replace("__HOST_PORT__", $HostPort)
|
||||
}
|
||||
|
||||
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$repoRoot = Split-Path -Parent $scriptDir
|
||||
$projectPath = Join-Path $repoRoot "RpgRoller\RpgRoller.csproj"
|
||||
|
||||
$remoteHost = "myvserver"
|
||||
$remoteRoot = "/root/docker/rpgroller"
|
||||
$remoteReleasesDir = "$remoteRoot/releases"
|
||||
$remoteCurrentLink = "$remoteRoot/current"
|
||||
$remoteDataDir = "$remoteRoot/data"
|
||||
|
||||
$containerName = "rpgroller"
|
||||
$imageName = "rpgroller"
|
||||
$containerPort = "8080"
|
||||
$hostPort = "8082"
|
||||
$releaseTimestamp = (Get-Date).ToUniversalTime().ToString("yyyyMMddHHmmss")
|
||||
$localStageDir = Join-Path $repoRoot "artifacts\deploy\$releaseTimestamp"
|
||||
$localPublishDir = Join-Path $localStageDir "publish"
|
||||
$remoteReleaseDir = "$remoteReleasesDir/$releaseTimestamp"
|
||||
|
||||
Write-Host "Deploying release $releaseTimestamp"
|
||||
|
||||
Require-Tool -Name "dotnet"
|
||||
Require-Tool -Name "ssh"
|
||||
Require-Tool -Name "scp"
|
||||
|
||||
try {
|
||||
New-Item -ItemType Directory -Path $localPublishDir -Force | Out-Null
|
||||
|
||||
Invoke-NativeCommand -Name "1) Publishing app locally..." -Action {
|
||||
dotnet publish $projectPath -c Release -o $localPublishDir
|
||||
}
|
||||
|
||||
@'
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:10.0
|
||||
WORKDIR /app
|
||||
ENV ASPNETCORE_URLS=http://+:8080
|
||||
ENV DOTNET_EnableDiagnostics=0
|
||||
EXPOSE 8080
|
||||
COPY publish/ ./
|
||||
RUN mkdir -p /app/data
|
||||
ENTRYPOINT ["dotnet", "RpgRoller.dll"]
|
||||
'@ | Set-Content -Path (Join-Path $localStageDir "Dockerfile") -NoNewline
|
||||
|
||||
Invoke-NativeCommand -Name "2) Preparing remote release directory..." -Action {
|
||||
ssh $remoteHost "mkdir -p '$remoteReleasesDir' '$remoteDataDir' && test ! -e '$remoteReleaseDir' && mkdir -p '$remoteReleaseDir'"
|
||||
}
|
||||
|
||||
Invoke-NativeCommand -Name "3) Uploading release payload..." -Action {
|
||||
Push-Location $localStageDir
|
||||
try {
|
||||
scp -r "Dockerfile" "publish" "${remoteHost}:$remoteReleaseDir/"
|
||||
}
|
||||
finally {
|
||||
Pop-Location
|
||||
}
|
||||
}
|
||||
|
||||
$remoteScript = Get-RemoteScript `
|
||||
-RemoteReleaseDir $remoteReleaseDir `
|
||||
-RemoteCurrentLink $remoteCurrentLink `
|
||||
-ContainerName $containerName `
|
||||
-ImageName $imageName `
|
||||
-ReleaseTimestamp $releaseTimestamp `
|
||||
-RemoteDataDir $remoteDataDir `
|
||||
-ContainerPort $containerPort `
|
||||
-HostPort $hostPort
|
||||
|
||||
Invoke-NativeCommand -Name "4) Building image and restarting container on remote host..." -Action {
|
||||
$remoteScript | ssh $remoteHost "bash -se"
|
||||
}
|
||||
|
||||
Write-Host "5) Deployment complete."
|
||||
}
|
||||
finally {
|
||||
if (Test-Path $localStageDir) {
|
||||
Remove-Item -Path $localStageDir -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user