一、kubernetes的定义
Kubernetes (希腊语"舵手" 或 "飞行员") 由Joe Beda,Brendan Burns和Craig McLuckie创立,并由其他谷歌工程师,包括Brian Grant和Tim Hockin进行加盟创作,并由谷歌在2014年首次对外宣布。它的开发和设计都深受谷歌的Borg系统的影响,它的许多顶级贡献者之前也是Borg系统的开发者。在谷歌内部,Kubernetes的原始代号曾经是Seven,即星际迷航中友好的Borg(博格人)角色。Kubernetes标识中舵轮有七个轮辐就是对该项目代号的致意。
Kubernetes作为容器集群管理工具,于2015年7月22日迭代到 v 1.0并正式对外公布,这意味着这个开源容器编排系统可以正式在生产环境使用。与此同时,谷歌联合Linux基金会及其他合作伙伴共同成立了CNCF基金会( Cloud Native Computing Foundation),并将Kuberentes 作为首个编入CNCF管理体系的开源项目,助力容器技术生态的发展进步。Kubernetes项目凝结了Google过去十年间在生产环境的经验和教训,从Borg的多任务Alloc资源块到Kubernetes的多副本Pod,从Borg的Cell集群管理,到Kubernetes设计理念中的联邦集群,在Docker等高级引擎带动容器技术兴起和大众化的同时,为容器集群管理提供独了到见解和新思路。
简而言之,kubernets是一个对容器进行编排的工具。而"编排"(Orchestration)在云计算行业里不算是新词汇,主要是指用户如何通过某些工具或者配置来完成一组虚拟机以及关联资源的定义、配置、创建、删除等工作,然后由云计算平台按照这些指定的逻辑来完成的过程。
二、kubernetes的主要节点与组件资源
1.master节点------核心节点(管理节点):
1.API-server组件:提供了一个控制集群的统一入口(创建、删除......指令)
2.scheduler组件:提供资源调度(将资源运行到某个节点上,调度方式:1.随机调度---默认。2.人工干预(指定节点名字Nodename,指定节点标签nodeSelector)、(污点tiant、亲和性和反亲和性)
3.replication controller组件:控制副本(保证集群中有和配置文件中定义一样个数的资源在运行),scheduler通过api-server找到一个服务etcd数据库集群(作用:保存整个k8s集群的信息与状态),选择在哪个node节点中创建资源,然后让api-server去告诉node节点进行工作,属于controller-manager的一部分
注:controller-manager---总组件,replication controller就是其中一个控制器组件,学习到的控制器包括:
1.replication controller
2.deployment controller
3.node controller
4.namespace controller:管理维护Namespace,定期清理无效的Namespace,包括Namesapce下的API对象,比如Pod、Service等。
5.service controller
6.endpoints controller
7.service account controller:管理维护Service Account,为每个Namespace创建默认的Service Account,同时为Service Account创建Service Account Secret。
8.Persistent Volume Controller:管理维护Persistent Volume和Persistent Volume Claim,为新的Persistent Volume Claim分配Persistent Volume进行绑定,为释放的Persistent Volume执行清理回收。
9.Daemon Set Controller:管理维护Daemon Set,负责创建Daemon Pod,保证指定的Node上正常的运行Daemon Pod。
10.Job Controller:管理维护Job,为Jod创建一次性任务Pod,保证完成Job指定完成的任务数目
11.Pod Autoscaler Controller:实现Pod的自动伸缩,定时获取监控数据,进行策略匹配,当满足条件时执行Pod的伸缩动作。
2.node节点------工作节点(运行pod的服务节点)
1.kubelet组件:与api-server组件连接,接收api-server发过来的所有请求
2.docker(containerd>=1.24默认更改)组件:创建容器、运行容器
3.kube-proxy组件:实现将客户端流量转发到容器内部。有三种工作模式:userspace、iptables、ipvs
3.各种资源
1.pod:是资源一种,是k8s集群最小的操作单位,包含一个或者多个关系紧密的容器,共享同样的存储空间,网络命名空间IP地址+port端口。
注:pod创建时,会先创建一个pause容器,pid为1,为系统自动创建,目的是为了让pod内的容器共享同一个名称空间:网络、pid、ipc通信方式、mnt挂载点、volume卷、uts、user等,后面加入的容器都会用容器映射的方式接入pause容器。
2.网卡方面:node节点上有eth0网卡,pod中有虚拟的docker0网卡,流量流入流出,ip转换类似于kvm的virbr0网卡接口和vnet0网卡。
3.volume:是一种pod映射目录的方法,将宿主机上的要映射的目录做成存储卷(configmap配置卷、secret存放密码的卷、存放数据的临时卷和持久卷pv),挂载到pod的pause容器上,供pod内的所有容器使用。
4.event:用来记录pod的创建调度过程(类似于log日志),不是文件,是一个字段,可以通过kubectl describe pod <pod_name>或者kubectl get events -n <namespace>查询。
5.endpoint:是一个内部的服务,主要实现在集群内部访问容器的一种方式,访问方式:访问pod的ip+容器的端口,这种访问方式被称为endpoint,属于k8s集群的一个资源。
注:使用service把服务暴露到外网时,会自动创建endpoint列表,访问流量会流进endpoint,查看列表到对应端口,进入响应容器服务。
6.replicaset:用于指定pod副本数量,资源控制器。
7.deployment:是一个更高层次的api对象,管理replicasets和pod,是replicaset的进阶版,用于创建定义资源副本的replication controller。
注:deployment的作用:1.定义pod的副本。2.实现蓝绿发布和金丝雀发布。3.能够实现弹性的伸缩扩容以及滚动更新(指定replicaset的副本个数进行伸缩扩容、滚动:关闭一个旧的,启动一个新的,平滑升级)。
如何创建deployment?通过编写配置文件xxx.yml---使用命令kubectl apply -f xxx.yml创建deployment(xxx.yml中定义了资源的类型为deployment,deployment的名字dep-nginx,pod的副本个数与标签)
deployment创建出来会创建replicaset(使用父对象的名字+指定字符串为名字,如dep-nginx-0fdsa3),真正的pod是由replicaset控制的,可能运行在同一个节点上(pod的名字也是随机生成的,使用父对象的名字+随机字符串生成,如dep-nginx-0fdsa3-ds3k,标签是标签,名字是名字)
8.service----作为四层代理,暴露内部服务的端口到外网的,提供了一个同一的入口及发现机制,用户只需要访问service就能将流量转到pod内,一个项目一组pod需要一个service作为代理。
注:service有四种类型:
1.clusterIP:默认类型,自动分配一个内部可以访问的虚拟ip,外部访问不到。
service配置文件中定义一个叫标签选择器这样的一个字段,选择deployment配置文件中设置的pod标签,就能从endpoint列表中找到pod的ip和端口了。
所以当流量转入clusterIP的service的IP时,会调用kube-proxy组件,使用ipvs模式调用lvs规则,负载均衡给带有标签的pod
2.nodeport:将pod内部的端口暴露在node上,访问node IP:port(端口映射)
需要指定nodeport(节点端口),而port:80只作为集群内通信端口
3.loadbalancer:在nodeport的基础上,使用云提供商的负载均衡器(如SLB),并将请求转发到nodeport,需要节点使用云产品
loadbalancer集成了nodeport,只需要写一个yaml文件定义loadbalancer的service。
(也就是说我只需要买个slb,然后把k8s的node节点全部加进slb规则里,之后再node节点上写个service的yaml文件,定义类型为loadbalancer,port:80,targetport为服务端口,k8s就会自动把我买的slb用上进行负载均衡咯)
4.ExternalName:把集群外部的服务引入集群内部来(数据跑容器里会丢失数据),在集群内部直接使用,想做负载均衡还得写一个clusterIP,这样还是只能在集群内生效,用处不大
如何实现访问集群里的服务?
1.做svc------四层负载
2.ingress------七层负载=nginx
4.创建pod的详细过程(原理级别)
一个master节点和四台node节点。先看上面master节点:开始从kubectl开始,kubectl和web ui都是k8s集群和用户交互的一个工具。可以通过kubectl这个是命令行工具通过命令操作集群,也可以是通过web ui这个界面操作集群。这个web ui是安装在k8s集群里面的一通过个应用。
重点是命令行:通过kubectl这个工具创建一个pod有副本,先去联系apiserver通过apiserver与Replication Controller(副本控制器),进行通信,找到之后就该创建了,那给哪个node上面创建是不是就该找Scheduler,如果我们不指定给哪台节点上面创建,默认就给是随机指定了。Scheduler如何知道集群中有哪些节点,这个时候Scheduler也要经过这个apiserver连接到etcd这个数据库通信,去查询数据库里面有哪些节点,然后选择一个节点去创建pod。比如现在选择好了一个节点是node1,这个时候Scheduler要通过这个apiserver与node1节点上面的kubelet进行通信,这个kubelet相当于我们node节点上面的一个代理,就是整个node节点上资源的创建都是通过master发起的任务,完成这个任务需要通过这个kubelet。找到kubelet之后需要创建一个pod,然后kubelet去找node1上面的docker engine,正真创建pod的不是kubelet,正真创建的还是docker。实际创建的还是一个容器,pod只是逻辑上面的概念。创建完容器之后要想给其他应用提供访问服务,就要通过kube-proxy的组件将请求转发到pod内部实现访问。外网通过防火墙实现访问service,会调用标签选择器,根据deployment里设置的pod的标签和service配置文件中的标签类型,在endpoint列表中找到对应node的ip和端口,最后将请求通过kube-proxy组件转发到服务里面。
有状态:daemonset deployment搭建
无状态:statefulset搭建
iptables是通过设置DNAT实现流量转发,不好用,消耗资源大
ipvs:做负载均衡
三、kubernetes集群部署方式
1.minukube工具
快速创建一个单点的k8s集群
2.kebeadm工具:见使用kubeadm的方式部署k8s-1.22-CSDN博客
3.直接使用epel-release yum源,版本低1.5不用
4.二进制包(麻烦,还有用的但不多)
四、kubectl相关命令
基础命令不多,但分支复杂,可以通过kubectl --help查看
1.kubectl get (nodes|pod|events|service|ns|.......) -n <namespace> -o(wide|yaml|.......)
2.kubectl describe (node|pod|ns|.......) -n <namespace>
3.kubectl delete (pod|ns|.......) <podname> | kubectl delete -f xxx.yml
3.kubectl cluster-info #查询apiserver信息
4.kubectl api-versions #查询api
5.kubectl exec -it <pod_name> -c <docker_name> -- /bin/bash #进入pod对应容器内部
6.kubectl apply -f xxx.yml #根据yaml文件创建资源
7.kubectl taint nodes <node_name> dedicated=negative:NoSchedule #给节点添加污点
五、创建资源------yml语言
1.创建名称空间
TypeScript
---
apiVersion: v1
kind: Namespace
metadata:
name: test
labels:
name: my-namespace
2.创建名称空间的资源限制
TypeScript
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: ns-quota
namespace: test
spec:
hard:
limits.cpu: "2"
limits.memory: "2Gi"
requests.cpu: "2"
requests.memory: "2Gi"
3.创建pod
TypeScript
---
apiVersion: v1
kind: Pod #类型为pod
metadata:
namespace: kube-system #所属名称空间
name: pod-1 #pod名称
labels: #标签为web=nginx
web: nginx
spec:
hostIPC: true #共享主机IPC
hostNetwork: true #共享主机网络
hostPID: true #共享主机PID,与shareProcessNamespace不能同时设置
hostAliases: #设置hosts,供pod内所有容器共享
- hostanames:
- "www.baidu.com"
- "www.baidu.cn"
ip: "192.168.89.167"
volumes: #使用投射数据卷
- name: vol-1
secret: #类型为secret
secretName: secret-1
- name: vol-2
configMap: #类型为config
name: test-config4
items:
- key: upstream.conf
path: upstream.conf
- name: vol-3
configMap:
name: test-config4
items:
- key: my.cnf
path: my.cnf
tolerations: #添加污点的容忍
- key: haha
effect: NoSchedule #影响力为
operator: Exists #
nodeName: master03
containers:
- name: nginx-2
image: daocloud.io/library/nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: http
protocol: TCP
volumeMounts: #挂载投射数据卷,与前面的volumes对应
- name: vol-1
mountPath: /usr/share/nginx/html/
- name: vol-2
mountPath: /etc/nginx/conf.d/
- name: vol-3
mountPath: /etc/
env: #设置环境变量,与前面volumes无任何关系
- name: user #需要设置的环境变量值
valueFrom:
secretKeyRef: #类型为secret
key: user #赋值为user的值
name: secret-1 #取自名称空间中的secret-1
- name: pass
valueFrom:
secretKeyRef:
key: pass
name: secret-1
- name: nginx_port
valueFrom:
configMapKeyRef:
name: test-config4
key: port
- name: nginx_user
valueFrom:
configMapKeyRef:
name: test-config4
key: user
envfrom: #与env设置环境变量不同,不用指定key值,引入configmap中所有环境变量
- configMapRef:
name: config-map
resources:
limits:
cpu: "1"
memory: "1Gi"
requests:
cpu: "100m"
memory: "500Mi"
lifecycle:
postStart:
exec:
command:
- sh
- -c
- echo '1' >> start.txt
preStop:
exec:
command:
- sh
- -c
- echo '1' >> stop.txt
- name: busybox
image: daocloud.io/library/busybox
stdin: true
tty: true
restartPolicy: Never #重启策略为永远不重启,默认为Always,异常退出OnFailure
4.创建secret
TypeScript
---
apiVersion: v1
kind: Secret
metadata:
name: secret-1
type: Opaque
data:
user: YWRtaW4=
pass: WVdSdGFXND0=
5.创建volume并挂载
TypeScript
---
apiVersion: v1
kind: Pod
metadata:
namespace: kube-system
name: pod-1
labels:
web: nginx
spec:
volumes:
- name: vol-1
secret:
secretName: secret-1
containers:
- name: nginx-1
image: daocloud.io/library/nginx:1.18
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
volumeMounts:
- name: vol-1
mountPath: /usr/share/nginx/html
env:
- name: user
valueFrom:
secretKeyRef:
key: user
name: secret-1
- name: pass
valueFrom:
secretKeyRef:
key: pass
name: secret-1
6.配置secret连接harbor仓库
在所有节点上配置harbor仓库的地址
cat /etc/docker/daemon.json
{
"insecure-registries": ["192.168.116.141"]
}
systemctl daemon-reload
systemctl restart docker
cat /root/.docker/config.json | base64 -w 0
TypeScript
---
apiVersion: v1
kind: Secret
metadata:
name: harbor-login
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjExNi4xNDEiOiB7CgkJCSJhdXRoIjogIllXUnRhVzQ2U0dGeVltOXlNVEl6TkRVPSIKCQl9Cgl9Cn0=
---
apiVersion: v1
kind: Pod
metadata:
name: nginx-web
spec:
containers:
- name: nginx-1
image: 192.168.116.141/nginx/nginx:v1.1 #指定镜像仓库地址
imagePullSecrets: #指定使用的harbor仓库的secret
- name: harbor-login
7.创建ConfigMap
命令行方式:
方式1:通过直接在命令行中指定configmap参数创建,即--from-literal。
kubectl create configmap test-configmap --from-literal=user=admin --from-literal=pass=admin123
方式2:通过指定文件创建,即将一个配置文件创建为一个ConfigMap,--from-file=<文件>
kubectl create configmap test-config2 --from-file=server.conf 。
方式3:通过指定目录创建,即将一个目录下的所有配置文件创建为一个ConfigMap,--from-file=<目录>。
kubectl create configmap test-config3 --from-file=./config
配置文件方式:
方式4:事先写好标准的configmap的yaml文件,然后kubectl create -f 创建。
TypeScript
---
apiVersion: v1
kind: ConfigMap
metadata:
name: test-config4
namespace: default
data:
upstream.conf: |
upstream test {
server 192.168.89.160;
server 192.168.89.161;
}
port: 80
user: nginx
my.cnf: |
[mysqld]
user = mysql
server_ID = 1
log-bin = /var/log/mysql-log
六、查看pod资源cpu内存占用率的工具------Metrics Server
在master一台节点上安装即可
1.下载地址,并查看对应的k8s使用的版本
https://github.com/kubernetes-sigs/metrics-server/
2.wget下来对应版本的yml文件
进入文件修改image为registry.aliyuncs.com/google_containers/metrics-server:v0.7.1
3.添加额外args参数:
- --kubelet-insecure-tls #禁用证书验证
4.kubectl apply -f high-availability-1.21+.yaml
5.安装成功可在master机上使用kubectl top (node|pod|.......) <node_name>查看pod的cpu和内存占用率
七、pod的生命周期
1.pod启动时先创建pause基础容器,pid为1,为pod内容器提供一个共享的网络、命名空间
2.按配置文件中initContainers先启动初始化容器,启动完成后才会启动containers的主容器,
3.主容器启动后,执行lifecycle钩子定义的容器启动后的操作
4.然后定义探针,三种探针(启动探针:检测容器是否启动成功,就绪探针:检测容器是否就绪,能够接收service请求,存活探针:检测容器内进程是否健康),启动探针最先进行,就绪存活没有先后顺序同时进行
5.关闭容器也会指定lifecycle钩子定义容器关闭前的操作
生命周期的状态有很多:
Pending:此状态表示Pod 的 YAML 文件已经提交给了 Kubernetes,API 对象已经被创建并保存在 Etcd 当中(准备状态)。但这个 Pod 里有些容器因为某种原因而不能被顺利创建。比如,调度不成功。
Running:此状态表示Pod 已经调度成功,跟一个具体的节点绑定。它包含的容器都已经创建成功,并且至少有一个正在运行中。
Succeeded:此状态表示 Pod 里的所有容器都正常运行完毕,并且已经退出了。这种情况在运行一次性任务时最为常见。
Failed:此状态表示 Pod 里至少有一个容器以不正常的状态(非 0 的返回码)退出。比如查看 Pod 的 Events 和日志。
Unknown:这是一个异常状态(未知状态),表示 Pod 的状态不能持续地被 kubelet 汇报给 kube-apiserver这很有可能是主从节点(Master 和 Kubelet)间的通信出现了问题
completed: pod里面所有容器正常退出
CrashLoopBackOff: 容器退出,kubelet正在将它重启
InvalidImageName: 无法解析镜像名称
ImageInspectError: 无法校验镜像
ErrImageNeverPull: 策略禁止拉取镜像
ImagePullBackOff: 正在重试拉取
RegistryUnavailable: 连接不到镜像中心
ErrImagePull: 拉取镜像出错
CreateContainerConfigError: 不能创建kubelet使用的容器配置
CreateContainerError: 创建容器失败
m.internalLifecycle.PreStartContainer 执行hook报错
RunContainerError: 启动容器失败
PostStartHookError: 执行hook报错
ContainersNotInitialized: 容器没有初始化完毕
ContainersNotReady: 容器没有准备完毕
ContainerCreating:容器创建中
PodInitializing:pod 初始化中
DockerDaemonNotReady:docker还没有完全启动
NetworkPluginNotReady: 网络插件还没有完全启动
八、投射数据卷
投射数据卷:将容器使用的数据做成一个卷挂载到容器内部供容器使用。
存储卷:将目录或存储设备定义成一个卷挂载到容器内去使用。用于存放容器产生的数据。
投射数据卷的类型:
secret:加密卷,用于保存敏感数据的k8s资源
ConfigMap:配置卷
Downward API
ServiceAccountToken
secret类型:
1.kubernetes.io/service-account-token:存储service-account信息。
2.opaque:base64:编码格式的Secret,用来存储密码、秘钥等。
3.kubernetes.io/dockerconfigjson:用来存储私有docker registry的认证信息。