参考书籍: kubernetes全栈架构师
Kubernetes 是谷歌以 Borg 为前身,基于谷歌 15年生产环境经验的基础上开源的一个项目,Kubernetes 致力于提供跨主机集群的自动部署,扩展,高可用以及运行应用程序容器的平台。
组件介绍
Master 节点
Master 节点是 Kubernetes 集群的控制节点,在生产环境中不建议部署集群核心组件外的任何 Pod,公司业务的 Pod 更是不建议部署到 Master 节点上,以免升级或者维护时对业务造成影响。
Master 组件包括:
- Kube-apiserver: 集群的控制中枢,各个模块之间的信息交互都需要经过 kube-apiserver,同时它也是集群管理,资源配置,以及整个集群安全机制的入口;
- Controller-Manager: 集群的状态管理器,保证 Pod 或其他资源达到预期值,也是需要和 APIServer 进行通信,在需要的时候创建,更新或删除它所管理的资源;
- Scheduler: 集群的调度中心,它会根据指定的一系列条件,选择一个或一批最佳的节点,然后部署我们的 Pod;
- Etcd: 键值数据库,包括一些集群的信息,一般生产环境中建议以部署三个以上节点(奇数个)。
Node 节点
Node 节点有时候也称为 Worker 节点,或者 Minion 节点,是主要负责部署容器(工作负载)的单机(或虚拟机),集群中的每个节点都必须具备容器的运行环境,比如 Docker 及其他组件等;Kubelet 作为守护进程运行在 Node 节点上,负责监听该节点上所有的 Pod,同时负责上报该节点上所有 Pod 的运行状态确保节点上的所有容器都能正常运行。当 Node 节点宕机(NotReady)时,该节点上运行的 Pod 会被自动转移到其他节点上。
Node 节点包括:
- Kubelet: 负责监听节点上 Pod 的状态,同时负责上报节点和节点上面 Pod 的状态。负责与 Master 节点通信,并管理节点上面的 Pod;
- Kube-proxy: 负责 Pod 之间的通信和负载均衡,将指定的流量分发到后端正确的机器上。
- Docker Engine: Docker 引擎,负责对容器的管理。
查看 Kube-proxy 的工作模式
查看 Kube-proxy 监听的端口
1
2
3
4
5netstat -anptl |grep kube-proxy
tcp 0 0 0.0.0.0:30000 0.0.0.0:* LISTEN 1073/kube-proxy
tcp 0 0 127.0.0.1:10249 0.0.0.0:* LISTEN 1073/kube-proxy
tcp 0 0 192.168.200.22:41662 192.168.200.110:8443 ESTABLISHED 1073/kube-proxy
tcp6 0 0 :::10256 :::* LISTEN 1073/kube-proxy查看 Kube-proxy 的工作模式
1
2curl 127.0.0.1:10249/proxyMode
ipvs
其他组件
- Calico: 符合 CNI 标准的网络插件,给每个 Pod 生成一个唯一的 IP 地址,并且把每个节点当做一个路由器;
- CoreDNS: 用于 Kubernetes 集群内部 Service 的解析,可以让 Pod 把 Service 名称解析成 IP 地址,然后通过 Service 的 IP 地址进行连接到对应的应用上。
- Docker: 容器引擎,负责对容器的管理。
Pod 讲解
什么是 Pod
Pod 可简单地理解为是一组,一个或多个容器,具有共享存储/网络及如何运行容器的规范。Pod 包含一个或多个相对紧密耦合的应用程序容器,处于同一个 Pod 中的容器共享同样的存储空间(Volume,卷或存储卷),IP 地址和 Port 端口,容器之间使用 localhost:port 相互访问。
Pod 包含的容器最好是一个容器只运行一个进程。每个 Pod 包含一个 pause 容器,pause 容器是 Pod 的父容器,它主要负责僵尸进程的回收管理。
Kubernetes 为每个 Pod 都分配一个唯一的 IP 地址,这样就可以保证应用程序使用同一端口。避免了发生冲突的问题。
一个 Pod 的状态信息保存在 PodStatus 对象中,在 PodStatus 中有一个 Phase 字段,用于描述 Pod 在其生命周期中的不同状态。如下:
状态 | 说明 |
---|---|
Pending(挂起) | Pod 已被 Kubernetes 系统接收,但仍有一个或多个容器未被创建。可以通过 describe 查看处于 Pending 状态的原因 |
Running(运行中) | Pod 已经被绑定到一个节点上,并且所有的容器都已经被创建。而且至少有一个是运行状态,或者是正在启动或者重启。可以通过 logs 查看 Pod 的日志 |
Succeeded(成功) | 所有容器执行成功成功并终止,并且不会再次重启 |
Failed(失败) | 所有容器都已终止,并且至少有一个容器以失败的方式终止,也就是说这个容器要么以非零状态退出,要么是被系统终止 |
Unknown(位置) | 通常是由于通信问题造成的无法获取 Pod 的状态 |
Pod 探针
Pod 探针用来检测容器内的应用是否正常,目前有三种方式,如下
种类 说明 StartupProbe k8s 1.16 版本后新加的探测方式,用于判断容器内应用程序是否已经启动。如果配置了 startupProbe,就会先禁用其他的探测,直到它成功为止,成功后不再进行探测 LivenessProbe 用于探测容器是否运行,如果探测失败,Kubelet 会根据配置的重启策略进行相应的处理。若没有配置该探针,默认就是 success ReadinessProbe 一般用于探测容器内进程是否健康,它的返回值如果为 success,那么就代表这个容器已经启动完成,并且程序已经是可以接受流量的状态。 Pod 探针的实现方式有以下三种
实现方式 说明 ExecAction 在容器内执行一个指定的命令,如果命令返回值为 0,则认为容器健康 TCPSocketAction 通过 TCP 连接检查容器指定的端口,如果端口开放,则认为容器健康 HTTPGetAction 对指定的 URL 进行 Get 请求,如果状态码在 200~400 之间,则认为容器健康 Pod 探针检查容器后可能得到的状态
状态 说明 Success(成功) 容器通过检查 Failure(失败) 容器检测失败 Unknown(未知) 诊断失败,因此不采取任何措施 Pod 探针检查参数配置
- initialDelaySeconds: 60 # 初始化时间
- timeoutSeconds: 5 # 超时时间
- periodSeconds: 10 # 检查间隔
- successThreshold: 1 # 检查成功为1次就表示就绪
- failureThreshold: 2 # 检查失败2次就表示未就绪
此处计算容器重启间隔的时间为,每次检查的时间间隔为 10s,最长超时时间是 5s,也就是单次检查时间应该是 10+5=15秒(periodSeconds+timeoutSeconds);所以最长的重启时间为 (10+5)*2=30s
; 即(periodSeconds + timeoutSeconds) * failureThreshold
此时又分为两种情况:
- 首次启动时:最长重启时间需要加上 initialDelaySeconds,因为需要等待 initialDelaySeconds 秒之后才会执行健康检查,最长重启时间为:(periodSeconds + timeoutSeconds) * failuerThreshold + initialDelaySeconds
- 程序启动完成后: 此时不需要计入 initialDelaySeconds,因此最长重启时间为 (periodSeconds + timeoutSeconds) * failureThreshold
Pod 镜像拉取策略和重启策略
Pod 镜像的拉去策略,用于配置当节点部署 Pod 时,对镜像的操作方式。如下
操作方式 | 说明 |
---|---|
Always | 总是拉取,当镜像 tag 为 latest 时,默认为 Always |
Never | 不管镜像是否存在都不会拉取 |
ifNotPresent | 镜像不存在时拉取镜像(默认值)。排除 latest |
Pod 的重启策略
Pod 重启策略,在 Pod 发生故障时对 Pod 的处理方式,如下
操作方式 | 说明 |
---|---|
Always | 默认策略,容器失效时,自动重启该容器 |
OnFailure | 容器以不为0的状态码终止,自动重启该容器 |
Never | 无论何种状态,都不会重启 |
Pod常用的配置参数
在生产环境中,很少会单独启动一个 Pod 直接使用,经常会用 Deployment,DaemonSet,StatefulSet 等方式调度并管理 Pod,定义 Pod 的参数同时适用于 Deployment,DaemonSet,StatefulSet 等方式。
以下是一个 Pod 常用的配置示例:
1 | apiVersion: v1 # 必选,API的版本号 |
一个简单的 Pod 示例
创建一个简单的 Pod 示例文件 nginx-test.yaml,用来启动一个 Nginx pod,文件内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
role: frontend
annotations:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: Always
command:
- nginx
- -g
- "daemon off;"
workingDir: /usr/share/nginx/html
volumeMounts:
- name: webroot
mountPath: /usr/share/nginx/html
readOnly: true
ports:
- name: http
containerPort: 80
protocol: TCP
env:
- name: TZ
value: Asia/Shanghai
- name: LANG
value: en_US.utf8
livenessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 30
timeoutSeconds: 5
periodSeconds: 5
successThreshold: 1
failureThreshold: 3
restartPolicy: Always
hostNetwork: false
volumes:
- name: webroot
emptyDir: {}
#hostPath:
#path: /etc/hosts使用 kubectl 启动 pod
1
kubectl create -f nginx-test.yaml
查看该 Pod 信息
1
2
3
4
5
6
7
8
9# 查看 Pod 运行状态
kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 47s
# 查看标签信息
kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx 1/1 Running 0 53s app=nginx,role=frontend
Pod 状态字段 Phase 的不同取值说明
状态 | 说明 |
---|---|
Pending(挂起) | Pod 已经被 Kubernetes 系统接收,但仍有一个或多个容器未被创建,可以通过 kubectl describe 查看处于 Pending 状态的原因 |
Running(运行中) | Pod 已经被绑定到一个节点上,并且所有的容器都已经被创建,而且至少有一个是运行状态,或者是正在启动或者重启,可以通过 kubectl logs 查看 Pod 日志 |
Succeeded(成功) | 所有容器执行成功并终止,并且不会再次重启,可以通过 kubectl logs 查看 Pod 日志 |
Failed(失败) | 所有容器都已终止,并且至少有一个容器以失败的方式告终,也就是说这个容器要么以非零状态退出,要么被系统终止,可以通过 logs 和 describe 查看 Pod 日志和状态 |
Unknown(位置) | 通常是由于通信问题造成的无法获得 Pod 的状态 |
ImagePullBackOff ErrImagePull | 镜像拉取失败,一般是由于镜像不存在,网络不通或者需要登录认证引起的,可以使用 describe 命令查看具体原因 |
CrashLoopBackOff | 容器启动失败,可以通过 logs 命令查看具体原因,一般为启动命令不正确,健康检查不通过等 |
OOMKilled | 容器内存溢出,一般是容器的内存 Limit 设置的过小,或者程序本身有内存溢出,可以通过 logs 查看程序的启动日志 |
Terminating | Pod 正在被删除,可以通过 describe 查看状态 |
SysctlForbidden | Pod 定义了内核配置,但 Kubelet 没有添加内核配置或配置的内核参数不支持,可以通过 describe 查看具体原因 |
Completed | 容器内部主进程退出,一般计划任务执行结束会显示该状态,此时可以通过 logs 查看容器日志 |
ContainerCreating | Pod 正在创建,一般为正在下载镜像,或者有配置不当的地方,可以通过 describe 查看具体原因 |
注意,Pod 的 Phase 字段只有 Pending,Running,Succeeded,Failed,Unknown,其余的为处于上述状态的原因,可以通过 kubectl get pod xxx -o yaml 查看
kubectl logs 命令格式:
1
kubectl logs -f POD_NAME -n POD_NAMESPACE
kubectl describe 命令格式
1
kubectl describe POD_NAME -n POD_NAMESPACE