Online Boutique Helm Chart 部署实战:从默认安装到 Service Mesh 安全加固与 Spanner 后端切换
2026/9/13 20:53:53 网站建设 项目流程

Online Boutique Helm Chart 部署实战:从默认安装到 Service Mesh 安全加固与 Spanner 后端切换

【免费下载链接】microservices-demoSample cloud-first application with 10 microservices showcasing Kubernetes, Istio, and gRPC.项目地址: https://gitcode.com/GitHub_Trending/mi/microservices-demo

本篇技术指南基于 helm-chart/README.md 展开,介绍如何在 Kubernetes 上通过 Helm 一键部署 Google Cloud 官方示例应用 Online Boutique(10 个微服务、gRPC、Istio 服务网格),覆盖默认安装、高级安全场景(Service Accounts、AuthorizationPolicies、NetworkPolicies、Sidecar)、cartservice 后端从 Redis 切换至 Cloud Spanner 等核心配置,并结合 helm-chart/values.yaml 与 helm-chart/templates 源码逐项讲解参数语义与底层渲染逻辑。读完本文你将掌握:如何用一条命令完成 Online Boutique 的默认部署,如何通过--set组合出面向生产的安全加固拓扑,以及如何通过cartservice.database相关参数将购物车数据层无缝迁移到 Spanner。

注意:Online Boutique 的 Helm chart 当前标记为实验性(experimental)。如遇到问题,可通过 GitHub Issue 反馈(原文档指向 Issue #1319 及新建 Issue 入口)。文章中的所有示例均以当前仓库内helm-chart目录的实际内容为准,chart 版本与 app 版本均为v0.10.6(见 helm-chart/Chart.yaml)。

一、准备工作:chart 从哪来、如何获取

Online Boutique 的 Helm chart 已经打包并发布到公开的 Artifact Registry(OCI Registry),因此你无需从源码构建,直接用 Helm 3 的 OCI 拉取能力即可安装:

# 默认安装 Online Boutique helm upgrade onlineboutique oci://us-docker.pkg.dev/online-boutique-ci/charts/onlineboutique \ --install

helm upgrade ... --install是一个幂等用法:若 releaseonlineboutique不存在则执行安装,已存在则升级,配合 OCI 引用天然适合后续的迭代更新。

如果你希望了解 chart 是如何被发布到这个 Registry 的,可以查看仓库中的发布脚本 docs/releasing/make-helm-chart.sh:它读取TAG环境变量,用gsed同步改写 helm-chart/Chart.yaml 中的versionappVersion,然后依次执行helm package .helm push onlineboutique-<version>.tgz oci://us-docker.pkg.dev/online-boutique-ci/charts。也就是说,本文安装命令中的镜像 tag 默认取自Chart.yamlappVersion: "v0.10.6"

二、Chart 结构速览:一个 chart 管住 12 类工作负载

在深入参数之前,先建立对 chart 布局的整体认知。当前仓库的 chart 目录结构如下:

helm-chart/ ├── Chart.yaml # chart 元数据:apiVersion: v2,type: application,version/appVersion: v0.10.6 ├── values.yaml # 全部可配置项的默认值(核心参数清单见下一节) └── templates/ ├── NOTES.txt # 安装成功后的提示信息(如何获取前端地址) ├── common.yaml # 全局 deny-all NetworkPolicy / AuthorizationPolicy ├── adservice.yaml / cartservice.yaml / checkoutservice.yaml ├── currencyservice.yaml / emailservice.yaml / frontend.yaml ├── loadgenerator.yaml / opentelemetry-collector.yaml ├── paymentservice.yaml / productcatalogservice.yaml ├── recommendationservice.yaml / shippingservice.yaml

Chart 遵循 Helm 2.x/v2 规范(apiVersion: v2,应用型 chart),values.yaml中为每个服务都提供了create开关,因此可以按需裁剪组件;同时每个服务的模板都遵循"资源 → 网络策略 → Sidecar → 授权策略"的统一四段式结构,为安全场景的批量开启提供了基础。

三、核心配置参数全解(values.yaml 逐项拆解)

完整的参数清单以 helm-chart/values.yaml 为准,下面按功能域分类讲解,并结合模板源码说明每个参数的实际影响。

3.1 镜像与发布

参数默认值说明
images.repositoryus-central1-docker.pkg.dev/online-boutique-ci/microservices-demo所有微服务镜像的仓库前缀,模板中用{{ .Values.images.repository }}/{{ .Values.<service>.name }}:{{ .Values.images.tag | default .Chart.AppVersion }}拼出完整镜像地址(见各服务模板)。使用私有或自建镜像仓库时务必覆盖此值
images.tag""覆盖镜像 tag;为空时回退到 chart 的appVersion(即v0.10.6

从 helm-chart/templates/adservice.yaml 可以看到典型的镜像渲染逻辑:image: {{ .Values.images.repository }}/{{ .Values.adService.name }}:{{ .Values.images.tag | default .Chart.AppVersion }}。因此覆盖images.repository后,全部 10 个微服务镜像将统一从新仓库拉取,这是离线部署与私有化环境的关键开关。

3.2 安全加固开关(服务账号 / 网络策略 / 授权策略 / Sidecar)

参数默认值说明
serviceAccounts.createtrue是否为每个应用创建独立的 ServiceAccount(模板中未开启时回退到serviceAccountName: default
serviceAccounts.annotations{}附加到 ServiceAccount 上的注解,典型用途是注入 Workload Identity 注解iam.gke.io/gcp-service-account
serviceAccounts.annotationsOnlyForCartservicefalse注解施加到 cartservice 的 ServiceAccount 上。遵循最小权限原则:只有 cartservice 需要连接外部数据库(如通过 Workload Identity 访问 Spanner),避免把云上高权限注解扩散到所有服务
networkPolicies.createfalse为每个应用生成一条细粒度 NetworkPolicy(见各模板文件),开启时同时生成全局 deny-all 策略(见 helm-chart/templates/common.yaml)
sidecars.createfalse为每个应用生成细粒度 Istio Sidecar 资源(白名单式声明可访问的 egress 目标,见各模板文件)
authorizationPolicies.createfalse为每个应用生成细粒度 Istio AuthorizationPolicy,与全局 deny-all 搭配形成"默认拒绝、按需放行"的授权模型

以 helm-chart/templates/cartservice.yaml 为例,开启authorizationPolicies.create后,cartservice 的 AuthorizationPolicy 只允许来自frontendcheckoutservice两个 ServiceAccount 的调用,且仅放行/hipstershop.CartService/AddItem/hipstershop.CartService/GetCart/hipstershop.CartService/EmptyCart三个 gRPC 路径的 POST 请求、端口 7070。这体现了从"进程级网络可达"到"方法级调用授权"的纵深防御思路。

3.3 可观测性:OpenTelemetry Collector 与 Google Cloud Operations

参数默认值说明
opentelemetryCollector.createfalse是否部署 OTel Collector 网关(Deployment + ClusterIP Service,端口 4317/gRPC-OTLP)
opentelemetryCollector.nameopentelemetrycollectorCollector 服务名
opentelemetryCollector.projectId"PROJECT_ID"GCP 项目 ID;保持默认值时,会通过 initContainer 从 metadata server 自动获取
googleCloudOperations.profilerfalse开启后向前端/结算服务注入ENABLE_PROFILER=1
googleCloudOperations.tracingfalse开启后注入ENABLE_TRACING=1
googleCloudOperations.metricsfalse指标开关(预留)

从 helm-chart/templates/opentelemetry-collector.yaml 可以看到一个精巧的机制:当projectId等于"PROJECT_ID"时,chart 会注入一个 busybox initContainer,执行sed "s/PROJECT_ID/$(curl -H 'Metadata-Flavor: Google' http://metadata.google.internal/computeMetadata/v1/project/project-id)/",把配置模板中的占位符替换为真实项目 ID 后写入共享卷,Collector 主容器再以--config=/conf/collector-gateway-config.yaml启动。Collector 配置里receivers.otlp+exporters.googlecloud形成 traces/metrics 两条直接上云的数据管道。

3.4 运行时安全上下文

参数默认值说明
securityContext.enabletrue为 Pod 注入fsGroup/runAsGroup/runAsNonRoot/runAsUser = 1000的 Pod 级 securityContext
seccompProfile.enablefalse是否启用 seccompProfile
seccompProfile.typeRuntimeDefaultseccomp 类型(仅在 enable 时生效)

此外,各服务容器本身都写死了安全加固字段(见 helm-chart/templates/cartservice.yaml):allowPrivilegeEscalation: falsecapabilities.drop: [ALL]privileged: falsereadOnlyRootFilesystem: true。这些是开箱即用的容器最小权限基线。

3.5 各微服务组件开关与资源配置

values.yaml为每个服务提供了createnameresources三件套,默认全部开启(create: true)。默认资源请求/限制如下(requests/limits,CPU/内存):

服务nameCPU 请求/限制内存请求/限制
adServiceadservice200m / 300m180Mi / 300Mi
cartServicecartservice200m / 300m128Mi / 256Mi
checkoutServicecheckoutservice100m / 200m64Mi / 128Mi
currencyServicecurrencyservice100m / 200m128Mi / 256Mi
emailServiceemailservice100m / 200m64Mi / 128Mi
frontendfrontend100m / 200m64Mi / 128Mi
loadGeneratorloadgenerator300m / 500m256Mi / 512Mi
paymentServicepaymentservice100m / 200m128Mi / 256Mi
productCatalogServiceproductcatalogservice100m / 200m64Mi / 128Mi
recommendationServicerecommendationservice100m / 200m220Mi / 450Mi
shippingServiceshippingservice100m / 200m64Mi / 128Mi

两个值得注意的专项参数:

  • productCatalogService.extraLatency(默认""):给 productcatalogservice 的每次请求注入额外延迟,用于压测/演示超时与重试行为,默认无额外延迟;
  • loadGenerator.checkFrontendInitContainer(默认true):loadgenerator 启动前先通过 busybox initContainer 用wget --server-response轮询前端(最多 12 次、间隔 10 秒,见 helm-chart/templates/loadgenerator.yaml),确保压测流量不会打到尚未就绪的前端。压测参数在模板中硬编码为USERS=10RATE=1(每秒 1 个请求/用户)。

3.6 前端访问与 Istio 路由

参数默认值说明
frontend.externalServicetrue是否额外创建frontend-external的 LoadBalancer Service(保留frontendClusterIP Service 用于网格内访问)
frontend.cymbalBrandingfalse是否启用 Cymbal 品牌标识(对应注入CYMBAL_BRANDING环境变量)
frontend.platformlocal部署平台标识,取值local/gcp/aws/azure/onprem/alibaba之一;对应注入ENV_PLATFORM环境变量,前端 main.go 据此渲染部署详情。默认local,GKE 上运行时自动切换为gcp
frontend.singleSharedSessionfalse是否启用单共享会话模式(对应ENABLE_SINGLE_SHARED_SESSION
frontend.virtualService.createfalse是否创建指向 ingress gateway 的 Istio VirtualService
frontend.virtualService.hosts["*"]VirtualService 的 host 列表
frontend.virtualService.gateway.nameasm-ingressgateway目标 Gateway 名称
frontend.virtualService.gateway.namespaceasm-ingress目标 Gateway 所在命名空间
frontend.virtualService.gateway.labelKeyasm用于从 ASM 命名空间中挑选网关 Pod 的标签键
frontend.virtualService.gateway.labelValueingressgateway对应标签值

关键关联:当frontend.externalService=falsefrontend.virtualService.create=true时,流量路径变为"Ingress Gateway → VirtualService → frontend:80",NetworkPolicy 会额外放行来自网关命名空间(kubernetes.io/metadata.name匹配frontend.virtualService.gateway.namespace)的入站请求(见 helm-chart/templates/frontend.yaml)。

3.7 购物车数据库:Redis 与 Spanner 双后端

参数默认值说明
cartDatabase.typeredis购物车数据层类型,可选redisspanner
cartDatabase.connectionStringredis-cart:6379连接串;Redis 模式为host:port,Spanner 模式为projects/<project>/instances/<instance>/databases/<db>
cartDatabase.inClusterRedis.createtrue是否随 chart 部署一个内置 Redis(Deployment + Service,端口 6379)
cartDatabase.inClusterRedis.nameredis-cart内置 Redis 名称
cartDatabase.inClusterRedis.publicRepositorytrue为 true 时使用 Docker Hub 的redis:alpine官方镜像(固定 digest 拉取),否则改用images.repository中的 redis
cartDatabase.externalRedisTlsOrigination.enablefalse是否对外部 Redis 启用 TLS 发起(配合 Istio ServiceEntry/DestinationRule)
cartDatabase.externalRedisTlsOrigination.nameexernal-redis-tls-originationTLS 资源命名前缀(注意原值拼写)
cartDatabase.externalRedisTlsOrigination.endpointAddress""外部 Redis 端点 IP
cartDatabase.externalRedisTlsOrigination.endpointPort""外部 Redis 端点端口
cartDatabase.externalRedisTlsOrigination.certificate""用于 TLS 校验的 PEM 证书内容

模板层的实际效果(见 helm-chart/templates/cartservice.yaml):

  • cartDatabase.type == "spanner"时,注入环境变量SPANNER_CONNECTION_STRING;否则注入REDIS_ADDR,值均取cartDatabase.connectionString
  • 开启externalRedisTlsOrigination.enable时,chart 会同时生成:保存 PEM 证书的 Secret、mode: SIMPLE的 DestinationRule(caCertificates 指向/etc/certs/<name>.pem)、location: MESH_EXTERNAL的 ServiceEntry(resolution: STATIC),并在 cartservice Pod 上通过sidecar.istio.io/userVolumeMount注解把证书卷挂到 sidecar 的/etc/certs,同时设置proxy.istio.io/config: {"holdApplicationUntilProxyStarts": true}保证 sidecar 就绪后再启动应用容器。

3.8 尚未纳入 Helm 的组件

shoppingAssistantService(购物助手)当前在values.yaml中以create: false占位并标注 TODO,尚未随 Helm 部署(可参考 kustomize/components/shopping-assistant 的独立安装方式)。

四、部署命令实战:默认安装与高级场景

4.1 场景一:默认部署

helm upgrade onlineboutique oci://us-docker.pkg.dev/online-boutique-ci/charts/onlineboutique \ --install

该命令会以默认值部署全部 10 个微服务 + 内置 Redis + loadgenerator,并创建一个frontend-externalLoadBalancer Service 对外暴露前端。安装完成后,chart 的 NOTES.txt 会给出获取访问地址的方法:

# 观察 frontend-external 的 LoadBalancer IP 就绪状态 kubectl get --namespace <release-namespace> svc -w frontend-external # 提取外部 IP 并打印访问地址 export SERVICE_IP=$(kubectl get svc --namespace <release-namespace> frontend-external --template "{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}") echo http://$SERVICE_IP

若开启了frontend.virtualService.create,NOTES.txt 还会提示通过 ingress gateway 的地址访问(同理用kubectl get svc -n <gateway-namespace> <gateway-name>提取 IP)。

4.2 场景二:高级安全拓扑(Service Mesh + Spanner + Workload Identity)

原文档给出了一条完整的进阶部署命令,它同时解决了镜像私有化、关闭外部直连、购物车后端切换、服务账号/授权/网络策略/Sidecar 全量开启、Istio 网关路由与 Workload Identity 注解等问题:

helm upgrade onlineboutique oci://us-docker.pkg.dev/online-boutique-ci/charts/onlineboutique \ --install \ --create-namespace \ --set images.repository=us-docker.pkg.dev/my-project/microservices-demo \ --set frontend.externalService=false \ --set redis.create=false \ --set cartservice.database.type=spanner \ --set cartservice.database.connectionString=projects/my-project/instances/onlineboutique/databases/carts \ --set serviceAccounts.create=true \ --set authorizationPolicies.create=true \ --set networkPolicies.create=true \ --set sidecars.create=true \ --set frontend.virtualService.create=true \ --set 'serviceAccounts.annotations.iam\.gke\.io/gcp-service-account=spanner-db-user@my-project.iam.gserviceaccount.com' \ --set serviceAccounts.annotationsOnlyForCartservice=true \ -n onlineboutique

逐项解读这条命令的意图:

参数作用
--create-namespace+-n onlineboutique自动创建并指定 release 命名空间
images.repository指向你私有项目下的镜像仓库(如 GCR/Artifact Registry 镜像迁移后)
frontend.externalService=false关闭 LoadBalancer 直连,对外流量统一走 Istio Ingress Gateway
redis.create=false不部署内置 Redis(Redis 已不再需要,因为后端切换为 Spanner)
cartservice.database.type=spanner将购物车数据层切换为 Cloud Spanner
cartservice.database.connectionString指定 Spanner 数据库连接串(项目/实例/数据库三级路径)
serviceAccounts.create=true每个服务独立 ServiceAccount,为方法级授权提供身份基础
authorizationPolicies.create=true开启 Istio 方法级授权策略(配合 common.yaml 的 deny-all 形成默认拒绝模型)
networkPolicies.create=true开启细粒度 Kubernetes NetworkPolicy(同样配合 deny-all 基线)
sidecars.create=true开启 Istio Sidecar 资源,收敛每个 Pod 的 egress 白名单
serviceAccounts.annotations.iam\.gke\.io/gcp-service-account=...为 ServiceAccount 注入 Workload Identity 注解(注意键中的点需要用\.转义)
serviceAccounts.annotationsOnlyForCartservice=true注解只落在 cartservice 上,最小权限原则:只有 cartservice 需要以spanner-db-user身份访问外部 Spanner

这个场景同时印证了源码中的几处设计:Spanner 模式仅注入SPANNER_CONNECTION_STRING(见 helm-chart/templates/cartservice.yaml);annotationsOnlyForCartservice控制注解是否只加到 cartservice 的 ServiceAccount(其余服务模板中均以{{- if not .Values.serviceAccounts.annotationsOnlyForCartservice }}守卫);cartservice 的 AuthorizationPolicy 只放行 frontend/checkoutservice 的特定 gRPC 方法。

4.3 与源码的对应关系:为什么cartservice.database.type=spanner会生效

cartservice 的底层实现也支持双后端:仓库中 src/cartservice/src/cartstore/ICartStore.cs 定义了存储抽象,RedisCartStore.cs 与 SpannerCartStore.cs 分别实现两种后端,其中 SpannerCartStore 通过读取SPANNER_CONNECTION_STRING(以及SPANNER_PROJECTSPANNER_INSTANCESPANNER_DATABASE)完成连接初始化。这正是 Helm 模板注入SPANNER_CONNECTION_STRING环境变量后能够无缝切换的底层依据——配置驱动、代码无感知。

五、从源码本地安装 chart(离线 / 调试场景)

如果你希望基于当前仓库的 chart 源码直接部署(例如验证模板改动或离线环境),可以省略 OCI 拉取,直接引用本地目录:

helm upgrade onlineboutique ./helm-chart \ --install \ -n onlineboutique --create-namespace

也可以先用helm template ./helm-chart渲染 YAML 检查输出,再决定是否执行。chart 的发布流程(版本号同步、helm packagehelm push)见 docs/releasing/make-helm-chart.sh。

六、验证与卸载

  • 健康检查:chart 为各服务配置了 Kubernetes 1.24+ 支持的 gRPC 探针(readinessProbe/livenessProbe中的grpc:字段,见 adservice/checkoutservice/cartservice 等模板),例如 cartservice 的 gRPC 探针位于端口 7070,initialDelaySeconds: 15;前端则使用带 Cookie 的 HTTP 探针访问/_healthz(见 helm-chart/templates/frontend.yaml)。
  • 查看 release 状态helm status onlineboutique -n onlineboutique;查看资源:kubectl get pods,svc -n onlineboutique
  • 卸载helm uninstall onlineboutique -n onlineboutique

七、小结与延伸阅读

本文完整覆盖了 Online Boutique Helm chart 的默认安装、全部核心配置参数(镜像、安全加固、可观测性、数据库后端、Istio 路由)与高级安全场景实战,并逐层对应到 helm-chart/values.yaml 与 helm-chart/templates 的模板源码。你可以在此基础上继续探索仓库内与之互补的部署方案:

  • 面向 GitOps 的 kustomize 变体:kustomize/README.md 及 kustomize/components 下的spannermemorystoreservice-mesh-istiogoogle-cloud-operations等组件;
  • 手写清单版本:kubernetes-manifests 与 istio-manifests(含 frontend gateway 与 VirtualService);
  • 底层服务实现:cartservice 的 C# 实现见 src/cartservice,购物车双后端存储类见 src/cartservice/src/cartstore;
  • Terraform 基础设施:terraform/README.md(GKE 集群与 Memorystore 的 IaC 定义)。

原文档还给出了三篇延伸博客主题:借助 Helm chart 简化 Service Mesh 与 GitOps 下的高级安全场景配置、Kubernetes 1.24+ 的 gRPC 健康探针、以及为 Online Boutique 接入 Cloud Spanner。结合本仓库源码阅读这些主题,可以更深入理解 chart 中每个开关背后的设计动机。

【免费下载链接】microservices-demoSample cloud-first application with 10 microservices showcasing Kubernetes, Istio, and gRPC.项目地址: https://gitcode.com/GitHub_Trending/mi/microservices-demo

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

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

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

立即咨询