Kubernetes-学习必备(awesome-kubernetes-notes)


git地址:https://github.com/redhatxl/aw ... notes
为方便更多k8s爱好者更系统性的学习文档,利用sphinx将笔记整理构建程在线文档,方便学习交流

demo.png


一 Kubernetes概述
1.1 容器编排工具
docker 官方编排工具
docker compose # 单机编排工具
docker swarm # 将多台 docker 提供的计算资源整合的接口,随后 docker compose 编排的时候只需要面向这个整合的接口进行编排就行,无论接口下有多少个主机。
docker mechine # 将一个主机初始化为一个能够加入 docker swarm 集群中的预置程序
mesos IDC 操作系统
IDC 操作系统,能将一个 IDC 提供的硬件资源,统一调度和分配,它只是一个资源分配工具,非能够直接托管容器的,所以它提供了以个能够直接编排框架,marathon。
kubernetes
目前最流行的容器编排工具,市场占有率最高
1.2 kubernetes
kubernetes 是希腊语,翻译过来是:舵手的意思,它的原型是谷歌内部使用 Borg 集群管理系统,可以说是集结了 Borg 设计思想的精华,并且吸收了 Borg 系统中的经验和教训。

它的目标不仅仅是一个编排系统,而是提供一个规范,可以让你来描述集群的架构,定义服务的最终状态,Kubernetes可以帮你将系统自动地达到和维持在这个状态。Kubernetes作为云原生应用的基石,相当于一个云操作系统,其重要性不言而喻。

kubernetes 在 2014 年发布了第一个版本,目前开源并托管在 Github 上。

https://github.com/Kubernetes
目前,AWS、阿里云、微软云,目前已经原生支持 K8S ,目前已经可以让用户直接部署云原生的服务。

有什么优势
- 基于 Borg 系统,设计成熟,开源、且轻量级,简单易学、容易理解;
- 模块化,可插拔,支持钩子,可任意组合,例如:网络组件 flannel,存储插件;
- 故障发现(存活性探针)和自我修复能力(副本数量)、服务滚动升级(就绪探针)和在线扩容(副本数量);
- 可扩展的资源自动调度机制(多维度的水平自动扩容)、多粒度的资源配额管理能力(资源限制)。
1.3 环境架构
Kubernetes 是一个集群,整合多台计算机的计算能力,它是一种有中心节点模式的集群,在 K8S 集群中主机分为两种角色:

Master:集群的管理节点,有一个或者一组节点,一般 3 个足够了。
nodes:提供计算资源的节点,就是运行容器的节点,可以扩展。
客户端创建启动容器的请求交给 Master ,Master 上有一个调度器它能分析各 nodes 节点上的资源状态,找一个最适合运行用户容器的节点,并在这个节点上使用 Docker 启动这个容器,node 节点的 Docker 在启动容器时候会首先检查本地有没有镜像,如果没有就从仓库中 pull 然后运行。

那么仓库可以运行为容器,所以也可以托管在 Kubernetes 之上,其实 Kubernetes 可以托管自身,即自托管。

ApiServer
kubernetes 接收用户创建容器等请求的是 Kubernetes Cluster,那么它对外提供服务的接口就是一个 API 接口 ,这个接口需要编程来访问,或者通过编写好的客户端程序来访问,Kubernetes Master 上有一个组件就是 ApiServer,来接收客端请求,解析客户端请求。

scheduler
如果客户请求是运行一个容器,那么 Master 会使用调度器(scheduler)根据用户的请求来分配一个能够运行容器的 nodes 节点,例如:根据用户对资源要求,CPU、内存、来评估哪个 nodes 最合适运行。

大概的过程就是:首先是预选,从 nodes 中挑选出符合用户容器运行要求的,然后在这些预选结果中进行优选,选出最佳的适配 node。

Controller(控制器)
如果运行容器的节点宕机或者容器本身运行出现问题,kubernetes 能够在其他节点再启动一个一模一样的容器,这就是 Kubernetes 提供的自愈能力。

控制器就实现了监控它所负责的每一个容器的健康状态,一旦发现不健康了,那么控制器会向 Master 发送请求,Master 会再次由调度器挑选出合适的节点再次运行这个容器。

它能持续性探测所管理的容器,一旦不健康,或不符合用户定义的健康状态,就会由它发起来请求,来保证容器向用户希望的健康状态迁徙。

而 Kubernets 支持众多的控制器,支持容器健康的控制器只是其中一种。

ControllerManager(制器管理器)
在 Master 内置组件中有一个控制器管理器,它负责监视着每一个控制器,如果控制器不健康无法工作,那么由控制器管理器来确保控制器的健康,由于 Master 有多个,所以具有冗余性。

Pod(原子调度单元,是容器的封装)
在 Kubernetes 上调度的原子单元,Kubernetes 不直接调度容器,而是 Pod,Pod可以理解为容器的二次封装,可以由一个或者多个容器组成,多个容器共享同一个网络名称空间:NET、UTS、IPC。

同一个 POD 里的容器,还能共享同一个存储卷,存储卷可以属于 POD。

一般一个 POD 只运行一个容器,如果需要在POD放多个容器,那么一般有一个主容器,其他容器是为主容器提供服务的。

node(工作节点)
提供计算资源的节点,就是运行 Pod 的主机,Kubenetes Cluster 统一管理所有的 node 节点的计算资源,当用户请求创建资源的时候,可以检查目前集群还有没有资源可以运行用户的容器,这实现了统一调度统一管理的一个平台。

label(标签)
一个由 key = value 组成的标签,可以为 POD 打上一个标签。

selecter(标签选择器)
集群中运行的众多 POD ,前面提到一个控制器可以管理若干个 POD ,那么控制器如何从集群中运行的所有 POD 中挑选出来自己需要管理的 POD 呢?

在创建一个 POD 的时候为 POD 打上一个标签,让程序可以通过这个标签来识别出来这个POD,还可以用来区分一组相同功能的POD,例如:创建四个nginx pod,可以给每个pod加一个 K/V类型的标签如:app=nginx,将来找出这四个 nginx pod,那么条件就是根据 拥有 key 为 app 的pod 并且 value 为 nginx 来挑出这组 POD。

标签不是 POD 唯一具有的机制,其他的组件同样可以有标签。

1.4 架构和组件
etcd
用于 Kubernetes 的后端数据存储,所有集群数据都存储在此处
Master 节点负责维护集群的目标状态,上面运行的主控组件有
kube-apiserver # 对外暴露了 Kubernetes API,它是的 Kubernetes 前端控制层,只有 API Server 会与 etcd 通信,其它模块都必须通过 API Server 访问集群状态
kube-controller-manager # 处理集群中常规任务,它是单独的进程,内部包含多个控制器,例如维护 POD 数量
kube-scheduler # 监视新创建的 Pod 为新创建的 POD 分配合适的 node 节点
Node 节点实际负责实施,也就是运行 POD 的节点,上面运行的组件有
kubelet # 它监测已经分配给自己的 Pod,为 POD 准备卷,下载 POD 所需的 Secret,下载镜像并运行,进行生命周期探测,上报 POD 和节点状态
kube-proxy # 通过维护主机上的网络规则并执行连接转发,将 Kubernetes 提供的网络服务代理到每个节点上,实现了Kubernetes服务抽象
docker # 用于运行容器
插件
插件是增强集群功能的 Pod 和 Service,插件对象本身是受命名空间限制的,被创建于 kube-system 命名空间。
DNS
虽然其他插件并不是必需的,但所有 Kubernetes 集群都应该具有Cluster DNS,许多应用依赖于它,为 Kubernetes 服务提供DNS记录,容器启动该后会自动将 DNS 服务器包含在 resolv.conf 中。
二 核心组件/附件
2.1 Controller
这些控制器分别用于确保不同类型的 POD 资源运行于符合用户所期望的状态。

RelicationController
控制同一类 POD 对象的副本数量,实现程序的滚动更新,或者回滚的操作。

在滚动更新时候,允许临时超出规定的副本数量,

RelicaSet
副本集控制器,它不直接使用,它有一个声明式中心控制器 Deployment

Deployment
它只能管理无状态的应用,这个控制器,支持二级控制器,例如:HPA(Horizontal Pod Autoscaler,水平 POD 自动伸缩控制器),当负载高的时候,自动启动更多的 POD。

StatefulSet
管理有状态的应用

DaeminSet
如果需要在每一个 node 上运行一个副本,而不是随意运行

Job
运行作业,时间不固定的操作,例如:备份、清理,临时启动一个 POD 来进行备份的任务,运行完成就结束了。

如果运行时候 JOB 挂了,那么需要重新启动起来,如果运行完成了则不需要再启动了。

Cronjob
和周期性作业

2.2 Service
为客户端提供一个稳定的访问入口,Service 靠标签选择器来关联 POD 的,只要 POD 上有相关的标签,那么就会被 Service 选中,作为 Service 的后端,Service 关联 POD 后会动态探测这个 POD 的 IP 地址和端口,并作为自己调度的后端。

总的来说客户端请求 Service 由 Service 代理至后端的 POD,所以客户端看到的始终是 Service 的地址。

K8S 上的 Service 不是一个应用程序,也不是一个组件,它是一个 iptables dnat 规则,或者 ipvs 规则,Service 只是规则,所以是 ping 不通的,但是它的确可以请求。

Service 作为 k8s 的对象来说,是有名称的,可以通过 Service 的名称解析为 Service 的 IP 地址。

AddOns
解析域名是由 DNS 来解析的,为 k8s 中提供域名解析这种基础服务,称之为基础架构 POD 也称为 k8s 附件,所以域名解析的 POD 就是 k8s 中的一种 AddOns。

而 k8s 中的 dns 附件,是动态的,例如:service 名称发生更改,就会自动触发 dns 中的解析记录的改变,如果手动修改 service 的地址,也会自动触发 DNS 解析记录的改变,所以客户端访问服务时,可以直接访问服务的名称。

2.3 网络模型
k8s 有三种网络:POD网络、集群网络、节点网络

POD网络:所有 POD 处于同一个网络中
集群网络:Service 是一个另外一个网络
节点网络:node 节点也是另外一个网络
所以,接入外部访问时候,请求首先到达 node 网络,然后 node 网络代理至 service 网络,service 根据 ipvs 规则来转发到 pod 网络中的 pod 上。

k8s 有三种通信:

同一个 POD 内的多个容器间的通信,可以直接通过 lo 通信。

POD 与 POD 通信,所有 POD 都处于一个网络,可以跨 node 与另外的 POD 直接通信,因为使用了叠加网络。

POD 与 Service 通信。

2.4 kube-proxy
在 node 节点上运行的一个守护进程,它负责随时与 apiserver 进行通信,因为每个 pod 发生变化后需要保存在 apiserver 中,而 apiserver 发生改变后会生成一个通知事件,这个事件可以被任何关联的组件接收到,例如被 kube-proxy 一旦发现某个 service 后端的 pod 地址发生改变,那么就由 kube-proxy 负责在本地将地址写入 iptables 或者 ipvs 规则中。

所以 service 的管理是靠 kube-proxy 来实现的,当你创建一个 service ,那么就靠 kube-proxy 在每个节点上创建为 iptables 或者 ipvs 规则,每个 service 的变动也需要 kube-proxy 反应到规则上。

apiserver 需要保存各个 node 信息,它需要保存在 etcd 中。

2.5 etcd
是一个键值存储的系统,与 redis 很想,但是 etcd 还有一些协调功能是 redis 所不具备的,它还有节点选举等功能,从这个角度来讲 etcd 更像 zookpeer。

由于整个集群的所有信息都保存在 etcd,所以 etcd 如果宕机,那么整个集群就挂了,因而 etcd 需要做高可用。

2.6 flanel
托管为 k8s 的附件运行

node 网络:各节点之间进行通信

POD 网络:所有 node上的 POD 彼此之间通过叠加,或者直接路由方式通信

service 网络:由 kube-proxy 负责管控和生成

知识小结
Master
kube-scheduler # 调度 pod
kuber-controller-manager # 管理 pod
kube-apiserver # 接收请求
etcd # 集群状态存储,集群所有的组件的状态都保存在这里
node
kubelet #
kube-proxy #
docker # 容器引擎
三 集群部署
Kubeadm 是 K8S 官方提供的快速部署工具,它提供了 kubeadm init 以及 kubeadm join 这两个命令作为快速创建 kubernetes 集群的最佳实践,本章节说明了使用 kubeadm 来部署 K8S 集群的过程。

集群组织结构
项目 说明
集群规模 Master、node1、node2
网络规划 POD:10.244.0.0/16、Service:10.96.0.0/12
3.1 部署前准备
本小节的所有的操作,在所有的节点上进行

3.1.1 关闭 firewalld 和 selinux
setenforce 0
sed -i '/^SELINUX=/cSELINUX=disabled' /etc/selinux/config

systemctl stop firewalld
systemctl disable firewalld
3.1.2 加载 ipvs 内核模块
安装 IPVS 模块
yum -y install ipvsadm ipset sysstat conntrack libseccomp
设置开机加载配置文件
cat >>/etc/modules-load.d/ipvs.conf<<EOF
ip_vs_dh
ip_vs_ftp
ip_vs
ip_vs_lblc
ip_vs_lblcr
ip_vs_lc
ip_vs_nq
ip_vs_pe_sip
ip_vs_rr
ip_vs_sed
ip_vs_sh
ip_vs_wlc
ip_vs_wrr
nf_conntrack_ipv4
EOF
设置开机加载 IPVS 模块
systemctl enable systemd-modules-load.service # 设置开机加载内核模块
lsmod | grep -e ip_vs -e nf_conntrack_ipv4 # 重启后检查 ipvs 模块是否加载
如果集群已经部署在了 iptables 模式下,可以通过下面命令修改,修改 mode 为 ipvs 重启集群即可。
kubectl edit -n kube-system configmap kube-proxy
3.1.3 下载 Docker 和 K8S
设置 docker 源
curl -o /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/doc ... .repo
设置 k8s 源
cat >>/etc/yum.repos.d/kuberetes.repo<<EOF
[kuberneres]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kub ... 6_64/
gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kub ... y.gpg
enabled=1
EOF
安装 docker-ce 和 kubernetes
yum install docker-ce kubelet kubectl kubeadm -y
systemctl start docker

systemctl enable docker
systemctl enable kubelet
3.1.4 设置内核及 K8S 参数
设置内核参数
cat >>/etc/sysctl.conf<<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
设置 kubelet 忽略 swap,使用 ipvs
cat >/etc/sysconfig/kubelet<<EOF
KUBELET_EXTRA_ARGS="--fail-swap-on=false"
KUBE_PROXY_MODE=ipvs
EOF
3.2 部署 Master
本小节的所有的操作,只在 Master 节点上进行

3.2.1 提前拉取镜像
kubeadm init 在初始化的时候会到谷歌的 docker hub 拉取镜像,所以我们要提前做好翻墙的准备,需要在本机 9666 端口启动翻墙的软件。

配置 Docker 拉取镜像时候的代理地址,vim /usr/lib/systemd/system/docker.service。
[Service]
Environment="HTTPS_PROXY=127.0.0.1:9666"
Environment="NO_PROXY=127.0.0.0/8,172.16.0.0/16"
提前拉取初始化需要的镜像
kubeadm config images pull
使用其他源镜像
docker pull mirrorgooglecontainers/kube-apiserver:v1.14.2
docker pull mirrorgooglecontainers/kube-controller-manager:v1.14.2
docker pull mirrorgooglecontainers/kube-scheduler:v1.14.2
docker pull mirrorgooglecontainers/kube-proxy:v1.14.2
docker pull mirrorgooglecontainers/pause:3.1
docker pull mirrorgooglecontainers/etcd:3.3.10
docker pull coredns/coredns:1.3.1

利用kubeadm config images list 查看需要的docker image name

k8s.gcr.io/kube-apiserver:v1.14.2
k8s.gcr.io/kube-controller-manager:v1.14.2
k8s.gcr.io/kube-scheduler:v1.14.2
k8s.gcr.io/kube-proxy:v1.14.2
k8s.gcr.io/pause:3.1
k8s.gcr.io/etcd:3.3.10
k8s.gcr.io/coredns:1.3.1

修改tag:

docker tag docker.io/mirrorgooglecontainers/kube-apiserver:v1.14.2 k8s.gcr.io/kube-apiserver:v1.14.2
docker tag docker.io/mirrorgooglecontainers/kube-scheduler:v1.14.2 k8s.gcr.io/kube-scheduler:v1.14.2
docker tag docker.io/mirrorgooglecontainers/kube-proxy:v1.14.2 k8s.gcr.io/kube-proxy:v1.14.2
docker tag docker.io/mirrorgooglecontainers/kube-controller-manager:v1.14.2 k8s.gcr.io/kube-controller-manager:v1.14.2
docker tag docker.io/mirrorgooglecontainers/etcd:3.3.10 k8s.gcr.io/etcd:3.3.10
docker tag docker.io/mirrorgooglecontainers/pause:3.1 k8s.gcr.io/pause:3.1
docker tag docker.io/coredns/coredns:1.3.1 k8s.gcr.io/coredns:1.3.1

docker rmi docker images |grep docker.io/ |awk '{print $1&quot;:&quot;$2}'
3.2.2 初始化Master
使用 kubeadm 初始化 k8s 集群
kubeadm init --kubernetes-version=v1.14.0 --pod-network-cidr=10.244.0.0/16 --service-cidr=10.96.0.0/12 --ignore-preflight-errors=Swap
如果有报错使用下面命令查看
journalctl -xeu kubelet
如果初始化过程被中断可以使用下面命令来恢复
kubeadm reset
下面是最后执行成功显示的结果,需要保存这个执行结果,以让 node 节点加入集群
Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/con ... dons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 172.16.100.9:6443 --token 2dyd69.hrfsjkkxs4stim7n \
--discovery-token-ca-cert-hash sha256:4e30c1f41aefb177b708a404ccb7e818e31647c7dbdd2d42f6c5c9894b6f41e7
最好以普通用户的身份运行下面的命令
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
部署 flannel 网络插件
kubectl apply -f https://raw.githubusercontent. ... l.yml
查看 kube-system 命名空间中运行的 pods
kubectl get pods -n kube-system
查看 k8s 集群组件的状态
kubectl get ComponentStatus
3.3 部署 Node
本小节的所有的操作,只在 Node 节点上进行。

3.3.1 加入集群
加入集群,注意在命令尾部加上 --ignore-preflight-errors=Swap ,以忽略 k8s 对主机 swap 的检查(k8s为了性能所以要求进制 swap )
kubeadm join 172.16.100.9:6443 --token 2dyd69.hrfsjkkxs4stim7n \
--discovery-token-ca-cert-hash sha256:4e30c1f41aefb177b708a404ccb7e818e31647c7dbdd2d42f6c5c9894b6f41e7 --ignore-preflight-errors=Swap
返回结果,表示加入集群成功
This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
3.3.2 查看进度
当 node 节点加入 K8S 集群中后,Master 会调度到 Node 节点上一些组件,用于处理集群事务,这些组件没有下载完成之前 Node 节点在集群中还是未就绪状态

在 node 执行下面命令,可以查看镜像的下载进度,下面是最终结果显示
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
k8s.gcr.io/kube-proxy v1.14.0 5cd54e388aba 6 weeks ago 82.1MB
quay.io/coreos/flannel v0.11.0-amd64 ff281650a721 3 months ago 52.6MB
k8s.gcr.io/pause 3.1 da86e6ba6ca1 16 months ago 742kB
可以在 Master 上使用下面命令来查看新加入的节点状态
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready master 3d21h v1.14.1
node1 Ready <none> 3d21h v1.14.1
node2 Ready <none> 3d21h v1.14.1
拷贝到node节点
for i in /tmp/*.tar; do scp -i $i root@172.16.0.15:/root/;done

node节点还原
for i in *.tar ;do docker load -i $i;done
查看 kube-system 这个 k8s 命名空间中有哪些组件,分别运行在哪个节点,-o wide 是以详细方式显示。
$ kubectl get pods -n kube-system -o wide

NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
coredns-fb8b8dccf-cp24r 1/1 Running 0 26m 10.244.0.2 i-xeahpl98 <none> <none>
coredns-fb8b8dccf-ljswp 1/1 Running 0 26m 10.244.0.3 i-xeahpl98 <none> <none>
etcd-i-xeahpl98 1/1 Running 0 25m 172.16.100.9 i-xeahpl98 <none> <none>
kube-apiserver-i-xeahpl98 1/1 Running 0 25m 172.16.100.9 i-xeahpl98 <none> <none>
kube-controller-manager-i-xeahpl98 1/1 Running 0 25m 172.16.100.9 i-xeahpl98 <none> <none>
kube-flannel-ds-amd64-crft8 1/1 Running 3 16m 172.16.100.6 i-me87b6gw <none> <none>
kube-flannel-ds-amd64-nckw4 1/1 Running 0 6m41s 172.16.100.10 i-qhcc2owe <none> <none>
kube-flannel-ds-amd64-zb7sg 1/1 Running 0 23m 172.16.100.9 i-xeahpl98 <none> <none>
kube-proxy-7kjkf 1/1 Running 0 6m41s 172.16.100.10 i-qhcc2owe <none> <none>
kube-proxy-c5xs2 1/1 Running 2 16m 172.16.100.6 i-me87b6gw <none> <none>
kube-proxy-rdzq2 1/1 Running 0 26m 172.16.100.9 i-xeahpl98 <none> <none>
kube-scheduler-i-xeahpl98 1/1 Running 0 25m 172.16.100.9 i-xeahpl98 <none> <none>
3.3.3 下载太慢
node 节点需要翻墙下载镜像太慢,建议使用 docker 镜像的导入导出功能 先将master的三个镜像打包发送到node节点,load后再jion

导出
docker image save -o /tmp/kube-proxy.tar k8s.gcr.io/kube-proxy
docker image save -o /tmp/flannel.tar quay.io/coreos/flannel
docker image save -o /tmp/pause.tar k8s.gcr.io/pause
导入
docker image load -i /tmp/kube-proxy.tar
docker image load -i /tmp/pause.tar
docker image load -i /tmp/flannel.tar
四 入门命令
4.1 kubectl
kubectl 是 apiserver 的客户端程序,这个客户端程序是通过连接 master 节点上的 apiserver ,实现各种 k8s 对象的增删改查等基本操作,在 k8s 可被管理的对象有很多个

基本命令 (初级):
create 从文件或标准输入创建资源
expose 获取一个复制控制器,服务,部署或者暴露一个 POD 将其作为新的 Kubernetes 服务公开
run 创建并运行特定的镜像,创建使用 deployment 或 job 管理的容器
set 设置对象的特定功能

基本命令 (中级):
explain 文档或者资源
get 显示一个或多个资源
edit 编辑服务器上的资源
delete 按文件名,标准输入,资源和名称或资源和标签选择器删除资源

部署命令:
rollout 管理资源的部署
scale 为部署设置新大小,ReplicaSet, Replication Controller, Job
autoscale 自动扩展一个部署, ReplicaSet, 或者 ReplicationController

群集管理命令:
certificate 修改证书资源.
cluster-info 显示群集信息
top 显示资源(CPU /内存/存储)使用情况。
cordon 将节点标记为不可调度
uncordon 将节点标记为可调度
drain 设定 node 进入维护模式
taint 更新一个或多个节点上的污点

故障排除和调试命令:
describe 显示特定资源或资源组的详细信息
logs 在容器中打印容器的日志
attach 附加到正在运行的容器
exec 在容器中执行命令
port-forward 将一个或多个本地端口转发到 pod
proxy 运行代理到 Kubernetes API 服务器
cp 将文件和目录复制到容器,和从容器复制,跨容器复制文件
auth 检查授权

高级命令:
diff 针对将要应用的版本的 Diff 实时版本
apply 通过文件名或标准输入将配置应用于资源
patch 使用策略合并补丁更新资源的字段
replace 用文件名或标准输入替换资源
wait 实验阶段命令:在一个或多个资源上等待特定条件,定义一个触发器
convert 在不同的API版本之间转换配置文件
kustomize 从目录或远程 URL 构建 kustomization 目标

设置命令:
label 更新资源上的标签
annotate 更新资源上的注释
completion 命令补全相关功能

其他命令:
api-resources 在服务器上打印支持的API资源
api-versions 以 "group/version" 的形式在服务器上打印支持的API版本
config 修改 kubeconfig 文件
plugin 提供与插件交互的实用程序
version 打印客户端和服务器版本信息
4.2 run
创建控制器并运行镜像
kubectl run nginx --image=nginx:latest # 创建一个名为 nginx 的控制器,运行 nginx:latest 版本的镜像
指定运行的 POD 数量
kubectl run nginx --image=nginx --replicas=5 # 启动 5 个 POD
不运行容器的默认命令,使用自定义的指令
kubectl run nginx --image=nginx --command -- <cmd> <arg1> ... <argN>
运行一个周期任务
kubectl run pi --schedule="0/5 * * * ?" --image=perl --restart=OnFailure -- perl -Mbignum=bpi -wle 'print bpi(2000)'
指定控制器名称运行 nginx 指定端口和副本数量,以测试模式运行
kubectl run nginx-deploy --image=nginx --port=80 --replicas=1 --dry-run=true
查看容器是否运行
kubectl get deployment
查看被调度的主机
kubectl get pod -o wide
通过 ip 地址直接访问,由于所有的 POD 处于同一个网络中,所以在集群内部是可以访问的
curl 10.244.2.2
假如现在删除刚创建的这个 POD,那么副本控制器会自动在其他的 node 上重建这个 POD
kubectl delete pods nginx-deploy-5c9b546997-jsmk6
再次执行查看,会发现容器已经被调度到其他节点上运行了
kubectl get pod -o wide
4.3 expose
现在存在一个问题,就是 POD 的 IP 地址可能随时发生变动,所以不能作为访问的入口,那么就需要 service 来代理 POD 来创建一个固定的端点。

创建一个 service 暴露一个服务
kubectl expose deployment nginx-deploy --name=nginx --port=80 --target-port=80 --protocol=TCP
在控制器 nginx-deploy 上创建名字为 nginx 的 service ,它工作端口为 80,代理的后端容器端口 80,协议为 TCP。
可以看到刚刚创建的名字为 nginx 的 service ,现在就可以在集群内用 service 的地址来访问了,外部不行
kubectl get service
删除一个任务
kubectl delete deployment nginx-deploy
4.4 cp
拷贝宿主机文件或目录到pod中,⚠️要求tar二进制文件已经存在容器中,不然拷贝会失败
kubectl cp /tmp/foo_dir <some-pod>:/tmp/bar_dir

[root@master ~]# kubectl cp flannel.tar nginx-58cd4d4f44-8pwb7:/usr/share/nginx/html
[root@master ~]# kubectl cp mainfile/ nginx-58cd4d4f44-8pwb7:/usr/share/nginx/html
[root@master ~]# kubectl exec -it nginx-58cd4d4f44-8pwb7 -- /bin/bash
root@nginx-58cd4d4f44-8pwb7:/# ls -l /usr/share/nginx/html/
total 54108
-rw-r--r-- 1 root root 537 Jul 11 2017 50x.html
-rw-r--r-- 1 root root 355 May 27 06:47 dashboard-adminuser.yaml
-rw------- 1 root root 55390720 May 27 01:49 flannel.tar
-rw-r--r-- 1 root root 612 Jul 11 2017 index.html
drwxr-xr-x 4 root root 51 Aug 17 14:16 mainfile
4.5 port-forward
端口转发,将svc地址或着pods端口利用kubelet映射到宿主机上,将访问宿主机的8888端口的所有流量转发到8111svc
kubectl port-forward --address 0.0.0.0 service/nginx 8888 8111
转发pods端口,将访问宿主机的8888端口流量转发到pod的5000端口
kubectl port-forward pod/mypod 8888:5000
4.6 coredns
service 提供了对 pod 的固定访问端点,但是 service 本身的变动我们无法知晓,需要 coredns 对 service 做域名解析。

查看 coredns 运行状态
kubectl get pods -n kube-system -o wide
查看各个 kube-system 命名空间运行的服务,可以看到 kube-dns 运行的 IP 地址
kubectl get service -n kube-system
使用 kube-dns 来解析 nginx 这个 service 的地址就可以正常解析了
dig -t A nginx.default.svc.cluster.local @10.96.0.10
创建一个访问 nginx 客户端容器,并进入交互式模式,这个容器默认的 dns 服务器就是 kube-dns 所在的服务器
kubectl run client --image=busybox --replicas=1 -it --restart=Never
/ # cat /etc/resolv.conf
nameserver 10.96.0.10 # kube-dns 地址
search default.svc.cluster.local svc.cluster.local cluster.local # 默认的解析搜索域
options ndots:5
在 busybox 这个容器中请求 nginx 这个域名的 service ,能够正常访问
wget -O - -q http://nginx:80/
4.7模拟 POD 被删除
现在我们删除 service 后端的 POD ,副本控制器会自动创建新的 POD,而 service 则会自动指向新创建的 POD
kubectl delete pods nginx-deploy-5c9b546997-4w24n
查看由副本控制器自动创建的 POD
kubectl get pods
在 busybox 这个容器中请求 nginx 这个域名的 service ,访问没有受到影响
wget -O - -q http://nginx:80/
4.8 模拟 service 被删除
当我们删除 service 并且重新建立一个 service 再次查看 service 的地址已经发生变化了
kubectl delete service nginx
kubectl expose deployment nginx-deploy --name=nginx --port=80 --target-port=80 --protocol=TCP
kubectl get service
在 busybox 这个容器中请求 nginx 这个域名的 service ,访问没有仍然没有受到影响
wget -O - -q http://nginx:80/
4.9 labels
为什么 Pod 被删除后,servic 仍然能够正确的调度到新的 POD 上,这就是 k8s 的 labels 这个机制来保证的。

能够使用标签机制不止有 pod、在 k8s 中很多对象都可以使用标签,例如:node、service

查看 service 的详细信息,会发现标签选择器
kubectl describe service nginx
Name: nginx
Namespace: default
Labels: run=nginx-deploy
Annotations: <none>
Selector: run=nginx-deploy # 这个选择器会自动选中 run 标签,且值为 nginx-deploy 的 POD
Type: ClusterIP
IP: 10.101.149.4
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.2.4:80 # 当 service 的后端,当 POD 发生变动则立即会更新
Session Affinity: None
Events: <none>
查看 POD 的标签,会看到拥有 run=nginx-deploy 标签的容器,而人为删除一个 POD 后,副本控制器创建的副本上的标签不会变化,所以标签又被 service 关联。
kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
client 1/1 Running 0 21m run=client
nginx-deploy-5c9b546997-kh88w 1/1 Running 0 8m37s pod-template-hash=5c9b546997,run=nginx-deploy
查看 POD 的详细信息,也可以查看到 POD 的详细信息
kubectl describe deployment nginx-deploy
根据标签过滤,使用 -l 来指定标签名称或同时过滤其值
kubectl get pods --show-labels -l run=nginx-deploy
标签选择器集中运算
关系与:KEY,KEY、KEY=VALUE2,KEY=VALUE2 # -l run,app
等值关系:KEY = VALUE、KEY != VALUE # -l run=nginx-deploy,app!=myapp
集合关系:KYE in|not in (VALUE1,VALUE2) # -l "release in (canary,bata,alpha)"

显示指定的标签的值,下面显示了两个标签
kubectl get pods --show-labels -L run,pod-template-hash
为指定的 POD 打标签,为 client 这个 POD 打上一个 release 标签,其值为 canary
kubectl label pods client release=canary
修改 POD 的标签,使用 --overwrite 进行修改原有标签
kubectl label pods client release=stable --overwrite
删除指定的 nodes 上的标签,使用标签名称加 - 符号
kubectl label nodes node2 disktype-
许多资源支持内嵌字段来定义其使用的标签选择器,例如 service 关联 pod 时候:
matchLabels:直接给定键值
matchExpressions:基于给定的表达式来定义使用标签选择器:{key:"KEY",operator:"OPERATOR",value:[VAL1,VAL2,...]}
使用 key 与 value 进行 operator 运算,复合条件的才被选择
操作符:
In、NotIn:其 value 列表必须有值
Exists、NotExists:其 value 必须为空
k8s 中很多对象都可以打标签,例如给 nodes 打一个标记,随后在添加资源时候就可以让资源对节点有倾向性了
kubectl label nodes node2 disktype=ssd
kubectl get nodes --show-labels
4.10 动态扩容
扩容一个集群的的 POD,下面命令表示修改 deployment 控制器下的 nginx-deply 容器的副本数量为2
kubectl scale --replicas=5 deployment nginx-deploy
4.11 滚动升级
更换 nginx-deploy 这个控制器下的 nginx-deploy 容器镜像为 ikubernetes/myapp:v2
kubectl set image deployment nginx-deploy nginx-deploy=ikubernetes/myapp:v2
查看更新的过程,直到 5 个容器中运行的镜像全部更新完
kubectl rollout status deployment nginx-deploy
[root@node1 ~]# kubectl rollout status deployment nginx-deploy
Waiting for deployment "nginx-deploy" rollout to finish: 3 out of 5 new replicas have been updated...
Waiting for deployment "nginx-deploy" rollout to finish: 3 out of 5 new replicas have been updated...
Waiting for deployment "nginx-deploy" rollout to finish: 3 out of 5 new replicas have been updated...
Waiting for deployment "nginx-deploy" rollout to finish: 3 out of 5 new replicas have been updated...
Waiting for deployment "nginx-deploy" rollout to finish: 3 out of 5 new replicas have been updated...
Waiting for deployment "nginx-deploy" rollout to finish: 4 out of 5 new replicas have been updated...
Waiting for deployment "nginx-deploy" rollout to finish: 4 out of 5 new replicas have been updated...
Waiting for deployment "nginx-deploy" rollout to finish: 4 out of 5 new replicas have been updated...
Waiting for deployment "nginx-deploy" rollout to finish: 4 out of 5 new replicas have been updated...
Waiting for deployment "nginx-deploy" rollout to finish: 4 out of 5 new replicas have been updated...
Waiting for deployment "nginx-deploy" rollout to finish: 2 old replicas are pending termination...
Waiting for deployment "nginx-deploy" rollout to finish: 2 old replicas are pending termination...
Waiting for deployment "nginx-deploy" rollout to finish: 2 old replicas are pending termination...
Waiting for deployment "nginx-deploy" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "nginx-deploy" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "nginx-deploy" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "nginx-deploy" rollout to finish: 4 of 5 updated replicas are available...
deployment "nginx-deploy" successfully rolled out
回滚操作,不指定任何的镜像则为上一个版本的镜像
kubectl rollout undo deployment nginx-deploy
如果防止更新过程中被调度,那么就需要学习就绪性检测才能实现

4.12 集群外访问
修改 service 的网络类型为 NodePort
kubectl edit service nginx
type: ClusterIP -> type: NodePort
查看 service 的信息,发现多了一个 30982 端口
kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 15h
nginx NodePort 10.105.27.11 <none> 80:30982/TCP 42m
在集群外部使用任意的 node IP 地址 + 端口来访问
http://172.16.100.101:30982/
4.13 排查日志
查看一个 pod 的某个容器的运行日志
kubectl logs pod-demo busybox
4.14 连入 POD 容器
kubectl exec -it pod-demo -c myapp -- /bin/sh
五 配置清单使用
apiserver 仅接收 json 格式的资源定义,yaml 格式定义提供的配置清单,apiserver 可自动将其转换为 json 格式,而后再进行执行。

5.1 可配置的对象
可用资源清单配置的对象
workload:Pod、ReplicaSet、Deployment、StatefulSet、DaemonSet、Job、CronJob
服务发现及均衡:Service、Ingress
配置与存储:Volume、CSI
ConfigMap、Secret
DownwardAPI
集群级资源
Namespace、None、Role、ClusterRole、RoleBinding、ClusterRoleBinding
元数据类型资源
HPA、PodTemplate、LimitRange
5.2 配置清单组成
配置清单组成部分,大部分资源使用配置清单方式来创建
apiVersion
# 以 "group/version" 形式指明,这个对象属于哪个 API 组(版本)
kind:
# 资源类别,标记创建什么类型的资源
metadata:
# 元数据内部是嵌套的字段
# 定义了资源对象的名称、命名空间(k8s级别的不是系统的)等、标签、注解等
spec:
# 规范定义资源应该拥有什么样的特性,依靠控制器确保特性能够被满足
# 它是用户定义的所期望了资源状态
status:
# 显示资源的当前状态,k8s 就是确保当前状态向目标状态无限靠近从而满足用户期望
# 它是只读的,代表了资源当前状态
获取全部的 api 版本
kubectl api-versions
5.3 获取清单帮助
查看 k8s 某个内置对象的配置清单格式,应该包含哪些字段,使用 . 来显示字段的格式帮助信息
kubectl explain pods
kubectl explain pods.metadata
5.4 清单基本格式
定义一个资源清单
apiVersion: v1
kind: Pod
metadata:
name: pod-deme
namespace: default
labels:
app: myapp
tier: frontend
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
- name: busybox
image: busybox:latest
command:
- "/bin/sh"
- "-c"
- "sleep 10"
5.5 快捷获取清单
使用 -o 参数来指定对象数据的输出格式,使用 --dry-run 来测试性执行一个指令,它两个结合起来,就可以通过命令创建,且生成 yaml 格式配置文件了 -o yaml --dry-run
kubectl create secret docker-registry regsecret --docker-server=registry-vpc.cn-hangzhou.aliyuncs.com --docker-username=admin --docker-password=123456 --docker-email=420123641@qq.com -o yaml --dry-run
5.6 create 创建
创建资源清单中的资源,这样创建的为裸 POD ,没有控制器管理,所以删除后不会自动重建
kubectl create -f pod-demo.yaml
5.7 delete 删除
删除资源清单中定义的 POD
kubectl delete -f pod-demo.yaml
5.8 applay 创建或更新
applay 可以执行多次,如果发现文件不同,则更新

kubectl applay -f pod-demo.yaml
六 POD 配置清单
6.1 pods.metadata POD元数据
6.1.1 labels 标签
labels 定义标签,键值对组成的标签
labels:
app: myapp
tier: frontend
6.2 pods.spec 规范
6.2.1 nodeName 运行节点
在使用资源清单定义 pod 时候,使用 nodeName 可以直接绑定资源对象在哪个 POD 运行的节点
apiVersion: v1
kind: Pod
metadata:
name: pod-deme
namespace: default
labels:
app: myapp
tier: frontend
spec:
nodeName: node2 # 直接指定 POD 运行的节点
containers:
- name: myapp
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
6.2.2 nodeSelector 节点选择
在使用资源清单定义 pod 时候,使用 nodeSelector (节点标签选择器)字段,来定义节点的倾向性
apiVersion: v1
kind: Pod
metadata:
name: pod-deme
namespace: default
labels:
app: myapp
tier: frontend
spec:
nodeSelector: # 在 spec 中定义这个 POD 的节点倾向性
disktype: ssd # 这个 POD 最终会运行在拥有 disktype 标签且值为 ssd 的 nodes 上
containers:
- name: myapp
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
ports:
从文件启动 pod,观察 pod 运行的节点,会发现已经运行在有标签的 node 节点上了
kubectl create -f pod-demo.yaml
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-demo 1/1 Running 0 21s 10.244.2.29 node3 <none> <none>
6.2.3 restartPolicy POD重启策略
Always:一旦容器挂了,那么总是重启它,k8s 每次重启策略为 30 秒的两倍,直到等待 300 秒重启。

OnFailure:只有其状态为错误的时候才去重启它

Never:从来不重启,挂了就挂了

一旦某个 POD 被调度到某个节点上,只要这个节点在,那么它就不会被重新调度,只能被重启,除非 POD 被删除才会被重新调度,或者 node 挂了,才会被重新调度,否则只要 node 在,那么 POD 就不会被重新调度,如果 POD 启动失败,那么将不断的重启 POD。
当需要终止 POD ,k8s 发送 kill -15 信号,让容器平滑的终止,等待 30 秒的宽限期,如果没有终止,那么则发送 kill 信号
6.2.4 hostNetwork 主机网络空间
使用布尔值指定是否让 POD 使用主机的网络名称空间

6.2.5 hostPID 主机PID空间
使用布尔值指定是否让 POD 使用主机的PID名称空间

6.2.6 containers 配置
kubectl explain pods.spec.containers

描述 POD 内所运行容器,语法:containers <[]Object>,表示它的值为数组,数组内使用对象的方式来描述一个容器,对象可以有以下参数:

可用参数
参数 作用
args

command
env 向容器传递环境变量
envFrom
image

imagePullPolicy
lifecycle

livenessProbe

name

ports

readinessProbe

resources

securityContext
stdin

stdinOnce

terminationMessagePath

terminationMessagePolicy

tty
volumeDevices

volumeMounts

workingDir

示例型配置
apiVersion: v1
kind: Pod
metadata:
name: pod-deme # pod 的名称
namespace: default
labels:
app: myapp
tier: frontend
spec:
containers:
- name: myapp # 运行的容器名称
image: ikubernetes/myapp:v1 # 容器的镜像
imagePullPolicy: IfNotPresent # 从仓库获取镜像的策略
ports: # 定义容器暴漏的端口
- name: busybox
image: busybox:latest
command:
- "/bin/sh"
- "-c"
- "sleep 10"
6.2.6.1 imagePullPolicy下载策略
imagePullPolicy 镜像获取的策略,详见:kubectl explain pods.spec.containers
Always # 总是从仓库下载
Never # 从不下载,本地有就用,没有就失败
IfNotPresent # 如果本地存在就直接使用,如果不存在就下载
如果标签是 latest 那么则始终从仓库下载

6.2.6.2 ports 端口信息
ports 定义容器保暴露的,详见:kubectl explain pods.spec.containers.ports
在此处暴露的端口可为系统提供有关容器的网络连接的信息,但主要是信息性的,此处没有指定的端口也不会阻止容器暴露该端口,容器中任何侦听 0.0.0.0 地址的端口都可以从网络访问

ports: # 定义两个端口对象一个 http 一个 https
- name: http # 定义这个端口的名称,方便别的对象取引用
containerPort: 80 # 端口号
- name: https # 方便引用的名称
containerPort: 443 # 这个端口号仅仅是起到信息的作用,方便查看和使用名称引用
6.2.6.3 env 传递环境变量
在容器中获取 POD 的信息

可以使用环境变量
可以使用 downwardAPI
https://kubernetes.io/zh/docs/ ... tion/
6.2.6.4 command ENTRYPOINT
command 定义容器运行的程序,详见:
一个 entrypoint array 而 command 启动的程序是不会运行在 Shell 中的,如果想要运行在 Shell 中需要自己填写,如果没有提供这个指令,那么将运行 docker 镜像中的 ENTRYPOINT。

6.2.6.5 args CMD
args 向 command 传递参数的
如果你没有定义 args 而镜像中又存在 ENTRYPOINT 指令和 CMD 指令,那么镜像自己的 CMD 将作为参数传递给 ENTRYPOINT。如果手动指定了 args 那么镜像中的 CMD 字段不再作为参数进行传递。

如果在 args 中引用了变量,则需要使用 $(VAR_NAME) 来引用一个变量,如果不想在这里进行命令替换,那么可以 $$(VAR_NAME),转义后在容器内使用。

6.2.6.6 annotations 注解信息
annotations 与 label 不同的地方在于,它不能用于挑选资源对象,仅为对象提供元数据,它的长度不受限制

apiVersion: v1
kind: Pod
metadata:
name: pod-deme
namespace: default
labels:
app: myapp
tier: frontend
annotations: # 注解关键字
kaliarch/created-by: "xuel" # 添加键值对的资源注解
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
6.2.6.7 POD 生命周期
一般状态
Pending:已经创建但是没有适合运行它的节点,已经调度,但是尚未完成
Running:运行状态
Failed: 启动失败
Succeed:成功,这个状态很短
Unkown: 未知的状态,如果 Apiserver 与 kubelet 通信失败则会处于这个状态
创建 POD 阶段
用户的创建请求提交给 apiserver ,而 apiserver 会将请求的目标状态保存在 etcd 中,而后 apiserver 会请求 schedule 进行调度,并且把调度的结果更新在 etcd 的 pod 状态中,随后一旦保存在 etcd 中,并完成 schedule 更新后目标节点的 kubelet 就会从 etcd 的状态变化得知有新任务给自己,所以此时会拿到用户所希望的资源清单目标状态,根据清单在当前节点运行这个 POD,如果创建成功或者失败,则将结果发回给 apiserver ,apiserver 再次保存在 etcd 中。

6.2.6.8 livenessProbe 存活性探测
详细见:kubectl explain pods.spec.containers.livenessProbe

livenessProbe / readinessProbe 是 k8s 两个生命周期,这两个生命周期都可以定义探针来探测容器状态做出不同反应
livenessProbe # 指示容器是否正在运行。如果存活探测失败,则依据 restartPolicy 策略来进行重启
readinessProbe # 指示容器是否准备好服务请求。如果就绪探测失败端点控制器将从与 Pod 匹配的所有 Service 的端点中删除该 Pod 的 IP 地址
livenessProbe / readinessProbe 可用的探针和探针特性,探针只能定义一种类型,例如:HTTPGetAction
exec # 在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。
tcpSocket # 对指定端口上的容器的 IP 地址进行 TCP 检查。如果端口打开,则诊断被认为是成功的。
httpGet # HTTP GET 请求指定端口和路径上的容器。如果响应码大于等于200 且小于 400,则诊断被认为是成功的。
failureThreshold # 探测几次才判定为探测失败,默认为 3 次。
periodSeconds # 每次探测周期的间隔时长。
timeoutSeconds # 每次探测发出后等待结果的超时时间,默认为 1 秒。
initalDelaySeconds # 在容器启动后延迟多久去进行探测,默认为启动容器后立即探测。
使用 exec 探针,实验结果应该为 39 秒后 POD 显示 ERROR ,但不自动重启 POD
apiVersion: v1
kind: Pod
metadata:
name: execlive
namespace: default
labels:
app: myapp
tier: frontend
spec:
containers:
- name: busybox
image: busybox
command:
- "/bin/sh"
- "-c"
- "touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 3600" # 创建一个文件等待 30 秒,这个时间探针应该是成功的,30 秒后则失败
livenessProbe: # 容器的存活性检测,如果失败则按照 restartPolicy 策略来重启 POD
exec: # exec 类型探针,进入容器执行一条命令
command: ["test", "-e" ,"/tmp/healthy"] # 执行的命令为测试文件存在性
initialDelaySeconds: 2 # 容器启动后延迟多久进行探测
periodSeconds: 3 # 每次探测周期的间隔时长为 3 秒
failureThreshold: 3 # 3 次失败后则判定为容器探测存活性失败
restartPolicy: Never # 当探测到容器失败是否重启 POD
使用 httpGet 探针,实验结果应该大约 40 秒后探测存活性失败,自动重启 POD,第一次重启会立即进行,随后是 30 秒的2倍直到 300 秒。
apiVersion: v1
kind: Pod
metadata:
name: httpgetlive
namespace: default
labels:
app: myapp
tier: frontend
spec:
containers:
- name: nginx
image: ikubernetes/myapp:v1
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
livenessProbe: # 容器的存活性检测,如果失败则按照 restartPolicy 策略来重启 POD
httpGet: # httpget 探针
path: /error.html # 探测的页面,为了效果这个页面不存在
port: http # 探测的端口,使用名称引用容器的端口
httpHeaders: # httpget 时候设置请求头
- name: X-Custom-Header
value: Awesome
initialDelaySeconds: 15 # 容器启动后延迟多久进行探测
timeoutSeconds: 1 # 每次探测发出等待结果的时长
restartPolicy: Always # 当探测到容器失败是否重启 POD
6.2.6.9 readinessProbe 就绪性检测
例如有一个容器运行的是 tomcat ,而 tomcat 展开 war 包,部署完成的时间可能较长,而默认 k8s 会在容器启动就标记为 read 状态,接收 service 的调度请求,但是容器启动不代表 tomcat 已经成功运行,所以需要 readinessProbe 进行就绪性探测,来决定是否可以接入 service 上。

livenessProbe / readinessProbe 可用的探针和探针特性基本一样,探针只能定义一种类型,例如:HTTPGetAction
livenessProbe # 指示容器是否正在运行。如果存活探测失败,则依据 restartPolicy 策略来进行重启
readinessProbe # 指示容器是否准备好服务请求。如果就绪探测失败端点控制器将从与 Pod 匹配的所有 Service 的端点中删除该 Pod 的 IP 地址
使用 httpGet 探针,实验结果应该大约 40 秒后探测存活性失败,自动重启 POD,第一次重启会立即进行,随后是 30 秒的2倍直到 300 秒。
apiVersion: v1
kind: Pod
metadata:
name: httpgetread
namespace: default
labels:
app: myapp
tier: frontend
spec:
containers:
- name: nginx
image: ikubernetes/myapp:v1
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
livenessProbe: # 容器的存活性检测,如果失败则按照 restartPolicy 策略来重启 POD
httpGet: # httpget 探针
path: /error.html # 探测的页面,为了效果这个页面不存在
port: http # 探测的端口,使用名称引用容器的端口
httpHeaders: # httpget 时候设置请求头
- name: X-Custom-Header
value: Awesome
initialDelaySeconds: 15 # 容器启动后延迟多久进行探测
timeoutSeconds: 1 # 每次探测发出等待结果的时长
restartPolicy: Always # 当探测到容器失败是否重启 POD
手动进入容器,删除 index.html 以触发就绪性探针的检测
kubectl exec -it httpgetread -- /bin/sh
$ rm -f /usr/share/nginx/html/index.html
结果这个 POD 的 READY 状态已经变成非就绪了,此时 service 不会再调度到这个节点了
[root@node1 ~]# kubectl get pods -w
NAME READY STATUS RESTARTS AGE
httpgetread 0/1 Running 0 2m50s
在容器内再创建一个文件,以触发就绪性探针的检测
kubectl exec -it httpgetread -- /bin/sh
$ echo "hello worlld" >>/usr/share/nginx/html/index.html
结果这个 POD 的的 READY 状态已经编程就绪了,此时 service 会调度到这个节点了
[root@node1 ~]# kubectl get pods -w
NAME READY STATUS RESTARTS AGE
httpgetread 1/1 Running 0 8m15s
6.2.6.10 lifecycle 生命周期钩子
详见:kubectl explain pods.spec.containers.lifecycle

postStart # 在容器启动后立即执行的命令,如果这个操作失败了,那么容器会终止,且根据 restartPolicy 来决定是否重启
preStop # 在容器终止前立即执行的命令
postStart / preStop 的基本使用
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
- name: lifecycle-demo-container
image: nginx

lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
preStop:
exec:
command: ["/usr/sbin/nginx","-s","quit"]
POD控制器

控制器管理的 POD 可以实现,自动维护 POD 副本数量,它能实现 POD 的扩容和缩容,但是不能实现滚的那个更新等高级功能。

名称 作用
ReplicationController 原来 k8s 只有这一种控制器,目前已经接近废弃
ReplicaSet 代用户创建指定数量的 POD 副本,还支持扩缩容,被称为新一代的 ReplicationController。主要由 3 个指标,1. 用户希望的 POD 副本,2. 标签选择器,判定 POD 是否归自己管理,3. 如果 POD 副本不够,按照哪个 POD template 创建 POD,但一般我们不直接使用 ReplicaSet。
Deployment Deployment 通过控制 ReplicaSet 来实现功能,除了支持 ReplicaSet 的扩缩容意外,还支持滚动更新和回滚等,还提供了声明式的配置,这个是我们日常使用最多的控制器。它是用来管理无状态的应用。
DaemonSet 用于确保集群内的每个 node 上只运行一个指定的 POD,如果有新增的节点也都会自动运行这个 POD,所以这个控制器无需定义 POD 运行的数量,只需要定义标签选择器和 POD template。所以可以跟根据标签选择器选中的 node 上只运行一个 POD 副本。
Job 执行一个一次性任务,例如数据库备份,任务完成后正常退出,则 POD 不会再被启动了,除非任务异常终止。
CronJob 执行一些周期性任务
StatefulSet 管理有状态的 POD ,但是对每个不同的有状态应用需要自行编写脚本,完成对有状态服务的管理,为了解决 StatefulSet 不方便编写有状态应用管理的问题。k8s 还提供了 helm 这样类似于 yum 的方式,方便用户从 helm 市场来安装一个有状态的应用。
七 控制器配置清单
7.1 ReplicaSet 控制器
详见:kubectl explain replicaset

清单规范
apiVersion <string> # api 版本号,一般为 apps/v1
kind <string> # 资源类别,标记创建什么类型的资源
metadata <Object> # POD 元数据
spec <Object> # 元数据
7.1.1 replicaset.spec 规范
replicas 副本数量,指定一个数字

selector 标签选择器,可以使用 matchLabels、matchExpressions 两种类型的选择器来选中目标 POD

matchLabels:直接给定键值
matchExpressions:基于给定的表达式来定义使用标签选择器:{key:"KEY",operator:"OPERATOR",value:[VAL1,VAL2,...]}
使用 key 与 value 进行 operator 运算,复合条件的才被选择
操作符:
In、NotIn:其 value 列表必须有值
Exists、NotExists:其 value 必须为空
template 模板,这里面定义的就是一个 POD 对象,这个对象只包含了 pod.metadata 和 pod.spec 两部分。
7.1.2 清单示例
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: myrs
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: myapp
release: canary
template:
metadata:
name: myapp-pod # 这个其实没用,因为创建的 POD 以 rs 的名字开头
labels:
app: myapp # 标签一定要符合 replicaset 标签选择器的规则,否则将陷入创建 pod 的死循环,直到资源耗尽
release: canary
spec:
containers:
- name: myapp-containers
image: ikubernetes/myapp:v1
ports:
- name: http
containerPort: 80
7.2 Deployment控制器
Deployment 通过控制 ReplicaSet 来实现功能,除了支持 ReplicaSet 的扩缩容意外,还支持滚动更新和回滚等,还提供了声明式的配置,这个是我们日常使用最多的控制器。它是用来管理无状态的应用。

Deployment 在滚动更新时候,通过控制多个 ReplicaSet 来实现,ReplicaSet 又控制多个 POD,多个 ReplicaSet 相当于多个应用的版本。

graph TB
Deployment[Deployment] --> replicaset1(replicaset1)
Deployment[Deployment] --> replicaset2(replicaset2)
Deployment[Deployment] --> replicaset3(replicaset3)
replicaset1(replicaset1) --> POD1{POD}
replicaset1(replicaset1) --> POD2{POD}
replicaset2(replicaset1) --> POD5{POD}
replicaset2(replicaset1) --> POD6{POD}
replicaset3(replicaset1) --> POD9{POD}
replicaset3(replicaset1) --> POD10{POD}
清单规范,详见:kubectl explain deployment
apiVersion <string> # apps/v1

kind <string> # 资源类别,标记创建什么类型的资源

metadata <Object> # POD 元数据

spec <Object> # 元数据
7.2.1 replicaset.spec 对象规范
replicas 副本数量,指定一个数字

selector 标签选择器,可以使用 matchLabels、matchExpressions 两种类型的选择器来选中目标 POD

matchLabels:直接给定键值
matchExpressions:基于给定的表达式来定义使用标签选择器:{key:"KEY",operator:"OPERATOR",value:[VAL1,VAL2,...]}
使用 key 与 value 进行 operator 运算,复合条件的才被选择
操作符:
In、NotIn:其 value 列表必须有值
Exists、NotExists:其 value 必须为空
template 模板,这里面定义的就是一个 POD 对象,这个对象只包含了 pod.metadata 和 pod.spec 两部分。

strategy 更新策略,支持滚动更新、支持滚动更新的更新方式

type: # 更新类型,Recreate 滚动更新,RollingUpdate 滚动更新策略
rollingUpdate: # 滚动更新时候的策略,这是默认的更新策略
maxSurge: # 滚动更新时候允许临时超出多少个,可以指定数量或者百分比,默认 25%
maxUnavailable: # 最多允许多少个 POD 不可用,默认 25%
revisionHistoryLimit 滚动更新后最多保存多少个更新的历史版本,值为一个数字

paused 当更新启动后控制是否暂停

7.2.2 清单示例
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deploy
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: myapp
release: canary
template:
metadata:
labels:
app: myapp
release: canary
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
ports:
- name: http
containerPort: 80
7.2.3 关于更新
直接修改清单文件,kubectl apply -f deployment.yaml
使用 kubectl patch 使用 json 格式给出更新的内容
kubectl patch deployment myapp-deploy -p '{"spec":{"replicas":5}}' # 修改 POD 副本数量

kubectl patch deployment myapp-deploy -p '{"spec":{"strategy":{"rollingUpdate":{"maxSurge":1,"maxUnavailable":0}}}}' # 修改更新策略
仅更新镜像 kubectl set image
kubectl set image deployment myapp-deploy myapp=ikubernetes/myapp:v3
7.2.4 模拟金丝雀发布
在更新刚刚启动的时候,将更新过程暂停,那么只能更新一个,这实现了在集群中增加一个金丝雀版本
kubectl set image deployment myapp-deploy myapp=ikubernetes/myapp:v3 && kubectl rollout pause deployment myapp-deploy
查看已经被更新中被暂停的控制器状态,可以看到一直处于暂停状态的 deployment
kubectl rollout status deployment myapp-deploy
Waiting for deployment "myapp-deploy" rollout to finish: 1 out of 5 new replicas have been updated...

等待部署“myapp-deploy”部署完成:5个新副本中的1个已更新...
如果金丝雀没有问题,那么继续可以使用继续更新的命令
kubectl rollout resume deployment myapp-deploy
7.2.5 更新策略
最大不可用为 0 ,更新时候可以临时超出1个
kubectl patch deployment myapp-deploy -p '{"spec":{"strategy":{"rollingUpdate":{"maxSurge":1,"maxUnavailable":0}}}}'
7.2.6 关于回滚
rollout undo 是回滚的命令,默认滚回上一版本
kubectl rollout undo deployment myapp-deploy
查看可以回滚的版本
kubectl rollout history deployment myapp-deploy
rollout undo 指定回滚的版本
kubectl rollout undo deployment myapp-deploy --to-revision=2
查看当前的工作版本
kubectl get rs -o wide
7.3 DaemonSet控制器
清单规范,详见 kubectl explain daemonset
apiVersion <string> # apps/v1

kind <string> # 资源类别,标记创建什么类型的资源

metadata <Object> # POD 元数据

spec <Object> # 元数据
7.3.1 DaemonSet.spec规范
此处只列举不同之处

updateStrategy 更新策略,支持滚动更新、支持滚动更新的更新方式,默认滚动更新每个 node
rollingUpdate # 滚动更新,它只有一个 rollingUpdate 参数,表示每次更新几个 node 上的 DaemonSet 任务
OnDelete # 在删除时更新
7.3.2 清单示例
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: redis
role: logstor
template:
metadata:
labels:
app: redis
role: logstor
spec:
containers:
- name: redis
image: redis:4.0-alpine
ports:
- name: redis
containerPort: 6379
--- # 可以使用 --- 来分隔多个记录
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: filebeat-daemonset
namespace: default
spec:
selector:
matchLabels:
app: filebeat
release: stalbe
template:
metadata:
labels:
app: filebeat
release: stalbe
spec:
containers:
- name: filebeat
image: ikubernetes/filebeat:5.6.5-alpine
env: # 向容器传递环境变量
- name: REDIS_HOST # 容器内的环境变量名称
value: redis.default.svc.cluster.local # 环境变量值,指向 redis service
- name: REDIS_LOG_LEVEL
value: info
7.3.3 关于更新
更新 filebeat-daemonset 这个 daemonset 控制器下的 filebeat 容器的镜像
kubectl set image daemonsets filebeat-daemonset filebeat=ikubernetes/filebeat:5.6.6-alpine
八 Service 配置清单
Service 为 POD 控制器控制的 POD 集群提供一个固定的访问端点,Service 的工作还依赖于 K8s 中的一个附件,就是 CoreDNS ,它将 Service 地址提供一个域名解析。

8.1 Service 工作模式
userspace: 1.1 之前版本
iptables: 1.10 之前版本
ipvs:1.11 之后版本
8.2 Service 类型
类型 作用
ClusterIP 默认值,分配一个 Service

0 个评论

要回复文章请先登录注册