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 三种重启策略
-
Always(总是重启)
- 容器挂了就立即重启
- 这就像固执的闹钟,无论怎样都会响起来
- Kubernetes 默认使用这种策略,确保服务始终运行
-
OnFailure(失败才重启)
- 只有当容器异常退出(退出码不为0)时才重启
- 类似于 “如果任务失败才需要重做”
- 适合那些成功完成就应该停止的任务
-
Never(永不重启)
- 无论发生什么,容器挂了就是挂了,不会重启
- 像是 “一次性” 的任务,完成或失败后就结束了
- 适合那些不应该重复执行的操作
重启间隔
- 为避免频繁重启消耗资源,kubelet使用延迟机制:
- 时间间隔按指数增长: 第一次重启后等10秒,然后20秒,40秒,80秒…
- 最长等待时间是5分钟
- 成功运行10分钟后,计时器重置
4.4.3 Pod与控制器的关系
-
ReplicationController / Deployment
- 通常使用
Always
,确保服务持续运行
- 通常使用
-
Job
- 通常使用
OnFailure
,任务成功完成后不需要重启
- 通常使用
-
DaemonSet
- 通常使用
Always
,确保每个节点上的服务持续运行
- 通常使用
-
静态 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 常见标签
-
版本标签:用于标识应用发布状态
- release:stable(稳定版)
- release:canary(测试版)
-
环境标签:区分不同运行环境
- environment:dev(开发环境)
- environment:production(生产环境)
-
架构标签:标识组件在系统中的角色
- tier:frontend(前端组件)
- tier:backend(后端组件)
- tier:middleware(中间件)
-
分区标签:按客户或租户划分资源
- partition:customerA(A客户资源)
- partition:customerB(B客户资源)
-
质量管控标签:指示更新和维护频率
- 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),那么控制器就是工厂的主管。
- 控制器是什么?
控制器是K8s中的核心概念,它们就像自动驾驶系统,不需要人工干预也能保证你的应用正常运行。它们主要负责:
- 保持状态:确保实际运行的Pod数量与你期望的一致,如果有Pod挂了,会自动创建新的
- 控制行为:定义Pod如何更新、如何伸缩(增加或减少Pod数量)
- 管理副本:维护指定数量的应用实例,确保高可用性
-
控制器如何工作?
控制器通过"标签"(Label)来识别和管理Pod,就像主管通过工号识别工人一样。比如:
- 控制器会找出所有带有特定标签的Pod(比如"app=nginx")
- 然后确保这些Pod都按照预期工作
- 如果Pod数量不足或有Pod不健康,控制器会自动调整
7.1.2 常见控制器类型
-
Deployment(部署)控制器
-
生活例子:想象一个快餐连锁店的分店。总部不关心每家店具体在哪个位置,只关心总共开了多少家,保证数量足够服务顾客即可。
-
特点:
- 适合部署没有"记忆"的应用,比如网站前端、API服务。
- 可以随机部署在集群任何节点上。
- 强调的是"有多少个"而不是"在哪里"。
- 最常用的控制器,日常工作中使用最多。
-
通俗解释:就像派送外卖员,你只关心有5个人在送外卖,不关心具体是哪5个人,有人请假了就再找一个顶上。
-
-
DaemonSet(守护进程集)控制器
-
生活例子:小区的门卫保安,每个小区门口必须有且只有一个保安亭。
-
特点:
- 在每个节点上运行且只运行一个Pod。
- 新节点加入集群自动部署,节点删除自动清理。
- 常用于各种监控组件、日志收集工具等。
-
通俗解释:就像每台电脑都需要安装的杀毒软件,不能少装也不能重复装,电脑买回来就装上,电脑丢了它也就跟着没了。举例的zabbix-agent就是一种监控代理,需要部署在每台服务器上收集监控数据。
-
-
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
评论