在 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代理访问此服务:
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
外部 IP
外部 IP 是由类型为负载均衡器的服务暴露的,通常在使用外部云提供商负载均衡器时使用。
要找到它们,请检查具有 EXTERNAL-IP
字段值的负载均衡器。
进入集群的流量,目标 IP 是外部 IP ,在服务端口上,将被路由到服务端点之一 。externalIPs
不受 Kubernetes 管理,是集群管理员的责任。
在服务规范中,可以与任何 ServiceTypes
一起指定 externalIPs
。在下面的示例中,"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
列出所有的入口:
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
参考