<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="https://blog.kali-team.cn/feed_style.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <tabi:metadata xmlns:tabi="https://github.com/welpo/tabi">
        <tabi:base_url>https://blog.kali-team.cn</tabi:base_url>
        <tabi:separator>
            •
        </tabi:separator>
        <tabi:about_feeds>
            这是Web Feed，又称为Atom Feed，把现在的网址复制到新闻阅读器即可订阅本站文章。造访「About Feeds」来了解更多资讯。
        </tabi:about_feeds>
        <tabi:visit_the_site>
            造访网站
        </tabi:visit_the_site>
        <tabi:recent_posts>
            近期文章
        </tabi:recent_posts>
        <tabi:last_updated_on>
            更新于 $DATE
        </tabi:last_updated_on>
        <tabi:default_theme></tabi:default_theme>
        <tabi:post_listing_date>date</tabi:post_listing_date>
        <tabi:current_section>cicd</tabi:current_section>
    </tabi:metadata><link rel="extra-stylesheet" href="https://blog.kali-team.cn/skins/arch.css?h=8b651815fde702215b07" /><title>Kali-Team - cicd</title>
        <subtitle>三米前有蕉皮的博客</subtitle>
    <link href="https://blog.kali-team.cn/tags/cicd/atom.xml" rel="self" type="application/atom+xml"/>
    <link href="https://blog.kali-team.cn/tags/cicd/" rel="alternate" type="text/html"/>
    <generator uri="https://www.getzola.org/">Zola</generator><updated>2026-09-02T00:00:00+00:00</updated><id>https://blog.kali-team.cn/tags/cicd/atom.xml</id><entry xml:lang="en">
        <title>安全开发-Gitea</title>
        <published>2026-09-02T00:00:00+00:00</published>
        <updated>2026-09-02T00:00:00+00:00</updated>
        <author>
            <name>三米前有蕉皮</name>
        </author>
        <link rel="alternate" href="https://blog.kali-team.cn/blog/2026/09/安全开发-Gitea/" type="text/html"/>
        <id>https://blog.kali-team.cn/blog/2026/09/安全开发-Gitea/</id>
        
            <content type="html">&lt;h2 id=&quot;qian-yan&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#qian-yan&quot; aria-label=&quot;Anchor link for: qian-yan&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
前言&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;上一篇《安全开发-Rancher平台搭建》把内网底座搭起来了：k3s 集群、私有 CA、Traefik 网关、Rancher 多集群管理。这篇补齐最后一环：&lt;strong&gt;用 Gitea Actions 把 CI/CD 真正跑起来&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CI（Continuous Integration，持续集成）&lt;/strong&gt; 负责代码合进来后自动检查、自动构建；&lt;strong&gt;CD（Continuous Delivery/Deployment，持续交付/部署）&lt;/strong&gt; 负责把成品自动发布出去。以前“把代码变成软件包“要人手动敲命令，编译、测试、打包、上传一步步来，慢还容易出错，现在代码一提交这些步骤就全自动跑一遍。&lt;/li&gt;
&lt;li&gt;为什么选 Gitea Actions：它&lt;strong&gt;跟 GitHub Actions 语法兼容&lt;/strong&gt;，你在网上见过、学过的那套 &lt;code&gt;workflow&lt;/code&gt; + &lt;code&gt;job&lt;/code&gt; + &lt;code&gt;step&lt;/code&gt; 写法基本能直接搬过来用。Jenkins 功能强但插件体系重、配置要靠 Jenkinsfile，Woodpecker 轻但生态小，Gitea Actions 学习成本最低。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.kali-team.cn/blog/2026/09/%E5%AE%89%E5%85%A8%E5%BC%80%E5%8F%91-Gitea/screenshot_7.png&quot; alt=&quot;Gitea Web 界面&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 1：Gitea 主界面（hub.kali-team.internal）&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;1-gitea-an-zhuang-yu-gong-yao-pei-zhi&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#1-gitea-an-zhuang-yu-gong-yao-pei-zhi&quot; aria-label=&quot;Anchor link for: 1-gitea-an-zhuang-yu-gong-yao-pei-zhi&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
1 Gitea：安装与公钥配置&lt;/h2&gt;
&lt;h3 id=&quot;1-1-dai-ma-tuo-guan-ping-tai-liu-shui-xian-de-yuan-tou&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#1-1-dai-ma-tuo-guan-ping-tai-liu-shui-xian-de-yuan-tou&quot; aria-label=&quot;Anchor link for: 1-1-dai-ma-tuo-guan-ping-tai-liu-shui-xian-de-yuan-tou&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
1.1 代码托管平台：流水线的源头&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;流水线要处理的代码、流水线配置、触发事件（提交、打 tag）都发生在代码托管平台上，平台一动，流水线才动。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gitea 是一个轻量级的自托管 Git 服务，功能类似 GitHub/GitLab，但资源占用更低&lt;/strong&gt;。内网场景代码本来就不能出内网，自托管是必然选择。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;1-2-an-zhuang-gitea-guan-fang-helm-chart-yi-jian-bu-shu&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#1-2-an-zhuang-gitea-guan-fang-helm-chart-yi-jian-bu-shu&quot; aria-label=&quot;Anchor link for: 1-2-an-zhuang-gitea-guan-fang-helm-chart-yi-jian-bu-shu&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
1.2 安装 Gitea：官方 Helm Chart 一键部署&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Gitea 提供了官方 Helm Chart，安装完成后通过 &lt;code&gt;hub.kali-team.internal&lt;/code&gt; 访问。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;需要手动改的配置只有一个 Service&lt;/strong&gt;：Gitea 的 SSH 端口 22 默认只在集群内部开放（&lt;strong&gt;ClusterIP&lt;/strong&gt;，只在集群内可达），宿主机克隆不了代码，所以把 SSH 服务改成 NodePort，映射到宿主机 32222 端口（&lt;strong&gt;NodePort&lt;/strong&gt; 在集群每个节点的一个固定端口上开口，外部机器按“宿主机 IP:端口“访问，32222 是从 30000–32767 区间里挑的，避开常用端口）。改完之后，连“任意节点 IP:32222“就等于连到 Gitea 的 SSH。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在 Rancher 的 Gitea chart 里修改 Service 配置，改完的页面：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.kali-team.cn/blog/2026/09/%E5%AE%89%E5%85%A8%E5%BC%80%E5%8F%91-Gitea/image.png&quot; alt=&quot;Gitea chart 的 Service 配置页&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 2：Rancher 里 Gitea chart 的 Service Settings 页：SSH 服务改为 NodePort、端口映射到宿主机 32222&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;对应的 values 改动（diff 格式：&lt;code&gt;-&lt;/code&gt; 是原值，&lt;code&gt;+&lt;/code&gt; 是改后值）：&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;diff&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;@@&lt;/span&gt;&lt;span&gt; -282,9 +282,9&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt; @@&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;loadBalancerClass: null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;loadBalancerIP: null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;loadBalancerSourceRanges: []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-11&quot;&gt;    nodePort: null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;    nodePort: 32222&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;port: 22&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-11&quot;&gt;    type: ClusterIP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;    type: NodePort&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;serviceAccount:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;annotations: {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;automountServiceAccountToken: false&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后点击安装，终端输出：&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;level&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;WARN&lt;/span&gt;&lt;span&gt; msg&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;--wait=true is deprecated (boolean value) and can be replaced with --wait=watcher&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;Release&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;gitea&amp;quot; has been upgraded. Happy Helming!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;NAME:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; gitea&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;LAST&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; DEPLOYED: Sun Sep&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; 13&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; 01:32:10&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; 2026&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;NAMESPACE:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;STATUS:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; deployed&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;REVISION:&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;DESCRIPTION:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; Upgrade complete&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;NOTES:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;1.&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; Get the application URL by running these commands:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;  http://hub.kali-team.internal/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;1.&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; Review these warnings:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;  -&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; Gitea uses &amp;#39;memory&amp;#39; for caching which is not recommended for production use. See https://docs.gitea.com/next/administration/config-cheat-sheet#cache-cache for available options.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;  -&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; Gitea uses &amp;#39;leveldb&amp;#39; for queue actions which is not recommended for production use. See https://docs.gitea.com/next/administration/config-cheat-sheet#queue-queue-and-queue for available options.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;  -&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; Gitea uses &amp;#39;memory&amp;#39; for sessions which is not recommended for production use. See https://docs.gitea.com/next/administration/config-cheat-sheet#session-session for available options.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;1-3-gitea-zai-devsecops-zhong-de-zuo-yong&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#1-3-gitea-zai-devsecops-zhong-de-zuo-yong&quot; aria-label=&quot;Anchor link for: 1-3-gitea-zai-devsecops-zhong-de-zuo-yong&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
1.3 Gitea 在 DevSecOps 中的作用&lt;/h3&gt;
&lt;p&gt;装好 Gitea，只是有了“代码的家“。在这套 DevSecOps 体系里，它还承担六项职能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;代码托管&lt;/strong&gt;：存储源代码，支持 Git 协议&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Webhook 触发&lt;/strong&gt;：代码提交时触发 CI/CD 流水线（Webhook 是一种“事件回调“：提前在平台里登记一个 URL，push 了代码这类事件发生时，平台主动向这个 URL 发 HTTP 请求通知对方）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;代码审查&lt;/strong&gt;：Pull Request 审查流程，安全团队可以参与评审（PR 是“合并请求“：开发者把改动的代码提请团队审查，通过后合入主干）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Issue 管理&lt;/strong&gt;：跟踪安全漏洞、技术债务等问题（Issue 是平台里的“工单“，用来登记要处理的问题和待办）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Package Registry&lt;/strong&gt;：存储构建产物、Helm Chart 等（平台自带的“制品仓库“，构建出的包存在这里，不用散落在各处）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;提供 OAuth / OIDC 登录&lt;/strong&gt;：其它平台可以直接接入 Gitea 账号做统一登录（8.4 展开）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;1-4-tian-jia-gong-yao&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#1-4-tian-jia-gong-yao&quot; aria-label=&quot;Anchor link for: 1-4-tian-jia-gong-yao&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
1.4 添加公钥&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;在宿主机上生成密钥对（&lt;code&gt;ssh-keygen&lt;/code&gt; 是系统自带的生成密钥对命令；&lt;code&gt;-t ed25519&lt;/code&gt; 指定密钥类型，ed25519 是较新的椭圆曲线算法，短小、快速、安全；&lt;code&gt;-C&lt;/code&gt; 后面的文字是给密钥加的备注，方便以后区分“这把钥匙是给哪台服务器用的“）：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;➜&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;  ~ ssh-keygen -t ed25519 -C &amp;quot;hub.kali-team.internal&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;Generating&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; public/private ed25519 key pair.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;Enter&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; file in which to save the key&lt;/span&gt;&lt;span&gt; (/home/kali-team/.ssh/id_ed25519): /home/kali-team/.ssh/kali-team.internal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;Enter&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; passphrase for &amp;quot;/home/kali-team/.ssh/kali-team.internal&amp;quot;&lt;/span&gt;&lt;span&gt; (empty&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; for no passphrase&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;Enter&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; same passphrase again:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;Your&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; identification has been saved in /home/kali-team/.ssh/kali-team.internal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;Your&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; public key has been saved in /home/kali-team/.ssh/kali-team.internal.pub&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;The&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; key fingerprint is:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;SHA256:GcSGRR0uq1cEVqiEVbmWJtbm35DdQY1sWqnhTE9fp9Y&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; hub.kali-team.internal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;The&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; key&amp;#39;s randomart image is:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;+--[ED25519 256]--+&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;|     o.*B=o. . + |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;|    . oo=o. o O +|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;|     . +ooo+ X +o|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;|      + B*  = = E|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;|     . *S .o o . |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;|       ...o . .  |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;|      . .. o     |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;|       .  . .    |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;|                 |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;+----[SHA256]-----+&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;➜  ~&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;➜  ~ cat .ssh/kali-team.internal.pub&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP1ovd63A23WxDJy58RylWDuC+9Sy2DOF4Op+uJR8K58 hub.kali-team.internal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;➜  ~&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;把公钥加进 Gitea：打开 Gitea 网页 → 点右上角头像 → &lt;strong&gt;设置&lt;/strong&gt; → &lt;strong&gt;SSH / GPG 密钥&lt;/strong&gt;，把公钥全文粘贴进密钥内容框、给个标题（比如 &lt;code&gt;hub.kali-team.internal&lt;/code&gt;），保存即可。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.kali-team.cn/blog/2026/09/%E5%AE%89%E5%85%A8%E5%BC%80%E5%8F%91-Gitea/gitea-ssh-keys.png&quot; alt=&quot;Gitea SSH 密钥页&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 3：Gitea SSH / GPG 密钥页：本节登记的 &lt;code&gt;hub.kali-team.internal&lt;/code&gt; 公钥已在列表（另有一把 &lt;code&gt;arch&lt;/code&gt; 密钥）&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;加完公钥，这台宿主机就能以 SSH 方式克隆 &lt;code&gt;hub.kali-team.internal&lt;/code&gt; 上的仓库了，克隆地址会带上 32222 端口，正是 1.2 节改出来的 SSH NodePort。仓库页面见 6.2 节的图 7。&lt;/p&gt;
&lt;h2 id=&quot;2-gai-nian-action-runner-dao-di-zai-gan-shen-me&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#2-gai-nian-action-runner-dao-di-zai-gan-shen-me&quot; aria-label=&quot;Anchor link for: 2-gai-nian-action-runner-dao-di-zai-gan-shen-me&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
2 概念：Action Runner 到底在干什么&lt;/h2&gt;
&lt;p&gt;最容易被绕晕的一点：&lt;strong&gt;Gitea 自己并不执行流水线&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&quot;2-1-san-zhang-jiao-se-de-fen-gong-gitea-pai-dan-runner-gan-huo-ren-wu-rong-qi-dong-shou&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#2-1-san-zhang-jiao-se-de-fen-gong-gitea-pai-dan-runner-gan-huo-ren-wu-rong-qi-dong-shou&quot; aria-label=&quot;Anchor link for: 2-1-san-zhang-jiao-se-de-fen-gong-gitea-pai-dan-runner-gan-huo-ren-wu-rong-qi-dong-shou&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
2.1 三张角色的分工：Gitea 派单，Runner 干活，任务容器动手&lt;/h3&gt;
&lt;p&gt;一套 Actions 跑起来有三个角色：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;角色&lt;/th&gt;&lt;th&gt;干什么&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Gitea（hub）&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;读代码仓库里的流水线 YAML，把任务挂进待办队列，把结果和日志展示出来&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Runner（运行器）&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;常驻进程，每隔几秒问 Gitea“有没有我的活“，有就领回来执行并回报结果&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;任务容器&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Runner 执行流水线时按配置新建一个 Docker 容器，流水线的命令都在这个容器里跑&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;Gitea 只负责“调度和展示“，真正的编译、打包都是在任务容器里发生的。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;2-2-san-ge-guan-jian-gai-nian-labels-secrets-shi-jian-shang-xia-wen&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#2-2-san-ge-guan-jian-gai-nian-labels-secrets-shi-jian-shang-xia-wen&quot; aria-label=&quot;Anchor link for: 2-2-san-ge-guan-jian-gai-nian-labels-secrets-shi-jian-shang-xia-wen&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
2.2 三个关键概念：labels、Secrets、事件上下文&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;labels（标签）&lt;/strong&gt;：流水线里每个 job 都会写 &lt;code&gt;runs-on: &amp;lt;标签&amp;gt;&lt;/code&gt;，意思是“我要一个能干这个活的机器“，Gitea 把 job 派给标签匹配的 Runner。标签值（如 &lt;code&gt;ubuntu-host&lt;/code&gt;）可以附带一个镜像地址，表示“任务装进这个镜像的容器里跑“。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Secrets（机密）&lt;/strong&gt;：仓库级的加密环境变量，只有这个仓库的流水线能读到，日志里一旦打印出来 Gitea 会自动打码。Harbor 的 robot 密码、SonarQube 的 token 这类“给程序用的密码“都放这里。&lt;/li&gt;
&lt;li&gt;事件上下文（&lt;code&gt;github.*&lt;/code&gt;）：平台自动注入的“情报“，如 &lt;code&gt;${{ github.event_name }}&lt;/code&gt;、&lt;code&gt;${{ github.ref }}&lt;/code&gt; 这类写法，是这次运行由什么触发、在哪个分支/标签上等信息，让流水线能“看情况办事“。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;2-3-zi-tuo-guan-runner-he-github-tuo-guan-runner-de-qu-bie&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#2-3-zi-tuo-guan-runner-he-github-tuo-guan-runner-de-qu-bie&quot; aria-label=&quot;Anchor link for: 2-3-zi-tuo-guan-runner-he-github-tuo-guan-runner-de-qu-bie&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
2.3 自托管 Runner 和 GitHub 托管 Runner 的区别&lt;/h3&gt;
&lt;p&gt;GitHub 官方也提供“托管 Runner“（你什么都不用装，GitHub 出机器）。自托管的区别主要在两点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;任务容器自己掌控&lt;/strong&gt;：我们能让任务跑在“内网能访问、且带齐内网 CA 证书“的镜像里；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;没有外部依赖&lt;/strong&gt;：内网根本连不上 &lt;code&gt;github.com&lt;/code&gt;，托管 Runner 那种“去公共库拉东西“的模式在内网行不通。所以 Runner 必须在内网自托管，而且流水线里引用的一切资源（镜像、依赖、Action）都得是内网可达的。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;3-bu-shu-zi-tuo-guan-runner-act-runner&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#3-bu-shu-zi-tuo-guan-runner-act-runner&quot; aria-label=&quot;Anchor link for: 3-bu-shu-zi-tuo-guan-runner-act-runner&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
3 部署自托管 Runner：act_runner&lt;/h2&gt;
&lt;p&gt;Gitea 官方的 Runner 实现叫 &lt;strong&gt;&lt;code&gt;act_runner&lt;/code&gt;&lt;/strong&gt;（&lt;a class=&quot;external&quot; rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/gitea/act_runner&quot;&gt;gitea/act_runner&lt;/a&gt;）。它兼容 GitHub Actions 的 &lt;code&gt;workflow&lt;/code&gt; 语法，所以 GitHub 上写过的流水线大多能直接搬过来。&lt;/p&gt;
&lt;h3 id=&quot;3-1-xian-jie-jue-liang-ge-nei-wang-te-you-de-wen-ti&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#3-1-xian-jie-jue-liang-ge-nei-wang-te-you-de-wen-ti&quot; aria-label=&quot;Anchor link for: 3-1-xian-jie-jue-liang-ge-nei-wang-te-you-de-wen-ti&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
3.1 先解决两个“内网特有“的问题&lt;/h3&gt;
&lt;p&gt;Runner 是 Go 写的，任务容器是 Docker 的，启动前有两个坑必须先堵上，否则它起不来或连不上。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问题 1：Runner 访问 Gitea（https）要校验证书。&lt;/strong&gt; 我们的 Gitea 证书是内网 CA 签的，而 Go 程序默认只信系统 CA 库。解法是把“系统 CA + 内网 CA“合并成一个文件，用环境变量 &lt;code&gt;SSL_CERT_FILE&lt;/code&gt; 指给 Go 程序（这是 Go 官方支持的证书加载方式）：&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# 合并：系统 CA 库 + 内网 CA（step 中间 CA + 根 CA）拼成一个 bundle&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;cat&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; /etc/ssl/certs/ca-certificates.crt kali-team-ca.crt&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; ca-bundle-kali.pem&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;问题 2：任务容器解析不了内网域名。&lt;/strong&gt; 任务容器默认走 Docker 的 bridge 网络，它的 &lt;code&gt;/etc/hosts&lt;/code&gt; 和 DNS &lt;strong&gt;跟宿主机完全隔离&lt;/strong&gt;，宿主机里写的 &lt;code&gt;hub.kali-team.internal&lt;/code&gt; 等内网域名容器里查不到，内网自建的 DNS 又不解析这些域名。解法：启动 Runner 时让它给每个任务容器追加 &lt;code&gt;--add-host&lt;/code&gt; 参数（Docker 的“手动往 /etc/hosts 写条目“开关）：&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# runner/config.yaml（节选）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;  # 任务容器加入的 Docker 网络。不指定时 Runner 每个任务随机建一个网络，越积越多&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;  network&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;action_default&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;  # 字符串形式，条目之间用空格分隔&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;  options&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;--add-host=hub.kali-team.internal:10.111.13.105 --add-host=mirror.kali-team.internal:10.111.13.105 --add-host=nexus.kali-team.internal:10.111.13.105 --add-host=sonarqube.kali-team.internal:10.111.13.105 --add-host=rancher.kali-team.internal:10.111.13.99 --add-host=ca.kali-team.internal:10.111.13.99&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;runner&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;  capacity&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; 1&lt;/span&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;        # 同一时间最多并行跑 1 个任务（小机器保守起见）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;  timeout&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; 3h&lt;/span&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;        # 单任务超时；Gitea 服务端也有 3h 默认超时，取较短者&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;  labels&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;    # 标签：&amp;lt;标签名&amp;gt;:&amp;lt;任务容器镜像&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;    -&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;ubuntu-host:docker://mirror.kali-team.internal/dev-sec-ops/gitea/runner-images:ubuntu-latest&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;action_default&lt;/code&gt; 这个网络要提前建好（&lt;code&gt;docker network create action_default&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;上面标签里引用的 &lt;code&gt;dev-sec-ops/gitea/runner-images:ubuntu-latest&lt;/code&gt;，就是 4 要自己构建的“任务容器镜像“，镜像走内网 Harbor 的 pull-through。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;3-2-qi-dong-runner-docker-compose-docker-run-er-xuan-yi&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#3-2-qi-dong-runner-docker-compose-docker-run-er-xuan-yi&quot; aria-label=&quot;Anchor link for: 3-2-qi-dong-runner-docker-compose-docker-run-er-xuan-yi&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
3.2 启动 Runner（docker compose / docker run 二选一）&lt;/h3&gt;
&lt;p&gt;我推荐 &lt;code&gt;docker compose&lt;/code&gt;（对应仓库的 &lt;code&gt;runner/docker-compose.yml&lt;/code&gt;）。宿主机没装 compose 插件的话，用一条等价的 &lt;code&gt;docker run&lt;/code&gt; 也行：&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;export&lt;/span&gt;&lt;span&gt; REGISTRATION_TOKEN&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&amp;lt;&lt;/span&gt;&lt;span&gt;在 Gitea 界面获取的注册 token&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;export&lt;/span&gt;&lt;span&gt; RUNNER_NAME&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span&gt;kali76-runner-01&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;export&lt;/span&gt;&lt;span&gt; RUNNER_LABELS&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;ubuntu-host:docker://mirror.kali-team.internal/dev-sec-ops/gitea/runner-images:ubuntu-latest&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;docker&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; run -d --name kali76-runner&lt;/span&gt;&lt;span class=&quot;z-16&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;  --network action_default&lt;/span&gt;&lt;span class=&quot;z-16&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;  --add-host hub.kali-team.internal:10.111.13.105&lt;/span&gt;&lt;span class=&quot;z-16&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;  -e CONFIG_FILE=/config.yaml&lt;/span&gt;&lt;span class=&quot;z-16&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;  -e GITEA_INSTANCE_URL=&amp;quot;https://hub.kali-team.internal/&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-16&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;  -e GITEA_RUNNER_REGISTRATION_TOKEN=&amp;quot;&lt;/span&gt;&lt;span&gt;$REGISTRATION_TOKEN&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-16&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;  -e GITEA_RUNNER_NAME=&amp;quot;&lt;/span&gt;&lt;span&gt;$RUNNER_NAME&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-16&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;  -e GITEA_RUNNER_LABELS=&amp;quot;&lt;/span&gt;&lt;span&gt;$RUNNER_LABELS&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-16&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;  -e SSL_CERT_FILE=/etc/ssl/certs/ca-bundle-kali.pem&lt;/span&gt;&lt;span class=&quot;z-16&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;  -v&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt; $(&lt;/span&gt;&lt;span class=&quot;z-11 z-i&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;/config.yaml:/config.yaml&lt;/span&gt;&lt;span class=&quot;z-16&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;  -v&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt; $(&lt;/span&gt;&lt;span class=&quot;z-11 z-i&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;/data:/data&lt;/span&gt;&lt;span class=&quot;z-16&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;  -v /var/run/docker.sock:/var/run/docker.sock&lt;/span&gt;&lt;span class=&quot;z-16&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;  -v&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt; $(&lt;/span&gt;&lt;span class=&quot;z-11 z-i&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;/ca-bundle-kali.pem:/etc/ssl/certs/ca-bundle-kali.pem:ro&lt;/span&gt;&lt;span class=&quot;z-16&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;  mirror.kali-team.internal/docker.io/gitea/act_runner:latest&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;几个挂载点的作用：&lt;code&gt;/var/run/docker.sock&lt;/code&gt; 是 Docker 的“控制接口“，Runner 靠它才能在宿主机上创建/销毁任务容器；&lt;code&gt;data&lt;/code&gt; 目录存注册结果（&lt;code&gt;.runner&lt;/code&gt; 状态文件里有 Runner 的服务端 ID 和随机密钥，&lt;strong&gt;丢了就得重新注册&lt;/strong&gt;）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;注册 token 从哪来&lt;/strong&gt;：仓库 → &lt;strong&gt;设置&lt;/strong&gt; → &lt;strong&gt;Actions&lt;/strong&gt; → &lt;strong&gt;Runner&lt;/strong&gt;，页面顶部有“注册 token“，点 Copy 复制。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.kali-team.cn/blog/2026/09/%E5%AE%89%E5%85%A8%E5%BC%80%E5%8F%91-Gitea/image-2.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Runner 启动后日志出现 &lt;code&gt;Runner registered successfully&lt;/code&gt; 即注册成功，之后 Runner 进入守护状态，按 &lt;code&gt;fetch_interval&lt;/code&gt;（默认 60s）周期性来 Gitea 取任务。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;注册 token、Gitea 访问令牌、Harbor robot 密码、SonarQube token 等&lt;/strong&gt;一律放仓库 Secret / 系统环境，文章和命令行里只用占位符，绝不写真实值。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;3-3-yan-zheng-runner-zai-xian&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#3-3-yan-zheng-runner-zai-xian&quot; aria-label=&quot;Anchor link for: 3-3-yan-zheng-runner-zai-xian&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
3.3 验证 Runner 在线&lt;/h3&gt;
&lt;p&gt;设置侧的 Runner 列表页（空闲即在线、未执行任务）：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.kali-team.cn/blog/2026/09/%E5%AE%89%E5%85%A8%E5%BC%80%E5%8F%91-Gitea/gitea-runner-online.png&quot; alt=&quot;Runner 列表页&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 4：仓库 → 设置 → &lt;strong&gt;Actions&lt;/strong&gt; → Runner：&lt;code&gt;kali76-runner-01&lt;/code&gt;（仓库级 Runner、标签 &lt;code&gt;ubuntu-host&lt;/code&gt;、版本 v0.6.1）状态空闲（Idle），空闲 = 在线且当前没有任务在跑&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;3-4-sheng-chan-hua-bu-shu-yong-guan-fang-helm-chart-helm-actions-zai-k3s-shang-pao-runner&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#3-4-sheng-chan-hua-bu-shu-yong-guan-fang-helm-chart-helm-actions-zai-k3s-shang-pao-runner&quot; aria-label=&quot;Anchor link for: 3-4-sheng-chan-hua-bu-shu-yong-guan-fang-helm-chart-helm-actions-zai-k3s-shang-pao-runner&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
3.4 生产化部署：用官方 Helm Chart（helm-actions）在 k3s 上跑 Runner&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;前面 3.2 用 &lt;code&gt;docker run&lt;/code&gt; 在单机上把 &lt;code&gt;act_runner&lt;/code&gt; 跑起来了，学习和单机小环境没问题，但生产部署短板明显：进程挂了不会自动拉起、没法扩副本、状态依赖宿主机目录、没有资源限制。&lt;/li&gt;
&lt;li&gt;这一节把同一个 &lt;code&gt;act_runner&lt;/code&gt; 用 &lt;strong&gt;官方 Helm Chart（helm-actions）&lt;/strong&gt; 包装成 &lt;strong&gt;StatefulSet&lt;/strong&gt; 跑进 k3s：自动重启、可扩副本、持久化存储、资源限制、由集群统一管理。1.2 已经用 Helm 在 k3s 上装了 &lt;strong&gt;Gitea 服务端本身&lt;/strong&gt;，本节装的是 Runner。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;StatefulSet&lt;/strong&gt; 是 Kubernetes 的“成组管理“工具：统一管理一组 &lt;strong&gt;Pod&lt;/strong&gt;（Pod 是部署的最小单位，“一起运行的几个容器”），给每个成员稳定的序号名字和持久存储，某个挂了就自动拉起一个补上。这里一个 StatefulSet 就是&lt;strong&gt;一组 Runner 副本&lt;/strong&gt;，每个副本都能独立领任务。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.kali-team.cn/blog/2026/09/%E5%AE%89%E5%85%A8%E5%BC%80%E5%8F%91-Gitea/image-1.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 5：Rancher「应用程序 → Chart 仓库」里的 actions chart（gitea-charts 仓库、版本 0.1.2）页面：Gitea Actions Helm chart for Kubernetes，Quick-start 即下面三步的 &lt;code&gt;helm repo add&lt;/code&gt; / &lt;code&gt;helm show values&lt;/code&gt; / &lt;code&gt;helm upgrade --install&lt;/code&gt; 三步&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;先获取 Runner Token（与 3.2 相同）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;方式和 3.2 一样：在 Gitea 侧添加 Runner（&lt;strong&gt;实例 / 组织 / 仓库&lt;/strong&gt;三级的 &lt;strong&gt;Actions&lt;/strong&gt; 设置里都可以），页面会给出&lt;strong&gt;注册 token&lt;/strong&gt;。区别只有一处：token 不再写进配置文件，而是放进 Secret。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;再创建 Secret&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;把下面内容存成token用占位符，真值以 Gitea 界面给出的为准）,hub为命名空间：&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;ubuntu@nuc-node:~$&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; kubectl create secret generic runner-secret&lt;/span&gt;&lt;span class=&quot;z-16&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;  --from-literal=runner-token=jmOxTd7nNfuCfwDoLqDFawbcmO9Y9Ztt3oGPOIOX -n hub&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;secret/runner-secret&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; created&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;ubuntu@nuc-node:~$&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;容易踩的坑：&lt;strong&gt;Secret 的 namespace 必须和 chart 部署的 namespace 一致&lt;/strong&gt;。Secret 是“只认本命名空间“的对象，两边不一致，Runner 就读不到 token，注册会一直重试。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;添加 chart 仓库，拉默认 values 模板&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;helm&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; repo add gitea-charts https://dl.gitea.com/charts/&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt; helm&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; repo update&lt;/span&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;  # 加官方 chart 仓库并刷新索引&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;helm&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; show values gitea-charts/actions&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; values.yaml&lt;/span&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;                          # 把 chart 的默认 values.yaml 导到本地&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;为什么先拉模板再改？chart 的默认值很多，逐条手敲容易漏也容易错；导出完整模板后&lt;strong&gt;只改需要的字段&lt;/strong&gt;，其余一律用默认值，最稳。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;填写 values.yaml&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;下面只列要改的字段（其余保持模板默认值），每行都注释了“为什么这么设“：&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;diff&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;@@&lt;/span&gt;&lt;span&gt; -1,7 +1,7&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt; @@&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-11&quot;&gt;enabled: false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-11&quot;&gt;existingSecret: &amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-11&quot;&gt;existingSecretKey: &amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-11&quot;&gt;giteaRootURL: &amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;enabled: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;existingSecret: runner-secret&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;existingSecretKey: runner-token&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;giteaRootURL: http://gitea-http.hub.svc.cluster.local:3000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; global:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   imagePullSecrets: []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   imageRegistry: &amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;@@&lt;/span&gt;&lt;span&gt; -48,6 +48,9&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt; @@&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;         level: debug&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       cache:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;         enabled: false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;      runner:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;        labels:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;          - &amp;quot;ubuntu-host:docker://mirror.kali-team.internal/dev-sec-ops/gitea/runner-images:ubuntu-latest&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       container:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;         require_docker: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;         docker_timeout: 300s&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;部署&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;helm&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; install --labels=catalog.cattle.io/cluster-repo-name=gitea-charts --namespace=hub --timeout=10m0s --values=/home/shell/helm/values-actions-0.1.2.yaml --version=0.1.2 --wait=true action /home/shell/helm/actions-0.1.2.tgz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;level&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;WARN&lt;/span&gt;&lt;span&gt; msg&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;--wait=true is deprecated (boolean value) and can be replaced with --wait=watcher&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;NAME:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; action&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;LAST&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; DEPLOYED: Wed Oct&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; 28&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; 07:52:44&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; 2026&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;NAMESPACE:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; hub&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;STATUS:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; deployed&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;REVISION:&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;DESCRIPTION:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; Install complete&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;TEST&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; SUITE: None&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;---------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;SUCCESS:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; helm install --labels=catalog.cattle.io/cluster-repo-name=gitea-charts --namespace=hub --timeout=10m0s --values=/home/shell/helm/values-actions-0.1.2.yaml --version=0.1.2 --wait=true action /home/shell/helm/actions-0.1.2.tgz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;---------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;部署成功可以查看日志得到&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;time&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;2026-10-28T08:25:23Z&amp;quot;&lt;/span&gt;&lt;span&gt; level&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;info&lt;/span&gt;&lt;span&gt; msg&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;Log level debug requested, setting up report caller for further debugging&amp;quot;&lt;/span&gt;&lt;span&gt; func&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;[initLogging]&amp;quot;&lt;/span&gt;&lt;span&gt; file&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;[daemon.go:236]&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;time&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;2026-10-28T08:25:23Z&amp;quot;&lt;/span&gt;&lt;span&gt; level&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;info&lt;/span&gt;&lt;span&gt; msg&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;log level set to debug&amp;quot;&lt;/span&gt;&lt;span&gt; func&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;[initLogging]&amp;quot;&lt;/span&gt;&lt;span&gt; file&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;[daemon.go:240]&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;time&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;2026-10-28T08:25:23Z&amp;quot;&lt;/span&gt;&lt;span&gt; level&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;info&lt;/span&gt;&lt;span&gt; msg&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;Starting runner daemon&amp;quot;&lt;/span&gt;&lt;span&gt; func&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;[func5]&amp;quot;&lt;/span&gt;&lt;span&gt; file&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;[daemon.go:42]&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;time&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;2026-10-28T08:25:23Z&amp;quot;&lt;/span&gt;&lt;span&gt; level&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;info&lt;/span&gt;&lt;span&gt; msg&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;Docker is ready&amp;quot;&lt;/span&gt;&lt;span&gt; func&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;[func5]&amp;quot;&lt;/span&gt;&lt;span&gt; file&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;[daemon.go:86]&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;time&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;2026-10-28T08:25:23Z&amp;quot;&lt;/span&gt;&lt;span&gt; level&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;info&lt;/span&gt;&lt;span&gt; msg&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;labels updated to: [ubuntu-host:docker://mirror.kali-team.internal/dev-sec-ops/gitea/runner-images:ubuntu-latest]&amp;quot;&lt;/span&gt;&lt;span&gt; func&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;[func5]&amp;quot;&lt;/span&gt;&lt;span&gt; file&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;[daemon.go:127]&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;time&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;2026-10-28T08:25:23Z&amp;quot;&lt;/span&gt;&lt;span&gt; level&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;info&lt;/span&gt;&lt;span&gt; msg&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;runner: action-runner-0, with version: v2.0.1, with labels: [ubuntu-host], declare successfully&amp;quot;&lt;/span&gt;&lt;span&gt; func&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;[func5]&amp;quot;&lt;/span&gt;&lt;span&gt; file&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;[daemon.go:148]&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.kali-team.cn/blog/2026/09/%E5%AE%89%E5%85%A8%E5%BC%80%E5%8F%91-Gitea/image-3.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 6：Gitea「dev-sec-ops」组织 → 设置 → 工作流 → 运行器：&lt;code&gt;action-runner-0&lt;/code&gt;（ID 2、v2.0.1、组织级、标签 &lt;code&gt;ubuntu-host&lt;/code&gt;）状态空闲——Helm 部署的 Runner 已注册并在线&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# .gitea/workflows/test.yaml（放法与 6 章相同）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; test&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-14&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;workflow_dispatch&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;        # 手动触发&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;  hello&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    runs-on&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; ubuntu-host&lt;/span&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;       # 必须与本集群 Runner 注册的 label 一致&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    steps&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;      -&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; run&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; echo &amp;quot;hello from k3s runner&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;runs-on&lt;/code&gt; 的值必须和本集群 Runner 的&lt;strong&gt;注册 label&lt;/strong&gt; 对上：注册时声明了与 3.2 相同的 &lt;code&gt;ubuntu-host&lt;/code&gt; label（values 模板里有对应 label 参数，以模板为准），就能直接复用第 4 章的内网任务镜像；若注册的是 chart 默认 label，就把这一行改成对应 label，任务镜像用该 label 指向的镜像。跑通即说明“Gitea 派单 → 集群内 Runner 领单 → 任务容器干活“整条链路可用。&lt;/p&gt;
&lt;h2 id=&quot;4-ren-wu-rong-qi-jing-xiang-zi-jian-yi-ge-ubuntu-latest&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#4-ren-wu-rong-qi-jing-xiang-zi-jian-yi-ge-ubuntu-latest&quot; aria-label=&quot;Anchor link for: 4-ren-wu-rong-qi-jing-xiang-zi-jian-yi-ge-ubuntu-latest&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
4 任务容器镜像：自建一个“ubuntu-latest“&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Runner 只负责把任务容器起起来，&lt;strong&gt;容器里装了什么工具&lt;/strong&gt;由镜像决定。&lt;/li&gt;
&lt;li&gt;GitHub 上流水线常见 &lt;code&gt;runs-on: ubuntu-latest&lt;/code&gt;，用的是 GitHub 官方维护的镜像；内网没有这个源，所以我自己造了一个功能对等的镜像，推上 Harbor，标签里指向它。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;任务镜像 &lt;code&gt;runner-images:ubuntu-latest&lt;/code&gt; 里预埋的东西（都是“流水线干活要用、但内网拉不到“的）：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;工具&lt;/th&gt;&lt;th&gt;为什么任务里需要&lt;/th&gt;&lt;th&gt;怎么来的&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Docker CLI&lt;/td&gt;&lt;td&gt;任务里要 &lt;code&gt;docker login&lt;/code&gt; / &lt;code&gt;docker buildx build&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;拷贝 Runner 宿主机的二进制&lt;/strong&gt;（29.8.2，与 daemon 同版本，最稳）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;buildx 插件&lt;/td&gt;&lt;td&gt;增强版 Docker 构建（多阶段、多平台、buildkit 缓存）&lt;/td&gt;&lt;td&gt;&lt;strong&gt;宿主机 Go 1.27.1 源码编译&lt;/strong&gt;（v0.38.0）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Go 工具链&lt;/td&gt;&lt;td&gt;Go 项目要 &lt;code&gt;go mod&lt;/code&gt;/&lt;code&gt;go build&lt;/code&gt;&lt;/td&gt;&lt;td&gt;golang 基础镜像自带（1.25）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;JRE&lt;/td&gt;&lt;td&gt;SonarScanner 扫描要 Java 运行时&lt;/td&gt;&lt;td&gt;预装&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;curl / wget / git / openssl&lt;/td&gt;&lt;td&gt;下载、克隆、证书&lt;/td&gt;&lt;td&gt;基础镜像自带&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;sudo（shim）&lt;/td&gt;&lt;td&gt;不少 action 脚本无脑 &lt;code&gt;sudo xxx&lt;/code&gt;&lt;/td&gt;&lt;td&gt;用 &lt;code&gt;exec &quot;$@&quot;&lt;/code&gt; 直通 shim 兜底&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;两个“为什么这么麻烦“的解释：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;为什么 Docker CLI 不自己装，而要拷宿主机的？&lt;/strong&gt; 任务容器里跑 &lt;code&gt;docker buildx build&lt;/code&gt;，最终是连到宿主机 Docker 守护进程干活的。daemon 是宿主机上的，客户端和 daemon 版本差太多可能出兼容问题，最稳的就是“同一个机器、同一个版本“。试过在容器里 &lt;code&gt;go install&lt;/code&gt; 最新 docker CLI，但它依赖要 Go ≥ 1.26，容器里只有 1.25，编译不过，直接拷二进制最干脆。buildx 同理：最新版 v0.38.0 也要 Go ≥ 1.26，容器编不了，就到宿主机（Arch，Go 1.27.1）上源码编译好再放进去。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;为什么 buildx 编译要吃一次 &lt;code&gt;GOPROXY&lt;/code&gt;？&lt;/strong&gt; 编译 buildx 要拉一堆 Go 依赖，内网到不了 &lt;code&gt;proxy.golang.org&lt;/code&gt;，所以走 Nexus 的 goproxy（后面会说到），这也提前埋下“构建环境也要接 Nexus“这条线。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这里踩过一个很隐蔽的坑：&lt;strong&gt;这台 docker CLI 不加载 cli-plugins&lt;/strong&gt;。buildx 的设计是“docker CLI 的插件“（放进 &lt;code&gt;~/.docker/cli-plugins/&lt;/code&gt; 就能 &lt;code&gt;docker buildx&lt;/code&gt; 调用），但本环境这套 docker 29.8.2 无论如何不加载插件。解法是写一个 wrapper 脚本放 &lt;code&gt;/usr/local/bin/docker&lt;/code&gt;（PATH 最前）：遇到 &lt;code&gt;buildx&lt;/code&gt; 子命令转给独立编译的 buildx 二进制，其余子命令原样透传给真正的 docker CLI。&lt;/p&gt;
&lt;p&gt;构建并推到一个私有 project（robot 账号登录，见Harbor 一节）：&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;docker&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; build -t mirror.kali-team.internal/dev-sec-ops/gitea/runner-images:ubuntu-latest .&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-11 z-i&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$MIRROR_TOKEN&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; |&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt; docker&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; login mirror.kali-team.internal -u &amp;quot;&lt;/span&gt;&lt;span&gt;$MIRROR_USER&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot; --password-stdin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;docker&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; push mirror.kali-team.internal/dev-sec-ops/gitea/runner-images:ubuntu-latest&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;5-zi-tuo-guan-actions-ba-chang-yong-action-ban-shang-gitea&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#5-zi-tuo-guan-actions-ba-chang-yong-action-ban-shang-gitea&quot; aria-label=&quot;Anchor link for: 5-zi-tuo-guan-actions-ba-chang-yong-action-ban-shang-gitea&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
5 自托管 Actions：把常用 action 搬上 Gitea&lt;/h2&gt;
&lt;h3 id=&quot;5-1-shen-me-shi-action-wei-shen-me-yao-zi-tuo-guan&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#5-1-shen-me-shi-action-wei-shen-me-yao-zi-tuo-guan&quot; aria-label=&quot;Anchor link for: 5-1-shen-me-shi-action-wei-shen-me-yao-zi-tuo-guan&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
5.1 什么是 Action，为什么要自托管&lt;/h3&gt;
&lt;p&gt;GitHub/Gitea 流水线里，一步经常写成：&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; uses&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; actions/checkout@v4&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这叫 &lt;strong&gt;Action&lt;/strong&gt;：一个可复用的“工具包“，别人把“克隆代码““登录镜像仓库”“构建镜像“这些通用操作封装好，你用一行就引用进来。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;但 Action 本质是“别人写的、会在你的流水线里执行的代码“&lt;/strong&gt;，这就是著名的&lt;strong&gt;供应链攻击面&lt;/strong&gt;：引用外部 Action = 允许别人写的代码在你的 CI 环境里跑（能读到你仓库的 Secrets）。内网场景更现实：任务容器根本访问不了 &lt;code&gt;github.com&lt;/code&gt;，&lt;code&gt;uses: actions/checkout@v4&lt;/code&gt; 直接拉不到。&lt;/p&gt;
&lt;p&gt;解法干脆：&lt;strong&gt;把需要的 Action 自己实现一份，托管在自己的 Gitea 上&lt;/strong&gt;。我在 Gitea 建了 &lt;code&gt;actions&lt;/code&gt; 组织，将常用的action镜像下来：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;仓库&lt;/th&gt;&lt;th&gt;标签&lt;/th&gt;&lt;th&gt;干什么&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;actions/checkout&lt;/code&gt;&lt;/td&gt;&lt;td&gt;v4&lt;/td&gt;&lt;td&gt;克隆当前仓库到工作区&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;actions/login-action&lt;/code&gt;&lt;/td&gt;&lt;td&gt;v2&lt;/td&gt;&lt;td&gt;&lt;code&gt;docker login&lt;/code&gt; 登录 Harbor&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;actions/setup-qemu-action&lt;/code&gt;&lt;/td&gt;&lt;td&gt;v3&lt;/td&gt;&lt;td&gt;注册 QEMU binfmt（多架构构建用；单架构自动跳过）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;actions/cache&lt;/code&gt;&lt;/td&gt;&lt;td&gt;v4&lt;/td&gt;&lt;td&gt;缓存占位（本机场景由 buildkit 缓存挂载替代，见 6）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;actions/setup-buildx-action&lt;/code&gt;&lt;/td&gt;&lt;td&gt;v5&lt;/td&gt;&lt;td&gt;设置/选择 buildx builder&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;actions/build-push-action&lt;/code&gt;&lt;/td&gt;&lt;td&gt;v6&lt;/td&gt;&lt;td&gt;&lt;code&gt;docker buildx build&lt;/code&gt; 构建并推送镜像&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;actions/sonarqube-scan-action&lt;/code&gt;&lt;/td&gt;&lt;td&gt;v9&lt;/td&gt;&lt;td&gt;从 Nexus 下载 SonarScanner 并执行扫描&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;6-xie-liu-shui-xian-yi-docker-yaml-cong-ti-jiao-dao-jing-xiang&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#6-xie-liu-shui-xian-yi-docker-yaml-cong-ti-jiao-dao-jing-xiang&quot; aria-label=&quot;Anchor link for: 6-xie-liu-shui-xian-yi-docker-yaml-cong-ti-jiao-dao-jing-xiang&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
6 写流水线（一）：docker.yaml，从提交到镜像&lt;/h2&gt;
&lt;h3 id=&quot;6-1-gai-nian-pu-dian-buildx-buildkit-yu-duo-jie-duan-gou-jian&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#6-1-gai-nian-pu-dian-buildx-buildkit-yu-duo-jie-duan-gou-jian&quot; aria-label=&quot;Anchor link for: 6-1-gai-nian-pu-dian-buildx-buildkit-yu-duo-jie-duan-gou-jian&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
6.1 概念铺垫：buildx / buildkit 与多阶段构建&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;buildx / buildkit&lt;/strong&gt;：Docker 官方构建引擎的“增强版“。&lt;code&gt;docker buildx&lt;/code&gt; 是客户端插件，&lt;code&gt;buildkit&lt;/code&gt; 是真正干活的引擎，支持多阶段构建、多平台构建、分层缓存。buildx 有几种驱动，我们选 &lt;strong&gt;&lt;code&gt;docker&lt;/code&gt; 驱动&lt;/strong&gt;（直接用 Docker 守护进程内置的 buildkit，零额外镜像），因为内网镜像源里没有 &lt;code&gt;moby/buildkit&lt;/code&gt; 镜像（这是一个“被迫“的取舍，见 9）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多阶段构建&lt;/strong&gt;：Dockerfile 里写多个 &lt;code&gt;FROM&lt;/code&gt;（阶段），构建时每个阶段只用自己和前一阶段的产物，最终镜像可以很小很干净。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;6-2-hong-fa-tiao-jian-on-duan&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#6-2-hong-fa-tiao-jian-on-duan&quot; aria-label=&quot;Anchor link for: 6-2-hong-fa-tiao-jian-on-duan&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
6.2 触发条件（&lt;code&gt;on:&lt;/code&gt; 段）&lt;/h3&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-14&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;  workflow_dispatch&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;        # 网页上手动点&amp;quot;运行&amp;quot;，带输入&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    inputs&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;      build_server&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        description&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;#39;Build server&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        default&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        type&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; boolean&lt;/span&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;       # 是否构建 server 服务&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;      version&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        description&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;#39;Version tag&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        default&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;#39;latest&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;   # 打的镜像 tag&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;      watchtower&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        description&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;#39;触发 Watchtower 更新&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        default&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        type&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; boolean&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;  push&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    tags&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;      -&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;v*&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;                # 打 v 开头的 git tag（如 v1.0.0）时自动触发&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;  repository_dispatch&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;      # 通过 API 发事件触发（外部系统联动用）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;三种触发方式对应三种使用场景：网页手动（调试/临时发版）、打 tag 推送（正式发版）、API 触发（跟其它系统联动）。&lt;/p&gt;
&lt;p&gt;以 &lt;code&gt;dev-sec-ops/example&lt;/code&gt; 仓库为例，clone 地址走 SSH 公钥认证的 32222 端口（SSH 的 NodePort）：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.kali-team.cn/blog/2026/09/%E5%AE%89%E5%85%A8%E5%BC%80%E5%8F%91-Gitea/screenshot_8.png&quot; alt=&quot;dev-sec-ops/example 仓库页面&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 7：dev-sec-ops/example 仓库页面，克隆地址使用 SSH 公钥认证的 32222 端口（SSH 的 NodePort）&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;6-3-job-1-setup-gai-da-shen-me-tag-you-yi-ge-qing-job-suan-chu-lai&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#6-3-job-1-setup-gai-da-shen-me-tag-you-yi-ge-qing-job-suan-chu-lai&quot; aria-label=&quot;Anchor link for: 6-3-job-1-setup-gai-da-shen-me-tag-you-yi-ge-qing-job-suan-chu-lai&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
6.3 Job 1：setup——“该打什么 tag“由一个轻 job 算出来&lt;/h3&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;  setup&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    runs-on&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; ubuntu-host&lt;/span&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;          # 找带 ubuntu-host 标签的 Runner（就是我们的 Runner）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    outputs&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;      version&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; ${{ steps.get-version.outputs.version }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    steps&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;      -&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; name&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; Get version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        id&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; get-version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        run&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;          if [[ &amp;quot;${{ github.event_name }}&amp;quot; == &amp;quot;push&amp;quot; ]] &amp;amp;&amp;amp; [[ &amp;quot;${{ github.ref }}&amp;quot; == refs/tags/v* ]]; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;            VERSION=${GITHUB_REF#refs/tags/}   # 打 tag → 版本号 = tag 名（去掉 refs/tags/ 前缀）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;          else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;            VERSION=&amp;quot;${{ github.event.inputs.version }}&amp;quot;   # 手动触发 → 用输入框填的&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;          fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;          echo &amp;quot;version=${VERSION}&amp;quot; &amp;gt;&amp;gt; $GITHUB_OUTPUT   # 写进 $GITHUB_OUTPUT 才成为 step 输出&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;${{ }}&lt;/code&gt; 是 Actions 的表达式；&lt;code&gt;github.event_name&lt;/code&gt; / &lt;code&gt;github.ref&lt;/code&gt; / &lt;code&gt;github.event.inputs.*&lt;/code&gt; 是 2 说的“事件上下文“。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$GITHUB_OUTPUT&lt;/code&gt; 是 Runner 提供的一个文件，步骤往里写 &lt;code&gt;key=value&lt;/code&gt;，后续步骤/ job 就能引用，git 版本管理、镜像 tag 这类跨步骤传递的“临时变量“都靠它。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;outputs&lt;/code&gt; 段把 step 的输出“上提“成整个 job 的输出，供下一个 job 用。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;6-4-job-2-build-and-push-zhen-zheng-gan-huo-de-huan-jie&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#6-4-job-2-build-and-push-zhen-zheng-gan-huo-de-huan-jie&quot; aria-label=&quot;Anchor link for: 6-4-job-2-build-and-push-zhen-zheng-gan-huo-de-huan-jie&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
6.4 Job 2：build-and-push——真正干活的环节&lt;/h3&gt;
&lt;p&gt;先有一个&lt;strong&gt;条件判断&lt;/strong&gt;（&lt;code&gt;if:&lt;/code&gt;），决定这条 job 什么时候跑：&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;  build-and-push&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    runs-on&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; ubuntu-host&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    needs&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; setup&lt;/span&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;                            # 等 setup 完成（依赖顺序）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    strategy&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;      fail-fast&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;      max-parallel&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;      matrix&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        include&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;          -&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; service&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;server&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;            build_input&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;build_server&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;    # 只有三种情况才构建 server：打 tag 推送、repository_dispatch、手动触发且 build_server=true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;    if&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;      (github.event_name == &amp;#39;push&amp;#39; &amp;amp;&amp;amp; startsWith(github.ref, &amp;#39;refs/tags/v&amp;#39;)) ||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;      (github.event_name == &amp;#39;repository_dispatch&amp;#39;) ||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;      (github.event_name == &amp;#39;workflow_dispatch&amp;#39; &amp;amp;&amp;amp; (github.event.inputs.build_server == &amp;#39;true&amp;#39; || github.event.inputs.build_server == true))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后是执行步骤，按顺序拆：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第 1 步 Init：把 Gitea 的证书装进系统信任库&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-11 z-i&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; -n&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; |&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt; openssl&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; s_client -showcerts -connect hub.kali-team.internal:443&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;/dev/null&lt;/span&gt;&lt;span class=&quot;z-16&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-1&quot;&gt;  |&lt;/span&gt;&lt;span class=&quot;z-3 z-i&quot;&gt; sed&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; -ne &amp;#39;/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; hub.kali-team.internal.crt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; cp hub.kali-team.internal.crt /usr/local/share/ca-certificates/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; update-ca-certificates&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用 &lt;code&gt;openssl s_client&lt;/code&gt; 把 Gitea 的证书链拉下来，装进 &lt;code&gt;update-ca-certificates&lt;/code&gt; 管的系统信任库。为什么？后面的 &lt;code&gt;checkout&lt;/code&gt; 走 https 克隆，任务容器必须信任内网 CA 才能握手成功。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第 2 步 Checkout code：克隆代码&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;      -&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; name&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; Checkout code&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        uses&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; https://hub.kali-team.internal/actions/checkout@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        env&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;          GIT_SSL_NO_VERIFY&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        with&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;          submodules&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;          fetch-depth&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;          token&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; ${{ secrets.TOKEN }}&lt;/span&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;   # 访问仓库的 Gitea 访问令牌（scopes=all）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用 5 节自建的 &lt;code&gt;checkout&lt;/code&gt; action 克隆代码。&lt;code&gt;token&lt;/code&gt; 是仓库 Secret 里存的访问令牌，克隆时认证用。&lt;code&gt;fetch-depth: 0&lt;/code&gt; 拉完整历史（扫描/构建可能要看全量 commit）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第 3 步 Verify Certificate：信任 dev-sec-ops 证书 + 注入 docker 客户端证书目录&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; cp kali-team-ca.crt /usr/local/share/ca-certificates/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; update-ca-certificates&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; mkdir -p /etc/docker/certs.d/mirror.kali-team.internal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3 z-i&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; cp kali-team-ca.crt /etc/docker/certs.d/mirror.kali-team.internal/ca.crt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后两行是内网 Docker 的经典细节：Docker 客户端有个约定，&lt;code&gt;/etc/docker/certs.d/&amp;lt;registry 域名&amp;gt;/ca.crt&lt;/code&gt; 会作为访问该 registry 的&lt;strong&gt;额外 CA&lt;/strong&gt;。这样 &lt;code&gt;docker login/push mirror.kali-team.internal&lt;/code&gt; 就算忘了全局信任，也能通过证书校验。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第 4 步 Login to Harbor：登录镜像仓库&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;      -&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; name&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; Login to Harbor Registry 登录Harbor Registry&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        uses&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; https://hub.kali-team.internal/actions/login-action@v2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        with&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;          registry&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; https://mirror.kali-team.internal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;          username&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; ${{ secrets.MIRROR_USER }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;          password&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; ${{ secrets.MIRROR_TOKEN }}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;MIRROR_USER&lt;/code&gt; / &lt;code&gt;MIRROR_TOKEN&lt;/code&gt; 是 Harbor 的 robot 账号（8 讲）。登录成功后凭据写进任务容器的 &lt;code&gt;~/.docker/config.json&lt;/code&gt;，后面的 push 自动带上。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第 5 步 Set up QEMU：注册 binfmt（多架构预留，本环境跳过）&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;      -&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; name&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; Set up QEMU&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        uses&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; https://hub.kali-team.internal/actions/setup-qemu-action@v3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        with&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;          image&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; mirror.kali-team.internal/docker.io/tonistiigi/binfmt:latest&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;QEMU&lt;/strong&gt; 是 CPU 模拟器（让 amd64 机器模拟 arm64 指令）；&lt;strong&gt;binfmt_misc&lt;/strong&gt; 是内核机制“看到某类文件就交给某解释器“。注册 &lt;code&gt;qemu-aarch64&lt;/code&gt; 后，内核就能在 amd64 上“执行“ arm64 二进制，多架构构建才用得上。&lt;/li&gt;
&lt;li&gt;本流水线只构 &lt;code&gt;linux/amd64&lt;/code&gt;（单架构），且注册 binfmt 需要特权容器，我们的 Runner 没开 &lt;code&gt;privileged&lt;/code&gt;，所以 action 里容错成“注册失败只打 warning 不中断“。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;第 6 步 Go Build Cache for Docker：缓存（占位）&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;      -&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; name&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; Go Build Cache for Docker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        uses&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; https://hub.kali-team.internal/actions/cache@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        with&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;          path&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; /tmp/.buildx-cache-${{ runner.os }}-buildx-${{ matrix.service }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;          key&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; ${{ runner.os }}-buildx-${{ matrix.service }}-${{ hashFiles(&amp;#39;**/go.sum&amp;#39;) }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;          restore-keys&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;            ${{ runner.os }}-buildx-${{ matrix.service }}-&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;            ${{ runner.os }}-buildx-&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;GitHub 上这步会把 &lt;code&gt;path&lt;/code&gt; 目录按 &lt;code&gt;key&lt;/code&gt; 存到中心缓存服务。本环境 Runner 没有中心缓存服务，且任务容器的 &lt;code&gt;/tmp&lt;/code&gt; 不跨任务保留，所以 &lt;code&gt;cache@v4&lt;/code&gt; 实现成“建目录 + 打日志“的占位。&lt;strong&gt;真正的跨任务缓存被“烤“进了镜像&lt;/strong&gt;，见 6.6 的 &lt;code&gt;gomod-cache&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第 7 步 Set up Docker Buildx&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;      -&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; name&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; Set up Docker Buildx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        uses&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; https://hub.kali-team.internal/actions/setup-buildx-action@v5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        with&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;          config-inline&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;            [registry.&amp;quot;mirror.kali-team.internal&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;              insecure = true  # buildkitd 官方镜像不含内网 CA，对 mirror 跳过 TLS 校验&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker&lt;/code&gt; 驱动下 buildkit 跑在 Docker 守护进程里，所以这段内联配置实际上&lt;strong&gt;不生效&lt;/strong&gt;（TLS 信任靠 Verify Certificate 步骤注入的 &lt;code&gt;/etc/docker/certs.d/&lt;/code&gt; CA）。保留它只是对齐上游 action 的接口。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;v5&lt;/code&gt; 的行为是 &lt;code&gt;driver=docker&lt;/code&gt; 时&lt;strong&gt;不新建 builder，直接 &lt;code&gt;docker buildx use default&lt;/code&gt;&lt;/strong&gt;，因为 docker 驱动是“单例“，守护进程自带的 &lt;code&gt;default&lt;/code&gt; builder 删不掉、再建会报错（详见 9 坑 #5）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;第 8 步 Build and push：核心构建&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;      -&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; name&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; Build and push Docker image for ${{ matrix.service }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        uses&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; https://hub.kali-team.internal/actions/build-push-action@v6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        with&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;          context&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; .&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;          platforms&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; linux/amd64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;          push&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-14&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;          build-args&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;            BUILDKIT_INLINE_CACHE=1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;          target&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; ${{ matrix.service }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;          tags&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;            mirror.kali-team.internal/dev-sec-ops/example-${{ matrix.service }}:${{ needs.setup.outputs.version }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;            mirror.kali-team.internal/dev-sec-ops/example-${{ matrix.service }}:latest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;          cache-from&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; type=local,src=/tmp/.buildx-cache-${{ runner.os }}-buildx-${{ matrix.service }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;          cache-to&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; type=local,dest=/tmp/.buildx-cache-new,mode=max&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;target&lt;/code&gt; 指的是 Dockerfile 里某一个“阶段“（配合多阶段构建，只构建 &lt;code&gt;server&lt;/code&gt; 这一个最终镜像）；&lt;code&gt;tags&lt;/code&gt; 打两个 tag（版本号 + latest）；&lt;code&gt;cache-from/to&lt;/code&gt; 是 buildkit 的本地目录缓存。&lt;/li&gt;
&lt;li&gt;这里有个&lt;strong&gt;实测要澄清的细节&lt;/strong&gt;（9 坑 #7）：&lt;code&gt;docker&lt;/code&gt; 驱动下 buildkit 跑在宿主机，&lt;code&gt;type=local&lt;/code&gt; 的路径指&lt;strong&gt;宿主机&lt;/strong&gt;文件系统；而流水线的 Move cache 步骤跑在任务容器里，两边对不上，所以这套 &lt;code&gt;cache-from/to&lt;/code&gt; 实际不跨任务生效（&lt;code&gt;Move cache&lt;/code&gt; 带了 &lt;code&gt;continue-on-error: true&lt;/code&gt; 不会挂）。真正跨任务缓存由 &lt;code&gt;gomod-cache&lt;/code&gt; 镜像承担（6.6）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;第 9 步 Inspect image：确认推送成功&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4&quot;&gt;      -&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; name&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; Inspect image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-3&quot;&gt;        run&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-7&quot;&gt;          docker buildx imagetools inspect mirror.kali-team.internal/dev-sec-ops/example-${{ matrix.service }}:${{ needs.setup.outputs.version }}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;imagetools inspect&lt;/code&gt; 不去拉镜像，只向 registry 要 manifest（镜像的“目录清单“），能打印出来就证明镜像确实在 Harbor 里。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;最后两步 Move cache 与 Trigger Watchtower&lt;/strong&gt;：前者是“搬缓存目录“（带 &lt;code&gt;continue-on-error&lt;/code&gt;，作用见第 8 步的澄清）；后者是可选“自动更新“。&lt;strong&gt;Watchtower&lt;/strong&gt; 是一个“容器看门狗“镜像，发现 registry 有新镜像就自动拉新、替换、重启。这里给它一个 HTTP API，构建完可选地通知它“去更新“。&lt;strong&gt;本环境暂未部署 Watchtower&lt;/strong&gt;，所以这步只在手动触发且勾选 &lt;code&gt;watchtower&lt;/code&gt; 时才执行。&lt;/p&gt;
&lt;h3 id=&quot;6-5-dui-ying-de-dockerfile-duo-jie-duan&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#6-5-dui-ying-de-dockerfile-duo-jie-duan&quot; aria-label=&quot;Anchor link for: 6-5-dui-ying-de-dockerfile-duo-jie-duan&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
6.5 对应的 Dockerfile：多阶段&lt;/h3&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;docker&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# 构建阶段：golang 镜像里编译 Go 程序；依赖走 Nexus goproxy（7 讲）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;FROM&lt;/span&gt;&lt;span&gt; --platform=$TARGETPLATFORM mirror.kali-team.internal/docker.io/golang:1.25-bookworm &lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt;AS&lt;/span&gt;&lt;span&gt; builder&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;WORKDIR&lt;/span&gt;&lt;span&gt; /app&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;ENV&lt;/span&gt;&lt;span&gt; GOPROXY=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;https://nexus.kali-team.internal/repository/goproxy/&amp;quot;&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GOSUMDB=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;sum.golang.org https://nexus.kali-team.internal/repository/go-sumdb/&amp;quot;&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    CGO_ENABLED=0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;COPY&lt;/span&gt;&lt;span&gt; kali-team-ca.crt /usr/local/share/ca-certificates/kali-team-ca.crt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;RUN&lt;/span&gt;&lt;span&gt; update-ca-certificates&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;COPY&lt;/span&gt;&lt;span&gt; go.mod go.sum ./&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# buildkit（docker 驱动）禁止 RUN --network=host，构建容器又解析不了内网域名（见 9 坑 #6）；&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# 所以在能联网的环境预先把 go mod download 的产物烤进 gomod-cache 镜像（推到 Harbor），&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# 这里用 COPY --from 把依赖缓存和编译缓存&amp;quot;搬&amp;quot;进来&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;COPY&lt;/span&gt;&lt;span&gt; --from=mirror.kali-team.internal/dev-sec-ops/gitea/gomod-cache:go1.25-gin1.10 \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    /go/pkg/mod /go/pkg/mod&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;COPY&lt;/span&gt;&lt;span&gt; --from=mirror.kali-team.internal/dev-sec-ops/gitea/gomod-cache:go1.25-gin1.10 \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    /root/.cache/go-build /root/.cache/go-build&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;RUN&lt;/span&gt;&lt;span&gt; go mod download&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;COPY&lt;/span&gt;&lt;span&gt; main.go .&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;RUN&lt;/span&gt;&lt;span&gt; go build -ldflags &lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;#39;-s -w&amp;#39;&lt;/span&gt;&lt;span&gt; -trimpath -o /app/example .&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# 运行时基础：精简 debian + 手动信任内网 CA&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# （bookworm 精简镜像没有 update-ca-certificates，用 openssl x509 -hash 预算 subject hash 建软链）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;FROM&lt;/span&gt;&lt;span&gt; --platform=$TARGETPLATFORM mirror.kali-team.internal/docker.io/library/debian:bookworm &lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt;AS&lt;/span&gt;&lt;span&gt; runtime-base&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;WORKDIR&lt;/span&gt;&lt;span&gt; /app&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;COPY&lt;/span&gt;&lt;span&gt; kali-team-ca.crt /etc/ssl/certs/kali-team-ca.crt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;RUN&lt;/span&gt;&lt;span&gt; ln -s kali-team-ca.crt /etc/ssl/certs/6ecaa1df.0 &amp;amp;&amp;amp; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ln -s kali-team-ca.crt /etc/ssl/certs/15763dfa.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# 非 root 运行用户（安全基线：容器内进程不跑 root）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;RUN&lt;/span&gt;&lt;span&gt; groupadd -g 10001 app &amp;amp;&amp;amp; useradd -u 10001 -g 10001 -d /app -s /usr/sbin/nologin app&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;LABEL&lt;/span&gt;&lt;span&gt; com.centurylinklabs.watchtower.enable=&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# 应用阶段：只从 builder 拷一个静态二进制&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;FROM&lt;/span&gt;&lt;span&gt; runtime-base &lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt;AS&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;WORKDIR&lt;/span&gt;&lt;span&gt; /app&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;USER&lt;/span&gt;&lt;span&gt; app&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;COPY&lt;/span&gt;&lt;span&gt; --from=builder /app/example /app/example&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;EXPOSE&lt;/span&gt;&lt;span&gt; 8080&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;ENTRYPOINT&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;/app/example&amp;quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;6-6-wei-shen-me-yao-you-gomod-cache-jing-xiang-ba-gou-jian-qi-wang-luo-zheng-ge-na-diao&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#6-6-wei-shen-me-yao-you-gomod-cache-jing-xiang-ba-gou-jian-qi-wang-luo-zheng-ge-na-diao&quot; aria-label=&quot;Anchor link for: 6-6-wei-shen-me-yao-you-gomod-cache-jing-xiang-ba-gou-jian-qi-wang-luo-zheng-ge-na-diao&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
6.6 为什么要有 &lt;code&gt;gomod-cache&lt;/code&gt; 镜像：把“构建期网络“整个拿掉&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;于是 &lt;code&gt;go mod download&lt;/code&gt; 退化成“离线校验一下缓存是否齐全“的 no-op，&lt;strong&gt;构建 100% 不依赖构建期网络&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;代价：依赖变了要重新“烤“一次这个镜像（多维护一张缓存镜像）。好处：构建过程彻底离线、稳定可复现。这是内网 CI 的经典 trade-off（9 坑 #6 展开）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;7-shi-ce-yan-zheng-san-tiao-liu-shui-xian-pao-qi-lai&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#7-shi-ce-yan-zheng-san-tiao-liu-shui-xian-pao-qi-lai&quot; aria-label=&quot;Anchor link for: 7-shi-ce-yan-zheng-san-tiao-liu-shui-xian-pao-qi-lai&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
7 实测验证：三条流水线跑起来&lt;/h2&gt;
&lt;p&gt;本节数据与截图来自真实运行（2026-10-15 起）。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.kali-team.cn/blog/2026/09/%E5%AE%89%E5%85%A8%E5%BC%80%E5%8F%91-Gitea/screenshot_9.png&quot; alt=&quot;docker.yaml 流水线运行成功&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 10：Gitea Actions 里 docker.yaml 的运行记录（run #6，手动触发，main 分支），状态「成功」，总耗时 1m25s，setup 与 build-and-push 两个 job 均为 success&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二个，Harbor 出现镜像&lt;/strong&gt;：&lt;code&gt;dev-sec-ops&lt;/code&gt; project 的 Repositories 页出现三行。&lt;code&gt;example-server&lt;/code&gt;（本次流水线推的，tags &lt;code&gt;1.0.0&lt;/code&gt; 和 &lt;code&gt;latest&lt;/code&gt;，指向同一 digest &lt;code&gt;sha256:4cd55…e3513&lt;/code&gt;，约 49.6 MiB，2026-10-15 14:00 UTC 推送；&lt;strong&gt;digest&lt;/strong&gt; 是镜像内容的“指纹“，内容相同指纹就相同，用来精确指认一个镜像）、&lt;code&gt;gitea/gomod-cache&lt;/code&gt;（构建期缓存镜像）、&lt;code&gt;gitea/runner-images&lt;/code&gt;（任务镜像）：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.kali-team.cn/blog/2026/09/%E5%AE%89%E5%85%A8%E5%BC%80%E5%8F%91-Gitea/screenshot_10.png&quot; alt=&quot;Harbor dev-sec-ops 项目镜像&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 11：Harbor 的 dev-sec-ops 私有 project：流水线推送的 example-server 与自建的 runner-images、gomod-cache 都在&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第三个，&lt;code&gt;sonarqube.yaml&lt;/code&gt;（run #8，成功）&lt;/strong&gt;：&lt;code&gt;sonarqube&lt;/code&gt; job 耗时 &lt;strong&gt;21s&lt;/strong&gt;、状态 success。SonarQube &lt;code&gt;example&lt;/code&gt; 项目（显示名「项目例子」）出现扫描记录：Quality Gate &lt;strong&gt;Passed&lt;/strong&gt;，61 行代码，Security / Reliability / Maintainability 三个维度 open issues 为 0 / 0 / 1（评级 A），Coverage 0.0%（示例项目没写单测，符合预期），最后分析 2026-10-15 14:12 UTC：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.kali-team.cn/blog/2026/09/%E5%AE%89%E5%85%A8%E5%BC%80%E5%8F%91-Gitea/screenshot_11.png&quot; alt=&quot;SonarQube 项目扫描结果&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 12：SonarQube 上 example 项目（显示名「项目例子」）的 Overview：Quality Gate Passed，三个维度的未关闭问题数与评级&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;hou-xu&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#hou-xu&quot; aria-label=&quot;Anchor link for: hou-xu&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
后续&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;给 SonarQube 配 quality gate 卡流水线（扫描不过不许发）&lt;/li&gt;
&lt;li&gt;多架构（arm64，需特权 binfmt）&lt;/li&gt;
&lt;li&gt;制品发布（Nexus 存二进制/Helm chart）&lt;/li&gt;
&lt;li&gt;流水线日志归档与告警&lt;/li&gt;
&lt;li&gt;把 DT 的 SCA 真正接进每日发版（见《安全开发-DependencyTrack》篇）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;can-kao&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#can-kao&quot; aria-label=&quot;Anchor link for: can-kao&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;/a&gt;
参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&quot;external&quot; rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.gitea.com/&quot;&gt;Gitea 官方文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;external&quot; rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.gitea.com/usage/actions/&quot;&gt;Gitea Actions（Runner）文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;external&quot; rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/gitea/act_runner&quot;&gt;gitea/act_runner&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;external&quot; rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://goharbor.io/docs/&quot;&gt;Harbor 文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;external&quot; rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://help.sonatype.com/repomanager3/&quot;&gt;Nexus Repository 文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;external&quot; rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.sonarsource.com/sonarqube-server/&quot;&gt;SonarQube 文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;external&quot; rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.docker.com/build/buildx/&quot;&gt;Docker Buildx 文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;external&quot; rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://gitea.com/gitea/helm-actions&quot;&gt;Gitea Actions Helm Chart 仓库&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;external&quot; rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://dl.gitea.com/charts/&quot;&gt;Gitea 官方 chart 仓库&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
        <summary type="html">用 Gitea Actions 在这套 DevSecOps 内网里把 CI/CD 真正跑起来：自托管 Runner 怎么建、composite Action 为什么自建、docker/sonarqube/dependency-track 三条流水线逐段拆解，以及 Harbor/Nexus/SonarQube/DT 的平台联动</summary>
        </entry>
</feed>
