春

春夏秋冬平平安安

A text-focused Halo theme

  • 首页
  • 关于
主页 kubernetes学习记录
文章

kubernetes学习记录

发表于 28天前 更新于 28天前
作者 Administrator
224~288 分钟 阅读

有状态和无状态

  • 会保存数据的是有状态

  • 不保存数据的是无状态

一、环境准备

3台虚拟机,至少是2C2G,互相能ping通

1.1 下载RockyLinux9

https://rockylinux.org/download

1.2 环境初始化

三个node的配置差不多,ip地址换一下就行

# 网卡配置
# cat /etc/NetworkManager/system-connections/ens160.nmconnection
[ipv4]
address1=192.168.66.11/24
method=manual
​
# 调用 nmcli 重启设备和连接配置
nmcli d r ens160 
nmcli c r ens160
​
# 更换yum源
sed -e 's|^mirrorlist=|#mirrorlist=|g' \
    -e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g' \
    -i.bak \
    /etc/yum.repos.d/rocky-*.repo
​
dnf makecache
​
# 防火墙修改 firewalld 为 iptables
systemctl stop firewalld
systemctl disable firewalld
​
# 可选
yum -y install iptables-services
systemctl start iptables
iptables -F
systemctl enable iptables
​
# 禁用 Selinux
setenforce 0
sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config
grubby --update-kernel ALL --args selinux=0
​
# 设置时区
timedatectl set-timezone Asia/Shanghai
​
# 关闭 swap 分区
swapoff -a
sed -i 's:/dev/mapper/rl-swap:#/dev/mapper/rl-swap:g' /etc/fstab
​
# 修改主机名
hostnamectl  set-hostname k8s-node01
# 安装 ipvs
yum install -y ipvsadm
# 开启路由转发
echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.conf
sysctl -p
# 加载 bridge
yum install -y epel-release
yum install -y bridge-utils
​
modprobe br_netfilter
echo 'br_netfilter' >> /etc/modules-load.d/bridge.conf
echo 'net.bridge.bridge-nf-call-iptables=1' >> /etc/sysctl.conf
echo 'net.bridge.bridge-nf-call-ip6tables=1' >> /etc/sysctl.conf
sysctl -p

1.3 安装docker

k8s也不一定要用docker作为容器运行时,可以直接使用containerd,k8s好像默认的也是containerd,使用docker作为容器运行起还需要安装cir-dockerd。参考链接 https://docs.docker.com/engine/install/rhel/

# 移除旧版本
sudo dnf remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine \
                  podman \
                  runc
# 添加仓库                  
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo

# 下载最新版本的docker
sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# 设置开启自启动
sudo systemctl enable --now docker

# 这里还需要配置docker的镜像,阿里云的镜像加速已经没用了,需要另外找
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://xxxx.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload

sudo systemctl restart docker

建议还是用containerd、cri-o等等作为容器运行时,cri-dockerd目前有很多CRI接口都没实现,会缺少很多信息。

1.4 安装cri-dockerd

docker之前的运行时在k8s v1.24移除了,所以现在要额外安装cri-dockerd才能用docker作为k8s的容器运行时。参考链接(https://mirantis.github.io/cri-dockerd/usage/install-manually/)

# 在github下载cri-dockerd
wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.17/cri-dockerd-0.3.17.amd64.tgz

# 解压
tar -zxvf cri-dockerd-0.3.17.amd64.tgz

# 安装
install -o root -g root -m 0755 cri-dockerd 解压的cri-dcokerd路径/bin/cri-dockerd
install packaging/systemd/* /etc/systemd/system
sed -i -e 's,/usr/bin/cri-dockerd,/usr/local/bin/cri-dockerd,' /etc/systemd/system/cri-docker.service
systemctl daemon-reload
systemctl enable --now cri-docker.socket

# 如果要在k8s中使用添加一些配置
# 需要追加--network-plugin=cni,通过该配置告诉容器,使用kubernetes的网络接口
# 覆盖沙盒 (pause) 镜像,正常情况下,国内你是拉取不到k8s.gcr.io/pause:3.8镜像的,可以换成国内的registry.aliyuncs.com/google_containers/pause:3.10,这个镜像是一切的 Pod 的基础,要么自己手动导入进来,要么改成国内的镜像,通过设置以下配置来覆盖默认的沙盒镜像
ExecStart=/usr/bin/cri-dockerd --container-runtime-endpoint fd:// --network-plugin=cni --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.10


# 重新启动cri-dockers服务
systemctl daemon-reload
systemctl enable cri-docker.service
systemctl enable --now cri-docker.socket
systemctl restart cri-dockerd

1.5 安装kubernetes

# 此操作会覆盖 /etc/yum.repos.d/kubernetes.repo 中现存的所有配置
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.31/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.31/rpm/repodata/repomd.xml.key
exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni
EOF

# 安装软件
sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
sudo systemctl enable --now kubelet

1.6 搭建集群

上面的操作需要在三个节点都执行一遍,也可以执行完后克隆虚拟机,修改ip地址

1.6.1 修改三个虚拟机的hostname

修改节点的hostname,这样就可以直接知识honstname访问node,添加到host

# 分别在不同虚拟机执行
hostnamectl  set-hostname k8s-node1
hostnamectl  set-hostname k8s-master
hostnamectl  set-hostname k8s-node2

# 添加到host文件
vim /etc/hosts
# 添加解析
192.168.66.11 k8s-master
192.168.66.22 k8s-node1
192.168.66.33 k8s-node2

1.6.2 初始化主节点

kubeadm init 
--apiserver-advertise-address=192.168.66.11    # apiserver地址
--image-repository registry.aliyuncs.com/google_containers # 镜像仓库
--kubernetes-version 1.32.3 # k8s的版本,使用kubectl version 查看,要和自己的版本对应 
--service-cidr=10.10.0.0/12 
--pod-network-cidr=10.244.0.0/16 # pod的地址
--ignore-preflight-errors=all 
--cri-socket unix:///var/run/cri-dockerd.sock # 使用docker作为容器运行时,如果使用containerd可以不加

kubeadm init --apiserver-advertise-address=192.168.66.11 --image-repository registry.aliyuncs.com/google_containers --kubernetes-version 1.32.3 --service-cidr=10.10.0.0/12 --pod-network-cidr=10.244.0.0/16 --ignore-preflight-errors=all --cri-socket unix:///var/run/cri-dockerd.sock # 使用docker作为容器运行时,如果使用containerd可以不加

# 上面命令执行完后会提示执行三条命令,已经从节点怎么加入集群的命令,记得注意结尾的命令

1.6.3 从节点加入集群

# 这里的token是在上面初始化主节点后输出的,拷贝过来,添加cri-dockerd的socket套接字执行
kubeadm join 192.168.66.11:6443 --token a6xh07.yg9wh2vru2grluwb         --discovery-token-ca-cert-hash sha256:7cd8499abae48c8403800152cc0f655ac704ea00ae30a549acd9bbac7b26dca4 --cri-socket unix:///var/run/cri-dockerd.sock

1.7 部署网络插件

# 下载配置文件
curl https://raw.githubusercontent.com/projectcalico/calico/v3.29.3/manifests/calico.yaml -O

vim calico.yaml

# 修改ipv4的地址为上面初始化主节点时的pod地址
- name: CALICO_IPV4POOL_CIDR
  value: "10.244.0.0/16"

# 修改为 BGP 模式
# Enable IPIP
- name: CALICO_IPV4POOL_IPIP
  value: "Always"  #改成Off

# 把配置文件里面的所有docker.io都删除,不然下载不到容器
sed -i 's|docker.io/||g' calico.yaml

kubectl apply -f calico.yaml  #等待容器安装完成即可

1.8 修改kube-proxy模式为ipvs

# kubectl edit configmap kube-proxy -n kube-system
mode: ipvs

kubectl delete pod -n kube-system -l k8s-app=kube-proxy

二、概念

Kubernetes 主要由以下几个核心组件组成:

  • etcd 保存了整个集群的状态;

  • apiserver 提供了资源操作的唯一入口,并提供认证、授权、访问控制、API 注册和发现等机制;

  • controller manager 负责维护集群的状态,比如故障检测、自动扩展、滚动更新等;

  • scheduler 负责资源的调度,按照预定的调度策略将 Pod 调度到相应的机器上;

  • kubelet 负责维护容器的生命周期,同时也负责 Volume(CSI)和网络(CNI)的管理;

  • Container runtime 负责镜像管理以及 Pod 和容器的真正运行(CRI);

  • kube-proxy 负责为 Service 提供 cluster 内部的服务发现和负载均衡;

除了核心组件,还有一些推荐的插件,其中有的已经成为 CNCF 中的托管项目:

  • CoreDNS 负责为整个集群提供 DNS 服务

  • Ingress Controller 为服务提供外网入口

  • Prometheus 提供资源监控

  • Dashboard 提供 GUI

  • Federation 提供跨可用区的集群

三、资源

k8s中所有的内容都抽象为资源,资源实例化之后叫做对象。

2.1 资源类别

  1. 命名空间级别

    • 工作负载型资源:Pod、ReplicaSet、Deployment ……

    • 服务发现及负载均衡型资源类型:Service、Ingress ……

    • 配置与存储型资源:Volume、CSI ……

    • 特殊类型的存储卷:ConfigMap、Secre ……

  2. 集群级资源

    • Namespace、Node、ClusterRole、ClusterRoleBinding

  3. 元数据型资源

    • HPA、PodTemplate、LimitRange

2.2 资源清单的编写

kubectl api-versions  # 获取api版本

几乎每个 Kubernetes 对象包含两个嵌套的对象字段,它们负责管理对象的配置: 对象 spec(规约) 和对象 status(状态)。 对于具有 spec 的对象,你必须在创建对象时设置其内容,描述你希望对象所具有的特征: 期望状态(Desired State)。

status 描述了对象的当前状态(Current State),它是由 Kubernetes 系统和组件设置并更新的。在任何时刻,Kubernetes 控制平面 都一直在积极地管理着对象的实际状态,以使之达成期望状态。

例如,Kubernetes 中的 Deployment 对象能够表示运行在集群中的应用。 当创建 Deployment 时,你可能会设置 Deployment 的 spec,指定该应用要有 3 个副本运行。 Kubernetes 系统读取 Deployment 的 spec, 并启动我们所期望的应用的 3 个实例 —— 更新状态以与规约相匹配。 如果这些实例中有的失败了(一种状态变更),Kubernetes 系统会通过执行修正操作来响应 spec 和 status 间的不一致 —— 意味着它会启动一个新的实例来替换。

https://github.com/kubernetes/examples/blob/master/guestbook/all-in-one/guestbook-all-in-one.yaml

apiVersion: v1 # 接口组/版本  没有写接口组就是core,根据资源类型来写
kind: Pod  # 类别
metadata:  # 元数据
  name: pod-demo  # 名字
  namespace: default  # 归属于哪个命名空间
  labels:  # 标签
    app: myapp
spec:  # 对象规约
  containers:
  - name: myapp-1
    image: myapp:v1.0
  - name: busybox-1
    image: tools:busybox
    command:
    - "/bin/sh"
    - "-c"
    - "sleep 3600"
status:  # 状态
  conditions:
  - lastProbeTime: null
    lastTransitionTime: "2023-11-21T08:49:07z"
    status: "True"
    type: Initialized
  - lastProbeTime: null

四、容器的生命周期

image-20250407094704165

4.1. initC

init容器与普通的容器相似,除了如下两点:

  • init 容器总是运行到成功完成为止,返回码为成功。

  • 每个init 容器都必须在下一个init容器启动之前成功完成

如果Pod的init容器失败,Kubernetes会不断地重启该Pod,直到init容器成功为止。然而,如果Pod对应的restartPolicy为Never,它不会重新启动。

  • initC与应用容器具备不同的镜像,可以把一些危险的工具放置在initC中进行使用。

  • initC多个之间是线性启动(串行执行)的,所以可以做一些延迟性操作。

  • initC无法定义readinessProbe(就绪探测),其他以外同应用容器定义无异。

4.2. 探针

探针是由kubelet对容器执行的定期诊断。要执行诊断,kubelet调用由容器实现的Handler。有三种类型的处理程序:

  • ExecAction:在容器内执行指定命令。如果命令退出时返回码为0则认为诊断成功

  • TCPSocketAction:对指定端口上的容器的IP地址进行TCP检查。如果端口打开,则诊断被认为是成功的

  • HTTPGetAction:对指定的端口和路径上的容器的IP地址执行HTTP Get请求。如果响应的状态码大于等于200且小于400,则诊断被认为是成功的

每次探测都将获得以下三种结果之一:

  • 成功:容器通过了诊断。

  • 失败:容器未通过诊断。

  • 未知:诊断失败,因此不会采取任何行动。

4.2.1 探针分类

  • startupProbe:启动探测,开始检测吗?

  • livenessProbe:存活探测,还活着吗

  • readinessProbe:就绪探测,准备提供服务了吗?

readinessProbe 就绪探针

k8s通过添加就绪探针,解决尤其是在扩容时保证提供给用户的服务都是可用的。在进行pod扩容时,如果新建的pod还没准备就绪,那么它就不应该提供给用户访问,就绪探测可以让pod就绪后才加入到service中。

选项说明:

  • initialDelaySeconds:容器启动后要等待多少秒后探针开始工作,单位“秒”,默认是0秒,最小值是0

  • periodSeconds:执行探测的时间间隔(单位是秒),默认为10s,单位“秒”,最小值1

  • timeoutSeconds:探针执行检测请求后,等待响应的超时时间,默认为1s,单位“秒”,最小值是1

  • successThreshold:探针检测失败后认为成功的最小连接成功次数,默认值为1。必须为1才能激活和启动。最小值为1

  • failurethreshold:探测失败的额重试次数,重试一定次数后将认为失败,默认值为3,最小值为1

如果pod内部的容器不添加就绪探测,默认就绪。如果添加了就绪探测,只有通过就绪探测成功以后,才标记修改为就许状态。当前pod内的所有容器都就绪,才标记当前pod就绪。

  • 探测成功:将当前的容器标记为就绪

  • 探测失败:静默

  • 探测未知:静默

livenessProbe存活探针

k8s通过添加存活探针,解决虽然活着但是已经死了的问题。

选项说明:

  • initialDelaySeconds:容器启动后要等待多少秒后探针开始工作,单位“秒”,默认是0秒,最小值0

  • periodSeconds:执行探测的时间间隔(单位是秒),默认为10s,单位“秒”,最小值是1

  • timeoutSeconds:探针执行检测请求后,等待响应的超时时间,默认为1s,单位“秒”,最小值是1

  • successThreshold:探针检测失败后认为成功的最小连接成功次数,默认值为1。必须为1才能激活行业启动。最小值为1

  • failureThreshold:探测失败的重试次数,重试一定次数后将认为失败,默认值为3,最小值为1

如果pod内部不指定存活探测,可能你会发送容器运行但是无法提供服务的情况

  • 成功:静默

  • 失败:根据重启的策略进行重启的动作(重建)

  • 未知:静默

startupProbe启动探针

k8s在1.16版本后增加startupProbe探针,主要解决在复杂的程序中readinessProbe、livenessProbe探针无法更好的判断程序是否启动、是否存活。

选项说明:

  • initialDelaySeconds:容器启动后要等待多少秒后探针开始工作,单位“秒”,默认是0秒,最小值0

  • periodSeconds:执行探测的时间间隔(单位是秒),默认为10s,单位“秒”,最小值是1

  • timeoutSeconds:探针执行检测请求后,等待响应的超时时间,默认为1s,单位“秒”,最小值是1

  • successThreshold:探针检测失败后认为成功的最小连接成功次数,默认值为1。必须为1才能激活行业启动。最小值为1

  • failureThreshold:探测失败的重试次数,重试一定次数后将认为失败,默认值为3,最小值为1

启动探针保障存活探针在执行的时候不会因为时间设定问题导致无限死亡或者延迟很长的情况

  • 成功:开始允许存活探测,就绪探测开始执行

  • 失败:静默

  • 未知:静默

4.3 钩子

Pod hook(钩子)是由k8s管理的kubelet发起的,当容器中的进程启动前或者容器中的进程终止之前运行,这是包含在容器的生命周期之中。可以同时为Pod中的所有容器都配置hook。启动后钩子,关闭前钩子

Hook的类型包括两种:

  • exec:执行一段命令

  • HTTP:发送HTTP请求

apiVersion: v1  
kind: Pod
metadata:
 name: lifecycle-pod
 labels:
   app: lifecycle-pod
spec:
 containers:
 - name: busybox-container
   image: wangyanglinux/tools:busybox
   command: ["/bin/sh","-c","touch /tmp/live ; sleep 600; rm -rf /tmp/live; sleep 3600"]
   livenessProbe:
     exec:
       command: ["test","-e","/tmp/live"]
     initialDelaySeconds: 1
     periodSeconds: 3
   lifecycle:
     postStart:
       httpGet:
         host: 192.168.66.11
         path: index.html
         port: 1234
     preStop:
       httpGet:
         host: 192.168.66.11
         path: hostname.html
         port: 1234
 - name: myapp-container
   image: wangyanglinux/myapp:v1.0
   livenessProbe:
     httpGet:
       port: 80
       path: /index.html
     initialDelaySeconds: 1
     periodSeconds: 3
     timeoutSeconds: 3
   readinessProbe:
     httpGet:
       port: 80
       path: /index1.html
     initialDelaySeconds: 1
     periodSeconds: 3
 initContainers:
 - name: init-myservice
   image: wangyanglinux/tools:busybox
   command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
 - name: init-mydb
   image: wangyanglinux/tools:busybox
   command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']

五、Pod的控制器

在Kubernetes中运行了一系列控制器来确保集群的当前状态与期望状态保持一致,它们就是Kubernetes集群内部的管理控制中心或者说是“中心大脑”。例如,ReplicaSet控制器负责维护集群中运行的Pod数量;Node控制器负责监控节点的状态,并在节点出现故障时,执行自动化修复流程,确保集群始终处于预期的工作状态。

  • ReplicationController、ReplicaSet

  • Deployment

  • DaemonSet

  • StateFulSet

  • Job/CronJob

  • Horizontal Pod Autoscaling

5.1 ReplicationController和ReplicaSet

ReplicationController(rc)用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的Pod来替代;而如果异常多出来的容器也会自动回收;

在新版本的Kubernetes中建议使用ReplicaSet(rs)来取代ReplicationController。ReplicaSet和ReplicationController没有本质的不同,只是名字不一样,并且ReplicaSet支持集合式的selector;

RC控制器,保障当前的Pod数量与期望值一致

RS控制器,功能与RC控制器类似,但是多了标签选择的运算方式

5.2 Deployment

原理:通过 Deployment 控制器控制不同的 RS 再去创建 Pod

Deployment为Pod和ReplicaSet提供了一个声明式定义(declarative)方法,用来替代以前的ReplicationController来方便的管理应用。典型的应用场景包括:

  • 定义Deployment来创建Pod和ReplicaSet

  • 滚动升级和回滚应用

Deployment和RS的关系

  • 扩容和缩容

  • 暂停和继续Deployment

5.2.1 声明式和命令式

声明性的东西是对结果的陈述,表明意图而不是实现它的过程。在Kubernetes中,这就说“应该有一个包含三个Pod的ReplicaSet”。

命令式充当命令。声明式是被动的,而命令式是主动且直接的:“创建一个包含三个Pod的ReplicaSet”。

5.2.2 replace与apply对比

替换方式
  • kubectl replace:使用新的配置完全替换掉现有资源的配置。这意味着新配置将覆盖现有资源的所有字段和属性,包含未指定的字段,会导致整个资源的替换。

  • kubectl apply:使用新的配置部分地更新现有资源的配置。它会根据提供的配置文件或参数,只更新与新配置中不同的部分,而不会覆盖整个资源的配置。

字段级别的更新
  • kubectl replace:由于是完全替换,所以会覆盖所有字段和属性,无论是否在新配置中指定。

  • kubectl apply:只更新与新配置中不同的字段和属性,保留未指定的字段不受影响。

部分更新
  • kubectl replace:不支持部分更新,它会替换整个资源的配置

  • kubectl apply:支持部分更新,只会更新新配置中发生变化的部分,保留未指定的部分不受影响

与其他配置的影响
  • kubectl replace:不考虑其他资源配置的状态,直接替换资源的配置。

  • kubectl apply:可以结合使用 -f 或 -k 参数,从文件或目录中读取多个资源配置,并根据当前集群中的资源状态进行更新。

5.2.3 常用命令

kubectl create -f deployment.yaml --record
# 根据yaml创建一个Deployment,--record参数可以记录命令,可以很方便的查看每次revision的变化
-f 通过基于文件的创建,但是如果此文件描述的对象存在,即使文件描述的信息发生了改变,再次提交时也不会应用

apply
	# 创建资源对象、修改资源对象
	-f 基于文件创建,如果目标对象与文件本身发生改变,那么会根据文件的内容一一修改目标对象的属性(部分更新)
replace
	# 创建资源对象、修改资源对象
	-f 基于文件创建,如果目标对象与文件本身发生改变,那么会重建此对象(替代替换)

kubectl scale deployment nginx-deployment --replicas 10 # 扩容,缩容都可以
kubectl autoscale deployment nginx-deployment --min=10 --max=15 --cpu-percent=80  # 扩展缩容阈值
kubectl set image deployment/nginx-deployment nginx-deployment-container=wangyanglinux/myapp:v2.0
# 回滚到上一个版本
kubectl rollout undo deployment/nginx-deployment

5.2.4 更新策略

Deployment 可以保证在升级时只有一定数量的 Pod 是 down 的。默认的,它会确保至少有比期望的 Pod 数量少一个是 up 状态(最多一个不可用)

Deployment 同时也可以确保只创建出超过期望数量一定数量的 Pod。默认的,他会确保最多比期望的 Pod 数量多一个的 Pod 是 up 的(最多 1 个 surge)

最多多25%,最多少25%(通过apps/v1接口组创建的)

kubectl explain deploy.spec.strategy.type
	Recreate  # 重建
    RollingUpdate # 滚动更新
    	maxSurge: # 指定超出副本数有几个,两种方式:1、指定数量 2、百分比
    	maxUnavailable: # 最多有几个不可用

5.2.5 金丝雀部署

创建少量的新版本 Pod 给用户访问,如果没有问题再将所有的 Pod 都更新到新版本。

kubectl patch deploy deployment-demo -p '{"spec": {"strategy": {"rollingUpdate": {"maxSurge": 1, "maxUnavailable": 0}}}}'

kubectl patch deploy deployment-demo --patch '{"spec": {"template": {"spec": {"containers": [{"name": "deployment-demo-container", "image": "wangyanglinux/myapp:v2.0"}]}}}}' && kubectl rollout pause deploy deployment-demo

5.2.6 回滚命令

# 查看的当前deployment的滚动更新状态
kubectl rollout status deploy nginx-deployment

# 查看的当前deployment的滚动更新历史
kubectl rollout history deployment/nginx-deployment

# 回滚到指定的revision版本
kubectl rollout undo deployment/nginx-deployment --to-revision=2
# 暂停滚动更新
kubectl rollout pause deployment/nginx-deployment
# 恢复滚动更新
kubectl rollout resume deploy deployment-demo

5.2.7 清理策略

可以通过设置.spec.revisionHistoryLimit项来指定 Deployment 最多保留多少 revision 历史记录。默认的会保留所有的 revision;如果将该项设置为0,Deployment 就不允许回滚了。

5.3 DaemonSet

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

使用 DaemonSet 的一些典型用法:

  • 运行集群存储 daemon,例如在每个 Node 上运行 glusterd、ceph

  • 在每个 Node 上运行日志收集 daemon,例如 fluentd、logstash

  • 在每个 Node 上运行监控 daemon,例如 Prometheus Node Exporter、collectd、Datadog 代理、New Relic 代理,或 Ganglia gmond

5.4 Job

Job 负责批处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个 Pod 成功结束,保障批处理任务一个或多个成功为止。

特殊说明:

  • spec.template 格式同 Pod

  • RestartPolicy 仅支持 Never 或 OnFailure

  • 单个 Pod 时,默认 Pod 成功运行后 Job即结束

  • .spec.completions 标志 Job结束需要成功运行的 Pod 个数,默认为 1

  • .spec.parallelism 标志并行运行的 Pod 的个数,默认为 1

  • .spec.activeDeadlineSeconds 标志失败 Pod 的重试最大时间,超过这个时间不会继续重试

5.5 CronJob

Cron Job管理基于时间的 Job,即:

  • 在给定时间点只运行一次

  • 周期性地在给定时间点运行

典型用法:

  • 在给定的时间点调度 Job 运行

  • 创建周期性运行的 Job,例如:数据库备份、发送邮件

spec下面的参数

  • .spec.schedule:调度,必需字段,指定任务运行周期,格式通 Cron

  • .spec.jobTemplate:Job 模板,必需字段,指定需要运行的任务,格式同 Job

  • .spec.startingDeadlineSeconds:启动 Job 的期限(秒级别),该字段是可选的。如果因为任何原因而错过了被调度的时间,那么错过执行时间的 Job 将被认为是失败的。如果没有指定,则没有期限。

  • .spec.concurrencyPolicy:并发策略,该字段也是可选的。它制定了如何处理被 Cron Job创建的 Job 的并发执行。只允许指定下面策略中的一种:

    • Allow(默认):允许并发运行 Job

    • Forbid:禁止并发运行,如果前一个还没有完成,则直接跳过下一个

    • Replace:取消当前正在运行的 Job,用一个新的来替换

    • 注意,当前策略只能应用于同一个 Cron Job 创建的 Job。如果存在多个 Cron Job,它们创建的 Job 之间总是运行并发执行。

  • .spec.suspend:挂起,该字段也是可选的。如果设置为 true,后续所有执行都会被挂起。它对已经执行的 Job 不起作用。默认值为 false

  • .spec.successfulJobsHistoryLimit 和 .spec.failedJobsHistoryLimit:历史限制,是可选的字段。它们制定了可以保留多少完成和失败的 Job。默认情况下,它们分别设置为 3 和 1。设置限制的值为 0,相关类型的 Job 完成后将不会被保留

周期性的创建 Job,典型的场景:数据库的周期性备份。。。

创建 Job 操作应该是幂等的

5.6 StatefulSet

有序创建有序回收

数据持久化 Pod 级别 > Pod绑定 pvc > pvc 绑定 pv > pv 绑定 nfs

稳定的网络访问方式

PodName.headlessSvcName.nsName.svc.domainName.
statefulSetName-num.headlessSvcName.nsName.svc.domainName.

六、Service

Kubernetes Service 定义了这样一种很抽象:一个 Pod 的逻辑分组,一种可以访问它们的策略 ——通过称为微服务。这一组 Pod 能够被 Service 访问到,通常是通过 Label Selector

在 Kubernetes 集群中,每个 Node 运行一个 kube-proxy 进程。kube-proxy 负责为 Service 实现了一种VIP(虚拟IP)的形式

在Kubernetes v1.0 版本,代理完全在userspace。在v1.1版本,新增了 iptables 代理,但并不是默认的运行模式。从v1.2起,默认即使 iptables 代理。在v1.8中添加了ipvs代理。

6.1 Service 类型

  • ClusterIP:默认类型,自动分配一个仅 Cluster 内部可以访问的虚拟IP(集群内部使用)

  • NodePort:在 ClusterIP 基础上为 Service 在每台机器上绑定一个端口,这样就可以通过 <NodeIP>:<NodePort> 来访问服务(暴露到集群外部)

  • LoadBalancer:在 NodePort 的基础上,借助 cloud provider 创建一个外部负载均衡器,并将请求转发到 <NodeIP>:<NodePort>

  • ExternalName:把集群外部的服务引入到集群内部来,在集群内部直接使用。没有任何类型代理被创建,这只有 Kubernetes 1.7 或更高版本的 kube-dns 才支持。(别名)

6.1.1 ClusterIP

svc DNS 域名

svcName.nsName.svc.domainName.

domainName cluster.local

internalTrafficPolicy 参数:
	Cluster: 访问集群内的所有pod
	Local: 仅限访问本机内的Pod

6.1.2 NodePort

暴露集群内部的服务给外部访问

6.1.3 ExternalName

ExternalName Service 是 Service 的特例,它没有 selector,也没有定义任何的端口和 Endpoint。相反的,对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务。

6.3 Endpoint

Kubernetes 中的 Service,它定义了一组 Pods 的逻辑集合和一个用于访问它们的策略。一个 Service 的目标 Pod 集合通常是由 Label Selector 来决定的 。

Endpoints 是一组实际服务的端点集合。一个 Endpoint 是一个可被访问的服务端点,即一个状态为 running 的 Pod 的可访问端点。一般 Pod 都不是一个独立存在,所以一组 Pod 的端点何在一起称为 Endpoints。只有被 Service Selector 匹配选中并且状态为 Running 的才会被加入到和 Service 同名的 Endpoints 中。

  • 自动关联体系:配置 selector

  • 手动关联体系:无配置 selector

七、存储

7.1 存储各类特性

  • 元数据

    • configMap:用于保存配置数据(明文)

    • Secret:用于保存敏感性数据(编码)

    • Downward API:容器在运行时从 Kubernetes API 服务器获取有关它们自身的信息

  • 真实数据

    • Volume:用于存储临时或者持久性数据

    • PersistentVolume:申请制的持久化存储

7.2 configMap

configMap 功能在Kubernetes 1.2 版本中引入,许多应用程序会从配置文件、命令行参数或环境变量中读取配置信息。configMap API 给我们提供了向容器中注入配置信息的机制,configMap 可以被用来保存单个属性,也可以用来保存整个配置文件或者 JSON 二进制等对象。

7.2.1 创建

kubectl create configmap game-config --from-file=hongfu.file
kubectl create configmap literal-config --from-literal=name=dave --from-literal=password=pass

7.2.2 热更新

更新 configMap 可以更改挂载到 Pod 上的文件,方式是注入,在很多应用中配置文件的更改并不一定会使得 Pod 内部应用的更新,因此可以利用滚动更新的策略重新创建 Pod,达到更新的效果。

更新 configMap 后:

  • 使用该 configMap 挂载的 Env 不会同步更新

  • 使用该 configMap 挂载的 volume 中的数据需要一段时间才能同步更新

7.2.3 不可改变 immutable

Kubernetes 给不可改变的 configMap 和 Secret 提供了一种可选配置,可以设置各个 Secret 和 configMap 为不可变的。对于大量使用 configMap 的集群,禁止变更它们的数据有下列好处:

  • 防止以外(或非预期的)更新导致应用程序中断

  • 通过将 configMap 标记为不可变来关闭 kube-apiserver 对其的监视,从而显著降低 kube-apiserver 的负载,提升集群性能。

configMap 如果修改为不可改变的状态,是不允许回退的,是不可逆的。可以删除此 configMap,然后重新创建一个没有不可改变字段的 configMap,防止出现一些错误的修改。

7.3 Secret

编码而来的安全

Secret 对象类型用来保存敏感信息,例如密码,OAuth 令牌和 SSH 密钥。将这些信息放在 Secret 中比放在 Pod 的定义或者 容器镜像 中来说更加安全和灵活。

Secret分类

7.3.1 特性

  • Kubernetes 通过仅仅将 Secret 分发到需要访问 Secret 的 Pod 所在的机器节点来保障其安全性

  • Secret 只会存储在节点的内存中,永不写入物理存储,这样从节点删除 Secret 时就不需要擦除磁盘数据

  • 从 Kubernetes 1.7 版本开始,etcd 会以加密形式存储 Secret,一定程度的保证了 Secret 安全性

7.3.2 Opaque

当 Secret 配置文件中未作显式设定时,默认的 Secret 类型是 Opaque。当你使用 kubectl 来创建一个 Secret 时,会使用 generic 子命令来表明要创建的是一个 Opaque 类型的 Secret

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  password: cGFzc3dk
  username: YWRtaW4=

7.4 Downward API

Downward API 是 Kubernetes 中的一个功能,它允许容器在运行时 从 Kubernetes API 服务器获取有关它们自身的信息。这些信息可以作为容器内部的环境变量或文件注入到容器中,以便可以获取有关其运行环境的各种信息,如 Pod 名称、命名空间、标签等。

  • 提供容器元数据

  • 动态配置

  • 与 Kubernetes 环境集成

Downward API 提供了一种简单的方式,将 Pod 和容器的元数据传递他给它们内部运行的进程。但这种方式其实仅仅暴露了一个 Pod 自身的元数据传递给在它们内部运行的进程。但是这种方式其实仅仅可以暴露一个 Pod 自身的元数据,而且只可以暴露部分元数据。

7.5 volume

容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题。首先,当容器崩溃时,kubelet 会重启(重建)它,但是容器中的文件将丢失——容器以干净的状态(镜像最初的状态)重新启动。其次,在 Pod 中同时运行多个容器时,这些容器之间通常需要共享文件。Kubernetes 中的 Volume 抽象就很好地解决了这些问题。

7.5.1 emptyDir

当 Pod 被分配给节点时,首先创建 emptyDir 卷,并且只要该 Pod 在该节点上运行,该卷就会存在。正如卷的名字所述,它最初是空的。Pod 中的容器可以读取和写入 emptyDir 卷中的相同文件,尽管改卷可以挂载到每个容器中的相同或不同路径上。当出于任何原因从节点中删除 Pod 时,emptyDir 中的数据将被永久删除

容器崩溃不会从节点中移除 Pod,因此 emptydir 卷中的数据在容器崩溃时是安全的

emptyDir 的用法有:

  • 暂存空间,例如用于磁盘的合并排序、用作长时间计算崩溃恢复时的检查点

  • Web 服务器容器提供数据时,保存内容管理器容器提取的文件

在 kubelet 的工作目录(root-dir 参数控制),默认为 /var/lib/kubelet,会为每个使用了 emptyDir: {} 的 Pod 创建一个目录,格式如 /var/lib/kubelet/pods/{podid}/volumes/kubernetes.io~empty-dir/,所有放在 emptyDir 中的数据,最终都是落在了 node 的上述路径中

7.5.2 hostPath

hostPath 卷将主机节点的文件系统中的文件或目录挂载到集群中

hostPath 用途如下:

  • 运行需要访问 Docker 内部的容器;使用 /var/lib/docker 的 hostPath

  • 在容器中运行 cAdvisor;使用 /dev/cgroups 的 hostPath

  • 允许 Pod 指定给定的 hostPath 是否应该在 Pod 运行之前存在,是否应该创建,以及它应该以什么形式存在

除了所需的 path 属性之外,用户还可以为 hostPath 卷指定 type

类型

值

行为

空字符串(默认)用于向后兼容,意味着在挂载 hostPath 卷之前不会执行任何检查

DirectoryOrCreate

如果在给定的路径上没有任何东西存在,那么将根据需要在那么创建一个空目录,权限设置为 0755,与 Kubelet 具有相同的组合所有权

Directory

给定的路径下必须存在目录

FileOrCreate

如果在给定的路径上没有任何东西存在,那么会根据需要创建一个空文件,权限设置为 0644,与 Kubelet 具有相同的组合所有权

File

给定的路径下必须存在文件

Socket

给定的路径下必须存在 UNIX 套接字

CharDevice

给定的路径下必须存在字符设备

BlockDevice

给定的路径下必须存在块设备

7.6 PV/PVC

PV/PVC之间的关系

PV/PVC 关联条件

  • 容量:PV 的值不小于 PVC 要求,可以大于最好一致

  • 读写策略:完全匹配

    • 单节点读写 - ReadWriteOnce - RWO

    • 多节点只读 - ReadOnlyMany - ROX

    • 多借点读写 - ReadWriteMany - RWX

  • 存储类:PV 的类与 PVC 的类必须一致,不存在包容降级关系

PV/PVC - 回收策略

  • Retain(保留):手动回收

  • Recycle(回收):基本擦除(rm -rf /thevolume/*)

  • Delete(删除):关联的存储资产(例如 AWS EBS、GCE PD、Azure Dis 和 OpenStack Cinder 卷)将被删除

当前,只有 NFS 和 HostPath 支持回收策略。AWS EBS、GCE PD、Azure Disk 和 Cinder 卷支持删除策略

PV/PVC - 状态

  • Available(可用):一块空闲资源还没有被任何声明所绑定

  • Bound(已绑定):卷已经被声明绑定

  • Released(已释放):声明被删除,但是资源还未被集群重新声明

  • Failed(失败):该卷的自动回收失败

命令行会显示绑定到 PV 的 PVC 的名称

7.7 storageClass

一种动态的申请存储的机制

StorageClass 是一种资源对象,用于定义持久卷(Persistent Volumes)的动态供给(Dynamic Provisioning)策略。StorageClass 允许管理员定义不同类型的存储,并指定如何动态创建持久卷以供应程序使用。这使得 Kubernetes 集群中的存储管理更加灵活和自动化

八、调度器

8.1 概念

scheduler 是作为单独的程序运行的,启动之后会一直监听 API Server,获取 PodSpec.NodeName 为空的 Pod,对每个 Pod 都会创建一个 binding,表明该 Pod 应该放到哪个节点上。

概念听起来是非常简单的,但有很多要考虑的问题:

  • 公平:如何保证每个节点都能被分配资源

  • 资源高效利用:集群所有资源最大化被使用

  • 效率:调度的性能要好,能够尽快地对大批量的 Pod 完成调度工作

  • 灵活:允许用户根据自己的需求控制调度的逻辑

除了 Kubernetes 自带的调度器,也可以编写自己的调度器。通过 spec.schedulername 参数指定调度器的名字,可以为 Pod 选择某个调度器进行调度。

过程

调度分为几个部分:首先是过滤掉不满足条件的节点,这个过程称为预选,然后对通过预选的节点按照优先级排序,这个是优选;最后从中选择优先级最高的节点。如果中间任何一步骤有错误,就直接返回错误。

8.2 亲和性

# 软亲和性,偏好满足条件的节点
apiVersion: v1
kind: Pod
metadata:
  name: node-affinity-preferred
  labels:
    app: node-affinity-preferred
spec: 
  containers:
  - name: node-affinity-preferred-pod
    image: wangyanglinux/myapp:v1.0
  # 亲和性
  affinity:
  # 节点亲和性
    nodeAffinity:
    # 软策略
      preferredDuringSchedulingIgnoreDuringExecution:
      # 权重
      - weight: 1
      # 偏好
        preference:
          matchExpressions:
          - key: domain
            operator: In
            values:
            - xinxianghf
# 硬亲和性,必须满足条件
---
apiVersion: v1
kind: Pod
metadata:
  name: node-affinity-required
  labels:
    app: node-affinity-required
spec:
  containers:
  - name: node-affinity-required-pod
    image: wangyanglinux/myapp:v1.0
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/hostname
            operator: In
            values:
            - k8s-node4

pod亲和性/反亲和性,希望和哪个 Pod 在(不在)同一个节点

希望创建的 Pod 和目标 Pod 在同一个拓扑域下,匹配顺序是,首先查找目标 Pod 的拓扑域,然后通过调度策略调度到目标 Pod 拓扑域下的任一节点

apiVersion: v1
kind: Pod
metadata:
  name: pod-aff-prefer
  labels:
    app: pod-aff
spec:
  containers:
  - name: myapp
    image: wangyanglinux/myapp:v1.0
  affinity:
    podAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: app
              operator: In
              values:
              - pod-1
          topologyKey: kubernetes.io/hostname
          
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-aff-required
  labels:
    app: pod-aff
spec:
  containers:
  - name: myapp
    image: wangyanglinux/myapp:v1.0
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - pod-1
        topologyKey: kubernetes.io/hostname

image-20250412143958462

8.3 污点和容忍

8.3.1 污点

Taint 和 toleration 相互配合,可以用来避免 Pod 被分配到不合适的节点上。每个节点上都可以应用一个或多个 taint,这表示对于那些不能容忍这些 taint 的 Pod,是不会被该节点接受的。如果将 toleration 应用于 Pod 上,则表示这些 Pod 可以(但不要求)被调度到具有匹配 taint 的节点上。

每个污点有一个 key 和 value 作为污点的标签,其中 value 可以为空,effect 描述污点的作用。当前 taint effect 支持如下三个选项:

  • NoSchedule:表示 k8s 不会将 Pod 调度到具有该污点的 Node 上。

  • PreferNoSchedule:表示 k8s 会尽量避免将 Pod 调度到具有该污点的 Node 上

  • NoExecute:表示 k8s 不会将 Pod 调度到具有该污点的 Node 上,同时会将 Node 上已经存在的 Pod 驱逐出去。(节点更新、物理机更新损坏等情况)

# 添加污点
kubectl taint node k8s-master computeengine=gpu:NoSchedule(key=value:effect)
# 删除污点
kubectl taint node k8s-master computeengine=gpu:NoSchedule-

8.3.2 容忍

设置了污点的 Node 将根据 taint 的 effect:NoSchedule、PreferNoSchedule、NoExecute 和 Pod 之间产生互斥的关系,Pod 将在一定程度上不会被调度到 Node 上。但我们可以在 Pod 上设置容忍(toleration),意思是设置了容忍的 Pod 将可以容忍污点的存在,可以被调度到存在污点的 Node 上

tolerations:
- key: key1
  operator: Equal
  value: value1
  effect: NoSchedule
  
tolerations:
- key: key1
  operator: Equal
  value: value1
  effect: NoExecute
  tolerationSeconds: 3600
 

1、当不指定 value 时,表示容忍所有的污点 value

- key: key2
  operator: Exists
  effect: NoSchedule

2、当不指定 key 值时,表示容忍所有的污点 key

tolerations:
- operator: Exists

3、当不指定 effect 值时,表示容忍所有的污点作用

tolerations:
- key: key
  operator: Exists

4、有多个 Master 存在时,防止资源浪费,可以如下设置

kubectl taint nodes NodeName node-role.kubernetes.io/master=:PreferNoSchedule

8.4 固定节点调度

通过设置 pod.spec.nodeName将 Pod 直接调度到指定的 Node 节点上,会跳过 Scheduler 的调度策略,该匹配规则是强制匹配,可以跳过污点

通过pod.spec.nodeSelector 标签选择机制,有调度器调度策略匹配 label,而后调度 Pod 到目标节点,该匹配规则属于强制约束,不能跳过污点

九、安全机制

Kubernetes 作为一个分布式集群的管理工具,保证集群的安全性是其一个重要的任务。API Server 是集群内部各个组件通信的中间,也是外部控制的入口。所以 Kubernetes 的安全机制基本就是围绕保护 API Server 来设计的。

image-20250412155644138

9.1 认证

9.1.1 类型

  • HTTP Token 认证:通过一个 Token 来识别合法用户

    • HTTP Token 的认证是用一个很长的特殊编码方式并且难以被模仿的字符串 - Token 来表达客户的一种方式。Token 是一个很长并且很复杂的字符串,每一个 Token 对应一个用户名存储在 API Server 能访问的文件中。当客户端发起 API 调用请求时,需要在 HTTP Header 里放入 Token。

  • HTTP Base 认证:通过 用户名+密码 的方式认证

    • 用户名+密码:用 BASE64 算法进行编码后的字符串放在 HTTP Request 中的 Heather Authorization 域里发送给服务端,服务端收到后进行编码,获取用户名及密码

  • 最严格的 HTTPS 证书认证:基于 CA 根证书签名的客户端身份认证方式

image-20250412190857131

apiserver 需要认证的类型

组件

  • 无需加密,基于 kubeadm 部署与 ApiServer 处于同一台机器,通过 127.0.0.1 访问

    • Controller Manager、Scheduler

  • 需要加密的

    • kubelet(证书自动颁发)、kube-proxy、kubectl(证书手动颁发)

Pod,通过 SA 认证

9.1.2 ServiceAccount

Pod 中的容器访问 API server。因为 Pod 的创建、销毁是动态的,所以要为它手动生成证书就不可行了,Kubernetes 使用 ServiceAccount 解决 Pod 访问 API Server 的认证问题。

Kubernetes 设计了一种资源对象叫做 Secret,分为两类,一种是用于 ServiceAccount 的 service-account-token,另一种是用于保存用户自定义保密信息的 Opaque。ServiceAccount 中用到包含三个部分:Token、ca.crt、namespace

  • Token 是使用 API Server 私钥签名的 JWT 。用于访问 API Server 时,Server 端认证。

  • ca.crt,根证书。用于 Client 端验证 API Server 发送的证书

  • namespace,表示这个 service-account-token 的作用域命名空间

默认情况下,每个 namespace 都会有一个 ServiceAccount,如果 Pod 在创建时没有指明 ServiceAccount,就会使用 Pod 所属 namespace 的 ServiceAccount

9.2 鉴权

9.2.1 类型

认证的过程只是用于通信的双方相互确认对方是可信的,可以相互通信。而鉴权是确定请求方有哪些资源的权限。API Server 目前支持以下几种授权策略(通过 API Server 的启动参数“--authorization-mode”设置)

  • AlwaysDeny:表示拒绝所有的请求,一般用户测试

  • AlwaysAllow:允许接受所有请求,如果集群不需要授权流程,则可以采用该策略

  • ABAC(Attribute-Based Access Control):基于属性的访问控制,表示使用用户配置的授权规则对用户请求进行匹配和控制

  • Webhook:通过调用外部 REST 服务对用户进行授权

  • RBAC(Role-Based Access Control):基于角色的访问控制,现行默认规则

9.2.2 RBAC

RBAC(Role-Based Access Control)基于角色的访问控制,相对于其它访问控制方式,拥有一下优势:

  • 对集群中的资源和非资源均拥有完整的覆盖

  • 整个 RBAC 完全由几个 API 对象完成,同其它 API 对象一样,可以用 kubectl 或 API 进行操作

  • 可以在运行时进行调整,无需重启 API Server

RBAC 引入了 4 个新的顶级资源对象:Role、ClusterRole、RoleBinding、ClusterRoleBinding,4 种对象类型均可以通过 kubectl 与 API 操作

image-20250412201807387

有三种绑定关系:

  • Role + RoleBinding

  • ClusterRole + ClusterRoleBinding

  • ClusterRole + RoleBinding (降维,作用域限制)

在 RBAC API 中,Role 表示一组规则权限,权限只会增加(累加权限),不存在一个资源一开始就有很多权限而通过 RBAC 对其进行减少的操作;Role 可以定义在一个 namespace 中,如果想要跨 namespace 则可以创建 ClusterRole

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
 namespace: default
 name: pod-reader
rules:
- apiGroups: [""] # "" 表示core组
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

ClusterRole 具有与 Role 相同的权限角色控制能力,不同的是 ClusterRole 是集群级别的,ClusterRole 可以用于:

  • 集群级别的资源控制(如 Node 访问权限)

  • 非资源型 endpoints (例如 /health 访问)

  • 所有命名空间资源控制(例如 Pods)

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
 name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]

RoleBinding + Role 可以将 Role 中定义的权限授予用于或用户组,RoleBinding 包含一组权限列表(subjects),权限列表中包含有不同形式的待授予权限资源类型(users, groups, service accounts);RoleBinding 同样包含对被 Bind 的 Role 引用;RoleBinding 适用于某个命名空间内授权,而 ClusterRoleBinding 适用于集群范围内的授权。

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
 name: read-pods
 namespace: default
subjects:
- kind: User
  name: jane
  apiGroup: rbac.authorization.k8s.io
roleRef:
 kind: Role
 name: pod-reader
 apiGroup: rbac.authorization.k8s.io

RoleBinding + ClusterRole 同样可以引用 ClusterRole 来对当前 namespace 内用户、用户组或 ServiceAccount 进行授权,这种操作允许集群管理员在整个集群内定义一些通用的 ClusterRole,然后在不同的 namespace 中使用 RoleBinding 来引用

# 这个角色绑定只允许dave在dev命名空间内读取Secret
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
 name: read-secrets
 namespace: dev
subjects:
- kind: User
  name: dave
  apiGroup: rbac.authorization.k8s.io
roleRef:
 kind: ClusterRole
 name: secret-reader
 apiGroup: rbac.authorization.k8s.io

ClusterRoleBinding 可以对整个集群中的所有命名空间资源权限进行授权;一下 ClusterRoleBinding 样例展示了授权 manager 组内所有用户在全部命名空间中对 secrets 进行访问

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
 name: read-secrets-global
subjects:
- kind: Group
  name: manager
  apiGroup: rbac.authorization.k8s.io
roleRef:
 kind: ClusterRole
 name: secret-reader
 apiGroup: rbac.authorization.k8s.io

Resources:Kubernetes 集群内一些资源一般以其名称字符串来表示,这些字符串一般会在 API 的 URL 地址中出现;同时某些资源也会包含子资源,例如 logs 资源就属于 pods 的子资源,API 中 URL 样例如下

GET /api/v1/namespace/{namespace}/pods/{name}/log

如果要在 RBAC 授权模型中控制这些子资源的访问权限,可以通过 / 分隔符来实现,以下是一个定义 pods 资源 logs 访问权限的 Role 定义样例

...
rules:
- apiGroups: [""]
  resources: ["pods/log"]
  verbs: ["get", "list"]

subjects

image-20250412211511314

9.2.3 实操

需求:创建一个用户只能管理 dev 命名空间

实现:创建证书 > 转换为 kubeconfig 文件 > 创建命名空间 > 角色绑定

  1. 创建 devuser 的证书

cd /etc/kubernetes/pki
cfssl gencert -ca=ca.crt -ca-key=ca.key -profile=kubernetes /root/devuser.json | cfssljson -bare devuser
// /root/devuser.json
{
    "CN": "devuser",
    "hosts": [],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "name": [
        {
            "C": "CN",
            "ST": "BeiJing",
            "L": "BeiJing",
            "O": "k8s",
            "OU": "system"
        }
    ]
}
# 设置集群参数
kubectl config set-cluster kubernetes \
--certificate-authority=ca.crt \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=devuser.kubeconfig

# 设置客户端认证参数
kubectl config set-credentials devuser \
--client-certificate=devuser.pem \
--client-key=devuser-key.pem \
--embed-certs=true \
--kubeconfig=devuser.kubeconfig

# 设置上下文参数
kubectl config set-context kubernetes \
--cluster=kubernetes \
--user=devuser \
--namespace=dev \
--kubeconfig=devuser.kubeconfig

# devuser 绑定到 admin 集群角色上
kubectl create rolebinding devuser-admin-binding \
--clusterrole=admin \
--user=devuser --namespace=dev

# 设置默认上下文
kubectl config use-context kubernetes --kubeconfig=devuser.kubeconfig
# 创建对应的用户放到home目录下
useradd dev
passwd dev
# 把配置文件放到用户home目录下,用户只能访问dev命名空间,
mv devuser.kubeconfig /home/dev/.kube/config

9.2.4 资源与角色类型的匹配

image-20250413123107109

9.2.5 常见的预定义角色

view ClusterRole

  • 允许读取一个命名空间中的大多数资源,除了 Role、RoleBinding 和 Secret

edit ClusterRole

  • 允许读取和修改 Secret。但是,它不允许查看或修改 Role 和 RoleBinding,这是为了防止权限扩散

admin ClusterRole

  • 一个命名空间中的资源的完全控制权是由 admin ClusterRole 赋予的。有这个 ClusterRole 的主体可以读取和修改命名空间中的任何资源,除了 ResourceQuota 和命名空间资源本身。edit 和 adminClusterRole 之间的主要区别是能否在命名空间中查看和修改 Role 和 RoleBinding

cluster-adminCluterRole

  • 通过将cluster-adminCluterRole 赋给主体,主体可以获得 Kubernetes 集群完全控制的权限

9.3 准入控制

准入控制是 API Server 的插件集合,通过添加不同的插件,实现额外的准入控制规则。甚至与 API Server 的一些主要的功能都需要通过 Admission Controllers 实现,比如 ServiceAccount。

  • NamespaceLifecycle:防止在不存在的 namespace 上创建对象,防止删除系统预置 namespace,删除 namespace 是,连带删除它的所有资源对象。

  • LimitRanger:确保请求的资源不会超过资源所在 namespace 和 LimitRanger 的限制

  • ServiceAccount:实现了自动化添加 SA

  • ResourceQuota:确保请求的资源不会超过资源的 ResourceQuota 限制

十、HELM

在没有使用 helm 之前,向 Kubernetes 部署应用,我们需要依次部署 deployment、service 等,步骤较繁琐。况且随着很多项目微服务化,复杂的应用在容器中部署以及管理显得较为复杂,helm 通过打包的方式,支持发布的版本管理和控制,很大程度上简化了 Kubernetes 应用的部署和管理

helm 本质就是让 Kubernetes 的应用管理(deployment、service等)可配置,能动态生成。通过动态生成资源清单文件。然后调用 kubectl 自动执行 Kubernetes 资源部署。

helm 是官方提供的类似于 yum 的包管理器,是部署环境的流程封装。helm 有两个重要的概念:chart 和 release

  • chart:是创建一个应用的信息集合,包括各种 Kubernetes 对象的配置模板、参数定义、依赖关系、文档说明等。chart 是应用部署的自包含逻辑单元。可以将 chart 想象成 apt、yum 中的软件安装包

  • release:是 chart 的运行实例,代表了一个正在运行的应用。当 chart 被安装到 Kubernetes 集群,就生成一个 release。chart 能够多次安装到同一个集群,每次安装都是一个 release

  • helm cli:helm 客户端组件,负责和 Kubernetes API Server 通信

  • repository: 用于发布和存储 chart 的仓库

十一、k8s运维

11.1 Harbor

Harbor 的目标是帮助用户迅速搭建一个企业级的 Docker registry 服务。它以 Docker 公司开源的 registry 为基础,额外提供了如下功能:

  • 基于角色的访问控制

  • 基于策略的镜像复制

  • 镜像的漏洞扫描

  • AD/LDAP集成

  • 镜像的删除和空间清理

  • 友好的管理 UI

  • 审计日志

  • RESTful API

  • 部署简单

kubectl操作

kubectl get ns(namespace) # 获取命名空间
kubectl get po(pod) # 获取默认命名空间下的pod
kubectl get nodes # 获取节点信息
kubectl scale deploy --replicas=3 nginx # 设置deploy副本数为3
kubectl create -f pod.yaml   # 基于pod.yaml文件创建pod资源
​
# 获取当前资源,pod、node、namespace
kubectl get pod
    -A,--all-namespaces     查看当前所有命名空间的资源
    -n                      指定命名空间,默认值default,kube-system空间存放的时当前组件资源
    -l                      筛选资源,key  key=value
    -o wide                 详细信息包括IP、分配的节点等
    -w                      监控资源的变化状态
    
# 示例
kubectl get pod --show-labels # 查看标签
kubectl get pod -l app(app=nginx) # 通过标签筛选pod   app是key
    
    
# 进入Pod内部的容器执行命令
# 当一个pod内部就一个容器时,可以省略ContainerName(不包括pause)
kubectl exec -it PodName -c ContainerName -- command
    -c                      可以省略,默认进入唯一的容器内部
​
# 示例
# 进入pod容器内部
kubectl exec -it pod名称 -c 容器名称 -- /bin/bash
kubectl exec -it nginx-5869d7778c-5wwcd -c nginx -- /bin/bash
​
# 查看资源的描述
kubectl explain pod.spec
​
# 查看Pod内部容器的日志
kubectl logs PodName -c ContainerName
kubectl logs app=nginx -c nginx # 查看日志
​
# 查看资源的详细信息
kubectl describe pod PodName (node NodeName)
​
# 删除pod
kubectl delete pod PodName
# 删除所有pod
kubectl delete pod --all
# 删除由k8s.ymal创建的资源
kubectl delete -f k8s.yaml
​
# 创建service,service会匹配myapp标签的pod
kubectl create svc clusterip myapp --tcp=80:80
​
​
# 标签操作
kubectl label pod PodName key=value  # 想PodName添加key=value的标签
    --overwrite
    
# 扩容操作
kubectl scale rc rcName --replicas=5
​
# --dry-run 只测试不运行,在不记得怎么写资源清单的时候可以用这个得到模板
kubectl create deploy myapp --image=wangyanglinux/myapp:v1.0 --dry-run -o yaml

每个Pod都有一个pause容器,Pod内的其他容器共享pause容器的Pid,Uid等信息

image-20250406163615248

高可用集群,如果一个节点挂了会发生哪些事情 https://developer.aliyun.com/article/785311

许可协议:  CC BY 4.0
分享

相关文章

下一篇

Go语言

上一篇

凝思操作系统开启系统日志

最近更新

  • kafka Kraft模式k8s集群搭建
  • 达梦数据库主备集群搭建
  • RocketMQ proxy
  • 凝思操作系统开启系统日志
  • kubernetes学习记录

热门标签

Halo

目录

©2025 春夏秋冬平平安安. 保留部分权利。

使用 Halo 主题 Chirpy