dashboard
Dashboard简介
Dashboard 是基于网页的 Kubernetes 用户界面。您可以使用 Dashboard 将容器应用部署到 Kubernetes 集群中,也可以对容器应用排错,还能管理集群本身及其附属资源。您可以使用 Dashboard 获取运行在集群中的应用的概览信息,也可以创建或者修改 Kubernetes 资源(如 Deployment,Job,DaemonSet 等等)。例如,可以对 Deployment 实现弹性伸缩、发起滚动升级、 重启 Pod 或者使用向导创建新的应用。
官网地址
https://github.com/kubernetes/dashboard
下载配置文件
https://github.com/kubernetes/dashboard/blob/v2.0.3/aio/deploy/recommended.ya
安装镜像
kubernetsui下边的镜像不需要科学上网
docker pull kubernetesui/dashboard:v2.0.3
docker pull kubernetesui/metrics-scraper:v1.0.4
修改配置文件
控制器部分
179行左右
containers:
- name: kubernetes-dashboard
image: kubernetesui/dashboard:v2.0.3
imagePullPolicy: IfNotPresent
262行左右。新增下载策略
containers:
- name: dashboard-metrics-scraper
image: kubernetesui/metrics-scraper:v1.0.4
imagePullPolicy: IfNotPresent
service部分
默认Dashboard只能集群内部访问,修改Service为NodePort类型,暴露到外部访问。找到Services配 置。在配置文件上边。增加type:NodePort和 nodePort:30100端口
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
ports:
- port: 443
targetPort: 8443
nodePort: 30100
type: NodePort
selector:
k8s-app: kubernetes-dashboard
管理 Service Accounts
这是一篇针对service accounts(服务账户)的集群管理员指南。 它呈现了 User Guide to Service Accounts中的信息。 对授权和用户账户的支持已在规划中,当前并不完备,为了更好地描述 service accounts,有时这些不 完善的特性也会被提及。
用户账户与服务账户
Kubernetes 区分用户账户和服务账户的概念主要基于以下原因:
- User(用户账户)是针对人而言的。 service accounts(服务账户)是针对运行在 pod 中的进程而言 的。
- 用户账户是全局性的。 其名称在集群各 namespace 中都是全局唯一的,未来的用户资源不会做 namespace 隔离, 服务账户是 namespace 隔离的。
- 通常情况下,集群的用户账户可能会从企业数据库进行同步,其创建需要特殊权限,并且涉及到复 杂的业务流程。 服务账户创建的目的是为了更轻量,允许集群用户为了具体的任务创建服务账户 ( 即权限最小化原则 )。
- 对人员和服务账户审计所考虑的因素可能不同。
- 针对复杂系统的配置可能包含系统组件相关的各种服务账户的定义。 因为服务账户可以定制化地创 建,并且有 namespace 级别的名称,这种配置是很轻量的。
服务账户的自动化
三个独立组件协作完成服务账户相关的自动化 :
- 服务账户准入控制器(Service account admission controller)
- Token 控制器(Token controller)
- 服务账户控制器(Service account controller)
服务账户准入控制器
对 pod 的改动通过一个被称为 Admission Controller 的插件来实现。它是 apiserver 的一部分。 当 pod 被创建或更新时,它会同步地修改 pod。 当该插件处于激活状态 ( 在大多数发行版中都是默认的 ),当 pod 被创建或更新时它会进行以下动作:
- 如果该 pod 没有 ServiceAccount 设置,将其 ServiceAccount 设为 default。
- 保证 pod 所关联的 ServiceAccount 存在,否则拒绝该 pod。
- 如果 pod 不包含 ImagePullSecrets 设置,那么 将 ServiceAccount 中的 ImagePullSecrets 信 息添加到 pod 中。
- 将一个包含用于 API 访问的 token 的 volume 添加到 pod 中。
- 将挂载于 /var/run/secrets/kubernetes.io/serviceaccount 的 volumeSource 添加到 pod 下的每个容器中。
Token 管理器
Token 管理器是 controller-manager 的一部分。 以异步的形式工作:
- 检测服务账户的创建,并且创建相应的 Secret 以支持 API 访问。
- 检测服务账户的删除,并且删除所有相应的服务账户 Token Secret。
- 检测 Secret 的增加,保证相应的服务账户存在,如有需要,为 Secret 增加 token。
- 检测 Secret 的删除,如有需要,从相应的服务账户中移除引用。
你需要通过 --service-account-private-key-file 参数项传入一个服务账户私钥文件至 Token 管理 器。 私钥用于为生成的服务账户 token 签名。 同样地,你需要通过 --service-account-key-file 参数 将对应的公钥传入 kube-apiserver。 公钥用于认证过程中的 token 校验。
服务账户管理器
服务账户管理器管理各命名空间下的服务账户,并且保证每个活跃的命名空间下存在一个名为 "default" 的服务账户
RBAC
使用 RBAC 鉴权。基于角色(Role)的访问控制(RBAC)是一种基于企业中用户的角色来调节控制对计 算机或网络资源的访问方法。 RBAC 使用 rbac.authorization.k8s.io API 组 来驱动鉴权操作,允许 管理员通过 Kubernetes API 动态配置策略。
在 1.8 版本中,RBAC 模式是稳定的并通过 rbac.authorization.k8s.io/v1 API 提供支持。
要启用 RBAC,在启动 API 服务器时添加 --authorization-mode=RBAC 参数。
Role 和 ClusterRole
在 RBAC API 中,一个角色包含一组相关权限的规则。权限是纯粹累加的(不存在拒绝某操作的规 则)。 角色可以用 Role 来定义到某个命名空间上, 或者用 ClusterRole 来定义到整个集群作用域。
一个 Role 只可以用来对某一命名空间中的资源赋予访问权限。 下面的 Role 示例定义到名称为 "default" 的命名空间,可以用来授予对该命名空间中的 Pods 的读取权限:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""] # "" 指定核心 API 组
resources: ["pods"]
verbs: ["get", "watch", "list"]
ClusterRole 可以授予的权限和 Role 相同, 但是因为 ClusterRole 属于集群范围,所以它也可以授予以 下访问权限:
集群范围资源 (比如 nodes)
非资源端点(比如 /healthz )
跨命名空间访问的有名字空间作用域的资源(如 Pods),比如运行命令 kubectl get pods --allnamespaces 时需要此能力
下面的 ClusterRole 示例可用来对某特定命名空间下的 Secrets 的读取操作授权, 或者跨所有命名空 间执行授权(取决于它是如何绑定的):
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
# 此处的 "namespace" 被省略掉是因为 ClusterRoles 是没有命名空间的。
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "watch", "list"]
RoleBinding 和 ClusterRoleBinding
角色绑定( RoleBinding )是将角色中定义的权限赋予一个或者一组用户。 它包含若干主体(用户, 组和服务账户)的列表和对这些主体所获得的角色的引用。 可以使用 RoleBinding 在指定的命名空间 中执行授权, 或者在集群范围的命名空间使用 ClusterRoleBinding 来执行授权。
一个 RoleBinding 可以引用同一的命名空间中的 Role 。 下面的例子 RoleBinding 将 pod-reader 角色授予在 "default" 命名空间中的用户 "jane"; 这样,用户 "jane" 就具有了读取 "default" 命名空间 中 pods 的权限。
roleRef 里的内容决定了实际创建绑定的方法。kind 可以是 Role 或 ClusterRole , name 将引用你 要指定的 Role 或 ClusterRole 的名称。在下面的例子中,角色绑定使用 roleRef 将用户 "jane" 绑定 到前文创建的角色 Role ,其名称是 pod-reader 。
apiVersion: rbac.authorization.k8s.io/v1
# 此角色绑定使得用户 "jane" 能够读取 "default" 命名空间中的 Pods
kind: RoleBinding
metadata:
name: read-pods
namespace: default
subjects:
- kind: User
name: jane # Name is case sensitive
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role #this must be Role or ClusterRole
name: pod-reader # 这里的名称必须与你想要绑定的 Role 或 ClusterRole 名称一致
apiGroup: rbac.authorization.k8s.io
RoleBinding 也可以引用 ClusterRole ,对 ClusterRole 所定义的、位于 RoleBinding 命名空间 内的资源授权。 这可以允许管理者在 整个集群中定义一组通用的角色,然后在多个命名空间中重用它 们。
Dashboard新增用户
可以选择使用资源文件方式或者命令行方式为dashboard新建具有管理集群角色的用户。
使用资源文件方式新增用户
在配置文件下边增加用户及给用户授予集群管理员角色
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
k8s-app: kubernetes-dashboard
name: dashboard-admin
namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: dashboard-admin-cluster-role
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: dashboard-admin
namespace: kubernetes-dashboard
使用命令行方式新增用户
创建service account并绑定默认cluster-admin管理员集群角色:
创建用户
kubectl create serviceaccount dashboard-admin -n kube-system
用户授权
kubectl create clusterrolebinding dashboard-admin --clusterrole=clusteradmin --serviceaccount=kube-system:dashboard-admin
kubectl delete clusterrolebinding dashboard-admin -n kube-system
删除用户
kubectl delete sa dashboard-admin -n kube-system
部署dashboard
部署完dashboard服务,可以选在使用token认证方式登录或者kubeconfig认证方式登录dashboard。
kubectl apply -f .
kubectl get pods -n kubernetes-dashboard -o wide
kubectl get svc -n kubernetes-dashboard
kubectl delete -f .
token认证方式
分步查看token信息
1.根据命名空间找到我们创建的用户
kubectl get sa -n kubernetes-dashboard
2.查看我们创建用户的详细信息。找到token属性对应的secret值
kubectl describe sa dashboard-admin -n kubernetes-dashboard
kubectl describe secrets dashboard-admin-token-9pl4b -n kubernetes-dashboard
3.或者是根据命名空间查找secrets。获得dashboard-admin用户的secret。
kubectl get secrets -n kubernetes-dashboard
kubectl describe secrets dashboard-admin-token-9pl4b -n kubernetes-dashboard
快速查看token信息
kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetesdashboard get secret | grep dashboard-admin | awk '{print $1}')
浏览器访问
注意:是https方式访问
https://192.168.198.156:30100/
kubeConfig认证方式
了解即可。
以下命令可以一起执行。可以更改dashboard-admin.conf的生成目录。关键点还是要首先或者
dashboard-admin用户的secret值。
DASH_TOCKEN=$(kubectl get secret -n kubernetes-dashboard dashboard-admintoken-jdvkg -o jsonpath={.data.token}|base64 -d)
kubectl config set-cluster kubernetes --server=192.168.198.156:6443 --
kubeconfig=/root/dashboard-admin.conf
kubectl config set-credentials dashboard-admin --token=$DASH_TOCKEN --
kubeconfig=/root/dashboard-admin.conf
kubectl config set-context dashboard-admin@kubernetes --cluster=kubernetes -
-user=dashboard-admin --kubeconfig=/root/dashboard-admin.conf
kubectl config use-context dashboard-admin@kubernetes --
kubeconfig=/root/dashboard-admin.conf
将生成的dashboard-admin.conf上传到windows系统中。浏览器选择dashboard-admin.conf文件即可用于登录dashboard
使用StatefulSet创建Zookeeper集群
这是k8s官方提供的案例。不推荐学员练习。因为要包含4个节点。学生们电脑内存压力大。k8s官网提 供镜像国内无法下载。老司机给大家演示一下即可。
运行 ZooKeeper, 一个 CP 分布式系统。本教程展示了在 Kubernetes 上使用 PodDisruptionBudgets 和 PodAntiAffinity 特性运行 Apache Zookeeper。
需要一个至少包含四个节点的集群,每个节点至少 2 CPUs 和 4 GiB 内存。在本教程中你应该使用一个 独占的集群,或者保证你造成的干扰不会影响其它租户。
教程目标
在学习本教程后,你将熟悉下列内容。
- 如何使用 StatefulSet 部署一个 ZooKeeper ensemble。
- 如何使用 ConfigMaps 一致性配置 ensemble。
- 如何在 ensemble 中 分布 ZooKeeper 服务的部署。
- 如何在计划维护中使用 PodDisruptionBudgets 确保服务可用性。
安装镜像
k8s官方提供进行国内无法下载,使用国内镜像地址下载。需要修改官网默认给的yaml文件,去掉官网镜像,使用我们下载的镜像。
docker pull mirrorgooglecontainers/kubernetes-zookeeper:1.0-3.4.10
资源文件清单
apiVersion: v1
kind: Service
metadata:
name: zk-hs
labels:
app: zk
spec:
ports:
- port: 2888
name: server
- port: 3888
name: leader-election
clusterIP: None
selector:
app: zk
---
apiVersion: v1
kind: Service
metadata:
name: zk-cs
labels:
app: zk
spec:
ports:
- port: 2181
name: client
selector:
app: zk
---
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
name: zk-pdb
spec:
selector:
matchLabels:
app: zk
maxUnavailable: 1
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: zk
spec:
selector:
matchLabels:
app: zk
serviceName: zk-hs
replicas: 3
updateStrategy:
type: RollingUpdate
podManagementPolicy: OrderedReady
template:
metadata:
labels:
app: zk
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: "app"
operator: In
values:
- zk
topologyKey: "kubernetes.io/hostname"
containers:
- name: kubernetes-zookeeper
imagePullPolicy: IfNotPresent
image: "mirrorgooglecontainers/kubernetes-zookeeper:1.0-3.4.10"
resources:
requests:
memory: "1Gi"
cpu: "0.5"
ports:
- containerPort: 2181
name: client
- containerPort: 2888
name: server
- containerPort: 3888
name: leader-election
command:
- sh
- -c
- "start-zookeeper \
--servers=3 \
--data_dir=/var/lib/zookeeper/data \
--data_log_dir=/var/lib/zookeeper/data/log \
--conf_dir=/opt/zookeeper/conf \
--client_port=2181 \
--election_port=3888 \
--server_port=2888 \
--tick_time=2000 \
--init_limit=10 \
--sync_limit=5 \
--heap=512M \
--max_client_cnxns=60 \
--snap_retain_count=3 \
--purge_interval=12 \
--max_session_timeout=40000 \
--min_session_timeout=4000 \
--log_level=INFO"
readinessProbe:
exec:
command:
- sh
- -c
- "zookeeper-ready 2181"
initialDelaySeconds: 10
timeoutSeconds: 5
livenessProbe:
exec:
command:
- sh
- -c
- "zookeeper-ready 2181"
initialDelaySeconds: 10
timeoutSeconds: 5
volumeMounts:
- name: datadir
mountPath: /var/lib/zookeeper
securityContext:
runAsUser: 1000
fsGroup: 1000
volumes:
- name: datadir
emptyDir: {}
部署zookeeper
kubectl apply -f .
监控zookeeper启动过程
kubectl get pods -o wide -w
kubectl delete -f .
statefuleSet
简介
前边我们讲了deployment来管理pod容器的副本数量,如果挂掉之后容器再次启动就可以了,但是如果 要是启动的是mysql集群、zookeeper集群、etcd这种集群,里面都有id号,这种有关联的,如果一旦挂 掉之后,在启动之后呢,集群id是否会变化呢?答案是肯定会变的。
那有没有另外的一种控制器模式吗?当然k8s会提供的--【statefulset】
那什么场景需要使用StatefulSet呢?官方给出的建议是,如果你部署的应用满足以下一个或多个部署需 求,则建议使用StatefulSet。
- 稳定的、唯一的网络标识。
- 稳定的、持久的存储。
- 有序的、优雅的部署和伸缩。
- 有序的、优雅的删除和停止。
- 有序的、自动的滚动更新。
statefulset和deployment的区别:
分类
K8s有状态应用部署分为两步:
- Headless Service: Headless Service 其实和service差不多,只不过定义的这个叫无头服务,它 们之间唯一的区别就是将Cluster ip 设置为了none,不会帮你配置ip
- StatefulSet:需要在pod模板中定义servicename。spec. serviceName。
Headless Service案例-不需要创建演示
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
clusterIP: None
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 9376
部署服务
kubectl create -f headless-svc.yaml
kubectl get svc
怎么去访问?我们给它定义一个标识。创建完之后会有这个标识符,它会使用这个DNS来解析这个名称,来相互的访问,headless就不会通过ip去访问了,必须通过名称去访问。
statefulSet案例-不需要创建演示
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: nginx-statefulset
namespace: default
spec:
serviceName: my-service
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
总结
- Pod会被顺序部署和顺序终结:StatefulSet中的各个 Pod会被顺序地创建出来,每个Pod都有一个 唯一的ID,在创建后续 Pod 之前,首先要等前面的 Pod 运行成功并进入到就绪状态。删除会销毁 StatefulSet 中的每个 Pod,并且按照创建顺序的反序来执行,只有在成功终结后面一个之后,才 会继续下一个删除操作。
- Pod具有唯一网络名称:Pod具有唯一的名称,而且在重启后会保持不变。通过Headless服务,基 于主机名,每个 Pod 都有独立的网络地址,这个网域由一个Headless 服务所控制。这样每个Pod 会保持稳定的唯一的域名,使得集群就不会将重新创建出的Pod作为新成员。
- Pod能有稳定的持久存储:StatefulSet中的每个Pod可以有其自己独立的PersistentVolumeClaim 对象。即使Pod被重新调度到其它节点上以后,原有的持久磁盘也会被挂载到该Pod。
- Pod能被通过Headless服务访问到:客户端可以通过服务的域名连接到任意Pod。
动态PV
安装镜像
由于quay.io仓库部分镜像国内无法下载,所以替换为其他镜像地址
docker pull vbouchaud/nfs-client-provisioner:v3.1.1
nfs4服务端配置
mkdir -p /nfs/data/
chmod 777 /nfs/data/
yum install -y nfs-utils rpcbind
更改归属组与用户
chown nfsnobody /nfs/data/
vi /etc/exports
/nfs/data *(rw,fsid=0,sync,no_wdelay,insecure_locks,no_root_squash)
为了方便接下来两个实验,提前建立2个共享子目录。
mkdir -p /nfs/data/mariadb
mkdir -p /nfs/data/nginx
systemctl start rpcbind
systemctl start nfs
设置开启启动
systemctl enable rpcbind
systemctl enable nfs
nfs的storageClass配置
rbac
nfsdynamic/nfsrbac.yml。每次配置文件,只需要调整ClusterRoleBinding、RoleBinding的 namespace值,如果服务是部署在默认的namespace中,配置文件不需要调整。
kind: ServiceAccount
apiVersion: v1
metadata:
name: nfs-client-provisioner
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-runner
rules:
- 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
namespace: default #替换成要部署NFS Provisioner的namespace
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
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
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
namespace: default #替换成要部署NFS Provisioner的namespace
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner
apiGroup: rbac.authorization.k8s.io
storageClass
nfsdynamic/nfsstorage.yml
kind: Deployment
apiVersion: apps/v1
metadata:
name: nfs-client-provisioner
labels:
app: nfs-client-provisioner
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
#由于quay.io仓库部分镜像国内无法下载,所以替换为其他镜像地址
image: vbouchaud/nfs-client-provisioner:v3.1.1
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: nfs-client #--- nfs-provisioner的名称,以后设置的storageclass要和这个保持一致
- name: NFS_SERVER
value: 192.168.198.156 #NFS服务器地址,与volumes.nfs.servers保持一致
- name: NFS_PATH
value: /nfs/data #NFS服务共享目录地址,与volumes.nfs.path保持一致
volumes:
- name: nfs-client-root
nfs:
server: 192.168.198.156 #NFS服务器地址,与spec.containers.env.value保持一致
path: /nfs/data #NFS服务器目录,与spec.containers.env.value保持一致
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-storage
annotations:
storageclass.kubernetes.io/is-default-class: "true" #设置为默认storageclass
provisioner: nfs-client #动态卷分配者名称,必须和创建的"provisioner"变量中设置的name一致
parameters:
archiveOnDelete: "true" #设置为"false"时删除PVC不会保留数据,"true"则保留数据
mountOptions:
- hard #指定为硬挂载方式
- nfsvers=4 #指定NFS版本,这个需要根据 NFS Server 版本号设置
测试pvc
nfsdynamic/nfstestpvc.yml
用于测试nfs动态pv是否成功。
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-pvc
spec:
storageClassName: nfs-storage #需要与上面创建的storageclass的名称一致
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Mi
部署nfs测试服务
kubectl apply -f .
查看storageClass
kubectl get storageclasses.storage.k8s.io || kubectl get sc
查看mariadb服务
kubectl get svc
查看pv pvc
查看statefulSet
kubectl get sts
查看mariadb、storageClass的pods
kubectl get pods
删除服务
pv是动态生成,通过查看pv状态,发现pv不会自动回收。
删除mariadb服务
kubectl delete -f .
查看动态nfs的pv状态。发现pv的status状态是:Released
kubectl get pv
编译pv的配置文件
kubectl edit pv pvc-59fb2735-9681-426a-8805-8c94685a07e3
将spec.claimRef属性下的所有内容全部删除
claimRef:
apiVersion: v1
kind: PersistentVolumeClaim
name: test-pvc
namespace: default
resourceVersion: "162046"
uid: 59fb2735-9681-426a-8805-8c94685a07e3
再次查看pv状态。发现pv的status状态是:Available
kubectl get pv
删除pv
kubectl delete pv pvc-59fb2735-9681-426a-8805-8c94685a07e3
删除共享目录动态pv的目录
rm -rf pvc-59fb2735-9681-426a-8805-8c94685a07e3
动态pv案例一
部署3个副本的nginx服务。主要学习 volumeClaimTemplate 属性。
statefulset组成
statefulSet的三个组成部分:
-
Headless Service
:名为nginx,用来定义Pod网络标识( DNS domain)。 -
StatefulSet
:定义具体应用,名为Nginx,有三个Pod副本,并为每个Pod定义了一个域名。 -
volumeClaimTemplates
: 存储卷申请模板,创建PVC,指定pvc名称大小,将自动创建pvc,且 pvc必须由存储类供应。
为什么需要 headless service 无头服务?
在用Deployment时,每一个Pod名称是没有顺序的,是随机字符串,因此是Pod名称是无序的,但是在 statefulset中要求必须是有序 ,每一个pod不能被随意取代,pod重建后pod名称还是一样的。而pod IP 是变化的,所以是以Pod名称来识别。pod名称是pod唯一性的标识符,必须持久稳定有效。这时候要用 到无头服务,它可以给每个Pod一个唯一的名称 。
为什么需要volumeClaimTemplate?
对于有状态的副本集都会用到持久存储,对于分布式系统来讲,它的最大特点是数据是不一样的,所以 各个节点不能使用同一存储卷,每个节点有自已的专用存储,但是如果在Deployment中的Pod template里定义的存储卷,是所有副本集共用一个存储卷,数据是相同的,因为是基于模板来的 ,而 statefulset中每个Pod都要自已的专有存储卷,所以statefulset的存储卷就不能再用Pod模板来创建了, 于是statefulSet使用volumeClaimTemplate,称为卷申请模板,它会为每个Pod生成不同的pvc,并绑 定pv, 从而实现各pod有专用存储。这就是为什么要用volumeClaimTemplate的原因。
nfs服务
rbac
nfsnginx/nfsrbac.yml。与前文保持一致。
kind: ServiceAccount
apiVersion: v1
metadata:
name: nfs-client-provisioner
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-runner
rules:
- 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
namespace: default #替换成要部署NFS Provisioner的namespace
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
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
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
namespace: default #替换成要部署NFS Provisioner的namespace
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner
apiGroup: rbac.authorization.k8s.io
storageClass
nfsnginx/nfsnginxstorage.yml。与前文介绍类似,注意修改storageClass的名称
kind: Deployment
apiVersion: apps/v1
metadata:
name: nfs-client-provisioner
labels:
app: nfs-client-provisioner
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
#由于quay.io仓库部分镜像国内无法下载,所以替换为其他镜像地址
image: vbouchaud/nfs-client-provisioner:v3.1.1
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: nfs-client-nginx #nfs-provisioner的名称,以后设置的storageclass要和这个保持一致
- name: NFS_SERVER
value: 192.168.198.156 #NFS服务器地址,与volumes.nfs.servers保持一致
- name: NFS_PATH
value: /nginx #NFS服务共享目录地址,与volumes.nfs.path保持一致。使用NFS4版本进行多级目录挂载
volumes:
- name: nfs-client-root
nfs:
server: 192.168.198.156 #NFS服务器地址,与spec.containers.env.value保持一致
path: /nginx #NFS服务器目录,与spec.containers.env.value保持一致。使用NFS4版本进行多级目录挂载
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-storage-nginx
annotations:
storageclass.kubernetes.io/is-default-class: "true" #设置为默认的storageclass
#动态卷分配者名称,必须和创建的"provisioner"变量中设置的name一致
provisioner: nfs-client-nginx
parameters:
archiveOnDelete: "true" #设置为"false"时删除PVC不会保留数据,"true"则保留数据
mountOptions:
- hard #指定为硬挂载方式
- nfsvers=4 #指定NFS版本,这个需要根据 NFS Server 版本号设置
nginx服务
如果定义多个副本。必须使用volumeClaimTemplate属性。如果定义1个副本。可以使用pod+pvc方 式。
nfsnginx/nginxstatefulset.yml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nginxdeployment
labels:
app: nginxdeployment
spec:
replicas: 3
serviceName: nginxsvc
template:
metadata:
name: nginxdeployment
labels:
app: nginxdeployment
spec:
containers:
- name: nginxdeployment
image: nginx:1.17.10-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
volumeMounts:
- mountPath: /usr/share/nginx/html/
name: nginxvolume
restartPolicy: Always
volumeClaimTemplates:
- metadata:
name: nginxvolume
annotations:
volume.beta.kubernetes.io/storage-class: "nfs-storage-nginx"
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
selector:
matchLabels:
app: nginxdeployment
---
apiVersion: v1
kind: Service
metadata:
name: nginxsvc
spec:
selector:
app: nginxdeployment
ports:
- port: 8080
clusterIP: None
部署nginx服务
kubectl apply -f .
kubectl get pods -o wide
kubectl get pv
kubectl get pvc
动态pv案例二
部署mariadb数据库服务。
nfs服务
rbac
nfsmariadb/nfsrbac.yml。与前文保持一致。
kind: ServiceAccount
apiVersion: v1
metadata:
name: nfs-client-provisioner
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-runner
rules:
- 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
namespace: default #替换成要部署NFS Provisioner的namespace
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
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
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
namespace: default #替换成要部署NFS Provisioner的namespace
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner
apiGroup: rbac.authorization.k8s.io
storageClass
nfsmariadb/nfsmariadbstorage.yml。与前文介绍类似,注意修改storageClass的名称
kind: Deployment
apiVersion: apps/v1
metadata:
name: nfs-client-provisioner
labels:
app: nfs-client-provisioner
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
#由于quay.io仓库部分镜像国内无法下载,所以替换为其他镜像地址
image: vbouchaud/nfs-client-provisioner:v3.1.1
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: nfs-client-mariadb #nfs-provisioner的名称,以后设置的storageclass要和这个保持一致
- name: NFS_SERVER
value: 192.168.198.156 #NFS服务器地址,与volumes.nfs.servers保持一致
- name: NFS_PATH
value: /mariadb #NFS服务共享目录地址,与volumes.nfs.path保持一致。使用NFS4版本进行多级目录挂载
volumes:
- name: nfs-client-root
nfs:
server: 192.168.198.156 #NFS服务器地址,与spec.containers.env.value保持一致
path: /mariadb #NFS服务器目录,与spec.containers.env.value保持一致。使用NFS4版本进行多级目录挂载
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-storage-mariadb
annotations:
storageclass.kubernetes.io/is-default-class: "true" #设置为默认的storageclass
#动态卷分配者名称,必须和创建的"provisioner"变量中设置的name一致
provisioner: nfs-client-mariadb
parameters:
archiveOnDelete: "true" #设置为"false"时删除
PVC不会保留数据,"true"则保留数据
mountOptions:
- hard #指定为硬挂载方式
- nfsvers=4 #指定NFS版本,这个需要根据 NFS Server 版本号设置
mariadb
pvc
nfsmariadb/mariadbpvc.yml。为后续容灾测试方便。单独创建pvc文件
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
# pvc名称
name: mariadbpvc
spec:
# 使用的存储类
storageClassName: nfs-storage-mariadb
# 读写权限
accessModes:
- ReadWriteMany
# 定义容量
resources:
requests:
storage: 5Gi
statefulset
nfsmariadb/mariadbstatefulset.yml
apiVersion: v1
kind: Service
metadata:
name: mariadbsvc
spec:
ports:
- port: 3306
# 创建service为无头服务,标识容器
clusterIP: None
selector:
app: mariadb-public
---
apiVersion: apps/v1
kind: StatefulSet
# 名称
metadata:
name: mariadbsts
spec:
# 指定service名称
serviceName: "mariadbsvc"
replicas: 1
# 标签选择器
template:
metadata:
labels:
app: mariadb-public
spec:
# 镜像容器编辑
containers:
- name: mariadb
image: mariadb:10.5.2
env:
# 创建数据库用户密码
- name: MYSQL_ROOT_PASSWORD
value: "admin"
- name: TZ
value: Asia/Shanghai
# 创建数据库
- name: MYSQL_DATABASE
value: test
args:
- "--character-set-server=utf8mb4"
- "--collation-server=utf8mb4_unicode_ci"
# 启用端口
ports:
- containerPort: 3306
# 数据卷
volumeMounts:
# 挂在容器目录
- mountPath: "/var/lib/mysql"
# 使用来源
name: mariadb-data
# 使用数据卷来源
volumes:
# 数据卷名称
- name: mariadb-data
# 指定数据卷动态供给
persistentVolumeClaim:
# pvc动态供给名称
claimName: mariadbpvc
selector:
matchLabels:
app: mariadb-public
部署mariadb服务
部署服务
kubectl apply -f .
查看storage
kubectl get storageclasses.storage.k8s.io
查看pv绑定情况
kubectl get pv
查看pvc绑定情况
kubectl get pvc
查看服务
kubectl get svc
查看statefulset
kubectl get sts
查看pod
kubectl get pods
测试mariadb
查看statefulset的服务名称
kubectl get svc
创建一个临时的pod用于访问statefulset。通过statefulset的服务名进行访问:-
hmariadbsvc。
语法规则:--command -- mysql,mysql与--之间有空格。
kubectl run mariadb-test --image=mariadb:10.5.2 --restart=Never -it --rm --
command -- mysql -hmariadbsvc -uroot -padmin
命令行方式查看database
show databases;
命令行方式创建database
create database lagou;
进入容器查看database目录
kubectl exec -it mariadbsts-0 sh
cd /var/lib/mysql
ls
exit
查看nfs共享目录,自动创建目录格式为:${namespace}-${pvcName}-${pvName}的文件夹
cd /nfs/data
ls
cd default-mariadbpvc-pvc-26c5785e-5703-4175-bc6a-3f9097d51d98/
ls
容灾测试
删除pod测试
删除pod进行测试
kubectl get pvc
kubectl delete pod
进入容器查看database目录
kubectl exec -it mariadbsts-0 sh
cd /var/lib/mysql
ls
exit
查看nfs共享目录中database保存情况
cd /nfs/data
ls
cd default-mariadbpvc-pvc-26c5785e-5703-4175-bc6a-3f9097d51d98/
ls
临时客户端查看
kubectl run mariadb-test --image=mariadb:10.5.2 --restart=Never -it --rm --
command -- mysql -hmariadbsvc -uroot -padmin
show databases;
exit
删除statefuset
kubectl delete -f .