서버 관리 Part 3: 서버 패키징

Flavor: 역할에 따라 서버 구분하기

경우에 따라서는 역할에 따라 서버를 설정해야되는 경우가 있습니다. 아이펀 엔진에서는 이런 목적으로 서버의 Flavor 를 지정할 수 있습니다.

Flavor 란?

Flavor 는 source code 를 공유하지만, 다른 역할을 담당하는 서버 타입을 의미합니다. 예를 들어, 동일한 source code 를 쓰더라도 lobby 용 서버 타입과 game 용 서버 타입이 다를 수 있는데, 아이펀 엔진에서는 이들을 각각 lobby flavor, game flavor 로 구분합니다.

Flavor 설정

만일 lobby 타입의 게임 서버와 game type 의 게임 서버를 구분하고자 한다면, 최상위 CMakeLists.txt 에 다음과 같이 flavor 를 지정합니다.

1
2
3
4
...
set(APP_FLAVORS lobby game)
...
include(Funapi)

Note

flavor 지정 시, default 는 엔진 내부에서 예약어(reserved keyword)로 사용하기 때문에 default 이외의 다른 이름을 사용해야 합니다.

Flavor 별 자동 생성 파일들

이렇게 설정하고 빌드를 하면, 아이펀 엔진은 자동으로 다음과 같은 파일들을 생성합니다.

MANIFEST.json

기본으로 포함된 src/MANIFEST.json 을 복사해서 source directory 상에서 src/MANIFEST.lobby.jsonsrc/MANIFEST.game.json 를 생성합니다. 이제 flavor 별 MANIFEST.json 을 적절하게 수정합니다.

Launcher script

Build directory 상에서 각 flavor 별로 launcher script 가 생성됩니다. 위의 예에서는 .lobby-local, .lobby-launcher, .game-local, game-launcher 로 끝나는 스크립트들이 생성됩니다.

Daemon script

CMakeLists.txt 에서 set(WANT_SYSTEMD true) 혹은 set(WANT_UPSTART true) 로 설정된 경우 게임 서버르를 daemon 으로 실행하기 위한 script 파일들도 생성됩니다. 이 때 각 flavor 용 파일은 MANIFEST.json 에서와 마찬가지로 기본으로 포함된 파일들을 복사해서 생성합니다.

  • set(WANT_SYSTEMD true) 인 경우:

    • source directory 상에서 etc/systemd/ 디렉토리 아래 .chat.service , .lobby.service 와 같은 형태로 파일이 생성됩니다.

  • set(WANT_UPSTART true) 인 경우:

    • source directory 상에서 etc/upstart/default/ 디렉토리 아래 .chat , .lobby 와 같은 파일이 생성됩니다.

    • source directory 상에서 etc/upstart/init/ 디렉토리 아래 .chat.conf , .lobby.conf 와 같은 파일이 생성됩니다.

Note

이렇게 생성된 파일들은 make install 이나 make package 시에 같이 포함되어 설치되거나 배포됩니다.

코드 상에서 현재 flavor 알아내기

flavor 별로 서버 동작을 다르게 처리 하기 위해서는 코드 상에서 현재 서버의 flavor 를 알아야 할 수 있습니다. 이 때는 app_flavor 라는 Google flag 를 이용합니다. 아래는 사용 예시입니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
 DECLARE_string(app_flavor)

 class MyGameServer : public Component {
  public:
   static bool Install(const ArgumentMap &arguments) {
     if (FLAGS_app_flavor == "lobby") {
       // Configure as a lobby server.
     } else if (FLAGS_app_flavor == "game") {
       // Configure as a game server.
     }
   }
 }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class Server
{
  public static void Install(ArgumentMap arguments)
  {
    if (Flags.GetString ("app_flavor") == "lobby")
    {
      // Configure as a lobby server.
    }
    else if (Flags.GetString ("app_flavor") == "game")
    {
      // Configure as a game server.
    }
  }
}

Tip

Flavor 를 사용하면, 해당 서버의 RPC 태그에는 그 flavor 이름이 자동으로 포함됩니다. 이를 통해 손쉽게 같은 flavor 의 서버 리스트를 가져올 수 있습니다. 자세한 내용은 태그로 분산 서버 구분 을 참고하세요.

실 서비스로 옮기기 위한 게임 서버 패키징

아이펀 엔진은 개발된 게임 서버를 손쉽게 패키지화할 수 있는 기능을 제공합니다. 이 기능을 사용하면, 게임 서버를 실제 서버로 복사하기 위해서 소스를 전체 다 복사하는 안전하지 못한 일을 피할 수 있습니다.

Note

아이펀 엔진 윈도우 버전의 패키징 방법은 프로젝트 배포하기 을 참고해주세요.

생성 가능한 패키지 타입

패키지 파일은 다음 세가지 형태로 생성이 가능하며, 각각은 프로젝트 최상위 CMakeLists.txt 파일에 다음과 같은 변수를 세팅하면 됩니다.

  • TGZ: gzip 으로 묶인 tar 파일입니다. set(WANT_TGZ_PACKAGE true) 로 세팅하면 생성됩니다. 게임 서버를 /usr/bin 등 OS 의 일반적인 경로에 설치하는 것이 아니라, 특정 사용자의 home directory 등에 설치할 때 유용합니다.

  • DEB: Debian package 파일입니다. set(WANT_DEB_PACKAGE true) 로 세팅하면 생성됩니다. Ubuntu 에서만 유효합니다. Ubuntu 의 컨벤션대로 실행파일을 설치하며, daemon script 도 포함합니다.

  • RPM: Redhat package 파일입니다. set(WANT_RPM_PACKAGE true) 로 세팅하면 생성됩니다. CentOS 에서만 유효합니다. CentOs 의 컨벤션대로 실행파일을 설치하며, daemon script 도 포함합니다.

생성되는 패키지의 버전 숫자 부여

패키지의 파일 이름은 “{{project}}_{{version}}_install.tgz” 형태로 생성되는데, version string 은 다음에 설명하는대로 major version string 와 source 저장소에서 추출한 code revision ID 로 구성됩니다.

Major 버전 숫자

서버 패키지의 버전을 올리기 위해서는 Source 디렉터리 구조 에 기술된 VERSION 파일의 내용을 수정하고 패키지를 생성하면 자동으로 서버 패키지의 버전을 올려줍니다.

Minor 버전 숫자 (code revision ID)

만일 수작업으로 갱신해야되는 VERSION 외에 GIT 의 commit id 나 SVN 의 revision number 를 빌드 번호로서 자동으로 버전 문자열에 추가하고 싶다면 최상위 CMakeLists.txt 파일에 다음과 같은 변수를 세팅하면 됩니다.

  • GIT: :code:set(PACKAGE_WITH_BUILD_NUMBER_FROM_GIT true) 로 세팅하면 GIT commit ID 를 minor version string 으로 세팅합니다.

    Tip

    만일 source tree 가 dirty 상태라면 commit id 뒤에 ~dirty 라는 문자열을 추가합니다. 이로써 아직 commit 하지 않은 내용이 있는 source tree 에서 빌드한 것이라는 것을 알 수 있습니다.

  • SVN: :code:set(PACKAGE_WITH_BUILD_NUMBER_FROM_SVN true) 로 세팅하면 svn info 에서 추출한 revision ID 를 minor version string 으로 세팅합니다.

    Warning

    svn 은 commit 후 update 명령을 실행하지 않으면 svn info 가 commit 전 revision 번호를 반환합니다. 이런 문제를 막기 위해서 패키지 생성 전에 svn update 를 실행해주세요.

패키지 생성방법

명령행 상에서 작업할 때

터미널 상에서 make package 라고 입력하면 패키지 파일을 생성합니다.

CLion 로 작업할 때

우측의 target 하위 메뉴를 선택하면, package 라는 target 을 선택할 수 있습니다. 그것을 더블클릭하면 패키지 파일을 생성합니다.

Visual Studio 로 작업할 때

Visual Studio 에서 패키지를 생성하는 기능은 추후에 제공될 예정입니다. Putty 등을 통해 리눅스 서버로 접속해서 위의 명령행 상에서 작업할 때 에 설명된 대로 생성하셔야 됩니다.

패키지 내용 확인하기

TGZ

다음과 같이 tar ztvf 로 패키지 내용을 확인할 수 있습니다.

$ tar ztvf example_0.0.1_install.tar.gz
drwxrwxr-x dkmoon/dkmoon     0 2017-05-18 14:24 etc/
drwxrwxr-x dkmoon/dkmoon     0 2017-05-18 14:24 etc/default/
-rw-r--r-- dkmoon/dkmoon    72 2017-05-18 14:23 etc/default/example
drwxrwxr-x dkmoon/dkmoon     0 2017-05-18 14:24 etc/init/
-rw-r--r-- dkmoon/dkmoon  1304 2017-05-18 14:23 etc/init/example.conf
drwxrwxr-x dkmoon/dkmoon     0 2017-05-18 14:24 usr/
drwxrwxr-x dkmoon/dkmoon     0 2017-05-18 14:24 usr/lib/
drwxrwxr-x dkmoon/dkmoon     0 2017-05-18 14:24 usr/lib/example/
drwxrwxr-x dkmoon/dkmoon     0 2017-05-18 14:24 usr/lib/example/default/
-rw-r--r-- dkmoon/dkmoon 5723064 2017-05-18 14:23 usr/lib/example/default/libexample.so
...
-rwxr-xr-x dkmoon/dkmoon    3288 2017-05-18 14:23 usr/bin/example-launcher

DEB

다음과 같이 dpkg-deb --contents 명령으로 패키지 내용을 확인할 수 있습니다.

$ dpkg-deb --contents example_0.0.1_install.deb
drwxrwxr-x root/root         0 2017-05-18 14:24 ./etc/
drwxrwxr-x root/root         0 2017-05-18 14:24 ./etc/default/
-rw-r--r-- root/root        72 2017-05-18 14:23 ./etc/default/example
drwxrwxr-x root/root         0 2017-05-18 14:24 ./etc/init/
-rw-r--r-- root/root      1304 2017-05-18 14:23 ./etc/init/example.conf
drwxrwxr-x root/root         0 2017-05-18 14:24 ./usr/
drwxrwxr-x root/root         0 2017-05-18 14:24 ./usr/bin/
-rwxr-xr-x root/root      3288 2017-05-18 14:23 ./usr/bin/example-launcher
drwxrwxr-x root/root         0 2017-05-18 14:24 ./usr/lib/
drwxrwxr-x root/root         0 2017-05-18 14:24 ./usr/lib/example/
drwxrwxr-x root/root         0 2017-05-18 14:24 ./usr/lib/example/default/
-rw-r--r-- root/root   5723064 2017-05-18 14:23 ./usr/lib/example/default/libexample.so
drwxrwxr-x root/root         0 2017-05-18 14:24 ./usr/share/
...

RPM

다음과 같이 rpm --qpl 명령으로 패키지 내용을 확인할 수 있습니다.

 $ rpm -qpl example_0.0.1_install.rpm
 /lib/systemd/system/example.service
 /usr/bin/example-launcher
 /usr/lib/example/default/libexample.so
 /usr/share/example/default/DEBIAN
 /usr/share/example/default/LICENSE
 /usr/share/example/default/README
 /usr/share/example/default/VERSION
 /usr/share/example/default/manifests/MANIFEST.json
 /usr/share/example/default/resources/.stamp
 /usr/share/example/default/resources/client_data/.stamp
 /usr/share/example/default/resources/client_data/README
 /usr/share/example/default/resources/game_data/.stamp
 /usr/share/example/default/resources/game_data/README
 /usr/share/example/default/resources/json_protocols/.stamp
 /usr/share/example/default/resources/json_protocols/README
 /usr/share/example/default/symbols/libexample.so/62BD5D7D261EC43AFCBABB208919AD480/libexample.so.sym

패키지에 아이펀 엔진 라이선스 파일 포함하기

라이선스 파일 적용 에 설명된 방법대로 account.ilf 를 설치해서 사용하는 경우, 패키지에도 이 파일이 포함되는 것이 바람직합니다.

account.ilf 를 source directory 상의 etc/ifunfactory/account.ilf 로 저장하면 DEB 혹은 RPM 파일로 패키지를 생성할 때 account.ilf 역시 같이 설치됩니다.

패키지에 게임 리소스 파일들 포함하기

콘텐츠 지원 Part 4: 기획 데이터 의 경우처럼 서버쪽 로직 구현을 위해서 참조되는 리소스 파일들이 있을 수 있습니다.

그런데 이런 리소스 파일들의 경우, 개발 중일 때와 실서비스에서 돌릴 때 게임 서버에서 모두 접근 가능해야됩니다. 이를 위해서 많은 경우 리소스 파일들을 고정된 위치에 복사해서 사용하게 되는데, 이는 사용자 ID 를 동일하게 유지해야되는 문제나 게임 서버를 update 할 때 리소스를 별도로 업데이트 해야되는 등의 문제를 야기합니다.

아이펀 엔진은 이런 문제를 해결하기 위해서 게임 개발자가 특정 디렉토리들을 리소스 디렉토리로 지정할 수 있습니다. 이렇게 지정된 디렉토리들은 게임 서버를 패키징할 때 패키지에 같이 포함되며, 게임 서버에서도 일관된 방법으로 파일을 접근할 수 있게 해줍니다.

리소스 디렉토리 지정

최상위 디렉터리의 CMakeLists.txtRESOURCE_DIRS 라는 변수에 리소스 디렉토리들을 나열합니다.

1
2
3
4
5
...
set(RESOURCE_DIRS game_data)
...

include(Funapi)

코드 상에서 리소스 파일 접근

리소스 파일들은 서버를 개발중일 때는 현재 소스 디렉토리 상에 위치하고, 서비스 중일 때는 패키지에 따라 특정 위치에 설치되게 됩니다. 이 때문에 리소스 파일들을 접근하기 위해서는 소스 코드에서 GetResRoot() 함수의 결과값을 prefix 로 이용해야됩니다. 이 함수는 게임 서버가 개발 중이든, 서비스 중이든 동일하게 리소스 파일을 접근할 수 있는 것을 보장합니다.

예를 들어, game_data 라는 디렉토리가 리소스로 지정된 앞의 예에서, game_data/my_file1 이라는 파일을 접근하기 위해서는 다음과 같이 사용합니다.

1
string path = GetResRoot() + "/game_data/my_file1";

실 서비스로 배포하기

패키지의 배포와 설치에 관해서는 서버 관리 Part 4: 서버 배포 를 참고해주세요.