更新季节菜单

KubernetesBeginner
立即练习

介绍

Juniper Café 准备推出秋季菜单。网站运行正常,但仍显示日常菜单。你将通过 Kubernetes 发布新菜单,保留旧配置,并为柜台团队下载实际菜单。

你应当已经认识 Pod、Deployment、Service、标签和简单的 YAML。集群、应用镜像和网站均已准备就绪,无需编写应用代码或拥有云账户。本实验将介绍完成任务所需的少量 Kustomize 知识,为每份配置生成一个基于内容的名称。

使用 Workspace 执行命令,使用 Café Menu 访问 Juniper,使用 Reference Menu 访问独立的阅览室咖啡馆。所有入口共用一台训练 VM。请保持参考咖啡馆、应用代码、Service、副本数以及提供的发布历史不变。作者估计本实验需要 40 分钟,其中包括阅读和处理普通错误的时间。

准备独立的菜单发布目录

在这一步中,你将了解当前网站与配置的关系,并准备一个发布目录,而不改变正在提供的菜单。

打开 Café Menu,选择 Explore the menu,找到 Maple Latte。它目前的价格是 $4.20,状态为 Not available today。Cold Brew 当前可供应。打开 Oat Latte 的 About this drink,然后使用 Back to the menu 返回。这些都是真实页面,由已准备好的应用提供。

切换到 Reference Menu,选择 Our menu。这里是 Willow Reading Room,一个必须保持正常运行的独立服务。切换到 Workspace。其起始目录为 /home/labex/project/cafe-menu;使用 pwd 确认,该命令会打印当前目录:

pwd

预期输出:

/home/labex/project/cafe-menu

Kubernetes ConfigMap 将配置与应用镜像分开存储。Pod 通过名称引用该 ConfigMap。这个咖啡馆进程只在启动时读取一次挂载的菜单文件。编辑配置不会让已有进程自动重新加载菜单。

准备好的 starter 目录包含三个小文件。使用 ls 列出它们:

ls starter
deployment.json  kustomization.yaml  menu.json

JSON 也可以作为 Kubernetes 清单的有效输入;deployment.json 是准备好的 Deployment 定义。你将保留其中的应用设置,只修改单独存放的菜单数据。

使用 cp -r 创建自己的目录:cp 表示复制,-r 表示包含目录中的内容。目标目录 release 目前尚不存在:

cp -r starter release

如果不小心执行了两次,cp 可能创建嵌套目录 release/starter。所需的三个文件仍应直接放在 release 中;仅使用 rm -r release/starter 删除误生成的嵌套副本。不要删除 release、versions 或 approved。

使用 cat 读取配置,该命令会打印文件内容:

cat release/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: cafe-menu
resources:
  - deployment.json
configMapGenerator:
  - name: cafe-menu
    files:
      - menu.json

resources 包含 Deployment。configMapGenerator 将 menu.json 转换为 ConfigMap 数据。Kustomize 添加一个由内容计算出的后缀,并更新 Deployment,使其引用生成的名称。因此,数据变化可以产生新的 Pod 模板并触发新的滚动更新,同时先前的 ConfigMap 仍然保留。后缀用于标识内容,并不能说明价格是否正确。

编写已获批准的秋季菜单

在这一步中,你将先准备完整的秋季菜单,再向 Kubernetes 应用更改。

留在 Workspace。柜台团队批准的菜单保存在 approved/menu.csv 中。CSV 指逗号分隔值:第一行是列名,之后每行描述一种饮品。price_cents 是以分为单位的整数,因此 450 表示 $4.50。true 和 false 表示该饮品是否可供应。

cat approved/menu.csv
id,name,price_cents,available
espresso,Espresso,250,true
oat-latte,Oat Latte,350,true
cold-brew,Cold Brew,390,false
maple-latte,Maple Latte,450,true

保持 Espresso 和 Oat Latte 不变。Cold Brew 从今日可供应的饮品中退出,Maple Latte 则以 $4.50 的价格开始供应。季节标签必须为 Autumn at Juniper;咖啡馆名称、地址、营业时间、饮品标识和描述均保持不变。

写入下面完整的 JSON。JSON 的属性名使用引号,条目之间用逗号分隔,布尔值使用不带引号的小写形式。Shell 表达式 cat > release/menu.json <<'EOF' 将包围的文本写入该文件。> 替换之前的内容;带引号的 EOF 使文本保持字面值。请一直粘贴到最后的 EOF 行,并让它单独占一行:

cat > release/menu.json <<'EOF'
{
  "name": "Juniper Café",
  "season": "Autumn at Juniper",
  "hours": "Mon–Sat · 08:00–17:00",
  "address": "14 Willow Lane",
  "items": [
    {"id": "espresso", "name": "Espresso", "price_cents": 250, "available": true, "description": "A small, rich cup with a golden crema."},
    {"id": "oat-latte", "name": "Oat Latte", "price_cents": 350, "available": true, "description": "Our espresso with smooth oat milk."},
    {"id": "cold-brew", "name": "Cold Brew", "price_cents": 390, "available": false, "description": "Slow-steeped coffee, served over ice."},
    {"id": "maple-latte", "name": "Maple Latte", "price_cents": 450, "available": true, "description": "Espresso, oat milk, and a little maple sweetness."}
  ]
}
EOF

使用 JSON 前先验证它。python3 -m json.tool 读取 JSON 并打印带缩进的版本,不会修改文件:

python3 -m json.tool release/menu.json

成功的输出应包含全部四种饮品。工具可能将 é 显示为 \u00e9;这是 JSON 转义,并不表示咖啡馆名称发生了变化。缺少逗号或引号会产生带行号和列号的解析错误。重新写入上面的完整代码块即可恢复,然后再次验证。路径错误会产生文件未找到错误;运行 pwd,再使用 cd /home/labex/project/cafe-menu 返回正确目录,然后重试。

网站仍显示日常菜单,因为你只改动了发布源文件。这是预期现象。

发布新的配置版本

在这一步中,你将渲染发布配置、应用它,并等待两个咖啡馆副本都使用新配置。

留在 Workspace。kubectl kustomize 渲染目录中的配置,但不会应用它。检查生成的 ConfigMap 名称以及 Deployment 中与之匹配的引用:

kubectl kustomize release

输出中包含形如 cafe-menu-... 的名称,Deployment 中名为 menu 的 volumes 条目下也会出现同一名称。具体后缀取决于数据。这是一个与日常菜单配置不同的配置对象。

使用 kubectl apply -k 应用该目录。-k 选项要求 kubectl 渲染 Kustomize 目录,而不是像 -f 那样读取一份清单:

kubectl apply -k release

预期输出包括:

configmap/cafe-menu-... created
deployment.apps/cafe configured

仅创建 ConfigMap 并不能证明运行中的应用已经改变。rollout status 等待 Deployment 控制器替换 Pod。-n cafe-menu 选择本课的命名空间;--timeout=120s 限制等待时间:

kubectl rollout status deployment/cafe -n cafe-menu --timeout=120s
deployment "cafe" successfully rolled out

如果等待超时,请保留现有现场,使用以下命令检查。镜像或容器错误会出现在 Pod 状态和事件中;不要重新运行 setup 或删除命名空间:

kubectl get pods -n cafe-menu
kubectl describe deployment cafe -n cafe-menu

正常滚动更新后,检查当前的 Deployment 及其 ReplicaSet。一个 ReplicaSet 维护一种特定的 Pod 模板;Deployment 将旧 ReplicaSet 保留为滚动更新历史:

kubectl get replicasets -n cafe-menu -l app=cafe

按名称检查 Deployment 本身:

kubectl get deployment cafe -n cafe-menu

它应显示 2/2 个就绪副本。多个配置对象仍然存在;应用新发布并没有覆盖旧菜单。列出它们:

kubectl get configmaps -n cafe-menu

不要删除这些旧配置。如果以后恢复旧版本,旧 ReplicaSet 仍需要它所引用的那个确切配置名称。

检查网站并交付菜单

在这一步中,你将验证实际顾客体验,并保存柜台团队将要使用的菜单。

切换到 Café Menu,选择 Our menu;如果页面已经打开,请刷新。Maple Latte 必须显示 Available today,价格为 $4.50。Cold Brew 必须显示 Not available today。打开 Maple Latte 的详情页,使用 Back to the menu 返回,然后使用 Visit us 确认地址和营业时间仍能正常查看。

已获批准的秋季菜单

留意供应状态徽章和价格:Cold Brew 不可供应,Maple Latte 可供应,价格为 $4.50。

使用 Download menu 下载实际的完整 CSV。打开它,将全部四种饮品与第 2 步中的批准表格比较。下载文件中也包含不可供应的饮品,其值为 false,这样员工就能将其与意外遗漏的饮品区分开。

切换到 Reference Menu,确认 Willow Reading Room 的日常菜单仍能正常使用。然后返回 Workspace。

你也可以在工作区保存 Juniper 的真实下载文件。curl 请求本地浏览器入口,该入口会转发到实际的 Kubernetes Service。--fail 报告 HTTP 错误;--silent 隐藏进度条;--show-error 保留错误信息;-o 选择输出文件名:

curl --fail --silent --show-error http://127.0.0.1:8081/menu.csv -o menu-handover.csv

使用 diff -u 将收到的文件与批准文件比较。-u 选项会在存在差异时显示相邻行:

diff -u approved/menu.csv menu-handover.csv

没有输出表示文件一致。出现差异是有用的证据:返回菜单源文件和线上滚动更新状态,修正原因,重新下载,再次比较。不要编辑收到的 CSV 来掩盖网站上的错误。

现在,你拥有可用的菜单、供员工使用的实际下载文件,以及能够重现运行中配置的发布目录。保留当前现场中的 versions 和旧 ConfigMap,作为恢复材料。下一课会准备自己的独立环境。

总结

你准备了完整的菜单发布配置,生成了以内容命名的 ConfigMap,并跟踪 Deployment 的滚动更新,直到两个应用副本都完成更新。你检查了真实页面和下载文件,保留了参考咖啡馆和早期配置,并交付了供员工使用的实际 CSV。

下一个实验将在独立环境中开始。它将复用这些方法,恢复一份应用运行正常、但价格有误的菜单。