<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>DevOps on 维克的博客</title><link>https://blogs.wuvikr.top/categories/devops/</link><description>Recent content in DevOps on 维克的博客</description><generator>Hugo</generator><language>en</language><lastBuildDate>Fri, 30 Oct 2026 15:59:39 +0800</lastBuildDate><atom:link href="https://blogs.wuvikr.top/categories/devops/index.xml" rel="self" type="application/rss+xml"/><item><title>从零开始：生产级 GitLab CI 流水线搭建</title><link>https://blogs.wuvikr.top/posts/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%94%9F%E4%BA%A7%E7%BA%A7gitlab-ci%E6%B5%81%E6%B0%B4%E7%BA%BF%E6%90%AD%E5%BB%BA/</link><pubDate>Fri, 30 Oct 2026 15:59:39 +0800</pubDate><guid>https://blogs.wuvikr.top/posts/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%94%9F%E4%BA%A7%E7%BA%A7gitlab-ci%E6%B5%81%E6%B0%B4%E7%BA%BF%E6%90%AD%E5%BB%BA/</guid><description>&lt;p>本文以 Go 语言为案例，从「只做编译和测试」的最小流水线起步，逐步加上&lt;strong>构建镜像&lt;/strong>、&lt;strong>镜像漏洞扫描&lt;/strong>、&lt;strong>推送 Harbor&lt;/strong>，最终形成五阶段完整生产级 GitLab CI 流水线。&lt;/p>
&lt;p>下面是本文的实践路线：&lt;/p>
&lt;ol>
&lt;li>最小流水线，只做 &lt;code>build&lt;/code> 和 &lt;code>test&lt;/code> 阶段，让流水线先简单跑通。&lt;/li>
&lt;li>增加 &lt;code>build-image&lt;/code> 阶段，用 Kaniko 按 Dockerfile 构建镜像。&lt;/li>
&lt;li>增加 &lt;code>scan-image&lt;/code> 阶段，用 Trivy 扫描镜像，有高危漏洞直接退出。&lt;/li>
&lt;li>增加 &lt;code>push&lt;/code> 阶段，扫描通过后把镜像推送并打上标签。&lt;/li>
&lt;li>&lt;strong>汇总&lt;/strong>：给出完整五阶段配置与生产最佳实践。&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>为什么从头开始一点点增加步骤&lt;/strong>?&lt;/p>
&lt;p>直接给出五十行的完整配置的话，出了问题根本不知道是编译、测试、构建、扫描还是推送哪一个阶段的问题。先跑通最小闭环，每次增加一个阶段，有问题能立即验证，排查范围小，人也更有把握。&lt;/p>
&lt;p>日常编写构建生产级别的流水线也建议这样一步步验证。&lt;/p>
&lt;h1 id="1-最小流水线验证">1. 最小流水线验证&lt;/h1>
&lt;p>先只配置两个 job：&lt;/p>
&lt;ul>
&lt;li>&lt;code>build&lt;/code> 阶段：负责编译校验，确认代码能否正常打包、是否存在语法错误。&lt;/li>
&lt;li>&lt;code>test&lt;/code> 阶段：运行单元测试。&lt;/li>
&lt;/ul>
&lt;p>这两个 job 是整个 CI 的基础，也是触发最频繁、最需要优先跑稳的部分。&lt;/p>
&lt;h2 id="11-为什么先只做这两步">1.1 为什么先只做这两步&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>反馈最快&lt;/strong>：编译和单元测试在同一个代码环境中运行，几秒内就能拿到结果，不依赖镜像仓库或外部服务。&lt;/li>
&lt;li>&lt;strong>成本最低&lt;/strong>：不构建镜像、不推送，也不做扫描，任何分支的提交都可以安全触发，不会产生多余产物。&lt;/li>
&lt;li>&lt;strong>优先保障代码质量&lt;/strong>：如果编译或测试失败，就不应继续执行后续的构建、扫描和推送步骤。&lt;/li>
&lt;/ul>
&lt;h2 id="13-写配置文件">1.3 写配置文件&lt;/h2>
&lt;p>在项目根目录新建 &lt;code>.gitlab-ci.yml&lt;/code>，写入下面内容：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">stages&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">build&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">test&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">variables&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">GO_VERSION&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;1.26&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 国内须覆盖 GOPROXY，否则 go mod download 走 proxy.golang.org 会超时&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">GOPROXY&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;https://goproxy.cn,direct&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">GOSUMDB&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;sum.golang.google.cn&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 镜像仓库地址&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">HARBOR_REGISTRY&lt;/span>: &lt;span style="color:#ae81ff">example.harbor.com&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">IMAGE_NAME&lt;/span>: &lt;span style="color:#ae81ff">${HARBOR_REGISTRY}/devops/web-demo&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 缓存目录&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">GOMODCACHE&lt;/span>: &lt;span style="color:#ae81ff">$CI_PROJECT_DIR/.cache/go-mod&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">GOCACHE&lt;/span>: &lt;span style="color:#ae81ff">$CI_PROJECT_DIR/.cache/go-build&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># ============================================================================&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Stage 1: 服务构建&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># ============================================================================&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">build&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">stage&lt;/span>: &lt;span style="color:#ae81ff">build&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">image&lt;/span>: &lt;span style="color:#ae81ff">${HARBOR_REGISTRY}/devops/golang:1.26-trixie&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">variables&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">GOFLAGS&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;-mod=mod&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">cache&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">key&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">files&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">go.sum&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">paths&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">.cache/go-mod/&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">.cache/go-build/&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">untracked&lt;/span>: &lt;span style="color:#66d9ef">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">before_script&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">mkdir -p ${GOMODCACHE} ${GOCACHE}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">script&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">go mod download&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">go build -o /dev/null ./... &lt;/span> &lt;span style="color:#75715e"># 只验证能否编译，不产出二进制&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">go vet ./...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># ============================================================================&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Stage 2: 单元测试&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># ============================================================================&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">test&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">stage&lt;/span>: &lt;span style="color:#ae81ff">test&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">image&lt;/span>: &lt;span style="color:#ae81ff">${HARBOR_REGISTRY}/devops/golang:1.26-trixie&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">cache&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">key&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">files&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">go.sum&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">paths&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">.cache/go-mod/&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">.cache/go-build/&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">untracked&lt;/span>: &lt;span style="color:#66d9ef">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">before_script&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">mkdir -p ${GOMODCACHE} ${GOCACHE}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">script&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">go mod download&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">go test -v -race -coverprofile=coverage.out ./...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">artifacts&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">when&lt;/span>: &lt;span style="color:#ae81ff">always&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">expire_in&lt;/span>: &lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#ae81ff">week&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">reports&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">coverage_report&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">coverage_format&lt;/span>: &lt;span style="color:#ae81ff">cobertura&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">path&lt;/span>: &lt;span style="color:#ae81ff">coverage.out&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">paths&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">coverage.out&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>配置说明&lt;/strong>：&lt;/p></description></item><item><title>Kaniko 从入门到实践</title><link>https://blogs.wuvikr.top/posts/kaniko%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E5%AE%9E%E8%B7%B5/</link><pubDate>Sat, 24 Oct 2026 11:28:31 +0800</pubDate><guid>https://blogs.wuvikr.top/posts/kaniko%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E5%AE%9E%E8%B7%B5/</guid><description>&lt;h1 id="1-kaniko-是什么">1. Kaniko 是什么&lt;/h1>
&lt;p>&lt;strong>Kaniko&lt;/strong> 是一个由 Google 开源的，在&lt;strong>容器或 Kubernetes 集群内部&lt;/strong>，直接根据 Dockerfile 构建容器镜像的工具。&lt;/p>
&lt;p>它最核心的特点只有一个：&lt;strong>不依赖 Docker daemon（守护进程）&lt;/strong>，所有构建动作都在用户态（userspace）完成。这意味着你不需要在集群里跑一个 Docker 服务，也不需要挂载 &lt;code>/var/run/docker.sock&lt;/code>，就可以构建出标准镜像。&lt;/p>
&lt;h1 id="2-kaniko-解决了什么问题">2. Kaniko 解决了什么问题&lt;/h1>
&lt;p>在 Kaniko 出现之前，CI 里构建镜像的主流做法是 &lt;strong>Docker-in-Docker（DinD）&lt;/strong>。即在 CI Job 里再起一个 Docker 守护进程，用它去 build。这套方案在 Kubernetes 集群里有两个致命痛点：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>需要 privileged 特权模式&lt;/strong>：dind 服务容器要操控内核特性，必须给 Pod 开 &lt;code>privileged: true&lt;/code>。这是很严重的安全隐患——容器可能逃逸到宿主机，很多安全策略严格的集群直接禁止。&lt;/li>
&lt;li>&lt;strong>性能差&lt;/strong>：每个 Job 都额外拉起一个完整 Docker daemon，启动慢、占用高，多任务并发时更是灾难。&lt;/li>
&lt;/ol>
&lt;p>Kaniko 就是为了解决这个问题而生的：&lt;strong>不用特权、不用 daemon，在标准 K8s 集群里就能安全构建镜像。&lt;/strong>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>问题&lt;/th>
&lt;th>DinD（旧方案）&lt;/th>
&lt;th>Kaniko&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>需要 privileged 特权&lt;/td>
&lt;td>✅ 必须&lt;/td>
&lt;td>❌ 不需要&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>依赖 Docker daemon&lt;/td>
&lt;td>✅ 必须&lt;/td>
&lt;td>❌ 完全不需要&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>挂载 docker.sock&lt;/td>
&lt;td>✅ 需要&lt;/td>
&lt;td>❌ 不需要&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>安全性&lt;/td>
&lt;td>有容器逃逸风险&lt;/td>
&lt;td>纯用户态，安全&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>性能开销&lt;/td>
&lt;td>每个 Job 起 daemon，慢&lt;/td>
&lt;td>轻量，快&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Kaniko 的核心价值用一句话来说就是：&lt;strong>在不安全、不方便跑 Docker daemon 的环境（尤其是 K8s 集群）里，仍然能安全、快速地构建镜像。&lt;/strong>&lt;/p></description></item><item><title>GitLab CICD 入门指南</title><link>https://blogs.wuvikr.top/posts/gitlab-cicd-%E5%9F%BA%E7%A1%80%E5%85%A5%E9%97%A8/</link><pubDate>Thu, 22 Oct 2026 10:02:12 +0800</pubDate><guid>https://blogs.wuvikr.top/posts/gitlab-cicd-%E5%9F%BA%E7%A1%80%E5%85%A5%E9%97%A8/</guid><description>&lt;h1 id="1-简介">1. 简介&lt;/h1>
&lt;h2 id="11-gitlab-cicd-是什么">1.1 GitLab CI/CD 是什么？&lt;/h2>
&lt;p>GitLab CI/CD 可以理解为：GitLab 内置的持续集成 / 持续交付引擎。代码提交、合并请求、打标签或定时触发后，GitLab 会根据项目里的 &lt;code>.gitlab-ci.yml&lt;/code> 生成流水线，再交给 GitLab Runner 去执行构建、测试、扫描、打包、部署等任务。&lt;/p>
&lt;p>它的整体架构可以分成三层：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align: center">&lt;strong>层级&lt;/strong>&lt;/th>
&lt;th style="text-align: center">&lt;strong>组件&lt;/strong>&lt;/th>
&lt;th style="text-align: center">&lt;strong>作用&lt;/strong>&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align: center">控制层&lt;/td>
&lt;td style="text-align: center">GitLab Server&lt;/td>
&lt;td style="text-align: center">解析 &lt;code>.gitlab-ci.yml&lt;/code>，生成 Pipeline，分发 Job，展示结果&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: center">执行层&lt;/td>
&lt;td style="text-align: center">GitLab Runner&lt;/td>
&lt;td style="text-align: center">从 GitLab 拉取任务，执行脚本，回传日志和产物&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: center">环境层&lt;/td>
&lt;td style="text-align: center">Executor&lt;/td>
&lt;td style="text-align: center">决定 Job 跑在哪里，比如 Docker、Kubernetes、Shell、SSH 等&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>一个典型的 Gitlab CICD 执行链路如下所示：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-plaintext" data-lang="plaintext">&lt;span style="display:flex;">&lt;span>开发者 push 代码或创建 MR，触发流水线
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ↓
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>GitLab 读取仓库里的 .gitlab-ci.yml，生成 Pipeline 流水线作业
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ↓
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Runner 轮询到待执行的任务，领取 Job
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ↓
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Job 的 Tag 会和 Executor 的 Tag 进行匹配，匹配成功后，Executor 去执行 Job
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ↓
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>执行完成后，日志、制品、状态回传到 GitLab，在页面上可以查看结果
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="12-如何定义流水线">1.2 如何定义流水线？&lt;/h2>
&lt;p>一个流水线本质上由两个核心概念构成：&lt;/p></description></item><item><title>Gitlab 备份恢复和版本升级</title><link>https://blogs.wuvikr.top/posts/gitlab%E5%A4%87%E4%BB%BD%E6%81%A2%E5%A4%8D%E5%92%8C%E7%89%88%E6%9C%AC%E5%8D%87%E7%BA%A7/</link><pubDate>Mon, 12 Oct 2026 19:32:50 +0800</pubDate><guid>https://blogs.wuvikr.top/posts/gitlab%E5%A4%87%E4%BB%BD%E6%81%A2%E5%A4%8D%E5%92%8C%E7%89%88%E6%9C%AC%E5%8D%87%E7%BA%A7/</guid><description>&lt;h1 id="1-gitlab-数据备份">1. gitlab 数据备份&lt;/h1>
&lt;h2 id="11-数据备份">1.1 数据备份&lt;/h2>
&lt;p>GitLab 提供一条命令 &lt;code>gitlab-backup create&lt;/code>，运行命令后会产出一个压缩 tar 归档，包含数据库、Git 仓库与 LFS、CI/CD artifacts、Wiki、附件上传、Pages、注册表等。但它&lt;strong>不包含&lt;/strong>配置文件、密钥、Redis 队列和对象存储，这些要另行处理。&lt;/p>
&lt;p>官方提示至少必须单独备份 &lt;code>/etc/gitlab/gitlab-secrets.json&lt;/code>（内含数据库加密密钥，丢失后无法解密两步验证和 CI 安全变量）与 &lt;code>/etc/gitlab/gitlab.rb&lt;/code>。建议连同 &lt;code>/etc/gitlab/trusted-certs&lt;/code>一起备份，避免整机恢复时出现中间人警告。&lt;/p>
&lt;h2 id="12-执行备份">1.2 执行备份&lt;/h2>
&lt;p>Omnibus 包安装的环境下，可以直接调用官方封装命令：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>gitlab-backup create
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>归档默认生成在 &lt;code>/var/opt/gitlab/backups/&lt;/code>，文件名一般是这个样子： &lt;code>1730000000_2026_10_12_17.5_gitlab_backup.tar&lt;/code>。&lt;/p>
&lt;p>可以在 &lt;code>/etc/gitlab/gitlab.rb&lt;/code> 中调整文件保存路径和时间:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 备份保留7天&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>gitlab_rails&lt;span style="color:#f92672">[&lt;/span>&lt;span style="color:#e6db74">&amp;#39;backup_keep_time&amp;#39;&lt;/span>&lt;span style="color:#f92672">]&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">604800&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 备份目录配置&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>gitlab_rails&lt;span style="color:#f92672">[&lt;/span>&lt;span style="color:#e6db74">&amp;#39;backup_path&amp;#39;&lt;/span>&lt;span style="color:#f92672">]&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;/var/opt/gitlab/backups&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>修改后执行 &lt;code>gitlab-ctl reconfigure&lt;/code>。&lt;/p>
&lt;p>需要排除某类数据时用 &lt;code>SKIP&lt;/code>，例如跳过 CI 输出日志：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>gitlab-backup create SKIP&lt;span style="color:#f92672">=&lt;/span>builds,artifacts
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="13-生产备份策略">1.3 生产备份策略&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>策略&lt;/th>
&lt;th>做法&lt;/th>
&lt;th>为什么&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>定时执行&lt;/strong>&lt;/td>
&lt;td>用 cron 每天/每周触发 &lt;code>gitlab-backup create&lt;/code>&lt;/td>
&lt;td>备份频率决定最多可丢失多少数据（RPO）&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>异地/对象存储&lt;/strong>&lt;/td>
&lt;td>把 tar 归档拷贝到另一台机器或对象存储（支持 S3 等 remote 配置）&lt;/td>
&lt;td>单机磁盘故障时本地归档同样会丢&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>配置密钥单独备&lt;/strong>&lt;/td>
&lt;td>定期打包 &lt;code>/etc/gitlab&lt;/code> 到加密存储&lt;/td>
&lt;td>密钥丢失=数据库无法解密，归档也无意义&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>定期恢复演练&lt;/strong>&lt;/td>
&lt;td>在测试机用备份实际恢复一次&lt;/td>
&lt;td>没验证能恢复的备份等于没有备份&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;div class="alert alert-tip" role="alert">
&lt;p class="alert-title">提示：&lt;/p></description></item><item><title>Gitlab 入门和生产部署实践</title><link>https://blogs.wuvikr.top/posts/gitlab%E5%85%A5%E9%97%A8%E5%92%8C%E7%94%9F%E4%BA%A7%E9%83%A8%E7%BD%B2%E5%AE%9E%E8%B7%B5/</link><pubDate>Mon, 12 Oct 2026 14:51:37 +0800</pubDate><guid>https://blogs.wuvikr.top/posts/gitlab%E5%85%A5%E9%97%A8%E5%92%8C%E7%94%9F%E4%BA%A7%E9%83%A8%E7%BD%B2%E5%AE%9E%E8%B7%B5/</guid><description>&lt;h1 id="1-什么是-gitlab">1. 什么是 GitLab&lt;/h1>
&lt;p>GitLab 是一款开源的 Git 代码托管平台，支持私有化部署，被众多企业用于搭建内部代码仓库。与 GitHub 主打开源协作不同，GitLab 更聚焦于代码托管和研发流程自动化，原生提供 CI/CD、代码评审、权限管控、镜像仓库、日志审计等能力。&lt;/p>
&lt;p>GitLab 主要分为两个版本：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>CE 社区版&lt;/strong>：免费开源，基本能满足 95% 中小企业的生产需求（本文案例）；&lt;/li>
&lt;li>&lt;strong>EE 企业版&lt;/strong>：付费使用，提供高可用架构、高级安全扫描、集群权限管控以及官方技术支持，比较适合大厂落地。&lt;/li>
&lt;/ul>
&lt;p>总之，对企业来说，GitLab 的核心价值主要体现在四个方面：&lt;strong>代码内网私有化存储、研发流程标准化、流水线自动化、操作可审计追溯&lt;/strong>。&lt;/p>
&lt;h1 id="2-三种部署方式选型">2. 三种部署方式（选型）&lt;/h1>
&lt;ol>
&lt;li>&lt;strong>Omnibus 包部署（生产首选）&lt;/strong>：官方推荐的标准生产部署方案，以一键安装包形式提供，支持主流 Linux 发行版。内置 PostgreSQL、Redis、Gitaly、Web、Sidekiq 等核心组件，部署路径清晰、运维成本较低、稳定性较高，是生产环境中最稳妥的选择。&lt;/li>
&lt;li>&lt;strong>K8s 混合部署（不推荐新人尝试）&lt;/strong>：面向大规模高并发场景时，官方推荐采用混合架构，将 Web、Sidekiq 等无状态组件部署在 Kubernetes 中，便于弹性扩缩；Gitaly、数据库、缓存等有状态服务则保留在虚拟机或独立节点上部署，以保证存储和数据的稳定性。不建议新手直接使用 Kubernetes 全组件部署 GitLab。有状态组件在容器环境中的存储管理、备份恢复和升级复杂度较高，生产风险较大。&lt;/li>
&lt;li>&lt;strong>Docker 单容器部署（仅测试用）&lt;/strong>：Docker 单容器部署启动快、上手简单，但在数据持久化、备份恢复、版本升级和高可用方面能力有限，仅适合本地测试、功能验证或演示环境，不建议用于生产。&lt;/li>
&lt;/ol>
&lt;h1 id="3-安装-gitlab">3. 安装 GitLab&lt;/h1>
&lt;p>&lt;a href="https://docs.gitlab.com/omnibus/installation/index.html">官方安装文档&lt;/a>&lt;/p>
&lt;h2 id="31-前置硬件系统要求">3.1 前置硬件&amp;amp;系统要求&lt;/h2>
&lt;ul>
&lt;li>仅支持 linux，最低配置：4核8G（10人以内小团队），生产推荐 8 核 16G 及以上；&lt;/li>
&lt;li>关闭 SELinux 或 AppArmor，否则可能影响服务正常运行；&lt;/li>
&lt;li>存储优先用 SSD；不建议用 NFS、EFS、Azure Files 这类网络文件系统放仓库数据；&lt;/li>
&lt;li>开放端口：80(http)、443(https)、22(ssh)。&lt;/li>
&lt;/ul>
&lt;h2 id="32-添加-apt-源安装">3.2 添加 apt 源安装&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 更新系统依赖&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo apt update &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> sudo apt upgrade -y
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 安装必备依赖&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo apt install -y curl openssh-server ca-certificates tzdata
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 添加 GitLab 官方 APT 源&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo curl --location &lt;span style="color:#e6db74">&amp;#34;https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh&amp;#34;&lt;/span> | sudo bash
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 安装 GitLab 社区版（默认启动初始化）&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo apt install gitlab-ce -y
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="33-离线包无网络环境使用">3.3 离线包（无网络环境使用）&lt;/h2>
&lt;p>&lt;a href="https://packages.gitlab.com/gitlab/gitlab-ce">官方离线包下载地址&lt;/a>&lt;/p></description></item><item><title>ArgoCD 入门和生产实践指南</title><link>https://blogs.wuvikr.top/posts/argocd%E5%85%A5%E9%97%A8%E5%92%8C%E7%94%9F%E4%BA%A7%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97/</link><pubDate>Sat, 10 Oct 2026 09:33:28 +0800</pubDate><guid>https://blogs.wuvikr.top/posts/argocd%E5%85%A5%E9%97%A8%E5%92%8C%E7%94%9F%E4%BA%A7%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97/</guid><description>&lt;h1 id="1-什么是-argocd">1. 什么是 ArgoCD&lt;/h1>
&lt;p>&lt;a href="https://argo-cd.readthedocs.io/en/stable/">ArgoCD&lt;/a> 是 CNCF 毕业级项目，面向 Kubernetes 的&lt;strong>声明式 GitOps 持续交付工具&lt;/strong>。&lt;/p>
&lt;p>GitOps 核心思想：&lt;strong>Git 仓库作为应用配置的唯一可信源&lt;/strong>。ArgoCD 持续监听 Git 仓库内定义的应用目标状态，对比集群内资源的实际运行状态，自动完成应用部署、版本更新与故障回滚。&lt;/p>
&lt;p>ArgoCD 原生支持多种配置编排方式：Helm Chart、Kustomize、Jsonnet、Ksonnet，以及原生 YAML/JSON Kubernetes 资源清单。&lt;/p>
&lt;h1 id="2-架构原理">2. 架构原理&lt;/h1>
&lt;p>ArgoCD 以 Kubernetes 控制器形态运行，持续对应用做状态巡检：&lt;/p>
&lt;ol>
&lt;li>拉取 Git 仓库中声明的&lt;strong>期望状态（Target State）&lt;/strong>&lt;/li>
&lt;li>采集集群内资源&lt;strong>实际运行状态（Live State）&lt;/strong>&lt;/li>
&lt;li>对比两者差异，不一致时标记为 &lt;code>OutOfSync&lt;/code>（不同步）&lt;/li>
&lt;li>可视化展示资源差异，支持&lt;strong>手动同步 / 自动同步&lt;/strong>，将集群状态收敛到 Git 定义的目标状态&lt;/li>
&lt;/ol>
&lt;p>Git 仓库中修改清单后，ArgoCD 会感知变更并同步至目标集群，实现“改 Git 即发布”。&lt;/p>
&lt;p>具体工作流程参见下面的图片：
&lt;img alt="argocd工作流程图" loading="lazy" src="https://blogs.wuvikr.top/posts/argocd%E5%85%A5%E9%97%A8%E5%92%8C%E7%94%9F%E4%BA%A7%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97/argocd%E5%B7%A5%E4%BD%9C%E6%B5%81%E7%A8%8B%E7%A4%BA%E6%84%8F%E5%9B%BE.png">&lt;/p>
&lt;p>&lt;strong>核心组件&lt;/strong>:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align: center">组件&lt;/th>
&lt;th style="text-align: center">核心作用&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align: center">&lt;code>argocd-server&lt;/code>&lt;/td>
&lt;td style="text-align: center">ArgoCD API 服务，提供 REST API、Web UI，处理认证鉴权&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: center">&lt;code>argocd-repo-server&lt;/code>&lt;/td>
&lt;td style="text-align: center">Git 仓库管理服务，缓存仓库代码、渲染 Helm/Kustomize 生成K8s清单&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: center">&lt;code>argocd-application-controller&lt;/code>&lt;/td>
&lt;td style="text-align: center">应用控制器，持续做状态比对，执行同步、健康检查&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: center">&lt;code>argocd-applicationset-controller&lt;/code>&lt;/td>
&lt;td style="text-align: center">ApplicationSet控制器，批量、模板化管理多环境/多集群 Application&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: center">&lt;code>argocd-redis&lt;/code>&lt;/td>
&lt;td style="text-align: center">缓存组件，存储仓库缓存、应用状态信息&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: center">&lt;code>argocd-dex-server&lt;/code>&lt;/td>
&lt;td style="text-align: center">可选，Dex 身份代理，对接OIDC、LDAP等外部身份源&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: center">&lt;code>argocd-notifications-controller&lt;/code>&lt;/td>
&lt;td style="text-align: center">可选，通知控制器，同步状态变更推送至邮件、Slack、Webhook等&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h1 id="3-部署">3. 部署&lt;/h1>
&lt;p>部署前建议查阅&lt;a href="https://argo-cd.readthedocs.io/en/stable/operator-manual/installation/#supported-versions">官方版本兼容矩阵&lt;/a>，选择与K8s集群匹配的ArgoCD版本。&lt;/p></description></item><item><title>Harbor 私有镜像仓库安装部署和最佳实践</title><link>https://blogs.wuvikr.top/posts/harbor%E7%A7%81%E6%9C%89%E9%95%9C%E5%83%8F%E4%BB%93%E5%BA%93%E5%AE%89%E8%A3%85%E9%83%A8%E7%BD%B2%E5%92%8C%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/</link><pubDate>Sat, 03 Oct 2026 11:32:44 +0800</pubDate><guid>https://blogs.wuvikr.top/posts/harbor%E7%A7%81%E6%9C%89%E9%95%9C%E5%83%8F%E4%BB%93%E5%BA%93%E5%AE%89%E8%A3%85%E9%83%A8%E7%BD%B2%E5%92%8C%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/</guid><description>&lt;h1 id="1-简介">1. 简介&lt;/h1>
&lt;p>Harbor 是 CNCF 托管、VMware 开源的企业级容器镜像仓库，基于 Docker Registry 二次开发。除基础镜像存储能力外，还提供 Web UI、细粒度RBAC权限、镜像漏洞扫描、垃圾回收、镜像复制同步、审计日志等企业级能力，是 Kubernetes 集群离线部署、容器镜像统一管理的核心组件。&lt;/p>
&lt;p>&lt;strong>适用场景&lt;/strong>：企业内网私有镜像托管、Kubespray 离线集群镜像分发、CI/CD流水线镜像仓库。&lt;/p>
&lt;p>&lt;strong>官方参考文档&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>Harbor 官方安装指南：&lt;a href="https://goharbor.io/docs/2.8.0/install-config/">https://goharbor.io/docs/2.8.0/install-config/&lt;/a>&lt;/li>
&lt;li>Harbor HTTPS 证书配置文档：&lt;a href="https://goharbor.io/docs/main/install-config/configure-https/">https://goharbor.io/docs/main/install-config/configure-https/&lt;/a>&lt;/li>
&lt;li>Harbor 版本生命周期与版本策略：&lt;a href="https://goharbor.io/docs/main/install-config/versioning/">https://goharbor.io/docs/main/install-config/versioning/&lt;/a>&lt;/li>
&lt;li>Harbor 备份恢复官方文档：&lt;a href="https://goharbor.io/docs/main/administration/backup-restore/">https://goharbor.io/docs/main/administration/backup-restore/&lt;/a>&lt;/li>
&lt;li>Harbor 生产环境最佳实践：&lt;a href="https://www.cncf.io/blog/2026/02/24/making-harbor-production-ready-essential-considerations-for-deployment/">https://www.cncf.io/blog/2026/02/24/making-harbor-production-ready-essential-considerations-for-deployment/&lt;/a>&lt;/li>
&lt;li>Harbor 官方 Trivy 文档：https://goharbor.io/docs/2.14.0/scan/&lt;/li>
&lt;li>Trivy 官方文档：&lt;a href="https://aquasecurity.github.io/trivy/">https://aquasecurity.github.io/trivy/&lt;/a>&lt;/li>
&lt;/ul>
&lt;h1 id="2-前置环境准备">2. 前置环境准备&lt;/h1>
&lt;h2 id="21-harbor版本选型指南">2.1 Harbor版本选型指南&lt;/h2>
&lt;p>当前最新版已经到 v2.15.x，很多人会直接选用最新版，但&lt;strong>不建议生产直接上最新大版本&lt;/strong>。&lt;/p>
&lt;p>Harbor版本命名规则：&lt;code>主版本.次版本.补丁号&lt;/code>，例如 &lt;code>2.10.2&lt;/code>、&lt;code>2.15.0&lt;/code>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>奇数小版本（2.11、2.13、2.15）&lt;/strong>：新特性版本，引入新功能、重构模块；bug相对多，适合测试体验，&lt;strong>不推荐生产直接使用&lt;/strong>。&lt;/li>
&lt;li>&lt;strong>偶数小版本（2.10、2.12、2.14）&lt;/strong>：长期维护稳定分支，重点修复漏洞，新增功能保守，&lt;strong>生产首选&lt;/strong>。&lt;/li>
&lt;/ul>
&lt;p>举例：&lt;/p>
&lt;ul>
&lt;li>&lt;code>v2.15.x&lt;/code>：新特性版，适合尝鲜、学习测试；&lt;/li>
&lt;li>&lt;code>v2.14.x&lt;/code>：当前最新稳定偶数版；&lt;/li>
&lt;li>&lt;code>v2.10.x&lt;/code>：久经大规模生产验证，bug少，社区问题资料极多，如果不需要新版本的一些新特性的话，推荐使用。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>企业生产环境&lt;/strong>：优先选择&lt;strong>偶数LTS稳定分支&lt;/strong>，发布至少3个月以上，积累足够补丁。不要选用刚发布的 &lt;code>.0&lt;/code> 首版（例如 &lt;code>2.15.0&lt;/code>），这类版本会存在较多未发现的bug。&lt;/p>
&lt;h2 id="22-基础依赖">2.2 基础依赖&lt;/h2>
&lt;p>Harbor 基于 Docker Compose V2 编排运行，提前准备依赖环境：&lt;/p>
&lt;ul>
&lt;li>Docker Engine：20.10+&lt;/li>
&lt;li>Docker Compose V2&lt;/li>
&lt;li>系统架构：amd64 / arm64 均可支持（OrbStack、VMware虚拟机均可正常运行）&lt;/li>
&lt;li>硬件资源：测试环境≥2核4G；生产环境≥4核8G，推荐SSD存储提升镜像读写性能&lt;/li>
&lt;/ul>
&lt;h1 id="3-harbor-离线安装流程">3. Harbor 离线安装流程&lt;/h1>
&lt;p>离线包稳定性高于在线安装，内网、离线集群优先选用。本文部署以&lt;code>v2.14.4&lt;/code>版本为例。&lt;/p></description></item></channel></rss>