배포 자동화를 위해 Gitea 서버를 호스팅하고, act_runner를 설정한 뒤 개발 PC 환경에서부터 IIS 배포까지의 과정을 검증할 수 있는 프로토타입을 구현했었다.
2026.01.06 - [분류 전체보기] - 토스 러너스하이 (2) - 목표 설정 및 테스트
토스 러너스하이 (2) - 목표 설정 및 테스트
가이드 세션을 듣기 전에는, 세션에서 알려주는 대로 방향성을 정하면 된다고 생각했는데, 가이드 세션에서의 유일한 가이드는 목표 지정 부터 개발 까지 모두 스스로의 방식으로 하면 된다는
maybe-developer.tistory.com
처음부터 순서대로 개발하지 않고 빠르게 프로토타입을 만든 이유가 있었는데, 역시나 예상했던 문제가 발생했다.
1. 문제 발생
현재 운영중인 서버는 모두 windows 운영체제를 사용하고 있고, act_runner를 windows환경에서 사용하기 위해서는 wsl을 필수적으로 사용해야 한다.(docker를 사용하려고 해도 마찬가지)
처음 프로토타입을 만들 때는 wsl을 install하고 사용하는데 문제가 없었는데, 몇 일이 지나자 사내PC 보안 프로그램에서 wsl을 통제하기 시작했다. 인프라팀에 문의를 해봐도 사내 보안 정책상 사용불가라는 답변만 받을 수 있었다.
wsl을 사용할 수 없다면, gitea를 포기하고 windows에서 self-hosting이 가능한 runner를 가진 gitlab 서버를 찾아야 했다.
다행히 친구가 있는 부서에서 폐쇄망 gitlab을 사용하는 인원이 있다는 것을 들었고, 해당 서버를 빌려 쓸 수 있었다.
2. 시스템 구성 변경


사용할 수 없는 Gitea를 GitLab로 대체하고, 테스트에서 사용했던 One drive를 현업에서 사용중인 NAS로 대체했다.
git서버가 확정된 후, 기존에 Gitea Action에서는 One drive에 빌드 산출물을 업로드 한 뒤 web hook으로 배포를 원격으로 실행시키는 불완전한 구조를 가지고 있었기 때문에 프로세스의 구체화가 필요했다.

새로 구상한 아키텍처의 프로세스는 아래 순서대로 진행하는 것을 계획했다.
1. 코드 push/merge
2. Test (Nunit)
3. Build
4. Nas 저장 및 백업
5. WinRm으로 서버 원격접속하여 Server의 IIS조작 및 배포
이 프로세스를 완성시키기 위해서는 gitlab CI/CD를 잘 만드는 것이 가장 중요했다.
3. GitLab CI/CD
GitLab CI/CD는 Gitea에서 act_runner를 사용하는 것과 매우 흡사하게 사용할 수 있었다. gitlab runner를 등록(self-hosted) 해 준 뒤에, 레포지토리의 루트에 ci.yml 파일을 작성해 파이프라인을 만들었다.
stages:
- test
- build
- deploy
variables:
DOTNET_CLI_TELEMETRY_OUTPUT: "1"
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: "1"
BUILD_CONFIGURATION: "Release"
test_project:
stage: test
tags:
- windows
allow_failure: false
script:
- Write-Host "=== [TEST] 단위 테스트 시작 ==="
- dotnet restore
- dotnet build --configuration $BUILD_CONFIGURATION
- |
if (Test-Path Z:\) {
Write-Host "Z: 드라이브가 이미 연결되어 있습니다."
} else {
Write-Host "Z: 드라이브를 NAS에 연결 중..."
& net use Z: "$NAS_PATH" /user:"$NAS_USER" "$NAS_PASS"
}
artifacts:
when: always
expire_in: 7 days
after_script:
- Write-Host "테스트 완료"
build_project:
stage: build
tags:
- windows
script:
- Write-Host "=== [BUILD] 빌드 시작 ==="
- dotnet restore
- dotnet build <csproj경로> --configuration $BUILD_CONFIGURATION
- Write-Host "=== [NAS 연결 확인] ==="
- |
if (Test-Path Z:\) {
Write-Host "Z: 드라이브가 이미 연결되어 있습니다."
} else {
Write-Host "Z: 드라이브를 NAS에 연결 중..."
& net use Z: "$NAS_PATH" /user:"$NAS_USER" "$NAS_PASS"
}
- Write-Host "=== [PUBLISH] 빌드 결과 배포 폴더 생성 ==="
- dotnet publish <csproj경로> -c $BUILD_CONFIGURATION -o "$NAS_PATH\publish"
- Write-Host "=== [NAS 연결 해제] ==="
- net use Z: /delete /y
dependencies:
- test_project
deploy_build:
stage: deploy
tags:
- windows
dependencies:
- build_project
script: |
$ErrorActionPreference = "Stop"
Write-Host "=== [DEPLOY] IIS 원격 배포 시작 ==="
$SecureString = $env:REMOTE_SERVER_PASS | ConvertTo-SecureString -AsPlainText -Force
$WinRMCredential = New-Object System.Management.Automation.PSCredential($env:REMOTE_SERVER_USER, $SecureString)
Invoke-Command -ComputerName $env:REMOTE_IIS_SERVER_IP -Credential $WinRMCredential -Authentication CredSSP -ScriptBlock {
param(
[string]$iisAppPoolName,
[string]$iisPhysicalPath,
[string]$nasPath,
[string]$nasUser,
[string]$nasPass,
[string]$iisReportPath
)
$ErrorActionPreference = "Stop"
Write-Host "NAS 연결 중..."
net use X: "$nasPath" /user:"$nasUser" "$nasPass" /persistent:no
Write-Host "AppPool 중지 중..."
Stop-WebAppPool -Name $iisAppPoolName
if (Test-Path $iisPhysicalPath) {
Write-Host "기존 사이트 파일 삭제 중..."
Remove-Item -Recurse -Force "$iisPhysicalPath\*"
} else {
Write-Host "사이트 폴더 생성 중..."
New-Item -ItemType Directory -Path $iisPhysicalPath | Out-Null
}
Write-Host "웹앱 복사 중 (NAS → IIS)..."
Copy-Item -Recurse -Force "X:\publish\*" $iisPhysicalPath
Write-Host "AppPool 재시작 중..."
Import-Module WebAdministration
Start-WebAppPool -Name $iisAppPoolName
Write-Host "NAS 연결 해제 중..."
net use X: /delete /y
Write-Host "웹앱 배포 완료"
} -ArgumentList `
$env:IIS_APP_POOL_NAME, `
$env:IIS_PHYSICAL_PATH, `
$env:NAS_PATH, `
$env:NAS_USER, `
$env:NAS_PASS, `
$env:IIS_REPORT_PATH
(코드 일부 삭제 및 수정)
yml은 기존 시스템 구성도에서 계획한 기능들만 정확하게 구현했다.
4. WinRM과 NAS를 조합하여 배포를 진행한 이유
1. 환경적/정책적 제약
클라우드와 컨테이너를 사용하는 것이 불가하기 때문에 Docker, Kubernetes, CodeDeploy, Argo CD등 대부분의 도구들이 사용이 불가능 했다. 또한 서버가 폐쇄망으로 외부 인터넷과 차단이 되어있고, 도입에서 Gitea를 GitLab으로 대체한 것처럼 언제든지 정책이 확대적용 될 수 있기 때문에 최대한 외부 종속성을 줄이는 기획이 필요했다.
2. 효율성
B2E 서비스 특성상 트래픽 변동이 거의 없고 확장 가능성이 낮다. 스케일링의 필요성이 없기 때문에 다른 도구들을 적용하는 것이 WinRM + NAS 조합 보다 운영 및 비용 대비하여 효율적이지 못할 것이라고 생각한다.
결론적으로 위 구조로 충분히 효율적으로 배포자동화의 핵심 목표를 달성할 수 있다고 판단했다.
5. 결과
- 기존 배포 방식
1. 프로젝트에서 배포파일 산출 => NAS로 복사 => 사내 VDI 접속 => [서버 원격접속(mstsc) => IIS AppPool 중지 => 기존 파일 백업 => 신규 파일 적용 => IIS AppPool 시작] * 4회 => 끝
* 필요 Acitivity 23회, 소요 시간 약 15~25분
2. 팀원들은 배포 불가(서버 권한 없음), 담당자에게 의존.
- 신규 배포 방식
1. Code Push/Merge => 끝
* 필요 Acitivity 1회, 소요 시간 약 2~4분
2. Git만 있으면 레포지토리 Developer들은 모두 배포 가능
5. 참고
WinRM을 처음사용해 봤는데, 배포 작업외에도 서버에서 작업할게 있을 때 원격접속 하지 않고 대부분의 작업을 할 수 있어 유용하게 사용할 것 같다.
2026.01.08 - [분류 전체보기] - WinRM(Windows Remote Management)
WinRM(Windows Remote Management)
지금 까지 서버에 배포를 하거나 IIS, 기타 환경설정을 할 때 회사에서 제공되는 VDI를 통해서 원격 접속을 하였다.(회사에서 기본적으로 Windows Server를 사용) 처음에는 자주 사용하는 일반 로컬PC
maybe-developer.tistory.com
'러너스하이' 카테고리의 다른 글
| 토스 러너스하이 (4) - 마무리 및 회고 (1) | 2026.01.19 |
|---|---|
| 토스 러너스하이 (4) - 피드백 (0) | 2026.01.14 |
| 토스 러너스하이 (2) - 목표 설정 및 테스트 (0) | 2026.01.06 |
| 토스 러너스하이 (1) - 개인적 회고 및 목표 설정 (1) | 2025.12.14 |