Skip to main content

Command Palette

Search for a command to run...

在 Knative 上部署 12 要素应用程序

Updated
4 min read

原文:Deploying 12 Factor Apps to Knative

作者:Dr Nic Williams

我尝试按照本文内容在 Azure 上使用 ACS-Engine 部署的 Kubernetes 上进行了测试,版本部分的案例得到了相反结果,不过还是按照原文发了出来,作为一个获取感性认识的入门还是不错的。

Google Next18 活动中,Google 宣称将会把 GKE 上的无服务器插件以 Knative 的名称进行开源。当时它被描述为无服务器平台的构建块,由此推断,Knative 可能需要 Google、Pivotal 或者 RedHat 的协助才能使用。这可能是开源的古怪时机。从我最初的摸索来看,Knative 能工作;当我把 Heroku/Cloud Foundry buildpacks 加入进来之后,整个系统变得越来越像 Heroku/Cloud Foundry,相对于原始 Kubernetes,我更加了解和喜爱这一系统。

本文中我们会将 Knative 安装到你自己的 Kubernetes 集群中(knctl install),然后用 Knative 做些有趣的事情(knctl deploy)。

Knative 能够为在 Kubernetes 集群上运行无状态应用的运维人员带来很多惊喜。对我来说,最引人入胜的一点就是伸缩性:在高负载时候进行扩容,没人喜欢你的应用了,就会一直缩容到 0。

下载和安装 Knative 客户端工具 knctl,然后就可以在你的 Kubernetes 上部署 Knative,然后发布你的应用了。

在 MacOS 中,可以利用我们的 Homebrew tap 进行安装:

brew install starkandwayne/kubernetes/knctl

这里我假设你再使用 Minikube。在 Minikube 中,可以使用 Node Port 代替 Load balancer:

minikube start --memory=8192 --cpus=3 \
  --kubernetes-version=v1.11.3 \
  --vm-driver=hyperkit \
  --bootstrapper=kubeadm

knctl install --node-ports --exclude-monitoring

可以参考 Knative 文档来获取在其它类型 Kubernetes 集群上进行部署的要点。

knctl install 命令可能要花上几分钟,甚至是十分钟或者更多。这个过程中需要下载大概一打镜像。不管是互联网带宽还是镜像尺寸都可能有变化,所以坐下放松一会,或者出去走走也好。

如果 knctl install 失败了,可能是你的 Internet 比较慢,Docker 镜像在命令超时之前还没能完成下载。运行 kubectl get pods --all-namespaces 直到所有 Pod 都在运行,然后再次运行 knctl install 命令继续完成安装过程。

现在你的 Kubernetes 就是无服务器架构了,不错吧。

可以运行 kubectl get pods --all-namespaces 看看原始的 Knative 的 Pod 们。

$ kubectl get pods --all-namespaces
NAMESPACE         NAME                                        READY   STATUS      RESTARTS   AGE
istio-system      istio-citadel-7d8f9748c5-zgm9x              1/1     Running     0          21m
istio-system      istio-cleanup-secrets-j4pkx                 0/1     Completed   0          21m
istio-system      istio-egressgateway-676c8546c5-dnwsd        1/1     Running     0          21m
istio-system      istio-galley-5669f7c9b-g774b                1/1     Running     0          21m
istio-system      istio-ingressgateway-5475685bbb-q5f2x       1/1     Running     0          21m
istio-system      istio-pilot-5795d6d695-9klrz                2/2     Running     0          21m
istio-system      istio-policy-7f945bf487-2wh88               2/2     Running     0          21m
istio-system      istio-sidecar-injector-d96cd9459-7knkm      1/1     Running     0          21m
istio-system      istio-statsd-prom-bridge-549d687fd9-lcmb7   1/1     Running     0          21m
istio-system      istio-telemetry-6c587bdbc4-t4jql            2/2     Running     0          21m
istio-system      knative-ingressgateway-7f4477dd99-n9wz2     1/1     Running     0          4m
knative-build     build-controller-7dcc4b7544-rkgwb           1/1     Running     0          4m
knative-build     build-webhook-fb6484576-sr4fk               1/1     Running     0          4m
knative-serving   activator-77d46b585d-b6g8n                  2/2     Running     0          4m
knative-serving   controller-85768cfd45-t8ktc                 1/1     Running     0          4m
knative-serving   webhook-56dd548f8-hjw44                     1/1     Running     0          4m
...

部署预构建的应用

接下来我们试试用一个现有的 Docker 镜像来作为自动伸缩的无状态应用运行到 Knative 上,在当前 Kubernetes 命令空间中:

kubectl create ns helloworld

knctl deploy \
      --namespace helloworld \
      --service hello \
      --image gcr.io/knative-samples/helloworld-go \
      --env TARGET=Rev1

命令执行后会输出一些信息,表明 hello 服务已经创建,它的第一个版本 hello-00001 已经创建,并且被标记为 latestprevious(第一个版本)。

Name  hello

Waiting for new revision to be created...

Tagging new revision 'hello-00001' as 'latest'

Tagging new revision 'hello-00001' as 'previous'

Succeeded

我们可以用一个 curl 请求,发送到 Knative 的路由层,来调用我们的 hello 服务:

$ knctl curl --namespace helloworld --service hello
Running: curl '-H' 'Host: hello.helloworld.example.com' 'http://192.168.64.8:32380'

Hello World: Rev1!

Succeeded

如果没有马上显示 Hello World: Rev1!,可能是因为你的系统还在下载应用镜像、可以稍后重试。

我使用的是 Minikube 中的 NodePort Ingress,这意味着我不能设置漂亮的 DNS 路由。以后我会讨论一下公共负载均衡、DNS、Knative 路由以及 https://github.com/cppforlife/kwt

knctl deploy 之后,我们的 Kubernetes 用单 Pod 的形式运行这一服务:

$ kubectl get pods --namespace helloworld
NAME                                      READY   STATUS    RESTARTS   AGE
hello-00001-deployment-5864685cbc-v8r7n   3/3     Running   0          15s

Knative 中,服务的版本是一个重要特性。我们可以看到我们的唯一版本的服务正在处理 100% 的流量:

$ knctl revisions list --namespace helloworld --service hello
Revisions for service 'hello'

Name         Tags      Allocated Traffic %  Serving State  Annotations  Age
hello-00001  latest    100%                 Active         -            3m
             previous

1 revisions

下一步我们使用 knctl deploy 创建一个新的版本,然后把所有流量分配到新版本:

$ knctl deploy \
      --namespace helloworld \
      --service hello \
      --image gcr.io/knative-samples/helloworld-go \
      --env TARGET=Rev2

Name  hello

Waiting for new revision (after revision 'hello-00001') to be created...

Tagging new revision 'hello-00002' as 'latest'

Tagging older revision 'hello-00001' as 'previous'

Succeeded

现在请求被发送到了我们的新版本:

$ knctl revisions list --namespace helloworld --service hello
Revisions for service 'hello'

Name         Tags      Allocated Traffic %  Serving State  Annotations  Age
hello-00002  latest    100%                 Active         -            1m
hello-00001  previous  0%                   Active         -            10m

$ knctl curl --namespace helloworld --service hello
Running: curl '-H' 'Host: hello.helloworld.example.com' 'http://192.168.64.8:32380'

Hello World: Rev2!

部署第二个版本之后,起初两个版本的 Pod 都会持续运行:

$ kubectl get pods --namespace helloworld
NAME                                      READY   STATUS    RESTARTS   AGE
hello-00001-deployment-5864685cbc-v8r7n   3/3     Running   0          1m
hello-00002-deployment-7874bf89b8-4b4k5   3/3     Running   0          29s

我们会看到 Knative 自动将没有路由指向的版本缩容到 0。

路由

下图展示了路由到服务某版本的过程中所涉及到的 Knative Serving 模块:

版本是代码、依赖和配置的的只读快照。没有被路由引用的版本会被放弃,其中的 Kubernetes 资源会被删除。

我们可以看到当前的路由:

$ knctl routes list --namespace helloworld
Routes in namespace 'helloworld'

Name   Traffic         All Traffic Assigned  Ready  Domain                        Age
hello  100% -> hello:  true                  true   hello.helloworld.example.com  2h

缩容至 0

如果离开五分钟再回来,你会发现 hello-00002 Pod 正在被终结或者已经不见了:

$ kubectl get pods --namespace helloworld
NAME                                      READY   STATUS        RESTARTS   AGE
hello-00001-deployment-5864685cbc-v8r7n   3/3     Running       0          6m
hello-00002-deployment-7874bf89b8-4b4k5   2/3     Terminating   0          5m

下一次 knctl curl,Knative 会动态的启动一个 Pod 来满足这一请求。

$ knctl curl --namespace helloworld --service hello
$ kubectl get pods --namespace helloworld
NAME                                      READY   STATUS    RESTARTS   AGE
hello-00001-deployment-5864685cbc-v8r7n   3/3     Running   0          8m
hello-00002-deployment-7874bf89b8-kfbm2   3/3     Running   0          10s

我还不太清楚为什么 hello-00001-deployment-... Pod 没有被缩容和终结。

未完待续

后续文章中将会尝试:

  • Knative Build 组件:使用 Dockerfile 或者 Cloud Foundry buildpack 自动从定制代码构建容器镜像(代码可以保存本地或者 Git 仓库之中)。

  • 为 Kubernetes 的负载均衡设置 DNS,从而为 Knative 路由和服务提供公共 URL。

  • 在不同版本之间进行流量分割(例如 10% 到最新版本,90% 到前一版本;然后将 100% 分配给新版本,老版本流量降低到 0%)。

  • Knative Eventing:在应用中进行 CloudEvents的绑定和分发。让你的服务更加“无服务器”。

社区

Knative 核心团队有自己的 Knative Slack,可以在 https://slack.knative.dev 申请加入。

knative-dev Group 中包含了总结和提议。

鸣谢

感谢 Google 的 Mark Chmarny,在 2018 Spring One 上首先回应了我的问题。

感谢 Pivotal 的 Dmitriy Kalinin 花时间帮助我将 Knative 运行起来,并给我展示了他的 knctl Knative CLI,以及 kwt Kubernetes Workstation Tools。相对于 YAML + kubectl 组合来说,一个好用的客户端工具更能够帮助 Knative 走向实用。

More from this blog

龙虾恐慌:AIOps 又要改名了?

ChatGPT 开始,把 AI 拉近到普罗大众的面前,让无数人感受到 AI 的亲民魅力。而龙虾,则把大模型驱动的自动化能力,突然间变得水灵灵、活泼泼地走进千家万户。它不只是“风口上的猪”,而是风口本身。热度高到让 Mac mini 一度断货,不知道这在不在库克的预料之内。 每代人都有每代人的鸡蛋,春节期间,我就领了我的鸡蛋。翻出古老的 MacBook Air M1,充值各种大模型。当然了,这个工具

Mar 9, 20261 min read

再见 2025

我猜不少人以为这个号废了吧?并没有,只是今年变化有点大,一直有种抄起键盘,无从说起的感觉,所以一直偷懒到今天,2025 的最后一天。 今年是我的第四个本命年,去年末一期播客里,大内说本命年不是灾年,是变化年,有危也有机。可是讲真啊,只看到危,没看到机。 各种因缘际会,从鹅厂跳槽到前东家,已经接近四年,第一个合同期已经进入尾声。除了前两年还在云原生领域嗷嗷叫,后两年基本都是些鸡零狗碎的东西了,用老东家的术语说是——偏离主航道,可谓是前景暗淡了。 一旦确定要滚蛋,反倒心思轻松起来,每天骑着我的小红车...

Jan 5, 20261 min read

辅助编程?dora 说:我知道你很急可是请你别急

从 OpenGPT 把大模型的火烧旺了之后,这三年来,相信很多组织或摩拳擦掌、或躬身入局,希望借助聪明能干的大模型,或想偿还技术宅,或想降本增效,或想弯道超车。一时间,沉寂许久的 AIxx 又活过来了,LLM Ops、Vibe Coding、中医大模型、GPT 算命等等,全都老树发新芽,焕发了勃勃生机。那么视角拉回从业者最关注的饭碗相关的领域之一——AI 辅助开发,产生了什么触动,应该如何拥抱呢? DORA 的年度报告中给出了很有意思的结论——强者恒强。 执行摘要部分总结了几个有趣的点: 问题...

Oct 6, 20251 min read

[译]dora:ai 辅助软件开发状态报告

执行摘要 在 2025 年,科技领导者面临的核心问题已不再是“是否要采用 AI”,而是“如何实现其价值”。 DORA 的研究基于超过 100 小时的定性访谈和来自全球近 5,000 名技术专业人士的问卷调查。研究揭示了一个关键事实:AI 在软件开发中的主要角色是“放大器”。它会放大高效能组织的优势,也会凸显组织的缺陷。 关键结论:AI 是放大器 AI 投资的最大回报并非来自工具本身,而是来自组织底层系统的战略性建设: 高质量的内部平台 清晰的工作流 团队的协同能力 缺少这些基础,AI ...

Oct 2, 202514 min read

僭越了,有人在用 Rust 写 Kubernetes

一个新语言问世,最爱做的事情之一,就是重写存量软件了。 云原生喝酒 SIG 重点扶持项目——rk8s(https://github.com/rk8s-dev/rk8s) 也可以归在这个范畴里,只不过这个项目重写的东西比较大,是 Kubernetes。 从 2025 年 1 月第一个 Commit 开始,到现在有了 200 多次 Commit,十几万行代码。当然距离 Kubernetes 的几百万行代码还差得远——老马就是喜欢整这种大无畏项目。 另外该项目也是国内第一个脱离 Cargo 转向使用 ...

Sep 27, 20253 min read

【伪】架构师

342 posts