Day 30 - 使用 CDK 创建 Open Unlight 游戏

https://ithelp.ithome.com.tw/upload/images/20201015/20117701P7SaYXBQqw.png

今天是铁人赛最後一天,我要来跟大家介绍一个游戏 Open Unlight 它是一个在 2019 年 7 月 27 日 Open Source 的一个游戏,刚开源的时候因为没有安装说明文件而且有缺少档案,所以不容易部署在当年的 2019 年 8 月 8 日由 Open Unlight 团队修改成 legacy-unlight-docker 继续维护
它应该算是全世界少数 Open Source Server-Client 架构的游戏之一,Open Source 的游戏实在是太少了 XD
而为什麽要介绍它呢?因为今天的题目就是教大家用 CDK 把 Unlight 游戏部署起来呀!

Unlight 游戏 Server 部署文件

我们今天目标以一台 EC2 在里面跑 Docker 的架构把整个游戏服务器创建起来

建置前我们先看一下 Legacy Unlight Docker (中文) 游戏专案介绍在文件里面可以看到游戏的部署分为 Server 端与 Client 端,而 Server 端有预编译 Image 可以使用,但是 Client 端没有需要自己手动编译,而且 Client 端编译的时候需要准备字型档

快速建置指令

而 Open Unlight 其实提供专属的 UnlightCLI 指令可以帮助快速建立系统,不一定需要用 Legacy Unlight Docker 从 Source Code 编译

下载指令

指令下载方法

$ gem install unlight-cli

启动专案

启动游戏方法

$ unlight init

导读完应该就大概知道怎麽把游戏建立起来了吧!那我们就来写今天的 CDK 吧!

Unlight 游戏 CDK

CDK 部分只有写到 Server 端部署完成,Client 端还是需要进入机器手动编译的,这点需要注意一下。

建立 Default VPC

今天只有一台 EC2 就直接使用 Default VPC 吧!

const vpc = ec2.Vpc.fromLookup(this, "VPC", {
  isDefault: true,
});

建立 EC2

系统安装脚本准备

今天建立的 EC2 主要让 User Data 帮我们把整个环境建立起来并执行游戏,它会开启 14 台游戏主机 1 台资料库与 1 台 cache 服务器

更新系统

yum update -y

安装 vim ruby Nginx

amazon-linux-extras install vim ruby2.4 nginx1 epel -y

安装 git htop

yum install git htop -y

安装 docker

amazon-linux-extras install -y docker

下载 docker-compose

curl -L https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose

加入 docker-compose 执行权限

chmod +x /usr/local/bin/docker-compose

启动 docker

systemctl restart docker

设定开机启动 docker

systemctl enable docker

设定 ec2-user 使用 docker

usermod -a -G docker ec2-user

安装 Nginx

amazon-linux-extras install nginx1 -y

启动 Nginx

systemctl restart nginx

设定开机启动 Nginx

systemctl enable nginx

下载 unlight-cli

gem install unlight-cli -N --clear-sources --minimal-deps

执行 unlight init 启动游戏

unlight init

CDK 建立 EC2

EC2 部分我们把上面讨论的 User Data 放进去让它开机的时候执行,这是因为服务需求比较大我们开的机器等级是 t3a.medium 更小台应该会跑不动

const instance = new ec2.Instance(this, "Instance", {
  vpc,
  instanceType: ec2.InstanceType.of(
    ec2.InstanceClass.T3A,
    ec2.InstanceSize.MEDIUM
  ),
  machineImage: ec2.MachineImage.latestAmazonLinux({
    generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2,
  }),
  vpcSubnets: {
    subnetType: ec2.SubnetType.PUBLIC,
  },
  keyName: "KeyPair",
});
instance.userData.addCommands(
  `yum update -y`,
  `amazon-linux-extras install vim ruby2.4 nginx1 epel -y`,
  `yum install tmux git htop -y`,
  `amazon-linux-extras install -y docker`,
  "curl -L https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose",
  `chmod +x /usr/local/bin/docker-compose`,
  `systemctl restart docker`,
  `systemctl enable docker`,
  `usermod -a -G docker ec2-user`,
  `amazon-linux-extras install nginx1 -y`,
  `systemctl restart nginx`,
  `systemctl enable nginx`,
  `gem install unlight-cli -N --clear-sources --minimal-deps`,
  `unlight init`
);
new cdk.CfnOutput(this, "instance", {
  value: instance.instancePublicDnsName,
});

设定防火墙

如果要开设给大家玩记得要把 22 port 保护起来呦!一样我们为了方便 debug 所以先把 22 port 全开

Unlight 游戏使用的 Port 为 11000 ~ 13000,相信大家应该不会想用前面几篇教的方法然後用 for 回圈跑吧 XD

所以今天说明一个之前没讲过用来控制 Security Group 方法 tcpRange 就可以一行帮我们完成 Port 区段的开设

instance.connections.allowFrom(ec2.Peer.anyIpv4(), ec2.Port.tcp(22));
instance.connections.allowFrom(
  ec2.Peer.anyIpv4(),
  ec2.Port.tcpRange(11000, 13000)
);

以上就是今天的 CDK 教学!就这麽简单!

Unlight 游戏 Server 部署测试

写完後我们就来执行今天的 CDK 吧!cdk deploy 把它执行下去!

查看系统是否有正常跑起来

部署完後我们就可以登入进去输入 docker ps 看看系统是否有跑起来拉!
如下资讯就可以看到系统是正常执行的情况

  • 14 台游戏主机
  • 1 台资料库
  • 1 台 cache 服务器

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-2/
[ec2-user@ip-172-31-43-71 ~]$ docker ps
CONTAINER ID        IMAGE                              COMMAND                  CREATED             STATUS              PORTS                      NAMES
ae55da85c62f        openunlight/legacy-server:latest   "server xmlsocket"       4 minutes ago       Up 23 seconds       0.0.0.0:11999->11999/tcp   openunlight_xmlsocket_1
dbd1591f84b9        openunlight/legacy-server:latest   "server raid_rank 12…"   4 minutes ago       Up 23 seconds       0.0.0.0:12070->12070/tcp   openunlight_raid_rank_server_1
5d491c301bcb        openunlight/legacy-server:latest   "server data_lobby 1…"   4 minutes ago       Up 22 seconds       0.0.0.0:12032->12032/tcp   openunlight_data_server_1
92189a119d6e        openunlight/legacy-server:latest   "server lobby 12002"     4 minutes ago       Up 28 seconds       0.0.0.0:12002->12002/tcp   openunlight_lobby_server_1
ca1c6b1795ba        openunlight/legacy-server:latest   "server matching 120…"   4 minutes ago       Up 23 seconds       0.0.0.0:12018->12018/tcp   openunlight_match_server_1
d502e85a13de        openunlight/legacy-server:latest   "server game 12008"      4 minutes ago       Up 22 seconds       0.0.0.0:12008->12008/tcp   openunlight_game_server_1
a615ab3896ae        openunlight/legacy-server:latest   "server global_chat …"   4 minutes ago       Up 27 seconds       0.0.0.0:12020->12020/tcp   openunlight_global_chat_server_1
f1fc99c578dd        openunlight/legacy-server:latest   "server raid_data 12…"   4 minutes ago       Up 31 seconds       0.0.0.0:12100->12100/tcp   openunlight_raid_data_server_1
97eb265c132f        openunlight/legacy-server:latest   "server chat 12012"      4 minutes ago       Up 29 seconds       0.0.0.0:12012->12012/tcp   openunlight_chat_server_1
0d7d7fe736cc        openunlight/legacy-server:latest   "server raid 12050"      4 minutes ago       Up 28 seconds       0.0.0.0:12050->12050/tcp   openunlight_raid_server_1
7bf3e0aeaea9        openunlight/legacy-server:latest   "server raid_chat 12…"   4 minutes ago       Up 21 seconds       0.0.0.0:12090->12090/tcp   openunlight_raid_chat_server_1
7899ae49d6b2        openunlight/legacy-server:latest   "server authenticati…"   4 minutes ago       Up 22 seconds       0.0.0.0:12001->12001/tcp   openunlight_auth_server_1
92c136738e17        openunlight/legacy-server:latest   "server watch 12080"     4 minutes ago       Up 29 seconds       0.0.0.0:12080->12080/tcp   openunlight_watch_server_1
b4fd0bec724b        openunlight/legacy-server:latest   "server quest 12005"     4 minutes ago       Up 28 seconds       0.0.0.0:12005->12005/tcp   openunlight_quest_server_1
58625fbb5e55        mysql:5.7                          "docker-entrypoint.s…"   4 minutes ago       Up 26 seconds       3306/tcp, 33060/tcp        openunlight_db_1
c60470b7c2f3        memcached:1.5.16-alpine            "docker-entrypoint.s…"   5 minutes ago       Up 29 seconds       11211/tcp                  openunlight_memcached_1

部署与编译 Client

如前面所说因为 Open Unlight 游戏的 Client 需要依靠资料库才可以被 build 出来,所以大家需要跟我一起进入机器手动把 Client 端 build 起来

字体档

字体档需要大家找一下把它放到 /home/ec2-user/OpenUnlight/fonts 里面,要准备的字体如:

语言 必要字体
繁体中文 cwming.ttf (cwTeXMing 明体), wt004.ttf (王汉宗特明体), nbr.ttf

nbr.ttf 是一个名为 Bradley Gratis 的字体,但 Unlight 是有客制化过的。

编译 Client

准备好字体档後,就可以来跑 client 建置脚本了,其实只要把字体档准备好差不多就好了,执行以下指令

$ export ROOT_DIR="/home/ec2-user/OpenUnlight"
$ git clone https://github.com/unlightcpa/Unlight-Images.git OpenUnlight/assets
$ mkdir ${ROOT_DIR}/OpenUnlight/dist
$ mkdir ${ROOT_DIR}/OpenUnlight/fonts

$ docker run --rm -v ${ROOT_DIR}/assets:/assets \
                  -v ${ROOT_DIR}/dist:/app/dist \
                  -v ${ROOT_DIR}/fonts:/app/fonts \
                  -e LANGUAGE=tcn \
                  openunlight/legacy-builder compile-client

结果会出现在 dist 资料夹里面

$ ls -all OpenUnlight/dist/
total 17136
drwxrwxr-x 2 ec2-user ec2-user       43 Oct 14 17:22 .
drwxrwxr-x 5 ec2-user ec2-user       83 Oct 14 17:11 ..
-rw-r--r-- 1 root     root         1976 Oct 14 17:22 index.html
-rw-r--r-- 1 root     root     17539965 Oct 14 17:22 Unlight.swf

Host Client

有了 Unlight.swf 与 index.html 後就可以把档案放到我们前面安装的 Nginx 里面拉!
它的结构需要如:

dist
├── Unlight.swf
├── index.html
└── public
    ├── config.xml
    ├── image/
    ├── news.xml
    └── sound/
  • image 与 sound
    • 在 OpenUnlight/assets 可以找到它
  • config.xml 与 news.xml

不过其实我有准备好脚本,执行它就可以了!

$ sudo cp /home/ec2-user/OpenUnlight/dist/index.html /home/ec2-user/OpenUnlight/dist/Unlight.swf /usr/share/nginx/html/
$ sudo cp -r /home/ec2-user/OpenUnlight/assets/public /usr/share/nginx/html/
$ sudo wget https://raw.githubusercontent.com/unlightcpa/Unlight/master/app/client/public/news.xml.orig -O /usr/share/nginx/html/news.xml
$ sudo wget https://raw.githubusercontent.com/unlightcpa/Unlight/master/app/client/public/config.xml.orig -O /usr/share/nginx/html/config.xml

在开始前需要记得修改 /usr/share/nginx/html/config.xml 把里面的 localhost 修改成自己的 EC2 网域或是 IP

https://ithelp.ithome.com.tw/upload/images/20201015/20117701JIwwIvdaGO.png

小错误:架设起来的 index.html 会有一个 swfobject.js 找不到虽然不会影响开启不过如果看到觉得烦可以修改一下到 CloudFlare CDN

https://cdnjs.cloudflare.com/ajax/libs/swfobject/2.2/swfobject.js

测试游戏

超兴奋的打开网址就可以看到登入介面罗!

https://ithelp.ithome.com.tw/upload/images/20201015/20117701lYnRGfRvOu.png

赶紧注册一下游戏帐号
https://ithelp.ithome.com.tw/upload/images/20201015/20117701ojDxbwFi4y.png

注册成功,如此就可以确定资料库串接也是正常的
https://ithelp.ithome.com.tw/upload/images/20201015/20117701WEZAZ8Owre.png

开始玩游戏吧!(误
https://ithelp.ithome.com.tw/upload/images/20201015/20117701yvpMM7KPKE.png

最後

谢谢大家这 30 天的陪伴,不管你是一开始就看我教学文的朋友或是看到分享才进来观看的朋友,希望这 30 天的教学文对於一个刚学习 AWS CDK 的朋友有帮助,因为我知道中文教学文其实还是一个偏少的一个情况,所以写中文就是希望让母语中文的朋友在学习上可以减少阻碍,另外如果大家对我的系列文章有兴趣,欢迎大家关注我的部落格谢谢大家拉 ~


想要看更多吗?欢迎到我的部落格参观

文章内容主要是网路或是程序开发类型的文章

本文同步刊载於 Clarence 部落格:Day 30 - 使用 CDK 创建 Open Unlight 游戏


「AWS CDK 完全学习手册:打造云端基础架构程序码 IaC」
本书改编并延伸自第 12 届 iT 邦帮忙铁人赛获得 DevOps 组冠军的《用 CDK 定义 AWS 架构》系列文章,以简单、好读的行文风格详述技术细节,并提供完整的程序码范例与说明,一步一步带领新手从零开始踏上 AWS CDK 技术达人之路。

有兴趣的朋友欢迎至天珑书局选购!

购书连结 https://bit.ly/2ZMAebE

https://ithelp.ithome.com.tw/upload/images/20211103/20117701W7l6fQnn2L.jpg


<<:  [Day - 30] 不完美的结束

>>:  [Day 30] 微探讨 Angular 的 Event binding 与 Property binding

《老师爱说故事,专家爱讲模型》

这本书内容少少的,但我划的重点跟思考颇多。 例如我们因为模型常要复杂但又易懂,最终得到的归纳就是那些...

开源网路钓鱼框架-Gophish(上)

开赛时提到的社交工程钓鱼邮件 除了快速好上手的SET工具之外 gophish具有美美的UI介面,简洁...

[Day13] 时间处理

今日目标 限制帧数 Framerate Independent 设计错误 这个是我再次参考Game ...

[Day13] Node.js & NPM

从头到尾硬干一个网站是非常费功费时的事情,为了节省开发时间就会尽量引用现成的套件,随着引用的套件越来...

#3 JavaScript Crash Course 2

今天教 Promise Async / Await。 Promise Promise 这个东西跟时间...