Kubernetes基础与入门实战

一、背景

1.1 物理机时代的运维痛点

  • 部署周期长:每次配置新服务器需手动安装OS、配置环境,经常需要2-3天才能交付
  • 故障恢复困难:硬件故障后,重建环境需重复之前的手工操作,无法保证环境一致性
  • 资源利用率低:我司服务器平均CPU利用率只有15%-20%,大量资源闲置但无法共享
  • 运维成本高:每10台服务器至少需要1名专职运维,人力成本居高不下

1.2 虚拟化技术带来的运维变革

  • 模板化部署:使用VMware模板,服务器部署时间从天级缩短到小时级
  • 快照与迁移:故障处理可通过快照回滚,服务迁移不再受物理硬件限制
  • 资源隔离与调度:不同应用间实现资源隔离,资源池化管理提升利用率
  • 降低硬件投入:通过整合工作负载,硬件采购成本降低约40%

虚拟机的主要问题是每个VM都需要独立OS,导致资源占用仍然较高。

1.3 容器化:运维工作的革命性变化

  • 镜像一致性:解决了"我这边正常,线上环境出问题"的困扰
  • 资源利用率提升:相同硬件上可部署的服务数量比VM提升3-5倍
  • 秒级启停:服务启动从分钟级缩短到秒级,大幅提升故障转移速度
  • CI/CD友好:与Jenkins等工具结合,实现自动化部署流水线

二、K8S的介绍与安装

2.1 K8S架构图的理解

主节点(MasterNode)组件:

  • API Server:作为集群控制平面的前端,处理所有API请求
  • Controller Manager:负责集群状态管理和控制循环
  • Scheduler:负责Pod调度决策
  • etcd:分布式键值存储,保存集群所有配置数据

工作节点(WorkerNode)组件:

  • Kubelet:确保容器按照PodSpec运行
  • Kubeproxy:维护网络规则,实现服务转发
  • Pod:最小部署单元,包含一组容器

工作流程:

  • 运维人员通过kubectl向API Server发送命令
  • API Server验证请求并存储到etcd
  • Controller Manager检测到状态变化并创建资源
  • Scheduler决定Pod应该调度到哪个节点
  • Kubelet接收指令并创建Pod
  • 从Docker Registry拉取镜像运行容器
  • Kubeproxy设置网络规则
  • 外部用户通过服务访问应用

2.2 K8S是什么?

Kubernetes(简称k8s)本质上是一个开源的容器编排平台。它源于Google内部使用多年的Borg系统,目的是帮助运维工程师自动化部署、扩展和管理容器化应用。

从运维角度看,k8s就像是一个超级"管家",它接管了我们原本需要手动完成的大量工作 - 从应用部署、扩缩容、故障恢复到资源管理等。它让我们可以将多台服务器作为一个统一的资源池来使用。

2.3 为什么需要Kubernetes?

  • 应用部署自动化:在传统环境中,我们常常需要手动部署应用,而k8s可以通过声明式配置实现全自动化部署
  • 弹性伸缩能力:可以根据负载情况自动扩展或缩减应用实例数量
  • 故障自愈功能:当容器崩溃时,k8s会自动重启或重新调度容器
  • 统一资源调度:将集群的计算资源视为一个整体,提高资源利用率
  • 服务发现和负载均衡:内置服务发现机制,无需额外配置复杂的负载均衡器

2.4 K8S名词解释

  • Deployment:Kubernetes中用于声明式管理Pod和ReplicaSet的资源对象(相当于一个自动化管理员,告诉系统"我需要运行什么"而不是"怎么运行")
  • ReplicaSet:确保指定数量的Pod副本在任何时间运行的下一代控制器(像一个复印机,不断确保你要求的Pod数量始终存在)
  • Replication Controller:确保Pod副本数量始终符合预期的资源对象(就是个监工,保证工人数量永远达标)
  • Namespace:Kubernetes集群内的虚拟分区,将资源分组隔离(相当于小区里的不同单元楼,各管各的资源)
  • Container:轻量级、可移植、自包含的软件执行环境(就像装货的集装箱,把应用和依赖打包在一起)
  • Node:Kubernetes集群中的工作机器,可以是物理机或虚拟机(就是干活的服务器,提供计算能力的实体机器)
  • Services:定义一组Pod及访问策略的抽象(像前台接待,统一接收外部请求并转发给内部工作的Pod)
  • Labels:附加到对象上的键值对(就是给资源贴的标签,方便分类和筛选)
  • Pods:Kubernetes中最小的可部署计算单元(应用的包装盒,装着一个或多个容器)

2.5 Kubernetes Pod控制器类型

  • Deployment:管理无状态应用的控制器,支持滚动更新和回滚(相当于应用的自动驾驶仪,负责平稳地更新和维护应用)
  • StatefulSet:管理有状态应用的控制器,为Pod提供持久存储和固定网络标识(像是有编号的员工,每个都有固定工位和个人储物柜)
  • DaemonSet:确保集群内每个节点上都运行特定的Pod(像小区保安,每栋楼都要配一个)
  • Job/CronJob:运行一次性或定时任务的控制器(Job像临时工,做完就走;CronJob像定时闹钟,按时执行特定任务)
  • ReplicaSet:维护Pod副本数量的控制器(复印机操作员,保证文件副本数量准确)
  • HorizontalPodAutoscaler:根据负载自动调整Pod数量(智能调度员,客流量大时自动增加服务窗口)
  • ConfigMap/Secret:配置管理控制器(ConfigMap是公开菜单,Secret是保险箱里的机密配方)

2.6 deploylment、rs、pod之间的关系

  • Pod:Kubernetes中最小的可部署计算单元,包含一个或多个容器(相当于装应用的容器盒子,里面装着你的应用程序)
  • ReplicaSet(RS) :确保指定数量的Pod副本在任何时间运行的控制器(像工厂的车间主管,负责保证工人数量)
  • Deployment:提供声明式更新和管理ReplicaSet的更高级控制器(相当于工厂经理,负责整体生产计划和升级策略)

Deployment管理ReplicaSet,ReplicaSet管理Pod,是一种层级关系。

当你创建Deployment时,它会自动创建ReplicaSet,而ReplicaSet会创建和管理Pod。

当你需要更新应用时,Deployment会创建新的ReplicaSet并逐步将流量从旧ReplicaSet转移到新的ReplicaSet,实现滚动更新。

简单说:Deployment管理ReplicaSet,ReplicaSet管理Pod,形成了三层控制关系

2.7 部署K8S前的环境准备

2.7.1 升级系统内核

见CentOS 7 RPM更新内核到5.4

2.7.2 部署规划

版本规划

软件 版本
centos 7.5 版本及以上
docker 19.03 及以上
kubernetse V1.20.5及以上
flanner V0.13.0及以上

2.7.3 节点规划

Hostname IP 内核版本
k8s-master-01 10.0.0.231 5.0 以上
k8s-node-01 10.0.0.232 5.0 以上
k8s-node-02 10.0.0.233 5.0 以上

2.7.4 修改主机名并解析DNS和主机

三台都操作

# 修改主机名
hostnamectl set-hostname k8s-master-01
hostnamectl set-hostname k8s-node-01
hostnamectl set-hostname k8s-node-02
# 解析主机
vim /etc/hosts
10.0.0.231   k8s-master-01   m1
10.0.0.232   k8s-node-01     n1
10.0.0.233   k8s-node-02     n2

# 添加 DNS 解析
vim /etc/resolv.conf
nameserver 223.5.5.5
nameserver 114.114.114.114

2.7.5 系统优化

三台都操作

# 关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
 
# 关闭selinux
# 临时关闭Selinux
setenforce 0 

# 永久关闭selinux
vim /etc/sysconfig/selinux 
SELINUX=disabled          # 将此处改为disabled

# 清空iptables规则
iptables -F    

#禁用swap交换分区
# 打开自动挂载的配置文件,将swap配置项注释掉
sed -ri '/^[^#]*swap/s@^@#@' /etc/fstab
swapoff -a 

# 确认输出的swap行如下(都为0)
free -h

# 免密登录,master操作
rm -rf /root/.ssh/
ssh-keygen   # 一直回车
cd /root/.ssh/
ll
# 两个子节点创建目录并将master的公钥复制到两个子节点
# 232:
rm -rf /root/.ssh
mkdir -p /root/.ssh
# 233:
rm -rf /root/.ssh
mkdir -p /root/.ssh
ssh-copy-id [email protected]
ssh-copy-id [email protected]

# 测试
ssh [email protected]
ssh [email protected]

# 同步集群时间,三台都操作
# 安装同步时间工具
yum install chrony -y
# 配置
vim /etc/chrony.conf
# 注释掉默认的server开头
server ntp1.aliyun.com iburst
server time.neu.edu.cn iburst
server time.nist.gov iburst
# 手动强制同步时间,系统时间完全同步
chronyc makestep
# 启动
systemctl start chronyd
systemctl enable chronyd
systemctl status chronyd
# 检查
chronyc tracking

# 集群时间同步
crontab -e
# Timing synchronization time
0 */1 * * * /usr/sbin/ntpdate ntp1.aliyun.com &>/dev/null
# 检查定时任务是否添加成功
crontab -l


# 新系统软件(排除内核)
yum update -y --exclud=kernel*

# 安装基础常用软件
yum install wget expect vim net-tools ntp bash-completion ipvsadm ipset jq iptables conntrack sysstat libseccomp -y

# yum安装ipvs
yum install -y conntrack-tools ipvsadm ipset conntrack libseccomp

# 创建并编辑 /etc/sysconfig/modules/ipvs.modules 文件
cat > /etc/sysconfig/modules/ipvs.modules <<EOF
#!/bin/bash
# 定义 IPVS 所需的模块列表
ipvs_modules="ip_vs ip_vs_lc ip_vs_wlc ip_vs_rr ip_vs_wrr ip_vs_lblc ip_vs_lblcr ip_vs_dh ip_vs_sh ip_vs_fo ip_vs_nq ip_vs_sed ip_vs_ftp nf_conntrack"

# 遍历模块列表,检查模块是否已加载,未加载则加载模块
for kernel_module in \${ipvs_modules}; do
    /sbin/modinfo -F filename \${kernel_module} > /dev/null 2>&1
    if [ \$? -eq 0 ]; then
        /sbin/modprobe \${kernel_module}
    fi
done
EOF

# 修改文件权限,使其可执行
chmod 755 /etc/sysconfig/modules/ipvs.modules

# 执行脚本以加载 IPVS 模块
bash /etc/sysconfig/modules/ipvs.modules

# 验证模块是否加载成功
lsmod | grep ip_vs

# 创建并编辑 /etc/sysctl.d/k8s.conf 文件
cat > /etc/sysctl.d/k8s.conf << EOF
# 启用 IP 转发
net.ipv4.ip_forward = 1

# 启用 bridge 网桥的 IP 表和 iptables 规则
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1

# 允许在 umount 时强制分离挂载点
fs.may_detach_mounts = 1

# 允许虚拟内存超过物理内存
vm.overcommit_memory=1

# 禁用 OOM(Out of Memory)杀手
vm.panic_on_oom=0

# 增加用户观察文件描述符的数量
fs.inotify.max_user_watches=89100

# 增加文件描述符的最大数量
fs.file-max=52706963

# 增加打开文件的数量
fs.nr_open=52706963

# 设置 TCP 连接的 keepalive 时间
net.ipv4.tcp_keepalive_time = 600

# 启用 TCP 时间戳重用
net.ipv4.tcp_tw_reuse = 1

# 设置 TCP 最大孤儿套接字数
net.ipv4.tcp_max_orphans = 327680

# 设置 TCP 孤儿重传次数
net.ipv4.tcp_orphan_retries = 3

# 启用 TCP 同步 cookie
net.ipv4.tcp_syncookies = 1

# 设置 TCP 最大 SYN 背压日志数
net.ipv4.tcp_max_syn_backlog = 16384

# 设置 IP 连接跟踪最大数量
net.ipv4.ip_conntrack_max = 65536

# 设置 TCP 最大 SYN 背压日志数
net.ipv4.tcp_max_syn_backlog = 16384

# 禁用 TCP 时间戳
net.ipv4.tcp_timestamps = 0

# 设置核心文件的最大数量
net.core.somaxconn = 16384
EOF

# 立即应用 sysctl 配置
sysctl --system

2.7.6 安装Docker

# 1) 卸载之前的 docker
# 卸载所有旧版本的 Docker 包
yum remove docker \
              docker-client \
              docker-client-latest \
              docker-common \
              docker-latest \
              docker-latest-logrotate \
              docker-logrotate \
              docker-engine -y

# 2) 安装 docker 所需安装包
# 安装 yum-utils 和其他一些必要的包
yum install -y yum-utils \
              device-mapper-persistent-data \
              lvm2

# 3) 安装 docker yum 源
# 安装依赖,下载 repo 文件,并把软件仓库地址替换为镜像站
yum install -y yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# 替换为清华的镜像
sed -i 's+https://download.docker.com+https://mirrors.tuna.tsinghua.edu.cn/docker-ce+' /etc/yum.repos.d/docker-ce.repo

# 或者直接使用阿里云下载docker-ce镜像
wget -P /etc/yum.repos.d/ https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

# 清理缓存
yum clean all
yum makecache

# 安装docker
yum install docker-ce -y

# 开启以及自启查看docker相关服务
systemctl enable --now docker.service
systemctl status docker
rpm -qa | grep docker

# 查看版本
docker version

# 查看docker信息
docker info

# 优化docker配置
vim /etc/docker/daemon.json
{
    "registry-mirrors": [
        "https://docker.1ms.run"
    ]
}
# 重新加载配置并重启
systemctl daemon-reload
systemctl restart docker
systemctl status docker
docker info

2.8 K8S安装

2.8.1 安装 kubenetes yum 源

三台都操作

# 创建并编辑 /etc/yum.repos.d/kubernetes.repo 文件
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
# 指定 Kubernetes 软件包的仓库地址
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
# 禁用 GPG 检查
repo_gpgcheck=0
# 指定 GPG 密钥地址,用于验证软件包的签名
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

# 安装 kubelet、kubeadm 和 kubectl
# 查看可用版本
yum list --showduplicates kubeadm --disableexcludes=kubernetes

# 安装特定版本
yum install -y kubelet-1.20.9 kubeadm-1.20.9 kubectl-1.20.9 --disableexcludes=kubernetes

###############################################################################################
关于--disableexcludes=kubernetes参数
--disableexcludes=kubernetes参数是在使用yum安装Kubernetes组件时使用的一个重要选项,它的作用是:
禁用kubernetes软件源的排除列表
确保安装完整的kubernetes所需依赖,不会因为排除规则而跳过某些包
避免因依赖问题导致的安装失败或功能缺失
如果不使用该参数可能会导致:
部分依赖包被忽略安装
集群组件之间出现版本不兼容问题
系统自动更新时可能会更新到不兼容的版本
###############################################################################################

# 启动 kubelet 服务,并设置为开机自启
systemctl enable --now kubelet
systemctl status kubelet


2.8.2 主节点操作(Master操作)

  • apiserver-advertise-address:apiserver监听地址
  • control-plane-endpoint:控制平面的IP地址或DNS名称
  • image-repository:镜像仓库,此处为国内阿里云镜像仓库加速下载
  • service-cidr:为Service分配的IP地址段
  • pod-network-cidr:为pod分配的IP地址段
# 初始化 master 节点(仅在master 节点上执行)
kubeadm init \
--image-repository registry.cn-hangzhou.aliyuncs.com/google_containers \
--kubernetes-version=v1.20.9 \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=10.244.0.0/16
# 注释
############################################################################################
# 初始化 Kubernetes 主节点
kubeadm init \
# 指定从阿里云镜像仓库拉取所需镜像
--image-repository registry.cn-hangzhou.aliyuncs.com/google_containers \ 
--kubernetes-version=v1.20.9 \ # 指定要安装的 Kubernetes 版本
--service-cidr=10.96.0.0/12 \ # 指定 Service 的 CIDR 网段,默认为 10.96.0.0/12
# 指定 Pod 的 CIDR 网段,与后续 CNI 插件配置相关,Flannel 通常使用 10.244.0.0/16
--pod-network-cidr=10.244.0.0/16 
############################################################################################

############################################################################################
# 成功显示:
Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 10.0.0.231:6443 --token 2c7dd0.ou672s7d8ltnw0wx \
    --discovery-token-ca-cert-hash sha256:601d4080331af07278deb66121aa5f8414276edd40a816e79d97cfe5eecfd9d9 
############################################################################################

# 初始化过程下载的容器镜像
[root@k8s-master-01 ~]# docker images
REPOSITORY                                                                    TAG        IMAGE ID       CREATED       SIZE
registry.cn-hangzhou.aliyuncs.com/google_containers/kube-proxy                v1.20.9    8dbf9a6aa186   3 years ago   99.7MB
registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver            v1.20.9    0d0d57e4f64c   3 years ago   122MB
registry.cn-hangzhou.aliyuncs.com/google_containers/kube-controller-manager   v1.20.9    eb07fd4ad3b4   3 years ago   116MB
registry.cn-hangzhou.aliyuncs.com/google_containers/kube-scheduler            v1.20.9    295014c114b3   3 years ago   47.3MB
registry.cn-hangzhou.aliyuncs.com/google_containers/etcd                      3.4.13-0   0369cf4303ff   4 years ago   253MB
registry.cn-hangzhou.aliyuncs.com/google_containers/coredns                   1.7.0      bfe3a36ebd25   4 years ago   45.2MB
registry.cn-hangzhou.aliyuncs.com/google_containers/pause                     3.2        80d28bedfe5d   5 years ago   683kB


# 建立用户集群权限
## 非root用户运行kubectl,请执行以下命令
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

# 如果是root用户,则可以使用:
echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile
source ~/.bash_profile

# 安装集群网络插件
wget https://ghfast.top/https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
kubectl apply -f kube-flannel.yml

# 将worker节点假如集群
####### 两个工作节点(232、233)操作
kubeadm join 10.0.0.231:6443 --token 2c7dd0.ou672s7d8ltnw0wx \
    --discovery-token-ca-cert-hash sha256:601d4080331af07278deb66121aa5f8414276edd40a816e79d97cfe5eecfd9d9 

# 检查集群状态,master操作
## 第一种方式
kubectl get pods
## 第二种方式
kubectl get pods -n kube-system

# 此过程需要等上一两分钟
[root@k8s-master-01 ~]# kubectl get pods -n kube-system
NAME                                    READY   STATUS    RESTARTS   AGE
coredns-54d67798b7-6qk8l                1/1     Running   0          33m
coredns-54d67798b7-qxxff                1/1     Running   0          33m
etcd-k8s-master-01                      1/1     Running   0          33m
kube-apiserver-k8s-master-01            1/1     Running   0          33m
kube-controller-manager-k8s-master-01   1/1     Running   0          33m
kube-proxy-2gpsd                        1/1     Running   0          7m4s
kube-proxy-b7wlb                        1/1     Running   0          7m4s
kube-proxy-shwgp                        1/1     Running   0          33m
kube-scheduler-k8s-master-01            1/1     Running   0          33m

2.8.3 kube-flannel文件详解

官方文件解释

# Flannel网络插件部署配置文件
# 该文件用于在Kubernetes集群中部署Flannel网络解决方案
# Flannel是一个简单高效的容器网络解决方案,为Kubernetes提供容器间通信

---
# 创建专用命名空间
# 命名空间用于隔离资源,这里创建kube-flannel命名空间来部署所有Flannel相关资源
kind: Namespace
apiVersion: v1
metadata:
  name: kube-flannel  # 命名空间名称为kube-flannel
  labels:
    k8s-app: flannel  # 添加标签,用于资源筛选和识别
    pod-security.kubernetes.io/enforce: privileged  # 设置安全策略为特权模式,因为网络插件需要较高权限

---
# 创建集群角色(ClusterRole)
# 集群角色定义了Flannel在集群范围内所需的权限
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  labels:
    k8s-app: flannel  # 标签,用于标识这是Flannel的资源
  name: flannel  # 角色名称为flannel
rules:  # 权限规则定义
- apiGroups:  # API组
  - ""  # 空字符串表示核心API组
  resources:
  - pods  # 允许访问pods资源
  verbs:
  - get  # 允许获取pod信息的操作
- apiGroups:
  - ""
  resources:
  - nodes  # 允许访问节点资源
  verbs:
  - get  # 允许获取节点信息
  - list  # 允许列出节点
  - watch  # 允许监视节点变化
- apiGroups:
  - ""
  resources:
  - nodes/status  # 允许访问节点状态
  verbs:
  - patch  # 允许修补(更新)节点状态

---
# 创建集群角色绑定(ClusterRoleBinding)
# 将上面创建的集群角色与服务账户绑定,赋予服务账户相应权限
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  labels:
    k8s-app: flannel  # 标签
  name: flannel  # 角色绑定名称
roleRef:  # 角色引用,指定要绑定的角色
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole  # 类型为集群角色
  name: flannel  # 引用名为flannel的集群角色
subjects:  # 主体,指定角色绑定的对象
- kind: ServiceAccount  # 类型为服务账户
  name: flannel  # 服务账户名称为flannel
  namespace: kube-flannel  # 服务账户所在的命名空间

---
# 创建服务账户(ServiceAccount)
# 服务账户用于Pod的身份认证和授权
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-app: flannel  # 标签
  name: flannel  # 服务账户名称
  namespace: kube-flannel  # 所在命名空间

---
# 创建配置映射(ConfigMap)
# 配置映射用于存储Flannel的配置信息,可以被Pod挂载使用
kind: ConfigMap
apiVersion: v1
metadata:
  name: kube-flannel-cfg  # 配置映射名称
  namespace: kube-flannel  # 所在命名空间
  labels:
    tier: node  # 标签,表明这是节点层级的资源
    k8s-app: flannel
    app: flannel
data:  # 配置数据
  cni-conf.json: |  # CNI插件的配置文件
    {
      "name": "cbr0",  # 网桥名称
      "cniVersion": "0.3.1",  # CNI版本
      "plugins": [  # 插件列表
        {
          "type": "flannel",  # 使用flannel插件
          "delegate": {  # 委托配置
            "hairpinMode": true,  # 启用发夹模式,允许容器访问自己暴露的服务
            "isDefaultGateway": true  # 将flannel设置为默认网关
          }
        },
        {
          "type": "portmap",  # 使用portmap插件,用于端口映射
          "capabilities": {
            "portMappings": true  # 启用端口映射功能
          }
        }
      ]
    }
  net-conf.json: |  # Flannel网络配置
    {
      "Network": "10.244.0.0/16",  # Pod网络的CIDR,定义可用IP范围
      "EnableNFTables": false,  # 禁用NFTables,使用iptables
      "Backend": {  # 后端配置
        "Type": "vxlan"  # 使用VXLAN作为封装技术
      }
    }

---
# 创建守护进程集(DaemonSet)
# 守护进程集确保所有(或部分)节点运行一个Pod副本,适合网络插件这类需要在每个节点运行的应用
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: kube-flannel-ds  # 守护进程集名称
  namespace: kube-flannel  # 所在命名空间
  labels:
    tier: node  # 标签
    app: flannel
    k8s-app: flannel
spec:
  selector:  # 选择器,用于选择要管理的Pod
    matchLabels:
      app: flannel
  template:  # Pod模板
    metadata:
      labels:
        tier: node
        app: flannel
    spec:
      affinity:  # 亲和性设置
        nodeAffinity:  # 节点亲和性
          requiredDuringSchedulingIgnoredDuringExecution:  # 调度时必须满足,运行时可忽略
            nodeSelectorTerms:  # 节点选择条件
            - matchExpressions:  # 匹配表达式
              - key: kubernetes.io/os  # 键为操作系统类型
                operator: In  # 操作符为"在...之中"
                values:
                - linux  # 值为linux,表示只在Linux节点上运行
      hostNetwork: true  # 使用主机网络
      priorityClassName: system-node-critical  # 优先级为系统节点关键,确保优先调度和不被驱逐
      tolerations:  # 容忍设置
      - operator: Exists  # 存在操作符,表示容忍所有污点
        effect: NoSchedule  # 效果为不调度,表示可以在设置了NoSchedule污点的节点上运行
      serviceAccountName: flannel  # 使用的服务账户名称
      initContainers:  # 初始化容器
      - name: install-cni-plugin  # 安装CNI插件的容器
        image: ghcr.io/flannel-io/flannel-cni-plugin:v1.6.2-flannel1  # 使用的镜像
        command:  # 执行的命令
        - cp  # 复制命令
        args:  # 命令参数
        - -f  # 强制复制
        - /flannel  # 源文件
        - /opt/cni/bin/flannel  # 目标位置,CNI插件目录
        volumeMounts:  # 卷挂载
        - name: cni-plugin  # 挂载名为cni-plugin的卷
          mountPath: /opt/cni/bin  # 挂载路径
      - name: install-cni  # 安装CNI配置的容器
        image: ghcr.io/flannel-io/flannel:v0.26.7  # 使用的镜像
        command:
        - cp
        args:
        - -f
        - /etc/kube-flannel/cni-conf.json  # 源配置文件
        - /etc/cni/net.d/10-flannel.conflist  # 目标位置,CNI配置目录
        volumeMounts:
        - name: cni  # 挂载名为cni的卷
          mountPath: /etc/cni/net.d  # 挂载路径
        - name: flannel-cfg  # 挂载名为flannel-cfg的卷
          mountPath: /etc/kube-flannel/  # 挂载路径
      containers:  # 主容器
      - name: kube-flannel  # Flannel主容器
        image: ghcr.io/flannel-io/flannel:v0.26.7  # 使用的镜像
        command:
        - /opt/bin/flanneld  # 执行flanneld守护进程
        args:
        - --ip-masq  # 启用IP伪装
        - --kube-subnet-mgr  # 使用Kubernetes子网管理器
        resources:  # 资源请求
          requests:
            cpu: "100m"  # 请求0.1核CPU
            memory: "50Mi"  # 请求50MB内存
        securityContext:  # 安全上下文
          privileged: false  # 不使用特权模式
          capabilities:  # 容器能力
            add: ["NET_ADMIN", "NET_RAW"]  # 添加网络管理和原始网络包处理能力
        env:  # 环境变量
        - name: POD_NAME  # Pod名称
          valueFrom:
            fieldRef:
              fieldPath: metadata.name  # 从Pod元数据中获取名称
        - name: POD_NAMESPACE  # Pod命名空间
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace  # 从Pod元数据中获取命名空间
        - name: EVENT_QUEUE_DEPTH
          value: "5000"  # 事件队列深度设置为5000
        volumeMounts:  # 卷挂载
        - name: run
          mountPath: /run/flannel  # 挂载运行目录
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/  # 挂载配置目录
        - name: xtables-lock
          mountPath: /run/xtables.lock  # 挂载xtables锁文件
      volumes:  # 卷定义
      - name: run  # 运行卷
        hostPath:  # 主机路径
          path: /run/flannel  # 主机上的路径
      - name: cni-plugin  # CNI插件卷
        hostPath:
          path: /opt/cni/bin  # 主机上的CNI插件目录
      - name: cni  # CNI配置卷
        hostPath:
          path: /etc/cni/net.d  # 主机上的CNI配置目录
      - name: flannel-cfg  # Flannel配置卷
        configMap:
          name: kube-flannel-cfg  # 使用名为kube-flannel-cfg的配置映射
      - name: xtables-lock  # xtables锁卷
        hostPath:
          path: /run/xtables.lock  # 主机上的xtables锁文件路径
          type: FileOrCreate  # 类型为文件或创建

Kubernetes资源对象使用场景

  • Namespace (命名空间)

场景:当需要在集群中隔离不同应用或团队的资源时,创建专用命名空间。例如,将网络组件与应用程序隔离,防止误操作影响整个集群网络。

  • ClusterRole (集群角色)

场景:当需要授予某个组件对整个集群范围内资源的访问权限时使用。例如,网络插件需要获取所有节点信息来配置跨节点通信。

  • ClusterRoleBinding (集群角色绑定)

场景:将集群角色与服务账户关联,使特定服务可以获得所需权限。例如,让Flannel服务账户拥有管理集群网络所需的权限。

  • ServiceAccount (服务账户)

场景:为Pod提供身份认证,用于Pod与API Server交互时的权限验证。例如,Flannel Pod需要身份认证才能读取网络配置并更新节点状态。

  • ConfigMap (配置映射)

场景:集中管理应用配置,并允许容器挂载使用这些配置。例如,存储CNI网络插件配置,使Flannel能够正确配置容器网络。

  • DaemonSet (守护进程集)

场景:需要在集群的每个节点上运行相同的Pod副本时使用。例如,网络插件需要在每个节点上部署以确保节点间通信。

  • 容器亲和性和容忍设置

场景:确保Pod调度到特定类型的节点上,并能够在有污点的节点上运行。例如,网络组件需要在所有Linux节点上运行,即使节点被标记为不可调度。

  • 初始化容器 (initContainers)

场景:在主容器启动前执行初始化任务。例如,在Flannel运行前先安装必要的CNI插件和配置文件。

  • 卷挂载 (volumeMounts)

场景:将存储资源挂载到容器中,使容器能够读写这些资源。例如,Flannel需要访问主机上的特定目录来安装CNI插件。

  • 主机路径卷 (hostPath)

场景:让容器访问宿主机文件系统上的目录或文件。例如,网络插件需要将配置写入主机的CNI目录。

三、kubectl常用命令详解

3.1 查看类

# 获取节点和服务版本信息
kubectl get nodes

# 获取节点和服务版本信息,并查看附加信息
kubectl get nodes -o wide

# 获取 pod 信息,默认是 default 名称空间
kubectl get pod

# 获取 pod 信息,默认是 default 名称空间,并查看附加信息【如:pod 的 IP 及在哪个节点运行】
kubectl get pod -o wide

# 获取指定名称空间的 pod
kubectl get pod -n kube-system

# 获取指定名称空间中的指定 pod
kubectl get pod -n kube-system podName
[root@k8s-master-01 ~]# kubectl get pod -n kube-system kube-apiserver-k8s-master-01
NAME                           READY   STATUS    RESTARTS   AGE
kube-apiserver-k8s-master-01   1/1     Running   1          2d1h

# 获取所有名称空间的 pod
kubectl get pod -A

# 查看 pod 的详细信息,以 yaml 格式或 json 格式显示
kubectl get pods -o yaml
kubectl get pods -o json

# 查看 pod 的标签信息
kubectl get pod -A --show-labels

#根据 Selector(label query)来查询 pod
kubectl get pod -A --selector="k8s-app=kube-dns"

# 查看运行 pod 的环境变量
kubectl exec podName env

# 查看指定 pod 的日志
kubectl logs -f --tail 500 -n kube-system kube-apiserver-k8s-master

# 查看所有名称空间的 service 信息
kubectl get svc -A

# 查看指定名称空间的 service 信息
kubectl get svc -n kube-system

# 查看 componentstatuses 信息
kubectl get cs

# 检查具体的组件状态
kubectl get pods -n kube-system -l component=kube-controller-manager
kubectl get pods -n kube-system -l component=kube-scheduler

# 查看所有 configmaps 信息
kubectl get cm -A

# 查看所有 serviceaccounts 信息
kubectl get sa -A

# 查看所有 daemonsets 信息
kubectl get ds -A
-----------------------
# 查看所有 deployments 信息
kubectl get deploy -A

# 查看所有 replicasets 信息
kubectl get rs -A

# 查看所有 statefulsets 信息
kubectl get sts -A

# 查看所有 jobs 信息
kubectl get jobs -A

# 查看所有 ingresses 信息
kubectl get ing -A

#查看有哪些名称空间
kubectl get ns

# 查看 pod 的描述信息
kubecti describe pod podName
kubectl describe pod -n kube-system kube-apiserver-k8s-master

#查看指定名称空间中指定 deploy 的描述信息
kubectl describe deploy -n kube-system coredns

# 查看 node 或 pod 的资源使用情况 # 需要 heapster 或 metrics-server 支持
kubectl top node
kubectl top pod

#查看集群信息
kubectl cluster-info
kubectl cluster-info dump

#查看各组件信息【172.16.1.110为master机器】
kubectl -s https://172.16.1.110:6443 get componentstatuses

3.2 操作类

# 创建yaml文件
vim demo.yaml
# 指定使用的 Kubernetes API 版本
apiVersion: v1
# 定义资源类型为 Pod
kind: Pod
# 定义 Pod 的元数据信息
metadata:
  # Pod 的名称
  name: nginx-pod
  # Pod 的标签,用于资源选择和分组
  labels:
    app: nginx
# 定义 Pod 的规格
spec:
  # 定义 Pod 中的容器列表
  containers:
  # 定义第一个容器
  - name: nginx    # 容器的名称
    image: nginx:1.14.2    # 使用的容器镜像
    # 定义容器需要暴露的端口
    ports:
    - containerPort: 80    # 容器内部监听的端口号 

# 创建资源
kubectl create -f demo.yaml

# 应用资源
kubectl apply -f demo.yaml

# 应用资源,该目录下的所有.yaml,.yml,或.json文件都会被使用
kubectl apply -f

# 创建test 名称空间
kubectl create namespace test

# 删除资源
kubectl delete -f demo.yaml
kubectl delete -f

# 删除指定的 pod
kubectl delete pod podName

# 删除指定名称空间的指定 pod
kubectl delete pod -n test podName

# 删除其他资源
kubectl delete svc svcName
kubectl delete deploy deployName
kubectl delete ns nsName

# 强制删除
kubectl delete pod podName -n nsName --grace-period=0 ---force
kubectl delete pod podName -n nsName --grace-period=1
kubectl delete pod podName -n nsName --now

# 编辑资源
kubectl edit pod podName

3.3 进阶操作

# kubectlexec:进入pod启动的容器
kubectl exec -it podName -n nsName /bin/sh #进入容器

# kubectl label:添加 label值
## 为指定节点添加标签
kubectllabel nodesk8s-node01zone=north 
## 为指定节点删除标签
kubectl label nodes k8s-node01 zone-
## 为指定 pod 添加标签
kubectl label pod podName-n nsName role-name=test 
## 修改lable标签值
kubectl label pod podName -n nsName role-name=dev --overwrite 
## 删除lable标签
kubectl label pod podName -n nsName role-name- 

# kubectl 滚动升级;
## 通过配置文件滚动升级
kubectl apply -f myapp-deployment-v2.yaml 
## 通过命令滚动升级
kubectl set image deploy/myapp-deployment myapp="registry.cn-beijing.aliyuncs.com/google_registry/myapp:v3"
## pod回滚到前一个版本
kubectl rollout undo deploy/myapp-deployment 或者 kubectl rollout undo deploy myapp-deployment 
## 回滚到指定历史版本
kubectl rollout undo deploy/myapp-deployment --to-revision=2 

# kubectl scale:动态伸缩
## 动态伸缩
kubectl scale deploy myapp-deployment --replicas=5 
## 动态伸缩【根据资源类型和名称伸缩,其他配置
kubectl scale--replicas=8-f myapp-deployment-v2.yaml 

四、容器与Pod资源

4.1 什么是Pod

Pod是Kubernetes(K8s)中最基本的概念,可以把它想象成一个小型公寓。在这个公寓里,可以住多个容器(比如Docker容器),它们共享同一个网络地址和存储空间,就像室友共享客厅和厨房一样。这种设计让不同的应用容器可以轻松通信和共享资料,例如一个容器负责展示网页(Nginx),而另一个容器负责处理后台数据,它们虽然是独立开发的,但在一个Pod里可以无缝协作提供完整的服务。

Kubernetes根据应用的不同需求,提供了多种控制器来管理这些Pod。就像不同工种的工人需要不同的管理方式一样,长期运行的应用(如网站)用Deployment来管理,定时任务用Job,需要在每个节点都运行的服务用DaemonSet,而有状态的应用(如数据库)则用StatefulSet。这些控制器确保Pod按照我们的要求正确运行、扩展和恢复,是K8s强大功能的核心。

4.2 编写一个简单的资源清单yaml

# API版本声明,v1是Kubernetes核心API的稳定版本
apiVersion: v1
# 资源类型,这里定义的是一个Pod
kind: Pod
# 元数据部分,包含Pod的名称、标签等信息
metadata: 
  # Pod的名称,用于标识和引用这个Pod
  name: test-pod
  # 标签,用于分类和选择Pod,便于管理和被选择器(selector)选中
  labels:
    app: test-pod
# 规格说明,定义Pod的具体配置
spec:
  # 容器列表,定义Pod中包含的所有容器
  containers:
    # 第一个容器
    - name: nginx     # 容器名称,用于在Pod内部引用
      image: nginx    # 容器镜像,指定使用nginx官方镜像
    # 第二个容器
    - name: tomcat    # 容器名称
      image: tomcat   # 容器镜像,指定使用tomcat官方镜像
  # 注意:这两个容器将在同一个Pod中运行,共享网络命名空间,可以通过localhost互相访问

#######################################################################
# 创建一个新的集群资源
kubectl apply -f test.yaml

# 查看运行的pods,需要等个两分钟左右
[root@k8s-master-01 k8s_yaml]# kubectl get pods
NAME       READY   STATUS    RESTARTS   AGE
test-pod   2/2     Running   0          3m58s

4.3 Pod作用、管理、持久性以及生命周期

4.3.1 Pod作用

  • 最小部署单元: Pod是Kubernetes中最基础的部署单位,一个Pod可以包含一个或多个容器。
  • 资源共享: Pod内的所有容器共享同一网络命名空间和IP地址,容器间可通过localhost直接通信。
  • 存储共享: Pod内容器可共享挂载的存储卷,便于数据交换。
  • 生命周期一致: Pod内所有容器同时创建、同时销毁,生死与共。
  • 协同工作: 适合需紧密协作的应用组件,如前端+后端或主应用+辅助工具。
  • 资源隔离: 不同Pod之间网络和资源相互隔离,保证应用安全性。

4.3.2 Pod管理

  • Deployment控制器: 最常用的控制器,用于管理无状态应用(如网站、API服务)。它能自动创建多个Pod副本,确保高可用,并支持滚动更新和回滚。
  • StatefulSet控制器: 专为有状态应用(如数据库)设计,提供稳定的网络标识(固定的Pod名称和DNS)和持久化存储,确保数据不丢失。
  • DaemonSet控制器: 确保集群中每个节点都运行一个Pod副本,适用于节点监控、日志收集等基础服务。
  • Job/CronJob控制器: 用于一次性或定时任务,任务完成后Pod会自动终止。Job负责一次性任务,CronJob负责定期执行的任务。
  • ReplicaSet: 确保指定数量的Pod副本在任何时候都处于运行状态,通常由Deployment自动管理。

4.3.3 Pod数据持久性

在Kubernetes世界里,Pod就像是一个临时工人,随时可能被解雇或重新安排工作。当集群遇到节点故障、资源不足或进行维护时,Pod会被销毁并在其他地方重建,而Pod内部存储的所有数据都会随之丢失。这就像你的手机没电关机了,没保存的文档就会消失一样。

要解决这个问题,我们需要使用"持久卷"(PersistentVolume)和"持久卷声明"(PersistentVolumeClaim)。这相当于给Pod配备了一个独立的云盘,即使Pod被销毁重建,数据仍然安全地存储在这个云盘上。新的Pod启动后可以重新挂载这个云盘,继续使用之前的数据。对于重要应用如数据库、文件服务器等,这种持久化存储机制是必不可少的。

4.3.4 Pod的生命周期(简化版)

Pod的生命周期就像一个员工从入职到离职的全过程

  • 创建阶段(Pending):Pod被创建后首先处于Pending状态,此时Kubernetes正在为Pod寻找合适的节点并分配资源,类似于新员工等待分配工位。
  • 初始化阶段:Pod被调度到节点后,会先运行Init容器(如果有),这些容器按顺序执行完成一些准备工作,相当于员工入职培训。
  • 运行阶段(Running):主容器启动并开始工作,此时Pod处于Running状态。Kubernetes会根据配置进行就绪检查(Readiness Probe)和存活检查(Liveness Probe),确保应用正常运行,就像主管定期检查员工工作状态。
  • 终止阶段(Succeeded/Failed):当Pod被删除或节点出现问题时,Pod进入终止过程。Kubernetes会先发送SIGTERM信号给容器进程,给应用留出优雅关闭的时间(默认30秒),之后才会强制终止(SIGKILL),类似于员工有序交接后离职。

注意:

Pod还有重启策略(RestartPolicy)控制容器失败后的行为:Always(默认,总是重启)、OnFailure(仅在失败时重启)或Never(从不重启)。

4.3.5 Pod的生命周期(图解版)

+-------------------------------------------------------------------------------------------------------------+
|                                         Kubernetes Pod 生命周期详解                                             |
+-------------------------------------------------------------------------------------------------------------+
|                                                                                                              |
|  +-------------+           +---------------+           +---------------+           +---------------+        |
|  |   创建阶段   |           |    初始化阶段   |           |    运行阶段     |           |    终止阶段     |        |
|  |  (Creation) |---------->| (Initialization)|--------->|   (Running)    |---------->| (Termination) |        |
|  +------+------+           +-------+---------+           +-------+---------+           +-------+---------+        |
|         |                          |                             |                             |                |
+---------|--------------------------|-----------------------------|-----------------------------|----------------+
          |                          |                             |                             |
          ↓                          ↓                             ↓                             ↓
+------------------+      +--------------------+        +--------------------+       +--------------------+
| 1. 用户创建Pod对象 |      | 1. 运行Init容器     |        | 1. 并行启动主容器    |       | 1. Pod标记为终止中  |
| ・通过YAML/命令   |      | ・按顺序执行        |        | ・所有业务容器同时启动|       | ・删除命令或节点故障 |
|                  |      | ・每个必须成功才继续 |        |                    |       |                    |
| 2. API服务器验证  |      | 2. 挂载存储卷       |        | 2. 执行PostStart钩子 |       | 2. 执行PreStop钩子  |
| ・检查格式和权限   |      | ・持久卷(PV/PVC)    |        | ・容器启动时立即执行  |       | ・优雅关闭的机会    |
|                  |      | ・ConfigMap        |        | ・与容器启动并行     |       | ・清理连接和资源    |
| 3. 调度器选择节点  |      | ・Secret           |        | 3. 健康检查开始      |       | 3. 发送SIGTERM信号 |
| ・资源需求匹配     |      | 3. 网络设置         |        | ・存活检测(Liveness) |       | ・给进程优雅终止时间 |
| ・亲和性/反亲和性  |      | ・创建pause容器     |        | ・应用是否崩溃       |       | ・默认30秒宽限期    |
| ・污点和容忍       |      | ・配置网络命名空间   |        | 4. 就绪检测(Readiness)|      | 4. 强制终止(SIGKILL)|
|                  |      | ・分配Pod IP地址    |        | ・应用是否可接收流量  |       | ・宽限期后仍在运行   |
| 4. Kubelet确认   |      |                    |        | ・影响服务发现       |       | ・强制结束进程      |
| ・准备节点环境     |      |                    |        | 5. 启动检测(Startup) |       | 5. 资源回收        |
| ・拉取镜像         |      |                    |        | ・慢启动应用专用      |       | ・删除容器         |
|                  |      |                    |        | ・防止过早重启        |       | ・释放网络资源      |
|                  |      |                    |        |                    |       | ・解除卷挂载       |
|                  |      |                    |        |                    |       | ・从etcd中移除     |
+------------------+      +--------------------+        +--------------------+       +--------------------+
          |                          |                             |                             |
          |                          |                             |                             |
          v                          v                             v                             v
+---------+--------------------------+-----------------------------+-----------------------------+-------+
|   Pod状态:  Pending               |        Running              |        Terminating           |        |
+-------------------------------------------------------------------------------------------------+
|                                      Pod可能的重启策略:                                          |
|           Always(默认,总是重启) | OnFailure(失败时重启) | Never(从不重启)                        |
+-------------------------------------------------------------------------------------------------+

4.4 RestartPolicy重启策略

4.4.1 Pod重启策略是什么?

Pod重启策略(RestartPolicy)就像是给容器设置的"故障应对计划"。当容器出现问题时,它告诉Kubernetes应该怎么办 - 是自动重启容器,还是让它就此停止。这个策略应用于Pod内的所有容器,由kubelet(节点上的"管家")负责执行。

4.4.2 三种重启策略

  1. Always(总是重启)

    • 容器挂了就立即重启
    • 这就像固执的闹钟,无论怎样都会响起来
    • Kubernetes 默认使用这种策略,确保服务始终运行
  2. OnFailure(失败才重启)

    • 只有当容器异常退出(退出码不为0)时才重启
    • 类似于 “如果任务失败才需要重做”
    • 适合那些成功完成就应该停止的任务
  3. Never(永不重启)

    • 无论发生什么,容器挂了就是挂了,不会重启
    • 像是 “一次性” 的任务,完成或失败后就结束了
    • 适合那些不应该重复执行的操作

重启间隔

  • 为避免频繁重启消耗资源,kubelet使用延迟机制:
  • 时间间隔按指数增长: 第一次重启后等10秒,然后20秒,40秒,80秒…
  • 最长等待时间是5分钟
  • 成功运行10分钟后,计时器重置

4.4.3 Pod与控制器的关系

  1. ReplicationController / Deployment

    • 通常使用 Always​,确保服务持续运行
  2. Job

    • 通常使用 OnFailure​,任务成功完成后不需要重启
  3. DaemonSet

    • 通常使用 Always​,确保每个节点上的服务持续运行
  4. 静态 Pod(直接由 kubelet 管理)

    • 根据具体需求设置

4.5 钩子PostStart、PreStop

4.5.1什么是Pod钩子?

钩子就像是容器生命中的"仪式",在特定时刻触发执行特定操作。Kubernetes提供了两种钩子:容器启动时的"PostStart"和容器结束前的"PreStop"。

4.5.2 PostStart钩子 - 容器的"开机仪式"

  • 触发时机:容器创建后立即执行

  • 执行方式:与容器主进程 (ENTRYPOINT) 并行执行,不会等待主进程

  • 常见用途

    • 部署必要资源
    • 准备运行环境
    • 注册服务
    • 下载配置文件
  • 注意事项

    • 如果钩子执行时间过长或失败,容器无法达到 Running 状态
    • 失败会导致容器被杀死,然后根据重启策略决定下一步
  • 形象理解:就像你开机后立即运行的自启动程序,但如果这个程序卡住,你的电脑可能就 “卡死” 了

4.5.3 PreStop钩子 - 容器的"关机仪式"

  • 触发时机:容器终止前执行

  • 执行方式:同步阻塞执行,必须完成才会继续终止流程

  • 常见用途

    • 优雅关闭应用程序
    • 保存状态和数据
    • 通知其他系统自己即将离线
    • 清理临时资源
  • 注意事项

    • 如果钩子执行卡住,Pod 会一直停留在 Running 状态
    • 即使钩子执行失败,容器仍会被终止
  • 形象理解:像关机前的保存文档提示,系统会等你保存完毕才真正关机

4.6 Pod的资源清单详解

# 指定使用的Kubernetes API版本,v1是最稳定的核心API版本
apiVersion: v1
# 声明资源类型,这里是创建一个Pod
kind: Pod
# 元数据部分,包含Pod的名称、标签等基本信息
metadata:
  # Pod的名称,在同一命名空间内必须唯一,用于引用这个Pod
  name: my-pod-example
  # 命名空间,用于资源隔离,如不指定则使用"default"
  namespace: default
  # 标签,键值对形式,用于分类和筛选Pod,是非常重要的组织资源的方式
  labels:
    app: myapp
    tier: frontend
    version: v1
  # 注解,键值对形式,用于存储额外信息,但不用于筛选Pod
  annotations:
    description: "这是一个Pod例子"
    contact: "[email protected]"

# 规格说明,定义Pod的具体配置内容
spec:
  # 重启策略,控制Pod中容器失败后如何处理
  # Always(默认):总是重启 | OnFailure:失败才重启 | Never:从不重启
  restartPolicy: Always
  
  # 容器列表,定义Pod中包含的所有容器
  containers:
  - # 容器名称,在Pod内必须唯一
    name: main-container
    # 容器镜像,指定要使用的Docker镜像
    image: nginx:1.20
    # 镜像拉取策略:Always(总是拉取) | IfNotPresent(本地没有才拉取) | Never(只用本地)
    imagePullPolicy: IfNotPresent
    
    # 容器启动命令,会覆盖镜像默认命令
    command: ["/bin/bash"]
    # 命令参数,传递给启动命令
    args: ["-c", "echo Hello Kubernetes; nginx -g 'daemon off;'"]
    
    # 定义容器端口
    ports:
    - # 容器内部开放的端口号
      containerPort: 80
      # 端口名称,方便在服务中引用
      name: http
      # 端口使用的协议,默认TCP
      protocol: TCP
    
    # 环境变量设置
    env:
    - # 环境变量名称
      name: DB_HOST
      # 直接指定的环境变量值
      value: "mysql-service"
    - name: APP_MODE
      value: "production"
    
    # 资源限制和请求
    resources:
      # 请求资源(保证可用),调度器确保Pod调度到满足这些请求的节点上
      requests:
        # CPU请求,可以是绝对值(如"1")或相对值(如"100m",表示0.1核)
        cpu: "100m"
        # 内存请求,可以使用Mi(兆)或Gi(吉)为单位
        memory: "128Mi"
      # 资源限制(上限),容器使用的资源不能超过这个值
      limits:
        # CPU限制,容器使用的CPU会被限制在这个值以内
        cpu: "500m"
        # 内存限制,如果容器尝试使用更多内存,可能会被终止
        memory: "256Mi"
    
    # 存活探针(Liveness Probe),检查容器是否仍在运行,失败则重启容器
    livenessProbe:
      # HTTP请求方式的探测
      httpGet:
        # 请求的路径
        path: /health
        # 请求的端口
        port: 80
      # 首次检查等待时间(容器启动后多久开始探测)
      initialDelaySeconds: 15
      # 检查间隔时间
      periodSeconds: 10
      # 超时时间
      timeoutSeconds: 2
      # 连续成功阈值
      successThreshold: 1
      # 连续失败阈值,达到后重启容器
      failureThreshold: 3
    
    # 就绪探针(Readiness Probe),检查容器是否准备好接收流量
    readinessProbe:
      # TCP套接字方式的探测,检查端口是否可访问
      tcpSocket:
        port: 80
      initialDelaySeconds: 5
      periodSeconds: 10
    
    # 生命周期钩子
    lifecycle:
      # 容器启动后立即执行的钩子
      postStart:
        exec:
          command: ["/bin/sh", "-c", "echo 容器已启动 >> /tmp/poststart.log"]
      # 容器终止前执行的钩子
      preStop:
        exec:
          command: ["/bin/sh", "-c", "nginx -s quit; echo 容器即将终止 >> /tmp/prestop.log"]
    
    # 数据卷挂载
    volumeMounts:
    - # 挂载的数据卷名称,必须与下面volumes中声明的名称匹配
      name: config-volume
      # 容器内的挂载路径
      mountPath: /etc/nginx/conf.d
      # 是否只读,true表示容器只能读取不能修改
      readOnly: true
    - name: data-volume
      mountPath: /var/www/html
  
  # Pod级别的安全上下文,定义权限和访问控制
  securityContext:
    # 运行容器的用户ID
    runAsUser: 1000
    # 容器是否可以提升权限
    allowPrivilegeEscalation: false
  
  # 镜像拉取密钥,用于从私有仓库拉取镜像
  imagePullSecrets:
  - name: my-registry-key
  
  # 节点选择器,用于指定Pod应该调度到哪类节点上
  nodeSelector:
    disk: ssd
    region: east
  
  # 数据卷定义
  volumes:
  - # 数据卷名称
    name: config-volume
    # 使用ConfigMap作为数据卷的来源
    configMap:
      name: nginx-config
  - name: data-volume
    # 使用持久卷声明(PVC)作为数据卷来源
    persistentVolumeClaim:
      claimName: my-data-claim

五、命名空间资源

5.1 命名空间简介

命名空间就像是Kubernetes集群中的"虚拟分区"或"隔离区域"。想象一下,你有一栋大楼(Kubernetes集群),命名空间就是里面的不同房间,每个房间可以住不同的租户,互不打扰。

为什么需要命名空间?

举个生活例子:假如你家里只有一个文件柜,家里所有人(爸爸工作文件、妈妈账单、孩子作业)都往里放东西,很快就会混乱不堪。但如果给文件柜分成不同的抽屉,每人专用一个,就能保持整洁有序。

命名空间的重要优势:

  • 隔离环境:可以在同一集群中创建开发、测试、生产的隔离环境
  • 资源划分:不同团队或项目可以使用同一集群而不会互相干扰
  • 访问控制:可以对不同命名空间设置不同的访问权限
  • 资源配额:可以限制各命名空间的资源使用量

5.2 使用命名空间

5.2.1 适用场景

命名空间特别适合多团队、多项目共享一个集群的情况。比如:

  • 一家公司内多个开发团队共用一个K8s集群
  • 同一应用的不同环境(开发/测试/生产)
  • 大型应用的不同组件(前端/后端/数据库)

5.2.2 命名空间的特性

  • 资源范围:资源名称在同一命名空间内必须唯一,但可以在不同命名空间中重复
  • 例如:可以在dev和prod命名空间各自拥有一个名为"mysql"的服务
  • 命名空间隔离:命名空间提供了逻辑隔离,但并非完全的网络隔离
  • 默认情况下,不同命名空间的Pod可以相互通信
  • 可以通过网络策略实现命名空间间的网络隔离
  • 资源限制:每个命名空间可以设置资源配额,限制该空间内可使用的CPU、内存等资源

5.2.3 实用建议

  • 不要为了小项目创建过多命名空间,增加管理复杂度
  • 使用有意义的命名空间名称(如团队名、项目名、环境名)
  • 某些Kubernetes资源是集群级别的,不属于任何命名空间(如节点、持久卷)
  • 优先使用标签(labels)来组织同一命名空间内的资源,而不是创建新的命名空间

如果你是完全的K8s新手,可以先忽略命名空间概念,使用默认的"default"命名空间。随着应用规模增长,再考虑引入命名空间进行组织和隔离。

5.3 列出所有的命名空间

# 列出集群中所有的命名空间
# 可以看到K8s默认创建了几个系统命名空间
[root@k8s-master-01 k8s_yaml]# kubectl get namespaces
NAME              STATUS   AGE
default           Active   4d    # 默认命名空间,未指定时资源会创建在这里
kube-flannel      Active   4d    # 网络插件Flannel使用的命名空间
kube-node-lease   Active   4d    # 存储节点心跳信息的命名空间,用于节点健康检查
kube-public       Active   4d    # 公共资源命名空间,所有用户(包括未认证用户)可读
kube-system       Active   4d    # 系统组件命名空间,存放K8s系统组件(如DNS、调度器等)

# 获取特定命名空间的基本信息
# 这是简单查询单个命名空间的方法
[root@k8s-master-01 k8s_yaml]# kubectl get namespaces default
NAME      STATUS   AGE
default   Active   4d

# 查看特定命名空间的详细信息
# describe命令提供比get命令更详细的资源信息
[root@k8s-master-01 k8s_yaml]# kubectl describe namespaces default
Name:         default            # 命名空间名称
Labels:       <none>             # 没有设置标签
Annotations:  <none>             # 没有设置注解
Status:       Active             # 命名空间处于活跃状态

No resource quota.               # 没有设置资源配额限制,意味着可以无限制使用集群资源
                                 # 生产环境中建议设置配额防止资源耗尽

No LimitRange resource.          # 没有设置默认资源限制,Pod不会有默认的资源请求/限制
                                 # 生产环境建议设置,避免某些Pod消耗过多资源

5.4 默认的命名空间

  • default(默认区域)

    • 功能:未指定命名空间的资源默认被创建在这里
    • 理解:就像不告诉快递员具体房间号,包裹就会被放在大厅前台
    • 适用场景:初学者的所有应用通常都会在这个命名空间中运行
  • kube-public(公共区域)

    • 功能:对所有用户开放(包括未认证用户)的命名空间
    • 理解:相当于公寓的公共休息室或公告栏,所有人都可以进入查看
    • 用途:存放需要公开可见的集群信息、证书和配置
  • kube-system(系统区域)

    • 功能:Kubernetes系统组件的专用命名空间
    • 理解:类似公寓的设备机房和管理办公室,住户通常不需要进入
    • 注意:不建议在该命名空间中运行自己的应用
  • kube-node-lease(节点租约区)

    • 功能:专门存储kubelet节点心跳信息的命名空间
    • 理解:像公寓的"考勤打卡系统",记录各个节点的活跃状态
    • 作用:帮助Kubernetes快速检测节点是否健康,提高集群可靠性

5.5 命名空间的案例

# 方法一:直接使用命令行创建命名空间
kubectl create namespace test1
# 输出:namespace/test1 created

# 方法二:通过YAML文件创建命名空间
# 首先创建YAML配置文件
vim test2.yaml
# YAML文件内容如下:
apiVersion: v1
kind: Namespace
metadata:
  name: test2
  labels:
    name: test2

# 使用apply命令应用YAML文件创建命名空间
kubectl apply -f test2.yaml
# 输出:namespace/test2 created

# 列出所有命名空间
kubectl get ns
# 输出结果显示所有命名空间
[root@k8s-master-01 k8s_yaml]# kubectl get ns
NAME              STATUS   AGE
default           Active   4d1h
kube-flannel      Active   4d1h
kube-node-lease   Active   4d1h
kube-public       Active   4d1h
kube-system       Active   4d1h
test1             Active   4m18s
test2             Active   12s
[root@k8s-master-01 k8s_yaml]# kubectl get namespaces
NAME              STATUS   AGE
default           Active   4d1h
kube-flannel      Active   4d1h
kube-node-lease   Active   4d1h
kube-public       Active   4d1h
kube-system       Active   4d1h
test1             Active   4m24s
test2             Active   18s

# 在指定命名空间中部署应用
# 创建一个nginx部署到test1命名空间
kubectl create deployment --image nginx demo-nginx --namespace=test1
# 输出:deployment.apps/demo-nginx created

# 确认部署在正确的命名空间
kubectl describe deployment demo-nginx --namespace=test1 |grep Namespace
# 输出:Namespace:       test1

# 删除命名空间前,先查看该命名空间中的所有资源
kubectl get all --namespace=test1
# 这会列出test1命名空间中的所有资源

# 删除命名空间(注意:这会删除该命名空间中的所有资源!)
kubectl delete namespaces test1
# 输出:namespace "test1" deleted

六、lable标签资源

6.1 标签介绍

6.1.1 什么是Label?

Label(标签)是Kubernetes中极其重要的概念,简单来说就是"贴在资源上的标识性便利贴"。想象一下,如果你有一大堆文件,你会用彩色标签纸来分类它们—红色标签代表"紧急",绿色代表"已完成"。在K8s中,Label就是这样的电子标签。

6.1.2 Label的核心特性

  • 键值对格式:每个标签都是一个key=value形式的数据

    例如:env=production, app=nginx, tier=frontend

  • 可应用于各种资源:可以贴在几乎所有K8s资源上

    节点(Node)、容器组(Pod)、服务(Service)、部署(Deployment)等

  • 无数量限制:

    一个资源可以有任意多个标签(比如既标记环境又标记应用类型)

    同一个标签可以贴在多个资源上(如多个Pod都标记为app=nginx)

  • 灵活管理:

    可以在创建资源时定义

    也可以在资源创建后动态添加或删除

为什么标签如此重要?

想象K8s集群是一个大型仓库,里面存放着成千上万的集装箱(Pod)。如果没有标签,要找出特定的一组集装箱几乎是不可能的任务。通过标签,我们可以:

  • 多维度组织资源:按环境(dev/test/prod)、按应用(nginx/mysql)、按团队(team-a/team-b)等

  • 资源选择:快速找到所有具有特定标签的资源

    “找出所有生产环境的前端应用”

  • 批量操作:对一组相同标签的资源执行操作

    “更新所有test环境的应用”

  • 关联资源:服务可以通过标签选择器关联到Pod

6.2 常见标签

  1. 版本标签:用于标识应用发布状态

    • release:stable(稳定版)
    • release:canary(测试版)
  2. 环境标签:区分不同运行环境

    • environment:dev(开发环境)
    • environment:production(生产环境)
  3. 架构标签:标识组件在系统中的角色

    • tier:frontend(前端组件)
    • tier:backend(后端组件)
    • tier:middleware(中间件)
  4. 分区标签:按客户或租户划分资源

    • partition:customerA(A客户资源)
    • partition:customerB(B客户资源)
  5. 质量管控标签:指示更新和维护频率

    • track:daily(每日更新项目)
    • track:weekly(每周更新项目)

6.3 标签使用案例

# 创建YAML配置文件定义一个Pod
vim test3.yml
# 以下是YAML文件内容:
apiVersion: v1               # 使用Kubernetes API v1版本
kind: Pod                    # 资源类型为Pod
metadata:                    # 元数据部分
  name: test-tag             # Pod名称为test-tag
  labels:                    # 标签部分
    release: stable          # 添加一个标签release=stable,表示这是稳定版
spec:                        # 规格说明部分
  containers:                # 容器列表
    - name: nginx            # 容器名称为nginx
      image: nginx           # 使用nginx镜像

# 使用kubectl apply命令应用YAML文件创建Pod
kubectl apply -f test3.yml 

# 查看所有Pod并显示它们的标签
kubectl get pod --show-labels
# 输出显示两个Pod:
# test-pod: 之前创建的Pod,有标签app=test-pod
# test-tag: 刚创建的Pod,有标签release=stable
# NAME       READY   STATUS    RESTARTS   AGE     LABELS
# test-pod   2/2     Running   0          6h31m   app=test-pod
# test-tag   1/1     Running   0          12s     release=stable

# 给test-tag Pod添加新标签app=tag
kubectl label pod test-tag app=tag
# 命令成功执行,输出确认标签已添加
# pod/test-tag labeled

# 再次查看Pod列表和标签,确认新标签已添加
kubectl get pod --show-labels
# 输出显示test-tag现在有两个标签:release=stable和app=tag
# NAME       READY   STATUS    RESTARTS   AGE     LABELS
# test-pod   2/2     Running   0          6h38m   app=test-pod
# test-tag   1/1     Running   0          7m25s   app=tag,release=stable

# 从test-tag Pod删除app标签
# 注意语法:标签名后面加减号"-"表示删除该标签
kubectl label pod test-tag app-
# 命令成功执行,输出确认标签已移除
# pod/test-tag labeled

# 再次查看Pod列表和标签,确认app标签已被删除
kubectl get pod --show-labels
# 输出显示test-tag现在只有一个标签:release=stable
# NAME       READY   STATUS    RESTARTS   AGE     LABELS
# test-pod   2/2     Running   0          6h39m   app=test-pod
# test-tag   1/1     Running   0          7m56s   release=stable

七、控制器资源

7.1 控制器的基本介绍和类型

7.1.1 控制器介绍

通俗解释: 在Kubernetes(K8s)的世界里,控制器就像是一群勤劳的"管理员",负责照看和管理我们的应用程序。想象一下,如果应用程序是工厂里的工人(Pod),那么控制器就是工厂的主管。

  1. 控制器是什么?

控制器是K8s中的核心概念,它们就像自动驾驶系统,不需要人工干预也能保证你的应用正常运行。它们主要负责:

  • 保持状态:确保实际运行的Pod数量与你期望的一致,如果有Pod挂了,会自动创建新的
  • 控制行为:定义Pod如何更新、如何伸缩(增加或减少Pod数量)
  • 管理副本:维护指定数量的应用实例,确保高可用性
  1. 控制器如何工作?

    控制器通过"标签"(Label)来识别和管理Pod,就像主管通过工号识别工人一样。比如:

    • 控制器会找出所有带有特定标签的Pod(比如"app=nginx")
    • 然后确保这些Pod都按照预期工作
    • 如果Pod数量不足或有Pod不健康,控制器会自动调整

7.1.2 常见控制器类型

  1. Deployment(部署)控制器

    • 生活例子:想象一个快餐连锁店的分店。总部不关心每家店具体在哪个位置,只关心总共开了多少家,保证数量足够服务顾客即可。

    • 特点

      • 适合部署没有"记忆"的应用,比如网站前端、API服务。
      • 可以随机部署在集群任何节点上。
      • 强调的是"有多少个"而不是"在哪里"。
      • 最常用的控制器,日常工作中使用最多。
    • 通俗解释:就像派送外卖员,你只关心有5个人在送外卖,不关心具体是哪5个人,有人请假了就再找一个顶上。

  2. DaemonSet(守护进程集)控制器

    • 生活例子:小区的门卫保安,每个小区门口必须有且只有一个保安亭。

    • 特点

      • 在每个节点上运行且只运行一个Pod。
      • 新节点加入集群自动部署,节点删除自动清理。
      • 常用于各种监控组件、日志收集工具等。
    • 通俗解释:就像每台电脑都需要安装的杀毒软件,不能少装也不能重复装,电脑买回来就装上,电脑丢了它也就跟着没了。举例的zabbix-agent就是一种监控代理,需要部署在每台服务器上收集监控数据。

  3. StatefulSet(有状态集)控制器

    • 生活例子:一个乐队的演出,贝斯手、鼓手、主唱必须按固定顺序出场,且每个位置只能有特定的人。

    • 特点

      • 专为有"记忆"的应用设计,如数据库、消息队列。
      • Pod有固定标识和启动顺序。
      • 确保数据一致性,有序部署、扩展、删除。
    • 通俗解释:就像班级里的学生,每个学生都有固定的座位号和姓名,不能随便调换,上学放学也要按顺序进出教室。数据库主从架构就需要这种控制器,因为从库必须在主库启动后才能启动。

7.2 Deployment案例

# 创建Deployment的YAML配置文件
vim test5.yml
# YAML内容解析:
apiVersion: apps/v1           # 使用apps/v1 API版本,Deployment属于apps API组
kind: Deployment              # 资源类型为Deployment,这是最常用的控制器类型
metadata:                     # 元数据部分
  name: deployment            # Deployment名称
spec:                         # 规格说明
  replicas: 1                 # 指定副本数量为1,即维护1个Pod副本
  selector:                   # 选择器,用于选择要管理的Pod
    matchLabels:              # 标签匹配条件
      release: stable         # 选择带有release=stable标签的Pod
  template:                   # Pod模板,定义要创建的Pod规格
    metadata:                 # Pod的元数据
      name: test-tag          # Pod名称(注意:实际创建时会被忽略,生成的Pod名有前缀)
      labels:                 # Pod标签
        release: stable       # 必须与selector中的matchLabels匹配
    spec:                     # Pod的规格
      containers:             # 容器列表
        - name: nginx         # 容器名称
          image: nginx        # 使用nginx官方镜像

# 应用配置文件创建Deployment
kubectl apply -f test5.yml

# 查看创建的Deployment
# NAME: Deployment名称
# READY: 已就绪的副本数/期望的副本数(1/1表示已就绪1个,期望1个)  
# UP-TO-DATE: 已更新到最新配置的副本数
# AVAILABLE: 当前可用的副本数 
# AGE: Deployment创建后经过的时间
kubectl get deployments.apps
# NAME         READY   UP-TO-DATE   AVAILABLE   AGE
# deployment   1/1     1            1           44s

# 再次应用配置文件,并添加--record参数
# --record参数会记录当前命令,用于后续查看变更历史
kubectl apply -f test5.yml --record
# deployment.apps/deployment configured

# 查看Deployment的变更历史记录
# REVISION: 版本号
# CHANGE-CAUSE: 变更原因,记录执行的命令
kubectl rollout history deployment deployment
# deployment.apps/deployment 
# REVISION  CHANGE-CAUSE
# 1         kubectl apply --filename=test5.yml --record=true

# 查看当前运行的所有Pod
# 可以看到Deployment创建的Pod名称格式为:Deployment名-ReplicaSet标识符-随机字符串
kubectl get pod
# NAME                          READY   STATUS    RESTARTS   AGE
# deployment-5849786498-7qn6l   1/1     Running   0          2m59s

# 详细查看Deployment信息
kubectl describe deployments.apps deployment
# Name: Deployment名称
# Namespace: 命名空间
# CreationTimestamp: 创建时间
# Labels: 标签(无)
# Annotations: 注解,包括版本和执行的命令
# Selector: Pod选择器
# Replicas: 副本状态(期望数/已更新数/总数/可用数/不可用数)
# StrategyType: 更新策略(RollingUpdate表示滚动更新)
# RollingUpdateStrategy: 滚动更新参数(最大不可用25%,最大超出25%)
# Pod Template: Pod模板定义
# Conditions: 当前状态条件
# OldReplicaSets: 旧的ReplicaSet(无)
# NewReplicaSet: 当前使用的ReplicaSet
# Events: 相关事件记录,包括副本集扩展事件


# 使用'-w'(watch)参数监视Pod状态变化,这会持续显示Pod状态的实时更新
kubectl get pod -w

# - 3个是deployment控制器创建的Pod(名称以deployment-开头)
# - test-pod和test-tag是之前创建的独立Pod
# NAME                          READY   STATUS    RESTARTS   AGE
# deployment-5849786498-4qk44   1/1     Running   0          11s
# deployment-5849786498-7qn6l   1/1     Running   0          10m
# deployment-5849786498-fpr4h   1/1     Running   0          11s

# 缩减deployment的副本数到1个(之前可能是3个)
kubectl scale deployment/deployment --replicas=1
# 输出表明操作成功
# deployment.apps/deployment scaled

# 使用patch命令直接修改deployment的replica数量为10
# patch命令允许部分更新资源,不需要修改整个YAML文件
kubectl patch deployments.apps deployment -p '{"spec":{"replicas":10}}'
# 操作成功
# deployment.apps/deployment patched

# 编辑之前的YAML文件,修改副本数为3
vim test5.yml
# YAML内容解析:
apiVersion: apps/v1           # 使用apps/v1 API版本,Deployment属于apps API组
kind: Deployment              # 资源类型为Deployment,这是最常用的控制器类型
metadata:                     # 元数据部分
  name: deployment            # Deployment名称
spec:                         # 规格说明
  replicas: 3                 # 指定副本数量为3,即维护3个Pod副本
  selector:                   # 选择器,用于选择要管理的Pod
    matchLabels:              # 标签匹配条件
      release: stable         # 选择带有release=stable标签的Pod
  template:                   # Pod模板,定义要创建的Pod规格
    metadata:                 # Pod的元数据
      name: test-tag          # Pod名称(注意:实际创建时会被忽略,生成的Pod名有前缀)
      labels:                 # Pod标签
        release: stable       # 必须与selector中的matchLabels匹配
    spec:                     # Pod的规格
      containers:             # 容器列表
        - name: nginx         # 容器名称
          image: nginx        # 使用nginx官方镜像
 
# 应用更新后的YAML文件,将副本数从10减少到3
kubectl apply -f test5.yml 
# 操作成功
# deployment.apps/deployment configured

# 再次监视Pod状态
# 这时只有3个deployment的Pod了,说明缩容成功(从10个减少到3个)
kubectl get pod -w
# NAME                          READY   STATUS    RESTARTS   AGE
# deployment-5849786498-4qk44   1/1     Running   0          4m9s
# deployment-5849786498-925xb   1/1     Running   0          116s
# deployment-5849786498-gm2zq   1/1     Running   0          116s