ROS CDK魔法书:建立你的游戏王国(Java篇)

引言

在虚拟游戏的世界里,数字化的乐趣如同流动的音符,谱写着无数玩家的共同回忆。而在这片充满创意与冒险的乐园中,您的使命就是将独特的游戏体验与丰富的技术知识相结合,打造出令人难以忘怀的作品。当面对如何实现这一宏伟蓝图时,您或许会想:如何将一款简单而富有趣味的游戏部署到云端,使更多玩家共享这份乐趣?

别担心,现在您手中握有一把开启无限可能的大门钥匙——阿里云资源编排服务(Resource Orchestration Service,简称ROS)的云开发套件(Cloud Development Kit,简称CDK)。借助这一强大的工具,您可以轻松创建和管理云资源,将您的2048小游戏安全、快速地部署到云端,以便让它在浩瀚的网络中闪耀光芒。

在接下来的文章中,我们将一起踏上这段旅程,通过将2048小游戏部属到阿里云的实例,让您借助ROS CDK的魔法,为您的梦想游戏搭建起一个坚实的云基础。无需复杂的配置,也不必担心繁琐的操作,我们将以最简单的方式,带您一步步揭开部署游戏的面纱,实现从本地到云端的无缝迁移。

背景

什么是ROS CDK?

想象一下,您是一位游戏设计师,面前有一个崭新的游戏世界等待您去构建。在传统的开发过程中,您可能需要逐步搭建每一个元素,反复测试和优化,这不仅费时费力,还需要应对大量的技术细节。然而,假设您拥有一本魔法书,只需一段简短的代码,就能轻松生成整个游戏的架构,这本魔法书便是阿里云资源编排服务(Resource Orchestration Service,简称ROS)的云开发套件(Cloud Development Kit,简称CDK)。

ROS CDK 是一个强大的开发框架,允许您使用熟悉的编程语言来定义、构建和部署云资源。通过ROS CDK,您能够将游戏基础设施转化为代码(Infrastructure as Code, IaC),就像编写游戏逻辑一样轻松创建和配置云资源。

借助这个框架,您无需再逐一配置每个组件,而是能够编写直观的代码描述游戏的整体结构。这些代码随后会被转换为具体的云资源配置,比如云服务器(ECS)、对象存储服务(OSS)以及数据库服务等,并快速在云端部署。这种简化的流程使得整个开发过程更加高效且可重复,帮助开发者轻松实现跨团队的协作与分享。

将基础设施代码化,不仅降低了人为错误的风险,还让云服务管理变得如同玩游戏般简单。ROS CDK 为快速开发、升级和扩展游戏应用提供了无与伦比的便利,使您能把更多的精力投入到创意和设计中,而不是被繁琐的操作所困扰。简而言之,ROS CDK 赋予您在云端构建游戏世界的无尽可能性,让您的创意得以在这片广阔的数字海洋中翱翔。

什么是ECS?

在这个广袤无垠的云霄之域,你是一名追寻智慧与力量的幻术师,渴望孕育出无数绚丽多彩的应用与服务。在这神秘的征途上,你需要一个强大的支持者,为你的创世之路提供源源不断的计算资源——这便是ECS(弹性计算服务)。

ECS宛如一座巍峨耸立的云端堡垒,拥有着无数灵活且可扩展的魔法隔间(实例),每一个隔间都蕴含着强大的运算能量,能够随心所欲地变幻组合,以适应你的任何需求。无论是轻巧的文字咒语(轻量级应用),还是巨大的虚拟巨兽(复杂计算任务),ECS都能迅速响应,助你一臂之力。

将你的应用部署在ECS上,仿佛为它们施下了一个永恒的召唤咒。不论是刮风下雨,亦或是雷霆万钧,ECS都将为你提供高度可靠的计算能力,确保每一个念头都能在瞬间化为现实,推动你的奇幻世界不断发展壮大。

如同天际星辰的引导者,ECS让你对计算资源进行灵巧的调配与管理。它的智能监控与弹性伸缩能力如同召唤的法术,让你在流动的需求中完全掌控,无需担忧资源的紧缺与浪费。而那些强大的安全护盾(网络隔离与访问控制)则守护着你的应用免受外敌的侵犯,确保你的魔法研究与创意成果在安全的环境中悄然绽放。

在阿里云这片充满灵气的领域,ECS已经成为每位幻术师实现创世梦想、探索无尽可能的最佳伙伴。无论你的梦想多么宏伟、挑战多么艰巨,ECS将始终是你可以倚靠的庇护所,让你在云端尽情释放智慧与创造力。因此,尊敬的幻术师,当你准备在云海中绘制你的未来蓝图时,ECS定会成为你不可或缺的助手,为你书写更辉煌的篇章。

准备工作

语言要求

在进入IaC魔法世界前,我们还需要一些准备工作。为了安装ROS CDK,请确保Node.js、TypeScript以及Java满足以下版本要求:

  • Node.js:14.17.0及以上
  • TypeScript:3.8及以上
  • Java语言请确保JDK和Maven满足以下版本要求:
    • JDK:8及以上
    • Maven:3.6及以上

初始化工程项目

首先让我们获取魔杖(安装ROS CDK)。

注意:请确保你安装的 ros-cdk-cli 版本在 1.0.50 以上,可以通过运行 npm list -g 确认。

在你的魔法实践中,每当你打算开始一个全新的咒法项目,你都需要在你的魔法工作台(编程环境)上准备一些基础元素。就好比在开始一场远征前的准备过程,你需要确保你有一张图(项目框架),一些指南(配置)以及能够让你进出神秘地域(云平台)的通行证(凭证信息)。

初始化工程就好比是在你的魔法工作台上铺好一张干净的魔法制图纸,上面标注了将要完成的奇迹蓝图的基本轮廓。在你的电脑上,这就是创建一个包含必要文件结构的新目录,给魔法师们(开发者)提供了一个可以施展咒语(编码)的场所。

配置凭证信息则像是在你的魔法袍上缝上一枚能够开启云之城门的徽章,这枚徽章(AccessKey)凭证证明了你有权利指挥云中的能量流动,操纵存储在云中的宝藏。在阿里云的世界里,这意味着你需要在本地环境中配置好用于鉴权的AccessKey ID和Secret AccessKey。这样一来,当你使用ROS CDK这个强大的咒法工具时,它能够确保你是有权操控这些云资源的魔法师,而不是一个无意闯入的冒险者。

那么让我们在施展更高级魔法之前,先布置一下仪式现场。

  1. 执行以下命令,创建工程目录并初始化工程:
    mkdir demo
    cd demo
    ros-cdk init --language=java --generate-only=true
    
  2. 执行以下命令,配置阿里云凭证信息:
    ros-cdk config
    
  3. 根据界面提示输入配置信息:
    endpoint(optional, default:https://ros.aliyuncs.com):
    defaultRegionId(optional, default:cn-hangzhou):
    
    [1] AK
    [2] StsToken
    [3] RamRoleArn
    [4] EcsRamRole
    [0] CANCEL
    
    Authenticate mode [1...4 / 0]: 1
    accessKeyId:************************
    accessKeySecret:******************************
    
    ✅ Your cdk configuration has been saved successfully!
    

配置内容说明如下:

  • endpoint:ROS服务地址。默认值为https://ros.aliyuncs.com。
  • defaultRegionId:ROS资源栈部署的地域。默认值为cn-hangzhou。
  • Authenticate mode:鉴权方式。本示例的鉴权方式为AccessKey,您需要输入AccessKey ID和AccessKey Secret。关于如何获取AccessKey,请参见交互式配置(快速配置)

万事俱备,让我们开始ROS CDK魔法之旅。

最佳实践:云端部署2048小游戏

接下来,我们将通过一个最佳实践案例来演示如何在云端服务器部署2048小游戏。

进行如下步骤之前请确保你已完成所有必须的准备工作,包括环境配置和初始化项目工程。

安装依赖

首先,我们需要安装开发 CDK 项目时所需的依赖。

进入在「准备工作」中初始化的项目,并修改 pom.xml 文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
         xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.myorg</groupId>
    <artifactId>demo</artifactId>
    <version>0.1</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <cdk.version>1.1.0</cdk.version>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.myorg.DemoApp</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <!-- AliCloud ROS Cloud Development Kit (ROS CDK) -->
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>ros-cdk-core</artifactId>
            <version>1.1.0</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>ros-cdk-ecs</artifactId>
            <version>1.1.0</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

修改完成后执行以下命令,安装依赖:

mvn compile

添加资源

接着,我们要为项目中添加资源。本示例涉及到的资源有:

本项目涉及到的收费项有:

进入项目目录,并修改 src/main/java/com/myorg/DemoStack.java 的内容如下:

package com.myorg;

import com.aliyun.ros.cdk.core.*;
import com.aliyun.ros.cdk.ecs.*;

import java.util.ArrayList;
import java.util.Arrays;

public class DemoStack extends Stack {
    public DemoStack(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public DemoStack(final Construct scope, final String id, final StackProps props) {
        super(scope, id, props);

        // The code that defines your stack goes here
        RosInfo.setDescription("Deploy 2048 game through ROS CDK.");
        RosParameter zoneId = RosParameter.Builder.create(this, "ZoneId")
                .type(RosParameterType.STRING)
                .build();

        Vpc vpc = Vpc.Builder.create(this, "Vpc")
                .cidrBlock("192.168.0.0/16")
                .build();

        SecurityGroup securityGroup = SecurityGroup.Builder.create(this, "SecurityGroup")
                .vpcId(vpc.getRef())
                .build();

        VSwitch vSwitch = VSwitch.Builder.create(this, "VSwitch")
                .cidrBlock("192.168.0.0/24")
                .zoneId(zoneId.getValue())
                .vpcId(vpc.getRef())
                .build();

        Instance instance = Instance.Builder.create(this, "Instance")
                .vpcId(vpc.getRef())
                .vSwitchId(vSwitch.getRef())
                .securityGroupId(securityGroup.getRef())
                .zoneId(zoneId.getValue())
                .instanceType("ecs.c6e.large")
                .imageId("centos_7_8")
                .systemDiskCategory("cloud_essd")
                .ioOptimized("optimized")
                .build();

        SecurityGroupIngress securityGroupIngress = SecurityGroupIngress.Builder.create(this, "SecurityGroupIngress")
                .ipProtocol("tcp")
                .portRange("80/80")
                .sourceCidrIp("0.0.0.0/0")
                .securityGroupId(securityGroup.getRef())
                .nicType("intranet")
                .build();

        RunCommand runCommand = RunCommand.Builder.create(this, "RunCommand")
                .instanceIds(new ArrayList<>(Arrays.asList(instance.getRef())))
                .type("RunShellScript")
                .sync(true)
                .timeout(3600)
                .commandContent("yum install -y httpd wget\nsystemctl start httpd\nwget 'https://computenest-artifacts-cn-hangzhou.oss-cn-hangzhou-internal.aliyuncs.com/1853370294850618/cn-beijing/1697533575326/2048.tgz' -O 2048.tgz\ntar xvf 2048.tgz\nmv 2048/* /var/www/html && rm -rf 2048")
                .build();
        runCommand.addDependency(securityGroupIngress);

        RosOutput.Builder.create(this, "Url")
                .value("http://" + instance.getAttrPublicIp().toString() +":80")
                .build();
    }
}

运行 mvn compile 以编译CDK项目。

部署资源栈

执行以下命令以部署资源栈:

ros-cdk deploy --parameters ZoneId=cn-hangzhou-i --sync=true

--sync=true 会将资源栈信息同步返回至终端显示。成功后,命令行终端返回如下信息:

Create bucket(cdk-tcbgaxxxx-assets-cn-hangzhou) successfully!
Upload file(./cdk.out/DemoStack.template.json) to bucket(cdk-tcbgaxxxx-assets-cn-hangzhou) successfully!
DemoStack: deploying...
|DemoStack               |2024-09-09T08:56:47 | CREATE_COMPLETE      | ALIYUN::ECS::SecurityGroup | sg-bp121z2wd687mdxxxxxx | SecurityGroup

|DemoStack               |2024-09-09T08:56:47 | CREATE_COMPLETE      | ALIYUN::ECS::SecurityGroupIngress | sg-bp121z2wd687mdxxxxxx | SecurityGroupIngress

|DemoStack               |2024-09-09T08:56:47 | CREATE_COMPLETE      | ALIYUN::ECS::Instance   | i-bp16t9mt9b0uscixxxxx | Instance

|DemoStack               |2024-09-09T08:56:47 | CREATE_COMPLETE      | ALIYUN::ECS::VPC        | vpc-bp10y18ke2x6v0bjxxxxx | Vpc

|DemoStack               |2024-09-09T08:56:47 | CREATE_COMPLETE      | ALIYUN::ECS::VSwitch    | vsw-bp1qfb9u90cuyu69xxxxx | VSwitch

|DemoStack               |2024-09-09T08:56:47 | CREATE_COMPLETE      | ALIYUN::ECS::RunCommand | t-hz04w6ckiuxxxxx | RunCommand


Outputs:

 Key: Url  Value: http://121.40.xxx.xx:80 Description: No description given

 ✅ The deployment(sync create stack) has completed!
Status: CREATE_COMPLETE
StatusReason: Stack CREATE completed successfully
StackId: 40c92773-33fb-4249-bd46-3ab6xxxxxxxx

等待部署完成后,复制Outputs中的链接并在浏览器中打开,即可畅玩2048!

在这里插入图片描述

删除资源栈

执行以下命令以删除资源栈:

ros-cdk destroy --sync=true 

CDK 会二次确认即将删除的资源栈:

The following stack(s) will be destroyed(Only deployed stacks will be displayed).

DemoStack

Please confirm.(Y/N)

输入 y 并回车,删除成功会显示如下信息:

✅ The task(sync destroy stack) has finished!
status: DELETE_COMPLETE
StatusReason: Stack DELETE completed successfully
StackId: 40c92773-33fb-4249-bd46-3ab6xxxxxxxx
机器人操作系统 ROS(机器人操作系统,Robot Operating System),是专为机器人软件开发所设计出来的一套电脑操作系统架构。它是一个开源的元级操作系统(后操作系统),提供类似于操作系统的服务,包括硬件抽象描述、底层驱动程序管理、共用功能的执行、程序间消息传递、程序发行包管理,它也提供一些工具和库用于获取、建立、编写和执行多机融合的程序。 ROS的运行架构是一种使用ROS通信模块实现模块间P2P的松耦合的网络连接的处理架构,它执行若干种类型的通讯,包括基于服务的同步RPC(远程过程调用)通讯、基于Topic的异步数据流通讯,还有参数服务器上的数据存储。 1 发展目标 2 ROS的概念 2.1 ROS 的 Filesystem Level 2.2 ROS 的 Computation Graph Level 3 参考文献 4 外部链接 发展目标 ROS的首要设计目标是在机器人研发领域提高代码复用率。ROS是一种分布式处理框架(又名Nodes)。这使可执行文件能被单独设计,并且在运行时松散耦合。这些过程可以封装到数据包(Packages)和堆栈(Stacks)中,以便于共享和分发。ROS还支持代码库的联合系统。使得协作亦能被分发。这种从文件系统级别到社区一级的设计让独立地决定发展和实施工作成为可能。上述所有功能都能由ROS的基础工具实现。 为了实现“共享与协作”这一首要目标,人们制订了ROS架构中的其他支援性目标: “轻便”:ROS是设计得尽可能方便简易。您不必替换主框架与系统,因为ROS编写的代码可以用于其他机器人软件框架中。毫无疑问的,ROS更易于集成与其他机器人软件框架。事实上ROS已完成与OpenRAVE、Orocos和Player的整合。 ROS-agnostic库:【agnostic:不可知论】建议的开发模型是使用clear的函数接口书写ROS-agnostic库。 语言独立性:ROS框架很容易在任何编程语言中执行。我们已经能在Python和C++中顺利运行,同时添加有Lisp、Octave和Java语言库。 测试简单:ROS有一个内建的单元/组合集测试框架,称为“rostest”。这使得集成调试和分解调试很容易。 扩展性:ROS适合于大型实时系统与大型的系统开发项目。 ROS的概念 ROS有三个层次的概念:分别为Filesystem level,Computation graph level, 以及Communication level。 以下内容具体的总结了这些层次及概念。除了这三个层次的概念, ROS也定义了两种名称-- Package资源名称和Graph资源名称。同样会在以下内容中提及。 ROS 的 Filesystem Level 文件系统层概念就是你在碟片里面遇到的资源,例如: Packages:ROS的基本组织,可以包含任意格式文件。一个Package 可以包含ROS执行时处理的文件(nodes),一个ROS的依赖库,一个数据集合,配置文件或一些有用的文件在一起。 Manifests:Manifests (manifest.xml) 提供关于Package元数据,包括它的许可信息和Package之间依赖关系,以及语言特性信息像编译旗帜(编译优化参数)。 Stacks: Stacks 是Packages的集合,它提供一个完整的功能,像“navigation stack” Stack与版本号关联,同时也是如何发行ROS软件方式的关键。 Manifest Stack Manifests: Stack manifests (stack.xml) 提供关于Stack元数据,包括它的许可信息和Stack之间依赖关系。 Message (msg) types: 信息描述, 位置在路径:my_package/msg/MyMessageType.msg, 定义数据类型在ROS的 messages ROS里面。 Service (srv) types: 服务描述,位置在路径:my_package/srv/MyServiceType.srv, 定义这个请求和相应的数据结构 在ROS services 里面。 ROS 的 Computation Graph Level Computation Graph Level(计算图)就是用ROS的P2P(peer-to-peer网络传输协议)网络集中处理所有的数据。基本的Computation Graph的概念包括Node, Master, Parameter Sever,messages, services, topics, 和bags, 以上所有的这些都以不同的方式给Graph传输数据。 Nodes: Nodes(节点)是一系列运行中的程序。ROS被设计成在一定颗粒度下的模块化系统。一个机器人控制系统通常包含许多Nodes。比如一个Node控制激光雷达,一个Node控制车轮马达,一个Node处理定位,一个Node执行路径规划,另外一个提供图形化界面等等。一个ROS节点是由Libraries ROS client library写成的, 例如 roscpp 和 rospy. Master: ROS Master 提供了登记列表和对其他计算图的查找。没有Master,节点将无法找到其他节点,交换消息或调用服务。 Server Parameter Server: 参数服务器使数据按照钥匙的方式存储。目前,参数服务器是主持的组成部分。 Messages:节点之间通过messages来传递消息。一个message是一个简单的数据结构,包含一些归类定义的区。支持标准的原始数据类型(整数、浮点数、布尔数,等)和原始数组类型。message可以包含任意的嵌套结构和数组(很类似于C语言的结构structs) Topics: Messages以一种发布/订阅的方式传递。一个node可以在一个给定的topic中发布消息。Topic是一个name被用于描述消息内容。一个node针对某个topic关注与订阅特定类型的数据。可能同时有多个node发布或者订阅同一个topic的消息;也可能有一个topic同时发布或订阅多个topic。总体上,发布者和订阅者不了解彼此的存在。主要的概念在于将信息的发布者和需求者解耦、分离。逻辑上,topic可以看作是一个严格规范化的消息bus。每个bus有一个名字,每个node都可以连接到bus发送和接受符合标准类型的消息。 Services:发布/订阅模型是很灵活的通讯模式,但是多对多,单向传输对于分布式系统中经常需要的“请求/回应”式的交互来说并不合适。因此,“请求/回应” 是通过services来实现的。这种通讯的定义是一种成对的消息:一个用于请求,一个用于回应。假设一个节点提供了一个服务提供下一个name和客户使用服务发送请求消息并等待答复。ROS的客户库通常以一种远程调用的方式提供这样的交互。 Bags: Bags是一种格式,用于存储和播放ROS消息。对于储存数据来说Bags是一种很重要的机制。例如传感器数据很难收集但却是开发与测试中必须的。 在ROS的计算图中,ROS的Master以一个name service的方式工作。它给ROS的节点存储了topics和service的注册信息。Nodes 与Master通信从而报告它们的注册信息。当这些节点与master通信的时候,它们可以接收关于其他以注册节点的信息并且建立与其它以注册节点之间的联系。当这些注册信息改变时Master也会回馈这些节点,同时允许节点动态创建与新节点之间的连接。 节点之间的连接是直接的; Master仅仅提供了查询信息,就像一个DNS服务器。节点订阅一个topic将会要求建立一个与发布该topics的节点的连接,并且将会在同意连接协议的基础上建立该连接。ROS里面使用最广的连接协议是TCPROS,这个协议使用标准的TCP/IP 接口。 这样的架构允许脱钩工作(decoupled operation),通过这种方式大型或是更为复杂的系统得以建立,其中names方式是一种行之有效的手段。names方式在ROS系统中扮演极为重要的角色: topics, services, and parameters 都有各自的names。每一个ROS客户端库都支持重命名,这等同于,每一个编译成功的程序能够以另一种形似【名字】运行。 例如,为了控制一个北阳激光测距仪(Hokuyo laser range-finder),我们可以启动这个hokuyo_node 驱动,这个驱动可以给与激光仪进行对话并且在"扫描"topic下可以发布sensor_msgs/LaserScan 的信息。为了处理数据,我们也许会写一个使用laser_filters的node来订阅"扫描"topic的信息。订阅之后,我们的过滤器将会自动开始接收激光仪的信息。 注意两边是如何脱钩工作的。 所有的hokuyo_node的节点都会完成发布"扫描",不需要知道是否有节点被订阅了。所有的过滤器都会完成"扫描"的订阅,不论知道还是不知道是否有节点在发布"扫描"。 在不引发任何错误的情况下,这两个nodes可以任何的顺序启动,终止,或者重启。 以后我们也许会给我们的机器人加入另外一个激光器,这会导致我们重新设置我们的系统。我们所需要做的就是重新映射已经使用过的names。当我们开始我们的第一个hokuyo_node时,我们可以说它用base_scan代替了映射扫描,并且和我们的过滤器节点做相同的事。现在,这些节点将会用base_scan的topic来通信从而代替,并且将不再监听"扫描"topic的信息。然后我们就可以为我们的新激光测距仪启动另外一个hokuyo_node。 参考文献 http://www.ros.org/wiki/ros http://bbs.axnzero.com/index.php http://blog.sina.com.cn/digital2image2processing
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值