什么是 Service
Service 可以简单的理解为逻辑上的一组 Pod。一种可以访问 Pod 的策略,而且其他 Pod 可以通过这个 Service 访问到这个 Service代理的 Pod。相对于 Pod 而言,它会有一个固定的名称,一旦创建就固定不变。
创建一个 Service
定义一个 Service 的文件 nginx-svc.yaml,内容如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20apiVersion: v1
kind: Service
metadata:
name: nginx-svc
labels:
app: nginx-svc
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
- name: https
port: 443
protocol: TCP
targetPort: 443
selector:
app: nginx
sessionAffinity: None
type: ClusterIP说明:
- spec.ports.name: Service 端口的名称
- spec.ports.port: Service 自身的端口
- spec.ports.targetPort: 后端应用的端口
- spec.ports.protocol: 端口协议,支持 TCP,UDP,SCTP,默认值为 TCP
定义一个 Deployment 文件,nginx-deployment.yaml,文件内容如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
namespace: default
spec:
progressDeadlineSeconds: 600
replicas: 2
revisionHistoryLimit: 10
selector:
matchLabels:
app: nginx
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:
containers:
- image: nginx:1.15.2
imagePullPolicy: IfNotPresent
name: nginx
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30创建 Deployment 资源
1
2# kubectl create -f nginx-deployment.yaml
deployment.apps/nginx created创建 Service 资源
1
2# kubectl create -f nginx-svc.yaml
service/nginx-svc created查看 Service
1
2
3
4
5
6
7
8# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-66bbc9fdc5-gmrzx 1/1 Running 0 2m41s 172.21.176.219 k8s-master-02 <none> <none>
nginx-66bbc9fdc5-lb5hm 1/1 Running 0 2m41s 172.30.107.92 k8s-master-01 <none> <none>
# kubectl get svc nginx-svc -owide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
nginx-svc ClusterIP 10.97.152.249 <none> 80/TCP,443/TCP 2m34s app=nginx
访问 Service 后的 Pod
集群外部通过 svc 的 IP 地址测试访问 Pod
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27# curl http://10.97.152.249
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
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>集群内部通过 svc 的名称访问 Pod
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51# 创建一个 busybox Pod 资源
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: busybox
namespace: default
spec:
containers:
- name: busybox
image: busybox:1.28
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
restartPolicy: Always
EOF
# 进入 busybox
# kubectl exec -it busybox -- sh
# 测试通过 svc 的名称访问 Pod
# wget http://nginx-svc
Connecting to nginx-svc (10.97.152.249:80)
index.html 100% |****************************************************************************************************************************************************************************************| 612 0:00:00 ETA
/ # cat index.html
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
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>
使用 Service 代理 k8s 外部应用
使用场景:
- 希望在生产环境中使用某个固定的名称而非 IP 地址进行访问外部的中间件服务;
- 希望 Service 指向另一个 Namespace 中或其他集群中的服务;
- 某个项目正在迁移至 k8s 集群,但是一部分服务仍然在集群外部,此时可以使用 Service 代理至 k8s 集群外部的服务;
示例:
创建 Service 文件 nginx-svc-external.yaml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14apiVersion: v1
kind: Service
metadata:
labels:
app: nginx-svc-external
name: nginx-svc-external
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
sessionAffinity: None
type: ClusterIP注意,该 Service 文件与之前的示例文件,只是去掉了
selector
属性,这样的话在创建svc
时,不会自动创建同名的endpoint
,需要手动创建 endpoint;创建 Endpoint 文件 nginx-ep-external.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14apiVersion: v1
kind: Endpoints
metadata:
labels:
app: nginx-svc-external
name: nginx-svc-external
namespace: defaul
subsets:
- addresses:
- ip: 140.205.94.189
ports:
- name: http
port: 80
protocol: TCP注意:
- metadata.name 和 metadata.labels.app 的值要和 Service 中的配置一样,这样才会自动匹配起来;
使用 kubectl 命令生成 svc 以及 ep 资源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23# kubectl create -f nginx-svc-external.yaml
service/nginx-svc-external created
# kubectl get svc -owide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 57d <none>
nginx-svc ClusterIP 10.97.152.249 <none> 80/TCP,443/TCP 35m app=nginx
nginx-svc-external ClusterIP 10.109.150.218 <none> 80/TCP 17s <none>
# kubectl get ep -owide
NAME ENDPOINTS AGE
kubernetes 192.168.200.110:6443 57d
nginx-svc 172.21.176.219:443,172.30.107.92:443,172.21.176.219:80 + 1 more... 35m
# 由于 svc 文件中去掉了 selector 字段,所以需要手动创建一个同名的 ep
# kubectl create -f nginx-ep-external.yaml
endpoints/nginx-svc-external created
# kubectl get ep -owide
NAME ENDPOINTS AGE
kubernetes 192.168.200.110:6443 57d
nginx-svc 172.21.176.219:443,172.30.107.92:443,172.21.176.219:80 + 1 more... 38m
nginx-svc-external 140.205.94.189:80 47s
使用 Service 反向代理域名
使用 Service 反向代理外部域名,可以不需要 endpoint,(不建议过多使用 Service 反向代理域名;主要是需要解决跨域问题)
创建 Service 的 yaml 文件 nginx-svc-externalName.yaml
1
2
3
4
5
6
7
8
9apiVersion: v1
kind: Service
metadata:
labels:
appp: nginx-externalname
name: nginx-externalname
spec:
type: ExternalName
externalName: www.baidu.com创建 Service 资源
1
2
3
4
5
6
7
8
9# kubectl create -f nginx-svc-externalname.yaml
service/nginx-externalname created
# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 57d
nginx-externalname ExternalName <none> www.baidu.com <none> 4s
nginx-svc ClusterIP 10.97.152.249 <none> 80/TCP,443/TCP 65m
nginx-svc-external ClusterIP 10.109.150.218 <none> 80/TCP 29m测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15# kubectl exec -it busybox -- sh
/ # nslookup www.baidu.com
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: www.baidu.com
Address 1: 14.215.177.39 14-215-177-39.nginx-svc-external.default.svc.cluster.local
Address 2: 14.215.177.38
/ # nslookup nginx-externalname
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: nginx-externalname
Address 1: 14.215.177.39 14-215-177-39.nginx-svc-external.default.svc.cluster.local
Address 2: 14.215.177.38
Service 的类型
Service 常用的几种类型如下:
- ClusterIP: 在集群内部使用,也是默认值
- ExternalName: 通过返回定义的 CNAME 别名
- NodePort: 在所有安装了 kube-proxy 的节点上打开一个端口,此端口可以代理至后端 Pod,然后集群外部可以使用节点的 IP 地址和 NodePort 的端口号访问到集群 Pod 的服务。NodePort 的端口范围默认是 30000-32767.
- LoadBalancer:使用云提供商的负载均衡器公开服务。(需要付费)