Organizations

  • Systemd 技巧 目前 Linux 发行版都集成 SystemCtl 做系统管理, 现在如果要把二进制应用写入成系统应用基本上绕不开. Systemctl 的服务基本可以分为以下类别: service: 常规服务 timer: 定时器 mount: 挂载点 device: 设备 socket: 套接字 这里先从基础的自定义 service 编写服务开始: # ============================================================================ # 基础单元描述信息 # 用于定义服务的基本信息、依赖关系、启动顺序等, 不涉及服务运行逻辑 # ============================================================================ [Unit] # Description: 服务的简短描述 Description=Java Depoly Application # Documentation: 服务的文档地址(如手册、URL) Documentation=https://app.meteorcat.me # After: 指定本单元应在哪些单元之后启动(仅控制顺序不强制依赖), 例如 After=network.target 表示网络就绪后再启动 # 注: 多个应用以空格划分, 允许依赖多个单元之后启动 After=network.target redis.service # Before: 与 After 相反, 指定本单元应在哪些单元之前启动防止被抢断 Before=nginx.service # Requires: 强制依赖, 若依赖的单元启动失败, 本单元也会启动失败; 若依赖单元停止,本单元也会被停止 # 这也是个很有用的配置, 防止数据库等崩溃还继续接收请求执行业务 Requires=mysql.
    部署 Created Fri, 14 Nov 2025 23:35:57 +0800
  • sudo授权 日常使用自动化脚本的时候常常会出现这种问题: 如果创建专用系统账户如果执行系统服务命令要么需要 sudo 输入密码, 要么就是无法使用命令 像是这种情况在日常当中也是十分常见, 好处也是很明显直接低配权限防止被入侵的时候完全掌控服务器: # 如果想以非 root 用户重启 nginx, 以下命令是无法生效 # 如果你的用户组正好是 sudo 组, 则会提示你必须手动输入用户密码确认启动 systemctl restart nginx # sudo 组则是需要通过以下方式 sudo systemctl restart nginx 但是在自动化运维的时候就很麻烦了, 引入不可能调用这些命令还要让你手动输入密码, 毕竟都自动化了肯定不能这样操作 所以这里就衍生出 visudo 和 NOPASSWD 概念, 通过配置可以让指定用户或用户组执行 sudo 命令时无需输入密码: # 进入 sudo 配置菜单, 注意调用的默认编辑其是 nano 而非 vi/vim sudo visudo 这里内部每一行就是定义权限: username ALL=(ALL) NOPASSWD: ALL # 按照配置顺序依次解释如下: # - username [指定的系统用户, 替换成实际用户名, 如果以 % 开头的就代表用户组] # - ALL [限制该规则生效的访问主机, 默认所有主机 ALL 访问即可] # - (ALL) [限制用户可切换到的用户或组, 比如 devops/root 之类切换允许对应组] # - NOPASSWD: [指定后续命令无需输入密码即可执行, 如果不带该标识则需要输入授权密码] # - ALL [限制允许执行的命令, ALL 表示所有命令, 若指定路径如 /usr/bin/apt 则仅允许该命令] # 这里命令是允许多条共存, 如下给专属账号配置专用, 但是后定义的规则优先级更高所以一般默认命令应该放置到最后 # 最好实践就是专门创建个执行组来做命令执行调用, 比如如下配置就设定只有 devops 用户组的用户才能无密码调用这些命令 %devops ALL=(ALL) NOPASSWD: /usr/bin/apt, /usr/bin/systemctl 另外有的发行版追加了 /etc/sudoers.
    部署 Created Wed, 12 Nov 2025 20:26:05 +0800
  • Cockpit 运维搭建 Cockpit 是开源的 Linux 服务器图形化管理工具, 专为简化服务器运维工作设计, 适合中小规模环境搭建使用. 一般用于常规 nas 或者 10 台服务器管理规模这类日常服务器运维 基本上主流的 Linux 都集成在包管理之中, 直接运行以下命令就可以安装: # debian 系 sudo apt install cockpit # redhat 系 sudo yum install cockpit 默认启动的服务端口为 9090 cockpit 并不是 EXSI 和 PVE 这种专门虚拟化管理那种专业化的虚拟化平台, 仅仅是作为界面化运维管理; 同时也不具有底层系统级别的管理能力, 且不具有大规模服务集群的能力. 不过如果只是想单独简单管理几台容器化服务, 利用 cockpit 反而更加轻量而无须对系统整个重新构建. cockpit-machines 只能间接管理 KVM 虚拟机, 仅支持基本的启停|创建, 没有快照|克隆|高可用方案 如果是小规模(5台)服务器范围且不需要快照备份功能, 只需要对应 cockpit 就足以满足. 系统级别虚拟化带来的问题就是物理资源有限制(有的虚拟化需要最少4G内存等), 并且系统资源占用也不低(cockpit占用不到100M) cockpit 需要 KVM 虚拟机可以选择 cockpit-machines, 如果需要容器化管理可以选择 cockpit-podman: # debian 系 sudo apt install cockpit-machines sudo apt install cockpit-podman # redhat 系 sudo yum install cockpit-machines sudo yum install cockpit-podman 安装之后启动服务即可:
    部署 Created Tue, 11 Nov 2025 21:45:56 +0800
  • Jenkins 部署 在项目正式部署上限的过程当中, 有时候需要用到项目 打包 -> 测试 -> 出包 流程, 这个流程一般是重复且复杂的, 所以就衍生 高效、可靠、可追溯的开发与交付体验 为目标的 流水线 部署流程. 目前 Jenkins 自动化构建流程基本支持前后端项目和容器化处理 推荐采用单独的设备来部署 Jenkins, 因为打包中心可能涉及到修改和暴露很多东西, 所以最好做环境方面隔离. 安装部署 推荐直接 Jenkins官网 去下载 LTS 版本, 虽然我是坚定的 apt 一键安装部署推崇者, 但是基于目前的国内网络原因更新下载速度及其离谱(有时候要更新一整晚); 所以最后不得不直接采用安装包来部署, 还能避免污染 apt 源更新(除非国内以后有镜像部署来加速). 不过这里还提供下 APT 部署流程: # 安装源证书 sudo wget -O /etc/apt/keyrings/jenkins-keyring.asc \ https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key # 写入镜像源 echo "deb [signed-by=/etc/apt/keyrings/jenkins-keyring.asc]" \ https://pkg.jenkins.io/debian-stable binary/ | sudo tee \ /etc/apt/sources.list.d/jenkins.list > /dev/null # 更新安装依赖组建, 注: JenkinsLTS 目前基于 Java17 构建, 热更版本是基于 Java21 sudo apt-get update sudo apt-get install fontconfig openjdk-17-jre sudo apt-get install jenkins 这里如果自带网络代理的时候, apt 作软件版本维护都挺不错, 可惜就国内网络基本上配置这个源会导致更新系统应用更加缓慢, 只能自己手动部署这个服务(不过一般这种都是作为长期服务启动不需要太频繁维护):
    部署 Created Mon, 10 Nov 2025 22:01:14 +0800
  • 基于 香橙派5Pro 这里对于配置方面不做过多介绍, 选择这款 ARM主板主要看重: 8核心(4大核 + 4小核) 16G(LPDDR5)内存 ARM 精简指令省电 支持单条 M2 固态 这里最开始计划是逐步替换家用的 X86服务器, X86 的主要问题还是功耗和噪音较大; 而日常的时候需要自己开发的时候需要利用 NAS 同步个人开发数据等, 并且会采用内网穿透来做网络转发. 这里最开始设计方案是 debian/ubuntu(宿主机) + cockpit(虚拟化), 而其中需要购买3个开发版来做以下集群: 数据服务: 单台搭建 数据库/Subversion, 外挂带外接电源的 USB3.1 硬盘扩展柜盒做 raid1 业务服务: 单台部署一些日常用的开发服务, 并且兼顾网络转发服务来从外网映射转发内网(相当于堡垒机) 监控服务: 将自己开发的闭路监控落地数据转发到这部设备外挂的硬盘柜服务 需要注意 TF 卡烧录系统, 而直接官方镜像可能没办法直接烧录启动, 需要去第三方镜像源下载镜像: Ubuntu第三方镜像: ubuntu-rock-chip 镜像烧录工具: etcher TF 卡烧录最简单, 但是推荐采用单独买条 M2固态硬盘, 无论从 设备IO 和 耐用性 出发都比 TF 好很多. 这里说明为什么不采用 Proxmox VE(PVE) 或者 EXSI 做虚拟化方案, 而是采用 cockpit 直接做服务器运维: 官方社区: 目前 PVE 并没有官方 ARM 方案, 更加别说 ioT 的虚拟化方案, EXSI-ARM 则是直接没有任何支持 CPU差异: 4 * Cortex-A76 + 4 * Cortex-A55 的异构 CPU 方案目前调度有问题 设备直通: 目前虚拟化的设备直通方案支持很差, 基本上没办法做设备直通处理 容器支持: cockpit 内部自带容器服务, 对于日常 nas 搭建服务来说已经足够 实际上对于日常服务的 nas 来说, 直接挂个 docker-gui 基本上就足够日常服务(可能就浪费这些硬件扩展接口)
    ARM Created Sat, 08 Nov 2025 18:40:22 +0800
  • Android海外发行 这里针对的是海外版本推广处理, 主要是 Google Play 游戏商城上架等事务. 首先必须要说明的是发行 SDK 除非官方已经强制要求升级, 否则尽量采用 JDK1.8 支持 JDK1.8 是国内普遍应用的版本, 直接采用对接过程能够省下很多联调功夫 需要说明 AGP(Android Gradle Plugin) 需要选择对应选择兼容版本: Gradle 7.0 → AGP 7.0.0+ Gradle 7.1 → AGP 7.1.0+ Gradle 7.2 → AGP 7.2.0+ Gradle 7.3 → AGP 7.3.0+ Gradle 7.4 → AGP 7.4.0+ Gradle 7.5 → AGP 7.4.2+ 注意: Gradle 7.x 以上版本推荐构建环境为 JDK11, 而编译目标为 JDK1.8 这里按照自身需求选定打包插件(AGP): buildscript { repositories { maven { url 'https://maven.aliyun.com/repository/google' } maven { url 'https://maven.
    联运发行 Created Sat, 18 Oct 2025 15:20:44 +0800
  • 开发环境依赖: Java: 1.8 Gradle: 7.2 minSdkVersion: 17 targetSdkVersion: 26 需要注意: 游戏开发和SDK接入是完全解耦的, 也就是发行设计SDK无需关心接入的游戏任何信息 这里具体的平台主要针对海外发行渠道, 所以默认是以 Google Play 作为上架平台来说明, 具体平台方向: 主流移动端应用市场(App Store/Google Play/Facebook) 官方渠道(比如官网, 一般情况下是提供安卓APK包和PC端的直接下载方式, H5则是提供游戏链接) 其他手游联运渠道(比如Huawei AppGallery/Samsung Store/Amazon Appstore/QooApp等商店渠道) 主流PC游戏市场(Steam/XBoxGame) 项目自定义的安卓发行包的包名: com.game.fgame(可以自己按照习惯去自定义包名) 这里模拟假设以下信息方便我们搭建自己的发行平台: 公司名: FastGame 公司主体: 快游Game 应用包: com.game.fgame 项目简称: fgame 项目目录: fgame-sdk 具体的项目架构如下: / ─── fgame-lib/ │ ├─ src/ │ │ ├─ main/ │ │ │ ├─ java/com/game/fgame/ │ │ │ │ ├─ core/ // 核心逻辑(单例管理、初始化) │ │ │ │ ├─ login/ // 登录模块 │ │ │ │ ├─ pay/ // 支付模块 │ │ │ │ ├─ report/ // 数据上报模块 │ │ │ │ ├─ config/ // 配置管理 │ │ │ │ ├─ utils/ // 工具类(加密、日志、网络等) │ │ │ │ └─ FGameSdk.
    联运发行 Created Wed, 15 Oct 2025 20:49:23 +0800
  • Godot分包方案 主要针对的是在 Godot 实现 Unity 的 AB包(Asset Bundle Package) 概念. 对于商业游戏来说都会把非核心资源切分成网络包, 通过CDN把资源包发布上加速资源下载速度; 也就是默认启动游戏应用都会生成空白游戏场景, 之后会把资源包从CDN更新到最新业务代码之中. 这种方式也算是一种热更新方式, 通过将非核心功能(场景|皮肤等)提取出来设置动态客户端的资源替换. 很有必要的流程, 可以直接做些临时的动态皮肤热更不用全面覆盖更新, 已上架的游戏不修改版本可以直接更新 这里需要说明的是, 以下示例都是采用 Godot C# 版本开发, 方便契合 Unity 转移到 Godot 开发; 并且 C# 能够尽可能复用 .net 相关的第三方社区扩展, 比如 Protobuf 这些相关的功能. 不过目前截止在 Godot 4.5 版本还无法做 Web 打包, H5 游戏支持需要后续版本解决才能出包 这里想构建项目, 并且追加两个场景分别是初始化入口场景和网络加载场景, 注意后续 C# 版本脚本文件都是尽可能采用 .net 规范(大驼峰): 注意: 一般推荐材质贴图单独封成材质包抽离出来, 做到 美术 和 业务 分离 一般需要准备材质表来加载其中所有的材质路径, 比如: user://Packages/UI.pck → https://cdn.localhost/Packages/UI.pck 这里具体流程如下: 请求远程接口确定目前最新版本的材质包文件 MD5 哈希码 获取本地 UI.pck MD5哈希码是否匹配, 不匹配需要删除本地的 pck 包 启动网络下载到本地 pck 资源, 写入到 user://xxx 最好和远程路径匹配方便映射 下载完成之后通过 ProjectSettings.
    Godot 游戏开发 Created Sat, 11 Oct 2025 22:31:37 +0800
  • 网络游戏的帧同步实现 本篇章主要实现多人在线的帧同步流程, 首先是定义客户端和服务端会用到的游戏交互事件 Protobuf: syntax = "proto3"; // 初始化最新的序列帧 - 这个事件是服务端和客户端双向共享, 也就是 Request-Response 响应方式 // 其实就是从服务端获取的最新序列帧ID, 然后挂载客户端目前已经执行的序列化帧上等待下个帧运行 // 后续需要初始化玩家坐标信息,场景信息也是通过该初始化事件加载; 比如下面声明初始化坐标位置[其实应该定义个 Vec2(x,y) 坐标结构] message InitFrame{ int32 frame = 1; // 后续初始化内容在以下扩充 float x = 2; float y = 3; } // 广播单项 - 玩家引发的发生帧变动 // 核心的 frame 字段是帧序列的编号, 需要确保客户端和服务端对发生帧做同步 // 当网络丢包重传的时候, 就能明确从那一个帧序列开始丢帧从而采用追帧方式让玩家回滚到最新状态 // frame 采用 uint32 最佳, 但无法确认开发语言是否支持 unsigned 特性, 所以采用到达最大值回滚为0重置或者设置int64也可以 // 从性能考虑来说采用 int32 就行, 对于小游戏来说 0 到 2^31-1 足够帧序列做行为序列处理 // 注意: 到达最大帧的时候服务端和客户端都要同步回滚处理才能对齐序列帧编号 message InputFrame{ string sessionId = 1; // 玩家唯一标识 int32 frame = 2; // 发生帧 int32 direction = 3; // 方向 bool jump = 4; // 是否触发跳跃 } // 广播事件 - 依据客户端提交的 InputFrame.
    游戏架构 Created Sun, 28 Sep 2025 20:39:05 +0800
  • Godot 集成 Protobuf Godot 版本默认指 Godot C# 版本 目前的 Godot 默认版本的 GDScript 脚本第三方的 Protobuf 库水平高低不平, 并且本身 Godot ABI 维护变动之下很容易某些属性|特性|方法在更新之后出现异常 所以如果需要采用 Godot 做网络序列化传输, 建议采用 C# 版本而非官方默认版, 从而才能利用上 .net 相关周边的第三方组件优势. 以上文档都是采用 LTS 版本的 .net 库相关 默认构建之后的项目之下有 XXXX.csproj 的 C# 配置文件, 这里就是主要的 .net 相关项目配置: <!-- 请留意这里, 这里代表默认采用 Godot-NET 自定义绑定, 也就是其实内部并不是完全支持全部 net 相关 --> <!-- 所以有些打包命令可能无法唤起, 像是 Protobuf 可能在常规 C# 项目当中引入可能没办法触发 Protobuf-Tools 自动打包命令 --> <!-- 需要注意的是因为采用的是 Godot.Net 绑定, 所以这里面默认加载目录分隔符号是 '/' 而不用区分 '\\' 和 '/' --> <Project Sdk="Godot.
    Godot 游戏开发 Created Sun, 28 Sep 2025 20:34:52 +0800