---
title: 'GitOps 实践理论：Kubernetes 部署策略深入解析'
ShowRssButtonInSectionTermList: true
date: 2023-11-25T18:00:31+08:00
draft: false
showtoc: true
tocopen: false
type: posts
author: '熊鑫伟，我'
keywords: ['GitOps', 'Kubernetes', 'Argo Rollouts', 'Canary Deployment', 'Blue-Green Deployment', 'Deployment Strategies', 'DevOps', 'Cloud Native', 'Service Mesh', 'Container Orchestration']
tags: ["GitOps", "Kubernetes", "Argo Rollouts", "Canary Deployment", "Blue-Green Deployment"]
categories: ["AI & Technology"]
description: '探索 GitOps 在 Kubernetes 中的实践，详细解析使用 Argo Rollouts 实现金丝雀和蓝绿部署策略。本文将为开发者提供深入的理论和实践指导，帮助优化持续部署流程。'
tldr:
  - "GitOps通过将Git作为真实状态源，结合Kubernetes Operator和自动化工具实现持续部署的完整流程，从代码提交到集群部署全程自动化，确保声明式配置和版本控制。"
  - "Kubernetes命名空间作为环境边界支撑多环境管理，包含代码、运行时和配置三要素，通过RBAC、网络策略和资源隔离实现QA、E2E、Stage和Prod等环境的安全隔离。"
  - "蓝绿部署和金丝雀部署是Argo Rollouts实现的高级部署策略，蓝绿部署适合需要快速切换和回滚的遗留应用，金丝雀部署通过渐进式流量转移和实时监控最小化新版本发布风险。"
---


今天我们来看看 kubernetes 和 gitops 的理论实践

## 命令介绍

首先我们来看看 kubectl 支持的子命名，方便我们使用：

1. **`kubectl apply`** - 应用一个或多个资源的定义。通常用于部署应用程序或更新资源。
2. **`kubectl get`** - 显示一个或多个资源的信息。这是查看 Kubernetes 集群中资源状态的常用命令。
3. **`kubectl describe`** - 显示一个或多个资源的详细信息，如事件、状态和配置。
4. **`kubectl delete`** - 删除 Kubernetes 集群中的资源。
5. **`kubectl exec`** - 在集群中的容器里执行命令。
6. **`kubectl logs`** - 打印容器的日志。
7. **`kubectl create`** - 从文件或标准输入中创建一个或多个资源。
8. **`kubectl edit`** - 编辑集群中的资源。这将打开一个编辑器来修改资源的配置。
9. **`kubectl port-forward`** - 将本地端口转发到集群中的 Pod。
10. **`kubectl run`** - 在集群中运行一个指定的镜像。
11. **`kubectl scale`** - 调整资源（如 Deployment、ReplicaSet）的副本数量。
12. **`kubectl rollout`** - 管理资源的部署，如查看状态、暂停、恢复或回滚更新。

**除了上面的命令，Kubernetes 中的 kubectl 还支持注解：**

`kubectl annotate` 命令用于给 Kubernetes 集群中的资源添加或更新注解（annotations）。注解是一种附加信息，可以用于存储非识别性的元数据。它们通常用于管理工具、库和客户端以存储辅助信息，例如描述、版本信息等。

```bash
kubectl annotate [type] [name] [key]=[value]
```



## Operator

optrator 和 controller 是经常混淆的两个术语，kubernetes operator 是一个应用特定的控制器，它扩展 Kubernetes API 来代表 Kubernetes 的实际用户去创建、配置和管理复杂的有状态应用实例，它在基础的 Kubernetes 资源和控制器概念上去建立的。

**所有的 Operator 都使用 Controller 的模式，但并非所有的 Controller 都是 Operator。**

首先，**Controller** 是 Kubernetes 中的一个核心概念。它是一个循环，不断监视集群的状态，并在必要时采取行动以将当前状态转变为所需状态。Controller 通过与 Kubernetes API 交互来实现这一点。例如，一个 Deployment Controller 负责确保指定数量的 Pod 副本正在运行。

相比之下，**Operator** 是一种更特定的控制器类型。Kubernetes Operator 是为了管理复杂、有状态的应用程序而设计的。它不仅包含标准的控制器功能，还扩展了 Kubernetes API，以便更好地管理特定应用程序的生命周期。例如，一个数据库 Operator 可以负责部署数据库、备份数据、恢复数据等。

关键区别在于：

+ **Controller** 通常是更通用的，负责管理 Kubernetes 中的标准资源，如 Pods、Deployments 等。
+ **Operator** 是一种特殊类型的 Controller，专门用于管理特定的、通常是复杂的应用程序。它们使用自定义资源（Custom Resources）来表示应用程序的状态，并实现特定于该应用程序的业务逻辑。

因此，**所有的 Operator 都使用 Controller 的模式，但并非所有的 Controller 都是 Operator**。这是因为所有 Operator 都是构建在控制器模式之上的，但控制器不一定需要具有管理特定应用程序生命周期的复杂逻辑和扩展 API 的能力，这是 Operator 特有的。



### 实现一个 Operator

我们了解了 Controller 的基础知识以及 Controller 和 Operator 之间的区别之后，我们准备实现一个 Operator 。示例 Operator 将解决实际环境中的任务：管理一组带有预配置静态资源内容的 Nginx 服务器。改 Operator 支持 用户 指定 Nginx 服务器列表，并且配置安装在每一个服务上的静态文件。

很容易想到的是，ConfigMap 是我们用来做环境变量，命令行参数或者卷轴的配置使用的。

Kubernetes 的控制器是可以使用任何一种语言来实现的，我们用 bash 来简单介绍一下


创建一个完整的 Kubernetes Operator 案例，尤其是涉及到 Nginx 服务器管理的 Operator，可以分为几个主要部分：定义 CRD（Custom Resource Definition），编写 Operator 控制器代码，以及部署和测试 Operator。在这个示例中，我们会使用一种更常用的语言如 Go，因为它提供了更强大的工具和库来与 Kubernetes API 交互。我们将通过以下步骤创建一个简单的 Operator：

### 定义 CRD

首先，定义一个 CRD 来表示 Nginx 的配置。这个 CRD 将描述 Nginx 实例的属性，如版本、配置文件内容和相关的静态资源。

```yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: nginxconfigs.example.com
spec:
  group: example.com
  versions:
    - name: v1
      served: true
      storage: true
  scope: Namespaced
  names:
    plural: nginxconfigs
    singular: nginxconfig
    kind: NginxConfig
    shortNames:
    - ngxconf
```

### 2. 编写 Operator 控制器

使用 Go 语言编写 Operator 控制器。Operator 控制器将监听 NginxConfig 资源的创建、更新和删除事件，并执行相应的操作。

```go
package main

import (
    // 引入必要的库
)

func main() {
    // 初始化客户端、监听 NginxConfig 资源的变化
    // 实现业务逻辑：创建/更新/删除 Nginx 实例
}
```

### 3. 处理 Nginx 实例

在控制器中，处理 Nginx 实例的创建和更新。当一个 NginxConfig 资源被创建或更新时，控制器会根据定义的规格来设置 Nginx Pod，包括所需的配置和静态文件。

### 4. 创建 Docker 镜像和部署 Operator

将 Operator 打包成 Docker 镜像，然后在 Kubernetes 集群中部署这个镜像。

```bash
# 使用合适的基础镜像
FROM golang:1.15

# 添加 Operator 代码
ADD . /operator
WORKDIR /operator

# 编译 Operator
RUN go build -o operator .

# 设置启动命令
CMD ["./operator"]
```

部署到 Kubernetes：

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-operator
spec:
  replicas: 1
  selector:
    matchLabels:
      name: nginx-operator
  template:
    metadata:
      labels:
        name: nginx-operator
    spec:
      containers:
      - name: operator
        image: nginx-operator:latest
```

### 5. 测试 Operator

创建一个 NginxConfig 实例来测试 Operator：

```yaml
apiVersion: "example.com/v1"
kind: NginxConfig
metadata:
  name: my-nginx
spec:
  version: "latest"
  staticContent: "Welcome to Nginx!"
```

监视 Kubernetes 集群，确保 Operator 正确响应了这个 NginxConfig 实例的创建。

### 注意事项

+ **错误处理和资源清理**：确保 Operator 能够优雅地处理错误和资源的生命周期。
+ **权限和安全**：确保 Operator 有适当的权限来管理 Kubernetes 资源，并考虑安全性。
+ **测试和验证**：在生产环境部署前，充分测试 Operator 的行为。



## 简单的 CICD 入门

接下来，我们首先创建一个 GitOps Operator 来驱动持续交付。

GitOps 是一种用于持续部署的实践，它将 Git 作为真实状态的源。在 GitOps 模型中，所有的部署和环境配置都存储在 Git 仓库中，这样做可以提供版本控制、审计跟踪和回滚能力。为了实现 GitOps，我们可以创建一个 GitOps Operator，它将自动化从 Git 仓库到 Kubernetes 集群的部署过程。



### 创建 GitOps Operator 的步骤

1. **定义 GitOps Operator 的职责**：
   + 监听 Git 仓库的变化。
   + 当仓库中的定义（如 Kubernetes 部署文件）发生变化时，自动应用这些变化到 Kubernetes 集群。
   + 确保集群状态与 Git 仓库中定义的状态保持一致。
2. **选择工具和框架**：
   + 使用如 Operator SDK 或 Kubebuilder 等工具可以简化 Operator 的创建和管理过程。
   + 对于 Git 交互，可以使用 Git 客户端库，例如 Go-git（对于 Go 语言）。
3. **实现 GitOps Operator**：
   + 使用 CRD 定义 GitOps 配置，包括 Git 仓库的 URL、分支、路径等。
   + 编写 Operator 控制器逻辑来处理这些自定义资源，包括从 Git 仓库克隆代码、解析 Kubernetes 配置文件，并将其应用到集群中。
4. **部署和测试 Operator**：
   + 将 Operator 容器化，部署到 Kubernetes 集群。
   + 创建 GitOps 配置资源来测试 Operator，确保它能正确地从 Git 仓库拉取和部署配置。
5. **整合持续集成流程**：
   + 将 GitOps Operator 集成到 CI 流程中，以自动触发集群的更新。
   + 在代码提交到 Git 仓库后，CI 工具（如 Jenkins、GitLab CI 或 GitHub Actions）可以运行测试，合并代码，触发 Operator 应用更新。



### 实现 GitOps Operator

1. **定义 GitOps CRD**：

   + 创建一个 Custom Resource Definition（CRD），用于表示 GitOps 配置。这个 CRD 应该包括 Git 仓库的地址、分支、以及路径。

   ```yanl
   apiVersion: apiextensions.k8s.io/v1
   kind: CustomResourceDefinition
   metadata:
     name: gitopsconfigs.gitops.example.com
   spec:
     group: gitops.example.com
     versions:
       - name: v1
         served: true
         storage: true
     scope: Namespaced
     names:
       plural: gitopsconfigs
       singular: gitopsconfig
       kind: GitOpsConfig
       shortNames:
       - goc
   ```

2. **编写 Operator 控制器**：

   + 使用 Go、Python 或其他编程语言编写 Operator 控制器。
   + 控制器应当监听 GitOpsConfig 资源的变化，并根据其定义的 Git 仓库信息同步配置。
   + 控制器应当能够从 Git 仓库克隆配置文件，解析 Kubernetes 部署文件，并将其应用到集群中。

3. **构建和部署 Operator**：

   + 创建 Docker 镜像并将 Operator 部署到 Kubernetes 集群。

4. **测试 Operator**：

   + 在 Git 仓库中更新 Nginx 的配置或版本。
   + 观察 Operator 是否自动将更新应用到 Kubernetes 集群。

### 持续集成 (CI) 集成

1. **设置 CI 工具**：
   + 选择一个 CI 工具（如 Jenkins、Travis CI、GitHub Actions）。
   + 在 Git 仓库中设置 CI 流程，以在代码提交时运行测试。
2. **自动化触发**：
   + 配置 CI 工具在代码变更被合并到主分支后自动通知 Kubernetes 集群，触发 GitOps Operator 应用更新。

### 完整的 GitOps 流程

+ 开发人员提交代码到 Git 仓库。
+ CI 工具在代码合并到主分支时运行测试。
+ GitOps Operator 监听到 Git 仓库的变化，自动同步更新到 Kubernetes 集群。



## 环境管理

不同的运行时环境，以及 Kubernetes 命名空间是如何定义环境边界的。

一个环境是由三个同样重要的部分组成的：

+ 代码
+ 满足先决条件的运行时
+ 配置

**代码：**

代码是应用程序执行特定任务的机器指令。要执行代码，可能还需要运行时依赖项。例如，Node.js代码需要Node.js二进制包和其他NPM包才能成功地执行。对于Kubernetes，所有运行时依赖项和代码都打包为一个可部署单元（又名Docker映像），并通过Docker守护进程进行编排。应用程序的Docker映像可以放心地在任何环境中运行，从开发人员的笔记本电脑到在云中运行的生产集群，因为映像封装了代码和所有依赖关系，消除了环境之间潜在的不兼容性。

在软件部署中，环境是部署和执行代码的地方。在软件开发的生存周期中，不同的环境服务于不同的目的。例如，本地开发环境（又名笔记本电脑）是工程师可以创建、测试和调试新代码版本的地方。在工程师完成代码开发后，下一步是将更改提交到Git，并开始部署到不同的环境中进行集成测试和最终的产品发布。这个过程被称为持续集成/持续部署（CI/CD），通常由以下环境组成：

+ QA
+ E2E
+ 阶段和产品

在QA环境中，新代码将根据硬件、数据和其他类似于生产的依赖项进行测试，以确保服务的正确性。如果所有的测试都通过了QA，新的代码将被提升到E2E环境，作为其他预发布服务测试/集成的稳定环境。QA和E2E环境也称为预生产（preprod）环境，因为它们不承载生产流量或使用生产数据。当一个新版本的代码准备好用于生产发布时，代码通常会首先部署在Stage环境中（它可以访问实际的生产依赖），以确保在代码进入Prod环境之前，所有的生产依赖都已到位。例如，新代码可能需要一个新的数据库模式更新，而Stage环境可以用来验证新模式是否正确。配置只将测试流量定向到Stage环境，这样新代码引入的任何问题都不会影响实际客户。但是，Stage环境通常配置为使用“真实的”生产数据库操作。在Stage环境中进行的测试必须经过仔细的审查，以确保它们在生产中是安全的。所有测试在Stage中通过后，新代码将最终部署到Prod中，用于实时生产流量。因为Stage和Prod都可以访问生产数据，所以它们都被认为是生产环境。



**命名空间管理**

命名空间是Kubernetes中支持环境的自然构造。它们允许在多个团队或项目之间划分群集资源。命名空间为唯一资源命名、资源配额、RBAC、硬件隔离和网络配置提供了范围：

`Kubernetes 命名空间~=环境`

在每个命名空间中，应用程序实例（又名Pod）是一个或多个Docker容器，在部署过程中注入了环境特定的应用程序属性。这些应用程序属性定义了环境应该如何运行（比如feature flag）以及应该使用哪些外部依赖（比如数据库连接字符串）。除了应用程序Pod之外，Namespace还可以包含提供环境所需的附加功能的其他Pod。

Namespace相当于Kubernetes中的环境。命名空间可以由Pods（应用程序实例）、网络策略（入口/出口）和RBAC（访问控制），以及在单独的Pod中运行的应用程序依赖。

RBAC是一种根据企业内各个用户的角色来管理对计算机或网络资源的访问的方法。在Kubernetes中，角色包含表示一组权限的规则。权限纯粹是加性的（没有否定规则）。角色可以使用角色在命名空间中定义，也可以使用Cluster Role在集群范围内定义。命名空间还可以具有专用的硬件和网络策略，以便根据应用程序需求对其配置进行优化。例如，CPU密集型应用程序可以部署在具有专用多核硬件的命名空间中。另一个需要重磁盘的服务我/O可以部署在具有高速SSD的单独命名空间中。每个名称空间还可以定义自己的网络策略（入口/出口），以限制跨名称空间流量或使用非限定DNS名称访问集群中的其他名称空间。



### 环境模拟

模拟两个环境，分别是 测试环境（qa) 以及非生产 e2e 环境（e2e)

首先，为您的每个来宾簿环境创建guestbook-qa和guestbook-e2e命名空间:

```bash
$ kubectl create namespace guestbook-qa
$ kubectl create namespace guestbook-e2
$ kubectl get namespaces
```

 现在，您可以使用以下命令将留言簿应用程序部署到留言簿-qa环境:

```bash
$ export K8S_GUESTBOOK_URL=https://raw.githubusercontent.com/kubernetes/website/main/content/zh-cn/examples/application/guestbook/redis-leader-deployment.yaml
$ kubectl apply -n guestbook-qa -f ${K8S_GUESTBOOK_URL}/redis-master-deployment.yaml
```

查询 Pod 列表以验证 Redis Pod 是否正在运行：

```shell
$ kubectl get pods -n guestbook-qa
NAME                            READY   STATUS    RESTARTS   AGE
redis-leader-5596fc7b68-wxjvp   1/1     Running   0          77s
```

运行以下命令查看 Redis Deployment 中的日志：

```bash
$ kubectl logs -f deployment/redis-leader -n guestbook-qa 
1:C 26 Nov 2023 05:57:07.309 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:C 26 Nov 2023 05:57:07.309 # Redis version=6.0.5, bits=64, commit=00000000, modified=0, pid=1, just started
1:C 26 Nov 2023 05:57:07.309 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
1:M 26 Nov 2023 05:57:07.311 * Running mode=standalone, port=6379.
1:M 26 Nov 2023 05:57:07.311 # Server initialized
1:M 26 Nov 2023 05:57:07.311 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
1:M 26 Nov 2023 05:57:07.311 * Ready to accept connections
```



### 创建 Redis 领导者服务

留言板应用需要往 Redis 中写数据。因此，需要创建 [Service](https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/) 来转发 Redis Pod 的流量。Service 定义了访问 Pod 的策略。

留言板应用需要往 Redis 中写数据。因此，需要创建 [Service](https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/) 来转发 Redis Pod 的流量。Service 定义了访问 Pod 的策略。

[`application/guestbook/redis-leader-service.yaml`](https://raw.githubusercontent.com/kubernetes/website/main/content/zh-cn/examples/application/guestbook/redis-leader-service.yaml) 

```yaml
# 来源：https://cloud.google.com/kubernetes-engine/docs/tutorials/guestbook
apiVersion: v1
kind: Service
metadata:
  name: redis-leader
  labels:
    app: redis
    role: leader
    tier: backend
spec:
  ports:
  - port: 6379
    targetPort: 6379
  selector:
    app: redis
    role: leader
    tier: backend
```

1. 使用下面的 `redis-leader-service.yaml` 文件创建 Redis 的服务：

   ```shell
   $ kubectl apply -f ./guestbook/redis-leader-service.yaml  -n guestbook-qa
   ```

1. 查询服务列表验证 Redis 服务是否正在运行：

   ```shell
   $ kubectl get -n guestbook-qa service
   ```

   响应应该与此类似：

   ```
   NAME           TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
   redis-leader   ClusterIP   10.68.10.77   <none>        6379/TCP   3s
   ```

**说明：**

这个清单文件创建了一个名为 `redis-leader` 的 Service， 其中包含一组与前面定义的标签匹配的标签，因此服务将网络流量路由到 Redis Pod 上。



### 设置 Redis 跟随者

尽管 Redis 领导者只有一个 Pod，你可以通过添加若干 Redis 跟随者来将其配置为高可用状态， 以满足流量需求。

```yaml
# 来源：https://cloud.google.com/kubernetes-engine/docs/tutorials/guestbook
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-follower
  labels:
    app: redis
    role: follower
    tier: backend
spec:
  replicas: 2
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
        role: follower
        tier: backend
    spec:
      containers:
      - name: follower
        image: gcr.io/google_samples/gb-redis-follower:v2
        resources:
          requests:
            cpu: 100m
            memory: 100Mi
        ports:
        - containerPort: 6379
```

1. 应用下面的 `redis-follower-deployment.yaml` 文件创建 Redis Deployment：

   ```shell
   $ kubectl apply -f ./guestbook/redis-follower-deployment.yaml -n guestbook-qa
   ```

2. 通过查询 Pods 列表，验证两个 Redis 跟随者副本在运行：

```shell
$ kubectl get  -n guestbook-qa pods
```

接下来同样也是测试 guestbook-qa 的环境是否是符合我们的预期。

然后同样是吧 guestbook-qa 晋级到 guestbook-e2e 环境，

然后同样的测试 guestbook-e2e 环境是否正常工作。



### 网络隔离

定义部署应用程序的环境的一个关键方面是确保只有目标客户端可以访问特定的环境。默认情况下，所有命名空间都可以连接到在所有其他命名空间中运行的服务。但是对于两个不同的环境，比如QA和Prod，您不希望这些环境之间发生串扰。幸运的是，可以应用命名空间网络策略来限制命名空间之间的网络通信。让我们看看如何将应用程序部署到两个不同的名称空间，并使用网络策略控制访问。我们将介绍在两个不同的命名空间中部署服务的步骤。您还将修改网络策略并观察其效果。

> Egress traffic is network traffic that begins inside a network and pro-EGRESSceeds through its routers to a destination somewhere outside the network.

出口流量是从网络内部开始，经过路由器到达网络外部某个目的地的网络流量。

>  Ingress traffic is composed of all the data communications and net-INGRESSwork traffic originating from external networks.

入口流量由来自外部网络的所有数据通信和网络-INGRESS工作流量组成。

> Before you begin, verify thatVERIFY KUBERNETES CLUSTER CONNECTIONyou have correctly configured your KUBECONFIG environment variable topoint to the desired Kubernetes cluster. Please refer to appendix A for more information.

开始之前，请验证您是否已正确配置KUBERNETES CLUSTER CONNECTION环境变量以指向所需的Kubernetes群集。详情请参阅附录A。

并且默认情况下，在一个命名空间中运行的 Pod 可以往不同的命名空间中运行的其他 Pod 发送网络流量，我们下面通过从 qa 命名空间的 Pod 到 prod 命名空间的 Nginx pod 执行一条 url 命令来证明这一点：

```bash
$ kubectl describe pod web -n prod | grep IPz
$ kubectl -n qa exec curl-pod -- curl -I http://<web pod ip>
$ kubectl -n prod exec curl-pod -- curl -I http://<web pod ip>
```

通常，您永远不希望qa和prod环境之间存在相互依赖性。如果应用程序的两个实例都被正确配置，那么qa和prod之间就不会有依赖关系，但是如果qa的配置中有一个bug，它意外地向prod发送了流量，那该怎么办呢？您可能会损坏生产数据。甚至在生产环境中，如果一个环境承载您的营销站点，而另一个环境承载包含敏感数据的HR应用程序，该怎么办？在这些情况下，阻止名称空间之间的网络流量或者只允许特定名称空间之间的流量可能是合适的。这可以通过向名称空间添加网络策略来完成。让我们在每个名称空间中为我们的Pods添加一个网络策略:

```bash
$ kubectl apply -f block-other-namespace.yaml
```



### Git 策略

GitOps 中针对 Git 的三种情况，分别是单分支（多目录），多分支，多代码库与单一代码库

1. **单分支（多目录）策略**：这种策略使用单一的Git分支来管理所有的配置文件，但将不同的环境（如开发、测试和生产）的配置放置在不同的目录中。这种方法的优点是简单易管理，因为所有环境的配置都在一个地方。但缺点是可能会因为配置的紧密耦合而导致问题的传播，例如，错误的配置可能会影响到多个环境。
2. **多分支策略**：在这种策略中，为不同的环境（如开发、测试和生产）创建不同的Git分支。这样做的优点是可以更好地隔离不同环境的配置，减少错误配置对其他环境的影响。缺点是需要更多的分支管理工作，并且在分支之间同步更改可能会变得复杂。
3. **多代码库与单一代码库**：这里的区别在于是将所有的配置集中存储在一个代码库中，还是将它们分散在多个代码库中。单一代码库的优点是集中管理和一致性，而多代码库的优点则是提供了更高的灵活性和可维护性，尤其是在大型或复杂的项目中。

每种策略都有其优点和缺点，选择哪一种取决于组织的需求、团队的大小、项目的复杂性以及对风险管理的态度。通常，这些策略可能会结合使用，以适应不同的项目和组织结构。



### 配置管理

环境的配置管理可以到每一个环境中创建一个目录，其中包含所有的应该部署的资源的 YAML 清单，这些 YAML 清单中所有值都可以硬编码为该环境所需的特定值。

需要进行部署，那么运行：

```bash
$ kubectl apply <directory>
```

一个 SaaS 的应用程序开发者将其定制的应用程序部署到一个或者多个环境（dev, test)

这些环境可能分布在不同的账户，集群或者命名空间。它们之间有细微的区别，因此配置重用是最重要的。



### helm

helm 作为出场的第一个配置工具，是 Kubernetes 生态中不可或缺的一部分。

以下是Helm的主要特点和它在Kubernetes生态中的作用：

1. **应用程序包管理**：Helm可以被看作是Kubernetes的包管理器。它允许开发者和运维人员将应用程序及其依赖项打包成一个称为"chart"的单元。这些chart是预配置的Kubernetes资源集合，可以在Kubernetes集群上轻松部署和管理。
2. **简化复杂部署**：Helm使得部署复杂的应用程序变得简单。它可以管理复杂的依赖关系，并确保所有Kubernetes组件以正确的顺序和配置部署。这对于那些需要多个服务和配置的大型应用程序来说尤其重要。
3. **易于版本控制和回滚**：Helm charts易于版本控制，这意味着你可以追踪到每次部署的变化，并在需要时轻松地回滚到旧版本。
4. **共享和重用**：通过Helm仓库，用户可以共享他们的charts，使得重用配置变得简单。这促进了最佳实践的共享和社区协作。
5. **配置灵活性**：Helm允许用户自定义chart的配置，以适应不同的环境和需求。这种灵活性是通过使用模板和配置文件实现的，这些文件可以在部署时修改。
6. **集成和扩展性**：Helm可以与其他Kubernetes工具和插件无缝集成，增加了它的扩展性。这使得它可以适应各种不同的部署需求和环境。



### Jsonnet

Jsonnet，作为一种编程语言，主要被设计来增强和简化JSON数据的声明和处理。虽然它并非专门为Kubernetes设计，但在Kubernetes社区中确实获得了广泛的应用和普及。以下是Jsonnet的关键特性和它在数据处理中的作用：

1. **增强的JSON**：Jsonnet可以被看作是JSON的一个超集，它在JSON的基础上添加了变量、条件表达式、函数、算术运算和其他编程语言的特性。这些扩展使得Jsonnet非常适合处理复杂的数据描述和配置文件。
2. **模板和抽象**：Jsonnet支持高级别的抽象和模板化，这对于管理大量的、结构相似的数据特别有用。用户可以定义通用的模式和结构，然后在不同的上下文中重复使用它们，减少重复和错误。
3. **灵活性和可维护性**：通过提供变量和函数，Jsonnet使得数据文件的维护变得更加灵活和易于管理。这对于需要频繁更新或修改的配置尤其重要。
4. **清晰的逻辑结构**：Jsonnet的编程语言特性允许用户以更清晰、逻辑化的方式编写和理解复杂的数据结构，这对于复杂的配置管理来说是一个巨大的优势。
5. **在Kubernetes中的应用**：虽然Jsonnet并非专门为Kubernetes设计，但它在管理Kubernetes的配置文件方面显示出了巨大的潜力。它可以生成复杂的Kubernetes资源定义，如部署、服务和pod配置，并支持高级的配置模式。
6. **社区支持和工具集成**：由于Jsonnet在Kubernetes社区中的流行，许多工具和库已经开发出来支持Jsonnet文件的生成和管理。这进一步增强了它在现代云原生架构中的应用。



## 流水线

CICD 流水线中的阶段

持续集成 （CI）是一种软件开发的实践，在这种实践中，所有的开发人员都会在一个中央仓库（GIT）中合并变更，通过 CI ，每一次代码变更（提交）都会触发给定仓库的自动构建和测试阶段，并向做出变更的开发者提供反馈。与传统的 CI 相比，GitOps 的主要区别在于，在构建和测试阶段成功完成后，CI 流水线还会在应用程序清单中更新新的镜像版本。

持续交付（CD） 是将整个软件发布过程自动化。

与传统的 CICD 不同，使用 GitOps Operator 来监控清单的变化并协调部署，只要 CI 构建完成，并且清单更新，GitOps Operator 就会

### 持续集成

**步骤如下：**

流程将从“拉取请求”开始，经过多个阶段，如“代码审核”、“漏洞扫描”、“代码分析”、“构建”、“单元测试”、“代码覆盖”、“Docker构建”、“Docker推送”、“Git克隆配置仓库”、“更新配置清单”、“Git提交和推送”、“发布CI指标”，最后到达“构建通知”。

![544991a1-6499-4de0-acef-bb43af85fdb3](http://sm.nsddd.top/sm202311261925321.webp)



集成 Go 语言和其他的一些工具：

1. **GitHub Actions 集成**：在流程图中的各个阶段，如“代码审核”、“漏洞扫描”、“代码分析”等，可以通过 GitHub Actions 自动化执行。这意味着每个步骤可以被配置为 GitHub Actions 的一个工作流，从而实现自动化和流程控制。
2. **Go 语言相关工具**：
   + **代码审核**：集成如 `golint` 或 `gometalinter` 的 Go 语言代码审查工具。
   + **漏洞扫描**：使用针对 Go 语言的漏洞扫描工具，如 `gosec`。
   + **代码分析**：应用如 `staticcheck` 的静态分析工具。
   + **单元测试**：利用 Go 自带的测试框架和 `go test` 命令。
   + **代码覆盖**：使用 Go 的 `cover` 工具来检查测试覆盖率。
3. **Docker 与 Go**：在 Docker 构建阶段，可以使用针对 Go 应用的 Dockerfile，确保应用被正确打包。
4. **配置管理**：对于“Git 克隆配置仓库”和“更新配置清单”阶段，可以考虑使用如 `Viper` 或 `Consul` 等 Go 语言配置管理工具，以便更好地管理和维护配置。

![chatp](http://sm.nsddd.top/sm202311261938086.png)



### 持续交付

持续集成后，就进入到持续交付的环节了，

建立在 GitOps CICD 基础上的完整的 CD 流水线

1. **Git 克隆配置仓库**：这一步骤保持不变，作为配置管理的一部分。
2. **发现清单**：这可能涉及自动化脚本或工具，用于检测和整理应用的配置项和依赖。
3. **kubectl apply**：在 Kubernetes 环境中应用配置更改或部署新的服务。
4. **功能测试**：执行自动化的功能测试，以验证应用的功能和性能。
5. **运行时漏洞扫描**：使用适合 Kubernetes 环境的工具来检测运行时的安全漏洞。
6. **发布 CD 指标**：收集和发布部署相关的指标，可能通过集成的监控工具或定制脚本实现。

![50629a41-bded-4f36-abfe-b3dfadd7c9d3](http://sm.nsddd.top/sm202311261945127.webp)



### 推动晋级工作

我们知道，Kubernetes 清单和代码一般不放在同一个仓库，这样可以获取到更灵活的部署选择，更好的访问控制和审计能力。那么我们应该在哪里维护特定的环境依赖的应用配置，如数据库链接和分布式缓存。

1. **单独的配置仓库**：创建一个独立的仓库来存储环境特定的配置文件。这种方法可以提供清晰的分离，确保代码和配置的独立管理，同时便于追踪和审计。
2. **配置管理工具**：使用配置管理工具，如 Helm、Kustomize 或 Terraform，来管理和应用不同环境的配置。这些工具可以帮助你根据环境差异（如开发、测试、生产）调整配置。
3. **秘密管理**：对于敏感信息（如数据库密码和访问密钥），使用 Kubernetes 的秘密（Secrets）管理功能来存储。这些秘密可以在部署时动态挂载到容器中。
4. **配置映射（ConfigMaps）**：对于非敏感的配置信息，如数据库链接和应用参数，可以使用 Kubernetes 的 ConfigMap 来存储。ConfigMap 可以在容器启动时作为环境变量或挂载的卷提供给应用程序。
5. **环境变量**：在某些情况下，直接在 Kubernetes 的部署配置中使用环境变量来传递配置信息是有用的。这种方法适用于不需要频繁更改的简单配置。
6. **GitOps 实践**：采用 GitOps 的方式来管理 Kubernetes 配置。在这种模式下，所有配置更改都通过 Git 仓库来进行，通过自动化流程应用到 Kubernetes 环境中。这有助于确保配置的一致性和可追溯性。

在 GitOps 实践中，`git reset` 和 `git revert` 是两个重要的 Git 命令，它们用于处理配置变更和维护历史记录。理解这两个命令的差异和适用场景对于有效地管理 Kubernetes 配置至关重要。

1. **git reset**：
   + `git reset` 命令用于撤销某些提交，它可以将 HEAD 指针移动到指定的提交。
   + 在 GitOps 中，如果你需要撤销一系列最近的提交，并将仓库状态回滚到以前的某个特定提交，可以使用 `git reset`。
   + 需要注意的是，`git reset` 会更改历史记录，这在共享仓库中可能会导致问题。其他开发者需要用 `git pull --force` 来同步更改，这可能导致混乱。
2. **git revert**：
   + `git revert` 命令用于撤销某个特定的提交，但它不会改变历史记录。相反，它会创建一个新的提交，这个新提交的状态与要撤销的提交相反。
   + 在 GitOps 中，如果需要撤销一个特定的更改，同时保留后续的更改，并且不想修改历史记录，`git revert` 是一个更好的选择。
   + `git revert` 更适合公共仓库或团队环境，因为它不会影响其他开发者的历史记录。

> 我的个人开发经验总结出来的是，个人不使用 `revert`，而是使用 `reset` 在本地，前提是自己对自己提交的树状图很清晰，不过生产中还是使用 `revert`，这是一个非常保险和安装的做法。

这和 git rebase 和 git merge 的理解一样的。

**merge 和 rebase**
merge 是合并的意思，rebase是复位基底的意思。
现在我们有这样的两个分支,test和master，提交如下：

```
     D---E test
    /
A---B---C---F master
```

在master执行`git merge test`然后会得到如下结果：

```
     D--------E
    /          \
A---B---C---F---G    test , master
```

在master执行`git rebase test`,然后得到如下结果：

```
 A---C---D---E---C `---F` test , master
```

可以看到merge操作会生成一个新的节点，之前提交分开显示。而rebase操作不会生成新的节点，是将两个分支融合成一个线性的操作。



## 部署策略

在 Kubernetes 中，你可以只用带有 PodSpec 的清单来部署一个 Pod，并且保证其可用性。在这种情况下，你可以自定义 ReplocaSet 清单，以保持在任何特定时间运行一组稳定的 Pod 副本集合。ReplicaSet 是通过指定用于识别 Pod 的选择器。

ReplicaSet 不是声明式的，因此不适合 GitOps 

我没知道 Deployment 是一个更高层的抽象，虽然可以使用带有 `PodSpec` 的清单直接部署单个 Pod，但这种方式通常不适用于保证 Pod 的可用性和可管理性。



### ReplicaSet

+ **作用**：`ReplicaSet` 的主要目的是确保在任何时候都有指定数量的 Pod 副本正在运行。
+ **选择器**：它通过使用标签选择器来识别要管理的 Pod。这些标签在 Pod 的定义中指定。
+ **缺点**：尽管 `ReplicaSet` 可以确保指定数量的 Pod 实例始终运行，但它本身并不支持滚动更新。如果你需要更新 Pod 的定义（例如，更新使用的容器镜像），就需要手动更新 `ReplicaSet`，或者删除并重新创建它。

### Deployment

+ **更高级的抽象**：`Deployment` 是一个更高级别的抽象，它在 `ReplicaSet` 的基础上提供了更多功能。它不仅确保 Pod 数量，还支持声明式地更新 Pod 和 `ReplicaSet`。
+ **滚动更新**：`Deployment` 支持滚动更新，允许你逐渐替换旧版本的 Pod 为新版本，而不会导致停机。
+ **适用于 GitOps**：由于其声明式的特性，`Deployment` 非常适合 GitOps 的工作流。你可以在 Git 仓库中声明应用的期望状态，然后使用自动化工具（如 Argocd 或 Flux）来监视仓库并将更改应用到 Kubernetes 集群。

![gitops-deployment-replicaset](http://sm.nsddd.top/sm202311262010756.png)



###  流量路由 Traffic Routing

在Kubernetes中，Service 是一种抽象，它定义了一组逻辑的Pods和访问它们的策略。服务所针对的豆 Pod targeted由以下选择器确定

Service minifest 中的字段。然后，服务将流量转发到带有选择器指定的匹配标签的Pods。如果底层的Pods是无状态和向后兼容的，那么Service可以进行循环负载平衡，并且非常适合滚动更新。如果需要为部署定制负载平衡，则需要探索其他路由替代方案。

当Service收到流量时，它会根据定义的选择器将流量转发到拥有相应匹配标签的Pods。例如，如果Service的选择器被设置为匹配标签“color: blue”，那么所有带有此标签的Pods将接收到由该Service转发的流量。这种方法使得流量管理既灵活又高效。

#### 无状态Pods和负载平衡

如果底层的Pods是无状态的（Stateless）并且保持向后兼容性，那么Service可以实现有效的循环负载平衡。这对于实施滚动更新尤为重要，因为它允许在不中断服务的情况下逐步替换旧的Pods。

#### 定制负载平衡与路由策略

对于需要更复杂路由逻辑或定制负载平衡的部署，可能需要探索Kubernetes提供的其他路由替代方案。例如，使用Ingress Controllers和Ingress Resources可以提供更高级的路由能力，比如基于URL的路由、SSL/TLS终端加密和负载均衡策略。

#### 标签驱动的路由

Kubernetes中的服务路由是完全基于标签的。这意味着，例如，一个标记为“blue”的Service只会将流量路由到带有“blue”标签的Pods，而一个标记为“green”的Service则只路由到带有“green”标签的Pods。这种设计允许简单而直观的流量分配和管理。

![ingree-istio](http://sm.nsddd.top/sm202311262110507.png)

#### NGINX Ingress Controller

NGINX Ingress Controller是一个功能强大的工具，用于在Kubernetes环境中管理进入集群的流量。它支持多种负载平衡和路由规则，适用于广泛的用例。关键特点包括：

+ **前端负载均衡器**：它可以配置为前端负载均衡器，负责处理进入集群的所有流量。
+ **自定义路由**：支持各种自定义路由功能，如TLS终端加密、URL重写，以及基于自定义规则的流量路由。
+ **流量分配**：可以配置规则来分配流量，例如将40%的流量路由到带有特定标签（如“blue”）的服务，而60%路由到另一个标签（如“green”）的服务。

通过这些功能，NGINX Ingress Controller能够有效地管理和优化进入Kubernetes集群的流量。

#### Istio Gateway

Istio Gateway是另一个关键组件，用于在Kubernetes集群的边缘管理流量。它主要负责处理进入和离开集群的HTTP和TCP连接。Istio Gateway的主要特点包括：

+ **边缘负载平衡器**：作为集群边缘的负载平衡器，它处理所有进入和离开集群的流量。
+ **端口和协议规范**：Istio Gateway允许定义一组要公开的端口，以及相关的协议类型，确保流量按照既定的规则和协议流动。
+ **集成与Istio服务网格**：作为Istio生态系统的一部分，它与Istio的服务网格功能紧密集成，提供高级的流量管理和安全性功能。

![istio-ingress](http://sm.nsddd.top/sm202311262115919.png)

> 说明通过Kubernetes中的Ingress控制器的流量流和Istio服务网格中的流量流的图表已经准备好了。这些图表清晰地比较了每个系统在Kubernetes环境中如何处理流量路由和管理，包括入口控制器和Istio网关的角色。



### Argo Rollouts

#### 什么是Argo Rollouts？

Argo Rollouts 是一个Kubernetes控制器，用于更复杂、更强大的部署策略，如蓝绿部署（Blue-Green Deployments）和金丝雀部署（Canary Deployments）。它通过扩展Kubernetes自身的部署能力，使得在不中断服务的情况下更新和管理应用程序变得更加容易。

#### 安装 & 使用 Argo Rollouts

1. **先决条件**：

   + 确保您有一个运行中的 Kubernetes 集群。
   + 您需要有足够的权限来部署新的 Kubernetes 资源。

2. **安装命令**：

   + Argo Rollouts 可以通过其 Helm 图表或使用 kubectl 直接从其 GitHub 仓库安装。

   + 使用 Helm 安装（如果您使用 Helm）:

     ```bash
     helm repo add argo https://argoproj.github.io/argo-helm
     helm install argo-rollouts argo/argo-rollouts
     ```

   + 或者，使用 kubectl 从其 GitHub 仓库安装：

     ```bash
     kubectl create namespace argo-rollouts
     kubectl apply -n argo-rollouts -f https://raw.githubusercontent.com/argoproj/argo-rollouts/stable/manifests/install.yaml
     ```

### 定义 Rollout 资源

1. **创建 Rollout 资源定义**：

   + Rollout 资源类似于 Kubernetes 的 Deployment 资源，但它包含额外的字段来指定部署策略（例如金丝雀或蓝绿部署）。
   + 创建一个 YAML 文件，定义您的 Rollout，包括镜像、副本数、更新策略等。

2. **示例 Rollout 定义**：

   ```yaml
   apiVersion: argoproj.io/v1alpha1
   kind: Rollout
   metadata:
     name: example-rollout
   spec:
     replicas: 3
     selector:
       matchLabels:
         app: example
     template:
       metadata:
         labels:
           app: example
       spec:
         containers:
         - name: app
           image: your-image:latest
           ports:
           - containerPort: 8080
     strategy:
       canary: 
         steps:
         - setWeight: 20
         - pause: {duration: 1h}
   ```

### 触发和管理部署

1. **应用 Rollout 资源**：

   + 使用 kubectl 应用您的 Rollout 定义：

     ```bash
     kubectl apply -f your-rollout-definition.yaml
     ```

2. **监控 Rollout 状态**：

   + 使用 kubectl 检查 Rollout 状态：

     ```bash
     kubectl argo rollouts get rollout example-rollout --watch
     ```

3. **管理 Rollout**：

   + 可以通过更新 Rollout 资源的定义（例如，更改镜像标签）来触发新的部署。
   + 使用 Argo Rollouts 的 CLI 工具，您可以管理 Rollout 的暂停、恢复和中止等操作。

#### Argo Rollouts的核心功能

+ **高级部署策略**：支持蓝绿部署和金丝雀部署等。
+ **自动化回滚**：如果新版本出现问题，它能自动回滚到上一个稳定版本。
+ **权重式流量分配**：可以控制新版本和旧版本之间的流量分配比例。
+ **集成度高**：与Istio、NGINX Ingress等服务网格和Ingress控制器紧密集成。

1. **蓝绿部署**：
   + 首先，您部署了新版本（绿色版本）而不会影响到当前运行的旧版本（蓝色版本）。
   + 一旦绿色版本就绪并且经过了测试验证其稳定性，流量将从蓝色版本平滑转移到绿色版本。
   + 如果绿色版本运行良好，则完成部署；如果有问题，则可以立即切换回蓝色版本。
2. **金丝雀部署**：
   + 在这种策略中，您会逐渐向新版本（金丝雀版本）引入一小部分用户流量。
   + 初始阶段，只有少量的流量被路由到新版本，同时监控其性能和稳定性。
   + 如果新版本表现良好，您可以逐渐增加流量比例，直到全部流量都转移到新版本。
   + 如果新版本出现问题，可以立即停止流量的转移，并将其路由回旧版本。



### 蓝绿发布

我们已经知道，支持声明式的 Deployment 的滚动更新是更新应用的绝佳方式，因为你的应用在部署期间将使用大致相同数量的资源，且停机时间为零，对性能的影响最小。然而，由于向后不兼容性或有状态性，有许多遗留应用程序不能很好地与滚动更新一起工作。有些应用程序可能还需要部署新版本并立即切换到该版本，或者在出现问题时快速回滚。对于这些用例，蓝绿色部署将是适当的部署策略。蓝绿部署通过让两个部署同时完全扩展，但只将传入流量定向到两个部署中的一个来实现这些。

> 这里我们使用 Nginx Ingress 控制器将 100% 的流量路由到 blue 或者 green deployment，因为内置的 kubernetes service 只支持 iptables，并不重置与 pod 的现有链接，因此不适合蓝绿发布。

在 Kubernetes 环境中，虽然声明式的 Deployment 通过滚动更新（Rolling Update）提供了零停机时间和最小化对性能的影响，但确实存在某些情况和应用程序类型，其中这种方法可能不是最佳选择。特别是对于那些有状态性（Stateful）应用或因向后不兼容性而难以进行滚动更新的遗留应用程序，蓝绿部署（Blue-Green Deployment）可能更适合。



### Iptable

Iptables 是 Linux 上一种强大的防火墙工具，用于控制进出 Linux 系统的网络流量。它是基于 Netfilter 提供的网络包过滤框架，允许系统管理员配置规则集，以过滤流量并提供 NAT 功能。

#### 主要特点和功能

1. **包过滤**：
   + Iptables 可以过滤进出系统的数据包，包括源地址、目的地址、传输协议等。
   + 它可以接受、拒绝或丢弃数据包，根据定义的规则对网络流量进行精确控制。
2. **链和表**：
   + Iptables 使用链（Chains）和表（Tables）来组织规则。
   + 常见的链有 INPUT、OUTPUT 和 FORWARD，分别控制进入系统、离开系统和穿过系统的流量。
   + 表如 `filter`、`nat` 和 `mangle` 表用于不同类型的流量处理。
3. **NAT（网络地址转换）**：
   + `Iptables` 支持 NAT 功能，包括源地址转换（SNAT）和目的地址转换（DNAT）。
   + 这对于路由和转发流量至内部网络中的私有地址非常重要。
4. **状态跟踪**：
   + Iptables 能够跟踪网络连接的状态，如新建、已建立、相关联和无效连接。
   + 这允许基于连接状态应用规则，提高过滤的灵活性和效果。

#### 应用场景

1. **安全防护**：
   + 在服务器和网络设备上实施防火墙规则，防止未授权访问和攻击。
2. **流量管理**：
   + 管理和限制特定类型的流量，优化网络使用。
3. **网络调试**：
   + 跟踪和监控网络流量，帮助诊断网络问题。

#### 使用示例

+ 阻止来自特定 IP 地址的流量：

  ```bash
  iptables -A INPUT -s 123.456.789.0 -j DROP
  ```

+ 允许特定端口的流量：

  ```bash
  iptables -A INPUT -p tcp --dport 22 -j ACCEPT
  ```

Iptables 的灵活性和强大功能使其成为 Linux 系统中管理网络流量和实施安全策略的关键工具。然而，由于其复杂性，建议在生产环境中谨慎使用，并且在应用任何规则之前进行充分的测试。



### 蓝绿部署的工作原理

蓝绿部署的核心思想是同时维护两个生产环境（或部署）的完全不同版本：一个蓝色（Blue）版本和一个绿色（Green）版本。

+ **蓝色部署**：当前运行的旧版本。
+ **绿色部署**：新版本，与蓝色部署相同但包含更新。

这两个部署都会完全扩展，但在任何时刻，只有一个部署（蓝色或绿色）会接收到所有传入流量。



### 使用 Nginx Ingress 控制器实现蓝绿部署

1. **流量路由**：

   + 在蓝绿部署中，Nginx Ingress 控制器可以用于将100%的流量路由到蓝色或绿色部署。或者是将部分的流量路由到蓝色部署，部分的流量路由到绿色部署。

     > 哈哈哈但是这样貌似就不是蓝绿部署了，有点像是金丝雀部署：
     >
     > 如果您的需求是同时向蓝色和绿色部署分配流量，那么您可能需要考虑使用金丝雀部署（Canary Deployment）。在金丝雀部署中，新版本（金丝雀）最初只接收一小部分流量，而主要流量仍然路由到旧版本。根据新版本的性能和稳定性，逐渐增加流向新版本的流量比例。

   + 这是通过更新 Ingress 资源来实现的，该资源决定了哪个服务（蓝色还是绿色）将接收流量。

2. **Kubernetes Service 的局限性**：

   + Kubernetes Service 基于 iptables 实现，不会重置与Pod的现有连接。
   + 这意味着在进行版本切换时，一些现有的连接可能仍然指向旧版本的Pod，这对于需要立即切换和快速回滚的应用不是最佳选择。
   + 因此，对于蓝绿部署，使用像 Nginx 这样的 Ingress 控制器可以更好地管理流量切换，因为它能更精确地控制流量的路由。



### 使用 Deployment 实现蓝绿部署

![deployment-blue-green](http://sm.nsddd.top/sm202311270932090.png)

> The diagram illustrating the concept of Blue-Green Deployment in a Kubernetes environment using NGINX Ingress and Deployments is ready. It visually explains how traffic is directed to either the Blue or Green Deployments, showcasing the clear separation and traffic management between these two deployments.

要使用 Ingress 实现 Kubernetes 中的蓝绿部署，您需要准备两套完全一样但不同版本的应用部署（Deployment），一个 Ingress 控制器（例如 NGINX），以及一个 Ingress 资源来控制流量的路由。以下是实现这一策略的步骤和示例代码。

### 设计方案

1. **准备两个 Deployment**：
   + 一个“蓝色”Deployment，运行当前版本的应用。
   + 一个“绿色”Deployment，运行新版本的应用。
2. **配置 Service**：
   + 为每个 Deployment 创建一个 Service。这些 Service 将作为流量的入口点。
3. **设置 Ingress 控制器**：
   + 确保您的 Kubernetes 集群中已安装并运行了 Ingress 控制器，例如 NGINX。
4. **编写 Ingress 资源**：
   + 创建一个 Ingress 资源来定义流量路由规则。开始时，将所有流量路由到蓝色 Deployment。
   + 当准备将流量切换到绿色 Deployment 时，更新 Ingress 资源。
5. **监控和切换**：
   + 在切换流量之前，确保绿色 Deployment 完全就绪且测试无误。
   + 通过更新 Ingress 规则，将流量从蓝色切换到绿色 Deployment。
   + 如果新版本运行正常，继续将流量路由到绿色 Deployment；如果有问题，可以快速切回蓝色 Deployment。



**示例代码：**

**蓝色 Deployment** (`blue-deployment.yaml`):

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: blue-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
      version: blue
  template:
    metadata:
      labels:
        app: myapp
        version: blue
    spec:
      containers:
      - name: myapp
        image: myapp:blue
```



**绿色 Deployment** (`green-deployment.yaml`):

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: green-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
      version: green
  template:
    metadata:
      labels:
        app: myapp
        version: green
    spec:
      containers:
      - name: myapp
        image: myapp:green

```



**结合argo Rollouts**

要将 Argo Rollouts 与蓝绿部署结合起来，您可以通过 Argo Rollouts 定义和管理蓝绿部署过程，同时利用其强大的流量控制和自动化回滚功能。这需要您在 Kubernetes 集群中安装 Argo Rollouts 控制器，并定义相应的 Rollout 资源来代替标准的 Deployment 资源。

### 结合argo Rollouts设计方案

1. **安装 Argo Rollouts 控制器**：
   + 确保您的 Kubernetes 集群中已经安装了 Argo Rollouts。
2. **定义 Rollout 资源**：
   + 替代传统的 Deployment 资源，使用 Rollout 资源来定义您的应用部署。
   + 在 Rollout 配置中指定蓝绿部署策略。
3. **配置 Service**：
   + 定义 Service 来指向 Rollout 管理的 Pods。
4. **配置 Ingress**：
   + 使用 Ingress 资源来控制外部流量进入您的服务。
5. **流量转移**：
   + 利用 Argo Rollouts 的能力来管理从蓝色到绿色的流量转移。

### 示例代码

1. **Rollout 资源** (`blue-green-rollout.yaml`):

   ```yaml
   apiVersion: argoproj.io/v1alpha1
   kind: Rollout
   metadata:
     name: bluegreen-rollout
   spec:
     replicas: 2
     selector:
       matchLabels:
         app: myapp
     template:
       metadata:
         labels:
           app: myapp
       spec:
         containers:
         - name: myapp
           image: myapp:latest
     strategy:
       blueGreen: 
         activeService: myapp-active
         previewService: myapp-preview
         autoPromotionEnabled: false
   ```

2. **Active Service** (`active-service.yaml`):

   ```yaml
   apiVersion: v1
   kind: Service
   metadata:
     name: myapp-active
   spec:
     selector:
       app: myapp
     ports:
     - protocol: TCP
       port: 80
       targetPort: 8080
   ```

3. **Preview Service** (`preview-service.yaml`):

   ```yaml
   apiVersion: v1
   kind: Service
   metadata:
     name: myapp-preview
   spec:
     selector:
       app: myapp
       rollouts-pod-template-hash: <HASH>
     ports:
     - protocol: TCP
       port: 80
       targetPort: 8080
   ```

4. **Ingress 资源** (`ingress.yaml`):

   ```yaml
   apiVersion: networking.k8s.io/v1
   kind: Ingress
   metadata:
     name: myapp-ingress
   spec:
     rules:
     - http:
         paths:
         - path: /
           pathType: Prefix
           backend:
             service:
               name: myapp-active
               port:
                 number: 80
   ```

在这个方案中，`activeService` 和 `previewService` 分别代表当前活跃版本和预览（新版本）的服务。Argo Rollouts 会根据配置自动管理蓝绿部署过程，包括流量的转移。您可以通过更新 Rollout 资源中的镜像版本来触发新的部署，并使用 Argo Rollouts 的命令行工具来控制流量转移和促进新版本的发布。



## 金丝雀部署

金丝雀部署是一种技术：

> 金丝雀部署（Canary Deployment）是一种软件发布技术，它在更新应用程序时采取逐步的方法，以最小化风险。这种策略的命名源于矿工使用金丝雀作为一种安全预警系统的历史。在软件部署的语境中，它代表了逐渐引入新版本应用程序的过程，以便在全面部署前对其进行测试和验证。

### 特点

1. **逐步推出**：
   + 新版本初始只向一小部分用户或环境发布，而大部分用户仍然使用旧版本。
2. **风险控制**：
   + 如果新版本表现不佳（如出现错误或性能问题），则影响的用户范围有限，且可以迅速回滚。
3. **实时反馈**：
   + 提供机会观察新版本在实际环境中的表现，收集实时反馈和性能数据。

### 实施步骤

1. **初始发布**：
   + 新版本最初只对一小组用户或一部分流量可见。
2. **监控和评估**：
   + 对新版本的性能、稳定性和用户反馈进行持续监控。
3. **逐步增加覆盖率**：
   + 如果新版本表现良好，逐步增加其对用户或流量的覆盖范围。
4. **全面部署或回滚**：
   + 根据反馈和监控结果，决定是全面部署新版本还是回滚到旧版本。

### 应用场景

+ **高风险更新**：对于可能对系统稳定性或用户体验有重大影响的更新。
+ **大型应用**：在大型或复杂的应用中，不同用户群可能对更新有不同的反应。
+ **连续部署环境**：在敏捷开发和持续集成/持续部署 (CI/CD) 环境中，金丝雀部署可以作为一种有效的风险管理工具。



### 使用 Ingress 和 Deployment 实现金丝雀部署

#### 设计方案

1. **准备两个 Deployment**：
   + 一个为当前版本（例如，标记为 `version: stable`）。
   + 另一个为新版本（例如，标记为 `version: canary`）。
2. **配置 Service**：
   + 为每个 Deployment 创建一个 Service。
3. **配置 Ingress**：
   + 使用 Ingress 资源定义流量的分配策略，指定一部分流量到新版本。

#### 示例代码

1. **Stable Deployment** (`stable-deployment.yaml`):

   ```yaml
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: myapp-stable
   spec:
     replicas: 3
     selector:
       matchLabels:
         app: myapp
         version: stable
     template:
       metadata:
         labels:
           app: myapp
           version: stable
       spec:
         containers:
         - name: myapp
           image: myapp:stable
   ```

2. **Canary Deployment** (`canary-deployment.yaml`):

   ```yaml
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: myapp-canary
   spec:
     replicas: 1  # Lesser replicas as it's a canary release
     selector:
       matchLabels:
         app: myapp
         version: canary
     template:
       metadata:
         labels:
           app: myapp
           version: canary
       spec:
         containers:
         - name: myapp
           image: myapp:canary
   ```

3. **Service** (`service.yaml`):

   ```
   yamlCopy codeapiVersion: v1
   kind: Service
   metadata:
     name: myapp-service
   spec:
     selector:
       app: myapp
     ports:
     - protocol: TCP
       port: 80
       targetPort: 8080
   ```

4. **Ingress 资源** (`ingress.yaml`):

   + 在这里，您需要使用 Ingress 控制器的特定功能来分配流量（例如，NGINX Ingress 的权重分配）。

### 使用 Argo Rollouts 实现金丝雀部署

#### 设计方案

1. **安装 Argo Rollouts**：
   + 确保您的 Kubernetes 集群中已经安装了 Argo Rollouts。
2. **定义 Rollout 资源**：
   + 使用 Rollout 资源来定义应用部署，并指定金丝雀策略。
3. **配置 Service**：
   + 定义 Service 来指向 Rollout 管理的 Pods。
4. **监控和管理部署**：
   + 利用 Argo Rollouts 提供的工具来监控和管理部署过程。

#### 示例代码

1. **Rollout 资源** (`canary-rollout.yaml`):

   ```yaml
   apiVersion: argoproj.io/v1alpha1
   kind: Rollout
   metadata:
     name: myapp-rollout
   spec:
     replicas: 4
     selector:
       matchLabels:
         app: myapp
     template:
       metadata:
         labels:
           app: myapp
       spec:
         containers:
         - name: myapp
           image: myapp:new-version
     strategy:
       canary:
         steps:
         - setWeight: 20
         - pause: {duration: 48h}
         - setWeight: 50
         - pause: {duration: 48h}
   ```

2. **Service** (`service.yaml`):

   + 同上面的 Ingress 和 Deployment 方法中的 Service。

在使用 Argo Rollouts 的情况下，部署的管理和流量分配变得更加简单和直观。您可以更精确地控制新版本的流量比例，并利用 Rollouts 的自动化特性来监控部署的健康状况和自动回滚



### 渐进式部署

渐进式部署是金丝雀部署的一个完全的自动化版本。渐进式交互不是在扩大金丝雀部署之前检测一个固定的时间段，而是持续监测 Pod 的健康状态，并且不断扩大规模，直到完全扩展。
