今天我们来看看 kubernetes 和 gitops 的理论实践
首先我们来看看 kubectl 支持的子命名,方便我们使用:
kubectl apply - 应用一个或多个资源的定义。通常用于部署应用程序或更新资源。kubectl get - 显示一个或多个资源的信息。这是查看 Kubernetes 集群中资源状态的常用命令。kubectl describe - 显示一个或多个资源的详细信息,如事件、状态和配置。kubectl delete - 删除 Kubernetes 集群中的资源。kubectl exec - 在集群中的容器里执行命令。kubectl logs - 打印容器的日志。kubectl create - 从文件或标准输入中创建一个或多个资源。kubectl edit - 编辑集群中的资源。这将打开一个编辑器来修改资源的配置。kubectl port-forward - 将本地端口转发到集群中的 Pod。kubectl run - 在集群中运行一个指定的镜像。kubectl scale - 调整资源(如 Deployment、ReplicaSet)的副本数量。kubectl rollout - 管理资源的部署,如查看状态、暂停、恢复或回滚更新。除了上面的命令,Kubernetes 中的 kubectl 还支持注解:
kubectl annotate 命令用于给 Kubernetes 集群中的资源添加或更新注解(annotations)。注解是一种附加信息,可以用于存储非识别性的元数据。它们通常用于管理工具、库和客户端以存储辅助信息,例如描述、版本信息等。
kubectl annotate [type] [name] [key]=[value]
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 可以负责部署数据库、备份数据、恢复数据等。
关键区别在于:
因此,所有的 Operator 都使用 Controller 的模式,但并非所有的 Controller 都是 Operator。这是因为所有 Operator 都是构建在控制器模式之上的,但控制器不一定需要具有管理特定应用程序生命周期的复杂逻辑和扩展 API 的能力,这是 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 来表示 Nginx 的配置。这个 CRD 将描述 Nginx 实例的属性,如版本、配置文件内容和相关的静态资源。
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
使用 Go 语言编写 Operator 控制器。Operator 控制器将监听 NginxConfig 资源的创建、更新和删除事件,并执行相应的操作。
package main
import (
// 引入必要的库
)
func main() {
// 初始化客户端、监听 NginxConfig 资源的变化
// 实现业务逻辑:创建/更新/删除 Nginx 实例
}
在控制器中,处理 Nginx 实例的创建和更新。当一个 NginxConfig 资源被创建或更新时,控制器会根据定义的规格来设置 Nginx Pod,包括所需的配置和静态文件。
将 Operator 打包成 Docker 镜像,然后在 Kubernetes 集群中部署这个镜像。
# 使用合适的基础镜像
FROM golang:1.15
# 添加 Operator 代码
ADD . /operator
WORKDIR /operator
# 编译 Operator
RUN go build -o operator .
# 设置启动命令
CMD ["./operator"]
部署到 Kubernetes:
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
创建一个 NginxConfig 实例来测试 Operator:
apiVersion: "example.com/v1"
kind: NginxConfig
metadata:
name: my-nginx
spec:
version: "latest"
staticContent: "Welcome to Nginx!"
监视 Kubernetes 集群,确保 Operator 正确响应了这个 NginxConfig 实例的创建。
接下来,我们首先创建一个 GitOps Operator 来驱动持续交付。
GitOps 是一种用于持续部署的实践,它将 Git 作为真实状态的源。在 GitOps 模型中,所有的部署和环境配置都存储在 Git 仓库中,这样做可以提供版本控制、审计跟踪和回滚能力。为了实现 GitOps,我们可以创建一个 GitOps Operator,它将自动化从 Git 仓库到 Kubernetes 集群的部署过程。
定义 GitOps CRD:
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
编写 Operator 控制器:
构建和部署 Operator:
测试 Operator:
不同的运行时环境,以及 Kubernetes 命名空间是如何定义环境边界的。
一个环境是由三个同样重要的部分组成的:
代码:
代码是应用程序执行特定任务的机器指令。要执行代码,可能还需要运行时依赖项。例如,Node.js代码需要Node.js二进制包和其他NPM包才能成功地执行。对于Kubernetes,所有运行时依赖项和代码都打包为一个可部署单元(又名Docker映像),并通过Docker守护进程进行编排。应用程序的Docker映像可以放心地在任何环境中运行,从开发人员的笔记本电脑到在云中运行的生产集群,因为映像封装了代码和所有依赖关系,消除了环境之间潜在的不兼容性。
在软件部署中,环境是部署和执行代码的地方。在软件开发的生存周期中,不同的环境服务于不同的目的。例如,本地开发环境(又名笔记本电脑)是工程师可以创建、测试和调试新代码版本的地方。在工程师完成代码开发后,下一步是将更改提交到Git,并开始部署到不同的环境中进行集成测试和最终的产品发布。这个过程被称为持续集成/持续部署(CI/CD),通常由以下环境组成:
在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命名空间:
$ kubectl create namespace guestbook-qa
$ kubectl create namespace guestbook-e2
$ kubectl get namespaces
现在,您可以使用以下命令将留言簿应用程序部署到留言簿-qa环境:
$ 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 是否正在运行:
$ kubectl get pods -n guestbook-qa
NAME READY STATUS RESTARTS AGE
redis-leader-5596fc7b68-wxjvp 1/1 Running 0 77s
运行以下命令查看 Redis Deployment 中的日志:
$ 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 中写数据。因此,需要创建 Service 来转发 Redis Pod 的流量。Service 定义了访问 Pod 的策略。
留言板应用需要往 Redis 中写数据。因此,需要创建 Service 来转发 Redis Pod 的流量。Service 定义了访问 Pod 的策略。
application/guestbook/redis-leader-service.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
使用下面的 redis-leader-service.yaml 文件创建 Redis 的服务:
$ kubectl apply -f ./guestbook/redis-leader-service.yaml -n guestbook-qa
查询服务列表验证 Redis 服务是否正在运行:
$ 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 领导者只有一个 Pod,你可以通过添加若干 Redis 跟随者来将其配置为高可用状态, 以满足流量需求。
# 来源: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
应用下面的 redis-follower-deployment.yaml 文件创建 Redis Deployment:
$ kubectl apply -f ./guestbook/redis-follower-deployment.yaml -n guestbook-qa
通过查询 Pods 列表,验证两个 Redis 跟随者副本在运行:
$ 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 命令来证明这一点:
$ 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添加一个网络策略:
$ kubectl apply -f block-other-namespace.yaml
GitOps 中针对 Git 的三种情况,分别是单分支(多目录),多分支,多代码库与单一代码库
每种策略都有其优点和缺点,选择哪一种取决于组织的需求、团队的大小、项目的复杂性以及对风险管理的态度。通常,这些策略可能会结合使用,以适应不同的项目和组织结构。
环境的配置管理可以到每一个环境中创建一个目录,其中包含所有的应该部署的资源的 YAML 清单,这些 YAML 清单中所有值都可以硬编码为该环境所需的特定值。
需要进行部署,那么运行:
$ kubectl apply <directory>
一个 SaaS 的应用程序开发者将其定制的应用程序部署到一个或者多个环境(dev, test)
这些环境可能分布在不同的账户,集群或者命名空间。它们之间有细微的区别,因此配置重用是最重要的。
helm 作为出场的第一个配置工具,是 Kubernetes 生态中不可或缺的一部分。
以下是Helm的主要特点和它在Kubernetes生态中的作用:
Jsonnet,作为一种编程语言,主要被设计来增强和简化JSON数据的声明和处理。虽然它并非专门为Kubernetes设计,但在Kubernetes社区中确实获得了广泛的应用和普及。以下是Jsonnet的关键特性和它在数据处理中的作用:
CICD 流水线中的阶段
持续集成 (CI)是一种软件开发的实践,在这种实践中,所有的开发人员都会在一个中央仓库(GIT)中合并变更,通过 CI ,每一次代码变更(提交)都会触发给定仓库的自动构建和测试阶段,并向做出变更的开发者提供反馈。与传统的 CI 相比,GitOps 的主要区别在于,在构建和测试阶段成功完成后,CI 流水线还会在应用程序清单中更新新的镜像版本。
持续交付(CD) 是将整个软件发布过程自动化。
与传统的 CICD 不同,使用 GitOps Operator 来监控清单的变化并协调部署,只要 CI 构建完成,并且清单更新,GitOps Operator 就会
步骤如下:
流程将从“拉取请求”开始,经过多个阶段,如“代码审核”、“漏洞扫描”、“代码分析”、“构建”、“单元测试”、“代码覆盖”、“Docker构建”、“Docker推送”、“Git克隆配置仓库”、“更新配置清单”、“Git提交和推送”、“发布CI指标”,最后到达“构建通知”。

集成 Go 语言和其他的一些工具:
golint 或 gometalinter 的 Go 语言代码审查工具。gosec。staticcheck 的静态分析工具。go test 命令。cover 工具来检查测试覆盖率。Viper 或 Consul 等 Go 语言配置管理工具,以便更好地管理和维护配置。
持续集成后,就进入到持续交付的环节了,
建立在 GitOps CICD 基础上的完整的 CD 流水线

我们知道,Kubernetes 清单和代码一般不放在同一个仓库,这样可以获取到更灵活的部署选择,更好的访问控制和审计能力。那么我们应该在哪里维护特定的环境依赖的应用配置,如数据库链接和分布式缓存。
在 GitOps 实践中,git reset 和 git revert 是两个重要的 Git 命令,它们用于处理配置变更和维护历史记录。理解这两个命令的差异和适用场景对于有效地管理 Kubernetes 配置至关重要。
git reset 命令用于撤销某些提交,它可以将 HEAD 指针移动到指定的提交。git reset。git reset 会更改历史记录,这在共享仓库中可能会导致问题。其他开发者需要用 git pull --force 来同步更改,这可能导致混乱。git revert 命令用于撤销某个特定的提交,但它不会改变历史记录。相反,它会创建一个新的提交,这个新提交的状态与要撤销的提交相反。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 的主要目的是确保在任何时候都有指定数量的 Pod 副本正在运行。ReplicaSet 可以确保指定数量的 Pod 实例始终运行,但它本身并不支持滚动更新。如果你需要更新 Pod 的定义(例如,更新使用的容器镜像),就需要手动更新 ReplicaSet,或者删除并重新创建它。Deployment 是一个更高级别的抽象,它在 ReplicaSet 的基础上提供了更多功能。它不仅确保 Pod 数量,还支持声明式地更新 Pod 和 ReplicaSet。Deployment 支持滚动更新,允许你逐渐替换旧版本的 Pod 为新版本,而不会导致停机。Deployment 非常适合 GitOps 的工作流。你可以在 Git 仓库中声明应用的期望状态,然后使用自动化工具(如 Argocd 或 Flux)来监视仓库并将更改应用到 Kubernetes 集群。
在Kubernetes中,Service 是一种抽象,它定义了一组逻辑的Pods和访问它们的策略。服务所针对的豆 Pod targeted由以下选择器确定
Service minifest 中的字段。然后,服务将流量转发到带有选择器指定的匹配标签的Pods。如果底层的Pods是无状态和向后兼容的,那么Service可以进行循环负载平衡,并且非常适合滚动更新。如果需要为部署定制负载平衡,则需要探索其他路由替代方案。
当Service收到流量时,它会根据定义的选择器将流量转发到拥有相应匹配标签的Pods。例如,如果Service的选择器被设置为匹配标签“color: blue”,那么所有带有此标签的Pods将接收到由该Service转发的流量。这种方法使得流量管理既灵活又高效。
如果底层的Pods是无状态的(Stateless)并且保持向后兼容性,那么Service可以实现有效的循环负载平衡。这对于实施滚动更新尤为重要,因为它允许在不中断服务的情况下逐步替换旧的Pods。
对于需要更复杂路由逻辑或定制负载平衡的部署,可能需要探索Kubernetes提供的其他路由替代方案。例如,使用Ingress Controllers和Ingress Resources可以提供更高级的路由能力,比如基于URL的路由、SSL/TLS终端加密和负载均衡策略。
Kubernetes中的服务路由是完全基于标签的。这意味着,例如,一个标记为“blue”的Service只会将流量路由到带有“blue”标签的Pods,而一个标记为“green”的Service则只路由到带有“green”标签的Pods。这种设计允许简单而直观的流量分配和管理。

NGINX Ingress Controller是一个功能强大的工具,用于在Kubernetes环境中管理进入集群的流量。它支持多种负载平衡和路由规则,适用于广泛的用例。关键特点包括:
通过这些功能,NGINX Ingress Controller能够有效地管理和优化进入Kubernetes集群的流量。
Istio Gateway是另一个关键组件,用于在Kubernetes集群的边缘管理流量。它主要负责处理进入和离开集群的HTTP和TCP连接。Istio Gateway的主要特点包括:

说明通过Kubernetes中的Ingress控制器的流量流和Istio服务网格中的流量流的图表已经准备好了。这些图表清晰地比较了每个系统在Kubernetes环境中如何处理流量路由和管理,包括入口控制器和Istio网关的角色。
Argo Rollouts 是一个Kubernetes控制器,用于更复杂、更强大的部署策略,如蓝绿部署(Blue-Green Deployments)和金丝雀部署(Canary Deployments)。它通过扩展Kubernetes自身的部署能力,使得在不中断服务的情况下更新和管理应用程序变得更加容易。
先决条件:
安装命令:
Argo Rollouts 可以通过其 Helm 图表或使用 kubectl 直接从其 GitHub 仓库安装。
使用 Helm 安装(如果您使用 Helm):
helm repo add argo https://argoproj.github.io/argo-helm
helm install argo-rollouts argo/argo-rollouts
或者,使用 kubectl 从其 GitHub 仓库安装:
kubectl create namespace argo-rollouts
kubectl apply -n argo-rollouts -f https://raw.githubusercontent.com/argoproj/argo-rollouts/stable/manifests/install.yaml
创建 Rollout 资源定义:
示例 Rollout 定义:
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}
应用 Rollout 资源:
使用 kubectl 应用您的 Rollout 定义:
kubectl apply -f your-rollout-definition.yaml
监控 Rollout 状态:
使用 kubectl 检查 Rollout 状态:
kubectl argo rollouts get rollout example-rollout --watch
管理 Rollout:
我们已经知道,支持声明式的 Deployment 的滚动更新是更新应用的绝佳方式,因为你的应用在部署期间将使用大致相同数量的资源,且停机时间为零,对性能的影响最小。然而,由于向后不兼容性或有状态性,有许多遗留应用程序不能很好地与滚动更新一起工作。有些应用程序可能还需要部署新版本并立即切换到该版本,或者在出现问题时快速回滚。对于这些用例,蓝绿色部署将是适当的部署策略。蓝绿部署通过让两个部署同时完全扩展,但只将传入流量定向到两个部署中的一个来实现这些。
这里我们使用 Nginx Ingress 控制器将 100% 的流量路由到 blue 或者 green deployment,因为内置的 kubernetes service 只支持 iptables,并不重置与 pod 的现有链接,因此不适合蓝绿发布。
在 Kubernetes 环境中,虽然声明式的 Deployment 通过滚动更新(Rolling Update)提供了零停机时间和最小化对性能的影响,但确实存在某些情况和应用程序类型,其中这种方法可能不是最佳选择。特别是对于那些有状态性(Stateful)应用或因向后不兼容性而难以进行滚动更新的遗留应用程序,蓝绿部署(Blue-Green Deployment)可能更适合。
Iptables 是 Linux 上一种强大的防火墙工具,用于控制进出 Linux 系统的网络流量。它是基于 Netfilter 提供的网络包过滤框架,允许系统管理员配置规则集,以过滤流量并提供 NAT 功能。
filter、nat 和 mangle 表用于不同类型的流量处理。Iptables 支持 NAT 功能,包括源地址转换(SNAT)和目的地址转换(DNAT)。阻止来自特定 IP 地址的流量:
iptables -A INPUT -s 123.456.789.0 -j DROP
允许特定端口的流量:
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
Iptables 的灵活性和强大功能使其成为 Linux 系统中管理网络流量和实施安全策略的关键工具。然而,由于其复杂性,建议在生产环境中谨慎使用,并且在应用任何规则之前进行充分的测试。
蓝绿部署的核心思想是同时维护两个生产环境(或部署)的完全不同版本:一个蓝色(Blue)版本和一个绿色(Green)版本。
这两个部署都会完全扩展,但在任何时刻,只有一个部署(蓝色或绿色)会接收到所有传入流量。
流量路由:
在蓝绿部署中,Nginx Ingress 控制器可以用于将100%的流量路由到蓝色或绿色部署。或者是将部分的流量路由到蓝色部署,部分的流量路由到绿色部署。
哈哈哈但是这样貌似就不是蓝绿部署了,有点像是金丝雀部署:
如果您的需求是同时向蓝色和绿色部署分配流量,那么您可能需要考虑使用金丝雀部署(Canary Deployment)。在金丝雀部署中,新版本(金丝雀)最初只接收一小部分流量,而主要流量仍然路由到旧版本。根据新版本的性能和稳定性,逐渐增加流向新版本的流量比例。
这是通过更新 Ingress 资源来实现的,该资源决定了哪个服务(蓝色还是绿色)将接收流量。
Kubernetes Service 的局限性:

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 资源来控制流量的路由。以下是实现这一策略的步骤和示例代码。
示例代码:
蓝色 Deployment (blue-deployment.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):
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 资源。
Rollout 资源 (blue-green-rollout.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
Active Service (active-service.yaml):
apiVersion: v1
kind: Service
metadata:
name: myapp-active
spec:
selector:
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 8080
Preview Service (preview-service.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
Ingress 资源 (ingress.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)是一种软件发布技术,它在更新应用程序时采取逐步的方法,以最小化风险。这种策略的命名源于矿工使用金丝雀作为一种安全预警系统的历史。在软件部署的语境中,它代表了逐渐引入新版本应用程序的过程,以便在全面部署前对其进行测试和验证。
version: stable)。version: canary)。Stable Deployment (stable-deployment.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
Canary Deployment (canary-deployment.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
Service (service.yaml):
yamlCopy codeapiVersion: v1
kind: Service
metadata:
name: myapp-service
spec:
selector:
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 8080
Ingress 资源 (ingress.yaml):
Rollout 资源 (canary-rollout.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}
Service (service.yaml):
在使用 Argo Rollouts 的情况下,部署的管理和流量分配变得更加简单和直观。您可以更精确地控制新版本的流量比例,并利用 Rollouts 的自动化特性来监控部署的健康状况和自动回滚
渐进式部署是金丝雀部署的一个完全的自动化版本。渐进式交互不是在扩大金丝雀部署之前检测一个固定的时间段,而是持续监测 Pod 的健康状态,并且不断扩大规模,直到完全扩展。
今天我们来看看 kubernetes 和 gitops 的理论实践
首先我们来看看 kubectl 支持的子命名,方便我们使用:
kubectl apply - 应用一个或多个资源的定义。通常用于部署应用程序或更新资源。kubectl get - 显示一个或多个资源的信息。这是查看 Kubernetes 集群中资源状态的常用命令。kubectl describe - 显示一个或多个资源的详细信息,如事件、状态和配置。kubectl delete - 删除 Kubernetes 集群中的资源。kubectl exec - 在集群中的容器里执行命令。kubectl logs - 打印容器的日志。kubectl create - 从文件或标准输入中创建一个或多个资源。kubectl edit - 编辑集群中的资源。这将打开一个编辑器来修改资源的配置。kubectl port-forward - 将本地端口转发到集群中的 Pod。kubectl run - 在集群中运行一个指定的镜像。kubectl scale - 调整资源(如 Deployment、ReplicaSet)的副本数量。kubectl rollout - 管理资源的部署,如查看状态、暂停、恢复或回滚更新。除了上面的命令,Kubernetes 中的 kubectl 还支持注解:
kubectl annotate 命令用于给 Kubernetes 集群中的资源添加或更新注解(annotations)。注解是一种附加信息,可以用于存储非识别性的元数据。它们通常用于管理工具、库和客户端以存储辅助信息,例如描述、版本信息等。
kubectl annotate [type] [name] [key]=[value]
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 可以负责部署数据库、备份数据、恢复数据等。
关键区别在于:
因此,所有的 Operator 都使用 Controller 的模式,但并非所有的 Controller 都是 Operator。这是因为所有 Operator 都是构建在控制器模式之上的,但控制器不一定需要具有管理特定应用程序生命周期的复杂逻辑和扩展 API 的能力,这是 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 来表示 Nginx 的配置。这个 CRD 将描述 Nginx 实例的属性,如版本、配置文件内容和相关的静态资源。
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
使用 Go 语言编写 Operator 控制器。Operator 控制器将监听 NginxConfig 资源的创建、更新和删除事件,并执行相应的操作。
package main
import (
// 引入必要的库
)
func main() {
// 初始化客户端、监听 NginxConfig 资源的变化
// 实现业务逻辑:创建/更新/删除 Nginx 实例
}
在控制器中,处理 Nginx 实例的创建和更新。当一个 NginxConfig 资源被创建或更新时,控制器会根据定义的规格来设置 Nginx Pod,包括所需的配置和静态文件。
将 Operator 打包成 Docker 镜像,然后在 Kubernetes 集群中部署这个镜像。
# 使用合适的基础镜像
FROM golang:1.15
# 添加 Operator 代码
ADD . /operator
WORKDIR /operator
# 编译 Operator
RUN go build -o operator .
# 设置启动命令
CMD ["./operator"]
部署到 Kubernetes:
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
创建一个 NginxConfig 实例来测试 Operator:
apiVersion: "example.com/v1"
kind: NginxConfig
metadata:
name: my-nginx
spec:
version: "latest"
staticContent: "Welcome to Nginx!"
监视 Kubernetes 集群,确保 Operator 正确响应了这个 NginxConfig 实例的创建。
接下来,我们首先创建一个 GitOps Operator 来驱动持续交付。
GitOps 是一种用于持续部署的实践,它将 Git 作为真实状态的源。在 GitOps 模型中,所有的部署和环境配置都存储在 Git 仓库中,这样做可以提供版本控制、审计跟踪和回滚能力。为了实现 GitOps,我们可以创建一个 GitOps Operator,它将自动化从 Git 仓库到 Kubernetes 集群的部署过程。
定义 GitOps CRD:
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
编写 Operator 控制器:
构建和部署 Operator:
测试 Operator:
不同的运行时环境,以及 Kubernetes 命名空间是如何定义环境边界的。
一个环境是由三个同样重要的部分组成的:
代码:
代码是应用程序执行特定任务的机器指令。要执行代码,可能还需要运行时依赖项。例如,Node.js代码需要Node.js二进制包和其他NPM包才能成功地执行。对于Kubernetes,所有运行时依赖项和代码都打包为一个可部署单元(又名Docker映像),并通过Docker守护进程进行编排。应用程序的Docker映像可以放心地在任何环境中运行,从开发人员的笔记本电脑到在云中运行的生产集群,因为映像封装了代码和所有依赖关系,消除了环境之间潜在的不兼容性。
在软件部署中,环境是部署和执行代码的地方。在软件开发的生存周期中,不同的环境服务于不同的目的。例如,本地开发环境(又名笔记本电脑)是工程师可以创建、测试和调试新代码版本的地方。在工程师完成代码开发后,下一步是将更改提交到Git,并开始部署到不同的环境中进行集成测试和最终的产品发布。这个过程被称为持续集成/持续部署(CI/CD),通常由以下环境组成:
在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命名空间:
$ kubectl create namespace guestbook-qa
$ kubectl create namespace guestbook-e2
$ kubectl get namespaces
现在,您可以使用以下命令将留言簿应用程序部署到留言簿-qa环境:
$ 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 是否正在运行:
$ kubectl get pods -n guestbook-qa
NAME READY STATUS RESTARTS AGE
redis-leader-5596fc7b68-wxjvp 1/1 Running 0 77s
运行以下命令查看 Redis Deployment 中的日志:
$ 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 中写数据。因此,需要创建 Service 来转发 Redis Pod 的流量。Service 定义了访问 Pod 的策略。
留言板应用需要往 Redis 中写数据。因此,需要创建 Service 来转发 Redis Pod 的流量。Service 定义了访问 Pod 的策略。
application/guestbook/redis-leader-service.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
使用下面的 redis-leader-service.yaml 文件创建 Redis 的服务:
$ kubectl apply -f ./guestbook/redis-leader-service.yaml -n guestbook-qa
查询服务列表验证 Redis 服务是否正在运行:
$ 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 领导者只有一个 Pod,你可以通过添加若干 Redis 跟随者来将其配置为高可用状态, 以满足流量需求。
# 来源: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
应用下面的 redis-follower-deployment.yaml 文件创建 Redis Deployment:
$ kubectl apply -f ./guestbook/redis-follower-deployment.yaml -n guestbook-qa
通过查询 Pods 列表,验证两个 Redis 跟随者副本在运行:
$ 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 命令来证明这一点:
$ 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添加一个网络策略:
$ kubectl apply -f block-other-namespace.yaml
GitOps 中针对 Git 的三种情况,分别是单分支(多目录),多分支,多代码库与单一代码库
每种策略都有其优点和缺点,选择哪一种取决于组织的需求、团队的大小、项目的复杂性以及对风险管理的态度。通常,这些策略可能会结合使用,以适应不同的项目和组织结构。
环境的配置管理可以到每一个环境中创建一个目录,其中包含所有的应该部署的资源的 YAML 清单,这些 YAML 清单中所有值都可以硬编码为该环境所需的特定值。
需要进行部署,那么运行:
$ kubectl apply <directory>
一个 SaaS 的应用程序开发者将其定制的应用程序部署到一个或者多个环境(dev, test)
这些环境可能分布在不同的账户,集群或者命名空间。它们之间有细微的区别,因此配置重用是最重要的。
helm 作为出场的第一个配置工具,是 Kubernetes 生态中不可或缺的一部分。
以下是Helm的主要特点和它在Kubernetes生态中的作用:
Jsonnet,作为一种编程语言,主要被设计来增强和简化JSON数据的声明和处理。虽然它并非专门为Kubernetes设计,但在Kubernetes社区中确实获得了广泛的应用和普及。以下是Jsonnet的关键特性和它在数据处理中的作用:
CICD 流水线中的阶段
持续集成 (CI)是一种软件开发的实践,在这种实践中,所有的开发人员都会在一个中央仓库(GIT)中合并变更,通过 CI ,每一次代码变更(提交)都会触发给定仓库的自动构建和测试阶段,并向做出变更的开发者提供反馈。与传统的 CI 相比,GitOps 的主要区别在于,在构建和测试阶段成功完成后,CI 流水线还会在应用程序清单中更新新的镜像版本。
持续交付(CD) 是将整个软件发布过程自动化。
与传统的 CICD 不同,使用 GitOps Operator 来监控清单的变化并协调部署,只要 CI 构建完成,并且清单更新,GitOps Operator 就会
步骤如下:
流程将从“拉取请求”开始,经过多个阶段,如“代码审核”、“漏洞扫描”、“代码分析”、“构建”、“单元测试”、“代码覆盖”、“Docker构建”、“Docker推送”、“Git克隆配置仓库”、“更新配置清单”、“Git提交和推送”、“发布CI指标”,最后到达“构建通知”。

集成 Go 语言和其他的一些工具:
golint 或 gometalinter 的 Go 语言代码审查工具。gosec。staticcheck 的静态分析工具。go test 命令。cover 工具来检查测试覆盖率。Viper 或 Consul 等 Go 语言配置管理工具,以便更好地管理和维护配置。
持续集成后,就进入到持续交付的环节了,
建立在 GitOps CICD 基础上的完整的 CD 流水线

我们知道,Kubernetes 清单和代码一般不放在同一个仓库,这样可以获取到更灵活的部署选择,更好的访问控制和审计能力。那么我们应该在哪里维护特定的环境依赖的应用配置,如数据库链接和分布式缓存。
在 GitOps 实践中,git reset 和 git revert 是两个重要的 Git 命令,它们用于处理配置变更和维护历史记录。理解这两个命令的差异和适用场景对于有效地管理 Kubernetes 配置至关重要。
git reset 命令用于撤销某些提交,它可以将 HEAD 指针移动到指定的提交。git reset。git reset 会更改历史记录,这在共享仓库中可能会导致问题。其他开发者需要用 git pull --force 来同步更改,这可能导致混乱。git revert 命令用于撤销某个特定的提交,但它不会改变历史记录。相反,它会创建一个新的提交,这个新提交的状态与要撤销的提交相反。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 的主要目的是确保在任何时候都有指定数量的 Pod 副本正在运行。ReplicaSet 可以确保指定数量的 Pod 实例始终运行,但它本身并不支持滚动更新。如果你需要更新 Pod 的定义(例如,更新使用的容器镜像),就需要手动更新 ReplicaSet,或者删除并重新创建它。Deployment 是一个更高级别的抽象,它在 ReplicaSet 的基础上提供了更多功能。它不仅确保 Pod 数量,还支持声明式地更新 Pod 和 ReplicaSet。Deployment 支持滚动更新,允许你逐渐替换旧版本的 Pod 为新版本,而不会导致停机。Deployment 非常适合 GitOps 的工作流。你可以在 Git 仓库中声明应用的期望状态,然后使用自动化工具(如 Argocd 或 Flux)来监视仓库并将更改应用到 Kubernetes 集群。
在Kubernetes中,Service 是一种抽象,它定义了一组逻辑的Pods和访问它们的策略。服务所针对的豆 Pod targeted由以下选择器确定
Service minifest 中的字段。然后,服务将流量转发到带有选择器指定的匹配标签的Pods。如果底层的Pods是无状态和向后兼容的,那么Service可以进行循环负载平衡,并且非常适合滚动更新。如果需要为部署定制负载平衡,则需要探索其他路由替代方案。
当Service收到流量时,它会根据定义的选择器将流量转发到拥有相应匹配标签的Pods。例如,如果Service的选择器被设置为匹配标签“color: blue”,那么所有带有此标签的Pods将接收到由该Service转发的流量。这种方法使得流量管理既灵活又高效。
如果底层的Pods是无状态的(Stateless)并且保持向后兼容性,那么Service可以实现有效的循环负载平衡。这对于实施滚动更新尤为重要,因为它允许在不中断服务的情况下逐步替换旧的Pods。
对于需要更复杂路由逻辑或定制负载平衡的部署,可能需要探索Kubernetes提供的其他路由替代方案。例如,使用Ingress Controllers和Ingress Resources可以提供更高级的路由能力,比如基于URL的路由、SSL/TLS终端加密和负载均衡策略。
Kubernetes中的服务路由是完全基于标签的。这意味着,例如,一个标记为“blue”的Service只会将流量路由到带有“blue”标签的Pods,而一个标记为“green”的Service则只路由到带有“green”标签的Pods。这种设计允许简单而直观的流量分配和管理。

NGINX Ingress Controller是一个功能强大的工具,用于在Kubernetes环境中管理进入集群的流量。它支持多种负载平衡和路由规则,适用于广泛的用例。关键特点包括:
通过这些功能,NGINX Ingress Controller能够有效地管理和优化进入Kubernetes集群的流量。
Istio Gateway是另一个关键组件,用于在Kubernetes集群的边缘管理流量。它主要负责处理进入和离开集群的HTTP和TCP连接。Istio Gateway的主要特点包括:

说明通过Kubernetes中的Ingress控制器的流量流和Istio服务网格中的流量流的图表已经准备好了。这些图表清晰地比较了每个系统在Kubernetes环境中如何处理流量路由和管理,包括入口控制器和Istio网关的角色。
Argo Rollouts 是一个Kubernetes控制器,用于更复杂、更强大的部署策略,如蓝绿部署(Blue-Green Deployments)和金丝雀部署(Canary Deployments)。它通过扩展Kubernetes自身的部署能力,使得在不中断服务的情况下更新和管理应用程序变得更加容易。
先决条件:
安装命令:
Argo Rollouts 可以通过其 Helm 图表或使用 kubectl 直接从其 GitHub 仓库安装。
使用 Helm 安装(如果您使用 Helm):
helm repo add argo https://argoproj.github.io/argo-helm
helm install argo-rollouts argo/argo-rollouts
或者,使用 kubectl 从其 GitHub 仓库安装:
kubectl create namespace argo-rollouts
kubectl apply -n argo-rollouts -f https://raw.githubusercontent.com/argoproj/argo-rollouts/stable/manifests/install.yaml
创建 Rollout 资源定义:
示例 Rollout 定义:
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}
应用 Rollout 资源:
使用 kubectl 应用您的 Rollout 定义:
kubectl apply -f your-rollout-definition.yaml
监控 Rollout 状态:
使用 kubectl 检查 Rollout 状态:
kubectl argo rollouts get rollout example-rollout --watch
管理 Rollout:
我们已经知道,支持声明式的 Deployment 的滚动更新是更新应用的绝佳方式,因为你的应用在部署期间将使用大致相同数量的资源,且停机时间为零,对性能的影响最小。然而,由于向后不兼容性或有状态性,有许多遗留应用程序不能很好地与滚动更新一起工作。有些应用程序可能还需要部署新版本并立即切换到该版本,或者在出现问题时快速回滚。对于这些用例,蓝绿色部署将是适当的部署策略。蓝绿部署通过让两个部署同时完全扩展,但只将传入流量定向到两个部署中的一个来实现这些。
这里我们使用 Nginx Ingress 控制器将 100% 的流量路由到 blue 或者 green deployment,因为内置的 kubernetes service 只支持 iptables,并不重置与 pod 的现有链接,因此不适合蓝绿发布。
在 Kubernetes 环境中,虽然声明式的 Deployment 通过滚动更新(Rolling Update)提供了零停机时间和最小化对性能的影响,但确实存在某些情况和应用程序类型,其中这种方法可能不是最佳选择。特别是对于那些有状态性(Stateful)应用或因向后不兼容性而难以进行滚动更新的遗留应用程序,蓝绿部署(Blue-Green Deployment)可能更适合。
Iptables 是 Linux 上一种强大的防火墙工具,用于控制进出 Linux 系统的网络流量。它是基于 Netfilter 提供的网络包过滤框架,允许系统管理员配置规则集,以过滤流量并提供 NAT 功能。
filter、nat 和 mangle 表用于不同类型的流量处理。Iptables 支持 NAT 功能,包括源地址转换(SNAT)和目的地址转换(DNAT)。阻止来自特定 IP 地址的流量:
iptables -A INPUT -s 123.456.789.0 -j DROP
允许特定端口的流量:
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
Iptables 的灵活性和强大功能使其成为 Linux 系统中管理网络流量和实施安全策略的关键工具。然而,由于其复杂性,建议在生产环境中谨慎使用,并且在应用任何规则之前进行充分的测试。
蓝绿部署的核心思想是同时维护两个生产环境(或部署)的完全不同版本:一个蓝色(Blue)版本和一个绿色(Green)版本。
这两个部署都会完全扩展,但在任何时刻,只有一个部署(蓝色或绿色)会接收到所有传入流量。
流量路由:
在蓝绿部署中,Nginx Ingress 控制器可以用于将100%的流量路由到蓝色或绿色部署。或者是将部分的流量路由到蓝色部署,部分的流量路由到绿色部署。
哈哈哈但是这样貌似就不是蓝绿部署了,有点像是金丝雀部署:
如果您的需求是同时向蓝色和绿色部署分配流量,那么您可能需要考虑使用金丝雀部署(Canary Deployment)。在金丝雀部署中,新版本(金丝雀)最初只接收一小部分流量,而主要流量仍然路由到旧版本。根据新版本的性能和稳定性,逐渐增加流向新版本的流量比例。
这是通过更新 Ingress 资源来实现的,该资源决定了哪个服务(蓝色还是绿色)将接收流量。
Kubernetes Service 的局限性:

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 资源来控制流量的路由。以下是实现这一策略的步骤和示例代码。
示例代码:
蓝色 Deployment (blue-deployment.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):
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 资源。
Rollout 资源 (blue-green-rollout.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
Active Service (active-service.yaml):
apiVersion: v1
kind: Service
metadata:
name: myapp-active
spec:
selector:
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 8080
Preview Service (preview-service.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
Ingress 资源 (ingress.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)是一种软件发布技术,它在更新应用程序时采取逐步的方法,以最小化风险。这种策略的命名源于矿工使用金丝雀作为一种安全预警系统的历史。在软件部署的语境中,它代表了逐渐引入新版本应用程序的过程,以便在全面部署前对其进行测试和验证。
version: stable)。version: canary)。Stable Deployment (stable-deployment.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
Canary Deployment (canary-deployment.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
Service (service.yaml):
yamlCopy codeapiVersion: v1
kind: Service
metadata:
name: myapp-service
spec:
selector:
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 8080
Ingress 资源 (ingress.yaml):
Rollout 资源 (canary-rollout.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}
Service (service.yaml):
在使用 Argo Rollouts 的情况下,部署的管理和流量分配变得更加简单和直观。您可以更精确地控制新版本的流量比例,并利用 Rollouts 的自动化特性来监控部署的健康状况和自动回滚
渐进式部署是金丝雀部署的一个完全的自动化版本。渐进式交互不是在扩大金丝雀部署之前检测一个固定的时间段,而是持续监测 Pod 的健康状态,并且不断扩大规模,直到完全扩展。