目录

Life in Flow

知不知,尚矣;不知知,病矣。
不知不知,殆矣。

X

K8S

应用部署演进

传统部署时代
早期的时候,在物理服务器上运行应用程序。缺点:

  • 无法限制在物理服务器中运行的应用程序资源使用,会导致资源分配问题,过高或过低
  • 部署多个物理机,维护许多物理服务器的成本很高

虚拟化部署时代
虚拟化技术允许在单个物理服务器的 CPU 上运行多台虚拟机(VM)。虚拟化能使应用程序在不同 VM 之间被彼此隔离,且能提供一定程度的安全性,能够更好地利用物理服务器的资源,具有更高的可伸缩性,以及降低硬件成本等等的好处。缺点:

  • 需要单独一个系统占用资源
  • 不能灵活的扩容和缩容

容器部署时代
容器类似于 VM,但是更宽松的隔离特性,使容器之间可以共享操作系统(OS)。容器比起 VM 被认为是更轻量级的,每个容器都具有自己的文件系统、CPU、内存、进程空间等。跨云和操作系统发行版本的可移植性:可在 Ubuntu、CoreOS、CentOS、 Google Kubernetes Engine 和其他任何地方运行。容器化部署存在的问题:

  • 10 个物理机发布 100 个容器,怎么快速发布和管理
  • 用户请求过来,怎么分配请求到 100 个容器里面
  • 突发海量请求过来,如何根据情况进行快速扩容
  • 应用发布上线出现问题,需要进行回滚历史版本,如何进行回滚
  • 某个容器故障了,如何快速启动新容器去替代
  • ....

上面容器管理的问题称为容器编排,为了解决这些问题,产生了一些容器编排的软件。

  • Docker Swarm :Docker 自己的容器编排工具
  • Mesos :Apache 的资源管控的工具,结合 Marathon 使用
  • Kubernetes :Google 开源的的容器编排工具, 基于内部 Borg 系统的开源版本

Kubernetes 简介

K8S的本质是一组服务器集群,可以在对应服务器集群的每个节点上运行程序,来对节点中的容器进行管理。类似Master-Work方式,每个服务器上安装特定的k8s组件,就可以形成集群,然后部署对应的应用即可。

核心功能

  • 服务发现和负载均衡
    • Kubernetes 可以使用 DNS 名称或自己的 IP 地址来暴露容器。
    • 如果进入容器的流量很大, Kubernetes 能够自动实现请求的负载均衡分配网络流量,从而使部署稳定
  • 存储编排
    • Kubernetes 允许自动挂载选择的存储系统,例如本地存储、云提供商存储等。
  • 自动部署和回滚
    • 可以用 k8s 自动化部署创建新容器, 删除现有容器并将它们的所有资源用于新容器。
    • 当版本发布错误,可以立刻回退到之前的版本
  • 自我修复
    • 如果某个容器宕机了,K8S 可以快速重新启动新的的容器,替换旧的容器
  • 密钥与配置管理
    • K8S 允许存储和管理敏感信息,例如密码、OAuth 令牌和 SSH 密钥

整体架构

K8S整体架构,也是Client-Server模型。

  • 控制节点 Master-Node,负责集群的管理
  • 工作节点 Worker-Node,负责为集群提供运行环境

Master-Node
控制节点,负责集群的管理。

  • apiserver:提供操作【k8s 集群资源】的唯一入口,RESTFul 方式请求,并提供认证、授权、访问控制、API 注册和发现等
  • scheduler:负责资源的调度,按照预定的调度策略,【计算】将 Pod 调度到相应的 Node 节点进行应用部署
  • controller-manager:控制器管理中心,负责维护集群的状态,比如故障检测、滚动更新等,根据调度器的安排通知对应的节点创建 pod
  • etcd:存储中心,是兼具一致性和高可用性的键值数据库,可以作为保存 Kubernetes 所有集群数据的后台数据库

Worker-Node
工作节点,负责为集群提供运行环境 。Node是Pod真正运行的主机,可以是物理机也可以是虚拟机, Node本质上不是K8S来创建的, K8S只是管理Node上的资源。
为了管理Pod,每个Node节点上至少需要运行container runtime(Docker)、kubelet和kube-proxy服务。

  • kubelet:相当于主节点派到工作节点的一个代表,用于管理本机容器(相当于 master 节点的化身),负责维护容器的生命周期也负责 Volume(CVI)和网络(CNI)的管理
  • kube-proxy:负责为 Service 提供 cluster 内部的服务发现/网络代理/负载均衡等操作,为部署的应用程序提供访问入口,和 apiserver 是不一样的,后者是操作 k8s 集群内部的

组件概念

Master
指的是集群控制节点(相当于整个集群的指挥中心),在每个Kubernetes集群里都需要有一个Master来负责整个集群的管理和控制。

Node
除了master,k8s集群中的其他机器被称为Node节点,Node节点才是kubernetes集群中的工作负载节点。每个Node节点都会被master分配一些工作负载(docker容器),node节点上的docker负责容器的运行。

Pod
Pod是一组容器, 在K8S中,最小的单位是Pod, 一个Pod可以包含多个容器,但通常情况下我们在每个Pod中仅使用一个容器。可以把Pod理解成豌豆荚, Pod内的每个容器是一颗颗豌豆

  • 自主创建:直接创建出来的 Pod,这种 pod 删除后就没有了,也不会自动重建
  • 控制器创建:通过控制器创建的 pod,这类 Pod 删除了之后还会自动重建

Pod Controller
控制器是管理pod的中间层,只需要告诉Pod控制器,想要创建多少个什么样的Pod,它会创建出满足条件的Pod并确保每一个Pod资源处于用户期望的目标状态。如果Pod在运行中出现故障,它会基于指定策略重新编排Pod。
通过它来实现对pod的管理,比如启动pod、停止pod、扩展pod的数量等等。
类型:ReplicaSet、Deployment、Horizontal Pod Autoscaler、DaemonSet等。

Service
在k8s里面,每个Pod都会被分配一个单独的IP地址,但这个IP地址会随着Pod的销毁而消失。
Service (服务)就是用来解决这个问题的, 对外服务的统一入口,用于为一组提供服务的Pod 抽象一个稳定的网络访问地址。 一个Service可以看作一组提供相同服务的Pod的对外访问接口,作用于哪些Pod是通过标签选择器来定义的

Label
K8S提供了一种机制来为Pod进行分类,那就是Label(标签),同一类pod会拥有相同的标签。
Label的具体形式是key-value的标记对,可以在创建资源的时候设置,也可以在后期添加和修改。
给某个资源对象定义一个Label,就相当于给它打了一个标签,可以通过Label Selector(标签选择器)查询和筛选拥有某些Label的资源对象,K8S通过这种方式实现了类似SQL的对象查询机制。

  • 未使用前,分散难管理,如果需要部署不同版本的应用到不同的环境中,难操作
  • 为 Pod 打上不同标签,使用 Label 组织的 Pod,轻松管理

Label 选择器
对应的资源打上标签后,可以使用标签选择器过滤指定的标签,标签选择器目前有两个:

  • 基于等值关系(等于、不等于)
  • 基于集合关系(属于、不属于、存在)

NameSpace
可以在一个物理集群上运行多个虚拟集群,这种虚拟集群被称作 命名空间,用来隔离pod的运行环境。

  • 同一个名字空间中的资源名称必须唯一,而不同名字空间之间则没有这个要求
  • NameSpace 是不能嵌套的,每一个 Kubernetes 的资源都只能在一个 NameSpace 内
  • 名字空间是在多个用户之间划分集群资源的一种方法(通过资源配额)
  • 不必使用多个名字空间来分隔轻微不同的资源,例如同一软件的不同版本: 应该使用标签 来区分同一名字空间中的不同资源
  • Kubernetes 会创建四个初始 NameSpace 名称空间:
    • default 没有指明使用其它名字空间的对象所使用的默认名字空间
    • kube-system Kubernetes 系统创建对象所使用的名字空间
    • kube-public
    • kube-node-lease

应用分类

  • 有状态应用
    • 不能简单的实现负载均衡的服务,有数据产生的服务,Redis、MySQL、RabbitMQ 等
    • 相关服务须通过一些较复杂的配置才能做到负载均衡。
    • 有状态的应用,建议直接在物理机部署,方便维护管理
  • 无状态应用
    • 没有对应业务数据的应用,可以简单的实现负载均衡,复制一个节点即可快速扩容,如 SpringCloud 中的业务服务
    • 无状态的应用适合部署在 Kubernetes(K8s)中或者容器中。

K8S 搭建

集群类型

集群类型 描述 硬件配置
单一个节点 单节点运行 服务器要求至少一台 2 核 4G 以上的云服务器
一主多从 一主多从 服务器要求至少 2 台 2 核 4G 以上的云服务器
多主多从 高可用集群 服务器要求至少 4 台 2 核 4G 以上的云服务器

K8S 搭建方式

  • kubeadm 搭建(推荐)是一个K8s部署工具,提供kubeadm init和kubeadm join 用于快速搭建k8s集群,比较推荐。
  • 二进制包搭建从github下载发行版的二进制包,手动部署每个组件, 组成Kubernetes集群,可以了解底层,但是步骤繁琐,坑比较多。
  • Minikube 搭建是一种轻量化的Kubernetes集群,是k8s社区为了帮助开发者和学习者能够更好学习和体验k8s功能而推出的,使用个人PC的虚拟化环境就快速构建启动单节点k8s。

Minikube 搭建单节点 k8s 集群

是一种轻量化的Kubernetes集群,是k8s社区为了帮助开发者和学习者能够更好学习和体验k8s功能而推出的,使用个人PC的虚拟化环境就快速构建启动单节点k8s。

 1########## 安装Docker
 2# 1.先安装yml
 3yum install -y yum-utils device-mapper-persistent-data lvm2
 4
 5# 2.设置阿里云镜像
 6yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
 7
 8# 3.查看可安装的docker版本
 9yum list docker-ce --showduplicates | sort -r
10
11#4. 安装docker
12yum -y install docker-ce-20.10.10-3.el7
13
14#5. 查看docker版本
15docker -v
16
17#配置开机自启动
18systemctl enable docker.service
19
20#6. 启动docker
21systemctl start docker
22
23#7. 查看docker 启动状态
24systemctl status docker
25
26########## 配置K8S镜像源(国外下载很慢)
27cat > /etc/yum.repos.d/kubernetes.repo << EOF
28[kubernetes]
29name=Kubernetes
30baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
31enabled=1
32gpgcheck=0
33repo_gpgcheck=0
34gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
35EOF
36
37
38########## 安装kubectl
39# 1.安装kubectl
40yum install -y kubectl-1.18.0
41
42########## 安装minikube
43# 1. 安装minikube
44curl -LO https://storage.googleapis.com/minikube/releases/v1.18.1/minikube-linux-amd64 && sudo install minikube-linux-amd64 /usr/local/bin/minikube
45
46# 2. 检查minikube安装是否成功
47[root@localhost yum.repos.d]# minikube  version
48minikube version: v1.18.1
49commit: 09ee84d530de4a92f00f1c5dbc34cead092b95bc
50
51# 3. 启动minikube
52minikube start --image-mirror-country='cn'  --driver=docker --force --kubernetes-version=1.18.1 --registry-mirror=https://registry.docker-cn.com
53
54# 4. 查看
55kubectl cluster-info

kubectl 常用命令

 1### 查看K8S集群信息
 2[root@localhost yum.repos.d]# kubectl cluster-info
 3Kubernetes master is running at https://192.168.49.2:8443
 4KubeDNS is running at https://192.168.49.2:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
 5
 6To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
 7
 8
 9### 查看节点信息
10[root@localhost yum.repos.d]# kubectl get node
11NAME       STATUS   ROLES    AGE   VERSION
12minikube   Ready    master   14m   v1.18.1
13
14
15### 查看内部组件
16[root@localhost yum.repos.d]# kubectl get pod -A
17NAMESPACE     NAME                               READY   STATUS             RESTARTS   AGE
18kube-system   coredns-546565776c-877x6           1/1     Running            0          14m
19kube-system   etcd-minikube                      1/1     Running            0          15m
20kube-system   kube-apiserver-minikube            1/1     Running            0          15m
21kube-system   kube-controller-manager-minikube   1/1     Running            0          15m
22kube-system   kube-proxy-5s5w5                   1/1     Running            0          14m
23kube-system   kube-scheduler-minikube            1/1     Running            0          15m
24kube-system   storage-provisioner                0/1     ImagePullBackOff   0          15m

署第一个 K8S 应用:Nginx

创建deployment(Pod控制器的一种, 直接删除pod后,会自动创建新的,需要删除deployment)

 1# kubectl部署应用
 2kubectl create deployment xdclass-nginx --image=nginx:1.23.0
 3
 4# 对比Docker部署
 5docker run  --name xdclass-nginx -p 8080:80 -d nginx:1.23.0
 6
 7# 查看pod
 8[root@localhost yum.repos.d]# kubectl get pod
 9NAME                             READY   STATUS              RESTARTS   AGE
10xdclass-nginx-859bdb9994-f77tr   0/1     ContainerCreating   0          9s
11
12# 查看deplayment
13[root@localhost yum.repos.d]# kubectl get deployment
14NAME            READY   UP-TO-DATE   AVAILABLE   AGE
15xdclass-nginx   0/1     1            0           72s
16
17# 同时查看多种类型
18[root@localhost yum.repos.d]# kubectl get pod,deployment
19NAME                                 READY   STATUS              RESTARTS   AGE
20pod/xdclass-nginx-859bdb9994-f77tr   0/1     ContainerCreating   0          2m51s
21
22NAME                            READY   UP-TO-DATE   AVAILABLE   AGE
23deployment.apps/xdclass-nginx   0/1     1            0           2m51s
24
25# 暴露80端口, 就是service服务
26[root@localhost yum.repos.d]# kubectl expose deployment xdclass-nginx --port=80  --type=NodePort
27service/xdclass-nginx exposed
28
29# 查看 svc (服务)
30[root@localhost yum.repos.d]# kubectl get svc
31NAME            TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
32kubernetes      ClusterIP   10.96.0.1      <none>        443/TCP        40m
33xdclass-nginx   NodePort    10.109.94.67   <none>        80:30470/TCP   12s
34
35# 转发端口(Mini Kube临时), kubectl port-forward 转发一个本地端口到 Pod 端口,不会返回数据,需要打开另一个终端来继续这个练习 
36kubectl port-forward  --address 0.0.0.0   service/xdclass-nginx 80:80
37
38# 访问 http://192.168.10.71/   
39Minikube的搭建跟用Kubeadm的有一点不一样
40Nodeport不能通过ip+端口直接访问,要通过minikube service(内网访问)和端口转发(公网访问)。

KubeAdm 搭建多节点 K8S 集群

  • 主机名区分:MasterNode、WorkerNode1
  • 防火墙关闭
  • 时间同步、时区一致

安装 Docker

 1########## 安装Docker
 2# 1.先安装yml
 3yum install -y yum-utils device-mapper-persistent-data lvm2
 4
 5# 2.设置阿里云镜像
 6yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
 7
 8# 3.查看可安装的docker版本
 9yum list docker-ce --showduplicates | sort -r
10
11#4. 安装docker
12yum -y install docker-ce-20.10.10-3.el7
13
14#5. 查看docker版本
15docker -v
16
17#配置开机自启动
18systemctl enable docker.service
19
20#6. 启动docker
21systemctl start docker
22
23#7. 查看docker 启动状态
24systemctl status docker

配置阿里云镜像源(主节点 + 工作节点)

1cat > /etc/yum.repos.d/kubernetes.repo << EOF
2[kubernetes]
3name=Kubernetes
4baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
5enabled=1
6gpgcheck=0
7repo_gpgcheck=0
8gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
9EOF

安装 kubelet kubeadm kubectl(主节点 + 工作节点)

1yum install -y kubelet-1.18.0 kubeadm-1.18.0 kubectl-1.18.0

主节点初始化(主节点)

 1# 关闭 swap分区
 2swapoff -a
 3
 4# 初始化
 5kubeadm init \
 6--apiserver-advertise-address=192.168.10.71 \
 7--image-repository registry.aliyuncs.com/google_containers \
 8--kubernetes-version v1.18.0 \
 9--service-cidr=10.96.0.0/12 \
10--pod-network-cidr=10.244.0.0/16
11
12只修改两个地方(master主机【内网IP】,k8s软件版本)
13
14
15说明:
16--apiserver-advertise-address:主节点的内网ip地址
17--image-repository 镜像仓库
18--kubernetes-version k8s版本
19--service-cidr + --pod-network-cidr 网段不重复即可
20
21
22#  主节点初始化
23mkdir -p $HOME/.kube
24sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
25sudo chown $(id -u):$(id -g) $HOME/.kube/config

入工作节点(工作节点)

 1kubeadm join 192.168.10.71:6443 --token 59jii3.njx7mosmp57wthb8 \
 2    --discovery-token-ca-cert-hash sha256:2ac62fc9462dc21296368751656ce5d30b78183063ae5a644278c54ee2507177
 3
 4
 5### 故障排查(参考)
 6# token过期
 7[root@localhost ~]# kubeadm token create
 8rdj0hp.beq71ql85wpbs2tk
 9kubeadm join 192.168.10.71:6443 --token rdj0hp.beq71ql85wpbs2tk \
10    --discovery-token-ca-cert-hash sha256:620f1669a7a9fad0a77faaebd293deda57551f23a10a31beb7b2160784becfed
11
12# node节点重新加入
13[root@workernode1 ~]# kubeadm reset

安装网络插件

 1# 状态都是NotReady,需要配置网络插件
 2[root@master tmp]# kubectl get nodes
 3NAME                    STATUS     ROLES    AGE   VERSION
 4localhost.localdomain   NotReady   master   32m   v1.18.0
 5workernode1             NotReady   <none>   20m   v1.18.0
 6
 7# 安装网络插件 kube-flannel
 8kubectl apply -f https://github.com/flannel-io/flannel/blob/master/Documentation/kube-flannel.yml
 9
10# 再次查看
11[root@master tmp]# kubectl get nodes
12NAME                    STATUS   ROLES    AGE   VERSION
13localhost.localdomain   Ready    master   33m   v1.18.0
14workernode1             Ready    <none>   21m   v1.18.0

署第一个 K8S 应用:Nginx

创建deployment(Pod控制器的一种, 直接删除pod后,会自动创建新的,需要删除deployment)

 1# kubectl部署应用
 2kubectl create deployment xdclass-nginx --image=nginx:1.23.0
 3
 4# 对比Docker部署
 5docker run  --name xdclass-nginx -p 8080:80 -d nginx:1.23.0
 6
 7# 查看pod
 8[root@localhost yum.repos.d]# kubectl get pod
 9NAME                             READY   STATUS              RESTARTS   AGE
10xdclass-nginx-859bdb9994-f77tr   0/1     ContainerCreating   0          9s
11
12# 查看deplayment
13[root@localhost yum.repos.d]# kubectl get deployment
14NAME            READY   UP-TO-DATE   AVAILABLE   AGE
15xdclass-nginx   0/1     1            0           72s
16# 暴露80端口, 就是service服务
17[root@localhost yum.repos.d]# kubectl expose deployment xdclass-nginx --port=80  --type=NodePort
18service/xdclass-nginx exposed
19
20# 查看 svc (服务)
21[root@master tmp]# kubectl get svc
22NAME            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
23kubernetes      ClusterIP   10.96.0.1        <none>        443/TCP        41m
24xdclass-nginx   NodePort    10.111.146.244   <none>        80:30573/TCP   3s
25
26###  Kubeadm部署,暴露端口对外服务,会随机选端口,默认范围是30000~32767,可以修改指定
27# 访问 MasterNode 
28http://192.168.10.71/      		成功
29http://192.168.10.71:30573/		成功
30
31# 访问 WorkerNode
32http://192.168.10.72/      		失败
33http://192.168.10.72:30573/		成功

常见资源管理命令

k8s是一个服务器集群系统,用户可以在集群中部署各种服务,也就是在k8s集群上运行一个个的容器。在k8s中,pod是最小的管理单元而非容器,一个pod中可以有多个容器。在k8s集群中,所有内容都可以被抽象为资源,通过操作资源来管理k8s集群。

kubectl 管理资源

 1kubectl [command] [TYPE] [NAME] [flags]
 2
 3commad:对资源具体的操作,如create创建、 get获取 、 delete删除
 4TYPE:指定资源类型,大小写敏感
 5NAME:指定资源的名称,大小写敏感,如果省略名称则显示所有资源
 6flags:指定可选的参数,如可用-s或者-server指定Kubernetes API server的地址和端口
 7
 8# 获取全部节点
 9kubectl get node
10
11# 获取全部pod
12kubectl get pod
13
14# 查看某个pod内容
15kubectl get pod pod_name
16
17#获取全部名称空间
18kubectl get ns
19
20
21# 查看创建的资源
22kubectl get pod,svc,deploy
23
24# 删除nginx pod,如果是靠deploy控制器创建的pod, 直接删除则会自动创建新的;
25# 如果需要删除则直接删除depoly控制器即可,pod会被删除
26kubectl delete pod pod名称
27kubectl delete deployment xdclass-nginx
28
29# 删除服务
30kubectl delete service xdclass-nginx

资源管理方式
kubectl create 命令首次执行时会创建资源,当再次执行的时候会报错,因为资源名称在同一命名空间内是唯一的。
kubectl apply在首次执行的时候也会创建对应的资源,当再次执行的时候会根据配置文件进行升级、扩容等操作,即使配置文件没有变化也不影响。

  • 命令式对象管理:直接使用命令去操作资源
    1kubectl run 资源名称 --image=镜像名称 --port=端口号
    2kubectl run xdclass-nignx-pod --image=nginx:1.23.0 --port=80
    3kubectl create deployment xdclass-nginx --image=nginx:1.23.0
    
  • 命令式对象配置:通过命令配置和配置文件去操作资源
    1kubectl create -f 配置文件名称.yaml
    
  • 声明式对象配置:通过 apply 和配置文件操作资源
    1kubectl apply -f 配置文件名称.yaml
    

YAML 文件内容

  • Deployment
 1apiVersion: apps/v1
 2kind: Deployment
 3metadata:
 4   name: nginx-deployment
 5   labels:
 6      app: nginx-deployment
 7spec:
 8   replicas: 1
 9   selector:
10      matchLabels:
11         app: nginx-pod
12   template:
13      metadata:
14           labels:
15              app: nginx-pod
16      spec:
17         containers:
18         - name: nginx
19             image: nginx:1.23.0
20             imagePullPolicy: IfNotPresent
21             ports:
22             - containerPort: 80
  • Pod
 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: nginx
 5spec:
 6  containers:
 7  - image: nginx:1.23.0
 8    name: pod
 9    ports:
10    - name: nginx-port
11      containerPort: 80
12      protocol: TCP

YAML 参数

yaml是一个类似 XML、JSON 的标记性语言。它强调以数据为中心,并不是以标识语言为重点。

语法格式

  • 通过缩进表示层级关系
  • 不能使用 tab 进行缩进,只能使用空格
  • 一般开头缩进两个空格
  • 大小写敏感
  • 字符后缩进一个空格,如冒号、逗号
  • 如果需要将多段 YAML 配置放在一个文件中,中间要使用 --- 分隔
  • 使用#表示注释

不需要从零手写,快速编写 YAML 文件,通过命令导出新的 YAML 文件

1# 创建nginx资源文件并且不启动资源
2kubectl create deployment xdclass-nginx --image=nginx:1.23.0 -o yaml --dry-run=client > nginx.yaml
3
4# 查看nginx.yaml
5cat nginx.yaml

精简版 YAML

 1apiVersion: apps/v1
 2kind: Deployment
 3metadata:
 4  creationTimestamp: null
 5  labels:
 6    app: xdclass-nginx
 7  name: xdclass-nginx
 8spec:
 9  replicas: 1
10  selector:
11    matchLabels:
12      app: xdclass-nginx
13  strategy: {}
14  template:
15    metadata:
16      creationTimestamp: null
17      labels:
18        app: xdclass-nginx
19    spec:
20      containers:
21      - image: nginx:1.23.0
22        name: nginx
23        resources: {}
24status: {}

pod 的 YAML 文件示例

 1# pod的最基础的yaml文件最少需要以下的几个参数
 2apiVersion: v1 # API版本号,注意:具有多个,不同的对象可能会使用不同API
 3kind: Pod  # 对象类型,pod
 4metadata:  # 元数据
 5  name: string # POD名称
 6  namespace: string # 所属的命名空间
 7spec: # specification of the resource content(资源内容的规范)
 8  containers: # 容器列表
 9    - name: string # 容器名称
10      image: string # 容器镜像

查看所有资源

1#查看资源
2kubectl api-resources
3
4#查看命令帮助
5kubectl --help

常用资源分类和缩写

  • 节点 nodes ,缩写 no
  • 名称空间 namespaces,缩写 ns
  • pod 资源 pods, 缩写 po
  • pod 控制器
    • replicasets,缩写 rs
    • deployments,缩写 deploy
  • 服务发现
    • 统一 pod 对外接口 services ,缩写 svc
    • 统一 pod 对外接口ingress ,缩写 ing
  • 存储资源
    • persistentvolumes,缩写 pv
    • persistentvolumeclaims,缩写 pvc
命令分类 命令 翻译
基本命令 create 创建资源
delete 删除资源
edit 编辑资源
get 获取资源
patch 更新资源
explain 解释资源
运行和调试 run 运行指定的镜像
expose 暴露服务
describe 描述资源内部信息
logs 打印容器在 pod 中的日志
attach 进入运行中的容器
exec 执行容器中的一个命令
cp 在 Pod 内外复制文件
scale 扩容/缩容 Pod 的数量
autoscale 扩容/缩容 Pod 的数量
高级命令 apply rc
label 标签
其他命令 cluster-info 集群信息
version 版本
1[root@master ~]# kubectl describe pod xdclass-nginx-859bdb9994-hc86v
2
3[root@master ~]# kubectl describe deployment  xdclass-nginx

名称空间

Namespace是k8s系统中的一种非常重要资源,它的主要作用是用来实现多套环境的资源隔离或者多用户的资源隔离。

  • 默认情况下,k8s 集群中的所有的 Pod 都是可以相互访问的。
  • 但是在实际中,可能不想让两个 Pod 之间进行互相的访问,那此时就可以将两个 Pod 划分到不同的 namespace 下。
  • k8s 通过将集群内部的资源分配到不同的 Namespace 中,可以形成逻辑上的"组",以方便不同的组的资源进行隔离使用和管理。
  • 可以通过 k8s 的授权机制,将不同的 namespace 交给不同租户进行管理,这样就实现了多租户的资源隔离。
  • 结合 k8s 的资源配额机制,限定不同租户能占用的资源,例如 CPU 使用量、内存使用量等等,来实现租户可用资源的管理。

Kubernetes 会创建四个初始NameSpace名称空间

  • default
    • 没有指明使用其它名字空间的对象所使用的默认名字空间
  • kube-system
    • Kubernetes 系统创建对象所使用的名字空间
  • kube-public
    • 是自动创建的,命名空间下的资源可以被所有人访问(包括未认证用户)
  • kube-node-lease
    • 集群节点之间的心跳维护

查看所有命令空间

1kubectl get namespace
2
3缩写
4kubectl get ns

命名空间操作

 1# 创建新命名空间
 2  kubectl create ns dev
 3
 4# 查看命名空间详情  
 5  kubectl describe ns dev
 6
 7# 指定输出格式  命令:kubectl get ns ns名称  -o 格式参数, 常见的是wide、json、yaml
 8# 输出命名空间详细信息
 9  kubectl get ns dev -o yaml
10  
11# 删除命名空间
12  kubectl delete ns dev
13  
14# 基于配置文件方式 namespace-dev.yaml
15  
16apiVersion: v1
17kind: Namespace
18metadata:
19  name: dev
20
21创建:kubectl create -f namespace-dev.yaml
22
23创建:kubectl apply -f namespace-dev.yaml
24
25删除:kubectl delete -f namespace-dev.yaml

Label Selector

K8S提供了一种机制来为资源进行分类,那就是Label(标签),同一类资源会拥有相同的标签。具体形式是key-value的标记对,可以在创建资源的时候设置,也可以在后期添加和修改。可以附加到各种资源对象上,如Node,Pod,Service,RC等 ……
一个资源拥有多个标签,可以实现不同维度的管理。给某个资源对象定义一个Label,就相当于给它打了一个标签,可以通过Label Selector(标签选择器)查询和筛选拥有某些Label的资源对象,K8S通过这种方式实现了类似SQL的对象查询机制,每个资源都存在多维度属性。

1版本标签:"release" : "stable" , "release" : "canary"...
2
3环境标签:"environment" : "dev" , "environment" : "production"
4
5架构标签:"tier" : "frontend" , "tier" : "backend" , "tier" : "middleware"
6
7分区标签:"partition" : "customerA" , "partition" : "customerB"...
  • 未使用前,分散难管理,如果需要部署不同版本的应用到不同的环境中,难操作
  • 为 Pod 打上不同标签,使用 Label 组织的 Pod,轻松管理

Label selector

Label selector是Kubernetes核心的分组机制,通过label selector客户端/用户能够识别一组有共同特征或属性的资源对象,对应的资源打上标签后,可以使用标签选择器过滤指定的标签。
标签选择器目前有两个:

  • matchLabels 用于定义一组 Label , 基于等值关系(等于、不等于) ,类似于 SQL 语句中的 = 或!=
  • matchExpressions 基于集合关系(属于、不属于、存在) ,类似于 SQL 语句中的 in 或 not in
  • 如果同时设置了 matchLabels 和 matchExpressions,则两组条件为 AND 关系,即需要同时满足所有条件才能完成 Selector 的筛选。

命令用法

 1# 通过 deployment控制器导出yaml文件,指定名称空间
 2kubectl create deployment xdclass-nginx --image=nginx:1.23.0 --namespace dev -o yaml --dry-run=client > nginx.yaml
 3
 4
 5#命令默认不会列出任何标签
 6kubectl get pods 
 7
 8# 使用 --show-labels 选项来查看
 9kubectl get pod -n dev --show-labels 
10
11# 查看 deploy控制器标签
12kubectl get deploy -n dev --show-labels
13
14# 查看 pod 标签
15kubectl get pod -n dev --show-labels
16
17# 查看node节点标签
18kubectl get node  --show-labels
19
20# 给Pod资源打标签
21kubectl label pod pod名称 -n dev version=1.0
22kubectl label pod xdclass-nginx-859bdb9994-jkm58 -n dev version=1.0
23
24# 给Pod资源更新标签
25kubectl label pod pod名称 -n dev version=2.0 --overwrite
26kubectl label pod xdclass-nginx-859bdb9994-jkm58 -n dev version=2.0 --overwrite
27
28# 使用标签选择器
29kubectl get pod -l "version=2.0" -n dev --show-labels
30kubectl get pod -l "version!=2.0" -n dev --show-labels
31
32
33# 删除标签 语法 kubectl label pod pod名称 -n dev 标签名-
34kubectl label pod pod名称 -n dev version-
35kubectl label pod xdclass-nginx-859bdb9994-jkm58 -n dev version-

Pod

Pod是一组容器, 在K8S中,最小的单位是Pod, 一个Pod可以包含多个容器,但通常情况下我们在每个Pod中仅使用一个容器,可以把Pod理解成豌豆荚, Pod内的每个容器是一颗颗豌豆。
Pod 的核心是运行容器,必须指定容器引擎,比如 Docker是其中一种技术。

Pod 分类
自主创建:直接创建出来的 Pod,这种 pod 删除后就没有了,也不会自动重建

1kubectl run xdclass-nignx-pod --image=nginx:1.23.0 --port=80

控制器创建:通过控制器创建的 pod,这类 Pod 删除了之后还会自动重建

1kubectl create deployment xdclass-nginx --image=nginx:1.23.0

Pod 运行容器数量
• 每个 Pod 中一个容器的模式是最常见的用法,Pod 是容器的简单封装,K8S 管理 Pod 而不是直接管理容器。
• 一个 Pod 中同时运行多个需要互相协作的容器,它们共享资源,同一个 Pod 中的容器可以作为 service 单位。

Pod 网络
• 一个 pod 包含一组容器,一个 pod 不会跨越多个工作节点
• 每个 Pod 都会被分配一个唯一的 IP 地址,Pod 中的所 有容器共享网络空间,包括 IP 地址和端口
• Pod 内 部的容器可以使用 localhost 互相通信

Pod 存储
• Volume 也可以用来持久化 Pod 中的存储资源,以防容器重启后文件丢失
• Pod 中 的所有容器都可以访问共享的 Volume

K8S集群中的系统组件都是以Pod方式运行的

 1[root@master ~]# kubectl get pod -n kube-system
 2NAME                                            READY   STATUS    RESTARTS   AGE
 3coredns-7ff77c879f-p77rl                        1/1     Running   0          2d16h
 4coredns-7ff77c879f-xmvs5                        1/1     Running   0          2d16h
 5etcd-localhost.localdomain                      1/1     Running   0          2d16h
 6kube-apiserver-localhost.localdomain            1/1     Running   0          2d16h
 7kube-controller-manager-localhost.localdomain   1/1     Running   0          2d16h
 8kube-proxy-fgtgx                                1/1     Running   0          2d16h
 9kube-proxy-g2kxc                                1/1     Running   0          2d16h
10kube-scheduler-localhost.localdomain            1/1     Running   0          2d16h

命令

 1# 自主创建Pod
 2kubectl run xdclass-nignx-pod --image=nginx:1.23.0 --port=80
 3
 4# 自主创建Pod,指定名称空间
 5kubectl run xdclass-nignx-pod --image=nginx:1.23.0 --port=80 --namespace dev
 6
 7# 通过控制器创建Pod
 8kubectl create deployment xdclass-nginx --image=nginx:1.23.0
 9
10# 通过 deployment控制器导出yaml文件,指定名称空间
11kubectl create deployment xdclass-nginx --image=nginx:1.23.0 --namespace dev -o yaml --dry-run=client > nginx.yaml
12
13#查看创建的资源
14kubectl get pod,deploy 
15
16# 删除nginx pod,如果是靠deploy控制器创建的pod, 直接删除则会自动创建新的;
17kubectl delete pod xdclass-nginx -n dev
18
19
20# 通过控制器创建pod,则删除控制器即可
21kubectl delete deploy xdclass-nginx -n dev
22
23#一次性部署3个pod,修改nginx.yaml 下面的从 1 改为 3
24#使用 kubectl apply -f nignx.yaml
25spec:
26  replicas: 3

Pod 底层原型

每个Pod中都可以包含一个或者多个容器,这些容器可以分为两类:

  • 用户程序所在的容器:数量可多可少
  • Pause 容器:这是每个 Pod 都会有的一个根容器,它的作用有两个:
    • 以它为依据,评估整个 Pod 的健康状态
    • 可以在根容器上设置 Ip 地址,Pod 内的其它容器都以此 Ip(Pod IP),以实现 Pod 内部的网路通信

  • 通过共享网络
    • 通过 pause 容器,把其他业务容器加入到 pause 容器里面,让所有业务容器在同一个 namespace 中,可以实现网络共享
  • 通过共享存储
    • 引入数据卷 volume 的概念,使用数据卷进行持久化存储

pod 镜像拉取策略 imagesPullPolicy

  • IfNotPresent:默认值,镜像在宿主机上不存在时才拉取
  • Always:每次创建 pod 都会重新拉取一次镜像
  • Never:pod 永远不会主动拉取这个镜像

pod 资源限制

  • requests: 资源请求量,当容器运行时,向 Node 申请的最少保障资源
  • limits: 资源上限,容器在 Node 上所能消耗的最高上限
 1resources:
 2  requests:
 3    memory:"内存大小"
 4    cpu:"cpu占用大小"
 5  limits: 
 6    memory:"内存占用大小"
 7    cpu:"cpu占用大小"
 8    
 9——————————————————————————————————————————————
10CPU 资源以 CPU 单位度量。Kubernetes 中的一个 CPU 等同于:
111 个 AWS vCPU
121 个 Azure vCore
13
14例如 100m CPU、100 milliCPU 和 0.1 CPU 都相同
15
16文档地址:
17https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/assign-cpu-resource/

Pod 创建流程与调度策略

通过kubectl apply -f xxx.yaml 创建pod。

1、kubectl 向 apiserver 发送创建 pod 的请求
2、 apiserver 把 pod 的创建信息存储到 etcd 进行保存
3、 scheduler 监听到未绑定 node 的 pod 资源,通过调度算法对该 pod 资源选定一个合适的 node 进行绑定,然后响应给 apiserver,更新 pod 状态并存储到 etcd 中
4、 在绑定的 node 中,Controller-Manager 通知 kubelet 收到分配到自身节点上的 pod,调用容器引擎 API 创建容器,并把容器状态响应给 apiserver

在默认情况下,一个Pod在哪个Node节点上运行,是由Scheduler组件采用相应的算法计算出来的,这个过程是不受人工控制的。但是在实际使用中,这并不满足的需求,因为很多情况下,我们想控制某些Pod到达某些节点上,那么应该怎么做呢?这就要求了解k8s对Pod的调度规则。

影响 pod 调度的因素:

  • pod 资源限制:scheduler 根据 requests 找到足够大小的 node 进行调度
  • 节点选择器标签(nodeSelector)
    • 把节点进行区分,例如 dev 开发环境和 prod 生产环境
    • 例如,当前需要把 pod 调度到开发环境中,则可以通过 scheduler 将 pod 调度到标签选择器中为 env_role:dev 的 node 中
      1nodeSelector: 
      2  env_role:dev/prod
      

NodeSelector

当Pod 一直处于 Pending 状态时,说明该 Pod 还未被调度到某个节点上。Pod 中 nodeSelector 指定了节点 Label,调度器将只考虑调度 Pod 到包含该 Label 的 Node 上,当不存在符合该条件的 Node 时,Pod 将无法被调度。

 1# 查看node节点标签
 2kubectl get node --show-labels
 3
 4# 给Node资源打标签,不能给master打标签
 5kubectl label node workernode1 env=test
 6
 7# 删除 node的标签 kubectl label node 删除指定的labels(标签 key 接 - 号即可)
 8kubectl label node workernode1 env-
 9
10# 列出所有正在运行的Pod及其对应的节点名称
11kubectl get pods -o wide
12
13# 查看指定Pod的更多详细信息
14kubectl describe  pod xdclass-nginx
15
16# 配置文件
17[root@master tmp]# cat nginx_label.yaml
18apiVersion: v1
19kind: Pod
20metadata:
21  name: xdclass-nginx
22spec:
23  containers:
24  - name: nginx
25    image: nginx:1.23.0
26    imagePullPolicy: IfNotPresent
27  nodeSelector:
28    env: test
29
30# 创建pod
31kubectl apply -f nginx.yaml

Pod Controller

控制器是管理pod的中间层,只需要告诉Pod控制器,想要创建多少个什么样的Pod,它会创建出满足条件的Pod,相当于一个状态机,用来控制Pod的具体状态和行为。controller会自动创建相应的pod资源,并在当pod发生故障的时候按照策略进行重新编排
通过它来实现对pod的管理,比如启动pod、停止pod、扩展pod的数量等等.
yaml文件中 kind 填写对应的类型即可

Pod Controller 的类型

ReplicaSet
一种副本控制器,简称rs,主要是控制由其管理的pod,使pod副本的数量始终维持在预设的个数,并支持pod数量扩缩容,镜像版本升级。官方建议不要直接使用ReplicaSet,用Deployments更好,并提供很多其它有用的特性。

Deployment
通过控制ReplicaSet来控制Pod,并支持滚动升级、回退版本,适合无状态的服务部署。
当某个应用有新版本发布时,Deployment会同时操作两个版本的ReplicaSet。其内置多种滚动升级策略,会按照既定策略降低老版本的Pod数量,同时也创建新版本的Pod。
Deployment控制器不直接管理Pod对象,而是 Deployment 管理ReplicaSet, 再由ReplicaSet管理Pod对象。

DaemonSet
在K8S集群部署中由于节点数量不定,那么如果我们需要对每个节点中都运行一个守护进程、日志收集进程等情况时,在k8s中如何实现呢?
这个时候就是DaemonSet应用场景了,这类Pod运行在K8S 集群里的每一个节点(Node)上,确保所有节点上有且仅有一个。
有新的节点加入 K8S集群后,该 Pod 会自动地在新节点上被创建出来,而当旧节点被删除后,它上面的 Pod也相应地会被回收掉。
应用场景:监控告警Agent、日志组件、监控组件等

StatefulSet
像RS、Deployment、DaemonSet都是面向无状态的服务,所管理的Pod的IP、名字,启停顺序都是随机。
StatefulSet就是有状态的集合,管理所有有状态的服务,StatefulSet 中的 Pod 具有黏性的、独一无二的身份标识,重新调度后PodName和HostName不变。
Pod重新调度后还是能访问到相同的持久化数据,基于PVC实现。 分配给每个 Pod 的唯一顺序索引,Pod 的名称的形式为。

1<statefulset name>-<ordinal index>

应用场景:比如MySQL、MongoDB集群

Horizontal Pod Autoscaler
可以基于 CPU 利用率或其他指标实现Pod水平自动扩缩
被伸缩的pod需要是通过deployment或者replica set管理
HPA不能应用于不可伸缩的对象,如:DaemonSets
由资源来决定控制器行为,控制器周期性调整目标pod的副本数量,让目标pod的实际cpu使用率符合用户指定的数值

Job
普通任务容器控制器,只会执行一次,只要完成任务就立即退出,不需要重启或重建
容器中的进程在正常运行结束后不会对其进行重启,而是将pod对象置于completed状态
若容器中的进程因错误而终止,则需要依据配置确定是否需要重启
应用场景:批处理程序,完成后容器就退出等

Cronjob
Linux 中有 cron 程序定时执行任务,K8s的 CronJob 提供了类似的功能,可以定时执行 Job
创建的Pod负责周期性任务控制
应用场景:执行周期性的重复任务,如备份数据、发送邮件、数据报表、报告生成等

ReplicaSet

一种副本控制器,简称rs,主要是控制由其管理的pod,使pod副本的数量始终维持在预设的个数,并支持pod数量扩缩容,镜像版本升级。官方建议不要直接使用ReplicaSet,用Deployments更好,并提供很多其它有用的特性。

 1apiVersion: apps/v1 # 版本号
 2kind: ReplicaSet  # 资源文件 
 3metadata: # 元对象信息
 4  name: xdclass-rs # rs控制器名称
 5  namespace: dev # 名称空间 
 6spec: # 具体详情
 7  replicas: 5 # 副本数量
 8  selector: # 选择器,指定rs控制器管理哪些pod资源
 9    matchLabels: # 标签匹配规则
10      app: xdclass-nginx-pod # 标签key是app,值是xdclass-nginx-pod
11      
12  template: # pod模板,当数量不满足的时候,根据下面编码创建pod副本
13    metadata: # 元对象信息
14      labels: # pod资源标签
15        app: xdclass-nginx-pod
16    spec: # 具体详情
17      containers: # 容器数组列表
18      - name: xdclass-nginx  # 容器名称
19        image: nginx:1.23.0  # 镜像和版本

replicaset-nginx.yaml

 1apiVersion: apps/v1
 2kind: ReplicaSet   
 3metadata:
 4  name: xdclass-rs
 5  namespace: dev
 6spec:
 7  replicas: 5
 8  selector: 
 9    matchLabels:
10      app: xdclass-nginx-pod
11  template:
12    metadata:
13      labels:
14        app: xdclass-nginx-pod
15    spec:
16      containers:
17      - name: xdclass-nginx
18        image: nginx:1.23.0

其他操作

 1# 创建
 2kubectl apply -f replicaset-nginx.yaml
 3
 4# 查看
 5kubectl get pods,deploy,replicaset -o wide -n dev
 6
 7# 命令行缩容
 8kubectl scale rs xdclass-rs --replicas=2 -n dev
 9
10# 删除,可以直接删除rs;也可以通过yaml删除
11kubectl delete -f replicaset-nginx.yaml

Deployment

通过控制ReplicaSet来控制Pod,并支持滚动升级、回退版本,适合无状态的服务部署。
当某个应用有新版本发布时,Deployment会同时操作两个版本的ReplicaSet。其内置多种滚动升级策略,会按照既定策略降低老版本的Pod数量,同时也创建新版本的Pod。
Deployment控制器不直接管理Pod对象,而是 Deployment 管理ReplicaSet, 再由ReplicaSet管理Pod对象。
总结:Deployment、ReplicaSet、Pod三者之间是一种阶梯控制的关系

deploy-nginx-pod.yaml

 1apiVersion: apps/v1
 2kind: Deployment
 3metadata:
 4  name: xdclass-deploy
 5  namespace: dev
 6spec:
 7  replicas: 5
 8  selector: 
 9    matchLabels:
10      app: xdclass-nginx-pod
11  template:
12    metadata:
13      labels:
14        app: xdclass-nginx-pod
15    spec:
16      containers:
17      - name: xdclass-nginx
18        image: nginx:1.23.0

其他操作

 1#创建
 2kubectl apply -f deploy-nginx-pod.yaml
 3
 4# 查看deployment
 5kubectl get deployment -n dev
 6
 7#查看
 8kubectl get pods,deploy,replicaset -o wide -n dev
 9
10# 删除,通过yaml删除
11kubectl delete -f deploy-nginx-pod.yaml
12
13# 检查集群中的 Deployment 时,所显示的字段有:* `NAME` 列出了集群中 Deployment 的名称。
14* `READY` 显示应用程序的可用的“副本”数,格式是“就绪个数/期望个数”。
15* `UP-TO-DATE` 显示为了达到期望状态已经更新的副本数。
16* `AVAILABLE` 显示可用的副本数。
17* `AGE` 应用程序运行的时间。

Deployment 控制器滚动升级 (金丝雀发布 or 灰度发布)
对各个实例批次进行单独更新,而非同一时刻对所有实例进行全部更新,达到不中断服务的更新升级方式。
Deployment控制器给旧版本(old_rs)副本数减少至0、给新版本(new_rs)副本数量增至期望值(replicas)。
Deployment更新有两种方式:

  • Recreate : 删除全部旧的pod,然后创建新的pod。服务会中断。
  • RollingUpdate:滚动升级更新,删除部分,更新部分,在整个更新过程中,存在两个版本的 pod
    • maxUnavailable
      1升级过程中不可用Pod的最大数量,默认为25%
      2在滚动更新时,我们可以忍受多少个 Pod 无法提供服务
      3值越小越能保证服务稳定,更新越平滑
      
    • maxSurge
      1升级过程中可以超过期望的Pod的最大数量,默认为25%;
      2在滚动更新时,可以有多少个额外的 Pod
      3值调的越大,副本更新速度越快
      

RollingUpdate 说明属性说明

1MaxUnavailable为0, 在新 Pod 启动并就绪之前,不要关闭任何旧Pod
2MaxSurge为100%, 立即启动所有新 Pod,也就是有足够的资源希望尽快完成更新。
3
4默认两个值都是 25%
5  如果更新一个 100 Pod 的 Deployment,会立刻创建 25 个新 Old,同时会关闭 25 个旧 Pod;
6  每次有 Pod 启动就绪,就可以关闭旧 Pod

deploy-rollout.yaml

 1apiVersion: apps/v1
 2kind: Deployment
 3metadata:
 4  name: xdclass-deploy
 5  namespace: dev
 6spec:
 7  replicas: 5
 8  revisionHistoryLimit: 5  #保留历史版本5个
 9  strategy: 
10    type: RollingUpdate
11  selector: 
12    matchLabels:
13      app: xdclass-nginx-pod
14  template:
15    metadata:
16      labels:
17        app: xdclass-nginx-pod
18    spec:
19      containers:
20      - name: xdclass-nginx
21        image: nginx:1.23.0

其他命令

 1# 创建
 2kubectl apply -f deploy-rollout.yaml
 3
 4# 查看
 5kubectl get pods,deploy,replicaset -o wide -n dev
 6
 7# 滚动升级(将nginx版本更新至1.15.8)
 8# --record 以保存正在更改资源的 kubectl 命令,方便查看history版本列表修改命令
 9kubectl set image deployment/xdclass-deploy xdclass-nginx=nginx:1.15.8 -n dev --record=true
10kubectl set image deployment/xdclass-deploy xdclass-nginx=nginx:1.23.0 -n dev --record=true
11
12# 动态查看升级过程,存在多个不同版本
13kubectl get pods -n dev -w
14
15# 查看历史版本列表
16kubectl rollout history deployment/xdclass-deploy -n dev
17
18# 查看具体某一个历史版本信息
19kubectl rollout history deployment/xdclass-deploy -n dev --revision=2
20
21# 回滚上一版本
22kubectl rollout undo deployment/xdclass-deploy -n dev
23
24# 查看升级情况
25kubectl rollout status deployment/xdclass-deploy -n dev
26
27# 回滚指定版本
28kubectl rollout undo deployment/xdclass-deploy -n dev --to-revision=2
29
30# 详情
31kubectl describe deploy xdclass-deploy -n dev
32
33# 删除,通过yaml删除
34kubectl delete -f deploy-rollout.yaml

DaemonSet

在K8S集群部署中由于节点数量不定,那么如果我们需要对每个节点中都运行一个守护进程、日志收集进程等情况时,在k8s中如何实现呢?
这个时候就是DaemonSet应用场景了,这类Pod运行在K8S 集群里的每一个节点(Node)上,确保所有节点上有且仅有一个。
有新的节点加入 K8S集群后,该 Pod 会自动地在新节点上被创建出来,而当旧节点被删除后,它上面的 Pod也相应地会被回收掉。
应用场景:监控告警Agent、日志组件、监控组件等

daemonset-nginx.yaml

 1apiVersion: apps/v1
 2kind: DaemonSet   
 3metadata:
 4  name: xdclass-ds
 5  namespace: dev
 6spec:
 7  selector: 
 8    matchLabels:
 9      app: xdclass-nginx-pod
10  template:
11    metadata:
12      labels:
13        app: xdclass-nginx-pod
14    spec:
15      containers:
16      - name: xdclass-nginx
17        image: nginx:1.23.0
18        imagePullPolicy: IfNotPresent

其他命令

1#创建
2kubectl apply -f daemonset-nginx.yaml
3
4#只有一个节点,多个节点的话,每个节点都有一个pod
5kubectl get pod,deploy,rs,ds -n dev -o wide
6
7# 删除
8kubectl delete -f daemonset-nginx.yaml

Job

普通任务容器控制器,只会执行一次,只要完成任务就立即退出,不需要重启或重建
容器中的进程在正常运行结束后不会对其进行重启,而是将pod对象置于completed状态
若容器中的进程因错误而终止,则需要依据配置确定是否需要重启
应用场景:批处理程序,完成后容器就退出等
启动pod在运行完毕任务后,就会变成Completed状态,job的状态会更新为complete,这个job任务已经执行完成,pod不在系统中继续运行

参数讲解

 1apiVersion: batch/v1
 2kind: Job
 3metadata:
 4  name: xdclass-job
 5  namespace: dev
 6spec:
 7  parallelism: 2 #job并发运行Pods的数量,默认 1
 8  completions: 3 #job需要成功运行Pods的次数,默认 1
 9  backoffLimit: 5 #job失败后进行重试的次数,默认是6
10  activeDeadlineSeconds: 100 #job运行超时时间,当job超过timeout时间,则job的状态也会更新为failed
11  template:
12    spec:
13      restartPolicy: Never #job重启策略,OnFailure或Never 
14      containers:
15      - name: demo
16        image: busybox:1.35.0 
17        # 容器的启动命令列表,在pod中的容器初始化完毕后运行命令
18        command: ["echo","hello xdclass.net k8s job"]

BusyBox

  • 是一个集成了三百多个最常用 Linux 命令和工具的软件
  • 包含了简单的工具,例如 ls、cat 和 echo 等等,还包含了一些更复杂的工具,例 grep、find、telnet

job-nginx.yaml

 1apiVersion: batch/v1
 2kind: Job
 3metadata:
 4  name: xdclass-job
 5  namespace: dev
 6spec:
 7  parallelism: 2
 8  completions: 3
 9  backoffLimit: 5
10  activeDeadlineSeconds: 100
11  template:
12    spec:
13      restartPolicy: Never
14      containers:
15      - name: demo
16        image: busybox:1.35.0
17        command: ["echo","hello xdclass.net k8s job"]

其他命令

 1#创建
 2kubectl apply -f job-nginx.yaml
 3
 4# 查看
 5kubectl get job,pod -n dev -o wide
 6kubectl get pods -o wide
 7
 8# 查看日志
 9kubectl logs xdclass-job-khc2q 
10
11# 删除
12kubectl delete -f job-nginx.yaml

Service

在k8s里面,每个Pod都会被分配一个单独的IP地址,但这个IP地址会随着Pod的销毁而消失,重启pod的ip地址会发生变化,此时客户如果访问原先的ip地址则会报错。
Service (服务)就是用来解决这个问题的, 对外服务的统一入口,防止pod失联,定义一组pod的访问策略(服务发现、负载均衡)
一个Service可以看作一组提供相同服务的Pod的对外访问接口,作用于哪些Pod是通过标签选择器来定义的
Service是一个概念,主要作用的是节点上的kube-proxy服务进程
Service 定义的抽象能够解耦这种关联。

Service 分类

  • ClusterIP
    • 默认类型,自动分配一个【仅集群内部】可以访问的虚拟 IP
  • NodePort
    • 对外访问应用使用,在 ClusterIP 基础上为 Service 在每台机器上绑定一个端口,就可以通过: ip+NodePort 来访问该服务
  • LoadBalancer(花钱的方案,相对比较少用)
    • 使在 NodePort 的基础上,借助公有云创建一个外部负载均衡器,并将请求转发到 NodePort
    • 可以实现集群外部访问服务的另外一种解决方案,不过并不是所有的 k8s 集群都会支持,大多是在公有云托管集群中会支持该类型
  • ExternalName(很少)
    • 把集群外部的服务引入到集群内部来,在集群内部直接使用。没有任何类型代理被创建,这只有 Kubernetes 1.7 或更高版本的 kube-dns 才支持。

Service 和 Pod 的关系
service和pod之间是通过 selector.app进行关联的。

1spec: # 描述
2  selector: # 标签选择器,确定当前service代理控制哪些pod
3    app: xdclass-nginx

YAML 文件

 1apiVersion: v1
 2kind: Service
 3metadata:
 4  creationTimestamp: null
 5  name: xdclass-nginx-svc # 服务的名称
 6spec:
 7  ports:
 8  - port: 80  # service服务端口
 9    protocol: TCP
10    targetPort: 80 # pod端口,常规和容器内部端口一致
11  selector:
12    app: xdclass-nginx-pod
13status:
14  loadBalancer: {}

YAML 文件中关于 K8S 中端口的概念区分
port和nodePort都是service的端口,port暴露给集群内客户访问服务,nodePort暴露给集群外客户访问服务。
这两个端口到来的数据都需要经过反向代理kube-proxy流入后端pod的targetPod,从而到达pod中容器的containerPort

  • port
    • 是 service 端口,即 k8s 中服务之间的访问端口 ,clusterIP:port 是提供给集群内部客户访问 service 的入口
  • nodePort
    • 容器所在 node 节点的端口,通过 nodeport 类型的 service 暴露给集群节点,外部可以访问的端口
  • targetPort
    • 是 pod 的端口 ,从 port 和 nodePort 来的流量经过 kube-proxy 流入到后端 pod 的 targetPort 上,最后进入容器。
  • containerPort
    • 是 pod 内部容器的端口,targetPort 映射到 containerPort。

配置说明

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: nginx
 5  namespace: dev
 6  labels:
 7    app: nginx
 8spec:
 9  containers:
10  - name: nginx
11    image: nginx:1.20
12    imagePullPolicy: IfNotPresent
13    ports:
14    - containerPort: 80 # 容器端口 
15---
16apiVersion: apps/v1
17kind: Service
18metadata:
19  name: nginx
20spec:
21  type: NodePort # 有配置NodePort,外部可访问k8s中的服务 ,
22  ports:
23  - name: nginx
24    port: 80  # 服务service的访问端口
25    protocol: TCP
26    targetPort: 80  # pod端口,映射到容器端口
27    nodePort: 30015  # NodePort,通过nodeport类型的service暴露给集群外部访问
28  selector:
29    app: nginx

ClusterIP

默认类型,自动分配一个【仅集群内部】可以访问的虚拟IP

 1# 创建deployment
 2kubectl apply -f deploy-nginx-pod.yaml
 3
 4# 查看deployment和pod(service的缩写是svc)
 5kubectl get deployment,pod,svc -n dev -o wide
 6
 7# 暴露服务 clusterIP 类型
 8kubectl expose deploy xdclass-deploy --name=svc-nginx1 --type=ClusterIP --port=80 --target-port=80 -n dev
 9
10# 访问service (CLUSTER-IP)  
11curl 10.98.60.116
12
13# 查看服务详情
14kubectl describe svc svc-nginx1 -n dev
15
16# 删除服务
17kubectl delete service svc-nginx1 -n dev
18
19# 删除deploy
20kubectl delete -f deploy-nginx-pod.yaml
21
22# 故障排查:k8s访问svc的clusterip异常的慢 (curl 10.98.60.116)
23# 参考:https://blog.csdn.net/xujiamin0022016/article/details/114457746
24ethtool -K flannel.1 tx-checksum-ip-generic off

NodePort

对外访问应用使用,在ClusterIP基础上为Service在每台机器上绑定一个端口,就可以通过: ip+NodePort来访问该服务。
在浏览器访问, 工作节点开放端口31325,访问工作节点ip:31325(网络安全组记得开放31325端口)

  • master、node 节点访问这个 开放的端口都可以
  • Kubeadm 部署,暴露端口对外服务,会随机选端口,默认范围是 30000~32767,可以修改指定范围
 1# 创建deployment
 2kubectl apply -f deploy-nginx-pod.yaml
 3
 4# 查看deployment和pod(service的缩写是svc)
 5kubectl get deployment,pod,svc -n dev -o wide
 6
 7# 暴露服务 NodePort 类型
 8kubectl expose deploy xdclass-deploy --name=svc-nodeport-nginx1 --type=NodePort --port=80 --target-port=80 -n dev
 9
10# 访问service (发现服务运行在 workernode1 节点上)  
11curl http://192.168.10.71:32344/    Master成功
12curl http://192.168.10.72:32344/    WorkerNode1成功
13
14# 查看服务详情
15kubectl describe svc svc-nodeport-nginx1 -n dev
16
17# 删除服务
18kubectl delete service svc-nodeport-nginx1 -n dev
19
20# 删除deploy
21kubectl delete -f deploy-nginx-pod.yaml
22
23# 故障排查:k8s访问svc的clusterip异常的慢 (curl 10.98.60.116)
24# 参考:https://blog.csdn.net/xujiamin0022016/article/details/114457746
25ethtool -K flannel.1 tx-checksum-ip-generic off

Endpoint
是k8s中的一个资源对象,存储在etcd中,记录service对应的所有pod的访问地址
里面有个Endpoints列表,就是当前service可以负载到的pod服务入口
service和pod之间的通信是通过endpoint实现的

1[root@master tmp]# kubectl get ep svc-nodeport-nginx1 -n dev -o wide
2NAME                  ENDPOINTS                                                  AGE
3svc-nodeport-nginx1   10.244.1.84:80,10.244.1.85:80,10.244.1.86:80 + 2 more...   18m

Endport

service 如何决定分发请求到后端的 Pod?

  • 默认,kube-proxy 的策略,如随机、轮询
  • 使用会话保持模式,即同个客户端的请求固定到某个 pod,在 spec 中添加 sessionAffinity:ClientIP 即可

 1# 查看全部pod和ip
 2kubectl get pods -n dev -o wide
 3
 4# 修改pod里面容器nginx的默认静态页面,内容为Pod所在的ip
 5kubectl exec -it xdclass-deploy-64967f6b67-hgh64  -n dev /bin/sh
 6echo "abc1024.pod2 " > /usr/share/nginx/html/index.html
 7exit
 8
 9
10# curl访问ip+port 或 浏览器直接访问 (每次访问内容都不同)
11http://192.168.10.71:32344/
12http://192.168.10.72:32344/

数据持久化

容器的生命周期可能很短,会被频繁地创建和销毁,容器 中的文件在磁盘上是临时存放的,这给容器中运行的较重要的应用程序带来一些问题。

  • 问题一 :当容器崩溃时文件丢失,kubelet 会重新启动容器,但容器会以干净的状态重启,之前保存在容器中的数据也会被清除
  • 问题二:当在一个 Pod 中同时运行多个容器时,常常需要在这些容器之间共享文件

Kubernetes 卷(Volume) 这一抽象概念能够解决这两个问题,卷的核心是包含一些数据的目录,Pod 中的容器可以访问该目录。

  • Volume 是 k8s 抽象出来的对象,它被定义在 Pod 上,然后被一个 Pod 里的多个容器挂载到具体的文件目录下
  • kubernetes 通过 Volume 实现同一个 Pod 中不同容器之间的数据共享以及数据的持久化存储
  • Volume 的生命周期不与 Pod 中单个容器的生命周期相关,当容器终止或者重启时,Volume 中的数据也不会丢失。
  • K8S 可以支持许多类型的卷,Pod 也能同时使用任意数量的卷

Volume 常见的类型

  • 常规存储:EmptyDir、HostPath
  • 高级存储(重点):PV、PVC
  • 配置存储:ConfigMap、Secret
  • 其他:网络存储系统 NFS、CIFS,包括云服务商提供的、本地、分布式

EmptyDir

当 Pod 指定到某个节点上时,首先创建的是一个emptyDir 卷,只要 Pod 在该节点上运行卷就一直存在。
当 Pod 因为某些原因被从节点上删除时,emptyDir卷中的数据也会永久删除
容器崩溃并不会导致 Pod 被从节点上移除,所以容器崩溃时 emptyDir卷中的数据是安全的。
用途:临时缓存空间。

案例
pod里面定义两个容器,一个产生日志,一个是读日志输出到控制台

volume-emptydir.yaml

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: xdclass-volume-emptydir
 5  namespace: dev
 6spec:
 7  containers:
 8  - name: xdclass-nginx
 9    image: nginx:1.20
10    ports:
11    - containerPort: 80
12    volumeMounts:  # 将nginx-log-volume挂在到nginx容器中,对应的目录为 /var/log/nginx
13    - name: nginx-log-volume
14      mountPath: /var/log/nginx
15
16  - name: xdclass-busybox
17    image: busybox:1.35.0 
18    command: ["/bin/sh","-c","tail -f /usr/local/test/access.log"] # 容器启动后初始命令,读取指定文件中内容
19    volumeMounts:  # 将nginx-log-volume挂在到busybox容器中,对应的目录为 /logs
20    - name: nginx-log-volume
21      mountPath: /usr/local/test
22
23  volumes: # 这里声明volume存储劵, name为nginx-log-volume,类型是emptyDir
24  - name: nginx-log-volume
25    emptyDir: {}

其他操作

 1# 创建
 2kubectl apply -f volume-emptydir.yaml
 3
 4# 查看
 5kubectl get pods -n dev -o wide
 6
 7# 查看详情
 8kubectl describe pod xdclass-volume-emptydir -n dev
 9
10# 访问nignx 产生访问日志
11curl 10.244.1.89
12
13# 查看容器输出 -f 后是 pod的名称
14kubectl logs -f xdclass-volume-emptydir -n dev -c xdclass-busybox
1510.244.0.0 - - [13/Jan/2024:05:41:15 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"
16
17# 删除(Pod被删除,emptyDir丢失)
18kubectl delete -f volume-emptydir.yaml

HostPath

emptyDir中数据没做持久化,随着Pod的结束而销毁,需要持久化到磁盘则选其他方式
hostPath类型的磁盘就是挂在了主机的一个文件或者目录
HostPath有多种类型,列举常见几个

  • Directory 给定的目录路径必须存在
  • DirectoryOrCreate 如果给定路径不存在,将根据需要在那里创建一个空目录
  • File 给定路径上必须存在对应文件
  • FileOrCreate 如果给定路径不存在,将根据需要在那里创建一个空文件

emptyDir 和 hostPath 对比

  • 都是本地存储卷方式
  • emptyDir 是临时存储空间,完全不提供持久化支持;
  • hostPath 的卷数据是持久化在 node 节点的文件系统中的,即便 pod 已经被删除了,volume 卷中的数据还留存在 node 节点上;

案例
某些应用需要用到docker的内部文件,这时只需要挂在本机的/var/lib/docker作为hostPath。

volume-hostpath.yaml

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: xdclass-volume-hostpath
 5  namespace: dev
 6spec:
 7  containers:
 8  - name: xdclass-nginx
 9    image: nginx:1.20
10    ports:
11    - containerPort: 80
12    volumeMounts:  # 将nginx-log-volume挂在到nginx容器中,对应的目录为 /var/log/nginx
13    - name: nginx-log-volume
14      mountPath: /var/log/nginx
15
16  - name: xdclass-busybox
17    image: busybox:1.35.0 
18    command: ["/bin/sh","-c","tail -f /usr/local/test/access.log"] # 容器启动后初始命令,读取指定文件中内容
19    volumeMounts:  # 将nginx-log-volume挂在到busybox容器中,对应的目录为 /logs
20    - name: nginx-log-volume
21      mountPath: /usr/local/test
22
23  volumes: # 这里声明volume存储劵, name为nginx-log-volume,类型是hostPath
24  - name: nginx-log-volume
25    hostPath:
26      path: /usr/local/test
27      type: DirectoryOrCreate #如果给定路径不存在,将根据需要在那里创建一个空目录

其他操作

 1# 创建
 2kubectl apply -f volume-hostpath.yaml
 3
 4# 查看
 5kubectl get pods -n dev -o wide
 6
 7# 访问nignx 产生访问日志
 8curl 10.244.1.90
 9
10# 查看容器输出 -f 后是 pod的名称
11kubectl logs -f xdclass-volume-hostpath -n dev -c xdclass-busybox
12
13# 去节点对应的目录查看文件是否有,即pod运行的节点,主节点上是没的!!!!
14ls /usr/local/test
15cat /usr/local/test/access.log
1610.244.0.0 - - [13/Jan/2024:06:07:57 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"
17
18# 删除(即使删除Pod,hostPath依然存在于Node节点中)
19kubectl delete -f volume-hostpath.yaml
20cat /usr/local/test/access.log

ConfigMap

很多应用在其初始化或运行期间要依赖一些配置信息。大多数时候,存在要调整配置参数所设置的数值的需求。ConfigMap 是 Kubernetes 用来向应用 Pod 中注入配置数据的方法。
ConfigMap介绍(缩写cm),是K8S的一种API对象,用来把【非加密数据】保存到键值对中,比如etcd
可以用作环境变量、命令行参数等,将环境变量、配置信息和容器镜像解耦,便于应用配置的修改
kubectl create configmap 命令,基于目录、 文件或者键值对来创建 ConfigMap

1kubectl create configmap NAME --from-literal=key1=value1 --from-literal=key2=value2

方式一:使用命令行创建 ConfigMap

1# 创建configmap
2kubectl create configmap xdclass-config --from-literal=account=xdclass --from-literal=password=123456
3
4# 查看
5kubectl get cm xdclass-config -o yaml
6
7# 删除
8kubectl delete cm xdclass-config

方式二:使用文件创建 configmap.yaml

 1# 准备yaml文件
 2[root@master tmp]# cat configmap.yaml
 3apiVersion: v1
 4kind: ConfigMap
 5metadata:
 6  name: xdclass-configmap
 7  namespace: dev
 8data:
 9  info:
10    username:xdclass
11    password:123456
12
13# 创建configmap
14kubectl create -f configmap.yaml
15
16# 查看
17kubectl get cm xdclass-configmap -n dev -o yaml
18
19# 详情
20kubectl describe cm xdclass-configmap -n dev
21
22# 删除
23kubectl delete -f configmap.yaml

pod-configmap.yaml 创建 pod,然后将创建的 configmap 挂载进去

 1# 创建configmap
 2kubectl create -f configmap.yaml
 3
 4# 准备pod-configmap.yaml
 5[root@master tmp]# cat pod-configmap.yaml
 6apiVersion: v1
 7kind: Pod
 8metadata:
 9  name: pod-configmap
10  namespace: dev
11spec:
12  containers:
13  - name: nginx
14    image: nginx:1.20
15    volumeMounts: # configmap挂载的目录
16    - name: config
17      mountPath: /config
18
19  volumes: # 声明configmap
20  - name: config
21    configMap:
22      name: xdclass-configmap
23
24# 创建pod
25kubectl create -f pod-configmap.yaml
26
27# 查看
28kubectl get pod pod-configmap -n dev
29
30# 进入容器
31kubectl exec -it pod-configmap -n dev -- /bin/sh
32cd /config
33cat info
34username:xdclass password:123456
35
36# 删除configMap
37kubectl delete -f configmap.yaml
38
39# 删除pod
40kubectl delete -f pod-configmap.yaml

Secret

有些配置需要加密存储,ConfigMap只能使用明文保存,因此不适合。
Secret用来保存敏感信息,例如密码、秘钥、证书、OAuth 令牌和 ssh key等…,就不需要把这些敏感数据暴露到镜像或者Pod中。
Pod 可以用三种方式之一来使用 Secret

  • 作为挂载到一个或多个容器上的卷中的文件
  • 作为容器的环境变量
  • 由 kubelet 在为 Pod 拉取镜像时使用

Secret 类型

  • dockerconfigjson:用来存储私有 docker registry的认证信息
  • Service Account:只要与Kubernetes API有交互的Pod,都会自动拥有此种类型的Secret K8S自动创建,并且会自动挂载到Pod的 /run/secrets/kubernetes.io/serviceaccount 目录中
 1# 查看
 2kubectl get pod -A | grep 'kube-proxy'
 3
 4# 进到容器,加了 -- /bin/bash,不会有警告
 5kubectl exec -it -n kube-system kube-proxy-9wb4g -- /bin/sh
 6
 7# 查看
 8ls -l /run/secrets/kubernetes.io/serviceaccount
 9cd /run/secrets/kubernetes.io/serviceaccount
10cat ca.crt
  • Opaque:加密类型为 base64,其特点就是将明文改为了密文
1echo -n 'admin' | base64  #账号
2echo -n '123456' | base64 #密码

案例
secret.yaml

1apiVersion: v1
2kind: Secret
3metadata:
4  name: mysecret
5type: Opaque
6data:
7  username: YWRtaW4=
8  password: MTIzNDU2

pod-secret-volume.yaml
将secret挂载到Pod的Volume中,创建pod-secret-volume.yaml

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: pod-secret
 5spec:
 6  containers:
 7  - name: nginx
 8    image: nginx:1.20
 9    volumeMounts: # secret挂载
10    - name: xdclass-config
11      mountPath: /etc/secret
12  volumes:
13  - name: xdclass-config
14    secret:
15      secretName: mysecret

其他操作

 1# 创建secret
 2kubectl apply -f secret.yaml 
 3
 4# 查看secret的信息
 5kubectl get secret
 6
 7# 查看mysecret详细信息
 8kubectl get secret mysecret -o yaml
 9
10# 创建pod
11kubectl apply -f pod-secret-volume.yaml
12
13# 查看
14kubectl get pod -o wide
15
16# 查看secret, 在pod中的secret信息实际已经被解密
17kubectl exec -it pod-secret -- /bin/sh
18ls /etc/secret
19cat /etc/secret/username
20cat /etc/secret/password
21
22# 删除secret
23kubectl delete secret mysecret
24
25# 删除pod
26kubectl delete -f pod-secret-volume.yaml

NFS(Network File System)

一种基于TCP/IP 传输的网络文件系统协议, 通过使用NFS协议,可以像访问本地目录一样访问远程服务器中的共享资源
NFS服务的实现依赖于RPC (Remote Process Call,远端过程调用)机制,以完成远程到本地的映射过程
一般需要安装nfs-utils、 rpcbind 软件包来提供NFS共享服务,前者用于NFS共享发布和访问,后者用于RPC支持
采用TCP/IP传输网络文件,适合局域网环境,简单操作

  • NFS 端口:2049
  • RPC 端口:111

NFS 在 K8S Volume里面的作用

  • 当某个节点发生故障的时候,该节点上的 pod 发生了转移,如何保证这些 pod 的数据不丢失呢?
  • 此时就需要引入外部网络文件系统,例如 nfs 或者其他具有对象存储功能的系统,可以保存当 pod 发生转移的时候数据也不丢失

部署 NFS 服务器(单节点:WorkerNode1)

 1# 下载nfs-util (对应要用到的节点都需要安装,但是不需要启动)
 2yum install nfs-utils -y
 3
 4# 创建目录(nfs服务器)、给路径授权
 5mkdir /opt/nfsdata
 6chmod 777 /opt/nfsdata
 7
 8# 编辑/etc/exports 配置文件(nfs服务器)
 9vim /etc/exports
10/opt/nfsdata 192.168.10.0/24(rw,insecure,sync)
11
12# 参数说明
13- rw 共享目录可读可写
14- secure 限制客户端只能从小于1024的tcp/ip端口连接服务器;
15- insecure允许客户端从大于1024的tcp/ip端口连接服务器;
16- sync 将数据同步写入内存缓冲区与磁盘中,效率低,但可以保证数据的一致性;
17- async 将数据先保存在内存缓冲区中,必要时才写入磁盘;
18
19# 启动rpcbind服务(安装nfs依赖包会自动下载)、启动nfs服务
20systemctl start rpcbind
21systemctl start nfs
22
23# 验证:显示当前所有挂载点
24showmount -e localhost
25/opt/nfsdata 192.168.10.0/24

NF 持久卷挂载
nginx的access.log持久化

nfs-pod.yaml
在pod中通过volumes挂载nfs

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: xdclass-nfs
 5  namespace: dev
 6  labels: 
 7    apps: nginx-nfs
 8spec:
 9  containers:
10  - name: nginx
11    image: nginx:1.20
12    ports:
13    - containerPort: 80
14    volumeMounts:
15    - name: logs-volume
16      mountPath: /var/log/nginx
17  volumes:
18  - name: logs-volume
19    nfs:
20      server: 192.168.10.72  #nfs服务器地址
21      path: /opt/nfsdata #共享文件路径

其他操作

 1# 创建pod
 2kubectl apply -f nfs-pod.yaml
 3
 4# 暴露服务
 5kubectl expose pod xdclass-nfs -n dev --port=80 --target-port=80 --type=NodePort
 6
 7# 查询对外暴露端口 (80:31601/TCP)
 8kubectl get pod,svc -n dev
 9
10# 访问
11curl http://192.168.10.71:31601/
12
13# 查看nfs的access.log
14cat /opt/nfsdata/access.log
1510.244.1.1 - - [13/Jan/2024:09:02:26 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" "-"
16
17# 删除service
18kubectl delete service xdclass-nfs -n dev
19
20# 删除pod
21kubectl delete -f nfs-pod.yaml

高级存储:PV、PVC

Kubernetes 支持的存储插件很多

  • awsElasticBlockStore - AWS 弹性块存储(EBS)
  • azureDisk - Azure Disk
  • azureFile - Azure File
  • cephfs- CephFS volume
  • azureDisk - Azure Disk
  • hostPath - HostPath 卷
  • nfs- 网络文件系统 (NFS) 存储
  • ...

在整个k8s集群中,有一些存储的资源,比如说NFS、CIFS等存储,这些存储都是由存储工程师去创建的,不同的存储方式不一样, 如果都掌握才可以使用,则很不方便的。
所以在k8s中提供了新的对象资源叫做PV(Persistent Volume)和PVC(Persistent Volume Claim),更方便用户直接进行使用。

PV 持久卷(Persistent Volume)
是集群中由管理员配置的一段网络存储,它是集群的一部分资源和底层存储密切相关,对象包含存储实现的细节,即:对接NFS、CIFS等存储系统
不同的PV会对应到不用的存储资源,这样在部署pod的时候直接调用集群内部的pv即可
PV没有命名空间隔离概念

PVC 持久卷声明 (Persistent Volume Claim)
PVC是用户存储的一种声明, PVC 可以请求特定的存储空间和访问模式,PVC 消耗的是 PV 资源
PVC必须与对应的PV建立关系,PVC会根据定义的PV去申请
创建pod的时候会附带一个PVC的请求,PVC的请求相当于就是去寻找一个合适的pv
使用逻辑

  • 在 pod 中定义一个存储卷(该存储卷类型为 PVC),定义的时候按指定大小,PVC 必须与对应的 PV 建立关系,PVC 会根据定义的需求【去 PV 申请】,而 PV 是由存储空间创建出来的

PV 和 PVC 逻辑
PV 是集群中的【资源】,PVC 是对这些【资源的请求】
PV 和 PVC 之间的相互作用遵循这个生命周期:Provisioning(配置) ---> Binding(绑定) ---> Using(使用) ---> Releasing(释放) ---> Recycling(回收)

PV 的 YAML 模板解析

 1apiVersion: v1
 2kind: PersistentVolume
 3metadata:
 4  name: xdclass-pv
 5spec:
 6  capacity:
 7    storage: 5Gi  # 存储大小
 8  accessModes: # 访问模式
 9    - ReadWriteOnce
10  persistentVolumeReclaimPolicy: Recycle # 回收策略
11  storageClassName: slow # 存储类别
12  nfs: # 卷插件
13    path: /tmp
14    server: 192.168.10.72
15
16###### 属性解析
17- 存储大小
18存储大小是可以设置和请求的唯一资源。 未来可能会包含 IOPS、吞吐量等属性
19
20- 访问模式(用户对资源的访问权限)
21ReadWriteOnce(RWO):读写权限,只能被单个节点挂载
22ReadOnlyMany(ROX): 只读权限,可以被多个节点挂载
23ReadWriteMany(RWX):读写权限,可以被多个节点挂载
24 
25- 回收策略(当PV不再被使用了之后的处理策略)
26保留 Retain -- 当PV对象被删除之后,与之相关的位于外部的基础设施中的数据仍然存在(如nfs),需要根据实际情况手动回收
27回收 Recycle -- 相当于在卷上执行rm -rf /volume/* 操作,之后该卷可以用于新的pvc申领
28删除 Delete -- 当PV对象被删除之后,与之相关的位于外部的基础设施中的数据也被一并删除(如nfs),需要根据实际情况手动回收,更多是云厂商设备
29
30- 存储类别
31每个 PV 可以属于某个类,通过将其 storageClassName属性设置为某个 StorageClass 的名称来指定。
32特定类的 PV 卷只能绑定到请求该类存储卷的 PVC 申领。
33未设置 storageClassName 的 PV 卷没有类设定,只能给到那些没有指定特定 存储类的 PVC 申领。

PV 生命周期有 4 种不同状态

  • Available(可用):块空闲资源还没有被任何声明绑定
  • Bound(已绑定):卷已经被声明绑定
  • Released(已释放):声明被删除,但是资源还未被集群重新声明
  • Failed(失败):该卷的自动回收失败

PVC 的 YAML 模板解析

 1apiVersion: v1
 2kind: PersistentVolumeClaim
 3metadata:
 4  name: xdclass-pvc
 5  namespace: dev
 6spec:
 7  accessModes: # 访问模式
 8  - ReadWriteMany
 9  selector: # 采用label标签对PV选择过滤
10  storageClassName: # 存储类别,设置对应的class的PV才能被系统选出
11  resources: # 需要存储资源的请求
12    requests:
13      storage: 3Gi

Pod 中定义 PVC

在 pod 中定义一个存储卷(该存储卷类型为 PVC),定义的时候按指定大小,PVC 必须与对应的 PV 建立关系,PVC 会根据定义的需求【去 PV 申请】,而 PV 是由存储空间创建出来的

案例:NFS、PV、PVC
需求如下:

  • 基于 NFS 存储,创建 2 个 PV
  • 创建 PVC 绑定 PV
  • 创建 Pod 挂载 PVC

搭建 nfs 环境

 1# 创建目录
 2mkdir /opt/nfsdata/pv1
 3mkdir /opt/nfsdata/pv2
 4chmod 777 /opt/nfsdata/pv1
 5chmod 777 /opt/nfsdata/pv2
 6
 7# 修改配置文件(WorkerNode1),暴露nfs服务
 8vim /etc/exports
 9/opt/nfsdata/pv1 192.168.10.0/24(rw,insecure,sync)
10/opt/nfsdata/pv2 192.168.10.0/24(rw,insecure,sync)
11
12# 重启nfs服务
13systemctl restart nfs

创建两个 PV

 1### volume-pv.yaml
 2apiVersion: v1
 3kind: PersistentVolume
 4metadata:
 5  name:  xdclass-pv1
 6spec:
 7  capacity: 
 8    storage: 1Gi
 9  accessModes:
10  - ReadWriteMany
11  persistentVolumeReclaimPolicy: Retain
12  nfs:
13    server: 192.168.10.72
14    path: /opt/nfsdata/pv1
15    
16
17---
18
19apiVersion: v1
20kind: PersistentVolume
21metadata:
22  name:  xdclass-pv2
23spec:
24  capacity: 
25    storage: 2Gi
26  accessModes:
27  - ReadWriteMany
28  persistentVolumeReclaimPolicy: Retain
29  nfs:
30    server: 192.168.10.72
31    path: /opt/nfsdata/pv2
32
33### 创建PV
34kubectl apply -f volume-pv.yaml
35
36### 查看PV
37kubectl get pv -o wide
38
39### 删除PV
40kubectl delete -f volume-pv.yaml

创建 2 个 PVC,使用 pvc.yaml (与 PV 不同,PVC 不属于集群资源,拥有自己的名称空间)

 1### volume-pvc.yaml 
 2apiVersion: v1
 3kind: PersistentVolumeClaim
 4metadata:
 5  name: xdclass-pvc1
 6  namespace: dev
 7spec:
 8  accessModes: 
 9  - ReadWriteMany
10  resources:
11    requests:
12      storage: 1Gi
13---
14apiVersion: v1
15kind: PersistentVolumeClaim
16metadata:
17  name: xdclass-pvc2
18  namespace: dev
19spec:
20  accessModes: 
21  - ReadWriteMany
22  resources:
23    requests:
24      storage: 3Gi
25
26### 创建PVC
27kubectl apply -f volume-pvc.yaml 
28
29### 查看PVC 
30# 可以发现目前xdclass-pvc1已经与xdclass-pv1绑定了,而xdclass-pvc2却没有绑定
31# 这是因为pvc2所申请的存储大小为3G,而pv2只能提供2G,因此无法进行绑定。
32kubectl get pvc -n dev
33
34### 删除PVC
35kubectl delete -f volume-pvc.yaml

创建 2 个 pod,并挂载 pvc
在 pod 中定义一个存储卷(该存储卷类型为 PVC),定义的时候按指定大小,PVC 必须与对应的 PV 建立关系,PVC 会根据定义的需求【去 PV 申请】,而 PV 是由存储空间创建出来的

 1### pod-pv-pvc.yaml
 2apiVersion: v1
 3kind: Pod
 4metadata:
 5  name: xdclass-pod1
 6  namespace: dev
 7spec:
 8  containers:
 9  - name: xdclass-busybox
10    image: busybox
11    command: ["/bin/sh","-c","while true;do echo hello xdclass pod1 >> /opt/print.txt; sleep 5; done;"]
12    volumeMounts:
13    - name: volume
14      mountPath: /opt/
15  volumes:
16    - name: volume
17      persistentVolumeClaim:
18        claimName: xdclass-pvc1
19        readOnly: false
20---
21apiVersion: v1
22kind: Pod
23metadata:
24  name: xdclass-pod2
25  namespace: dev
26spec:
27  containers:
28  - name: xdclass-busybox
29    image: busybox
30    command: ["/bin/sh","-c","while true;do echo hello xdclass pod2 >> /opt/print.txt; sleep 5; done;"]
31    volumeMounts:
32    - name: volume
33      mountPath: /opt/
34  volumes:
35    - name: volume
36      persistentVolumeClaim:
37        claimName: xdclass-pvc2
38        readOnly: false
39
40### 创建pod
41kubectl apply -f pod-pv-pvc.yaml
42
43### 查看pod
44kubectl get pod -n dev
45
46### nfs服务器查看 /opt/nfsdata/pv1/print.txt
47hello xdclass pod1
48hello xdclass pod1
49hello xdclass pod1
50
51### nfs服务器查看 /opt/nfsdata/pv2/print.txt
52没有文件
53
54### 删除pod
55kubectl delete -f pod-pv-pvc.yaml

K8S 部署 SpringBoot 项目

  • 部署 SpringBoot 项目到阿里云
  • 基于容器打包,推送私有镜像仓库
  • 采用 K8S 集群部署,对外暴露服务,pod 副本扩容,公网可以访问

Linux 服务器配置 Maven 和 JDK 构建环境

安装 Docker(本身已经安装)

安装 JDK11 配置全局环境变量

 1tar -zxvf jdk-11.0.8_linux-x64_bin.tar.gz
 2mkdir /usr/local/software
 3mv jdk-11.0.8 /usr/local/software/jdk11
 4
 5vim /etc/profile
 6JAVA_HOME=/usr/local/software/jdk11
 7CLASSPATH=$JAVA_HOME/lib/
 8PATH=$PATH:$JAVA_HOME/bin
 9export PATH JAVA_HOME CLASSPATH
10
11source /etc/profile
12java -version

安装 Maven

 1yum install unzip -y
 2unzip apache-maven-3.5.4-bin.zip
 3mv apache-maven-3.5.4 /usr/local/software/maven3.5
 4
 5vim /etc/profile
 6JAVA_HOME=/usr/local/software/jdk11
 7CLASSPATH=$JAVA_HOME/lib/
 8PATH=$PATH:$JAVA_HOME/bin
 9MAVEN_HOME=/usr/local/software/maven3.5
10PATH=$PATH:$MAVEN_HOME/bin
11export PATH JAVA_HOME CLASSPATH MAVEN_HOME
12
13source /etc/profile
14
15mvn -v

配置 Maven 阿里云

1vim /usr/local/software/maven3.5/conf/settings.xml
2
3    <mirror>
4      <id>alimaven</id>
5      <name>aliyun maven</name>
6      <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
7      <mirrorOf>central</mirrorOf>       
8    </mirror>

SpringBoot 项目构建、打包 Docker 镜像

 1# 进到项目根目录
 2[root@master xdclass-k8s]# pwd
 3/tmp/xdclass-k8s
 4[root@master xdclass-k8s]# ls
 5Dockerfile  HELP.md  mvnw  mvnw.cmd  pom.xml  src  xdclass-k8s.iml
 6
 7# 进到项目根目录打包
 8mvn clean install
 9
10# 构建镜像(不要忽略最后的一个点)
11docker build -t xdclass-k8s:1.0 .
12
13# 查看镜像列表
14docker images
15
16# 启动(需要打开防火墙)
17docker run -d -it -p 8080:8080 --name=k8sdemo xdclass-k8s:1.0
18
19# 访问
20http://192.168.10.71:8080/api/v1/test
21{
22"hello": "xdclass.net "
23}
24
25# 访问(网络安全组记得开放端口) 不要忘记停止这个容器
26docker logs -f k8sdemo
27接口访问时间:2024-01-13T10:47:07.217620
28
29docker stop k8sdemo
30docker rm k8sdemo

阿里云镜仓库像推送

推送私有镜像仓

1# 登录阿里云Docker Registry
2docker login --username=soulboy1990116 registry.cn-shanghai.aliyuncs.com
3
4# 将镜像推送到Registry
5docker tag 71a361a64058 registry.cn-shanghai.aliyuncs.com/leon_ns/xdclass-demo:1.0
6docker push registry.cn-shanghai.aliyuncs.com/leon_ns/xdclass-demo:1.0
7
8# 从Registry中拉取镜像
9docker pull registry.cn-shanghai.aliyuncs.com/leon_ns/xdclass-demo:[镜像版本号]

K8S 部署 SpringBoot 项目

K8S部署SpringBoot步骤

  • 步骤一:登录私有镜像仓,拉取镜像
  • 步骤二:创建 deployment
  • 步骤三:暴露服务访问端口即可

Secret 有多个类型

  • dockerconfigjson
    • 存储私有 docker registry 的认证信息
    • 用来创建用户 docker registry 认证的 Secret,直接使用 kubectl create 命令创建即可
  • Service Account
  • Opaque

创建 Secret

1### 创建Secret
2kubectl create secret docker-registry aliyun-soulboy-docker-secret --docker-server=registry.cn-shanghai.aliyuncs.com --docker-username=soulboy1111111 --docker-password=11111111

创建 k8sdemo-deployment 的 YAML 文件,并修改 xdclass-k8s.yaml
1. 修改副本数量为 2
2. 挂载 secret

 1### 修改xdclass-k8s.yaml
 2# 1.修改副本数量为2
 3# 2.挂载secret
 4apiVersion: apps/v1
 5kind: Deployment
 6metadata:
 7  creationTimestamp: null
 8  labels:
 9    app: k8sdemo
10  name: k8sdemo
11spec:
12  replicas: 2
13  selector:
14    matchLabels:
15      app: k8sdemo
16  strategy: {}
17  template:
18    metadata:
19      creationTimestamp: null
20      labels:
21        app: k8sdemo
22    spec:
23      imagePullSecrets:
24        - name: aliyun-soulboy-docker-secret
25      containers:
26      - image: registry.cn-shanghai.aliyuncs.com/leon_ns/xdclass-demo:1.0
27        name: xdclass-k8s
28        resources: {}
29status: {}

创建 delpoyment 控制器

 1# 创建delpoyment控制器
 2kubectl apply -f xdclass-k8s.yaml
 3
 4# 创建service, nodePort类型 
 5kubectl expose deploy k8sdemo --name=svc-k8sdemo-springboot --port=8080 --target-port=8080 --type=NodePort
 6
 7# 查看pod (8080:30377/TCP)
 8kubectl get pod,deploy,svc -o wide 
 9
10# 测试运行(防火墙关闭)
11curl 192.168.10.71:30377/api/v1/test
12curl 192.168.10.72:30377/api/v1/test
13
14# 查看日志
15kubectl logs k8sdemo-9c78f4765-2zvwx
16接口访问时间:2024-01-13T11:50:47.361305
17接口访问时间:2024-01-13T11:50:47.51027
18
19# 删除service
20kubectl delete service svc-k8sdemo-springboot
21
22# 删除pod
23kubectl apply -f xdclass-k8s.yaml

Java 源码

 1package net.xdclass.demo;
 2
 3import org.springframework.boot.SpringApplication;
 4import org.springframework.boot.autoconfigure.SpringBootApplication;
 5import org.springframework.web.bind.annotation.RequestMapping;
 6import org.springframework.web.bind.annotation.RestController;
 7
 8import java.time.LocalDateTime;
 9import java.util.HashMap;
10import java.util.Map;
11
12@SpringBootApplication
13@RestController
14public class XdclassK8sApplication {
15
16	public static void main(String[] args) {
17		SpringApplication.run(XdclassK8sApplication.class, args);
18	}
19
20
21	@RequestMapping("/api/v1/test")
22	public Map<String,String> testApi(){
23		Map<String,String> map = new HashMap<>(1);
24		map.put("hello","xdclass.net ");
25
26		System.out.println("接口访问时间:"+LocalDateTime.now());
27
28		return map;
29	}
30
31}

作者:Soulboy