一、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规则,负载均衡给带有标签的pod2.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组件转发到服务里面。有状态:statefulset搭建
无状态:daemonset deployment搭建
iptables是通过设置 DNAT实现流量转发,不好用,消耗资源大
ipvs:做负载均衡
三、kubernetes集群部署方式
1.minikube工具:可以在本地快速运行一个单点的Kubernetes,尝试Kubernetes或日常开发的用户使用,不能用于生产环境。
2.kebeadm工具:见使用kubeadm的方式部署k8s-1.22-CSDN博客,用于快速创建一个单点的k8s集群。
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.创建名称空间
---
apiVersion: v1
kind: Namespace
metadata:
name: test
labels:
name: my-namespace
2.创建名称空间的资源限制
---
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
---
apiVersion: v1
kind: Pod #类型为pod
metadata:
namespace: default #所属名称空间
name: pod-1 #pod名称
labels: #标签为web=nginx
web: nginx
spec:
hostIPC: true #共享主机IPC
hostNetwork: true #共享主机网络
hostPID: true #共享主机PID,与shareProcessNamespace不能同时设置
hostAliases: #设置hosts,供pod内所有容器共享
- hostnames:
- "www.baidu.com"
- "www.baidu.cn"
ip: "192.168.89.167"
volumes: #使用投射数据卷
- name: vol-1
secret: #类型为secret
secretName: mysql-secret
- name: vol-2
configMap: #类型为config
name: test-config4
items:
- key: upstream.conf #configmap中的key
path: upstream.conf #挂载到容器目录下的upstream.conf中
- name: vol-3
configMap:
name: test-config4
items:
- key: my.cnf
path: my.cnf
- name: vol-4
downwardAPI: #类型为downwardAPI
items:
- path: "label" #文件名字
fieldRef:
fieldPath: metadata.labels #文件内容
- name: vol-5
emptyDir: {} #空目录卷,在pod节点机上创建一个空目录用于数据存储,无法得知目录名称
- name: vol-6
hostPath:
path: /data/foo # 主机上的目录位置
type: Directory # 此字段可选
- name: vol-7
nfs: #将远程192.168.89.164上的/my-nfs-volume目录做成nfs卷
server: 192.168.89.164
path: /my-nfs-volume
readOnly: true
# 还有一个local卷,将本地的某个磁盘做成卷,需要创建PersistentVolume资源并在内部指定
tolerations: #添加污点的容忍
- key: node-role.kubernetes.io/master
effect: NoSchedule #影响力为NoSchedule,但其实可以不加此容忍,因为该影响力只影
响随机调度,指定nodeName还是可以调度上去,除非master03节点上存在NoExecute,此时才需要容
忍
operator: Exists #对存在上述key的污点进行容忍,Equal需要指定value,空值时要>写“”
nodeName: master03
restartPolicy: Never #重启策略为永远不重启,默认为Always,异常退出OnFailure
containers:
- name: nginx
image: daocloud.io/library/nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: http
protocol: TCP
volumeMounts: #挂载投射数据卷,与前面的volumes对应
- name: vol-1
mountPath: /usr/share/nginx/html/
readOnly: true
- name: vol-2
mountPath: /etc/nginx/conf.d/
readOnly: true
- name: vol-4
mountPath: /etc/podinfo #会在容器中生成一个/etc/podinfo/label文件,名字由前面volumes指定
env: #设置环境变量,与前面volumes无任何关系
- name: user #需要设置的环境变量值
valueFrom:
secretKeyRef: #来自名称空间中secret类型
key: user #赋值为user的值
name: mysql-secret #取自名称空间中的mysql-secret
- name: pass
valueFrom:
secretKeyRef:
key: pass
name: mysql-secret
- name: nginx_port
valueFrom:
configMapKeyRef: #来自名称空间中configmap类型
name: test-config4
key: port
- name: nginx_user
valueFrom:
configMapKeyRef:
name: test-config4
key: user
- name: pod_name
valueFrom:
fieldRef: #使用downwardAPI获取
fieldPath: metadata.name #通过-o yaml查看pod的层级关系
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
startupProbe: #定义启动探针进行健康检查
exec: #指定使用的类型为命令类型
command:
- "/bin/bash"
- "-c"
- "cat /usr/share/nginx/html/index.html"
# httpGet: #指定使用的类型为页面访问类型
# path: /index.html
# port: 80
# tcpSocket: #指定使用的类型为查看端口套接字类型
# port: 80
initialDelaySeconds: 5 #健康检查,在容器启动5s后开始执行,单位“秒”,默认是0秒
periodSeconds: 5 #执行探测的时间间隔(单位是秒),默认为 10s,单位“秒”,最小值是1
timeoutSeconds: 2 #表示容器必须在2s内做出相应反馈给probe,否则视为探测失败,默认值为1
successThreshold: 1 #连续探测几次成功,才认为探测成功,探测1次成功表示成功,最小值为1
failureThreshold: 3 #探测失败的重试次数,重试一定次数后将认为失败,默认为3,最小值为1
livenessProbe:
exec:
command:
- "/bin/bash"
- "-c"
- "cat /usr/share/nginx/html/index.html"
initialDelaySeconds: 5
periodSeconds: 5
readinessProbe:
exec:
command:
- "/bin/bash"
- "-c"
- "cat /usr/share/nginx/html/index.html"
initialDelaySeconds: 5
periodSeconds: 5
- name: mysql
image: daocloud.io/library/mysql:5.7
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3306
name: mysql
protocol: TCP
volumeMounts: #挂载投射数据卷,与前面的volumes对应
- name: vol-3
mountPath: /etc/
env: #设置环境变量,与前面volumes无任何关系
- name: MYSQL_ROOT_PASSWORD #需要设置的环境变量值
valueFrom:
secretKeyRef: #类型为secret
key: pass
name: mysql-secret
- name: busybox
image: daocloud.io/library/busybox
stdin: true #标准输入
tty: true #终端
4.创建secret
密码加密算法为base64
# echo "Secret@123" | base64
可以echo U2VjcmV0QDEyMwo= |base64 --decode
---
apiVersion: v1
kind: Secret
metadata:
name: secret-1
type: Opaque #模糊,base64编码;kubernetes.io/service-account-token;kubernetes.io/dockerconfigjson;kubernetes.io/tls
data:
user: YWRtaW4= #echo -n 'admin' | base64
pass: U2VjcmV0QDEyMwo= #echo "Secret@123" | base64
---
apiVersion: v1
kind: Pod
metadata:
name: pod
spec:
containers:
- name: test
image: daocloud.io/library/redis
volumeMounts:
- name: vol-1 #这个名字需要与定义的卷的名字一致
mountPath: "/etc/foo" #挂载到容器里哪个目录下,随便写
readOnly: true
volumes:
- name: vol-1
secret:
secretName: secret-1 #调用上面定义的secret
5.创建volume并挂载
---
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仓库
1.在所有节点上配置harbor仓库的地址
cat /etc/docker/daemon.json
{
"insecure-registries": ["192.168.116.141"]
}# systemctl daemon-reload
# systemctl restart docker
2.cat /root/.docker/config.json | base64 -w 0
---
apiVersion: v1
kind: Secret
metadata:
name: harbor-secret
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-secret
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 apply -f 创建。
---
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
---
apiVersion: v1
kind: Pod #类型为pod
metadata:
name: pod-1 #pod名称
spec:
volumes: #使用投射数据卷
- name: vol-2
configMap: #类型为config
name: test-config4
items:
- key: upstream.conf #configmap中的key
path: upstream.conf #挂载到容器目录下的upstream.conf中
- name: vol-3
configMap:
name: test-config4
items:
- key: my.cnf
path: my.cnf
containers:
- name: nginx
image: daocloud.io/library/nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
volumeMounts: #挂载投射数据卷,与前面的volumes对应
- name: vol-2
mountPath: /etc/nginx/conf.d/
readOnly: true
env: #设置环境变量,与前面volumes无任何关系
- name: nginx_port
valueFrom:
configMapKeyRef: #来自名称空间中configmap类型
name: test-config4
key: port
- name: nginx_user
valueFrom:
configMapKeyRef:
name: test-config4
key: user
- name: mysql
image: daocloud.io/library/mysql:5.7
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3306
volumeMounts: #挂载投射数据卷,与前面的volumes对应
- name: vol-3
mountPath: /etc/conf.d
8.创建serviceAccount
kubectl create serviceaccount mysa #创建serviceaccount mysa
kubectl describe sa mysa #查看mysa信息
---
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
labels:
app: my-pod
spec:
containers:
- name: my-pod
image: daocloud.io/library/nginx
ports:
- name: http
containerPort: 80
serviceAccountName: mysa #定义使用哪个serviceAccount与API-server通信
9.创建Role和RoleBending
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""] #""表明使用默认的api-server组
resources: ["pods"]
verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: default
subjects: #可以指定不止一个subject(主体)
- kind: User
name: jack #该账号在下面的第九部分中创建
apiGroup: rbac.authorization.k8s.io
roleRef: #roleRef指定与某Role或ClusterRole的绑定关系
kind: Role #此字段必须是Role或ClusterRole
name: pod-reader #此字段必须与你要绑定的Role或ClusterRole的名称匹配
apiGroup: rbac.authorization.k8s.io
RoleBinding 也可以引用 ClusterRole,以将对应 ClusterRole 中定义的访问权限授予 RoleBinding 所在名字空间的资源。这种引用使得你可以跨整个集群定义一组通用的角色, 之后在多个名字空间中复用。
10.创建ClusterRole和ClusterRoleBinding
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"] #如果是所有资源,可以写"*"
verbs: ["get", "watch", "list"] #如果是所有权限,可以写"*"
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: read-secrets-global
subjects:
- kind: Group #主体分三种User、Group、ServiceAccount
name: manager
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
11.创建Deployment
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: default
labels:
web: nginx
spec:
replicas: 3
selector:
matchLabels:
web: nginx
template:
metadata:
labels:
web: nginx
spec:
containers:
- name: nginx
image: daocloud.io/library/nginx:1.18
ports:
- containerPort: 80
volumeMounts:
- name: vol-1
mountPath: "/opt"
12.创建service
需要先kubectl edit cm kube-proxy -n kube-system
搜索mode:添加为ipvs
---
apiVersion: v1
kind: Service
metadata:
name: nginx-clusterip
labels:
app: svc
server: nginx
spec:
type: ClusterIP #未指定type,即为ClusterIP
selector: #标签选择器
web: nginx
ports:
- name: http
protocol: TCP
port: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-nodeport
labels:
app: svc
server: nginx
namespace: default
spec:
type: NodePort #NodePort模式,用于将服务暴露给外部网络
selector: #service通过标签选择器进行流量的负载均衡
web: nginx
ports:
- name: http
protocol: TCP
port: 80 #用于集群间通信的端口
targetPort: 80 #定义流量转发到pod内的端口,一般设置为与port一致
nodePort: 30001 #定义从集群外部通过节点 IP 地址访问 Service 的端口
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
web: nginx
spec:
replicas: 3
selector:
matchLabels:
web: nginx
template:
metadata:
labels: #service通过标签选择器进行流量的负载均衡
web: nginx
spec:
volumes:
- name: vol-1
hostPath:
path: "/data/nginx"
containers:
- name: nginx
image: daocloud.io/library/nginx:1.18
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
volumeMounts:
- name: vol-1
mountPath: "/usr/share/nginx/html/"
13.创建ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: / #地址重定向
spec:
ingressClassName: nginx-example
rules:
- host: "test.ingress" #如果没有域名,做完需要在访问机子的hosts文件中添加node机IP host
http:
paths:
- path: / #指定访问的路径
pathType: Prefix #前缀相同即可转发,exact请求路径要与定义path完全一致才可转发
backend:
service:
name: test
port:
number: 80
关于http域名的转发
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-wildcard-host
spec:
rules:
- host: "foo.bar.com"
http:
paths:
- pathType: Prefix
path: "/bar"
backend:
service:
name: service1
port:
number: 80
- host: "*.foo.com" #*只能代表一级子域名,零或者多都匹配不到
http:
paths:
- pathType: Prefix
path: "/foo"
backend:
service:
name: service2
port:
number: 80
ingress如何制作https的域名流量转发
---
apiVersion: v1
kind: Secret
metadata:
name: testsecret-tls
namespace: default
data:
tls.crt: base64 编码的证书
tls.key: base64 编码的私钥
type: kubernetes.io/tls
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-example-ingress
spec:
tls:
- hosts:
- https-example.foo.com
secretName: testsecret-tls
rules:
- host: https-example.foo.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: service1
port:
number: 80
14.创建pv与pvc
创建pv
apiVersion: v1
kind: PersistentVolume #类型定义为pv
metadata:
name: my-pv #pv的名字
labels: #定义标签
type: nfs
spec:
storageClassName: nfs # 存储类型,需要与底层实际的存储一致,这里采用 nfs
nfs: # 定义nfs的配置信息
server: 192.168.122.24 # NFS服务器的 IP
path: "/mnt/data" # NFS上共享的目录
capacity: #定义存储能力
storage: 3Gi #指定存储空间
accessModes: #定义访问模式
- ReadWriteMany #读写权限,允许被多个Node挂载
persistentVolumeReclaimPolicy: Retain #定义数据回收策略,这里是保留
创建pvc
---
apiVersion: v1
kind: PersistentVolumeClaim #定义类型为PVC
metadata:
name: mypvc #声明pvc的名称,当做pod的卷使用时会用到
spec:
accessModes: #定义访问pvc的模式,与pv拥有一样的模式
- ReadWriteMany #读写权限,允许被多个pod挂载
resources: #声明可以请求特定数量的资源,目前仅支持 request.storage 的设置,即存储空间大小。
requests:
storage: 3Gi #定义空间大小
storageClassName: nfs #指定绑定pv的类型,即使不指定类型pvc也会自动去匹配对应大小的pv
15.创建StatefulSet
---
apiVersion: v1
kind: Service #定义无头服务
metadata:
name: web-svc
labels:
app: web
spec:
ports:
- port: 80 #定义svc的端口
clusterIP: None #定义none表示该svc没有clusterip也称为无头服务
selector: #定义标签选择器,关联带有该标签的pod
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
namespace: default
labels:
app: web
spec:
replicas: 3
selector: #定义statefulset要管理带有某个标签的pod
matchLabels:
app: nginx
serviceName: web-svc #指定管理的svc的名字
volumeClaimTemplates: #定义持久化存储卷的申请模版
- metadata: #定义模版的名字
name: www #创建的pvc名字
spec:
accessModes: ["ReadWriteOnce"] #定义卷的访问模式
storageClassName: nfs #定义卷的类型,以上两个值都需要与定义的pv一致才能自动匹配到对应的pv
resources:
requests:
storage: 2Gi #定义卷的大小
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: daocloud.io/library/nginx:1.16
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
volumeMounts:
- name: www #卷的名字,与卷模版的名字一样即可
mountPath: /usr/share/nginx/html
六、查看pod资源cpu内存占用率的工具——Metrics Server
在master一台节点上安装daes-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:用于获取pod的基本信息,不需要创建资源使用,直接在pod资源中指定要获取的基本信息赋给环境变量或者做成卷挂载到容器中就行
ServiceAccountToken:为pod内的进程与api-server通信时提供一个身份认证,默认创建Namespace的时候会自动生成一个default账号,而UserAcoount是人为设计的,能够跨名称空间与api-server进行通信使用kubectl config view能够查看集群的UserAcoount,默认user: kubernetes-admin
使用kuctlctl get sa,secret -n default可以查看默认名称空间的默认service account和其token
secret类型:
1.kubernetes.io/service-account-token:存储service-account信息。
2.opaque:base64:编码格式的Secret,用来存储密码、秘钥等。
3.kubernetes.io/dockerconfigjson:用来存储私有docker registry的认证信息。
4.kubernetes.io/tls:此类型仅用于存储私钥和证书。
九、RBAC(基于角色的访问控制)
在Kubernetes中,授权有ABAC(基于属性的访问控制)、RBAC(基于角色的访问控制)、Webhook、Node、AlwaysDeny(一直拒绝)和AlwaysAllow(一直允许)这6种模式。
UserAcoount如何对k8s进行操作:
1.需要给操作集群的用户与api-server做认证,这样才可以访问api-server。
2.还需要给这个用户授予相应的权限才可以实现对集群的各种资源进行操作。
在RABC API中,通过如下的步骤进行授权:
1.定义角色:在定义角色时会指定此角色对于资源的访问控制的规则。
2.绑定角色:将主体与角色进行绑定,对用户进行访问授权。k8s中角色分为两个级别:
1.普通角色Role:一个Role对象只能用于授予对某一单一命名空间中资源的访问权限,普通角色只是在当前的名称空间生效,允许的操作有get,list,update,create,delete等。
2.集群角色ClusterRole:整个Kubernetes集群范围内有效的角色则通过ClusterRole对象实现,可以访问整个集群资源,允许操作的对象有pod,svc等资源。
1.创建用户
1.创建私钥
# (umask 077; openssl genrsa -out jack.key 2048)
2.用私钥创建一个csr(证书签名请求)文件
# openssl req -new -key jack.key -out jack.csr -subj "/CN=jack"
3.拿着私钥和请求文件生成证书
# openssl x509 -req -in jack.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out jack.crt -days 365
4.生成用户
# kubectl config set-credentials jack --client-certificate=jack.crt --client-key=jack.key --embed-certs=true
2.设置上下文环境
指的是创建这个账号的环境在当前名称空间中
# kubectl config set-context jack@kubernetes --cluster=kubernetes --user=jack
3.切换用户(切换上下文)
# kubectl config use-context jack@kubernetes
# kubectl config current-context jack@kubernetes #验证是否已经切换到了新的用户
4.创建角色与角色绑定用户
参见5.9
十、容器监控检查及恢复机制
1.探针的类型
k8s支持启动startupProbe和就绪readinessProbe还有存活livenessProbe(启动探针)三种种探针
1.startupProbe(启动探针):指示容器中的应用是否已经启动,最先执行,如果启动探针检测失败,其他两个探针不运行。
2.livenessProbe(存活探针):指示容器里面的程序是否正在运行,关注的是容器的健康状态,一旦发现容器不再健康,就会重启容器。
3.readinessProbe(就绪探针):指示容器是否准备好服务请求。如果探测失败,Kubernetes 会暂时将该容器从服务的 endpoint 列表中移除,关注的是容器是否准备好服务请求,如果没有准备好,就不会将其加入服务的负载均衡中。
2.探针的定义方式
1.Exec:Probe执行容器中的命令并检查命令退出的状态码,如果状态码为0则说明已经就绪。
2.HTTP GET:往容器的IP:Port发送HTTP GET请求,如果Probe收到2xx或3xx,说明已经就绪。
3.TCP Socket:尝试与容器建立TCP连接,如果能建立连接说明已经就绪。
3.探针的检测结果
探针探测结果有以下值:
1.Success:表示通过检测。
2.Failure:表示未通过检测。
3.Unknown:表示检测没有正常进行。
4.定义探针
见5.3
5.容器的重启策略
Pod 的重启策略:
可以通过设置 restartPolicy,改变 Pod 的恢复策略。一共有3种:
1. Always: 在任何情况下,只要容器不在运行状态,就自动重启容器;
2. OnFailure: 只在容器 异常时才自动重启容器;
3. Never: 从来不重启容器。
实际使用时,需要根据应用运行的特性,合理设置这三种恢复策略。
十一、Deployment副本控制器资源详解
为了降低单节点故障与访问压力过大的问题,引入了副本概念。就是同时创建多个相同的pod提供相同的服务。
Deployment是k8s中最常用的资源对象,为ReplicaSet和Pod的创建提供了一种声明式的定义方法,官方建议使用Deployment管理ReplicaSets,而不是直接使用ReplicaSets,是因为Deployment 还负责在 Pod 定义发生变化时,对每个副本进行滚动更新(Rolling Update)。
每创建一个Deployment控制器都会创建一个对应的ReplicaSet,在通过ReplicaSet去创建pod,删除Deployment,同时也会删除对应的ReplicaSet和Pod。
Deployment的优势:1.定义pod的副本。2.实现蓝绿发布和金丝雀发布。3.能够实现弹性的伸缩扩容以及滚动更新(指定ReplicaSet的副本个数进行伸缩扩容、滚动:关闭一个旧的,启动一个新的,平滑升级)。
Deployment创建出来会创建Replicaset(使用父对象的名字+指定字符串为名字,如dep-nginx-0fdsa3),真正的Pod是由Replicaset控制的,可能运行在同一个节点上(Pod的名字也是随机生成的,使用父对象的名字+随机字符串生成,如dep-nginx-0fdsa3-ds3k,但是会对Pod打标签,用于给Replicaset管理pod,副本的Pod标签是相同的)。
Deployment与Daemonset的区别:Deployment只能指定创建副本的数量,无法保证副本创建在每个节点上,可能会出现同一个节点上创建多个Pod的情况存在,而DaemonSet能够实现每个节点上运行一个Pod。
创建Deployment详见5.11
十二、控制器模式解析
k8s 项目通过一个称作"控制器模式"(controller pattern)的设计方法,来统一地实现对各种不同的对象或者资源进行的编排操作。
kube-controller-manager 组件:这个组件,就是一系列控制器的集合。
控制器类型:
deployment job podautoscaler
cloud disruption namespace
replicaset serviceaccount volume
cronjob garbagecollector nodelifecycle
replication statefulset daemonset每一个控制器,都以独有的方式负责某种编排功能,而被控制对象的定义,则来自于一个"模板"。比如,Deployment 里的 template 字段。所有被这个 Deployment 管理的 Pod 实例,都是根据这个 template 字段的内容创建出来的。
1.水平扩展Deployment副本数量的方法
1.命令方式:
kubectl scale deployment/nginx-deployment --replicas=10
2.yaml文件方式:
3.edit在线编辑
kubectl edit deployment/nginx-deployment
2.滚动更新
kubectl edit deployment/nginx-deployment
3.版本回滚
1.查看版本历史
# kubectl rollout history deployment/nginx-deployment
由于在创建这个 Deployment 的时候,没有指定了--record 参数,不会记录创建这些版本时变更的数据
2. 把整个 Deployment 回滚到上一个版本:
# kubectl rollout undo deployment/nginx-deployment
3.查看回滚状态
# kubectl rollout status deployment/nginx-deployment
4.回滚到更早之前的版本:
#默认配置下,Kubernetes 只会保留最近的十个revision,可以在 Deployment 配置文件中通过 revisionHistoryLimit: 属性增加 revision 数量。
查看第三个版本的详细信息:
# kubectl rollout history deployment/nginx-deployment --revision=3
回滚到指定第二个版本:
# kubectl rollout undo deployment/nginx-deployment --to-revision=2
5.命令行更新版本
# kubectl set image deployment/nginx-deployment nginx=nginx:1.20
等号前面的nginx为容器名
十三、ingress
1.ingress和ingress-controller
要理解ingress,需要区分两个概念,ingress和ingress-controller:
ingress对象:
指的是k8s中的一个api对象,一般用yaml配置。作用是定义请求如何转发到service的规则,可以理解为配置模板。ingress-controller:
具体实现反向代理及负载均衡的程序,对ingress定义的规则进行解析,根据配置的规则来实现请求转发。简单来说,ingress-controller才是负责具体转发的组件,通过各种方式将它暴露在集群入口,外部对集群的请求流量会先到ingress-controller,而ingress对象是用来告诉ingress-controller该如何转发请求,比如哪些域名哪些path要转发到哪些服务等等。
2. service和ingress的区别
service 的表现形式为IP:PORT,即工作在第四层传输层(TCP/IP层),对于不同的URL地址经常对应用不同的后端服务或者虚拟服务器,这些应用层的转发机制仅通过kubernetes的service机制是无法实现的,这种情况我么可以使用ingress策略定义和一个具体的ingress Controller.
Ingress提供七层负载均衡能力,可以通过 Ingress 配置提供外部可访问的 URL、负载均衡、SSL、基于名称的虚拟主机等。作为集群流量接入层,Ingress 的高可靠性显得尤为重要。
3.ingress的工作原理
ingress配置中定义转发规则,例如访问site1域名的时候,site1的service会通过标签选择器,把后端对应的pod的ip加端口保存到endpoint列表中,ingress就会从endpoint列表中查询到对应的ip和端口,流量直接流进pod内,实现了对应服务的访问。
ingress配置中定义转发规则,并通过APIserver实时获取service和后端pod的变化,然后动态的更新nginx中的负载均衡器的配置并刷新,达到服务自动发现的作用。
4.部署ingress
1.下载 ingress controller
记得做域名解析
199.232.28.133 raw.githubusercontent.com
需要下载对应版本的
1.3.0的ingress可以支持1.20-1.24的k8s,对应3.16的alphin和1.19.10+的nginx。
2.修改deploy.yaml文件中apiVersion为apps/v1的kind为DaemonSet,用于将ingress调度到每一个节点上;在spec下方添加hostNetwork:True,用于共享主机网络;修改并复制nodeSelector的标签名,在master节点上为所有node添加标签#kubectl label nodes node-1 标签,防止matser和node上存在同一个标签,使ingress被调度到master节点上;最后替换文件中的所有image为阿里云镜像 image: registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:v1.3.0@sha256:d1707ca76d3b044ab8a28277a2466a02100ee9f58a86af1535a3edf9323ea1b5
image: registry.cn-hangzhou.aliyuncs.com/google_containers/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc678686603.#kubectl apply -f deploy.yaml
十四、持久化存储pv&pvc
1.存储的类型
投射数据卷:将容器使用的数据做成一个卷挂载到容器内部供容器使用。
存储卷:将目录或存储设备定义成一个卷挂载到容器内去使用。用于存放容器产生的数据。
2.volume的类型
1.临时空目录(随着Pod的销毁而销毁)
emptyDir:2.配置类(将配置文件以Volume的形式挂载到容器内)
ConfigMap:将保存在ConfigMap资源对象中的配置文件信息挂载到容器内的某个目录下Secret:将保存在Secret资源对象中的密码密钥等信息挂载到容器内的某个文件中。
downwardAPI:将downwardAPI的数据以环境变量或文件的形式注入容器中。
3.本地存储类
hostpath:将宿主机的目录或文件挂载到容器内进行使用。4.共享存储
PV(Persistent Volume):将共享存储定义为一种“持久存储卷”,可以被多个容器应用共享使用。PVC(Persistent Volume Claim):用户对存储资源的一次“申请”,PVC申请的对象是PV,一旦申请成功,应用就能够像使用本地目录一样使用共享存储了。
3.为什么要使用PV
因为pv持久化存储,能把pod的数据永久的保存下来,具有独立的生命周期,不会因为pod的创建而创建,临时占用还会交还存储资源,其后端一般是独立的存储系统如NFS、iSCSI、cephfs、glusterfs等。
4.pv概念与pvc概念
1、PV 概念
PersistentVolume(PV)是集群中的一块存储,可以由管理员配置或者使用存储类(Storage Class)来动态配置。持久卷是集群资源。PV持久卷和普通的 Volume 一样,也是使用卷插件来实现的,pv是对各种诸如NFS、iSCSI、云存储等各种存储为后端所提供的存储(如:可以从远程的NFS 或分布式对象存储系统中创建出PV存储空间大小、访问方式)。PV拥有完全独立的生命周期。
PV 就是从存储设备中的空间创建出一个存储资源。2、PVC概念
PersistentVolumeClaim(PVC) 是用户对存储的请求。概念上与 Pod 类似。Pod会耗用节点资源,而 PVC 申领会耗用 PV 资源。所以用户不能直接使用PV,需要通过pvc先向系统申请存储空间。PVC 的使用逻辑:在pod中定义一个存储卷(该存储卷类型为PVC),PVC必须与对应的PV建立关系,PVC会根据配置定义的时候定义申请的空间大小与访问模式去向PV申请存储空间。
总结:
PV是集群中的资源。 PVC是对这些资源的请求。
PV 和 PVC 可以将 pod 和数据卷解耦,pod 不需要知道确切的文件系统或者支持它的持久化引擎。
5.PV和PVC的生命周期
1.PV 和 PVC 之间的相互作用遵循这个生命周期:
Provisioning(配置) ---> Binding(绑定) ---> Using(使用) ---> Releasing(释放) ---> Recycling(回收)。
-Provisioning,即 PV 的创建,可以直接创建 PV(静态方式),也可以使用 StorageClass 动态创建pv。
StorageClass:是一种用来描述存储卷插件的配置选项的对象,常用于自动化存储卷的创建过程,通过定义存储插件和磁盘类型来描述存储卷的特性和行为,使存储卷的创建更加的灵活,属于资源的一种,元数据里的name就是PVC里storageClassName字段(nfs存储卷直接指定pv类型是nfs)
-Binding,将 PV 分配给 PVC。
-Using,Pod 通过 PVC 使用该Volume,并可以通过准入控制StorageProtection(1.9及以前版本为PVCProtection) 阻止删除正在使用的PVC。
-Releasing,Pod 释放 Volume 并删除 PVC。
-Recycling,回收 PV,可以保留 PV 以便下次使用,也可以直接从云存储中删除。2.回收策略:Retained(保留)、Recycled(回收)、Delete(删除)。
-保留(Retain):会将pv保留下来,卷上仍然存在这前一申领人的数据,该卷还不能用于其他申领,如果想要使用得手动删除。
-删除(Delete):解绑的时候会把pv和pv里面的数据全部删除,动态模式的回收策略默认为Delete。
-回收(Recycled):保留pv只是清楚pv内的数据,以供pv可以重新使用,只有NFS和HostPath两种类型的pv支持,已经弃用,建议使用动态模式制备pv。
PV生命周期的各个阶段:
- Available:可用状态,还未与某个 PVC 绑定。
- Bound:已与某个 PVC 绑定。
- Released:释放,绑定的 PVC 已经删除,但没有被集群回收存储空间 。
- Failed:自动资源回收失败。
PV的创建分为两种模式:
1.静态创建:由系统管理员负责创建、提供、维护,系统管理员为用户屏蔽真正提供存储的后端及其实现细节,普通用户作为消费者,只需通过PVC申请、使用此类资源。
2.动态创建:定义StorageClass,存储插件为永久存储插件,磁盘类型可以指定为标准磁盘,然后用户直接创建 PVC指定使用上面的StorageClass,并在其中定义好 PV 的属性,比如存储类型、大小,然后 Kubernetes 就会调用 StorageClass 声明的存储插件,自动创建需要的 PV 并进行绑定。
一个PV从创建到销毁的具体流程:
一个PV创建完后状态会变成Available,等待被PVC绑定。
一旦被PVC邦定,PV的状态会变成Bound,就可以被定义了相应PVC的Pod使用。
Pod使用完后会释放PV,PV的状态变成Released。
变成Released的PV会根据定义的回收策略做相应的回收工作。
PV与PVC的绑定
用户创建包含容量、访问模式等信息的PVC,向系统请求存储资源。系统查找已存在PV或者监控新创建PV,如果与PVC匹配则将两者绑定。
如果PVC创建动态PV,则系统将一直将两者绑定。PV与PVC的绑定是一一对应关系,不能重复绑定。如果系统一直没有为PVC找到匹配PV,则PVC会一直处在pending状态,直到系统找到匹配PV。实际绑定的PV容量可能大于PVC中申请的容量。
6.持久卷PV的类型
- GCEPersistentDisk
- AWSElasticBlockStore
- AzureFile
- AzureDisk
- FC (Fibre Channel)
- Flexvolume
- Flocker
- NFS
- iSCSI
- RBD (Ceph Block Device)
- CephFS
- Cinder (OpenStack block storage)
- Glusterfs
- VsphereVolume
- Quobyte Volumes
- HostPath (Single node testing only – local storage is not supported in any way and WILL NOT WORK in a multi-node cluster)
- Portworx Volumes
- ScaleIO Volumes
- StorageOS
7.pv的访问模式
1.ReadWriteOnce(RWO)
卷可以被一个节点以读写方式挂载。 ReadWriteOnce 访问模式仍然可以在同一节点上运行的多个 Pod 访问该卷。 对于单个 Pod 的访问,请参考 ReadWriteOncePod 访问模式。
2.ReadOnlyMany(ROX)
卷可以被多个节点以只读方式挂载。
3.ReadWriteMany(RWX)
卷可以被多个节点以读写方式挂载。
4.ReadWriteOncePod(RWOP)
卷可以被单个 Pod 以读写方式挂载。 如果你想确保整个集群中只有一个 Pod 可以读取或写入该 PVC, 请使用 ReadWriteOncePod 访问模式。
8.实验mysql基于NFS共享存储实现静态持久化存储
1.制作nfs服务端作为共享文件系统(在nfs服务器上)
# yum install -y nfs-utils rpcbind
# mkdir /mnt/data #制作共享目录
# vim /etc/exports
/mnt/data 192.168.122.0/24(rw,no_root_squash)# systemctl start rpcbind nfs #启动服务
2.集群工作节点安装客户端工具
# yum install -y nfs-utils #不用启动服务
3.制作pv .yaml (在master)
见5.14.1
# kubectl apply -f pv.yaml
4.制作pvc
见5.14.2
# kubectl apply -f pvc.yaml
5.创建secret
# echo -n 'QianFeng@123!' | base64
# vim mysql-secret.yaml
见5.4.1
# kubectl apply -f mysql-secret.yaml
6.创建myslq-pod文件
mysql-pod.yaml
见下图
7.验证(去nfs机器上)
# ll /mnt/nfs
---
apiVersion: v1
kind: Pod
metadata:
name: my-mysql
labels:
db: mysql
spec:
containers:
- name: my-mysql
image: daocloud.io/library/mysql:5.7
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: secret-1
key: pass
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
volumes:
- name: mysql-data
persistentVolumeClaim: #定义卷的类型为pvc
claimName: pvc #指定对应pvc的名字
十五、Statefulset有状态服务控制器
1.k8s有状态服务和无状态服务的区别
无状态服务特点:
1. 不需要持久化存储,多个实例共享相同的数据。
2. 启动无顺序,pod名字是随机生成的
3. 扩缩容都是随机的。
有状态服务特点:
1. 需要本地持久化存储,如:mysql/kafka/zookeeper/redis主从架构。
2. 实例之间有依赖的关系,比如,主从关系,启动顺序,pod的名字是有顺序的。
3. 如果停止集群中任一实例pod,就可能会导致数据丢失或者集群失败。4. 创建有状态服务的方式:StatefulSet管理。
2. StatefulSet的组成部分
1. Headless Service:无头服务,用于为Pod资源标识符生成可解析的DNS记录。
2. volumeClaimTemplates:存储卷申请模板,创建pvc,指定pvc名称大小,自动创建pv,且pv由存储类供应。
3. StatefulSet:管理有状态的pod实例的。注:Headless service不分配cluster IP,headless service可以通过解析service的域名,返回所有Pod的endpoint列表。
1.headless service会为service分配一个域名。
2.StatefulSet会为关联的Pod定义一个不变的Pod Name:名字格式为$(StatefulSet name)-$(pod序号),序号从0开始。
3.StatefulSet会为关联的Pod分配一个dnsName
$<Pod Name>.$<service name>.$<namespace name>.svc.cluster.local。
3.Statefulset管理有状态的应用,Pod有一下特点:
1. Statefulset管理的pod会被分配一个唯一序号:由statefulset的名字-0、1、2这种格式组成。
2. 创建statefulset资源的时候,须事先创建好一个service,如果创建的service没有ip,那对这个service做dns解析,会找到它所关联的pod ip。
3. statefulset管理的pod是有顺序的,Pod在被部署、扩展、收缩、删除和更新时,都会按照顺序执行。新创建的pod名字跟删除的pod名字是一样的。
4. statefulset具有volumeclaimtemplate这个字段,这个是卷申请模板,会自动创建pv,pvc也会自动生成,跟pv进行绑定,创建的pod数据目录是独享的,即使Pod被重新调度后,仍然能挂载原有的PV,从而保证了数据的完整性和一致。
十六、金丝雀发布和蓝绿发布
蓝绿发布:两套环境交替升级,旧版本保留一定时间便于回滚特点:对用户无感,是最安全的发布方式,需要两套系统,对资源要求比较高,成本高。
金丝雀发布(又称灰度发布、灰度更新):金丝雀发布一般先发1台,或者一个小比例,例如5%的服务器,主要做流量验证用,也称为金丝雀 (Canary) 测试(国内常称灰度测试)。
1.准备两个版本德镜像文件
[root@master03 v1]# cat nginx.repo
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=0
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
[root@master03 v1]# cat Dockerfile
FROM centos:7
ADD . /etc/yum.repos.d
RUN yum install -y nginx && yum clean all && echo v1 > /usr/share/nginx/html/index.html
EXPOSE 80
CMD ["nginx","-g","daemon off;"]
[root@master03 v1]# docker build -t testpm/nginx-v1:v1.0 .
[root@master03 v2]# cat nginx.repo
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=0
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
[root@master03 v2]# cat Dockerfile
FROM centos:7
ADD . /etc/yum.repos.d
RUN yum install -y nginx && yum clean all && echo v2 > /usr/share/nginx/html/index.html
EXPOSE 80
CMD ["nginx","-g","daemon off;"]
[root@master03 v2]# docker build -t testpm/nginx-v2:v2.0 .
将镜像保存为tar包并传送到node节点(实际工作中直接将镜像上传到harbor仓库)
[root@master03 ~]# docker save -o nginx-v1.tar testpm/nginx-v1:v1.0
[root@master03 ~]# docker save -o nginx-v2.tar testpm/nginx-v2:v2.0
[root@master03 ~]# scp nginx-v* node-1:/root/
nginx-v1.tar 100% 233MB 91.6MB/s 00:02
nginx-v2.tar 100% 233MB 105.4MB/s 00:02
[root@master03 ~]# scp nginx-v* node-2:/root/
nginx-v1.tar 100% 233MB 94.7MB/s 00:02
nginx-v2.tar 100% 233MB 103.4MB/s 00:02
[root@node-1 ~]# docker load -i nginx-v1.tar
[root@node-1 ~]# docker load -i nginx-v2.tar
[root@node-2 ~]# docker load -i nginx-v1.tar
[root@node-2 ~]# docker load -i nginx-v2.tar
2.创建版本为v1的deploy
[root@master01 deploy]# cat app-v1.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-v1
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: myapp
version: v1
template:
metadata:
namespace: default
labels:
app: myapp
version: v1
spec:
containers:
- name: myapp
image: testpm/nginx-v1:v1.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
[root@master01 deploy]# kubectl apply -f app-v1.yml
[root@master01 deploy]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp-v1-654dd88f7f-49vbj 1/1 Running 0 5m31s 10.244.3.18 node-1 <none> <none>
myapp-v1-654dd88f7f-fvdhm 1/1 Running 0 5m31s 10.244.3.19 node-1 <none> <none>
myapp-v1-654dd88f7f-r8wdk 1/1 Running 0 10m 10.244.4.6 node-2 <none> <none>
[root@master01 deploy]# curl 10.244.3.18
v1
2.定义svc用来暴露服务
[root@master01 deploy]# cat app-svc.yml
apiVersion: v1
kind: Service
metadata:
name: myapp-svc
namespace: default
labels:
app: myapp
spec:
type: NodePort
ports:
- port: 80
nodePort: 30070
targetPort: 80
selector:
app: myapp
version: v1
[root@master01 deploy]# kubectl apply -f v1-svc.yml
3. 打开一个标签进行灰度发布
[root@master02 ~]# kubectl set image deployment myapp-v1 myapp=testpm/nginx-v2:v2.0 && kubectl rollout pause deployment myapp-v1
通过运行一段时间发现新版本的pod并没有出现问题,那么现在进行全部更新,将暂停取消
[root@master02 ~]# kubectl rollout resume deployment myapp-v1
4.蓝绿发布
准备v1环境的deployment和v2环境的deployment,并重新定义service里的标签选择器选择标签版本,更换为v2版本的,如果出现问题,及时回滚至v1版本,并修改bug,如果没有问题则更新成功。