<?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>GitLab on 维克的博客</title><link>https://blogs.wuvikr.top/tags/gitlab/</link><description>Recent content in GitLab 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/tags/gitlab/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></channel></rss>