Steam에 게임을 출시해보자 (3편) - 스팀게임 CI(빌드 자동화) 파이프라인 구축 (ver. Unity)

왜? 빌드 자동화를 구축해야 할까?
이전 포스팅을 통해서 스팀 게임을 업로드하고 출시할 수 있는 과정을 진행했습니다. 여기까지만 하더라도 여러분들이 원하는 게임을 출시하고 관리하는 것이 가능하지만, 매번 수동으로 출시 과정을 관리한다면 실제 게임 개발 과정에서 게임을 만드는 시간보다 출시를 준비하는 것에 더 많은 시간을 쏟아야 하는 상황이 발생합니다.
- 출시를 수동으로 하는 경우 발생하는 문제
- 매번 동일한 반복 작업을 수없이 반복해야 합니다.
- 휴먼 에러(실수)가 발생했을 때 앞선 과정들을 다시 처음부터 진행해야 하는 상황이 발생합니다.
- 업로드가 완료될 때까지 필요한 시간을 기다리고 있어야 합니다.
- 여러 팀원들과 협업하는 상황에서는 빌드를 진행하기 위해서 모든 팀원의 작업을 멈춰야 하는 상황이 발생합니다
이러한 이유들 때문에 빌드 자동화 과정은 필수라고 할 수 있습니다! 게임을 잘 개발하는 것도 능력이지만, 게임을 잘 개발할 수 있는 환경을 조성하는 것도 개발자의 능력이기 때문이죠. 그러므로 코드 변경사항을 Git에 Push만 하면, [빌드 -> 테스트 -> 업로드 -> 결과 알림]까지 알아서 자동으로 진행해주는 "빌드 자동화 파이프 라인" 구축이 필수적입니다!

CI/CD 란?
CI/CD는 지속적 통합(Continuous Integration)과 지속적 배포(Continuous Deployment)를 의미합니다. 게임 개발 업계에서 통합과 배포에 필요한 과정을 자동화하고 오로지 게임 개발에만 집중할 수 있도록 환경을 조성하는 것을 뜻합니다.

- CI (Continuous Integration, 지속적 통합)
- CI는 개발자들이 작성한 코드를 자주, 그리고 안전하게 하나로 통합하는 과정을 뜻합니다.
- 기존의 문제 : 여러 명의 개발자가 각자 코드를 짜고 합치려다 보면, 파일이 꼬이고 수많은 에러가 발생합니다.
- CI의 해결책 : 코드를 Git 같은 저장소에 올릴 때마다, 자동화 서버가 즉시 코드를 빌드해보고 에러가 없는지 테스트합니다.
- 기대 효과 : 코드를 통합하는 과정마다 자동으로 빌드 과정을 수행하고 에러가 없는지 확인하기 때문에 문제가 발생하는 코드를 조기에 확인하고 수정할 수 있습니다.
- CD (Continuous Deployment, 지속적 배포)
- CD는 성공적으로 만들어진 빌드(결과물)를 실제 유저가 사용할 수 있도록 서비스에 올리는 과정입니다.
- 기존의 문제 : 업로드 버튼을 누른 뒤 게임이 업로드 되기까지의 시간을 계속 기다려야하는 문제가 발생합니다.
- CD의 해결책 : 완성된 게임 빌드를 스팀 서버에 자동으로 업로드를 진행합니다.
- 기대 효과 : 지속적으로 개발된 모든 버전이 스팀 서버에서 확인이 가능하며, 최종적으로 유저에게 선보여야하는 버전만 선택하여 출시하는 과정만 수행하면 됩니다.
Step 1. Unity CLI 빌드 스크립트 작성
만약 여러분들이 기존의 게임빌드 과정을 수행한다면 유니티 에디터를 열고 Build Profile 클릭하여 빌드 설정을 연 뒤 Build 버튼을 클릭하여 빌드과정을 수행하실 겁니다. 하지만, 컴퓨터 입장에서는 이러한 마우스 클릭과 GUI 환경에서 진행하는 것이 아닌 명령어를 통해서 빌드하는 과정을 더욱 수월하게 수행합니다. 즉, 인간이 빌드를 한다면 마우스와 GUI에서 클릭하여 진행하겠지만, 컴퓨터가 자동으로 빌드한다면 클릭이 필요없이 명령어를 통해서 빌드를 수행하는 것이 수월하죠.
유니티도 이러한 상황처럼 직접 빌드 버튼을 눌러 빌드를 수행하는 과정 대신 명령어를 통해서 빌드도 가능합니다. 이를 Batchmode(배치모드)라고 하며 기본적으로 제공하는 명령프롬프트(CMD)에 CLI 빌드 스크립트를 작성하여 빌드를 수행할 수 있습니다. 처음보는 상황이라 익숙하지 않지만 Step by Step으로 천천히 과정을 진행해보죠.
유니티 빌드 스크립트 작성
먼저 빌드를 자동화하기 위해서는 유니티 빌드 과정을 설정할 필요가 있습니다. 스크립트를 통해서 빌드설정과정과 수행과정을 구성해두면 이후에는 이 수행과정을 실행만 해내면 됩니다.
테스트 환경
- 운영체제 : Window 11
- 유니티 버전 : Unity 6.3 LTS
- 빌드를 수행할 게임 프로젝트를 엽니다.

- 먼저 Editor 폴더를 생성합니다. 유니티는 프로젝트 구성에 있어서 특수 폴더들이 있습니다. 이중 Editor라는 이름의 폴더는 게임 진행 도중 사용하는 기능이 아닌 게임을 편집하는 에디터에서 사용하기 위한 전용 기능을 쓰기 위한 폴더입니다. 즉, 유니티에서 에디터 기능을 추가하기 위해 Editor 폴더 안에 에디터 전용 스크립트를 작성하기 위한 용도로 사용합니다. (참고자료 : https://docs.unity3d.com/kr/2022.3/Manual/SpecialFolders.html)

- Editor 폴더 안에 새로운 스크립트를 작성합니다. 컴포넌트가 필요한 것이 아닌 에디터 기능이 필요한 것이므로 빈 C# 스크립트를 작성하겠습니다. 이름은 적당히 BuildScript.cs 로 작성하겠습니다.

- 빌드 스크립트를 작성합니다.
using UnityEditor;
public static class BuildScript
{
[MenuItem("Build/Window")]
public static void BuildWindow()
{
// 빌드를 진행할 때 설정할 옵션들
BuildPlayerOptions options = new BuildPlayerOptions();
// 빌드에 포함되어야 할 씬 목록
options.scenes = new [] {
"Assets/FPS/Scenes/IntroMenu.unity",
"Assets/FPS/Scenes/WinScene.unity",
"Assets/FPS/Scenes/LoseScene.unity",
"Assets/FPS/Scenes/MainScene.unity",
"Assets/FPS/Scenes/SecondaryScene.unity",
};
// 빌드 결과물이 나오는 경로 (윈도우게임 실행파일 경로인 .exe로 끝나야 함)
options.locationPathName = "C:\\/ProjectDC_Window/ProjectDC.exe";
// 빌드 타겟 플랫폼
options.target = BuildTarget.StandaloneWindows;
// 빌드 진행
BuildPipeline.BuildPlayer(options);
}
}
- 스크립트 작성이 완료된다면 에디터 상단에 Build 메뉴가 생기며 버튼 클릭시에 빌드과정이 진행됩니다.


- 빌드가 성공적으로 완료된 경우에는 빌드 경로로 설정했던 곳에서 게임 빌드파일을 확인할 수 있습니다.

- 쉽게 생각하자면 그동안 직접 빌드 설정을 열고 빌드를 실행했던 과정을 스크립트 에디터 기능으로 진행한 것 뿐입니다.

- 이로서 꼭 빌드설정을 열고 마우스로 클릭해야만 빌드를 할 수 있는 것이 아닌 스크립트를 통해서 빌드 과정을 진행할 수 있게 되었습니다.
배치모드를 통한 유니티 빌드
스크립트를 통해서 빌드과정을 진행할 수 있다면 이제는 유니티를 열지 않은 상황에서 빌드를 수행할 수 있는 명령어를 구성해야 합니다. 유니티를 열지 않은 상황에서 빌드를 수행할 수 있다면, 주기적 또는 필요시 게임을 빌드하여 업로드해야 하는 과정에서 꼭 유니티를 열어야 하는 제약사항 없이 백그라운드에서 게임을 빌드하고 업로드하는 과정이 가능합니다.
이를 위해서는 유니티 커맨드 라인 인자라는 방법이 필요하며 유니티의 자동화된 빌드, 작업을 테스트할 때 매우 유용합니다. (참고자료 : https://docs.unity3d.com/kr/2022.3/Manual/EditorCommandLineArguments.html)
- 먼저 유니티 프로젝트를 닫은 상황에서 테스트할 필요가 있습니다. (지금은 테스트를 위해 유니티 프로젝트를 닫고 진행하지만 이후에는 닫을 필요 없이 별도로 자동으로 진행할 예정입니다)
- 배치모드를 통해서 유니티를 열지 않은 상황에서도 유니티 프로젝트 내의 static 함수를 실행시킬 수 있습니다. 해당 커맨드는 아래와 같습니다.
- {유니티 경로} : 유니티 프로그램이 설치되어 있는 경로를 입력합니다.
- -quit : 다른 커맨드 실행을 마친 후 Unity 에디터를 종료합니다.
- -batchmode : 배치 모드로 Unity를 실행합니다. 배치 모드에서 Unity는 사람의 개입 없이 작업을 수행합니다.
- {프로젝트 경로} : 프로젝트를 만든 경로를 입력합니다.
- -executeMethod {클래스이름}.{함수이름} : Unity에서 프로젝트를 열자마자 지정한 static 함수를 실행합니다.
{유니티 경로} -quit -batchmode -projectPath {프로젝트 경로} -executeMethod {클래스이름}.{함수이름}
- 위 배치모드를 실행하기 위해 필요한 정보를 확인하기 위해 유니티 허브를 잠시 이용하겠습니다.

- 유니티 경로는 설치 탭에서 설치된 에디터를 기준으로 확인할 수 있습니다.

- 프로젝트 경로는 프로젝트 탭에서 만든 프로젝트 하단에 경로로 확인할 수 있습니다.

- 내용을 기반해서 저의 상황에서 진행하는 명령인자는 아래와 같습니다. (여러분들도 설치경로와 프로젝트 경로에 따라 상황이 다를 수 있으므로 자신의 컴퓨터 상황에 맞추어 작성할 필요가 있습니다)
"C:\Program Files\Unity\Hub\Editor\6000.3.9f1\Editor\Unity.exe" -quit -batchmode -projectPath "C:\Project\Unity\FPSSample" -executeMethod BuildScript.BuildWindow
- 윈도우 실행에서 명령 프롬프트를 열고 위 명령어를 진행한다면 잠시의 시간 후에 게임이 빌드되는 것을 확인할 수 있습니다. (실제 빌드가 잘 수행되는지 확인하기 위해서 게임 파일을 지운 뒤 테스트해보는 것을 추천합니다)

- 여기까지 진행했다면 이제는 유니티를 열 필요 없이 명령어를 통해서 빌드 과정을 수행할 수 있습니다.
Step 2. Jenkins를 통한 자동화 구축
위 과정을 통해서 명령어를 통해서 유니티를 열 필요 없이 빌드 과정을 수행할 수 있습니다. 하지만 아직 자동화 단계를 진행했다고 볼 수는 없습니다. 우리가 원하는 것은 게임을 개발하고 있을 때 컴퓨터가 자동적으로 게임 빌드를 수행해주는 것을 최종 목표로 하고 있습니다. 이를 가능하게 해주는 프로그램이 Jenkins가 있습니다. Jenkins는 CI/CD 도구로 지금까지도 현업에서 가장 많이 활용하고 있는 툴입니다. (참고자료 : https://www.jenkins.io/doc/tutorials/)

이번에는 Jenkins를 활용하여 게임 빌드 자동화 시스템을 구축하지만, 앞으로의 개발자 인생에서 여러분이 잘 활용하면 무궁무진한 가능성을 가지고 있는 도구이기 때문에, 시간이 여력이 있다면 Jenkins를 여러 용도로 활용하시는 것을 적극 추천합니다.
Jenkins 설치 과정
Jenkins를 설치하기 앞서 Jenkins는 Java SDK 21 또는 25 버전 설치를 필요로 합니다. 따라서 Java SDK부터 설치한 뒤 Jenkins 설치 과정을 진행하도록 하겠습니다.
- 먼저 Java SDK 를 검색하여 홈페이지로 들어갑니다.(https://www.oracle.com/kr/java/technologies/downloads/)

- JDK 25 -> Windows -> x64 MSI Installer 의 설치 파일을 다운받습니다.

- 설치 과정을 차근차근 진행하여 JDK 설치를 진행합니다. 이때 설치 경로는 Jenkins 설치 시에 필요하니 기억해두시는 것을 추천합니다.




- 이어서 Jenkins를 설치하도록 하겠습니다. 인터넷에 Jenkins를 검색하여 홈페이지로 들어갑니다. (https://www.jenkins.io/)

- Download -> Jenkins LTS Windows 버전을 선택하고 다운로드 합니다.

- 다운로드한 파일을 실행시켜 설치작업을 진행합니다.


- 설치 중 Logon Type은 편의를 위해 LocalSystem으로 선택하겠습니다.

- Jenkins는 기본적으로 8080 포트를 사용합니다. 테스트를 통해서 사용이 가능한 포트인지 확인해보고 사용가능한 경우에서 진행하시면 됩니다. 이미 사용 중인 포트라면 임의의 포트 번호를 지정하면 됩니다.

- 앞서 설치한 JDK 경로를 요구합니다. 설치 경로를 지정하고 다음으로 넘어갑니다.





Jenkins 환경 설정
설치가 완료되었다면 이제 Jenkins가 동작하기 위한 환경을 설정할 필요가 있습니다. 이 경우도 한 단계씩 진행하겠습니다.
- 설치가 완료되었다면 https://localhost:8080 으로 접속합니다. (만약 포트번호를 변경했다면 변경한 포트번호를 입력합니다.)
jenkins는 원격 포트를 사용하여 외부에서 접속이 가능합니다.
즉, 이 의미는 자동 빌드설정이 완료된 게임빌드 PC를 원격으로 접속하여 작업이 가능하다는 뜻입니다.
- 접속이 되었다면 보안 설정을 진행합니다.
화면 중앙에 표시되는 경로에 따라 파일을 확인하면 패스워드가 작성된 파일을 확인할 수 있습니다.


- 패스워드 입력 후 기본 설정으로 진행합니다.

- 기본 설정을 선택하는 경우 Jenkins에서 자주 활용되는 plug-in들을 설치하게 됩니다.

- 설치 후 계정을 생성합니다.

- 계정 생성을 완료한 경우 jenkins를 쓸 준비가 되었습니다!
- https://localhost:8080 에 접속하면 jenkins 메인 화면이 나옵니다.

- 설정을 위해 우측 상단 설정을 선택하고 plug-in을 선택합니다.

- 설치 가능한 plug-in 중 유니티 플러그인을 설치합니다. (또한 디스코드 & slack 등을 사용한다면 설치를 권장합니다.)

- Plug-in 설치 후 Tool을 설정합니다.

- Unity 플러그인의 경로를 설정합니다. (unity editor 버전까지의 설치 경로를 입력합니다.)

Credential 발급
환경 설정이 완료되었다면 Credential 을 발급 받아야합니다. Jenkins는 안전하게 원하는 계정의 정보를 얻어내기 위해 Credential을 사용합니다.

- Username with Password로 Credential을 추가합니다.



- 여기서 아이디와 토큰이 필요합니다. 토큰을 발급 받기 위해서 Github에 접속합니다.
- 깃허브 우측상단의 프로필에서 settings를 선택합니다.

- 좌측 탭 메뉴에서 Developer settings 를 선택합니다.

- 좌측 탭 메뉴의 Personal access tokens 를 선택하고 Fine-grained tokens 를 선택합니다.
- Generate new token를 선택하여 토큰 생성을 시작합니다.

- 토큰 생성을 위한 기본 정보를 입력합니다. (기간 제한은 의도에 맞추어 설정합니다.)

- 토큰으로 접근이 가능한 레포지토리를 선택합니다.

- 토큰이 가지는 권한을 설정합니다. (저는 모든 권한을 부여했습니다.)

- 토큰 생성 완료시 key 값을 발급받습니다. 해당 키값은 잘 보관해두도록 합니다. 키 값은 보안상의 이유로 한번 페이지를 닫게 되면 다시 공개되지 않습니다.

- 발급받은 키로 Credential을 생성합니다.


Item 생성
환경설정이 마무리 되었다면, 새로운 Item를 만들고 빌드를 진행해볼 수 있습니다.

- Item의 유형은 Freestyle project로 선택합니다.

- 기본 정보와 깃허브 레포지토리 링크을 입력합니다.

- 소스제어 방식을 Git으로 선택하며 레포지토리 링크와 Credential을 입력합니다. (Credential이 유효하지 않는다면 경고문구가 나옵니다)

- 빌드 커맨드를 작성합니다. Tool에서 설정한 Unity를 선택하며 유니티의 빌드 스크립트를 동작시킬 수 있도록 작성합니다.
만약 디스코드 또는 슬랙으로 빌드 알림을 받는 기능까지 추가하려 한다면 빌드 후 조치에서 추가가 가능합니다.

- 설정이 완료되었다면 지금 빌드를 선택하여 빌드가 정상적으로 진행되는지 확인합니다.
만약 빌드 중 오류가 발생하는 경우는 로그를 통해서 확인할 수 있습니다.
대다수의 오류는 라이센스 문제로, 유니티 허브에서 라이센스를 다시 재발급 받는 경우 문제를 해결할 수 있습니다.

- 정상적으로 빌드에 성공하는 경우 선정한 게임 빌드 폴더에 게임이 생성이 되며, 빌드과정에 대한 로그를 확인할 수 있습니다.

빌드 트리거 구성
빌드를 주기적으로 또는 새로운 코드가 추가된 경우에 자동으로 빌드가 수행되도록 설정한다면, Jenkins는 신경쓰지 않고 오로지 개발에만 집중할 수 있는 환경을 갖추게 됩니다. 이를 빌드 트리거라고 합니다.

Github hook은 github에 새로운 코드가 올라온 경우에 발동되는 트리거 입니다. Github 레포지토리의 설정에서 Webhook을 설정하는 경우에 코드의 갱신이 있을때마다 빌드를 실행시킬 수 있습니다. 다만, 이 경우는 Github에서 빌드 피시를 접근하기 위한 ddns 가 있을 필요가 있습니다. 각자 보유하신 공유기의 설정에서 ddns 설정과 포트포워딩을 구성한다면 로컬 컴퓨터에서도 Webhook을 받을 수 있습니다.


만약 ddns 설정과 포트포워딩 설정이 어렵다면 poll SCM 방식을 권장합니다. 해당 방법은 코드의 갱신과 무관하게 주기적으로 빌드를 수행할 수 있습니다. 물론 변경사항이 없는 경우 빌드를 수행하지 않기 때문에 무의미하게 빌드하는 경우는 발생하지 않습니다. 너무 짧은 주기를 선정하는 경우 네트워크에 무리가 갈 수 있으니 너무 짧은 주기로 빌드하지 않도록 주의해주세요.

마무리
이제 Jenkins를 통해서 환경설정을 구성한 경우에는, 유니티 프로젝트를 편집하면서 동시에 Jenkins로 빌드가 가능해집니다. 즉, 작업을 멈출 필요 없이 계속해서 유니티 프로젝트를 작업하시면 되며, 빌드가 필요한 경우에는 Jenkins의 지금 빌드를 진행하면 됩니다. 둘 모두 독립적으로 동작하며 서로 작업에 영향을 주지 않습니다.
앞으로의 작업은 오로지 유니티 프로젝트 제작 작업에만 몰두하시면 됩니다. 빌드 과정은 Jenkins가 담당하며 빌드 과정의 이력 또한 저장하고 있습니다. 자동화하여 빌드 과정을 구성한 경우 이제는 프로젝트 개발에만 집중하시면 됩니다!






와....정성이....대단하십니다...