01 金丝雀部署

金丝雀部署(Canary releases)是一种软件发布技术,可以通过将新版本的应用程序逐步部署到生产环境中的一小部分用户,来降低部署新软件版本的风险。如果新版本在初期测试中表现良好,它可以逐步推广到所有用户。
Istio控制流量的百分比

04 istio

k8s 1.21.5 对应 istio 1.12
istio部署步骤 移除污点
kubectl taint nodes node-role.kubernetes.io/master-

001 istio中 addons是干嘛的?

在 Istio 中,“addons” 是指一组用于增强和扩展 Istio 功能的附加组件。这些附加组件提供了额外的功能和特性,可以帮助你更好地管理和监控你的服务网格。

Istio 的 “addons” 组件包括:

  1. Grafana:一个流行的开源数据可视化工具,用于监控和展示 Istio 的度量指标。
  2. Jaeger:一个分布式追踪系统,用于跟踪和调试请求在微服务架构中的流动情况。
  3. Kiali:一个图形化的控制台工具,用于可视化和理解 Istio 网格的拓扑结构、流量状况、策略等。
  4. Prometheus:一个用于监控和报警的开源系统,用于收集、存储和分析各种指标数据。

这些 “addons” 组件可以通过运行 kubectl apply -f samples/addons 命令来安装到 Istio 部署中。

通过添加这些附加组件,你可以更好地监控你的服务网格并获得更多的洞察力,同时也能够更好地管理和操作你的 Istio 部署。

002 istio功能

0001 请求路由

网页有三个版本,可以控制网页怎么刷新都只走v1版本,还有让jack用户登录后看到的是v2版本

0002 故障注入
  1. 模拟延迟:登录网站后延迟7秒网页才反应过来
  2. http异常:手动注入让 jason用户的reviews模块不可用
    delete virtual-service-all-v1.yaml即可清理全部
0003 流量转移
  1. 开始的时候,100%的流量到v1版本。50%到v1版本,50%到v3版本。然后再把100%流量发送到v3
0004 熔断 就是限流

针对某个服务

  1. 连接池的连接数大于设定值的时候就会熔断,无法访问网页
  2. 在多少秒之内,当网关的错误数超过设定值,熔断
  3. 可以设置比如3分钟静默期,不在接收任何其他请求
0005 流量镜像

流量镜像(Traffic mirroring)是一种网络流量管理技术,用于将实时的网络流量复制到另一个目标或目标组,以进行监控、调试、安全分析或其他目的。

通过流量镜像,网络管理员可以在不影响正常流量传输的情况下获得副本或镜像的流量,以进行深入的分析和观察。通常,这个镜像流量被发送到专门用于处理和分析的工具或系统,例如数据包分析器、入侵检测系统(IDS)、日志分析平台等。

流量镜像的主要应用包括:

  1. 监控和故障排除:通过将流量镜像到监控系统,可以实时监视网络的性能、流量模式和问题,以快速识别和解决故障。
  2. 安全分析:将流量镜像到入侵检测系统(IDS)或安全信息与事件管理系统(SIEM),可以进行实时的流量分析,发现潜在的威胁、异常行为或恶意活动。
  3. 性能优化:通过镜像流量进行性能分析,可以确定瓶颈、延迟或带宽消耗,并采取相应的优化措施。
  4. 合规性和法规要求:许多合规性标准和法规要求对网络流量进行监控和审计。流量镜像可以帮助满足这些要求,并为安全审核提供必要的数据。
    重点注意这些被流量的镜像是“即发即弃”,就是说镜像请求的响应会被丢弃

003 kubectl logs -f --tail 100 -c istio-proxy和直接kubectl logs -f --tail 100 打印出来的日志有什么不同呢?

在 Kubernetes 环境中,kubectl logs 命令用于获取集群中运行的 pod 的日志。如果一个 pod 仅运行一个容器,那么只需提供 pod 名称即可。但如果 pod 中运行多个容器,就需要指定要获取日志的容器名。

在 Istio 服务网格中,部署到集群的 pod 通常会有两个容器:

  1. 业务容器:运行您的应用程序的地方。
  2. Sidecar 容器(istio-proxy):这是由 Istio 自动注入的 Envoy 代理容器,用于处理所有进出 pod 的流量。

现在,让我们区分这两个命令:

kubectl logs -f --tail 100 <pod-name> -c istio-proxy

这个命令将会:

  • 打印出名为 <pod-name> 的 pod 中的 istio-proxy 容器的实时日志。
  • 由于使用了 -f,如果在日志末尾添加新行,它将继续打印,这意味着您正在“跟踪”日志输出。
  • --tail 100 表示您只想查看最后的 100 行日志。
  • 这些日志主要关注入站和出站流量的信息,错误,警告和其他 Envoy 代理活动。

总之,直接使用 kubectl logs -f --tail 100 <pod-name> 通常会获取您的应用容器的日志,而不是 sidecar 的 istio-proxy 容器的日志。 若要获取特定于 Istio 功能和流量管理的日志,您需要指定 -c istio-proxy

关于出站和入站流量的控制
在Istio服务网格中,"入站"和"出站"流量指的是流经每个服务实例边车(sidecar)代理的网络流量。具体来说:

  1. 入站流量
    例如,如果服务A调用服务B,那么对于服务B的sidecar代理来说,从服务A到服务B的流量被视为入站流量。
  2. 出站流量
    例如,如果服务B需要查询数据库或调用外部API,它将通过它的sidecar代理发送请求,这些请求被认为是出站流量。

Istio的Envoy sidecar利用这些信息来提供丰富的功能集,例如:

  • 流量路由控制:基于HTTP请求信息(如头信息)将流量引导至不同的服务版本(例如,A/B测试或蓝/绿部署)。
  • 重试和超时:为了提高服务的健壮性和可靠性,对失败的服务调用进行重试,设置请求的超时限制。
  • 故障注入:故意制造失败场景,例如延迟或错误响应,以测试系统的弹性。
  • 安全通信:使用mTLS(相互TLS)确保服务之间的通信安全。
  • 访问控制:限制哪些服务可以访问您的服务实例。
  • 遥测数据收集:收集有关系统流量模式、效率和安全的详细指标、日志和追踪数据。

通过分析这些入站和出站流量的日志和指标,开发者和运维团队能够更好地理解其系统的行为和性能,从而能够更加有效地响应问题、调整资源分配和计划未来的需求。

004 jager的意义–谁调谁,谁耗时多都能查出来

假设您在Istio服务网格中运行了一个在线零售网站的微服务架构。这个架构包括以下服务:

  1. 前端界面(frontend
  2. 订单处理(orders
  3. 产品目录(catalog
  4. 付款处理(payment

用户通过frontend服务浏览产品,下单购买,这个请求流会涉及其他服务的调用。比如,用户下单可能就需要orders服务记录订单,catalog服务确认产品信息,payment服务处理支付。

在这样的系统中使用Jaeger的例子如下:

场景:用户报告说,当他们尝试下单时,经常会遇到延迟,有时甚至会失败。

问题定位与解决

  1. 启动追踪:您在Istio中启用了Jaeger分布式追踪系统,系统开始收集通过服务网格的请求的追踪数据。
  2. 发现性能瓶颈:通过Jaeger的界面,您可以看到用户下单的请求流程。在这个流程中,每个请求通过frontend传递到orderscatalog、然后是payment服务。您注意到payment服务响应时间长,而且有时会失败。
  3. 深入分析:通过Jaeger,您能够深入到每个单独的追踪,查看payment服务处理请求的详细信息。您发现,每当请求延迟或失败时,都是因为与第三方支付网关的通信延迟。
  4. 优化与修复:了解了问题原因后,您决定实施一些更改,比如增加对第三方支付网关调用的超时时间,并且设置重试逻辑。或者,您可能会与支付网关提供商讨论优化他们的服务性能。
  5. 持续监控:更改上线后,您继续使用Jaeger监控服务调用。随着时间的推移,您注意到支付请求的性能有所改善,用户体验也得到提高。

在此示例中,Jaeger使您能够可视化请求在系统中的流动,发现性能瓶颈,并针对具体问题采取行动。没有分布式追踪,这种级别的问题解析和微调将会非常具有挑战性和耗时。

005 kiali 能看到吞吐量,ops

在 Kiali 中,“OPS” 可能指的是 “Operations Per Second” 的缩写,即每秒操作数。它通常用于衡量系统或组件的性能和处理能力。
OPS 是一个指标,用于衡量在给定时间间隔内系统或组件能够执行的操作数量。它可以用于评估系统的处理速度、并发性和性能瓶颈等方面。
Kiali和Jaeger的组合使用为服务网格中的问题诊断、配置管理和优化提供了全方位的支持。Kiali提供了宏观视角和操作能力,而Jaeger提供了更细粒度的事务分析。

05 CRDs

deployment,statfulset,daemonset只是控制pod,要是控制其他资源用什么?用CRDs

001 自定义的todo

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: todos.sample.com
spec:
  group: sample.com
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                task:
                  type: string
                priority:
                  type: string
  scope: Namespaced
  names:
    plural: todos
    singular: todo
    kind: Todo

在上述示例中,我们在 CRD 定义的 spec.versions[0] 下添加了 schema 部分,并定义了一个简单的模式。该模式指定了 spec.taskspec.priority 字段的类型为字符串。

请根据你的实际需要调整模式的定义。一旦添加了正确的模式后,再次运行 kubectl apply 命令来应用 CRD 定义:

kubectl apply -f todo-crd.yaml
  1. 创建一个 Todo 实例。假设我们有一个名为 todo-instance.yaml 的 YAML 文件,其中包含了要创建的 Todo 实例的信息。例如,内容如下:
apiVersion: sample.com/v1
   kind: Todo
   metadata:
     name: my-todo
   spec:
     task: 购买杂货
     priority: 高

在这个例子中,我们创建了一个名为 my-todoTodo 实例,具有购买杂货的任务和高优先级。

运行以下命令来创建这个 Todo 实例:

kubectl apply -f todo-instance.yaml

Kubernetes 将会在集群中创建一个名为 my-todoTodo 实例。

  1. 使用 kubectl 或其他 Kubernetes 工具管理 Todo 实例。例如,可以通过以下命令获取所有的 Todo 实例列表:
kubectl get todos

你还可以使用类似的命令进行创建、更新或删除 Todo 实例。

002 istio中

通过使用VirtualService和DestinationRule,Istio可以动态地改变服务网格中的流量规则和通信策略,而无需改动任何实际的服务代码。这种灵活性和控制力是通过Istio控制平面到数据平面(Envoy代理)的紧密协作实现的

003 GPU

没有gpu的crd,k8s怎么知道每台机器上都有哪些gpu,都有几块,知道了才能自动调度过去

06 docker export的例子

在项目开发和运维中,docker export 的用途可能并不像 docker save 那样常见,因为后者可以保存完整的镜像,包括历史和元数据。然而,有一些场景下 docker export 还是很有用的。以下是一个具体的例子:

项目背景

假设你正在一个开发团队工作,该团队负责一个基于Web的应用程序。你们使用Docker容器来隔离应用程序的开发、测试和生产环境。在开发过程中,你们可能需要在不同开发人员之间共享应用程序的当前状态,或者从开发环境向测试环境迁移带有特定数据和配置的应用实例。

用例:共享应用状态

开发人员Alice已经在她的本地开发环境中,使用一个Docker容器进行了一系列的修改,包括安装了新的依赖、调整了配置文件和加入了一些临时的测试数据。现在,她需要将这个容器的当前状态分享给另一个开发人员Bob,这样Bob就可以在Alice的基础上继续工作。

Alice决定使用docker export来快速地创建一个包含容器文件系统的快照,并将这个快照发送给Bob。

执行步骤

  1. Alice列出正在运行的容器,找到她正在工作的容器ID。
docker ps
  1. Alice导出容器的文件系统到一个tar包中。
docker export my_app_container -o my_app_snapshot.tar
  1. Alice将my_app_snapshot.tar文件通过网络驱动器、文件共享服务或任何其他文件传输方法发送给Bob。
  2. Bob收到tar文件后,使用docker import来创建一个新的镜像。
cat my_app_snapshot.tar | docker import - my_app_snapshot_image
  1. Bob现在可以使用这个镜像来创建一个新的容器,并在Alice离开的地方继续工作。
docker run -d --name bob_work_container my_app_snapshot_image

注意事项

  • 这种方法仅适用于无状态应用或者状态全部包含在容器内部的情况。如果应用程序使用了外部数据卷或数据库服务,这种方法则不会包含那部分数据。
  • docker export 不包含容器的元数据,如环境变量、命令历史或者专门的配置。如果这些信息对于容器的运行很重要,你需要以其他方式(如文档、脚本等)进行共享。

在实际项目中,更推荐的持久化和迁移方式可能是通过Docker镜像和数据卷的快照,特别是在需要持久化关键数据和保留完整配置信息时。但在某些快速共享和低成本备份的场景下,docker export 还是一个非常有用的工具。

07 移动mysql docker

如何查看mysql容器,数据库内容存在哪里?

当您在Docker容器中运行MySQL时,数据库文件实际上存储在容器的文件系统内部,但对于持久存储和管理方便,通常会将数据保存在容器外部的卷(volume)或绑定挂载(bind mount)中。要查看这些数据文件,您可以按照以下步骤操作:

查看MySQL容器使用的卷:

  1. 查看容器详情:
    使用docker inspect命令来查找容器的详细信息,包括卷和挂载信息。
docker inspect <container_name_or_id>

<container_name_or_id>替换为您的MySQL容器的名称或ID。

  1. 查找“Mounts”部分:
    docker inspect的输出中,找到“Mounts”部分。这里会列出所有的挂载点,其中包括源路径(在宿主机上的位置)和目标路径(在容器内部的位置)。
"Mounts": [
    {
        "Type": "bind",
        "Source": "/my/own/datadir",
        "Destination": "/var/lib/mysql",
        "Mode": "",
        "RW": true,
        "Propagation": "rprivate"
    }
]

或者,如果使用的是卷:

"Mounts": [
    {
        "Type": "volume",
        "Name": "mydbdata",
        "Source": "/var/lib/docker/volumes/mydbdata/_data",
        "Destination": "/var/lib/mysql",
        "Driver": "local",
        "Mode": "",
        "RW": true,
        "Propagation": ""
    }
]

在这个例子中,MySQL的数据存储在宿主机的/my/own/datadir目录或者卷mydbdata对应的路径/var/lib/docker/volumes/mydbdata/_data中。

访问数据文件:

  1. 如果您使用的是绑定挂载,直接访问宿主机上相应的目录即可查看文件。
ls /my/own/datadir
  1. 如果您使用的是卷,可以通过以下两种方法访问:
  • 直接访问卷在宿主机上的存储位置(如上面的“Source”所示)。
  • 使用docker exec命令进入容器内部,然后访问挂载点。
docker exec -it <container_name_or_id> bash

然后在容器内部访问/var/lib/mysql目录。

请注意,处理这些MySQL数据文件时应该非常小心,因为直接修改或移动这些文件可能会导致数据损坏或丢失。当容器正在运行时,不建议在外部直接操作这些数据文件。如果需要备份或操作数据,应该使用MySQL提供的工具如mysqldump或者相应的Docker命令来操作容器。

如果使用docker save 的话,打包出来的tar放到另一台机器上load 进 tar包,/var/lib/docker/volumes/mydbdata/_data里面的数据会跟过来吗?

不会,docker save 命令导出的是Docker镜像,不包括容器的运行时数据。具体来说,docker save 导出的是镜像的所有层以及构成这些层的文件,还有镜像的配置(例如,环境变量、默认运行命令、暴露端口等),但是不包含以下内容:

  • 容器的当前运行状态或进程信息。
  • 挂载到容器上的数据卷内容(如 /var/lib/docker/volumes/mydbdata/_data 中的数据)。
  • 容器的临时存储。

如果你想在另一台机器上重建容器的完整环境,包括数据,你需要单独备份数据卷内容。通常,这是通过在源机器上运行额外的命令来完成的,例如使用 docker cp 来拷贝数据,或者直接将数据卷所在的目录打包为tar文件。然后,将数据卷和镜像一起移动到目标机器上,创建新的容器时再挂载数据卷。

这里是你可能会采用的步骤:

  1. 使用 docker save 来保存镜像为tar文件:
docker save myimage:tag -o myimage.tar
  1. 将数据卷打包为tar文件(如果是在宿主机的特定目录下):
sudo tar cvf mydbdata.tar /var/lib/docker/volumes/mydbdata/_data
  1. 将这两个tar文件传输到目标机器。
  2. 在目标机器上,使用 docker load 来加载镜像:
docker load -i myimage.tar
  1. 解压数据卷tar到新的数据卷目录:
sudo tar xvf mydbdata.tar -C /path/to/newvolume
  1. 创建新的容器,并将数据卷挂载到正确的位置:
docker run -v /path/to/newvolume:/var/lib/mysql -d -p 3336:3306 myimage:tag

这样,新机器上的容器将使用与原始机器相同的镜像,并且能够访问到原始数据。记得,在处理数据时一定要小心,尤其是数据库数据,避免在不同环境间直接拷贝生产数据到测试环境,以免导致数据泄露或者不一致性问题。

Problems

01 K8s Ingress 解决 “长连接” 负载不均衡的问题

在 Kubernetes (k8s) 环境中,长连接可能导致的负载不均衡问题是一个关键议题。长连接,即持久连接,是指客户端和服务器之间建立的TCP连接在传输完成后依然保持打开状态,以便后续的请求可以使用同一连接。这种机制对于减少建立连接的开销、提高性能很有帮助,但在负载均衡方面,可能会出现问题。

  1. 问题描述:
    当使用基于连接的负载均衡(例如最简单的轮询机制)时,新的连接会被均匀分配到后端的各个服务器。但是,对于长连接的场景,一旦连接被建立并分配给了某个服务器,它会持续一段相对较长的时间。如果在这段时间内,有大量的请求沿着这些现存的连接发送,那么,即使某些服务器可能已经过载,新的请求还是会发送到这些服务器,因为连接已经建立。
    这种情况下,新启动的 pod 或者相对空闲的服务器可能接收不到足够的流量,因为它们没有与客户端建立足够的长连接。这就导致了不均衡的负载分配。
  2. 举例说明:
    比如,一个在线游戏的后端运行在 Kubernetes 集群上,游戏客户端与服务器之间维持着长连接。在高峰期,成千上万的玩家同时在线。初始情况下,当玩家数量较少时,系统中的每个 pod 可能只处理少量的连接,但随着更多的玩家上线,新的连接会被创建,并可能会全部分配到某些 pod。
    假设此时扩展了集群,增加了更多的 pod。理想情况下,新的玩家应该连接到新的 pod 上,以实现负载均衡。但由于长连接的存在,现有的玩家仍连接在原有的 pod 上,继续给这些 pod 带来高负载,而新的 pod 可能却处于空闲状态,因为它们还没有收到新的连接。即使负载均衡器介入,但由于长连接已经建立,新的请求(游戏内的操作)仍然会沿着已有的连接发送,不会引导到新的 pod。
  3. 解决方案:
    解决这种长连接导致的负载不均衡问题的一种方法是引入更智能的负载均衡机制,比如基于请求的负载均衡或者使用一些算法(如最少连接方法)动态地重新分配连接。
    另外,可以在应用层面上做一些优化,例如,通过在应用程序中实现断线重连逻辑,定期让客户端重新连接服务器,这样新的连接就有机会被重新均衡分配到不同的服务器上。

在使用 Kubernetes 和长连接时,理解这些挑战并采取适当的策略是非常重要的,以确保系统可以高效、公平地处理不同的负载。