Kubernetes 简介及部署方法
Kubernetes(简称 K8s)是一个开源的容器编排平台,用于自动化容器化应用的部署、扩展、管理和运维。它由 Google 基于内部的 Borg 系统经验开发,2014 年开源后由云原生计算基金会(CNCF)维护,现已成为容器编排的事实标准。
一、K8s 的核心功能
K8s 的核心目标是解决容器化应用在大规模部署时的复杂性,主要功能包括:
p
- 自动化部署:支持通过配置文件定义应用部署规则,自动完成容器的创建、调度和启动。
- 弹性伸缩:根据 CPU 使用率、内存占用等指标自动扩缩容(如 HPA Horizontal Pod Autoscaler),也支持手动调整副本数。
- 负载均衡:通过 Service 组件为 Pod(容器组)提供稳定的访问地址,并自动实现流量分发。
- 自愈能力:当容器或节点故障时,自动重启容器、替换故障节点上的 Pod,确保应用可用性。
- 滚动更新与回滚:支持应用版本的平滑更新(不中断服务),若更新失败可快速回滚到上一版本。
- 存储编排:支持多种存储类型(本地存储、云存储、分布式存储等),可动态挂载到容器。
- 配置管理:通过 ConfigMap、Secret 等组件统一管理应用配置和敏感信息(如密码、证书),避免硬编码。
二、K8s 的核心组件
K8s 集群由控制平面(Control Plane) 和节点(Node) 两部分组成,各组件协同工作实现集群管理。
1. 控制平面组件(集群的 “大脑”)
控制平面负责集群的全局决策(如调度、管理、监控),可部署在单个节点或多个节点(高可用架构)。
- API Server:所有操作的统一入口(通过 REST API 暴露),接收用户输入的命令,提供认证、授权、API注册和发现等机制,是控制平面与其他组件、用户的交互枢纽,负责认证、授权和请求处理。
- etcd:分布式键值数据库,存储集群的所有配置数据(如 Pod 状态、部署规则等),是集群的 “数据源”。
- Scheduler:负责 Pod 的调度决策,根据节点资源(CPU、内存)、亲和性规则、污点 / 容忍等条件,选择最合适的节点运行 Pod。
- Controller Manager:运行各种控制器进程的组件,确保集群状态与期望状态一致。常见控制器包括:
- 节点控制器(Node Controller):监控节点故障并处理。
- 副本控制器(ReplicaSet Controller):确保 Pod 副本数符合期望。
- 部署控制器(Deployment Controller):管理 Deployment 的创建、更新和回滚。
- Cloud Controller Manager:可选组件,用于对接云服务提供商(如 AWS、阿里云)的 API,实现云资源(如负载均衡、存储)的自动管理。
2. 节点组件(集群的 “工作单元”)
节点是实际运行容器的服务器(物理机或虚拟机),每个节点需安装以下组件:
- kubelet:运行在每个节点上的代理程序,负责与控制平面通信,确保容器(按 Pod 定义)在节点上正常运行,并监控容器状态。
- kube-proxy:运行在每个节点上的网络代理,负责维护节点的网络规则(如 Service 的负载均衡、Pod 间通信),实现集群内部和外部的网络访问。
- 容器运行时(Container Runtime):负责运行容器的软件,K8s 支持 Docker、containerd、CRI-O 等符合容器运行时接口(CRI)的工具。
三、K8s 的核心概念
理解这些概念是使用 K8s 的基础,它们是 K8s 抽象出的 “操作单元”。
概念 | 作用说明 |
Pod | 最小部署单元,由一个或多个紧密关联的容器组成(共享网络和存储),是 K8s 调度的基本单位。 |
Service | 为 Pod 提供稳定的访问地址(固定 IP 和端口),解决 Pod 动态创建 / 销毁导致的地址变化问题,支持 ClusterIP(集群内访问)、NodePort(节点端口)、LoadBalancer(负载均衡器)等类型。 |
Deployment | 用于管理无状态应用的部署,支持滚动更新、回滚、扩缩容,通过控制 ReplicaSet 实现 Pod 的副本管理。 |
StatefulSet | 用于管理有状态应用(如数据库),为 Pod 提供稳定的名称、网络标识和存储,确保部署顺序和唯一性。 |
ConfigMap | 存储非敏感配置信息(如环境变量、配置文件),可被 Pod 挂载为文件或环境变量,便于配置与代码分离。 |
Secret | 存储敏感信息(如密码、Token),内容会被 Base64 编码(非加密,需配合外部加密工具增强安全性),用法与 ConfigMap 类似。 |
Namespace | 用于集群内资源的隔离(如开发、测试、生产环境),避免资源命名冲突,可配合资源配额限制资源使用。 |
Label | 键值对标签,用于对资源(Pod、Service 等)进行分类和筛选,是 K8s 中 “关联资源” 的核心机制(如 Service 通过 Label 关联 Pod)。 |
Ingress | 管理外部访问集群内服务的规则(如 HTTP/HTTPS 路由),可实现域名转发、SSL 终止等功能,需配合 Ingress Controller(如 Nginx Ingress)使用。 |
Volume | 为 Pod 提供持久化存储,生命周期与 Pod 绑定(Pod 删除后 Volume 可能保留,取决于存储类型),支持 EmptyDir(临时存储)、HostPath(节点本地目录)、PV/PVC(持久卷 / 持久卷声明)等。 |
PV/PVC | PV(PersistentVolume)是集群级别的存储资源(由管理员创建),PVC(PersistentVolumeClaim)是用户对 PV 的 “申请”,实现存储的 “按需分配”。 |
四、K8s 的工作流程(以部署应用为例)
- 用户通过kubectl命令或 API 提交 Deployment 配置(定义应用镜像、副本数等)。
- API Server 接收请求,验证后将配置存入 etcd。
- Deployment Controller 检测到 “期望状态”(如 3 个副本)与 “当前状态”(0 个副本)不一致,创建 ReplicaSet。
- ReplicaSet Controller 检测到副本数不足,向 API Server 请求创建 Pod。
- Scheduler 根据节点资源和调度规则,为 Pod 选择合适的节点。
- 目标节点的 kubelet 接收到 Pod 创建请求,通过容器运行时启动容器。
- kube-proxy 更新节点网络规则,确保 Service 能访问到新创建的 Pod。
- 后续若 Pod 故障,kubelet 会重启容器;若节点故障,Controller 会在其他节点重建 Pod,始终维持期望状态。
五、K8s 的应用场景
- 微服务架构:适合部署由多个独立服务组成的微服务应用,通过 Service 实现服务间通信,通过 Deployment/StatefulSet 管理不同类型的服务。
- CI/CD 集成:与 Jenkins、GitLab CI 等工具结合,实现代码提交→构建镜像→自动部署到 K8s 集群的全流程自动化。
- 多环境管理:通过 Namespace 隔离开发、测试、生产环境,使用 ConfigMap/Secret 区分不同环境的配置。
- 混合云 / 多云部署:K8s 的跨平台特性支持在私有云、公有云(如 AWS EKS、阿里云 ACK)或混合环境中统一部署和管理应用。
六、K8s 的优势与挑战
- 优势:
- 自动化程度高,减少人工运维成本;
- 弹性伸缩能力强,适应流量波动;
- 松耦合架构,支持应用快速迭代;
- 强大的生态系统(如监控、日志、服务网格工具)。
- 挑战:
- 学习曲线陡峭,需掌握大量概念和操作;
- 集群运维复杂(如高可用配置、升级、故障排查);
- 网络和存储配置需结合具体场景设计;
- 资源开销较高(控制平面和节点组件占用一定资源)。
七、K8s 生态系统
K8s 的强大得益于丰富的周边工具,常见生态组件包括:
- 部署工具:Helm(K8s 包管理工具,简化应用部署)、Kustomize(配置管理工具)。
- 监控与日志:Prometheus( metrics 监控)、Grafana(可视化)、ELK Stack(日志收集与分析)。
- 服务网格:Istio(流量管理、服务间通信加密、监控)。
- CI/CD:ArgoCD(GitOps 持续部署)、Tekton(云原生 CI/CD 管道)。
- 安全工具:Falco(运行时安全监控)、Trivy(容器镜像漏洞扫描)。
总之,K8s 是容器化时代的核心技术之一,掌握它能有效提升大规模应用的管理效率和可靠性,但也需要结合实际场景合理规划和使用。
K8S集群环境搭建
k8s中容器的管理方式
**centainerd**
默认情况下,K8S在创建集群时使用的方式
**docker**
Docker使用的普记录最高,虽然K8S在1.24版本后已经费力了kubelet对docker的支持,但时可以借助cri-docker方式来实现集群创建
**cri-o**
CRI-O的方式是Kubernetes创建容器最直接的一种方式,在创建集群的时候,需要借助于cri-o插件的方式来实现Kubernetes集群的创建。
> [!NOTE]
>
> docker 和cri-o 这两种方式要对kubelet程序的启动参数进行设置
k8s 集群部署
k8s 环境部署说明
集群环境初始化
K8S中文官网:https://kubernetes.io/zh-cn/
| **主机名** | **ip** | **角色** |
| ---------------------------- | ------------------ | --------------------------- |
| ** harbor ** | **172.25.254.200** | **harbor仓库** |
| ** master ** | **172.25.254.100** | **master,k8s集群控制节点** |
| ** node1 ** | **172.25.254.10** | **worker,k8s集群工作节点** |
| ** node2 ** | **172.25.254.20** | **worker,k8s集群工作节点** |
- 所有节点禁用selinux和防火墙
- 所有节点同步时间和解析
- 所有节点安装docker-ce
- 所有节点禁用swap,注意注释掉/etc/fstab文件中的定义
所有禁用swap和本地解析
]# systemctl mask swap.target
]# swapoff -a
]# vim /etc/fstab
swap defaults 0 0 注释这一行
[root@k8s-master ~]# vim /etc/hosts
```
所有安装虚拟机docker
```bash
[root@k8s-master ~]# vim /etc/yum.repos.d/docker.repo
[docker]
name=docker
baseurl=https://mirrors.aliyun.com/docker-ce/linux/rhel/9/x86_64/stable/
gpgcheck=0
[root@k8s-master ~]# dnf install docker-ce -y
```
搭建私有仓库harbor
[root@k8s-master ~]# vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://reg.xie.org"],
}
[root@k8s-master ~]# ls -l /etc/docker/certs.d/reg.xie.org/ca.crt
[root@k8s-master ~]# systemctl enable --now docker
4.3.3 为Registry提加密传输
#生成认证key和证书
[root@docker ~]# openssl req -newkey rsa:4096 \-nodes -sha256 -keyout certs/xie.org.key \-addext "subjectAltName = DNS:reg.xie.org" \ -x509 -days 365 -out certs/xie.org.crt
#指定备用名称
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:Shaanxi
Locality Name (eg, city) [Default City]:Xi'an
Organization Name (eg, company) [Default Company Ltd]:xie
Organizational Unit Name (eg, section) []:docker
Common Name (eg, your name or your server's hostname) []:reg.xie.org
Email Address []:admin@xie.org
#启动registry仓库
[root@docker ~]# docker run -d -p 443:443 --restart=always --name registry \
> --name registry -v /opt/registry:/var/lib/registry \
> -v /root/certs:/certs \
> -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
> -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/xie.org.crt \
> -e REGISTRY_HTTP_TLS_KEY=/certs/xie.org.key registry
测试:
[root@docker docker]# docker push reg.xie.org/busybox:latest
户端没有key和证书
Error response from daemon: Get "https://reg.xie.org/v2/": tls: failed to
verify certificate: x509: certificate signed by unknown authority
#为客户端建立证书
[root@docker docker]# mkdir /etc/docker/certs.d/reg.xie.org/ -p
[root@docker docker]# cp /root/certs/xie.org.crt
/etc/docker/certs.d/reg.xie.org/ca.crt
[root@docker docker]# systemctl restart docker
#docker客
[root@docker docker]# docker push reg.xie.org/busybox:latest
The push refers to repository [reg.xie.org/busybox]
d51af96cf93e: Pushed
latest: digest:
sha256:28e01ab32c9dbcbaae96cf0d5b472f22e231d9e603811857b295e61197e40a9b size: 527
[root@docker docker]# curl -k https://reg.xie.org/v2/_catalog
{"repositories":["busybox"]}
4.3.4 为仓库建立登陆认证
#安装建立认证文件的工具包
[root@docker docker]# dnf install httpd-tools -y
#建立认证文件
[root@docker ~]# mkdir auth
[root@docker ~]# htpasswd -Bc auth/htpasswd xie #-B 强制使用最安全加密方式,
默认用md5加密
New password:
Re-type new password:
Adding password for user xie
#添加认证到registry容器中
[root@docker ~]# docker run -d -p 443:443 --restart=always --name registry \
> --name registry -v /opt/registry:/var/lib/registry \
> -v /root/certs:/certs \
> -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
> -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/xie.org.crt \
> -e REGISTRY_HTTP_TLS_KEY=/certs/xie.org.key \
> -v /root/auth:/auth \
> -e "REGISTRY_AUTH=htpasswd" \
> -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
> -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
> registry
[root@docker ~]# curl -k https://reg.xie.org/v2/_catalog -u xie:lee
{"repositories":["busybox","nginx"]}
#登陆测试
[root@docker ~]# docker login reg.xie.org
Username: xie
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credential-stores
Login Succeeded
当仓库开启认证后必须登陆仓库才能进行镜像上传
#未登陆情况下上传镜像
[root@docker ~]# docker push reg.xie.org/busybox
Using default tag: latest
The push refers to repository [reg.xie.org/busybox]
d51af96cf93e: Preparing
no basic auth credentials
#未登陆下不能下载
[root@docker-node2 ~]# docker pull reg.xie.org/busybox
Using default tag: latest
Error response from daemon: Head
"https://reg.xie.org/v2/busybox/manifests/latest": no basic auth
credentials
[root@docker ~]# tar zxf harbor-offline-installer-v2.5.4.tgz
[root@docker ~]# ls
anaconda-ks.cfg certs harbor-offline-installer-v2.5.4.tgz
auth
harbor
[root@docker ~]# cd harbor/
[root@docker harbor]# cp harbor.yml.tmpl harbor.yml
[root@docker harbor]# vim harbor.yml
hostname: reg.xie.org
certificate: /data/certs/xie.org.crt
private_key: /data/certs/xie.org.key
harbor_admin_password: lee
[root@docker harbor]# ./install.sh --help
Please set --with-notary
Please set --with-trivy
#证书签名
#安全扫描
Please set --with-chartmuseum if needs enable Chartmuseum in Harbor
[root@docker harbor]# ./install.sh --with-chartmuseum
#管理harbor的容器
[root@docker harbor]# docker compose stop
[root@docker harbor]# docker compose up -d
输入用户名和密码后
docker info
认证harbor仓库 https://reg.xie.org
#### 安装K8S部署工具
```bash
#部署软件仓库,添加K8S源
[root@k8s-master ~]# vim /etc/yum.repos.d/k8s.repo
[k8s]
name=k8s
baseurl=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.30/rpm
gpgcheck=0
#安装软件
[root@k8s-master ~]# dnf install kubelet-1.30.0 kubeadm-1.30.0 kubectl-1.30.0 -y
```
#### 设置kubectl命令补齐功能
```
[root@k8s-master ~]# dnf install bash-completion -y
[root@k8s-master ~]# echo "source <(kubectl completion bash)" >> ~/.bashrc
[root@k8s-master ~]# source ~/.bashrc
在所节点安装cri-docker
k8s从1.24版本开始移除了dockershim,所以需要安装cri-docker插件才能使用docker
软件下载:https://github.com/Mirantis/cri-dockerd
```bash
[root@k8s-master ~]# dnf install libcgroup-0.41-19.el8.x86_64.rpm \
> cri-dockerd-0.3.14-3.el8.x86_64.rpm -y
[root@k8s-master ~]# vim /lib/systemd/system/cri-docker.service
[root@k8s-master ~]# systemctl daemon-reload
[root@k8s-master ~]# systemctl start cri-docker
cri-dockerd的套接字文件
在master节点拉取K8S所需镜像
#拉取k8s集群所需要的镜像
[root@k8s-master ~]# kubeadm config images pull \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.30.0 \
--cri-socket=unix:///var/run/cri-dockerd.sock
#上传镜像到harbor仓库
[root@k8s-master ~]# docker images | awk '/google/{ print $1":"$2}' \
| awk -F "/" '{system("docker tag "$0" reg.xie.org/k8s/"$3)}'
[root@k8s-master ~]# docker images | awk '/k8s/{system("docker push "$1":"$2)}'
```
集群初始化
```bash
#启动kubelet服务
[root@k8s-master ~]# systemctl status kubelet.service
#执行初始化命令
[root@k8s-master ~]# kubeadm init --pod-network-cidr=10.244.0.0/16 \
--image-repository reg.xie.org/k8s \
--kubernetes-version v1.30.0 \
--cri-socket=unix:///var/run/cri-dockerd.sock
#指定集群配置文件变量
[root@k8s-master~]#echo"export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile
#当前节点没有就绪,因为还没有安装网络插件,容器没有运行
[root@k8s-master ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master.xie.org NotReady control-plane 4m25s v1.30.0
root@k8s-master ~]# kubectl get pod -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-647dc958972sgn8 0/1 Pending 0 6m13s
kube-system coredns-647dc95897-bvtxb 0/1 Pending 0 6m13s
kube-system etcd-k8s-master.xie.org 1/1 Running 0 6m29s
kube-system kube-apiserver-k8s-master.xie.org 1/1 Running 0 6m30s
kube-system kube-controller-manager-k8s-master.xie.org1/1 Running 0 6m29s
kube-system kube-proxy-fq85m 1/1 Running 0 6m14s
kube-system kube-scheduler-k8s-master.xie.org 1/1 Running 0 6m29s
```
> [!NOTE]
>
> 在此阶段如果生成的集群token找不到了可以重新生成
>
> ```bash
> [root@k8s-master ~]# kubeadm token create --print-join-command
kubeadm join 172.25.254.100:6443 --token slx36w.np3pg2xzfhtj8hsr \
--discovery-token-ca-cert-hash sha256:29389ead6392e0bb1f68adb025e3a6817c9936a26f9140f8a166528e521addb3 --cri-socket=unix:///var/run/cri-dockerd.sock
kubeadm join 172.25.254.100:6443 --token olyuv1.g1q8jht9b1p69xla --discovery-token-ca-cert-hash sha256:29389ead6392e0bb1f68adb025e3a6817c9936a26f9140f8a166528e521addb3 --cri-socket=unix:///var/run/cri-dockerd.sock
> ```
#### 2.2.2.10 安装flannel网络插件
官方网站:https://github.com/flannel-io/flannel
```bash
#下载flannel的yaml部署文件
[root@k8s-master ~]# wget https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
#下载镜像:
[root@k8s-master ~]# docker pull docker.io/flannel/flannel:v0.25.5
[root@k8s-master ~]# docekr docker.io/flannel/flannel-cni-plugin:v1.5.1-flannel1
#上传镜像到仓库
[root@k8s-master ~]# docker tag flannel/flannel:v0.25.5 \
reg.xie.org/flannel/flannel:v0.25.5
[root@k8s-master ~]# docker push reg.xie.org/flannel/flannel:v0.25.5
[root@k8s-master ~]# docker tag flannel/flannel-cni-plugin:v1.5.1-flannel1 \
reg.xie.org/flannel/flannel-cni-plugin:v1.5.1-flannel1
[root@k8s-master ~]# docker push reg.xie.org/flannel/flannel-cni-plugin:v1.5.1-flannel1
#编辑kube-flannel.yml 修改镜像下载位置
[root@k8s-master ~]# vim kube-flannel.yml
#需要修改以下几行
[root@k8s-master ~]# grep -n image kube-flannel.yml
146: image: reg.xie.org/flannel/flannel:v0.25.5
173: image: reg.xie.org/flannel/flannel-cni-plugin:v1.5.1-flannel1
184: image: reg.xie.org/flannel/flannel:v0.25.5
#安装flannel网络插件
[root@k8s-master ~]# kubectl apply -f kube-flannel.yml
```
#### 2.2.2.11 节点扩容
在所有的worker节点中
1 确认部署好以下内容
2 禁用swap
3 安装:
- kubelet-1.30.0
- kubeadm-1.30.0
- kubectl-1.30.0
- docker-ce
- cri-dockerd
4 修改cri-dockerd启动文件添加
- --network-plugin=cni
- --pod-infra-container-image=reg.xie.org/k8s/pause:3.9
5 启动服务
- kubelet.service
- cri-docker.service
以上信息确认完毕后即可加入集群
```
[root@k8s-node1 & 2 ~]# kubeadm join 172.25.254.100:6443 --token 5hwptm.zwn7epa6pvatbpwf --discovery-token-ca-cert-hash sha256:52f1a83b70ffc8744db5570288ab51987ef2b563bf906ba4244a300f61e9db23 --cri-socket=unix:///var/run/cri-dockerd.sock
在master阶段中查看所有node的状态
```
[root@k8s-master ~]# kubectl get nodes
测试集群运行情况
```
#建立一个pod
[root@k8s-master ~]# kubectl run test --image nginx
#查看pod状态
[root@k8s-master ~]# kubectl get pods
Kubernetes中pod的管理及优化
资源管理介绍
- 在kubernetes中,所有的内容都抽象为资源,用户需要通过操作资源来管理kubernetes。
- kubernetes的本质上就是一个集群系统,用户可以在集群中部署各种服务
- 所谓的部署服务,其实就是在kubernetes集群中运行一个个的容器,并将指定的程序跑在容器中。
- kubernetes的最小管理单元是pod而不是容器,只能将容器放在`Pod`中,
- kubernetes一般也不会直接管理Pod,而是通过`Pod控制器`来管理Pod的。
- Pod中服务的访问是由kubernetes提供的`Service`资源来实现。
- Pod中程序的数据需要持久化是由kubernetes提供的各种存储系统来实现
资源管理方式
- 命令式对象管理:直接使用命令去操作kubernetes资源
`kubectl run nginx-pod --image=nginx:latest --port=80`
- 命令式对象配置:通过命令配置和配置文件去操作kubernetes资源
`kubectl create/patch -f nginx-pod.yaml`
- 声明式对象配置:通过apply命令和配置文件去操作kubernetes资源
`kubectl apply -f nginx-pod.yaml`
| 类型 |适用环境| 优点 | 缺点 |
| 命令式对象管理 | 测试 | 简单 | 只能操作活动对象,无法审计、跟踪
| 命令式对象配置 | 开发 | 可以审计、跟踪 | 项目大时,配置文件多,操作麻烦 |
| 声明式对象配置 | 开发 | 支持目录操作 | 意外情况下难以调试
命令式对象管理
kubectl是kubernetes集群的命令行工具,通过它能够对集群本身进行管理,并能够在集群上进行容器化应用的安装部署
kubectl命令的语法如下:
```
kubectl [command] [type] [name] [flags]
```
**comand**:指定要对资源执行的操作,例如create、get、delete
**type**:指定资源类型,比如deployment、pod、service
**name**:指定资源的名称,名称大小写敏感
**flags**:指定额外的可选参数
```
# 查看所有pod
kubectl get pod
# 查看某个pod
kubectl get pod pod_name
# 查看某个pod,以yaml格式展示结果
kubectl get pod pod_name -o yaml
资源类型
kubernetes中所有的内容都抽象为资源
基本命令示例
kubectl version
kubectl cluster-info
#创建一个webcluster控制器,控制器中pod数量为2
kubectl create deployment webcluseter --image nginx --replicas 2
#查看控制器
[root@k8s-master ~]# kubectl get deployments.apps
#查看资源帮助
[root@k8s-master ~]# kubectl explain deployment
#查看控制器参数帮助
[root@k8s-master ~]# kubectl explain deployment.spec
#编辑控制器配置
[root@k8s-master ~]# kubectl edit deployments.apps webcluseter
#删除资源
[root@k8s-master ~]# kubectl delete deployments.apps webcluseter
deployment.apps " webcluseter" deleted
[root@k8s-master ~]# kubectl get deployments.apps
运行和调试命令示例
#端口暴漏
[root@k8s-master ~]# kubectl get services
[root@k8s-master ~]# kubectl expose pod testpod --port 80 --target-port 80
[root@k8s-master ~]# kubectl get services
[root@k8s-master ~]# curl 10.110.169.130
#查看资源日志
[root@k8s-master ~]# kubectl logs pods/testpod
#利用命令生成yaml模板文件
[root@k8s-master ~]# kubectl create deployment --image nginx webcluster --dry-run=client -o yaml > webcluster.yml
#利用yaml文件生成资源
[root@k8s-master ~]# vim webcluster.yml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: webcluster
name: webcluster
spec:
replicas: 2
selector:
matchLabels:
app: webcluster
template:
metadata:
labels:
app: webcluster
spec:
containers:
- image: nginx
name: nginx
[root@k8s-master ~]# kubectl apply -f webcluster.yml
[root@k8s-master ~]# kubectl get deployments.apps
[root@k8s-master ~]# kubectl delete -f webcluster.yml
利用控制器管理pod(推荐)
**高可用性和可靠性**:
- **自动故障恢复**:如果一个 Pod 失败或被删除,控制器会自动创建新的 Pod 来维持期望的副本数量。确保应用始终处于可用状态,减少因单个 Pod 故障导致的服务中断。
- **健康检查和自愈**:可以配置控制器对 Pod 进行健康检查(如存活探针和就绪探针)。如果 Pod 不健康,控制器会采取适当的行动,如重启 Pod 或删除并重新创建它,以保证应用的正常运行。
**可扩展性**:
- **轻松扩缩容**:可以通过简单的命令或配置更改来增加或减少 Pod 的数量,以满足不同的工作负载需求。例如,在高流量期间可以快速扩展以处理更多请求,在低流量期间可以缩容以节省资源。
- **水平自动扩缩容(HPA)**:可以基于自定义指标(如 CPU 利用率、内存使用情况或应用特定的指标)自动调整 Pod 的数量,实现动态的资源分配和成本优化。
**版本管理和更新**:
- **滚动更新**:对于 Deployment 等控制器,可以执行滚动更新来逐步替换旧版本的 Pod 为新版本,确保应用在更新过程中始终保持可用。可以控制更新的速率和策略,以减少对用户的影响。
- **回滚**:如果更新出现问题,可以轻松回滚到上一个稳定版本,保证应用的稳定性和可靠性。
**声明式配置**:
- **简洁的配置方式**:使用 YAML 或 JSON 格式的声明式配置文件来定义应用的部署需求。这种方式使得配置易于理解、维护和版本控制,同时也方便团队协作。
- **期望状态管理**:只需要定义应用的期望状态(如副本数量、容器镜像等),控制器会自动调整实际状态与期望状态保持一致。无需手动管理每个 Pod 的创建和删除,提高了管理效率。
**服务发现和负载均衡**:
- **自动注册和发现**:Kubernetes 中的服务(Service)可以自动发现由控制器管理的 Pod,并将流量路由到它们。这使得应用的服务发现和负载均衡变得简单和可靠,无需手动配置负载均衡器。
- **流量分发**:可以根据不同的策略(如轮询、随机等)将请求分发到不同的 Pod,提高应用的性能和可用性。
**多环境一致性**:
- **一致的部署方式**:在不同的环境(如开发、测试、生产)中,可以使用相同的控制器和配置来部署应用,确保应用在不同环境中的行为一致。这有助于减少部署差异和错误,提高开发和运维效率。
#建立控制器并自动运行pod
[root@k8s-master ~]# kubectl create deployment xie --image nginx
[root@k8s-master ~]# kubectl get pods
[root@k8s-master ~]# kubectl scale deployment xie --replicas 6
#为xie缩容
root@k8s-master ~]# kubectl scale deployment xie --replicas 2
deployment.apps/xie scaled
[root@k8s-master ~]# kubectl get pods
应用版本的更新
```bash
#利用控制器建立pod
[root@k8s-master ~]# kubectl create deployment xie --image myapp:v1 --replicas 2
#暴漏端口
[root@k8s-master ~]# kubectl expose deployment xie --port 80 --target-port 80
[root@k8s-master ~]# kubectl get services
#产看历史版本
[root@k8s-master ~]# kubectl rollout history deployment xie
#更新控制器镜像版本
[root@k8s-master ~]# kubectl set image deployments/xie myapp=myapp:v2
#查看历史版本
[root@k8s-master ~]# kubectl rollout history deployment xie
#访问内容测试
[root@k8s-master ~]# curl 10.98.134.63
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
#版本回滚
[root@k8s-master ~]# kubectl rollout undo deployment xie --to-revision 1
deployment.apps/xie rolled back
[root@k8s-master ~]# curl 10.98.134.63
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
利用yaml文件部署应用
### 用yaml文件部署应用有以下优点
**声明式配置**:
- 清晰表达期望状态:以声明式的方式描述应用的部署需求,包括副本数量、容器配置、网络设置等。这使得配置易于理解和维护,并且可以方便地查看应用的预期状态。
- 可重复性和版本控制:配置文件可以被版本控制,确保在不同环境中的部署一致性。可以轻松回滚到以前的版本或在不同环境中重复使用相同的配置。
- 团队协作:便于团队成员之间共享和协作,大家可以对配置文件进行审查和修改,提高部署的可靠性和稳定性。
**灵活性和可扩展性**:
- 丰富的配置选项:可以通过 YAML 文件详细地配置各种 Kubernetes 资源,如 Deployment、Service、ConfigMap、Secret 等。可以根据应用的特定需求进行高度定制化。
- 组合和扩展:可以将多个资源的配置组合在一个或多个 YAML 文件中,实现复杂的应用部署架构。同时,可以轻松地添加新的资源或修改现有资源以满足不断变化的需求。
**与工具集成**:
- 与 CI/CD 流程集成:可以将 YAML 配置文件与持续集成和持续部署(CI/CD)工具集成,实现自动化的应用部署。例如,可以在代码提交后自动触发部署流程,使用配置文件来部署应用到不同的环境。
- 命令行工具支持:Kubernetes 的命令行工具 `kubectl` 对 YAML 配置文件有很好的支持,可以方便地应用、更新和删除配置。同时,还可以使用其他工具来验证和分析 YAML 配置文件,确保其正确性和安全性。
### 资源清单参数
| 参数名称 | 类型 | 参数说明 |
| ------------------------------------------- | ------- | ------------------------------------------------------------ |
| version | String | 这里是指的是K8S API的版本,目前基本上是v1,可以用kubectl api-versions命令查询 |
| kind | String | 这里指的是yaml文件定义的资源类型和角色,比如:Pod |
| metadata | Object | 元数据对象,固定值就写metadata |
| metadata.name | String | 元数据对象的名字,这里由我们编写,比如命名Pod的名字 |
| metadata.namespace | String | 元数据对象的命名空间,由我们自身定义 |
| Spec | Object | 详细定义对象,固定值就写Spec |
| spec.containers[] | list | 这里是Spec对象的容器列表定义,是个列表 |
| spec.containers[].name | String | 这里定义容器的名字 |
| spec.containers[].image | string | 这里定义要用到的镜像名称 |
| spec.containers[].imagePullPolicy | String | 定义镜像拉取策略,有三个值可选: (1) Always: 每次都尝试重新拉取镜像 (2) IfNotPresent:如果本地有镜像就使用本地镜像 (3) )Never:表示仅使用本地镜像 |
| spec.containers[].command[] | list | 指定容器运行时启动的命令,若未指定则运行容器打包时指定的命令 |
| spec.containers[].args[] | list | 指定容器运行参数,可以指定多个 |
| spec.containers[].workingDir | String | 指定容器工作目录 |
| spec.containers[].volumeMounts[] | list | 指定容器内部的存储卷配置 |
| spec.containers[].volumeMounts[].name | String | 指定可以被容器挂载的存储卷的名称 |
| spec.containers[].volumeMounts[].mountPath | String | 指定可以被容器挂载的存储卷的路径 |
| spec.containers[].volumeMounts[].readOnly | String | 设置存储卷路径的读写模式,ture或false,默认为读写模式 |
| spec.containers[].ports[] | list | 指定容器需要用到的端口列表 |
| spec.containers[].ports[].name | String | 指定端口名称 |
| spec.containers[].ports[].containerPort | String | 指定容器需要监听的端口号 |
| spec.containers[] ports[].hostPort | String | 指定容器所在主机需要监听的端口号,默认跟上面containerPort相同,注意设置了hostPort同一台主机无法启动该容器的相同副本(因为主机的端口号不能相同,这样会冲突) |
| spec.containers[].ports[].protocol | String | 指定端口协议,支持TCP和UDP,默认值为 TCP |
| spec.containers[].env[] | list | 指定容器运行前需设置的环境变量列表 |
| spec.containers[].env[].name | String | 指定环境变量名称 |
| spec.containers[].env[].value | String | 指定环境变量值 |
| spec.containers[].resources | Object | 指定资源限制和资源请求的值(这里开始就是设置容器的资源上限) |
| spec.containers[].resources.limits | Object | 指定设置容器运行时资源的运行上限 |
| spec.containers[].resources.limits.cpu | String | 指定CPU的限制,单位为核心数,1=1000m |
| spec.containers[].resources.limits.memory | String | 指定MEM内存的限制,单位为MIB、GiB |
| spec.containers[].resources.requests | Object | 指定容器启动和调度时的限制设置 |
| spec.containers[].resources.requests.cpu | String | CPU请求,单位为core数,容器启动时初始化可用数量 |
| spec.containers[].resources.requests.memory | String | 内存请求,单位为MIB、GIB,容器启动的初始化可用数量 |
| spec.restartPolicy | string | 定义Pod的重启策略,默认值为Always. (1)Always: Pod-旦终止运行,无论容器是如何 终止的,kubelet服务都将重启它 (2)OnFailure: 只有Pod以非零退出码终止时,kubelet才会重启该容器。如果容器正常结束(退出码为0),则kubelet将不会重启它 (3) Never: Pod终止后,kubelet将退出码报告给Master,不会重启该 |
| spec.nodeSelector | Object | 定义Node的Label过滤标签,以key:value格式指定 |
| spec.imagePullSecrets | Object | 定义pull镜像时使用secret名称,以name:secretkey格式指定 |
| spec.hostNetwork | Boolean | 定义是否使用主机网络模式,默认值为false。设置true表示使用宿主机网络,不使用docker网桥,同时设置了true将无法在同一台宿主机 上启动第二个副本 |
### 如何获得资源帮助
```
kubectl explain pod.spec.containers
```
### 编写示例
运行多个容器pod
> [!WARNING]
>
> 注意如果多个容器运行在一个pod中,资源共享的同时在使用相同资源时也会干扰,比如端口
```bash
#一个端口干扰示例:
[root@k8s-master ~]# vim pod.yml
apiVersion: v1
kind: Pod
metadata:
labels:
run: timing
name: xie
spec:
containers:
- image: nginx:latest
name: web1
- image: nginx:latest
name: web2
[root@k8s-master ~]# kubectl apply -f pod.yml
[root@k8s-master ~]# kubectl get pods
> [!NOTE]
>
> 在一个pod中开启多个容器时一定要确保容器彼此不能互相干扰
端口映射
```bash
[root@k8s-master ~]# vim pod.yml
apiVersion: v1
kind: Pod
metadata:
labels:
run: xie
name: test
spec:
containers:
- image: myapp:v1
name: myapp1
ports:
- name: http
containerPort: 80
hostPort: 80
protocol: TCP
#测试
[root@k8s-master ~]# kubectl apply -f pod.yml
[root@k8s-master ~]# kubectl get pods -o wide
如何设定环境变量
```bash
[root@k8s-master ~]# vim pod.yml
apiVersion: v1
kind: Pod
metadata:
labels:
run: xie
name: test
spec:
containers:
- image: busybox:latest
name: busybox
command: ["/bin/sh","-c","echo $NAME;sleep 3000000"]
env:
- name: NAME
value: xie
[root@k8s-master ~]# kubectl apply -f pod.yml
选择运行节点
```
[root@k8s-master ~]# vim pod.yml
apiVersion: v1
kind: Pod
metadata:
labels:
run: xie
name: test
spec:
nodeSelector:
kubernetes.io/hostname: node1
restartPolicy: Always
containers:
- image: myapp:v1
name: myapp
[root@k8s-master ~]# kubectl apply -f pod.yml
[root@k8s-master ~]# kubectl get pods -o wide
探针
**探针是由 kubelet 对容器执行的定期诊断:**
- ExecAction:在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。
- TCPSocketAction:对指定端口上的容器的 IP 地址进行 TCP 检查。如果端口打开,则诊断被认为是成功的。
- HTTPGetAction:对指定的端口和路径上的容器的 IP 地址执行 HTTP Get 请求。如果响应的状态码大于等于200 且小于 400,则诊断被认为是成功的。
每次探测都将获得以下三种结果之一:
- 成功:容器通过了诊断。
- 失败:容器未通过诊断。
- 未知:诊断失败,因此不会采取任何行动。
**Kubelet 可以选择是否执行在容器上运行的三种探针执行和做出反应:**
- livenessProbe:指示容器是否正在运行。如果存活探测失败,则 kubelet 会杀死容器,并且容器将受到其重启策略的影响。如果容器不提供存活探针,则默认状态为 Success。
- readinessProbe:指示容器是否准备好服务请求。如果就绪探测失败,端点控制器将从与 Pod 匹配的所有 Service 的端点中删除该 Pod 的 IP 地址。初始延迟之前的就绪状态默认为 Failure。如果容器不提供就绪探针,则默认状态为 Success。
- startupProbe: 指示容器中的应用是否已经启动。如果提供了启动探测(startup probe),则禁用所有其他探测,直到它成功为止。如果启动探测失败,kubelet 将杀死容器,容器服从其重启策略进行重启。如果容器没有提供启动探测,则默认状态为成功Success。
**ReadinessProbe 与 LivenessProbe 的区别**
- ReadinessProbe 当检测失败后,将 Pod 的 IP:Port 从对应的 EndPoint 列表中删除。
- LivenessProbe 当检测失败后,将杀死容器并根据 Pod 的重启策略来决定作出对应的措施
**StartupProbe 与 ReadinessProbe、LivenessProbe 的区别**
- 如果三个探针同时存在,先执行 StartupProbe 探针,其他两个探针将会被暂时禁用,直到 pod 满足 StartupProbe 探针配置的条件,其他 2 个探针启动,如果不满足按照规则重启容器。
- 另外两种探针在容器启动后,会按照配置,直到容器消亡才停止探测,而 StartupProbe 探针只是在容器启动后按照配置满足一次后,不在进行后续的探测。
k8s中的控制器应用
什么是控制器
控制器也是管理pod的一种手段
- 自主式pod:pod退出或意外关闭后不会被重新创建
- 控制器管理的 Pod:在控制器的生命周期里,始终要维持 Pod 的副本数目
Pod控制器是管理pod的中间层,使用Pod控制器之后,只需要告诉Pod控制器,想要多少个什么样的Pod就可以了,它会创建出满足条件的Pod并确保每一个Pod资源处于用户期望的目标状态。如果Pod资源在运行中出现故障,它会基于指定策略重新编排
当建立控制器后,会把期望值写入etcd,k8s中的apiserver检索etcd中我们保存的期望状态,并对比pod的当前状态,如果出现差异代码自驱动立即恢复
控制器常用类型
控制器类型 | 核心用途 | 关键特性 | 典型适用场景 |
Deployment(部署) | 管理无状态应用的部署、更新和自愈 | 1. 维护指定数量的 Pod 副本 | 无状态服务(如 Web 应用、API 服务、前端服务) |
StatefulSet(有状态集) | 管理有状态应用,提供稳定标识和持久化存储 | 1. 固定 Pod 名称和 DNS 标识(如web-0、web-1) | 有状态服务(如数据库 MySQL、分布式系统 ZooKeeper、消息队列 Kafka) |
DaemonSet(守护进程集) | 确保所有(或指定)节点运行相同的 Pod | 1. 新节点加入时自动部署 Pod | 集群级支撑服务(如日志收集 Fluentd、监控代理 Node Exporter、网络插件 Calico) |
ReplicaSet(副本集) | 维持指定数量的 Pod 副本(Deployment 的底层组件) | 1. 通过标签选择器管理 Pod | 通常不直接使用,由 Deployment 间接管理 |
Job(任务) | 管理一次性任务,确保任务成功完成 | 1. 任务完成后终止(退出码为 0) | 批处理任务(如数据备份、日志分析、数据库迁移) |
CronJob(定时任务) | 基于时间调度周期性执行任务(类似 crontab) | 1. 支持 cron 表达式定义执行时间 | 定时任务(如日志清理、数据同步、周期性报表生成) |
HorizontalPodAutoscaler(HPA) | 根据指标自动调整 Pod 副本数量(水平扩缩容) | 1. 基于 CPU / 内存或自定义指标触发扩缩容 | 流量波动大的服务(如电商促销期扩容、低谷期缩容) |
replicaset控制器
replicaset功能
- ReplicaSet 是下一代的 Replication Controller,官方推荐使用ReplicaSet
- ReplicaSet和Replication Controller的唯一区别是选择器的支持,ReplicaSet支持新的基于集合的选择器需求
- ReplicaSet 确保任何时间都有指定数量的 Pod 副本在运行
- 虽然 ReplicaSets 可以独立使用,但今天它主要被Deployments 用作协调 Pod 创建、删除和更新的机制
配置层级 | 参数名称 | 核心作用 | 取值说明 / 约束 | 是否必填 |
顶层元数据 | apiVersion | 定义 ReplicaSet 使用的 Kubernetes API 版本 | 固定为 apps/v1(K8s 1.9+ 版本统一,旧版本 extensions/v1beta1 已废弃) | 是 |
kind | 声明资源类型为 ReplicaSet | 固定为 ReplicaSet | 是 | |
metadata | 定义 ReplicaSet 自身的元数据 | 包含 name(资源名)、namespace(所属命名空间,默认 default)、labels(标签)等 | 是(至少含 name) | |
核心期望状态 | spec.replicas | 指定需要维持的 Pod 副本数量 | 非负整数,默认值为 1;设为 0 可删除所有受控 Pod | 否(有默认值) |
spec.selector | 定义标签选择器,用于匹配 / 管理 Pod | 仅支持 matchLabels(精确匹配标签),需与 spec.template.metadata.labels 完全一致 | 是 | |
spec.selector.matchLabels | 键值对形式的标签匹配规则,筛选出 ReplicaSet 要管理的 Pod | 例:app: nginx(仅匹配标签 app=nginx 的 Pod) | 是(嵌套在 selector 下) | |
Pod 模板 | spec.template | 定义用于创建 Pod 的模板(PodTemplate),所有受控 Pod 均基于此模板生成 | 需符合 Pod 配置规范,包含 metadata(Pod 标签)和 spec(Pod 容器等配置) | 是 |
spec.template.metadata | 定义 Pod 的元数据,核心是 Pod 标签 | 标签需与 spec.selector.matchLabels 匹配,否则 ReplicaSet 无法管理生成的 Pod | 是(至少含匹配标签) | |
spec.template.spec | 定义 Pod 的具体配置,如容器、存储、网络等 | 包含 containers(容器列表,必填)、volumes(存储卷)、restartPolicy(重启策略)等 | 是(至少含 containers) | |
Pod 模板 - 容器 | spec.template.spec.containers | 定义 Pod 中的容器列表,每个容器需配置核心参数 | 数组形式,至少包含 1 个容器 | 是(嵌套在 template.spec 下) |
containers[].name | 定义容器名称(Pod 内唯一) | 字符串,需符合 DNS 子域名规范(如 nginx-container) | 是(每个容器必填) | |
containers[].image | 指定容器使用的镜像(如镜像仓库地址、版本标签) | 例:nginx:1.25(指定 Nginx 1.25 版本);若未指定标签,默认拉取 latest 版本 | 是(每个容器必填) | |
Pod 模板 - 重启策略 | spec.template.spec.restartPolicy | 定义 Pod 内容器故障时的重启策略,影响 ReplicaSet 自愈逻辑 | 可选值: | 否(默认 Always) |
replicaset 示例
```bash
#生成yml文件
[root@k8s-master ~]# kubectl create deployment replicaset --image myapp:v1 --dry-run=client -o yaml > replicaset.yml
[root@k8s-master ~]# vim replicaset.yml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: replicaset #指定pod名称,一定小写,如果出现大写报错
spec:
replicas: 2 #指定维护pod数量为2
selector: #指定检测匹配方式
matchLabels: #指定匹配方式为匹配标签
app: myapp #指定匹配的标签为app=myapp
template: #模板,当副本数量不足时,会根据下面的模板创建pod副本
metadata:
labels:
app: myapp
spec:
containers:
- image: myapp:v1
name: myapp
[root@k8s-master ~]# kubectl apply -f replicaset.yml
[root@k8s-master ~]# kubectl get pods --show-labels
#replicaset是通过标签匹配pod
[root@k8s-master ~]# kubectl label pod replicaset-bhm6t app=xie --overwrite
[root@k8s-master ~]# kubectl get pods --show-labels
#恢复标签后
[root@k8s2 pod]# kubectl label pod replicaset-bhm6t app-
[root@k8s2 pod]# kubectl get pod --show-labels
#replicaset自动控制副本数量,pod可以自愈
[root@k8s-master ~]# kubectl delete pods replicaset- bhm6t
[root@k8s-master ~]# kubectl get pods --show-labels
回收资源
[root@master zuoye]# kubectl delete -f replicaset.yml
deployment 控制器
- 为了更好的解决服务编排的问题,kubernetes在V1.2版本开始,引入了Deployment控制器。
- Deployment控制器并不直接管理pod,而是通过管理ReplicaSet来间接管理Pod
- Deployment管理ReplicaSet,ReplicaSet管理Pod
- Deployment 为 Pod 和 ReplicaSet 提供了一个申明式的定义方法
- 在Deployment中ReplicaSet相当于一个版本
**典型的应用场景:**
- 用来创建Pod和ReplicaSet
- 滚动更新和回滚
- 扩容和缩容
- 暂停与恢复
deployment控制器示例
#生成yaml文件
[root@k8s-master ~]# kubectl create deployment deployment --image myapp:v1 --dry-run=client -o yaml > deployment.yml
[root@k8s-master ~]# vim deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment
spec:
replicas: 4
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- image: myapp:v1
name: myapp
#建立pod
root@k8s-master ~]# kubectl apply -f deployment.yml
daemonset控制器
DaemonSet 确保全部(或者某些)节点上运行一个 Pod 的副本。当有节点加入集群时, 也会为他们新增一个 Pod ,当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod
DaemonSet 的典型用法:
- 在每个节点上运行集群存储 DaemonSet,例如 glusterd、ceph。
- 在每个节点上运行日志收集 DaemonSet,例如 fluentd、logstash。
- 在每个节点上运行监控 DaemonSet,例如 Prometheus Node Exporter、zabbix agent等
- 一个简单的用法是在所有的节点上都启动一个 DaemonSet,将被作为每种类型的 daemon 使用
- 一个稍微复杂的用法是单独对每种 daemon 类型使用多个 DaemonSet,但具有不同的标志, 并且对不同硬件类型具有不同的内存、CPU 要求
daemonset 示例
[root@k8s2 pod]# cat daemonset-example.yml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: daemonset-example
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
tolerations: #对于污点节点的容忍
- effect: NoSchedule
operator: Exists
containers:
- name: nginx
image: nginx
[root@k8s-master ~]# kubectl get pods -o wide
job 控制器
job控制器功能
Job,主要用于负责批量处理(一次要处理指定数量任务)短暂的一次性(每个任务仅运行一次就结束)任务
Job特点如下:
- 当Job创建的pod执行成功结束时,Job将记录成功结束的pod数量
- 当成功结束的pod达到指定的数量时,Job将完成执行
job 控制器示例:
[root@k8s2 pod]# vim job.yml
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
completions: 6 #一共完成任务数为6
parallelism: 2 #每次并行完成2个
template:
spec:
containers:
- name: pi
image: perl:5.34.0
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] 计算Π的后2000位
restartPolicy: Never #关闭后不自动重启
backoffLimit: 4 #运行失败后尝试4重新运行
[root@k8s2 pod]# kubectl apply -f job.yml
cronjob 控制器
- Cron Job 创建基于时间调度的 Jobs。
- CronJob控制器以Job控制器资源为其管控对象,并借助它管理pod资源对象,
- CronJob可以以类似于Linux操作系统的周期性任务作业计划的方式控制其运行时间点及重复运行的方式。
- CronJob可以在特定的时间点(反复的)去运行job任务。
[root@k8s2 pod]# vim cronjob.yml
apiVersion: batch/v1
kind: CronJob
metadata:
name: hello
spec:
schedule: "* * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure
[root@k8s2 pod]# kubectl apply -f cronjob.yml
k8s中的微服务
什么是微服务
用控制器来完成集群的工作负载,那么应用如何暴漏出去?需要通过微服务暴漏出去后才能被访问
- Service是一组提供相同服务的Pod对外开放的接口。
- 借助Service,应用可以实现服务发现和负载均衡。
- service默认只支持4层负载均衡能力,没有7层功能。(可以通过Ingress实现)
服务类型 | 核心作用 | 访问方式 | 适用场景 | 关键特性 |
ClusterIP | 为集群内的 Pod 提供固定的内部访问地址,实现集群内部服务通信 | 仅能通过集群内的 ClusterIP:Port 访问(如 10.96.0.1:80) | 集群内部服务间通信(如前端服务调用后端 API、数据库服务被应用访问) | 1. 自动分配唯一的集群内部 IP(也可手动指定); |
NodePort | 在 ClusterIP 基础上,通过在集群所有节点开放静态端口,实现外部访问集群服务 | 外部可通过 任意节点IP:NodePort 访问(如 192.168.1.100:30080) | 开发 / 测试环境中临时暴露服务(如外部访问内部 API 进行调试) | 1. 会自动创建 ClusterIP,NodePort 是在其基础上的扩展; |
LoadBalancer | 在 NodePort 基础上,结合云厂商负载均衡器(或 MetalLB 等工具)提供外部访问 | 外部通过负载均衡器分配的公网 IP / 域名访问(如 http://10.1.2.3:80) | 生产环境中需要公网访问的服务(如 Web 应用、对外 API 服务) | 1. 自动创建 NodePort 和 ClusterIP,底层依赖外部负载均衡器; |
ExternalName | 将 Service 映射到集群外部的域名(如外部数据库、第三方 API),实现域名别名 | 集群内通过 Service 名称访问,自动解析为外部域名(如 external-service.default.svc.cluster.local 映射到 api.example.com) | 集群内服务需要访问外部固定域名的服务(如连接云厂商托管数据库、调用第三方 API) | 1. 不创建 ClusterIP 或端口,仅做域名映射; |
#生成控制器文件并建立控制器
[root@master zuoye]# kubectl create deployment xie --image myapp:v1 --replicas 2 --dry-run=client -o yaml > xie.yaml
[root@master zuoye]# kubectl create deployment xie --image myapp:v1 --replicas 2 --dry-run=client -o yaml >> xie.yaml
[root@k8s-master ~]# vim xie.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: xie
name: xie
spec:
replicas: 2
selector:
matchLabels:
app: xie
template:
metadata:
creationTimestamp: null
labels:
app: xie
spec:
containers:
- image: myapp:v1
name: myapp
--- #不同资源间用---隔开
apiVersion: v1
kind: Service
metadata:
labels:
app: xie
name: xie
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: xie
[root@master zuoye]# kubectl apply -f xie.yaml
[root@k8s-master ~]# kubectl get services
微服务默认使用iptables调度
ipvs模式
- Service 是由 kube-proxy 组件,加上 iptables 来共同实现的
- kube-proxy 通过 iptables 处理 Service 的过程,需要在宿主机上设置相当多的 iptables 规则,如果宿主机有大量的Pod,不断刷新iptables规则,会消耗大量的CPU资源
- IPVS模式的service,可以使K8s集群支持更多量级的Pod
在所有节点中安装ipvsadm
```bash
[root@k8s-所有节点 pod]yum install ipvsadm –y
[root@k8s-master ~]# kubectl -n kube-system edit cm kube-proxy
metricsBindAddress: ""
mode: "ipvs" #设置kube-proxy使用ipvs模式
nftables:
重启pod,在pod运行时配置文件中采用默认配置,当改变配置文件后已经运行的pod状态不会变化,所以要重启pod
微服务类型详解
clusterip
特点:
clusterip模式只能在集群内访问,并对集群内的pod提供健康检测和自动发现功能
[root@k8s2 service]# vim myapp.yml
---
apiVersion: v1
kind: Service
metadata:
labels:
app: xie
name: xie
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: xie
type: ClusterIP
service创建后集群DNS提供解析
[root@k8s-master ~]# dig xie.default.svc.cluster.local @10.96.0.10
; <<>> DiG 9.16.23-RH <<>> xie.default.svc.cluster.local @10.96.0.10
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 27827
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 057d9ff344fe9a3a (echoed)
;; QUESTION SECTION:
;xie.default.svc.cluster.local. IN A
;; ANSWER SECTION:
xie.default.svc.cluster.local. 30 IN A 10.97.59.25
;; Query time: 8 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Wed Sep 04 13:44:30 CST 2024
;; MSG SIZE rcvd: 127
ClusterIP中的特殊模式headless
headless(无头服务)
对于无头 `Services` 并不会分配 Cluster IP,kube-proxy不会处理它们, 而且平台也不会为它们进行负载均衡和路由,集群访问通过dns解析直接指向到业务pod上的IP,所有的调度有dns单独完成
[root@k8s-master ~]# vim xie.yaml
---
apiVersion: v1
kind: Service
metadata:
labels:
app: xie
name: xie
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: xie
type: ClusterIP
clusterIP: None
[root@k8s-master ~]# kubectl delete -f xie.yaml
[root@k8s-master ~]# kubectl apply -f xie.yaml
#测试
[root@k8s-master ~]# kubectl get services xie
nodeport
通过ipvs暴漏端口从而使外部主机通过master节点的对外ip:<port>来访问pod业务
[root@k8s-master ~]# vim xie.yaml
---
apiVersion: v1
kind: Service
metadata:
labels:
app: xie-service
name: xie-service
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: xie
type: NodePort
[root@k8s-master ~]# kubectl apply -f xie.yaml
[root@k8s-master ~]# kubectl get services xie-service
loadbalancer
云平台会为我们分配vip并实现访问,如果是裸金属主机那么需要metallb来实现ip的分配
[root@k8s-master ~]# vim xie.yaml
---
apiVersion: v1
kind: Service
metadata:
labels:
app: xie-service
name: xie-service
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: xie
type: LoadBalancer
默认无法分配外部访问IP
LoadBalancer模式适用云平台,裸金属环境需要安装metallb提供支持
metalLB
metalLB功能,为LoadBalancer分配vip
部署方式
1.设置ipvs模式
[root@k8s-master ~]# kubectl edit cm -n kube-system kube-proxy
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:
strictARP: true
[root@k8s-master ~]# kubectl -n kube-system get pods | awk '/kube-proxy/{system("kubectl -n kube-system delete pods "$1)}'
2.下载部署文件
[root@k8s2 metallb]# wget https://raw.githubusercontent.com/metallb/metallb/v0.13.12/config/manifests/metallb-native.yaml
3.修改文件中镜像地址,与harbor仓库路径保持一致
[root@k8s-master ~]# vim metallb-native.yaml
4.上传镜像到harbor
部署服务
[root@k8s2 metallb]# kubectl apply -f metallb-native.yaml
[root@k8s-master ~]# kubectl -n metallb-system get pods
配置分配地址段
[root@k8s-master ~]# vim configmap.yml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool #地址池名称
namespace: metallb-system
spec:
addresses:
- 172.25.254.50-172.25.254.99 #修改为自己本地地址段
--- #两个不同的kind中间必须加分割
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: example
namespace: metallb-system
spec:
ipAddressPools:
- first-pool #使用地址池
[root@k8s-master ~]# kubectl apply -f configmap.yml
[root@k8s-master ~]# kubectl get services
#通过分配地址从集群外访问服务
externalname
- 开启services后,不会被分配IP,而是用dns解析CNAME固定域名来解决ip变化问题
- 一般应用于外部业务和pod沟通或外部业务迁移到pod内时
- 在应用向集群迁移过程中,externalname在过度阶段就可以起作用了。
- 集群外的资源迁移到集群时,在迁移的过程中ip可能会变化,但是域名+dns解析能完美解决此问题
[root@k8s-master ~]# vim xie.yaml
---
apiVersion: v1
kind: Service
metadata:
labels:
app: xie-service
name: xie-service
spec:
selector:
app: xie
type: ExternalName
externalName: www.xie.org
[root@k8s-master ~]# kubectl apply -f xie.yaml
[root@k8s-master ~]# kubectl get services xie-service
Ingress-nginx
- 一种全局的、为了代理不同后端 Service 而设置的负载均衡服务,支持7层
- Ingress由两部分组成:Ingress controller和Ingress服务
- Ingress Controller 会根据你定义的 Ingress 对象,提供对应的代理能力。
- 业界常用的各种反向代理项目,比如 Nginx、HAProxy、Envoy、Traefik 等,都已经为Kubernetes 专门维护了对应的 Ingress Controller。
部署ingress
下载部署文件
[root@k8s-master ~]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.11.2/deploy/static/provider/baremetal/deploy.yaml
上传ingress所需镜像到harbor
[root@k8s-master ~]# docker tag registry.k8s.io/ingress-nginx/controller:v1.11.2@sha256:d5f8217feeac4887cb1ed21f27c2674e58be06bd8f5184cacea2a69abaf78dce reg.xie.org/ingress-nginx/controller:v1.11.2
[root@k8s-master ~]# docker tag registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.4.3@sha256:a320a50cc91bd15fd2d6fa6de58bd98c1bd64b9a6f926ce23a600d87043455a3 reg.xie.org/ingress-nginx/kube-webhook-certgen:v1.4.3
[root@k8s-master ~]# docker push reg.xie.org/ingress-nginx/controller:v1.11.2
[root@k8s-master ~]# docker push reg.xie.org/ingress-nginx/kube-webhook-certgen:v1.4.3
安装ingress
[root@k8s-master ~]# vim deploy.yaml
445 image: ingress-nginx/controller:v1.11.2
546 image: ingress-nginx/kube-webhook-certgen:v1.4.3
599 image: ingress-nginx/kube-webhook-certgen:v1.4.3
[root@k8s-master app]# vim myapp-v1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: myapp-v1
name: myapp-v1
spec:
replicas: 1
selector:
matchLabels:
app: myapp-v1
strategy: {}
template:
metadata:
labels:
app: myapp-v1
spec:
containers:
- image: myapp:v1
name: myapp
---
apiVersion: v1
kind: Service
metadata:
labels:
app: myapp-v1
name: myapp-v1
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: myapp-v1
[root@k8s-master app]# vim myapp-v2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: myapp-v2
name: myapp-v2
spec:
replicas: 1
selector:
matchLabels:
app: myapp-v2
template:
metadata:
labels:
app: myapp-v2
spec:
containers:
- image: myapp:v2
name: myapp
---
apiVersion: v1
kind: Service
metadata:
labels:
app: myapp-v2
name: myapp-v2
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: myapp-v2
[root@k8s-master app]# kubectl expose deployment myapp-v1 --port 80 --target-port 80 --dry-run=client -o yaml >> myapp-v1.yaml
[root@k8s-master app]# kubectl expose deployment myapp-v2 --port 80 --target-port 80 --dry-run=client -o yaml >> myapp-v1.yaml
基于域名的访问
[root@reg ~]# vim /etc/hosts
172.25.254.50 www.xie.org myappv1.xie.org myappv2.xie.org
# 建立基于域名的yml文件
[root@k8s-master app]# vim ingress.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
name: ingress2
spec:
ingressClassName: nginx
rules:
- host: myappv1.xie.org
http:
paths:
- backend:
service:
name: myapp-v1
port:
number: 80
path: /
pathType: Prefix
- host: myappv2.xie.org
http:
paths:
- backend:
service:
name: myapp-v2
port:
number: 80
path: /
pathType: Prefix
[root@k8s-master app]# kubectl expose deployment myapp-v1 --port 80 --target-port 80 --dry-run=client -o yaml >> myapp-v1.yaml
[root@k8s-master app]# kubectl expose deployment myapp-v2 --port 80 --target-port 80 --dry-run=client -o yaml >> myapp-v1.yaml
#利用文件建立ingress
[root@k8s-master app]# kubectl apply -f ingress.yml
[root@k8s-master app]# kubectl describe ingress ingress2
Canary金丝雀发布
什么是金丝雀发布
金丝雀发布(Canary Release)也称为灰度发布,是一种软件发布策略。
主要目的是在将新版本的软件全面推广到生产环境之前,先在一小部分用户或服务器上进行测试和验证,以降低因新版本引入重大问题而对整个系统造成的影响。
是一种Pod的发布方式。金丝雀发布采取先添加、再删除的方式,保证Pod的总量不低于期望值。并且在更新部分Pod后,暂停更新,当确认新Pod版本运行正常后再进行其他版本的Pod的更新。
基于header(http包头)灰度
- 通过Annotaion扩展
- 创建灰度ingress,配置灰度头部key以及value
- 灰度流量验证完毕后,切换正式ingress到新版本
- 之前我们在做升级时可以通过控制器做滚动更新,默认25%利用header可以使升级更为平滑,通过key 和vule 测试新的业务体系是否有问题。
[root@k8s-master app]# vim ingress7.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
name: myapp-v1-ingress
spec:
ingressClassName: nginx
rules:
- host: myapp.xie.org
http:
paths:
- backend:
service:
name: myapp-v1
port:
number: 80
path: /
pathType: Prefix
kubernetes下的存储管理
configmap的功能
- configMap用于保存配置数据,以键值对形式存储。
- configMap 资源提供了向 Pod 注入配置数据的方法。
- 镜像和配置文件解耦,以便实现镜像的可移植性和可复用性。
- etcd限制了文件大小不能超过1M
configmap的使用场景
- 填充环境变量的值
- 设置容器内的命令行参数
- 填充卷的配置文件
configmap创建方式
字面值创建,通过文件创建,通过目录创建,通过yaml文件创建
configmap的使用方式
- 通过环境变量的方式直接传递给pod
- 通过pod的 命令行运行方式
- 作为volume的方式挂载到pod内
使用configmap填充环境变量
[root@k8s-master ~]# vim testpod1.yml
apiVersion: v1
kind: Pod
metadata:
labels:
run: testpod
name: testpod
spec:
containers:
- image: busyboxplus:latest
name: testpod
command:
- /bin/sh
- -c
- env
env:
- name: key1
valueFrom:
configMapKeyRef:
name: lee4-config
key: db_host
- name: key2
valueFrom:
configMapKeyRef:
name: lee4-config
key: db_port
restartPolicy: Never
[root@k8s-master ~]# kubectl apply -f testpod.yml
[root@k8s-master ~]# kubectl logs pods/testpod
通过数据卷使用configmap
[root@k8s-master ~]# vim testpod4.yml
apiVersion: v1
kind: Pod
metadata:
labels:
run: testpod
name: testpod
spec:
containers:
- image: busyboxplus:latest
name: testpod
command:
- /bin/sh
- -c
- cat /config/db_host
volumeMounts: #调用卷策略
- name: config-volume #卷名称
mountPath: /config
volumes: #声明卷的配置
- name: config-volume #卷名称
configMap:
name: lee4-config
restartPolicy: Never
#查看日志
[root@k8s-master ~]# kubectl logs testpod
利用configMap填充pod的配置文件
#建立配置文件模板
[root@k8s-master ~]# vim nginx.conf
server {
listen 8000;
server_name _;
root /usr/share/nginx/html;
index index.html;
}
#利用模板生成cm
root@k8s-master ~]# kubectl create cm nginx-conf --from-file nginx.conf
configmap/nginx-conf created
[root@k8s-master ~]# kubectl describe cm nginx-conf
#建立nginx控制器文件
[root@k8s-master ~]# kubectl create deployment nginx --image nginx:latest --replicas 1 --dry-run=client -o yaml > nginx.yml
#设定nginx.yml中的卷
[root@k8s-master ~]# vim nginx.yml
[root@k8s-master ~]# cat nginx.
cat: nginx.: 没有那个文件或目录
[root@k8s-master ~]# cat nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx:latest
name: nginx
volumeMounts:
- name: config-volume
mountPath: /etc/nginx/conf.d
volumes:
- name: config-volume
configMap:
name: nginx-conf
#测试
[root@k8s-master ~]# kubectl get pods -o wide
[root@master zuoye]# curl 10.244.104.8:8000
secrets配置管理
secrets的功能介绍
- Secret 对象类型用来保存敏感信息,例如密码、OAuth 令牌和 ssh key。
- 敏感信息放在 secret 中比放在 Pod 的定义或者容器镜像中来说更加安全和灵活
- Pod 可以用两种方式使用 secret:
- 作为 volume 中的文件被挂载到 pod 中的一个或者多个容器里。
- 当 kubelet 为 pod 拉取镜像时使用。
- Secret的类型:
- Service Account:Kubernetes 自动创建包含访问 API 凭据的 secret,并自动修改 pod 以使用此类型的 secret。
- Opaque:使用base64编码存储信息,可以通过base64 --decode解码获得原始数据,因此安全性弱。
- kubernetes.io/dockerconfigjson:用于存储docker registry的认证信息
secrets的创建
在创建secrets时我们可以用命令的方法或者yaml文件的方法
从文件创建
```bash
[root@k8s-master secrets]# echo -n xie > username.txt
[root@k8s-master secrets]# echo -n lee > password.txt
root@k8s-master secrets]# kubectl create secret generic userlist --from-file username.txt --from-file password.txt
secret/userlist created
[root@k8s-master secrets]# kubectl get secrets userlist -o yaml
编写yaml文件
```bash
[root@k8s-master secrets]# echo -n xie | base64
dGltaW5nbGVl
[root@k8s-master secrets]# echo -n lee | base64
bGVl
[root@k8s-master secrets]# kubectl create secret generic userlist --dry-run=client -o yaml > userlist.yml
[root@k8s-master secrets]# vim userlist.yml
apiVersion: v1
kind: Secret
metadata:
creationTimestamp: null
name: userlist
type: Opaque
data:
username: dGltaW5nbGVl
password: bGVl
[root@k8s-master secrets]# kubectl apply -f userlist.yml
[root@k8s-master secrets]# kubectl describe secrets userlist
Secret的使用方法
将Secret挂载到Volume中
[root@k8s-master secrets]# kubectl run nginx --image nginx --dry-run=client -o yaml > pod1.yaml
#向固定路径映射
[root@k8s-master secrets]# vim pod1.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: nginx
name: nginx
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- name: secrets
mountPath: /secret
readOnly: true
volumes:
- name: secrets
secret:
secretName: userlist
[root@k8s-master secrets]# kubectl apply -f pod1.yaml
[root@k8s-master secrets]# kubectl exec pods/nginx -it -- /bin/bash
k8s下的网络通信与调度
k8s通信整体架构
- k8s通过CNI接口接入其他插件来实现网络通讯。目前比较流行的插件有flannel,calico等
- CNI插件存放位置:# cat /etc/cni/net.d/10-flannel.conflist
- 插件使用的解决方案如下
- 虚拟网桥,虚拟网卡,多个容器共用一个虚拟网卡进行通信。
- 多路复用:MacVLAN,多个容器共用一个物理网卡进行通信。
- 硬件交换:SR-LOV,一个物理网卡可以虚拟出多个接口,这个性能最好。
- 容器间通信:
- 同一个pod内的多个容器间的通信,通过lo即可实现pod之间的通信
- 同一节点的pod之间通过cni网桥转发数据包。
- 不同节点的pod之间的通信需要网络插件支持
- pod和service通信: 通过iptables或ipvs实现通信,ipvs取代不了iptables,因为ipvs只能做负载均衡,而做不了nat转换
- pod和外网通信:iptables的MASQUERADE
- Service与集群外部客户端的通信;(ingress、nodeport、loadbalancer)
flannel网络插件
插件组成:
| 插件 | 功能 |
| --------- | ------------------------------------------------------------ |
| VXLAN | 即Virtual Extensible LAN(虚拟可扩展局域网),是Linux本身支持的一网种网络虚拟化技术。VXLAN可以完全在内核态实现封装和解封装工作,从而通过“隧道”机制,构建出覆盖网络(Overlay Network) |
| VTEP | VXLAN Tunnel End Point(虚拟隧道端点),在Flannel中 VNI的默认值是1,这也是为什么宿主机的VTEP设备都叫flannel.1的原因 |
| Cni0 | 网桥设备,每创建一个pod都会创建一对 veth pair。其中一端是pod中的eth0,另一端是Cni0网桥中的端口(网卡) |
| Flannel.1 | TUN设备(虚拟网卡),用来进行 vxlan 报文的处理(封包和解包)。不同node之间的pod数据流量都从overlay设备以隧道的形式发送到对端 |
| Flanneld | flannel在每个主机中运行flanneld作为agent,它会为所在主机从集群的网络地址空间中,获取一个小的网段subnet,本主机内所有容器的IP地址都将从中分配。同时Flanneld监听K8s集群数据库,为flannel.1设备提供封装数据时必要的mac、ip等网络数据信息 |
### flannel跨主机通信原理
- 当容器发送IP包,通过veth pair 发往cni网桥,再路由到本机的flannel.1设备进行处理。
- VTEP设备之间通过二层数据帧进行通信,源VTEP设备收到原始IP包后,在上面加上一个目的MAC地址,封装成一个内部数据帧,发送给目的VTEP设备。
- 内部数据桢,并不能在宿主机的二层网络传输,Linux内核还需要把它进一步封装成为宿主机的一个普通的数据帧,承载着内部数据帧通过宿主机的eth0进行传输。
- Linux会在内部数据帧前面,加上一个VXLAN头,VXLAN头里有一个重要的标志叫VNI,它是VTEP识别某个数据桢是不是应该归自己处理的重要标识。
- flannel.1设备只知道另一端flannel.1设备的MAC地址,却不知道对应的宿主机地址是什么。在linux内核里面,网络设备进行转发的依据,来自FDB的转发数据库,这个flannel.1网桥对应的FDB信息,是由flanneld进程维护的。
- linux内核在IP包前面再加上二层数据帧头,把目标节点的MAC地址填进去,MAC地址从宿主机的ARP表获取。
- 此时flannel.1设备就可以把这个数据帧从eth0发出去,再经过宿主机网络来到目标节点的eth0设备。目标主机内核网络栈会发现这个数据帧有VXLAN Header,并且VNI为1,Linux内核会对它进行拆包,拿到内部数据帧,根据VNI的值,交给本机flannel.1设备处理,flannel.1拆包,根据路由表发往cni网桥,最后到达目标容器。
calico网络插件
calico简介:
- 纯三层的转发,中间没有任何的NAT和overlay,转发效率最好。
- Calico 仅依赖三层路由可达。Calico 较少的依赖性使它能适配所有 VM、Container、白盒或者混合环境场景。
calico网络架构
- Felix:监听ECTD中心的存储获取事件,用户创建pod后,Felix负责将其网卡、IP、MAC都设置好,然后在内核的路由表里面写一条,注明这个IP应该到这张网卡。同样如果用户制定了隔离策略,Felix同样会将该策略创建到ACL中,以实现隔离。
- BIRD:一个标准的路由程序,它会从内核里面获取哪一些IP的路由发生了变化,然后通过标准BGP的路由协议扩散到整个其他的宿主机上,让外界都知道这个IP在这里,路由的时候到这里
下载部署文件
[root@k8s-master calico]# curl https://raw.githubusercontent.com/projectcalico/calico/v3.28.1/manifests/calico-typha.yaml -o calico.yaml
下载镜像上传至仓库:
```bash
[root@k8s-master ~]# docker pull docker.io/calico/cni:v3.28.1
[root@k8s-master ~]# docker pull docker.io/calico/node:v3.28.1
[root@k8s-master ~]# docker pull docker.io/calico/kube-controllers:v3.28.1
[root@k8s-master ~]# docker pull docker.io/calico/typha:v3.28.1
更改yml设置
```bash
[root@k8s-master calico]# vim calico.yaml
4835 image: calico/cni:v3.28.1
4835 image: calico/cni:v3.28.1
4906 image: calico/node:v3.28.1
4932 image: calico/node:v3.28.1
5160 image: calico/kube-controllers:v3.28.1
5249 - image: calico/typha:v3.28.1
4970 - name: CALICO_IPV4POOL_IPIP
4971 value: "Never"
4999 - name: CALICO_IPV4POOL_CIDR
5000 value: "10.244.0.0/16"
5001 - name: CALICO_AUTODETECTION_METHOD
5002 value: "interface=eth0"
[root@k8s-master calico]# kubectl apply -f calico.yaml
[root@k8s-master calico]# kubectl -n kube-system get pods
k8s调度(Scheduling)
调度在Kubernetes中的作用
- 调度是指将未调度的Pod自动分配到集群中的节点的过程
- 调度器通过 kubernetes 的 watch 机制来发现集群中新创建且尚未被调度到 Node 上的 Pod
- 调度器会将发现的每一个未调度的 Pod 调度到一个合适的 Node 上来运行
调度原理:
- 创建Pod
- 用户通过Kubernetes API创建Pod对象,并在其中指定Pod的资源需求、容器镜像等信息。
- 调度器监视Pod
- Kubernetes调度器监视集群中的未调度Pod对象,并为其选择最佳的节点。
- 选择节点
- 调度器通过算法选择最佳的节点,并将Pod绑定到该节点上。调度器选择节点的依据包括节点的资源使用情况、Pod的资源需求、亲和性和反亲和性等。
- 绑定Pod到节点
- 调度器将Pod和节点之间的绑定信息保存在etcd数据库中,以便节点可以获取Pod的调度信息。
- 节点启动Pod
- 节点定期检查etcd数据库中的Pod调度信息,并启动相应的Pod。如果节点故障或资源不足,调度器会重新调度Pod,并将其绑定到其他节点上运行。
调度器种类
- 默认调度器(Default Scheduler):
- 是Kubernetes中的默认调度器,负责对新创建的Pod进行调度,并将Pod调度到合适的节点上。
- 自定义调度器(Custom Scheduler):
- 是一种自定义的调度器实现,可以根据实际需求来定义调度策略和规则,以实现更灵活和多样化的调度功能。
- 扩展调度器(Extended Scheduler):
- 是一种支持调度器扩展器的调度器实现,可以通过调度器扩展器来添加自定义的调度规则和策略,以实现更灵活和多样化的调度功能。
- kube-scheduler是kubernetes中的默认调度器,在kubernetes运行后会自动在控制节点运行
常用调度方法
nodename
- nodeName 是节点选择约束的最简单方法,但一般不推荐
- 如果 nodeName 在 PodSpec 中指定了,则它优先于其他的节点选择方法
- 使用 nodeName 来选择节点的一些限制
- 如果指定的节点不存在。
- 如果指定的节点没有资源来容纳 pod,则pod 调度失败。
- 云环境中的节点名称并非总是可预测或稳定的
实例:
```bash
#建立pod文件
[[root@k8s-master scheduler]# kubectl run testpod --image myapp:v1 --dry-run=client -o yaml > pod1.yml
#设置调度
[root@k8s-master scheduler]# vim pod1.yml
apiVersion: v1
kind: Pod
metadata:
labels:
run: testpod
name: testpod
spec:
nodeName: k8s-node2
containers:
- image: myapp:v1
name: testpod
#建立pod
[root@k8s-master scheduler]# kubectl apply -f pod1.yml
[root@k8s-master scheduler]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
testpod 1/1 Running 0 18s 10.244.169.130
affinity(亲和性)
亲和与反亲和
- nodeSelector 提供了一种非常简单的方法来将 pod 约束到具有特定标签的节点上。亲和/反亲和功能极大地扩展了你可以表达约束的类型。
- 使用节点上的 pod 的标签来约束,而不是使用节点本身的标签,来允许哪些 pod 可以或者不可以被放置在一起。
nodeAffinity节点亲和
- 那个节点服务指定条件就在那个节点运行
- requiredDuringSchedulingIgnoredDuringExecution 必须满足,但不会影响已经调度
- preferredDuringSchedulingIgnoredDuringExecution 倾向满足,在无法满足情况下也会调度pod
- IgnoreDuringExecution 表示如果在Pod运行期间Node的标签发生变化,导致亲和性策略不能满足,则继续运行当前的Pod。
- nodeaffinity还支持多种规则匹配条件的配置如
| 匹配规则 | 功能 |
| ------------ | --------------------------------------- |
| ln | label 的值在列表内 |
| Notln | label 的值不在列表内 |
| Gt | label 的值大于设置的值,不支持Pod亲和性 |
| Lt | label 的值小于设置的值,不支持pod亲和性 |
| Exists | 设置的label 存在 |
| DoesNotExist | 设置的 label 不存在 |
nodeAffinity示例
[root@k8s-master scheduler]# vim pod3.yml
apiVersion: v1
kind: Pod
metadata:
name: node-affinity
spec:
containers:
- name: nginx
image: nginx
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disk
operator: In | NotIn #两个结果相反
values:
- ssd
Podaffinity示例
[root@k8s-master scheduler]# vim example4.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx
topologyKey: "kubernetes.io/hostname"
[root@k8s-master scheduler]# kubectl get pods -o wide
Podantiaffinity(pod反亲和)
[root@k8s-master scheduler]# vim example5.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
affinity:
podAntiAffinity: #反亲和
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx
topologyKey: "kubernetes.io/hostname"
[root@k8s-master scheduler]# kubectl get pods -o wide
Taints(污点模式,禁止调度
- Taints(污点)是Node的一个属性,设置了Taints后,默认Kubernetes是不会将Pod调度到这个Node上
- Kubernetes如果为Pod设置Tolerations(容忍),只要Pod能够容忍Node上的污点,那么Kubernetes就会忽略Node上的污点,就能够(不是必须)把Pod调度过去
- 可以使用命令 kubectl taint 给节点增加一个 taint:
```
$ kubectl taint nodes <nodename> key=string:effect #命令执行方法
$ kubectl taint nodes node1 key=value:NoSchedule #创建
$ kubectl describe nodes server1 | grep Taints #查询
$ kubectl taint nodes node1 key- #删除
其中[effect] 可取值:
| effect值 | 解释 |
| ---------------- | ------------------------------------------------------------ |
| NoSchedule | POD 不会被调度到标记为 taints 节点 |
| PreferNoSchedule | NoSchedule 的软策略版本,尽量不调度到此节点 |
| NoExecute | 如该节点内正在运行的 POD 没有对应 Tolerate 设置,会直接被逐出 |
#建立控制器并运行
[root@k8s-master scheduler]# vim example6.yml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: web
name: web
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- image: nginx
name: nginx
[root@k8s-master scheduler]# kubectl apply -f example6.yml
#设定污点为NoSchedule
[root@k8s-master scheduler]# kubectl taint node node1
[root@k8s-master scheduler]# kubectl describe nodes k8s-node1 | grep Tain
#删除污点
[root@k8s-master scheduler]# kubectl describe nodes node1 | grep Tain
tolerations(污点容忍)
- tolerations中定义的key、value、effect,要与node上设置的taint保持一直:
- 如果 operator 是 Equal ,则key与value之间的关系必须相等。
- 如果 operator 是 Exists ,value可以省略
- 如果不指定operator属性,则默认值为Equal。
- 还有两个特殊值:
- 当不指定key,再配合Exists 就能匹配所有的key与value ,可以容忍所有污点。
- 当不指定effect ,则匹配所有的effect
#### 污点容忍示例:
```bash
#设定节点污点
[root@k8s-master scheduler]# kubectl taint node k8s-node1 name=lee:NoExecute
node/k8s-node1 tainted
[root@k8s-master scheduler]# kubectl taint node k8s-node2 nodetype=bad:NoSchedule
node/k8s-node2 tainted
[root@k8s-master scheduler]# vim example7.yml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: web
name: web
spec:
replicas: 6
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- image: nginx
name: nginx
tolerations: #容忍所有污点
- operator: Exists
tolerations: #容忍effect为Noschedule的污点
- operator: Exists
effect: NoSchedule
tolerations: #容忍指定kv的NoSchedule污点
- key: nodetype
value: bad
effect: NoSchedule
```
> [!NOTE]
>
> 三种容忍方式每次测试写一个即可
kubernetes中的认证授权
Authentication(认证)
- 认证方式现共有8种,可以启用一种或多种认证方式,只要有一种认证方式通过,就不再进行其它方式的认证。通常启用X509 Client Certs和Service Accout Tokens两种认证方式。
- Kubernetes集群有两类用户:由Kubernetes管理的Service Accounts (服务账户)和(Users Accounts) 普通账户。k8s中账号的概念不是我们理解的账号,它并不真的存在,它只是形式上存在。
Authorization(授权)
- 必须经过认证阶段,才到授权请求,根据所有授权策略匹配请求资源属性,决定允许或拒绝请求。授权方式现共有6种,AlwaysDeny、AlwaysAllow、ABAC、RBAC、Webhook、Node。默认集群强制开启RBAC。
认证(在k8s中建立认证用户)
创建UserAccount
#建立证书
[root@k8s-master auth]# cd /etc/kubernetes/pki/
[root@k8s-master pki]# openssl genrsa -out timinglee.key 2048
[root@k8s-master pki]# openssl req -new -key timinglee.key -out timinglee.csr -subj "/CN=timinglee"
[root@k8s-master pki]# openssl x509 -req -in timinglee.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out timinglee.crt -days 365
#建立k8s中的用户
[root@k8s-master pki]# kubectl config set-credentials timinglee --client-certificate /etc/kubernetes/pki/timinglee.crt --client-key /etc/kubernetes/pki/timinglee.key --embed-certs=true
User "timinglee" set.
[root@k8s-master pki]# kubectl config view
#为用户创建集群的安全上下文
root@k8s-master pki]# kubectl config set-context timinglee@kubernetes --cluster kubernetes --user timinglee
#切换用户,用户在集群中只有用户身份没有授权
[root@k8s-master ~]# kubectl config use-context timinglee@kubernetes
Switched to context "timinglee@kubernetes".
[root@k8s-master ~]# kubectl get pods
Error from server (Forbidden): pods is forbidden: User "timinglee" cannot list resource "pods" in API group "" in the namespace "default"
#切换会集群管理
[root@k8s-master ~]# kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".
#如果需要删除用户
[root@k8s-master pki]# kubectl config delete-user timinglee
deleted user timinglee from /etc/kubernetes/admin.conf
```
RBAC(Role Based Access Control)
基于角色访问控制授权:
- 允许管理员通过Kubernetes API动态配置授权策略。RBAC就是用户通过角色与权限进行关联。
- RBAC只有授权,没有拒绝授权,所以只需要定义允许该用户做什么即可
- RBAC的三个基本概念
- Subject:被作用者,它表示k8s中的三类主体, user, group, serviceAccount
- Role:角色,它其实是一组规则,定义了一组对 Kubernetes API 对象的操作权限。
- RoleBinding:定义了“被作用者”和“角色”的绑定关系
- RBAC包括四种类型:Role、ClusterRole、RoleBinding、ClusterRoleBinding
- Role 和 ClusterRole
- Role是一系列的权限的集合,Role只能授予单个namespace 中资源的访问权限。
- ClusterRole 跟 Role 类似,但是可以在集群中全局使用。
- Kubernetes 还提供了四个预先定义好的 ClusterRole 来供用户直接使用
- cluster-amdin、admin、edit、view
role授权实施
#生成role的yaml文件
[root@k8s-master rbac]# kubectl create role myrole --dry-run=client --verb=get --resource pods -o yaml > myrole.yml
#更改文件内容
[root@k8s-master rbac]# vim myrole.yml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
creationTimestamp: null
name: myrole
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- watch
- list
- create
- update
- path
- delete
#创建role
[root@k8s-master rbac]# kubectl apply -f myrole.yml
[root@k8s-master rbac]# kubectl describe role myrole
[root@k8s-master rbac]# kubectl create rolebinding timinglee --role myrole --namespace default --user timinglee --dry-run=client -o yaml > rolebinding-myrole.yml
[root@k8s-master rbac]# vim rolebinding-myrole.yml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: timinglee
namespace: default #角色绑定必须指定namespace
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: myrole
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: timinglee
[root@k8s-master rbac]# kubectl apply -f rolebinding-myrole.yml
rolebinding.rbac.authorization.k8s.io/timinglee created
[root@k8s-master rbac]# kubectl get rolebindings.rbac.authorization.k8s.io timinglee
#切换用户测试授权
[root@k8s-master rbac]# kubectl config use-context timinglee@kubernetes
Switched to context "timinglee@kubernetes".
[root@k8s-master rbac]# kubectl get pods
No resources found in default namespace.
[root@k8s-master rbac]# kubectl get svc #只针对pod进行了授权,所以svc依然不能操作
Error from server (Forbidden): services is forbidden: User "timinglee" cannot list resource "services" in API group "" in the namespace "default"
#切换回管理员
[root@k8s-master rbac]# kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".
#切换回管理员
[root@k8s-master rbac]# kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".