CKA-Kubernets(K8s) (二)
# 环境简易拓扑示意图
存储管理
创建卷
# 用命令生产一个pod1的yaml文件
kubectl run pod1 --image=buxybox --image-pull-policy=IfNotPresent --dry-run=client -o yaml > pod1.yaml
kind: Pod metadata: creationTimestamp: null labels: run: pod1 name: pod1 spec: terminationGracePeriodSeconds: 0 volumes: - name: v1 emptyDir: {} # Not sure Physical directory containers: - image: busybox name: pod1 imagePullPolicy: IfNotPresent command: ["sh","-c","sleep 3000"] volumeMounts: - name: v1 mountPath: /xx # in Docker Path /xx # readOnly: false # default paramater dnsPolicy: ClusterFirst restartPolicy: Always status: {}
相关挂载参数介绍:
emptyDir(用于临时存储,删除pod,随即消失) 相当于 -v /xx # 只写一个路径默认是容器里的目录,物理机随机生成
如何查看随机生产的物理路径在什么位置?
首先,在Master节点查看你pod是在哪个节点
kubectl get pods -o wide
然后,去相应的节点服务器上根据pod名字找出相应的容器名。
sudo docker ps |grep "pod1"
最后,根据自己设定的挂载容器目录名找到物理路径
sudo docker inspect c9163e85ac41 |grep "/xx"
并且看到我们在容器里面创建的测试文件loki.txt 存在这个目录下面
Tips:但是,这样的emptyDir挂载方式,我的数据会随着pod的删除而丢失。
hostPath(永久性存储,使用的是本地存储,没法实现数据的同步) 相当于-v /xx:/yy # 左边是物理机目录,右边是容器目录
apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: pod2 name: pod2 spec: terminationGracePeriodSeconds: 0 volumes: - name: v1 hostPath: path: /home/loki/4-volume # Physical directory containers: - image: busybox name: pod2 imagePullPolicy: IfNotPresent command: ["sh","-c","sleep 3000"] volumeMounts: - name: v1 mountPath: /xx # in Docker Path /xx # readOnly: false # default paramater dnsPolicy: ClusterFirst restartPolicy: Always status: {}
# 在相应节点服务器上创建了一个物理目录/home/loki/4-volume/yy并且映射到容器的/xx里面
这样就算,删掉了容器,这个目录里面的数据也是永久存储。
Tips:但是,又出现一个新的问题。不同的worker节点这个目录的数据也是不一致的?
# 下面的实验环境需要一台NFS - Server 我们这里用VM4来模拟
nfs(ceph,iscsi... 共享存储)
在vm4,上面进行vm4安装NFS-Server(下面配置仅用于实验,生产环境请勿模仿!!!)
sudo yum install -y nfs-utils
sudo systemctl start nfs-server; sudo systemctl enable nfs-server
# 创建一个共享目录 mkdir /home/loki/ShareDir
# 编辑nfs共享存储目录 vim /etc/exports ,下入下面信息
/home/loki/ShareDir *(rw,async,no_root_squash)
Tips:参数介绍 no_root_squash # root 的权限不做任何的改变
# 让配置的生效 sudo exportfs -avr
Tips:参数介绍 exportfs 命令常用选项如下:
● -a 全部挂载或者全部卸载
● -r 重新挂载
● -u 卸载某一个目录
● -v 显示共享目录
注意打开防火墙(下面的命令仅是为了实验方便,生产环境不要模仿!!!)
sudo firewall-cmd --set-default-zone=trusted
# 再worker上安装客户端
sudo yum install nfs-utils -y
# 测试一下是否能正常链接NFS showmount -e 192.168.27.219
# 测试挂载
sudo mount 192.168.27.219:/home/loki/ShareDir /mnt
sudo umoun /mnt
# yaml文件修改
apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: pod3 name: pod3 spec: nodeName: vm3 terminationGracePeriodSeconds: 0 volumes: - name: v1 nfs: server: 192.168.27.219 # NFS Sever IP path: /home/loki/ShareDir # NFS Share directory containers: - image: busybox name: pod3 imagePullPolicy: IfNotPresent command: ["sh","-c","sleep 3000"] volumeMounts: - name: v1 mountPath: /xx # in Docker Path /xx # readOnly: false # default paramater dnsPolicy: ClusterFirst restartPolicy: Always status: {}
Tips: NFS,解决不同节点数据同步,但是多个项目数据安全不能保证。大家都可以往目录里面进行读写操作
持久性存储 pv
Tips: 小技巧,通过kubectl api-resource 可以查看对应名利的“缩写”形式
# 查询此名称空间是否有pv和pvc
# 需要到官方网站上download模板
https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistent-volumes
# 创建PV 的yaml文件
apiVersion: v1 kind: PersistentVolume metadata: name: pv01 spec: capacity: storage: 5Gi volumeMode: Filesystem accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Recycle # storageClassName: slow nfs: path: /home/loki/ShareDir # Yours NFS PATH server: 192.168.27.219 # Yours NFS IP
# 查看PV 状态 kubectl get pv
# 创建PVC 依然去官方网站上拿模板进行修改
https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc01 spec: accessModes: - ReadWriteOnce volumeMode: Filesystem resources: requests: storage: 5Gi # storageClassName: slow
# 获取pvc信息 kubectl get pvc
# 查看pvc当前状态 kubectl get pv -n defalut 看到STATUS 已经是Bound
# 不能再次关联 新建另外一个PVC02的时候发现,状态已经是Pending
# 默认情况下 PVC和PV进行关联,主要看2个值
1. 容量大小
pvc的大小 <= pv 的大小
注:PV的容量值如果大于PVC的话,是可以进行关联。但是PVC的值大于PV的话,则不能进行关联,出现Pending。
2. accessmode相同
ReadWriteOnce 允许一次一个写
ReadOnlyMany 只允许多个写
ReadWriteMany 允许同时多个写
3. 让特定的PV和PVC进行关联,需要设置storageClassName (pvc 和 pv的这个值)相同的情况下会进行关联
# PV上面的设置storageClassName
# PVC上面的设置storageClassName
# 这次再来看结果pvc01就已经是Pending了,因为pvc02指定了storageClassName -- loki
# PV和PVC创建好以后,开始进行YAML 文件设定
apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: pod4 name: pod4 spec: nodeName: vm3 terminationGracePeriodSeconds: 0 volumes: - name: v1 persistentVolumeClaim: # Options PVC claimName: pvc02 # pvc name containers: - image: busybox name: pod4 imagePullPolicy: IfNotPresent command: ["sh","-c","sleep 3000"] volumeMounts: - name: v1 mountPath: /xx # in Docker Path /xx # readOnly: false # default paramater dnsPolicy: ClusterFirst restartPolicy: Always status: {}
# RECLAIM POLICY 回收策略 删除pvc后
注:删除pvc之前需要先删掉对应的pod
Recycle 意思就是,当PVC被删除之后,pv会把自己存储里的数据情空,然后变成可用的
# 回收策略修改,PV默认有2种回收策略
Recycle --会删除数据
• 会生成一个pod回收数据
• 删除pvc之后,pv可复用
• pv状态由Released变为Available
Retain--不回收数据
• 但是删除pvc之后,pv依然不可用
• pv状态长期保持为 Released
# 修改pv的YAML文件策略修改为 Retain测试
# 查看修改了Retain的pv,创建结果
# 再次删除pvc,此时数据依然保留,pv依然显示被Released(关联)状态
# 需要重新删除pv(关联的NFS数据依然保留),让状态变成Available,再次创建pv后即可再次进行关联
注:一般pv关联的NFS不要使用相同目录,尤其注意父目录和子目录,变其中有设置为Recycle,导致的连带删除。
Tips: 此时解决了数据安全隔离的问题,但是又有一个新问题诞生,就是每次这个PV都需要管理员手动创建。如果管理员不再或者无人值守,能自动扩充吗?
动态卷供应 storageClass 简称 SC
#kubernetes 默认有一些自带的分配器,包括不仅限于:
kubernetes.io/aws-ebs
kubernetes.io/gce-pd
kubernetes.io/glusterfs
kubernetes.io/cinder
kubernetes.io/vsphere-volume
kubernetes.io/rbd
kubernetes.io/quobyte
kubernetes.io/azure-disk
kubernetes.io/azure-file
kubernetes.io/portworx-volume
kubernetes.io/scaleio
kubernetes.io/storageos
kubernetes.io/no-provisioner
在动态创建 pv 的时候,根据使用不同的后端存储,应该选择一个合适的分配器
# 没有的需要手动创建--分配器
利用NFS 创建动态卷供应
准备工作
1. K8s 1.20 需要手动修改一个参数
sudo vim /etc/kubernetes/manifests/kube-apiserver.yaml
解决报错: unexpected error getting claim reference: selfLink was empty, can't make reference
1. 会导致pvc启动变成Pending
2. 会导致external-storage里面的deployment.yaml 启动出现上面报错
# k8s 1.20版本需要在master上,修改一个参数
Cause: 参考Github
In v1.16, we will deprecate the SelfLink field in both ObjectMeta and ListMeta objects by: documenting in field definition that it is deprecated and is going to be removed adding a release-note about field deprecation We will also introduce a feature gate to allow disabling setting SelfLink fields and opaque the logic setting it behind this feature gate.
In v1.20 (12 months and 4 release from v1.16) we will switch off the feature gate which will automatically disable setting SelfLinks. However it will still be possible to revert the behavior by changing value of a feature gate.
译文:在1.20版本中(从1.16版本到12个月的4个版本),我们将关闭会自动禁用设置SelfLinks的功能。然而,仍然有可能通过改变参数的值来恢复这种行为。
In v1.21, we will get rid of the whole code propagating those fields and fields themselves. In the meantime, we will go over places referencing that field (see below) and get rid of those too.
修改完毕后重启kubelet, systemctl restart kubelet
2. 创建好可以访问的NFS目录,这里就沿用上面的vm4的 NFS: /home/loki/ShareDir
3. 下载相关插件来创建nfs外部分配器
下载所需的包
https://github.com/kubernetes-retired/external-storage.git
# 读安装说明README.md
/home/loki/4-volume/external-storage-master/nfs-client/README.md
$ NS=$(kubectl config get-contexts|grep -e "^\*" |awk '{print $5}') $ NAMESPACE=${NS:-default} $ sed -i'' "s/namespace:.*/namespace: $NAMESPACE/g" ./deploy/rbac.yaml ./deploy/deployment.yaml $ kubectl create -f deploy/rbac.yaml
# 执行用自己的当前的名称空间替换rbac.yaml和deployment.yaml文件,然后创建rbac.yaml
部署NFS分配器
vim ./deploy/deployment.yaml 修改如下内容
apiVersion: apps/v1 kind: Deployment metadata: name: nfs-client-provisioner labels: app: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: 4-volume 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: quay.io/external_storage/nfs-client-provisioner:latest imagePullPolicy: IfNotPresent volumeMounts: - name: nfs-client-root mountPath: /persistentvolumes env: - name: PROVISIONER_NAME value: fuseim.pri/ifs - name: NFS_SERVER value: 192.168.27.219 - name: NFS_PATH value: /home/loki/ShareDir volumes: - name: nfs-client-root nfs: server: 192.168.27.219 path: /home/loki/ShareDir
1. 当前你自己的名称空间,如果自己分不清楚的可以用以下命令查:
kubectl config get-contexts|grep -e "^\*" |awk '{print $5}'
2. 所需镜像自己提前先download下来,所有节点 pull下来我这里是用阿里镜像加速pull的
quay.io/external_storage/nfs-client-provisioner:latest
3. env里,PROVISIONER_NAME用于指定分配器的名字,这里是fuseim.pri/ifs,
NFS_SERVER和NFS_PATH分别指定这个分配器所使用的存储信息
4. 在volume里的server和path指定共享服务器和目录
# 修改配置文件后,执行命令 kubectl apply -f deployment.yaml
# 查看是否创建pod kubectl get pods
# 在部署这个的时候俞到2个报错(遇到这2个报错是因为我下载错了版本,用了v5.5.0)
报错1:
解决办法:修改文件 Cause: 在新版本中 Deployment 已经弃用 extensions/v1beta1
kind: Deployment apiVersion: extensions/v1beta1 metadata: 改为: kind: Deployment apiVersion: apps/v1 metadata:
报错2:
解决办法:修改文件 Cause: 也是版本问题
spec: replicas: 1 strategy: type: Recreate template: metadata: 改为:(增加了3行内容) spec: replicas: 1 selector: matchLabels: app: nfs-client-provisioner strategy: type: Recreate template: metadata:
部署storageClass
创建了nfs分配器以后.西面将开始创建一个使用这个分配器的storageClass
vim /home/loki/4-volume/external-storage-5.5.0/nfs-client/deploy/class.yaml
这里provisioner的值是fuseim.pri/ifs(默认值)是由deployment.yaml 文件里指定的分配器名字.
这个文件作用是:创建一个名字为managed-nfs-storage的storageClass.使用名字为fuseim.pri/ifs的分配器
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: managed-nfs-storage provisioner: fuseim.pri/ifs # or choose another name, must match deployment's env PROVISIONER_NAME' parameters: archiveOnDelete: "false"
开始执行 kubectl apply -f class.yaml ,执行后查看结果 kubectl get sc
# 开始创建pvc文件,复制模板 cp external-storage-5.5.0/nfs-client/deploy/test-claim.yaml .
kind: PersistentVolumeClaim apiVersion: v1 metadata: name: pvc04 annotations: volume.beta.kubernetes.io/storage-class: "managed-nfs-storage" spec: accessModes: - ReadWriteMany resources: requests: storage: 5Gi
还可以写成:
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc03 spec: accessModes: - ReadWriteOnce volumeMode: Filesystem resources: requests: storage: 5Gi storageClassName: managed-nfs-storage
# 测试查看pvc状态,是否创建pvc的同时产生了pv
密码管理
在一些pod里面,是需要填写必要的用户名和密码的
# 创建一个新的名称空间 5-secpass NS
# secret 两种方式键值对和文件 kubectl get secret
建议以命令行的方式来创建
# secret 第一种 kubectl create secret generic mysec1 --from-literal=name=loki --from-literal=age=16
# 查看创建的情况 Opaque(英文意思:不透明的)
# 用yaml的方式查看结果
# 用Json方式查看
# 通过jsonpath查看指定参数的值
# 查看设定的键值对,用jsonpath的方式(默认base64编码)
# 直接查看base64加密后的真实值
# secret 第二种 文件加密
如何使用secret
1. 卷的方式挂载secret,用于传递文件到容器
# sercert 文件传递 创建到/xx 以文件的形式(如果有多个值,想要用其中一个文件)
# 应用场景1: 用于传递配置文件,替代模板镜像的配置文件内容
# 应用场景2(推荐):以变量的方式,用于保存密码
# 这样就不用把明文密码写在yaml文件,而是直接用sercert引入进来
configmap (一般传递文件用configmap)
# cm 简写= configmap
# 创建configmap kv键值对 kubectl create cm <CM_NAME> --from-literal=<Key>=<Value> ...
# 创建configmap 文件 kubectl create cm <CM_NAME> --from-file=<FILE_PATH> ...
# 查看设置的cm (明显发现保存的内容是明文) kubectl get <CM_NAME> kubectl describe cm <CM_NAME>
# 应用场景1(推荐):通过cm把配置文件传入进去,并替换镜像默认模板配置文件
注: 当创建一个pod的时候,都检查没有问题,就是创建不成功,检查secret或者cm是否存在
# 创建过程也会卡在ContainerCreating
# 查看kubectl get ev 里面明显的提示 not found
# 应用场景2: 传入变量值
kubectl edit
# 可以通过命令修改cm 配置文件 kubectl edit cm <CM_NAME> -n <NAMESPACE>
# secret 也可以类似修改方法
#场景应用: 修改kube-proxy 模式iptable ipvs,修改后删掉之前创建的pod
deployment 控制器
# pod只要挂掉了,就不会再次启动
# pod 不具备再生性,不健壮的
所以,需要使用控制器来管理pod
了解deployment的作用(相当于是一个机器人)
创建deployment
# 推荐使用yaml的文件方式来创建deploy, 从1.18开始命令方式写的选项少于yaml文件
kubectl create deployment <DEPLOY_NAME> --image=<IMAGE_NAME> --dry-run=client -o yaml > <导出的文件>
deploy 文件区域介绍
#deployment 盯着pod是通过标签(matchLabels)
# 2个标签要匹配
deployment
# 通过控制器模板(deployment)创建
# deploy 基本信息查看 kubectl get deploy kubectl get deploy -o wide
课看到默认分配了一个标签app=web1
# 修改 副本数
命令行方式
scale(伸缩) 瞬间增加副本到5个
修改方式1/3: kubectl scale deploy <DEPLOY_NAME> --replicas=<Numbers>
EDIT方式
# 修改方式2/3: 还可以通过edit的方式修改副本数 kubectl edit deploy <DEPLOY_NAME>
YAML方式
# 修改方式3/3: 直接修改yaml文件的方式修改副本数,修改后要生效需要重新执行 apply -f <DEPLOY_YAML>
# 水平自动伸缩 HPA
纵向扩展:只能增加cpu,内存,硬件相关
横向扩展:比较灵活可弹性增删节点
# 配置HPA之前准备
mtric server # 确保安装
kubectl top nodes # 验证
# 创建hpa
不存在优先级的问题
# 查看hpa情况 kubectl get hpa
# 解决当前cpu使用量为unknown(需要设置pod资源限制)
1.可以在线修改,用 kubectl edit deploy <DEPLOY_NAME> PS:前提是你已经设置了资源限制
2.修改yaml文件
# 创建HPA,CPU限制
如果是设置相同的deployment就需要删除后重新输入 kubectl autoscale deployment <DEPLOY_NAME> --min=1 --max=5 --cpu-percent=60
# 设置了resources: 字段以后这里就不再显示unknown了
实验阶段
# master 上 启用svc(负债均衡器,后面会讲,这里为了实验借用一下)
# 创建一个名为svc1 的负载均衡器,对应到控制器web1 的80端口,并且外部端口随机分配
kubectl expose --namesvc1 deploy web1 --port=80 --type=NodePort
# 分配了一个集群IP(仅集群内部可以访问和绑定了一个随机外部端口32111)
然后分别开启hpa和pods的情况监控,watch kubectl get hpa 和 watch kubectl get pods
# 因为hpa发现了cpu负载变高,开始大量增加pods数量 ,按照我们刚刚设置的最多可以开5台
# 在vm4 使用ab工具 模拟产生请求数
首先,安装工具 yum install httpd-tools -y
ab -t 600 -n 1000000 -c 1000 http://192.168.27.216:32111/index.html
ab命令常用参数介绍:
-t 时间
-n requests,总共发送多少个请求
-c concurrency, 并发
# 如果测试终止,会等待五分钟会把pods 缩小到最小值---间隔5分钟原因是防止“抖动”
deployment 健壮性测试
# 首先,查看当前pod在vm2的节点上运行
# 然后,我们去vm2服务器上进行重启 init 0,下线差不多5分钟左右会发现再vm3上面重新创建了一个pod,这个时候我们在开机vm2节点,在vm3上面的pod不会返回到vm2上面。
# kubernetes-升级镜像
更新容器镜像版本,首先查看当前镜像版本 nginx:latest (默认不跟版本就是latest)
更新镜像版本 kubectl set image deploy <DEPLOY_NAME> <CONTAINERS>=<IMAGES> [--record]
# 更新完毕后再次查看,发现版本已经是我们设定的版本
注:如果设置了--record,就可以使用查看历史记录命令你查看操作记录
回滚操作: kubectl rollout undo deployment <DEPLOY_NAME>
查看历史记录: kubectl rollout history deployment <DEPLOY_NAME>
# 在线修改滚动更新策略 kubectl edit deploy <DEPLOY_NAME>
找到下面内容位置:
参数介绍:
# 可以使用百分比,也可以是具体个数
maxSurge: 在升级过程中一次升级几个
maxUnavailable: 在升级过程中,只能有1个不可用一次性删除多少个pod
实验: 比如我们修改为一次升级3个,一次性删除1个。然后多开放几个副本进行测试
可以通过 kubectl get rs 命令来查看副本转移过程
# 如果想回退到某个指定阶段的版本 kubectl rollout undo deployment <DEPLOY_NAME> --to-revision=<numbers>
其他一些控制器
# 新建一个名称空间开始这个阶段
daemonset 例如: calico和kube-proxy每个节点都有一个ds
创建ds
# 通过deploy的yaml文件进行修改,因为daemonset本身不存在模板
默认没有模板yaml,需要通过deployment模板修改4处后如下:
# 最后DS模板如下
apiVersion: apps/v1 kind: DaemonSet metadata: creationTimestamp: null labels: app: web1 name: web1 spec: selector: matchLabels: app: web1 template: metadata: creationTimestamp: null labels: app: web1 spec: containers: - image: nginx name: nginx resources: {}
# 针对在有ssd标签上运行
# 查看创建的ds kubectl get ds
# 查看创建的ds 更详细信息 kubectl describe ds
通过标签(label)控制pod所在的节点位置(默认,带有污点(Taints)的nodes是不会创建pod)
# 创建一个节点的标签 kubectl label node <NODE> <LABEL_Key=LABEL_Value>
# 查看标签命令 kubectl get node --show-labels
# 根据上面设置的label设定YAML文件,然后apply -f 文件,启动后会发现,打有loki标签的节点上启动了pod(此node一定不能为有Taints,不然依然不能在这个节点上启动)
ReplicationController(RC)
apiVersion: v1 kind: ReplicationController metadata: name: web1 spec: replicas: 3 selector: app: web1 template: metadata: labels: app: web1 spec: containers: - image: nginx name: nginx ports: - containerPort: 80
# 查看rc 情况 kubectl get rc
# 查看rc 详细情况,这里面可以看到rc创建的pod名字 kubectl describe rc
ReplicaSet(RS)
rs 控制器,看文档实验
apiVersion: apps/v1 kind: ReplicaSet metadata: name: rs1 labels: test2: bbb spec: replicas: 2 selector: matchLabels: test1: aaa template: metadata: labels: test1: aaa spec: containers: - image: nginx name: nginx
# 注意这些lables,一个代表Labels,一个代表Selector
# 查看rs 运行情况
# 查看rs 详细情况
# 增加RS 运行的副本数
# 都是通过depoly 模板进行修改
健康性检查 (探测)
检测方式之一: liveness probe -- command
command 在容器里执行一个命令,检测此命令能否正常执行
# 创建新的一个NS空间, 开始进行试验 8-probe
apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: test: liveness run: liveness-exec name: liveness-exec spec: terminationGracePeriodSeconds: 0 containers: - image: busybox imagePullPolicy: IfNotPresent name: liveness-exec args: - /bin/sh - -c - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 10 livenessProbe: exec: command: - cat - /tmp/healthy initialDelaySeconds: 5 # 容器启动5s内不检测 periodSeconds: 5 # 每5s检测一次 resources: {} dnsPolicy: ClusterFirst restartPolicy: Always status: {}
# 通过livenessProbe字段下面的command来进行检测,如果发现没有/tmp/healthy文件,则容器重启
kubectl describe pod liveness-exec 或者 kubectl get ev 来进行观察
检测方式之二: liveness probe -- httpGET/tcp
httpGET
apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: liveness-http name: liveness-http spec: terminationGracePeriodSeconds: 0 containers: - image: nginx imagePullPolicy: IfNotPresent name: liveness-http livenessProbe: failureThreshold: 3 # 当Pod启动了并且探测到失败,K8s的重试次数。存活探测情况下的放弃就意味着>重新启动容器。就绪探测情况下的放弃 Pod 会被打上未就绪的标签。默认值是 3。最小值是 1 httpGet: path: /index.html # 这里并非指的根目录,而是 指的是nginx主目录/usr/share/nginx/html port: 80 initialDelaySeconds: 10 # 容器启动10s内不检测 periodSeconds: 10 # 每5s检测一次 successThreshold: 1 # 检测失败后,再次检测。连续1次才被认定为成功,默认是1,对于liveness必须是 1,最小值是1. timeoutSeconds: 10 # 探测超时时间,默认为10秒,最小1秒 resources: {} dnsPolicy: ClusterFirst restartPolicy: Always status: {}
# 模拟删掉主页文件
kubectl exec -it liveness-http -- rm /usr/share/nginx/html/index.html
TCPSocket
apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: liveness-tcp name: liveness-tcp spec: terminationGracePeriodSeconds: 0 containers: - image: nginx imagePullPolicy: IfNotPresent name: liveness-tcp livenessProbe: failureThreshold: 3 # 当Pod启动了并且探测到失败,K8s的重试次数。存活探测情况下的放弃就意味着重新启动容器。就绪探测情况下的放弃 Pod 会被打上未就绪的标签。默认值是 3。最小值是 1 tcpSocket: port: 81 initialDelaySeconds: 10 # 容器启动10s内不检测 periodSeconds: 10 # 每5s检测一次 successThreshold: 1 # 检测失败后,再次检测。连续1次才被认定为成功,默认是1,对于liveness必须是1,最小值是1. timeoutSeconds: 10 # 探测超时时间,默认为10秒,最小1秒 resources: {} dnsPolicy: ClusterFirst restartPolicy: Always status: {}
# 这样就会自动检测端口81是否存活,如果3次都不成功就会“重启大法”
livenessProbe 通过重启来解决问题
readinessProbe 检测到问题,并不会使用“重启大法”
# readinessProbe -- command
apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: readiness-exec name: readiness-exec spec: terminationGracePeriodSeconds: 0 containers: - image: busybox imagePullPolicy: IfNotPresent name: readiness-exec args: - /bin/sh - -c - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 10 readinessProbe: exec: command: - cat - /tmp/healthy initialDelaySeconds: 5 # 容器启动5s内不检测 periodSeconds: 5 # 每5s检测一次 resources: {} dnsPolicy: ClusterFirst restartPolicy: Always status: {}
# readinessProbe -- http
apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: readiness-http name: readiness-http spec: terminationGracePeriodSeconds: 0 containers: - image: nginx imagePullPolicy: IfNotPresent name: readiness-http readinessProbe: failureThreshold: 3 # 当Pod启动了并且探测到失败,K8s的重试次数。存活探测情况下的放弃就意味着 重新启动容器。就绪探测情况下的放弃 Pod 会被打上未就绪的标签。默认值是 3。最小值是 1 httpGet: path: /index.html port: 80 initialDelaySeconds: 10 # 容器启动10s内不检测 periodSeconds: 10 # 每5s检测一次 successThreshold: 1 # 检测失败后,再次检测。连续1次才被认定为成功,默认是1,对于readiness必须 是1,最小值是1. timeoutSeconds: 10 # 探测超时时间,默认为10秒,最小1秒 resources: {} dnsPolicy: ClusterFirst restartPolicy: Always status: {}
# readinessProbe -- Tcp
apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: readiness-tcp name: readiness-tcp spec: terminationGracePeriodSeconds: 0 containers: - image: nginx imagePullPolicy: IfNotPresent name: readiness-tcp readinessProbe: failureThreshold: 3 # 当Pod启动了并且探测到失败,K8s的重试次数。存活探测情况下的放弃就意味着 重新启动容器。就绪探测情况下的放弃 Pod 会被打上未就绪的标签。默认值是 3。最小值是 1 tcpSocket: port: 81 initialDelaySeconds: 10 # 容器启动10s内不检测 periodSeconds: 10 # 每5s检测一次 successThreshold: 1 # 检测失败后,再次检测。连续1次才被认定为成功,默认是1,对于readiness必须 是1,最小值是1. timeoutSeconds: 10 # 探测超时时间,默认为10秒,最小1秒 resources: {} dnsPolicy: ClusterFirst restartPolicy: Always status: {}
文件写法和livenessProbe类似,只是关键词不一样
kubectl get ev # 查看事件,用于排错
# 创建服务
kubectl expose --name=<SVC_NAME> deploy <DEPLOY_NAME> --port=<PORT_NUMBER> --type=NodePort
# svc 负载均衡 测试(每个容器的index.html首页为了方便识别,分别修改了111,222,333)
job
创建job kubectl create job <JOB_NAME> --image=<IMAGE_NAME> --dry-run=client -o yaml > <YAML_NAME>
# 修改配置文件,执行一个date命令,然后休息10秒
# 可以看到命令执行成功
# 可以看到job 已经1/1 表示执行完成
# job 模式不允许使用Always
# 如果使用过了就出现提示,只允许使用Never和OnFailure
Never: 不重启--通过创建新的pod来解决问题
OnFailure: 如果没有完成任务,则不停的通过创建重启来完成
# job常用的一些参数介绍
backoffLimit: 重试次数
completions: 至少有几次成功
parallelism: 同时一次创建几个任务
# 圆周率实验(一次性计算一个圆周率)
# 所需镜像 docker pull perl
# 编辑yaml文件
# 执行结果,运算出圆周率后200位的值
cronjob 简写cj
# 创建cronjob的yaml文件
# 修改yaml
# 可以看到cj,根据schedule每一分钟会创建一个pod,执行一次date命令
kubectl get ev 里面可以查看到每分钟创建的情况
服务的配置 svc
服务的介绍
创建服务
服务的发现
服务的发布
# 确认服务使用的IP地址段 kubeadm config view
# pod 和 svc 所在的网段是集群内部可访问
# 实验阶段
# 创建deploy ,修改默认副本数到2
# 修改默认的副本数为3 kubectl scale deploy <DEPLOY_NAME> --replicas=<NUMBER>
# 临时修改3个pod里面nginx首页显示内容
# 开始创建svc服务 kubectl expose --name=<SVC_NAME> deploy <DEPLOY_NAME> --port=<PORT_NUMBER> --target-port=<PORT_NUMBER>
# svc服务的CLUSTER-IP也只是集群内部可访问的
# 找到svc selector 标签,快速定位对应的pods
服务发现
服务的发现通过三种方式:
1. 直接通过clusterIP
2. 通过变量
注意事项:
1)需要相同的命名空间
2)变量获取只能获取创建之前svc的变量
3. dns
wordpress+mysql实验,先去download相关镜像
# 准备阶段(work节点镜像准备)
sudo docker pull hub.c.163.com/library/mysql:latest
sudo docker pull hub.c.163.com/library/wordpress:latest
sudo docker pull hub.c.163.com/library/centos:latest
首先,创建mysql 的 pod
apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: db name: db spec: terminationGracePeriodSeconds: 0 volumes: - name: v1 containers: - image: hub.c.163.com/library/mysql:latest # 这里记得替换为自己使用的image地址 imagePullPolicy: IfNotPresent name: db resources: {} env: - name: MYSQL_ROOT_PASSWORD # MySQL需要的一些变量 value: mysql_password - name: MYSQL_DATABASE value: db_name dnsPolicy: ClusterFirst restartPolicy: Always status: {}
# 使用生产的yaml文件,创建一个数据库的svc的服务
kubectl expose --name=dbsvc pod db --port=3306
# 查看kubectl get svc -o wide
在创建wordpress pod
apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: blog name: blog spec: terminationGracePeriodSeconds: 0 volumes: - name: v1 containers: - image: hub.c.163.com/library/wordpress:latest imagePullPolicy: IfNotPresent name: blog resources: {} env: - name: WORDPRESS_DB_USER value: db_username - name: WORDPRESS_DB_PASSWORD value: password - name: WORDPRESS_DB_NAME value: db_name - name: WORDPRESS_DB_HOST value: cluster-ip(x.x.x.x) # 这个地址来源你的db_svc dnsPolicy: ClusterFirst restartPolicy: Always status: {}
# 同样的创建blog的svc服务(为了方便测试,这里使用了一个参数--type=NodePort把端口映射到物理机随机端口上)
kubectl expose --name=blogsvc pod blog --port=80 --type=NodePort
# 记住这个端口,找一台机器访问物理机这个端口进行wordpress初始化
# 访问,集群的物理IP+NodePort端口,看到如下界面
# 填上基本信息,只要没有出现让你填写数据库相关信息,表示通过cluster-ip方式成功。
# 变量的方式
跟着,我们创建一个临时pod,查看env(当前的pod,会记录之前创建好的svc的信息)
kubectl run c1 --rm -it --image=busybox --image-pull-policy=IfNotPresent -- sh
记录方式:
大写的服务名_SERVICE_HOST= 那个服务的IP
大写的服务名_SERVICE_PORT= 那个服务的端口
Note:这个pod里,它只记录那些在这个pod创建之前的svc的信息,当前创建的是不会记录的
# 这个pod里再次创建(删除blog 的pod,我们修改为这个变量值,再次创建)
# 缺点:必须在同一个命名空间,需要注意创建顺序
# DNS的方式
# 系统里面默认的kube-system 里面存在一个kube-dns的服务
# 查看这个svc里面跑了2个pod,这个2个pod的作用就是做名称解析
# 开始测试,创建一个新的pod名叫 demo1,并为它创建一个svc,修改index.html内容为“Loki in here!”
# 发现访问的svc的名称,也可以直接访问到
原理解析: 当我们每创建一个svc的时候,这个svc就会向kube-system这个ns去注册,服务名 -- IP
# 创建的一个nginx pod <----相同的命名空间
# 在不同的命名空间需要加上命名空间名
# 相同命名空间,直接用变量名(DNS),如果不同命名空间还需要加上 空间名 服务名.NameSpace名
服务的发布