文章目录

1、Kubernetes介绍

1.1 应用部署方式演变

在部署应用程序的方式上,主要经历了三个时代:

  • 传统部署:互联网早期,会直接将应用程序部署在物理机上.
    • 优点:简单,不需要其它技术的参与;
    • 缺点:不能为应用程序定义资源使用边界,很难合理地分配计算资源,而且程序之间容易产生影响。
  • 虚拟化部署:可以在一台物理机上运行多个虚拟机,每个虚拟机都是独立的一个环境
    • 优点:程序环境不会相互产生影响,提供了一定程度的安全性;
    • 缺点:增加了操作系统,浪费了部分资源
  • 容器化部署:与虚拟化类似,但是共享了操作系统,有以下优点:
    • 可以保证每个容器拥有自己的文件系统、CPU、内存、进程空间等;
    • 运行应用程序所需要的资源都被容器包装,并和底层基础架构解耦;
    • 容器化的应用程序可以跨云服务商、跨Linux操作系统发行版进行部署.

三种部署方式如下图所示:

在这里插入图片描述
容器化部署方式给带来很多的便利,但是也会出现一些问题,比如说:

  • 一个容器故障停机了,怎么样让另外一个容器立刻启动去替补停机的容器;
  • 当并发访问量变大的时候,怎么样做到横向扩展容器数量。

这些容器管理的问题统称为容器编排问题,为了解决这些容器编排问题,就产生了一些容器编排的软件,比如:

  • Swarm:Docker自己的容器编排工具;
  • Mesos:Apache的一个资源统一管控的工具,需要和Marathon结合使用;
  • Kubernetes:Google开源的的容器编排工具。

其中,Google的Kubernetes市场占有率独占鳌头,如今已经成为了容器编排的标准。
在这里插入图片描述

1.2 Kubernetes简介

在这里插入图片描述
Kubernetes,是一个全新的基于容器技术的分布式架构领先方案,是谷歌严格保密十几年的秘密武器----Borg系统的一个开源版本,于2014年9月发布第一个版本,2015年7月发布第一个正式版本。

Kubernetes的本质是一组服务器集群,它可以在集群的每个节点上运行特定的程序,来对节点中的容器进行管理。目的是实现资源管理的自动化,主要提供了如下的主要功能:

  • 自动修复:一旦某一个容器崩溃,能够在1秒中左右迅速启动新的容器;
  • 弹性伸缩:可以根据需要,自动对集群中正在运行的容器数量进行调整;
  • 服务发现:服务可以通过自动发现的形式找到它所依赖的服务;
  • 负载均衡:如果一个服务启动了多个容器,能够自动实现请求的负载均衡;
  • 版本回退:如果发现新发布的程序版本有问题,可以立即回退到原来的版本;
  • 存储编排:可以根据容器自身的需求自动创建存储卷。

在这里插入图片描述

1.3 Kubernetes中的组件

一个Kubernetes集群主要是由控制节点(master)工作节点(node) 构成,每个节点上都会安装不同的组件。

master:集群的控制平面,负责集群的决策 ( 管理 )

  • ApiServer : 资源操作的唯一入口,接收用户输入的命令,提供认证、授权、API注册和发现等机制;
  • Scheduler : 负责集群资源调度,按照预定的调度策略将Pod调度到相应的node节点上;
  • ControllerManager : 负责维护集群的状态,比如程序部署安排、故障检测、自动扩展、滚动更新等;
  • Etcd :负责存储集群中各种资源对象的信息。

node:集群的数据平面,负责为容器提供运行环境 ( 干活 )

  • Kubelet : 负责维护容器的生命周期,即通过控制docker,来创建、更新、销毁容器;
  • KubeProxy : 负责提供集群内部的服务发现和负载均衡;
  • Docker : 负责节点上容器的各种操作。

在这里插入图片描述
下面,以部署一个nginx服务来说明Kubernetes系统各个组件调用关系:
1、首先要明确,一旦Kubernetes环境启动之后,master和node都会将自身的信息存储到etcd数据库中。
2、一个nginx服务的安装请求会首先被发送到master节点的apiServer组件。
3、apiServer组件会调用scheduler组件来决定到底应该把这个服务安装到哪个node节点上;在此时,它会从etcd中读取各个node节点的信息,然后按照一定的算法进行选择,并将结果告知apiServer。
4、apiServer调用controller-manager去调度Node节点安装nginx服务。
5、kubelet接收到指令后,会通知docker,然后由docker来启动一个nginx的pod;pod是kubernetes的最小操作单元,容器必须跑在pod中。
6、至此,一个nginx服务就运行了,如果需要访问nginx,就需要通过kube-proxy来对pod产生访问的代理。

这样,外界用户就可以访问集群中的nginx服务了。

1.4 Kubernetes中的概念

Master:集群控制节点,每个集群需要至少一个master节点负责集群的管控;
Node:工作负载节点,由master分配容器到这些node工作节点上,然后node节点上的docker负责容器的运行;
Pod:kubernetes的最小控制单元,容器都是运行在pod中的,一个pod中可以有1个或者多个容器;
Controller:控制器,通过它来实现对pod的管理,比如启动pod、停止pod、伸缩pod的数量等等;(控制器在kubernetes中是一类概念,也就是说,不仅仅只有一种控制器,而是有多种控制器,每一种都各自的使用场景)
Service:pod对外服务的统一入口,下面可以维护着同一类的多个pod;
Label:标签,用于对pod进行分类,同一类pod会拥有相同的标签;
NameSpace:命名空间,用来隔离pod的运行环境。

2、Kubernetes集群环境搭建

2.1 环境规划

2.1.1 集群类型

Kubernetes集群大致分为两类:一主多从多主多从

● 一主多从:一个Master节点和多台Node节点,搭建简单,但是有单机故障风险,适合用于测试环境。
● 多主多从:多台Master和多台Node节点,搭建麻烦,安全性高,适合用于生产环境。
在这里插入图片描述

为了测试简单,本次搭建的是一主两从类型的集群.

2.1.2 安装方式

目前生产部署Kubernetes 集群主要有两种方式:

  • Kubeadm

Kubeadm 是一个K8s 部署工具,提供kubeadm init 和kubeadm join,用于快速部署Kubernetes 集群。
 
官方文档:https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm/

  • 二进制包

从github 下载发行版的二进制包,手动部署每个组件,组成Kubernetes 集群。

Kubeadm降低了部署门槛,但屏蔽了很多细节,遇到问题很难排查。如果想更容易可控,推荐使用二进制包部署Kubernetes 集群,虽然手动部署麻烦点,期间可以学习很多工作原理,也利于后期维护。

在这里插入图片描述

2.1.3 主机规划

在这里插入图片描述

2.2 环境搭建

本次环境搭建需要三台CentOS服务器(一主二从),然后在每台服务器中分别安装Docker(18.06.3)、kubeadm(1.17.4)、kubectl(1.17.4)和kubelet(1.17.4)。

2.2.1 主机安装

略。

2.2.2 环境初始化

(1) 检查操作系统版本

要求操作系统的版本至少在7.5以上.
在这里插入图片描述
(2) 主机名解析

为了方便后面集群节点间的直接调用,在这配置一下主机名解析。企业中推荐使用内部DNS服务器。

# 主机名解析,编辑三台服务器 /etc/hosts文件,添加下面内容:
192.168.166.111    k8s-master01
192.168.166.112    k8s-node01
192.168.166.113    k8s-node02

(3) 时间同步

kubernetes要求集群中的节点时间必须精确一致,这里直接使用chronyd服务从网络同步时间。 企业中建议配置内部的时间同步服务器。

# 启动 chronyd服务
[root@k8s-master01 ~]# systemctl start chronyd
# 设置chronyd服务开机自启
[root@k8s-master01 ~]# systemctl enable chronyd
# chronyd服务启动稍等几秒钟,就可以使用date命令验证时间了。
[root@k8s-master01 ~]# date

(4) 禁用iptables和firewalld服务

kubernetes和docker在运行中会产生大量的iptables规则,为了不让系统规则跟它们混淆,直接关闭系统的规则。

# 1、关闭firewalld服务
[root@k8s-master01 ~]# systemctl stop firewalld
[root@k8s-master01 ~]# systemctl disable firewalld
# 2、关闭iptables服务
[root@k8s-master01 ~]# systemctl stop iptables
[root@k8s-master01 ~]# systemctl disable iptables

(5) 禁用selinux

selinux是linux系统下的一个安全服务,如果不关闭它,在安装集群中会产生各种各样的奇葩问题。

# 编辑 /etc/selinux/config 文件,修改SELINUX的值为disabled
# 注意修改完毕之后需要重启linux服务器
SELINUX=disabled

在这里插入图片描述
(6) 禁用swap分区

swap分区指的是虚拟内存分区,它的作用是在物理内存使用完之后,将磁盘空间虚拟成内存来使用。启用swap分区会对系统的性能产生非常负面的影响,因此kubernetes要求每个节点都要禁用swap设备,但如果因为某些原因不能关闭swap分区,就需要在集群安装过程中通过明确的参数进行配置说明。

# 编辑分区配置文件 /etc/fstab,注释掉swap分区一行
# 注意修改完毕之后需要重启linux服务器

在这里插入图片描述
(7) 修改linux的内核参数

# 修改linux的内核参数,添加网桥过滤和地址转发功能
# 编辑 /etc/sysctl.d/kubernetes.conf 文件,添加如下配置:
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1

# 重新加载配置
[root@k8s-master01 ~]# sysctl -p

# 加载网桥过滤模块
[root@k8s-master01 ~]# modprobe br_netfilter

# 查看网桥过滤模块是否加载成功
[root@k8s-master01 ~]# lsmod | grep br_netfilter

(8) 配置ipvs功能

在kubernetes中service有两种代理模型,一种是基于iptables的,一种是基于ipvs的,两者比较的话,ipvs的性能明显要高一些,但如果要使用它,需要手动载入ipvs模块。

# 1、安装ipset和ipvsadm
[root@k8s-master01 ~]# yum install ipset ipvsadmin -y

# 2、添加需要加载的模块写入脚本文件
[root@k8s-master01 ~]# cat <<EOF > /etc/sysconfig/modules/ipvs.modules
#!/bin/bash
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4
EOF

# 3、为脚本文件添加执行权限
[root@k8s-master01 ~]# chmod +x /etc/sysconfig/modules/ipvs.modules

# 4、执行脚本文件
[root@k8s-master01 ~]# /bin/bash /etc/sysconfig/modules/ipvs.modules

# 5、查看对应的模块是否加载成功
[root@k8s-master01 ~]# lsmod |grep -e ip_vs -e nf_conntrack_ipv4

(9) 重启服务器

上面步骤完成之后,需重启linux服务器

[root@k8s-master01 ~]# reboot

2.2.3 安装docker

# 1、切换镜像源
[root@k8s-node01 ~]# wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo

# 2、查看当前镜像源中支持的docker版本
[root@k8s-node01 ~]# yum list docker-ce --showduplicates

# 3、安装特定版本的docker-ce
# 必须指定 --setopt=obsoletes=0, 否则yum会自动安装更高版本
[root@k8s-node01 ~]# yum install --setopt=obsoletes=0 docker-ce-18.06.3.ce-3.el7 -y

# 4、添加一个配置文件
# Docker在默认情况下使用的Cgroup Driver为cgroupfs,而kubernetes推荐使用systemd来替代cgroupfs.
[root@k8s-node01 ~]# mkdir /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"registry-mirrors": ["https://bhu1x6ya.mirror.aliyuncs.com"]
}
EOF

# 5、启动docker、并设置开机启动
[root@k8s-node01 ~]# systemctl restart docker

# 6、检查docker状态和版本
[root@k8s-node01 ~]# docker version

在这里插入图片描述

2.2.4 安装kubernetes组件

# 由于kubenetes的镜像源在国外,速度比较慢,这里切换成国内的镜像源
# 编辑 /etc/yum.repos.d/kubernetes.repo,添加下面的配置
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgchech=0
repo_gpgcheck=0
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
       http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg

# 安装kubeadm、kubelet和kubectl
[root@k8s-master01 ~]# yum install --setopt=obsoletes=0 kubeadm-1.17.4-0 kubelet-1.17.4-0 kubectl-1.17.4-0 -y

# 配置kubelet的cgroup
# 编辑 /etc/sysconfig/kubelet,添加下面的配置
KUBELET_CGROUP_ARGS="--cgroup-driver=systemd"
KUBE_PROXY_MODE="ipvs"

# 设置kubelet 开机自启
[root@k8s-master01 ~]# systemctl enable kubelet

2.2.5 准备集群镜像

# 在安装kubernetes集群之前,必须要提前准备好集群需要的镜像,所需镜像可以通过下面命令查看
[root@k8s-master01 ~]# kubeadm config images list

# 下载镜像
# 此镜像在kubernetes的仓库中,由于网络原因,无法连接,下面提供了一种替代方案

images=(
  kube-apiserver:v1.17.4
  kube-controller-manager:v1.17.4
  kube-scheduler:v1.17.4
  kube-proxy:v1.17.4
  pause:3.1
  etcd:3.4.3-0
  coredns:1.6.5
)

for imageName in ${images[@]}; do
     docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName
     docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName k8s.gcr.io/$imageName
     docker rmi registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName
done

下载完成后如下图:
在这里插入图片描述

2.2.6 集群初始化

下面开始对集群进行初始化,并将node节点加入到集群中。

下面的操作只需在master节点上操作。

[root@k8s-master01 ~]# kubeadm init \
    --kubernetes-version=v1.17.4 \
    --pod-network-cidr=10.244.0.0/16 \
    --service-cidr=10.96.0.0/12 \
    --apiserver-advertise-address=192.168.166.111

# 创建必要文件
[root@k8s-master01 ~]# mkdir -p $HOME/.kube
[root@k8s-master01 ~]# cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
[root@k8s-master01 ~]# chown $(id -u):$(id -g) $HOME/.kube/config

下面的操作只需在node节点上操作。

# 将node节点加入到集群中
[root@k8s-node01 ~]# kubeadm join 192.168.166.111:6443 --token ke6low.t57x5lcgfs3mv3s2 \
    --discovery-token-ca-cert-hash sha256:8e8a425856325997b7f4d2370d6f0e0d49304641a9115e79a74adb524ec607f3

此时通过kubectl get nodes查看节点状态,发现 STATUS 处显示为 NotReady状态。表示节点之间网络还不通,需要安装网络插件。

2.2.7 安装网络插件

kubenetes支持多种网络插件,比如flannel、calico、canal等等,任选一种使用即可,本次选择flannel.

以下操作依旧只在master节点执行即可,插件使用的是DaemonSet的控制器,它会在每个节点上运行。

# 获取fannel的配置文件
[root@k8s-master01 ~]# wget 
https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml

# 修改文件中 quay.io 参控股为 quay-mirror.qiniu.com

# 使用配置文件启动 fannel
[root@k8s-master01 ~]# kubectl apply -f kube-flannel.yml

# 稍等片刻,再次查看集群节点的状态
[root@k8s-master01 ~]# kubectl get nodes
NAME           STATUS   ROLES    AGE   VERSION
k8s-master01   Ready    master   15m   v1.17.4
k8s-node01     Ready    <none>   13m   v1.17.4
k8s-node02     Ready    <none>   12m   v1.17.4

至此,kubernetes的集群环境搭建完成。

2.3 部署服务

接下来在kubernetes集群中部署一个Nginx服务,测试下集群是否正常工作。

# 部署nginx
[root@k8s-master01 ~]# kubectl create deployment nginx --image=nginx:1.21-alpine

# 暴露端口
[root@k8s-master01 ~]# kubectl expose deployment nginx --port=80 --type=NodePort

# 查看服务状态
[root@k8s-master01 ~]# kubectl get pods,services
NAME                         READY   STATUS    RESTARTS   AGE
pod/nginx-655cb49fc5-j9m4d   1/1     Running   0          3m13s

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
service/kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP        10h
service/nginx        NodePort    10.99.210.176   <none>        80:32203/TCP   2m14s

#  最后在浏览器上访问部署的nginx服务

在这里插入图片描述

3、资源管理

本章节主要介绍yaml语法和kubernetes的资源管理方式。

3.1 资源管理介绍

在kubernetes中,所有的内容都抽象为资源,用户需要通过操作资源来管理kubernetes。

kubernetes本质上就是一个集群系统,用户可以在集群中部署各种服务,所谓的部署服务,其实就是在kubernetes集群中运行一个个的容器,并将指定的程序跑在容器中。
 
kubernetes的最小管理单元是pod,而不是容器。所以只能将容器放在Pod中,而kubernetes一般也不会直接管理Pod,而是通过Pod控制器 来管理Pod。
 
Pod提供服务之后,就要考虑如何访问Pod中的服务,kubernetes提供了Service资源实现这个功能。另外,如果Pod中程序的数据需要持久化,kubernetes还提供了各种存储系统。
 
学习kubernetes的核心,就是学习如何对集群上的PodPod控制器Service存储等各种资源进行操作。
在这里插入图片描述


3.2 yaml语言介绍

YAML是一个类似XML、JSON的标记性语言。它强调以数据为中心,并不是以标识语言为重点。因而YAML本身的定义比较简单,号称"一种人性化的数据格式语言"。

xml 示例

<person>
    <age>15</age>
    <address>Beijing</address>
</person>

yaml 示例

person:
  age: 15
  address: Beijing

YAML的语法比较简单,主要有以下几个:

  • 大小写敏感;
  • 使用缩进标识层级关系;
  • 缩进不允许使用tab,只允许空格;
  • 缩进的空格数不重要,只要相同层级的元素左对齐即可;
  • # 表示注释。

YAML支持以下几种数据类型:

  • 纯量:单个的、不可再分的值;
  • 对象:键值对的集合,又称为映射(mapping)/ 哈希(hash)/ 字典(dictionary)
  • 数组:一组按次序排列的值,又称为序列(sequence)/ 列表(list)

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

Tips:
(1) 书写yaml切记:后面要加一个空格;
(2) 如果需要将多段yaml配置放在一个文件中,中间要使用 ---分割

 
分享一个json和yaml的对比、互相转换的网站,可用来验证yaml的书写是否正确:
http://json2yaml.com/convert-yaml-to-json

3.3 资源管理方式

  • 命令式对象管理:直接使用命令去操作kubernetes资源
kubectl run nginx-pod --image=nginx:1.17.1 --port=80
  • 命令式对象配置:通过命令配置和配置文件去操作kubernetes资源
kubectl create/patch -f nginx-pod.yaml
  • 声明式对象配置:通过apply命令和配置文件去操作kubernetes资源
kubectl apply -f nginx-pod.yaml

在这里插入图片描述

3.3.1 命令式对象管理

kubectl命令

kubectl是kubernetes集群的命令行工具,通过它能够对集群本身进行管理,并能够在集群上进行容器化应用的安装部署。kubectl命令的语法如下:

kubectl [command] [type] [name] [flags]
  • command:指定要对资源执行的操作,如create、get、delete
  • type:指定资源类型,比如deployment、pod、service
  • name:指定资源的名称,名称大小写敏感
  • flags:指定额外的可选参数
# 查看所有的pod
kubectl get pod

# 查看某个pod
kubectl get pod pod_name

# 查看某个pod,并以yaml格式展示结果
kubectl get pod pod_name -o yaml

资源类型

kubernetes中所有的内容都抽象为资源,可通过下面的命令进行查看:

kubectl api-resources

经常使用的有如下这些:
在这里插入图片描述
在这里插入图片描述

操作
kubernetes允许对资源进行多种操作,可以通过--help查看详细的操作命令。

kubectl --help

经常使用的操作有如下这些:
在这里插入图片描述
在这里插入图片描述
下面以一个namespace / pod 的创建和删除简单演示下命令的使用:

# 创建一个namespace
[root@k8s-master01 ~]# kubectl create namespace dev
namespace/dev created

# 获取namespace
[root@k8s-master01 ~]# kubectl get namespaces
NAME              STATUS   AGE
default           Active   16h
dev               Active   3s
kube-node-lease   Active   16h
kube-public       Active   16h
kube-system       Active   16h

# 在此namespace下创建并运行一个nginx的Pod
[root@k8s-master01 ~]# kubectl run pod --image=nginx --namespace=dev
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
deployment.apps/pod created

# 查看新创建的Pod
[root@k8s-master01 ~]# kubectl get pods --namespace=dev
NAME                   READY   STATUS    RESTARTS   AGE
pod-864f9875b9-b489g   1/1     Running   0          5m59s

# 删除指定的Pod
[root@k8s-master01 ~]# kubectl delete pod pod-864f9875b9-b489g --namespace=dev
pod "pod-864f9875b9-b489g" deleted

3.3.2 命令式对象配置

命令式对象配置就是使用命令配置配置文件一起来操作kubernetes资源。

(1) 创建一个nginxpod.yaml,内容如下:

apiVersion: v1
kind: Namespace
metadata: 
  name: dev

---

apiVersion: v1
kind: Pod
metadata:
  name: nginxpod
  namespace: dev
spec:
  containers:
  - name: nginx-containers
  - image: nginx:1.17.1

(2) 执行create命令,创建资源

[root@k8s-master01 ~]# kubectl create -f nginxpod.yml
namespace/dev created
pod/nginxpod created

此时发现创建了两个资源对象,分别是namespace和pod.

(3) 执行get命令,查看资源:

[root@k8s-master01 ~]# kubectl get -f nginxpod.yml
NAME            STATUS   AGE
namespace/dev   Active   82m

NAME           READY   STATUS    RESTARTS   AGE
pod/nginxpod   1/1     Running   1          82m

这样就显示了两个资源对象的信息。

(4) 执行delege命令,删除资源:

[root@k8s-master01 ~]# kubectl delete -f nginxpod.yml
namespace "dev" deleted
pod "nginxpod" deleted

此时发现两个资源对象被删除了。

总结:命令式对象配置的方式操作资源,可以简单的认为是:命令 + yaml配置文件(里面是命令需要的各种参数)

3.3.3 声明式对象配置

声明式对象配置跟命令式对象配置很相似,但它只有一个命令:apply

# 首先执行一次kubectl apply -f <yaml文件>,发现创建了资源
[root@k8s-master01 ~]# kubectl apply -f nginxpod.yml
namespace/dev created
pod/nginxpod created

# 再次执行一次kubectl apply -f yaml文件,发现说资源没有变动。
[root@k8s-master01 ~]# kubectl apply -f nginxpod.yml
namespace/dev unchanged
pod/nginxpod unchanged

总结:
其实声明式对象配置就是使用apply描述一个资源的最终状态(在yaml中定义状态)
使用apply操作资源:

  • 如果资源不存在,就创建,相当于 kubectl create
  • 如果资源已存在,就更新, 相当于 kubectl patch

扩展:kubectl可以在node节点上运行吗?

kubectl的运行时需要进行配置的,它的配置文件是$HOME/.kube,如果想要在node节点运行此命令,需要将master节点上的.kube文件复制到node节点上,即在master节点上执行以下操作:

scp -r HOME/.kube node1:$HOME/

3.3.4 使用推荐

使用推荐: 三种方式应该怎么用?

  • 创建/更新资源:使用声明式对象配置(kubectl apply -f xxx.yaml
  • 删除资源:使用命令式对象配置(kubectl delete -f xxx.yaml
  • 查询资源:使用命令式对象管理(kubectl get(describe) <资源名称>

4、实战入门

4.1 Namespace

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

默认情况下,kubernetes集群中的所有的Pod都是可以相互访问的。但在实际中,可能不想让两个Pod之间进行互相访问,那此时就可以将两个Pod划分到不同的namespace下。kubernetes通过将集群内部的资源分配到不同的Namespace中,可以形成逻辑上的"组",以方便不同的组的资源进行隔离使用和管理。

可以通过kubernetes的授权机制,将不同的namespace交给不同租户进行管理,这样就实现了多租户的资源隔离。此时还能结合kubernetes的资源配额机制,限定不同租户能占用的资源,例如CPU使用量、内存使用量等等,来实现租户可用资源的管理。
在这里插入图片描述
kubernetes在集群启动之后,会默认创建几个namespace.
在这里插入图片描述
下面来看namespace资源的具体操作。

查看

# 1、查看所有的namespace,命令:kubectl get ns/namespaces
[root@k8s-master01 ~]# kubectl get namespaces
NAME              STATUS   AGE
default           Active   23h
kube-node-lease   Active   23h
kube-public       Active   23h
kube-system       Active   23h

# 2、查看指定的namespace,命令:kubectl get namespace <ns名称>
[root@k8s-master01 ~]# kubectl get namespace default
NAME      STATUS   AGE
default   Active   23h

# 3、指定输出格式  命令:kubectl get ns <ns名称> -o 格式参数
# kubernetes支持的格式很多,常见的是wide、json、yaml
[root@k8s-master01 ~]# kubectl get namespaces -o yaml
apiVersion: v1
items:
- apiVersion: v1
  kind: Namespace
  metadata:
    creationTimestamp: "2022-03-11T14:18:39Z"
    name: default
    resourceVersion: "146"
    selfLink: /api/v1/namespaces/default
    uid: 57dddb3d-7645-4be1-878f-afc7b4486f4e
  spec:
    finalizers:
    - kubernetes
  status:
    phase: Active
 ...

# 4、查看ns详情   命令:kubectl describe ns ns名称
[root@k8s-master01 ~]# kubectl describe namespaces default
Name:         default
Labels:       <none>
Annotations:  <none>
Status:       Active   # Active:命名空间正在使用。Terminating 正在删除命名空间

# ResourceQuota:针对namespace做的资源限制
# LimitRange:针对namespace中的每个组件做的资源限制
No resource quota.
No LimitRange resource.

创建

# 创建namespace
[root@k8s-master01 ~]# kubectl create ns dev
namespace/dev created

删除

# 删除namespace
[root@k8s-master01 ~]# kubectl delete ns dev
namespace "dev" deleted

配置方式
首先准备一个yaml文件:ns-dev.yaml

apiVersion: v1
kind: Namespace
metadata:
    name: dev

然后就可以执行对应的创建和删除命令了:
创建:kubectl create -f ns-dev.yaml
删除:kubectl delete -f ns-dev.yaml

4.2 Pod

Pod是kubernetes集群进行管理的最小单元,程序要运行必须部署在容器中,而容器必须存在于Pod中。Pod可以认为是容器的封装,一个Pod中可以存在一个或多个容器。
在这里插入图片描述

[root@k8s-master01 ~]# kubectl get pod -n kube-system
NAME                                   READY   STATUS    RESTARTS   AGE
coredns-6955765f44-4pwjb               1/1     Running   1          24h
coredns-6955765f44-h2vpk               1/1     Running   1          24h
etcd-k8s-master01                      1/1     Running   2          24h
kube-apiserver-k8s-master01            1/1     Running   2          24h
kube-controller-manager-k8s-master01   1/1     Running   2          24h
kube-flannel-ds-7xx6d                  1/1     Running   1          14h
kube-flannel-ds-cmmv9                  1/1     Running   1          14h
kube-flannel-ds-vh55n                  1/1     Running   1          14h
kube-proxy-f9hmd                       1/1     Running   2          24h
kube-proxy-qqnlw                       1/1     Running   2          24h
kube-proxy-vd7dx                       1/1     Running   2          24h
kube-scheduler-k8s-master01            1/1     Running   2          24h

创建并运行

kubernetes没有提供单独运行Pod命令,都是通过Pod控制器来实现的。

# 命令格式:kubectl run <pod控制器名称> [参数]
# --image 指定Pod的镜像
# --port  指定端口
# --namespace  指定namespace
[root@k8s-master01 ~]# kubectl run nginx --image=nginx:1.17.1 --port=80 --namespace dev
deployment.apps/nginx created

查看pod信息

# 查看Pod基本信息
[root@k8s-master01 ~]# kubectl get pod -n dev
NAME                      READY   STATUS    RESTARTS   AGE
nginx17-96944c7cd-945rx   1/1     Running   0          15m

# 查看Pod的详细信息
[root@k8s-master01 ~]# kubectl describe pod nginx17-96944c7cd-945rx -n dev
Name:         nginx17-96944c7cd-945rx
Namespace:    dev
Priority:     0
Node:         k8s-node02/192.168.166.113
Start Time:   Sat, 12 Mar 2022 10:02:54 -0500
Labels:       pod-template-hash=96944c7cd
              run=nginx17
Annotations:  <none>
Status:       Running
IP:           10.244.2.7
IPs:
  IP:           10.244.2.7
Controlled By:  ReplicaSet/nginx17-96944c7cd
Containers:
  nginx17:
    Container ID:   docker://c08ddb4bff649ac2cdc190117841e78bc737cbec9074d04d88a0060ee98b13dc
    Image:          nginx:1.17.1
    Image ID:       docker-pullable://nginx@sha256:b4b9b3eee194703fc2fa8afa5b7510c77ae70cfba567af1376a573a967c03dbb
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Sat, 12 Mar 2022 10:02:55 -0500
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-mkgg5 (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  default-token-mkgg5:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-mkgg5
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age   From                 Message
  ----    ------     ----  ----                 -------
  Normal  Scheduled  16m   default-scheduler    Successfully assigned dev/nginx17-96944c7cd-945rx to k8s-node02
  Normal  Pulled     16m   kubelet, k8s-node02  Container image "nginx:1.17.1" already present on machine
  Normal  Created    16m   kubelet, k8s-node02  Created container nginx17
  Normal  Started    16m   kubelet, k8s-node02  Started container nginx17

访问Pod

# 获取pod IP
[root@k8s-master01 ~]# kubectl get pod -n dev -o wide
NAME                      READY   STATUS    RESTARTS   AGE   IP           NODE         NOMINATED NODE   READINESS GATES
nginx17-96944c7cd-945rx   1/1     Running   0          17m   10.244.2.7   k8s-node02   <none>           <none>

# 访问pod
[root@k8s-master01 ~]# curl http://10.244.2.7
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

删除指定Pod

# 删除指定Pod
[root@k8s-master01 ~]# kubectl delete pod nginx17-96944c7cd-945rx -n dev
pod "nginx17-96944c7cd-945rx" deleted

# 此时,显示删除指定Pod成功,但再次查询,发现又新生成了一个
[root@k8s-master01 ~]# kubectl get pod -n dev
NAME                      READY   STATUS    RESTARTS   AGE
nginx17-96944c7cd-k5hgm   1/1     Running   0          12s

# 这是因为当前Pod是由Pod控制器创建的,控制器会监控Pod,一旦发现Pod私网,会立即重建.
# 此时要想删除Pod,必须删除Pod控制器.

# 先来查询一下当前namespace下的Pod控制器
[root@k8s-master01 ~]# kubectl get deployments.apps  -n dev
NAME      READY   UP-TO-DATE   AVAILABLE   AGE
nginx17   1/1     1            1           21m

# 接下来,删除此Pod控制器
[root@k8s-master01 ~]# kubectl delete deployments.apps -n dev nginx17
deployment.apps "nginx17" deleted

# 稍等片刻,再查询Pod,发现Pod被删除了.
[root@k8s-master01 ~]# kubectl get pod -n dev
No resources found in dev namespace.

配置操作
创建一个pod-nginx.yaml,内容如下:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: dev
spec: 
  containers:
  - image: nginx:1.17.1
     imagePullPolicy: IfNotPresent
     name: pod
     ports:
       - name: nginx-port
         containerPort: 80
         protocol: TCP

然后就可以执行对应的创建和删除命令了:
创建:kubectl create -f pod-nginx.yaml
删除:kubectl delete -f pod-nginx.yaml

4.3 Label

Label是kubernetes系统中的一个重要概念。它的作用就是在资源上添加标识,用来对它们进行区分和选择。

Label的特点:

  • 一个Label会以key/value键值对的形式附加到各种对象上,如Node、Pod、Service等等。
  • 一个资源对象可以定义任意数量的Label,同一个Label也可以被添加到任意数量的资源对象上去。
  • Label通常在资源对象定义时确定,当然也可以在对象创建后动态添加或删除。

可以通过Label实现资源的多维度分组,以便灵活、方便地进行资源分配、调度、配置、部署等管理工作。

一些常用的Label示例如下:

  • 版本标签:“version”:“release”, “version”:“stable”…
  • 环境标签:“environment”:“dev”, “environment”:“test”, “environment”:“pro”
  • 架构标签:“tier”:“frontend”, “tier”:“backend”.

标签定义完毕之后,还要考虑到标签的选择,这就要使用到Label Selector,即:

  • Label用于给某个资源对象定义标识;
  • Label Selector用于查询和筛选拥有某些标签的资源对象。

当前有两种Label Selector:

  • 基于等式的Label Selector
    name = slave:选择所有包含Label中key="name"且value="slave"的对象;
    env != production:选择所有包括Label中的key="env"且value不等于"production"的对象。

  • 基于集合的Label Selector
    name in (master, slave):选择所有包含Label中的key="name"且value="master"或"slave"的对象;
    name not in (frontend):选择所有包含Label中的key="name"且value不等于"frontend"的对象。

    标签的选择条件可以使用多个,此时将多个Label Selector进行组合,使用逗号","进行分隔即可。例如:
    name=slave, env!=production
    name not in (frontend), env!=production

命令方式

# 为pod资源打标签
[root@k8s-master01 ~]# kubectl label pod nginx-pod version=1.0 -n dev
pod/nginx-pod labeled

# 为pod资源更新标签
[root@k8s-master01 ~]# kubectl label pod nginx-pod version=2.0 -n dev --overwrite
pod/nginx-pod labeled

# 查看标签
[root@k8s-master01 ~]# kubectl get pod nginx-pod -n dev --show-labels
NAME        READY   STATUS    RESTARTS   AGE     LABELS
nginx-pod   1/1     Running   0          4m21s   version=2.0

# 筛选标签
[root@k8s-master01 ~]# kubectl get pod  -l version=2.0   -n dev --show-labels
NAME        READY   STATUS    RESTARTS   AGE     LABELS
nginx-pod   1/1     Running   0          6m43s   version=2.0

[root@k8s-master01 ~]# kubectl get pod  -l version!=2.0   -n dev --show-labels
No resources found in dev namespace.

# 删除标签
[root@k8s-master01 ~]# kubectl label pod nginx-pod version- -n dev
pod/nginx-pod labeled
[root@k8s-master01 ~]#
[root@k8s-master01 ~]# kubectl get pod nginx-pod --show-labels -n dev
NAME        READY   STATUS    RESTARTS   AGE     LABELS
nginx-pod   1/1     Running   0          8m32s   <none>

配置方式

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: dev
  labels:
    version: "3.0"
    env: "test"
spec:
  containers:
  - image: nginx:1.17.1
    name: pod
    ports:
    - name: nginx-port
      containerPort: 80
      protocol: TCP

然后就可以执行对应的更新命令了:kubectl apply -f pod-nginx.yml

4.4 Deployment

在kubernetes中,Pod是最小的控制单元,但kubernetes很少直接控制Pod,一般都是通过Pod控制器来完成的。Pod控制器用于pod的管理,确保pod资源符合预期的状态,当pod的资源出现故障时,会尝试进行重启或重建Pod。

在kubernetes中Pod控制器的种类有很多,本章只介绍一种:Deployment.
在这里插入图片描述
命令操作

# 命令格式:kubectl run <deployment名称> [参数]
# --image 指定pod的镜像
# --port  指定端口
# --replicas  指定创建pod数量
# --namespace 指定namespace
[root@k8s-master01 ~]# kubectl run nginx --image=nginx:1.17.1 --port=80 --replicas=3 -n dev
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
deployment.apps/nginx created

# 查看创建的pod
[root@k8s-master01 ~]# kubectl get pod -n dev
NAME                     READY   STATUS    RESTARTS   AGE
nginx-64777cd554-fbcdr   1/1     Running   0          2m20s
nginx-64777cd554-kmm6t   1/1     Running   0          2m20s
nginx-64777cd554-mv27v   1/1     Running   0          2m20s

# 查看deployment的信息
[root@k8s-master01 ~]# kubectl get deployments.apps -n dev
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   3/3     3            3           4m42s

# UP-TO-DATE:成功升级的副本数量
# AVALIABLE: 可用副本的数量
[root@k8s-master01 ~]# kubectl get deployments.apps -n dev -o wide
NAME    READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS   IMAGES         SELECTOR
nginx   3/3     3            3           5m50s   nginx        nginx:1.17.1   run=nginx

# 查看deployment的详细信息
[root@k8s-master01 ~]# kubectl describe deployments.apps nginx -n dev
Name:                   nginx
Namespace:              dev
CreationTimestamp:      Sat, 12 Mar 2022 22:30:44 -0500
Labels:                 run=nginx
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               run=nginx
Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  run=nginx
  Containers:
   nginx:
    Image:        nginx:1.17.1
    Port:         80/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   nginx-64777cd554 (3/3 replicas created)
Events:
  Type    Reason             Age    From                   Message
  ----    ------             ----   ----                   -------
  Normal  ScalingReplicaSet  6m58s  deployment-controller  Scaled up replica set nginx-64777cd554 to 3

# 删除deployment
[root@k8s-master01 ~]# kubectl delete deployments.apps nginx -n dev
deployment.apps "nginx" deleted

配置操作

创建一个deploy-nginx.yaml,内容如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      run: nginx
  template:
    metadata:
      labels:
        run: nginx
    spec:
      containers:
      - image: nginx:1.21.5
        name: nginx
        ports:
        - containerPort: 80
          protocol: TCP

然后,就可以执行对应的创建和删除命令了:
创建:kubectl create -f deploy-nginx.yml
删除:kubectl delete -f deploy-nginx.yml

4.5 Service

通过上一节的学习,已经能够利用Deployment 来创建一组Pod来提供具有高可用性的服务。
虽然每个Pod都会分配一个单独的Pod IP,然而却存在如下两个问题:

  • Pod IP会随着Pod的重建产生变化;
  • Pod IP仅仅是集群内可见的虚拟IP,外部无法访问。

这样对于访问这个服务带来了难度。因此,kubernetes设计了Service来解决这个问题。

Service可以看作是一组同类Pod对外的访问接口。借助Service,应用可以方便地实现服务发现和负载均衡。
在这里插入图片描述
操作一:创建集群内部可访问的Service

# 暴露Service
[root@k8s-master01 ~]# kubectl expose deployment nginx --name=svc-nginx1 --type=ClusterIP --port=80 --target-port=80 -n dev
service/svc-nginx1 exposed

# 查看service
[root@k8s-master01 ~]# kubectl get service svc-nginx1 -n dev -o wide
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE   SELECTOR
svc-nginx1   ClusterIP   10.100.224.218   <none>        80/TCP    54s   run=nginx

# 这里产生了一个CLUSTER-IP,这就是service的IP,在service的生命周期中,这个地址是不会变动的
# 可以通过这个IP访问当前service对应的Pod
[root@k8s-master01 ~]# curl http://10.100.224.218

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
...
</html>

操作二:创建集群外部可访问的Service

# 上面创建的Service的type类型为ClusterIP,这个IP地址只能集群内部访问;
# 如果需要创建外部也可以访问的Service,需要修改type为NodePort
[root@k8s-master01 ~]# kubectl expose deployment nginx --name=svc-nginx2 --type=NodePort  --port=80 --target-port=80 -n dev
service/svc-nginx2 exposed

# 此时查看,会发现出现了NodePort类型的service, 而且又一对Port(80:31529/TCP)
[root@k8s-master01 ~]# kubectl get service svc-nginx2 -n dev -o wide
NAME         TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE   SELECTOR
svc-nginx2   NodePort   10.106.124.15   <none>        80:31529/TCP   35s   run=nginx

# 接下来就可以通过集群外的主机访问 `节点IP:31529` 来访问服务了。
# 例如在电脑主机上通过浏览器访问  http://192.168.166.113:31529

删除Service

[root@k8s-master01 ~]# kubectl delete service svc-nginx1 -n dev
service "svc-nginx1" deleted

配置方式
创建一个svc-nginx.yml,内容如下:

apiVersion: v1
kind: Service
metadata:
  name: svc-nginx1
  namespace: dev
spec:
  clusterIP: 10.100.224.219
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    run: nginx
  type: ClusterIP

然后就可以执行对应的创建和删除操作了:
创建:kubectl create -f svc-nginx.yml
删除:kubectl delete -f svc-nginx.yml

小结
至此,已经掌握了Namespace、Pod、Deployment、Service资源的基本操作,有了这些操作,就可以在Kubernetes集群中实现一个服务的简单部署和访问了。但如果想要更好的使用kubernetes,就需要深入学习这几种资源的细节和原理。

5、Pod详解

本章将详细介绍Pod资源的各种配置(yaml)和原理。

5.1 Pod介绍

5.1.1 Pod结构

在这里插入图片描述
每个Pod中都可以包含一个或多个容器,这些容器可以分为两类:

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

    这里是Pod内部的通讯,Pod之间的通讯采用虚拟二层网络技术来实现,我们当前环境用的是Flannel.

5.1.2 Pod定义

下面是Pod的资源清单:

apiVersion: v1	#必选,版本号,例如v1
kind: Pod		#必选,资源类型,例如Pod
metadata:		#必选,元数据
  name: string	#必选,Pod名称
  namespace: string	#Pod所述的命名空间,默认为"default"
  labels:		#自定义标签列表
    - name: string
spec:			#必选,Pod中容器的详细定义
	containers:	#必选, Pod中容器列表
	- name: string	#必选,容器名称
	  image: string	#必选,容器的镜像名称
	  imagePullPolicy: [Always|Never|IfNotPresent]	#获取镜像的策略
	  command: [string]	#容器的启动命令列表,如不指定,使用打包时使用的启动命令
	  args: [string]	#容器的启动命令参数列表
	  workingDir: string	#容器的工作目录
	  volumeMounts:		#挂载到容器内部的存储卷配置
	  - name: string	#引用pod定义的共享存储卷的名称,需用volumes[]部分定义的卷名
	    mountPath: string	#存储卷在容器内mount的绝对路径,应少于512字符
	    readOnly: boolean	#是否为只读模式
	  ports:	#需要暴露的端口号列表
	  - name: string	#端口的名称
	    containerPort: int	#容器需要监听的端口号
	    hostPort: int		#容器所在主机需要监听的端口号,默认与Container相同
	    protocol: string	#端口协议,支持TCP和UDP,默认TCP
	  env: 		#容器运行前需设置的环境变量列表
	  - name: string		#环境变量名称
	    value: string		#环境变量的值
	  resources: 		#资源限制和请求的设置
	    limits:			#资源限制的设置
	      cpu: string	#CPU的限制,单位为core数,将用于docker run --cpu-shares参数
	      memory: string   #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
	    requests:	#资源请求的设置
	      cpu: string		#cpu请求,容器启动的初始可用数量
	      memory: string	#内存请求,容器启动的初始可用数量
	  lifecycle:	#声明周期钩子
	    postStart:	#容器启动后立即执行此钩子,如果执行失败,会根据重启策略进行重启
	    preStop:		#容器终止前执行此钩子,无论结果如何,容器都会终止
	  livenessProbe:	#对Pod内各容器健康检查的设置,当探测无响应几次后将自动重启该容器
	    exec:		#对Pod内各容器健康检查的设置,当探测无响应几次后将自动重启该容器
	      command: [string]		#exec方式需要制定的命令或脚本
	    httpGet:	#对Pod内各容器健康检查方法设置为HttpGet,需要制定Path、port
	      path: string
	      port: number
	      host: string
	      scheme: string
	      HttpHeaders:
	      - name: string
	        value: string
	    tcpSocket:		#对Pod内各容器健康检查方式设置为tcpSocket方式
	      port: number
	    initialDelaySeconds: 0	#容器启动完成后首次探测的时间,单位为秒
	    timeoutSeconds: 0		#对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
	    periodSeconds: 0		#对容器监控检查的定期探测时间设置,单位秒,默认10秒/次
	    successThreshold: 0
	    failureThreshold: 0
	    securityContext:
	      privileged: false
	restartPolicy: [Always|Never|OnFailure]	#Pod的重启策略
	nodeName: <string>	#设置NodeName表示将该Pod调度到指定名称的node节点上
	nodeSelector: object	#设置NodeSelector表示将该Pod调度到包含这个label的node上
	imagePullSecrets:	#Pull镜像时使用的secret名称,以key: secretkey格式指定
	- name: string
	hostNetwork: false	#是否使用主机网络模式,默认false,如果设置true,表示使用宿主机网络
	volumes:	#在该pod上定义共享存储卷列表
	- name: string	#共享存储卷名称(volumes类型有很多种)
	  emptyDir: {}	#类型为emptyDir的存储卷,与Pod同生命周期的一个临时目录,为空值
	  hostPath: string	#类型为hostPath的存储卷,表示挂载Pod苏偶在宿主机的目录
	    path: string	#Pod所在宿主机的目录,将被用于同期中mount的目录

Tips:
可通过一个命令来查看每种资源的可配置项:

  • kubectl explain <资源类型> //查看某种资源可配置的一级属性
  • kubectl explain <资源类型.属性> //查看属性的子属性
[root@k8s-master01 ~]# kubectl explain pod
KIND:     Pod
VERSION:  v1

DESCRIPTION:
     Pod is a collection of containers that can run on a host. This resource is
     created by clients and scheduled onto hosts.

FIELDS:
   apiVersion	<string>
     APIVersion defines the versioned schema of this representation of an
     object. Servers should convert recognized schemas to the latest internal
     value, and may reject unrecognized values. More info:

   kind	<string>
     Kind is a string value representing the REST resource this object
     represents. Servers may infer this from the endpoint the client submits
     requests to. Cannot be updated. In CamelCase. More info:

   metadata	<Object>
     Standard object's metadata. More info:

   spec	<Object>
     Specification of the desired behavior of the pod. More info:
     
   status	<Object>
     Most recently observed status of the pod. This data may not be up to date.
     Populated by the system. Read-only. More info:

在kubernetes中基本所有资源的一级属性都是一样的,主要包含5个部分:

  • apiVersion <string> 版本,由kubernetes内部定义,版本号可以用kubectrl api-versions查询
  • kind <string> 类型,由kubernetes内部定义,版本号可以用kubectrl api-resources查询
  • metadata <Object> 元数据,主要是资源标识和说明,常用的有name, namespace, labels等
  • spec <Object> 描述,这是配置中最重要的一部分,里面是对各种资源配置的详细描述
  • status <Object> 状态信息,里面的内容不需要定义,由kubernetes自动生成。

在上面的属性中,spec是接下来研究的终端,继续看下它的常见子属性:

  • containers <[]Object> 容器列表,用于定义容器的详细信息
  • nodeName <String> 根据nodeName的值将pod调度到指定的Node节点上
  • nodeSelector <map[]> 根据nodeSelector中定义的信息选择将该pod调度到包含这些label的Node上.
  • hostNetwork <boolean> 是否使用主机网络模式,默认false,如果设为true则表示使用宿主机网络
  • volumes <[]Object> 存储卷,用于定义pod上面挂载的存储信息
  • restartPolicy <string> 重启策略,表示pod在遇到故障时的处理策略.

5.2 Pod配置

本小姐主要介绍pod.spec.containers 属性,这也是Pod配置中最为关键的一项配置。

[root@k8s-master01 ~]# kubectl explain pod.spec.containers
KIND:     Pod
VERSION:  v1

RESOURCE: containers <[]Object>

DESCRIPTION:
     List of containers belonging to the pod. Containers cannot currently be
     added or removed. There must be at least one container in a Pod. Cannot be
     updated.

     A single application container that you want to run within a pod.

FIELDS:
   args	<[]string>	 #容器名称
   command	<[]string>  #容器
   env	<[]Object>	#容器环境变量的配置
   image	<string>	#容器需要的镜像地址
   imagePullPolicy	<string>	#镜像拉取策略
   name	<string> 	#容器名称
   ports	<[]Object>	#容器需要暴露的端口号列表
   resources	<Object>	#资源限制和资源请求的设置

5.2.1 基本配置

创建pod-base.yml文件,内容如下:

apiVersion: v1
kind: Pod
metadata:
  name:  pod-base
  namespace: dev
  labels:
    user: m01e
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  - name: busybox
    image: busybox:1.30

上面定义了一个比较简单的Pod的配置,里面有两个容器:

  • nginx:用1.17.1 版本的nginx镜像创建
  • busybox: 用1.30版本的busybox镜像创建(busybox是一个小巧的linux命令集合)
# 创建Pod
[root@k8s-master01 ~]# kubectl apply -f pod-base.yml
pod/pod-base created

# 查看pod状况
# READY 1/2:表示当前pod中有两个容器,其中1个准备就绪,1个未就绪;
# RESTARTS:重启次数,因为有1个容器故障了,Pod一直在重启视图恢复它.
[root@k8s-master01 ~]# kubectl get pod -n dev
NAME       READY   STATUS             RESTARTS   AGE
pod-base   1/2     CrashLoopBackOff   4          2m1s

# 可以通过describe查看内部详情
# 测试已经运行起来了一个基本的Pod,虽然它暂时有问题
[root@k8s-master01 ~]# kubectl describe pod pod-base -n dev

5.2.2 镜像拉取

创建pod-imagepullpolicy.yml文件,内容如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-imagepullpolicy
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    imagePullPolicy: Always #用于设置镜像拉取策略
  - name: busybox
    image: busybox:1.30

imagePullPolicy, 用于设置镜像拉取策略,kubernetes支持配置三种拉取策略:

  • Always:总是从远程仓库拉取镜像;
  • IfNotPresent:本地有则使用本地镜像,否则从远程仓库拉取镜像;
  • Never:只使用本地镜像,本地没有就报错.

默认值说明:
如果镜像tag为具体版本号,默认策略是:IfNotPresent
如果镜像tag为 latest(最新版本),默认策略是always

# 创建pod
[root@k8s-master01 ~]# kubectl create -f pod-imagepullpolicy.yml
pod/pod-imagepullpolicy created

# 查看pod详情
# 此时明显可以看到nginx镜像有一步Pulling image "nginx:1.17.2" 的过程
Events:
  Type    Reason     Age   From                 Message
  ----    ------     ----  ----                 -------
  Normal  Pulling    48s   kubelet, k8s-node01  Pulling image "nginx:1.17.2"
  Normal  Scheduled  47s   default-scheduler    Successfully assigned dev/pod-imagepullpolicy to k8s-node01
  Normal  Pulled     17s   kubelet, k8s-node01  Successfully pulled image "nginx:1.17.2"
  Normal  Created    13s   kubelet, k8s-node01  Created container nginx
  Normal  Started    13s   kubelet, k8s-node01  Started container nginx
  Normal  Pulling    13s   kubelet, k8s-node01  Pulling image "busybox:1.30"

5.2.3 启动命令

在前面的案例中,一直有一个问题没有解决,就是busybox容器一直没有成功运行,到底是什么原因导致这个容器的故障呢?

原来busybox并不是一个程序,而是类似于一个工具类的集合,kubernetes集群启动管理后,它会自动关闭。解决方法就是让其一直在运行,这就用到了command配置项。

创建pod-command.yml文件,内容如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-command
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  - name: busybox
    image: busybox:1.30
    command: ["/bin/sh","-c","touch /tmp/hello.txt;while true;do /bin/echo $(datte +%T) >> /tmp/hello.txt; sleep 3; done"]
# 创建Pod
[root@k8s-master01 ~]# kubectl create -f pod-command.yml
pod/pod-command created

# 查看pod状态
# 此时发现pod的两个容器均正常运行了
[root@k8s-master01 ~]# kubectl get pod pod-command -n dev
NAME          READY   STATUS    RESTARTS   AGE
pod-command   2/2     Running   0          2m23s

# 进入pod中的busybox容器,查看文件内容
# 补充一个命令: kubectl exec <pod名称> -n <命名空间> -it -c <容器名称> /bin/sh
# 使用这个命令就可以进入某个容器的内部,然后进行相关操作了
# 比如:
[root@k8s-master01 ~]# kubectl exec pod-command -n dev -it -c busybox  /bin/sh
/ # id
uid=0(root) gid=0(root) groups=10(wheel)
/ # tail -f /tmp/hello.txt
00:39:34
00:39:37
00:39:40
00:39:43
00:39:46

特别说明:
通过上面发现command已经可以完成启动命令和传递参数的功能,为什么这里还要提供一个args选项,用于传递参数呢?这其实跟docker优点观念西,kubernetes中的command、args两项其实是实现覆盖Dockerfile中ENTRYPOINT的功能。
(1) 如果command和args均没有写,那么用Dockerfile的配置.
(2) 如果command写了,但args没有写,那么Dockerfile默认的配置会被忽略,执行输入的command.
(3) 如果command没写,但args写了,那么Dockerfile中配置的ENTRYPOINT的命令会被执行,使用当前args的参数;
(4) 如果command和args都写了,那么Dockerfile的配置被忽略,执行command并追加上args参数。

5.2.4 环境变量

创建pod-env.yml文件,内容如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-env
  namespace: dev
spec:
  containers:
  - name: busybox
    image: busybox:1.30
    command: ["/bin/sh","-c","while true;do /bin/echo $(date +%T);sleep 60; done;"]
    env: #设置环境变量列表
    - name:  "username"
      value: "admin"
    - name: "password"
      value: "123456"

env,环境变量,用于在pod中的容器设置环境变量。

# 创建pod
[root@k8s-master01 ~]# kubectl create -f pod-env.yml
pod/pod-env created

# 进入容器,输出环境变量
[root@k8s-master01 ~]# kubectl exec pod-env -n dev -it -c busybox /bin/sh
/ #
/ # echo $username
admin
/ #
/ # echo $password
123456

# 还可以通过attach命令(对应docker里的docker attach)进入容器当前的进程, 可看到每隔1分钟输出一次时间
[root@k8s-master01 ~]# kubectl attach pod-env -n dev -c busybox
If you don't see a command prompt, try pressing enter.

01:44:34

这种方式不是很推荐,推荐将这些配置单独存储在配置文件中,这种方式将在后面介绍。

5.2.5 端口设置

本小结来介绍容器的端口设置,也就是containers的ports选项。
首先看下ports支持的子选项:

[root@k8s-master01 ~]# kubectl explain pod.spec.containers.ports
KIND:     Pod
VERSION:  v1

RESOURCE: ports <[]Object>
FIELDS:
    name    <string>  #端口名称,如果指定,必须保证name在pod中是唯一的
    containerPort  <Integer>    #容器要监听的端口(0<x<65536)
    hostPort  <Integer>  #容器要再主机上公开的端口,如果设置,主机上只能运行容器的一个副本(一般省略)
    hostIP  <string>  #要讲外部端口绑定到的主机IP(一般省略)
    protocol  <string>  #端口协议,必须是UDP/TCP/SCTP 三者之一 ,默认为TCP。

接下来,编写一个测试案例,创建pod-ports.yaml

apiVersion: v1
kind: Pod
metadata:
  name: pod-ports
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports: #设置容器暴露的端口列表
    - name: nginx-port
      containerPort: 80
      protocol: TCP
# 创建Pod
[root@k8s-master01 ~]# kubectl create -f pod-ports.yml
pod/pod-ports created

# 查看pod
# 在下面可以明显看到配置信息
[root@k8s-master01 ~]# kubectl get pod pod-ports -n dev -o yaml
...

[root@k8s-master01 ~]# kubectl get pod pod-ports -n dev -o yaml |grep IP
  hostIP: 192.168.166.112
  podIP: 10.244.1.15
  podIPs:
[root@k8s-master01 ~]#
[root@k8s-master01 ~]# kubectl get pod pod-ports -n dev -o yaml |grep Port
    - containerPort: 80

访问容器中的对外服务/应用,使用的是 podIP:containerPort。

5.2.6 资源配额

容器中的程序要运行,肯定是要占用一定资源的,比如cpu和内存等,如果不对某个容器的资源做限制,那么它就可能吃掉大量资源,导致其它容器无法运行。针对这种情况,kubernetes提供了对内存和CPU的资源进行配额的机制,这种机制主要通过resources选项实现,他有两个子选项:

  • limits: 用于限制运行时容器的最大占用资源,当容器申请内存超过limits时会被终止,并进行重启;
  • requests:用于设置容器需要的最小资源,如果资源不够,容器将无法启动。

可以通过上面两个选项设置资源的上下限。

接下来,编写一个测试案例,创建pod-resources.yml

apiVersion: v1
kind: Pod
metadata:
  name: pod-resources
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    resources: #资源配额
      limits:  #限制资源(上限)
        cpu: "2"  #cpu限制,单位是core数
        memory: "3Gi"  #内存限制
      requests:  #请求资源(下限)
        cpu: "1"  #cpu限制,单位是core数
        memory: "10Mi"  #内存限制

在这对cpu和memory的单位做一个说明:

  • cpu:core数,可以为整数或小数;
  • memory: 内存大小,可以使用Gi、 Mi、 G、M等形式。
# 运行pod
[root@k8s-master01 ~]# kubectl create -f pod-resources.yml
pod/pod-resources created

# 查看发现pod运行正常
[root@k8s-master01 ~]# kubectl get pod pod-resources -n dev
NAME            READY   STATUS    RESTARTS   AGE
pod-resources   1/1     Running   0          28s

# 接下来,停止pod
[root@k8s-master01 ~]# kubectl delete -f pod-resources.yml
pod "pod-resources" deleted

5.3 Pod生命周期

我们一般将pod对象从创建到终止的这段时间范围称为pod的生命周期,它主要包含下面的过程:

  • pod创建过程;
  • 运行初始化容器(init container)过程;
  • 运行主容器(main container)过程;
    • 容器启动后钩子(post start)、容器终止前钩子(pre stop)
    • 容器的存活性探测(liveness probe)、就绪性探测(readiness probe)
  • pod终止过程。
    在这里插入图片描述

在整个生命周期中,pod会出现5种状态相位),如下:

  • 挂起(Pending):apiserver已经创建了pod资源对象,但它尚未被调度完成或仍处于下载镜像的过程中;
  • 运行中(Running):pod已经被调度至某节点,并且所有容器都已经被kubelet创建完成;
  • 成功(Succeeded):pod中的所有容器都已经成功终止并且不会被重启;
  • 失败(Failed):所有容器都已经终止,但至少有一个容器终止失败,即容器返回了非0值的退出状态;
  • 未知(Unknown):apiserver无法正常获取到pod对象的状态信息,通常由网络通信失败所导致。

5.3.1 创建和终止

pod的创建过程

(1) 用户通过kubectl或其他api客户端提交需要创建的pod信息给apiServer;
(2) apiServer开始生成pod对象的信息,并将信息存入etcd,然后返回确认信息至客户端;
(3) apiServer开始反映etcd中的pod对象的变化,其它组件使用watch机制来跟踪检查apiServer上的变动;
(4) scheduler发现又新的pod对象要创建,开始为pod分配主机并将结果信息更新至apiServer
(5) node节点上的kubelet发现有pod调度过来,尝试调用docker启动容器,并将结果回送至apiServer;
(6) apiServer将接收到的pod状态信息存入etcd中。
在这里插入图片描述
pod的终止过程

(1) 用户向apiServer发送删除Pod对象的命令;
(2) apiServer中的pod对象信息会随着时间的推移而更新,在宽限期内(默认30s),Pod被视为dead;
(3) 将pod标记为terminating状态;
(4) kubelet在监控到pod对象转为terminating状态的同时启动pod关闭过程;
(5) 端点控制器监控到pod对象的关闭行为时将其从所有匹配到此端点的service资源的端点列表中移除;
(6) 如果当前pod对象定义了preStop钩子处理器,则在其标记为terminating后即会以同步的方式启动执行;
(7) pod对象中的容器进程收到停止信号;
(8) 宽限期结束后,若pod中还存在奶仍在运行的进程,那么pod对象会收到立即终止的信号;
(9) kubelet请求apiServer将此pod资源的宽限期设置为0从而完成删除操作,此时pod对于用户已不可见。

5.3.2 初始化容器

初始化容器是在pod的主容器启动之前要运行的容器,主要是做一些主容器的前置工作,它具有两大特征:
(1) 初始化容器必须运行完成直至结束,若某初始化容器运行失败,那么kubernetes需要重启它直到成功完成;
(2) 初始化容器必须按照定义的顺序执行,当且仅当前一个成功之后,后面的一个才能运行。

初始化容器有很多的应用场景,下面列出的是最常见的几个:

  • 提供主容器镜像中不具备的工具程序或自定义代码;
  • 初始化容器要先于应用容器串行启动并运行完成,因此可用于延后应用容器的启动直至其依赖的条件得到满足。

接下来做一个案例,模拟下面这个需求:
假设要以主容器来运行Nginx,但是要求在运行nginx之前先要能够连接上mysql和redis所在服务器。
为了简化测试,事先规定好mysql(192.168.109.201)和redis(192.168.109.202)服务器的地址。

创建pod-initcontainer.yml,内容如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-initcontainer
  namespace: dev
spec:
  containers:
  - name: main-container
    image: nginx:1.17.1
    ports:
    - name: nginx-port
      containerPort: 80
  initContainers:
    - name: test-mysql
      image: busybox:1.30
      command: ['sh','-c','until ping 192.168.166.201 -c 1; do echo waiting for mysql...;sleep 2; done']
    - name: test-redis
      image: busybox:1.30
      command: ['sh','-c','until ping 192.168.166.202 -c 1; do echo waiting for redis...;sleep 2; done']
# 创建pod
[root@k8s-master01 ~]# kubectl create -f pod-initcontainer.yml
pod/pod-initcontainer created

# 查看pod状态
# 发现pod卡在启动第一个初始化容器过程中,后面的容器不会运行
[root@k8s-master01 ~]# kubectl describe pod pod-initcontainer -n dev
...

# 动态查看pod
[root@k8s-master01 ~]# kubectl get pod pod-initcontainer.yml -n dev -w
Error from server (NotFound): pods "pod-initcontainer.yml" not found
[root@k8s-master01 ~]# kubectl get pod pod-initcontainer -n dev -w
NAME                READY   STATUS     RESTARTS   AGE
pod-initcontainer   0/1     Init:0/2   0          15s
pod-initcontainer   0/1     Init:1/2   0          26s
pod-initcontainer   0/1     Init:1/2   0          27s
pod-initcontainer   0/1     PodInitializing   0          39s
pod-initcontainer   1/1     Running           0          40s

# 接下来新开一个shell,为当前服务器新增两个ip,观察pod的变化
[root@k8s-master01 ~]# ifconfig ens33:1 192.168.166.201 netmask 255.255.255.0 up
[root@k8s-master01 ~]# ifconfig ens33:2 192.168.166.202 netmask 255.255.255.0 up

5.3.3 钩子函数

钩子函数能够感知自身生命周期中的事件,并在相应的时刻到来时运行用户指定的程序代码。
kubernetes在主容器的启动之后和停止之前提供了两个钩子函数:

  • post start: 容器创建之后执行,如果失败了会重启容器;
  • pre stop: 容器终止之前执行,执行完成之后容器将成功终止,在其完成之前会阻塞删除容器的操作。

钩子处理器支持使用下面三种方式定义动作:

  • Exec命令:在容器内执行一次命令
...
  lifecycle:
    postStart:
      exec:
        command:
        - cat
        - /tmp/healthy
...
  • TCPSocket:在当前容器尝试访问指定的socket
...
  lifecycle:
    postStart:
      tcpSocket:
        port: 8080
...
  • HTTPGet: 在当前容器中向某url发起Http请求
...
  lifecycle:
    postStart:
      httpGet:
        path: /  #URI地址
        port: 80  #端口号
        host: 192.168.166.111  #主机地址
        scheme: HTTP  #支持的协议:http/https
...

接下来,以exec方式为例,演示下钩子函数的使用,创建pod-hook-exec.yml文件,内容如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-hook-exec
  namespace: dev
spec:
  containers:
  - name: main-container
    image: nginx:1.17.1
    ports:
    - name: nginx-port
      containerPort: 80
    lifecycle:
      postStart:
        exec:  # 在容器启动时执行一个命令,修改掉nginx默认首页的内容
          command:  ["/bin/sh","-c","echo postStart... > /usr/share/nginx/html/index.html"]
      preStop:
        exec:  # 在容器停止之前停止nginx服务
          command: ["/usr/sbin/nginx","-s","quit"]
# 创建pod
[root@k8s-master01 ~]# kubectl create -f pod-hook-exec.yml
pod/pod-hook-exec created

# 查看pod
[root@k8s-master01 ~]# kubectl get pod pod-hook-exec -n dev -o wide
NAME            READY   STATUS    RESTARTS   AGE   IP            NODE         NOMINATED NODE   READINESS GATES
pod-hook-exec   1/1     Running   0          27s   10.244.2.32   k8s-node02   <none>           <none>

# 访问pod
[root@k8s-master01 ~]# curl http://10.244.2.32
postStart...

5.3.4 容器探测

容器探测用于检测容器中的应用实例是否正常工作,是保障业务可用性的一种传统机制。如果经过探测,实例的状态不符合预期,那么kubernetes就会把该问题实例"摘除",不承担业务流量。kubernetes提供了两种探针来实现容器探测,分别是:

  • liveness probes: 存活性探针,用于检测应用实例当前是否处于正常运行状态,如果不是,k8s会重启容器;
  • readiness probes:就绪性探针,用于检测应用实例当前是否可以接收请求,如果不能,k8s不会转发流量。

livenessProbe 决定是否重启容器,readinessProbe 决定是否将请求转发给容器。

上面两种探针目前均支持三种探测方式:

  • Exec命令:在容器内执行一次命令,如果命令执行的退出码为0,则认为程序正常,否则不正常;
...
  livenessProbe:
    exec:
      command:
      - cat
      - /tmp/healthy
...
  • TCPSocket: 将会尝试访问一个用户容器的端口,如果能够建立这条连接,则认为程序正常,否则不正常;
...
  livenessProbe:
    tcpSocket:
      port: 8080
...
  • HTTPGet:调用容器内Web应用的URL,如果返回的状态码在200和399之间,则认为程序正常,否则不正常。
...
  livenessProbe:
    httpGet:
      path: /  #URI地址
      port: 80  #端口号
      host: 127.0.0.1   #主机地址
      scheme: HTTP  #支持的协议,http/https
...

下面以liveness probes为例,做几个演示:

方式一:Exec
创建pod-liveness-exec.yml

apiVersion: v1
kind: Pod
metadata:
  name: pod-liveness-exec
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports:
      name: nginx-port
      containerPort: 80
    livenessProbe:
      exec:
        command: ["/bin/cat", "/tmp/hello.txt"]  #执行一个查看文件的命令

创建pod,观察结果

# 创建pod
[root@k8s-master01 ~]# kubectl create -f pod-liveness-exec.yml
pod/pod-liveness-exec created

# 查看pod详情
[root@k8s-master01 ~]# kubectl describe pod pod-liveness-exec -n dev
...
Events:
  Type     Reason     Age                From                 Message
  ----     ------     ----               ----                 -------
  Normal   Scheduled  75s                default-scheduler    Successfully assigned dev/pod-liveness-exec to k8s-node01
  Normal   Pulled     20s (x3 over 76s)  kubelet, k8s-node01  Container image "nginx:1.17.1" already present on machine
  Normal   Created    20s (x3 over 76s)  kubelet, k8s-node01  Created container nginx
  Normal   Started    20s (x3 over 76s)  kubelet, k8s-node01  Started container nginx
  Normal   Killing    20s (x2 over 50s)  kubelet, k8s-node01  Container nginx failed liveness probe, will be restarted
  Warning  Unhealthy  10s (x7 over 72s)  kubelet, k8s-node01  Liveness probe failed: /bin/cat: /tmp/hello.txt: No such file or directory

# 观察上面的信息会发现nginx容器启动之后就进行了健康检查
# 检查失败之后,容器被kill掉,然后尝试进行重启(这是重启策略的作用,后面会讲解)
# 稍等一会之后,再观察pod信息,就可以看到RESTARTS不再是0,而是一直增长。
[root@k8s-master01 ~]# kubectl get pod pod-liveness-exec -n dev
NAME                READY   STATUS    RESTARTS   AGE
pod-liveness-exec   1/1     Running   5          3m22s

# 接下来,可以修改成一个存在的文件,再试,结果就正常了...

方式二:TCPSocket

创建pod-liveness-tcpsocket.yml

apiVersion: v1
kind: Pod
metadata:
  name: pod-liveness-tcpsocket
  namespace: dev
spec:
  containers:
  - name: nginx
  image: nginx:1.17.1
  ports:
  - name: nginx-port
    containerPort: 80
  livenessProbe:
    tcpSocket:
      port: 8080  # 尝试访问8080端口

创建pod,观察效果

# 创建pod
[root@k8s-master01 ~]# kubectl create -f pod-liveness-tcpsocket.yml
pod/pod-liveness-tcpsocket created

# 查看Pod详情
[root@k8s-master01 ~]# kubectl describe pod pod-liveness-tcpsocket -n dev
...
Events:
  Type     Reason     Age                From                 Message
  ----     ------     ----               ----                 -------
  Normal   Scheduled  26s                default-scheduler    Successfully assigned dev/pod-liveness-tcpsocket to k8s-node01
  Normal   Pulled     26s                kubelet, k8s-node01  Container image "nginx:1.17.1" already present on machine
  Normal   Created    26s                kubelet, k8s-node01  Created container nginx
  Normal   Started    25s                kubelet, k8s-node01  Started container nginx
  Warning  Unhealthy  11s (x2 over 21s)  kubelet, k8s-node01  Liveness probe failed: dial tcp 10.244.1.18:8080: connect: connection refused

# 观察上面的信息,发现尝试访问8080端口,但失败了
# 稍等一会之后再观察pod信息,就可以看到RESTARTS不再是0,而是一直增长。
[root@k8s-master01 ~]# kubectl get pod pod-liveness-tcpsocket -n dev
NAME                     READY   STATUS    RESTARTS   AGE
pod-liveness-tcpsocket   1/1     Running   3          106s

# 可以修改成一个可以访问的端口,比如80,再试,结果就正常了。

方式三:HTTPGet

创建pod-liveness-httpget.yml

apiVersion: v1
kind: Pod
metadata:
  name: pod-liveness-httpget
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports:
    - name: nginx-port
      containerPort: 80
      protocol: TCP
    livenessProbe:
      httpGet:    #其实就是访问scheme://host:port/path
        scheme: HTTP  #支持的协议,Http或https
        port: 80   #端口号
        path: /hello  #URI地址

创建pod,观察效果

# 创建pod
[root@k8s-master01 ~]# kubectl create -f pod-liveness-httpget.yml
pod/pod-liveness-httpget created

# 查看pod详情
[root@k8s-master01 ~]# kubectl describe  pod pod-liveness-httpget -n dev
...
Events:
  Type     Reason     Age                From                 Message
  ----     ------     ----               ----                 -------
  Normal   Scheduled  25s                default-scheduler    Successfully assigned dev/pod-liveness-httpget to k8s-node01
  Normal   Pulled     25s                kubelet, k8s-node01  Container image "nginx:1.17.1" already present on machine
  Normal   Created    25s                kubelet, k8s-node01  Created container nginx
  Normal   Started    24s                kubelet, k8s-node01  Started container nginx
  Warning  Unhealthy  10s (x2 over 20s)  kubelet, k8s-node01  Liveness probe failed: HTTP probe failed with statuscode: 404

# 观察上面信息,尝试访问路径,但是未找到,出现404错误
# 稍等一会,再观察pod信息,就可以看到RESTARTS不再是0,而是一直增长
[root@k8s-master01 ~]# kubectl get pod pod-liveness-httpget -n dev
NAME                   READY   STATUS    RESTARTS   AGE
pod-liveness-httpget   1/1     Running   2          31s

至此,已经使用livenessProbe演示了三种探测方式,但查看liveProbe的子属性,会发现除了这三种方式,还有一些其他的配置,这里一并解释一下:

[root@k8s-master01 ~]# kubectl explain pod.spec.containers.livenessProbe
KIND:     Pod
VERSION:  v1
...
FIELDS:
    exec <Object>
    tcpSocket <Object>
    httpGet <Object>
    initialDelaySeconds <integer> 	#容器启动后等待多少秒执行第一次探测
    timeoutSeconds  <integer>  		#探测超时时间。默认1秒,最小1秒
    periodSeconds <integer>			#执行探测的频率。默认10秒,最小1秒
    failureThreshold <integer>		#连续探测失败多少次才被认定为失败。默认是3,最小值是1
    successThreshold <integer>		#连续探测成功多少次才被认定为成功。默认是1

5.3.5 重启策略

在上一节中,一旦容器探测出现了问题,kubernetes就会对容器所在的pod进行重启,其实这是由pod的重启策略决定的,pod的重启策略有3种,分别如下:

  • Always:容器失效时,自动重启该容器,这也是默认值。
  • OnFailure:容器终止运行且退出码不为0时重启。
  • Never:不论状态为何,都不重启该容器

重启策略适用于pod对象中的所有容器,首次需要重启的容器,将在其需要时立即进行重启,随后再次需要重启的操作将由kubelet延迟一段时间后进行,且反复的重启操作的延迟时长为:10s、20s、40s、80s、160s和300s,300s是最大延迟时长。

创建pod-restartpolicy.yml

apiVersion: v1
kind: Pod
metadata:
  name: pod-restartpolicy
  namespace: dev
spec:
  containers:
  - name: nginx:1.17.1
    ports:
    - name: nginx-port
      containerPort: 80
    livenessProbe:
      httpGet:
        scheme: HTTP
        port: 80
        path: /hello
  restartPolicy: Never  #设置重启策略为Never

运行pod测试

# 创建pod
[root@k8s-master01 ~]# kubectl create -f pod-restartPolicy.yml
pod/pod-restartpolicy created

# 查看pod详情,发现nginx容器失败
[root@k8s-master01 ~]# kubectl describe pod pod-restartpolicy -n dev
...
Events:
  Type     Reason     Age                From                 Message
  ----     ------     ----               ----                 -------
  Normal   Scheduled  76s                default-scheduler    Successfully assigned dev/pod-restartpolicy to k8s-node01
  Normal   Pulled     75s                kubelet, k8s-node01  Container image "nginx:1.17.1" already present on machine
  Normal   Created    75s                kubelet, k8s-node01  Created container nginx-port
  Normal   Started    75s                kubelet, k8s-node01  Started container nginx-port
  Warning  Unhealthy  46s (x3 over 66s)  kubelet, k8s-node01  Liveness probe failed: HTTP probe failed with statuscode: 404
  Normal   Killing    46s                kubelet, k8s-node01  Stopping container nginx-port


#多等一会,再观察pod的重启次数,发现一直是0,并未重启,且STATUS变为了Completed
[root@k8s-master01 ~]# kubectl get pod pod-restartpolicy -n dev
NAME                READY   STATUS      RESTARTS   AGE
pod-restartpolicy   0/1     Completed   0          2m5s

5.4 Pod调度

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

  • 自动调度:运行在哪个节点上完全由Scheduler经过一系列的算法计算得出;
  • 定向调度:NodeName、NodeSelector;
  • 亲和性调度:NodeAffinity、PodAffinity、PodAntiAffinity
  • 污点(容忍)调度:Taints、Toleration

5.4.1 定向调度

定向调度,指的是利用在pod上声明nodeName或nodeSelector,以此将pod调度到期望的node节点上。注意,这里的调度是强制的,这就意味着即使要调度的目标Node不存在,也会向上面进行调度,只不过pod运行失败而已。

NodeName

NodeName用于强制约束将Pod调度到指定的Name的Node节点上。这种方式,其实是直接跳过Scheduler的调度逻辑,直接将Pod调度到指定名称的节点。

实验一下:创建一个Pod-nodename.yml 文件,内容如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodename
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  nodeName: k8s-node01   #指定调度到k8s-node01节点上
# 创建Pod
[root@k8s-master01 ~]# kubectl create -f pod-nodename.yml
pod/pod-nodename created

# 查看pod,发现确实调度到了k8s-node01节点上
[root@k8s-master01 ~]# kubectl get pod pod-nodename -n dev -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP            NODE         NOMINATED NODE   READINESS GATES
pod-nodename   1/1     Running   0          18s   10.244.1.22   k8s-node01   <none>           <none>

# 如果pod-nodename.yml文件中指定将pod调度到一个不存在的Node节点上,如下:
[root@k8s-master01 ~]# kubectl get pod pod-nodename -n dev -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP            NODE         NOMINATED NODE   READINESS GATES
pod-nodename    0/1     Pending     0       43s   <none>        k8s-node1    <none>           <none>

NodeSelector

NodeSelector用于将pod调度到添加了指定标签的node节点上。它是通过kubernetes的label-selector机制实现的,也就是说,在pod创建之前,会由scheduler使用MatchNodeSelector调度策略进行label匹配,找出目标node,然后将pod调度到目标节点,该匹配规则是强制约束。

接下来实验一下:

(1) 首先分别为node节点添加标签

[root@k8s-master01 ~]# kubectl label node k8s-node01 nodeenv=pro
node/k8s-node01 labeled
[root@k8s-master01 ~]# kubectl label node k8s-node02 nodeenv=test
node/k8s-node02 labeled

(2) 创建一个pod-nodeselector.yaml文件,并使用它创建Pod

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeselector
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  nodeSelector:
    nodeenv: pro   #指定调度到具有nodeenv=pro标签的节点上
# 创建pod
[root@k8s-master01 ~]# kubectl create -f pod-nodeselector.yml
pod/pod-nodeselector created

# 查看pod,确实调度到了k8s-node01节点上
[root@k8s-master01 ~]# kubectl get pod pod-nodeselector -n dev -o wide
NAME               READY   STATUS    RESTARTS   AGE   IP            NODE         NOMINATED NODE   READINESS GATES
pod-nodeselector   1/1     Running   0          43s   10.244.1.23   k8s-node01   <none>           <none>

# 删除pod,修改nodeSelector的值为nodeenv: xxxx(不存在打有此标签的节点)
# 再次查看,发现pod无法正常运行,NODE的值为none
[root@k8s-master01 ~]# kubectl get pod pod-nodeselector -n dev -o wide
NAME               READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES
pod-nodeselector   0/1     Pending   0          14s   <none>   <none>   <none>           <none>

# 查看详情,发现node selector匹配失败的提示
[root@k8s-master01 ~]# kubectl describe pods pod-nodeselector -n dev
...

5.4.2 亲和性调度

上一节,介绍了两种定向调度的方式,使用起来非常方便,但也有一定的问题,那就是如果满足条件的Node,那么pod将不会被执行,即使在集群中海油可用Node列表也不行,这就限制了它的使用场景。

基于上面的问题,kubernetes还提供了一种亲和性调度(Affinity)。它在NodeSelector的基础之上进行了扩展,可以通过配置的形式,实现优先选择满足条件的Node进行调度,如果没有,也可以调度到不满足条件的节点上,使调度更加灵活。

Affinity主要分为三类:

  • nodeAffinity(node亲和性):以node为目标,解决pod可以调度到哪些node的问题;
  • podAffinity(pod亲和性):以pod为目标,解决pod可以和哪些已存在的pod部署在同一个拓扑域中的问题;
  • podAntiAffinity(pod反亲和性):以pod为目标,解决pod不能和哪些已存在pod部署在同一个拓扑域中的问题。

关于亲和性(反亲和性)使用场景的说明:
亲和性:如果两个应用频繁交互,那就有必要利用亲和性让两个应用尽可能的靠近,这样可以减少因网络通信带来的性能损耗。
 
反亲和性:当应用采用多副本部署时,有必要采用反亲和性让各个应用实例打散分布在各个node上,这样可以提高服务的高可用性。


首先来看一下nodeAffinity的可配置项:
kubectl explain pod.spec.affinity.nodeAffinity

...
  nodeAffinity
    requiredDuringSchedulingIgnoredDuringExecution  #Node节点必须满足指定的所有规则才可以,相当于硬限制
      nodeSelectorTerms  #节点选择列表
        matchFields		 #按节点字段列出的节点选择器要求列表
        matchExpressions #按节点标签列出的节点选择器要求列表(推荐)
          key			 #键
          value			 #值
          operator		 #关系符,支持Exists、DoesNotExist、In、NotIn、Gt、Lt
    preferredDuringSchedulingIgnoredDuringExecution #优先调度到满足指定规则的Node,相当于软限制(倾向)
      preference		 #一个节点选择器项,与相应的权重相关联
        matchFields		 #按节点字段列出的节点选择器要求列表
        matchExpressions #按节点标签列出的节点选择器要求列表(推荐)
          key			 #键
          value			 #值
          operator		 #关系符,支持In、NotIn、Exists、DoesNotExist、Gt、Lt
      weight			 #倾向权重,范围:1-100     
# 关系符的使用说明:

- matchExpressions:
  - key: nodeenv			#匹配存在标签的key为nodeenv的节点
    operator: Exists
  - key: nodeenv			#匹配标签的key为nodeenv,且value是"xxx"或"yyy"的节点
    operator: In
    values: ["xxx","yyy"]
  - key: nodeenv			#匹配标签的key为nodeenv,且value大于"xxx"的节点
    operator: Gt
    values: "xxx"

接下来首先演示一下 requiredDuringSchedulingIgnoredDuringExecution
创建 pod-nodeaffinity-required.yml,内容为:

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeaffinity-required
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:  #亲和性设置
    nodeAffinity:  #设置node亲和性
      requiredDuringSchedulingIgnoredDuringExecution:  #硬限制
        nodeSelectorTerms:
        - matchExpressions: #匹配env的值在["xxx","yyy"]中的标签
          - key: nodeenv
            operator: In
            values: ["xxx", "yyy"]
# 创建pod
[root@k8s-master01 ~]# kubectl create -f pod-nodeaffinity-required.yml
pod/pod-nodeaffinity-required created

# 查看pod状态(运行失败)
[root@k8s-master01 ~]# kubectl get pod pod-nodeaffinity-required -n dev -o wide
NAME                        READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES
pod-nodeaffinity-required   0/1     Pending   0          34s   <none>   <none>   <none>           <none>

# 查看pod的详情
# 发现调度失败,提示node选择失败
[root@k8s-master01 ~]# kubectl describe pod pod-nodeaffinity-required -n dev
...
Events:
  Type     Reason            Age                 From               Message
  ----     ------            ----                ----               -------
  Warning  FailedScheduling  29s (x2 over 117s)  default-scheduler  0/3 nodes are available: 3 node(s) didn't match node selector.

# 接下来,停止pod
[root@k8s-master01 ~]# kubectl delete -f pod-nodeaffinity-required.yml
pod "pod-nodeaffinity-required" deleted

# 修改文件,将values: ["xxx","yyy"] --> ["pro","yyy"]

# 再次启动
[root@k8s-master01 ~]# kubectl create -f pod-nodeaffinity-required.yml
pod/pod-nodeaffinity-required created

# 此时查看,调度成功,,已将pod调度到了k8s-node01上。
[root@k8s-master01 ~]# kubectl get pod pod-nodeaffinity-required -n dev -o wide
NAME                        READY   STATUS    RESTARTS   AGE   IP            NODE         NOMINATED NODE   READINESS GATES
pod-nodeaffinity-required   1/1     Running   0          52s   10.244.1.26   k8s-node01   <none>           <none>

接下来再演示一下 preferredDuringSchedulingIgnoredDuringExecution
创建 pod-nodeaffinity-preferred.yml

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeaffinity-preferred
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:  #亲和性设置
    nodeAffinity:  #设置node亲和性
      preferredDuringSchedulingIgnoredDuringExecution:  #软限制
      - weight: 1
        preference:
          matchExpressions:  #匹配env的值在["xxx","yyy"]中的标签(当前环境没有)
          - key: nodeenv
            operator: In
            values: ["xxx", "yyy"]
# 创建pod
[root@k8s-master01 ~]# kubectl create -f pod-nodeaffinity-preferred.yml
pod/pod-nodeaffinity-preferred created

# 查看pod状态(运行成功)
[root@k8s-master01 ~]# kubectl get pod pod-nodeaffinity-preferred -n dev -o wide
NAME                         READY   STATUS    RESTARTS   AGE   IP            NODE         NOMINATED NODE   READINESS GATES
pod-nodeaffinity-preferred   1/1     Running   0          6s    10.244.1.27   k8s-node01   <none>           <none>

NodeAffinity规则设置的注意事项:

(1) 如果同时定义了nodeSelector和nodeAffinity,那么必须两个条件都得到满足,pod才能运行在指定的node上;
(2) 如果nodeAffinity指定了多个nodeSelectorTerms,那么只需要其中一个能够匹配成功即可;
(3) 如果一个nodeSelectorTerms中又多个matchExpressions,则一个节点必须满足所有的才能匹配成功;
(4) 如果一个pod所在的node在pod运行期间其标签发生了改变,不再符合该pod的节点亲和性需求,则系统将忽略此变化。


PodAffinity

PodAffinity主要实现以运行的pod为参照,实现让新创建的Pod跟参照pod在一个区域的功能。

首先来看一下PodAffinity的可配置项:
kubectl explain pod.spec.affinity.podAffinity

...
  requiredDuringSchedulingIgnoredDuringExecution   #硬限制
    namespaces		#指定参照pod的namespace
    topologyKey		#指定调度作用域
    labelSelector	#标签选择器
      matchExpressions  #按节点标签列出的节点选择器要求列表(推荐)
        key			#键
        value 		#值
        operator	#关系符,支持In、NotIn、Exists、DoesNotExist.
      matchLabels	#指多个matchExpressions映射的内容
  preferredDuringSchedulingIgnoredDuringExecution	#软限制
    podAffinityTerm	#选项
      namespaces
      toppologyKey
      labelSelector
        matchExpressions
          key		#键
          values	#值
          operator
          matchLabels
      weight	#倾向权重,在范围1-100

topologyKey用于指定调度时作用域,例如:

  • 如果指定为kubernetes.io/hostname,那就是以node节点为区分范围
  • 如果指定为 beta.kubernetes.io/os,则以node节点的操作系统类型来区分.

接下来,演示一下 requiredDuringSchedulingIgnoredDuringExecution
(1) 首先创建一个参照pod,pod-podaffinity-target.yml:

apiVersion: v1
kind: Pod
metadata:
  name: pod-podaffinity-target
  namespace: dev
  labels:
    podenv: pro		#设置标签
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  nodeName: k8s-node01		#将目标pod明确指定到k8s-node01节点上
# 启动目标pod(参照pod)
[root@k8s-master01 ~]# kubectl create -f pod-podaffinity-target.yml
pod/pod-podaffinity-target created

# 查看pod状况
[root@k8s-master01 ~]# kubectl get pod pod-podaffinity-target -n dev -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP            NODE         NOMINATED NODE   READINESS GATES
pod-podaffinity-target   1/1     Running   0          81s   10.244.1.28   k8s-node01   <none>           <none>

(2) 创建 pod-podaffinity-required.yml,内容如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-podaffinity-required
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:		#亲和性设置
    podAffinity:	#设置pod亲和性
      requiredDuringSchedulingIgnoredDuringExecution:	#硬限制
      - labelSelector:
          matchExpressions:	  #匹配env的值在["xxx","yyy"]中的标签
          - key: podenv
            operator: In
            values: ["xxx", "yyy"]
        topologyKey:  kubernetes.io/hostname

上面配置表达的意思是:新Pod必须要与拥有标签podenv=xxx或podenv=yyy的pod在同一节点上,显然现在没有这样的pod,接下来,运行测试一下。

# 启动pod
[root@k8s-master01 ~]# kubectl create -f pod-podaffinity-required.yml
pod/pod-podaffinity-required created

# 查看pod状态,发现未运行
[root@k8s-master01 ~]# kubectl get pod pod-podaffinity-required -n dev
NAME                       READY   STATUS    RESTARTS   AGE
pod-podaffinity-required   0/1     Pending   0          2m39s

# 查看详细信息
[root@k8s-master01 ~]# kubectl describe pod -n dev pod-podaffinity-required
...
Events:
  Type     Reason            Age                 From               Message
  ----     ------            ----                ----               -------
  Warning  FailedScheduling  29s (x4 over 3m7s)  default-scheduler  0/3 nodes are available: 1 node(s) had taints that the pod didn't tolerate, 2 node(s) didn't match pod affinity rules.

# 接下来修改,values:["xxx", "yyy"] ----> values:["pro", "yyy"]
# 意思是:新Pod必须要与拥有标签podenv=pro或podenv=yyy的pod在同一node上

# 然后重新创建pod,查看结果
[root@k8s-master01 ~]# kubectl delete -f pod-podaffinity-required.yml
pod "pod-podaffinity-required" deleted
[root@k8s-master01 ~]# kubectl create -f pod-podaffinity-required.yml
pod/pod-podaffinity-required created
[root@k8s-master01 ~]# kubectl get pod -n dev pod-podaffinity-required  -o wide
NAME                       READY   STATUS    RESTARTS   AGE   IP            NODE         NOMINATED NODE   READINESS GATES
pod-podaffinity-required   1/1     Running   0          20s   10.244.1.29   k8s-node01   <none>           <none>

关于PodAffinitypreferredDuringSchedulingIgnoredDuringExecution,这里不再演示。


PodAntiAffinity

PodAntiAffinity 主要实现以运行的Pod为参照,让新创建的Pod跟参照pod不再一个区域中的功能。
它的配置方式和选项跟PodAffinity是一样的,这里不再详细解释,直接做一个测试案例。

(1) 继续使用上一个案例中的目标pod

[root@k8s-master01 ~]# kubectl get pod -n dev -o wide --show-labels
NAME                       READY   STATUS    RESTARTS   AGE    IP            NODE         NOMINATED NODE   READINESS GATES   LABELS
pod-podaffinity-required   1/1     Running   0          6m1s   10.244.1.30   k8s-node01   <none>           <none>            <none>
pod-podaffinity-target     1/1     Running   0          35m    10.244.1.28   k8s-node01   <none>           <none>            podenv=pro

(2) 创建pod-podantiaffinity-required.yml,内容如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-podantiaffinity-required
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:		#亲和性设置
    podAntiAffinity:	#设置pod亲和性
      requiredDuringSchedulingIgnoredDuringExecution:   #硬限制
      - labelSelector:
          matchExpressions:  #匹配podenv的值在["pro"]中的标签
          - key: podenv
            operator: In
            values: ["pro"]
        topologyKey: kubernetes.io/hostname

上面配置表达的意思是:新Pod必须要与拥有标签podenv=pro的pod不再同一Node上。
运行测试一下。

# 创建pod
[root@k8s-master01 ~]# kubectl create -f pod-podantiaffinity-required.yml
pod/pod-podantiaffinity-required created

#查看pod
# 发现调度到了k8s-node02节点上
[root@k8s-master01 ~]# kubectl get pod -n dev -o wide --show-labels
NAME                           READY   STATUS    RESTARTS   AGE   IP            NODE         NOMINATED NODE   READINESS GATES   LABELS
pod-podaffinity-required       1/1     Running   0          68m   10.244.1.30   k8s-node01   <none>           <none>            <none>
pod-podaffinity-target         1/1     Running   0          98m   10.244.1.28   k8s-node01   <none>           <none>            podenv=pro
pod-podantiaffinity-required   1/1     Running   0          5s    10.244.2.36   k8s-node02   <none>           <none>            <none>

5.4.3 污点和容忍

污点(Taints)

前面的调度方式都是站在Pod的角度上,通过在Pod上添加属性,来确定pod是否要调度到指定的node上,其实我们也可以站在node的角度上,通过在node上添加污点属性,来决定是否允许pod调度过来。

node被设置上污点之后就和pod之间存在了一种相斥的关系,进而拒绝pod调度进来,甚至可以将已存在的pod驱逐出去。

污点的格式:key=value:effect,key和value是污点的标签,effect描述污点的作用,支持如下三个选项:

  • PreferNoSchedule: kubernetes将尽量避免把pod调度到具有该污点的node上,除非没有其他节点可调度;
  • NoSchedule:kubernetes将不会把pod调度到具有该污点的node上,但不会影响当前node上已存在的pod;
  • NoExecute:kubernetes将不会把pod调度到具有该污点的node上,同时也会将node上已存在的pod驱离。
    在这里插入图片描述
    使用kubectl设置和去除污点的命令示例如下:
# 设置污点
kubectl taint nodes node1 key=value:effect

# 去除污点
kubectl taint nodes node1 key:effect-

# 去除所有污点
kubectl taint nodes node1 key-

接下来,演示下污点的效果:
(1) 准备节点node1(为了演示效果更加明显,暂时停止node2节点(把虚拟机挂起即可))
(2) 为node1节点设置一个污点:tag=mole:PreferNoSchedule,然后创建pod1(pod1正常)
(3) 修改为node1节点设置一个污点:tag=mole:NoSchedule,然后创建pod2(pod1正常,pod2失败)
(4) 修改为node1节点设置一个污点:tag=mole:NoExecute,然后创建pod3(3个pod都失败)

# 为node1设置污点(PreferNoSchedule)
[root@k8s-master01 ~]# kubectl taint node k8s-node01 tag=mole:PreferNoSchedule
node/k8s-node01 tainted

# 创建pod1,pod1成功运行并被调度到node1节点上
[root@k8s-master01 ~]# kubectl run taint1 --image=nginx:1.17.1 -n dev
deployment.apps/taint1 created
[root@k8s-master01 ~]# kubectl get pod -n dev -o wide
NAME                           READY   STATUS        RESTARTS   AGE   IP            NODE         NOMINATED NODE   READINESS GATES
taint1-766c47bf55-xgmfv        1/1     Running       0          43s   10.244.1.36   k8s-node01   <none>           <none>

# 为node1设置污点(取消PreferNoSchedule, 设置NoSchedule)
[root@k8s-master01 ~]# kubectl taint node k8s-node01 tag:PreferNoSchedule-
node/k8s-node01 untainted
[root@k8s-master01 ~]# kubectl taint node k8s-node01 tag=mole:NoSchedule
node/k8s-node01 tainted

# 创建pod2,pod2运行失败,无法被调度,而pod1依旧正常运行
[root@k8s-master01 ~]# kubectl run taint2 --image=nginx:1.17.1 -n dev
deployment.apps/taint2 created
[root@k8s-master01 ~]# kubectl get pod  -n dev -o wide
NAME                           READY   STATUS        RESTARTS   AGE     IP            NODE         NOMINATED NODE   READINESS GATES
taint1-766c47bf55-xgmfv        1/1     Running       0          5m35s   10.244.1.36   k8s-node01   <none>           <none>
taint2-84946958cf-77jcm        0/1     Pending       0          110s    <none>        <none>       <none>           <none>

# 为node1设置污点(取消NoSchedule,设置NoExecute)
[root@k8s-master01 ~]# kubectl taint node k8s-node01 tag:NoSchedule-
node/k8s-node01 untainted
[root@k8s-master01 ~]# kubectl taint node k8s-node01 tag=mole:NoExecute
node/k8s-node01 tainted

# 创建pod3,pod3运行失败,无法被调度,且此时pod1、pod2也运行失败
[root@k8s-master01 ~]# kubectl run taint3 --image=nginx:1.17.1 -n dev
deployment.apps/taint3 created
[root@k8s-master01 ~]# kubectl get pod  -n dev -o wide
NAME                           READY   STATUS        RESTARTS   AGE   IP            NODE         NOMINATED NODE   READINESS GATES
taint1-766c47bf55-v8kjq        0/1     Pending       0          82s   <none>        <none>       <none>           <none>
taint2-84946958cf-6nxcw        0/1     Pending       0          82s   <none>        <none>       <none>           <none>
taint3-57d45f9d4c-x82rm        0/1     Pending       0          10s   <none>        <none>       <none>           <none>

使用kubeadm搭建的集群,默认会给master节点添加一个污点标记,所以pod不会调度到master节点上。
在这里插入图片描述


容忍(Toleration)

上面介绍了污点的作用,我们可以在node上添加污点用于拒绝pod调度上来,但如果就是想将一个pod调度到一个有污点的node上去,这时应该怎么做呢?这就要使用到容忍
在这里插入图片描述

污点就是拒绝,容忍就是忽略,Node通过污点拒绝pod调度上去,pod通过容忍忽略拒绝。

下面通过一个案例看一下效果:
(1) 上一小节,已经在node1节点上打上了NoExecute的污点,此时pod是调度不上去的;
(2) 本小节,可以通过给pod添加容忍,然后将其调度上去。

创建pod-toleration.yml,内容如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-toleration
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  tolerations:	#添加容忍
  - key: "tag"	#要容忍的污点的key
    operator: "Equal"	#操作符
    value: "mole"		#容忍的污点的value
    effect: "NoExecute"	#添加容忍的规则,这里必须和标记的污点规则相同
# 添加容忍之后,pod-toleration成功被调度到node1节点
[root@k8s-master01 ~]# kubectl create -f pod-toleration.yml
pod/pod-toleration created
[root@k8s-master01 ~]# kubectl get pod pod-toleration -n dev -o wide
NAME             READY   STATUS    RESTARTS   AGE   IP            NODE         NOMINATED NODE   READINESS GATES
pod-toleration   1/1     Running   0          9s    10.244.1.38   k8s-node01   <none>           <none>

下面看一下容忍的详细配置

[root@k8s-master01 ~]# kubectl explain pod.spec.tolerations
...
FIELDS:
    key			#对应着容忍的污点的键,空的话意味着匹配所有的键
    value		#对应着要容忍的污点的值
    operator	#key-value的运算符,支持Equal和Exists(默认)
    effect		#对应污点的effect,空意味着匹配所有影响
    tolerationSeconds	#容忍时间,当effect为NoExecute时生效,表示pod在Node上的停留时间

6、Pod控制器详解

6.1 Pod控制器介绍

在kubernetes中,按照pod的创建方式可以将其分为两类:

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

什么是Pod控制器?

Pod控制器是管理pod的中间层,使用了pod控制器之后,我们只需要告诉pod控制器,想要多少个什么样的pod就可以了,它就会创建出满足条件的pod并确保每一个pod处于用户期望的状态,如果pod在运行中出现故障,控制器会基于指定策略重启动或者重建pod。

在kubernetes中,有很多类型的pod控制器,每种都有自己的适合的场景,常见的有下面这些:

  • ReplicationController:比较原始的pod控制器,已经被废弃,由ReplicaSet替代;
  • ReplicaSet:保证指定数量的pod运行,并支持pod数量变更,镜像版本变更;
  • Deployment:通过控制ReplicaSet来控制pod,并支持滚动升级、版本回退;
  • Horizontal Pod Autoscaler:可以根据集群负载自动调整pod的数量,实现削峰填谷;
  • DaemonSet:在集群中的指定Node上都运行一个副本,一般用于守护进程类的任务;
  • Job:它创建出来的pod只要完成任务就立即退出,用于执行一次性任务;
  • CronJob:它创建的pod会周期性的执行,用于执行周期性任务;
  • StatefulSet:管理有状态的应用。

6.2 ReplicaSet(RS)

ReplicaSet的主要作用是保证一定数量的pod能够正常运行,它会持续监听这些pod的运行状态,一旦Pod发生故障,就会重启或重建。同时它还支持对pod数量的扩缩容版本镜像的升级
在这里插入图片描述
ReplicaSet的资源清单文件:

apiVersion: apps/v1   #版本号
kind: ReplicaSet	  #类型
metadata:			  #元数据
  name:				  #rs名称
  namespace:		  #所属命名空间
  labels:			  #标签
    controller: rs
spec:				  #详情描述
  replicas: 3		  #副本数量
  selector:			  #选择器,通过它指定该控制器管理哪些pod
    matchLabels:	  #Labels匹配规则
      app: nginx-pod
    matchExpressions: #Expressions匹配规则
      - {key: app, operator: In, values: [nginx-pod]}
  template:			  #模板,当副本数量不足时,会根据下面的模板创建pod副本
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
        ports:
        - containerPort: 80

在这里面,需要新了解的配置项是spec下面的几个选项:

  • replicas: 指定副本数量,其实就是当前rs创建出来的pod的数量,默认为1;
  • selector: 选择器。它的作用是建立pod控制器和pod之间的关联关系,采用的Label Selector机制;
  • template: 模板。就是当前控制器创建pod所使用的模板,里面其实就是前一章学过的pod的定义。

创建ReplicaSet

创建pc-replicaset.yml,内容如下:

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: pc-replicaset
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
# 创建rs
[root@k8s-master01 ~]# kubectl create -f pc-replicaset.yml
replicaset.apps/pc-replicaset created

# 查看rs
[root@k8s-master01 ~]# kubectl get rs  pc-replicaset -n dev -o wide
NAME            DESIRED   CURRENT   READY   AGE   CONTAINERS   IMAGES         SELECTOR
pc-replicaset   3         3         3       46s   nginx        nginx:1.17.1   app=nginx-pod

# 查看当前控制器创建出来的pod
# 这里发现控制器创建出来的pod的名称是在控制器名称后面拼接了-xxxxx随机码
[root@k8s-master01 ~]# kubectl get pod -n dev
NAME                  READY   STATUS    RESTARTS   AGE
pc-replicaset-9xc4p   1/1     Running   0          8s
pc-replicaset-kz97b   1/1     Running   0          8s
pc-replicaset-qb7l7   1/1     Running   0          8s

扩缩容

# 编辑rs的副本数量,修改spec:replicas: 6即可
[root@k8s-master01 ~]# kubectl edit replicasets.apps pc-replicaset -n dev
replicaset.apps/pc-replicaset edited

# 查看pod
[root@k8s-master01 ~]# kubectl get pod -n dev
NAME                  READY   STATUS    RESTARTS   AGE
pc-replicaset-6n8qc   1/1     Running   0          20s
pc-replicaset-9xc4p   1/1     Running   0          3m44s
pc-replicaset-ff4x7   1/1     Running   0          20s
pc-replicaset-kz97b   1/1     Running   0          3m44s
pc-replicaset-mgf6s   1/1     Running   0          20s
pc-replicaset-qb7l7   1/1     Running   0          3m44s

# 当然也可以直接使用命令实现
# 使用scale命令实现扩缩容,后面--replicas=n 直接指定目标数量即可
[root@k8s-master01 ~]# kubectl scale rs pc-replicaset --replicas=2  -n dev
replicaset.apps/pc-replicaset scaled

# 命令运行完毕,立即查看,发现已有4个开始准备退出了
[root@k8s-master01 ~]# kubectl get pod -n dev
NAME                  READY   STATUS        RESTARTS   AGE
pc-replicaset-9xc4p   1/1     Running       0          6m5s
pc-replicaset-gb79z   0/1     Terminating   0          11s
pc-replicaset-hkjg2   0/1     Terminating   0          11s
pc-replicaset-k8jlb   0/1     Terminating   0          11s
pc-replicaset-lcrm5   0/1     Terminating   0          11s
pc-replicaset-qb7l7   1/1     Running       0          6m5s

# 稍等片刻,只剩2个
[root@k8s-master01 ~]# kubectl get pod -n dev
NAME                  READY   STATUS    RESTARTS   AGE
pc-replicaset-9xc4p   1/1     Running   0          7m21s
pc-replicaset-qb7l7   1/1     Running   0          7m21s

镜像升级

# 编辑rs的容器镜像 - image: nginx:1.17.2
[root@k8s-master01 ~]# kubectl edit rs pc-replicaset -n dev
replicaset.apps/pc-replicaset edited

# 再次查看,发现镜像版本已经变更了
[root@k8s-master01 ~]# kubectl get rs -n dev -o wide
NAME            DESIRED   CURRENT   READY   AGE   CONTAINERS   IMAGES         SELECTOR
pc-replicaset   2         2         2       9m    nginx        nginx:1.17.2   app=nginx-pod

# 同样的道理,也可以使用命令完成这个工作
# kubectl set image rs <rs名称> 容器=镜像版本 -n <namespace>
[root@k8s-master01 ~]# kubectl set image rs pc-replicaset nginx=nginx:1.17.1 -n dev
replicaset.apps/pc-replicaset image updated

# 再次查看,发现镜像版本已变更
[root@k8s-master01 ~]# kubectl get rs -n dev -o wide
NAME            DESIRED   CURRENT   READY   AGE   CONTAINERS   IMAGES         SELECTOR
pc-replicaset   2         2         2       11m   nginx        nginx:1.17.1   app=nginx-pod

删除ReplicaSet

# 使用kubectl delete命令会删除此RS以及它管理的Pod
# 在kubernetes删除RS前,会将RS的replicasclear调整为0,等待所有的pod被删除后,在执行rs对象的删除
[root@k8s-master01 ~]# kubectl delete rs pc-replicaset -n dev
repicaset.apps "pc-replicaset" deleted

# 如果希望仅仅删除rs对象(保留pod),可以使用kubectl delete命令时添加--cascade=false选项(不推荐)。
[root@k8s-master01 ~]# kubectl delete rs pc-replicaset -n dev --cascade=false

# 也可以使用yaml直接删除(推荐)
[root@k8s-master01 ~]# kubectl delete -f pc-replicaset.yml
replicaset.apps "pc-replicaset" deleted

6.3 Deployment(Deploy)

为了更好的解决服务编排的问题,kubernetes在V1.2版本开始,引入了Deployment控制器。值得一提的是,这种控制器并不直接管理pod,而是通过管理ReplicaSet来间接管理Pod,即:Deployment管理ReplicaSet,ReplicaSet管理Pod。所以Deployment比ReplicaSet功能更加强大。
在这里插入图片描述
Deployment主要功能有下面几个:

  • 支持ReplicaSet的所有功能;
  • 支持发布的停止、继续;
  • 支持版本滚动升级和版本回退。

Deployment的资源清单文件:
在这里插入图片描述
在这里插入图片描述


创建deployment

创建pc-deployment.yml,内容如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pc-deployment
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
# 创建deployment
# --record=true    记录每次的版本变化
[root@k8s-master01 ~]#
[root@k8s-master01 ~]# kubectl create -f pc-deployment.yml --record=true
deployment.apps/pc-deployment created

# 查看deployment
# UP-TO-DATE 最新版本的pod的数量
# AVAILABLE 当前可用的pod的数量
[root@k8s-master01 ~]# kubectl get deployments.apps pc-deployment -n dev
NAME            READY   UP-TO-DATE   AVAILABLE   AGE
pc-deployment   3/3     3            3           48m

# 查看rs
# 发现rs的名称是在原来deployment的名字后面添加了一个10位数的随机串
[root@k8s-master01 ~]# kubectl get rs -n dev
NAME                       DESIRED   CURRENT   READY   AGE
pc-deployment-5d89bdfbf9   3         3         3       49m

# 查看pod
# 发现pod的名称是在原来rs的名字后面添加一个5位数的随机串
[root@k8s-master01 ~]# kubectl get pod -n dev
NAME                             READY   STATUS    RESTARTS   AGE
pc-deployment-5d89bdfbf9-5n2vs   1/1     Running   0          49m
pc-deployment-5d89bdfbf9-5pvwt   1/1     Running   0          49m
pc-deployment-5d89bdfbf9-7gwk7   1/1     Running   0          49m

扩缩容

# 变量副本数量为5个
[root@k8s-master01 ~]# kubectl scale deploy pc-deployment  --replicas=5 -n dev
deployment.apps/pc-deployment scaled

# 查看deployment
[root@k8s-master01 ~]# kubectl get deployments.apps -n dev
NAME            READY   UP-TO-DATE   AVAILABLE   AGE
pc-deployment   5/5     5            5           52m

# 查看pod
[root@k8s-master01 ~]# kubectl get pod -n dev
NAME                             READY   STATUS    RESTARTS   AGE
pc-deployment-5d89bdfbf9-5n2vs   1/1     Running   0          52m
pc-deployment-5d89bdfbf9-5pvwt   1/1     Running   0          52m
pc-deployment-5d89bdfbf9-7gwk7   1/1     Running   0          52m
pc-deployment-5d89bdfbf9-wjbt6   1/1     Running   0          11s
pc-deployment-5d89bdfbf9-x6b88   1/1     Running   0          11s

# 编辑deployment的副本数量,修改spec:replicas: 4即可
[root@k8s-master01 ~]# kubectl edit deployments.apps pc-deployment -n dev
deployment.apps/pc-deployment edited

# 查看deployment和pod
[root@k8s-master01 ~]# kubectl get deployments.apps -n dev
NAME            READY   UP-TO-DATE   AVAILABLE   AGE
pc-deployment   4/4     4            4           54m

[root@k8s-master01 ~]# kubectl get pod -n dev
NAME                             READY   STATUS    RESTARTS   AGE
pc-deployment-5d89bdfbf9-5n2vs   1/1     Running   0          54m
pc-deployment-5d89bdfbf9-5pvwt   1/1     Running   0          54m
pc-deployment-5d89bdfbf9-7gwk7   1/1     Running   0          54m
pc-deployment-5d89bdfbf9-x6b88   1/1     Running   0          2m10s

镜像更新

Deployment支持两种镜像更新的策略:重建更新滚动更新(默认),可以通过strategy选项进行配置。

...
  strategy:    #指定新的pod替换旧的pod的策略,支持两个属性:
    type:       #指定策略类型,支持两种策略
      Recreate:   #在创建出新的pod之前会先杀掉所有已存在的pod
      RollingUpdate:   #滚动更新,就是杀死一部分,就启动一部分,在更新过程中,存在两个版本的pod  
    rollingUpdate:   #当type未RollingUpdate时生效,用于为RollingUpdate设置参数,支持两个属性:
      maxUnavailable:  #用来指定在升级过程中不可用pod的最大数量,默认为25%
      maxSurge:  #用来指定在升级过程中可以超过期望的pod的最大数量,默认为25%
..  

重建更新

(1) 编辑pc-deployment.yml,在spec节点下添加更新策略:

spec:
  strategy:   #策略
    type: Recreate   #重建更新策略

(2) 创建deploy进行验证

# 添加策略后,使用apply命令更新配置
[root@k8s-master01 ~]# kubectl apply -f pc-deployment.yml
Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply
deployment.apps/pc-deployment configured

# 变更镜像
[root@k8s-master01 ~]# kubectl set image deployment pc-deployment nginx=nginx:1.17.2  -n dev
deployment.apps/pc-deployment image updated

# 观察升级过程
[root@k8s-master01 ~]# kubectl get pod -n dev -w
NAME                             READY   STATUS    RESTARTS   AGE
pc-deployment-5d89bdfbf9-5n2vs   1/1     Running   0          66m
pc-deployment-5d89bdfbf9-5pvwt   1/1     Running   0          66m
pc-deployment-5d89bdfbf9-7gwk7   1/1     Running   0          66m

pc-deployment-5d89bdfbf9-5pvwt   1/1     Terminating   0          70m
pc-deployment-5d89bdfbf9-5n2vs   1/1     Terminating   0          70m
pc-deployment-5d89bdfbf9-7gwk7   1/1     Terminating   0          70m
pc-deployment-5d89bdfbf9-5pvwt   0/1     Terminating   0          70m
pc-deployment-5d89bdfbf9-5n2vs   0/1     Terminating   0          70m
pc-deployment-5d89bdfbf9-7gwk7   0/1     Terminating   0          70m

pc-deployment-675d469f8b-sxgtj   0/1     Pending       0          0s
pc-deployment-675d469f8b-6cjnd   0/1     Pending       0          0s
pc-deployment-675d469f8b-tdzdb   0/1     Pending       0          0s

pc-deployment-675d469f8b-sxgtj   0/1     ContainerCreating   0          1s
pc-deployment-675d469f8b-tdzdb   0/1     ContainerCreating   0          1s
pc-deployment-675d469f8b-6cjnd   0/1     ContainerCreating   0          1s

pc-deployment-675d469f8b-tdzdb   1/1     Running             0          34s
pc-deployment-675d469f8b-sxgtj   1/1     Running             0          45s
pc-deployment-675d469f8b-6cjnd   1/1     Running             0          59s

滚动更新

(1) 编辑pc-deployment.yml,在spec节点下添加更新策略

spec:
  strategy:   #策略
    type: RollingUpdate:    #滚动更新策略
    rollingUpdate:
      maxUnavailable: 25%
      maxSurge: 25%

(2) 创建deploy进行验证

# 变更镜像
[root@k8s-master01 ~]# kubectl set image deployment pc-deployment -n dev nginx=nginx:1.17.3
deployment.apps/pc-deployment image updated

# 观察升级过程
[root@k8s-master01 ~]# kubectl get pod -n dev -w
NAME                             READY   STATUS    RESTARTS   AGE
pc-deployment-5d89bdfbf9-nddvr   1/1     Running   0          40m
pc-deployment-5d89bdfbf9-ppnb4   1/1     Running   0          39m
pc-deployment-5d89bdfbf9-tf9m9   1/1     Running   0          40m

pc-deployment-7865c58bdf-88b94   0/1     Pending   0          0s
pc-deployment-7865c58bdf-88b94   0/1     ContainerCreating   0          0s
pc-deployment-7865c58bdf-88b94   1/1     Running             0          41s

pc-deployment-5d89bdfbf9-ppnb4   1/1     Terminating         0          42m

pc-deployment-7865c58bdf-wvdmx   0/1     Pending             0          0s
pc-deployment-7865c58bdf-wvdmx   0/1     ContainerCreating   0          0s
pc-deployment-7865c58bdf-wvdmx   1/1     Running             0          2s

pc-deployment-5d89bdfbf9-tf9m9   1/1     Terminating         0          42m

pc-deployment-7865c58bdf-582xd   0/1     Pending             0          0s
pc-deployment-7865c58bdf-582xd   0/1     ContainerCreating   0          0s
pc-deployment-7865c58bdf-582xd   1/1     Running             0          2s

pc-deployment-5d89bdfbf9-nddvr   1/1     Terminating         0          42m

滚动更新的过程:
在这里插入图片描述
镜像更新中rs的变化:

# 查看rs,发现原来的rs依旧存在,只是pod数量变为了0,而后又新产生了一个rs,pod数量为3
# 其实这就是deployment能够进行版本回退的奥妙所在,后面会详细解释。
[root@k8s-master01 ~]# kubectl get rs -n dev -o wide
NAME                       DESIRED   CURRENT   READY   AGE     CONTAINERS   IMAGES         SELECTOR
pc-deployment-5d89bdfbf9   0         0         0       128m    nginx        nginx:1.17.1   app=nginx-pod,pod-template-hash=5d89bdfbf9
pc-deployment-675d469f8b   0         0         0       57m     nginx        nginx:1.17.2   app=nginx-pod,pod-template-hash=675d469f8b
pc-deployment-7865c58bdf   3         3         3       9m30s   nginx        nginx:1.17.3   app=nginx-pod,pod-template-hash=7865c58bdf

版本回退

deployment支持版本升级过程中的暂停、继续功能,以及版本回退等诸多功能,下面具体来看。

kubectl rollout:版本升级相关功能,支持下面的选项:

  • status:显示当前升级状态
  • history:显示升级历史记录
  • pause:暂停版本升级过程
  • resume:继续已经暂停的版本升级过程
  • restart:重启版本升级过程
  • undo:回滚到上一级版本(可以使用–to-revision回滚到指定版本)
# 查看升级历史记录
[root@k8s-master01 ~]# kubectl rollout history deployment -n dev pc-deployment
deployment.apps/pc-deployment
REVISION  CHANGE-CAUSE
2         kubectl create --filename=pc-deployment.yml --record=true
3         kubectl create --filename=pc-deployment.yml --record=true
4         kubectl create --filename=pc-deployment.yml --record=true
# 可以发现又三次版本记录,说明完成过两次升级。

# 版本回滚 
# 这里直接使用--to-revision=2回滚到了2版本
[root@k8s-master01 ~]# kubectl rollout undo deployment -n dev pc-deployment --to-revision=2
deployment.apps/pc-deployment rolled back
[root@k8s-master01 ~]# kubectl get rs -n dev -o wide
NAME                       DESIRED   CURRENT   READY   AGE    CONTAINERS   IMAGES         SELECTOR
pc-deployment-5d89bdfbf9   0         0         0       143m   nginx        nginx:1.17.1   app=nginx-pod,pod-template-hash=5d89bdfbf9
pc-deployment-675d469f8b   3         3         3       72m    nginx        nginx:1.17.2   app=nginx-pod,pod-template-hash=675d469f8b
pc-deployment-7865c58bdf   0         0         0       24m    nginx        nginx:1.17.3   app=nginx-pod,pod-template-hash=7865c58bdf

#回滚到3版本
[root@k8s-master01 ~]# kubectl rollout undo deployment -n dev pc-deployment --to-revision=3
deployment.apps/pc-deployment rolled back
[root@k8s-master01 ~]# kubectl get rs -n dev -o wide
NAME                       DESIRED   CURRENT   READY   AGE    CONTAINERS   IMAGES         SELECTOR
pc-deployment-5d89bdfbf9   3         3         3       144m   nginx        nginx:1.17.1   app=nginx-pod,pod-template-hash=5d89bdfbf9
pc-deployment-675d469f8b   0         0         0       73m    nginx        nginx:1.17.2   app=nginx-pod,pod-template-hash=675d469f8b
pc-deployment-7865c58bdf   0         0         0       25m    nginx        nginx:1.17.3   app=nginx-pod,pod-template-hash=7865c58bdf

#如上,其实deployment之所以可以实现版本的回滚,就是通过记录下历史rs来实现的。
# 一旦想回滚到哪个版本,只需要将当前版本pod数量降为0,然后将回滚版本的pod提升为目标数量就可以了。

金丝雀发布

Deployment控制器支持自定义控制更新过程中的滚动节奏,如"暂停(pause)" 或"继续(resume)" 更新操作。比如等待第一批新的Pod资源创建完成后立即暂停更新过程,此时,仅存在一部分新版本的应用,主体部分还是旧的版本。然后,再筛选一小部分的用户请求路由到新版本的Pod应用,继续观察能否稳定地按期望的方式运行。确定没问题之后再继续完成余下的Pod资源滚动更新,否则立即回滚更新操作。这就是所谓的金丝雀发布。

# 更新deployment的版本,并配置暂停deployment
[root@k8s-master01 ~]# kubectl set image deploy pc-deployment nginx=nginx:1.17.5  -n dev && kubectl rollout pause deployment pc-deployment -n dev
deployment.apps/pc-deployment image updated
deployment.apps/pc-deployment paused

# 观察更新状态
[root@k8s-master01 ~]# kubectl rollout status deployment pc-deployment -n dev
Waiting for deployment "pc-deployment" rollout to finish: 1 out of 3 new replicas have been updated...

# 监控更新的过程,可以看到已经新增了一个资源,但是并未按照预期的状态去删除一个旧的资源,就是因为使用了pause暂停命令
[root@k8s-master01 ~]# kubectl get rs,pod -n dev -o wide
NAME                                       DESIRED   CURRENT   READY   AGE     CONTAINERS   IMAGES         SELECTOR
replicaset.apps/pc-deployment-5d89bdfbf9   0         0         0       14h     nginx        nginx:1.17.1   app=nginx-pod,pod-template-hash=5d89bdfbf9
replicaset.apps/pc-deployment-675d469f8b   0         0         0       12h     nginx        nginx:1.17.2   app=nginx-pod,pod-template-hash=675d469f8b
replicaset.apps/pc-deployment-6c9f56fcfb   3         3         3       3m29s   nginx        nginx:1.17.4   app=nginx-pod,pod-template-hash=6c9f56fcfb
replicaset.apps/pc-deployment-6dcd994dc9   1         1         1       2m6s    nginx        nginx:1.17.5   app=nginx-pod,pod-template-hash=6dcd994dc9
replicaset.apps/pc-deployment-7865c58bdf   0         0         0       12h     nginx        nginx:1.17.3   app=nginx-pod,pod-template-hash=7865c58bdf

NAME                                 READY   STATUS    RESTARTS   AGE     IP            NODE         NOMINATED NODE   READINESS GATES
pod/pc-deployment-6c9f56fcfb-4trrn   1/1     Running   0          3m29s   10.244.2.76   k8s-node02   <none>           <none>
pod/pc-deployment-6c9f56fcfb-glfr5   1/1     Running   0          2m56s   10.244.2.78   k8s-node02   <none>           <none>
pod/pc-deployment-6c9f56fcfb-qrk6t   1/1     Running   0          2m57s   10.244.2.77   k8s-node02   <none>           <none>
pod/pc-deployment-6dcd994dc9-k4694   1/1     Running   0          2m6s    10.244.2.79   k8s-node02   <none>           <none>

# 确保更新的pod没问题了,继续更新
[root@k8s-master01 ~]# kubectl rollout resume deployment pc-deployment -n dev
deployment.apps/pc-deployment resumed

# 查看最后的更新情况
replicaset.apps/pc-deployment-5d89bdfbf9   0         0         0       14h     nginx        nginx:1.17.1   app=nginx-pod,pod-template-hash=5d89bdfbf9
replicaset.apps/pc-deployment-675d469f8b   0         0         0       12h     nginx        nginx:1.17.2   app=nginx-pod,pod-template-hash=675d469f8b
replicaset.apps/pc-deployment-6c9f56fcfb   0         0         0       5m10s   nginx        nginx:1.17.4   app=nginx-pod,pod-template-hash=6c9f56fcfb
replicaset.apps/pc-deployment-6dcd994dc9   3         3         3       3m47s   nginx        nginx:1.17.5   app=nginx-pod,pod-template-hash=6dcd994dc9
replicaset.apps/pc-deployment-7865c58bdf   0         0         0       12h     nginx        nginx:1.17.3   app=nginx-pod,pod-template-hash=7865c58bdf

NAME                                 READY   STATUS    RESTARTS   AGE     IP            NODE         NOMINATED NODE   READINESS GATES
pod/pc-deployment-6dcd994dc9-4gcg4   1/1     Running   0          40s     10.244.2.80   k8s-node02   <none>           <none>
pod/pc-deployment-6dcd994dc9-j9j92   1/1     Running   0          38s     10.244.2.81   k8s-node02   <none>           <none>
pod/pc-deployment-6dcd994dc9-k4694   1/1     Running   0          3m47s   10.244.2.79   k8s-node02   <none>           <none>

删除Deployment

# 删除deployment,其下的rs和pod也将被删除
[root@k8s-master01 ~]# kubectl delete -f pc-deployment.yml
deployment.apps "pc-deployment" deleted

[root@k8s-master01 ~]# kubectl get rs,pod -n dev -o wide
No resources found in dev namespace.

6.4 Horizontal Pod Autoscaler(HPA)

在这里插入图片描述
在这里插入图片描述

1.安装metrics-server

metrics-server可以用来收集集群中的资源使用情况.

#  获取metrics-server,注意使用的版本
[root@k8s-master01 github]# git clone -b v0.3.6 https://github.com/kubernetes-sigs/metrics-server
# 修改deployment,注意修改的是镜像和初始化参数
[root@k8s-master01 1.8+]# pwd
/root/github/metrics-server/deploy/1.8+
[root@k8s-master01 1.8+]# vim metrics-server-deployment.yaml
# 按照下图中添加如下选项:
hostNetwork: true
registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server-amd64:v0.3.6
- --kubelet-insecure-tls
- -- kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP

在这里插入图片描述

# 安装metrics-server
[root@k8s-master01 1.8+]# kubectl apply -f ./

# 查看pod运行情况
[root@k8s-master01 1.8+]# kubectl get pod -n kube-system
NAME                                   READY   STATUS    RESTARTS   AGE
metrics-server-6b976979db-tqrjr        1/1     Running   0          137m

# 使用kubecl top node 查看资源使用情况
# 这里解释一下cpu
[root@k8s-master01 1.8+]# kubectl top node (稍等一会才能查到数据)
NAME           CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
k8s-master01   241m         12%    802Mi           29%
k8s-node01     52m          2%     230Mi           8%
k8s-node02     94m          4%     334Mi           12%
[root@k8s-master01 1.8+]# kubectl top pod -n kube-system
NAME                                   CPU(cores)   MEMORY(bytes)
coredns-6955765f44-4pwjb               7m           12Mi
coredns-6955765f44-h2vpk               5m           12Mi
etcd-k8s-master01                      30m          54Mi
kube-apiserver-k8s-master01            77m          296Mi
kube-controller-manager-k8s-master01   27m          39Mi
kube-flannel-ds-7xx6d                  8m           30Mi
kube-flannel-ds-vh55n                  6m           20Mi
kube-proxy-f9hmd                       1m           14Mi
kube-proxy-qqnlw                       2m           14Mi
kube-proxy-vd7dx                       1m           14Mi
kube-scheduler-k8s-master01            7m           17Mi
metrics-server-6b976979db-tqrjr        2m           9Mi

# 至此,metrics-server安装完成

2.准备deployment和service

为了操作简单,直接使用命令

# 创建deployment
[root@k8s-master01 1.8+]# kubectl run nginx --image=nginx:1.17.1 --requests=cpu=100m -n dev
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
deployment.apps/nginx created

# 创建service
[root@k8s-master01 1.8+]# kubectl get deployments.apps,pod,service -n dev
NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx   1/1     1            1           40s

NAME                         READY   STATUS    RESTARTS   AGE
pod/nginx-778cb5fb7b-xb4g9   1/1     Running   0          40s

NAME            TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
service/nginx   NodePort   10.100.88.190   <none>        80:32227/TCP   13s

3.部署HPA

创建pc-hpa.yaml

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: pc-hpa
  namespace: dev
spec:
  minReplicas: 1   #最小pod数量
  maxReplicas: 10  #最大pod数量
  targetCPUUtilizationPercentage: 3  #cpu使用率指标,3表示3%(为了测试方便才设得比较低)
  scaleTargetRef: # 指定要控制的nginx信息
    apiVersion: apps/v1
    kind: Deployment
    name: nginx
# 创建hpa
[root@k8s-master01 1.8+]# kubectl create -f pc-hpa.yml
horizontalpodautoscaler.autoscaling/pc-hpa created

# 查看hpa
[root@k8s-master01 1.8+]# kubectl get hpa -n dev
NAME     REFERENCE          TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
pc-hpa   Deployment/nginx   0%/3%     1         10        1          43s

4.测试

使用压测工具对service地址 192.168.166.111:32227 进行压测,然后通过控制台查看hpa和pod的变化. (这里用burpsuite的intruder模块进行大并发访问)

hpa变化
在这里插入图片描述

deployment变化
在这里插入图片描述

pod 变化
在这里插入图片描述

等压测停下来后,要过一段时间(有可能是几分钟,或10分钟左右,不一定),hpa才会自动缩容。

6.5 DaemonSet(DS)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
下面先来看一下DaemonSet的资源清单文件:
在这里插入图片描述
创建pc-deaemonset.yaml,内容如下:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: pc-daemonset
  namespace: dev
spec:
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
# 创建daemonset
[root@k8s-master01 ~]# kubectl create -f pc-daemonset.yml
daemonset.apps/pc-daemonset created

# 查看daemonset
[root@k8s-master01 ~]# kubectl create -f pc-daemonset.yml
daemonset.apps/pc-daemonset created

# 查看daemonset
[root@k8s-master01 ~]# kubectl get ds pc-daemonset -n dev -o wide
NAME           DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE    CONTAINERS   IMAGES         SELECTOR
pc-daemonset   1         1         1       1            1           <none>          4m2s   nginx        nginx:1.17.1   app=nginx-pod

# 查看pod,发现在每个node上都运行一个pod
[root@k8s-master01 ~]# kubectl get ds pc-daemonset -n dev -o wide
NAME           DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE    CONTAINERS   IMAGES         SELECTOR
pc-daemonset   2         2         2       2            2           <none>          4m2s   nginx        nginx:1.17.1   app=nginx-pod

# 删除daemonset
[root@k8s-master01 ~]# kubectl delete -f pc-daemonset.yml
daemonset.apps "pc-daemonset" deleted

6.6 Job

Job,主要用于负责批量处理(一次要处理指定数量的任务) 短暂的一次性任务。Job特点如下:

  • 当Job创建的pod执行成功时,Job将记录成功结束的pod数量;
  • 当成功结束的pod达到指定的数量时,Job将完成执行。
    在这里插入图片描述
    Job的资源清单文件:
    在这里插入图片描述
    关于重启策略的说明:

如果指定为onFailure,则Job会在Pod出现故障时重启容器,而不是创建pod,failed次数;
如果指定为Never,则job会在pod出现故障时创建新的pod,并且故障pod不会消失,也不会重启,failed次数加1;
如果指定为Always,就意味着一直重启,意味着job任务会重复去执行,这当然不对,所以Job的重启策略不能设置为Always

创建pc-job.yml

apiVersion: batch/v1
kind: Job
metadata:
  name: pc-job
  namespace: dev
spec:
  manualSelector: true
  selector:
    matchLabels:
      app: counter-pod
  template:
    metadata:
      labels:
        app: counter-pod
    spec:
      restartPolicy: Never
      containers:
      - name: counter
        image: busybox:1.30
        command: ["/bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1;do echo $i;sleep 3; done"]
# 创建job
[root@k8s-master01 ~]# kubectl create -f pc-job.yml
job.batch/pc-job created

# 查看job
[root@k8s-master01 ~]# kubectl get job -n dev -o wide -w
NAME     COMPLETIONS   DURATION   AGE   CONTAINERS   IMAGES         SELECTOR
pc-job   0/1                      0s    counter      busybox:1.30   app=counter-pod
pc-job   0/1           0s         0s    counter      busybox:1.30   app=counter-pod
pc-job   1/1           31s        31s   counter      busybox:1.30   app=counter-pod

# 通过观察pod状态可以看到,pod在运行完毕任务后,就会变成Completed状态
[root@k8s-master01 ~]# kubectl get pod -n dev -o wide -w
NAME                     READY   STATUS    RESTARTS   AGE     IP             NODE         NOMINATED NODE   READINESS GATES
pc-job-dw84w             1/1     Running   0          21s     10.244.2.103   k8s-node02   <none>           <none>
pc-job-dw84w             0/1     Completed   0          31s     10.244.2.103   k8s-node02   <none>           <none>

# 接下来,调整下pod运行的总数量和并行数量,即:在spec下设置下面两个选项:
#  completions: 6  #指定job需要成功运行pod的个数为6
# parallelism:3   #指定job并发运行pod的数量为3
# 然后重新运行job,观察效果,此时会发现,job会每次运行3个pod,总共运行了6个pod
[root@k8s-master01 ~]# kubectl get pod -n dev -w
NAME                     READY   STATUS    RESTARTS   AGE
pc-job-7rxp6             1/1     Running   0          11s
pc-job-k4f6n             1/1     Running   0          11s
pc-job-kxbz9             1/1     Running   0          11s
pc-job-7rxp6             0/1     Completed   0          30s
pc-job-h8pms             0/1     Pending     0          0s
pc-job-h8pms             0/1     Pending     0          0s
pc-job-kxbz9             0/1     Completed   0          30s
pc-job-qbnss             0/1     Pending     0          0s
pc-job-qbnss             0/1     Pending     0          0s
pc-job-h8pms             0/1     ContainerCreating   0          0s
pc-job-k4f6n             0/1     Completed           0          30s
pc-job-gqrq7             0/1     Pending             0          0s
pc-job-gqrq7             0/1     Pending             0          0s
pc-job-qbnss             0/1     ContainerCreating   0          0s
pc-job-gqrq7             0/1     ContainerCreating   0          1s
pc-job-gqrq7             1/1     Running             0          2s
pc-job-qbnss             1/1     Running             0          3s
pc-job-h8pms             1/1     Running             0          3s
pc-job-gqrq7             0/1     Completed           0          29s
pc-job-qbnss             0/1     Completed           0          29s
pc-job-h8pms             0/1     Completed           0          29s

# 删除job
[root@k8s-master01 ~]# kubectl delete -f pc-job.yml
job.batch "pc-job" deleted

6.7 CronJob(CJ)

在这里插入图片描述
在这里插入图片描述
CronJob的资源清单文件:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

创建pc-cronjob.yml,内容如下:

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: pc-cronjob
  namespace: dev
  labels:
    controller: cronjob
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    metadata:
    spec:
      template:
        spec:
          restartPolicy: Never
          containers:
          - name: counter
            image: busybox:1.30
            command: ["/bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1;do echo $i;sleep 3;done"]
# 创建cronjob
[root@k8s-master01 ~]# kubectl create -f pc-cronjob.yml
cronjob.batch/pc-cronjob created

# 查看cronjob
[root@k8s-master01 ~]# kubectl get cj -n dev -o wide -w
NAME         SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE   CONTAINERS   IMAGES         SELECTOR
pc-cronjob   */1 * * * *   False     0        <none>          3s    counter      busybox:1.30   <none>
pc-cronjob   */1 * * * *   False     1        3s              43s   counter      busybox:1.30   <none>
pc-cronjob   */1 * * * *   False     0        33s             73s   counter      busybox:1.30   <none>

# 查看job
[root@k8s-master01 ~]# kubectl get job -n dev -o wide -w
NAME                    COMPLETIONS   DURATION   AGE   CONTAINERS   IMAGES         SELECTOR
pc-cronjob-1647597840   0/1                      0s    counter      busybox:1.30   controller-uid=9e150b5f-d183-4b1d-b053-0e3b474ba253
pc-cronjob-1647597900   0/1                      0s    counter      busybox:1.30   controller-uid=4965b04d-2746-4e50-9b90-4b5c5e91233d

# 删除cronjob
[root@k8s-master01 ~]# kubectl delete -f pc-cronjob.yml
cronjob.batch "pc-cronjob" deleted

6.8 StatefulSet(有状态)

  • 无状态应用:
    ○ 认为Pod都是一样的。
    ○ 没有顺序要求。
    ○ 不用考虑在哪个Node节点上运行。
    ○ 随意进行伸缩和扩展。
  • 有状态应用:
    ○ 有顺序的要求。
    ○ 认为每个Pod都是不一样的。
    ○ 需要考虑在哪个Node节点上运行。
    ○ 需要按照顺序进行伸缩和扩展。
    ○ 让每个Pod都是独立的,保持Pod启动顺序和唯一性。
  • StatefulSet是Kubernetes提供的管理有状态应用的负载管理控制器。
  • StatefulSet部署需要HeadLinessService(无头服务)。

为什么需要HeadLinessService(无头服务)?
在用Deployment时,每一个Pod名称是没有顺序的,是随机字符串,因此是Pod名称是无序的,但是在StatefulSet中要求必须是有序 ,每一个Pod不能被随意取代,Pod重建后pod名称还是一样的。
而Pod IP是变化的,所以是以Pod名称来识别。Pod名称是Pod唯一性的标识符,必须持久稳定有效。这时候要用到无头服务,它可以给每个Pod一个唯一的名称 。

  • StatefulSet常用来部署RabbitMQ集群、Zookeeper集群、MySQL集群、Eureka集群等。

创建pc-statefulset.yml,内容如下:

apiVersion: v1
kind: Service
metadata:
  name: service-headliness
  namespace: dev
spec:
  selector:
    app: nginx-pod
  clusterIP: None # 将clusterIP设置为None,即可创建headliness Service
  type: ClusterIP
  ports:
    - port: 80 # Service的端口
      targetPort: 80 # Pod的端口
---

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: pc-statefulset
  namespace: dev
spec:
  replicas: 3
  serviceName: service-headliness
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
        - name: nginx
          image: nginx:1.17.1
          ports:
            - containerPort: 80
# 创建statefulset
[root@k8s-master01 ~]# kubectl create -f pc-statefulset.yml
service/service-headliness created
statefulset.apps/pc-statefulset created

# 查看statefulset
[root@k8s-master01 ~]# kubectl get statefulsets.apps pc-statefulset -n dev -o wide
NAME             READY   AGE     CONTAINERS   IMAGES
pc-statefulset   3/3     2m37s   nginx        nginx:1.17.1

# 查看pod
[root@k8s-master01 ~]# kubectl get pod -n dev -o wide
NAME                     READY   STATUS    RESTARTS   AGE     IP             NODE         NOMINATED NODE   READINESS GATES
pc-statefulset-0         1/1     Running   0          2m56s   10.244.2.116   k8s-node02   <none>           <none>
pc-statefulset-1         1/1     Running   0          2m55s   10.244.2.117   k8s-node02   <none>           <none>
pc-statefulset-2         1/1     Running   0          2m54s   10.244.2.118   k8s-node02   <none>           <none>

# 删除statefulset
[root@k8s-master01 ~]# kubectl delete -f pc-statefulset.yml
service "service-headliness" deleted
statefulset.apps "pc-statefulset" deleted

Deployment和StatefulSet的区别

  • Deployment没有唯一标识而StatefulSet有唯一标识。
  • StatefulSet的唯一标识是根据主机名+一定规则生成的。
  • StatefulSet的唯一标识是主机名.无头Service名称.命名空间.svc.cluster.local。

StatefulSet的金丝雀发布

StatefulSet支持两种更新策略:OnDeleteRollingUpdate(默认),其中OnDelete表示删除之后才更新,RollingUpdate表示滚动更新。

...
  updateStrategy:
    rollingUpdate: # 如果更新的策略是OnDelete,那么rollingUpdate就失效
      partition: 2 # 表示从第2个分区开始更新,默认是0
    type: RollingUpdate /OnDelete # 滚动更新
...

示例:pc-statefulset.yaml

apiVersion: v1
kind: Service
metadata:
  name: service-headliness
  namespace: dev
spec:
  selector:
    app: nginx-pod
  clusterIP: None # 将clusterIP设置为None,即可创建headliness Service
  type: ClusterIP
  ports:
    - port: 80 # Service的端口
      targetPort: 80 # Pod的端口
---

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: pc-statefulset
  namespace: dev
spec:
  replicas: 3
  serviceName: service-headliness
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
        - name: nginx
          image: nginx:1.17.1
          ports:
            - containerPort: 80
			
  updateStrategy:
    rollingUpdate:
      partition: 0
    type: RollingUpdate  			

7、Service详解

本章节主要介绍kubernetes的流量负载组件:ServiceIngress

7.1 Service介绍

在kubernetes中,pod是应用程序的载体,我们可以通过pod的IP来访问应用程序,但是pod的ip不是固定的,这也就意味着不方便直接采用pod的ip对服务进行访问。

为了解决这个问题,kubernetes提供了Service资源,Service对提供同一个服务的多个pod进行聚合,并且提供一个统一的入口地址,通过访问Service的入口地方就能访问到后面的pod服务。
在这里插入图片描述
Service在很多情况下只是一个概念,真正起作用的其实是kube-proxy服务进程,每个Node节点上都运行着一个kube-proxy服务进程。当创建Service的时候会通过api-server向etcd写入创建的service的信息,而kube-proxy会基于监听的机制发现这种Service的变动,然后它会将最新的Service信息转换成对应的访问规则。
在这里插入图片描述在这里插入图片描述
kube-proxy目前支持三种工作模式:

userspace模式

在userspace模式下,kube-proxy会为每一个Service创建一个监听端口,发向Cluster IP的请求被iptables规则重定向到kube-proxy监听的端口上,kube-proxy根据LB算法选择一个提供服务的Pod并和其建立连接,以将请求转发到pod上。

该模式下,kube-proxy充当了一个四层负载均衡器的角色。由于kube-proxy运行在userspace中,在进行转发处理时增加内核和用户空间之间的数据拷贝,虽然比较稳定,但效率比较低。
在这里插入图片描述
iptables模式

在iptables模式下,kube-proxy为service后端的每个pod创建对应的iptables规则,直接将发向Cluster IP的请求重定向到一个Pod IP。

该模式下的kube-proxy不承担四层负载均衡器的角色,只负责创建iptables规则。该模式的优点是较userspace模式效率更高,但不能提供灵活的LB策略,当后端Pod不可用时也无法进行重试。
在这里插入图片描述
ipvs模式

ipvs模式和iptables类似,kube-proxy监控pod的变化并创建相应的ipvs规则。ipvs相对iptables转发效率更高。除此之外,ipvs支持更多的LB算法。
在这里插入图片描述

# 此模式必须按照ipvs模块,否则会降级为iptables(第二章搭建环境时已按照ipvs)
# 开启ipvs:使用以下命令编辑kube-proxy,将mode项改为:"ipvs",如下图.
[root@k8s-master01 ~]# kubectl edit cm kube-proxy -n kube-system
configmap/kube-proxy edited

# 然后删除标签为 k8s-app=kube-proxy 的pod,删除后pod会自动重建,从而使用ipvs。
[root@k8s-master01 ~]# kubectl delete pod -l k8s-app=kube-proxy -n kube-system
pod "kube-proxy-f9hmd" deleted
pod "kube-proxy-qqnlw" deleted
pod "kube-proxy-vd7dx" deleted

[root@k8s-master01 ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  127.0.0.1:30856 rr
  -> 10.244.2.122:80              Masq    1      0          0            Masq    1      0          0
TCP  192.168.166.111:30856 rr
  -> 10.244.2.122:80              Masq    1      0          2


# 上面规则的含义,以 第二条为例:当访问 192.168.166.111:30856时,
# 会转发到 10.244.2.122:80 。

在这里插入图片描述

7.2 Service类型

Service的资源清单文件:
在这里插入图片描述

  • ClusterIP:默认值,它是kubernetes系统自动分配的虚拟IP,只能在集群内部访问;
  • NodePort:将Service通过指定的Node上的端口暴露给外部,通过此方法,就可以在集群外部访问服务;
  • LoadBalancer:使用外接负载均衡器完成到服务的负载分发,注意此模式需要外部云环境支持;
  • ExternalName:把集群外部的服务引入集群内部,直接使用。

7.3 Service使用

7.3.1 实验环境准备

在使用service之前,首先利用Deployment创建出3个pod,注意要为pod设置 app=nginx-pod 的标签。

创建pc-deployment-2.yaml,内容如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pc-deployment
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
        ports:
        - containerPort: 80
#创建deployment
[root@k8s-master01 ~]# kubectl create -f pc-deployment-2.yml
deployment.apps/pc-deployment created

# 查看pod详情
[root@k8s-master01 ~]# kubectl get pod -n dev -o wide --show-labels
NAME                             READY   STATUS    RESTARTS   AGE    IP            NODE         NOMINATED NODE   READINESS GATES   LABELS
pc-deployment-6696798b78-f7426   1/1     Running   0          2m1s   10.244.2.9    k8s-node02   <none>           <none>            app=nginx-pod,pod-template-hash=6696798b78
pc-deployment-6696798b78-qz8g2   1/1     Running   0          2m1s   10.244.1.7    k8s-node01   <none>           <none>            app=nginx-pod,pod-template-hash=6696798b78
pc-deployment-6696798b78-rwdqp   1/1     Running   0          2m1s   10.244.2.10   k8s-node02   <none>           <none>            app=nginx-pod,pod-template-hash=6696798b78

为了方便后面的测试,修改下三台nginx的index.html页面(三台修改的IP地址不一致)
[root@k8s-master01 ~]# kubectl exec -it pc-deployment-6696798b78-f7426 -n dev /bin/sh
# echo "IP=10.244.2.9<br>NODE=k8s-node02" > /usr/share/nginx/html/index.html

# 修改完毕后,访问测试
[root@k8s-master01 ~]# curl http://10.244.2.9
IP=10.244.2.9<br>NODE=k8s-node02
[root@k8s-master01 ~]# curl http://10.244.1.7
IP=10.244.1.7<br>NODE=k8s-node01
[root@k8s-master01 ~]# curl http://10.244.2.10
IP=10.244.2.10<br>NODE=k8s-node02

7.3.2 ClusterIP类型的Service

创建service-clusterip.yaml文件,内容如下:

apiVersion: v1
kind: Service
metadata:
  name: service-clusterip
  namespace: dev
spec:
  selector:
    app: nginx-pod
  clusterIP: 10.97.97.97  #service的ip地址,如果不写,默认会生成一个
  type: ClusterIP
  ports:
  - port: 80  #service的端口
    targetPort: 80  #pod的端口
# 创建service
[root@k8s-master01 ~]# kubectl create -f service-clusterip.yaml
service/service-clusterip created

# 查看service
[root@k8s-master01 ~]# kubectl get service -n dev service-clusterip -o wide
NAME                TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE     SELECTOR
service-clusterip   ClusterIP   10.97.97.97   <none>        80/TCP    8m43s   app=nginx-pod

# 查看service的详细信息
# 在这里有一个Endpoints列表,里面就是当前service可以负载到的服务入口
[root@k8s-master01 ~]# kubectl describe  service -n dev service-clusterip
Name:              service-clusterip
Namespace:         dev
Labels:            <none>
Annotations:       <none>
Selector:          app=nginx-pod
Type:              ClusterIP
IP:                10.97.97.97
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.1.8:80,10.244.2.11:80,10.244.2.12:80
Session Affinity:  None
Events:            <none>

# 查看ipvs的映射规则
[root@k8s-master01 ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.97.97.97:80 rr
  -> 10.244.1.8:80                Masq    1      0          0
  -> 10.244.2.11:80               Masq    1      0          0
  -> 10.244.2.12:80               Masq    1      0          0

# 访问10.97.97.97:80 观察效果

Endpoint

Endpoint是kubernetes中的一个资源对象,存储在etcd中,用来记录一个service对应的所有pod的访问地址,它是根据service配置文件中selector描述产生的。

一个Service由一组pod组成,这些pod通过Endpoints暴露出来,endpoints是实现实际服务的端点集合。换句话说,service和pod之间的联系是通过endpoints实现的。
在这里插入图片描述
在这里插入图片描述
负载分发策略

对Service的访问被分发到了后端的pod上去,目前kubernetes提供了两种负载分发策略:

  • 如果不定义,默认使用kube-proxy的策略,比如随机、轮询;
  • 基于客户端地址的会话保证模式,即来自同一个客户端发起的所有请求都会转发到固定的一个pod上,此模式可以使在spec中添加 sessionAffinity:ClientIP 选项。
# 查看ipvs的映射规则【rr:轮询】
[root@k8s-master01 ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.97.97.97:80 rr
  -> 10.244.1.8:80                Masq    1      0          0
  -> 10.244.2.11:80               Masq    1      0          0
  -> 10.244.2.12:80

# 循环访问测试
[root@k8s-master01 ~]# while true; do curl 10.97.97.97:80; sleep 5; done;
IP=10.244.2.12<br>NODE=k8s-node02
IP=10.244.2.11<br>NODE=k8s-node02
IP=10.244.1.8<br>NODE=k8s-node01
IP=10.244.2.12<br>NODE=k8s-node02
IP=10.244.2.11<br>NODE=k8s-node02
IP=10.244.1.8<br>NODE=k8s-node01

# 修改分发策略-------- sessionAffinity:ClientIP

# 查看ipvs规则【persistent:代表持久】
[root@k8s-master01 ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.97.97.97:80 rr persistent 10800
  -> 10.244.1.8:80                Masq    1      0          0
  -> 10.244.2.11:80               Masq    1      0          0
  -> 10.244.2.12:80               Masq    1      0          0

# 循环访问测试
[root@k8s-master01 ~]# while true; do curl 10.97.97.97:80; sleep 5; done;
IP=10.244.2.12<br>NODE=k8s-node02
IP=10.244.2.12<br>NODE=k8s-node02
IP=10.244.2.12<br>NODE=k8s-node02

# 删除service
[root@k8s-master01 ~]# kubectl delete -f service-clusterip.yaml
service "service-clusterip" deleted

在这里插入图片描述

7.3.3 HeadLiness类型的Service

在某些场景中,开发人员可能不想使用Service提供的负载均衡功能,而希望自己来控制负载均衡策略,针对这种情况,kubernetes提供了HeadLiness Service,这类Service不会分配ClusterIP,如果想要访问service,只能通过service的域名进行查询。

创建 service-headliness.yaml:

apiVersion: v1
kind: Service
metadata:
  name: service-headliness
  namespace: dev
spec:
  selector:
    app: nginx-pod
  clusterIP: None  #将clusterIP设置成None,即可创建headliness Service
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 80
# 创建service
[root@k8s-master01 ~]# kubectl create -f service-headliness.yaml
service/service-headliness created

# 获取service,发现CLUSTER-IP未分配
[root@k8s-master01 ~]# kubectl get service service-headliness -n dev -o wide
NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE   SELECTOR
service-headliness   ClusterIP   None         <none>        80/TCP    10s   app=nginx-pod

# 查看service详情
[root@k8s-master01 ~]# kubectl describe service service-headliness -n dev
Name:              service-headliness
Namespace:         dev
Labels:            <none>
Annotations:       <none>
Selector:          app=nginx-pod
Type:              ClusterIP
IP:                None
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.1.8:80,10.244.2.11:80,10.244.2.12:80
Session Affinity:  None
Events:            <none>

# 查看域名的解析情况
[root@k8s-master01 ~]# kubectl exec -it pc-deployment-6696798b78-4fwr6 -n dev /bin/bash
root@pc-deployment-6696798b78-4fwr6:/#
root@pc-deployment-6696798b78-4fwr6:/# cat /etc/resolv.conf
nameserver 10.96.0.10
search dev.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

[root@k8s-master01 ~]# dig @10.96.0.10 service-headliness.dev.svc.cluster.local
...
;; ANSWER SECTION:
service-headliness.dev.svc.cluster.local. 30 IN	A 10.244.1.8
service-headliness.dev.svc.cluster.local. 30 IN	A 10.244.2.12
service-headliness.dev.svc.cluster.local. 30 IN	A 10.244.2.11
...

7.3.4 NodePort类型的Service

在之前的样例中,创建的Service的IP地址只有集群内部才可以访问,如果希望将Service暴露给集群外部使用,那么就要使用到另外一种类型的Service,称为NodePort类型。NodePort的工作原理其实就是将service的端口映射到node的一个端口上,然后就可以通过NodeIP:NodePort 来访问service了。
在这里插入图片描述
创建service-nodeport.yaml

apiVersion: v1
kind: Service
metadata:
  name: service-nodeport
  namespace: dev
spec:
  selector:
    app: nginx-pod
  type: NodePort  #service类型
  ports:
  - port: 80
    nodePort: 32227  #指定绑定的node端口(默认取值范围是:30000-32767),如果不指定,会默认分配
    targetPort: 80
# 创建service
[root@k8s-master01 ~]# kubectl create -f service-nodeport.yaml
service/service-nodeport created

# 查看service
[root@k8s-master01 ~]# kubectl get service -n dev -o wide
NAME               TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE    SELECTOR
service-nodeport   NodePort   10.106.176.29   <none>        80:32227/TCP   6m5s   app=nginx-pod

# 然后可以通过电脑主机的浏览器访问集群任意一个node ip的32227端口,便可访问到pod的nginx服务

在这里插入图片描述
在这里插入图片描述

7.3.5 LoadBalancer类型的Service

LoadBalancer和NodePort很相似,目的都是向外部暴露一个端口,区别在于LoadBalancer会在集群的外部再来做一个负载均衡设备,而这个设备需要外部环境支持的,外部服务发送到这个设备上的请求,会被设备负载之后转发到集群中。
在这里插入图片描述

7.3.6 ExternalName类型的Service

在ExternalName类型的Service用于引入集群外部的服务,它通过externalName 属性指定外部一个服务的地址,然后在集群内部访问此service就可以访问到外部的服务了。
在这里插入图片描述
创建 service-externalname.yaml

apiVersion: v1
kind: Service
metadata:
  name: service-externalname
  namespace: dev
spec:
  type: ExternalName  #service类型
  externalName: www.baidu.com   #改成IP地址也可以
# 创建service
[root@k8s-master01 ~]# kubectl create -f service-externalname.yaml
service/service-externalname created

# 域名解析
[root@k8s-master01 ~]# dig @10.96.0.10 service-externalname.dev.svc.cluster.local
;; ANSWER SECTION:
service-externalname.dev.svc.cluster.local. 5 IN CNAME www.baidu.com.
www.baidu.com.		5	IN	CNAME	www.a.shifen.com.
www.a.shifen.com.	5	IN	A	182.61.200.6
www.a.shifen.com.	5	IN	A	182.61.200.7

7.4 Ingress介绍

在前面课程中已经提到,Service对集群之外暴露服务的主要方式有两种:NodePort和LoadBalancer,但是这两种方式都有缺点:

  • NodePort方式的缺点是会占用很多集群机器的端口,那么当集群服务变多的时候,这个缺点就愈发明显;
  • LB方式的缺点是每个Service需要一个LB,浪费、麻烦,并且需要kubernetes之外设备的支持。

基于这种现状,kubernetes提供了Ingress资源对象,Ingress只需要一个NodePort或者一个LB就可以满足暴露多个Service的需求。工作机制大致如下图所示:
在这里插入图片描述
实际上,Ingress相当于一个7层的负载均衡器,是kubernetes对反向代理的一个抽象,它的工作原理类似于Nginx,可以理解成在Ingress里建立诸多映射规则,Ingress Controller通过监听这些配置规则并转化成nginx的配置,然后对外部提供服务,在这里有两个核心概念:

  • Ingress:kubernetes中的一个对象,作用是定义请求如何转发到service的规则;
  • Ingress Controller:具体实现反向代理及负载均衡的程序,对Ingress定义的规则进行解析,根据配置的规则来实现请求转发,实现方式有很多,比如Nginx、Contour、HAProxy等。

Ingress(以nginx为例)的工作原理如下:
(1) 用户编写Ingress规则,说明哪个域名对应kubernetes集群中的哪个Service
(2) Ingress控制器动态感知Ingress服务规则的变化,然后生成一段对应的Nginx配置
(3) Ingress控制器会将生成的nginx配置写入到一个运行着的nginx服务中,并动态更新;
(4) 到此为止,其实真正在工作的就是一个nginx了,内部配置了用户定义的请求转发规则。
在这里插入图片描述

7.5 Ingress使用

7.5.1 环境准备

搭建Ingress环境

# 创建文件夹
[root@k8s-master01 ~]# mkdir ingress-controller
[root@k8s-master01 ~]# cd ingress-controller/

# 获取ingress-nginx,本次案例使用的是0.30.0版本
[root@k8s-master01 ingress-controller]# wget -e "https_proxy=http://192.168.3.36:1087" https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml
[root@k8s-master01 ingress-controller]# wget -e "https_proxy=http://192.168.3.36:1087" https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml

# 修改mandatory.yaml文件中的仓库
# 修改quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0 为:
#  quay.mirrors.ustc.edu.cn/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0(这里换成中科大的源,因为七牛云quay-mirror.qiniu.com的失效了)
# 创建ingress-nginx
[root@k8s-master01 ingress-controller]# kubectl apply -f ./
namespace/ingress-nginx created
configmap/nginx-configuration created
configmap/tcp-services created
configmap/udp-services created
serviceaccount/nginx-ingress-serviceaccount created
clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole created
role.rbac.authorization.k8s.io/nginx-ingress-role created
rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding created
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding created
deployment.apps/nginx-ingress-controller created
limitrange/ingress-nginx created
service/ingress-nginx created

# 查看ingress-nginx
[root@k8s-master01 ingress-controller]# kubectl get svc,pod -n ingress-nginx -o wide
NAME                    TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE   SELECTOR
service/ingress-nginx   NodePort   10.105.200.169   <none>        80:31470/TCP,443:31569/TCP   22m   app.kubernetes.io/name=ingress-nginx,app.kubernetes.io/part-of=ingress-nginx

NAME                                            READY   STATUS    RESTARTS   AGE     IP            NODE         NOMINATED NODE   READINESS GATES
pod/nginx-ingress-controller-6ddf7d6bc4-ccg2k   1/1     Running   0          2m26s   10.244.2.21   k8s-node02   <none>           <none>

准备service和pod

为了后面的实验方便,创建如下图所示的模型:
在这里插入图片描述
创建tomcat-nginx.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-pod
  template: 
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
        ports:
        - containerPort: 80

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat-deployment
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      app: tomcat-pod
  template:
    metadata:
      labels:
        app: tomcat-pod
    spec:
      containers:
      - name: tomcat
        image: tomcat:8.5-jre10-slim
        ports:
        - containerPort: 8080

---

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: dev
spec:
  selector:
    app: nginx-pod
  clusterIP: None
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 80

---

apiVersion: v1
kind: Service
metadata:
  name: tomcat-service
  namespace: dev
spec:
  selector:
    app: tomcat-pod
  clusterIP: None
  type: ClusterIP
  ports:
  - port: 8080
    targetPort: 8080
# 创建
[root@k8s-master01 ~]# kubectl create ns dev
namespace/dev created
[root@k8s-master01 ~]#
[root@k8s-master01 ~]# kubectl create -f tomcat-nginx.yaml
deployment.apps/nginx-deployment created
deployment.apps/tomcat-deployment created
service/nginx-service created
service/tomcat-service created

# 查看
[root@k8s-master01 ~]# kubectl get service -n dev -o wide
NAME             TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE   SELECTOR
nginx-service    ClusterIP   None         <none>        80/TCP     29s   app=nginx-pod
tomcat-service   ClusterIP   None         <none>        8080/TCP   29s   app=tomcat-pod

7.5.2 HTTP代理

创建 ingress-http.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-http
  namespace: dev
spec:
  rules:
  - host: nginx.mole.org
    http:
      paths:
      - path: /
        backend:
          serviceName: nginx-service
          servicePort: 80
  - host: tomcat.mole.org
    http:
      paths:
      - path: /
        backend:
          serviceName: tomcat-service
          servicePort: 8080
# 创建
[root@k8s-master01 ~]# kubectl create -f ingress-http.yaml
ingress.extensions/ingress-http create

# 查看
[root@k8s-master01 ~]# kubectl get ingresses.extensions -n dev
NAME           HOSTS                            ADDRESS          PORTS   AGE
ingress-http   nginx.mole.org,tomcat.mole.org   10.105.200.169   80      21s
[root@k8s-master01 ~]#

# 查看详情
[root@k8s-master01 ~]# kubectl describe ingresses.extensions -n dev
Name:             ingress-http
Namespace:        dev
Address:          10.105.200.169
Default backend:  default-http-backend:80 (<none>)
Rules:
  Host             Path  Backends
  ----             ----  --------
  nginx.mole.org
                   /   nginx-service:80 (10.244.1.15:80,10.244.1.16:80,10.244.2.22:80)
  tomcat.mole.org
                   /   tomcat-service:8080 (10.244.1.14:8080,10.244.2.23:8080,10.244.2.24:8080)
...

# 接下来,在本地电脑上配置hosts文件,解析上面的两个域名到 192.168.166.111 (master节点) 上
# 然后,就可以分别访问 http://tomcat.mole.org:31470  和 http://nginx.mole.org:31470 查看效果了

在这里插入图片描述

7.5.3 HTTPS代理

创建证书

# 生成证书
[root@k8s-master01 ~]# openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/C=CN/ST=BJ/L=BJ/O=nginx/CN=mole.org"
Generating a 2048 bit RSA private key
......................................................................+++
............................+++
writing new private key to 'tls.key'
-----

# 创建密钥
[root@k8s-master01 ~]# kubectl create secret tls tls-secret --key tls.key --cert tls.crt
secret/tls-secret created

创建ingress-https.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-https
  namespace: dev
spec:
  tls:
    - hosts:
      - nginx.mole.org
      - tomcat.mole.org
      secretName: tls-secret  #指定密钥
  rules:
  - host: nginx.mole.org
    http:
      paths:
      - path: /
        backend:
          serviceName: nginx-service
          servicePort: 80
  - host: tomcat.mole.org
    http:
      paths:
      - path: /
        backend:
          serviceName: tomcat-service
          servicePort: 8080
# 创建
[root@k8s-master01 ~]# kubectl create -f ingress-https.yaml
ingress.extensions/ingress-https created

# 查看
[root@k8s-master01 ~]# kubectl get ingresses.extensions ingress-https -n dev
NAME            HOSTS                            ADDRESS   PORTS     AGE
ingress-https   nginx.mole.org,tomcat.mole.org             80, 443   50s

# 查看详情
[root@k8s-master01 ~]# kubectl describe ingresses.extensions ingress-https -n dev
Name:             ingress-https
Namespace:        dev
Address:          10.105.200.169
Default backend:  default-http-backend:80 (<none>)
TLS:
  tls-secret terminates nginx.mole.org,tomcat.mole.org
Rules:
  Host             Path  Backends
  ----             ----  --------
  nginx.mole.org
                   /   nginx-service:80 (10.244.1.15:80,10.244.1.16:80,10.244.2.22:80)
  tomcat.mole.org
                   /   tomcat-service:8080 (10.244.1.14:8080,10.244.2.23:8080,10.244.2.24:8080)
...

# 下面可以通过浏览器访问 https://nginx.mole.org:31569  和 https://tomcat.mole.org:31569 来查看了

在这里插入图片描述

Logo

开源、云原生的融合云平台

更多推荐