小阿轩yx-Kubernetes服务发布基础
前言
- 通过 k8s 的调度,可以成功的将服务部署到 Kubernetes,应用部署后,最重要的就是对用户开放。
区别
传统的架构中
- 用户访问公司内的服务可能通过了多层代理、网关、防火墙等。
- 可能是通过Nginx、Haproxy、LVS、公有云的 SLB、ELB 等实现的负载均衡和域名路由。
- 配置多个相同服务的负载均衡可能使用的是 Nginx的upstream。
- 配置域名访问应用可能使用 Nginx 的 Server 配置。
Kubernetes 中
- 访问 Kubernetes 中的的应用同样也会经过多层代理、网关、防火墙等。
- 虽然也是通过诸如此类的技术实现的域名路由或者负载均衡,只不过对应的名字叫法可能有所变化,不要把这些当做-个比较新颖的东西,其实内部的实现和之前并无区别。
- 配置多个相同服务的负载均衡可能使用Service 实现。
- 用Ingress 实现域名路由的配置。
service 的定义
- 用于为一组提供服务的 Pod 抽象一个稳定的网络访问地址
- 是 k8s 实现微服务的核心概念
- 通过定义设置的访问地址是 DNS 域名格式的服务名称,对于客户端应用来说,网络访问方式并没有改变。
- 还提供了负载均衡器的功能,将客户端请求负载分发到后端提供具体服务的各个Pod 上。
- 主要用于提供网络服务,通过定义,能够为客户端应用提供稳定的访问地址(域名或 IP 地址)和负载均衡功能,以及屏蔽后端 EndPoint 的变化,是 Kubernetes 实现微服务的核心资源。
总之,service 是 kubernetes 中一个非常重要的概念,service 用于将外部请求代理到内部 pod上,提供4层负载均衡和服务发现的功能,使得我们可以构建高可用和可扩展的应用程序。
Service 的概念和原理
service 基本介绍
- 是 kubernetes 中的一种抽象
- 用于定义一组 pod 以及访问这一组 pod 的策略
- service 会为一组 pod 创建一个虚拟的 IP 地址,通过这个 IP 地址可以访问这组 pod 中的任意一个 pod。
- 当客户端请求这个虚拟 IP 地址时,请求会被负载均衡到一组 pod 中的某一个 pod 上,从而完成对 pod 的访问。
作用
- 是将一组 pod 封装为一个虚拟的服务,并提供一个统一的入口,供客户端访问。
service 支持的功能
- 负载均衡
- 服务发现
- 服务暴露
kubernetes 中
- pod的IP地址是动态变化的,因此无法直接通过pod的IP地址进行访问。service的出现正式为了解决找个问题的。
service 的实现依赖于 kube-proxy 组件和 CoreDNS组件。它们共同协作,将 service 与 pod 连接起来,实现对 pod 代理访问
总之,service 是 kubernetes 中一种非常重要的资源对象,它可以让 pod 对外提供服务,并提供负载均衡、服务发现等功能。
service 的负载均衡机制
- 当一个 Service 对象在 Kubernetes 集群中被定义出来时,集群内的客户端应用就可以通过服务 IP访问到具体的 Pod 容器提供的服务了。
- 从服务 IP 到后端 Pod 的负载均衡机制,则是由每个 node 上的kube-proxy 代理来负责实现的。
kubeproxy 的代理模式有
- userspace
- iptables
- ipvs
- kernelspace
userspace
- 起初,kube-proxy进程是一个真实的TCP/UDP代理
- 当某个 pod 以 clusterIP 方式访问某个service的时候,流量会被 pod 所在的本机的 iptables 转发到本机的 kube-proxy 进程,然后将请求转发到后端某个 pod 上。
具体过程
- kube-proxy 为每个 service 在 node 上打开一个随机端口作为代理端口
- 建立 iptables 规则,将 clusterip 的请求重定向到代理端口(用户空间)
- 到达代理端口的请求再由 kubeproxy 转发到后端
clusterip 重定向到 kube-proxy 服务的过程存在内核态到用户态的切换
开销很大,因此有了iptables 模式,而 userspace 模式也被废弃了。
iptabels
- kubernets 从1.2版本开始将iptabels模式作为默认模式,这种模式下kube-proxy不再起到proxy的作用。
核心功能
- 通过 API Server 的 Watch 接口实时跟踪 Service 和 Endpoint 的变更信息,并更新对应的 iptables 规则,Client 的请求流量通过 iptables 的 NAT 机制“直接路由”到目标 Pod
不同于 userspace
iptables 的模式中
- kube-proxy不再负责转发数据包,kube-proxy 主要完成对 iptables 策略的动态管理。
- 数据包的走向完全由 iptables 规则决定,这样的过程不存在内核态到用户态的切换,效率明显会高很多。
- 随着 service的增加,iptables 规则会不断增加,导致内核十分繁忙(等于在读一张很大的没建索引的表)。
ipvs
- 从 kubernetes 1.8版本开始引入第三代的 IPVS 模式
- 它也是基于 netfilter 实现的
定位不同
- iptables 是为防火墙设计的
- IPVS 则专门用于高性能负载均衡,并使用高效的数据结构 Hash 表,允许几乎无限的规模扩张。
ipvs 为负载均衡提供了更多的算法
- rr:轮训
- lc:最小连接数
- df:目标哈希
- sh:源哈希
- sed:预计延迟最短
- nq:从不排队
- ipvs 使用 ipset 存储 iptables 规则,在査找时类似 hash 表査找,时间复杂度为 0(1)
- 而 iptables 时间复杂度则为 0(n)
- 可以将 ipset 简单理解为 ip 集合
- 集合的内容可以是 IP 地址、IP 网段、端口等,iptabels可以直接添加规则对这个可变集合进行操作,这样做的好处可以大大减少 iptables 规则的数量,从而减少性能损耗。
査看系统是否开启了 ipvs 模块,可以使用命令
lsmod | grep ip_vs
- 时间复杂度用字母 0 表示
kernelspace
- Windows server 上的代理模式
service 的4种类型
ClusterIP
- 这是最常用的 Service 类型
- 它为 Pod 提供了一个虚拟的 IP 地址。
- 当其他 Pod 需要访问该 Service 时,它们只需要使用该虚拟 IP 地址即可。
- Kubernetes 会自动将请求路由到相应的 Pod 上
NodePort
- 将 Pod 公开为集群中所有节点上的某个端口。
- 当外部请求到达任何一个节点上的该端口时,Kubernetes 会将请求路由到相应的 Pod 上。
LoadBalancer Service
- 使用云提供商的负载均衡器将请求路由到后端 PodKubernetes 会自动创建和配置负载均衡器,并将其绑定到 Service 上。
externalName Service
- 允许你将 Service 映射到集群外部的某个名称。
- 当 Pod需要访问该 service 时,它们将使用该名称来解析出相应的 IP 地址。
将 images 镜像文件通过 Xftp 上传至 master、node01、node02(101、102、103)
将资源清单单独上传至 master 主节点(101)
三台主机导入镜像
主机一
[root@k8s-master ~]# cd images/
[root@k8s-master images]# bash imp_docker_img.sh
主机二
[root@k8s-node01 ~]# cd images/
[root@k8s-node01 images]# bash imp_docker_img.sh
主机三
[root@k8s-node02 ~]# cd images/
[root@k8s-node02 images]# bash imp_docker_img.sh
生成用于测试 service 的 Deployment
- 编写 Deployment,用于各种 service 的验证
- 应用 Service 概念之前,先创建一个提供 web 服务的 Pod 集合,有两个 Tomcat 容器副本组成,每个容器提供的服务端口都为 8080
编辑 deployment
[root@k8s-master ~]# cat webapp-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
spec:
#pod 的副本数
replicas:2
#目标 Pod 的标签选择器
selector:
#需要匹配的标签
matchLabels:
#对应了目标 pod 的标签名称
app: webapp
#自动创建新的 pod 副本的模板
template:
metadata:
#定义 pod 的标签
labels:
#标签值为 app:webapp
app: webapp
spec:
containers:
- name: webapp
image: kubeguide/tomcat-app:v1
ports:
- name: http
containerPort: 8080
protocol: TCP
selector(选择器)
- 主要用于资源的匹配,只有符合条件的资源才会被调用或使用,可以使用该方式对集群中的各类资源进行分配。
- Kubernetes 和核心资源 Deployment、statefulset 管理的 Pod 是通过选择器字段决定的,通过 Service 访问这些后端 Pod 也是通过选择器字段决定的。
label(标签)
- 可以对 Kubernetes 的其他资源进行配置,当Kubernetes 对系统的任何 API 对象如Pod 进行分组时,会对其添加标签,用以精准的选择对应的API对象。
创建该 Deployment
[root@k8s-master ~]# kubectl create-f webapp-deployment.yaml
查看 pod 创建情况
[root@k8s-master ~l# kubectl get pod
NAME READY STATUS RESTARTS AGE
webapp-8554f77548-9xwmm 1/1 Running 0 93s
webapp-8554f77548-jrw7f 1/1 Running 0 93s
查看各个 pod 的 IP 地址
[root@k8s-master ~]# kubectl get pods -l app=webapp -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
webapp-8554f77548-9xwmm 1/1 Running 0 2mss5 172.17.125.3 k8snode01 <none> <none>
webapp-8554f77548-jrw7f 1/1 Running。 0 2m55s 172.27.14.195 k8s-node02 <none> <none>
访问这两个地址
[root@k8s-master ~]# curl 172.17.125.3:8080
[root@k8s-master ~l# curl 172.27.14.195:8080
service 的创建
创建一个ClusterIP类型 service
描述
- ClusterIP 是默认的 Service 类型。
- 它将创建一个虚拟的 clusterIp 地址,用于在集群内部访问 Service。
使用场景
- 适用于集群内部的服务通信,例如将前端服务和后端服务连接起来,供内部其他服务使用。
通过 expose 命令创建 clusterIP 类型的 service
- 为了让客户端应用能够访问到前面创建的两个 Tomcat Pod 实例,需要创建一个 Service 来提供服务。
k8s 提供了一种快速的方法
- 即通过 kubectl expose 命令来创建 Service。
执行 expose 命令暴露端口
[root@k8s-master ~l# kubectl expose deployment webapp
查看创建的 Service
[root@k8s-master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 9d
webapp Cluster 10.104.162.209 <none> 8080/TCP 32d
- 可以看到,系统为他分配了一个虚拟 IP 地址,Service 的端口号,从 pod 中复制而来。我们就可以通过这个虚拟 IP 地址,和端口号来访问这个 Service 了。
访问测试
[root@k8s-master ~]# curl 10.104.162.209:8080
- 客户端对 Service 的访问被自动负载分发到了后端的两个 pod 之一。
- Kubernetes 自动完成将客户端请求转发到后端多个 EndPoint 的负载分发的工作。
- 通过负载均衡机制,Kubernetes 实现了一种分布式应用的统一入口,免去了客户端应用获知后端服务实例列表和变化的复杂度。
删除此 Service
[root@k8s-master ~]# kubectl delete service webapp
使用 yaml 文件创建 Service
- 除了使用 expose 的命令创建 Service,更便于管理的方式是 yaml 文件来创建 Service。
编辑 service 文件
root@k8s-master ~]# cat webapp-service.yaml
apiVersion: v1
kind: Service
metadata:
name: webapp
spec:
ports:
- protocol: TCP
port: 8080
targetPort: 8080
selector:
app: webapp
- 案例中的 ports 定义的是 Service 本身的端口号 8080(用于提供给外部用户访问的端口)targetPort 则用来指定后端 Pod 的容器端口号,selector 定义的是后端 Pod 所拥有的 label
利用 yaml 创建此服务
[root@k8s-master ~]# kubectl create -f webapp--service.yaml
查看创建的 Service
[root@k8s-master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP POET(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 9d
webapp ClusterIP 10.108.79.50 <none> 8080/TCP 9s
访问测试
[root@k8s-master ~]# curl 10.108.79.50:8080
查看 EndPoint 列表
- 一个 Service 对应的后端由 Pod 的 IP 地址何容器的端口号组成,即一个完成的 IP:Port 访问地址。
- 这在 k8s 中叫做 EndPoint。
- 通过査看 Service 的详细信息,可以看到其后端的 EndPoint 列表
[root@k8s-master ~]# kubectl describe svc webapp
Name: webapp
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=webapp
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.108.79.50
IPs: 10.108.79.50
POrt: <unset> 8080/TCP
TargetPort: 8080/TCP
Endpoints: 172.17.125.4:8080,172.27.14.196:8080
Session Affinity: None
Events: <none>
查看 EndPoint 资源对象
- 实际上,k8s 自动创建了与 Service 关联的 EndPoint 资源对象,这可以通过 EndPoint 对象进行查看
[root@k8s-master ~]# kubectl get endpoints
NAME ENDPOINTS AGE
kubernetes 192.168.10.101:6443 9d
webapp 172.17.125.4:8080,172.27.14.196:8080 6m19s
删除这个 Service
[root@k8s-master ~]# kubectl delete -f webapp-service.yaml
或
[root@k8s-master ~]# kubectl delete service webapp
创建 NodePort 类型的 service
描述
- NodePort 将在每个节点上公开一个端口,并将流量转发到 Service。它会创建一个ClusterIP,并将指定的端口映射到每个节点上的相同端口。
使用场景
- 适用于需要从外部访问集群中的服务时,可以通过节点的 IP 地址和映射的端口进行访问。
- 这对于开发和测试环境非常有用。
创建 Service 文件
- 设置 Service 类型为 NodePort,并设置具体的 nodePort 端口号位30008
[root@k8s-master ~]# cat webapp-svc-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: webapp
spec:
type: NodePort
ports:
- port: 8080
targetPort: 8080
nodePort: 30008
selector:
app: webapp
- nodePort 端口的范围在 1.23.6 的版本中为 30000-32767
创建此 Service
- 继续使用刚才的 webapp 的 Deployment,为此 Deployment 创建一个 NodePort 类型的 service
[root@k8s-master ~]# kubectl create -f webapp-svc-nodeport.yaml
查看创建的 Service
[root@k8s-master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 9d
webapp NodePOrt 10.98.184.252 <none> 8080:30008/TCP 119s
用浏览器访问地址
- 192.168.10.101:30008
- 因为 NodePort 的方式可以在每个 Node 节点创建出这个端口,所以在任何一个节点使用 netstat -anptgrep 30008 命令查询,都可以看到此端口,在访问的时候,IP 地址可以使用任何一个主机的 IP 地址
删除该 Service
[root@k8s-master ~]# kubectl delete -f webapp-svc-nodeport.yaml
创建 LoadBalancer 类型的 service
公有云的环境中会使用 LoadBalancer 的类型
- 可以将 Service 映射到公有云提供的某个负载均衡器的 IP 地址上,客户端通过负载均衡器的 IP 和 Service 的端口号就可以访问到具体的服务。
描述
- LoadBalancer 为 Service 创建一个外部负载均衡器,并分配一个外部 IP 地址。
- 它通常由云提供商的负载均衡服务实现。
使用场景
- 适用于需要将流量从外部负载均衡器分发到集群内部的服务
编写 LoadBalancer 类型的 Service 文件
[root@k8s-master ~]# cat webapp-svc-loadbalancer.yaml
apiVersion: v1
kind: Service
metadata:
name:webapp
namespace: default
labels:
app: webapp
spec:
type: LoadBalancer
ports:
- port: 8080
targetPort: http
protocol: TCP
name: http
#没有此参数,系统会自动指定一个随机端口
nodePort: 31771
selector:
app: webapp
- Service 创建好后,云服务商会在 Service 定义中补充 LoadBalancer 的 IP 地址,之后就可以在客户端访问该 Service 了。
- nodePort 的端口范围在 30000-32767 之间。
创建此 Service
[root@k8s-master ~]# kubectl create -f webapp-svc-loadbalancer.yaml
查看创建结果
[root@k8s-master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 10.96.0.1 <none> 9d
webapp LoadBalancer 10.111.51.212 <pending> 8080:31458 2m56s
用浏览器访问
- 192.168.10.101:31458
删除 Service
[root@k8s-master ~]# kubectl delete -f webapp-svc-loadbalancer.yaml
创建 ExternalName 类型的 service
描述
- ExternalName 允许 Service 通过返回CNAME记录来引用集群外部的服务。
- 它没有ClusterIP、NodePort 或 LoadBalancer。
使用场景
- 适用于需要将K8s内部的服务与集群外的现有服务进行关联
ExternalName 类型是 Service 的特例
- 用于将集群外的服务定义为 Kubernetes 的集群 Service,并通过 ExternalName 字段指定外部服务的地址,可以使用域名或 IP 格式。
- 集群内客户端应用通过访问这个 Service 就能访问外部服务了。
- 他没有选择器,没有定义任何端口和 EndPoint,他通过返回该外部服务的别名来提供服务。
- 也可以用于两个不同的 namespace 之间的不同 pod 可以通过 name 的形式访问。
两个不同的命名空间中的 pod,可以直接使用他们的 IP 地址进行通信,但是 pod 的 IP 地址是随机分配的,重建 pod 后其 IP 地址就改变了,因此我们要用 pod 对应的 service 名称进行通信。
但是跨命名空间是不能解析其他命名空间中创建的 service 名称的。
这个时候就可以使用 ExternalName 实现两个不同命名空间中的各个 pod 间的通信。
创建案例所需的两个命名空间
[root@k8s-master ~]# kubectl create namespace test01
[root@k8s-master ~]# kubectl create namespace test02
第一个 Pod
编写 myapp01.yaml 文件
[root@k8s-master ~]# cat myapp01.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp01
namespace: test01
spec:
replicas: 1
#标签选择器
selector:
#匹配的标签为
matchLabels:
app:myapp01
release: canary
template:
metadata:
labels:
app:myapp01#和上面的 myapp 要匹配
release: canary
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
ports:
- name: http01
containerPort: 80
创建命名空间位 test01 的 Pod
[root@k8s-master ~]# kubectl create -f myapp01.yaml
创建一个无头(headless)Service
[root@k8s-master ~]# cat myapp-svc-headless01.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp-svc01
namespace: test01
spec:
selector:
#挑选的 pod 还是 myapp01。一个 pod 可以有多个 service
app:myapp01
release: canary
#None 表示是无头 service
clusterIp: None
ports:
#service ip 中的端口
- port: 39320
#容器 ip 中的端口
targetPort:80
- (Headless Service)无头 Service:这种服务没有入口地址(没有clusterIP),kube-proxy 也不会为其创建负载转发的规则,服务名的解析机制取决于这个无头 Service 是否设置了标签选择器。
- 无头服务创建出来之后,对于其他外部的 pod 来讲,该 pod 对应的名字就确定了下来,其固定的格式:无头服务名,命名空间,svc.cluster.local
创建 myapp-svc-headless01.yaml 文件
[root@k8s-master ~]# kubectl create -f myapp-svc-headless01.yaml
创建 extername
[root@k8s-master ~]# cat myapp-svc-extername01.yaml
kind: service
apiVersion: v1
metadata:
name: myapp-svcname02
namespace: test01
spec:
type: ExternalName
externalName: myapp-svc02.test02.svc.cluster.local
- name:myapp-svcname02:指的是外部的服务名称
- myapp-svc02.test02.svc.cluster.local:对方无头服务的名字
- svc.cluster.local:对方命名空间的名字
创建 myapp-svc-extername01.yaml 文件
[root@k8s-master ~]# kubectl create -f myapp-svc-extername01.yaml
创建第二个 Pod
查看命名空间位 test02 的 Pod
[root@k8s-master ~]# cat myapp02.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp02
namespace: test02
spec:
replicas: 1
#标签选择器
selector:
#匹配的标签为
matchLabels:
app: myapp02
release:canary
template:
metadata:
labels :
#和上面的 myapp 要匹配
app: myapp02
release:canary
spec:
containers:
- name: myapp02
image: ikubernetes/myapp:v1
ports:
- name: http02
containerPort:80
创建 myapp02.yaml 文件
[root@k8s-master ~]# kubectl create -f myapp02.yaml
创建一个无头(headless)Service
[root@k8s-master ~]# cat myapp-svc-headless02.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp-svc02
namespace: test02
spec:
selector:
#挑选的 pod 还是 myapp。一个 pod 可以有多个 service
app: myapp02
release: canary
#None 表示是无头service
clusterIP: None
ports:
#service ip 中的端口
- port:39320
#容器 ip 中的端口
targetPort:80
创建 myapp-svc-headless02.yaml 文件
[root@k8s-master ~]# kubectl create -f myapp-svc-headless02.yaml
创建 extername
[root@k8s-master ~]# cat myapp-svc-extername02.yaml
kind: Service
apiVersion: v1
metadata:
name: myapp-svcname01
namespace: test02
spec:
type: ExternalName
externalName:myapp-svc01.test01.svc.cluster.local
- name: myapp-svcname01:指的是外部的服务名称
创建 myapp-svc-extername02.yaml 文件
[root@k8s-master ~]# kubectl create -f myapp-svc-extername02.yaml
验证 Pod 间的通信
查看命名空间为 test01 的 Pod
[root@k8s-master ~]# kubectl get pods -n test01
NAME READY STATUS RESTARTS AGE
myapp01-696c886d6b-tq7vv 1/1 Running 0 54s
登录文件
[root@k8s-master ~]# kubectl exec -it myapp01-696c886d6b-tq7vv -n test01 -- /bin/sh
/ # nslookup myapp-svcname02
/ # ping myapp-svcname02
PING myapp-svcname01 (172.17.125.3): 56 data bytes
64 bytes from 172.17.125.3: seq=0 ttl=62 time=0.903 ms
64 bytes from 172.17.125.3: seq=1 ttl=62 time=3.139 ms
/ # nslookup myapp-svc02.test02.svc.cluster.local
/ # ping myapp-svc02.test02.svc.cluster.local
PING myapp-svc02.test02.svc.cluster.local (172.17.125.3): 56 data bytes
64 bytes from 172.17.125.3: seq=0 ttl=62 time=0.903 ms
64 bytes from 172.17.125.3: seq=1 ttl=62 time=3.139 ms
获取文件详细信息
[root@k8s-master ~]# kubectl get pods -n test02 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp-6bb4786bcd-hsr28 1/1 Running 0 7m31s 172.17.125.3 k8s-node01 <none> <none>
[root@k8s-master ~]# kubectl get pods -n test02 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp-696c886d6b-tndns 1/1 Running 0 9m30s 172.25.244.197 k8s-master01 <none> <none>
查看命名空间为 test02 的 Pod
[root@k8s-master ~]# kubectl get pods -n test02 -o wide
NAME TYPE CLYSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
myapp-svc ClusterIP None <none> 39320/TCP 7m25s app=myapp,release=canary
myapp-svcname ExternalName <none> myapp-svc.test02.svc.cluster.local <none> 6m45s <none>
查看命名空间为 test01 的 Pod
[root@k8s-master ~]# kubectl get pods -n test01 -o wide
NAME TYPE CLYSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
myapp-svc ClusterIP None <none> 39320/TCP 10 app=myapp,release=canary
myapp-svcname ExternalName <none> myapp-svc.test02.svc.cluster.local <none> 9m59s <none>
service 的其它应用
Service 的多端口设置
- 一个容器应用可以提供多个端口的服务,在 Service 的定义中也可以相应的设置多个端口号
创建 service 文件
[root@k8s-master ~]# cat service-multiple-ports.yaml
apiVersion: v1
kind: Service
metadata:
name: webapp
spec:
ports:
- port: 8080
targetPort: 8080
name: web
protocol: TCP
- port: 8005
targetPort: 8005
name: management
protocol: TCP
selector:
app: webapp
- selector 中的 app: webapp 的标签对应的是 webapp-deployment.yaml 中的 pod 的标签
创建 service
[root@k8s-master ~]# kubectl create -f service-multiple-ports.yaml
查看 EndPoint 列表
[root@k8s-master ~]# kubectl describe svc webapp
查看创建的 Service
[root@k8s-master ~]# kubectl get svc webapp
删除这个 Service
[root@k8s-master ~]# kubectl delete -f webapp-service.yaml
或
[root@k8s-master ~]# kubectl delete service webapp
Kubernetes 服务发现
- 服务发现机制是指客户端如何在一个 kubernetes 集群中获知后端服务的访问地址。
Kubernetes 服务发现有两种方式
- 环境变量
- DNS
基于环境变量的服务发现
- 当 Pod 部署到一个 node 节点后,该 node 节点上的 kubelet 会在该 pod 内部设置一组环境变量,这些环境变量是根据活跃的 Service 生成的,所以,要使用基于环境变量的服务发现,需要先创建对应的Service 后再创建所需的 Pod。
先创建出之前用的 service
[root@k8s-master ~]# kubectl create -f service-multiple-ports.yaml
[root@k8s-master ~]# kubectl create -f webapp-deployment.yaml
获取 Pod 状态
[root@k8s-master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
webapp-86b5d9fc88-cv6qq 1/1 Running 0 82s
webapp-86b5d9fc88-s4smp 1/1 Running 0 82s
- 任意的 Pod 都会根据这些 service 创建一组变量用于服务发现。
登录文件
[root@k8s-master ~]# kubectl exec -it webapp-86b5d9fc88-cv6qq -- enV
PATH=/usr/local/tomcat/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=webapp-86b5d9fc88-cv6qqTERM=xterm
KUBERNETES PORT 443 TCP=tcp://10.96.0.1:443
MYNGINX SERVICE PORT HTTP=80
MYNGINX PORT 80 TCP PORT=80
MYNGINX PORT 80 TCP ADDR=10.109.164.93
KUBERNETES PORT 443 TCP PORT=443
MYNGINX SERVICE PORT=80
MYNGINX PORT 80 TCP=tcp://10.109.164.93:80
KUBERNETES PORT 443 TCP PROTO=tCP
KUBERNETES PORT 443 TCP ADDR=10.96.0.1
KUBERNETES SERVICE HOST=10.96.0.1
KUBERNETES SERVICE PORT=443
KUBERNETES SERVICE PORT HTTPS=443
MYNGINX PORT 80 TCP PROTO=tcp
KUBERNETES PORT=tcp://10.96.0.1:443
MYNGINX SERVICE HOST=10.109.164.93
MYNGINX PORT=tcp://10.109.164.93:80
LANG=C.UTF-8
JAVA HOME=/usr/lib/jvm/java-7-openjdk-amd64/jre
JAVA_VERSION=7u101
基于 DNS 的服务发现
- Kubernetes 进行服务发现的另一种方式是基于 Kubernetes 内部的 DNS 记录
- 新版的 Kubernetes默认使用 CoreDNS 作为集群的内部 DNS,一般 coreDNs 的 Service 地址为 Service 网段的低 10 个地址,比如 10.96.0.10,端口为 53,集群内的 Pod 可以通过该地址和端口进行 Kubernetes 内部的服务解析。
- DNS 服务器监听 Kubernetes 创建的 Service,然后给每个 Service 添加一组 DNS 记录,集群中的 Pod就能通过 Kubernetes 内部的 DNS 解析到 Service 的 IP,也就是 Service 的 ClusterIP。
创建一个含有 nslookup 命令的容器
[root@k8s-master ~]# kubectl run redis --image=redis:3.2.10-alpine
测试解析 kube-dns 的 Service
[root@k8s-master ~]# kubectl exec -it redis -- nslookup redis
nslookup: can't resolve '(null)': Name does not resolve
Name : redis
Address 1: 10.244.85.204 redis
[root@k8s-master ~]# kubectl exec -it redis -- nslookup kube-dns.kube-system
nslookup: can't resolve '(null)': Name does not resolve
Name : kube-dns.kube-system
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
删除资源
- kubectl delete -f myappe1.yamL
- kubectl delete -f myapp-svc-headlesse1.yamlkubectl delete -f myapp-svc-extername01.yaml
- kubectl delete -f myapp02.yaml
- kubectl delete -f myapp-svc-headless02.yaml
- kubectl delete -f myapp-svc-extername02.yaml
将 Service 和 Deployment 整合的案例
案例一
查看 nginx-service.yaml 文件
[root@k8s-master ~]# cat nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
name: mynginx
namespace: default
labels:
app: mynginx
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app: mynginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mynginx-deployment
namespace: default
labels:
app: mynginx
spec:
replicas: 2
selector:
matchLabels:
app: mynginx
template:
metadata:
labels:
app: mynginx
spec:
containers:
- name: mynginx
image: nginx:1.7.9
ports:
- name: http
containerPort: 80
protocol: TCP
app: mynginx
- 红色部分的标签名称需要一致。
案例二
[root@k8s-master ~]# cat tomcat-service.yaml
apiVersion: v1
kind: Service
metadata:
name: webapp
namespace: default
labels:
app: mynginx
spec:
type: NodePort
ports:
- port: 8080
targetPort: 8080
nodePort: 30008
name: http
selector:
app: webapp
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
namespace: default
labels:
app: mynginx
spec:
replicas: 2
selector:
matchLabels:
app: mynginx
template:
metadata:
labels:
app: webapp
spec:
containers:
- name: webapp
image: kubeguide/tomcat-app:v1
ports:
- name: http
containerPort: 8080
protocol: TCP
小阿轩yx-Kubernetes服务发布基础