서버 관리 Part 4: 서버 배포¶
iFun Engine으로 작성한 게임 서버는 서비스 설정을 지정하고, 이를 패키지로 묶어서 개별 서버에 설치/업그레이드 할 수 있습니다. 이 문서에서는 그 과정을 설명합니다. 현재 지원하는 운영체제는 아래와 같습니다. * Ubuntu 16.04 64bit(Xenial) * Ubuntu 18.04 64bit(Bionic) * Ubuntu 20.04 64bit(Focal) * CentOS 7 64bit * CentOS 8 64bit
Important
Ubutu 14.04 LTS (Trusty Tahr) 에 대한 지원은 1.0.0-3986 Stable 버전을 끝으로 종료되었습니다.
Note
아이펀 엔진 윈도우 버전의 배포 방법은 프로젝트 배포하기 을 참고해주세요.
서비스 설정하기¶
Note
Ubuntu 16.04 버전과 CentOS 7 버전부터는 운영체제가 서비스를 관리하기 위해 systemd 를 공통적으로 사용합니다.
Systemd¶
프로젝트 소스 디렉터리의 etc/systemd/{{project-name}}.service
파일을
패키지 생성 시에 포함해서 배포합니다.
설정 파일 내용과 관련한 세부 사항은 Systemd 페이지를 확인해주세요.
Note
Flavor: 역할에 따라 서버 구분하기 에 언급된 flavor 를 사용할 경우, 파일 이름은
etc/systemd/{{project-name}}.{{flavor}}.service
입니다.
예제: 서비스를 실행할 유저 변경하기
보안 상의 이유로, root
대신에 다른 유저를 생성하고, 해당 유저 계정으로
서비스를 실행하는 것을 권장합니다.
아래는 centos 라는 유저와 그룹으로 서비스를 실행하게끔 수정한 예시입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | [Service]
LimitNOFILE=999999
# It is strongly recommended that one should use uid:gid other than the root
# NOTE: Please update User=, Group=, and ExecStartPre=
User=centos
Group=centos
# Makes the daemon automatically restart
Type=simple
Restart=on-failure
RestartSec=5s
# create directories, and change permissions (with root privileges)
PermissionsStartOnly=true
ExecStartPre=/usr/bin/mkdir -p /var/log/funapi/example/glog \
/var/log/funapi/example/activity \
/var/crash/funapi/example
# NOTE: change root:root to service's uid:gid
ExecStartPre=/usr/bin/chown -R centos:centos /var/log/funapi/example/glog \
/var/log/funapi/example/activity \
/var/crash/funapi/example
ExecStart=/usr/bin/example-launcher
|
패키지 생성¶
패키지 생성에 대해서는 서버 관리 Part 3: 서버 패키징 을 참고해주세요.
패키지 설치/업그레이드¶
Ubuntu 16.04 또는 18.04 또는 20.04¶
서버 관리 Part 3: 서버 패키징 에서 설명된 대로 deb 파일을 생성합니다.
이 파일을 서버에 복사한 후 dpkg
명령으로 설치합니다.
가령 example 이라는 이름의 게임인 경우 다음과 같습니다.
$ sudo dpkg -i example_0.0.1_install.deb
[sudo] password for ubuntu:
Selecting previously unselected package example.
(Reading database ... 424079 files and directories currently installed.)
Preparing to unpack example_0.0.1_install.deb ...
Unpacking example (0.0.1) ...
Setting up example (0.0.1) ...
Processing triggers for ureadahead (0.100.0-16) ...
ureadahead will be reprofiled on next reboot
Important
만약 funapi1-runtime
이 설치되지 않은 경우 패키지 설치 오류 메시지가 나옵니다. 이런 경우에는 다음 명령을 실행하면 자동으로 필요한 패키지와 서버 패키지가 설치됩니다.
$ sudo apt-get install -f
Centos 7 또는 Centos 8¶
서버 관리 Part 3: 서버 패키징 에서 설명된 대로 rpm 파일을 생성합니다.
이 파일을 서버에 복사한 후 rpm
명령으로 설치합니다.
가령 example 이라는 이름의 게임인 경우 다음과 같습니다.
$ sudo rpm -i example_0.0.1_install.rpm
Important
만약 funapi1-runtime
이 설치되지 않은 경우 패키지 설치 오류 메시지가 나옵니다. 이런 경우에는 다음 명령을 실행해서 funapi1-runtime 을 먼저 설치합니다.
$ sudo yum install funapi1-runtime
서비스 시작/종료하기¶
Note
Ubuntu 16.04 버전과 CentOS 7 버전부터는 운영체제가 서비스를 관리하기 위해 systemd 를 공통적으로 사용합니다.
서비스 인스턴스 여러개 실행하기¶
하나의 호스트에 같은 서버 프로세스를 여러 개 띄우고자 할 때에는 서비스 유닛
파일을 수정해서 systemctl
명령을 실행할 때, 실행 인자로 구별자를 전달할 수
있습니다.
앞에서 설치한 exmaple 라는 서비스를 01, 02 라는 인스턴스로 구별해서 실행하는 방법을 순서에 따라 설명하겠습니다.
Note
아이펀 엔진 프로젝트인 exmaple 패키지가 설치되어 있다고 가정하겠습니다.
설명에서 예시로 사용하는 example 은 프로젝트명으로 Flavor 를 사용하는 경우에는 다른 형식으로 표현됩니다. 01, 02 프로세스를 구별하기 위한 구별자 예시로 사용자 여러분이 원하는 이름으로 변경할 수 있습니다.
준비하기¶
먼저, 서비스 실행과 관련한 파일들이 실행 인자를 처리할 수 있도록 변경해야 합니다.
패키지를 설치할 때 생성된 원본 파일들은 보존하기 위해서 복사해서 사용하겠습니다.
# 실행 인자를 처리할 수 있는 서비스 유닛 파일 생성
$ sudo cp /lib/systemd/system/example.service /lib/systemd/system/example@.service
# 서버 런처 스크립트 생성
$ sudo cp /usr/bin/example-launcher /usr/bin/example-launcher.tmpl
# 개별 서버 프로세스에 적용될 MANIFST 파일을 비어있는 상태로 생성
$ sudo mkdir /etc/example
$ sudo touch /etc/example/MANIFEST-01.override.json
$ sudo touch /etc/example/MANIFEST-02.override.json
서비스 유닛 파일 수정¶
앞서 생성한 /lib/systemd/system/example@.service
파일을 열어서 다음과 같이
수정해 주세요.
%i
문자열이 서비스를 실행할 때 전달하는 인스턴스 구분자로 치환됩니다.
# Systemd service configuration for example template
[Unit]
Description=iFun Engine game - example %i
After=syslog.target network-online.target
... 중략 ...
# create directories, and change permissions (with root privileges)
PermissionsStartOnly=true
ExecStartPre=/usr/bin/mkdir -p /var/log/funapi/example-%i/glog \
/var/log/funapi/example-%i/activity \
/var/log/funapi/example-%i/counter \
/var/crash/funapi/example
# NOTE: change root:root to service's uid:gid
ExecStartPre=/usr/bin/chown -R root:root /var/log/funapi/example-%i/glog \
/var/log/funapi/example-%i/activity \
/var/log/funapi/example-%i/counter \
/var/crash/funapi/example
EnvironmentFile=/etc/default/example
ExecStart=/bin/bash -e /usr/bin/example-launcher.tmpl %i
서버 런처 파일 수정¶
마찬가지로 /usr/bin/example-launcher.tmpl
파일을 열어서 다음과 같이 수정해
주세요.
런처 스크립트의 실행 인자($1
)로 인스턴스 구분자를 전달 받아서
사용합니다.
#!/bin/bash -e
# vim: fileencoding=utf-8 tabstop=2 softtabstop=2 shiftwidth=2 expandtab
... 중략 ...
# You can override by using 'export VAR="value"' before running this script.
# If you are running the script through upstart or systemd, set the variable
# in /etc/default/<your_game_name>.
################################################################################
# consume instance name from command line
INSTANCE=$1
shift
... 중략 ...
################################################################################
# YOUR GAME LOCATIONS.
################################################################################
debugging_symbol_dir="$GAME_ROOT_DIR/usr/share/example/default/symbols"
resource_root_dir="$GAME_ROOT_DIR/usr/share/example/default/resources"
component_library_dir="$GAME_ROOT_DIR/usr/lib/example/default"
component_manifest_dir="$GAME_ROOT_DIR/usr/share/example/default/manifests"
component_override_file="${GAME_MANIFEST_OVERRIDE:-/etc/example/MANIFEST-${INSTANCE}.override.json}"
log_root_dir="${GAME_LOG_ROOT_DIR:-/var/log/funapi/example-${INSTANCE}}"
crashdump_root_dir="${GAME_CRASHDUMP_ROOT_DIR:-/var/crash/funapi/example}"
glog_options="${GAME_GLOG_OPTIONS:- --max_log_size=10 --stop_logging_if_full_disk}"
contact_email_address="${GAME_CONTACT_EMAIL_ADDRESS:-}"
################################################################################
# Sources the implementation to run the executable.
################################################################################
source ${FUNAPI_DATA_DIR}/bash/launcher-common.sh
설정 오버라이드 하기¶
서버 프로세스들은 서비스에 사용할 포트 번호가 중복되면 안되기 때문에 서비스 각자 MANIFEST override 파일을 생성해서 개별적으로 설정해야 합니다.
미리 생성해 둔 /etc/example/MANIFEST-01.override.json
,
/etc/example/MANIFEST-02.override.json
파일을 열어서 아래와 같이 각자 포트가 중복되지 않도록 설정합니다.
기본 프로젝트에서 사용하는 포트들만 변경했으며, RPC 기능 등을 사용한다면 관련 포트들도 모두 설정해야 합니다. 자세한 내용은 MANIFEST.json 오버라이드하기 를 참고해 주시기 바랍니다.
// /etc/example/MANIFEST-01.override.json
{
"override": {
"ApiService": {
"api_service_port": 8014
},
"SessionService": {
"tcp_json_port": 8012,
"http_json_port": 8018
}
}
}
// /etc/example/MANIFEST-02.override.json
{
"override": {
"ApiService": {
"api_service_port": 9014
},
"SessionService": {
"tcp_json_port": 9012,
"http_json_port": 9018
}
}
}
서비스 실행하기¶
이제 example@{인스턴스명}
과 같은 형식으로 각 서비스를 구별할 수 있습니다.
서비스를 실행하기에 앞서 다음 명령을 실행해서 서비스를 활성화합니다.
sudo systemctl daemon-reload
sudo systemctl enable hello@01
sudo systemctl enable hello@02
자, 이제 서비스를 실행해 보겠습니다.
sudo systemctl start hello@01
sudo systemctl start hello@02
서비스 실행 로그 보기¶
Ubuntu 16.04 버전과 CentOS 7 보다 이후에 출시된 리눅스 배포판들은 운영체제에서 실행되는 서비스를 관리하는 데에 systemd 를 공통적으로 사용합니다.
systemd 는 서버가 실행되거나 종료될 때 별도의 로그를 생성하는데, 이 로그를 통해서 서비스가 원활히 실행되고 있는지 확인할 수 있습니다.
Note
게임 서버 자체의 로그는 프로그래밍 Part1: 디버그용 로그 을 참고해주세요.
Note
게임 서버의 coredump 에 대해서는 디버깅 및 프로파일링 지원 을 참고해주세요.
Systemd¶
systemd 로 실행한 경우, 서비스 로그는 journalctl -x -u {{project-name}}
명령으로 확인할 수 있습니다.
만일 example 이라는 서버의 경우 다음과 같이 로그를 볼 수 있습니다.
$ sudo journalctl -x -u example
패키지 버전 고정하기¶
라이브 환경에서는 사용하는 funapi1-runtime
나 에이전트, 혹은 개발하는데 사용한 외부 라이브러리의
버전을 고정해야하는 경우가 있습니다. 아래와 같은 방법을 이용하시면 됩니다.
Ubuntu 환경에서 버전 고정하기¶
버전 고정:
funapi1-runtime
의 버전을 고정한다고 하면, 다음과 같이 명령을 입력하면 됩니다.
$ sudo apt-mark hold funapi1-runtime
해당 명령 후에는 apt-get upgrade
등에서 해당 패키지를 제외하고 업데이트하게 됩니다.
버전이 고정된 패키지 확인:
$ sudo apt-mark showhold
funapi1-runtime
위에서 입력한 패키지가 버전이 고정된 것을 확인하실 수 있습니다.
버전 고정 해제:
다음 명령으로 패키지 버전이 고정된 것을 풀 수 있습니다.
$ sudo apt-mark unhold funapi1-runtime
이 이후에는 패키지를 업그레이드할 수 있습니다.
CentOS 환경에서 버전 고정하기¶
CentOS 환경에서 버전을 고정하려면 추가 패키지가 필요합니다. 다음 명령으로 설치해주시면 됩니다.
$ sudo yum install yum-versionlock
yum-versionlock
패키지를 설치한 후에 아래 명령들을 실행할 수 있습니다.
버전 고정:
funapi1-runtime
의 버전을 고정한다고 하면, 다음과 같이 명령을 입력하면 됩니다.
$ sudo yum versionlock funapi1-runtime
해당 명령 후에는 yum update
등에서 해당 패키지를 제외하고 업데이트하게 됩니다.
버전이 고정된 패키지 확인:
$ sudo yum -q versionlock list
0:funapi1-runtime-1.0.0-1680centos7.*
위에서 입력한 패키지가 버전이 고정된 것을 확인하실 수 있습니다.
버전 고정 해제:
다음 명령으로 패키지 버전이 고정된 것을 풀 수 있습니다.
$ sudo yum versionlock delete funapi1-runtime
이 이후에는 패키지를 업그레이드할 수 있습니다.
Important
CentOS 6에서는 sudo yum versionlock delete '*:funapi1-runtime*'
처럼 입력하셔야 합니다.
비표준 위치에 게임 서버 설치하기¶
비표준 위치에 게임 서버 패키지 설치하기¶
앞에서는 DEB
나 RPM
형태의 파일을 만들어서 배포하는 것을 설명했습니다. 이런 패키지 파일은 미리 정해진 위치에 게임 서버를 설치하고, root 권한도 필요로 합니다.
그러나 경우에 따라서는 root 권한을 취득할 수 없는 경우도 있을 수 있고, 특정 디렉토리 아래 게임 서버 내용을 모두 설치해야될 수도 있습니다. 예를 들어, 퍼블리셔에게 게임 서버를 전달하면 퍼블리셔가 사용하는 Linux 계정 아래 게임 패키지가 그대로 설치되길 바라는 경우를 생각해볼 수 있습니다. 이런 경우는 설치 위치를 강제하는 DEB
나 RPM
으로는 곤란하고 tar.gz
로 패키지를 생성해서 퍼블리셔에게 전달하고 퍼블리셔가 원하는 위치에 압축을 풀게 하는 것이 좋습니다. (tar.gz
의 생성에 관련해서는 생성 가능한 패키지 타입 을 참고하세요.)
편의상 우리가 만드는 게임의 이름을 hello
라고 하고, lobby
flavor 를 사용했다고 하겠습니다. 그러면 생성되는 패키지는 hello_0.0.1_install-lobby.tar.gz
가 될 것입니다.
이제 퍼블리셔가 관리하는 리눅스 서버의 계정이 zeus 라고 가정했을 때, 퍼블리셔는 저 패키지를 /home/zeus
아래에서 풀었을 것입니다.
$ cd /home/zeus
$ tar zxf hello_0.0.1_install-lobby.tar.gz
이렇게 하면 /home/zeus
아래에 DEB
나 RPM
으로 설치했을 때 /
디렉토리 아래 설치되었을 내용들이 그대로 복사된 것을 확인하실 수 있을 겁니다.
비표준 위치에 게임 서버 패키지 설치하고 서비스로 띄우기¶
그런데, 이 방법은 파일은 복사하지만, upstart
나 systemd
처럼 게임 서버를 서비스로 (즉, 데몬으로) 실행시키는 것을 자동으로 해줄 수는 없습니다. 따라서 이런 설정은 수작업으로 해줘야됩니다.
또한 서비스를 등록하더라도 /
가 아니라 우리가 지정한 /home/zeus
에서 게임 서버를 찾을 수 있게끔 경로를 지정하는 작업도 필요합니다. 이 작업들은 게임 서버 OS를 세팅할 때 처음 1회만 하면 됩니다.
아래는 Upstart 와 Systemd 의 경우에 대해서 서비스를 등록하는 방법을 설명합니다. 두 가지 방법 모두, 환경 변수를 지정해주고 스크립트를 등록해주는 작업을 하게 됩니다.
서비스 설정 파일에 지정 가능한 환경 변수¶
GAME_ROOT_DIR: 게임 서버가 설치된 경로를 지정합니다. 지정하지 않으면 / 가 기본값으로 사용됩니다.
GAME_MANIFEST_OVERRIDE: MANIFEST.json 오버라이드하기 에 기술된
MANIFEST.json
오버라이드 파일 위치를 지정합니다. 지정하지 않으면 /etc/{{project}}/MANIFEST.override.json 으로 기본 지정됩니다.GAME_LOG_ROOT_DIR: 로그 파일들이 생성될 디렉토리를 지정합니다. 지정하지 않으면 기본값으로 /var/log/funapi/게임이름 이 사용됩니다.
GAME_CRASHDUMP_ROOT_DIR: 코어덤프 디렉토리를 지정합니다. 지정하지 않으면 기본값으로 /var/crash/funapi/게임이름 이 사용됩니다.
GAME_GLOG_OPTIONS: Google logging 의 추가 옵션을 지정합니다. 지정하지 않으면 기본값으로 –max_log_size=10 –stop_logging_if_full_disk 가 사용됩니다.
GAME_CONTACT_EMAIL_ADDRESS: 게임 서버가 죽는 경우 알림을 받을 이메일 주소를 지정합니다. 지정하지 않으면 이메일을 보내지 않습니다.
Tip
GAME_CONTACT_EMAIL_ADDRESS 를 세팅하면 게임 서버가 죽을 때마다 알림 메일을 받을 수 있어서 편리합니다.
systemd 를 사용하는 경우 수작업으로 서비스 등록하기¶
비표준 위치에 설치한 게임 서버를 서비스로 등록하려면 패키지 생성 전 작업이 필요합니다.
먼저 소스 디렉터리로 이동한 후 CMakeLists.txt
에 주석처리 되어 있는 set(WANT_SYSTEMD false) 의 주석을 풀고 true
로 설정해 줍니다.
set(WANT_SYSTEMD true)
그리고 etc/systemd/hello.lobby
파일에 systemd 가 우리가 게임을 설치한 /home/zeus
에서 프로그램을 찾게끔 다음처럼 써줍니다.
서비스 설정 파일에 지정 가능한 환경 변수 에 나열된 다른 변수들도 개행하여 여러개 쓸 수 있습니다.
GAME_ROOT_DIR=/home/zeus
Important
export
를 쓰지 않습니다.
그 후 etc/systemd/hello.lobby.service
파일을 열어서 2 개의 ExecStartPre 와 맨 아래줄에 있는 ExecStart 의 경로의 /usr
앞에
게임을 설치할 home/zeus
를 추가해 줍니다.
ExecStartPre=/bin/mkdir -p /home/zeus/var/log/funapi/example/glog \
/home/zeus/var/log/funapi/example/activity \
/home/zeus/var/log/funapi/example/counter \
/home/zeus/var/crash/funapi/example
ExecStartPre=/bin/chown -R root:root /home/zeus/var/log/funapi/example/glog \
/home/zeus/var/log/funapi/example/activity \
/home/zeus/var/log/funapi/example/counter \
/home/zeus/var/crash/funapi/example
...
ExecStart=/home/zeus/usr/bin/hello.lobby-launcher
마지막으로 예제: 서비스를 실행할 유저 변경하기 의 설명에 따라 서버를 실행할 유저를 변경합니다.
서비스 등록을 위한 사전 작업을 완료했습니다. TGZ 로 패키징 합니다.
서버를 설치할 머신에서 패키징 한 파일의 압축을 풀면 etc/default/ 와 lib/systemd/system/ 이라는 디렉터리가 있을 것입니다.
이 디렉터리들 아래에는 각각 hello.lobby 파일과 hello.lobby.service 라는 systemd
서비스 설정 파일이 존재할 것입니다.
$ ls etc/default
hello.lobby
$ ls lib/systemd/system
hello.lobby.service
이 파일들을 다음처럼 복사합니다.
$ sudo cp etc/default/hello.lobby /etc/default/
$ sudo cp lib/systemd/system/hello.lobby.service /lib/systemd/system/
이제 다음처럼 게임 서버를 실행할 수 있습니다.
$ sudo systemctl start hello.lobby