# 第四模块 Kubernetes落地实践(上)
# K8S 概述
- 容器调度管理平台 Kubernetes https://kubernetes.io/ (opens new window)
# 概述-架构图
分布式系统,两类角色:管理节点和工作节点
# 概述-核心组件
ETCD: 分布式高性能键值数据库,存储整个集群的所有元数据
APIServer: API服务器,集群资源访问控制入口,提供RESTAPI及安全访问控制
Scheduler: 调度器,负责把业务容器调度到最合适的Node节点
Controller Manager: 控制器管理,确保集群资源按照期望的方式运行
- Replication Controller
- Node Controller
- ResourceQuota Controller
- Namespace Controller
- ServiceAccount Controller
- Token Controller
- Service Controller
- Endpoints Controller
kubelet: 运行在每个节点上的主要的"节点代理"
- Pod 管理
- 容器健康检查
- 容器监控
kube-proxy: 维护节点中的iptables或者ipvs规则
kubectl: 命令行接口,用于对 Kubernetes 集群运行命令
# 组件运行方式
- 静态Pod的方式:
# 系统初始化配置 /etc/kubernetes/manifests
# etcd、apiserver、controller-manager、kube-scheduler
[root@k8s-master manifests]# kubectl -n kube-system get po
NAME READY STATUS RESTARTS AGE
coredns-59d64cd4d4-fq2tb 1/1 Running 1 74d
coredns-59d64cd4d4-qjrdg 1/1 Running 1 74d
etcd-k8s-master 1/1 Running 1 74d
kube-apiserver-k8s-master 1/1 Running 5 74d
kube-controller-manager-k8s-master 1/1 Running 3 74d
kube-proxy-9p685 1/1 Running 1 74d
kube-proxy-pmwhf 1/1 Running 0 68d
kube-scheduler-k8s-master 1/1 Running 2 74d
- systemd服务方式:
systemctl status kubelet
- kubectl: 二进制命令行工具
[root@k8s-master ~]# kubectl -h
[root@k8s-master ~]# kubectl get -h
[root@k8s-master ~]# kubectl create -h
[root@k8s-master ~]# kubectl create namespace -h
# 概述-集群资源
- 组件是支撑k8s平台的运行的软件;
- 资源是管理k8s的一种单位,是一种能力的体现;
[root@k8s-master ~]# kubectl api-resources
NAME SHORTNAMES APIVERSION NAMESPACED KIND
namespaces ns v1 false Namespace
nodes no v1 false Node
- 命名空间 namespace 类似于资源池的概念,一个池子里可以有各种资源类型
[root@k8s-master ~]# kubectl get namespaces
NAME STATUS AGE
default Active 74d
kube-flannel Active 69d
kube-node-lease Active 74d
kube-public Active 74d
kube-system Active 74d
命名空间 namespace 注意事项
- NAMESPACED的资源,创建的时需要指定namespace,若不指定,默认会在default命名空间下
- 相同namespace下的同类资源不可以重名,不同类型的资源可以重名
- 不同namespace下的同类资源可以重名
- 通常在项目使用的时候,我们会创建带有业务含义的namespace来做逻辑上的整合
# K8S 工作流程
1. 用户创建yaml编排文件(记录业务应用的名称、镜像地址等),通过调用APIServer执行创建Pod;
2. APIServer收到用户的Pod创建请求,将Pod信息写入到etcd中;
3. 调度器通过list-watch的方式,发现有新的pod数据,但是这个pod还没有绑定到某一个节点中;
4. 调度器通过调度算法,计算出最适合该pod运行的节点,并调用APIServer,把信息更新到etcd中;
5. kubelet同样通过list-watch方式,发现有新的pod调度到本机的节点了,因此调用容器运行时,去根据pod的描述信息,拉取镜像,启动容器,同时生成事件信息;
6. 同时,把容器的信息、事件及状态也通过APIServer写入到etcd中;
架构设计的几点思考
- 系统各个组件分工明确
- APIServer是所有请求入口
- Controller Manager是控制中枢
- Scheduler主管调度
- Kubelet负责运行),配合流畅,整个运行机制一气呵成
- 除了配置管理和持久化组件ETCD,其他组件并不保存数据,即无状态
- 因为组件无状态,组件的升级,重启,故障等并不影响集群最终状态,组件恢复后从中断处继续运行
- 各个组件和kube-apiserver之间的数据推送都是通过list-watch机制来实现
# Pod 基本概念
# 最小调度单元 Pod
docker调度的是容器,在k8s集群中,最小的调度单元是Pod(豆荚)
# 为什么引入Pod
平台设计与容器引擎的具体的实现解耦,可兼容Docker、Rkt
多容器共享网络|存储|进程空间,支持的业务场景更加灵活
# Pod 编排文件
- 前期准备
# 项目地址
https://gitee.com/nining1314/fastapi_demo
# 本地 docker build
docker build . -t fastapi:0.0.1
# 本地测试 docker 运行
docker run -it --rm -p 80:80 fastapi:0.0.1
# 推到自制hub服务器 192.168.1.106:5000
docker tag fastapi:0.0.1 192.168.1.106:5000/fastapi:0.0.1
docker push 192.168.1.106:5000/fastapi:0.0.1
- 新增编排文件
fastapi/one-pod/pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: fastapi
namespace: ni-ning
labels:
component: fastapi
spec:
containers:
- name: fastapi
image: 192.168.1.106:5000/fastapi:0.0.1
ports:
- containerPort: 80
apiVersion | 含义 |
---|---|
alpha | 进入k8s功能的早期候选版本,可能包含bug,最终不一定进入k8s |
beta | 已经过测试的版本,最终会进入k8s,但功能、对象定义可能会发生变更 |
stable | 可安全使用的稳定版本 |
v1 | stable 版本之后的首个版本,包含了更多的核心对象 |
apps/v1 | 使用最广泛的版本,像Deployment、ReplicaSets都已进入该版本 |
- 快速获得资源和版本
[root@k8s-master one-pod]# kubectl explain pod
[root@k8s-master one-pod]# kubectl explain Pod.apiVersion
# Pod 增删改查
- 创建Pod服务
# 创建namespace, namespace是逻辑上的资源池
[root@k8s-master one-pod]# kubectl create namespace ni-ning
# 使用指定文件创建Pod
[root@k8s-master one-pod]# kubectl create -f pod.yaml
# 查看pod,可以简写po
# 所有的操作都需要指定namespace,如果是在default命名空间下,则可以省略
[root@k8s-master one-pod]# kubectl -n ni-ning get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
fastapi 1/1 Running 0 43s 10.244.0.11 k8s-master <none> <none>
# 使用Pod Ip访问服务 80
[root@k8s-master one-pod]# curl 10.244.0.11:80
{"Hello":"World"}
# 进入容器,执行初始化, 不必到对应的主机执行docker exec
[root@k8s-master one-pod]# kubectl -n ni-ning exec -it fastapi -c fastapi -- sh
/data/app/fastapi # python main.py
- pause:3.4.1 容器
[root@k8s-master one-pod]# docker ps -a | grep 'fastapi'
# 发现有2个容器: fastapi程序以及Infra容器
# Pod内部共享Infra容器的网络空间(Docker网络的container模式),实现内部通信,资源消耗低
pod容器命名: k8s_<container_name>_<pod_name>_<namespace>_<random_string>
- 查看pod详细信息
# 查看pod调度节点及pod_ip
[root@k8s-master one-pod]# kubectl -n ni-ning get pods -o wide
# 查看完整的yaml
[root@k8s-master one-pod]# kubectl -n ni-ning get po fastapi -o yaml
# 查看pod的明细信息及事件
[root@k8s-master one-pod]# kubectl -n ni-ning describe pod fastapi
- Troubleshooting and Debugging
# 进入Pod内的容器
$ kubectl -n <namespace> exec <pod_name> -c <container_name> -ti /bin/sh
# 查看Pod内容器日志,显示标准或者错误输出日志
$ kubectl -n <namespace> logs -f <pod_name> -c <container_name>
- 更新服务版本
[root@k8s-master one-pod]# kubectl apply -f pod.yaml
- 删除Pod服务
# 根据文件删除
$ kubectl delete -f pod.yaml
# 根据pod_name删除
$ kubectl -n ni-ning delete pod fastapi
# Pod 数据持久化
删除Pod时,容器内部数据都会丢失,可以进行数据持久化
volumes:hostPath
实现方式
apiVersion: v1
kind: Pod
metadata:
name: fastapi-v2
namespace: ni-ning
labels:
component: fastapi-v2
spec:
volumes:
- name: log-data
hostPath:
path: /root/fastapi/logs
containers:
- name: fastapi
image: 192.168.1.106:5000/fastapi:0.0.2
ports:
- containerPort: 80
volumeMounts:
- name: log-data
mountPath: /data/logs/fastapi
[root@k8s-master one-pod]# kubectl create -f pod-with-volume.yaml
[root@k8s-master one-pod]# kubectl -n ni-ning get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
fastapi 1/1 Running 0 115m 10.244.0.13 k8s-master <none> <none>
fastapi-v2 1/1 Running 0 23s 10.244.0.15 k8s-master <none> <none>
[root@k8s-master logs]# curl 10.244.0.15
{"Hello":"World"}
[root@k8s-master logs]# cat access.log
10.244.0.1:50582 - "GET / HTTP/1.1" 200
# 删除再创建
[root@k8s-master one-pod]# kubectl delete -f pod-with-volume.yaml
[root@k8s-master one-pod]# kubectl create -f pod-with-volume.yaml
[root@k8s-master one-pod]# kubectl -n ni-ning get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
fastapi 1/1 Running 0 118m 10.244.0.13 k8s-master <none> <none>
fastapi-v2 1/1 Running 0 7s 10.244.0.16 k8s-master <none> <none>
# 查看旧日志信息仍然存在
[root@k8s-master logs]# curl 10.244.0.16
{"Hello":"World"}
[root@k8s-master logs]# cat access.log
10.244.0.1:50582 - "GET / HTTP/1.1" 200
10.244.0.1:50706 - "GET / HTTP/1.1" 200
- 使用ceph等分布式存储解决方案
# Pod 健康检查
- 不设置,默认Pod是健康的
- 设置时,两种机制
- LivenessProbe探针 存活性探测: 用于判断容器是否存活,即Pod是否为running状态
- ReadinessProbe探针 可用性探测:用于判断容器是否正常提供服务,即容器的Ready是否为True
containers:
- name: fastapi
image: 192.168.1.106:5000/fastapi:0.0.3
livenessProbe:
httpGet:
path: /
port: 80
scheme: HTTP
initialDelaySeconds: 10 # 容器启动后第一次执行探测是需要等待多少秒
periodSeconds: 10 # 执行探测的频率
timeoutSeconds: 2 # 探测超时时间
readinessProbe:
httpGet:
path:
port: 80
scheme: HTTP
initialDelaySeconds: 10
timeoutSeconds: 2
periodSeconds: 10
[root@k8s-master one-pod]# kubectl create -f pod-with-probe.yaml
[root@k8s-master one-pod]# kubectl -n ni-ning get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
fastapi 1/1 Running 0 147m 10.244.0.13 k8s-master <none> <none>
fastapi-v2 1/1 Running 0 28m 10.244.0.16 k8s-master <none> <none>
fastapi-v3 1/1 Running 0 71s 10.244.0.17 k8s-master <none> <none>
- 三种探测类型
- exec:通过执行命令来检查服务是否正常,返回值为0则表示容器健康
- httpGet方式:通过发送http请求检查服务是否正常,返回200-399状态码则表明容器健康
- tcpSocket:通过容器的IP和Port执行TCP检查,如果能够建立TCP连接,则表明容器健康
# Pod 重启策略
当某个容器异常退出或者健康检查失败时,kubelet将根据RestartPolicy的设置来进行相应的操作
- Always:当容器进程退出后,由kubelet自动重启该容器,默认值;
- OnFailure:当容器终止运行且退出码不为0时,由kubelet自动重启该容器;
- Never:不论容器运行状态如何,kubelet都不会重启该容器。
演示重启策略:
apiVersion: v1
kind: Pod
metadata:
name: test-restart-policy
spec:
restartPolicy: Always
containers:
- name: busybox
image: busybox
args:
- /bin/sh
- -c
- sleep 10
# Pod 拉取策略
spec:
containers:
- name: fastapi
image: 192.168.1.106:5000/fastapi:0.0.1
imagePullPolicy: IfNotPresent
- Always,总是拉取镜像,即使本地有镜像也从仓库拉取
- IfNotPresent ,本地有则使用本地镜像,本地没有则去仓库拉取
- Never,只使用本地镜像,本地没有则报错
# Pod 资源限制
对于一个Pod来说,资源最基础的2个的指标就是:CPU和内存
- requests 容器使用的最小资源需求,作为调度判断依据
- limits 容器能使用资源的最大值
containers:
- name: fastapi
image: 192.168.1.106:5000/fastapi:0.0.1
ports:
- containerPort: 80
resources:
requests:
memory: 100Mi
cpu: 50m
limits:
memory: 500Mi
cpu: 100m
1 CPU = 1000 millicpu(1 Core = 1000m)
# Pod 秘钥信息
k8s提供两类资源 ConfigMap和Secret
具体实现略
# Pod 生命周期
- Pod的状态如下表所示
状态值 | 描述 |
---|---|
Pending | API Server已经创建该Pod,等待调度器调度 |
ContainerCreating | 拉取镜像启动容器中 |
Running | Pod内容器均已创建,且至少有一个容器处于运行状态、正在启动状态或正在重启状态 |
Succeeded|Completed | Pod内所有容器均已成功执行退出,且不再重启 |
Failed|Error | Pod内所有容器均已退出,但至少有一个容器退出为失败状态 |
CrashLoopBackOff | Pod内有容器启动失败,比如配置文件丢失导致主进程启动失败 |
Unknown | 由于某种原因无法获取该Pod的状态,可能由于网络通信不畅导致 |
- 生命周期示意图
- 启动和关闭示意
- 初始化容器
- 验证业务应用依赖的组件是否均已启动
- 修改目录的权限
- 调整系统参数
initContainers:
- command:
- /sbin/sysctl
- -w
- vm.max_map_count=262144
image: alpine:3.6
imagePullPolicy: IfNotPresent
name: elasticsearch-logging-init
resources: {}
securityContext:
privileged: true
- name: fix-permissions
image: alpine:3.6
command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"]
securityContext:
privileged: true
volumeMounts:
- name: elasticsearch-logging
mountPath: /usr/share/elasticsearch/data
- 验证Pod生命周期
apiVersion: v1
kind: Pod
metadata:
name: pod-lifecycle
namespace: ni-ning
labels:
component: pod-lifecycless
spec:
initContainers:
- name: init
image: busybox
command: ['sh', '-c', 'echo $(date +%s): INIT >> /loap/timing']
volumeMounts:
- mountPath: /loap
name: timing
containers:
- name: main
image: busybox
command: ['sh', '-c', 'echo $(date +%s): START >> /loap/timing;
sleep 10; echo $(date +%s): END >> /loap/timing;']
volumeMounts:
- mountPath: /loap
name: timing
livenessProbe:
exec:
command: ['sh', '-c', 'echo $(date +%s): LIVENESS >> /loap/timing']
readinessProbe:
exec:
command: ['sh', '-c', 'echo $(date +%s): READINESS >> /loap/timing']
lifecycle:
postStart:
exec:
command: ['sh', '-c', 'echo $(date +%s): POST-START >> /loap/timing']
preStop:
exec:
command: ['sh', '-c', 'echo $(date +%s): PRE-STOP >> /loap/timing']
volumes:
- name: timing
hostPath:
path: /tmp/loap
- 创建pod测试
$ kubectl create -f pod-lifecycle.yaml
## 查看demo状态
$ kubectl -n ni-ning get po -o wide -w
## 查看调度节点的/tmp/loap/timing
$ cat /tmp/loap/timing
1585424708: INIT
1585424746: START
1585424746: POST-START
1585424754: READINESS
1585424756: LIVENESS
1585424756: END