K8S设计理念-分层架构
核心层
包括K8S的API(内置API:部署好后自带的API接口;自定义资源:CRD,部署K8S后通过安装其他组件等方式扩展出来的API。/apis分类/myapiAPI组/v1API版本/pods)资源对象、控制器、service、namespace、node等,是运行pod的基础环境。
应用层
实现服务部署(
无状态应用
如nginx使用deployment,
有状态应用
如mysql主从redis选举使用statefulSet)和路由(通过service实现服务之间调用)
管理层
实现自动化(如pod弹性伸缩,动态存储卷创建和回收)和策略管理(资源限制,RBAC授权,NetworkPolicy等,主要解决项目之间的pod隔离,网络安全和自动伸缩等功能)
接口层
包括kubectl命令行客户端工具和SDK(dashboard)等客户端访问接口
云原生生态系统
是在接口层只是的K8S集群管理调度生态系统,有两个范畴:K8S内部:CRI(容器运行时接口,主要实现容器运行)、CNI(网络接口,创建容器和删除容器时地址分配和回收,创建容器网络规则如calicoctl,flannel)、CSI(存储接口如nfs)、镜像仓库;K8S外部:监控、日志、CI/CD、配置管理等
K8S设计理念-API设计原则
- 所有API应该是声明式的。
- ·API对象是彼此互补而且可组合的。·
- 高层API以操作意图为基础设计。·
- 低层API根据高层API的控制需要设计.
- ·尽量避免简单封装,不要有在外部API无法显式知道的内部隐藏的机制。
- API操作复杂度与对象数量成正比。
- API对象状态不能依赖于网络连接状态
- ·尽量避免让操作机制依赖于全局状态,因为在分布式系统中要保证全局状态的同步是非常困难的
K8S 内置API以及资源对象简介
内置API接口查询方法
#kubectl get secrets -A | grep admin
kubernetes-dashboard admin-token-fsfb2 kubernetes.io/service-account-token 3 4d22h
kubectl describe secrets admin-token-fsfb2 -n kubernetes-dashboard #获取token
curl -k --cacert /etc/kubeasz/clusters/k8s-cluster1/ssl/ca.pem -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IlJjVXRjX0FEemIxb0Y0OFIyOU03OFEyNkxNbUJNOV9JS25JNmtXbFBKeWsifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJhZG1pbi10b2tlbi1mc2ZiMiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJhZG1pbiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImFhZmFhY2RjLWUzZWQtNDI0Ni1iOGU5LWQ3NmRlNGJlMmMxZCIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlcm5ldGVzLWRhc2hib2FyZDphZG1pbiJ9.KTsRFF2WW8tC4J34RV-w2JJdWSYnwfrJwZAvg2JAN3In-2bk5Y_P41y6M-KlxdR05N5oEZPLu3lyFOvvZdVXaS94U0FBBGmk0IWT89J7Dlw3m3Gt5YZDTW7EdulQl_BAc_OUhYV_yJwKx6CdcAEhfrneLSCm0QX4P1L1ahuaUfAkPLnfyI7taUiJFpGL6roOhEob_zASQ6VrjvyCCONVzmeJPBF-xs2Dnf1kd4GcMOuy1sjgEaCn3JPNnAx-NsTfpgQRMn5U4z8lLzkm5KShVBwNTLTs9U8ynhnb8yVgtxE_AbCL6Jj4I4oVZTjvzPdw2HDSY0AlJhVWU__b364r6Q" https://192.168.226.144:6443
调API接口查询node信息
curl -k --cacert /etc/kubeasz/clusters/k8s-cluster1/ssl/ca.pem -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IlJjVXRjX0FemIxb0Y0OFIyOU03OFEyNkxNbUJNOV9JS25JNmtXbFBKeWsifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJhZG1pbi10b2tlbi1mc2ZiMiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJhZG1pbiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImFhZmFhY2RjLWUzZWQtNDI0Ni1iOGU5LWQ3NmRlNGJlMmMxZCIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlcm5ldGVzLWRhc2hib2FyZDphZG1pbiJ9.KTsRFF2WW8tC4J34RV-w2JJdWSYnwfrJwZAvg2JAN3In-2bk5Y_P41y6M-KlxdR05N5oEZPLu3lyFOvvZdVXaS94U0FBBGmk0IWT89J7Dlw3m3Gt5YZDTW7EdulQl_BAc_OUhYV_yJwKx6CdcAEhfrneLSCm0QX4P1L1ahuaUfAkPLnfyI7taUiJFpGL6roOhEob_zASQ6VrjvyCCONVzmeJPBF-xs2Dnf1kd4GcMOuy1sjgEaCn3JPNnAx-NsTfpgQRMn5U4z8lLzkm5KShVBwNTLTs9U8ynhnb8yVgtxE_AbCL6Jj4I4oVZTjvzPdw2HDSY0AlJhVWU__b364r6Q" https://192.168.226.144:6443/api/v1/nodes
资源类型
资源类型 | 资源名称 |
资源对象 | Pod、ReplicaSet、ReplicationController、Deployment、StatefulSet、DaemonSet、Job、CronJob.HorizontalPodAutoscaling、Node、Namespace、Service、Ingress、Label、CustomResourceDefinition |
存储对象 | Volume、PersistentVolume、PersistentVolumeClaim、Secret、ConfigMap |
策略对象 | SecurityContext.ResourceQuota、LimitRange |
身份对象 | ServiceAccount、Role、ClusterRole |
资源对象操作命令
命令集 |
命令 |
用途 |
基础命令 |
create/delete/edit/get/describe/logs/exec/scale |
增删改查 |
explain |
命令说明 |
|
配置命令 |
Label:给node标记label,实现亲pod 与node亲和性 |
标签管理 |
apply |
动态配置 |
|
集群管理命令 |
cluster-info/top |
集群状态 |
cordon:警戒线,标记node不被调度 uncordon:取消警戒标记为cordon的node drain:驱逐node上的pod,用于node下线等场景 taint:给node标记污点,实现反亲pod 与node反亲和性 |
node节点管理 |
|
config |
客户端kube-ininfig配置 |
|
api-resources/api-versions/version |
api资源 |
K8S的重要概念
-
资源对象:K8S基于声明式API,和资源对象进行交互
-
yaml文件,为了方便后期管理,通过使用yaml文件通过API管理资源对象
-
yaml必须要的字段:
-
apiVersion:创建该对象所使用的API的版本
-
kind:创建的对象类型
-
metadata:定义识别对象的唯一性的数据,包括一个name名称,可选的namespace
-
spec(
期望状态)
:定义资源对象的详细规范信息(统一的label标签、容器名称、镜像、端口映射等)
-
status(
实际状态
):Pod创建完成后K8S自动生成的status状态(实时更新)
job与cronjob区别
Job,主要用于负责批量处理(一次要处理指定数量任务)短暂的一次性(每个任务仅运行一次就结束)任务。Job特点如下:
- 当Job创建的pod执行成功结束时,Job将记录成功结束的pod数量
- 当成功结束的pod达到指定的数量时,Job将完成执行
apiVersion: batch/v1
kind: Job
metadata:
name: job-mysql-init
namespace: linux66
spec:
template:
spec:
containers:
- name: job-mysql-init-container
image: centos:7.9.2009
command: ["/bin/sh"]
args: ["-c", "echo data init job at `date +%Y-%m-%d_%H-%M-%S` >> /cache/data.log"]
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume
hostPath:
path: /tmp/jobdata
restartPolicy: Never # 重启策略只能设置为Never或者OnFailure
关于重启策略设置的说明
:
- 如果指定为OnFailure,则job会在pod出现故障时重启容器,而不是创建pod,failed次数不变
- 如果指定为Never,则job会在pod出现故障时创建新的pod,并且故障pod不会消失,也不会重启,failed次数加1
- 如果指定为Always的话,就意味着一直重启,意味着job任务会重复去执行了,当然不对,所以不能设置为Always
CronJob控制器以Job控制器资源为其管控对象,并借助它管理pod资源对象,Job控制器定义的作业任务在其控制器资源创建之后便会立即执行,但CronJob可以以类似于Linux操作系统的周期性任务作业计划的方式控制其运行时间点及重复运行的方式。也就是说,CronJob可以在特定的时间点(反复的)去运行job任务。
apiVersion: batch/v1
kind: CronJob
metadata:
name: cronjob-mysql-databackup
spec:
#schedule: "30 2 * * *"
schedule: "* * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: cronjob-mysql-databackup-pod
image: centos:7.9.2009
#imagePullPolicy: IfNotPresent
command: ["/bin/sh"]
args: ["-c", "echo mysql databackup cronjob at `date +%Y-%m-%d_%H-%M-%S` >> /cache/data.log"]
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume
hostPath:
path: /tmp/cronjobdata
restartPolicy: OnFailure
schedule: cron表达式,⽤于指定任务的执⾏时间
*/1 * * * *
<分钟> <⼩时> <⽇> <⽉份> <星期>
分钟 值从 0 到 59.
⼩时 值从 0 到 23.
⽇ 值从 1 到 31.
⽉ 值从 1 到 12.
星期 值从 0 到 6, 0 代表星期⽇
多个时间可以⽤逗号隔开; 范围可以⽤连字符给出;*可以作为通配符; /表示每…
concurrencyPolicy:
Allow: 允许Jobs并发运⾏(默认)
Forbid: 禁⽌并发运⾏,如果上⼀次运⾏尚未完成,则跳过下⼀次运⾏
Replace: 替换,取消当前正在运⾏的作业并⽤新作业替换它
RC/RS副本控制器
Replication Controller
:副本控制器,只通过selector标签进行匹配,操作符只支持= !=。创建pod失败、被删除或者被终止时会自动替换
ReplicaSet:与上面区别是除了支持selector,还支持in notin
Deployment控制器
比rs更高一级的控制器,除了拥有rs功能外,还有滚动升级(按照pod数量的25%,
会新启动rs进行创建pod
),回滚(kubectl rollout undo deployment nginx-deployment -n default)等功能
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2
selector:
#app: ng-deploy-80 #rc
matchLabels: #rs or deployment
app: ng-deploy-80
#matchExpressions:
# - {key: app, operator: In, values: [ng-deploy-80,ng-rs-81]}
template:
metadata:
labels:
app: ng-deploy-80
spec:
containers:
- name: ng-deploy-80
image: nginx:1.16.0
ports:
- containerPort: 80
deployment名称-rs名称-pod名称
Service简介
-
由于pod重建之后ip就变了,因此pod之间使用pod的IP直接访问会出现无法访问的问题,而service则解耦了服务和应用,service的实现方式就是通过label标签动态匹配后端endpoint.
-
kube-proxy监听着k8s-apiserver,一旦service资源发生变化(调k8s-api修改service信息), kube-proxy就会生成对应的负载调度的调整,这样就保证service的最新状态.
-
kube-proxy有三种调度模型:userspace: k8s1.1之前;kube-proxy有三种调度模型:userspace: k8s1.1之前;ipvs: k8s 1.11之后,如果没有开启ipvs,则自动降级为iptables。
ingress将请求发送给Kube API Server,Kube API Server创建规则关联到ingress。
客户端通过访问ingresscontroller,ingresscontroller根据现有规则将域名与规则进行匹配,并将请求转给对应service,service(只会请求当前namespace)将请求(默认轮询)转给pod
service类型
ClusterlP
:用于内部服务基于service name的访问,默认
NodePort
:用于kubernetes集群以外的服务主动访问运行在kubernetes集群内部的服务。
LoadBalancer
:用于公有云环境的服务暴露。
ExternalName
:用于将k8s集群外部的服务映射至k8s集群内部访问,从而让集群内部的pod能够通过固定的servicename访问集群外部的服务,有时候也用于将不同namespace之间的pod通过ExternalName进行访问.
ClusterlP
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
name: ng-deployment
spec:
replicas: 1
selector:
#matchLabels: #rs or deployment
# app: ng-deploy3-80
matchExpressions:
- {key: app, operator: In, values: [ng-deploy-80,ng-rs-81]}
template:
metadata:
labels:
app: ng-deploy-80
spec:
containers:
- name: ng-deploy-80-pod
image: nginx:1.17.5
ports:
- containerPort: 80
#nodeSelector:
# env: group1
service.yaml
apiVersion: v1
kind: Service
metadata:
name: ng-deploy-80
spec:
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
type: ClusterIP
selector:
app: ng-deploy-80 #与默认目模板下的app:ng-deploy-80保持一致
NodePort
apiVersion: v1
kind: Service
metadata:
name: ng-deploy-80
spec:
ports:
- name: http
port: 81
targetPort: 80
nodePort: 30012 #不指定会随机分配,每台节点包括master都会监听,访问哪台都可以
protocol: TCP
type: NodePort
selector:
app: ng-deploy-80
Vilume-存储卷简介
Volume将容器中指定数据和容器解耦,并将数据存储到指定位置,不同的存储卷功能不一样,如果基于网络存储的存储卷可实现容器间数据共享和持久化
静态存储卷需要在使用前手动创建PV和PVC,然后绑定到pod使用
常用的几种存储卷:
- emptyDir:本地临时卷。容器所在宿主机本地,不会持久化,容器删除数据删除。用于同一pod内多个数据共享如两个容器日志共享
- hostPath:本地存储卷。容器所在宿主机本地,容器删除不会删除数据,但是容器a迁到b主机,日志数据没法迁移到b主机。
- configmap:配置文件。
- Secret:一种包含少了敏感信息如密码、令牌或密钥的对象
- nfs等:网络存储卷
emptyDir
- 当Pod被分配给节点时,首先创建emptyDir卷,并且只要该Pod在该节点上运行,该卷就会存在,正如卷的名字所述,它最初是空的(联合文件系统),Pod中的容器可以读取和写入emptyDir卷中的相同文件,尽管该卷可以挂载到每个容器中的相同或不同路径上.当出于任何原因从节点中删除Pod时,emptyDir 中的数据将被永久删除。
- /var/lib/kubelet/pods/$ID/volumes/kubernetes.io~empty-dir/cache-volume/$FILE(默认路径)
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels: #rs or deployment
app: ng-deploy-80
template:
metadata:
labels:
app: ng-deploy-80
spec:
containers:
- name: ng-deploy-80
image: nginx
ports:
- containerPort: 80
volumeMounts: #卷挂载指令
- mountPath: /cache #挂载node节点路径
name: cache-volume #通过卷名称匹配挂载
volumes:
- name: cache-volume #声明卷名称
emptyDir: {} #默认信息
容器删除,数据就会被删除
hostPath
hostPath卷将主机节点的文件系统中的文件或目录挂载到集群中,pod删除的时候,卷不会被删除。类似docker -v
容器删除数据还会保留,这是与emptyDir区别
nfs等共享存储
nfs卷允许将现有的NFS(网络文件系统)共享挂载到你的容器中.不像emptyDir,当删除Pod时, nfs卷的内容被保留,卷仅仅是被卸载.这意味着NFS卷可以预填充数据,并且可以在pod之间“切换”数据.NFS 可以被多个写入者同时挂载。
单个共享路径
准备nfs挂载路径
[root@k8s-master1 case7-nfs]# vim /etc/exports
/data/k8sdata/ *(rw,no_root_squash)# *与(中间不能有空格,IP写时候要包括宿主机ip。no_root_squash 不做权限映射,普通用户写的文件不修改为root用户
systemctl restart nfs.service#重启
#验证挂载是否成功
[root@k8s-master1 case7-nfs]# showmount -e 192.168.226.144
Export list for 192.168.226.144:
/data/k8sdata *
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: ng-deploy-80
template:
metadata:
labels:
app: ng-deploy-80
spec:
containers:
- name: ng-deploy-80
image: nginx
ports:
- containerPort: 80
volumeMounts:
- mountPath: /usr/share/nginx/html/mysite
name: my-nfs-volume
volumes:
- name: my-nfs-volume
nfs: #命令kubectl explain Deployment.spec.template.spec.volumes.nfs 查看使用方法
server: 192.168.226.144 #写server地址和共享路径,确保安装nfs-server(yum install nfs-common)并启动
path: /data/k8sdata/linux66
---
apiVersion: v1
kind: Service
metadata:
name: ng-deploy-80
spec:
ports:
- name: http
port: 81
targetPort: 80
nodePort: 30016
protocol: TCP
type: NodePort
selector:
app: ng-deploy-80
容器中没有内核,node节点没有nfs。所以不会是这两个进行挂载,实际是宿主机把192.168.226.144:/data/k8sdata/nfsdata挂载到容器的工作目录,在使用联合文件系统映射到容器中使用
多个共享路径
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-site2
spec:
replicas: 1
selector:
matchLabels:
app: ng-deploy-81
template:
metadata:
labels:
app: ng-deploy-81
spec:
containers:
- name: ng-deploy-81
image: nginx
ports:
- containerPort: 80
volumeMounts:
- mountPath: /usr/share/nginx/html/mysite
name: my-nfs-volume
- mountPath: /usr/share/nginx/html/magedu
name: magedu-statics-volume
volumes:
- name: my-nfs-volume
nfs:
server: 172.31.7.109
path: /data/k8sdata/linux66
- name: magedu-statics-volume
nfs:
server: 172.31.7.110
path: /data/magedu
---
apiVersion: v1
kind: Service
metadata:
name: ng-deploy-81
spec:
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30017
protocol: TCP
type: NodePort
selector:
app: ng-deploy-81
PV/PVC
PersistentVolume(PV)是集群中已经由kubernetes管理员配置的一个网络存储,集群中的存储资源一个集群资源,即不隶属于任何namespace(kubectl api-resources 查看,namespaced那列是false),PV的数据最终存储在硬件存储,pod不能直接挂载PV,PV需要绑定给PVC并最终由pod挂载PVC使用,PV其支持NFS、Ceph、商业存储或云提供商的特定的存储等,可以自定义PV的类型是块还是文件存储、存储空间大小、访问模式等,PV的生命周期独立于Pod,即当使用PV的Pod被删除时可以对PV中的数据没有影响。
PersistentVolumeClaim(PVC):是pod对存储的请求,pod挂载PVC并将数据存储在PVC,而PVC需要绑定到PV才能使用,另外PVC在创建的时侯要知道namespace,即pod要和PVC运行在同一个namespace,可以对PVC设置特定的空间大小和访问模式,使用PVC的pod在删除时也可以对PVC中的数据没有影响。
两者都是逻辑组卷,并不是真正的存储数据
用于实现pod和storage的解耦,这样我们修改storage的时候不需要修改pod。
与NFS的区别,可以在PV和PVC层面实现实现对存储服务器的空间分配、存储的访问权限管理等。kubernetes 从1.0版本开始支持PersistentVolume和PersistentVolumeClaim。
PV挂载模式
注
:每个卷同一时刻只能以一种模式访问,即使该卷支持多种模式
。
- ReadWriteOnce(RWO):被单个客户端以读写权限挂载,适合有状态服务如MySQL主从
- ReadOnlyMany(ROX):可以被多个节点挂载但权限只读比如挂载nginx前端
- ReadWriteMany(RWX):可以被多个节点读写方式挂载使用,如java程序
- ReadWriteOncePod:单次临时挂载
PV/PVC总结
-
PV是对底层网络存储的抽象,即将网络存储定义为一种存储资源,将一个整体的存储资源拆分成多份后给不同的业务使用。
-
PVC是对PV资源的申请调用,pod是通过PVC将数据保存至PV,PV再把数据保存至真正的硬件存储.
。
PV回收策略
- Retain:删除PV后保持原状,需要管理员手动删除,推荐策略
- Recycle:空间回收,删除存储卷所有数据,目前仅支持nfs和hostPath
- Delete:自动删除存储卷
PV
卷类型
定义存储卷使用的文件系统是块设备还是文件系统,默认为文件系统
PVC参数
- ReadWriteOnce(RWO):被单个客户端以读写权限挂载,适合有状态服务如MySQL主从
- ReadOnlyMany(ROX):可以被多个节点挂载但权限只读比如挂载nginx前端
- ReadWriteMany(RWX):可以被多个节点读写方式挂载使用,如java程序
- resources:定义PVC创建存储卷的空间大小,小于等于PV
- selector:#标签选择器,选择要绑定的PV
- matchLabels#匹配标签名称,1
- matchExpressions #基于正则表达式匹配,模糊匹配,2
- volumeName要绑定的PV名称,精确指定,3
Volume 存储卷类型
-
static:静态存储卷,需要在使用前手动创建PV、然后创建PVC并绑定到PV,然后挂载至pod使用,适用于PV和PVC相对比较固定的业务场景。
-
dynamin:动态存储卷,先创建一个存储类storageclass,1后期pod在使用PVC的时候可以通过存储类动态创建PvC,适用于有状态服务集群如MySQL一主多从、zookeeper集群等。
创建静态存储卷
创建PV
apiVersion: v1 #api版本
kind: PersistentVolume #类型为PV
metadata:
name: myserver-myapp-static-pv #PV的名称
spec:
capacity:
storage: 10Gi #分配PV空间大小
accessModes:
- ReadWriteOnce #访问模式,单个pod以读写权限挂载
nfs: #类型为nfs
path: /data/k8sdata/pv-static #nfs路径
server: 192.168.226.144 #nfs地址
验证PV状态
[root@k8s-master1 case8-pv-static]# kubectl get pv #状态必须为Available
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
myserver-myapp-static-pv 10Gi RWO Retain Available 8s
创建PVC绑定PV
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: myserver-myapp-static-pvc #pvc名称
namespace: myserver #pvc的namespace,必须要与业务pod在同一个namespace
spec:
volumeName: myserver-myapp-static-pv #要绑定的PV
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
验证PVC是否绑定到PV
[root@k8s-master1 case8-pv-static]# kubectl get pvc -n myserver
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
myserver-myapp-static-pvc Bound myserver-myapp-static-pv 10Gi RWO 17s
创建业务容器绑定到pvc
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: myserver-myapp
name: myserver-myapp-deployment-name
namespace: myserver
spec:
replicas: 3
selector:
matchLabels:
app: myserver-myapp-frontend
template:
metadata:
labels:
app: myserver-myapp-frontend
spec:
containers:
- name: myserver-myapp-container
image: nginx:1.20.0
#imagePullPolicy: Always
volumeMounts:
- mountPath: "/usr/share/nginx/html/statics" #将容器中该路径进行挂载
name: statics-datadir
volumes:
- name: statics-datadir #声明卷
persistentVolumeClaim: #卷类型为pvc
claimName: myserver-myapp-static-pvc #pvc名称
---
kind: Service
apiVersion: v1
metadata:
labels:
app: myserver-myapp-service
name: myserver-myapp-service-name
namespace: myserver
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30080
selector:
app: myserver-myapp-frontend
验证
创建动态存储卷
动态需要定义存储类。StorageClass为管理员提供了描述存储”类”的方法。不同的类型可能会映射到不同的服务质量等级或备份策略,或是由集群管理员制定的任意策略。Kubernetes本身并不清楚各种类代表的什么。这个类的概念在其他存储系统中有时被称为”配置文件”。
授权
apiVersion: v1
kind: Namespace
metadata:
name: nfs
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner #创建账号用于集群内认证
# replace with namespace where provisioner is deployed
namespace: nfs
---
kind: ClusterRole #角色绑定
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-runner
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-client-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: nfs
roleRef:
kind: ClusterRole
name: nfs-client-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: nfs
rules:
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: nfs
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: nfs
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner
apiGroup: rbac.authorization.k8s.io
创建存储类
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-nfs-storage #存储类名称
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # or choose another name, must match deployment's env PROVISIONER_NAME'
reclaimPolicy: Retain #PV的删除策略,默认为delete,删除PV后立即删除NFS server的数据
mountOptions:
- noresvport #告知NFS客户端在重新建立网络连接时,使用新的传输控制协议源端口
- noatime #访问文件时不更新文件inode中的时间戳,高并发环境可提高性能
parameters:
mountOptions: "vers=4.1,noresvport,noatime"
archiveOnDelete: "true" #删除pod时保留pod数据,默认为false时为不保留数据
创建pod
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-provisioner
labels:
app: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: nfs
spec:
replicas: 1
strategy: #部署策略
type: Recreate #回收策略,重建
selector:
matchLabels:
app: nfs-client-provisioner
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner
containers:
- name: nfs-client-provisioner
#image: k8s.gcr.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2
image: docker.io/shuaigege/nfs-subdir-external-provisioner:v4.0.2 #负责动态创建PV
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env: #声明环境变量到192.168.226.144:/data/k8sdata/pv-dynamic创建PV
- name: PROVISIONER_NAME
value: k8s-sigs.io/nfs-subdir-external-provisioner
- name: NFS_SERVER
value: 192.168.226.144
- name: NFS_PATH
value: /data/k8sdata/pv-dynamic
volumes:
- name: nfs-client-root
nfs:
server: 192.168.226.144
path: /data/k8sdata/pv-dynamic
创建PVC
# Test PVC
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: myserver-myapp-dynamic-pvc
namespace: myserver
spec:
storageClassName: managed-nfs-storage #调用的storageclass 名称
accessModes:
- ReadWriteMany #访问权限
resources:
requests:
storage: 500Mi #空间大小
创建nginx容器挂载pvc
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: myserver-myapp
name: myserver-myapp-deployment-name
namespace: myserver
spec:
replicas: 1
selector:
matchLabels:
app: myserver-myapp-frontend
template:
metadata:
labels:
app: myserver-myapp-frontend
spec:
containers:
- name: myserver-myapp-container
image: nginx:1.20.0
#imagePullPolicy: Always
volumeMounts:
- mountPath: "/usr/share/nginx/html/statics"
name: statics-datadir
volumes:
- name: statics-datadir
persistentVolumeClaim:
claimName: myserver-myapp-dynamic-pvc
---
kind: Service
apiVersion: v1
metadata:
labels:
app: myserver-myapp-service
name: myserver-myapp-service-name
namespace: myserver
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30080
selector:
app: myserver-myapp-frontend
ConfigMaps
Configmap配置信息和镜像解耦,实现方式为将配置信息放到configmap对象中,然后在pod的中作为Volume挂载到pod中,从而实现导入配置的目的。
使用场景
- ·通过Configmap给pod定义全局环境变量
- ·通过Configmap给pod传递命令行参数,如mysql -u -p中的账户名密码可以通过Configmap传递.·
- 通过Configmap给pod中的容器服务提供配置文件,配置文件以挂载到容器的形式使用.
注意事项:
Configmap需要在pod使用它之前创建。
pod只能使用位于同一个namespace的Configmap,及Configmap不能夸namespace使用。通常用于非安全加密的配置场景。
Configmap通常是小于1MB的配置。
案例一
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config #指定configmap名称
data:
default: | #内容
server {
listen 80;
server_name www.mysite.com;
index index.html index.php index.htm;
location / {
root /data/nginx/html;
if (!-e $request_filename) {
rewrite ^/(.*) /index.html last;
}
}
}
---
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: ng-deploy-80
template:
metadata:
labels:
app: ng-deploy-80
spec:
containers:
- name: ng-deploy-80
image: nginx:1.20.0
ports:
- containerPort: 80
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/conf.d/mysite
- name: myserver-nfs
mountPath: /etc/nginx
volumes:
- name: nginx-config #卷名称,随意
configMap:
name: nginx-config #匹配configmap名
items:
- key: default #匹配上面的data.default
path: mysite.conf #将配置文件挂在/etc/nginx/conf.d/mysite
- name: myserver-nfs
nfs:
server: 192.168.226.144
path: /data/k8sdata/configdata
---
apiVersion: v1
kind: Service
metadata:
name: ng-deploy-80
spec:
ports:
- name: http
port: 81
targetPort: 80
nodePort: 30019
protocol: TCP
type: NodePort
selector:
app: ng-deploy-80
Secret
Secret的功能类似于ConfigMap给pod提供额外的配置信息,但是Secret是一种包含少量敏感信息例如密码、令牌或密钥的对象。Secret的名称必须是合法的DNS子域名。
每个Secret的大小最多为1MiB,主要是为了避免用户创建非常大的Secret进而导致API服务器和kubelet内存耗尽,不过创建很多小的Secret也可能耗尽内存,可以使用资源配额来约束每个名字空间中Secret的个数。
在通过yaml文件创建secret时,可以设置data或stringData字段, dat和stringData字段都是可选的, data字段中所有键值都必须是base64编码的字符串,如果不希望执行这种base64字符串的转换操作,也可以选择设置stringData字段,其中可以使用任何非加密的字符串竹为其取值。
Pod可以用三种方式的任意一种来使用Secret:
-
作为挂载到一个或多个容器上的卷中的文件(crt文件、 key文件).作为容器的环境变量.
-
由kubelet在为Pod拉取镜像时使用(与镜像仓库的认证)
Secret类型
-
Opaque:用户定义的任意数据
-
kubernetes.io/service-account-token:ServiceAccount令牌
-
kubernetes.io/dockercfg:~/.dockercfg文件的序列化形式
-
kubernetes.io/dockerconfigjson:~l.dockerlconfig.json文件的序列化形式
-
kubernetes.io/basic-auth:用于基本身份认证的凭据
-
kubernetes.io/ssh-auth:用于SSH身份认证的凭据
-
kubernetes.io/tls:用于TLS环境,保存crt证书和key证书
-
bootstrap.kubernetes.io/token:启动引导令牌数据
案例一
创建secret
apiVersion: v1
kind: Secret
metadata:
name: mysecret-data
namespace: myserver
type: Opaque
data:
user: YWRtaW4K
password: MTIzNDU2Cg==
容器启动并读取secret
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
name: myserver-myapp-app1-deployment
namespace: myserver
spec:
replicas: 1
selector:
matchLabels:
app: myserver-myapp-app1
template:
metadata:
labels:
app: myserver-myapp-app1
spec:
containers:
- name: myserver-myapp-app1
image: tomcat:7.0.94-alpine
ports:
- containerPort: 8080
volumeMounts:
- mountPath: /data/myserver/auth
name: myserver-auth-secret
volumes:
- name: myserver-auth-secret
secret:
secretName: mysecret-data
---
apiVersion: v1
kind: Service
metadata:
name: myserver-myapp-app1
namespace: myserver
spec:
ports:
- name: http
port: 8080
targetPort: 8080
nodePort: 30018
protocol: TCP
type: NodePort
selector:
app: myserver-myapp-app1
流程
创建secret,api-server将数据写到etcd中。在使用时,kubelet调api-server将数据拿到本地宿主机,在挂到容器中使用
案例二-自签名证书
生成自签名证书
openssl req -x509 -sha256 -newkey rsa:4096 -keyout ca.key -out ca.crt -days 3560 -nodes -subj '/CN=www.ca.com'
openssl req -new -newkey rsa:4096 -keyout server.key -out server.csr -nodes -subj '/CN=www.mysite.com'
openssl x509 -req -sha256 -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt
kubectl create secret tls myserver-tls-key --cert=./server.crt --key=./server.key -n myserver
kubectl get secrets myserver-tls-key -n myserver -o yaml
创建web服务
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
namespace: myserver
data:
default: |
server {
listen 80;
server_name www.mysite.com;
listen 443 ssl;
ssl_certificate /etc/nginx/conf.d/certs/tls.crt;
ssl_certificate_key /etc/nginx/conf.d/certs/tls.key;
location / {
root /usr/share/nginx/html;
index index.html;
if ($scheme = http ){ #未加条件判断,会导致死循环
rewrite / https://www.mysite.com permanent;
}
if (!-e $request_filename) {
rewrite ^/(.*) /index.html last;
}
}
}
---
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
name: myserver-myapp-frontend-deployment
namespace: myserver
spec:
replicas: 1
selector:
matchLabels:
app: myserver-myapp-frontend
template:
metadata:
labels:
app: myserver-myapp-frontend
spec:
containers:
- name: myserver-myapp-frontend
image: nginx:1.20.2-alpine
ports:
- containerPort: 80
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/conf.d/myserver
- name: myserver-tls-key
mountPath: /etc/nginx/conf.d/certs
volumes:
- name: nginx-config
configMap:
name: nginx-config
items:
- key: default
path: mysite.conf
- name: myserver-tls-key
secret:
secretName: myserver-tls-key #把这个挂载在/etc/nginx/conf.d/certs
---
apiVersion: v1
kind: Service
metadata:
name: myserver-myapp-frontend
namespace: myserver
spec:
type: NodePort
ports:
- name: http #http
port: 80
targetPort: 80
nodePort: 30018
protocol: TCP
- name: https#https 是30020
port: 443
targetPort: 443
nodePort: 30020
protocol: TCP
selector:
app: myserver-myapp-frontend
验证
案例三-不需要登录下载私有仓库文件
通过docker认证文件创建
docker login k8s-harbor.com
kubectl create secret generic aliyun-registry-image-pull-key \
--from-file=.dockerconfigjson=/root/.docker/config.json \
--type=kubernetes.io/dockerconfigjson \
-n myserver
创建pod
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
name: myserver-myapp-frontend-deployment
namespace: myserver
spec:
replicas: 1
selector:
matchLabels:
app: myserver-myapp-frontend
template:
metadata:
labels:
app: myserver-myapp-frontend
spec:
containers:
- name: myserver-myapp-frontend
image: k8s-harbor.com/test/nginx:v1
ports:
- containerPort: 80
imagePullSecrets:
- name: aliyun-registry-image-pull-key
---
apiVersion: v1
kind: Service
metadata:
name: myserver-myapp-frontend
namespace: myserver
spec:
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30018
protocol: TCP
type: NodePort
selector:
app: myserver-myapp-frontend
验证
kubuectl将请求发给api-server,apiserver将请求写到etcd中,node节点上kubelet发现事件,从api-server拿到secret,并将创建容器请求传给docker,由docker携带认证来下载镜像