一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第23天,点击查看活动详情。
在开发阶段或是临时应用,如果想要外部客户端访问集群服务,最常用的方式就是 NodePort Service。
NodePort Service 是在 ClusterIP Service 的基础上,为 Service 在集群所有 Node 节点上绑定一个端口,外部客户端通过 nodeIP:nodePort 就可以访问服务。
在定义 YAML 文件时需要:
spec.type: 设置值为NodePortspec.ports.nodePort: 设置在Node节点上开发的端口号
修改 nginx-deployment.yaml 文件,并向其中写入如下代码:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80 # 指定开放 80 端口
执行创建:
# 如果提示存在先 delete
$ kubeclt create -f nginx-deployment.yaml
deployment.apps/nginx created
在 /home/shiyanlou 目录下新建 nginx-service-nodeport.yaml 文件,并向其中写入如下代码:
apiVersion: v1
kind: Service
metadata:
name: nginx-service-nodeport
spec:
type: NodePort
ports:
- port: 80 # 设置 ClusterIP 对应的端口为 80
targetPort: 80 # Pod 开放的端口为 80
nodePort: 31000 # 设置在 Node 上开放的端口为 31000
selector:
app: nginx
注意:nodePort 的默认范围为 30000-32767,我们设置的时候也需要在这个范围之内。
执行创建:
$ kubectl create -f nginx-service-nodeport.yaml
service/nginx-service-nodeport created
# CLUSTER-IP 的值为 10.110.152.192,PORT(S) 表示集群 IP(80 端口)和 node 端口(31000)
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service-nodeport NodePort 10.110.152.192 <none> 80:31000/TCP 15s
那么现在外部客户端可以通过 nodeIP:nodePort 访问服务:
# 这里访问的是 kubernetes-worker 节点
shiyanlou:~/ $ curl 172.18.0.2:31000
<!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>
...
也可以在集群内部使用 clusterIP:port 访问服务:
shiyanlou:~/ $ docker exec -it kubernetes-worker bash
root@kubernetes-worker:/# curl 10.110.152.192
<!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>
...
在使用 nodePort Service 时,需要注意:
node每个端口只能提供一个服务- 如果
node IP地址发生变化,访问的地址也要随之发生改变
案例:客户端直接访问 Pod
服务 Service 直接被外部客户端访问,其实 Pod 也可以直接被外部客户端访问。
主要通过两种方式实现,在定义 Pod YAML 文件时设置:
spec.ports.hostPort: 容器级别的设置,将容器应用的端口号映射到Node节点上;spec.hostNetwork:Pod级别的设置,Pod中所有容器的端口号都被直接映射到Node节点上;
还有一种方式是使用命令 kubectl port-forward 实现数据转发,kubectl 会主动监听本地的某个端口,然后将对于本地端口的请求转发到 Pod 容器端口上。
hostPort
hostPort 是将容器应用的端口号映射到所在 Node 节点上,通过 NodeIP + hostPort 可以直接访问容器应用。
在 /home/shiyanlou 目录下新建 pod-hostport.yaml 文件,并向其中写入如下代码:
apiVersion: v1
kind: Pod
metadata:
name: pod-hostport
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
hostPort: 8888
执行创建:
$ kubectl create -f pod-hostport.yaml
pod/pod-hostport created
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-hostport 1/1 Running 0 7m14s 10.244.3.3 kubernetes-worker2 <none> <none>
可以看到 pod-hostport 在 kubernetes-worker2 节点上,然后可以直接通过 kubernetes-worker2 IP:hostPort 直接访问容器:
curl 172.18.0.3:8888
但是这里需要注意的是:当 Pod 被重新调度以后,所在的 Node 节点也会发生变化。
hostNetwork
hostNetwork 用于直接定义 Pod 网络,将 Pod 中所有容器的端口号直接映射到 Node 节点上。通过 spec.hostNetwork=true 设置,并且 spec.ports.containerPort 和 spec.ports.hostPort 必须相同:
- 当不指定
spec.ports.hostPort时,默认hostPort与containerPort相同 - 当指定
spec.ports.hostPort时,hostPort必须与containerPort相同
在 f/home/shiyanlou 目录下新建 pod-hostnetwork.yaml 文件,并向其中写入如下代码:
apiVersion: v1
kind: Pod
metadata:
name: pod-hostnetwork
labels:
app: nginx
spec:
hostNetwork: true
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
hostPort: 80
执行创建:
$ kubectl create -f pod-hostnetwork.yaml
pod/pod-hostnetwork created
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-hostnetwork 1/1 Running 0 63s 172.18.0.2 kubernetes-worker <none> <none>
可以看到 pod-hostnetwork 在 kubernetes-worker 节点上,并且 IP 地址也是节点的 IP 地址:172.18.0.2,然后可以直接通过 kubernetes-worker IP:hostPort 直接访问容器:
curl 172.18.0.2:80
这里由于节点是使用 docker 模拟的,在环境中不能直接访问,大家可以在自己的本地环境中尝试。
需要注意的是:启动 Pod 后它被调度分配到的节点可能都是不同的,所以想要访问 Pod 的 nodeIP 地址是不固定的,并且需要注意 Pod 的端口不能与 Node 节点的端口有冲突。
Port Forward
Port Forward是直接将本地端口与Pod端口绑定,通常用于调试服务。
当客户端发送请求到 kubectl 监听的本地端口后,kubectl 会将数据发送给 apiServer,apiServer 与 kubelet 建立连接,然后通过目标 Pod 端口以及 Pod 内部指定的容器端口,最终将请求送达。
我们直接使用命令创建一个 nginx Podd` 进行查看:
$ kubectl run nginx --image nginx:1.7.9 --port=80
pod/nginx created
查看 nginx Pod 监听的端口:
$ kubectl get pods nginx --template='{{(index (index .spec.containers 0).ports 0).containerPort}}{{"\n"}}'
80
现在将本地的 3000 端口转发到 nginx Pod 的 80 端口:
$ kubectl port-forward nginx 3000:80
Forwarding from 127.0.0.1:3000 -> 80
Forwarding from [::1]:3000 -> 80
新开一个终端访问 127.0.0.1:3000 地址:
$ curl 127.0.0.1:3000
<!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>
\