<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>运维 · Amigoer‘s Blog</title><link>https://www.amigoer.com/categories/%E8%BF%90%E7%BB%B4/</link><description>记录技术探索 · 项目 · 生活</description><generator>Hugo + amigoer</generator><language>zh-cn</language><copyright>© 2026 Amigoer</copyright><lastBuildDate>Thu, 30 Apr 2026 18:46:01 +0000</lastBuildDate><atom:link href="https://www.amigoer.com/categories/%E8%BF%90%E7%BB%B4/index.xml" rel="self" type="application/rss+xml"/><item><title>自建内网 K8s 测试集群与 CI/CD 工作流</title><link>https://www.amigoer.com/posts/internal-k8s-cicd/</link><pubDate>Fri, 01 May 2026 01:26:33 +0800</pubDate><author>i@amigoer.com (Amigoer)</author><guid isPermaLink="true">https://www.amigoer.com/posts/internal-k8s-cicd/</guid><description>公司内网一台 Mac Studio，一周内从 Docker Compose 切到 K3s + Rancher + ArgoCD + GitOps 的踩坑记 —— 包括 OrbStack 闪退导致 Harbor 镜像全丢的事故，以及最终落到「集群配置即 Git 仓库」的方案。</description><content:encoded><![CDATA[<p><img src="kubernetes.webp" alt="kubernetes"></p>
<h2 id="背景">背景</h2>
<p>目前在公司内我负责的活主要是 AI 的一些基础管线的开发，包括对外提供服务的接入端点，然后一些管理系统的搭建，再就是部署集群的搭建，基础管线实际上是之前就有一版本 Python 的，按照那个架构进行重构就行了，我做的部分比较少，主要还是一些稳定性的功能优化。最近这一周主要的工作还是在 K8S 集群搭建上面，虽然熟练使用 Docker，但是也是在真实环境下自己搭建内部的开发 K8S 集群，还是感觉学到不少东西的。所以感觉有必要开一篇文章记录一下。</p>
<h2 id="技术栈">技术栈</h2>
<p>其实在这方面我也算是有一丢丢经验，之前在第二家公司就搭建了一整套的内网开发环境，包括自建 Gitea、Github Action、Runner 等等，不过这次微服务比较多，而且也是需要模拟线上环境，就得使用 K8s 了。</p>
<p>在和 Claude Opus 4.7 Copilot 后的推荐方案大概如下，也是目前比较主流的开源方案：</p>
<ul>
<li>设备：Mac Studio M2 Max 32GB</li>
<li>Kubernetes / K3S</li>
<li>Rancher 可视化面板</li>
<li>ArgoCD 自动发布</li>
<li>GitOps 管理集群环境和配置</li>
<li>Cloudflare Tunnal 内网穿透</li>
</ul>
<h2 id="需求">需求</h2>
<p>我们小组是承担了业务方面的 90% 的开发了，比如底层基座，还有我负责的面向开发者和 C 端用户的后端以及管理后台的前后端，所以搭建下来的微服务组件大概就有 20 多个，并且需要提供一套稳定的系统给其他组的同事进行测试，也需要一套我们组内自己快速迭代的集群用于测试，所以这个活也就落到我头上了，为了满足这个需求也是踩了不少坑。</p>
<h3 id="1-docker-compose">1. Docker Compose</h3>
<p>为了快速拉起服务，就选择了这个方案，写好 docker-compose.yaml 就能迅速拉起来多套集群，并且使用 mac 上的 OrbStack 也是非常迅速，这部分还是很得心应手的，只是一些基础服务都没搭建，比如镜像仓库、Github Action 等等。</p>
<p>使用的方案也是非常简单，直接本地 Docker Build 打包后直接 SCP 到服务器上，然后启动。然后使用 Traefik 来做内网域名映射，Dnsmasq 来支持内网的 DNS 解析。</p>
<p>虽然非常简陋，但是也是能够支持快速的上线调试要求了，就是苦了我 🥹，每个人都得让我手动给他们部署组件，不过好在还有 Claude 辅助，能大大提高工作效率了。（这部分还是需要谨慎的，一旦出事直接就会爆炸）</p>
<h3 id="2-komodo">2. Komodo</h3>
<p>每个组件的一些配置需要经常变动，而且直接操作服务器的话，也不太方便，就想着搭建一个可视化的管理面板，通过面板来管理集群，这样也方便。于是检索了一些方案，经过对比之后决定使用 Komodo 来搭建。</p>
<p><img src="komodo-dashboard.webp" alt="Komodo"></p>
<ul>
<li>Komodo：可视化多服务器管理、容器管理、Stacks、编排构建等</li>
<li>Dockge：几乎就是&quot;compose 文件的 Web 编辑器 + 启停按钮&quot;，极简。</li>
<li>Portainer CE：功能多但界面更复杂，compose 在它那叫 &ldquo;Stacks&rdquo; 但体验不如 Komodo 原生。</li>
<li>Dozzle：只看日志，不做管理。</li>
</ul>
<p>Komodo 支持按照 Stacks 来管理集群，也支持多服务器部署，但是由于我们只有一台 Mac 所以就用不到这个功能了。部署好以后，界面感觉还是非常干净的，没有花里胡哨的功能，一眼能看到那个功能该去哪里找。但是因为不支持 K8S 所以这个搭建好了之后，也没有使用几天就废弃了，转到 Rancher + Argo CD 了。</p>
<h3 id="3-k8s">3. K8S</h3>
<p>因为公司提供的设备就只有一台内网环境下的 Mac Studio，也就是说只能部署单节点的 K8S，由于经常性的使用 OrbStack，并且还集成了 K8s 的功能，直接可以开始部署集群，所以也是紧锣密鼓的开始搭建了，然后选择了 Rancher 可视化管理和 ArgoCD 来做自动发布。</p>
<p>直接开了两个集群 stable 和 dev，一股脑将组件拉起来，算上一些基础依赖组件两套集群拉起来后大概就有 90 多个 pod，至此能够满足公司目前的使用是没有问题的，按理来说到这里部署的工作就应该完成了，该去做自动发布构建的了。但是我看了一眼 Rancher 的后台，最多只支持 110 个 Pod，这个怎么能行，按照组件的资源量预估了一下，单机抗 500 Pod 应该是没啥问题，所以就想着将 Pod 数量调整到 500，由于 K8s 中每个 Pod 都是需要占用一个 IP 的，所以这里就必须调整划分给 OrbStack 的 CIDR，默认是 /25 128 个 ip，那直接将这个数字改成 /23 就能支持 512 个 IP，也就能满足我的需求，但是修改 OrbStack 的配置死活不生效，修改好了，就会被修改回去。</p>
<p>大概查了一下，OrbStack 自带的 K8S 没有开放修改的端点，应该还是直接写死的，所以这里没法满足我的需求，就开始想办法了，既然自带的不能满足，那就自己搭一个就行了，于是这里我就选择了使用 OrbSatck 里面的 VM 虚拟机，创建了一个 Ubuntu 24.04，然后在这个里面去搭建 K3S 集群，就能自己随意配置了。</p>
<p>说干就干，立马创建好了虚拟机环境，就得开始迁移 pod 了，这里偷懒使用 Codex GPT 5.5 来进行迁移，按照理想情况下，应该是在迁移完成以后，写好项目的组件服务文档，但是意外出现了，在迁移的过程中，OrbStack 突然闪退，我正在监控的活动监视器中的内存使用突然骤降，我就感觉事情不太妙，结果一看 OrbStack 挂了，里面的所有镜像和 VM 都丢了。</p>
<p>这下炸了，近乎 10 几个组件的 images 都是托管在这个里面的 Harbor 内的，导致所有数据全部丢失，并且没有备份，查了一下这个情况出现的挺多的，也没法找回，只能重新搭建了。</p>
<h3 id="4-gitops">4. GitOps</h3>
<p>于是赶紧和 Claude 商讨了一版方案出来，推荐将集群的管理抽离到 Git 仓库中，这样方便 Action 修改集群配置，于是新版本最终定的架构是 Rancher 做可视化面板进行管理，ArgoCD 来做自动发布，GitOps 来做集群、配置管理。这样子如果一旦服务器崩溃，数据在没有备份的情况下，还能通过 GitOps 中的配置来快速进行恢复，并且也方便后续发布上线。</p>
<p>所以最终的架构是修改 GitOps 仓库中的配置 push 后，就自动能更新对应集群的 pod，并且各个组件的仓库的 push 和 tag 也会触发 Action 去执行修改 GitOps 仓库的配置，以实现控制集群并且能够进行追溯回滚的效果。</p>
<p>个人感觉这种方案是目前的最优解，既能对配置进行管理，还能实现版本控制，也能实现自动化。</p>
<p>所以目前公司的两套服务都部署在 Ubuntu 上的 K8S 内，截止现在还稳定运行，希望能撑过 5.1 休假期间，也能够验证服务的稳定性了。</p>
<h2 id="踩坑">踩坑</h2>
<p>部署中其他组件都比较顺利，唯一遇到的比较坑的就是因为使用的 Cloudflare 的 Tunnal 穿透，然后像让 Github Action Runner 到 Harbor 走内网，并且接入的端点域名不变，也就是在内网环境下就走内网，内网不通就走外网。</p>
<p>这里 Cloudflare 的话是只支持 100MB 的 TCP 传输的，一旦镜像大小超过 100MB，就没法支持了，所以这里只能做切块或者走内网了，为了速度和安全，这块就配置内网。</p>
<p>但是内网的话，一直报 tls 问题，三种错前后都赶上了一遍。</p>
<p>最开始是 Runner 跑 docker push 直接 <code>x509: certificate signed by unknown authority</code>，Harbor 起来用的是自签证书，containerd 默认根本不认这条链。想着把 CA 装进去就完事了，结果一看证书的 SAN，跟实际访问的内网域名压根对不上，错误立马变成 <code>x509: certificate is valid for X, not Y</code>。</p>
<p>更头疼的是 DNS 劈裂这一刀：同一个 <code>harbor.xxx</code> 域名，公网走 Cloudflare 边缘（拿到的是 CF 证书）、内网通过 Dnsmasq 解析到 Mac Studio 的内网 IP（拿到的是 origin 自签证书），公私两套完全分裂。Runner 在内网拿到的永远是 origin cert，本地信任链里啥都没有，怎么连都不对。</p>
<p>最后分两头修：</p>
<ol>
<li><strong>Harbor 那边</strong>：重新签证书，把内网域名、内网 IP、公网域名全部塞进 SAN，至少让&quot;看到什么证书&quot;这件事先统一掉，不再因为域名对不上来回跳错。</li>
<li><strong>Runner / containerd 这边</strong>：把 Harbor 的 CA 挂进 <code>/etc/containerd/certs.d/&lt;host&gt;/ca.crt</code>，让 containerd 真信任这条链。个别历史遗留的 Runner 时间紧没法马上重启刷配置的，临时上 <code>insecure_skip_verify = true</code> 先把流水线跑通再说，后面排期重启时再补。</li>
</ol>
<p>K8s 多节点还有个隐藏的烦人点：每加一台 worker 都得把 CA 同步进去，不像 docker 那么直接，所以这套证书分发也顺手写进 GitOps 仓库的 init job 里，新节点起来自动跑一遍，不然每加一台都得手动配，又是一坨重复劳动。</p>
]]></content:encoded><category>运维</category></item></channel></rss>