1.容器编排工具
1.1 什么是容器编排
容器编排是指在容器集群中对容器进行自动化部署、管理和伸缩的过程,比如自动化部署、负载均衡、自动伸缩、故障恢复、批量更新等操作。容器编排可以帮助开发人员更加方便地管理容器化应用程序,提高应用程序的可靠性和可扩展性。
容器编排概念最早出自Google,他们在2014年发布了一个名为Kubernetes的项目,这是一个用于管理和编排容器化应用程序的开源平台。Kubernetes旨在为容器化工作负载提供一个自动化的部署、更新、伸缩和运行环境。随着容器技术的流行,越来越多的容器编排工具被开发出来,比如Docker Swarm、Mesos、Nomad等。这些工具都致力于简化容器应用的部署、管理和伸缩,使得开发者可以更加专注于应用程序的开发和创新。
1.2 容器编排工具有哪些?
以下是主流容器编排工具 1. Docker Compose: 适用场景:适合在单个主机上运行的多个容器应用。比如,一个Web应用需要依赖多个容器来运行,可以使用 Docker Compose来管理和编排这些容器。 使用方式:使用YAML文件定义和管理多个容器,可以通过命令行或者Docker Compose UI进行管理。 功能特性:支持容器间通信和网络配置等功能,支持自动化启动和停止容器应用。 2. Kubernetes(k8s): 适用场景:适合大规模容器集群的管理和编排,支持自动化部署、扩展和容错等功能。 使用方式:使用Kubernetes API或者命令行工具进行管理和编排,可以使用Kubernetes Dashboard进行可视化 管理。 功能特性:支持Pod、Service、Replication Controller、Deployment等多种对象,可以进行自动化扩展、滚动更新、负载均衡等操作。 3. Docker Swarm: 适用场景:适合在多个主机上运行的多个容器应用,可以使用Docker API进行管理和编排。 使用方式:使用命令行工具进行管理和编排,可以使用Docker Swarm Visualizer进行可视化管理。 功能特性:支持容器的部署、管理和监控,支持自动化容器扩展和负载均衡。 4. Mesos: 适用场景:适合大规模数据中心的管理和编排,可以将资源池分配给不同的容器应用,支持多种容器运行时。 使用方式:使用Mesos API或者命令行工具进行管理和编排,可以使用Mesosphere DC/OS进行可视化管理。 功能特性:支持多种容器运行时(Docker、rkt、LXC等),支持自动化部署、弹性扩展和容错等功能。 5. Nomad: 适用场景:适用于多种应用场景的容器编排工具,支持多种任务类型和多种操作系统。 使用方式:使用命令行工具进行管理和编排,可以使用Nomad UI进行可视化管理。 功能特性:支持多种任务类型(batch、service、system等),支持多种操作系统(Linux、Windows等),支持自动化部署、弹性扩展和故障转移等功能。 使用场景举例总结: 比如,如果要在本地开发环境中运行一个Web应用,可以使用Docker Compose来管理和编排多个容器。如果要在多个主机上运行多个容器应用,可以使用Docker Swarm来进行容器编排。如果要在生产环境中部署一个大规模的容器集群,可以使用Kubernetes来进行自动化部署和管理。如果要在大规模数据中心中进行容器管理和编排,可以使用Mesos来进行资源池分配和容器调度。如果要在多种操作系统和任务类型上运行容器应用,可以使用Nomad来进行容器编排。
2. 容器编排工具 - Kubernetes
2.1 概述
Kubernetes is a portable, extensible, open source platform for managing containerized workloads and services, that facilitates both declarative configuration and automation
翻译:Kubernetes 是一个可移植、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化
Tips: Kubernetes 这个名字源于希腊语,意为“舵手”或“飞行员”。k8s 这个缩写是因为 k 和 s 之间有八个字符的关系。
Google 在 2014 年开源了 Kubernetes 项目。Kubernetes源自Google15年生产环境的运维经验,同时凝聚了社区的最佳创意和实践。
Google 每周运行数十亿个容器,Kubernetes 基于与之相同的原则来设计,能够在不扩张运维团队的情况下进行规模扩展
2.1.1 用来做什么,提供了什么?
传统部署时代:
早期,各个组织是在物理服务器上运行应用程序。 由于无法限制在物理服务器中运行的应用程序资源使用,因此会导致资源分配问题。 例如,如果在同一台物理服务器上运行多个应用程序, 则可能会出现一个应用程序占用大部分资源的情况,而导致其他应用程序的性能下降。 一种解决方案是将每个应用程序都运行在不同的物理服务器上, 但是当某个应用程式资源利用率不高时,剩余资源无法被分配给其他应用程式, 而且维护许多物理服务器的成本很高。
虚拟化部署时代:
因此,虚拟化技术被引入了。虚拟化技术允许你在单个物理服务器的 CPU 上运行多台虚拟机(VM)。 虚拟化能使应用程序在不同 VM 之间被彼此隔离,且能提供一定程度的安全性, 因为一个应用程序的信息不能被另一应用程序随意访问。
虚拟化技术能够更好地利用物理服务器的资源,并且因为可轻松地添加或更新应用程序, 而因此可以具有更高的可扩缩性,以及降低硬件成本等等的好处。 通过虚拟化,你可以将一组物理资源呈现为可丢弃的虚拟机集群。
每个 VM 是一台完整的计算机,在虚拟化硬件之上运行所有组件,包括其自己的操作系统。
容器部署时代:
容器类似于 VM,但是更宽松的隔离特性,使容器之间可以共享操作系统(OS)。 因此,容器比起 VM 被认为是更轻量级的。且与 VM 类似,每个容器都具有自己的文件系统、CPU、内存、进程空间等。 由于它们与基础架构分离,因此可以跨云和 OS 发行版本进行移植。
容器是打包和运行应用程序的好方式。在生产环境中, 你需要管理运行着应用程序的容器,并确保服务不会下线。 例如,如果一个容器发生故障,则你需要启动另一个容器。 如果此行为交由给系统处理,是不是会更容易一些? Kubernetes 为你提供了一个可弹性运行分布式系统的框架。 Kubernetes 会满足你的扩展要求、故障转移你的应用、提供部署模式等。
2.1.2 Kubernetes 的特性
- 服务发现和负载均衡:Kubernetes 可以使用 DNS 名称或自己的 IP 地址来暴露容器。 如果进入容器的流量很大, Kubernetes 可以负载均衡并分配网络流量,从而使部署稳定。
- 存储编排: Kubernetes 允许你自动挂载你选择的存储系统,例如本地存储、公共云提供商等。
- 自动部署和回滚 : 你可以使用 Kubernetes 描述已部署容器的所需状态, 它可以以受控的速率将实际状态更改为期望状态。 例如,你可以自动化 Kubernetes 来为你的部署创建新容器, 删除现有容器并将它们的所有资源用于新容器。
- 自动完成装箱计算: 为 Kubernetes 提供许多节点组成的集群,在这个集群上运行容器化的任务。 告诉 Kubernetes 每个容器需要多少 CPU 和内存 (RAM)。 Kubernetes 可以将这些容器按实际情况调度到你的节点上,以最佳方式利用你的资源
- 自我修复: Kubernetes 将重新启动失败的容器、替换容器、杀死不响应用户定义的运行状况检查的容器, 并且在准备好服务之前不将其通告给客户端
- 密钥与配置管理: Kubernetes 允许你存储和管理敏感信息,例如密码、OAuth 令牌和 SSH 密钥。 你可以在不重建容器镜像的情况下部署和更新密钥和应用程序配置,也无需在堆栈配置中暴露密钥。
3. Kubernetes架构以及基本概念
在学习Kubernetes如何实现其功能之前, 先具体了解下Kubemetes集群有哪些组件?
3.1 Master节点
k8s集群是由master节点与Worker节点组成。Control Plane(控制平面)组件负责管理和控制整个集群的运行状态。通常是集群中的一个或多个节点,可以通过高可用性组件(如HAProxy、Keepalived等)进行保护,以确保Kubernetes集群的高可用性。在生产环境中,通常将Master节点和Worker节点分开部署,以提高集群的安全性和可靠。
3.1.1 API Server(API服务器)
Kubernetes的所有的操作都是通过API Server进行的。Kubemetes API服务器作为中心组件, 其他组件或者客户端(如kubectl)都会去调用它。以RESTfulAPI的形式提供了可以查询、修改集群状态的CRUD(Create、Read、 Update、 Delete)接口。 它将状态存储到etcd中。
资源变更,API 服务器没有做其他额外的工作。例如,当你创建一 个 ReplicaSet资源时,它不会去创建pod,那是控制器的工作。同时它不会去管理服务的端点。它只提供了能够使其他组件监控己部署资源的变更并提供订阅资源被创 建、修改或删除的通知接口,使得可以在集群元数据变化时候执行任何需要做的任务。
如下图:
3.1.2 Scheduler(调度器)
通常不会去指定 pod 应该运行在哪个集群节点上,这项工作交给调度器。调度器的操作比较简单。就是利用 API 服务器的监听 机制等待新创建的 pod, 然后给每个新的、 没有节点集的 pod 分配节点。
调度器不会直接命令选中的节点(或者节点上运行的 Kubelet) 去运行 pod。 调度器
做的就是通过 API 服务器更新 pod的定义。 然后 API 服务器再去通知 Kubelet(同样,
通过之前描述的监听机制)该 pod 已经被调度过。 当目标节点上的 Kubelet 发现该
pod 被调度到本节点, 它就会创建并且运行 pod 的容器。
Kubernetes 的默认调度器算法,选择节点操作可以分解为两部分:
- 过滤所有节点找出能分配给 pod 的可用节点列表。调度器会给每个节点下发一组配置好的预测检查函数,所有这些测试都必须通过, 节点才有资格调度给pod。
(1)节点是否能满足pod对硬件资源的要求
(2)节点是否耗尽资源(内存/硬盘压力参数)
(3)pod是否要求被调度到指定节点(通过名字), 是否是当前节点?
(4) 节点是否有和pod规格定义里的节点选择器一致的标签?
(5) 如果pod要求绑定指定的主机端口那么这个节点上的这个 端口是否已经 被占用?
(6) 如果pod要求有特定类型的卷, 该节点是否能为此pod加载此卷, 或者说该
节点上是否已经有pod在使用该卷了。
(7)pod是否能够容忍节点的污点,污点则是在不修改巳有pod信息的前提下, 通过在节点上添加污点信息,来拒绝pod在某些节点上的部署(后续会详细讲)。
(8)pod是否定义了节点、pod的亲缘性以及非亲缘性规则?如果是 那么调度节
点给该pod是否会违反规则?亲缘性通过明确的在pod中添加的信息,来决定一个pod可
以或者不可以被调度到哪些节点上。(后续会详细讲)
- 对可用节点按优先级排序,找出最优节点。如果多个节点都有最高的优先级
分数,那么则循环分配,确保平均分配给 pod。
尽管所有这些节点都能运行pod, 其中的一些可能还是优于另外一些 。 假设有一个2节点集群, 两个节点都可用, 但是其中一个运行10个pod, 而另一个, 不知道什么原因,当前没有运行任何pod。因此例子中明显调度器应该选第二个节点。
高级调度(后续讨论) 考虑另外一个例子。 假设一个pod有多个副本 ,理想情况下, 你会期望副本能
够分散在尽可能多的节点上, 而不是全部分配到单独一个节点上 。 该节点的宅机会导致pod支持的服务不可用 。 但是如果pod分散在不同的节点上, 单个节点宅机, 并不会对服务造成什么影响。 默认情况下, 归属同 一服务和ReplicaSet的pod会分散在多个节点上 。 但不保 证每次都是这样 。不过可以通过定义pod的亲缘性、非亲缘规则强制pod分散在集群内或者集中在一起。因此调度其实很复杂,因为它依赖于大量的因子,因此很复杂。
3.1.3 Controller Manager(控制器管理器)
上面讲到,API 服务器只做了存储资源到 etcd 和通知客户端有变更的工作。 调度器则只是给 pod 分配节点,所以需要有活跃的组件确保系统真实状态,并 API服务器定期的获取状态以及元数据信息。 这个工作由控制器管理器里的控制器来实现。
控制器之间不会直接通信,它们甚至不知道其他控制器的存在.每个控制器都连接到 API服务器,通过监听机制, 请求订阅该控制器负责的一系 列资源的变更。
下面是概括的描述了每个常用的控制器做了什么
如果对控制器如何运作感兴趣,强烈推荐看一遍源代码https://github.com/kubemetes/kubernetes/tree/master/pkg/controller
如下:
- Replication 管理器 (ReplicationController 资源的管理器)
启动 ReplicationController 资源的控制器叫作 Replication 管理器,Replication 管理器通 API 务器操纵 pod API 象来完成其工作。
当运行 pod 实例太少时需要 ReplicationController 增加运行实例,但它自己实际上不会去运行 pod 它会创建新的 pod发布到 API 服务器,让调度器以及kubelet 做调度工作并运行 pod。
。
ReplicationController是什么?
ReplicationController是一种Kubemetes资源,可确保它的pod始终保持运行状态。
如果pod因任何原因消失(例如节点从集群中消失或由于该pod已从节点中逐出),则ReplicationController会注意到缺少了pod并创建替代pod。
如下图示,podA是被直接创建的,因此是非托管的pod,而podB由ReplicationController管理。节点异常退出后 ReplicationController会创建一个新的pod(pod B2)来替换缺少的podB, 而podA 完全丢失 —— 没有东西负责重建它。一般ReplicationController创建和管理一个pod的多个副本(replicas)。
ReplicationController控制器会持续监控正在运行的pod列表,并保证相应 ” 类型” 的
pod的数目与期望相符。如正在运行的pod太少, 它会根据pod模板创建新的副本。如果正在运行的pod太多,它将删除多余的副本。
ReplicationController控制器的协调流程如下图:
- Deployment 控制器
Deployment 控制器负责使 deployment 的实际状态与对应 Deployment API
的部署配置期望的状态同步。每次 Deployment 象修改后(如果修改会影响到部署的 pod),
Deployment控制器都会滚动升级到新的版本通过创建一个 eplicaSet ,然后按照 Deployment
定义的策略同时伸缩新、旧 RelicaSet 到旧pod被新的替代。
- StatefulSet 控制器
StatefulSet是为了管理有状态服务的问题而设计的,它所管理的Pod的名称不能随意变化。数据持久化的目录也是不一样,每一个Pod都有自己独有的数据持久化存储目录。比如MySQL主从、redis集群等
- Node 控制器
- Service 控制器
- Endpoints 控制器
- Namespace 控制器
- PersistentVolume 控制器
3.1.4 etcd
一个高可用的分布式键值存储,用于存储Kubernetes集群的所有配置信息和状态数据
3.2 Node节点
除了Master,Kubernetes集群中的其他机器被称为Node节点(工作节点),在较早的版本中也被称为
Minion。与Master一样,Node节点可以是一台物理主机,也可以是一台虚拟机。Node节点才是Kubernetes集群中的工作负载节点,每个Node都会被Master分配一些工作负载(Docker容器),当某个Node 宕机时,其上的工作负载会被Master自动转移到其他节点上去。
每个Node节点上都运行着以下一组关键进程:
kubelet:负责Pod对应的容器的创建、启停等任务,同时与Master节点密切协作,实现集群管理的基本功能。
kube-proxy:实现Kubernetes Service的通信与负载均衡机制的重要组组件
容器运行时 : 容器运行环境是负责运行容器的软件。Kubernetes 支持许多容器运行环境,例如 containerd、 CRI-O 以及 Kubernetes CRI (容器运行环境接口) 的其他任何实现
问题:支持的容器引擎有哪些?
线上容器引擎其实有很多,在上一章提到过。 kubernets的一个限制条件:K8s 只能与CRI 运行时通信。
CRI(Container Runtime Interface)是 K8s 定义的一组与容器运行时进行交互的接口,用于将 K8s 平台与特定的容器实现解耦。在 K8s 早期的版本中,对于容器环境的支持是通过 hard code 方式直接调用 Docker API 的,后来为支持更多的容器运行时和更精简的容器运行时,K8s 提出了CRI。Docker 并不支持 CRI(容器运行时接口)这一 Kubernetes 运行时 API,而 Kubernetes 用户一直以来所使用的其实是名为“dockershim”的桥接服务。Dockershim 能够转换 Docker API 与 CRI。
https://blog.csdn.net/qq_25986067/article/details/122868438?ydreferer=aHR0cHM6Ly9jbi5iaW5nLmNvbS8%3D
3.3 Pod
Pod是Kubernetes的最小部署单元,它可以包含一个或多个相关的容器,并共享相同的网络和存储资源。Pod提供了一个逻辑主机的概念,使得多个容器可以共享同一个主机,从而更好地协同工作。
注意点:当一个Pod包含多个容器时候,所有这些容器始终在单个工作节点上运行——它永远不会跨越多个
工作节点。Pod 中的容器共享同一个网络命名空间,容器之间的通信是通过 localhost 实现的。如果这些容器分别运行在不同的节点上,则无法通过 localhost 进行通信。
Kubernetes引入Pod的概念主要原因:
在容器化的应用中,通常会有多个容器协同工作,例如,一个Web应用可能需要一个Web服务器容器和一个数据库容器。这些容器需要共享网络和存储等资源,而且它们通常需要在同一主机上运行。但是,容器本身是无状态的,它们缺乏共享状态和资源的机制。此外,容器的生命周期是短暂的,容器可能会被频繁重启或删除。
3.3.1 合理通过pod管理容器
问题: 对于一个多层应用程序, 应该将其配置为单个 pod 还是两个 pod 呢?
考虑点:
1. 应用分层:
如果前端和后端都在同一个容器中, 那么两者将始终在同一 台计算机上运行。 如果你有一个双节点 Kubemetes 集群, 而只有一个单独的pod, 那么你将始终只会用一个工作节点, 而不会充分利用第二个节点上的计算资源 (CPU 和内存)。 因此更合理的做法是将pod 拆分到两个工作节点上。
2.基于缩扩容
pod 也是扩缩 容的基本单位, 对于 Kubemetes 来说, 它不能横向扩缩单个容器, 只能扩缩整个 pod。这意味着如果pod 由 一个前端和一个后端容器组成, 那么当扩大pod的 实例数量时, 比如扩大为两个, 最终会得到两个前端容器和两个后端容器。 通常来说, 前端组件与后端组件具有完全不同的扩缩容需求, 所以一般倾向于分别独立地扩缩它们。
3. 但如果应用是由一个主进程和一个或多个辅助进程组成。 例如提供对外的服务是一个浏览的文件目录的web服务,其中有另外一个线程定期的下载文件存储到一个共享目录。如下图:
结论:当决定是将两个容器放入一个 pod 还是两个单独的 pod 时,需要考虑以下几个问题:
它们需要一起运行还是可以在不同的主机上运行?
它们代表的是整体还是相互独立的组件?
它们必须 一起进行扩缩容还是分别可以分别进行?
3.4 Service
Kubemetes服务是一种为一组功能相同的 pod 提供单一不变的接入点的资源。 当服务存在时,它的 IP 地址和端口不会改变。 客户端通过 IP 地址和端口号建立连接,这些连接会被路由到提供该服务的任意一个 pod 上。 通过这种方式, 客户端不需要 知道每个单独的提供服务的 pod 的地址, 这样这些 pod 就可以在集群中随时被创建
或移除。
例如:比如有一个web应用,有前端 web 服务器和后端数据库服务器。 有多个 pod 提供前端
服务,而只有一个pod提供后台数据库服务。需要解决两个问题才能使系统发挥作用。
• 外部客户端无须关心服务器数量而连接到前端 pod 上。
• 前端的 pod需要连接后端的数据库。 由于数据库运行在 pod 中, 它可能会在 集群中移来移去, 导致 IP 地址变化。 当后台数据库被移动时, 无须对前端 pod 重新配置。
通过为前端 pod 创建服务, 并且将其配置成可以在集群外部访问, 可以暴露一
个单一不变的 IP 地址让外部的客户端连接 pod。 同理, 可以为后台数据库 pod 创建
服务, 并为其分配一个固定的 IP 地址。 尽管 pod 的 IP 地址会改变, 但是服务的 IP
地址固定不变。
3.4.1 Service定义
Service 在 Kubernetes 中是一个对象 (与 Pod 或 ConfigMap 类似的对象)。你可以使用 Kubernetes API 创建、查看或修改 Service 定义。 通常你使用 kubectl
这类工具来进行这些 API 调用。
例子,假定有一组 Pod,每个 Pod 都在侦听 TCP 端口 9376,同时还被打上 app.kubernetes.io/name=MyApp
标签。 你可以定义一个 Service 来发布 TCP 侦听器
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app.kubernetes.io/name: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
下面完整的service定义内容:
3.4.2 服务访问地址暴露方式
ClusterIP
ClusterIP
通过集群的内部 IP 暴露服务,选择该值时服务只能够在集群内部访问。 这也是你没有为服务显式指定 type
时使用的默认值。如果定义的服务将 .spec.clusterIP
设置为 "None"
,则 Kubernetes 不会分配 IP 地址。其他几种服务类型在 ClusterIP
类型的基础上进行构建。
在 Service
创建的请求中,可以通过设置 spec.clusterIP
字段来指定自己的集群 IP 地址。 比如,希望替换一个已经已存在的 DNS 条目,或者遗留系统已经配置了一个固定的 IP 且很难重新配置。
用户选择的 IP 地址必须合法,并且这个 IP 地址在 service-cluster-ip-range
CIDR 范围内, 这对 API 服务器来说是通过一个标识来指定的。 如果 IP 地址不合法,API 服务器会返回 HTTP 状态码 422,表示值不合法。
NodePort
通过每个节点上的 IP 和静态端口(NodePort
)暴露服务。 为了让节点端口可用,Kubernetes 设置了集群 IP 地址,这等同于你请求 type: ClusterIP
的服务。
如果你将 type
字段设置为 NodePort
,则 Kubernetes 控制平面将在 --service-node-port-range
标志指定的范围内分配端口(默认值:30000-32767)。 每个节点将那个端口(每个节点上的相同端口号)代理到你的服务中。 你的服务在其 .spec.ports[*].nodePort
字段中报告已分配的端口。
使用 NodePort 可以让你自由设置自己的负载均衡解决方案, 配置 Kubernetes 不完全支持的环境, 甚至直接暴露一个或多个节点的 IP 地址。
如果需要特定的端口号,你可以在 nodePort
字段中指定一个值。 控制平面将为你分配该端口或报告 API 事务失败。 这意味着你需要自己注意可能发生的端口冲突。 你还必须使用有效的端口号,该端口号在配置用于 NodePort 的范围内。
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: NodePort
selector:
app.kubernetes.io/name: MyApp
ports:
# 默认情况下,为了方便起见,`targetPort` 被设置为与 `port` 字段相同的值。
- port: 80
targetPort: 80
# 可选字段
# 默认情况下,为了方便起见,Kubernetes 控制平面会从某个范围内分配一个端口号(默认:30000-32767)
nodePort: 30007
LoadBalancer
spec.type 设置 type
的值为 "LoadBalancer"
, 将为 Service 提供负载均衡器。 负载均衡器是异步创建的,关于被提供的负载均衡器的信息将会通过 Service 的 status.loadBalancer
字段发布出去。
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app.kubernetes.io/name: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
clusterIP: 10.0.171.239
type: LoadBalancer
status:
loadBalancer:
ingress:
- ip: 192.0.2.127
ExternalName
将服务映射到 externalName
字段的内容(例如,映射到主机名 api.foo.bar.example
)。 该映射将集群的 DNS 服务器配置为返回具有该外部主机名值的 CNAME
记录。 无需创建任何类型代理。
类型为 ExternalName 的服务将服务映射到 DNS 名称,而不是典型的选择算符,例如 my-service
或者 cassandra
。 你可以使用 spec.externalName
参数指定这些服务。
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com
3.4.3 服务发现
Kubernetes 支持两种主要的服务发现模式:环境变量和 DNS。
(1)环境变量:
当 Pod 运行在某 Node 上时,kubelet 会为每个活跃的 Service 添加一组环境变量。 kubelet 为 Pod 添加环境变量 {SVCNAME}_SERVICE_HOST
和 {SVCNAME}_SERVICE_PORT
举个例子,一个 Service redis-primary
暴露了 TCP 端口 6379, 同时被分配了 Cluster IP 地址 192.168.1.192,这个 Service 生成的环境变量如下:
REDIS_PRIMARY_SERVICE_HOST=192.168.1.192
REDIS_PRIMARY_SERVICE_PORT=6379
(2)你可以使用附加组件(CoreDNS) 为 Kubernetes 集群安装 DNS 服务。这样并为每个 Service 创建一组 DNS 记录。 如果在整个集群中都启用了 DNS,则所有 Pod 都能够通过 DNS 名称自动解析 Service。
例如,如果你在 Kubernetes 命名空间 my-ns
中有一个名为 my-service
的 Service, 则控制平面和 DNS 服务共同为 my-service.my-ns
创建 DNS 记录。 名字空间 my-ns
中的 Pod 应该能够通过按名检索 my-service
来找到服务 (my-service.my-ns
也可以)
3.5 Label(标签)
标签是一种简单却功能强大的Kubemetes特性, 不仅可以组织pod, 也可以组织所有其他的Kubemetes资源。
标签是可以附加到资源的任意键值对。用以选择具有该确切标签的资源。
通过给这些pod添加标签, 可以得到一个更组织化的系统, 以便我们理解。
举个例子 下面每个pod都标有两个标签:
• app, 它指定pod属于哪个应用、 组件或微服务。
• rel, 它显示在pod中运行的应用程序版本是stable、beta还是canary
3.5.1 创建标签
在metadata.labels指定标签,如下图
注意:默认通过kubectl get pods命令是不会显示pod的标签,需要增加 --show-labels 选项来查看。
3.5.2 通过标签选择器列出pod子集
1) kubectl get po -1 命令查询
同样列出没有env标签的pod
kubectl get po -1 '!env'
其他表达式:
(1)creation_rnethod!=rnanual 选择带有creation_rnethod标签 并且值不等于manual的pod (2)env in (prod, dev)选择带有env标签且值为prod或dev的pod (3)env notin (prod, dev)选择带有env标签, 但其值不是prod或dev的pod
3.5.3 使用标签和选择器来约束pod调度
在Yaml文件通过标签指定选择节点创建pod,如下图:
3.6 Annotations
annotation 的定位是 Kubernetes 资源上附加任意的非标识性元数据,除了在 key 上有跟 label key 完全一样的限制外,在 value 上没有任何限制:可长可短,可结构化可非结构化,可包含任意字符。
允许在 Kubernetes 资源上附加任意的非标识性元数据,用来记录资源的一些属性。这些元数据主要是给工具或者库来提取信息,一般不会直接开放给用户。
3.7 Namespaces(命名空间)
用于隔离不同的资源,例如Pod、Service和Volume等。不同的Namespace之间互相隔离,以避免资源冲突。例如,可以为不同的部门或项目创建不同的Namespace,以便更好地管理资源。
3.7.1 创建命令空间
kubectl create namespace custom-namespace
3.8 ConfigMap
用于存储应用程序的配置信息,例如数据库连接字符串、环境变量等。可以将ConfigMap挂载到Pod中,以便应用程序可以读取配置信息。
3.9 停止和移除pod
3.9.1 按名称删除pod
kubectl delete po kubia-gpu
3.9.2 使用标签选择器删除pod
kubectl delete po -1 creation method=manual
3.9.3 通过删除整个命名空间来删除pod
kubectl delete ns custom-namespace
3.9.4 删除命名空间中的所有 pod ,但保留命名空间
$ kubectl get pods
$ kubectl delete pro --all
4.实践工具
4.1 kubectl示例
1.创建资源对象
根据yaml配置文件一次性创建service和rc:
$ kubectl create -f my-service.yaml -f my-rc.yaml
根据<directory>目录下所有.yaml、.yml、json文件的定义进行创建操作作:
$ kubectl create -f <directory>
2.查看资源对象
查看所有Pod列表:
$ kubectlget pods
查看rc和service列表:
$ kubectl get rc,service
3.描述资源对象
显示Node的详细信息:
$ kubectl describe nodes <node-name>
显示Pod的详细信息:
$ kubectl describe pods/<pod-name>
显示由RC管理的Pod的信息:
$ kubectl describe pods <rc-name>
4.删除资源对象
基于pod.yaml定义的名称删除Pod:
$ kubectldelete -f pod.yaml
删除所有包含某个label的Pod和service:
$ kubectl delete pods, services -| name=<label-name
删除所有Pod:
$ kubectl delete pods --all
5.执行容器的命令
执行Pod的date命令,默认使用Pod中的第1个容器执行:
$ kubec
exec <pod-name> date
指定Pod中某个容器执行date命令:
$ kubectl exec <pod-name> -c <container-name> date
通过bash获得Pod中某个容器的TTY,相当于登录容器:
$ kubectl exec -ti <pod-name> -c <container-name> /bin/bash
6.查看容器的日志
查看容器输出到stdout的日志:
$ kubectl logs <pod-name>
跟踪查看容器的日志,相当于tail-f命令的结果:
$ kubectl logs -f <pod-name> -c <container-name>
4.2 安装
在CentOS上安装Kubernetes需要进行以下步骤:
- 安装 Docker
Kubernetes需要Docker作为容器运行时环境,因此需要先安装Docker。可以执行以下命令安装:
sudo yum install -y docker
sudo systemctl enable docker
sudo systemctl start docker
- 安装 Kubernetes
可以使用yum安装Kubernetes:
sudo tee /etc/yum.repos.d/kubernetes.repo <<EOF
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF
sudo yum install -y kubelet kubeadm kubectl
sudo systemctl enable kubelet
sudo systemctl start kubelet
- 初始化 Master 节点
在Master节点上执行以下命令初始化Kubernetes:
sudo kubeadm init
执行完上述命令后,会显示kubeadm join命令,用于将Worker节点加入Kubernetes集群。将该命令保存下来,后续会用到。
- 安装网络插件
Kubernetes需要网络插件来实现Pod之间的通信。可以使用Flannel作为网络插件:
sudo kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
安装完成后,可以通过执行kubectl get pods --all-namespaces
命令来查看插件是否正常运行。
- 将Worker节点加入集群
在Worker节点上执行之前保存下来的kubeadm join命令,将Worker节点加入Kubernetes集群:
sudo kubeadm join <Master节点IP>:<Master节点端口> --token <token值> --discovery-token-ca-cert-hash <ca证书hash值>
注意,这里的<Master节点IP>
和<Master节点端口>
需要替换为Master节点的IP地址和端口号,<token值>
和<ca证书hash值>
需要替换为初始化Master节点时生成的对应值。
- 验证集群状态
在Master节点上执行以下命令,验证集群是否正常运行:
sudo kubectl get nodes
如果所有节点都显示为Ready状态,则说明集群已经成功安装并运行。