본문 바로가기
Git

Gitlab(폐쇄망) CI/CD로 .net core 프로젝트 배포 자동화 만들기

by 아마도개발자 2024. 11. 25.

 

 

배경


 

지금 운영중인 서비스에서 업데이트가 진행되는 경우 배포해야할 어플리케이션은 3~5개이다. 지금까지 업데이트를 할 때마다 직접 배포파일을 만들고, 서버에 옮긴 뒤 IIS APP풀을 내리고 파일을 교체하고 다시 풀을 재시작하는.. 노가다를 반복했었다. 시간이 부족하다는 핑계로 생산성이 떨어지는 미련한 짓을 거의 1년 넘게 반복하다 보니 이제는 정말 자동화된 배포 프로세스가 필요하다고 느꼈다. 배포 자동화를 해야겠다는 마음을 먹으니 자동화 프로세스 구축으로  배포가 간단해지는 것 이외에 다른 부가적인 효과들도 기대할 수 있을 것 같았다.

 

 

과정


 

우선 서버에서 나를 대신해 열심히 빌드부터 배포까지 진행해 줄 gitlab-runner를 설치해주어야 한다.

 

- 프로젝트 레포지토리 => Settings => CI/CD => Runner Expand 경로로 이동 

Runner에서 Expand버튼을 누른 뒤 스크롤을 내려보면 gitlab-runner 인스톨러가 하이퍼링크 되어있다. 설치를 진행해주고, 어플리케이션을 호스팅하는 서버에 옮겨주자.

 

서버로 gitlab-runner를 옮겨줬다면, gitlab-runner가 설치된 폴더경로에서 cmd창을 열고 "gitlab-runner install" 명령어를 입력해 runner를 설치해준다

 

명령이 완료되면 다시 "gitlab-runner register" 명령을 입력해 서버에 runner 등록을 진행한다.

- Enter the GItlab instance URL       => 위 이미지 참조

- Enter the registration token            => 위 이미지 참조

- Enter tags for the runner                 => 러너에 붙일 tag입력

*나머지는 대충 입력하고 넘어가도 무관

 

- Enter an executor에서는 runner동작시킬 실행기를 선택해준다. 나의 경우는 windows서버였기 때문에 shell을 선택하였다.

 

여기까지 입력을 해주면 정상적으로 runner를 등록한 것을 확인할 수 있고, 폴더에 config.toml파일이 생성된 것을 볼 수 있다.

 

config.toml 파일을 확인해보면 [[runners]] 하위에 내가 등록한 runner가 저장되어 있는 것을 볼 수 있다.

executor가 shell인경우 shell이 "pwsh"로 자동저장 되어있는데, 나중에 명령어 실행 시 오류가 발생하는 경우 windows기본인 "powershell"로 변경해주면 된다.

 

다시 gitalb레포지토리로 돌아가보면 내가 로컬에서 등록한 runner가 정상적으로 레포지토리에 반영되어 있는 것을 확인할 수 있다

 

 

이제 등록된 runner가 일을 해 줄 수 있도록 해주어야 한다. gitlab-runner에게 일을 시키기 위해서는 .gitlab-ci.yml 파일을 프로젝트 root에 작성해주어야 한다. 이 yml파일을 통해 runner가 각 stage에서 내가 지정한 job을 수행할 수 있도록 할 수 있다.

 

 

before_script:

script가 실행되기 이전에 수행하는 단계이다. CHCP 65001은 인코딩 에러를 방지하기 위해 넣어주었다.

 

stages:

순차적으로 내가 수행할 job들을 나열해준다. stages에 등록된 job들이 script에서 수행된다.

 

build_project(job 이름):

프로젝트를 빌드하기 위한 job이다.

우선 cd명령어로 프로젝트가 위치한 폴더로 이동한다(runner가 원격 레포지토리와 정상적으로 연결되어 있다면, runner내부에 원격 레포지토리로부터 소스가 받아져 있다)

 

- 빌드과정(.NET)

1. restore명령어로 nuget패키지를 복원

2. csproj파일을 찾아 build를 진행

3. 빌드 이후, 게시를 진행해주면 API서버 배포를 위한 파일들이 모두 준비된다.

 

참고로, 폐쇄망인 경우 로컬에서 nuget파일을 서버로 직접 가지고 와서 restore해줘야 한다. 이후 build, publish과정에서는 --no-restore로 restore과정을 생략한다.

 

artifacts:

artifacts에 등록된 path에 있는 파일들을 gitlab 웹사이트에서 확인할 수 있다. 빌드 결과물 혹은 로그를 로컬에서 확인할 때 사용하면 유용하다.

 

only:

- job을 수행할 브랜치명을 기입한다. 나는 deploy브랜치에 조작이 있을 경우에만 자동 배포를 진행하기 때문에 deploy브랜치만을 넣엇다.

 

 

이후 deploy_project에서는 배포파일 교체를 위해 IIS를 조작하였다.  APPCMD를 이용해 기존 서버를 물고 있던 어플리케이션 풀을중지 한뒤 파일을 교체하였다. 이후 다시 풀을 시작하면 정상적으로 파일 교체 후 호스팅까지 자동으로 이루어진다.

 

.NET CORE프로젝트에서 게시 - 서버로 파일 공유 - iis 중지 - 파일 교체 - iis 재시작의 단계로 이루어지는 액티비티들을, git push 명령어 하나로 작동할 수 있게 되었다.

 

효과


1. 배포과정의 단순화

- 배포 시 필요한 액티비티가 확연히 줄어드며, 프로세스가 단순해진다. 결국 이것은 배포시간의 감소로 이어지며, 수동으로 했을 때에 비해 휴먼에러가 생길 확률 또한 압도적으로 줄어들게 된다.

 

2. 팀 개발 생산성 증가

- 우리 프로젝트에서 merge권한은 나에게만 있다. 그래서 이전에는 다른 팀원들이 api를 개발해도, 내가 merge를 하고 서버에 올려주지 않으면 api테스트가 불가능하였다. 때문에 내가 바쁘거나 부재중일 때는 최소 몇 시간에서 하루 이틀을 기다려야 테스트를 할 수 있었다. 하지만 이제 deploy브랜치에서 merge 혹은 push하는 것만으로 서버에 api를 올려 테스트할 수 있기 때문에 생산성이 크게 증가하였다.

 

3. 추가기능 개발

- 배포자동화 외에도 runner와 ci/cd를 활용한 다른 다양한 기능들을 이용할 수 있게되었다. test를 추가한다거나 스케쥴을 걸어 master브랜츠를 관리하는 등 프로젝트를 생산적으로 관리할 수 있는 포인트들이 늘어났기 때문에 조금 더 팀원들이 개발에 집중할 수 있는 환경이 되었다.

 

개인적으로 지금까지 우리팀은 git을 그저 코드 병합용, 버전관리용으로만 사용하는데 그쳤었는데, 이번 배포 자동화를 기점으로 조금 더 git을 활용한 다양한 시도들을 할 수 있게 되었다는 점이 가장 큰 효과라고 생각된다.

 

 

 

에러


 

1. could not lock config file 에러

$env:RUNNER_TEMP_PROJECT_DIR=$RUNNER_TEMP_PROJECT_DIR
$GITLAB_ENV="C:\Users\<사용자>\Desktop\runner\builds\sqitzHs2\0\cada\AAA\bbb.tmp\gitlab_runner_env"
$env:GITLAB_ENV=$GITLAB_ENV
New-Item -ItemType directory -Force -Path "C:\Users\<사용자>\Desktop\runner\builds\sqitzHs2\0\AAA\bbb\bbb.tmp
" | out-null
if(!(Test-Path "C:\Users\<사용자>\Desktop\runner\builds\sqitzHs2\0\cada\AAA\bbb.tmp\gitlab_runner_env")) { New
-Item -ItemType file -Force "C:\Users\<사용자>\Desktop\runner\builds\sqitzHs2\0\AAA\bbb\bbb.tmp\gitlab_runner
_env" | out-null }
Try { Get-Content "C:\Users\<사용자>\Desktop\runner\builds\sqitzHs2\0\AAA\bbb\bbb.tmp\gitlab_runner_env" | Fo
rEach { $k, $v = $_.split('='); Set-Content env:\$k $v} } Catch {
  echo "��ġ ��:219 ����:7
+ & "git" 'config' '-f' 'C:\Users\<사용자>\Desktop\runner\builds\sqitzHs2 ...
+       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
���ڿ��� " �����ڰ� �����ϴ�.
��ġ ��:1 ����:3
+ & {
+   ~
�� ���� �Ǵ� ���� ���ǿ� �ݴ� '}'�� �����ϴ�.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : UnexpectedToken
 
error: could not lock config file C:\Users\ <사용자> \Desktop\runner\builds\sqitzHs2\0\cada\AAA\bbb.tmp\git-template\config: No such file or directory
ERROR: Job failed: exit status 255

 

나를 가장 괴롭혔던 에러였다. 로그가 깨져있어 정확한 에러 원인을 확인하기 어려웠는데, 결국 gitlab_runner_env파일이 경로에 없었기 때문에 발생한 문제였다.. 수 시간을 해메이다 gitlab_runner_env 더미파일을 만들어주니 귀신같이 해결되었다.

 

2. dotnet restore시 에러 발생(https://api.nuget.org/v3/index.json 원본에 대한 서비스 인덱스를 로드할 수 없습니다.)

C:\Program Files\dotnet\sdk\2.1.818\NuGet.targets(123,5): error : https://api.nuget.org/v3/index.json 원본에 대한 서비스 인덱스를 로드할 수 없습니다. [<프로젝트경로>]
C:\Program Files\dotnet\sdk\2.1.818\NuGet.targets(123,5): error :   연결된 구성원으로부터 응답이 없어 연결하지 못했거나, 호스트로부터 응답이 없어 연결이 끊어졌습니다 [<프로젝트경로>]

 

인터넷 환경에서는 기본적으로 웹사이트를 통해 nuget정보를 가져오는데 폐쇄망에서는 그게 불가능하다보니 발생한 문제로 보였다. 로컬의 nuget을 가져와 restore시 소스를 직접 넣어주니 문제가 해결되었다.

 

 

 

 

마무리


별것 아닌 과정이라고 볼 수 있지만 폐쇄망이라는 특수성때문에 굉장히 고생을 많이 했다. 하지만 서비스를 개발하면서, 기능을 개발하는 것만큼 개발환경을 만들어가는 것도 중요하다는 것을 느끼고 있기 때문에 꼭 필요한 부분이라고 생각한다. 개발자를 위한 개발도 꽤 재미가 있는 듯..