Kubernetes

一、k8s部署

kubernetes 简介

  • 在Docker 作为高级容器引擎快速发展的同时,在Google内部,容器技术已经应用了很多年

  • Borg系统运行管理着成千上万的容器应用。

  • Kubernetes项目来源于Borg,可以说是集结了Borg设计思想的精华,并且吸收了Borg系统中的经验和教训。

  • Kubernetes对计算资源进行了更高层次的抽象,通过将容器进行细致的组合,将最终的应用服务交给用户

K8S 的 常用名词感念

  • Master:集群控制节点,每个集群需要至少一个master节点负责集群的管控

  • Node:工作负载节点,由master分配容器到这些node工作节点上,然后node节点上的

  • Pod:kubernetes的最小控制单元,容器都是运行在pod中的,一个pod中可以有1个或者多个容器

  • Controller:控制器,通过它来实现对pod的管理,比如启动pod、停止pod、伸缩pod的数量等等

  • Service:pod对外服务的统一入口,下面可以维护者同一类的多个pod

  • Label:标签,用于对pod进行分类,同一类pod会拥有相同的标签

  • NameSpace:命名空间,用来隔离pod的运行环境

k8s 集群部署

K8S中文官网:Kubernetes

  • 所有节点禁用selinux和防火墙

  • 所有节点同步时间和解析

  • 所有节点安装docker-ce

  • 所有节点禁用swap,注意注释掉/etc/fstab文件中的定义

所有禁用swap和本地解析
所有安装docker
所有节点设定docker的资源管理模式为systemd
所有阶段复制harbor仓库中的证书并启动docker
安装K8S部署工具
设置kubectl命令补齐功能
在所节点安装cri-docker

软件下载:https://github.com/Mirantis/cri-dockerd

在master节点拉取K8S所需镜像
集群初始化
安装flannel网络插件

官方网站:https://github.com/flannel-io/flannel

二、Kubernetes中pod的管理及优化

资源管理介绍

  • 在kubernetes中,所有的内容都抽象为资源,用户需要通过操作资源来管理kubernetes。

  • kubernetes的本质上就是一个集群系统,用户可以在集群中部署各种服务

  • 所谓的部署服务,其实就是在kubernetes集群中运行一个个的容器,并将指定的程序跑在容器中。

  • kubernetes的最小管理单元是pod而不是容器,只能将容器放在Pod中,

  • kubernetes一般也不会直接管理Pod,而是通过Pod控制器来管理Pod的。

  • Pod中服务的访问是由kubernetes提供的Service资源来实现。

  • Pod中程序的数据需要持久化是由kubernetes提供的各种存储系统来实现

什么是pod

Pod是可以创建和管理Kubernetes计算的最小可部署单元

一个Pod代表着集群中运行的一个进程,每个pod都有一个唯一的ip。

一个pod类似一个豌豆荚,包含一个或多个容器(通常是docker)

多个容器间共享IPC、Network和UTC namespace。

创建自主式pod (生产不推荐)

优点:

灵活性高:

可以精确控制 Pod 的各种配置参数,包括容器的镜像、资源限制、环境变量、命令和参数等,满足特定的应用需求。

学习和调试方便:

对于学习 Kubernetes 的原理和机制非常有帮助,通过手动创建 Pod 可以深入了解 Pod 的结构和配置方式。在调试问题时,可以更直接地观察和调整 Pod 的设置。

适用于特殊场景:

在一些特殊情况下,如进行一次性任务、快速验证概念或在资源受限的环境中进行特定配置时,手动创建 Pod 可能是一种有效的方式。

缺点:

管理复杂:

如果需要管理大量的 Pod,手动创建和维护会变得非常繁琐和耗时。难以实现自动化的扩缩容、故障恢复等操作。

缺乏高级功能:

无法自动享受 Kubernetes 提供的高级功能,如自动部署、滚动更新、服务发现等。这可能导致应用的部署和管理效率低下。

可维护性差:

手动创建的 Pod 在更新应用版本或修改配置时需要手动干预,容易出现错误,并且难以保证一致性。相比之下,通过声明式配置或使用 Kubernetes 的部署工具可以更方便地进行应用的维护和更新。

一个pod里可以运行多个容器

一个pod里可以运行多个容器

创建pod模版

刚刚这里有一个运行成功,有一个失败,因为两个都是使用nginx的镜像,第一个占用了80端口,第二个肯定用不了了

修改配置文件,把第二个容器修改所需镜像,不再争取一个接口

此时两个容器就都能用了

缠绕启动之前创建的容器

虽然没有安装nginx,但是却也可以访问成功测试页面

因为它们位于一个pod中,是共用一个网络栈的,所以也能够访问到nginx测试页

可是这样写pod的维护性很差

查看当前命名空间的pod

查看所有命名空间里的pod

查看所有pod的详细信息

#建立控制器并自动运行pod

#为timinglee扩容

#为timinglee缩容

应用版本的更新

#利用控制器建立pod

#暴漏端口

访问服务

root@k8s-master \~# curl 10.110.195.120

Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>

root@k8s-master \~# curl 10.110.195.120

Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>

指定版本,会把老的版本关闭,开启新版本的内容

这些功能实际上是控制器的功能

yaml文件部署应用

声明式配置

  • 清晰表达期望状态:以声明式的方式描述应用的部署需求,包括副本数量、容器配置、网络设置等。这使得配置易于理解和维护,并且可以方便地查看应用的预期状态。

  • 可重复性和版本控制:配置文件可以被版本控制,确保在不同环境中的部署一致性。可以轻松回滚到以前的版本或在不同环境中重复使用相同的配置。

  • 团队协作:便于团队成员之间共享和协作,大家可以对配置文件进行审查和修改,提高部署的可靠性和稳定性。

灵活性和可扩展性

  • 丰富的配置选项:可以通过 YAML 文件详细地配置各种 Kubernetes 资源,如 Deployment、Service、ConfigMap、Secret 等。可以根据应用的特定需求进行高度定制化。

  • 组合和扩展:可以将多个资源的配置组合在一个或多个 YAML 文件中,实现复杂的应用部署架构。同时,可以轻松地添加新的资源或修改现有资源以满足不断变化的需求。

与工具集成

  • 与 CI/CD 流程集成:可以将 YAML 配置文件与持续集成和持续部署(CI/CD)工具集成,实现自动化的应用部署。例如,可以在代码提交后自动触发部署流程,使用配置文件来部署应用到不同的环境。

  • 命令行工具支持:Kubernetes 的命令行工具 kubectl 对 YAML 配置文件有很好的支持,可以方便地应用、更新和删除配置。同时,还可以使用其他工具来验证和分析 YAML 配置文件,确保其正确性和安全性

运行简单的单个容器pod

运行多个容器pod

理解pod间的网络整合

端口映射

如何设定环境变量

pod的生命周期

INIT 容器

官方文档:Pod | Kubernetes ​​

INIT 容器的功能

  • Init 容器可以包含一些安装过程中应用容器中不存在的实用工具或个性化代码。

  • Init 容器可以安全地运行这些工具,避免这些工具导致应用镜像的安全性降低。

  • 应用镜像的创建者和部署者可以各自独立工作,而没有必要联合构建一个单独的应用镜像。

  • Init 容器能以不同于Pod内应用容器的文件系统视图运行。因此,Init容器可具有访问 Secrets 的权限,而应用容器不能够访问。

  • 由于 Init 容器必须在应用容器启动之前运行完成,因此 Init 容器提供了一种机制来阻塞或延迟应用容器的启动,直到满足了一组先决条件。一旦前置条件满足,Pod内的所有的应用容器会并行启动

INIT 容器示例

探针实例

三、k8s中的控制器的使用

官方文档:

工作负载管理 | Kubernetes

控制器也是管理pod的一种手段

  • 自主式pod:pod退出或意外关闭后不会被重新创建

  • 控制器管理的 Pod:在控制器的生命周期里,始终要维持 Pod 的副本数目

Pod控制器是管理pod的中间层,使用Pod控制器之后,只需要告诉Pod控制器,想要多少个什么样的Pod就可以了,它会创建出满足条件的Pod并确保每一个Pod资源处于用户期望的目标状态。如果Pod资源在运行中出现故障,它会基于指定策略重新编排Pod

当建立控制器后,会把期望值写入etcd,k8s中的apiserver检索etcd中我们保存的期望状态,并对比pod的当前状态,如果出现差异代码自驱动立即恢复

replicaset控制器

  • ReplicaSet 是下一代的 Replication Controller,官方推荐使用ReplicaSet
  • ReplicaSet和Replication Controller的唯一区别是选择器的支持,ReplicaSet支持新的基于集合的选择器需求
  • ReplicaSet 确保任何时间都有指定数量的 Pod 副本在运行
  • 虽然 ReplicaSets 可以独立使用,但今天它主要被Deployments 用作协调 Pod 创建、删除和更新的机制

replicaset 示例

deployment 控制器

版本迭代

#pod运行容器版本为v1

查看更新效果

更新的过程是重新建立一个版本的RS,新版本的RS会把pod 重建,然后把老版本的RS回收

可以看到版本变化了

版本回滚
滚动更新策略

这次更新了一部分,下次更新就5秒一次,一共要更新8个

影响最小的,最丝滑的更新策略

更一个关一个

daemonset控制器

DaemonSet 确保全部(或者某些)节点上运行一个 Pod 的副本。当有节点加入集群时, 也会为他们新增一个 Pod ,当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod

DaemonSet 的典型用法:

  • 在每个节点上运行集群存储 DaemonSet,例如 glusterd、ceph。
  • 在每个节点上运行日志收集 DaemonSet,例如 fluentd、logstash。
  • 在每个节点上运行监控 DaemonSet,例如 Prometheus Node Exporter、zabbix agent等
  • 一个简单的用法是在所有的节点上都启动一个 DaemonSet,将被作为每种类型的 daemon 使用
  • 一个稍微复杂的用法是单独对每种 daemon 类型使用多个 DaemonSet,但具有不同的标志, 并且对不同硬件类型具有不同的内存、CPU 要求

daemonset 示例

过滤一下污点信息

现在只在master设定了污点,默认是不被调用的

我们的myapp是会在node1&2上都会有,但是master上是默认不会有的,因为是有污点的

但是master上也不是不可以有,可以设置对污点的容忍度,就可以运行了

强容忍,即便有也不在乎

job 控制器

Job,主要用于负责批量处理(一次要处理指定数量任务)短暂的一次性(每个任务仅运行一次就结束)任务

Job特点如下:

  • 当Job创建的pod执行成功结束时,Job将记录成功结束的pod数量
  • 当成功结束的pod达到指定的数量时,Job将完成执行

cronjob 控制器功能

  • Cron Job 创建基于时间调度的 Jobs。
  • CronJob控制器以Job控制器资源为其管控对象,并借助它管理pod资源对象,
  • CronJob可以以类似于Linux操作系统的周期性任务作业计划的方式控制其运行时间点及重复运行的方式。
  • CronJob可以在特定的时间点(反复的)去运行job任务

四、kubernetes中的微服务

用控制器来完成集群的工作负载,那么应用如何暴漏出去?需要通过微服务暴漏出去后才能被访问

  • Service是一组提供相同服务的Pod对外开放的接口。
  • 借助Service,应用可以实现服务发现和负载均衡。
  • service默认只支持4层负载均衡能力,没有7层功能。(可以通过Ingress实现)

微服务的类型

微服务默认使用iptables调度

ipvs模式

  • Service 是由 kube-proxy 组件,加上 iptables 来共同实现的
  • kube-proxy 通过 iptables 处理 Service 的过程,需要在宿主机上设置相当多的 iptables 规则,如果宿主机有大量的Pod,不断刷新iptables规则,会消耗大量的CPU资源
  • IPVS模式的service,可以使K8s集群支持更多量级的Pod

ipvs模式配置方式

1 在所有节点中安装ipvsadm

复制代码
[root@k8s-所有节点 pod]yum install ipvsadm –y

2 修改master节点的代理配置

复制代码
[root@k8s-master ~]# kubectl -n kube-system edit cm kube-proxy
    metricsBindAddress: ""
    mode: "ipvs"                            #设置kube-proxy使用ipvs模式
    nftables:

3 重启pod,在pod运行时配置文件中采用默认配置,当改变配置文件后已经运行的pod状态不会变化,所以要重启pod

clusterip

特点:

clusterip模式只能在集群内访问,并对集群内的pod提供健康检测和自动发现功能

headless(无头服务)

对于无头 `Services` 并不会分配 Cluster IP,kube-proxy不会处理它们, 而且平台也不会为它们进行负载均衡和路由,集群访问通过dns解析直接指向到业务pod上的IP,所有的调度有dns单独完成

nodeport

通过ipvs暴漏端口从而使外部主机通过master节点的对外ip:<port>来访问pod业务

loadbalancer

云平台会为我们分配vip并实现访问,如果是裸金属主机那么需要metallb来实现ip的分配

metalLB

官网:Installation :: MetalLB, bare metal load-balancer for Kubernetes

externalname

  • 开启services后,不会被分配IP,而是用dns解析CNAME固定域名来解决ip变化问题
  • 一般应用于外部业务和pod沟通或外部业务迁移到pod内时
  • 在应用向集群迁移过程中,externalname在过度阶段就可以起作用了。
  • 集群外的资源迁移到集群时,在迁移的过程中ip可能会变化,但是域名+dns解析能完美解决此问题

k8s中的存储

configmap的功能

  • configMap用于保存配置数据,以键值对形式存储。
  • configMap 资源提供了向 Pod 注入配置数据的方法。
  • 镜像和配置文件解耦,以便实现镜像的可移植性和可复用性。
  • etcd限制了文件大小不能超过1M

configmap创建方式

字面值创建

通过文件创建

通过目录创建

通过yaml文件创建

以变量的方式注入

name指的是这个文件里的键值

如果

以文件的方式

以卷的方式来做

真正的键值挂载到那个目录下mountPath

读取认证文件,加密文件如何注入pod呢,就是以文件的形式

存储docker registry的认证信息

写入之后默认使用集群的屏障

没有指定为什么可以下载镜像,因为在指定时,指定了建立软件仓库时的用户和密码,所以可以直接下载到

volumes配置管理

  • 容器中文件在磁盘上是临时存放的,这给容器中运行的特殊应用程序带来一些问题
  • 当容器崩溃时,kubelet将重新启动容器,容器中的文件将会丢失,因为容器会以干净的状态重建。
  • 当在一个 Pod 中同时运行多个容器时,常常需要在这些容器之间共享文件。
  • Kubernetes 卷具有明确的生命周期与使用它的 Pod 相同
  • 卷比 Pod 中运行的任何容器的存活期都长,在容器重新启动时数据也会得到保留
  • 当一个 Pod 不再存在时,卷也将不再存在。
  • Kubernetes 可以支持许多类型的卷,Pod 也能同时使用任意数量的卷。

emptyDir卷

功能:

当Pod指定到某个节点上时,首先创建的是一个emptyDir卷,并且只要 Pod 在该节点上运行,卷就一直存在。卷最初是空的。 尽管 Pod 中的容器挂载 emptyDir 卷的路径可能相同也可能不同,但是这些容器都可以读写 emptyDir 卷中相同的文件。 当 Pod 因为某些原因被从节点上删除时,emptyDir 卷中的数据也会永久删除

hostpath卷

功能:

hostPath 卷能将主机节点文件系统上的文件或目录挂载到您的 Pod 中,不会因为pod关闭而被删除

hostPath 的一些用法

  • 运行一个需要访问 Docker 引擎内部机制的容器,挂载 /var/lib/docker 路径。
  • 在容器中运行 cAdvisor(监控) 时,以 hostPath 方式挂载 /sys。
  • 允许 Pod 指定给定的 hostPath 在运行 Pod 之前是否应该存在,是否应该创建以及应该以什么方式存在

hostPath的安全隐患

  • 具有相同配置(例如从 podTemplate 创建)的多个 Pod 会由于节点上文件的不同而在不同节点上有不同的行为。
  • 当 Kubernetes 按照计划添加资源感知的调度时,这类调度机制将无法考虑由 hostPath 使用的资源。
  • 基础主机上创建的文件或目录只能由 root 用户写入。您需要在 特权容器 中以 root 身份运行进程,或者修改主机上的文件权限以便容器能够写入 hostPath 卷。

部署一台nfs共享主机并在所有k8s节点中安装nfs-utils

部署nfs卷

volumes状态说明
  • Available 卷是一个空闲资源,尚未绑定到任何申领
  • Bound 该卷已经绑定到某申领
  • Released 所绑定的申领已被删除,但是关联存储资源尚未被集群回收
  • Failed 卷的自动回收操作失败
在pod中使用pvc

存储类storageclass

官网: https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner

部署NFS Client Provisioner

一定要成功运行

必须要指定你已经存在的存储分配器

之间建立pvc就行,有存储分配器可以直接分配pv

此时存储分配器自动生成的pv

回收自动创建的pv也消失了

tatefulset控制器

功能特性

  • Statefulset是为了管理有状态服务的问提设计的
  • StatefulSet将应用状态抽象成了两种情况:
  • 拓扑状态:应用实例必须按照某种顺序启动。新创建的Pod必须和原来Pod的网络标识一样
  • 存储状态:应用的多个实例分别绑定了不同存储数据。
  • StatefulSet给所有的Pod进行了编号,编号规则是:(statefulset名称)-(序号),从0开始。
  • Pod被删除后重建,重建Pod的网络标识也不会改变,Pod的拓扑状态按照Pod的"名字+编号"的方式固定下来,并且为每个Pod提供了一个固定且唯一的访问入口,Pod对应的DNS记录
构建方法

建立无头服务

建立statefulset模板

在建立pod的同时就会给它建立pv

优点:永远挂载是一对一的

测试:

#为每个pod建立index.html文件

#建立测试pod访问web-0~2

#删掉重新建立statefulset,#访问依然不变


statefulset的弹缩

statefulset有序回收

k8s下的网络通信与调度

k8s通信整体架构

  • k8s通过CNI接口接入其他插件来实现网络通讯。目前比较流行的插件有flannel,calico等

  • CNI插件存放位置:# cat /etc/cni/net.d/10-flannel.conflist

  • 插件使用的解决方案如下

    • 虚拟网桥,虚拟网卡,多个容器共用一个虚拟网卡进行通信。

    • 多路复用:MacVLAN,多个容器共用一个物理网卡进行通信。

    • 硬件交换:SR-LOV,一个物理网卡可以虚拟出多个接口,这个性能最好。

  • 容器间通信:

    • 同一个pod内的多个容器间的通信,通过lo即可实现pod之间的通信

    • 同一节点的pod之间通过cni网桥转发数据包。

    • 不同节点的pod之间的通信需要网络插件支持

  • pod和service通信: 通过iptables或ipvs实现通信,ipvs取代不了iptables,因为ipvs只能做负载均衡,而做不了nat转换

  • pod和外网通信:iptables的MASQUERADE

  • Service与集群外部客户端的通信;(ingress、nodeport、loadbalancer)

calico简介:

  • 纯三层的转发,中间没有任何的NAT和overlay,转发效率最好。
  • Calico 仅依赖三层路由可达。Calico 较少的依赖性使它能适配所有 VM、Container、白盒或者混合环境场景

部署calico

删除flannel插件

复制代码
[root@k8s-master ~]# kubectl delete  -f kube-flannel.yml

删除所有节点上flannel配置文件,避免冲突

复制代码
[root@k8s-master & node1-2 ~]# rm -rf /etc/cni/net.d/10-flannel.conflist

下载部署文件

复制代码
[root@k8s-master calico]# curl https://raw.githubusercontent.com/projectcalico/calico/v3.28.1/manifests/calico-typha.yaml -o calico.yaml

下载镜像上传至仓库:

复制代码
[root@k8s-master ~]# docker pull docker.io/calico/cni:v3.28.1
[root@k8s-master ~]# docker pull docker.io/calico/node:v3.28.1
[root@k8s-master ~]# docker pull docker.io/calico/kube-controllers:v3.28.1
[root@k8s-master ~]# docker pull docker.io/calico/typha:v3.28.1

更改yml设置

调度在Kubernetes中的作用

  • 调度是指将未调度的Pod自动分配到集群中的节点的过程
  • 调度器通过 kubernetes 的 watch 机制来发现集群中新创建且尚未被调度到 Node 上的 Pod
  • 调度器会将发现的每一个未调度的 Pod 调度到一个合适的 Node 上来运行

调度原理:

创建Pod

  • 用户通过Kubernetes API创建Pod对象,并在其中指定Pod的资源需求、容器镜像等信息。
  • 调度器监视Pod
  • Kubernetes调度器监视集群中的未调度Pod对象,并为其选择最佳的节点。
  • 选择节点
  • 调度器通过算法选择最佳的节点,并将Pod绑定到该节点上。调度器选择节点的依据包括节点的资源使用情况、Pod的资源需求、亲和性和反亲和性等。
  • 绑定Pod到节点
  • 调度器将Pod和节点之间的绑定信息保存在etcd数据库中,以便节点可以获取Pod的调度信息。
  • 节点启动Pod
  • 节点定期检查etcd数据库中的Pod调度信息,并启动相应的Pod。如果节点故障或资源不足,调度器会重新调度Pod,并将其绑定到其他节点上运行。

nodename

  • nodeName 是节点选择约束的最简单方法,但一般不推荐

  • 如果 nodeName 在 PodSpec 中指定了,则它优先于其他的节点选择方法

  • 使用 nodeName 来选择节点的一些限制

  • 如果指定的节点不存在。

  • 如果指定的节点没有资源来容纳 pod,则pod 调度失败。

  • 云环境中的节点名称并非总是可预测或稳定的

Nodeselector(通过标签控制节点)

affinity(亲和性)

官方文档 :

将 Pod 指派给节点 | Kubernetes

Podaffinity(pod的亲和)

  • 那个节点有符合条件的POD就在那个节点运行
  • podAffinity 主要解决POD可以和哪些POD部署在同一个节点中的问题
  • podAntiAffinity主要解决POD不能和哪些POD部署在同一个节点中的问题。它们处理的是Kubernetes集群内部POD和POD之间的关系。
  • Pod 间亲和与反亲和在与更高级别的集合(例如 ReplicaSets,StatefulSets,Deployments 等)一起使用时,
  • Pod 间亲和与反亲和需要大量的处理,这可能会显著减慢大规模集群中的调度。

Taints(污点模式,禁止调度)

  • Taints(污点)是Node的一个属性,设置了Taints后,默认Kubernetes是不会将Pod调度到这个Node上

  • Kubernetes如果为Pod设置Tolerations(容忍),只要Pod能够容忍Node上的污点,那么Kubernetes就会忽略Node上的污点,就能够(不是必须)把Pod调度过去

  • 可以使用命令 kubectl taint 给节点增加一个 taint: