目录

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。

########## 安装Docker
# 1.先安装yml
yum install -y yum-utils device-mapper-persistent-data lvm2

# 2.设置阿里云镜像
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

# 3.查看可安装的docker版本
yum list docker-ce --showduplicates | sort -r

#4. 安装docker
yum -y install docker-ce-20.10.10-3.el7

#5. 查看docker版本
docker -v

#配置开机自启动
systemctl enable docker.service

#6. 启动docker
systemctl start docker

#7. 查看docker 启动状态
systemctl status docker

########## 配置K8S镜像源(国外下载很慢)
cat > /etc/yum.repos.d/kubernetes.repo << EOF
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF


########## 安装kubectl
# 1.安装kubectl
yum install -y kubectl-1.18.0

########## 安装minikube
# 1. 安装minikube
curl -LO https://storage.googleapis.com/minikube/releases/v1.18.1/minikube-linux-amd64 && sudo install minikube-linux-amd64 /usr/local/bin/minikube

# 2. 检查minikube安装是否成功
[root@localhost yum.repos.d]# minikube  version
minikube version: v1.18.1
commit: 09ee84d530de4a92f00f1c5dbc34cead092b95bc

# 3. 启动minikube
minikube start --image-mirror-country='cn'  --driver=docker --force --kubernetes-version=1.18.1 --registry-mirror=https://registry.docker-cn.com

# 4. 查看
kubectl cluster-info

kubectl常用命令

### 查看K8S集群信息
[root@localhost yum.repos.d]# kubectl cluster-info
Kubernetes master is running at https://192.168.49.2:8443
KubeDNS is running at https://192.168.49.2:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.


### 查看节点信息
[root@localhost yum.repos.d]# kubectl get node
NAME       STATUS   ROLES    AGE   VERSION
minikube   Ready    master   14m   v1.18.1


### 查看内部组件
[root@localhost yum.repos.d]# kubectl get pod -A
NAMESPACE     NAME                               READY   STATUS             RESTARTS   AGE
kube-system   coredns-546565776c-877x6           1/1     Running            0          14m
kube-system   etcd-minikube                      1/1     Running            0          15m
kube-system   kube-apiserver-minikube            1/1     Running            0          15m
kube-system   kube-controller-manager-minikube   1/1     Running            0          15m
kube-system   kube-proxy-5s5w5                   1/1     Running            0          14m
kube-system   kube-scheduler-minikube            1/1     Running            0          15m
kube-system   storage-provisioner                0/1     ImagePullBackOff   0          15m

署第一个K8S应用:Nginx

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

# kubectl部署应用
kubectl create deployment xdclass-nginx --image=nginx:1.23.0

# 对比Docker部署
docker run  --name xdclass-nginx -p 8080:80 -d nginx:1.23.0

# 查看pod
[root@localhost yum.repos.d]# kubectl get pod
NAME                             READY   STATUS              RESTARTS   AGE
xdclass-nginx-859bdb9994-f77tr   0/1     ContainerCreating   0          9s

# 查看deplayment
[root@localhost yum.repos.d]# kubectl get deployment
NAME            READY   UP-TO-DATE   AVAILABLE   AGE
xdclass-nginx   0/1     1            0           72s

# 同时查看多种类型
[root@localhost yum.repos.d]# kubectl get pod,deployment
NAME                                 READY   STATUS              RESTARTS   AGE
pod/xdclass-nginx-859bdb9994-f77tr   0/1     ContainerCreating   0          2m51s

NAME                            READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/xdclass-nginx   0/1     1            0           2m51s

# 暴露80端口, 就是service服务
[root@localhost yum.repos.d]# kubectl expose deployment xdclass-nginx --port=80  --type=NodePort
service/xdclass-nginx exposed

# 查看 svc (服务)
[root@localhost yum.repos.d]# kubectl get svc
NAME            TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
kubernetes      ClusterIP   10.96.0.1      <none>        443/TCP        40m
xdclass-nginx   NodePort    10.109.94.67   <none>        80:30470/TCP   12s

# 转发端口(Mini Kube临时), kubectl port-forward 转发一个本地端口到 Pod 端口,不会返回数据,需要打开另一个终端来继续这个练习 
kubectl port-forward  --address 0.0.0.0   service/xdclass-nginx 80:80

# 访问 http://192.168.10.71/   
Minikube的搭建跟用Kubeadm的有一点不一样
Nodeport不能通过ip+端口直接访问,要通过minikube service(内网访问)和端口转发(公网访问)。

KubeAdm搭建多节点K8S集群

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

安装Docker

########## 安装Docker
# 1.先安装yml
yum install -y yum-utils device-mapper-persistent-data lvm2

# 2.设置阿里云镜像
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

# 3.查看可安装的docker版本
yum list docker-ce --showduplicates | sort -r

#4. 安装docker
yum -y install docker-ce-20.10.10-3.el7

#5. 查看docker版本
docker -v

#配置开机自启动
systemctl enable docker.service

#6. 启动docker
systemctl start docker

#7. 查看docker 启动状态
systemctl status docker

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

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

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

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

主节点初始化(主节点)

# 关闭 swap分区
swapoff -a

# 初始化
kubeadm init \
--apiserver-advertise-address=192.168.10.71 \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.18.0 \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=10.244.0.0/16

只修改两个地方(master主机【内网IP】,k8s软件版本)


说明:
--apiserver-advertise-address:主节点的内网ip地址
--image-repository 镜像仓库
--kubernetes-version k8s版本
--service-cidr + --pod-network-cidr 网段不重复即可


#  主节点初始化
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

入工作节点(工作节点)

kubeadm join 192.168.10.71:6443 --token 59jii3.njx7mosmp57wthb8 \
    --discovery-token-ca-cert-hash sha256:2ac62fc9462dc21296368751656ce5d30b78183063ae5a644278c54ee2507177


### 故障排查(参考)
# token过期
[root@localhost ~]# kubeadm token create
rdj0hp.beq71ql85wpbs2tk
kubeadm join 192.168.10.71:6443 --token rdj0hp.beq71ql85wpbs2tk \
    --discovery-token-ca-cert-hash sha256:620f1669a7a9fad0a77faaebd293deda57551f23a10a31beb7b2160784becfed

# node节点重新加入
[root@workernode1 ~]# kubeadm reset

安装网络插件

# 状态都是NotReady,需要配置网络插件
[root@master tmp]# kubectl get nodes
NAME                    STATUS     ROLES    AGE   VERSION
localhost.localdomain   NotReady   master   32m   v1.18.0
workernode1             NotReady   <none>   20m   v1.18.0

# 安装网络插件 kube-flannel
kubectl apply -f https://github.com/flannel-io/flannel/blob/master/Documentation/kube-flannel.yml

# 再次查看
[root@master tmp]# kubectl get nodes
NAME                    STATUS   ROLES    AGE   VERSION
localhost.localdomain   Ready    master   33m   v1.18.0
workernode1             Ready    <none>   21m   v1.18.0

署第一个 K8S 应用:Nginx

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

# kubectl部署应用
kubectl create deployment xdclass-nginx --image=nginx:1.23.0

# 对比Docker部署
docker run  --name xdclass-nginx -p 8080:80 -d nginx:1.23.0

# 查看pod
[root@localhost yum.repos.d]# kubectl get pod
NAME                             READY   STATUS              RESTARTS   AGE
xdclass-nginx-859bdb9994-f77tr   0/1     ContainerCreating   0          9s

# 查看deplayment
[root@localhost yum.repos.d]# kubectl get deployment
NAME            READY   UP-TO-DATE   AVAILABLE   AGE
xdclass-nginx   0/1     1            0           72s
# 暴露80端口, 就是service服务
[root@localhost yum.repos.d]# kubectl expose deployment xdclass-nginx --port=80  --type=NodePort
service/xdclass-nginx exposed

# 查看 svc (服务)
[root@master tmp]# kubectl get svc
NAME            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes      ClusterIP   10.96.0.1        <none>        443/TCP        41m
xdclass-nginx   NodePort    10.111.146.244   <none>        80:30573/TCP   3s

###  Kubeadm部署,暴露端口对外服务,会随机选端口,默认范围是30000~32767,可以修改指定
# 访问 MasterNode 
http://192.168.10.71/      		成功
http://192.168.10.71:30573/		成功

# 访问 WorkerNode
http://192.168.10.72/      		失败
http://192.168.10.72:30573/		成功

常见资源管理命令

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

kubectl管理资源

kubectl [command] [TYPE] [NAME] [flags]

commad:对资源具体的操作,如create创建、 get获取 、 delete删除
TYPE:指定资源类型,大小写敏感
NAME:指定资源的名称,大小写敏感,如果省略名称则显示所有资源
flags:指定可选的参数,如可用-s或者-server指定Kubernetes API server的地址和端口

# 获取全部节点
kubectl get node

# 获取全部pod
kubectl get pod

# 查看某个pod内容
kubectl get pod pod_name

#获取全部名称空间
kubectl get ns


# 查看创建的资源
kubectl get pod,svc,deploy

# 删除nginx pod,如果是靠deploy控制器创建的pod, 直接删除则会自动创建新的;
# 如果需要删除则直接删除depoly控制器即可,pod会被删除
kubectl delete pod pod名称
kubectl delete deployment xdclass-nginx

# 删除服务
kubectl delete service xdclass-nginx

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

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

yaml文件内容

  • Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
   name: nginx-deployment
   labels:
      app: nginx-deployment
spec:
   replicas: 1
   selector:
      matchLabels:
         app: nginx-pod
   template:
      metadata:
           labels:
              app: nginx-pod
      spec:
         containers:
         - name: nginx
             image: nginx:1.23.0
             imagePullPolicy: IfNotPresent
             ports:
             - containerPort: 80
  • Pod
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - image: nginx:1.23.0
    name: pod
    ports:
    - name: nginx-port
      containerPort: 80
      protocol: TCP

yaml参数

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

语法格式

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

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

# 创建nginx资源文件并且不启动资源
kubectl create deployment xdclass-nginx --image=nginx:1.23.0 -o yaml --dry-run=client > nginx.yaml

# 查看nginx.yaml
cat nginx.yaml

精简版 yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: xdclass-nginx
  name: xdclass-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: xdclass-nginx
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: xdclass-nginx
    spec:
      containers:
      - image: nginx:1.23.0
        name: nginx
        resources: {}
status: {}

pod的yaml文件示例

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

查看所有资源

#查看资源
kubectl api-resources

#查看命令帮助
kubectl --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的数量
高级命令applyrc
label标签
其他命令cluster-info集群信息
version版本
[root@master ~]# kubectl describe pod xdclass-nginx-859bdb9994-hc86v

[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
    • 集群节点之间的心跳维护

查看所有命令空间

kubectl get namespace

缩写
kubectl get ns

命名空间操作

# 创建新命名空间
  kubectl create ns dev

# 查看命名空间详情  
  kubectl describe ns dev

# 指定输出格式  命令:kubectl get ns ns名称  -o 格式参数, 常见的是wide、json、yaml
# 输出命名空间详细信息
  kubectl get ns dev -o yaml
  
# 删除命名空间
  kubectl delete ns dev
  
# 基于配置文件方式 namespace-dev.yaml
  
apiVersion: v1
kind: Namespace
metadata:
  name: dev

创建:kubectl create -f namespace-dev.yaml

创建:kubectl apply -f namespace-dev.yaml

删除:kubectl delete -f namespace-dev.yaml

Label Selector

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

版本标签:"release" : "stable" , "release" : "canary"...

环境标签:"environment" : "dev" , "environment" : "production"

架构标签:"tier" : "frontend" , "tier" : "backend" , "tier" : "middleware"

分区标签:"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的筛选。

命令用法

# 通过 deployment控制器导出yaml文件,指定名称空间
kubectl create deployment xdclass-nginx --image=nginx:1.23.0 --namespace dev -o yaml --dry-run=client > nginx.yaml


#命令默认不会列出任何标签
kubectl get pods 

# 使用 --show-labels 选项来查看
kubectl get pod -n dev --show-labels 

# 查看 deploy控制器标签
kubectl get deploy -n dev --show-labels

# 查看 pod 标签
kubectl get pod -n dev --show-labels

# 查看node节点标签
kubectl get node  --show-labels

# 给Pod资源打标签
kubectl label pod pod名称 -n dev version=1.0
kubectl label pod xdclass-nginx-859bdb9994-jkm58 -n dev version=1.0

# 给Pod资源更新标签
kubectl label pod pod名称 -n dev version=2.0 --overwrite
kubectl label pod xdclass-nginx-859bdb9994-jkm58 -n dev version=2.0 --overwrite

# 使用标签选择器
kubectl get pod -l "version=2.0" -n dev --show-labels
kubectl get pod -l "version!=2.0" -n dev --show-labels


# 删除标签 语法 kubectl label pod pod名称 -n dev 标签名-
kubectl label pod pod名称 -n dev version-
kubectl label pod xdclass-nginx-859bdb9994-jkm58 -n dev version-

Pod

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

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

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

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

kubectl 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方式运行的

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

命令

# 自主创建Pod
kubectl run xdclass-nignx-pod --image=nginx:1.23.0 --port=80

# 自主创建Pod,指定名称空间
kubectl run xdclass-nignx-pod --image=nginx:1.23.0 --port=80 --namespace dev

# 通过控制器创建Pod
kubectl create deployment xdclass-nginx --image=nginx:1.23.0

# 通过 deployment控制器导出yaml文件,指定名称空间
kubectl create deployment xdclass-nginx --image=nginx:1.23.0 --namespace dev -o yaml --dry-run=client > nginx.yaml

#查看创建的资源
kubectl get pod,deploy 

# 删除nginx pod,如果是靠deploy控制器创建的pod, 直接删除则会自动创建新的;
kubectl delete pod xdclass-nginx -n dev


# 通过控制器创建pod,则删除控制器即可
kubectl delete deploy xdclass-nginx -n dev

#一次性部署3个pod,修改nginx.yaml 下面的从 1 改为 3
#使用 kubectl apply -f nignx.yaml
spec:
  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上所能消耗的最高上限
resources:
  requests:
    memory:"内存大小"
    cpu:"cpu占用大小"
  limits: 
    memory:"内存占用大小"
    cpu:"cpu占用大小"
    
——————————————————————————————————————————————
CPU 资源以 CPU 单位度量。Kubernetes 中的一个 CPU 等同于:
1 个 AWS vCPU
1 个 Azure vCore

例如 100m CPU、100 milliCPU 和 0.1 CPU 都相同

文档地址:
https://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中
      nodeSelector: 
        env_role:dev/prod
      

NodeSelector

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

# 查看node节点标签
kubectl get node --show-labels

# 给Node资源打标签,不能给master打标签
kubectl label node workernode1 env=test

# 删除 node的标签 kubectl label node 删除指定的labels(标签 key 接 - 号即可)
kubectl label node workernode1 env-

# 列出所有正在运行的Pod及其对应的节点名称
kubectl get pods -o wide

# 查看指定Pod的更多详细信息
kubectl describe  pod xdclass-nginx

# 配置文件
[root@master tmp]# cat nginx_label.yaml
apiVersion: v1
kind: Pod
metadata:
  name: xdclass-nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.23.0
    imagePullPolicy: IfNotPresent
  nodeSelector:
    env: test

# 创建pod
kubectl 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 的名称的形式为。

<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更好,并提供很多其它有用的特性。

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

replicaset-nginx.yaml

apiVersion: apps/v1
kind: ReplicaSet   
metadata:
  name: xdclass-rs
  namespace: dev
spec:
  replicas: 5
  selector: 
    matchLabels:
      app: xdclass-nginx-pod
  template:
    metadata:
      labels:
        app: xdclass-nginx-pod
    spec:
      containers:
      - name: xdclass-nginx
        image: nginx:1.23.0

其他操作

# 创建
kubectl apply -f replicaset-nginx.yaml

# 查看
kubectl get pods,deploy,replicaset -o wide -n dev

# 命令行缩容
kubectl scale rs xdclass-rs --replicas=2 -n dev

# 删除,可以直接删除rs;也可以通过yaml删除
kubectl 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

apiVersion: apps/v1
kind: Deployment
metadata:
  name: xdclass-deploy
  namespace: dev
spec:
  replicas: 5
  selector: 
    matchLabels:
      app: xdclass-nginx-pod
  template:
    metadata:
      labels:
        app: xdclass-nginx-pod
    spec:
      containers:
      - name: xdclass-nginx
        image: nginx:1.23.0

其他操作

#创建
kubectl apply -f deploy-nginx-pod.yaml

# 查看deployment
kubectl get deployment -n dev

#查看
kubectl get pods,deploy,replicaset -o wide -n dev

# 删除,通过yaml删除
kubectl delete -f deploy-nginx-pod.yaml

# 检查集群中的 Deployment 时,所显示的字段有:* `NAME` 列出了集群中 Deployment 的名称。
* `READY` 显示应用程序的可用的“副本”数,格式是“就绪个数/期望个数”。
* `UP-TO-DATE` 显示为了达到期望状态已经更新的副本数。
* `AVAILABLE` 显示可用的副本数。
* `AGE` 应用程序运行的时间。

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

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

RollingUpdate说明属性说明

MaxUnavailable为0, 在新 Pod 启动并就绪之前,不要关闭任何旧Pod
MaxSurge为100%, 立即启动所有新 Pod,也就是有足够的资源希望尽快完成更新。

默认两个值都是 25%
  如果更新一个 100 Pod 的 Deployment,会立刻创建 25 个新 Old,同时会关闭 25 个旧 Pod;
  每次有 Pod 启动就绪,就可以关闭旧 Pod

deploy-rollout.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: xdclass-deploy
  namespace: dev
spec:
  replicas: 5
  revisionHistoryLimit: 5  #保留历史版本5个
  strategy: 
    type: RollingUpdate
  selector: 
    matchLabels:
      app: xdclass-nginx-pod
  template:
    metadata:
      labels:
        app: xdclass-nginx-pod
    spec:
      containers:
      - name: xdclass-nginx
        image: nginx:1.23.0

其他命令

# 创建
kubectl apply -f deploy-rollout.yaml

# 查看
kubectl get pods,deploy,replicaset -o wide -n dev

# 滚动升级(将nginx版本更新至1.15.8)
# --record 以保存正在更改资源的 kubectl 命令,方便查看history版本列表修改命令
kubectl set image deployment/xdclass-deploy xdclass-nginx=nginx:1.15.8 -n dev --record=true
kubectl set image deployment/xdclass-deploy xdclass-nginx=nginx:1.23.0 -n dev --record=true

# 动态查看升级过程,存在多个不同版本
kubectl get pods -n dev -w

# 查看历史版本列表
kubectl rollout history deployment/xdclass-deploy -n dev

# 查看具体某一个历史版本信息
kubectl rollout history deployment/xdclass-deploy -n dev --revision=2

# 回滚上一版本
kubectl rollout undo deployment/xdclass-deploy -n dev

# 查看升级情况
kubectl rollout status deployment/xdclass-deploy -n dev

# 回滚指定版本
kubectl rollout undo deployment/xdclass-deploy -n dev --to-revision=2

# 详情
kubectl describe deploy xdclass-deploy -n dev

# 删除,通过yaml删除
kubectl delete -f deploy-rollout.yaml

DaemonSet

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

daemonset-nginx.yaml

apiVersion: apps/v1
kind: DaemonSet   
metadata:
  name: xdclass-ds
  namespace: dev
spec:
  selector: 
    matchLabels:
      app: xdclass-nginx-pod
  template:
    metadata:
      labels:
        app: xdclass-nginx-pod
    spec:
      containers:
      - name: xdclass-nginx
        image: nginx:1.23.0
        imagePullPolicy: IfNotPresent

其他命令

#创建
kubectl apply -f daemonset-nginx.yaml

#只有一个节点,多个节点的话,每个节点都有一个pod
kubectl get pod,deploy,rs,ds -n dev -o wide

# 删除
kubectl delete -f daemonset-nginx.yaml

Job

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

参数讲解

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

BusyBox

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

job-nginx.yaml

apiVersion: batch/v1
kind: Job
metadata:
  name: xdclass-job
  namespace: dev
spec:
  parallelism: 2
  completions: 3
  backoffLimit: 5
  activeDeadlineSeconds: 100
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: demo
        image: busybox:1.35.0
        command: ["echo","hello xdclass.net k8s job"]

其他命令

#创建
kubectl apply -f job-nginx.yaml

# 查看
kubectl get job,pod -n dev -o wide
kubectl get pods -o wide

# 查看日志
kubectl logs xdclass-job-khc2q 

# 删除
kubectl 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进行关联的。

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

yaml文件

apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  name: xdclass-nginx-svc # 服务的名称
spec:
  ports:
  - port: 80  # service服务端口
    protocol: TCP
    targetPort: 80 # pod端口,常规和容器内部端口一致
  selector:
    app: xdclass-nginx-pod
status:
  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。

配置说明

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: dev
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.20
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80 # 容器端口 
---
apiVersion: apps/v1
kind: Service
metadata:
  name: nginx
spec:
  type: NodePort # 有配置NodePort,外部可访问k8s中的服务 ,
  ports:
  - name: nginx
    port: 80  # 服务service的访问端口
    protocol: TCP
    targetPort: 80  # pod端口,映射到容器端口
    nodePort: 30015  # NodePort,通过nodeport类型的service暴露给集群外部访问
  selector:
    app: nginx

ClusterIP

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

# 创建deployment
kubectl apply -f deploy-nginx-pod.yaml

# 查看deployment和pod(service的缩写是svc)
kubectl get deployment,pod,svc -n dev -o wide

# 暴露服务 clusterIP 类型
kubectl expose deploy xdclass-deploy --name=svc-nginx1 --type=ClusterIP --port=80 --target-port=80 -n dev

# 访问service (CLUSTER-IP)  
curl 10.98.60.116

# 查看服务详情
kubectl describe svc svc-nginx1 -n dev

# 删除服务
kubectl delete service svc-nginx1 -n dev

# 删除deploy
kubectl delete -f deploy-nginx-pod.yaml

# 故障排查:k8s访问svc的clusterip异常的慢 (curl 10.98.60.116)
# 参考:https://blog.csdn.net/xujiamin0022016/article/details/114457746
ethtool -K flannel.1 tx-checksum-ip-generic off

NodePort

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

  • master、node节点访问这个 开放的端口都可以
  • Kubeadm部署,暴露端口对外服务,会随机选端口,默认范围是30000~32767,可以修改指定范围
# 创建deployment
kubectl apply -f deploy-nginx-pod.yaml

# 查看deployment和pod(service的缩写是svc)
kubectl get deployment,pod,svc -n dev -o wide

# 暴露服务 NodePort 类型
kubectl expose deploy xdclass-deploy --name=svc-nodeport-nginx1 --type=NodePort --port=80 --target-port=80 -n dev

# 访问service (发现服务运行在 workernode1 节点上)  
curl http://192.168.10.71:32344/    Master成功
curl http://192.168.10.72:32344/    WorkerNode1成功

# 查看服务详情
kubectl describe svc svc-nodeport-nginx1 -n dev

# 删除服务
kubectl delete service svc-nodeport-nginx1 -n dev

# 删除deploy
kubectl delete -f deploy-nginx-pod.yaml

# 故障排查:k8s访问svc的clusterip异常的慢 (curl 10.98.60.116)
# 参考:https://blog.csdn.net/xujiamin0022016/article/details/114457746
ethtool -K flannel.1 tx-checksum-ip-generic off

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

[root@master tmp]# kubectl get ep svc-nodeport-nginx1 -n dev -o wide
NAME                  ENDPOINTS                                                  AGE
svc-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即可

# 查看全部pod和ip
kubectl get pods -n dev -o wide

# 修改pod里面容器nginx的默认静态页面,内容为Pod所在的ip
kubectl exec -it xdclass-deploy-64967f6b67-hgh64  -n dev /bin/sh
echo "abc1024.pod2 " > /usr/share/nginx/html/index.html
exit


# curl访问ip+port 或 浏览器直接访问 (每次访问内容都不同)
http://192.168.10.71:32344/
http://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

apiVersion: v1
kind: Pod
metadata:
  name: xdclass-volume-emptydir
  namespace: dev
spec:
  containers:
  - name: xdclass-nginx
    image: nginx:1.20
    ports:
    - containerPort: 80
    volumeMounts:  # 将nginx-log-volume挂在到nginx容器中,对应的目录为 /var/log/nginx
    - name: nginx-log-volume
      mountPath: /var/log/nginx

  - name: xdclass-busybox
    image: busybox:1.35.0 
    command: ["/bin/sh","-c","tail -f /usr/local/test/access.log"] # 容器启动后初始命令,读取指定文件中内容
    volumeMounts:  # 将nginx-log-volume挂在到busybox容器中,对应的目录为 /logs
    - name: nginx-log-volume
      mountPath: /usr/local/test

  volumes: # 这里声明volume存储劵, name为nginx-log-volume,类型是emptyDir
  - name: nginx-log-volume
    emptyDir: {}

其他操作

# 创建
kubectl apply -f volume-emptydir.yaml

# 查看
kubectl get pods -n dev -o wide

# 查看详情
kubectl describe pod xdclass-volume-emptydir -n dev

# 访问nignx 产生访问日志
curl 10.244.1.89

# 查看容器输出 -f 后是 pod的名称
kubectl logs -f xdclass-volume-emptydir -n dev -c xdclass-busybox
10.244.0.0 - - [13/Jan/2024:05:41:15 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"

# 删除(Pod被删除,emptyDir丢失)
kubectl 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

apiVersion: v1
kind: Pod
metadata:
  name: xdclass-volume-hostpath
  namespace: dev
spec:
  containers:
  - name: xdclass-nginx
    image: nginx:1.20
    ports:
    - containerPort: 80
    volumeMounts:  # 将nginx-log-volume挂在到nginx容器中,对应的目录为 /var/log/nginx
    - name: nginx-log-volume
      mountPath: /var/log/nginx

  - name: xdclass-busybox
    image: busybox:1.35.0 
    command: ["/bin/sh","-c","tail -f /usr/local/test/access.log"] # 容器启动后初始命令,读取指定文件中内容
    volumeMounts:  # 将nginx-log-volume挂在到busybox容器中,对应的目录为 /logs
    - name: nginx-log-volume
      mountPath: /usr/local/test

  volumes: # 这里声明volume存储劵, name为nginx-log-volume,类型是hostPath
  - name: nginx-log-volume
    hostPath:
      path: /usr/local/test
      type: DirectoryOrCreate #如果给定路径不存在,将根据需要在那里创建一个空目录

其他操作

# 创建
kubectl apply -f volume-hostpath.yaml

# 查看
kubectl get pods -n dev -o wide

# 访问nignx 产生访问日志
curl 10.244.1.90

# 查看容器输出 -f 后是 pod的名称
kubectl logs -f xdclass-volume-hostpath -n dev -c xdclass-busybox

# 去节点对应的目录查看文件是否有,即pod运行的节点,主节点上是没的!!!!
ls /usr/local/test
cat /usr/local/test/access.log
10.244.0.0 - - [13/Jan/2024:06:07:57 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"

# 删除(即使删除Pod,hostPath依然存在于Node节点中)
kubectl delete -f volume-hostpath.yaml
cat /usr/local/test/access.log

ConfigMap

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

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

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

# 创建configmap
kubectl create configmap xdclass-config --from-literal=account=xdclass --from-literal=password=123456

# 查看
kubectl get cm xdclass-config -o yaml

# 删除
kubectl delete cm xdclass-config

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

# 准备yaml文件
[root@master tmp]# cat configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: xdclass-configmap
  namespace: dev
data:
  info:
    username:xdclass
    password:123456

# 创建configmap
kubectl create -f configmap.yaml

# 查看
kubectl get cm xdclass-configmap -n dev -o yaml

# 详情
kubectl describe cm xdclass-configmap -n dev

# 删除
kubectl delete -f configmap.yaml

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

# 创建configmap
kubectl create -f configmap.yaml

# 准备pod-configmap.yaml
[root@master tmp]# cat pod-configmap.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-configmap
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.20
    volumeMounts: # configmap挂载的目录
    - name: config
      mountPath: /config

  volumes: # 声明configmap
  - name: config
    configMap:
      name: xdclass-configmap

# 创建pod
kubectl create -f pod-configmap.yaml

# 查看
kubectl get pod pod-configmap -n dev

# 进入容器
kubectl exec -it pod-configmap -n dev -- /bin/sh
cd /config
cat info
username:xdclass password:123456

# 删除configMap
kubectl delete -f configmap.yaml

# 删除pod
kubectl 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 目录中
# 查看
kubectl get pod -A | grep 'kube-proxy'

# 进到容器,加了 -- /bin/bash,不会有警告
kubectl exec -it -n kube-system kube-proxy-9wb4g -- /bin/sh

# 查看
ls -l /run/secrets/kubernetes.io/serviceaccount
cd /run/secrets/kubernetes.io/serviceaccount
cat ca.crt
  • Opaque:加密类型为base64,其特点就是将明文改为了密文
echo -n 'admin' | base64  #账号
echo -n '123456' | base64 #密码

案例
secret.yaml

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

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

apiVersion: v1
kind: Pod
metadata:
  name: pod-secret
spec:
  containers:
  - name: nginx
    image: nginx:1.20
    volumeMounts: # secret挂载
    - name: xdclass-config
      mountPath: /etc/secret
  volumes:
  - name: xdclass-config
    secret:
      secretName: mysecret

其他操作

# 创建secret
kubectl apply -f secret.yaml 

# 查看secret的信息
kubectl get secret

# 查看mysecret详细信息
kubectl get secret mysecret -o yaml

# 创建pod
kubectl apply -f pod-secret-volume.yaml

# 查看
kubectl get pod -o wide

# 查看secret, 在pod中的secret信息实际已经被解密
kubectl exec -it pod-secret -- /bin/sh
ls /etc/secret
cat /etc/secret/username
cat /etc/secret/password

# 删除secret
kubectl delete secret mysecret

# 删除pod
kubectl 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)

# 下载nfs-util (对应要用到的节点都需要安装,但是不需要启动)
yum install nfs-utils -y

# 创建目录(nfs服务器)、给路径授权
mkdir /opt/nfsdata
chmod 777 /opt/nfsdata

# 编辑/etc/exports 配置文件(nfs服务器)
vim /etc/exports
/opt/nfsdata 192.168.10.0/24(rw,insecure,sync)

# 参数说明
- rw 共享目录可读可写
- secure 限制客户端只能从小于1024的tcp/ip端口连接服务器;
- insecure允许客户端从大于1024的tcp/ip端口连接服务器;
- sync 将数据同步写入内存缓冲区与磁盘中,效率低,但可以保证数据的一致性;
- async 将数据先保存在内存缓冲区中,必要时才写入磁盘;

# 启动rpcbind服务(安装nfs依赖包会自动下载)、启动nfs服务
systemctl start rpcbind
systemctl start nfs

# 验证:显示当前所有挂载点
showmount -e localhost
/opt/nfsdata 192.168.10.0/24

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

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

apiVersion: v1
kind: Pod
metadata:
  name: xdclass-nfs
  namespace: dev
  labels: 
    apps: nginx-nfs
spec:
  containers:
  - name: nginx
    image: nginx:1.20
    ports:
    - containerPort: 80
    volumeMounts:
    - name: logs-volume
      mountPath: /var/log/nginx
  volumes:
  - name: logs-volume
    nfs:
      server: 192.168.10.72  #nfs服务器地址
      path: /opt/nfsdata #共享文件路径

其他操作

# 创建pod
kubectl apply -f nfs-pod.yaml

# 暴露服务
kubectl expose pod xdclass-nfs -n dev --port=80 --target-port=80 --type=NodePort

# 查询对外暴露端口 (80:31601/TCP)
kubectl get pod,svc -n dev

# 访问
curl http://192.168.10.71:31601/

# 查看nfs的access.log
cat /opt/nfsdata/access.log
10.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" "-"

# 删除service
kubectl delete service xdclass-nfs -n dev

# 删除pod
kubectl 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模板解析

apiVersion: v1
kind: PersistentVolume
metadata:
  name: xdclass-pv
spec:
  capacity:
    storage: 5Gi  # 存储大小
  accessModes: # 访问模式
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle # 回收策略
  storageClassName: slow # 存储类别
  nfs: # 卷插件
    path: /tmp
    server: 192.168.10.72

###### 属性解析
- 存储大小
存储大小是可以设置和请求的唯一资源。 未来可能会包含 IOPS、吞吐量等属性

- 访问模式(用户对资源的访问权限)
ReadWriteOnce(RWO):读写权限,只能被单个节点挂载
ReadOnlyMany(ROX): 只读权限,可以被多个节点挂载
ReadWriteMany(RWX):读写权限,可以被多个节点挂载
 
- 回收策略(当PV不再被使用了之后的处理策略)
保留 Retain -- 当PV对象被删除之后,与之相关的位于外部的基础设施中的数据仍然存在(如nfs),需要根据实际情况手动回收
回收 Recycle -- 相当于在卷上执行rm -rf /volume/* 操作,之后该卷可以用于新的pvc申领
删除 Delete -- 当PV对象被删除之后,与之相关的位于外部的基础设施中的数据也被一并删除(如nfs),需要根据实际情况手动回收,更多是云厂商设备

- 存储类别
每个 PV 可以属于某个类,通过将其 storageClassName属性设置为某个 StorageClass 的名称来指定。
特定类的 PV 卷只能绑定到请求该类存储卷的 PVC 申领。
未设置 storageClassName 的 PV 卷没有类设定,只能给到那些没有指定特定 存储类的 PVC 申领。

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

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

PVC的yaml模板解析

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

Pod中定义PVC

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

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

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

搭建nfs环境

# 创建目录
mkdir /opt/nfsdata/pv1
mkdir /opt/nfsdata/pv2
chmod 777 /opt/nfsdata/pv1
chmod 777 /opt/nfsdata/pv2

# 修改配置文件(WorkerNode1),暴露nfs服务
vim /etc/exports
/opt/nfsdata/pv1 192.168.10.0/24(rw,insecure,sync)
/opt/nfsdata/pv2 192.168.10.0/24(rw,insecure,sync)

# 重启nfs服务
systemctl restart nfs

创建两个PV

### volume-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name:  xdclass-pv1
spec:
  capacity: 
    storage: 1Gi
  accessModes:
  - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    server: 192.168.10.72
    path: /opt/nfsdata/pv1
    

---

apiVersion: v1
kind: PersistentVolume
metadata:
  name:  xdclass-pv2
spec:
  capacity: 
    storage: 2Gi
  accessModes:
  - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    server: 192.168.10.72
    path: /opt/nfsdata/pv2

### 创建PV
kubectl apply -f volume-pv.yaml

### 查看PV
kubectl get pv -o wide

### 删除PV
kubectl delete -f volume-pv.yaml

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

### volume-pvc.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: xdclass-pvc1
  namespace: dev
spec:
  accessModes: 
  - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: xdclass-pvc2
  namespace: dev
spec:
  accessModes: 
  - ReadWriteMany
  resources:
    requests:
      storage: 3Gi

### 创建PVC
kubectl apply -f volume-pvc.yaml 

### 查看PVC 
# 可以发现目前xdclass-pvc1已经与xdclass-pv1绑定了,而xdclass-pvc2却没有绑定
# 这是因为pvc2所申请的存储大小为3G,而pv2只能提供2G,因此无法进行绑定。
kubectl get pvc -n dev

### 删除PVC
kubectl delete -f volume-pvc.yaml

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

### pod-pv-pvc.yaml
apiVersion: v1
kind: Pod
metadata:
  name: xdclass-pod1
  namespace: dev
spec:
  containers:
  - name: xdclass-busybox
    image: busybox
    command: ["/bin/sh","-c","while true;do echo hello xdclass pod1 >> /opt/print.txt; sleep 5; done;"]
    volumeMounts:
    - name: volume
      mountPath: /opt/
  volumes:
    - name: volume
      persistentVolumeClaim:
        claimName: xdclass-pvc1
        readOnly: false
---
apiVersion: v1
kind: Pod
metadata:
  name: xdclass-pod2
  namespace: dev
spec:
  containers:
  - name: xdclass-busybox
    image: busybox
    command: ["/bin/sh","-c","while true;do echo hello xdclass pod2 >> /opt/print.txt; sleep 5; done;"]
    volumeMounts:
    - name: volume
      mountPath: /opt/
  volumes:
    - name: volume
      persistentVolumeClaim:
        claimName: xdclass-pvc2
        readOnly: false

### 创建pod
kubectl apply -f pod-pv-pvc.yaml

### 查看pod
kubectl get pod -n dev

### nfs服务器查看 /opt/nfsdata/pv1/print.txt
hello xdclass pod1
hello xdclass pod1
hello xdclass pod1

### nfs服务器查看 /opt/nfsdata/pv2/print.txt
没有文件

### 删除pod
kubectl delete -f pod-pv-pvc.yaml

K8S部署SpringBoot项目

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

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

安装Docker(本身已经安装)

安装JDK11 配置全局环境变量

tar -zxvf jdk-11.0.8_linux-x64_bin.tar.gz
mkdir /usr/local/software
mv jdk-11.0.8 /usr/local/software/jdk11

vim /etc/profile
JAVA_HOME=/usr/local/software/jdk11
CLASSPATH=$JAVA_HOME/lib/
PATH=$PATH:$JAVA_HOME/bin
export PATH JAVA_HOME CLASSPATH

source /etc/profile
java -version

安装Maven

yum install unzip -y
unzip apache-maven-3.5.4-bin.zip
mv apache-maven-3.5.4 /usr/local/software/maven3.5

vim /etc/profile
JAVA_HOME=/usr/local/software/jdk11
CLASSPATH=$JAVA_HOME/lib/
PATH=$PATH:$JAVA_HOME/bin
MAVEN_HOME=/usr/local/software/maven3.5
PATH=$PATH:$MAVEN_HOME/bin
export PATH JAVA_HOME CLASSPATH MAVEN_HOME

source /etc/profile

mvn -v

配置Maven阿里云

vim /usr/local/software/maven3.5/conf/settings.xml

    <mirror>
      <id>alimaven</id>
      <name>aliyun maven</name>
      <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
      <mirrorOf>central</mirrorOf>       
    </mirror>

SpringBoot项目构建、打包Docker镜像

# 进到项目根目录
[root@master xdclass-k8s]# pwd
/tmp/xdclass-k8s
[root@master xdclass-k8s]# ls
Dockerfile  HELP.md  mvnw  mvnw.cmd  pom.xml  src  xdclass-k8s.iml

# 进到项目根目录打包
mvn clean install

# 构建镜像(不要忽略最后的一个点)
docker build -t xdclass-k8s:1.0 .

# 查看镜像列表
docker images

# 启动(需要打开防火墙)
docker run -d -it -p 8080:8080 --name=k8sdemo xdclass-k8s:1.0

# 访问
http://192.168.10.71:8080/api/v1/test
{
"hello": "xdclass.net "
}

# 访问(网络安全组记得开放端口) 不要忘记停止这个容器
docker logs -f k8sdemo
接口访问时间:2024-01-13T10:47:07.217620

docker stop k8sdemo
docker rm k8sdemo

阿里云镜仓库像推送

推送私有镜像仓

# 登录阿里云Docker Registry
docker login --username=soulboy1990116 registry.cn-shanghai.aliyuncs.com

# 将镜像推送到Registry
docker tag 71a361a64058 registry.cn-shanghai.aliyuncs.com/leon_ns/xdclass-demo:1.0
docker push registry.cn-shanghai.aliyuncs.com/leon_ns/xdclass-demo:1.0

# 从Registry中拉取镜像
docker 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

### 创建Secret
kubectl 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

### 修改xdclass-k8s.yaml
# 1.修改副本数量为2
# 2.挂载secret
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: k8sdemo
  name: k8sdemo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: k8sdemo
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: k8sdemo
    spec:
      imagePullSecrets:
        - name: aliyun-soulboy-docker-secret
      containers:
      - image: registry.cn-shanghai.aliyuncs.com/leon_ns/xdclass-demo:1.0
        name: xdclass-k8s
        resources: {}
status: {}

创建delpoyment控制器

# 创建delpoyment控制器
kubectl apply -f xdclass-k8s.yaml

# 创建service, nodePort类型 
kubectl expose deploy k8sdemo --name=svc-k8sdemo-springboot --port=8080 --target-port=8080 --type=NodePort

# 查看pod (8080:30377/TCP)
kubectl get pod,deploy,svc -o wide 

# 测试运行(防火墙关闭)
curl 192.168.10.71:30377/api/v1/test
curl 192.168.10.72:30377/api/v1/test

# 查看日志
kubectl logs k8sdemo-9c78f4765-2zvwx
接口访问时间:2024-01-13T11:50:47.361305
接口访问时间:2024-01-13T11:50:47.51027

# 删除service
kubectl delete service svc-k8sdemo-springboot

# 删除pod
kubectl apply -f xdclass-k8s.yaml

Java源码

package net.xdclass.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

@SpringBootApplication
@RestController
public class XdclassK8sApplication {

	public static void main(String[] args) {
		SpringApplication.run(XdclassK8sApplication.class, args);
	}


	@RequestMapping("/api/v1/test")
	public Map<String,String> testApi(){
		Map<String,String> map = new HashMap<>(1);
		map.put("hello","xdclass.net ");

		System.out.println("接口访问时间:"+LocalDateTime.now());

		return map;
	}

}

作者:Soulboy