Kubernetes(k8s)服务service:service的发现和service的发布
一.系统环境
本文主要基于Kubernetes1.21.9和Linux操作系统CentOS7.4。
服务器版本 | docker软件版本 | Kubernetes(k8s)集群版本 | CPU架构 |
---|---|---|---|
CentOS Linux release 7.4.1708 (Core) | Docker version 20.10.12 | v1.21.9 | x86_64 |
Kubernetes集群架构:k8scloude1作为master节点,k8scloude2,k8scloude3作为worker节点。
服务器 | 操作系统版本 | CPU架构 | 进程 | 功能描述 |
---|---|---|---|---|
k8scloude1/192.168.110.130 | CentOS Linux release 7.4.1708 (Core) | x86_64 | docker,kube-apiserver,etcd,kube-scheduler,kube-controller-manager,kubelet,kube-proxy,coredns,calico | k8s master节点 |
k8scloude2/192.168.110.129 | CentOS Linux release 7.4.1708 (Core) | x86_64 | docker,kubelet,kube-proxy,calico | k8s worker节点 |
k8scloude3/192.168.110.128 | CentOS Linux release 7.4.1708 (Core) | x86_64 | docker,kubelet,kube-proxy,calico | k8s worker节点 |
二.前言
Kubernetes 是一个强大的容器编排平台,它可以帮助开发者快速、可靠地部署和管理容器化应用程序。其中一个重要的概念就是 service(服务)。在 Kubernetes 中,service 是一组 Pod 的抽象,用于提供稳定的网络端点以便其他应用程序访问。本文将介绍 Kubernetes service 的相关知识,包括服务的发现和服务的发布。
使用service服务的前提是已经有一套可以正常运行的Kubernetes集群,关于Kubernetes(k8s)集群的安装部署,可以查看博客《Centos7 安装部署Kubernetes(k8s)集群》https://www.cnblogs.com/renshengdezheli/p/16686769.html。
三.Kubernetes service简介
Kubernetes 中的 service 是一种可以提供内部负载均衡的抽象,用于将应用程序暴露为一个稳定的网络端点。Kubernetes service 可以通过一个虚拟 IP 地址或者 DNS 来暴露一个应用程序。当需要访问这个应用程序时,只需要使用这个虚拟 IP 地址或者 DNS 就可以了,而不需要知道实际运行这个应用程序的节点的 IP 地址。这种方式可以帮助我们解耦应用程序和底层网络架构,从而使应用程序能够更加灵活地运行在不同的环境中。
Kubernetes 中的 service 还有一些重要的特性,包括:
- 内部负载均衡:Kubernetes service 提供了内部负载均衡的功能,可以将请求均匀地分配给后端 Pod,从而提高应用程序的可用性和响应速度。
- 服务发现:Kubernetes service 允许我们使用标准的 DNS 解析或者环境变量来查找其他服务。这种方式可以使得不同的服务之间能够更加方便地进行通信。
- 在线升级:Kubernetes service 支持在线升级,可以在不影响现有的服务的情况下进行版本升级。
四.使用hostPort向外界暴露应用程序
service简写为svc。创建svc存放yaml文件的目录。
[root@k8scloude1 ~]# mkdir svc
[root@k8scloude1 ~]# cd svc/
[root@k8scloude1 svc]# pwd
/root/svc
创建svc的namespace
[root@k8scloude1 svc]# kubectl create ns svc
namespace/svc created
切换命名空间到svc
[root@k8scloude1 svc]# kubens svc
Context "kubernetes-admin@kubernetes" modified.
Active namespace is "svc".
[root@k8scloude1 svc]# kubectl get pod
No resources found in svc namespace.
4.1 创建deploy
deploy控制器能更好的控制pod,我们先创建deploy。关于deploy控制器的详细内容请查看博客《Kubernetes(k8s)控制器(一):deployment》。
生成创建deploy的yaml文件。
[root@k8scloude1 svc]# kubectl create deploy nginx --image=nginx --dry-run=client -o yaml >nginxdeploy.yaml
[root@k8scloude1 svc]# cat nginxdeploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
resources: {}
status: {}
修改yaml文件,表示创建一个名为nginx的deploy,pod副本数为1。
[root@k8scloude1 svc]# vim nginxdeploy.yaml
[root@k8scloude1 svc]# cat nginxdeploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx
name: nginx
spec:
#replicas: 1表示pod副本数为1
replicas: 1
selector:
matchLabels:
app: nginx
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:
#terminationGracePeriodSeconds: 0 表示当Pod被终止时,不需要等待额外的时间。
terminationGracePeriodSeconds: 0
containers:
- image: nginx
imagePullPolicy: IfNotPresent
name: nginx
resources: {}
status: {}
创建deploy,可以看到1个pod。
[root@k8scloude1 svc]# kubectl apply -f nginxdeploy.yaml
deployment.apps/nginx created
[root@k8scloude1 svc]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-6cf858f6cf-5wh5s 1/1 Running 0 7s 10.244.112.155 k8scloude2 <none> <none>
[root@k8scloude1 svc]# kubectl get deploy -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
nginx 1/1 1 1 23s nginx nginx app=nginx
pod的地址为10.244.112.155,对于pod的地址,在kubernetes集群的任何节点都可以访问,但是外界访问不了。
[root@k8scloude1 svc]# ping 10.244.112.155
PING 10.244.112.155 (10.244.112.155) 56(84) bytes of data.
64 bytes from 10.244.112.155: icmp_seq=1 ttl=63 time=0.430 ms
64 bytes from 10.244.112.155: icmp_seq=2 ttl=63 time=0.516 ms
64 bytes from 10.244.112.155: icmp_seq=3 ttl=63 time=0.595 ms
^C
--- 10.244.112.155 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
rtt min/avg/max/mdev = 0.430/0.513/0.595/0.072 ms
4.2 使用hostPort向外界暴露pod的端口
为了让kubernetes集群以外的机器可以访问pod,可以使用hostPort
字段把容器的端口映射到物理机的端口,这样外界就可以访问pod了,类似于docker容器端口映射,关于docker容器端口映射可以查看博客《一文搞懂docker容器基础:docker镜像管理,docker容器管理》。
查看hostPort字段的解释
[root@k8scloude1 svc]# kubectl explain pod.spec.containers.ports.hostPort
KIND: Pod
VERSION: v1
FIELD: hostPort <integer>
DESCRIPTION:
Number of port to expose on the host. If specified, this must be a valid
port number, 0 < x < 65536. If HostNetwork is specified, this must match
ContainerPort. Most containers do not need this.
修改deploy的yaml文件,添加hostPort参数,把容器80端口映射到物理机的6554端口。
[root@k8scloude1 svc]# vim nginxdeploy.yaml
[root@k8scloude1 svc]# cat nginxdeploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:
#terminationGracePeriodSeconds: 0 表示Pod终止时不需要等待额外时间。
terminationGracePeriodSeconds: 0
containers:
- image: nginx
imagePullPolicy: IfNotPresent
#把容器80端口映射到物理机的6554端口
ports:
- name: http
containerPort: 80
hostPort: 6554
name: nginx
resources: {}
status: {}
删除旧的deploy并创建新的deploy
[root@k8scloude1 svc]# kubectl delete deploy nginx
deployment.apps "nginx" deleted
[root@k8scloude1 svc]# kubectl apply -f nginxdeploy.yaml
deployment.apps/nginx created
[root@k8scloude1 svc]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 1/1 1 1 8s
查看pod,发现pod运行在k8scloude2上,访问k8scloude2的6554端口即可访问pod。
[root@k8scloude1 svc]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-6f64cc5884-kkqmf 1/1 Running 0 15s 10.244.112.158 k8scloude2 <none> <none>
[root@k8scloude1 svc]# kubectl get deploy -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
nginx 1/1 1 1 25s nginx nginx app=nginx
nginx-6f64cc5884-kkqmf 这个pod运行在k8scloude2上,访问k8scloude2地址加端口,即可访问pod的nginx服务。
[root@k8scloude1 svc]# curl http://192.168.110.129:6554
<!DOCTYPE html>
......
<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><em>Thank you for using nginx.</em></p>
</body>
</html>
把deploy的副本数变为2
[root@k8scloude1 svc]# kubectl scale deploy nginx --replicas=2
deployment.apps/nginx scaled
[root@k8scloude1 svc]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 2/2 2 2 6m23s
现在有2个pod了,pod分别运行在两个worker上
[root@k8scloude1 svc]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-6f64cc5884-h78tv 1/1 Running 0 17s 10.244.251.252 k8scloude3 <none> <none>
nginx-6f64cc5884-kkqmf 1/1 Running 0 6m30s 10.244.112.158 k8scloude2 <none> <none>
此时k8scloude3也可以访问成功
[root@k8scloude1 svc]# curl 192.168.110.128:6554
<!DOCTYPE html>
<html>
......
<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><em>Thank you for using nginx.</em></p>
</body>
</html>
把deploy的副本数变为3
[root@k8scloude1 svc]# kubectl scale deploy nginx --replicas=3
deployment.apps/nginx scaled
[root@k8scloude1 svc]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 2/3 3 2 8m29s
这时候问题就来了!可以发现通过hostPort把容器端口映射到物理机端口这种方法不太好,因为如果一个worker上有两个pod,每个pod都要映射物理机端口,就会造成端口冲突,pod创建失败
。
[root@k8scloude1 svc]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-6f64cc5884-h78tv 1/1 Running 0 2m23s 10.244.251.252 k8scloude3 <none> <none>
nginx-6f64cc5884-kkqmf 1/1 Running 0 8m36s 10.244.112.158 k8scloude2 <none> <none>
nginx-6f64cc5884-msdqx 0/1 Pending 0 14s <none> <none> <none> <none>
[root@k8scloude1 svc]# kubectl get deploy -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
nginx 2/3 3 2 8m43s nginx nginx app=nginx
删除deploy
[root@k8scloude1 svc]# kubectl delete deploy nginx
deployment.apps "nginx" deleted
[root@k8scloude1 svc]# kubectl get pod
No resources found in svc namespace.
[root@k8scloude1 svc]# kubectl get deploy
No resources found in svc namespace.
五.使用service服务向外界暴露应用程序
修改deploy的yaml文件,给pod指定多个标签,但是deploy只匹配其中一个标签matchLabels:app1: nginx1。
[root@k8scloude1 svc]# vim nginxdeploy.yaml
[root@k8scloude1 svc]# cat nginxdeploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx
name: nginx
spec:
#pod副本数为2个
replicas: 2
#deploy只匹配其中一个标签
selector:
matchLabels:
app1: nginx1
strategy: {}
template:
metadata:
creationTimestamp: null
#pod有3个标签
labels:
app1: nginx1
app2: nginx2
app3: nginx3
spec:
##当需要关闭容器时,立即杀死容器而不等待默认的30秒优雅停机时长。
terminationGracePeriodSeconds: 0
containers:
- image: nginx
##imagePullPolicy: IfNotPresent:表示如果本地已经存在该镜像,则不重新下载;否则从远程 Docker Hub 下载该镜像
imagePullPolicy: IfNotPresent
name: nginx
resources: {}
status: {}
创建deploy
[root@k8scloude1 svc]# kubectl apply -f nginxdeploy.yaml
deployment.apps/nginx created
deploy根据标签进行匹配
[root@k8scloude1 svc]# kubectl get deploy -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
nginx 2/2 2 2 7s nginx nginx app1=nginx1
[root@k8scloude1 svc]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-75b9846bd7-22btx 1/1 Running 0 12s 10.244.112.157 k8scloude2 <none> <none>
nginx-75b9846bd7-m2pdq 1/1 Running 0 12s 10.244.112.159 k8scloude2 <none> <none>
可以看到pod有三个标签
[root@k8scloude1 svc]# kubectl get pod -o wide --show-labels
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
nginx-75b9846bd7-22btx 1/1 Running 0 30s 10.244.112.157 k8scloude2 <none> <none> app1=nginx1,app2=nginx2,app3=nginx3,pod-template-hash=75b9846bd7
nginx-75b9846bd7-m2pdq 1/1 Running 0 30s 10.244.112.159 k8scloude2 <none> <none> app1=nginx1,app2=nginx2,app3=nginx3,pod-template-hash=75b9846bd7
5.1 使用service服务向外界暴露pod
5.1.1 创建service服务
查看service,服务service简写为svc
[root@k8scloude1 svc]# kubectl get svc
No resources found in svc namespace.
[root@k8scloude1 svc]# kubectl get service
No resources found in svc namespace.
创建service服务建议使用命令行,而不是使用yaml文件。
svc创建语法如下:
- kubectl expose --name=名字 资源类型/名字 --port=xxx --target-port=yyy
- kubectl expose --name=名字 deploy/web1 --port=xxx --target-port=yyy
- kubectl expose --name=名字 deploy web1 --port=xxx --target-port=yyy
- kubectl expose --name=名字 pod/web1 --port=xxx --target-port=yyy
- kubectl expose --name=名字 pod web1 --port=xxx --target-port=yyy
svc具有一个负载均衡器的作用,svc本身的端口(--port=xxx)可以随意定义,svc转发到pod的端口(--target-port=yyy)不可以随意定义,需要根据容器的实际情况来定义,svc通过标签选择后端的pod。
为deploy创建一个service服务
[root@k8scloude1 svc]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 2/2 2 2 46m
[root@k8scloude1 svc]# kubectl expose --name=nginxsvc deploy nginx --port=80
service/nginxsvc exposed
[root@k8scloude1 svc]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
nginxsvc ClusterIP 10.98.213.102 <none> 80/TCP 15s app1=nginx1
如果svc没有指定使用哪个标签定位pod时,使用的标签和deploy一样。
[root@k8scloude1 svc]# kubectl get svc -o wide --show-labels
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR LABELS
nginxsvc ClusterIP 10.98.213.102 <none> 80/TCP 44s app1=nginx1 app=nginx
[root@k8scloude1 svc]# kubectl get pod -o wide --show-labels
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
nginx-75b9846bd7-22btx 1/1 Running 0 48m 10.244.112.157 k8scloude2 <none> <none> app1=nginx1,app2=nginx2,app3=nginx3,pod-template-hash=75b9846bd7
nginx-75b9846bd7-m2pdq 1/1 Running 0 48m 10.244.112.159 k8scloude2 <none> <none> app1=nginx1,app2=nginx2,app3=nginx3,pod-template-hash=75b9846bd7
删除svc
[root@k8scloude1 svc]# kubectl delete svc nginxsvc
service "nginxsvc" deleted
可以手动指定svc选择的标签
[root@k8scloude1 svc]# kubectl expose --name=nginxsvc deploy nginx --port=80 --selector=app2=nginx2
service/nginxsvc exposed
[root@k8scloude1 svc]# kubectl get svc nginxsvc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
nginxsvc ClusterIP 10.98.95.134 <none> 80/TCP 23s app2=nginx2
查看svc的描述信息,Endpoints表示svc后端定位的pod。
[root@k8scloude1 svc]# kubectl describe svc nginxsvc
Name: nginxsvc
Namespace: svc
Labels: app=nginx
Annotations: <none>
Selector: app2=nginx2
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.98.95.134
IPs: 10.98.95.134
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.112.157:80,10.244.112.159:80
Session Affinity: None
Events: <none>
[root@k8scloude1 svc]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-75b9846bd7-22btx 1/1 Running 0 57m 10.244.112.157 k8scloude2 <none> <none>
nginx-75b9846bd7-m2pdq 1/1 Running 0 57m 10.244.112.159 k8scloude2 <none> <none>
把deploy的副本数变为4
[root@k8scloude1 svc]# kubectl scale deploy nginx --replicas=4
deployment.apps/nginx scaled
[root@k8scloude1 svc]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-75b9846bd7-22btx 1/1 Running 0 58m 10.244.112.157 k8scloude2 <none> <none>
nginx-75b9846bd7-bswx2 1/1 Running 0 10s 10.244.251.248 k8scloude3 <none> <none>
nginx-75b9846bd7-kzx7h 1/1 Running 0 10s 10.244.251.249 k8scloude3 <none> <none>
nginx-75b9846bd7-m2pdq 1/1 Running 0 58m 10.244.112.159 k8scloude2 <none> <none>
Endpoints定位的pod自动变为4个
[root@k8scloude1 svc]# kubectl describe svc nginxsvc
Name: nginxsvc
Namespace: svc
Labels: app=nginx
Annotations: <none>
Selector: app2=nginx2
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.98.95.134
IPs: 10.98.95.134
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.112.157:80,10.244.112.159:80,10.244.251.248:80 + 1 more...
Session Affinity: None
Events: <none>
把deploy的副本数再次变为2
[root@k8scloude1 svc]# kubectl scale deploy nginx --replicas=2
deployment.apps/nginx scaled
Endpoints定位的pod自动变为2个
[root@k8scloude1 svc]# kubectl describe svc nginxsvc
Name: nginxsvc
Namespace: svc
Labels: app=nginx
Annotations: <none>
Selector: app2=nginx2
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.98.95.134
IPs: 10.98.95.134
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.112.157:80,10.244.251.248:80
Session Affinity: None
Events: <none>
现在手动生成一个pod,pod的标签为app2=nginx2,svc也能自动选择此pod。
[root@k8scloude1 svc]# kubectl run pod1 --image=nginx --image-pull-policy=IfNotPresent --labels="app2=nginx2"
pod/pod1 created
[root@k8scloude1 svc]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-75b9846bd7-22btx 1/1 Running 0 64m 10.244.112.157 k8scloude2 <none> <none>
nginx-75b9846bd7-bswx2 1/1 Running 0 5m58s 10.244.251.248 k8scloude3 <none> <none>
pod1 1/1 Running 0 7s 10.244.112.161 k8scloude2 <none> <none>
svc的Endpoints自动定位到该pod1
[root@k8scloude1 svc]# kubectl describe svc nginxsvc
Name: nginxsvc
Namespace: svc
Labels: app=nginx
Annotations: <none>
Selector: app2=nginx2
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.98.95.134
IPs: 10.98.95.134
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.112.157:80,10.244.112.161:80,10.244.251.248:80
Session Affinity: None
Events: <none>
删除手动创建的pod1
[root@k8scloude1 svc]# kubectl delete pod pod1 --force
warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
pod "pod1" force deleted
把deploy的副本数变为3
[root@k8scloude1 svc]# kubectl scale deploy nginx --replicas=3
deployment.apps/nginx scaled
[root@k8scloude1 svc]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-75b9846bd7-22btx 1/1 Running 0 66m 10.244.112.157 k8scloude2 <none> <none>
nginx-75b9846bd7-7q7qm 1/1 Running 0 27s 10.244.112.166 k8scloude2 <none> <none>
nginx-75b9846bd7-bswx2 1/1 Running 0 8m24s 10.244.251.248 k8scloude3 <none> <none>
5.1.2 测试svc的负载均衡
现在测试svc的负载均衡功能,看看svc能不能把流量均匀的分配给后端pod。
修改3个pod里的Nginx首页文件index.html,这样能辨别出每一个pod。
[root@k8scloude1 svc]# kubectl exec -it nginx-75b9846bd7-22btx -- sh -c "echo 111 >/usr/share/nginx/html/index.html"
[root@k8scloude1 svc]# kubectl exec -it nginx-75b9846bd7-7q7qm -- sh -c "echo 222 >/usr/share/nginx/html/index.html"
[root@k8scloude1 svc]# kubectl exec -it nginx-75b9846bd7-bswx2 -- sh -c "echo 333 >/usr/share/nginx/html/index.html"
svc的地址在集群内部可以访问,访问svc,可以看到svc具有负载均衡的作用,分别转发给了后端三个pod
[root@k8scloude1 svc]# while true ;do curl -s 10.98.95.134:80;sleep 1;done
222
111
111
222
333
333
222
值得注意的是:ping不通svc的地址,但是可以telnet svc地址和80端口,因为svc只开放了端口80。
kube-proxy模式默认是iptables,如果kube-proxy模式为iptables时,在集群内部,ping不通svc的地址,但是如果kube-proxy模式为ipvs时,则能ping通svc的地址
。
#ping不通svc的地址
[root@k8scloude1 svc]# ping 10.98.95.134
PING 10.98.95.134 (10.98.95.134) 56(84) bytes of data.
^C
--- 10.98.95.134 ping statistics ---
18 packets transmitted, 0 received, 100% packet loss, time 17001ms
#可以telnet svc的地址
[root@k8scloude1 svc]# telnet 10.98.95.134 80
Trying 10.98.95.134...
Connected to 10.98.95.134.
Escape character is '^]'.
^CConnection closed by foreign host.
删除deploy
[root@k8scloude1 svc]# ls
nginxdeploy.yaml
[root@k8scloude1 svc]# kubectl delete -f nginxdeploy.yaml
deployment.apps "nginx" deleted
[root@k8scloude1 svc]# kubectl get pod
No resources found in svc namespace.
六.service服务的发现
什么是服务的发现?创建了一个svc之后,pod怎么发现服务svc,这就是服务的发现。
服务的发现有三种方式:1.clusterIP 2.变量的方式 3.DNS。
下面进行逐一讲述。
6.1 使用clusterIP的方式进行服务发现
我们之前所创建的应用都比较单一,现在创建多级应用,使用wordpress镜像和mysql镜像搭建博客。以往还介绍了使用docker搭建博客的案例,详情请查看博客《使用docker 5分钟搭建一个博客(mysql+WordPress)》。
先在kubernetes集群的worker节点拉取mysql镜像和WordPress镜像。
[root@k8scloude2 ~]# docker pull hub.c.163.com/library/wordpress:latest
[root@k8scloude2 ~]# docker pull hub.c.163.com/library/mysql:latest
[root@k8scloude3 ~]# docker pull hub.c.163.com/library/wordpress:latest
[root@k8scloude3 ~]# docker pull hub.c.163.com/library/mysql:latest
生成创建pod的yaml文件,使用hub.c.163.com/library/mysql:latest镜像创建pod。
[root@k8scloude1 svc]# kubectl run mysqlpod --image=hub.c.163.com/library/mysql:latest --image-pull-policy=IfNotPresent --dry-run=client -o yaml > mysqlpod.yaml
修改yaml文件,设置mysql的环境变量(root密码,MySQL用户,MySQL用户密码,要使用的MySQL数据库名)。
[root@k8scloude1 svc]# vim mysqlpod.yaml
[root@k8scloude1 svc]# cat mysqlpod.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: mysqlpod
name: mysqlpod
spec:
#当需要关闭容器时,立即杀死容器而不等待默认的30秒优雅停机时长。
terminationGracePeriodSeconds: 0
containers:
- image: hub.c.163.com/library/mysql:latest
#imagePullPolicy: IfNotPresent:表示如果本地已经存在该镜像,则不重新下载;否则从远程 Docker Hub 下载该镜像
imagePullPolicy: IfNotPresent
name: mysqlpod
resources: {}
env:
#root密码
- name: MYSQL_ROOT_PASSWORD
value: rootmima
#MySQL用户
- name: MYSQL_USER
value: lisi
#MySQL用户密码
- name: MYSQL_PASSWORD
value: lisimim
#要使用的MySQL数据库名
- name: MYSQL_DATABASE
value: wordpress
#dnsPolicy: ClusterFirst 表示Pod使用集群的DNS解析服务来解析域名。
dnsPolicy: ClusterFirst
#restartPolicy: Always 表示容器退出后总是重新启动。
restartPolicy: Always
status: {}
创建pod
[root@k8scloude1 svc]# kubectl apply -f mysqlpod.yaml
pod/mysqlpod created
[root@k8scloude1 svc]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mysqlpod 1/1 Running 0 8s 10.244.112.163 k8scloude2 <none> <none>
pod创建好之后,创建pod的svc,--port=3306指定svc端口,--target-port=3306指定mysql容器端口。
[root@k8scloude1 svc]# kubectl expose --name=mysqlsvc pod mysqlpod --port=3306 --target-port=3306
service/mysqlsvc exposed
查看svc
[root@k8scloude1 svc]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
mysqlsvc ClusterIP 10.104.58.98 <none> 3306/TCP 13s run=mysqlpod
nginxsvc ClusterIP 10.98.95.134 <none> 80/TCP 8h app2=nginx2
接下来创建wordpress。yaml配置文件功能为:创建名为wordpresspod的pod,使用hub.c.163.com/library/wordpress:latest镜像,设置wordpress的环境变量,用于连接 MySQL 数据库,分别指定了MySQL数据库地址、MySQL数据库用户名、MySQL数据库密码和数据库名称。
WORDPRESS_DB_HOST数据库地址这里填mysql svc的ClusterIP,这是通过clusterIP进行服务发现。
[root@k8scloude1 svc]# vim wordpresspod.yaml
[root@k8scloude1 svc]# cat wordpresspod.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: wordpresspod
name: wordpresspod
spec:
#当需要关闭容器时,立即杀死容器而不等待默认的30秒优雅停机时长。
terminationGracePeriodSeconds: 0
containers:
- image: hub.c.163.com/library/wordpress:latest
#imagePullPolicy: IfNotPresent:表示如果本地已经存在该镜像,则不重新下载;否则从远程 Docker Hub 下载该镜像
imagePullPolicy: IfNotPresent
name: wordpresspod
resources: {}
#设置wordpress的变量
env:
#MySQL数据库地址,WORDPRESS_DB_HOST数据库地址这里填mysql svc的ClusterIP
- name: WORDPRESS_DB_HOST
value: 10.104.58.98
#MySQL数据库用户名
- name: WORDPRESS_DB_USER
value: lisi
#MySQL数据库密码
- name: WORDPRESS_DB_PASSWORD
value: lisimim
#数据库名称
- name: WORDPRESS_DB_NAME
value: wordpress
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
创建wordpresspod
[root@k8scloude1 svc]# kubectl apply -f wordpresspod.yaml
pod/wordpresspod created
[root@k8scloude1 svc]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mysqlpod 1/1 Running 0 13m 10.244.112.163 k8scloude2 <none> <none>
wordpresspod 1/1 Running 0 9s 10.244.251.255 k8scloude3 <none> <none>
给wordpresspod创建一个svc用于外界访问wordpress,--type=NodePort用于服务发布,这样外界就可以访问此svc服务。
[root@k8scloude1 svc]# kubectl expose --name=wordpresssvc pod wordpresspod --port=80 --type=NodePort
service/wordpresssvc exposed
查看svc,80:31860/TCP 把pod的80 端口映射到物理机的31860端口,访问物理机的31860端口就可访问wordpress,如下所示:
[root@k8scloude1 svc]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
mysqlsvc ClusterIP 10.104.58.98 <none> 3306/TCP 14m run=mysqlpod
nginxsvc ClusterIP 10.98.95.134 <none> 80/TCP 8h app2=nginx2
wordpresssvc NodePort 10.107.76.238 <none> 80:31860/TCP 8s run=wordpresspod
浏览器访问kubernetes集群任意节点IP+端口31860,就可访问wordpress页面,访问http://192.168.110.128:31860,语言选择简体中文,点击继续。
设置站点标题,用户名,密码,email,安装WordPress。
WordPress安装成功之后,点击登录。
根据你设置的账号进行登录。
此时个人博客就搭建完毕了。
6.2 使用环境变量的方式进行服务发现
上面是通过clusterIP进行服务发现,下面使用环境变量的方式进行服务发现。
现在有两个pod
[root@k8scloude1 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mysqlpod 1/1 Running 0 63m 10.244.112.163 k8scloude2 <none> <none>
wordpresspod 1/1 Running 0 50m 10.244.251.255 k8scloude3 <none> <none>
进入wordpresspod里,使用env查看pod里的环境变量,可以看到里面有很多环境变量。
[root@k8scloude1 ~]# kubectl exec -it wordpresspod -- bash
#使用env查看pod里的环境变量
root@wordpresspod:/var/www/html# env
NGINXSVC_PORT_80_TCP_PROTO=tcp
......
PWD=/var/www/html
MYSQLSVC_PORT_3306_TCP_PORT=3306
MYSQLSVC_PORT=tcp://10.104.58.98:3306
NGINXSVC_PORT_80_TCP_ADDR=10.98.95.134
NGINXSVC_SERVICE_PORT=80
MYSQLSVC_PORT_3306_TCP_ADDR=10.104.58.98
MYSQLSVC_PORT_3306_TCP_PROTO=tcp
NGINXSVC_PORT_80_TCP=tcp://10.98.95.134:80
NGINXSVC_PORT=tcp://10.98.95.134:80
WORDPRESS_DB_USER=lisi
......
root@wordpresspod:/var/www/html# exit
exit
pod会以环境变量的方式去记录服务svc的信息,格式为:大写服务名_SERVICE_HOST=服务的IP ; 大写服务名_SERVICE_PORT=服务的端口,wordpress连接的mysql svc为mysqlsvc。MYSQLSVC_SERVICE_HOST为mysql svc的IP地址。
注意:pod创建之后会自动记录之前的存在的svc信息,在pod之后创建的svc信息不自动记录。
[root@k8scloude1 ~]# kubectl exec -it wordpresspod -- bash
root@wordpresspod:/var/www/html# env | grep -i mysqlsvc
MYSQLSVC_SERVICE_HOST=10.104.58.98
MYSQLSVC_PORT_3306_TCP_PORT=3306
MYSQLSVC_PORT=tcp://10.104.58.98:3306
MYSQLSVC_PORT_3306_TCP_ADDR=10.104.58.98
MYSQLSVC_PORT_3306_TCP_PROTO=tcp
MYSQLSVC_SERVICE_PORT=3306
MYSQLSVC_PORT_3306_TCP=tcp://10.104.58.98:3306
root@wordpresspod:/var/www/html# exit
exit
现在一个mysql的pod和svc,一个wordpress的pod和svc
[root@k8scloude1 ~]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
mysqlsvc ClusterIP 10.104.58.98 <none> 3306/TCP 71m run=mysqlpod
nginxsvc ClusterIP 10.98.95.134 <none> 80/TCP 9h app2=nginx2
wordpresssvc NodePort 10.107.76.238 <none> 80:31860/TCP 57m run=wordpresspod
[root@k8scloude1 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mysqlpod 1/1 Running 0 74m 10.244.112.163 k8scloude2 <none> <none>
wordpresspod 1/1 Running 0 61m 10.244.251.255 k8scloude3 <none> <none>
删除wordpresspod
[root@k8scloude1 ~]# kubectl delete pod wordpresspod --force
warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
pod "wordpresspod" force deleted
[root@k8scloude1 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mysqlpod 1/1 Running 0 75m 10.244.112.163 k8scloude2 <none> <none>
修改wordpresspod的yaml文件,设置wordpress的环境变量,用于连接 MySQL 数据库,分别指定了MySQL数据库地址、MySQL数据库用户名、MySQL数据库密码和数据库名称。
WORDPRESS_DB_HOST数据库地址这里填mysql svc的环境变量WORDPRESS_DB_HOST,这是通过环境变量进行服务发现。
[root@k8scloude1 ~]# cd svc/
[root@k8scloude1 svc]# pwd
/root/svc
[root@k8scloude1 svc]# vim wordpresspod.yaml
[root@k8scloude1 svc]# cat wordpresspod.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: wordpresspod
name: wordpresspod
spec:
#当需要关闭容器时,立即杀死容器而不等待默认的30秒优雅停机时长。
terminationGracePeriodSeconds: 0
containers:
- image: hub.c.163.com/library/wordpress:latest
#imagePullPolicy: IfNotPresent:表示如果本地已经存在该镜像,则不重新下载;否则从远程 Docker Hub 下载该镜像
imagePullPolicy: IfNotPresent
name: wordpresspod
resources: {}
env:
#MySQL数据库地址,WORDPRESS_DB_HOST数据库地址这里填mysql svc的环境变量
- name: WORDPRESS_DB_HOST
#使用变量的方式
value: $(MYSQLSVC_SERVICE_HOST)
#MySQL数据库用户名
- name: WORDPRESS_DB_USER
value: lisi
#MySQL数据库密码
- name: WORDPRESS_DB_PASSWORD
value: lisimim
#数据库名称
- name: WORDPRESS_DB_NAME
value: wordpress
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
创建wordpresspod,这时候一切又正常了,搭建的博客又可以正常工作了。
此时浏览器访问http://192.168.110.128:31860/,即可访问wordpress。
[root@k8scloude1 svc]# kubectl apply -f wordpresspod.yaml
pod/wordpresspod created
[root@k8scloude1 svc]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mysqlpod 1/1 Running 0 79m 10.244.112.163 k8scloude2 <none> <none>
wordpresspod 1/1 Running 0 6s 10.244.112.162 k8scloude2 <none> <none>
[root@k8scloude1 svc]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
mysqlsvc ClusterIP 10.104.58.98 <none> 3306/TCP 76m run=mysqlpod
nginxsvc ClusterIP 10.98.95.134 <none> 80/TCP 9h app2=nginx2
wordpresssvc NodePort 10.107.76.238 <none> 80:31860/TCP 62m run=wordpresspod
通过环境变量的方式进行服务发现,存在缺陷如下:
- 只能获取相同namespace里的变量;
- 变量的获取有先后顺序,引用的变量必须要先创建。
6.3 使用DNS的方式进行服务发现(推荐)
Kubernetes 中的 DNS 服务是一个专门的服务,用于为 Pod 提供服务发现功能。当我们创建一个 service 时,Kubernetes 会自动为该 service 创建一个 DNS 记录。这个 DNS 记录中包含了该 service 的名称、IP 地址以及端口信息。当一个 Pod 需要访问该 service 时,它可以通过该 service 的名称来查找该 DNS 记录,并将该名称解析为一个 IP 地址。这样,该 Pod 就可以直接通过该 IP 地址来访问该 service。
kube-dns记录了集群的DNS信息,svc创建好之后会向kube-dns进行注册,等以后pod想通过服务名直接访问svc时,会向kube-dns查询svc的IP地址,kube-dns把查到的svc地址返回给pod,pod就可访问svc。
[root@k8scloude1 svc]# kubectl get svc -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 32d
metrics-server ClusterIP 10.97.8.134 <none> 443/TCP 31d
如何查询到kube-dns这个svc对应的pod?使用标签查找。
先查看svc选择的标签为k8s-app=kube-dns。
[root@k8scloude1 svc]# kubectl get svc -n kube-system -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 32d k8s-app=kube-dns
metrics-server ClusterIP 10.97.8.134 <none> 443/TCP 31d k8s-app=metrics-server
通过标签k8s-app=kube-dns定位到pod
[root@k8scloude1 svc]# kubectl get pod -A -o wide -l k8s-app=kube-dns
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-system coredns-545d6fc579-7wm95 1/1 Running 21 32d 10.244.158.109 k8scloude1 <none> <none>
kube-system coredns-545d6fc579-87q8j 1/1 Running 21 32d 10.244.158.110 k8scloude1 <none> <none>
删除svc,重新给wordpress创建svc
[root@k8scloude1 svc]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
mysqlsvc ClusterIP 10.104.58.98 <none> 3306/TCP 164m run=mysqlpod
nginxsvc ClusterIP 10.98.95.134 <none> 80/TCP 11h app2=nginx2
wordpresssvc NodePort 10.107.76.238 <none> 80:31860/TCP 151m run=wordpresspod
[root@k8scloude1 svc]# kubectl delete svc wordpresssvc
service "wordpresssvc" deleted
[root@k8scloude1 ~]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
mysqlsvc ClusterIP 10.104.58.98 <none> 3306/TCP 15h run=mysqlpod
nginxsvc ClusterIP 10.98.95.134 <none> 80/TCP 24h app2=nginx2
[root@k8scloude1 ~]# kubectl expose --name=wordpresssvc pod wordpresspod --port=80 --type=NodePort
service/wordpresssvc exposed
[root@k8scloude1 ~]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
mysqlsvc ClusterIP 10.104.58.98 <none> 3306/TCP 15h run=mysqlpod
nginxsvc ClusterIP 10.98.95.134 <none> 80/TCP 24h app2=nginx2
wordpresssvc NodePort 10.100.99.82 <none> 80:32729/TCP 9s run=wordpresspod
使用Nginx镜像创建一个nginx pod。
[root@k8scloude1 svc]# cat pod.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
test: podtest
name: podtest
spec:
#当需要关闭容器时,立即杀死容器而不等待默认的30秒优雅停机时长。
terminationGracePeriodSeconds: 0
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
[root@k8scloude1 svc]# kubectl apply -f pod.yaml
pod/podtest created
查看pod
[root@k8scloude1 svc]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mysqlpod 1/1 Running 1 15h 10.244.112.168 k8scloude2 <none> <none>
podtest 1/1 Running 0 9s 10.244.251.195 k8scloude3 <none> <none>
wordpresspod 1/1 Running 1 14h 10.244.112.164 k8scloude2 <none> <none>
修改pod里的index.html文件,把index.html内容修改为111。
[root@k8scloude1 svc]# kubectl exec -it podtest -- sh -c "echo 111 > /usr/share/nginx/html/index.html"
给podtest创建svc服务
[root@k8scloude1 svc]# kubectl expose --name=podtestsvc pod podtest --port=80
service/podtestsvc exposed
[root@k8scloude1 svc]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
mysqlsvc ClusterIP 10.104.58.98 <none> 3306/TCP 15h run=mysqlpod
nginxsvc ClusterIP 10.98.95.134 <none> 80/TCP 24h app2=nginx2
podtestsvc ClusterIP 10.108.102.183 <none> 80/TCP 7s test=podtest
wordpresssvc NodePort 10.100.99.82 <none> 80:32729/TCP 8m23s run=wordpresspod
--rm表示创建一个临时pod,退出pod就会自动删除pod。
创建名为clientpod的临时pod作为客户端,去访问其他svc,首先访问podtestsvc。
[root@k8scloude1 svc]# kubectl run clientpod --image=nginx --image-pull-policy=IfNotPresent -it --rm -- bash
If you don't see a command prompt, try pressing enter.
#直接访问svc就可访问服务
root@clientpod:/# curl podtestsvc
111
root@clientpod:/# exit
exit
Session ended, resume using 'kubectl attach clientpod -c clientpod -i -t' command when the pod is running
pod "clientpod" deleted
-n default:表示进入pod后,自动切换为default命名空间,继续访问podtestsvc。
[root@k8scloude1 svc]# kubectl run clientpod --image=nginx --image-pull-policy=IfNotPresent -it --rm -n default -- bash
If you don't see a command prompt, try pressing enter.
#因为是在default命名空间里访问svc命名空间里的服务,所以访问失败
root@clientpod:/# curl podtestsvc
curl: (6) Could not resolve host: podtestsvc
#需要指定svc命名空间
root@clientpod:/# curl podtestsvc.svc
111
#查看pod里DNS信息:nameserver 10.96.0.10对应的就是kube-dns的IP
root@clientpod:/# cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
root@clientpod:/# exit
exit
Session ended, resume using 'kubectl attach clientpod -c clientpod -i -t' command when the pod is running
pod "clientpod" deleted
删除wordpresspod,重新创建。
[root@k8scloude1 svc]# kubectl delete pod wordpresspod --force
warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
pod "wordpresspod" force deleted
[root@k8scloude1 svc]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mysqlpod 1/1 Running 1 16h 10.244.112.168 k8scloude2 <none> <none>
podtest 1/1 Running 0 10m 10.244.251.195 k8scloude3 <none> <none>
修改wordpresspod的yaml文件,设置wordpress的环境变量,用于连接 MySQL 数据库,分别指定了MySQL数据库地址、MySQL数据库用户名、MySQL数据库密码和数据库名称。
WORDPRESS_DB_HOST数据库地址这里直接填mysql svc的名称mysqlsvc,这是通过DNS进行服务发现。
[root@k8scloude1 svc]# vim wordpresspod.yaml
[root@k8scloude1 svc]# cat wordpresspod.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: wordpresspod
name: wordpresspod
spec:
#当需要关闭容器时,立即杀死容器而不等待默认的30秒优雅停机时长。
terminationGracePeriodSeconds: 0
containers:
- image: hub.c.163.com/library/wordpress:latest
#imagePullPolicy: IfNotPresent:表示如果本地已经存在该镜像,则不重新下载;否则从远程 Docker Hub 下载该镜像
imagePullPolicy: IfNotPresent
name: wordpresspod
resources: {}
#设置wordpress的变量
env:
#MySQL数据库地址,WORDPRESS_DB_HOST数据库地址这里直接填mysql svc的名称mysqlsvc
- name: WORDPRESS_DB_HOST
#使用DNS的方式
value: mysqlsvc
#MySQL数据库用户名
- name: WORDPRESS_DB_USER
value: lisi
#MySQL数据库密码
- name: WORDPRESS_DB_PASSWORD
value: lisimim
#数据库名称
- name: WORDPRESS_DB_NAME
value: wordpress
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
创建wordpresspod,这时候一切又正常了,搭建的博客又可以正常工作了。
此时浏览器访问http://192.168.110.128:32632/,即可访问wordpress。
[root@k8scloude1 svc]# kubectl apply -f wordpresspod.yaml
pod/wordpresspod created
[root@k8scloude1 svc]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mysqlpod 1/1 Running 1 16h 10.244.112.168 k8scloude2 <none> <none>
wordpresspod 1/1 Running 0 10s 10.244.251.198 k8scloude3 <none> <none>
[root@k8scloude1 svc]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
mysqlsvc ClusterIP 10.104.58.98 <none> 3306/TCP 16h run=mysqlpod
nginxsvc ClusterIP 10.98.95.134 <none> 80/TCP 24h app2=nginx2
wordpresssvc NodePort 10.109.31.167 <none> 80:32632/TCP 4m42s run=wordpresspod
删除pod和svc
[root@k8scloude1 svc]# kubectl delete pod mysqlpod wordpresspod --force
warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
pod "mysqlpod" force deleted
pod "wordpresspod" force deleted
[root@k8scloude1 svc]# kubectl delete svc mysqlsvc nginxsvc wordpresssvc
service "mysqlsvc" deleted
service "nginxsvc" deleted
service "wordpresssvc" deleted
[root@k8scloude1 svc]# kubectl get pod -o wide
No resources found in svc namespace.
[root@k8scloude1 svc]# kubectl get svc -o wide
No resources found in svc namespace.
七.service服务的发布
在Kubernetes中,服务发布是指将应用程序或服务对外部公开,以便其他应用程序或用户可以访问它们。简而言之服务发布就是使外界能访问svc。
Kubernetes集群中的服务可以使用三种不同的类型进行发布和暴露:ClusterIP,NodePort以及LoadBalancer:
-
ClusterIP:ClusterIP是最常见的服务发布类型,它将Pod暴露给集群内部,并通过集群内部的DNS进行发现。这意味着只有在同一Kubernetes集群内的其他Pod才能访问该服务,而外部客户端无法访问。ClusterIP类型的服务通常用于基于微服务架构的应用程序内部通信。
-
NodePort:使用NodePort类型的服务可以公开一个Pod,以便从集群外部访问。当您创建一个NodePort类型的服务时,Kubernetes会在每个节点上公开一个随机端口。通过此端口,来自集群外部的客户端可以访问此服务。NodePort类型的服务通常用于测试、开发和小型生产环境。
-
LoadBalancer:LoadBalancer类型的服务可以公开一个Pod,以便从外部负载平衡器访问。当您创建一个LoadBalancer类型的服务时,Kubernetes会为其分配一个外部IP地址,并配置外部负载平衡器以将流量路由到该地址。LoadBalancer类型的服务通常用于生产环境中需要大规模处理流量的应用程序。
-
除了这三种类型之外,还有一种称为ExternalName的特殊类型。使用ExternalName类型的服务可以将一个Kubernetes服务映射到集群外部的DNS名称。这种类型的服务通常用于需要访问集群外部资源的应用程序,例如外部数据库或Web服务。
注意:service在哪个节点上运行这种说法是错误的,service是抽象的,不存在在哪个节点上运行。
除了使用NodePort,LoadBalancer进行服务的发布以外,还有一种更灵活,功能更多的发布方式,就是使用Ingress来发布Kubernetes服务,详情请查看博客《Kubernetes(k8s)使用ingress发布服务》。
7.1 使用nodeport进行服务的发布
先弄清楚几个参数:NodePort是svc映射到物理机的端口,port是svc的端口,target-port是pod容器里的端口,hostport是pod映射到物理机的端口。
7.1.1 使用kubectl edit修改服务类型为NodePort
使用Nginx镜像创建一个pod。
[root@k8scloude1 svc]# cat pod.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
test: podtest
name: podtest
spec:
#当需要关闭容器时,立即杀死容器而不等待默认的30秒优雅停机时长。
terminationGracePeriodSeconds: 0
containers:
- name: nginx
image: nginx
#imagePullPolicy: IfNotPresent:表示如果本地已经存在该镜像,则不重新下载;否则从远程 Docker Hub 下载该镜像
imagePullPolicy: IfNotPresent
#创建一个nginx pod
[root@k8scloude1 svc]# kubectl apply -f pod.yaml
pod/podtest created
给pod创建svc
[root@k8scloude1 svc]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
podtest 1/1 Running 0 26s 10.244.112.169 k8scloude2 <none> <none>
[root@k8scloude1 svc]# kubectl expose --name=podtestsvc pod podtest --port=80
service/podtestsvc exposed
[root@k8scloude1 svc]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
podtestsvc ClusterIP 10.100.92.123 <none> 80/TCP 6s test=podtest
直接编辑svc:把type: ClusterIP改为type: NodePort。
[root@k8scloude1 svc]# kubectl edit svc podtestsvc
service/podtestsvc edited
把type: ClusterIP改为type: NodePort之后,svc类型就变了,此时svc的发布类型已经改变,在浏览器访问物理机IP:30908,即可访问svc服务。
[root@k8scloude1 svc]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
podtestsvc NodePort 10.100.92.123 <none> 80:30908/TCP 3m39s test=podtest
浏览器访问192.168.110.129:30908,即可成功访问Nginx。
要恢复svc的发布类型,直接把type: NodePort 改为type: ClusterIP即可。
[root@k8scloude1 svc]# kubectl edit svc podtestsvc
service/podtestsvc edited
此时svc发布类型又变为ClusterIP了。
[root@k8scloude1 svc]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
podtestsvc ClusterIP 10.100.92.123 <none> 80/TCP 7m28s test=podtest
删除svc
[root@k8scloude1 svc]# kubectl delete svc podtestsvc
service "podtestsvc" deleted
7.1.2 使用type指定服务类型为NodePort
也可以使用命令行的方式指定svc的发布类型为NodePort。
[root@k8scloude1 svc]# kubectl expose --name=podtestsvc pod podtest --port=80 --type=NodePort
service/podtestsvc exposed
现在svc类型为NodePort
[root@k8scloude1 svc]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
podtestsvc NodePort 10.97.91.78 <none> 80:31596/TCP 2s test=podtest
删除svc
[root@k8scloude1 svc]# kubectl delete svc podtestsvc
service "podtestsvc" deleted
注意:NodePort的svc发布类型存在一定问题:
- NodePort映射的端口越多,漏洞越大;
- NodePort端口太多维护困难。
7.2 使用LoadBalancer的方式进行服务的发布
7.2.1 安装METALLB
使用LoadBalancer的方式进行服务发布,需要借助第三方的工具(METALLB)。
每个svc都有一个私有地址,只能在集群内部访问,如果我们把svc的类型设置为LoadBalancer,则svc会获取到一个外部IP,这个外部IP来自地址池,本文使用METALLB配置地址池。
METALLB的官网如下:https://metallb.universe.tf/
查看MetalLB的安装方式,Installation MetalLB By Manifest。
创建metallb的namespace
[root@k8scloude1 svc]# kubectl create ns metallb-system
namespace/metallb-system created
下载metallb的安装文件
[root@k8scloude1 svc]# wget https://raw.githubusercontent.com/metallb/metallb/v0.11.0/manifests/metallb.yaml
[root@k8scloude1 svc]# wget https://raw.githubusercontent.com/metallb/metallb/v0.11.0/manifests/namespace.yaml
[root@k8scloude1 svc]# ls
metallb.yaml namespace.yaml
查看metallb需要的镜像
[root@k8scloude1 svc]# grep image metallb.yaml
image: quay.io/metallb/speaker:v0.11.0
image: quay.io/metallb/controller:v0.11.0
修改metallb.yaml 文件,修改metallb.yaml里的镜像下载策略为IfNotPresent,表示如果本地已经存在该镜像,则不重新下载;否则从远程仓库下载该镜像。
[root@k8scloude1 svc]# vim metallb.yaml
[root@k8scloude1 svc]# cat metallb.yaml | grep image
image: quay.io/metallb/speaker:v0.11.0
imagePullPolicy: IfNotPresent
image: quay.io/metallb/controller:v0.11.0
imagePullPolicy: IfNotPresent
在worker节点提前下载speaker和controller镜像。
[root@k8scloude2 ~]# docker pull quay.io/metallb/speaker:v0.11.0
[root@k8scloude2 ~]# docker pull quay.io/metallb/controller:v0.11.0
[root@k8scloude2 ~]# docker images | grep metallb
quay.io/metallb/speaker v0.11.0 896b796b12bb 3 months ago 50.2MB
quay.io/metallb/controller v0.11.0 85a7890eec45 3 months ago 46.5MB
[root@k8scloude3 ~]# docker pull quay.io/metallb/speaker:v0.11.0
[root@k8scloude3 ~]# docker pull quay.io/metallb/controller:v0.11.0
[root@k8scloude3 ~]# docker images | grep metallb
quay.io/metallb/speaker v0.11.0 896b796b12bb 3 months ago 50.2MB
quay.io/metallb/controller v0.11.0 85a7890eec45 3 months ago 46.5MB
应用命名空间文件,安装metallb。
[root@k8scloude1 svc]# kubectl apply -f namespace.yaml
Warning: resource namespaces/metallb-system is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
namespace/metallb-system configured
[root@k8scloude1 svc]# kubectl apply -f metallb.yaml
Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
podsecuritypolicy.policy/controller created
podsecuritypolicy.policy/speaker created
......
rolebinding.rbac.authorization.k8s.io/config-watcher created
rolebinding.rbac.authorization.k8s.io/pod-lister created
rolebinding.rbac.authorization.k8s.io/controller created
daemonset.apps/speaker created
deployment.apps/controller created
查看pod,可以看到metallb安装成功。
[root@k8scloude1 svc]# kubectl get pod -n metallb-system -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
controller-7dcc8764f4-qdwl2 1/1 Running 0 2m41s 10.244.112.160 k8scloude2 <none> <none>
speaker-892pm 1/1 Running 0 2m41s 192.168.110.128 k8scloude3 <none> <none>
speaker-jfccb 1/1 Running 0 2m41s 192.168.110.130 k8scloude1 <none> <none>
speaker-nkrgk 1/1 Running 0 2m41s 192.168.110.129 k8scloude2 <none> <none>
7.2.2 配置地址池
查看配置地址池的yaml文件。
接下来配置地址池,地址池的IP范围为:192.168.110.188-192.168.110.250
[root@k8scloude1 svc]# vim ipaddrpool.yaml
[root@k8scloude1 svc]# cat ipaddrpool.yaml
apiVersion: v1
kind: ConfigMap
metadata:
namespace: metallb-system
name: config
data:
config: |
address-pools:
- name: default
protocol: layer2
#地址池的IP范围
addresses:
- 192.168.110.188-192.168.110.250
创建地址池
[root@k8scloude1 svc]# kubectl apply -f ipaddrpool.yaml
configmap/config created
[root@k8scloude1 svc]# kubectl get configmap -o wide
NAME DATA AGE
kube-root-ca.crt 1 35h
7.2.3 使用LoadBalancer的方式进行服务发布
现在podtest没有svc,给podtest创建svc,类型为LoadBalancer。
[root@k8scloude1 svc]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
podtest 1/1 Running 0 148m 10.244.112.169 k8scloude2 <none> <none>
[root@k8scloude1 svc]# kubectl get svc -o wide
No resources found in svc namespace.
[root@k8scloude1 svc]# kubectl expose --name=podtestsvc pod podtest --port=80 --type=LoadBalancer
service/podtestsvc exposed
查看svc,EXTERNAL-IP地址是从地址池里分配的。
[root@k8scloude1 svc]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
podtestsvc LoadBalancer 10.97.238.10 192.168.110.188 80:30725/TCP 3s test=podtest
浏览器直接访问外部IP即可访问svc服务:http://192.168.110.188/ 。
再给podtest创建一个svc,类型还是LoadBalancer。
[root@k8scloude1 svc]# kubectl expose --name=podtestsvc2 pod podtest --port=80 --type=LoadBalancer
service/podtestsvc2 exposed
[root@k8scloude1 svc]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
podtestsvc LoadBalancer 10.97.238.10 192.168.110.188 80:30725/TCP 5m3s test=podtest
podtestsvc2 LoadBalancer 10.96.128.89 192.168.110.189 80:32644/TCP 5s test=podtest
浏览器直接访问外部IP即可访问svc服务:http://192.168.110.189/。
删除svc。
[root@k8scloude1 svc]# kubectl delete svc podtestsvc podtestsvc2
service "podtestsvc" deleted
service "podtestsvc2" deleted
[root@k8scloude1 svc]# kubectl get svc -o wide
No resources found in svc namespace.
[root@k8scloude1 svc]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
podtest 1/1 Running 0 159m 10.244.112.169 k8scloude2 <none> <none>