如果读者按照前面的流程建好了服务,那么应该会有一个问题困扰,如何访问这个nginx服务呢?
首先查看服务的信息,执行命令kubectl describe pods static-web
Name: static-web
Namespace: default
Priority: 0
PriorityClassName: <none>
Node: ip/ip
Start Time: Fri, 15 Jan 2021 15:50:16 +0800
Labels: role=myrole
Annotations: kubectl.kubernetes.io/
Status: Running
IP: ip这里有两个ip。一个是Node的ip,一个是自己的IP。从我们之前的构建文件来看,暴露的端口是80,所以我们用curl来试试。
先使用Node的ip。你会发现,访问失败了。
再使用IP,你会发现访问成功了。
换一个场景来看,我们使用集群外部的机器来访问,你会发现,两个IP都无法访问。
这就是一个非常蛋疼的点了。集群内部,可以正常访问,集群外部,无法访问。
但是我们很多时候,是需要在集群外部访问我们的服务。
常规的来说,外部访问k8s的流程是,请求到k8s的service或者,然后节点转发给Pods。
为什么这么设计呢,官方的说法是:
创建和销毁 Kubernetes Pod 以匹配集群状态。 Pod 是非永久性资源。 如果你使用 Deployment 来运行你的应用程序,则它可以动态创建和销毁 Pod。 每个 Pod 都有自己的 IP 地址,但是在 Deployment 中,在同一时刻运行的 Pod 集合可能与稍后运行该应用程序的 Pod 集合不同。
这导致了一个问题: 如果一组 Pod(称为“后端”)为集群内的其他 Pod(称为“前端”)提供功能, 那么前端如何找出并跟踪要连接的 IP 地址,以便前端可以使用工作量的后端部分?
进入 Services。
所以想要外部来访问,我们就需要创建一个service。
apiVersion: v1
kind: Service
metadata:
name: nginx-service
labels:
role: myrole
spec:
ports:
- name: nginx
port: 80
targetPort: 80
nodePort: 30002
selector:
role: myrole
type: NodePort在客户端执行kubectl apply -f nginx-service.yaml
执行完毕后,就会创建一个service,这个service有一个selector,通过selector绑定标签为role: myrole。然后指定nodePort端口是30002,表示node对外暴露的端口是30002,targetPort是80,表示30002端口收到请求之后,把请求转发到绑定的Pods的80端口。
执行命令:kubectl get services,可以看到这样的输出:
kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service NodePort ip <none> 80:30002/TCP 3h7m表示这个service已经建立好了,并且80端口和30002端口做了映射。
这个时候,我们在集群外部再来请求,这个时候请求的是Node的IP和30002端口。你会发现,请求成功了,返回了Nginx的欢迎页面的html代码
为了更方便的理解,我们这里还是以docker对照来说明。
一开始,我们使用k8s创建一个nginx服务,就类似用docker起一个nginx容器,正常起的nginx容器,由于没有做端口映射,就会出现服务提供了80端口,容器内部curl是能正常访问的,但是外部无法访问的情况。
对于docker来说,我们不需要创建service,而是在启动容器的时候,使用-p 8000:80参数,则会把宿主机的8000端口映射到容器的80端口。
同理,k8s中的service也提供了这样类似的功能(当然,service提供的功能不止这些)。
当然,由于nginx使用的http是七层协议,还可以使用Ingress来实现类似的功能。后续再来描述这块功能。