基础模式 声明式部署

艾因技术K8s翻译大约 19 分钟

基础模式 声明式部署

2.2 Declarative Deployment

2.2 声明式部署

The heart of the Declarative Deployment pattern is Kubernetes’ Deployment resource. This abstraction encapsulates the upgrade and rollback processes of a group of containers and makes its execution a repeatable and automated activity.

声明式部署模式的核心是部署K8s的资源。这是一种通过抽象和封装一组容器的升级和回滚过程,使其执行成为可重复和自动化的活动。

2.2.1 Problem

2.2.1 问题

We can provision isolated environments as namespaces in a self-service manner and have the services placed in these environments with minimal human intervention through the scheduler. But with a growing number of microservices, continually updating and replacing them with newer versions becomes an increasing burden too.

我们可以以自助服务的方式将隔离的环境作为命名空间进行配置,并通过调度器以最少的人为干预将服务放置在这些环境中。但是随着微服务数量的不断增加,不断更新并用新版本替换它们也成为了一个越来越大的负担。

Upgrading a service to a next version involves activities such as starting the new version of the Pod, stopping the old version of a Pod gracefully, waiting and verifying that it has launched successfully, and sometimes rolling it all back to the previous version in the case of failure. These activities are performed either by allowing some downtime but no running concurrent service versions, or with no downtime, but increased resource usage due to both versions of the service running during the update process. Performing these steps manually can lead to human errors, and scripting properly can require a significant amount of effort, both of which quickly turn the release process into a bottleneck.

将服务升级到下一个版本涉及的活动包括启动Pod的新版本、优雅地停止Pod的旧版本、等待并验证其已成功启动,以及有时在出现故障时将其全部回滚到上一个版本。这些活动可以通过允许一些停机但不运行并发服务版本来执行,也可以不停机但由于在更新过程中运行两个版本的服务而增加资源使用率来执行。手动执行这些步骤可能会导致人为错误,正确编写脚本可能需要大量的工作,这两者都会很快将发布过程变成瓶颈。

2.2.2  Solution

2.2.2 解决方案

Luckily, Kubernetes has automated this activity as well. Using the concept of Deployment, we can describe how our application should be updated, using different strategies,and tuning the various aspects of the update process. If you consider that you do multiple Deployments for every microservice instance per release cycle (which,depending on the team and project, can span from minutes to several months), this is another effort-saving automation by Kubernetes.

幸运的是,Kubernetes也实现了这一活动的自动化。使用部署的概念,我们可以描述应用程序应该如何更新,使用不同的策略,以及调整更新过程的各个方面。如果考虑每个发布周期对每个微服务实例进行多个部署(这取决于团队和项目,可以跨越几分钟到几个月),这是Kubernetes在自动化方面的另一个努力。

In Chapter 2, we have seen that, to do its job effectively, the scheduler requires sufficient resources on the host system, appropriate placement policies, and containers with adequately defined resource profiles. Similarly, for a Deployment to do its job correctly, it expects the containers to be good cloud-native citizens. At the very core of a Deployment is the ability to start and stop a set of Pods predictably. For this to work as expected, the containers themselves usually listen and honor lifecycle events (such as SIGTERM; see Chapter 5, Managed Lifecycle) and also provide health-check endpoints as described in Chapter 4, Health Probe, which indicate whether they started successfully.

在第上一节中,我们已经看到,为了有效地完成其工作,调度器需要主机系统上的足够资源、适当的放置策略和具有充分定义的资源配置文件的容器。类似地,为了让部署正确地完成其工作,它希望容器是良好的云原生公民。部署的核心是可预测地启动和停止一组Pods的能力。为了使其按预期工作,容器本身通常会侦听和处理生命周期事件(如SIGTERM;请参阅第2章第4节,托管生命周期),并提供第2章第3节,健康探测中所述的健康检查端点,以指示它们是否成功启动。

If a container covers these two areas accurately, the platform can cleanly shut down old containers and replace them by starting updated instances. Then all the remaining aspects of an update process can be defined in a declarative way and executed as one atomic action with predefined steps and an expected outcome. Let’s see the options for a container update behavior.

如果一个容器准确地覆盖了这两个区域,那么平台可以干净地关闭旧容器,并通过启动更新的实例来替换它们。然后,可以以声明方式定义更新过程的所有剩余方面,并将其作为一个原子操作执行,其中包含预定义的步骤和预期的结果。让我们看看容器更新行为的选项。

Imperative Rolling Updates with kubectl Are Deprecated

不推荐使用kubectl命令进行更新

Kubernetes has supported rolling updates since its very beginning. The first implementation was imperative in nature; the client kubectl tells the server what to do for each update step.

Kubernetes从一开始就支持滚动更新。第一次执行在性质上是必要的;客户机kubectl告诉服务器每个更新步骤要做什么。

Although the kubectl rolling-update command is still present, it’s highly deprecated because of the following drawbacks of such an imperative approach:

尽管kubectl rolling update命令仍然存在,但由于这种命令式方法的以下缺点,它被高度弃用:

  • Rather than describing the desired end state, kubectl rolling-update issues commands to get the system into the desired state.
  • kubectl rolling update命令不是描述所需的最终状态,而是发出命令使系统进入所需状态。
  • The whole orchestration logic for replacing the containers and the Replication‐Controllers is performed by kubectl, which monitors and interacts with the API Server behind the scenes while the update process happens, moving an inherent server-side responsibility to the client.
  • 更换容器和复制控制器的整个编排逻辑由kubectl执行,在更新过程中,kubectl会在后台监视API服务器并与之交互,从而将固有的服务器端责任转移给客户端。
  • You may need more than one command to get the system into the desired state. These commands must be automated and repeatable in different environments.
  • 你可能需要多个命令才能使系统进入所需状态。这些命令必须是自动化的,并且可以在不同的环境中重复。
  • Somebody else may override your changes with time.
  • 随着时间的推移,其他人可能会覆盖你的更改。
  • The update process has to be documented and kept up-to-date while the service evolves.
  • 更新过程必须记录在案,并在服务发展过程中保持最新。
  • The only way to find out what we have deployed is by checking the condition of the system. Sometimes the state of the current system might not be the desired state, in which case we have to correlate it with the deployment documentation.
  • 查明我们部署了什么的唯一方法是检查系统的状况。有时,当前系统的状态可能不是所需的状态,在这种情况下,我们必须将其与部署文档相关联。

Instead, the Deployment resource object was introduced for supporting a declarative update, fully managed by the Kubernetes backend. As declarative updates have so many advantages, and imperative update support will vanish eventually, we focus exclusively on declarative updates in this pattern.

相反,引入部署资源对象是为了支持声明式更新,该更新完全由Kubernetes后端管理。由于声明式更新有很多优点,而且命令式更新支持最终将消失,因此我们只关注这种模式中的声明式更新。

2.2.2.1 Rolling Deployment

2.2.2.1 滚动式部署

The declarative way of updating applications in Kubernetes is through the concept of Deployment. Behind the scenes, the Deployment creates a ReplicaSet that supports set-based label selectors. Also, the Deployment abstraction allows shaping the update process behavior with strategies such as RollingUpdate (default) and Recreate. Example 3-1 shows the important bits for configuring a Deployment for a rolling update strategy.

Kubernetes中更新应用程序的声明方式是通过部署的概念。在后台,部署将创建一个支持基于集合的标签选择器的复制集。此外,部署抽象允许使用诸如RollingUpdate(默认)和Recreate之类的策略来塑造更新过程行为。示例3-1显示了为滚动更新策略配置部署的重要信息。

Example 3-1. Deployment for a rolling update

apiVersion: apps/v1
kind: Deployment
metadata:
  name: random-generator
spec:
  replicas: 3
#Declaration of three replicas. You need more than one replica for a rolling update to make sense.
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
#Number of Pods that can be run temporarily in addition to the replicas specified during an update. In this example, it could be a total of four replicas at maximum.
      maxUnavailable: 1
#Number of Pods that can be unavailable during the update. Here it could be that only two Pods are available at a time during the update.
    selector:
      matchLabels:
        app: random-generator
    template:
      metadata:
        labels:
          app: random-generator
        spec:
          containers:
          - image: k8spatterns/random-generator:1.0
            name: random-generator
#Readiness probes are very important for a rolling deployment to provide zerodowntime—don’t forget them (see Chapter 4, Health Probe).
            readinessProbe:
              exec:
                command: [ "stat", "/random-generator-ready" ]

RollingUpdate strategy behavior ensures there is no downtime during the update process. Behind the scenes, the Deployment implementation performs similar moves by creating new ReplicaSets and replacing old containers with new ones. One enhancement here is that with Deployment, it is possible to control the rate of a new container rollout. The Deployment object allows you to control the range of available and excess Pods through maxSurge and maxUnavailable fields. Figure 3-1 shows the rolling update process.

滚动式(RollingUpdate)策略行为确保更新过程中没有停机。在后台,部署实现通过创建新的复制集并用新容器替换旧容器来执行类似的操作。这里的一个增强功能是,通过部署,可以控制新容器卷展的速率。部署对象允许您通过maxSurge和maxUnavailable字段控制可用和多余POD的范围。图3-1显示了滚动更新过程。 image.png Figure 3-1. Rolling deployment

To trigger a declarative update, you have three options: 你可以通过以下的三种选项去触发一个声明式的更新:

  • Replace the whole Deployment with the new version’s Deployment with kubectl replace.
  • 使用kubectl Replace替换新版本的部署来替换整个部署。
  • Patch (kubectl patch) or interactively edit (kubectl edit) the Deployment to set the new container image of the new version.
  • 通过修补(kubectl Patch)或交互编辑(kubectl edit)命令部署以设置新版本的新容器映像。
  • Use kubectl set image to set the new image in the Deployment.
  • 使用kubectl set image命令在部署中设置新映像。

See also the full example in our example repository, which demonstrates the usage of these commands, and shows you how you can monitor or roll back an upgrade with kubectl rollout.

另外请参见示例代码库中的完整示例,该示例演示了这些命令的用法,并向你展示了如何使用kubectl rollout命令进行监视或回滚升级。

In addition to addressing the previously mentioned drawbacks of the imperative way of deploying services, the Deployment brings the following benefits: 除了解决前面提到的直接命令部署服务方式的缺点外,声明式部署还带来以下好处:

  • Deployment is a Kubernetes resource object whose status is entirely managed by Kubernetes internally. The whole update process is performed on the server side without client interaction.
  • 部署是Kubernetes资源对象,其状态完全由Kubernetes内部管理。整个更新过程在服务器端执行,无需客户端交互。
  • The declarative nature of Deployment makes you see how the deployed state should look rather than the steps necessary to get there.
  • 部署的声明性质使你看到部署状态应该是什么样子,而不是达到部署状态所需的步骤。
  • The Deployment definition is an executable object, tried and tested on multiple environments before reaching production.
  • 部署定义是一个可执行对象,在到达生产环境之前在多个环境中进行了尝试和测试。
  • The update process is also wholly recorded, and versioned with options to pause,continue, and roll back to previous versions.
  • 更新过程也会被完整记录,并使用暂停、继续和回滚到以前版本的选项进行版本控制。

2.2.2.2 Fixed Deployment

2.2.2.2 固定式部署

A RollingUpdate strategy is useful for ensuring zero downtime during the update process. However, the side effect of this approach is that during the update process, two versions of the container are running at the same time. That may cause issues for the service consumers, especially when the update process has introduced backwardincompatible changes in the service APIs and the client is not capable of dealing with them. For this kind of scenario, there is the Recreate strategy, which is illustrated in Figure 3-2.

RollingUpdate策略对于确保更新过程中零停机时间非常有用。然而,这种方法的副作用是,在更新过程中,容器的两个版本同时运行。这可能会给服务使用者带来问题,特别是当更新过程在服务API中引入了后向不兼容的更改,并且客户端无法处理这些更改时。对于这种情况,有一种重新创建策略,如图3-2所示。 image.png

Figure 3-2. Fixed deployment using a Recreate strategy 图3-2 固定式部署使用的是一种重新创建Pod的策略

The Recreate strategy has the effect of setting maxUnavailable to the number of declared replicas. This means it first kills all containers from the current version and then starts all new containers simultaneously when the old containers are evicted. The result of this sequence of actions is that there is some downtime while all containers with old versions are stopped, and there are no new containers ready to handle incoming requests. On the positive side, there won’t be two versions of the containers running at the same time, simplifying the life of service consumers to handle only one version at a time.

重新创建策略的作用是将maxUnavailable设置为已声明副本的数量。这意味着它首先从当前版本中删除所有容器,然后在旧容器被逐出时同时启动所有新容器。这一系列操作的结果是,当所有具有旧版本的容器都停止时,会有一些停机时间,并且没有新的容器准备好处理传入的请求。从积极的方面来看,不会有两个版本的容器同时运行,从而简化了服务使用者的生命周期,一次只处理一个版本。

2.2.2.3 Blue-Green Release

2.2.2.3 蓝绿发布

The Blue-Green deployment is a release strategy used for deploying software in a production environment by minimizing downtime and reducing risk. Kubernetes’ Deployment abstraction is a fundamental concept that lets you define how Kubernetes transitions immutable containers from one version to another. We can use the Deployment primitive as a building block, together with other Kubernetes primitives, to implement this more advanced release strategy of a Blue-Green deployment.

蓝绿部署是一种发布策略,用于通过最小化停机时间和降低风险在生产环境中部署软件。Kubernetes的部署抽象是一个基本概念,它允许您定义Kubernetes如何将不可变容器从一个版本转换到另一个版本。我们可以使用部署原语作为构建块,与其他Kubernetes原语一起,实现蓝绿部署的更高级发布策略。

A Blue-Green deployment needs to be done manually if no extensions like a Service Mesh or Knative is used, though. Technically it works by creating a second Deployment with the latest version of the containers (let’s call it green) not serving any requests yet. At this stage, the old Pod replicas (called blue) from the original Deployment are still running and serving live requests.

但是,如果没有使用诸如服务网格或Knative之类的扩展,则需要手动完成蓝绿部署。从技术上讲,它的工作原理是使用最新版本的容器(让我们称之为绿色)创建第二个部署,而不服务于任何请求。在此阶段,原始部署中的旧Pod副本(称为blue)仍在运行并服务于实时请求。

Once we are confident that the new version of the Pods is healthy and ready to handle live requests, we switch the traffic from old Pod replicas to the new replicas. This activity in Kubernetes can be done by updating the Service selector to match the new containers (tagged as green). As demonstrated in Figure 3-3, once the green containers handle all the traffic, the blue containers can be deleted and the resources freed for future Blue-Green deployments.

一旦我们确信新版本的Pods是健康的,并且可以处理实时请求,我们就将流量从旧的Pod副本切换到新的副本。Kubernetes中的这个活动可以通过更新服务选择器来匹配新容器(标记为绿色)来完成。如图3-3所示,一旦绿色容器处理了所有通信量,蓝色容器就可以被删除,并为将来的蓝绿部署释放资源。 image.png Figure 3-3. Blue-Green release

A benefit of the Blue-Green approach is that there’s only one version of the application serving requests, which reduces the complexity of handling multiple concurrent versions by the Service consumers. The downside is that it requires twice the application capacity while both blue and green containers are up and running. Also, there can be significant complications with long-running processes and database state drifts during the transitions.

蓝绿发布方法的一个好处是,只有一个版本的应用程序服务于请求,这降低了服务使用者处理多个并发版本的复杂性。缺点是,当蓝色和绿色容器都启动并运行时,它需要两倍的应用程序容量。此外,在转换过程中,长时间运行的进程和数据库状态漂移可能会带来严重的复杂性。

2.2.2.4 Canary Release

2.2.2.4  金丝雀发布

Canary release is a way to softly deploy a new version of an application into production by replacing only a small subset of old instances with new ones. This technique reduces the risk of introducing a new version into production by letting only some of the consumers reach the updated version. When we are happy with the new version of our service and how it performed with a small sample of users, we can replace all the old instances with the new version in an additional step after this canary release. Figure 3-4 shows a canary release in action.

金丝雀发布是一种将应用程序的新版本软部署到生产环境中的方法,它只使用新实例替换旧实例的一小部分。这种技术通过只让部分用户访问更新版本,降低了在生产中引入新版本的风险。当我们对新版本的服务以及它在一小部分用户中的表现感到满意时,我们可以在这个金丝雀版本发布后的额外步骤中用新版本替换所有旧实例。图3-4显示了金丝雀释放的作用。 image.png Figure 3-4. Canary release

In Kubernetes, this technique can be implemented by creating a new ReplicaSet for the new container version (preferably using a Deployment) with a small replica count that can be used as the Canary instance. At this stage, the Service should direct some of the consumers to the updated Pod instances. After the canary release and once we are confident that everything with new ReplicaSet works as expected, we scale the new ReplicaSet up, and the old ReplicaSet down to zero. In a way, we are performing a controlled and user-tested incremental rollout.

在Kubernetes中,这种技术可以通过为新容器版本创建一个新的复制集(最好使用部署)来实现,该复制集具有一个小的复制副本计数,可以用作Canary实例。在此阶段,服务应将一些使用者引导到更新的Pod实例。在金丝雀发布之后,一旦我们确信新ReplicaSet的所有功能都能按预期工作,我们就可以扩展新的ReplicaSet,将旧的ReplicaSet降到零。在某种程度上,我们正在执行一个受控的、经过用户测试的增量发布。

2.2.3 Discussion

2.2.3 讨论

The Deployment primitive is an example of where Kubernetes turns the tedious process of manually updating applications into a declarative activity that can be repeated and automated. The out-of-the-box deployment strategies (rolling and recreate) control the replacement of old containers by new ones, and the release strategies (bluegreen and canary) control how the new version becomes available to service consumers. The latter two release strategies are based on a human decision for the transition trigger and as a consequence are not fully automated but require human interaction. Figure 3-5 shows a summary of the deployment and release strategies, showing instance counts during transitions.

部署原语就是这样一个例子,Kubernetes将手动更新应用程序的繁琐过程转变为可以重复和自动执行的声明性活动。开箱即用的部署策略(滚动和重新创建)控制用新容器替换旧容器,而发布策略(蓝绿发布和金丝雀发布)控制如何向服务消费者提供新版本。后两种发布策略基于转换触发器的人工决策,因此不是完全自动化的,而是需要人工交互。图3-5显示了部署和发布策略的摘要,显示了转换期间的实例计数。 image.png Figure 3-5. Deployment and release strategies

Every software is different, and deploying complex systems usually requires additional steps and checks. The techniques discussed in this chapter cover the Pod update process, but do not include updating and rolling back other Pod dependencies such as ConfigMaps, Secrets, or other dependent services.

每个软件都是不同的,部署复杂系统通常需要额外的步骤和检查。本章讨论的技术包括Pod更新过程,但不包括更新和回滚其他Pod依赖项,如ConfigMaps、Secrets或其他依赖服务。

As of this writing, there is a proposal for Kubernetes to allow hooks in the deployment process. Pre and Post hooks would allow the execution of custom commands before and after Kubernetes has executed a deployment strategy. Such commands could perform additional actions while the deployment is in progress and would additionally be able to abort, retry, or continue a deployment. Those commands are a good step toward new automated deployment and release strategies. For now, an approach that works is to script the update process at a higher level to manage the update process of services and its dependencies using the Deployment and other primitives discussed in this book.

在撰写本文时,有人建议Kubernetes允许在部署过程中使用钩子。Pre和Post挂钩允许在Kubernetes执行部署策略之前和之后执行自定义命令。这些命令可以在部署过程中执行其他操作,还可以中止、重试或继续部署。这些命令是迈向新的自动化部署和发布策略的良好一步。目前,一种有效的方法是在更高级别编写更新过程脚本,以使用本书中讨论的部署和其他原语管理服务的更新过程及其依赖关系。

Regardless of the deployment strategy you are using, it is essential for Kubernetes to know when your application Pods are up and running to perform the required sequence of steps reaching the defined target deployment state. The next pattern, Health Probe, in Chapter 4 describes how your application can communicate its health state to Kubernetes.

无论你使用何种部署策略,Kubernetes都必须知道应用程序所在的pods何时启动并运行,以执行达到定义的目标部署状态所需的步骤序列。下一节中的下一个模式,Health Probe,描述了应用程序如何将其健康状态传递给Kubernetes。