Kubernetes在微服务中的最佳实践

标签: kubernetes 微服务 最佳实践 | 发表时间:2020-05-24 01:59 | 作者:cainzhong
出处:http://weekly.dockone.io

你可以在网上找到许多关于如何正确构建微服务体系架构的最佳实践。其中之一是我以前写的一篇文章 Spring Boot在微服务中的最佳实践。我把重点放在在生产上基于Spring Boot构建的微服务应用程序应该考虑哪些方面。我没有使用任何用于编排或管理应用程序的平台,而只是一组独立的应用程序。在本文中,我将基于已经介绍的最佳实践,在Kubernetes平台上部署微服务,你需要注意的一些新规则和事项。

第一个问题是,如果将微服务部署在Kubernetes上,而不是直接独立的运行它们,会有什么不同吗?答案可能是“相同”或者“不同”。不同在于你有了一个管理所有应用程序的平台,负责运行和监控你的应用程序,还会有一些附件的规则你需要遵守。相同在于你的整个应用程序体系仍然是微服务体系架构,由一组低耦合、独立的应用程序构成,你不应该忘记微服务体系架构的本质!在Kubernetes中,前面介绍的许多最佳实践都是依然有效的,只是有一些微调而已,还有一些新的最佳实践被引入。

有一点必须说明。这个最佳实践列表是我总结出的实际经验,并非从其他文章或书籍中抄袭而来。在我的组织中,我们已经将微服务从Spring Cloud (Eureka、Zuul、Spring Cloud Config)迁移到了OpenShift中,基于我们的维护情况,不断地演进此架构。

代码

以下所有代码由Kotlin编写,你可以在如下链接中找到所有完整代码。 sample-spring-kotlin-microservice

1. 允许平台收集指标数据

我在我上一篇文章中加入了类似的章节。当时我们使用InfluxDB作为指标数据的存储介质。但在Kubernetes中,收集指标数据的方法发生了一些变化,所以我重新定义了这一章节,“允许平台收集指标数据”。他们的主要区别在于收集数据的方式。在Kubernetes中,我们推荐使用Prometheus,因为平台可以帮助我们管理。InfluxDB需要应用程序将指标数据推送给它。而Prometheus会定期地主动拉取指标数据。因此,我们的主要职责是在应用程序端为Prometheus提供端点暴露数据。

幸运的是,通过Spring Boot为Prometheus提供端点是非常容易的。你只需要添加如下依赖。
  
org.springframework.boot
spring-boot-starter-actuator


io.micrometer
micrometer-registry-prometheus



我们还需要公开Spring Boot Actuator的HTTP端点。您可以只公开专用于Prometheus的端点,或者如下所示公开所有HTTP端点。
management.endpoints.web.exposure.include: '*'  


启动应用程序后,你可以看到如下的可用端点, /actuator/prometheus



假设您在Kubernetes上运行您的应用程序,那么您需要部署和配置Prometheus,以便从您的Pod中提取日志。配置信息可以通过Kubernetes ConfigMap来实现。 prometheus.yml文件应该包含 metrics_pathkubernetes_sd_configs。Prometheus试图通过Kubernetes Endpoints来发现应用程序的Pod。应用程序应该使用 app=sample-spring-kotlin-microservice进行标记,并公开端口。
apiVersion: v1  
kind: ConfigMap
metadata:
name: prometheus
labels:
name: prometheus
data:
prometheus.yml: |-
scrape_configs:
  - job_name: 'springboot'
    metrics_path: /actuator/prometheus
    scrape_interval: 5s
    kubernetes_sd_configs:
    - role: endpoints
      namespaces:
        names:
          - default

    relabel_configs:
      - source_labels: [__meta_kubernetes_service_label_app]
        separator: ;
        regex: sample-spring-kotlin-microservice
        replacement: $1
        action: keep
      - source_labels: [__meta_kubernetes_endpoint_port_name]
        separator: ;
        regex: http
        replacement: $1
        action: keep
      - source_labels: [__meta_kubernetes_namespace]
        separator: ;
        regex: (.*)
        target_label: namespace
        replacement: $1
        action: replace
      - source_labels: [__meta_kubernetes_pod_name]
        separator: ;
        regex: (.*)
        target_label: pod
        replacement: $1
        action: replace
      - source_labels: [__meta_kubernetes_service_name]
        separator: ;
        regex: (.*)
        target_label: service
        replacement: $1
        action: replace
      - source_labels: [__meta_kubernetes_service_name]
        separator: ;
        regex: (.*)
        target_label: job
        replacement: ${1}
        action: replace
      - separator: ;
        regex: (.*)
        target_label: endpoint
        replacement: http
        action: replace


最后一步是把Prometheus部署在Kubernetes中。将ConfigMap作为配置文件添加到Prometheus 的Deployment中。然后你就可以通过路径来使用这个配置文件了,例如, --config.file=/prometheus2/prometheus.yml
apiVersion: apps/v1  
kind: Deployment
metadata:
name: prometheus
labels:
app: prometheus
spec:
replicas: 1
selector:
matchLabels:
  app: prometheus
template:
metadata:
  labels:
    app: prometheus
spec:
  containers:
    - name: prometheus
      image: prom/prometheus:latest
      args:
        - "--config.file=/prometheus2/prometheus.yml"
        - "--storage.tsdb.path=/prometheus/"
      ports:
        - containerPort: 9090
          name: http
      volumeMounts:
        - name: prometheus-storage-volume
          mountPath: /prometheus/
        - name: prometheus-config-map
          mountPath: /prometheus2/
  volumes:
    - name: prometheus-storage-volume
      emptyDir: {}
    - name: prometheus-config-map
      configMap:
        name: prometheus


现在,您可以通过访问 /targets来验证Prometheus是否已经发现您的应用程序在Kubernetes上运行。



2. 准备正确格式的日志

收集日志的方法与收集指标数据非常类似。我们的应用程序不应该自己处理发送日志的过程。它只需要适当地格式化发送到输出流的日志。因为Docker为Fluentd提供了内置的日志驱动程序,所以在Kubernetes上运行的应用程序可以很方便地使用它作为日志收集器。这意味着在容器上不需要额外的代理来将日志推送到Fluentd。日志直接从STDOUT发送到Fluentd服务,不需要额外的日志文件或持久存储。Fluentd试图读取结构化的JSON数据,以便进行统一处理。

为了将我们的日志格式化为Fluentd可读的JSON格式,我们可以将Logstash Logback Encoder引入到我们的依赖中。
  
net.logstash.logback
logstash-logback-encoder
6.3



然后,我们只需要在logback-spring.xml文件中为我们的Spring Boot应用程序设置一个默认的控制台日志追加器。
  

    


    


    




日志以如下所示的格式打印到STDOUT中。



在Minikube上安装Fluentd, Elasticsearch和Kibana非常简单。这种方法的缺点是版本不够新。
$ minikube addons enable efk  
* efk was successfully enabled
$ minikube addons enable logviewer
* logviewer was successfully enabled


启用efk和logviewer插件后,Kubernetes启动所有必需的Pod,如下所示。



感谢logstash-logback-encoder,我们可以自动创建与Fluentd兼容的日志,包括MDC字段。这是Kibana的页面截图,显示了我们的应用程序的日志。



您还可以添加我的库来记录Spring Boot应用程序的请求/响应。
  
com.github.piomin
logstash-logging-spring-boot-starter
1.2.2.RELEASE



3.实现LIVENESS和READINESS健康检查

理解Kubernetes中liveness探针和readiness探针的区别是很重要的。不正确使用这些探针,可能会降低服务的整体操作性,例如导致不必要的重新启动容器。liveness探针用于判断是否需要重启容器。如果应用程序因为任何原因不可用,重新启动容器有时是有意义的。而readiness探针用于确认容器是否能够处理请求。如果readiness探针失败,则将应用程序从负载平衡中移除。readiness探针的失败不会导致Pod重新启动。对于web应用程序来说,最典型的liveness探针和readiness探针是通过HTTP端点实现的。

不在Kubernetes平台之上运行的典型web应用程序,您不会区分liveness探针和readiness探针的健康检查。这就是为什么大多数web框架只提供一个内置的健康检查。对于Spring Boot应用程序,您可以通过Spring Boot Actuator轻松地启用健康检查。您需要注意Spring Boot Actuator的健康检查,它的行为可能会因应用程序和第三方系统之间的集成而有所不同。例如,如果通过Spring datasource定义了数据库连接,或与其他消息中间件的连接。Spring Boot Actuator的健康检查可能会通过自动配置自动包含此类连接的验证。因此,如果将默认的Spring Boot Actuator的健康检查设置为readiness探针,则在应用程序无法连接数据库或其他消息中间件时可能导致不必要的重新启动。由于不希望出现这种行为,我建议您应该实现非常简单的liveness探针端点,它只验证应用程序的可用性,而不检查与其他外部系统的连接。

自定义实现Spring Boot的健康检查并不是很难。有一些不同的方法可以做到这一点。比如,我们正在使用 Spring Boot Actuator。值得注意的是,我们不会覆盖默认的健康检查,但我们将添加另一个自定义的健康检查。下面的实现只是检查应用程序是否能够处理传入的请求。
@Component  
@Endpoint(id = "liveness")
class LivenessHealthEndpoint {

@ReadOperation
fun health() : Health = Health.up().build()

@ReadOperation
fun name(@Selector name: String) : String = "liveness"

@WriteOperation
fun write(@Selector name: String) {

}

@DeleteOperation
fun delete(@Selector name: String) {

}

}


反过来,默认的Spring Boot Actuator的健康检查可以作为readiness探针使用。假设您的应用程序将连接到数据库Postgres和RabbitMQ消息代理,您应该将以下依赖项添加到Maven pom.xml中。
  
org.springframework.boot
spring-boot-starter-amqp


org.springframework.boot
spring-boot-starter-data-jpa


org.postgresql
postgresql
runtime



现在,为了获得更多信息,请将以下属性添加到您的application.yml。通过 /health端点查看更多详细信息。
management:  
endpoint:
health:
  show-details: always


最后,让我们调用 /actuator/health查看详细信息。正如您在下图中看到的,结果中返回了有关Postgres和RabbitMQ连接的信息。



在web应用程序中使用liveness探针和readiness探针还有另一个注意点。这与线程池有关。在像Tomcat这样的标准web容器中,每个请求都由HTTP线程池处理。如果您在主线程中处理每个请求,并且您的应用程序中有一些长时间运行的任务,那么您可能会阻塞所有可用的HTTP线程。如果你的liveness探针连续几次失败,Pod将会被重新启动。因此,您应该考虑使用另一个线程池来实现长时间运行的任务。下面是使用DeferredResult和Kotlin协程实现HTTP端点的示例。
@PostMapping("/long-running")  
fun addLongRunning(@RequestBody person: Person): DeferredResult {
var result: DeferredResult  = DeferredResult()
GlobalScope.launch {
    logger.info("Person long-running: {}", person)
    delay(10000L)
    result.setResult(repository.save(person))
}
return result
}


4. 考虑其他应用程序集成

如果没有任何外部系统,如数据库、消息中间件或其他应用程序,我们的应用程序几乎不可能存在。与第三方应用程序的集成有两个方面需要仔细考虑:连接设置和资源的自动创建。

让我们从连接设置开始。您可能还记得,在上一节中,我们使用Spring Boot Actuator的 /health 端点作为readiness探针。但是,如果您为Postgres和Rabbit保留默认连接设置,那么每次readiness探针调用都需要很长时间(如果它们不可用的话)。这就是为什么我建议将这些超时时间减少到更低值,如下所示。
spring:  
application:
name: sample-spring-kotlin-microservice
datasource:
url: jdbc:postgresql://postgres:5432/postgres
username: postgres
password: postgres123
hikari:
  connection-timeout: 2000
  initialization-fail-timeout: 0
jpa:
database-platform: org.hibernate.dialect.PostgreSQLDialect
rabbitmq:
host: rabbitmq
port: 5672
connection-timeout: 2000


除了正确配置的连接超时之外,还应该保证自动创建应用程序所需的资源。例如,如果在两个应用程序之间使用RabbitMQ队列进行异步消息传递,则应确保在启动时创建队列(如果不存在),通常在应用程序的监听器端实现。
@Configuration  
class RabbitMQConfig {

@Bean
fun myQueue(): Queue {
    return Queue("myQueue", false)
}

}


以下是一个监听器端的例子。
@Component  
class PersonListener {

val logger: Logger = LoggerFactory.getLogger(PersonListener::class.java)

@RabbitListener(queues = ["myQueue"])
fun listen(msg: String) {
    logger.info("Received: {}", msg)
}

}


跟数据库集成也是类似的情况。首先,即使连接数据库失败,也应该确保应用程序启动。这就是为什么我使用PostgreSQLDialect。如果应用程序无法连接到数据库,则需要使用此方法。此外,实体模型中的每个更改都应该在应用程序启动之前应用于表。

幸运的是,Spring Boot为管理数据库表结构更改提供了一些工具,比如Liquibase和Flyway。要启用Liquibase,我们只需要在Maven pom.xml中包含以下依赖项。
  
org.liquibase
liquibase-core



然后,您只需要创建更改日志,并将其放在默认位置db/changelog/db.changelog-master.yaml中。下面是用于创建表person的示例。
databaseChangeLog:  
- changeSet:
  id: 1
  author: piomin
  changes:
    - createTable:
        tableName: person
        columns:
          - column:
              name: id
              type: int
              autoIncrement: true
              constraints:
                primaryKey: true
                nullable: false
          - column:
              name: name
              type: varchar(50)
              constraints:
                nullable: false
          - column:
              name: age
              type: int
              constraints:
                nullable: false
          - column:
              name: gender
              type: smallint
              constraints:
                nullable: false


5. 使用服务网格

如果您不使用Kubernetes构建微服务架构,那么您需要在应用程序端实现负载平衡、断路、回退或重试等机制。流行的云原生框架,如Spring Cloud简化了应用程序中这些模式的实现,并将其简化为向项目添加专用库。但是,如果将微服务迁移到Kubernetes,就不应该继续使用这些库来进行流量管理。它正在成为某种反模式。微服务之间通信的流量管理应该委托给平台。这种方法在Kubernetes上称为服务网格。

由于Kubernetes最初并没有专门用于微服务,所以它没有为许多应用程序之间的流量管理提供任何内置机制。不过,还有一些专门用于流量管理的附加解决方案,可以很容易地安装在Kubernetes上。其中最受欢迎的一个是Istio。除了流量管理,它还解决了与安全、监视、跟踪和指标数据收集相关的问题。

Istio可以很容易地安装在您的集群或Minikube上。下载Istio之后,只需运行以下命令。
istioctl manifest apply  


Istio组件需要注入到部署清单中。在此之后,我们可以使用YAML清单定义通信规则。Istio提供了许多有趣的配置选项。下面的示例显示如何将故障注入到现有路由。它可以是延迟,也可以是中止。我们可以使用percent字段为这两种类型的错误定义一个百分比级别。在Istio资源中,我为每个发送到Service account-service的请求定义了2秒的延迟。
apiVersion: networking.istio.io/v1alpha3  
kind: VirtualService
metadata:
name: account-service
spec:
hosts:
- account-service
http:
- fault:
  delay:
    fixedDelay: 2s
    percent: 100
route:
- destination:
    host: account-service
    subset: v1


除了VirtualService,我们还需要为 account-service定义DestinationRule。这非常简单,我们只需定义目标服务的版本标签。
apiVersion: networking.istio.io/v1alpha3  
kind: DestinationRule
metadata:
name: account-service
spec:
host: account-service
subsets:
- name: v1
labels:
  version: v1


6. 允许添加外部解决方案

Kubernetes有很多有趣的工具和解决方案,它们可以帮助您运行和管理应用程序。但是,您也不应该忘记您所使用的框架所提供的一些有趣的工具和解决方案。让我给你举几个例子。其中一个是Spring Boot Admin。它是一个有用的工具,用于发现Spring Boot应用程序。假设你在Kubernetes上运行微服务,你也可以在Kubernetes中安装Spring Boot Admin。

在Spring Cloud中还有另一个有趣的项目——Spring Cloud Kubernetes。它提供了一些有用的特性,简化了Spring Boot应用程序和Kubernetes之间的集成。其中之一是跨所有命名空间的服务发现。如果您将该功能与Spring Boot Admin一起使用,那么您可以轻松创建一个强大的工具,它能够监视运行在Kubernetes集群上的所有Spring Boot微服务。有关实现的更多细节,可以参考我的另一篇文章 Spring Boot Admin on Kubernetes

有时,您可以将第三方工具与Spring Boot集成来轻松地在Kubernetes上部署,而无需构建单独的部署。您甚至可以构建一个由多个实例组成的集群。此方法适用于可嵌入到Spring Boot应用程序中的产品。它可以是,例如RabbitMQ或Hazelcast(流行的内存数据网格)。如果您对使用这种方法在Kubernetes上运行Hazelcast集群的更多细节感兴趣,请参阅我的文章 Hazelcast with Spring Boot on Kubernetes

7. 为回滚做好准备

Kubernetes提供了一种方便的方法,可以基于 ReplicaSetDeployment对象将应用程序回滚到旧版本。在默认情况下,Kubernetes保留了10个之前的 ReplicaSet,并允许您回滚到其中任何一个 ReplicaSet。然而,有一件事需要指出。回滚不包括存储在ConfigMap和Secret中的配置。有时不仅需要回滚应用程序的二进制文件,还需要回滚配置。

幸运的是,Spring Boot为我们管理外部配置提供了可能性。我们可以将配置文件保存在应用程序内部,也可以从外部位置加载它们。在Kubernetes上,我们可以使用ConfigMap和Secret来定义Spring配置文件。用ConfigMap定义 application-rollbacktest.ymlapplication-rollbacktest.yml只包含一个属性。只有当Spring配置文件rollbacktest被激活时,应用程序才加载该配置。
apiVersion: v1  
kind: ConfigMap
metadata:
name: sample-spring-kotlin-microservice
data:
application-rollbacktest.yml: |-
property1: 123456


ConfigMap通过挂载卷的方式添加到应用程序中。
spec:  
containers:
- name: sample-spring-kotlin-microservice
image: piomin/sample-spring-kotlin-microservice
ports:
- containerPort: 8080
   name: http
volumeMounts:
- name: config-map-volume
   mountPath: /config/
volumes:
- name: config-map-volume
   configMap:
     name: sample-spring-kotlin-microservice


在应用程序的类路径上也存在 application.yml,包含一个属性。
property1: 123  


第二步,我们将激活rollbacktest配置文件。因为,特定配置文件 application-rollbacktest.yml具有比 application.yml更高的优先级。属性 property1的值将被 application-rollbacktest.yml中的值覆盖。
property1: 123  
spring.profiles.active: rollbacktest


让我们简单测试一下。
@RestController  
@RequestMapping("/properties")
class TestPropertyController(@Value("\${property1}") val property1: String) {

@GetMapping
fun printProperty1(): String  = property1

}     


让我们看看如何回滚Deployment版本。首先,让我们看看有多少个版本。
$ kubectl rollout history deployment/sample-spring-kotlin-microservice  
deployment.apps/sample-spring-kotlin-microservice
REVISION  CHANGE-CAUSE
1         
2         
3  


现在,我们调用端点 /properties,它返回属性 property1的值。因为配置文件 application-rollbacktest.yml处于激活状态,返回 application-rollbacktest.yml中的属性值。
$ curl http://localhost:8080/properties  
123456


让我们回滚到以前的版本。
$ kubectl rollout undo deployment/sample-spring-kotlin-microservice --to-revision=2  
deployment.apps/sample-spring-kotlin-microservice rolled back


正如下图所示,已经看不到 revision=2,Deployment现在被部署为最新的 revision=4
$ kubectl rollout history deployment/sample-spring-kotlin-microservice  
deployment.apps/sample-spring-kotlin-microservice
REVISION  CHANGE-CAUSE
1         
3         
4    


在此版本的应用程序配置文件中, application-rollbacktest.yml未处于激活状态,因此属性 property1的值取自 application.yml
$ curl http://localhost:8080/properties  
123

相关 [kubernetes 微服务 最佳实践] 推荐:

Kubernetes在微服务中的最佳实践

- - DockOne.io
你可以在网上找到许多关于如何正确构建微服务体系架构的最佳实践. 其中之一是我以前写的一篇文章 Spring Boot在微服务中的最佳实践. 我把重点放在在生产上基于Spring Boot构建的微服务应用程序应该考虑哪些方面. 我没有使用任何用于编排或管理应用程序的平台,而只是一组独立的应用程序. 在本文中,我将基于已经介绍的最佳实践,在Kubernetes平台上部署微服务,你需要注意的一些新规则和事项.

2023年 Kubernetes 最佳实践

- - IT瘾-dev
作为容器编排平台,Kubernetes(K8s)具有诸多优势. 例如,K8s 在工作负载发现、自我修复和应用容器化扩展等方面具备很强的自动化能力. 然而,在经过一些调整后,Kubernetes 并不总是适用于生产环境. 本文向您分享了一些重要的 Kubernetes 最佳实践,以提高您的 K8s 安全性、性能和成本.

Kubernetes 服务部署最佳实践(一)

- - 腾讯云容器团队
业务容器化后,如何将其部署在 K8S 上. 如果仅仅是将它跑起来,很简单,但如果是上生产,我们有许多地方是需要结合业务场景和部署环境进行方案选型和配置调优的. 比如,如何设置容器的 Request 与 Limit、如何让部署的服务做到高可用、如何配置健康检查、如何进行弹性伸缩、如何更好的进行资源调度、如何选择持久化存储、如何对外暴露服务等.

最全Kubernetes加固指南:12个最佳实践,防止Kubernetes配置错误

- - DockOne.io
在容器环境中,Kubernetes管理着拥有数个、数百个甚至数千个节点的容器集群,其配置的重要性不可忽略. Kubernetes的配置选项很复杂,一些安全功能并非默认开启,这加大了安全管理难度. 如何有效地使用包括Pod安全策略、网络策略、API服务器、Kubelet及其他Kubernetes组件和功能策略建立安全的Kubernetes环境.

生产环境中的Kubernetes最佳实践

- - DockOne.io
2020年,12月1日 Pavan Belagatti. DevOps从提出到现在,已经走过了一段很长的路. 包括Docker和Kubernetes在内的多种平台也已经帮助企业用前所未有的速度实现了软件应用的交付. 同时,随着应用的容器化构建和发布比率不断上升,作为事实上的容器编排工具,Kubernetes在企业用户中备受欢迎和广泛认可.

五大Kubernetes最佳实践_Docker的专栏-CSDN博客

- -
在最近的一次Weave用户组在线会议WOUG[1]上两个工程师做了Kubernetes相关的分享. 谷歌云的开发者布道师Sandeep Dinesh(@SandeepDinesh)做了一个演讲,给大家列举了在Kubernetes上运行应用的最佳实践清单;Jordan Pellizzari(@jpellizzari),是来自Weaveworks的工程师,随后也做了一个分享,内容是在他们使用Kubernetes开发运行SaaS Weave Cloud两年之后学到的经验教训.

从Uber微服务看最佳实践如何炼成?

- - 程序猿DD
导读:Uber成长非常迅速,工程师团队快速扩充,据说Uber有2000名工程师,8000个代码仓库,部署了1000多个微服务. 微服务架构是Uber应对技术团队快速增长,功能快速上线很出色的解决方案. 本文偏向微服务的入门篇,以Uber微服务为例,进行了深入浅出的讲解. 对于微服务没有适当的定义,你可以说它是一个框架,由小型的、独立的可部署的服务组成,执行不同的操作.

同程旅游微服务最佳实践 – ITPUB

- -
本文首发胖波聊架构界,微信公众号:xiaobo2as. 如何从单体架构平滑过渡到微服务. 同程微服务从立项到实施推广已经走过了整整两个年头,从最初的简单粗糙到今天的精细完善,接入服务数量也实现了从1到10,000+的增长. 微服务开发团队和大家一起踩过了无数的坑,最终打造了今天的DSF2.0平台. 回顾爬坑记录,现整理一些爬坑心得体验供大家参考,也斗胆提出一些最佳实践以抛砖引玉.

Spring Boot在微服务中的最佳实践

- - DockOne.io
在本文中,我将列出构建Spring Boot应用程序的“金科玉律”,这些应用程序是微服务系统一部分. 这些“金科玉律”都来自我过往的经验,我曾经将运行在JEE服务器上的单体SOAP应用程序迁往基于REST的小型Spring Boot应用程序. 这些最佳实践假设你的产品上已经拥有许多微服务,且每天要应对海量的请求.

在 Kubernetes 中部署高可用性应用程序的最佳实践 - 第1部分 Best practices for deploying highly available apps in Kubernetes. Part 1 – Flant blog

- -
如您所知,在 Kubernetes 中部署一个基本可行的应用程序配置是轻而易举的事. 另一方面,试图使您的应用程序尽可能地可用和容错不可避免地会带来大量的障碍和陷阱. 在本文中,我们分解了我们认为在 Kubernetes 中部署高可用性应用程序并以简洁的方式共享它们时最重要的规则. 请注意,我们不会使用任何开箱即用的功能.