容器编排(生产环境 k8s)k8s基础组件
目录
1.3.3 Horizontal Pod Autoscaler(HPA)
一个kubernetes集群主要是由控制节点(master)、工作节点(node)构成,每个节点上都会安装不同的组件。
master:集群的控制平面,负责集群的决策 ( 管理 )
ApiServer : 资源操作的唯一入口,接收用户输入的命令,提供认证、授权、API注册和发现等机制
Scheduler : 负责集群资源调度,按照预定的调度策略将Pod调度到相应的node节点上
ControllerManager : 负责维护集群的状态,比如程序部署安排、故障检测、自动扩展、滚动更新等
Etcd :负责存储集群中各种资源对象的信息,k/v方式存储,所有的 k8s 集群数据存放在此
Kuberctl: 命令行配置工具
node:集群的数据平面,负责为容器提供运行环境 ( 干活 )
Kubelet : 负责维护容器的生命周期,即通过控制docker,来创建、更新、销毁容器,会按固定频率检查节点健康状态并上报给 APIServer,该状态会记录在 Node 对象的 status 中。
KubeProxy : 负责提供集群内部的服务发现和负载均衡
Docker : 负责节点上容器的各种操作
下面,以部署一个nginx服务来说明kubernetes系统各个组件调用关系:
-
首先要明确,一旦kubernetes环境启动之后,master和node都会将自身的信息存储到etcd数据库中
-
一个nginx服务的安装请求会首先被发送到master节点的apiServer组件
-
apiServer组件会调用scheduler组件来决定到底应该把这个服务安装到哪个node节点上
在此时,它会从etcd中读取各个node节点的信息,然后按照一定的算法进行选择,并将结果告知apiServer
-
apiServer调用controller-manager去调度Node节点安装nginx服务
-
kubelet接收到指令后,会通知docker,然后由docker来启动一个nginx的pod
pod是kubernetes的最小操作单元,容器必须跑在pod中至此,
-
一个nginx服务就运行了,如果需要访问nginx,就需要通过kube-proxy来对pod产生访问的代理
这样,外界用户就可以访问集群中的nginx服务了
1.1 kubernetes概念
Master:集群控制节点,每个集群需要至少一个master节点负责集群的管控
Node:工作负载节点,由master分配容器到这些node工作节点上,然后node节点上的docker负责容器的运行
Pod:kubernetes的最小控制单元,容器都是运行在pod中的,一个pod中可以有1个或者多个容器
Controller:控制器,通过它来实现对pod的管理,比如启动pod、停止pod、伸缩pod的数量等等
Service:pod对外服务的统一入口,下面可以维护者同一类的多个pod
Label:标签,用于对pod进行分类,同一类pod会拥有相同的标签
NameSpace:命名空间,用来隔离pod的运行环境
学习kubernetes的核心,就是学习如何对集群上的Pod、Pod控制器、Service、存储
等各种资源进行操作
kubernetes在集群启动之后,会默认创建几个namespace:default、kube-node-lease、kube-public、kube-system
默认情况下,kubernetes集群中的所有的Pod都是可以相互访问的。但是在实际中,可能不想让两个Pod之间进行互相的访问,那此时就可以将两个Pod划分到不同的namespace下。kubernetes通过将集群内部的资源分配到不同的Namespace中,可以形成逻辑上的"组",以方便不同的组的资源进行隔离使用和管理。
1.2 Pod
Pod是kubernetes集群进行管理的最小单元,程序要运行必须部署在容器中,而容器必须存在于Pod中。Pod可以认为是容器的封装,一个Pod中可以存在一个或者多个容器。同一个Pod中的容器共享 IP 地址,进程间的通讯(IPC),主机名以及其他资源。
同一 Node 中的 Pod 的默认路由都是 docker0 的地址,由于他们关联在同一个 docker0 网桥上,地址段相同,所以能直接通信。
不同 Node 中的 Pod 间通信要满足 2 哥条件: Pod 的 IP 不能冲突;将 Pod 的 IP 和所在的 Node 的 IP 关联起来,通过这个关联让 Pod 可以互相访问。
#常用命令
# 查看Pod基本信息
kubectl get pods -n dev
# 查看Pod的详细信息
kubectl describe pod nginx -n dev
# 获取podIP
kubectl get pods -n dev -o wide
#访问POD
curl http://10.244.1.23:80
# 删除指定Pod
kubectl delete pod nginx -n dev
1.2.1 pod的生命周期
pod创建过程
运行初始化容器(init container)过程
运行主容器(main container)
容器启动后钩子(post start)、容器终止前钩子(pre stop)
容器的存活性探测(liveness probe)、就绪性探测(readiness probe)
pod终止过程
在整个生命周期中,Pod会出现5种状态(相位),分别如下:
-
挂起(Pending):apiserver已经创建了pod资源对象,但它尚未被调度完成或者仍处于下载镜像的过程中
-
运行中(Running):pod已经被调度至某节点,并且所有容器都已经被kubelet创建完成
-
成功(Succeeded):pod中的所有容器都已经成功终止并且不会被重启
-
失败(Failed):所有容器都已经终止,但至少有一个容器终止失败,即容器返回了非0值的退出状态
-
未知(Unknown):apiserver无法正常获取到pod对象的状态信息,通常由网络通信失败所导致
pod的创建过程
-
用户通过kubectl或其他api客户端提交需要创建的pod信息给apiServer
-
apiServer开始生成pod对象的信息,并将信息存入etcd,然后返回确认信息至客户端
-
apiServer开始反映etcd中的pod对象的变化,其它组件使用watch机制来跟踪检查apiServer上的变动
-
scheduler发现有新的pod对象要创建,开始为Pod分配主机并将结果信息更新至apiServer
-
node节点上的kubelet发现有pod调度过来,尝试调用docker启动容器,并将结果回送至apiServer
-
apiServer将接收到的pod状态信息存入etcd中
pod的终止过程
-
用户向apiServer发送删除pod对象的命令
-
apiServcer中的pod对象信息会随着时间的推移而更新,在宽限期内(默认30s),pod被视为dead
-
将pod标记为terminating状态
-
kubelet在监控到pod对象转为terminating状态的同时启动pod关闭过程
-
端点控制器监控到pod对象的关闭行为时将其从所有匹配到此端点的service资源的端点列表中移除
-
如果当前pod对象定义了preStop钩子处理器,则在其标记为terminating后即会以同步的方式启动执行
-
pod对象中的容器进程收到停止信号
-
宽限期结束后,若pod中还存在仍在运行的进程,那么pod对象会收到立即终止的信号
-
kubelet请求apiServer将此pod资源的宽限期设置为0从而完成删除操作,此时pod对于用户已不可见
1.3 Pod控制器
Pod是kubernetes的最小管理单元,在kubernetes中,按照pod的创建方式可以将其分为两类:
-
自主式pod:kubernetes直接创建出来的Pod,这种pod删除后就没有了,也不会重建
-
控制器创建的pod:kubernetes通过控制器创建的pod,这种pod删除了之后还会自动重建
什么是Pod控制器
Pod控制器是管理pod的中间层,使用Pod控制器之后,只需要告诉Pod控制器,想要多少个什么样的Pod就可以了,它会创建出满足条件的Pod并确保每一个Pod资源处于用户期望的目标状态。如果Pod资源在运行中出现故障,它会基于指定策略重新编排Pod。
常见的有Pod控制器有下面这些:
-
ReplicationController:比较原始的pod控制器,已经被废弃,由ReplicaSet替代
-
ReplicaSet(RS):保证副本数量一直维持在期望值,并支持pod数量扩缩容,镜像版本升级
-
Deployment:通过控制ReplicaSet来控制Pod,并支持滚动升级、回退版本
-
Horizontal Pod Autoscaler(HPA):可以根据集群负载自动水平调整Pod的数量,实现削峰填谷
-
DaemonSet:在集群中的指定Node上运行且仅运行一个副本,一般用于守护进程类的任务
-
Job:它创建出来的pod只要完成任务就立即退出,不需要重启或重建,用于执行一次性任务
-
Cronjob:它创建的Pod负责周期性任务控制,不需要持续后台运行
-
StatefulSet:管理有状态应用
1.3.1 ReplicaSet(RS)
ReplicaSet的主要作用是保证一定数量的pod正常运行,它会持续监听这些Pod的运行状态,一旦Pod发生故障,就会重启或重建。同时它还支持对pod数量的扩缩容和镜像版本的升降级。
# 查看rs
kubectl get rs pc-replicaset -n dev -o wide
# 编辑rs的副本数量,修改spec:replicas: 6即可
kubectl edit rs pc-replicaset -n dev
# 使用scale命令实现扩缩容, 后面--replicas=n直接指定目标数量即可
kubectl scale rs pc-replicaset --replicas=2 -n dev
# 镜像修改 kubectl set image rs rs名称 容器=镜像版本 -n namespace
kubectl set image rs pc-replicaset nginx=nginx:1.17.1 -n dev
执行RS对象的删除
kubectl delete rs pc-replicaset -n dev
如果希望仅仅删除RS对象(保留Pod),可以使用kubectl delete命令时添加--cascade=false选项(不推荐)。
kubectl delete rs pc-replicaset -n dev --cascade=false
1.3.2 Deployment
为了更好的解决服务编排的问题,kubernetes在V1.2版本开始,引入了Deployment控制器。值得一提的是,这种控制器并不直接管理pod,而是通过管理ReplicaSet来简介管理Pod,即:Deployment管理ReplicaSet,ReplicaSet管理Pod。所以Deployment比ReplicaSet功能更加强大。
Deployment主要功能有下面几个:
-
支持ReplicaSet的所有功能
-
支持发布的停止、继续
-
支持滚动升级和回滚版本
deployment支持版本升级过程中的暂停、继续功能以及版本回退等诸多功能,下面具体来看.
kubectl rollout: 版本升级相关功能,支持下面的选项:
-
status 显示当前升级状态
-
history 显示 升级历史记录
-
pause 暂停版本升级过程
-
resume 继续已经暂停的版本升级过程
-
restart 重启版本升级过程
-
undo 回滚到上一级版本(可以使用--to-revision回滚到指定版本)
# 查看当前升级版本的状态 kubectl rollout status deploy pc-deployment -n dev # 查看升级历史记录 kubectl rollout history deploy pc-deployment -n dev # 版本回滚 # 这里直接使用--to-revision=1回滚到了1版本, 如果省略这个选项,就是回退到上个版本,就是2版本 kubectl rollout undo deployment pc-deployment --to-revision=1 -n dev
金丝雀发布
Deployment控制器支持控制更新过程中的控制,如“暂停(pause)”或“继续(resume)”更新操作。
比如有一批新的Pod资源创建完成后立即暂停更新过程,此时,仅存在一部分新版本的应用,主体部分还是旧的版本。然后,再筛选一小部分的用户请求路由到新版本的Pod应用,继续观察能否稳定地按期望的方式运行。确定没问题之后再继续完成余下的Pod资源滚动更新,否则立即回滚更新操作。这就是所谓的金丝雀发布。
# 更新deployment的版本,并配置暂停deployment
kubectl set image deploy pc-deployment nginx=nginx:1.17.4 -n dev && kubectl rollout pause deployment pc-deployment
# 确保更新的pod没问题了,继续更新
kubectl rollout resume deploy pc-deployment -n dev
1.3.3 Horizontal Pod Autoscaler(HPA)
在前面的课程中,我们已经可以实现通过手工执行kubectl scale
命令实现Pod扩容或缩容,但是这显然不符合Kubernetes的定位目标--自动化、智能化。 Kubernetes期望可以实现通过监测Pod的使用情况,实现pod数量的自动调整,于是就产生了Horizontal Pod Autoscaler(HPA)这种控制器。
HPA可以获取每个Pod利用率,然后和HPA中定义的指标进行对比,同时计算出需要伸缩的具体值,最后实现Pod的数量的调整。其实HPA与之前的Deployment一样,也属于一种Kubernetes资源对象,它通过追踪分析RC控制的所有目标Pod的负载变化情况,来确定是否需要针对性地调整目标Pod的副本数,这是HPA的实现原理。
1.3.4 DaemonSet
DaemonSet类型的控制器可以保证在集群中的每一台(或指定)节点上都运行一个副本。一般适用于日志收集、节点监控等场景。也就是说,如果一个Pod提供的功能是节点级别的(每个节点都需要且只需要一个),那么这类Pod就适合使用DaemonSet类型的控制器创建。
DaemonSet控制器的特点:
-
每当向集群中添加一个节点时,指定的 Pod 副本也将添加到该节点上
-
当节点从集群中移除时,Pod 也就被垃圾回收了
1.3.5 Job
Job,主要用于负责批量处理(一次要处理指定数量任务)短暂的一次性(每个任务仅运行一次就结束)任务。Job特点如下:
-
当Job创建的pod执行成功结束时,Job将记录成功结束的pod数量
-
当成功结束的pod达到指定的数量时,Job将完成执行
1.3.6 Cronjob
CronJob控制器以Job控制器资源为其管控对象,并借助它管理pod资源对象,Job控制器定义的作业任务在其控制器资源创建之后便会立即执行,但CronJob可以以类似于Linux操作系统的周期性任务作业计划的方式控制其运行时间点及重复运行的方式。也就是说,CronJob可以在特定的时间点(反复的)去运行job任务。
1.4 Service
在kubernetes中,pod是应用程序的载体,我们可以通过pod的ip来访问应用程序,但是pod的ip地址不是固定的,这也就意味着不方便直接采用pod的ip对服务进行访问。
为了解决这个问题,kubernetes提供了Service资源,Service会对提供同一个服务的多个pod进行聚合,并且提供一个统一的入口地址。通过访问Service的入口地址就能访问到后面的pod服务。
Service在很多情况下只是一个概念,真正起作用的其实是kube-proxy服务进程,每个Node节点上都运行着一个kube-proxy服务进程。当创建Service的时候会通过api-server向etcd写入创建的service的信息,而kube-proxy会基于监听的机制发现这种Service的变动,然后它会将最新的Service信息转换成对应的访问规则。
kube-proxy目前支持三种工作模式:
userspace 模式
userspace模式下,kube-proxy会为每一个Service创建一个监听端口,发向Cluster IP的请求被Iptables规则重定向到kube-proxy监听的端口上,kube-proxy根据LB算法选择一个提供服务的Pod并和其建立链接,以将请求转发到Pod上。 该模式下,kube-proxy充当了一个四层负责均衡器的角色。由于kube-proxy运行在userspace中,在进行转发处理时会增加内核和用户空间之间的数据拷贝,虽然比较稳定,但是效率比较低。
iptables 模式
iptables模式下,kube-proxy为service后端的每个Pod创建对应的iptables规则,直接将发向Cluster IP的请求重定向到一个Pod IP。 该模式下kube-proxy不承担四层负责均衡器的角色,只负责创建iptables规则。该模式的优点是较userspace模式效率更高,但不能提供灵活的LB策略,当后端Pod不可用时也无法进行重试。
ipvs 模式
ipvs模式和iptables类似,kube-proxy监控Pod的变化并创建相应的ipvs规则。ipvs相对iptables转发效率更高。除此以外,ipvs支持更多的LB算法。
Service常用类型
-
ClusterIP:默认值,它是Kubernetes系统自动分配的虚拟IP,只能在集群内部访问
-
NodePort:将Service通过指定的Node上的端口暴露给外部,通过此方法,就可以在集群外部访问服务
-
LoadBalancer:使用外接负载均衡器完成到服务的负载分发,注意此模式需要外部云环境支持
-
ExternalName: 把集群外部的服务引入集群内部,直接使用
1.4.1 ClusterIP类型的Service
Endpoint
Endpoint是kubernetes中的一个资源对象,存储在etcd中,用来记录一个service对应的所有pod的访问地址,它是根据service配置文件中selector描述产生的。
一个Service由一组Pod组成,这些Pod通过Endpoints暴露出来,Endpoints是实现实际服务的端点集合。换句话说,service和pod之间的联系是通过endpoints实现的。
负载分发策略
对Service的访问被分发到了后端的Pod上去,目前kubernetes提供了两种负载分发策略:
-
如果不定义,默认使用kube-proxy的策略,比如随机、轮询
-
基于客户端地址的会话保持模式,即来自同一个客户端发起的所有请求都会转发到固定的一个Pod上
此模式可以使在spec中添加
sessionAffinity:ClientIP
选项
# 查看service
kubectl get svc -n dev -o wide
# 查看service的详细信息
# 在这里有一个Endpoints列表,里面就是当前service可以负载到的服务入口
kubectl describe svc service-clusterip -n dev
# 查看ipvs的映射规则【rr 轮询】
ipvsadm -Ln
# 查看域名的解析情况
kubectl exec -it pc-deployment-66cb59b984-8p84h -n dev /bin/sh
1.4.2 HeadLiness类型的Service
在某些场景中,开发人员可能不想使用Service提供的负载均衡功能,而希望自己来控制负载均衡策略,针对这种情况,kubernetes提供了HeadLiness Service,这类Service不会分配Cluster IP,如果想要访问service,只能通过service的域名进行查询。
1.4.3 NodePort类型的Service
在之前的样例中,创建的Service的ip地址只有集群内部才可以访问,如果希望将Service暴露给集群外部使用,那么就要使用到另外一种类型的Service,称为NodePort类型。NodePort的工作原理其实就是将service的端口映射到Node的一个端口上,然后就可以通过NodeIp:NodePort
来访问service了。
1.4.4 LoadBalancer类型的Service
LoadBalancer和NodePort很相似,目的都是向外部暴露一个端口,区别在于LoadBalancer会在集群的外部再来做一个负载均衡设备,而这个设备需要外部环境支持的,外部服务发送到这个设备上的请求,会被设备负载之后转发到集群中。
1.4.5 ExternalName类型的Service
ExternalName类型的Service用于引入集群外部的服务,它通过externalName
属性指定外部一个服务的地址,然后在集群内部访问此service就可以访问到外部的服务了。
1.5 Volume
为了持久化保存容器的数据,kubernetes引入了Volume的概念。
Volume是Pod中能够被多个容器访问的共享目录,它被定义在Pod上,然后被一个Pod里的多个容器挂载到具体的文件目录下,kubernetes通过Volume实现同一个Pod中不同容器之间的数据共享以及数据的持久化存储。Volume的生命容器不与Pod中单个容器的生命周期相关,当容器终止或者重启时,Volume中的数据也不会丢失。
kubernetes的Volume支持多种类型,比较常见的有下面几个:
-
简单存储:EmptyDir、HostPath、NFS
-
高级存储:PV、PVC
-
配置存储:ConfigMap、Secret
1.5.1 基本存储
1.5.1.1 EmptyDir
EmptyDir是最基础的Volume类型,一个EmptyDir就是Host上的一个空目录。
EmptyDir是在Pod被分配到Node时创建的,它的初始内容为空,并且无须指定宿主机上对应的目录文件,因为kubernetes会自动分配一个目录,当Pod销毁时, EmptyDir中的数据也会被永久删除。 EmptyDir用途如下:
-
临时空间,例如用于某些应用程序运行时所需的临时目录,且无须永久保留
-
一个容器需要从另一个容器中获取数据的目录(多容器共享目录)
1.5.1.3 HostPath
EmptyDir中数据不会被持久化,它会随着Pod的结束而销毁,如果想简单的将数据持久化到主机中,可以选择HostPath。
HostPath就是将Node主机中一个实际目录挂在到Pod中,以供容器使用,这样的设计就可以保证Pod销毁了,但是数据依据可以存在于Node主机上。
1.5.1.4 NFS
HostPath可以解决数据持久化的问题,但是一旦Node节点故障了,Pod如果转移到了别的节点,又会出现问题了,此时需要准备单独的网络存储系统,比较常用的用NFS、CIFS。
NFS是一个网络文件存储系统,可以搭建一台NFS服务器,然后将Pod中的存储直接连接到NFS系统上,这样的话,无论Pod在节点上怎么转移,只要Node跟NFS的对接没问题,数据就可以成功访问。
1.5.2 高级存储
PV(Persistent Volume)是持久化卷的意思,是对底层的共享存储的一种抽象。一般情况下PV由kubernetes管理员进行创建和配置,它与底层具体的共享存储技术有关,并通过插件完成与共享存储的对接。
PVC(Persistent Volume Claim)是持久卷声明的意思,是用户对于存储需求的一种声明。换句话说,PVC其实就是用户向kubernetes系统发出的一种资源需求申请。
使用了PV和PVC之后,工作可以得到进一步的细分:
-
存储:存储工程师维护
-
PV: kubernetes管理员维护
-
PVC:kubernetes用户维护
PVC和PV是一一对应的,PV和PVC之间的相互作用遵循以下生命周期:
-
资源供应:管理员手动创建底层存储和PV
-
资源绑定:用户创建PVC,kubernetes负责根据PVC的声明去寻找PV,并绑定
在用户定义好PVC之后,系统将根据PVC对存储资源的请求在已存在的PV中选择一个满足条件的
-
一旦找到,就将该PV与用户定义的PVC进行绑定,用户的应用就可以使用这个PVC了
-
如果找不到,PVC则会无限期处于Pending状态,直到等到系统管理员创建了一个符合其要求的PV
PV一旦绑定到某个PVC上,就会被这个PVC独占,不能再与其他PVC进行绑定了
-
-
资源使用:用户可在pod中像volume一样使用pvc
Pod使用Volume的定义,将PVC挂载到容器内的某个路径进行使用。
-
资源释放:用户删除pvc来释放pv
当存储资源使用完毕后,用户可以删除PVC,与该PVC绑定的PV将会被标记为“已释放”,但还不能立刻与其他PVC进行绑定。通过之前PVC写入的数据可能还被留在存储设备上,只有在清除之后该PV才能再次使用。
-
资源回收:kubernetes根据pv设置的回收策略进行资源的回收
对于PV,管理员可以设定回收策略,用于设置与之绑定的PVC释放资源之后如何处理遗留数据的问题。只有PV的存储空间完成回收,才能供新的PVC绑定和使用
1.5.2.1 PV
PV 的关键配置参数说明:
-
存储类型
底层实际存储的类型,kubernetes支持多种存储类型,每种存储类型的配置都有所差异
-
存储能力(capacity)
目前只支持存储空间的设置( storage=1Gi ),不过未来可能会加入IOPS、吞吐量等指标的配置
-
访问模式(accessModes)
用于描述用户应用对存储资源的访问权限,访问权限包括下面几种方式:
-
ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载
-
ReadOnlyMany(ROX): 只读权限,可以被多个节点挂载
-
ReadWriteMany(RWX):读写权限,可以被多个节点挂载
需要注意的是,底层不同的存储类型可能支持的访问模式不同
-
-
回收策略(persistentVolumeReclaimPolicy)
当PV不再被使用了之后,对其的处理方式。目前支持三种策略:
-
Retain (保留) 保留数据,需要管理员手工清理数据
-
Recycle(回收) 清除 PV 中的数据,效果相当于执行 rm -rf /thevolume/*
-
Delete (删除) 与 PV 相连的后端存储完成 volume 的删除操作,当然这常见于云服务商的存储服务
需要注意的是,底层不同的存储类型可能支持的回收策略不同
-
-
存储类别
PV可以通过storageClassName参数指定一个存储类别
-
具有特定类别的PV只能与请求了该类别的PVC进行绑定
-
未设定类别的PV则只能与不请求任何类别的PVC进行绑定
-
-
状态(status)
一个 PV 的生命周期中,可能会处于4中不同的阶段:
-
Available(可用): 表示可用状态,还未被任何 PVC 绑定
-
Bound(已绑定): 表示 PV 已经被 PVC 绑定
-
Released(已释放): 表示 PVC 被删除,但是资源还未被集群重新声明
-
Failed(失败): 表示该 PV 的自动回收失败
-
1.5.2.2 PVC
PVC是资源的申请,用来声明对存储空间、访问模式、存储类别需求信息。
PVC 的关键配置参数说明:
-
访问模式(accessModes)
用于描述用户应用对存储资源的访问权限
-
选择条件(selector)
通过Label Selector的设置,可使PVC对于系统中己存在的PV进行筛选
-
存储类别(storageClassName)
PVC在定义时可以设定需要的后端存储的类别,只有设置了该class的pv才能被系统选出
-
资源请求(Resources )
描述对存储资源的请求
1.5.3 配置存储
1.5.3.1 ConfigMap
ConfigMap是一种比较特殊的存储卷,它的主要作用是用来存储配置信息的。
1.5.3.1 Secret
在kubernetes中,还存在一种和ConfigMap非常类似的对象,称为Secret对象。它主要用于存储敏感信息,例如密码、秘钥、证书等等。
1) 首先使用base64对数据进行编码
[root@k8s-master01 ~]# echo -n 'admin' | base64 #准备username
YWRtaW4=
[root@k8s-master01 ~]# echo -n '123456' | base64 #准备password
MTIzNDU22) 接下来编写secret.yaml,并创建Secret
apiVersion: v1
kind: Secret
metadata:
name: secret
namespace: dev
type: Opaque
data:
username: YWRtaW4=
password: MTIzNDU2
- 点赞
- 收藏
- 关注作者
评论(0)