
1、为什么要有Service在kubernetes中Pod是有生命周期的如果Pod重启它的IP很有可能会发生变化。如果我们的服务都是将Pod的IP地址写死Pod挂掉或者重启那么和刚才重启的pod相关联的其他服务将会找不到它所关联的Pod为了解决这个问题在kubernetes中定义了service资源对象Service定义了一个服务访问的入口客户端通过这个入口即可访问服务背后的应用集群实例service是一组Pod的逻辑集合这一组Pod能够被Service访问到通常是通过Label Selector实现的。1、pod ip经常变化service是pod的代理我们客户端访问只需要访问service就会把请求代理到Pod2、pod ip 在k8s集群之外无法访问所以需要创建service这个service可以在k8s集群外访问的。3、kube-proxyiptables或者ipvs防火墙规则。4、coredns进行域名解析可以把service的域名解析成ip。2、Service概述service是一个固定接入层客户端可以通过访问service的ip和端口访问到service关联的后端pod这个service工作依赖于在kubernetes集群之上部署的一个附件就是kubernetes的dns服务不同kubernetes版本的dns默认使用的也是不一样的1.11之前的版本使用的是kubeDNs较新的版本使用的是corednsservice的名称解析是依赖于dns附件的因此在部署完k8s之后需要再部署dns附件kubernetes要想给客户端提供网络功能需要依赖第三方的网络插件flannelcalico等。每个K8s节点上都有一个组件叫做kube-proxykube-proxy这个组件将始终监视着apiserver中有关service资源的变动信息需要跟master之上的apiserver交互随时连接到apiserver上获取任何一个与service资源相关的资源变动状态这种是通过kubernetes中固有的一种请求方法watch监视来实现的一旦有service资源的内容发生变动如创建删除kube-proxy都会将它转化成当前节点之上的能够实现service资源调度把我们请求调度到后端特定的pod资源之上的规则这个规则可能是iptables也可能是ipvs取决于service的实现方式。3、Service工作原理k8s在创建Service时会根据标签选择器selector(lable selector)来查找Pod据此创建与Service同名的endpoint对象当Pod地址发生变化时endpoint也会随之发生变化service接收前端client请求的时候就会通过endpoint找到转发到哪个Pod进行访问的地址。(至于转发到哪个节点的Pod由负载均衡kube-proxy决定)4、k8s集群中有三类IP地址4.1 Node Network节点网络物理节点或者虚拟节点的网络如ens33接口上的网络地址4.2 Pod Networkpod网络创建的pod具有的ip地址4.3 Cluster Network集群网络可以称为service network这个地址是虚拟的地址没有配置在某个接口上只是出现在service的规则当中。5、创建Service之前我们在学习deploy滚动更新的时候就用了svc四层代理现在我们深入展开学习。Kubernetes 中 Service 的spec.type官方支持4 种类型类型作用访问方式ClusterIP默认类型仅在集群内部暴露服务通过集群内虚拟 IP 端口访问NodePort在每个 Node 上开一个端口对外暴露服务NodeIP:NodePort默认端口范围30000-32767LoadBalancer在 NodePort 基础上向云厂商/负载均衡器申请外部 LB通过外部负载均衡器 IP/域名访问ExternalName把 Service 名称通过 DNS CNAME 映射到外部域名集群内访问该 Service 名解析到外部地址5.1创建type类型是ClusterIP的service# 创建pod-test.yaml文件 vi pod-test.yaml # 填入以下内容 apiVersion: apps/v1 # 指定使用的 Kubernetes API 版本apps/v1 用于 Deployment kind: Deployment # 资源类型为 Deployment用于管理无状态应用的 Pod 副本 metadata: # Deployment 的元数据 name: my-nginx # Deployment 名称 spec: # Deployment 的期望状态 selector: # 选择器用来匹配要管理的 Pod matchLabels: # 通过标签匹配 Pod run: my-nginx # 匹配标签 runmy-nginx 的 Pod replicas: 2 # 期望运行的 Pod 副本数量为 2 template: # Pod 模板用于创建 Pod metadata: # Pod 模板的元数据 labels: # 给创建的 Pod 打标签 run: my-nginx # Pod 标签 runmy-nginx与 selector 匹配 spec: # Pod 模板的期望状态 containers: # 容器列表 - name: my-nginx # 容器名称 image: nginx # 容器使用的镜像 imagePullPolicy: IfNotPresent # 镜像拉取策略本地不存在时才拉取 ports: # 容器端口列表 - containerPort: 80 # Pod 中容器需要暴露的端口# 启动pod kubectl apply -f pod-test.yaml # 查看pod启动状态 kubectl get pod -o wide创建test-service.yamlapiVersion: v1 # 指定 Kubernetes API 版本v1 用于 Service 等核心资源 kind: Service # 资源类型为 Service用于定义一组 Pod 的访问入口 metadata: # Service 的元数据信息 name: my-nginx # Service 的名称 labels: # Service 的标签 run: my-nginx # 标签 runmy-nginx用于标识该 Service spec: # Service 的期望状态 type: ClusterIP # Service 类型为 ClusterIP仅在集群内部可访问 ports: # Service 端口列表 - port: 80 # Service 的端口暴露给 k8s 集群内部服务访问 protocol: TCP # 端口使用的协议为 TCP targetPort: 80 # Pod 容器中定义的端口流量转发到该端口 selector: # 选择器用于匹配后端 Pod run: my-nginx # 选择拥有 runmy-nginx 标签的 Pod启动test-service.yaml查看service访问servicekubectl apply -f svc_test.yaml kubectl describe svc my-nginx curl 10.107.57.148:80注意上面的10.107.57.148:80地址只能是在k8s集群内部可以访问在外部无法访问比方说我们想要通过浏览器访问那么是访问不通的如果想要在k8s集群之外访问是需要把servicetype类型改成nodePort5.2创建type类型是NodePort的service# 创建pod-node-export.yaml文件 vi pod-node-export.yaml # 填入以下内容 apiVersion: apps/v1 # 指定 Kubernetes API 版本apps/v1 用于 Deployment kind: Deployment # 资源类型为 Deployment用于管理无状态应用的 Pod 副本 metadata: # Deployment 的元数据信息 name: my-nginx-nodeport # Deployment 的名称 spec: # Deployment 的期望状态 selector: # 选择器用于匹配该 Deployment 管理的 Pod matchLabels: # 通过标签选择器匹配 Pod run: my-nginx-nodeport # 匹配标签 runmy-nginx-nodeport 的 Pod replicas: 2 # 期望运行的 Pod 副本数量为 2 template: # Pod 模板用于创建 Pod metadata: # Pod 模板的元数据 labels: # 给创建的 Pod 打标签 run: my-nginx-nodeport # Pod 标签为 runmy-nginx-nodeport需与 selector 匹配 spec: # Pod 模板的期望状态 containers: # 容器列表 - name: my-nginx-nodeport-container # 容器名称 image: nginx # 容器使用的镜像为 nginx imagePullPolicy: IfNotPresent # 镜像拉取策略本地不存在时才拉取 ports: # 容器端口列表 - containerPort: 80 # Pod 中容器需要暴露的端口启动pod查看pod状态apply -f pod-node-export.yaml kubectl get pod -o wide创建svc_node_port.yaml# 创建svc_node_port.yaml vi svc_node_port.yaml # 填入以下内容 apiVersion: v1 # 指定 Kubernetes API 版本v1 用于 Service 等核心资源 kind: Service # 资源类型为 Service用于定义一组 Pod 的访问入口 metadata: # Service 的元数据信息 name: my-nginx-nodeport # Service 的名称 labels: # Service 的标签 run: my-nginx-nodeport # 标签 runmy-nginx-nodeport用于标识该 Service spec: # Service 的期望状态 type: NodePort # Service 类型为 NodePort可通过集群节点 IP nodePort 从外部访问 ports: # Service 端口列表 - port: 80 # Service 自身暴露的端口集群内部通过该端口访问服务 protocol: TCP # 端口使用的协议为 TCP targetPort: 80 # 后端 Pod 容器中定义的端口流量转发到该端口 nodePort: 30380 # 在每个节点上暴露的端口外部通过 节点IP:30380 访问服务 selector: # 选择器用于匹配后端 Pod run: my-nginx-nodeport # 选择拥有 runmy-nginx-nodeport 标签的 Pod启动svc查看svc访问svckubectl apply -f svc_node_port.yaml kubectl describe svc my-nginx-nodeport # 内网访问 curl 10.96.202.229:80 # 宿主机访问(外网访问) curl http://192.168.138.135:30380/服务请求走向Client-→nodeip:30380-service ip:80-→pod ip:container portClient-192.168.138.135:30380-110.96.202.229:80-pod ip:805.3创建type类型是ExternalName的service应用场景跨名称空间访问需求default名称空间下的client服务想要访问nginx-ns名称空间下的nginx-svc服务首先创建一个client.yamlvi client.yaml # 填入以下内容 apiVersion: apps/v1 # 指定 Kubernetes API 版本apps/v1 用于 Deployment kind: Deployment # 资源类型为 Deployment用于管理无状态应用的 Pod 副本 metadata: # Deployment 的元数据信息 name: client # Deployment 的名称 spec: # Deployment 的期望状态 replicas: 1 # 期望运行的 Pod 副本数量为 1 selector: # 选择器用于匹配该 Deployment 管理的 Pod matchLabels: # 通过标签选择器匹配 Pod app: busybox # 匹配标签 appbusybox 的 Pod template: # Pod 模板用于创建 Pod metadata: # Pod 模板的元数据 labels: # 给创建的 Pod 打标签 app: busybox # Pod 标签为 appbusybox需与 selector 匹配 spec: # Pod 模板的期望状态 containers: # 容器列表 - name: busybox # 容器名称 image: busybox # 容器使用的镜像为 busybox command: [/bin/sh, -c, sleep 36000] # 覆盖容器默认命令启动后休眠 36000 秒启动client查看clientkubectl apply -f client.yaml kubectl get pod -o wide创建svc_client.yamlapiVersion: v1 # 指定 Kubernetes API 版本v1 用于 Service 等核心资源 kind: Service # 资源类型为 Service用于定义一组 Pod 的访问入口或外部服务别名 metadata: # Service 的元数据信息 name: client-svc # Service 的名称 spec: # Service 的期望状态 type: ExternalName # Service 类型为 ExternalName将服务映射到外部 DNS 名称 externalName: nginx-svc.nginx-ns.svc.cluster.local # 外部服务的 DNS 名称访问该 Service 时会解析到此地址 ports: # 端口列表ExternalName 类型下端口通常不是必需的targetPort 可能被忽略 - name: http # 端口名称标识该端口为 http port: 80 # Service 暴露的端口 targetPort: 80 # 目标端口在 ExternalName 类型中通常不生效可省略启动svc并查看svckubectl apply -f svc_client.yaml kubectl describe svc client-svc接着创建一个创建一个命名空间kubectl create ns nginx-ns kubectl get ns在这个命名空间下创建一个podvi nginx-pod.yaml #填入以下内容 apiVersion: apps/v1 # 指定 Kubernetes API 版本apps/v1 用于 Deployment kind: Deployment # 资源类型为 Deployment用于管理无状态应用的 Pod 副本 metadata: # Deployment 的元数据信息 name: nginx # Deployment 的名称 namespace: nginx-ns # 指定该 Deployment 所在的命名空间为 nginx-ns spec: # Deployment 的期望状态 replicas: 1 # 期望运行的 Pod 副本数量为 1 selector: # 选择器用于匹配该 Deployment 管理的 Pod matchLabels: # 通过标签选择器匹配 Pod app: nginx # 匹配标签 appnginx 的 Pod template: # Pod 模板用于创建 Pod metadata: # Pod 模板的元数据 labels: # 给创建的 Pod 打标签 app: nginx # Pod 标签为 appnginx需与 selector 匹配 spec: # Pod 模板的期望状态 containers: # 容器列表 - name: nginx # 容器名称 image: nginx # 容器使用的镜像为 nginx imagePullPolicy: IfNotPresent # 镜像拉取策略本地不存在时才拉取启动pod并查看pod状态kubectl apply -f nginx-pod.yaml # 查看nginx-ns命名空间下的pod如果是kubectl get pods -o wide是无法查看的 # 因为这个是查看default的命名空间所以如下命令中带上了 -n nginx-ns表示要查看nginx-ns命名空间下的pod kubectl get pods -n nginx-ns -o wide最后给这个nginx-pod做一个service代理# 创建nginx_svc.yaml vi nginx_svc.yaml # 填入以下内容 apiVersion: v1 # 指定 Kubernetes API 版本v1 用于 Service 等核心资源 kind: Service # 资源类型为 Service用于定义一组 Pod 的访问入口 metadata: # Service 的元数据信息 name: nginx-svc # Service 的名称 namespace: nginx-ns # 指定该 Service 所在的命名空间为 nginx-ns spec: # Service 的期望状态 selector: # 选择器用于匹配后端 Pod app: nginx # 选择拥有 appnginx 标签的 Pod ports: # Service 端口列表 - name: http # 端口名称标识该端口为 http protocol: TCP # 端口使用的协议为 TCP port: 80 # Service 自身暴露的端口集群内部通过该端口访问服务 targetPort: 80 # 后端 Pod 容器中定义的端口流量转发到该端口启动这个service并查看这个servicekubectl apply -f nginx_svc.yaml kubectl describe svc nginx-svc -n nginx-ns登录到client pode# 登录client kubectl exec -it client-54bd759bfc-kqtpf -- /bin/sh # 分别执行如下两个命令 wget -q -O - client-svc.default.svc.cluster.local wget -q -O - nginx-svc.nginx-ns.svc.cluster.local # 两个命令结果一致