在Kubernetes中有不同的方法来暴露服务 ,以便内部 端点和外部 端点都可以访问它们。这个Kubernetes配置非常关键,因为管理员可能会给攻击者访问他们不应该能够访问的服务 的权限。
自动枚举
在开始枚举K8s提供的暴露服务给公众的方法之前,请知道如果您可以列出命名空间、服务和入口,则可以找到所有暴露给公众的内容:
Copy kubectl get namespace -o custom-columns= 'NAME:.metadata.name' | grep -v NAME | while IFS = '' read -r ns ; do
echo "Namespace: $ns"
kubectl get service -n "$ns"
kubectl get ingress -n "$ns"
echo "=============================================="
echo ""
echo ""
done | grep -v "ClusterIP"
# Remove the last '| grep -v "ClusterIP"' to see also type ClusterIP
ClusterIP
一个 ClusterIP 服务是 默认 的 Kubernetes 服务 。它为您提供一个 集群内部 的服务,其他应用可以访问该服务。没有 外部访问 。
然而,可以使用 Kubernetes Proxy 进行访问:
Copy kubectl proxy --port=8080
现在,您可以通过以下方案导航 Kubernetes API 以访问服务:
http://localhost:8080/api/v1/proxy/namespaces/<NAMESPACE>/services/<SERVICE-NAME>:<PORT-NAME>/
例如,您可以使用以下 URL:
http://localhost:8080/api/v1/proxy/namespaces/default/services/my-internal-service:http/
来访问此服务:
Copy apiVersion : v1
kind : Service
metadata :
name : my-internal-service
spec :
selector :
app : my-app
type : ClusterIP
ports :
- name : http
port : 80
targetPort : 80
protocol : TCP
此方法要求您以 经过身份验证的用户 身份运行 kubectl
。
列出所有 ClusterIPs:
Copy kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP,PORT(S):.spec.ports[*].port,TARGETPORT(S):.spec.ports[*].targetPort,SELECTOR:.spec.selector' | grep ClusterIP
NodePort
当 NodePort 被使用时,所有节点(代表虚拟机)上会开放一个指定的端口。指向该特定端口的 流量 会被系统地 路由到服务 。通常,由于其缺点,这种方法不推荐使用。
列出所有 NodePorts:
Copy kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP,PORT(S):.spec.ports[*].port,NODEPORT(S):.spec.ports[*].nodePort,TARGETPORT(S):.spec.ports[*].targetPort,SELECTOR:.spec.selector' | grep NodePort
NodePort 规格的示例:
Copy apiVersion : v1
kind : Service
metadata :
name : my-nodeport-service
spec :
selector :
app : my-app
type : NodePort
ports :
- name : http
port : 80
targetPort : 80
nodePort : 30036
protocol : TCP
如果您不指定 yaml中的nodePort (这是将要打开的端口),将使用30000–32767范围内的端口 。
LoadBalancer
通过使用云提供商的负载均衡器 将服务公开到外部。在GKE上,这将启动一个网络负载均衡器 ,它将为您提供一个单一的IP地址,该地址将所有流量转发到您的服务。在AWS上,它将启动一个负载均衡器。
您必须为每个公开的服务支付负载均衡器的费用,这可能会很昂贵。
列出所有负载均衡器:
Copy kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP,EXTERNAL-IP:.status.loadBalancer.ingress[*],PORT(S):.spec.ports[*].port,NODEPORT(S):.spec.ports[*].nodePort,TARGETPORT(S):.spec.ports[*].targetPort,SELECTOR:.spec.selector' | grep LoadBalancer
外部 IPs
外部 IPs 是由类型为 Load Balancers 的服务暴露的,通常在使用外部云提供商的 Load Balancer 时使用。
要查找它们,请检查 EXTERNAL-IP
字段中有值的负载均衡器。
流入集群的流量使用 external IP (作为 目标 IP ),在服务端口上,将被 路由到其中一个服务端点 。externalIPs
不是由 Kubernetes 管理的,责任在于集群管理员。
在服务规格中,externalIPs
可以与任何 ServiceTypes
一起指定。在下面的示例中,"my-service
" 可以通过 "80.11.12.10:80
"(externalIP:port
)被客户端访问。
Copy apiVersion : v1
kind : Service
metadata :
name : my-service
spec :
selector :
app : MyApp
ports :
- name : http
protocol : TCP
port : 80
targetPort : 9376
externalIPs :
- 80.11.12.10
ExternalName
来自文档: ExternalName 类型的服务 将服务映射到 DNS 名称 ,而不是像 my-service
或 cassandra
这样的典型选择器。您可以使用 spec.externalName
参数来指定这些服务。
例如,此服务定义将 prod
命名空间中的 my-service
服务映射到 my.database.example.com
:
Copy apiVersion : v1
kind : Service
metadata :
name : my-service
namespace : prod
spec :
type : ExternalName
externalName : my.database.example.com
当查找主机 my-service.prod.svc.cluster.local
时,集群 DNS 服务返回一个值为 my.database.example.com
的 CNAME
记录。访问 my-service
的方式与其他服务相同,但有一个关键区别,即 重定向发生在 DNS 层面 而不是通过代理或转发。
列出所有 ExternalNames:
Copy kubectl get services --all-namespaces | grep ExternalName
Ingress
与上述所有示例不同,Ingress 不是一种服务类型 。相反,它位于**多个服务前面,充当“智能路由器”**或集群的入口点。
您可以使用 Ingress 做很多不同的事情,并且有许多类型的 Ingress 控制器具有不同的功能 。
默认的 GKE Ingress 控制器将为您启动一个 HTTP(S) 负载均衡器 。这将允许您对后端服务进行基于路径和子域的路由。例如,您可以将 foo.yourdomain.com 上的所有请求发送到 foo 服务,将 yourdomain.com/bar/ 路径下的所有请求发送到 bar 服务。
在 GKE 上使用 L7 HTTP 负载均衡器 的 Ingress 对象的 YAML 可能如下所示:
Copy apiVersion : extensions/v1beta1
kind : Ingress
metadata :
name : my-ingress
spec :
backend :
serviceName : other
servicePort : 8080
rules :
- host : foo.mydomain.com
http :
paths :
- backend :
serviceName : foo
servicePort : 8080
- host : mydomain.com
http :
paths :
- path : /bar/*
backend :
serviceName : bar
servicePort : 8080
列出所有的 ingresses:
Copy kubectl get ingresses --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,RULES:spec.rules[*],STATUS:status'
虽然在这种情况下,逐个获取每个信息以便更好地阅读是更好的选择:
Copy kubectl get ingresses --all-namespaces -o=yaml
参考文献