在 Kubernetes 中运行无服务器函数时，实现更快的启动速度和更小的内存占用。由于运行上千个应用程序 容器荚 Pod 所耗费的资源多，令它实现较少工作节点和资源占用所需成本也较高，所以在使用 Kubernetes 时，快速启动和较少的内存占用是至关重要的。在 Kubernetes 平台运行容器化微服务时，内存占用是比吞吐量更重要的考量因素，这是因为：由于需要持续运行，所以耗费资源更多（不同于 CPU 占用）微服务令开销成本成倍增加一个单体应用程序变为若干个微服务的情况（例如 20 个微服务占用的存储空间约有 20GB）这些情况极大影响了无服务器函数的发展和 Java 部署模型。到目前为止，许多企业开发人员选择 Go、Python 或 Node.js 这些替代方案来解决性能瓶颈，直到出现了 Quarkus 这种基于 kubernetes 的原生 Java 堆栈，才有所改观。本文介绍如何在使用了 Quarkus 的 kubernetes 平台上进行性能优化，以便运行无服务器函数。容器优先的设计理念由于 Java 生态系统中传统的框架都要进行框架的初始化，包括配置文件的处理、classpath 的扫描、类加载、注解的处理以及构建元模型，这些过程都是必不可少的，所以它们都比较耗费资源。如果使用了几种不同的框架，所耗费的资源也是成倍增加。Quarkus 通过“ 左移 shifting left ”，把所有的资源开销大的操作都转移到构建阶段，解决了这些 Java 性能问题。在构建阶段进行代码和框架分析、字节码转换和动态元模型生成，而且只有一次，结果是：运行时可执行文件经过高度优化，启动非常快，不需要经过那些传统的启动过程，全过程只在构建阶段执行一次。更重要的是：Quarkus 支持构建原生可执行文件，它具有良好性能，包括快速启动和极小的 驻留集大小 resident set size （RSS）内存占用，跟传统的云原生 Java 栈相比，具备即时扩展的能力和高密度的内存利用。这里有个例子，展示如何使用 Quarkus 将一个 Java 无服务器 项目构建为本地可执行文件。1、使用 Quarkus 创建无服务器 Maven 项目以下命令生成一个 Quarkus 项目，（例如 quarkus-serverless-native）以此创建一个简单的函数：$ mvn io.quarkus:quarkus-maven-plugin:1.13.4.Final:create \ -DprojectGroupId=org.acme \ -DprojectArtifactId=quarkus-serverless-native \ -DclassName="org.acme.getting.started.GreetingResource" 2、构建一个本地可执行文件你需要使用 GraalVM 为 Java 程序构建一个本地可执行文件。你可以选择 GraalVM 的任何发行版，例如 Oracle GraalVM Community Edition (CE) 或 Mandrel（Oracle GraalVM CE 的下游发行版）。Mandrel 是为支持 OpenJDK 11 上的 Quarkus-native 可执行文件的构建而设计的。打开 pom.xml，你将发现其中的 native 设置。你将使用它来构建本地可执行文件。<profiles> <profile> <id>native</id> <properties> <quarkus.package.type>native</quarkus.package.type> </properties> </profile> </profiles> 注意： 你可以在本地安装 GraalVM 或 Mandrel 发行版。你也可以下载 Mandrel 容器映像来构建它（像我那样），因此你还需要在本地运行一个容器引擎（例如 Docker）。假设你已经打开了容器运行时，此时需要运行一下 Maven 命令：使用 Docker 作为容器引擎：$ ./mvnw package -Pnative \ -Dquarkus.native.container-build=true \ -Dquarkus.native.container-runtime=docker 使用 Podman 作为容器引擎：$ ./mvnw package -Pnative \ -Dquarkus.native.container-build=true \ -Dquarkus.native.container-runtime=podman 输出信息结尾应当是 BUILD SUCCESS。不借助 JVM 直接运行本地可执行文件：$ target/quarkus-serverless-native-1.0.0-SNAPSHOT-runner 输出信息类似于：__ ____ __ _____ ___ __ ____ ______ --/ __ \/ / / / _ | / _ \/ //_/ / / / __/ -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \ --\___\_\____/_/ |_/_/|_/_/|_|\____/___/ INFO [io.quarkus] (main) quarkus-serverless-native 1.0.0-SNAPSHOT native (powered by Quarkus xx.xx.xx.) Started in 0.019s. Listening on: http://0.0.0.0:8080 INFO [io.quarkus] (main) Profile prod activated. INFO [io.quarkus] (main) Installed features: [cdi, kubernetes, resteasy] 简直是超音速！启动只花了 19 毫秒。你的运行时间可能稍有不同。使用 Linux 的 ps 工具检测一下，结果内存占用还是很低。检测的方法是：在应用程序运行期间，另外打开一个终端，运行如下命令：$ ps -o pid,rss,command -p $(pgrep -f runner) 输出结果类似于： PID RSS COMMAND 10246 11360 target/quarkus-serverless-native-1.0.0-SNAPSHOT-runner 该进程只占 11MB 内存。非常小！注意: 各种应用程序（包括 Quarkus）的驻留集大小和内存占用，都因运行环境而异，并随着应用程序载入而上升。你也可以使用 REST API 访问这个函数。输出结果应该是 Hello RESTEasy:$ curl localhost:8080/hello Hello RESTEasy 3、把函数部署到 Knative 服务如果你还没有创建命名空间，现在就在 OKD（OpenShift Kubernetes 发行版）创建一个命名空间（例如 quarkus-serverless-native），进而把这个本地可执行文件部署为无服务器函数。然后添加 quarkus-openshift 扩展：$ ./mvnw -q quarkus:add-extension -Dextensions="openshift" 向 src/main/resources/application.properties 文件中添加以下内容，配置 Knative 和 Kubernetes 的相关资源：quarkus.container-image.group=quarkus-serverless-native quarkus.container-image.registry=image-registry.openshift-image-registry.svc:5000 quarkus.native.container-build=true quarkus.kubernetes-client.trust-certs=true quarkus.kubernetes.deployment-target=knative quarkus.kubernetes.deploy=true quarkus.openshift.build-strategy=docker 构建本地可执行文件，并把它直接部署到 OKD 集群：$ ./mvnw clean package -Pnative 注意： 提前使用 oc login 命令，确保登录的是正确的项目（例如 quarkus-serverless-native）。输出信息结尾应当是 BUILD SUCCESS。完成一个本地二进制文件的构建并部署为 Knative 服务需要花费几分钟。成功创建服务后，使用 kubectl 或 oc 命令工具，可以查看 Knative 服务和版本信息：$ kubectl get ksvc NAME URL [...] quarkus-serverless-native http://quarkus-serverless-native-[...].SUBDOMAIN True $ kubectl get rev NAME CONFIG NAME K8S SERVICE NAME GENERATION READY REASON quarkus-serverless-native-00001 quarkus-serverless-native quarkus-serverless-native-00001 1 True 4、访问本地可执行函数运行 kubectl 命令，搜索无服务器函数的节点：$ kubectl get rt/quarkus-serverless-native 输出信息类似于：NAME URL READY REASON quarkus-serverless-native http://quarkus-serverless-restapi-quarkus-serverless-native.SUBDOMAIN True 用 curl 命令访问上述信息中的 URL 字段：$ curl http://quarkus-serverless-restapi-quarkus-serverless-native.SUBDOMAIN/hello 过了不超过一秒钟，你也会得到跟本地操作一样的结果：Hello RESTEasy 当你在 OKD 群集中访问 Quarkus 运行中的节点的日志，你会发现本地可执行文件正在以 Knative 服务的形式运行。下一步呢？你可以借助 GraalVM 发行版优化 Java 无服务器函数，从而在 Knative 中使用 Kubernetes 将它们部署为无服务器函数。Quarkus 支持在普通的微服务中使用简易配置进行性能优化。本系列的下一篇文章将指导你在不更改代码的情况下跨多个无服务器平台实现可移植函数。(Daniel Oh, CC BY-SA 4.0)via: https://opensource.com/article/21/6/java-serverless-functions-kubernetes作者：Daniel Oh 选题：lujun9972 译者：cool-summer-021 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
Quarkus 令你可以使用类似 Java 的技术开发无服务器的工作负载。对 无服务器 Java 的研究始于函数 —— 就是按需求运行的一小段代码。这一阶段并没有持续很长时间。虽然在 1.0 阶段，基于虚拟机架构的函数使这种范式变得很流行，但它仍然有局限性，例如执行时间、协议和糟糕的本地开发体验，都不太理想，如下图所示。开发者随后意识到，可以把同样的无服务器特性应用于微服务和 Linux 容器，带来的好处也是一样的。由此进入 1.5 阶段，在这个阶段，一些无服务器容器完全抽象化了 Kubernetes，通过 Knative 或其它位于它之上的抽象层来提供无服务器的体验。在 2.0 阶段，无服务器开始处理更复杂的编排和集成模式，并结合某些层级的状态管理。更重要的是，开发者关注的是能否在旧的系统中使用熟悉的 Java 应用程序运行时来组合运行无服务器和非无服务器的工作负载。Java 开发者开始进行无服务器函数开发之前，第一步是要选择一种新的云原生 Java 框架，从而能够以快于传统单体应用程序的速度和较小的内存占用运行 Java 函数。这在各种基础设施环境中，包括物理服务器、虚拟机、多云或混合云环境中的容器，都是适用的。开发者也有可能固执地选择 Spring 框架中的 Spring 云函数 来进行命令式和反应式函数的开发。Spring 也支持将 Java 函数部署到可安装的无服务器平台，比如 Kubeless、Apache OpenWhisk、Fission 和 Project Riff。然而，人们担心 Spring 的启动慢、响应时间长以及内存占用大的问题。在诸如 Kubernetes 这种可扩展的容器环境中运行 Java 函数，这些问题可能会更严重。Quarkus 是一个新推出的开源云原生 Java 框架，它有助于解决这些问题。它的作用是设计无服务器应用程序，以及编写运行于云基础设施（例如 Kubernetes）的云原生微服务。Quarkus 重新审视了 Java，它使用了封闭的方法构建和运行 Java 程序。它把 Java 转变为一种可与 Go 相媲美的运行时。Quarkus 也包含 100 多种扩展功能，集成了企业级能力，例如数据库访问、无服务器集成、消息、安全、可观察性和业务自动化。这里有一个简单例子，展现如何使用 Quarkus 创建一个 Java 无服务器项目的框架。1、基于 Maven 创建一个 Quarkus 无服务器项目安装一个本地 Kubernetes 集群，开发者有多种选择，包括 Minikube 和 OKD。因为使用 OKD 在 Knative 和 DevOps 工具上安装无服务器相关功能较方便，本文使用 OKD 安装集群。这些关于 OKD 安装 和 Knative 操作员安装 的相关指南中提供了更多的设置资料。下面的命令创建了一个 Quarkus 项目（例如 quarkus-serverless-restapi），对外暴露一个简单的 REST API，并下载 quarkus-openshift 扩展，用于 Knative 服务的部署：$ mvn io.quarkus:quarkus-maven-plugin:1.13.4.Final:create \ -DprojectGroupId=org.acme \ -DprojectArtifactId=quarkus-serverless-restapi \ -Dextensions="openshift" \ -DclassName="org.acme.getting.started.GreetingResource" 2、在本地运行无服务器功能使用 Quarkus 开发模式运行程序，检查 REST API 是否有效，稍稍调整一下代码：$ ./mvnw quarkus:dev 输出如下内容：__ ____ __ _____ ___ __ ____ ______ --/ __ \/ / / / _ | / _ \/ //_/ / / / __/ -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \ --\___\_\____/_/ |_/_/|_/_/|_|\____/___/ INFO [io.quarkus] (Quarkus Main Thread) quarkus-serverless-restapi 1.0.0-SNAPSHOT on JVM (powered by Quarkus xx.xx.xx.) started in 2.386s. Listening on: http://localhost:8080 INFO [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated. INFO [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, kubernetes, resteasy] 注意: 保持 Quarkus 应用程序运行，需要使用 热部署 Live Coding 。这样，当代码修改后，你就不必重新构建、重新部署以及重启运行时。现在，你可以使用一个 curl 命令快速访问 REST API。输出结果应当是 Hello RESTEasy:$ curl localhost:8080/hello Hello RESTEasy 在 GreetingResource.java 中修改返回值：public String hello() { return "Quarkus Function on Kubernetes"; } 再次访问 REST API，输出信息也会相应更新：$ curl localhost:8080/hello Quarkus Function on Kubernetes 普通的微服务跟无服务器函数之间的差别并不大。使用 Quarkus 的好处在于：开发者可以使用任何微服务，将 Kubernetes 部署为无服务器函数。3、在 Knative 服务中部署相关的函数如果你还没有创建命名空间，就在你的 OKD 集群上 创建命名空间（例如 quarkus-serverless-restapi），用来部署 Java 无服务器函数。Quarkus 令开发者可以通过在 src/main/resources/application.properties 中添加以下变量，创建 Knative 和 Kubernetes 资源：quarkus.container-image.group=quarkus-serverless-restapi <1> quarkus.container-image.registry=image-registry.openshift-image-registry.svc:5000 <2> quarkus.kubernetes-client.trust-certs=true <3> quarkus.kubernetes.deployment-target=knative <4> quarkus.kubernetes.deploy=true <5> quarkus.openshift.build-strategy=docker <6> 说明: 在你部署无服务器应用程序的位置定义项目名 使用容器注册中心 在这个简单例子中，使用自签名证书，以便通过相关信任机制 允许创建 Knative 资源 指示在构建容器映像之后将扩展部署到 OpenShift 设置 Docker 构建策略执行以下命令，构建应用程序，并直接部署到 OKD 集群：$ ./mvnw clean package -DskipTests 注意: 应该提前使用 oc login 命令，确保登录到正确的项目（例如quarkus-serverless-restapi）。输出结果应该以 BUILD SUCCESS 结束。在对于 Knative 服务执行的 oc 命令中，加上标签:$ oc label rev/quarkus-serverless-restapi-00001 app.openshift.io/runtime=quarkus --overwrite 然后访问 OKD 网页控制台，就能进入 开发人员透视图中的拓扑视图。你可能会看到你的 容器荚 Pod （无服务器函数）已经缩小为零（白线圈）。4、在 Kubernetes 环境下测试函数运行如下 oc 命令，搜索含有无服务器函数的路由：$ oc get rt/quarkus-serverless-restapi [...] NAME URL READY REASON quarkus-serverless[...] http://quarkus[...].SUBDOMAIN True 使用 curl 命令访问搜索到的路由：$ curl http://quarkus-serverless-restapi-quarkus-serverless-restapi.SUBDOMAIN/hello 过几秒钟，你可以得到跟在本地相同的结果：Quarkus Function on Kubernetes 当你回到 OKD 集群内的拓扑图，Knative 服务会自动扩展。由于 Knative 服务的默认设置，其 pod 在 30 秒后会再次下降至零。下一步呢？无服务器不断地在演变，始于运行于虚拟机的函数，到后来的无服务器容器，并与企业原有系统集成。在此过程中，企业开发者借助 Quarkus，仍然可以使用自己熟悉的技术（比如 Java）创建一个项目，然后构建并部署到 Kubernetes。本系列的下一篇文章将指导你优化 Kubernetes 中的 Java 无服务器函数，从而令程序启动更快，内存占用更小。文内图像来自：Daniel Oh, CC BY-SA 4.0via: https://opensource.com/article/21/6/java-serverless-functions作者：Daniel Oh 选题：lkxed 译者：cool-summer-021 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
无服务器计算将服务器从规划中移除，使企业能够专注于应用功能。那么，企业是不是都应该选择无服务器计算呢？让我们来探究一下吧！直至不久之前，几乎每个产品经理都会将他/她的工程资源，分成两个独立的团队 —— 开发团队和运维团队。开发团队通常参与编码、测试和构建应用功能，而运维团队负责应用程序的交付、部署和运行维护。当开发团队构建电商应用时，运维团队会搭建好服务器来托管该应用。搭建服务器涉及到许多方面，其中包括：选择合适的硬件和操作系统应用所需的补丁集搭建所需服务器环境，如 JDK、Python、Tomcat、NodeJS 等部署、配置和提供实际的应用打开并固定合适的端口搭建所需的数据库引擎……这个名单还在继续。除此之外，管理人员还对容量规划感到头疼。毕竟，任何重要应用都应始终保持 100% 可用、可靠且可扩展。这需要对硬件进行最佳投资。众所周知，在一些关键时期，硬件短缺会导致业务损失，而硬件冗余又会损害利润。因此，无论应用是针对本地数据中心，还是针对云基础架构，容量规划都是至关重要的。到目前为止，很明显，企业不仅在功能构建上投入了大量的精力，还在功能交付上也花费了大量的时间。 无服务器计算 Serverless computing 旨在提供一种无缝的方式来交付功能，而无需担心服务器的设置和维护。换句话说，无服务器计算平台提供了一个“ 即用型 ready-to-use ”环境，企业可以尽快将应用程序构建和部署为一些较小的功能。这就是为什么这种方法被称为“ 功能即服务 Function as a Service ”（FaaS）。请记住，无服务器计算中仍然存在服务器，但它由 AWS、微软和谷歌等 FaaS 供应商负责。例如，AWS 以 “Lambda 函数”的形式提供了一个无服务器计算环境。开发人员可以选择将应用程序构建为一组 Lambda 函数，这些函数可以用 NodeJS、Java、Python 和其他一些语言编写。AWS 提供了一个现成的环境来部署这些函数。它还提供了即用​​型数据库服务器、文件服务器、应用程序网关和身份验证服务器等。同样，微软 Azure 也提供了一个环境，它可以用 C# 等语言构建和部署 Azure 函数。为什么选择无服务器？有两个主要因素推动了无服务器计算的普及。1、即用型环境显然，这是无服务器计算的最大卖点。企业无需提前采购/预订硬件或实例，也无需操心许可证，以及设置和配置服务器。他们不需要为扩大和缩小规模而烦恼。所有这些都由 FaaS 供应商负责。2、最优成本由于 FaaS 供应商总是根据环境的利用率向客户收费（按使用付费模式），因此企业无需担心前期成本和资源浪费。例如，AWS 根据 Lambda 函数接收的请求数量、在数据表上运行的查询数量等指标来向客户端收费。无服务器计算的挑战与任何其他方法一样，无服务器计算也不是每个人都可以盲目遵循的完美方法。它本身也有一系列限制。以下是其中的几个。1、供应商锁定当使用无服务器计算时，第一个也是最重要的问题就是，Lambda 或 Azure 等函数将使用供应商提供的 API 来编写。例如，使用 AWS Lambda API 编写的函数无法部署到 Google Cloud 中，反之亦然。因此，无服务器计算迫使企业在许多年内，只能使用同一家供应商。并且，应用的成功或失败不仅取决于它的功能，还取决于供应商在性能等方面的能力。2、编程语言没有哪家无服务器计算平台支持所有的编程语言。此外，对于它支持的编程语言，它也可能不支持其所有版本。这样一来，应用开发团队只能选择供应商提供的语言。就团队的能力而言，这可能是非常关键的。3、最优成本，真的吗？其实也不一定，这一切都取决于资源的使用情况。如果你的应用正在承受巨大的负载，例如每秒数百万个请求，那么你所支付的费用可能会过高。在这样的规模下，在本地或云端拥有自己的服务器可能会更便宜。这并不意味着具有 Web 规模的应用不适合用无服务器计算。归根结底，它还是取决于你的平台的构建方式，以及你与供应商签署的协议。4、生态系统没有哪个应用是为了一个孤立的环境而编写的。它总是需要其他组件，如数据存储、数据库、安全引擎、网关、消息服务器、队列、缓存等。每个平台都提供自己的一组此类工具。例如，AWS 提供了 Dynamo DB 作为其 NoSQL 解决方案之一。显然，其他供应商也提供了自己的 NoSQL 解决方案。因此，团队又会被迫地基于所选平台来构建应用程序。尽管大多数商业 FaaS 供应商都为特定需求提供了多个组件，但并非每个组件都可能是同类型中最佳的。为什么不考虑容器呢？在过去十年中，我们中的许多人都迁移到了容器化部署模型，因为它们为昂贵的物理机或虚拟机提供了一种轻量级的替代方案。有了 Kubernetes 等编排工具后，我们乐于部署容器化应用，同时也满足了 Web 规模的要求。容器提供了与底层环境一定程度的隔离，这使得部署相对容易。但是，我们仍然需要在硬件（本地或云）、许可证、网络、配置等方面进行投资，这需要具有前瞻性的规划、合适的技术能力和仔细的监控。无服务器计算，尽管它也有自己的优点和缺点，但它让我们把这些责任也摆脱了。展望未来我们正处于持续开发、持续集成和持续部署的时代。每个企业都面临着竞争。产品 上市时间 Time to market （TTM）在吸引客户、留住客户这两个方面，发挥着重要作用。在这种背景下，企业喜欢花更多时间来尽可能快地推出功能，而不是在部署和维护的细节上苦苦挣扎。无服务器计算有可能满足这些需求。大玩家们正在投入巨额资金，以使 FaaS 尽可能地无缝且经济。无服务器计算的未来看起来是一片光明。via: https://www.opensourceforu.com/2021/12/should-businesses-opt-for-serverless-computing/作者：Krishna Mohan Koyya 选题：lkxed 译者：lkxed 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
Java 仍是开发企业应用程序最流行的语言之一。那么，为什么 无服务器 serverless 开发人员对它望而却步？几十年来，企业已经在各类平台上开发了关键业务应用程序，包括物理服务器、虚拟机和云环境。这些应用程序在各行各业都有一个共同点，那就是无论需求如何，它们都需要持续可用（24x7x365），保证稳定性、可靠性和性能。因此，即使实际资源利用率低于 50%，每个企业都必须付出高额成本维护基础架构（如 CPU、内存、磁盘、网络等）。无服务器架构是为了帮助解决这些问题而产生的。无服务器允许开发人员按需构建和运行应用程序，保证高可用性，不必在多云和混合云环境中管理服务器。在幕后，无服务器拓扑中仍有很多服务器，但它们是从应用程序开发中抽象出来的。相反，云提供商使用无服务器进行资源管理，例如配置、维护、联网和扩展服务器实例。由于其高效性，无服务器开发模式现在是一些企业的需求，这些企业希望按需启动服务，而不是一直运行服务。许多新建的开源项目用来在 Kubernetes 集群上通过 Linux 容器包来管理无服务器应用程序。CNCF 的《交互式无服务器全景》 是一份关于开源项目、工具、框架和公共云平台的指南，帮助 DevOps 团队处理无服务器应用程序。开发人员可以编写代码，然后将其快速部署到各种无服务器环境中。然后，无服务器应用程序响应需求，并根据需要自动伸缩扩展。你可能想知道什么编程语言和运行环境最适合无服务器应用程序开发，以便与上图中的技术集成。这个问题不只一个答案，但是让我们退一步来讨论在企业生产环境中开发业务应用程序最流行的应用程序运行环境：Java。据 Developer Economics 称，截至 2020 年第三季度，仍有 800 多万家企业开发人员在使用 Java 来实现其业务需求。然而，根据 2020 年的一项调查，Java（占比 6%）显然不是有前瞻意识的开发人员的首选，他们使用当前云服务做开发。来自 NewRelic 无服务器基准报告的数据（Daniel Oh, CC BY-SA 4.0）资源使用、响应时间和延迟在无服务器开发中至关重要。公有云提供商提供的无服务器产品通常是按需计量的，只有在无服务器应用程序启动时，才会通过事件驱动的执行模式收费。因此，当无服务器应用程序闲置或缩减为零时，企业无需支付任何费用。带有容器的 Java 状态在这种背景下，你可能会问：“既然现有业务应用程序很可能是在 Java 技术上开发的，那么开发人员为什么不尝试使用 Java 栈进行无服务器应用程序开发呢？”隐藏的真相是：很难在新的不可变更的基础设施（例如 Kubernetes 这样的容器平台）中优化 Java 应用程序。该图描述了 Java 进程与竞争的语言、框架（如 Node.js 和 Go）之间内存资源使用的差异。Java HotSpot 占用资源最大，其中包括每个 Java 虚拟机 Java Virtual Machine （JVM）实例分配的堆内存。中间显示了 Node.js 每个进程要比 Java 小得多。最后，Go 是一种流行的云服务编程语言，因为它的内存消耗最低。如你所见，当你在这张图从左到右走，你会看到更密的节点。这就是开发人员在云、容器和 Kubernetes 上编写无服务器应用程序时回避 Java（包括 Spring Boot，一种顽固的微服务 Java 框架）的原因。下一步是什么？企业可以通过实现无服务器应用程序获得明显的好处，但是资源密度问题导致他们避免使用 Java 堆栈在 Kubernetes 上开发无服务器应用程序开发。但是选择其他语言会给全球数百万 Java 开发人员带来学习负担。因此，在本系列的下一篇文章中，我将指导你如何开始使用 Java 无服务器函数，而不是使用其他语言。via: https://opensource.com/article/21/5/what-serverless-java作者：Daniel Oh 选题：lujun9972 译者：DCOLIVERSUN 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
我在 $work 建立了一个基于 Kubernetes 的平台已经快一年了，而且有点像 Kubernetes 的布道者了。真的，我认为这项技术太棒了。然而我并没有对它的运营和维护的困难程度抱过什么幻想。今年早些时候我读了这样的一篇文章，并对其中某些观点深以为然。如果我在一家规模较小的、有 10 到 15 个工程师的公司，假如有人建议管理和维护一批 Kubernetes 集群，那我会感到害怕的，因为它的运维开销太高了！尽管我现在对 Kubernetes 的一切都很感兴趣，但我仍然对“ 无服务器 Serverless ”计算会消灭运维工程师的说法抱有好奇。这种好奇心主要来源于我希望在未来仍然能有一份有报酬的工作 —— 如果我们前景光明的未来不需要运维工程师，那我得明白到底是怎么回事。我已经在 Lamdba 和Google Cloud Functions 上做了一些实验，结果让我印象十分深刻，但我仍然坚信无服务器解决方案只是解决了一部分问题。我关注 AWS Fargate 已经有一段时间了，这就是 $work 的开发人员所推崇为“无服务器计算”的东西 —— 主要是因为 Fargate，用它你就可以无需管理底层节点而运行你的 Docker 容器。我想看看它到底意味着什么，所以我开始尝试从头开始在 Fargate 上运行一个应用，看看是否可以成功。这里我对成功的定义是一个与“生产级”应用程序相近的东西，我想应该包含以下内容：一个在 Fargate 上运行的容器配置信息以环境变量的形式下推“秘密信息” 不能是明文的位于负载均衡器之后有效的 SSL 证书的 TLS 通道我以“基础设施即代码”的角度来开始整个任务，不遵循默认的 AWS 控制台向导，而是使用 terraform 来定义基础架构。这很可能让整个事情变得复杂，但我想确保任何部署都是可重现的，任何想要遵循此步骤的人都可发现我的结论。上述所有标准通常都可以通过基于 Kubernetes 的平台使用一些外部的附加组件和插件来实现，所以我确实是以一种比较的心态来处理整个任务的，因为我要将它与我的常用工作流程进行比较。我的主要目标是看看Fargate 有多容易，特别是与 Kubernetes 相比时。结果让我感到非常惊讶。AWS 是有开销的我有一个干净的 AWS 账户，并决定从零到部署一个 webapp。与 AWS 中的其它基础设施一样，我必须首先使基本的基础设施正常工作起来，因此我需要先定义一个 VPC。遵循最佳实践，因此我将这个 VPC 划分为跨可用区（AZ）的子网，一个公共子网和私有子网。这时我想到，只要这种设置基础设施的需求存在，我就能找到一份这种工作。AWS 是免运维的这一概念一直让我感到愤怒。开发者社区中的许多人理所当然地认为在设置和定义一个设计良好的 AWS 账户和基础设施是不需要付出多少工作和努力的。而这种想当然甚至发生在开始谈论多帐户架构之前就有了——现在我仍然使用单一帐户，我已经必须定义好基础设施和传统的网络设备。这里也值得记住，我已经做了很多次，所以我很清楚该做什么。我可以在我的帐户中使用默认的 VPC 以及预先提供的子网，我觉得很多刚开始的人也可以使用它。这大概花了我半个小时才运行起来，但我不禁想到，即使我想运行 lambda 函数，我仍然需要某种连接和网络。定义 NAT 网关和在 VPC 中路由根本不会让你觉得很“Serverless”，但要往下进行这就是必须要做的。运行简单的容器在我启动运行了基本的基础设施之后，现在我想让我的 Docker 容器运行起来。我开始翻阅 Fargate 文档并浏览 入门 文档，这些就马上就展现在了我面前：等等，只是让我的容器运行就至少要有三个步骤？这完全不像我所想的，不过还是让我们开始吧。任务定义“ 任务定义 Task Definition ”用来定义要运行的实际容器。我在这里遇到的问题是，任务定义这件事非常复杂。这里有很多选项都很简单，比如指定 Docker 镜像和内存限制，但我还必须定义一个网络模型以及我并不熟悉的其它各种选项。真需要这样吗？如果我完全没有 AWS 方面的知识就进入到这个过程里，那么在这个阶段我会感觉非常的不知所措。可以在 AWS 页面上找到这些 参数 的完整列表，这个列表很长。我知道我的容器需要一些环境变量，它需要暴露一个端口。所以我首先在一个神奇的 terraform 模块 的帮助下定义了这一点，这真的让这件事更容易了。如果没有这个模块，我就得手写 JSON 来定义我的容器定义。首先我定义了一些环境变量：container_environment_variables = [ { name = "USER" value = "${var.user}" }, { name = "PASSWORD" value = "${var.password}" } ]然后我使用上面提及的模块组成了任务定义：module "container_definition_app" { source = "cloudposse/ecs-container-definition/aws" version = "v0.7.0" container_name = "${var.name}" container_image = "${var.image}" container_cpu = "${var.ecs_task_cpu}" container_memory = "${var.ecs_task_memory}" container_memory_reservation = "${var.container_memory_reservation}" port_mappings = [ { containerPort = "${var.app_port}" hostPort = "${var.app_port}" protocol = "tcp" }, ] environment = "${local.container_environment_variables}" }在这一点上我非常困惑，我需要在这里定义很多配置才能运行，而这时什么都没有开始呢，但这是必要的 —— 运行 Docker 容器肯定需要了解一些容器配置的知识。我 之前写过 关于 Kubernetes 和配置管理的问题的文章，在这里似乎遇到了同样的问题。接下来，我在上面的模块中定义了任务定义（幸好从我这里抽象出了所需的 JSON —— 如果我不得不手写JSON，我可能已经放弃了）。当我定义模块参数时，我突然意识到我漏掉了一些东西。我需要一个 IAM 角色！好吧，让我来定义：resource "aws_iam_role" "ecs_task_execution" { name = "${var.name}-ecs_task_execution" assume_role_policy = <<EOF { "Version": "2008-10-17", "Statement": [ { "Action": "sts:AssumeRole", "Principal": { "Service": "ecs-tasks.amazonaws.com" }, "Effect": "Allow" } ] } EOF } resource "aws_iam_role_policy_attachment" "ecs_task_execution" { count = "${length(var.policies_arn)}" role = "${aws_iam_role.ecs_task_execution.id}" policy_arn = "${element(var.policies_arn, count.index)}" }这样做是有意义的，我需要在 Kubernetes 中定义一个 RBAC 策略，所以在这里我还未完全错失或获得任何东西。这时我开始觉得从 Kubernetes 的角度来看，这种感觉非常熟悉。resource "aws_ecs_task_definition" "app" { family = "${var.name}" network_mode = "awsvpc" requires_compatibilities = ["FARGATE"] cpu = "${var.ecs_task_cpu}" memory = "${var.ecs_task_memory}" execution_role_arn = "${aws_iam_role.ecs_task_execution.arn}" task_role_arn = "${aws_iam_role.ecs_task_execution.arn}" container_definitions = "${module.container_definition_app.json}" }现在，为了运行起来我已经写了很多行代码，我阅读了很多 ECS 文档，我所做的就是定义一个任务定义。我还没有让这个东西运行起来。在这一点上，我真的很困惑这个基于 Kubernetes 的平台到底增值了什么，但我继续前行。服务服务，一定程度上是将容器如何暴露给外部，另外是如何定义它拥有的副本数量。我的第一个想法是“啊！这就像一个 Kubernetes 服务！”我开始着手映射端口等。这是我第一次在 terraform 上跑：resource "aws_ecs_service" "app" { name = "${var.name}" cluster = "${module.ecs.this_ecs_cluster_id}" task_definition = "${data.aws_ecs_task_definition.app.family}:${max(aws_ecs_task_definition.app.revision, data.aws_ecs_task_definition.app.revision)}" desired_count = "${var.ecs_service_desired_count}" launch_type = "FARGATE" deployment_maximum_percent = "${var.ecs_service_deployment_maximum_percent}" deployment_minimum_healthy_percent = "${var.ecs_service_deployment_minimum_healthy_percent}" network_configuration { subnets = ["${values(local.private_subnets)}"] security_groups = ["${module.app.this_security_group_id}"] } }当我必须定义允许访问所需端口的安全组时，我再次感到沮丧，当我这样做了并将其插入到网络配置中后，我就像被扇了一巴掌。我还需要定义自己的负载均衡器？什么？当然不是吗？负载均衡器从未远离老实说，我很满意，我甚至不确定为什么。我已经习惯了 Kubernetes 的服务和 Ingress 对象，我一心认为用 Kubernetes 将我的应用程序放到网上是多么容易。当然，我们在 $work 花了几个月的时间建立一个平台，以便更轻松。我是 external-dns 和 cert-manager 的重度用户，它们可以自动填充 Ingress 对象上的 DNS 条目并自动化 TLS 证书，我非常了解进行这些设置所需的工作，但老实说，我认为在 Fargate 上做这件事会更容易。我认识到 Fargate 并没有声称自己是“如何运行应用程序”这件事的全部和最终目的，它只是抽象出节点管理，但我一直被告知这比 Kubernetes 更加容易。我真的很惊讶。定义负载均衡器（即使你不想使用 Ingress 和 Ingress Controller）也是向 Kubernetes 部署服务的重要组成部分，我不得不在这里再次做同样的事情。这一切都让人觉得如此熟悉。我现在意识到我需要：一个负载均衡器一个 TLS 证书一个 DNS 名字所以我着手做了这些。我使用了一些流行的 terraform 模块，并做了这个：# Define a wildcard cert for my app module "acm" { source = "terraform-aws-modules/acm/aws" version = "v1.1.0" create_certificate = true domain_name = "${var.route53_zone_name}" zone_id = "${data.aws_route53_zone.this.id}" subject_alternative_names = [ "*.${var.route53_zone_name}", ] tags = "${local.tags}" } # Define my loadbalancer resource "aws_lb" "main" { name = "${var.name}" subnets = [ "${values(local.public_subnets)}" ] security_groups = ["${module.alb_https_sg.this_security_group_id}", "${module.alb_http_sg.this_security_group_id}"] } resource "aws_lb_target_group" "main" { name = "${var.name}" port = "${var.app_port}" protocol = "HTTP" vpc_id = "${local.vpc_id}" target_type = "ip" depends_on = [ "aws_lb.main" ] } # Redirect all traffic from the ALB to the target group resource "aws_lb_listener" "main" { load_balancer_arn = "${aws_lb.main.id}" port = "80" protocol = "HTTP" default_action { target_group_arn = "${aws_lb_target_group.main.id}" type = "forward" } } resource "aws_lb_listener" "main-tls" { load_balancer_arn = "${aws_lb.main.id}" port = "443" protocol = "HTTPS" certificate_arn = "${module.acm.this_acm_certificate_arn}" default_action { target_group_arn = "${aws_lb_target_group.main.id}" type = "forward" } }我必须承认，我在这里搞砸了好几次。我不得不在 AWS 控制台中四处翻弄，以弄清楚我做错了什么。这当然不是一个“轻松”的过程，而且我之前已经做过很多次了。老实说，在这一点上，Kubernetes 看起来对我很有启发性，但我意识到这是因为我对它非常熟悉。幸运的是我能够使用托管的 Kubernetes 平台（预装了 external-dns 和 cert-manager），我真的很想知道我漏掉了 Fargate 什么增值的地方。它真的感觉不那么简单。经过一番折腾，我现在有一个可以工作的 ECS 服务。包括服务在内的最终定义如下所示：data "aws_ecs_task_definition" "app" { task_definition = "${var.name}" depends_on = ["aws_ecs_task_definition.app"] } resource "aws_ecs_service" "app" { name = "${var.name}" cluster = "${module.ecs.this_ecs_cluster_id}" task_definition = "${data.aws_ecs_task_definition.app.family}:${max(aws_ecs_task_definition.app.revision, data.aws_ecs_task_definition.app.revision)}" desired_count = "${var.ecs_service_desired_count}" launch_type = "FARGATE" deployment_maximum_percent = "${var.ecs_service_deployment_maximum_percent}" deployment_minimum_healthy_percent = "${var.ecs_service_deployment_minimum_healthy_percent}" network_configuration { subnets = ["${values(local.private_subnets)}"] security_groups = ["${module.app_sg.this_security_group_id}"] } load_balancer { target_group_arn = "${aws_lb_target_group.main.id}" container_name = "app" container_port = "${var.app_port}" } depends_on = [ "aws_lb_listener.main", ] }我觉得我已经接近完成了，但后来我记起了我只完成了最初的“入门”文档中所需的 3 个步骤中的 2 个，我仍然需要定义 ECS 群集。集群感谢 定义模块，定义要所有这些运行的集群实际上非常简单。module "ecs" { source = "terraform-aws-modules/ecs/aws" version = "v1.1.0" name = "${var.name}" }这里让我感到惊讶的是为什么我必须定义一个集群。作为一个相当熟悉 ECS 的人，你会觉得你需要一个集群，但我试图从一个必须经历这个过程的新人的角度来考虑这一点 —— 对我来说，Fargate 标榜自己“ Serverless”而你仍需要定义集群，这似乎很令人惊讶。当然这是一个小细节，但它确实盘旋在我的脑海里。告诉我你的 Secret在这个阶段，我很高兴我成功地运行了一些东西。然而，我的原始的成功标准缺少一些东西。如果我们回到任务定义那里，你会记得我的应用程序有一个存放密码的环境变量：container_environment_variables = [ { name = "USER" value = "${var.user}" }, { name = "PASSWORD" value = "${var.password}" } ]如果我在 AWS 控制台中查看我的任务定义，我的密码就在那里，明晃晃的明文。我希望不要这样，所以我开始尝试将其转化为其他东西，类似于 Kubernetes 的Secrets管理。AWS SSMFargate / ECS 执行 secret 管理 secret management 部分的方式是使用 AWS SSM（此服务的全名是 AWS 系统管理器参数存储库 Systems Manager Parameter Store，但我不想使用这个名称，因为坦率地说这个名字太愚蠢了）。AWS 文档很好的涵盖了这个内容，因此我开始将其转换为 terraform。指定秘密信息首先，你必须定义一个参数并为其命名。在 terraform 中，它看起来像这样：resource "aws_ssm_parameter" "app_password" { name = "${var.app_password_param_name}" # The name of the value in AWS SSM type = "SecureString" value = "${var.app_password}" # The actual value of the password, like correct-horse-battery-stable }显然，这里的关键部分是 “SecureString” 类型。这会使用默认的 AWS KMS 密钥来加密数据，这对我来说并不是很直观。这比 Kubernetes 的 Secret 管理具有巨大优势，默认情况下，这些 Secret 在 etcd 中是不加密的。然后我为 ECS 指定了另一个本地值映射，并将其作为 Secret 参数传递：container_secrets = [ { name = "PASSWORD" valueFrom = "${var.app_password_param_name}" }, ] module "container_definition_app" { source = "cloudposse/ecs-container-definition/aws" version = "v0.7.0" container_name = "${var.name}" container_image = "${var.image}" container_cpu = "${var.ecs_task_cpu}" container_memory = "${var.ecs_task_memory}" container_memory_reservation = "${var.container_memory_reservation}" port_mappings = [ { containerPort = "${var.app_port}" hostPort = "${var.app_port}" protocol = "tcp" }, ] environment = "${local.container_environment_variables}" secrets = "${local.container_secrets}"出了个问题此刻，我重新部署了我的任务定义，并且非常困惑。为什么任务没有正确拉起？当新的任务定义（版本 8）可用时，我一直在控制台中看到正在运行的应用程序仍在使用先前的任务定义（版本 7）。解决这件事花费的时间比我预期的要长，但是在控制台的事件屏幕上，我注意到了 IAM 错误。我错过了一个步骤，容器无法从 AWS SSM 中读取 Secret 信息，因为它没有正确的 IAM 权限。这是我第一次真正对整个这件事情感到沮丧。从用户体验的角度来看，这里的反馈非常糟糕。如果我没有发觉的话，我会认为一切都很好，因为仍然有一个任务正在运行，我的应用程序仍然可以通过正确的 URL 访问 —— 只不过是旧的配置而已。在 Kubernetes 里，我会清楚地看到 pod 定义中的错误。Fargate 可以确保我的应用不会停止，这绝对是太棒了，但作为一名运维，我需要一些关于发生了什么的实际反馈。这真的不够好。我真的希望 Fargate 团队的人能够读到这篇文章，改善这种体验。就这样了到这里就结束了，我的应用程序正在运行，也符合我的所有标准。我确实意识到我做了一些改进，其中包括：定义一个 cloudwatch 日志组，这样我就可以正确地写日志了添加了一个 route53 托管区域，使整个事情从 DNS 角度更容易自动化修复并重新调整了 IAM 权限，这里太宽泛了但老实说，现在我想反思一下这段经历。我写了一个关于我的经历的 推特会话，然后花了其余时间思考我在这里的真实感受。代价经过一夜的反思，我意识到无论你是使用 Fargate 还是 Kubernetes，这个过程都大致相同。最让我感到惊讶的是，尽管我经常听说 Fargate “更容易”，但我真的没有看到任何超过 Kubernetes 平台的好处。现在，如果你正在构建 Kubernetes 集群，我绝对可以看到这里的价值 —— 管理节点和控制面板只是不必要的开销，问题是 —— 基于 Kubernetes 的平台的大多数消费者都没有这样做。如果你很幸运能够使用 GKE，你几乎不需要考虑集群的管理，你可以使用单个 gcloud 命令来运行集群。我经常使用 Digital Ocean 的 Kubernetes 托管服务，我可以肯定地说它就像操作 Fargate 集群一样简单，实际上在某种程度上它更容易。必须定义一些基础设施来运行你的容器就是此时的代价。谷歌本周可能刚刚使用他们的 Google Cloud Run 产品改变了游戏规则，但他们在这一领域的领先优势远远领先于其他所有人。从这整个经历中，我可以肯定的说：大规模运行容器仍然很难。它需要思考，需要领域知识，需要运维和开发人员之间的协作。它还需要一个基础来构建 —— 任何基于 AWS 的操作都需要事先定义和运行一些基础架构。我对一些公司似乎渴望的 “NoOps” 概念非常感兴趣。我想如果你正在运行一个无状态应用程序，你可以把它全部放在一个 lambda 函数和一个 API 网关中，这可能不错，但我们是否真的适合在任何一种企业环境中这样做？我真的不这么认为。公平比较令我印象深刻的另一个现实是，技术 A 和技术 B 之间的比较通常不太公平，我经常在 AWS 上看到这一点。这种实际情况往往与 Jeff Barr 博客文章截然不同。如果你是一家足够小的公司，你可以使用 AWS 控制台在 AWS 中部署你的应用程序并接受所有默认值，这绝对更容易。但是，我不想使用默认值，因为默认值几乎是不适用于生产环境的。一旦你开始剥离掉云服务商服务的层面，你就会开始意识到最终你仍然是在运行软件 —— 它仍然需要设计良好、部署良好、运行良好。我相信 AWS 和 Kubernetes 以及所有其他云服务商的增值服务使得它更容易运行、设计和操作，但它绝对不是免费的。Kubernetes 的争议最后就是：如果你将 Kubernetes 纯粹视为一个容器编排工具，你可能会喜欢 Fargate。然而，随着我对 Kubernetes 越来越熟悉，我开始意识到它作为一种技术的重要性 —— 不仅因为它是一个伟大的容器编排工具，而且因为它的设计模式 —— 它是声明性的、API 驱动的平台。 在整个 Fargate 过程期间发生的一个简单的事情是，如果我删除这里某个东西，Fargate 不一定会为我重新创建它。自动缩放很不错，不需要管理服务器和操作系统的补丁及更新也很棒，但我觉得因为无法使用 Kubernetes 自我修复和 API 驱动模型而失去了很多。当然，Kubernetes 有一个学习曲线，但从这里的体验来看，Fargate 也是如此。总结尽管我在这个过程中遭遇了困惑，但我确实很喜欢这种体验。我仍然相信 Fargate 是一项出色的技术，AWS 团队对 ECS/Fargate 所做的工作确实非常出色。然而，我的观点是，这绝对不比 Kubernetes “更容易”，只是……难点不同。在生产环境中运行容器时出现的问题大致相同。如果你从这篇文章中有所收获，它应该是这样的：不管你选择的哪种方式都有运维开销。不要相信你选择一些东西你的世界就变得更轻松。我个人的意见是：如果你有一个运维团队，而你的公司要为多个应用程序团队部署容器 —— 选择一种技术并围绕它构建流程和工具以使其更容易。人们说的一点肯定没错，用点技巧可以更容易地使用某种技术。在这个阶段，谈到 Fargate，下面的漫画这总结了我的感受：via: https://leebriggs.co.uk/blog/2019/04/13/the-fargate-illusion.html作者：Lee Briggs 选题：lujun9972 译者：Bestony 校对：wxy, 临石（阿里云智能技术专家）本文由 LCTT 原创编译，Linux中国 荣誉推出
以及，对于 无服务器 Serverless 架构，什么时候该用，什么时候不该用呢？如果将如今互联网体验中最方便实用的那一部分去掉，那么留下来的基本就是 客户端-服务端 client-server 模式了。这一个模式在互联网建立初期就已经在使用了，直到目前都没有太大的变化，也就是说，这个模式仍然在为我们服务。那么，当人们谈论 无服务器 Serverless 架构的时候，到底是指什么呢？其实，无服务器架构并不是说不使用服务器了。恰恰相反，客户端-服务端模式仍然在其中发挥着重要的作用。无服务器架构实际上指的是能够让开发者在不需要关心服务器上架、为操作系统打补丁、创建容器镜像这些工作的情况下，就能够完成编码、部署和创建应用这一整套流程的架构。无服务器架构的三个重要意义一些缺乏开发经验的人员现在要参与到开发工作中来了。无服务器架构能够让他们尽量只学习必要的工作内容，把更多的时间放在更具创造性的开发工作中。开发者不再需要重复造轮子。运行和维护服务器、为操作系统打补丁、创建容器等这一系列工作，都可以由更专业的无服务器架构提供商来完成。最现实的一点是，如果不使用无服务器架构，那么在服务器管理方面，总需要有一个作最终决策的人。当服务器发生崩溃时，或是需要在服务器上执行某些操作时，总是需要这样一个统领全局的人来作出决策。因此最佳的方案是使用无服务器架构。什么时候该用或者不该用无服务器架构？听起来无服务器架构是个好东西。但事实上，无服务器架构并不是万能的，在使用之前还需要考虑以下这些因素：成本使用范围时间控制方式其中值得注意的是控制方式。现在已经有一些项目为开发者提供了操作和控制无服务器架构计算环境的工具了，Apache OpenWhisk 就是其中之一。为什么要将无服务器架构开源？关于这方面的更多内容，可以观看无服务器架构方面的专家 Saron Yitbarek 在 Command Line Heroes 节目中的访谈。via: https://opensource.com/article/18/12/serverless-podcast-command-line-heros作者：Jen Wike Huger 选题：lujun9972 译者：HankChow 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
如何成规模地部署多云的无服务器程序和 Cloud Foundry API
IBM 的 Ken Parmelee 说：“微服务和 API 是产品，我们需要以这种方式思考。”领导 IBM 的 API 网关和 Big Blue 开源项目的的 Ken Parmelee 对以开源方式 “进攻” API 以及如何创建微服务和使其伸缩有一些思考。Parmelee 说：“微服务和 API 是产品，我们需要以这种方式思考这些问题。当你开始这么做，人们依赖它作为它们业务的一部分。这是你在这个领域所做的关键方面。”他在最近的北欧 APIs 2017 平台峰会登上讲台，并挑战了一些流行的观念。“快速失败不是一个很好的概念。你想在第一场比赛中获得一些非常棒的东西。这并不意味着你需要花费大量的时间，而是应该让它变得非常棒，然后不断的发展和改进。如果一开始真的很糟糕，人们就不会想要用你。”他谈及包括 OpenWhisk 在内的 IBM 现代无服务器架构，这是一个 IBM 和 Apache 之间的开源伙伴关系。 云优先的基于分布式事件的编程服务是这两年多来重点关注这个领域的成果；IBM 是该领域领先的贡献者，它是 IBM 云服务的基础。它提供基础设施即服务（IaaS）、自动缩放、为多种语言提供支持、用户只需支付实际使用费用即可。这次旅程充满了挑战，因为他们发现服务器操作需要安全、并且需要轻松 —— 匿名访问、缺少使用路径、固定的 URL 格式等。任何人都可以在 30 秒内在 https://console.bluemix.net/openwhisk/ 上尝试这些无服务器 API。“这听起来很有噱头，但这是很容易做到的。我们正在结合 Cloud Foundry 中完成的工作，并在 OpenWhisk 下的 Bluemix 中发布了它们，以提供安全性和可扩展性。”他说：“灵活性对于微服务也是非常重要的。 当你使用 API 在现实世界中工作时，你开始需要跨云进行扩展。”这意味着从你的内部云走向公共云，并且“对你要怎么做有一个实在的概念很重要”。在思考“任何云概念”的时候，他警告说，不是“将其放入一个 Docker 容器，并到处运行。这很棒，但需要在这些环境中有效运行。Docker 和 Kubernetes 有提供了很多帮助，但是你想要你的操作方式付诸实施。” 提前考虑 API 的使用，无论是在内部运行还是扩展到公有云并可以公开调用 - 你需要有这样的“架构观”，他补充道。Parmelee 说：“我们都希望我们所创造的有价值，并被广泛使用。” API 越成功，将其提升到更高水平的挑战就越大。API 是微服务或“服务间”的组成部分。他说，API 的未来是原生云的 - 无论你从哪里开始。关键因素是可扩展性，简化后端管理，降低成本，避免厂商锁定。你可以在下面或在 YouTube 观看他整整 23 分钟的演讲。via: http://superuser.openstack.org/articles/deploy-multi-cloud-serverless-cloud-foundry-apis-scale/作者：Superuser 译者：geekpi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
Up：在几秒钟内部署无服务器应用程序
去年，我为 Up 规划了一份蓝图，其中描述了如何以最小的成本在 AWS 上为大多数构建块创建一个很棒的无服务器环境。这篇文章则是讨论了 Up 的初始 alpha 版本。为什么关注 无服务器 serverless ？对于初学者来说，它可以节省成本，因为你可以按需付费，且只为你使用的付费。无服务器方式是自愈的，因为每个请求被隔离并被视作“无状态的”。最后，它可以无限轻松地扩展 —— 没有机器或集群要管理。部署你的代码就行了。大约一个月前，我决定开始在 apex/up 上开发它，并为动态 SVG 版本的 GitHub 用户投票功能写了第一个小型无服务器示例程序 tj/gh-polls。它运行良好，成本低于每月 1 美元即可为数百万次投票服务，因此我会继续这个项目，看看我是否可以提供开源版本及商业的变体版本。其长期的目标是提供“你自己的 Heroku” 的版本，支持许多平台。虽然平台即服务（PaaS）并不新鲜，但无服务器生态系统正在使这种方案日益萎缩。据说，AWS 和其他的供应商经常由于他们提供的灵活性而被人诟病用户体验。Up 将复杂性抽象出来，同时为你提供一个几乎无需运维的解决方案。安装你可以使用以下命令安装 Up，查看这篇临时文档开始使用。或者如果你使用安装脚本，请下载二进制版本。（请记住，这个项目还在早期。）curl -sfL https://raw.githubusercontent.com/apex/up/master/install.sh | sh 只需运行以下命令随时升级到最新版本：up upgrade 你也可以通过 NPM 进行安装：npm install -g up 功能这个早期 alpha 版本提供什么功能？让我们来看看！请记住，Up 不是托管服务，因此你需要一个 AWS 帐户和 AWS 凭证。如果你对 AWS 不熟悉，你可能需要先停下来，直到熟悉流程。我遇到的第一个问题是：up(1) 与 apex(1) 有何不同？Apex 专注于部署功能，用于管道和事件处理，而 Up 则侧重于应用程序、API 和静态站点，也就是单个可部署单元。Apex 不为你提供 API 网关、SSL 证书或 DNS，也不提供 URL 重写，脚本注入等。单命令无服务器应用程序Up 可以让你使用单条命令部署应用程序、API 和静态站点。要创建一个应用程序，你只需要一个文件，在 Node.js 的情况下，./app.js 监听由 Up 提供的 PORT'。请注意，如果你使用的是package.json，则会检测并使用start和build` 脚本。const http = require('http') const { PORT = 3000 } = process.env http.createServer((req, res) => { res.end('Hello World\n') }).listen(PORT) 额外的运行时环境也支持开箱可用，例如用于 Golang 的 “main.go”，所以你可以在几秒钟内部署 Golang、Python、Crystal 或 Node.js 应用程序。package main import ( "fmt" "log" "net/http" "os" ) func main() { addr := ":" + os.Getenv("PORT") http.HandleFunc("/", hello) log.Fatal(http.ListenAndServe(addr, nil)) } func hello(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Hello World from Go") } 要部署应用程序输入 up 来创建所需的资源并部署应用程序本身。这里没有模糊不清的地方，一旦它说“完成”了那就完成了，该应用程序立即可用 —— 没有远程构建过程。后续的部署将会更快，因为栈已被配置：使用 up url --open 测试你的程序，以在浏览器中浏览它，up url --copy 可以将 URL 保存到剪贴板，或者可以尝试使用 curl：curl `up url` Hello World 要删除应用程序及其资源，只需输入 up stack delete：例如，使用 up staging 或 up production 和 up url --open production 部署到预发布或生产环境。请注意，自定义域名尚不可用，它们将很快可用。之后，你还可以将版本“推广”到其他环境。反向代理Up 的一个独特的功能是，它不仅仅是简单地部署代码，它将一个 Golang 反向代理放在应用程序的前面。这提供了许多功能，如 URL 重写、重定向、脚本注入等等，我们将在后面进一步介绍。基础设施即代码在配置方面，Up 遵循现代最佳实践，因此对基础设施的更改都可以在部署之前预览，并且 IAM 策略的使用还可以限制开发人员访问以防止事故发生。一个附带的好处是它有助于自动记录你的基础设施。以下是使用 Let's Encrypt 通过 AWS ACM 配置一些（虚拟）DNS 记录和免费 SSL 证书的示例。{ "name": "app", "dns": { "myapp.com": [ { "name": "myapp.com", "type": "A", "ttl": 300, "value": ["35.161.83.243"] }, { "name": "blog.myapp.com", "type": "CNAME", "ttl": 300, "value": ["34.209.172.67"] }, { "name": "api.myapp.com", "type": "A", "ttl": 300, "value": ["54.187.185.18"] } ] }, "certs": [ { "domains": ["myapp.com", "*.myapp.com"] } ] } 当你首次通过 up 部署应用程序时，需要所有的权限，它为你创建 API 网关、Lambda 函数、ACM 证书、Route53 DNS 记录等。ChangeSets 尚未实现，但你能使用 up stack plan 预览进一步的更改，并使用 up stack apply 提交，这与 Terraform 非常相似。详细信息请参阅配置文档。全球部署regions 数组可以指定应用程序的目标区域。例如，如果你只对单个地区感兴趣，请使用：{ "regions": ["us-west-2"] } 如果你的客户集中在北美，你可能需要使用美国和加拿大所有地区：{ "regions": ["us-*", "ca-*"] } 最后，你可以使用 AWS 目前支持的所有 14 个地区：{ "regions": ["*"] } 多区域支持仍然是一个正在进行的工作，因为需要一些新的 AWS 功能来将它们结合在一起。静态文件服务Up 默认支持静态文件服务，并带有 HTTP 缓存支持，因此你可以在应用程序前使用 CloudFront 或任何其他 CDN 来大大减少延迟。当 type 为 static 时，默认情况下的工作目录是 .，但是你也可以提供一个 static.dir：{ "name": "app", "type": "static", "static": { "dir": "public" } } 构建钩子构建钩子允许你在部署或执行其他操作时定义自定义操作。一个常见的例子是使用 Webpack 或 Browserify 捆绑 Node.js 应用程序，这大大减少了文件大小，因为 node 模块是很大的。{ "name": "app", "hooks": { "build": "browserify --node server.js > app.js", "clean": "rm app.js" } } 脚本和样式表插入Up 允许你插入脚本和样式，无论是内联方式或声明路径。它甚至支持一些“罐头”脚本，用于 Google Analytics（分析）和 Segment，只需复制并粘贴你的写入密钥即可。{ "name": "site", "type": "static", "inject": { "head": [ { "type": "segment", "value": "API_KEY" }, { "type": "inline style", "file": "/css/primer.css" } ], "body": [ { "type": "script", "value": "/app.js" } ] } } 重写和重定向Up 通过 redirects 对象支持重定向和 URL 重写，该对象将路径模式映射到新位置。如果省略 status 参数（或值为 200），那么它是重写，否则是重定向。{ "name": "app", "type": "static", "redirects": { "/blog": { "location": "https://blog.apex.sh/", "status": 301 }, "/docs/:section/guides/:guide": { "location": "/help/:section/:guide", "status": 302 }, "/store/*": { "location": "/shop/:splat" } } } 用于重写的常见情况是 SPA（单页面应用程序），你希望不管路径如何都提供 index.html，当然除非文件存在。{ "name": "app", "type": "static", "redirects": { "/*": { "location": "/", "status": 200 } } } 如果要强制实施该规则，无论文件是否存在，只需添加 "force": true 。环境变量密码将在下一个版本中有，但是现在支持纯文本环境变量：{ "name": "api", "environment": { "API_FEATURE_FOO": "1", "API_FEATURE_BAR": "0" } } CORS 支持CORS 支持允许你指定哪些（如果有的话）域可以从浏览器访问你的 API。如果你希望允许任何网站访问你的 API，只需启用它：{ "cors": { "enable": true } } 你还可以自定义访问，例如仅将 API 访问限制为你的前端或 SPA。{ "cors": { "allowed_origins": ["https://myapp.com"], "allowed_methods": ["HEAD", "GET", "POST", "PUT", "DELETE"], "allowed_headers": ["Content-Type", "Authorization"] } } 日志对于 $0.5/GB 的低价格，你可以使用 CloudWatch 日志进行结构化日志查询和跟踪。Up 实现了一种用于改进 CloudWatch 提供的自定义查询语言，专门用于查询结构化 JSON 日志。你可以查询现有日志：up logs 跟踪在线日志：up logs -f 或者对其中任一个进行过滤，例如只显示耗时超过 5 毫秒的 200 个 GET/HEAD 请求：up logs 'method in ("GET", "HEAD") status = 200 duration >= 5' 查询语言是非常灵活的，这里有更多来自于 up help logs 的例子### 显示过去 5 分钟的日志 $ up logs ### 显示过去 30 分钟的日志 $ up logs -s 30m ### 显示过去 5 小时的日志 $ up logs -s 5h ### 实时显示日志 $ up logs -f ### 显示错误日志 $ up logs error ### 显示错误和致命错误日志 $ up logs 'error or fatal' ### 显示非 info 日志 $ up logs 'not info' ### 显示特定消息的日志 $ up logs 'message = "user login"' ### 显示超时 150ms 的 200 响应 $ up logs 'status = 200 duration > 150' ### 显示 4xx 和 5xx 响应 $ up logs 'status >= 400' ### 显示用户邮件包含 @apex.sh 的日志 $ up logs 'user.email contains "@apex.sh"' ### 显示用户邮件以 @apex.sh 结尾的日志 $ up logs 'user.email = "*@apex.sh"' ### 显示用户邮件以 tj@ 开始的日志 $ up logs 'user.email = "tj@*"' ### 显示路径 /tobi 和 /loki 下的错误日志 $ up logs 'error and (path = "/tobi" or path = "/loki")' ### 和上面一样，用 in 显示 $ up logs 'error and path in ("/tobi", "/loki")' ### 更复杂的查询方式 $ up logs 'method in ("POST", "PUT") ip = "207.*" status = 200 duration >= 50' ### 将 JSON 格式的错误日志发送给 jq 工具 $ up logs error | jq 请注意，and 关键字是暗含的，虽然你也可以使用它。冷启动时间这是 AWS Lambda 平台的特性，但冷启动时间通常远远低于 1 秒，在未来，我计划提供一个选项来保持它们在线。配置验证up config 命令输出解析后的配置，有默认值和推断的运行时设置 - 它也起到验证配置的双重目的，因为任何错误都会导致退出状态 > 0。崩溃恢复使用 Up 作为反向代理的另一个好处是执行崩溃恢复 —— 在崩溃后重新启动服务器，并在将错误的响应发送给客户端之前重新尝试该请求。例如，假设你的 Node.js 程序由于间歇性数据库问题而导致未捕获的异常崩溃，Up 可以在响应客户端之前重试该请求。之后这个行为会更加可定制。适合持续集成很难说这是一个功能，但是感谢 Golang 相对较小和独立的二进制文件，你可以在一两秒中在 CI 中安装 Up。HTTP/2Up 通过 API 网关支持 HTTP/2，对于服务很多资源的应用和站点可以减少延迟。我将来会对许多平台进行更全面的测试，但是 Up 的延迟已经很好了：错误页面Up 提供了一个默认错误页面，如果你要提供支持电子邮件或调整颜色，你可以使用 error_pages 自定义。{ "name": "site", "type": "static", "error_pages": { "variables": { "support_email": "support@apex.sh", "color": "#228ae6" } } } 默认情况下，它看上去像这样：如果你想提供自定义模板，你可以创建以下一个或多个文件。特定文件优先。error.html – 匹配任何 4xx 或 5xx5xx.html – 匹配任何 5xx 错误4xx.html – 匹配任何 4xx 错误CODE.html – 匹配一个特定的代码，如 404.html查看文档阅读更多有关模板的信息。伸缩和成本你已经做了这么多，但是 Up 怎么伸缩？目前，API 网关和 AWS 是目标平台，因此你无需进行任何更改即可扩展，只需部署代码即可完成。你只需按需支付实际使用的数量并且无需人工干预。AWS 每月免费提供 1,000,000 个请求，但你可以使用 http://serverlesscalc.com 来插入预期流量。在未来 Up 将提供更多的平台，所以如果一个成本过高，你可以迁移到另一个！未来目前为止就这样了！它可能看起来不是很多，但它已经超过 10,000 行代码，并且我刚刚开始开发。看看这个问题队列，假设项目可持续发展，看看未来会有什么期待。如果你发现这个免费版本有用，请考虑在 OpenCollective 上捐赠我，因为我没有任何工作。我将在短期内开发早期专业版，对早期用户有年费优惠。专业或企业版也将提供源码，因此可以进行内部修复和自定义。via: https://medium.freecodecamp.org/up-b3db1ca930ee作者：TJ Holowaychuk 译者：geekpi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出