Loki Operator 镜像构建与推送策略全解析:从 Dockerfile 到 CI/CD 工作流
2026/9/20 5:02:03 网站建设 项目流程

Loki Operator 镜像构建与推送策略全解析:从 Dockerfile 到 CI/CD 工作流

【免费下载链接】lokiLike Prometheus, but for logs.项目地址: https://gitcode.com/GitHub_Trending/lok/loki

本文围绕 Grafana Loki Operator 的镜像构建与推送机制展开,系统讲解 operator 镜像(loki-operator)、OpenShift 捆绑包镜像(loki-operator-bundle)以及存储容量计算工具镜像(storage-size-calculator)在 DockerHub 与 Quay.io 两大注册中心的构建、打标签与发布策略。读者阅读后可完整掌握 Loki Operator 的持续集成镜像流水线、release-please 驱动的版本化发布流程、多平台(amd64/arm64/arm)交叉构建原理,以及如何在本地复现这些镜像的构建过程。

镜像构建与推送总览

Loki Operator 仓库采用「一套构建逻辑、多注册中心分发」的策略:所有镜像构建逻辑收敛到复用的构建工作流中,再由各 CI 工作流按场景(日常开发 vs 正式发布)调用。整个体系由三部分组成:

  1. 持续集成构建(latest 标签):推送main分支(仅operator/**路径变更)或手动触发时,构建并推送所有 operator 相关镜像,标签为latest
  2. 正式发布构建(版本号标签):release-please 创建新 Release 时,构建并推送带语义化版本号({major}.{minor}.{patch})的镜像;
  3. 复用构建工作流:集中处理多平台构建(linux/amd64linux/arm64linux/arm)与基于注册中心的认证逻辑,供其他工作流workflow_call调用。

对应的工作流文件与镜像 Dockerfile 均位于仓库根目录,可对照查阅:operator-images.yaml、operator-release-please.yml、operator-reusable-image-build.yml,以及 operator/Dockerfile、operator/calculator.Dockerfile、operator/bundle/openshift/bundle.Dockerfile。

构建与推送策略

DockerHub(docker.io)

官方文档声明,loki-operator镜像同时面向 DockerHub 分发。在仓库的实际工作流中,DockerHub 的推送经由 Google Artifact Registry(us-docker.pkg.dev)下的grafanalabs-global/dockerhub-loki-prod-mirror仓库完成,即先将镜像推送到 GAR 的镜像仓库,再同步/镜像至 DockerHub 命名空间:

镜像触发时机组织标签工作流文件
loki-operator推送 main 分支grafana(经grafanalabs-global/dockerhub-loki-prod-mirror中转)latestoperator-images.yaml
loki-operator创建 Release同上{major}.{minor}.{patch}operator-release-please.yml

Quay.io

Quay.io 是 OpenShift 生态的分发主阵地,面向openshift-logging组织推送三款镜像,其中 operator 主镜像与 bundle 捆绑包镜像配合,可被 OpenShift OperatorHub / OLM 直接消费:

镜像触发时机组织标签工作流文件
loki-operator推送 main 分支openshift-logginglatestoperator-images.yaml
loki-operator-bundle推送 main 分支openshift-logginglatestoperator-images.yaml
storage-size-calculator推送 main 分支openshift-logginglatestoperator-images.yaml

值得注意的是,实际工作流在 Quay.io 侧还额外发布了第 4 个镜像passthrough-gateway(基于 operator/passthrough-gateway.Dockerfile,对应 operator/cmd/passthrough-gateway 入口),用于 OpenShift 上的多租户网关场景,属于对文档表格的运行时扩展。

工作流文件逐层拆解

operator-images.yaml:持续集成构建

operator-images.yaml 是 daily CI 的入口,触发条件为:

  • pushmain分支,且变更路径命中operator/**(即只有 operator 相关代码变动才触发镜像构建,避免无关提交浪费构建资源);
  • workflow_dispatch手动触发,便于运维人员随时重新构建。

该工作流在同一文件内声明了 5 个并行 job,全部通过uses: ./.github/workflows/operator-reusable-image-build.yml复用统一构建逻辑,仅通过with传入不同的构建参数:

JobDockerfileRegistry组织/仓库镜像名标签
publish-grafana-operatoroperator/Dockerfileus-docker.pkg.devgrafanalabs-global/dockerhub-loki-prod-mirrorloki-operatorlatest
publish-openshift-operatoroperator/Dockerfilequay.ioopenshift-loggingloki-operatorlatest
publish-openshift-bundleoperator/bundle/openshift/bundle.Dockerfilequay.ioopenshift-loggingloki-operator-bundlelatest
publish-openshift-size-calculatoroperator/calculator.Dockerfilequay.ioopenshift-loggingstorage-size-calculatorlatest
publish-openshift-passthrough-gatewayoperator/passthrough-gateway.Dockerfilequay.ioopenshift-loggingpassthrough-gatewaylatest

每个 job 都显式声明id-token: write权限,这是 OIDC 无密钥认证(Workload Identity Federation)的前提——推送到 GAR 时不再依赖静态账号密码。

operator-reusable-image-build.yml:集中式构建核心

operator-reusable-image-build.yml 是整套体系的「心脏」,采用workflow_call可复用事件,对外暴露 5 个必填输入:

  • image_name:镜像名称;
  • dockerfile:构建所用的 Dockerfile 路径;
  • tag:镜像标签;
  • registry:目标注册中心(us-docker.pkg.devquay.io);
  • organization:注册中心下的组织/项目名。

其执行步骤完整呈现了现代多平台镜像 CI 的标准姿势:

  1. checkout 代码:使用actions/checkout(v7.0.1)拉取仓库,并设置persist-credentials: false防止令牌泄漏;
  2. 配置 QEMU:通过docker/setup-qemu-action注册模拟器,使构建机能够为linux/arm64linux/arm等非宿主架构执行跨平台编译;
  3. 配置 Buildx:通过docker/setup-buildx-action启用 BuildKit 多平台构建能力;
  4. 认证(按注册中心分流)
    • 目标为 GAR(us-docker.pkg.dev)时,调用grafana/shared-workflows/actions/login-to-gar完成 OIDC 登录;
    • 目标为 Quay.io 时,先调用get-vault-secrets从 Vault 读取openshift-credentials(用户名/密码),再通过docker/login-action(v4.6.0,带logout: true)登录;
  5. 构建并推送:调用docker/build-push-action(v7.3.0),关键参数如下:
- name: Build and push uses: docker/build-push-action@v7.3.0 with: # 根据镜像名推断构建上下文: # bundle 镜像使用 operator/bundle/openshift,其余使用 operator context: ${{ inputs.image_name == 'loki-operator-bundle' && 'operator/bundle/openshift' || 'operator' }} file: ${{ inputs.dockerfile }} platforms: "linux/amd64,linux/arm64,linux/arm" push: true tags: ${{ inputs.registry }}/${{ inputs.organization }}/${{ inputs.image_name }}:${{ inputs.tag }}

工作流中的注释特别说明了 context 的推断逻辑:采用条件表达式而非直接暴露context输入,是为了规避 zizmor(GitHub Actions 静态安全扫描工具)对「输入可能展开为攻击者可控代码」的高危告警——这是 CI 供应链安全加固的典型实践。

operator-release-please.yml:版本化发布流水线

operator-release-please.yml 定义了正式发布流程,触发条件为推送main分支且变更operator/**。其流程分为三个串联阶段:

  1. releasePlease job:使用googleapis/release-please-action(v5.0.0)分析 Conventional Commits,自动推进版本号并创建 Release。其行为由 operator/release-please-config.json 控制,核心配置包括:bump-minor-pre-major: true(0.x 阶段升 minor 而非 major)、include-component-in-tag: truetag-separator: "/"(形成operator/vX.Y.Z形式的 tag)、PR 标题模板chore(operator): Community release ${version}以及changelog-path: CHANGELOG.md。该 job 还会输出operator--release_createdoperator--tag_nameoperator--major/minor/patch等关键结果供下游消费。认证使用 GitHub App(loki-gh-app)生成的临时令牌,避免使用机器人账号密码;
  2. publishImages jobif: ${{ needs.releasePlease.outputs.release_created }}守卫——仅当 release 真正创建后才执行。复用operator-reusable-image-build.yml构建loki-operator,但标签不再是latest,而是拼接为{major}.{minor}.{patch}的正式版本号,推送到us-docker.pkg.dev/grafanalabs-global/dockerhub-loki-prod-mirror
  3. publishRelease job:依赖前两个 job 成功,通过gh release edit将 Release 从草稿状态(release-please 默认draft: true)转为正式发布,并标记为非最新(--latest=false),确保版本的发布状态与镜像推送结果保持一致。

该设计实现了「版本号生成 → 镜像构建推送 → Release 正式发布」的原子化闭环:镜像构建失败则 Release 不会转正。

镜像清单与 Dockerfile 深入解读

loki-operator:主 Operator 二进制镜像

构建文件为 operator/Dockerfile,采用经典的两阶段构建:

# 阶段一:编译 FROM golang:1.26.6@sha256:0d1d3a794be25f809dd2cb3160d8c73276c4056a9f8242a138e908ddeee7b6b6 as builder WORKDIR /workspace # 先复制 go.mod/go.sum 与 api 模块,缓存依赖层 COPY api/ api/ COPY go.mod go.mod COPY go.sum go.sum RUN go mod download # 再复制源码,避免源码变更导致依赖层失效 COPY cmd/loki-operator/main.go cmd/loki-operator/main.go COPY internal/ internal/ RUN CGO_ENABLED=0 GOOS=linux GO111MODULE=on go build -mod=readonly -o manager cmd/loki-operator/main.go # 阶段二:精简运行镜像 FROM gcr.io/distroless/static:nonroot WORKDIR / COPY --from=builder /workspace/manager . USER 65532:65532 ENTRYPOINT ["/manager"]

几个值得注意的工程细节:

  • 依赖缓存:先COPY go.mod go.sum并执行go mod download,再复制源码,利用 Docker 层缓存避免每次提交都重新下载依赖;
  • 静态编译CGO_ENABLED=0 GOOS=linux产出纯静态二进制,可安全运行于不含 glibc 的 distroless 基础镜像;
  • 最小攻击面:最终镜像基于gcr.io/distroless/static:nonroot,无 shell、无包管理器,并以非 root 用户(UID 65532)运行;
  • 入口:ENTRYPOINT 直指编译产物/manager,对应 operator 主程序入口 operator/cmd/loki-operator/main.go。

storage-size-calculator:容量计算工具镜像

构建文件为 operator/calculator.Dockerfile,结构与主镜像完全对称:在golang:1.26.6builder 阶段编译 operator/cmd/size-calculator/main.go,产物为size-calculator;运行阶段同样基于 distroless 并以非 root 运行,ENTRYPOINT ["/size-calculator"]。该工具用于计算 LokiStack 各组件(如查询、写入、存储)的资源与容量需求,与 operator 内的 size-calculator 逻辑呼应。

loki-operator-bundle:OpenShift OLM 捆绑包镜像

构建文件为 operator/bundle/openshift/bundle.Dockerfile,它与前两者完全不同——不包含任何二进制,而是 OLM(Operator Lifecycle Manager)规范下的元数据镜像:

FROM scratch # Core bundle labels. LABEL operators.operatorframework.io.bundle.mediatype.v1=registry+v1 LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/ LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ LABEL operators.operatorframework.io.bundle.package.v1=loki-operator LABEL operators.operatorframework.io.bundle.channels.v1=stable LABEL operators.operatorframework.io.bundle.channel.default.v1=stable LABEL operators.operatorframework.io.metrics.builder=operator-sdk-unknown LABEL operators.operatorframework.io.metrics.mediatype.v1=metrics+v1 LABEL operators.operatorframework.io.metrics.project_layout=go.kubebuilder.io/v4 # Labels for testing. LABEL operators.operatorframework.io.test.mediatype.v1=scorecard+v1 LABEL operators.operatorframework.io.test.config.v1=tests/scorecard/ # Copy files to locations specified by labels. COPY ./manifests /manifests/ COPY ./metadata /metadata/ COPY ./tests/scorecard /tests/scorecard/

基于scratch的捆绑包镜像通过一组operators.operatorframework.io.*标签声明其 OLM 元数据布局,并复制三个关键目录:

  • manifests/:包含 ClusterServiceVersion(loki-operator.clusterserviceversion.yaml)、CRD(loki.grafana.com_lokistacks.yamlloki.grafana.com_alertingrules.yamlloki.grafana.com_recordingrules.yamlloki.grafana.com_rulerconfigs.yaml)、RBAC 与 ServiceMonitor 等清单(见 operator/bundle/openshift/manifests);
  • metadata/:存放annotations.yaml,供 OLM 索引解析 bundle 元数据(见 operator/bundle/openshift/metadata);
  • tests/scorecard/:scorecard 测试配置,用于在发布前对 operator 进行 smoke test。

OLM 依据channels.v1=stablechannel.default.v1=stableloki-operator暴露在stable频道,OpenShift 集群用户可通过 OperatorHub 直接订阅安装。

本地复现镜像构建

在仓库根目录下,可以通过 Makefile 提供的 target 在本地验证 operator 镜像构建流程。Makefile 中定义:

# Loki Operator loki-operator-image: ## build the operator docker image $(OCI_BUILD) -t $(OPERATOR_IMAGE) -f operator/Dockerfile ./operator

其中OPERATOR_IMAGE := $(IMAGE_PREFIX)/loki-operator:$(IMAGE_TAG),执行make loki-operator-image即会以operator/为构建上下文、operator/Dockerfile 为构建文件产出镜像。这与 CI 中context: operatorfile: operator/Dockerfile的调用完全一致,本地产物与线上流水线行为可对齐验证。

若需完全复刻 CI 的多平台构建,可参照 operator-reusable-image-build.yml 中的 Buildx 配置,在本地启用 buildx 后指定--platform linux/amd64,linux/arm64,linux/arm进行交叉构建。

小结

Loki Operator 的镜像交付体系可以归纳为「一个可复用构建工作流 + 两条发布通道 + 三类镜像」:

  • 一个核心:operator-reusable-image-build.yml 统一承担多平台构建、注册中心认证与推送,通过workflow_call被 CI 与发布流水线共享,最大程度消除构建逻辑分叉;
  • 两条通道:operator-images.yaml 负责日常latest构建,operator-release-please.yml 负责 release-please 驱动的版本化发布,并通过「Release 草稿转正依赖镜像构建成功」的依赖关系保证发布原子性;
  • 三类镜像:operator 主程序镜像、bundle 捆绑包元数据镜像(供 OLM 消费)、工具类镜像(容量计算),分别由三份职责清晰的 Dockerfile 产出,且主程序与工具镜像均以 distroless 非 root 形态交付。

对需要自建或改造 Operator 镜像 CI 的团队而言,这套策略在触发粒度(operator/**路径过滤)、跨平台构建、OIDC/密钥分级认证、安全加固(zizmor 告警规避、最小基础镜像)以及发布闭环(release-please 与镜像联动)等方面都提供了可直接借鉴的模板。

【免费下载链接】lokiLike Prometheus, but for logs.项目地址: https://gitcode.com/GitHub_Trending/lok/loki

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询