API资源对象Deployment;API资源对象Service;API资源对象DaemonSet;API资源对象StatefulSet
API资源对象Deployment
Deployment YAML示例:
vi ng-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:labels:app: myngname: ng-deploy
spec:replicas: 2 ##副本数selector:matchLabels:app: myngtemplate:metadata:labels:app: myngspec:containers:- name: myngimage: nginx:1.23.2ports:- name: myng-portcontainerPort: 80
使用YAML创建deploy:
kubectl apply -f ng-deploy.yaml
查看:
kubectl get deploy
kubectl get po
查看pod分配到哪个节点上
kubectl get po -o wide
API资源对象Service
Service简称(svc) YAML示例:
vi ng-svc.yaml
apiVersion: v1
kind: Service
metadata:name: ngx-svc
spec:selector:app: myngports:- protocol: TCPport: 8080 ##service的porttargetPort: 80 ##pod的port
使用YAML创建service:
kubectl apply -f ng-svc.yaml
查看:
kubectl get svc
三种Service 类型:
1)ClusterIP
该方式为默认类型,即,不定义type字段时(如上面service的示例),就是该类型。
spec:selector:app: myngtype: ClusterIPports:- protocol: TCPport: 8080 ##service的porttargetPort: 80 ##pod的port
2)NodePort
如果想直接通过k8s节点的IP直接访问到service对应的资源,可以使用NodePort,Nodeport对应的端口范围:30000-32767
spec:selector:app: myngtype: NodePortports:- protocol: TCPport: 8080 ##service的porttargetPort: 80 ##pod的portnodePort: 30009 ##可以自定义,也可以不定义,它会自动获取一个端口
3)LoadBlancer
这种方式,需要配合公有云资源比如阿里云、亚马逊云来实现,这里需要一个公网IP作为入口,然后来负载均衡所有的Pod。
spec:selector:app: myngtype: LoadBlancerports:- protocol: TCPport: 8080 ##service的porttargetPort: 80 ##pod的port
API资源对象DaemonSet
有些场景需要在每一个node上运行Pod(比如,网络插件calico、监控、日志收集),Deployment无法做到,而Daemonset(简称ds)可以。Deamonset的目标是,在集群的每一个节点上运行且只运行一个Pod。
Daemonset不支持使用kubectl create获取YAML模板,所以只能照葫芦画瓢了,参考Deployment的YAML编写,其实Daemonset和Deployment的差异很小,除了Kind不一样,还需要去掉replica配置。
vi ds-demo.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:labels:app: ds-demoname: ds-demo
spec:selector:matchLabels:app: ds-demotemplate:metadata:labels:app: ds-demospec:containers:- name: ds-demoimage: nginx:1.23.2ports:- name: mysql-portcontainerPort: 80
使用YAML创建ds
kubectl apply -f ds-demo.yaml
查看:
kubectl get ds
kubectl get po
但只在两个node节点上启动了pod,没有在master上启动,这是因为默认master有限制。
kubectl describe node k8s01 |grep -i 'taint'
Taints: node-role.kubernetes.io/control-plane:NoSchedule
说明:Taint叫做污点,如果某一个节点上有污点,则不会被调度运行pod。
但是这个还得取决于Pod自己的一个属性:toleration(容忍),即这个Pod是否能够容忍目标节点是否有污点。
为了解决此问题,我们可以在Pod上增加toleration属性。下面改一下YAML配置:
vi ds-demo.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:labels:app: ds-demoname: ds-demo
spec:selector:matchLabels:app: ds-demotemplate:metadata:labels:app: ds-demospec:tolerations:- key: node-role.kubernetes.io/control-planeeffect: NoSchedulecontainers:- name: ds-demoimage: nginx:1.23.2ports:- name: mysql-portcontainerPort: 80
再次应用此YAML
kubectl apply -f ds-demo.yaml
API资源对象StatefulSet
Pod根据是否有数据存储分为有状态和无状态:
- 无状态:指的Pod运行期间不会产生重要数据,即使有数据产生,这些数据丢失了也不影响整个应用。比如Nginx、Tomcat等应用适合无状态。
- 有状态:指的是Pod运行期间会产生重要的数据,这些数据必须要做持久化,比如MySQL、Redis、RabbitMQ等。
Deployment和Daemonset适合做无状态,而有状态也有一个对应的资源,那就是Statefulset(简称sts)。
说明:由于StatefulSet涉及到了数据持久化,用到了StorageClass,需要先创建一个基于NFS的StorageClass
额外开一台虚拟机,搭建NFS服务(具体步骤略)
假设NFS服务器IP地址为192.168.222.128,共享目录为/data/nfs
另外,要想使用NFS的sc,还需要安装一个NFS provisioner,它的作用是自动创建NFS的pv
github地址: https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner
将源码下载下来:
git clone https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner
cd nfs-subdir-external-provisioner/deploy
sed -i 's/namespace: default/namespace: kube-system/' rbac.yaml ##修改命名空间为kube-system
kubectl apply -f rbac.yaml ##创建rbac授权
修改deployment.yaml
sed -i 's/namespace: default/namespace: kube-system/' deployment.yaml ##修改命名空间为kube-system##你需要修改标红的部分 spec:serviceAccountName: nfs-client-provisionercontainers:- name: nfs-client-provisionerimage: chronolaw/nfs-subdir-external-provisioner:v4.0.2 ##改为dockerhub地址volumeMounts:- name: nfs-client-rootmountPath: /persistentvolumesenv:- name: PROVISIONER_NAMEvalue: k8s-sigs.io/nfs-subdir-external-provisioner- name: NFS_SERVERvalue: 192.168.222.128 ##nfs服务器地址- name: NFS_PATHvalue: /data/nfs ##nfs共享目录volumes:- name: nfs-client-rootnfs:server: 192.168.222.128 ##nfs服务器地址path: /data/nfs ##nfs共享目录
应用yaml
kubectl apply -f deployment.yaml
kubectl apply -f class.yaml ##创建storageclass
SC YAML示例
cat class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: nfs-client
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # or choose another name, must match deployment's env PROVISIONER_NAME'
parameters:archiveOnDelete: "false" ##自动回收存储空间
Sts示例:
vi redis-sts.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:name: redis-stsspec:serviceName: redis-svc ##这里要有一个serviceName,Sts必须和service关联volumeClaimTemplates:- metadata:name: redis-pvcspec:storageClassName: nfs-clientaccessModes:- ReadWriteManyresources:requests:storage: 500Mireplicas: 2selector:matchLabels:app: redis-ststemplate:metadata:labels:app: redis-stsspec:containers:- image: redis:6.2name: redisports:- containerPort: 6379volumeMounts:- name: redis-pvcmountPath: /data
vi redis-svc.yaml
apiVersion: v1
kind: Service
metadata:name: redis-svcspec:selector:app: redis-stsports:- port: 6379protocol: TCPtargetPort: 6379
应用两个YAML文件
kubectl apply -f redis-sts.yaml -f redis-svc.yaml
对于Sts的Pod,有如下特点:
① Pod名固定有序,后缀从0开始;
② “域名”固定,这个“域名”组成: Pod名.Svc名,例如 redis-sts-0.redis-svc;
③ 每个Pod对应的PVC也是固定的;
实验:
ping 域名
kubectl exec -it redis-sts-0 -- bash ##进去可以ping redis-sts-0.redis-svc 和 redis-sts-1.redis-svc
创建key
kubectl exec -it redis-sts-0 -- redis-cli
127.0.0.1:6379> set k1 'abc'
OK
127.0.0.1:6379> set k2 'bcd'
OK
模拟故障
kubectl delete pod redis-sts-0
删除后,它会自动重新创建同名Pod,再次进入查看redis key
kubectl exec -it redis-sts-0 -- redis-cli
127.0.0.1:6379> get k1
"abc"
127.0.0.1:6379> get k2
"bcd"
数据依然存在。
关于Sts里的多个Pod之间的数据同步
K8s并不负责Sts里的Pod间数据同步, 具体的数据同步和一致性策略取决于我们部署的有状态应用程序。不同的应用程序可能使用不同的数据同步和一致性策略。例如,关系型数据库(如 MySQL)可能使用主-从复制,而分布式数据库(如 MongoDB)可能使用一种基于分区和副本的数据同步机制。