K8S-基础资源(小白的“升级打怪”成长之路)
#查看对象中包含哪些字段类型maxSurge:和期望的副本数比,超过期望副本数最大比例(或最大值),这个值调的越大,副本更新速度越快。maxUnavailable:和期望的副本数比,不可用副本数最大比例(或最大值),这个值越小,越能保证服务稳定,更新越平滑;设置方式按数量maxUnavailable: [0, 副本数]maxSurge: [0, 副本数]注两者不能同时为0。按比例。
目录
一、namespace资源管理
1、查看名称空间及其资源对象
k8s集群默认提供了几个名称空间用于特定目的,例如,kube-system主要用于运行系统级资源,存放k8s一些组件的。而default则为那些未指定名称空间的资源操作提供一个默认值。
##查看名称空间 kubectl get namespace ##查看特定的名称空间的详细信息 kubectl describe namespace NAME
[root@k8s-master namespaces]# kubectl get ns NAME STATUS AGE calico-apiserver Active 34h calico-system Active 34h default Active 16d ingress-nginx Active 34h kube-node-lease Active 16d kube-public Active 16d kube-system Active 16d metallb-system Active 24h tigera-operator Active 34h [root@k8s-master namespaces]# kubectl get namespaces NAME STATUS AGE calico-apiserver Active 34h calico-system Active 34h default Active 16d ingress-nginx Active 34h kube-node-lease Active 16d kube-public Active 16d kube-system Active 16d metallb-system Active 24h tigera-operator Active 34h
[root@k8s-master namespaces]# kubectl describe ns default Name: default Labels: kubernetes.io/metadata.name=default Annotations: <none> Status: Active No resource quota. No LimitRange resource.
2、管理namespace资源
namespace资源的名称仅能由字母、数字、下划线、连接线等字符组成。删除namespace资源会级联删除其包含的所有其他资源对象。
##创建名称空间 kubectl create namespace 名称 ##删除名称空间 kubectl delete namespace 名称
[root@k8s-master namespaces]# kubectl create ns myns1 namespace/myns1 created [root@k8s-master namespaces]# kubectl get ns NAME STATUS AGE calico-apiserver Active 34h calico-system Active 34h default Active 16d ingress-nginx Active 34h kube-node-lease Active 16d kube-public Active 16d kube-system Active 16d metallb-system Active 24h myns1 Active 4s tigera-operator Active 34h [root@k8s-master namespaces]# kubectl delete ns myns1 namespace "myns1" deleted [root@k8s-master namespaces]# kubectl get ns NAME STATUS AGE calico-apiserver Active 34h calico-system Active 34h default Active 16d ingress-nginx Active 34h kube-node-lease Active 16d kube-public Active 16d kube-system Active 16d metallb-system Active 24h tigera-operator Active 34h
用yaml文件创建命令空间
vim namespaces.yaml
apiVersion: v1 kind: Namespace metadata: name: myns2
[root@k8s-master namespaces]# kubectl apply -f namespaces.yaml namespace/myns2 created [root@k8s-master namespaces]# kubectl get ns NAME STATUS AGE calico-apiserver Active 35h calico-system Active 35h default Active 16d ingress-nginx Active 34h kube-node-lease Active 16d kube-public Active 16d kube-system Active 16d metallb-system Active 24h myns1 Active 10m myns2 Active 3s tigera-operator Active 35h
3、切换默认查看命名空间
默认命名空间是default
[root@k8s-master namespaces]# kubectl get po No resources found in default namespace. [root@k8s-master namespaces]# kubectl -n default get po No resources found in default namespace.
切换默认命名空间
[root@k8s-master01 ~]# kubectl config set-context --current --namespace=kube-system #注意:切换命名空间后,kubectl get pods 如果不指定-n,查看的就是kube-system命名空间的资源了。
[root@k8s-master namespaces]# kubectl get ns NAME STATUS AGE calico-apiserver Active 34h calico-system Active 34h default Active 16d ingress-nginx Active 34h kube-node-lease Active 16d kube-public Active 16d kube-system Active 16d metallb-system Active 24h myns1 Active 9s tigera-operator Active 34h
[root@k8s-master namespaces]# kubectl config set-context --current --namespace myns1 Context "kubernetes-admin@kubernetes" modified. [root@k8s-master namespaces]# kubectl get po No resources found in myns1 namespace. [root@k8s-master namespaces]# kubectl -n myns1 get po No resources found in myns1 namespace.
4、配置namespace资源限额
vim namespace-quota.yaml
apiVersion: v1 kind: ResourceQuota metadata: name: mem-cpu-quota namespace: myns2 spec: hard: requests.cpu: '2' requests.memory: 2Gi limits.cpu: '4' limits.memory: 4Gi ####解析#### #创建的ResourceQuota对象将在myns2名字空间中添加以下限制: #每个容器必须设置内存请求(memory request),内存限额(memory limit),cpu请求(cpu request)和cpu限额(cpu limit)。 ##所有容器的内存请求总额不得超过2GiB。 ##所有容器的内存限额总额不得超过4GiB。 ##所有容器的CPU请求总额不得超过2CPU。 ##所有容器的CPU限额总额不得超过4CPU。 ##应用配额文件并查看命名空间是否收到了限制
[root@k8s-master namespaces]# kubectl apply -f namespace-quota.yaml resourcequota/mem-cpu-quota created [root@k8s-master namespaces]# kubectl describe ns myns2 Name: myns2 Labels: kubernetes.io/metadata.name=myns2 Annotations: <none> Status: Active Resource Quotas Name: mem-cpu-quota Resource Used Hard -------- --- --- limits.cpu 0 4 limits.memory 0 4Gi requests.cpu 0 2 requests.memory 0 2Gi No LimitRange resource.
当创建该pod没有配置资源限制时无法创建成功
vim pod-test.yaml
apiVersion: v1 kind: Pod metadata: name: pod-test namespace: myns2 labels: app: nginx-pod-test spec: containers: - name: nginx-test ports: - containerPort: 80 image: nginx:latest imagePullPolicy: IfNotPresent
[root@k8s-master pod]# kubectl apply -f pod-test.yaml Error from server (Forbidden): error when creating "pod-test.yaml": pods "pod-test" is forbidden: failed quota: mem-cpu-quota: must specify limits.cpu for: nginx-test; limits.memory for: nginx-test; requests.cpu for: nginx-test; requests.memory for: nginx-test
当创建该pod配置资源限制时才能创建成功
vim pod-test.yaml
apiVersion: v1 kind: Pod metadata: name: pod-test namespace: myns2 labels: app: nginx-pod-test spec: containers: - name: nginx-test ports: - containerPort: 80 image: nginx:latest imagePullPolicy: IfNotPresent resources: limits: cpu: 0.5 memory: 1024Mi
[root@k8s-master pod]# kubectl apply -f pod-test.yaml pod/pod-test created [root@k8s-master pod]# kubectl -n myns2 get po NAME READY STATUS RESTARTS AGE pod-test 1/1 Running 0 49s
二、Pod资源对象
POD创建过程
第一步: 客户端提交创建Pod的请求,可以通过调用API Server的Rest API接口,也可以通过kubectl命令行工具。如kubectl apply -f filename.yaml(资源清单文件) 第二步: apiserver接收到pod创建请求后,会将yaml中的属性信息(metadata)写入etcd。 第三步: apiserver触发watch机制准备创建pod,信息转发给调度器scheduler,调度器用一组规则过滤掉不符合要求的主机,比如Pod指定了所需要的资源量,那么可用资源比Pod需要的资源量少的主机会被过滤掉。调度器使用调度算法选择node,调度器将node信息给apiserver,apiserver将绑定的node信息写入etcd。 第四步: apiserver又通过watch机制,调用kubelet,指定pod信息,调用Docker API创建并启动pod内的容器。 第五步: worker创建完成之后反馈给自身的kubelet, 再反馈给控制器的kubelet,然后将pod的状态信息给apiserver,apiserver又将pod的状态信息写入etcd。
1、Pod资源清单介绍
##查看对象中包含哪些字段 [root@k8s-master01 ~]# kubectl explain pod.spec.containers
2、POD YAML文件示例
# yaml格式的pod定义文件完整内容: # Pod的API版本,核心资源使用v1版本 apiVersion: v1 # 必选,版本号,例如v1 # 资源类型,这里定义为Pod kind: Pod # 必选,Pod # 元数据信息,用于标识和描述Pod metadata: # 必选,元数据 name: string # 必选,Pod的名称,在命名空间内必须唯一 namespace: string # 可选,Pod所属的命名空间,默认是default labels: # 可选,键值对形式的标签,用于资源筛选和关联 - name: string # 标签名称和值 annotations: # 可选,键值对形式的注解,用于存储额外说明信息(不用于资源选择) - name: string # 注解名称和值 # Pod的规格说明,定义Pod的运行状态和容器配置 spec: containers: # 必选,容器列表,一个Pod至少包含一个容器 - name: string # 必选,容器名称,在Pod内必须唯一 image: string # 必选,容器使用的镜像名称,格式为[仓库地址/]镜像名:标签 # 镜像拉取策略 imagePullPolicy: [Always | Never | IfNotPresent] # 可选,Always:总是拉取;Never:从不拉取;IfNotPresent:本地不存在时拉取 command: [string] # 可选,容器启动命令,会覆盖镜像的默认命令 args: [string] # 可选,启动命令的参数 workingDir: string # 可选,容器的工作目录 volumeMounts: # 可选,容器挂载的存储卷配置 - name: string # 存储卷名称,必须与spec.volumes中的名称一致 mountPath: string # 容器内的挂载路径 readOnly: boolean # 可选,是否为只读挂载,默认false ports: # 可选,容器暴露的端口声明(仅用于标识,不实际暴露服务) - name: string # 可选,端口名称,用于标识 containerPort: int # 必选,容器内部监听的端口号 hostPort: int # 可选,映射到主机的端口号(不推荐,可能导致端口冲突) protocol: string # 可选,协议类型,默认TCP env: # 可选,容器的环境变量配置 - name: string # 环境变量名称 value: string # 环境变量值 resources: # 可选,容器的资源限制和请求配置 limits: # 资源限制,容器不能超过此值 cpu: string # CPU限制,例如"500m"表示0.5核,单位为core数 memory: string # 内存限制,例如"512Mi",单位可以为Mib/Gib requests: # 资源请求,调度时参考此值分配资源 cpu: string # CPU请求,容器启动的初始可用数量,例如"100m"表示0.1核 memory: string # 内存请求,容器启动的初始可用数量,例如"128Mi" livenessProbe: # 可选,存活探针,用于检测容器是否正常运行,失败会重启容器,检查方法有exec、httpGet和tcpSocket,对一个容器只需设置其中一种方法即可 exec: # 执行命令方式检测 command: [string] # 执行的命令,返回0表示成功 httpGet: # HTTP请求方式检测 path: string # 请求路径 port: number # 请求端口 host: string # 请求主机 scheme: string # 协议,HTTP或HTTPS HttpHeaders: # 自定义请求头 - name: string # 头名称 value: string # 头值 tcpSocket: # TCP连接方式检测 port: number # 连接端口 initialDelaySeconds: 0 # 容器启动后延迟多久开始检测,单位秒 timeoutSeconds: 0 # 检测超时时间,单位秒,默认1秒 periodSeconds: 0 # 检测间隔时间,单位秒,默认10秒一次 successThreshold: 0 # 连续成功多少次视为正常 failureThreshold: 0 # 连续失败多少次视为异常 securityContext: # 可选,容器的安全上下文 privileged: false # 是否以特权模式运行容器 # 容器重启策略 restartPolicy: [Always | Never | OnFailure] # 可选,Always:总是重启,表示一旦不管以何种方式终止运行,pod都将重启,OnFailure表示只有Pod以非0退出码退出才重启,Nerver表示不再重启该Pod nodeSelector: obeject # 可选,节点选择器,设置NodeSelector表示将该Pod调度到包含这个label的node上,以key:value的格式指定 imagePullSecrets: # 可选,拉取私有镜像的密钥 - name: string # 密钥名称 hostNetwork: false # 可选,是否使用主机网络命名空间,默认false,如果设置为true,表示使用宿主机网络 volumes: # 可选,存储卷定义,供容器挂载使用 - name: string # 存储卷名称,在Pod内唯一 emptyDir: {} # 临时存储卷,Pod删除时数据丢失 hostPath: string # 主机路径存储卷,挂载主机上的文件或目录 path: string # 主机上的路径 secret: # 密钥存储卷,挂载Secret资源 scretname: string # Secret名称 items: # 可选,指定要挂载的密钥项 - key: string # 密钥中的键 path: string # 挂载到容器内的路径 configMap: # 配置存储卷,挂载ConfigMap资源到容器内部 name: string # ConfigMap名称 items: # 可选,指定要挂载的配置项 - key: string # ConfigMap中的键 path: string # 挂载到容器内的路径
3 、标签
给pod资源打标签
#对已经存在的pod打标签 [root@k8s-master01 ~]# kubectl label pods pod-first release=v1 #查看标签是否打成功 [root@k8s-master01 ~]# kubectl get pods pod-first --show-labels
查看资源标签
#查看默认名称空间下所有pod资源的标签 [root@k8s-master01 ~]# kubectl get pods --show-labels #查看默认名称空间下指定pod具有的所有标签 [root@k8s-master01 ~]# kubectl get pods pod-first --show-labels #列出默认名称空间下标签key是release的pod,不显示标签 [root@k8s-master01 ~]# kubectl get pods -l release #列出默认名称空间下标签key是release、值是v1的pod,不显示标签 [root@k8s-master01 ~]# kubectl get pods -l release=v1 #列出默认名称空间下标签key是release的所有pod,并打印对应的标签值 [root@k8s-master01 ~]# kubectl get pods -L release #查看所有名称空间下的所有pod的标签 [root@k8s-master01 ~]# kubectl get pods --all-namespaces --show-labels
4 、资源限制
4.1、节点资源不足,导致调度失败
vim pod-test2.yaml
apiVersion: v1 kind: Pod metadata: name: pod-test2 labels: app: nginx-pod-test spec: containers: - name: nginx-test2 ports: - containerPort: 80 image: nginx:latest imagePullPolicy: IfNotPresent resources: limits: cpu: 8 memory: 8Gi requests: cpu:
[root@k8s-master pod]# kubectl apply -f pod-test2.yaml pod/pod-test2 created [root@k8s-master pod]# kubectl get pod NAME READY STATUS RESTARTS AGE pod-test2 0/1 Pending 0 8s [root@k8s-master pod]# kubectl describe pod pod-test2 ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedScheduling 2m9s default-scheduler 0/3 nodes are available: 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }, 2 Insufficient cpu, 2 Insufficient memory. preemption: 0/3 nodes are available: 1 Preemption is not helpful for scheduling, 2 No preemption victims found for incoming pod..
4.2、所在命名空间资源不足
vim namespace-quota.yaml
apiVersion: v1 kind: ResourceQuota metadata: name: mem-cpu-quota namespace: myns2 spec: hard: requests.cpu: '2' requests.memory: 2Gi limits.cpu: '4' limits.memory: 4Gi
[root@k8s-master namespaces]# kubectl apply -f namespace-quota.yaml resourcequota/mem-cpu-quota created [root@k8s-master namespaces]# kubectl describe ns myns2 Name: myns2 Labels: kubernetes.io/metadata.name=myns2 Annotations: <none> Status: Active Resource Quotas Name: mem-cpu-quota Resource Used Hard -------- --- --- limits.cpu 0 4 limits.memory 0 4Gi requests.cpu 0 2 requests.memory 0 2Gi No LimitRange resource.
vim nginx,.yaml
apiVersion: v1 kind: Pod metadata: name: nginx-pod2 namespace: myns2 spec: containers: - name: nginx2 image: nginx imagePullPolicy: IfNotPresent resources: limits: cpu: '8' memory: '8Gi' requests: cpu: '6' memory: '2Gi'
提交后的报错信息
[root@k8s-master pod]# kubectl apply -f nginx.yaml Error from server (Forbidden): error when creating "nginx.yaml": pods "nginx-pod2" is forbidden: exceeded quota: mem-cpu-quota, requested: limits.cpu=8,limits.memory=8Gi,requests.cpu=6,requests.memory=2Gi, used: limits.cpu=500m,limits.memory=1Gi,requests.cpu=500m,requests.memory=1Gi, limited: limits.cpu=4,limits.memory=4Gi,requests.cpu=2,requests.memory=2Gi
5 、Pod探针
探针的类型
-
livenessProbe(存活探针):判断容器是否正常运行。如果存活探测失败,那么kubelet就会把老的容器删除,然后根据重启策略对容器做操作。如果容器没有存活探针,默认状态为Success。
-
readinessProbe(就绪探针):判断容器的是否就绪。比如:应用在启动时可能需要加载大量的数据或配置文件,或是启动后要依赖等待外部服务。在这种情况下,既不想杀死应用,也不想给它发送请求。这个时候就需要用到这个探针。当就绪探测失败,端点控制器将从与 Pod匹配的所有服务的端点列表中删除该 Pod 的 IP 地址(如果是用nodeport映射端口到外网,这个时候就不能访问网站了,但是容器不会被删除),初始延迟之前的就绪态的状态值默认为 Failure。 如果容器不提供就绪态探针,则默认状态为 Success。
-
startupProbe(启动探针):指示容器中的应用是否已经启动。如果提供了启动探针,则所有其他探针都会被禁用,直到此探针成功为止。如果启动探测失败,kubelet 将删除容器,而容器依其重启策略进行重启。如果容器没有提供启动探测,则默认状态为 Success。
注意:startupProbe 和 livenessProbe 最大的区别就是startupProbe在探测成功之后就不会继续探测了,而livenessProbe在pod的生命周期中一直在探测!
探针属性
-
(initialDelaySeconds: 5):初始化延迟时间,主要是告诉kubelet,容器启动需要的时间,当过了这个时间再进行探测,要不然容器可能还没启动就会删除了。
-
(periodSeconds: 5):探测周期间隔时间,主要是指定kubelet对容器进行探针的时间周期,也就是第一次探测结束后,等待多少时间后对容器进行探测。默认值为10秒,最小值为1秒。
-
(timeoutSeconds: 5):单次探测超时时间,指定kubelet对容器探测的最大时间,超过这个时间证明容器探测失败。默认为1秒,最小为1秒。
-
(successThreshold: 5):探测失败到成功的重试次数,当kubelet对某个容器第一次探测失败后,重新进行探测的次数,比如指定为1,那么就会直接将容器删除。如果使用的探针是livenessProbe,那么只能配置为1,最小值为1次。
-
(failureThreshold: 5):探测成功到失败的重试次数,当kubelet对某个容器进行探测过程中,允许失败的次数,当用于readinessProbe探针,默认是3次,最小值为1次。也就是说当3次探测失败后,容器会被删除。当用于startupProbe探针,如果还设置了periodSeconds时间,那么等待容器启动的时间为failureThreshold的时间乘以periodSeconds时间的值,在这段时间内,容器没有启动,那么就会删除容器。
5.1、livenessProbe探针案例
livenessProbe和kubelet-exec
vim nginx_pod.yaml
apiVersion: v1 kind: Pod metadata: name: nginx-pods labels: app: nginx spec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent livenessProbe: exec: #定义探测方式 command: #不断查看文件是否存在,文件必须是镜像原本存在的文件 - cat - /usr/share/nginx/html/index.html initialDelaySeconds: 5 #指定探针多少秒后启动 periodSeconds: 5 #指定探针探测周期时间
[root@k8s-master pod]# kubectl delete -f nginx-re-exec.yml deployment.apps "nginx" deleted service "nginx-svc-nodeport" deleted [root@k8s-master pod]# kubectl get pod NAME READY STATUS RESTARTS AGE nginx-pods 1/1 Running 0 87s ###进入容器,触发探针 [root@k8s-master pod]# kubectl exec -it nginx-pods /bin/bash kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. root@nginx-pods:/# cd /usr/share/nginx/html/ root@nginx-pods:/usr/share/nginx/html# ls 50x.html index.html root@nginx-pods:/usr/share/nginx/html# mv index.html index1.html root@nginx-pods:/usr/share/nginx/html# ls 50x.html index1.html root@nginx-pods:/usr/share/nginx/html# exit exit ##发现重启了一次 [root@k8s-master pod]# kubectl get pod NAME READY STATUS RESTARTS AGE nginx-pods 1/1 Running 1 (31s ago) 3m12s ##再次进入容器,发现文件重建了 [root@k8s-master pod]# kubectl exec -it nginx-pods /bin/bash kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. root@nginx-pods:/# cd /usr/share/nginx/html/ root@nginx-pods:/usr/share/nginx/html# ls 50x.html index.html
livenessProbe和kubelet-httpGet
[root@k8s-master01 ~]# cat /root/pod/nginx_pod.yaml apiVersion: v1 kind: Pod metadata: name: nginx-pods labels: app: nginx spec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent livenessProbe: httpGet: #指定探针探测方式 path: /index.html #定义请求的URL port: 80 #定义GET的端口 initialDelaySeconds: 3 #指定探针多少秒后启动 periodSeconds: 3 #指定探针的探测周期 [root@k8s-master01 ~]# kubectl apply -f /root/pod/nginx_pod.yaml [root@k8s-master01 ~]# kubectl get pod ###进入容器,触发探针 [root@k8s-master01 nginx]# kubectl exec -it nginx-pods /bin/bash root@nginx-pods:/usr/share/nginx/html# mv index.html index1.html ###好处看看后发现重启了1次 [root@k8s-master01 ~]# kubectl get pod NAME READY STATUS RESTARTS AGE nginx-pods 1/1 Running 1 (59s ago) 4m15s ##再次进入容器,发现文件重建了 [root@k8s-master01 nginx]# kubectl exec -it nginx-pods /bin/bash root@nginx-pods:/usr/share/nginx/html# ls 50x.html index.html
livenessProbe和kubelet-tcpSocket
[root@k8s-master01 ~]# vim /root/pod/nginx-tcp.yml apiVersion: v1 kind: Pod metadata: name: nginx2-pods labels: app: nginx spec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent livenessProbe: tcpSocket: #指定探针探测方式 port: 80 #定义GET的端口 initialDelaySeconds: 3 #指定探针多少秒后启动 periodSeconds: 3 #指定探针的探测周期 [root@k8s-master01 ~]# kubectl apply -f /root/pod/nginx-tcp.yml #创建容器 [root@k8s-master01 ~]# kubectl get pod -A #查看pod ####测试##### [root@k8s-master01 ~]# kubectl exec -it nginx2-pods -- bash #连接容器 sed -i 's/listen 80;/listen 8080;/' /etc/nginx/conf.d/default.conf #修改配置文件 server { listen 8080; #把80都改为8080 listen [::]:8080; nginx -s reload #重新加载配置文件 [root@k8s-master01 ~]# kubectl get pod -A #查看pod,可以看到RESTARTS,证明容器重启过 [root@k8s-master01 ~]# kubectl exec -it nginx2-pods -- bash #连接容器 [root@k8s-master01 ~]# head -n 10 /etc/nginx/conf.d/default.conf #可以看到配置被还原了,证明容器重建了
5.2、 readinessProbe探针案例
readinessProbe和kubelet-exec
vim nginx-re-exec.yml
apiVersion: apps/v1 kind: Deployment metadata: labels: app: nginx name: nginx namespace: default spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent ports: - containerPort: 80 readinessProbe: #指定探针 exec: #指定探针探测方式 command: - cat - /usr/share/nginx/html/index.html initialDelaySeconds: 5 periodSeconds: 5 --- apiVersion: v1 kind: Service metadata: labels: svc: nginx-svc-nodeport name: nginx-svc-nodeport spec: type: NodePort ports: - port: 8000 ##pod的端口 targetPort: 80 ##容器内部暴露的端口 nodePort: 30080 ##对外访问端口 selector: app: nginx
kubectl apply -f nginx-re-exec.yml
[root@k8s-master pod]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-8595754649-5rg5q 1/1 Running 0 27s 10.244.169.132 k8s-node2 <none> <none> [root@k8s-master pod]# kubectl get svc -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 16d <none> nginx-svc-nodeport NodePort 10.109.159.156 <none> 8000:30080/TCP 44s app=nginx [root@k8s-master01 ~]# kubectl describe svc nginx-svc-nodeport #查看pod和service绑定 Name: nginx-svc-nodeport Namespace: default Labels: svc=nginx-svc-nodeport Annotations: <none> Selector: app=nginx Type: NodePort IP Family Policy: SingleStack IP Families: IPv4 IP: 10.109.159.156 IPs: 10.109.159.156 Port: <unset> 8000/TCP TargetPort: 80/TCP NodePort: <unset> 30080/TCP Endpoints: 10.244.169.132:80 Session Affinity: None External Traffic Policy: Cluster Events: <none> [root@k8s-master01 ~]# curl -I http://192.168.116.132:30080 #访问网站成功
[root@k8s-master01 ~]# kubectl get pod -A -o wide 查看容器名字,可以看到原本READY是1/1 ###进入容器,触发探针 [root@k8s-master01 nginx]# kubectl exec -it nginx-pods /bin/bash root@nginx-pods:/usr/share/nginx/html# mv index.html index1.html root@nginx-pods:/usr/share/nginx/html# exit [root@k8s-master pod]# kubectl get po -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-8595754649-5rg5q 0/1 Running 0 4m8s 10.244.169.132 k8s-node2 <none> <none> [root@k8s-master pod]# curl -I http://192.168.116.132:30080 ^C [root@k8s-master pod]# kubectl describe svc nginx-svc-nodeport Name: nginx-svc-nodeport Namespace: default Labels: svc=nginx-svc-nodeport Annotations: <none> Selector: app=nginx Type: NodePort IP Family Policy: SingleStack IP Families: IPv4 IP: 10.109.159.156 IPs: 10.109.159.156 Port: <unset> 8000/TCP TargetPort: 80/TCP NodePort: <unset> 30080/TCP Endpoints: Session Affinity: None External Traffic Policy: Cluster Events: <none>
readinessProbe和kubelet-httpGet
[root@k8s-master01 ~]# vim nginx-re-httpGet.yml apiVersion: apps/v1 kind: Deployment metadata: labels: app: nginx name: nginx namespace: default spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent ports: - containerPort: 80 readinessProbe: #指定探针 httpGet: #指定探针方式 path: /index.html port: 80 initialDelaySeconds: 5 periodSeconds: 5 --- apiVersion: v1 kind: Service metadata: labels: svc: nginx-svc-nodeport name: nginx-svc-nodeport spec: type: NodePort ports: - port: 80 targetPort: 80 nodePort: 30080 selector: app: nginx [root@k8s-master01 ~]# kubectl apply -f nginx-re-httpGet.yml #创建容器 [root@k8s-master01 ~]# curl -I http://192.168.116.132:30080 #和上面一样,访问网站成功 [root@k8s-master01 ~]# kubectl get pod -A -o wide #查看容器名字,可以看到原本READY是1/1 ###测试#### [root@k8s-master01 ~]# kubectl exec -it nginx-75f8cfd9d-6x8jz -- bash #连接容器 #cd /usr/share/nginx/html/ #修改探针指定探测的文件名字,让探针触发 #ls #mv index.html index1.html #exit [root@k8s-master01 ~]# kubectl get pod -A -o wide #可以看到READY变成了0/1,证明探针被触发了,容器没有被删除,也没有重建 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-556bcf764d-7qpjh 0/1 Running 0 29m 172.16.79.76 k8s-worker01 <none> <none> [root@k8s-master01 ~]# curl -I http://192.168.116.132:30080 #可以看到网站访问不了 (等待5分钟) [root@k8s-master01 ~]# kubectl describe svc nginx-svc-nodeport #可以看到Endpoints没有值,证明探针把service和pod解除绑定了 Name: nginx-svc-nodeport Namespace: default Labels: svc=nginx-svc-nodeport Annotations: <none> Selector: app=nginx Type: NodePort IP Family Policy: SingleStack IP Families: IPv4 IP: 10.10.166.16 IPs: 10.10.166.16 Port: <unset> 8000/TCP TargetPort: 80/TCP NodePort: <unset> 30080/TCP Endpoints: Session Affinity: None External Traffic Policy: Cluster Events: <none>
readinessProbe和kubelet-tcpSocket
[root@k8s-master01 ~]# vim nginx-re-tcpSocket.yml apiVersion: apps/v1 kind: Deployment metadata: labels: app: nginx name: nginx namespace: default spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent ports: - containerPort: 80 readinessProbe: #指定探针 tcpSocket: #指定探测方式 port: 80 initialDelaySeconds: 5 periodSeconds: 5 --- apiVersion: v1 kind: Service metadata: labels: svc: nginx-svc-nodeport name: nginx-svc-nodeport spec: type: NodePort ports: - port: 80 targetPort: 80 nodePort: 30080 selector: app: nginx [root@k8s-master01 ~]# kubectl apply -f nginx-re-tcpSocket.yml #创建容器 [root@k8s-master01 ~]# curl -I http://192.168.116.132:30080 #和上面一样,访问网站成功 [root@k8s-master01 ~]# kubectl get pod -A #查看pod ####测试#### [root@k8s-master01 ~]# kubectl exec -it nginx-6bf8bf8577-9skvn -- bash #连接容器 #vi /etc/nginx/conf.d/default.conf #修改配置文件 server { listen 8080; #把80都改为8080 listen [::]:8080; #nginx -s reload #重新加载配置文件 [root@k8s-master01 ~]# kubectl get pod -A 可以看到READY变成了0/1,证明探针被触发了,容器没有被删除,也没有重建 [root@k8s-master01 ~]# curl -I http://192.168.116.132:30080 可以看到因为探针触发,外网是访问不了容器了
6、生成pod模板文件
生成YAML文件
##生成Pod模版 [root@k8s-master pod]# kubectl run pod --image=nginx --dry-run=client -o yaml > my-pod.yaml [root@k8s-master pod]# cat my-pod.yaml apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: pod name: pod spec: containers: - image: nginx name: pod resources: {} dnsPolicy: ClusterFirst restartPolicy: Always status: {}
7、pod状态常见故障
CrashLoopBackOff 容器退出,kubelet正在将它重启 InvalidImageName 无法解析镜像名称 ImageInspectError 无法校验镜像 ErrImageNeverPul 策略禁止拉取镜像 ImagePullBackOff 正在重试拉取 RegistryUnavailable 连接不到镜像中心 ErrImagePull 通用的拉取镜像出错 CreateContainerConfigError 不能创建kubelet使用的容器配置 CreateContainerError 创建容器失败 m.internalLifecycle.PreStartContainer 执行hook报错 RunContainerError 启动容器失败 PostStartHookError 执行hook报错 ContainersNotInitialized 容器没有初始化完毕 ContainersNotReady 容器没有准备完毕 ContainerCreating 容器创建中 PodInitializing pod 初始化中 DockerDaemonNotReady docker还没有完全启动 NetworkPluginNotReady 网络插件还没有完全启动 Evicted 即驱赶的意思,意思是当节点出现异常时,kubernetes将有相应的机制驱赶该节点上的Pod。 多见于资源不足时导致的驱赶。
三、Deployment控制器
Deployment为Pod和ReplicaSet提供了一个声明式定义(declarative)方法,用来替代以前的ReplicationController来方便的管理应用。
典型的应用场景包括:
-
定义Deployment来创建Pod和ReplicaSet
-
滚动升级和回滚应用
-
扩容和缩容
-
暂停和继续Deployment更新
滚动升级一个服务,实际是创建一个新的RS,然后逐渐将新 RS 中副本数增加到理想状态,将旧RS中的副本数减少到0的复合操作。
1、YAML文件详解
# Deployment 资源使用的 API 版本,apps/v1 是当前稳定版本 apiVersion: apps/v1 # 接口版本,Deployment 属于 apps 组,v1 为稳定版 kind: Deployment # 接口类型,声明创建的是 Deployment 资源(用于管理 Pod 的创建和扩展) metadata: name: cango-demo # Deployment 名称,在命名空间内唯一 namespace: cango-prd # 命名空间,资源所属的逻辑隔离空间 labels: app: cango-demo # 标签,用于标识和筛选该 Deployment 资源 spec: replicas: 3 # 期望的 Pod 副本数,K8s 会维持此数量的 Pod 运行 selector: # 标签选择器,用于匹配要管理的 Pod(必须与 template.metadata.labels 一致) matchLabels: app: cango-demo strategy: # 更新策略,定义 Pod 滚动更新的规则 rollingUpdate: # 滚动更新策略(默认) maxSurge: 1 # 更新过程中允许超出期望副本数的最大数量(1 表示 1 个 Pod 或 25% 副本数,取大者) maxUnavailable: 1 # 更新过程中允许不可用的最大 Pod 数量 template: # Pod 模板,定义要创建的 Pod 的规格(核心配置) metadata: labels: app: cango-demo # Pod 标签,必须与 spec.selector.matchLabels 匹配,否则 Deployment 无法管理 spec: containers: - name: cango-demo1 # 容器名称,在 Pod 内唯一 image: swr.cn-east-2.myhuaweicloud.com/cango-prd/cango-demo:0.0.1-SNAPSHOT # 容器镜像地址(华为云 SWR 仓库) # 容器启动命令,覆盖镜像默认的 ENTRYPOINT command: [ "/bin/sh","-c","cat /etc/config/path/to/special-key" ] # 启动时执行的命令(查看配置文件内容) # 启动命令的参数(与 command 配合使用) args: # 传递给 command 的参数列表 - '-storage.local.retention=$(STORAGE_RETENTION)' - '-storage.local.memory-chunks=$(STORAGE_MEMORY_CHUNKS)' - '-config.file=/etc/prometheus/prometheus.yml' - '-alertmanager.url=http://alertmanager:9093/alertmanager' - '-web.external-url=$(EXTERNAL_URL)' #如果command和args均没有写,那么用Docker默认的配置。 #如果command写了,但args没有写,那么Docker默认的配置会被忽略而且仅仅执行.yaml文件的command(不带任何参数的)。 #如果command没写,但args写了,那么Docker默认配置的ENTRYPOINT的命令行会被执行,但是调用的参数是.yaml中的args。 #如果如果command和args都写了,那么Docker默认的配置被忽略,使用.yaml的配置。 # 镜像拉取策略:本地不存在时从仓库拉取 imagePullPolicy: IfNotPresent # 可选值:Always(总是拉取)、Never(从不拉取)、IfNotPresent(默认) # 存活探针(检测容器是否运行正常,失败会重启容器) livenessProbe: # 用于判断容器是否"存活",失败会触发重启 httpGet: # 通过 HTTP 请求检测 path: /health # 检测路径(应用的健康检查接口) port: 8080 # 检测端口 scheme: HTTP # 协议(HTTP/HTTPS) initialDelaySeconds: 60 # 容器启动后延迟 60 秒开始首次检测(避免启动中误判) timeoutSeconds: 5 # 检测超时时间(5 秒无响应视为失败) successThreshold: 1 # 连续 1 次成功视为正常 failureThreshold: 5 # 连续 5 次失败视为异常(触发重启) # 就绪探针(检测容器是否可接收请求,失败会从 Service 中移除) readinessProbe: # 用于判断容器是否"就绪"(可提供服务) httpGet: path: /health # 就绪检查接口(通常与存活探针相同) port: 8080 scheme: HTTP initialDelaySeconds: 30 # 启动后延迟 30 秒开始检测 timeoutSeconds: 5 successThreshold: 1 failureThreshold: 5 # 资源限制与请求(避免资源争抢) resources: ## CPU 和内存的资源配置 requests: # 资源请求(调度时的最小分配) cpu: 2 # 请求 2 核 CPU memory: 2048Mi # 请求 2GiB 内存 limits: # 资源限制(容器不能超过此值) cpu: 2 # 限制 2 核 CPU memory: 2048Mi # 限制 2GiB 内存 # 环境变量配置(传递给容器的 OS 环境变量) env: ## 容器的环境变量定义 - name: LOCAL_KEY # 环境变量名称(自定义) value: value # 环境变量值(直接指定) - name: CONFIG_MAP_KEY # 从 ConfigMap 中读取的环境变量 valueFrom: configMapKeyRef: name: special-config # 引用的 ConfigMap 名称 key: special.type # 引用 ConfigMap 中 data 下的 key # 容器暴露的端口(仅声明,需配合 Service 实际暴露) ports: - name: http # 端口名称(用于标识) containerPort: 8080 # 容器内部监听的端口(与应用实际端口一致) # 容器挂载的存储卷(将 volumes 中定义的存储挂载到容器内) volumeMounts: # 存储卷挂载配置 - name: log-cache # 存储卷名称(需与 volumes 中定义的一致) mountPath: /tmp/log # 容器内的挂载路径(临时日志目录) - name: sdb # 挂载宿主机目录的存储卷 mountPath: /data/media # 容器内挂载点 - name: nfs-client-root # NFS 存储卷 mountPath: /mnt/nfs # 挂载到容器的 /mnt/nfs 目录 - name: example-volume-config # 挂载 ConfigMap 的存储卷 mountPath: /etc/config # 容器内挂载路径(ConfigMap 内容会映射为文件) - name: rbd-pvc # 挂载 PVC(持久化存储) mountPath: /path/to/mount # 需补充实际挂载路径(原配置缺失) # 定义存储卷(供上面的 volumeMounts 挂载使用) volumes: # 存储卷列表,可被容器挂载到内部路径 - name: log-cache # 临时存储卷(Pod 销毁时数据丢失) emptyDir: {} # emptyDir 类型:Pod 生命周期内的临时目录 - name: sdb # 挂载宿主机目录的存储卷 hostPath: path: /any/path/it/will/be/replaced # 宿主机上的实际路径 - name: example-volume-config # 挂载 ConfigMap 的存储卷(高级用法) configMap: name: example-volume-config # 关联的 ConfigMap 名称 items: # 选择性挂载 ConfigMap 中的 key(而非全部) - key: log-script # ConfigMap 中的 key path: path/to/log-script # 挂载到容器内的相对路径(/etc/config/path/to/log-script) - key: backup-script # ConfigMap 中的另一个 key path: path/to/backup-script # 对应容器内的路径 - name: nfs-client-root # NFS 类型存储卷(共享存储) nfs: server: 10.42.0.55 # NFS 服务器地址 path: /opt/public # NFS 共享目录(需提前在服务器端配置) - name: rbd-pvc # 挂载持久化存储声明(PVC) persistentVolumeClaim: claimName: rbd-pvc1 # 关联的 PVC 名称(需提前创建)
案例:
vim my-deployment.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: mydm spec: replicas: 2 selector: matchLabels: app: myapp-nginx template: metadata: labels: app: myapp-nginx spec: containers: - name: myapp-nginx image: nginx:latest imagePullPolicy: IfNotPresent ports: - containerPort: 80
执行后查看
[root@k8s-master deployment]# kubectl apply -f my-deployment.yaml deployment.apps/mydm created [root@k8s-master deployment]# kubectl get deployments.apps NAME READY UP-TO-DATE AVAILABLE AGE mydm 2/2 2 2 11s [root@k8s-master deployment]# kubectl get po NAME READY STATUS RESTARTS AGE mydm-895646859-44sqm 1/1 Running 0 18s mydm-895646859-wjj9k 1/1 Running 0 18s
2、回滚
查看历史版本
[root@k8s-master01 ~]# kubectl rollout history deployment name
回滚操作
[root@k8s-master01 ~]# kubectl rollout undo deployment name --to-revision=1 ##revision=1回滚到指定的版本
案例;
vim nginx-deploy-v1.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deploy spec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.21 # v1版本镜像 ports: - containerPort: 80
kubectl apply -f nginx-deploy-v1.yaml
查看初始版本状态
# 查看Deployment状态 kubectl get deploy nginx-deploy # 查看历史版本(此时只有1个版本) kubectl rollout history deployment/nginx-deploy
更新到 v2 版本 修改镜像为 nginx:1.22(模拟新版本发布):
kubectl set image deployment/nginx-deploy nginx=nginx:1.22 --record
查看更新后的版本:
kubectl rollout history deployment/nginx-deploy #此时会看到新增了 REVISION 2 的版本
假设 v2 版本出现问题,需要回滚到上一个稳定版本(v1):
# 回滚到上一个版本(v1) kubectl rollout undo deployment/nginx-deploy # 或者指定回滚到版本1(更精确) kubectl rollout undo deployment/nginx-deploy --to-revision=1
验证回滚结果
# 查看当前版本状态 kubectl get deploy nginx-deploy # 查看Pod使用的镜像(确认已回滚到1.21) kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{" "}{.spec.containers[0].image}{"\n"}{end}' # 查看历史记录(确认当前版本已回到1) kubectl rollout history deployment/nginx-deploy
3、自定义更新策略
类型
-
maxSurge:和期望的副本数比,超过期望副本数最大比例(或最大值),这个值调的越大,副本更新速度越快。
-
maxUnavailable:和期望的副本数比,不可用副本数最大比例(或最大值),这个值越小,越能保证服务稳定,更新越平滑;
设置方式
-
按数量
-
maxUnavailable: [0, 副本数]
-
maxSurge: [0, 副本数]
-
注两者不能同时为0。
-
按比例
-
maxUnavailable: [0%, 100%] 向下取整,比如10个副本,5%的话==0.5个,但计算按照0个;
-
maxSurge: [0%, 100%] 向上取整,比如10个副本,5%的话==0.5个,但计算按照1个;
-
两者不能同时为0。
配置案例
apiVersion: apps/v1 kind: Deployment metadata: name: myapp-v1 spec: replicas: 3 selector: matchLabels: app: myapp version: v1 strategy: rollingUpdate: maxSurge: 1 maxUnavailable: 1 template: metadata: labels: app: myapp version: v1 spec: containers: - name: myapp image: nginx:latest imagePullPolicy: IfNotPresent ports: - containerPort: 80
通过修改副本数量,再次执行命令可以成功看到pod的数量在进行跟新
四、daemonset控制器
DaemonSet 控制器能够确保 k8s 集群所有的节点都运行一个相同的 pod 副本,当向 k8s 集群中增加 node 节点时,这个 node 节点也会自动创建一个 pod 副本,当 node 节点从 集群移除,这些 pod 也会自动删除;删除 Daemonset 也会删除它们创建的 pod
DaemonSet 工作原理
daemonset 的控制器会监听 kuberntes 的 daemonset 对象、pod 对象、node 对象,这些被监听的对象之变动,就会触发 syncLoop 循环让 kubernetes 集群朝着 daemonset 对象描述的状态进行演进。
Daemonset 典型的应用场景
在集群的每个节点上运行存储,比如:glusterd 或 ceph。 在每个节点上运行日志收集组件,比如:flunentd 、 logstash、filebeat 等。 在每个节点上运行监控组件,比如:Prometheus、 Node Exporter 、collectd 等。
DaemonSet 与 Deployment 的区别
Deployment 部署的副本 Pod 会分布在各个 Node 上,每个 Node 都可能运行好几个副本。
DaemonSet 的不同之处在于:每个 Node 上最多只能运行一个副本。
1、清单模版
apiVersion: apps/v1 kind: DaemonSet metadata: name: pod-controller # ds名称 labels: # 给ds打标签 controller: daemonset spec: revisionHistoryLimit: 3 # 保留历史版本数量,默认为10 updateStrategy: # Pod更新策略,默认是RollingUpdate type: RollingUpdate # 滚动更新策略。另一种是OnDelete,其没有子属性配置参数 rollingUpdate: # 当type为RollingUpdate的时候生效,为其配置参数 maxSurge: 25% # 升级过程中可以超过期望的Pod的最大数量,可以为百分比,也可以为整数。默认是25% maxUnavailable: 25% # 升级过程中最大不可用状态的Pod数量,可以为百分比,也可以为整数。默认是25% selector: # 选择器,通过该控制器管理哪些pod matchLabels: # Labels匹配规则。和matchExpressions类似 app: nginx-pod ###或者 matchExpressions: # Expressions匹配规则。和matchLabels类似 - {key: app, operator: 'In', values: ["nginx-pod"]} template: # pod副本创建模板。属性和Pod的属性一样 metadata: labels: app: nginx-pod spec: containers: - name: nginx image: nginx:latest ports: - name: nginx-port containerPort: 80 protocol: TCP
2、DaemonSet 使用案例
vim pod-controller.yaml
apiVersion: apps/v1 kind: DaemonSet metadata: name: pod-controller labels: controller: daemonset spec: selector: matchLabels: app: nginx-pod template: metadata: labels: app: nginx-pod spec: containers: - name: nginx image: nginx:latest ports: - name: nginx-port containerPort: 80 protocol: TCP
查看
[root@k8s-master daemonset]# kubectl apply -f pod-controller.yaml daemonset.apps/pod-controller created [root@k8s-master daemonset]# kubectl get po -owide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-controller-9qm5z 1/1 Running 0 2m 10.244.169.138 k8s-node2 <none> <none> pod-controller-sd7w9 1/1 Running 0 2m 10.244.36.77 k8s-node1 <none> <none>
五、Statefulset控制器
1、Statefulset控制器:概念、原理解读
StatefulSet是为了管理有状态服务的问题而设计的。
1.1、有状态服务
StatefulSet是有状态的集合,管理有状态的服务,它所管理的Pod的名称不能随意变化。数据持久化的目录也是不一样,每一个Pod都有自己独有的数据持久化存储目录。比如MySQL主从、redis集群等。
1.2、无状态服务
RC、Deployment、DaemonSet都是管理无状态的服务,它们所管理的Pod的IP、名字,启停顺序等都是随机的。个体对整体无影响,所有pod都是共用一个数据卷的,部署的tomcat就是无状态的服务,tomcat被删除,在启动一个新的tomcat,加入到集群即可,跟tomcat的名字无关。
1.3、StatefulSet部分组成
-
Headless Service:用来定义pod网路标识,生成可解析的DNS记录
-
volumeClaimTemplates:存储卷申请模板,创建pvc,指定pvc名称大小,自动创建pvc,且pvc由存储类供应。
-
StatefulSet:管理pod的
1.4、Headless service
Headless service不分配clusterIP,headless service可以通过解析service的DNS,返回所有Pod的dns和ip地址 (只有statefulSet部署的Pod才有DNS地址),普通的service,只能通过解析service的DNS返回service的ClusterIP。
为什么要用headless service(没有service ip的service)?
在使用Deployment时,创建的Pod名称是没有顺序的,是随机字符串,在用statefulset管理pod时要求pod名称必须是有序的 ,每一个pod不能被随意取代,pod重建后pod名称还是一样的。因为pod IP是变化的,所以要用Pod名称来识别。pod名称是pod唯一性的标识符,必须持久稳定有效。这时候要用到无头服务,它可以给每个Pod一个唯一的名称。
1、headless service会为service分配一个域名
<service name>.$<namespace name>.svc.cluster.local
K8s中资源的全局FQDN格式:
Service_NAME.NameSpace_NAME.Domain.LTD.Domain.LTD.=svc.cluster.local. #这是默认k8s集群的域名。
FQDN 全称 Fully Qualified Domain Name 即全限定域名:同时带有主机名和域名的名称 FQDN = Hostname + DomainName 如:主机名是 duoduo 域名是 [baidu.com](http://baidu.com/) FQDN= duoduo.baidu.com. #eg: [root@k8s-master deployment]# dig nginx-deploy-svc.default.svc.cluster.local @10.96.0.10 ; <<>> DiG 9.11.36-RedHat-9.11.36-14.el8_10 <<>> nginx-deploy-svc.default.svc.cluster.local @10.96.0.10 ;; global options: +cmd ;; Got answer: ;; WARNING: .local is reserved for Multicast DNS ;; You are currently testing what happens when an mDNS query is leaked to DNS ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 19414 ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; WARNING: recursion requested but not available ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ; COOKIE: 16379d4770867ed4 (echoed) ;; QUESTION SECTION: ;nginx-deploy-svc.default.svc.cluster.local. IN A ;; ANSWER SECTION: nginx-deploy-svc.default.svc.cluster.local. 30 IN A 10.97.172.98 ;; Query time: 7 msec ;; SERVER: 10.96.0.10#53(10.96.0.10) ;; WHEN: 一 1月 13 01:25:21 EST 2025 ;; MSG SIZE rcvd: 141 [root@k8s-master deployment]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d4h nginx-deploy-svc NodePort 10.97.172.98 <none> 80:30676/TCP 2m20s
2、StatefulSet会为关联的Pod保持一个不变的Pod Name
statefulset中Pod的名字格式为 【 $(StatefulSet name)-$(pod序号) 】
3、StatefulSet会为关联的Pod分配一个dnsName
$<Pod Name>.$<service name>.$<namespace name>.svc.cluster.local
headless service
vim statefulset.yaml
apiVersion: v1 kind: Service metadata: name: nginx-svc labels: app: nginx spec: ports: - port: 80 name: web clusterIP: "None" selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: selector: matchLabels: app: nginx serviceName: "nginx-svc" replicas: 2 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent ports: - containerPort: 80 name: web
[root@k8s-master statefulset]# kubectl apply -f statefulset.yaml service/nginx-svc created statefulset.apps/web created #查看statefulset是否创建成功 [root@k8s-master statefulset]# kubectl get statefulset NAME READY AGE web 2/2 15s #可以看到创建的pod是有序的 [root@k8s-master statefulset]# kubectl get pods NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 32s web-1 1/1 Running 0 30s [root@k8s-master statefulset]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 18d nginx-svc ClusterIP None <none> 80/TCP 56s service-green-blue NodePort 10.103.244.123 <none> 80:30030/TCP 29h #查看pod主机名 [root@k8s-master statefulset]# for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname';done web-0 web-1
vim pod-second.yaml
apiVersion: v1 kind: Pod metadata: name: pod-second labels: app: backend tier: db spec: containers: - name: busybox image: busybox imagePullPolicy: IfNotPresent command: ["sh","-c","sleep 3600"]
[root@k8s-master statefulset]# kubectl apply -f pod-second.yaml pod/pod-second created [root@k8s-master statefulset]# kubectl exec -it pod-second -- sh / # nslookup web-0.nginx-svc.default.svc.cluster.local Server: 10.96.0.10 Address: 10.96.0.10:53 Name: web-0.nginx-svc.default.svc.cluster.local Address: 10.244.169.146 / # nslookup -type=A nginx-svc.default.svc.cluster.local Server: 10.96.0.10 Address: 10.96.0.10:53 Name: nginx-svc.default.svc.cluster.local Address: 10.244.36.84 Name: nginx-svc.default.svc.cluster.local Address: 10.244.169.146
对比普通的server vim deploy-service.yaml
apiVersion: v1 kind: Service metadata: name: my-nginx labels: run: my-nginx spec: type: ClusterIP ports: - port: 80 # Service暴露的端口 protocol: TCP targetPort: 80 # 对应Pod的端口 selector: run: my-nginx # 匹配Pod的标签 --- apiVersion: apps/v1 kind: Deployment metadata: name: my-nginx spec: selector: matchLabels: run: my-nginx replicas: 2 template: metadata: labels: run: my-nginx spec: containers: - name: my-nginx image: nginx:latest imagePullPolicy: IfNotPresent ports: - containerPort: 80 command: ["sleep", "3600"]
[root@k8s-master statefulset]# kubectl apply -f deploy-service.yaml service/my-nginx created deployment.apps/my-nginx created [root@k8s-master statefulset]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 18d my-nginx ClusterIP 10.101.65.110 <none> 80/TCP 68s nginx-svc ClusterIP None <none> 80/TCP 32m service-green-blue NodePort 10.103.244.123 <none> 80:30030/TCP 29h [root@k8s-master statefulset]# kubectl get pods NAME READY STATUS RESTARTS AGE my-nginx-7b87c497b8-hzrcg 1/1 Running 0 100s my-nginx-7b87c497b8-nxn4h 1/1 Running 0 100s pod-second 1/1 Running 0 25m web-0 1/1 Running 0 33m web-1 1/1 Running 0 33m [root@k8s-master statefulset]# kubectl exec -it pod-second -- sh / # nslookup my-nginx.default.svc.cluster.local Server: 10.96.0.10 Address: 10.96.0.10:53 Name: my-nginx.default.svc.cluster.local Address: 10.101.65.110
六、Service资源对象
1、概述
在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信息转换成对应的访问规则。
2、Kube-proxy的三种模式
2.1 userspace 模式
userspace模式下,kube-proxy会为每一个Service创建一个监听端口,发向Cluster IP的请求被Iptables规则重定向到kube-proxy监听的端口上,kube-proxy根据LB(LoadBalance,负载均衡)算法选择一个提供服务的Pod并和其建立链接,以将请求转发到Pod上。 该模式下,kube-proxy充当了一个四层负载均衡器的角色。由于kube-proxy运行在userspace中,在进行转发处理时会增加内核和用户空间之间的数据拷贝,虽然比较稳定,但是效率比较低。
2.2 iptables 模式
iptables模式下,kube-proxy为service后端的每个Pod创建对应的iptables规则,直接将发向Cluster IP的请求重定向到一个Pod IP。 该模式下kube-proxy不承担四层负载均衡器的角色,只负责创建iptables规则。该模式的优点是较userspace模式效率更高,但不能提供灵活的LB策略,当后端Pod不可用时也无法进行重试。
2.3 ipvs 模式
ipvs模式和iptables类似,kube-proxy监控Pod的变化并创建相应的ipvs规则。ipvs相对iptables转发效率更高。除此以外,ipvs支持更多的LB算法。
##查看是否开启ipvs模块 lsmod | grep ip_vs ##开启ipvs模块,所有节点都要开启 modprobe ip_vs ##所有节点安装ipvsadm yum install -y ipvsadm
# 此模式必须安装ipvs内核模块(集群部署的时候已安装),否则会降级为iptables; modprobe ip_vs # 开启ipvs,cm: configmap [root@k8s-master01 ~]# modprobe ip_vs [root@k8s-master01 ~]# yum install -y ipvsadm [root@k8s-master01 ~]# kubectl edit cm kube-proxy -n kube-system # 修改mode: "ipvs" [root@k8s-master01 ~]# kubectl delete pod -l k8s-app=kube-proxy -n kube-system [root@node1 ~]# ipvsadm -Ln IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 172.16.32.128:30080 rr -> 172.16.79.79:80 Masq 1 0 0 TCP 172.16.32.128:32665 rr -> 172.16.79.82:8443 Masq 1 0 0 TCP 172.17.0.1:30080 rr -> 172.16.79.79:80 Masq 1 0 0 TCP 172.17.0.1:32665 rr -> 172.16.79.82:8443 Masq 1 0 0 TCP 192.168.115.161:30080 rr -> 172.16.79.79:80 Masq 1 0 0 TCP 192.168.115.161:32665 rr -> 172.16.79.82:8443 Masq 1 0 0 TCP 192.168.115.166:30080 rr -> 172.16.79.79:80 Masq 1 0 0 TCP 192.168.115.166:32665 rr -> 172.16.79.82:8443 Masq 1 0 0 TCP 10.10.0.1:443 rr -> 192.168.115.161:6443 Masq 1 0 0 -> 192.168.115.162:6443 Masq 1 0 0 -> 192.168.115.163:6443 Masq 1 1 0 TCP 10.10.0.10:53 rr -> 172.16.122.139:53 Masq 1 0 0 -> 172.16.122.140:53 Masq 1 0 0 TCP 10.10.0.10:9153 rr -> 172.16.122.139:9153 Masq 1 0 0 -> 172.16.122.140:9153 Masq 1 0 0 TCP 10.10.39.128:8000 rr -> 172.16.79.80:8000 Masq 1 0 0 TCP 10.10.128.23:443 rr -> 172.16.79.81:443 Masq 1 0 0 TCP 10.10.166.16:8000 rr -> 172.16.79.79:80 Masq 1 0 0 TCP 10.10.195.192:443 rr -> 172.16.79.82:8443 Masq 1 0 0 UDP 10.10.0.10:53 rr -> 172.16.122.139:53 Masq 1 0 0 -> 172.16.122.140:53 Masq 1 0 0
3、service资源类型
apiVersion: v1 kind: Service matadata: #元数据 name: string #service的名称 namespace: string #命名空间 labels: #自定义标签属性列表 - name: string annotations: #自定义注解属性列表 - name: string spec: #详细描述 selector: [] #label selector配置,将选择具有label标签的Pod作为管理范围 type: string #service的类型,指定service的访问方式,默认为clusterIp clusterIP: string #虚拟服务地址 sessionAffinity: string #是否支持session ports: #service需要暴露的端口列表 - name: string #端口名称 protocol: string #端口协议,支持TCP和UDP,默认TCP port: int #服务监听的service端口号 targetPort: int #需要转发到后端Pod的端口号 nodePort: int #当type = NodePort时,指定映射到物理机的端口号 status: #当spce.type=LoadBalancer时,设置外部负载均衡器的地址 loadBalancer: #外部负载均衡器 ingress: #外部负载均衡器 ip: string #外部负载均衡器的Ip地址值 hostname: string #外部负载均衡器的主机名
apiVersion: v1 # 资源版本 kind: Service # 资源类型 metadata: # 元数据 name: service # 资源名称 namespace: dev # 命名空间 spec: # 描述 selector: # 标签选择器,用于确定当前service代理哪些pod app: nginx type: # Service类型,指定service的访问方式 clusterIP: # 虚拟服务的ip地址 sessionAffinity: # session亲和性,支持ClientIP、None两个选项 ports: # 端口信息 - protocol: TCP port: 3017 # service端口 targetPort: 5003 # pod端口 nodePort: 31122 # 主机端口
Service中的service.spec.type类型
类型 | 含义 |
---|---|
ClusterIP | 意味着服务仅在集群内部可用,只能通过集群IP访问。 |
ExternalName | 意味着服务仅包含一个对外部名称的引用,Kubedns或等价物将返回作为CNAME记录,不会涉及任何容器的暴露或代理。 |
LoadBalancer | 意味着服务将通过外部负载均衡器(如果云提供商支持的话)进行暴露,除了NodePort类型之外。 |
NodePort | 意味着服务将在每个节点的一个端口上进行暴露,除了ClusterIP类型之外。 |
Service中的三类IP地址
IP类型 | 作用 |
---|---|
Node IP | 节点IP是Kubernetes集群中每个节点的唯一标识符。它代表了节点的网络接口,用于在集群内部进行通信。节点IP通常是一个私有IP地址范围,用于在集群内部进行通信。节点IP是Service在集群内部提供服务的唯一标识,用于路由流量到指定的Pod。 |
Pod IP | Pod IP是Kubernetes中每个Pod的唯一标识符。它代表了Pod的网络接口,用于在集群内部进行通信。Pod IP通常是一个私有IP地址范围,用于在集群内部进行通信。Pod IP是Service在集群内部提供服务的唯一标识,用于路由流量到指定的Pod。 |
Cluster IP | Cluster IP是Kubernetes集群中Service的IP地址。它代表了Service在集群内部提供的服务,用于在集群内部进行通信。Cluster IP通常是一个私有IP地址范围,用于在集群内部进行通信。Cluster IP是Service在集群内部提供服务的唯一标识,用于路由流量到指定的Pod。 |
综上所述,Kubernetes中的三类IP地址分别是Node IP、Pod IP和Cluster IP。这些IP地址用于在不同网络之间路由流量,以便外部和内部应用程序可以访问Kubernetes集群中的服务和Pod。
4、Service实战案例
4.1、实验环境准备
在使用service之前,首先利用Deployment创建出3个pod,注意要为pod设置app=nginx-pod的标签
创建deployment.yaml,内容如下:
apiVersion: apps/v1 kind: Deployment metadata: name: pc-deployment namespace: dev spec: replicas: 3 selector: matchLabels: app: nginx-pod template: metadata: labels: app: nginx-pod spec: containers: - name: nginx image: nginx ports: - containerPort: 80
[root@k8s-master01 ~]# kubectl create -f deployment.yaml deployment.apps/pc-deployment created # 查看pod详情 [root@k8s-master01 ~]# kubectl get pods -n dev -o wide --show-labels NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS pc-deployment-59c564ffb7-8vzp5 1/1 Running 0 89s 172.16.79.83 k8s-worker01 <none> <none> app=nginx-pod,pod-template-hash=59c564ffb7 pc-deployment-59c564ffb7-fg2j8 1/1 Running 0 89s 172.16.69.206 k8s-worker02 <none> <none> app=nginx-pod,pod-template-hash=59c564ffb7 pc-deployment-59c564ffb7-sprp7 1/1 Running 0 89s 172.16.69.207 k8s-worker02 <none> <none> app=nginx-pod,pod-template-hash=59c564ffb7 # 为了方便后面的测试,修改下三台nginx的index.html页面(三台修改的IP地址不一致) [root@k8s-master01 ~]# kubectl exec -it pc-deployment-59c564ffb7-8vzp5 -n dev -- /bin/sh root@pc-deployment-59c564ffb7-8vzp5:/# echo "172.16.79.83" > /usr/share/nginx/html/index.html [root@k8s-master01 ~]# kubectl -n dev exec -it pc-deployment-59c564ffb7-fg2j8 -- /bin/bash root@pc-deployment-59c564ffb7-fg2j8:/# echo "172.16.69.206" > /usr/share/nginx/html/index.html [root@k8s-master01 ~]# kubectl -n dev exec -it pc-deployment-59c564ffb7-sprp7 -- /bin/bash root@pc-deployment-59c564ffb7-sprp7:/# echo "172.16.69.207" > /usr/share/nginx/html/index.html #修改完毕之后,访问测试 [root@k8s-master01 ~]# curl 172.16.79.83 172.16.79.83 [root@k8s-master01 ~]# curl 172.16.69.206 172.16.69.206 [root@k8s-master01 ~]# curl 172.16.69.207 172.16.69.207
4.2 ClusterIP类型的Service
创建service-clusterip.yaml文件
apiVersion: v1 kind: Service metadata: name: service-clusterip namespace: dev spec: selector: app: nginx-pod clusterIP: 10.10.97.97 # service的ip地址,如果不写,默认会生成一个 type: ClusterIP ports: - port: 80 # Service端口 targetPort: 80 # pod端口
# 创建service [root@k8s-master01 ~]# kubectl create -f service-clusterip.yaml service/service-clusterip created # 查看service [root@k8s-master01 ~]# kubectl get svc -n dev [root@k8s-master01 ~]# kubectl -n dev get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service-clusterip ClusterIP 10.10.97.97 <none> 8001/TCP 10s # 查看service的详细信息 # 在这里有一个Endpoints列表,里面就是当前service可以负载到的服务入口 [root@k8s-master01 ~]# kubectl describe service -n dev Name: service-clusterip Namespace: dev Labels: <none> Annotations: <none> Selector: app=nginx-pod Type: ClusterIP IP Family Policy: SingleStack IP Families: IPv4 IP: 10.10.97.97 IPs: 10.10.97.97 Port: <unset> 8001/TCP TargetPort: 80/TCP Endpoints: 172.16.69.206:80,172.16.69.207:80,172.16.79.83:80 Session Affinity: None Events: <none> # 查看ipvs的映射规则 [root@k8s-master01 ~]# ipvsadm -Ln TCP 10.97.97.97:80 rr -> 10.10.1.39:80 Masq 1 0 0 -> 10.10.1.40:80 Masq 1 0 0 -> 10.10.2.33:80 Masq 1 0 0 # 访问10.10.97.97:8001观察效果 [root@k8s-master01 ~]# curl 10.10.97.97:8001 172.16.79.83 [root@k8s-master01 ~]# curl 10.10.97.97:8001 172.16.69.207 [root@k8s-master01 ~]# curl 10.10.97.97:8001 172.16.69.206
Endpoint解析
-
Endpoint是kubernetes中的一个资源对象,存储在etcd中,用来记录一个service对应的所有pod的访问地址,它是根据service配置文件中selector描述产生的。
-
一个Service由一组Pod组成,这些Pod通过Endpoints暴露出来,Endpoints是实现实际服务的端点集合。换句话说,service和pod之间的联系是通过endpoints实现的。
负载分发策略
对Service的访问被分发到了后端的Pod上去,目前kubernetes提供了两种负载分发策略:
-
如果不定义,默认使用kube-proxy的策略,比如随机、轮询
-
基于客户端地址的会话保持模式,即来自同一个客户端发起的所有请求都会转发到固定的一个Pod上
# 查看ipvs的映射规则【rr 轮询】 [root@k8s-master01 ~]# ipvsadm -Ln TCP 10.97.97.97:80 rr -> 10.10.1.39:80 Masq 1 0 0 -> 10.10.1.40:80 Masq 1 0 0 -> 10.10.2.33:80 Masq 1 0 0 # 循环访问测试 [root@k8s-master01 ~]# while true;do curl 10.97.97.97:80; sleep 5; done; 10.10.1.40 10.10.1.39 10.10.2.33 10.10.1.40 10.10.1.39 10.10.2.33 # 修改分发策略----sessionAffinity:ClientIP # 查看ipvs规则【persistent 代表持久】 [root@k8s-master01 ~]# ipvsadm -Ln TCP 10.97.97.97:80 rr persistent 10800 -> 10.10.1.39:80 Masq 1 0 0 -> 10.10.1.40:80 Masq 1 0 0 -> 10.10.2.33:80 Masq 1 0 0 # 循环访问测试 [root@k8s-master01 ~]# while true;do curl 10.97.97.97; sleep 5; done; 10.10.2.33 10.10.2.33 10.10.2.33 # 删除service [root@k8s-master01 ~]# kubectl delete -f service-clusterip.yaml service "service-clusterip" deleted [root@k8s-master01 ~]# kubectl delete service service-clusterip -n dev service "service-clusterip" deleted
4.3HeadLiness类型的Service
在某些场景中,开发人员可能不想使用Service提供的负载均衡功能,而希望自己来控制负载均衡策略,针对这种情况,kubernetes提供了HeadLiness Service,这类Service不会分配Cluster IP,如果想要访问service,只能通过service的域名进行查询。
创建service-headliness.yaml
apiVersion: v1 kind: Service metadata: name: service-headliness namespace: dev spec: selector: app: nginx-pod clusterIP: "None" # 将clusterIP设置为None,即可创建headliness Service type: ClusterIP ports: - port: 80 targetPort: 80
# 创建service [root@k8s-master01 ~]# kubectl apply -f deployment-nginx-headliness.yaml service/service-headliness created # 获取service, 发现CLUSTER-IP未分配 [root@k8s-master01 ~]# kubectl -n dev get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service-headliness ClusterIP None <none> 80/TCP 10s # 查看service详情 [root@k8s-master01 ~]# kubectl describe svc -n dev Name: service-headliness Namespace: dev Labels: <none> Annotations: <none> Selector: app=nginx-pod Type: ClusterIP IP Family Policy: SingleStack IP Families: IPv4 IP: None IPs: None Port: <unset> 80/TCP TargetPort: 80/TCP Endpoints: 172.16.69.206:80,172.16.69.207:80,172.16.79.83:80 Session Affinity: None Events: <none> # 查看域名的解析情况 [root@k8s-master01 ~]# kubectl -n dev exec -it pc-deployment-59c564ffb7-8vzp5 -- /bin/bash [root@k8s-master01 ~]# kubectl -n dev exec -it pc-deployment-59c564ffb7-8vzp5 -- /bin/bash root@pc-deployment-59c564ffb7-8vzp5:/# root@pc-deployment-59c564ffb7-8vzp5:/# cat /etc/resolv.conf search dev.svc.cluster.local svc.cluster.local cluster.local nameserver 10.10.0.10 options ndots:5 [root@k8s-master01 ~]# dig @10.96.0.10 service-headliness.dev.svc.cluster.local service-headliness.dev.svc.cluster.local. 30 IN A 172.16.79.83 service-headliness.dev.svc.cluster.local. 30 IN A 172.16.69.206 service-headliness.dev.svc.cluster.local. 30 IN A 172.16.69.207 #删除service [root@k8s-master01 ~]# kubectl delete -n dev svc service-headliness service "service-headliness" deleted
4.4 NodePort类型的Service
在之前的样例中,创建的Service的ip地址只有集群内部才可以访问,如果希望将Service暴露给集群外部使用,那么就要使用到另外一种类型的Service,称为NodePort类型。NodePort的工作原理其实就是将service的端口映射到Node的一个端口上,然后就可以通过NodeIp:NodePort来访问service了。
创建service-nodeport.yaml
apiVersion: v1 kind: Service metadata: name: service-nodeport namespace: dev spec: selector: app: nginx-pod type: NodePort # service类型 ports: - port: 80 nodePort: 30002 # 指定绑定的node的端口(默认的取值范围是:30000-32767), 如果不指定,会默认分配 targetPort: 80
# 创建service [root@k8s-master01 ~]# kubectl apply -f deployment-nginx-nodeport.yaml service/service-nodeport created # 查看service [root@k8s-master01 ~]# kubectl -n dev get svc -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR service-nodeport NodePort 10.10.25.194 <none> 80:30002/TCP 29s app=nginx-pod # 接下来可以通过电脑主机的浏览器去访问集群中任意一个nodeip的30002端口,即可访问到pod #删除service [root@k8s-master01 ~]# kubectl delete -n dev svc service-nodeport service "service-nodeport" deleted
4.5 LoadBalancer类型的Service
LoadBalancer和NodePort很相似,目的都是向外部暴露一个端口,区别在于LoadBalancer会在集群的外部再来做一个负载均衡设备,而这个设备需要外部环境支持的,外部服务发送到这个设备上的请求,会被设备负载之后转发到集群中。
# 定义一个Deployment提供后端服务 apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deploy spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest ports: - containerPort: 80 # 容器内端口 --- # 定义LoadBalancer类型的Service apiVersion: v1 kind: Service metadata: name: nginx-loadbalancer spec: type: LoadBalancer # 类型为LoadBalancer ports: - port: 80 # Service暴露的端口 targetPort: 80 # 对应容器的端口 protocol: TCP selector: app: nginx # 关联标签为app:nginx的Pod
4.6、ExternalName类型的Service
ExternalName类型的Service用于引入集群外部的服务,它通过externalName属性指定外部一个服务的地址,然后在集群内部访问此service就可以访问到外部的服务了。
创建service-externalname.yaml
apiVersion: v1 kind: Service metadata: name: service-externalname spec: type: ExternalName # service类型 externalName: www.baidu.com
# 创建service [root@k8s-master01 ~]# kubectl apply -f deployment-nginx-externalname.yaml service/service-externalname created [root@k8s-master01 ~]# kubectl -n dev get svc -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR service-externalname ExternalName <none> www.baidu.com <none> 7s <none> [root@k8s-master01 ~]# kubectl describe -n dev svc Name: service-externalname Namespace: dev Labels: <none> Annotations: <none> Selector: <none> Type: ExternalName IP Families: <none> IP: IPs: <none> External Name: www.baidu.com Session Affinity: None Events: <none> # 域名解析 [root@k8s-master01 ~]# dig @10.10.0.10 service-externalname.dev.svc.cluster.local ; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7_9.15 <<>> @10.10.0.10 service-externalname.dev.svc.cluster.local ; (1 server found) ;; global options: +cmd ;; Got answer: ;; WARNING: .local is reserved for Multicast DNS ;; You are currently testing what happens when an mDNS query is leaked to DNS ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33580 ;; flags: qr aa rd; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1 ;; WARNING: recursion requested but not available ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;service-externalname.dev.svc.cluster.local. IN A ;; ANSWER SECTION: service-externalname.dev.svc.cluster.local. 5 IN CNAME www.baidu.com. www.baidu.com. 5 IN CNAME www.a.shifen.com. www.a.shifen.com. 5 IN A 39.156.66.18 www.a.shifen.com. 5 IN A 39.156.66.14 ;; Query time: 127 msec ;; SERVER: 10.10.0.10#53(10.10.0.10) ;; WHEN: 四 1月 25 15:04:37 CST 2024 ;; MSG SIZE rcvd: 247
# 创建service [root@k8s-master01 ~]# kubectl apply -f deployment-nginx-externalname.yaml service/service-externalname created [root@k8s-master01 ~]# kubectl -n dev get svc -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR service-externalname ExternalName <none> www.baidu.com <none> 7s <none> [root@k8s-master01 ~]# kubectl describe -n dev svc Name: service-externalname Namespace: dev Labels: <none> Annotations: <none> Selector: <none> Type: ExternalName IP Families: <none> IP: IPs: <none> External Name: www.baidu.com Session Affinity: None Events: <none> # 域名解析 [root@k8s-master01 ~]# dig @10.10.0.10 service-externalname.dev.svc.cluster.local ; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7_9.15 <<>> @10.10.0.10 service-externalname.dev.svc.cluster.local ; (1 server found) ;; global options: +cmd ;; Got answer: ;; WARNING: .local is reserved for Multicast DNS ;; You are currently testing what happens when an mDNS query is leaked to DNS ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33580 ;; flags: qr aa rd; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1 ;; WARNING: recursion requested but not available ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;service-externalname.dev.svc.cluster.local. IN A ;; ANSWER SECTION: service-externalname.dev.svc.cluster.local. 5 IN CNAME www.baidu.com. www.baidu.com. 5 IN CNAME www.a.shifen.com. www.a.shifen.com. 5 IN A 39.156.66.18 www.a.shifen.com. 5 IN A 39.156.66.14 ;; Query time: 127 msec ;; SERVER: 10.10.0.10#53(10.10.0.10) ;; WHEN: 四 1月 25 15:04:37 CST 2024 ;; MSG SIZE rcvd: 247
看到感觉有帮助的朋友劳烦动动发财的小手给博主点个赞
更多推荐
所有评论(0)