Files
Genesis_GameServer/deploy/publish-linux.ps1
2026-09-04 01:44:59 +09:00

145 lines
5.0 KiB
PowerShell

# 리눅스용 자체 포함 실행 파일을 만든다. (윈도우 PowerShell 용)
# bash 가 필요 없다. VS Code 기본 터미널에서 그대로 돌아간다.
#
# .\deploy\publish-linux.ps1
# .\deploy\publish-linux.ps1 -Target ubuntu@서버주소 # 만들고 복사까지
#
# 경로·서비스 이름이 다르면:
# .\deploy\publish-linux.ps1 -Target ubuntu@서버 `
# -RemoteDir /home/ubuntu/gameserver -Service GameServer
#
# 서버에는 .NET 을 설치할 필요가 없다.
param(
[string]$Target = "",
[string]$RemoteDir = "/srv/genesis",
# 비우면 서버에서 자동으로 찾는다.
[string]$Service = ""
)
$ErrorActionPreference = "Stop"
# 저장소 루트로 이동 (이 스크립트는 deploy/ 안에 있다)
$root = Split-Path -Parent $PSScriptRoot
Set-Location $root
$project = "GameServer/GameServer.csproj"
$out = "artifacts/linux-x64"
Write-Host "== 1) 빌드 ==" -ForegroundColor Cyan
if (Test-Path $out) { Remove-Item $out -Recurse -Force }
dotnet publish $project `
-c Release `
-r linux-x64 `
--self-contained true `
-p:PublishSingleFile=true `
-p:EnableCompressionInSingleFile=true `
-p:DebugType=none `
-p:DebugSymbols=false `
-o $out `
--nologo
if ($LASTEXITCODE -ne 0) { throw "publish 실패" }
# 개발용 설정은 서버로 보내지 않는다.
Remove-Item "$out/appsettings.Development.json" -Force -ErrorAction SilentlyContinue
# 서버에서 바로 띄울 실행 스크립트.
# - ASPNETCORE_URLS 가 없으면 localhost:5000 에만 묶여 외부에서 안 보인다.
# - 윈도우에서 복사하면 실행 권한이 사라지므로 스스로 chmod 한다.
# 반드시 LF 로 저장해야 한다. CRLF 면 리눅스에서 "bad interpreter" 로 죽는다.
$runSh = @(
'#!/usr/bin/env bash',
'# 서버에서 이 폴더로 들어와 ./run.sh 하면 바로 뜬다.',
'# PORT=8080 ./run.sh 처럼 포트를 바꿀 수 있다.',
'set -euo pipefail',
'cd "$(dirname "$0")"',
'',
'PORT="${PORT:-5281}"',
'',
'chmod +x ./GameServer 2>/dev/null || true',
'mkdir -p wwwroot/uploads',
'',
'# 0.0.0.0 이어야 바깥에서 접속된다. 127.0.0.1 로 두면 서버 안에서만 보인다.',
'export ASPNETCORE_URLS="http://0.0.0.0:${PORT}"',
'export ASPNETCORE_ENVIRONMENT=Production',
'',
'# genesis.env 가 있으면 거기 값이 appsettings.json 보다 우선한다.',
'if [ -f ./genesis.env ]; then',
' set -a; . ./genesis.env; set +a',
'fi',
'',
'echo "http://0.0.0.0:${PORT} 에서 실행합니다. (Ctrl+C 로 종료)"',
'exec ./GameServer',
''
) -join "`n"
# UTF-8(BOM 없음) + LF 로 기록
$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
[System.IO.File]::WriteAllText((Join-Path $root "$out/run.sh"), $runSh, $utf8NoBom)
# 배포 후 확인 스크립트도 함께 넣는다.
Copy-Item (Join-Path $PSScriptRoot "healthcheck.sh") "$out/" -Force -ErrorAction SilentlyContinue
$size = "{0:N0} MB" -f ((Get-ChildItem $out -Recurse -File | Measure-Object Length -Sum).Sum / 1MB)
Write-Host ""
Write-Host " 산출물: $out ($size)" -ForegroundColor Green
if ([string]::IsNullOrWhiteSpace($Target)) {
Write-Host ""
Write-Host " 서버로 올리려면:" -ForegroundColor Yellow
Write-Host " .\deploy\publish-linux.ps1 -Target user@서버주소"
Write-Host ""
Write-Host " 직접 복사한다면:"
Write-Host " scp -r $out/* user@서버주소:$RemoteDir/"
Write-Host " ssh user@서버주소 `"cd $RemoteDir && chmod +x run.sh && ./run.sh`""
exit 0
}
Write-Host ""
Write-Host "== 2) 업로드 ==" -ForegroundColor Cyan
Write-Host " 대상: ${Target}:$RemoteDir"
# scp 는 지우지 않고 덮어쓰기만 한다.
# 산출물에 wwwroot/uploads 가 없으므로 서버의 사진은 그대로 남는다.
ssh $Target "mkdir -p '$RemoteDir'"
if ($LASTEXITCODE -ne 0) { throw "서버 접속 실패" }
scp -r "$out/*" "${Target}:$RemoteDir/"
if ($LASTEXITCODE -ne 0) { throw "복사 실패" }
Write-Host ""
Write-Host "== 3) 마무리 ==" -ForegroundColor Cyan
# 서버에서 실행할 명령. 작은따옴표 here-string 이라 PowerShell 이 손대지 않는다.
$remoteScript = @'
set -e
cd "__DIR__"
chmod +x GameServer run.sh
mkdir -p wwwroot/uploads
echo " 실행 권한 설정 완료"
SVC="__SVC__"
if [ -z "$SVC" ]; then
for c in GameServer genesis gameserver portfolio; do
if systemctl list-unit-files 2>/dev/null | grep -q "^$c.service"; then SVC="$c"; break; fi
done
fi
if [ -n "$SVC" ]; then
sudo systemctl restart "$SVC" && echo " $SVC 서비스 재시작"
else
echo " systemd 서비스를 찾지 못했습니다. ./run.sh 로 직접 실행하세요."
fi
'@
$remoteScript = $remoteScript.Replace('__DIR__', $RemoteDir).Replace('__SVC__', $Service)
$remoteScript | ssh $Target "bash -s"
Write-Host ""
Write-Host "완료. 서버에서 실행하려면:" -ForegroundColor Green
Write-Host " ssh $Target"
Write-Host " cd $RemoteDir && ./run.sh"
Write-Host ""
Write-Host " (계속 띄워 두려면 README 5절의 systemd 등록을 참고하세요)"