Kubernetes调度器深度解析:从筛选打分到高级策略实战

发布时间:2026/8/5 5:39:45

Kubernetes调度器深度解析:从筛选打分到高级策略实战
1. 项目概述从“能跑”到“跑得好”的跨越在容器化部署的早期我们常常满足于“能把应用跑起来”。当你的服务实例还不多手动敲几个kubectl run或者kubectl apply -f deployment.yaml就能搞定。但随着微服务架构的普及一个稍具规模的应用可能动辄包含几十个、上百个服务每个服务又有多个副本整个集群的 Pod 数量轻松突破四位数。这时候问题就来了新创建的 Pod 应该被放到集群里的哪台节点上运行是随机扔过去还是有个“智能大脑”来统筹安排这个“智能大脑”就是 Kubernetes 的调度器而“统筹安排”的过程就是我们今天要深入探讨的K8s集群调度。简单来说调度就是决定一个 Pod 在哪个 Node 上“安家”的过程。这听起来简单实则背后是一套极其复杂的决策系统。它不仅要考虑 Node 的硬件资源CPU、内存是否充足还要处理一系列“软性”约束比如这个 Pod 是否必须和另一个 Pod 部署在同一台机器亲和性是否必须避开某些打了特定标签的节点污点和容忍度甚至当集群资源紧张时如何“牺牲”一些不重要的 Pod 来保障核心业务的运行优先级与抢占理解调度是理解 K8s 如何实现高可用、高性能、高资源利用率的关键。无论是解决k8s虚拟机cpu占用率太高的燃眉之急还是规划ruoyi-cloud k8s 完整部署教程中的资源分配策略亦或是应对k8s面试题中关于调度的灵魂拷问其核心都绕不开对调度机制的深刻把握。2. 调度器核心原理与工作流拆解2.1 调度器的“筛选-打分”两阶段模型Kubernetes 调度器kube-scheduler是一个独立运行的控制器它持续监听 API Server寻找那些nodeName为空的 Pod即待调度的 Pod。对于每一个这样的 Pod调度器都会为其执行一个经典的两阶段决策流程过滤和打分。过滤阶段也可以称为“预选”。调度器会遍历集群中的所有 Node用一系列预选策略逐一检查将不满足条件的 Node 直接淘汰。这是一个“非黑即白”的过程。常见的过滤策略包括PodFitsResources检查 Node 的可用资源CPU、内存是否满足 Pod 的请求。这里注意它对比的是 Pod 配置中resources.requests的值而不是limits。很多新手混淆requests和limits导致调度判断失准。requests是调度依据limits是运行时的限制。PodFitsHostPorts检查 Pod 申请的宿主机端口在目标 Node 上是否已被占用。MatchNodeSelector检查 Node 的标签是否满足 Pod 配置的nodeSelector或nodeAffinity规则。PodToleratesNodeTaints检查 Pod 是否容忍 Node 上的污点。这是实现“专用节点”或“驱逐Pod”的核心机制。经过过滤后通常会得到一个符合条件的 Node 列表。如果列表为空Pod 将一直处于 Pending 状态并给出相应的事件说明。打分阶段也称为“优选”。调度器会对通过过滤的 Node 列表进行评分为每个 Node 计算一个分数0-100分得分最高的 Node 就是最终被选中的“幸运儿”。常见的打分策略包括LeastRequestedPriority倾向于将 Pod 调度到请求资源CPU、内存利用率最低的 Node 上。公式大致是得分 (Node空闲资源 / Node总资源) * 权重。这有助于平衡集群负载。BalancedResourceAllocation在 CPU 和内存利用率之间寻求平衡。它不希望出现一个 Node 的 CPU 用光了但内存还很空闲或者反之的情况。这能提升资源的综合利用率。NodeAffinityPriority实现节点亲和性的优选逻辑。满足亲和性规则的 Node 会获得更高的分数。ImageLocalityPriority倾向于选择已经存在 Pod 所需容器镜像的 Node可以加速 Pod 的启动过程。注意默认的调度策略可能不适用于所有场景。例如在 AI 训练或大数据计算场景你可能更希望 Pod 被集中调度到少数几个资源充足的节点上而不是分散开。这时就需要理解并定制调度策略。2.2 调度过程深度解析与关键对象要真正玩转调度必须理解几个关键对象及其相互作用Node、Pod、Label、Taint、Toleration、Affinity。Label是附着在对象上的键值对是 K8s 中最核心的组织和选择工具。Node 可以有标签如disktypessd,gputruePod 也可以有标签。调度器可以通过nodeSelector选择具有特定标签的 Node。污点和容忍度提供了一种“排斥”机制。你可以给 Node 打上一个污点声明“凡是没有特殊通行证的 Pod不许来此节点”。这个“特殊通行证”就是 Pod 上的容忍度。例如你可以给 Master 节点打上污点node-role.kubernetes.io/master:NoSchedule这样普通的业务 Pod 就不会被调度上去保证了控制平面的稳定。又或者你可以给一些即将维护的节点打上PreferNoSchedule的污点调度器会尽量避免将新 Pod 调度上去。亲和性与反亲和性则提供了更丰富、更灵活的“吸引”或“排斥”规则。它分为节点亲和性和Pod 亲和性/反亲和性。节点亲和性规则基于 Node 的标签让 Pod 倾向于或必须调度到某些特征的 Node 上。Pod 亲和性规则基于其他 Pod 的标签。例如Web 服务器 Pod 希望和它的缓存 Pod如 Redis部署在同一个 Node 或同一个可用区以减少网络延迟这就是 Pod 亲和性。Pod 反亲和性规则同样基于其他 Pod 的标签。最常见的使用场景是实现高可用同一个应用的两个副本你绝对不希望它们被调度到同一个 Node 上否则该 Node 宕机会导致服务全挂。这时就需要 Pod 反亲和性。在实际的ruoyi-cloud k8s 完整部署教程中你一定会用到这些概念。比如将 MySQL 数据库 Pod 通过节点亲和性固定到带有storagefast标签的 SSD 磁盘节点上为 RuoYi-Cloud 的各个微服务如 auth、gateway、system配置 Pod 反亲和性确保每个服务的多个副本分散在不同节点给监控组件如 Prometheus的节点打上专用污点避免业务 Pod 干扰其运行。3. 高级调度特性实战与应用场景3.1 资源请求与限制调度的基石与运行护栏这是调度中最基础也最容易出错的部分。在 Pod 的spec.containers[].resources下你需要定义两个关键字段resources: requests: memory: 256Mi cpu: 250m limits: memory: 512Mi cpu: 500mrequestsPod请求的资源量。这是调度器做决策的唯一依据。调度器会检查各 Node 的Allocatable资源总资源减去系统预留和已分配的资源确保 Node 的剩余资源 Pod 的requests。它决定了 Pod 能被调度到哪里。limitsPod 资源使用的上限。这是 kubelet 在节点上执行 Pod 时设置的 Cgroup 限制。它决定了 Pod 最多能用多少。如果 Pod 内存使用超过limits其中的进程可能会被 OOM Killer 杀死如果 CPU 超过limits则会被限流。一个常见的坑是只设limits不设requests。如果不设置requests默认等于limits。这会导致调度器认为这个 Pod 需要很多资源可能因为找不到足够资源的 Node 而无法调度。更合理的做法是根据应用的实际平均负载设置requests根据其峰值负载设置limits。对于k8s虚拟机cpu占用率太高的问题首先就应该检查 Pod 的limits是否设置过低导致进程频繁被限流从而拉长任务执行时间变相提高了 CPU 占用率或者检查requests是否设置过高导致节点资源被过度承诺调度器“以为”资源已满实则空载。3.2 优先级与抢占关键业务的“护航舰”在集群资源紧张时如何保证订单支付服务比后台报表生成服务更重要K8s 的优先级和抢占机制就是为了解决这个问题。定义 PriorityClass这是一个集群级别的资源用来定义优先级类别。apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: high-priority value: 1000000 # 值越大优先级越高 globalDefault: false # 是否作为未指定优先级 Pod 的默认值 description: 用于关键业务服务在 Pod 中引用在 Pod 的spec.priorityClassName字段中指定上面定义的优先级。抢占过程当一个高优先级 Pod 无法被调度时没有节点满足其要求调度器会尝试驱逐一个或多个低优先级 Pod为高优先级 Pod 腾出空间。被驱逐的 Pod 会优雅终止并在有机会时被重新调度。这个功能非常强大但需谨慎使用。不当的配置可能导致低优先级服务频繁被中断引发级联故障。通常只对真正的核心链路服务如网关、认证、核心交易使用高优先级。3.3 节点亲和性与 Pod 间亲和性/反亲和性配置详解让我们通过一个ruoyi-cloud的部署案例来具体说明。假设我们的集群节点有三种标签node-type: compute通用计算节点node-type: storage带高速存储的节点zone: zone-a和zone: zone-b不同可用区。场景一将 RuoYi-Cloud 的system模块数据库部署到存储节点。这里使用节点亲和性中的requiredDuringSchedulingIgnoredDuringExecution硬亲和性必须满足# deployment-system-db.yaml affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: node-type operator: In values: - storage场景二确保gateway服务的两个副本运行在不同的可用区实现跨可用区高可用。这里使用Pod 反亲和性中的preferredDuringSchedulingIgnoredDuringExecution软反亲和性尽量满足# deployment-gateway.yaml affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 # 权重用于打分阶段 podAffinityTerm: labelSelector: matchLabels: app: ruoyi-gateway # 选择自身 Pod 的标签 topologyKey: zone # 拓扑域这里指“可用区”标签这个配置的意思是“调度器请尽量避免将标签为appruoyi-gateway的 Pod 调度到zone标签值相同的节点上”。topologyKey是关键它定义了“同一位置”的范围可以是zone、hostname节点名、rack机架等。场景三希望web服务尽量和cache服务部署在同一可用区但非强制。这里使用Pod 亲和性的软策略# deployment-web.yaml affinity: podAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 80 podAffinityTerm: labelSelector: matchLabels: app: ruoyi-cache topologyKey: zone3.4 污点与容忍度节点管理与 Pod 隔离污点通常用于专用节点给 GPU 节点打上gputrue:NoSchedule只有声明了相应容忍度的 AI 训练 Pod 才能调度上去。节点驱逐准备在维护节点前先打上maintenance:PreferNoSchedule避免新 Pod 调度上来然后逐步排空已有 Pod。问题节点隔离当发现某个节点不稳定可以打上node.kubernetes.io/unreachable:NoExecuteK8s 控制器会自动驱逐上面的 Pod。给 Node 添加污点kubectl taint nodes node1 key1value1:NoSchedule在 Pod 中声明容忍度tolerations: - key: key1 operator: Equal value: value1 effect: NoSchedule或者容忍所有具有该 key 的污点tolerations: - key: key1 operator: Exists effect: NoSchedule4. 调度器性能调优与问题排查实录4.1 大规模集群下的调度器扩展当集群规模达到数千节点、数万 Pod 时默认的调度器可能成为瓶颈。K8s 提供了多种扩展方案多调度器你可以运行多个自定义调度器并为不同的 Pod 通过spec.schedulerName指定使用哪个调度器。例如可以为机器学习任务开发一个专用的调度器。调度框架从 K8s v1.19 开始稳定它允许你以插件的形式扩展调度器的过滤和打分阶段而无需重写整个调度器。这是官方推荐的扩展方式。调度器性能调优通过调整kube-scheduler的启动参数例如--percentage-of-nodes-to-score默认50%在超大规模集群中可以设置一个阈值避免调度器每次都为 Pod 评估所有节点而是随机抽样一部分节点进行评估以提升调度吞吐量。4.2 常见调度失败问题排查思路当 Pod 一直处于Pending状态时按以下步骤排查查看 Pod 事件这是第一步也是最重要的一步。kubectl describe pod pod-name -n namespace在Events部分通常会直接告诉你原因例如0/3 nodes are available: 1 Insufficient cpu, 2 node(s) didnt match Pods node affinity/selector.(资源不足或节点选择器不匹配)0/3 nodes are available: 3 node(s) had taint {node.kubernetes.io/not-ready: }, that the pod didnt tolerate.(不容忍节点污点)检查节点资源kubectl describe node node-name查看Allocatable和Allocated resources确认 CPU、内存是否真的充足。注意Allocatable是总资源减去kube-reserved和system-reserved后的可分配量。检查节点亲和性/选择器确认 Pod 的nodeSelector或nodeAffinity规则与目标节点的标签是否匹配。检查污点与容忍度确认 Pod 是否容忍了目标节点上的污点。特别注意NoExecute污点它会导致已运行的 Pod 被驱逐。检查资源请求确认 Pod 的resources.requests是否设置得过高或不合理。检查持久化存储如果 Pod 使用了 PVC检查 PVC 是否处于Pending状态可能是 StorageClass 配置问题或后端存储资源不足。检查调度器本身极少数情况下可能是调度器组件故障。检查kube-schedulerPod 的日志。kubectl logs -n kube-system kube-scheduler-pod-name4.3 实战避坑那些年我踩过的调度“坑”坑一requests与limits的误用。如前所述将limits当作requests用导致集群资源视图“虚高”大量 Pod 无法调度。最佳实践是为所有 Pod 设置合理的requestslimits可以略高于requests或与之相等。坑二Pod 反亲和性配置不当导致“调度死锁”。例如你为一个 Deployment 的 3 个副本配置了硬性的 Pod 反亲和性requiredDuringScheduling...要求每个副本都不能与其他副本在同一节点。但如果你的集群只有 2 个节点那么第三个 Pod 将永远无法被调度因为找不到满足“与其他两个副本都不在同一节点”条件的节点。解决方案对于多副本的高可用通常使用软反亲和性preferredDuringScheduling...或者确保拓扑域如topologyKey: zone的数量大于副本数。坑三忽略kube-reserved和system-reserved。在kubelet配置中你需要为系统进程和 K8s 组件预留资源。如果预留不足节点上的系统进程可能会因为资源竞争而被 OOM Kill导致节点不稳定。在规划节点容量时必须把这部分预留考虑进去。坑四prometheus监控k8s集群状态的详细操作注意prometheus在k8集群外场景下的调度影响。当监控组件在集群外时它对集群内 Pod 的资源使用没有感知。如果你在集群内同时运行了另一个资源采集器如 metrics-server要确保两者的采集间隔和资源计算方式不会冲突避免出现调度器基于旧数据做出错误决策。同时确保集群外 Prometheus 的拉取操作不会对集群内服务造成压力必要时可以通过 Service 的externalTrafficPolicy: Local等策略进行优化。5. 自定义调度与未来展望虽然默认调度器非常强大但在某些特定场景下你可能需要更精细的控制。这时就需要用到自定义调度器。你可以用任何语言编写一个程序监听 API Server 的 Pod 事件实现自己的调度逻辑并通过设置 Pod 的spec.schedulerName来指定使用它。例如一个基于深度学习预测负载的自定义调度器或者一个专门用于批处理作业的调度器。另一个强大的工具是Kubernetes Scheduler Framework。它允许你以插件的形式“侵入”默认调度器的各个扩展点比如在过滤前后增加自定义的过滤逻辑在打分阶段增加自定义的评分项。这样你既能享受默认调度器的稳定性又能加入业务特有的调度策略比如“将 Pod 调度到离其依赖的数据源最近的节点”。最后社区也在不断演进调度能力。动态资源分配正在 Alpha 阶段它允许 Pod 请求像 GPU、FPGA、特定型号的网卡等异构设备而不仅仅是 CPU 和内存。基于批量的调度也在完善更适合于 AI 训练、科学计算等需要同时调度大量 Pod 的作业场景。理解 K8s 集群调度就像是掌握了容器化舰队在复杂海域中航行的导航术。从基础的资源请求到高级的亲和性策略再到应对大规模场景的调优和问题排查每一步都需要结合实际的业务需求和集群状态来仔细考量。没有一套放之四海而皆准的配置最好的策略往往来自于对业务特性的深刻理解以及对调度原理的扎实掌握。当你再面对k8s集群搭建后的资源规划或是处理k8s故障案例中棘手的 Pod Pending 问题时希望这套从原理到实战的调度知识体系能帮你更快地定位问题设计出更优雅、更稳健的部署方案。

相关新闻

解决ANSYS Fluent HDF5文件与Tecplot兼容性问题:3种实用方案

解决ANSYS Fluent HDF5文件与Tecplot兼容性问题:3种实用方案

2026/8/5 5:39:45

1. 问题缘起:当Fluent遇上Tecplot,格式之墙如何破?最近在群里和论坛里,看到不少做CFD仿真的朋友都在问同一个问题:用新版本的ANSYS Fluent(比如2023 R2、2024 R1这些)计算完,保存成默…

基于BERT的文本情感分析实战:从数据到部署的完整指南

基于BERT的文本情感分析实战:从数据到部署的完整指南

2026/8/5 5:39:45

1. 项目概述:从文本到情感的智能解码情感分析,或者说意见挖掘,是自然语言处理领域里一个既经典又充满活力的研究方向。简单来说,它的目标就是让机器能读懂文字背后的情绪。这听起来有点像科幻,但实际应用已经渗透到我们…

Wireshark抓取VLAN包全攻略:原理、场景与实战排查

Wireshark抓取VLAN包全攻略:原理、场景与实战排查

2026/8/5 5:29:45

1. 项目概述:为什么需要抓取VLAN包?在网络运维和故障排查的日常工作中,我们经常会遇到一些“奇怪”的现象:比如,配置了VLAN的交换机上,某个端口下的设备明明IP地址正确,却无法访问网关&#xff…

Lenovo Legion Toolkit终极指南:拯救者笔记本硬件控制的范式革新

Lenovo Legion Toolkit终极指南:拯救者笔记本硬件控制的范式革新

2026/8/5 8:20:01

Lenovo Legion Toolkit终极指南:拯救者笔记本硬件控制的范式革新 【免费下载链接】LenovoLegionToolkit Lightweight Lenovo Vantage and Hotkeys replacement for Lenovo Legion laptops. 项目地址: https://gitcode.com/gh_mirrors/le/LenovoLegionToolkit …

数仓 APP 层存储设计:Hive 与 OLAP 引擎如何分工

数仓 APP 层存储设计:Hive 与 OLAP 引擎如何分工

2026/8/5 8:20:01

为什么 APP 层既要落 Hive,又要同步到 ClickHouse / Doris? 前段时间,和一位之前一起做数据的同学聊到了一个问题: 数仓的 APP 层为什么要先在 Hive 建表,之后还要在 ClickHouse 或 Doris 中再建一张表? 既…

RocketMQ自动创建Topic机制深度解析:原理、风险与生产环境最佳实践

RocketMQ自动创建Topic机制深度解析:原理、风险与生产环境最佳实践

2026/8/5 8:20:01

1. 从一次线上告警说起:为什么需要自动创建Topic? 那天晚上,我正盯着监控大盘,突然收到一条告警:“Topic ORDER_PAY_SUCCESS_NOTIFY 不存在,消息发送失败”。排查后发现,是订单服务新上线了一…

AI编程助手乱回答现象解析:从幻觉到指令遵循的技术原理与工程实践

AI编程助手乱回答现象解析:从幻觉到指令遵循的技术原理与工程实践

2026/8/5 8:20:01

最近,不少开发者和技术博主都在讨论一个现象:一些看似强大的AI编程助手或智能体(Agent),在某些特定指令下,会给出完全错误、甚至“一本正经胡说八道”的答案。这不禁让人思考,我们正在依赖的AI工…

二维码文件传输革命:告别数据线,手机电脑秒速互传

二维码文件传输革命:告别数据线,手机电脑秒速互传

2026/8/5 8:20:00

二维码文件传输革命:告别数据线,手机电脑秒速互传 【免费下载链接】qr-filetransfer Transfer files over WiFi between your computer and your smartphone from the terminal 项目地址: https://gitcode.com/gh_mirrors/qr/qr-filetransfer 你是…

从SQL到语义层:构建AI Agent时代的数据理解新范式

从SQL到语义层:构建AI Agent时代的数据理解新范式

2026/8/5 8:09:59

1. 项目概述:当数据语义成为新基建 最近和几个做数据平台和AI应用的朋友聊天,大家不约而同地提到了同一个痛点:数据“听不懂人话”。一个典型的场景是,业务同学跑过来问:“上个月的GMV是多少?” 数据工程师…

ncmdumpGUI:一键解锁网易云音乐ncm文件的终极解决方案

ncmdumpGUI:一键解锁网易云音乐ncm文件的终极解决方案

2026/8/4 15:23:37

ncmdumpGUI:一键解锁网易云音乐ncm文件的终极解决方案 【免费下载链接】ncmdumpGUI C#版本网易云音乐ncm文件格式转换,Windows图形界面版本 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdumpGUI 你是否曾经从网易云音乐下载了心爱的歌曲&am…

分布式配置中心选型实战:Nacos与Consul在创业场景下的对比

分布式配置中心选型实战:Nacos与Consul在创业场景下的对比

2026/8/5 6:02:27

分布式配置中心选型实战:Nacos与Consul在创业场景下的对比工程导读:本文深入讨论 分布式配置中心选型实战:Nacos与Consul在创业场景下的对比 在生产工程实践中的核心落地方案。基于 分布式架构与微服务设计 视角,剖析实际痛点、架…

MoneyPrinterPlus实战指南:AI视频批量生成与自动化发布完整解决方案

MoneyPrinterPlus实战指南:AI视频批量生成与自动化发布完整解决方案

2026/8/5 8:19:55

MoneyPrinterPlus实战指南:AI视频批量生成与自动化发布完整解决方案 【免费下载链接】MoneyPrinterPlus AI一键批量生成各类短视频,自动批量混剪短视频,自动把视频发布到抖音,快手,小红书,视频号上,赚钱从来没有这么容易过! 支持本地语音模型chatTTS,fasterwhisper,…

Go + 云原生微服务架构实战:2026 企业级开发完整指南

Go + 云原生微服务架构实战:2026 企业级开发完整指南

2026/8/5 0:09:22

Go 云原生微服务架构实战:2026 企业级开发完整指南 CNCF 最新数据显示,2026 年云原生相关岗位增速同比上涨 62%。Kubernetes、Docker、Etcd、Prometheus 等云原生基础设施全部由 Go 语言编写。Go 语言凭借简洁的语法、出色的并发模型、极快的编译速度和…

LangChain项目上线就翻车?团队接手的拦路虎从来不是代码

LangChain项目上线就翻车?团队接手的拦路虎从来不是代码

2026/8/5 0:09:22

聊《一个LangChain项目上线后,最先暴露的并不是代码问题》之前,先说一句实在的:别急着背概念,先看它在真实项目里到底解决什么问题。 摘要 摘要:我见过太多LangChain Demo能跑的项目,一交出去就崩。不是模…

3步轻松实现音乐格式自由:ncmdump网易云NCM解密完整指南

3步轻松实现音乐格式自由:ncmdump网易云NCM解密完整指南

2026/8/5 0:09:22

3步轻松实现音乐格式自由:ncmdump网易云NCM解密完整指南 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 你是否曾经在网易云音乐下载了心爱的歌曲,却发现只能在特定客户端播放?当你想在车载音响、…

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

2026/8/4 13:34:51

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…

导师推荐!2026最新AI论文工具测评与实用推荐

导师推荐!2026最新AI论文工具测评与实用推荐

2026/8/4 14:25:14

2026年真正好用的AI论文工具,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

告别游戏崩溃:XCOM 2模组管理器的智能革命

告别游戏崩溃:XCOM 2模组管理器的智能革命

2026/8/4 15:11:03

告别游戏崩溃:XCOM 2模组管理器的智能革命 【免费下载链接】xcom2-launcher The Alternative Mod Launcher (AML) is a replacement for the default game launchers from XCOM 2 and XCOM Chimera Squad. 项目地址: https://gitcode.com/gh_mirrors/xc/xcom2-lau…