在之前已经创建了一个有两个nginx副本数的deployment,如下所示:
[root@k8s-node1 mytestyaml]# kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 2/2 2 2 45m
[root@k8s-node1 mytestyaml]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-85ff79dd56-42mh9 1/1 Running 0 38m 10.244.2.62 k8s-node3 <none> <none>
nginx-deployment-85ff79dd56-gx2dl 1/1 Running 0 44m 10.244.1.68 k8s-node2 <none> <none>
并且直接访问其IP地址也能够正常的访问到nginx,但是这些Pod的IP地址并不是固定的,如果这个Pod被重新部署的话,他的IP地址是跟着一起变的。如果只是为了对外提供服务,外界不应去关注这个IP地址的变化,最好是能够访问一个固定的IP。
而在k8s中,service就是专门来做这个事情的。
我们可以直接expose这个deployment来实现,如下所示:
[root@k8s-node1 mytestyaml]# kubectl expose deployment nginx-deployment
service/nginx-deployment exposed
[root@k8s-node1 mytestyaml]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 28d
nginx-deployment ClusterIP 10.96.112.83 <none> 80/TCP 26s
这里已经分配给了nginx-deployment 一个 CLUSTER-IP 为 10.96.112.83 ,端口号依旧是80。
那么我们直接访问这个CLUSTER-IP和端口号就能够访问到nginx了,因为service会自动的帮我们把访问到10.96.112.83:80的请求进行负载均衡,转发到10.244.2.62:80和10.244.1.68:80上去。
无论pod被重新部署或者所扩容与否,即使是IP地址变了,我们依然是可以访问CLUSTER-IP:PORT进行访问的。
如下所示,访问10.96.112.83:80:
[root@k8s-node1 mytestyaml]# curl 10.96.112.83:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
还有一种使用yaml文件的方式来声明service。
如下nginx-service.yaml:
apiVersion: v1
kind: Service
metadata:
name: nginx-service # service的名称,全局唯一
spec:
ports:
- port: 80 # service暴露的端口号
targetPort: 80 # 目标端口号
selector:
app: nginx
[root@k8s-node1 mytestyaml]# kubectl apply -f nginx-service.yaml
service/nginx-service created
[root@k8s-node1 mytestyaml]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 28d
nginx-service ClusterIP 10.96.164.32 <none> 80/TCP 10s
上面的yaml文件部署是ClusterIP类型的service,由于这些IP或者端口号都是k8s集群内部的虚拟出来的,因此他只能够用来在k8s集群内部访问,如果需要从集群的外部访问这些service或者Pod,就需要将service部署成为NodePort类型,将集群内部的端口号映射到这台物理机的端口上去,这样就能够直接通过物理机的IP地址+映射的端口号来访问了。
使用NodePort方式的yaml文件如下:
nginx-service2.yaml:
apiVersion: v1
kind: Service
metadata:
name: nginx-service # service的名称,全局唯一
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 30080 # 映射到物理机的端口号
selector:
app: nginx
创建该service
[root@k8s-node1 mytestyaml]# kubectl apply -f nginx-service2.yaml
service/nginx-service created
[root@k8s-node1 mytestyaml]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 40d <none>
nginx-service NodePort 10.96.162.144 <none> 80:30080/TCP 28s app=nginx
从web页面上访问,因为我开的这个 虚拟机的ip是192.168.56.100,而映射的端口号为30080,所以就访问这地址,如下所示:
显示Welcome to nginx! 访问成功
Headless Service即无头服务,就是没有ClusterIP的Service,他的作用也不同于普通的Service,不能直接通过ClusterIP访问路由到后端的Pod上去。
而他的作用就是,当客户端通过k8s api访问这个无头服务的时候,会将其通过Label Selector匹配上的Pod列表信息返回给客户端,客户端就能够通过获得的信息,自义定去作出某些操作。
如下为无头服务的yaml文件:
apiVersion: v1
kind: Service
metadata:
name: nginx-service # service的名称,全局唯一
spec:
clusterIP: None # 设置clusterIP为None,就表示它是一个无头服务
ports:
- port: 80 # service暴露的端口号
targetPort: 80
selector:
app: nginx
创建无头服务
[root@k8s-node1 mytestyaml]# kubectl apply -f nginx-headless-service.yaml
service/nginx-service created
[root@k8s-node1 mytestyaml]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 41d <none>
nginx-service ClusterIP None <none> 80/TCP 2m24s app=nginx
查看这个nginx-service的详细信息,可以看到Endpoints已经匹配到了两个后端的Pod地址
[root@k8s-node1 mytestyaml]# kubectl describe svc nginx-service
Name: nginx-service
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"nginx-service","namespace":"default"},"spec":{"clusterIP":"None",...
Selector: app=nginx
Type: ClusterIP
IP: None
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.1.82:80,10.244.2.77:80
Session Affinity: None
Events: <none>
再通过postman对 k8s 的restful api进行访问:
https://192.168.56.100:6443/api/v1/namespaces/default/endpoints/nginx-service
可以看到,访问无头服务,返回的出现了这两个Pod的详细信息
我们也可以通过java程序去使用restful api来访问k8s获取这些信息,这样就能够在应用程序中去定义自己想要的功能了。
apiVersion: v1
kind: Service
metadata: # 元数据
name: string # service的名称,全局唯一
namespace: string #命名空间,不指定时,默认为default
labels: #自定义标签属性列表
- name: string
annotations: #自定义注解属性列表
- name: string
spec: #详细信息
selector: [] #Label Selector配置,将选择具有指定label 标签的Pod作为管理范围
type: string #类型,指定Service的访问方式,默认为Cluster IP,还有NodePort、LoadBalancer
clusterIP: string #当type为clusterIP时,可以手动指定,不指定则自动分配
sessionAffinity: string # 支持session则同一个客户端访问则会转发到同一个Pod
ports: #Service需要暴露的端口列表
- name: string # 端口名称
protocol: string # 端口协议,默认TCP,还可选UDP
port: int # 服务监听的的端口号
targetPort: int # 需要转发到后端的Pod端口号
nodePort: int # 当type为NodePort时,这里指定映射到物理机的端口号
status: # 当spec.type=LoadBalancer时,设置外部负载均衡器的地区
loadBalancer:
ingress:
ip: string # 外部负载均衡器的ip地址
hostname: string # 外部负载均衡器的主机名