为 Kubernetes 服务分配外部 IP

47

我设置的整个目的是(如果可能)实现以下内容:

  • 我有多个k8s节点
  • 当我联系公司网络中的IP地址时,它应该被路由到我的一个容器/ pod /服务/任何东西。
  • 我应该能够轻松设置该IP(例如在我的服务.yml定义中)

我正在运行一个小型Kubernetes集群(使用kubeadm构建),以评估是否可以将我的Docker(旧版)Swarm设置移动到k8s。我绝对需要的功能是能够为容器分配IP,就像我使用MacVlan一样。

在我的当前docker设置中,我使用MacVlan将IP地址从公司网络分配给某些容器,以便我可以直接访问它们(无需反向代理),就像访问任何物理服务器一样。我正在尝试通过k8s实现类似的功能。

我发现:

  • 我必须使用Service
  • 我不能使用LoadBalancer类型,因为它只适用于兼容的云提供商(如GCE或AWS)。
  • 我应该使用{{link1:ExternalIPs}}
  • Ingress Resources是某种反向代理吗?

我的yaml文件是:

apiVersion: apps/v1beta1
kind: Deployment
metadata:
      name: nginx-deployment
spec:
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80
      nodeSelector:
        kubernetes.io/hostname: k8s-slave-3
---
kind: Service
apiVersion: v1
metadata:
  name: nginx-service
spec:
  type: ClusterIP
  selector:
    app: nginx
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 80
  externalIPs: 
    - A.B.C.D

我希望我的服务能够获得IP地址A.B.C.D(这是我公司网络中的一个)。我的部署正在工作,因为我可以使用其ClusterIP从k8s集群内部访问我的nginx容器。

我错过了什么?或者至少,我在哪里可以找到有关我的网络流量的信息,以便查看数据包是否到达?

$ kubectl get svc
NAME            CLUSTER-IP     EXTERNAL-IP       PORT(S)   AGE
kubernetes      10.96.0.1      <none>            443/TCP   6d
nginx-service   10.102.64.83   A.B.C.D           80/TCP    23h

你确定所提到的外部IP路由到了k8s集群节点吗?另外,当你运行kubectl get service时,你看到了什么? - Mayur Nagekar
我将 kubectl get svc 的输出添加为编辑内容。删除 type: ClusterIP 不会改变任何东西,因为它是默认值。我该如何检查流量是否到达我的集群?在 kube-proxy 中吗? - Jérôme Pin
1
我已经尝试了,但它没有起作用。这就是问题所在。我的容器可以从集群内部访问,但无法从外部访问。 - Jérôme Pin
我以为k8s会自动处理IP分配。所以我要尝试将A.B.C.D分配给我的一个节点。但是这意味着(a)我必须手动将该IP分配给我的节点,而且(b)流量必须经过该节点才能传输。 - Jérôme Pin
@DanielAlder,如果你谈论LoadBalancer控制器,那么它只适用于某些云服务提供商。对于裸金属集群,除了Ingress外,您可以查看metallb - Jérôme Pin
显示剩余8条评论
9个回答

48

首先运行以下命令:

kubectl get -n namespace services

上述命令将返回以下输出:

 NAME            TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)         AGE
backend   NodePort   10.100.44.154         <none>          9400:3003/TCP   13h   
frontend        NodePort   10.107.53.39     <none>        3000:30017/TCP   13h

从上面的输出可以清楚地看出,服务尚未分配外部IP。要将外部IP分配给后端服务,请运行以下命令。

 kubectl patch svc backend -p '{"spec":{"externalIPs":["192.168.0.194"]}}'

要为运行在前端服务上分配外部IP,请运行以下命令。

 kubectl patch svc frontend -p '{"spec":{"externalIPs":["192.168.0.194"]}}'

现在获取命名空间服务以检查外部IP的分配:

kubectl get -n namespace services

我们得到了以下输出:

NAME     TYPE     CLUSTER-IP     EXTERNAL-IP    PORT(S)             AGE
backend  NodePort 10.100.44.154  192.168.0.194  9400:3003/TCP       13h
frontend NodePort 10.107.53.39   192.168.0.194  3000:30017/TCP      13h

干杯!!! Kubernetes外部IP现在已经被分配。


如何替换已经由负载均衡器MetalLB分配的IP地址(ix-putty)? 在putty LoadBalancer 172.17.25.2 10.10.8.211,10.10.12.211 10266/TCP中,即使执行了kubectl patch svc -n ix-putty putty-vnc -p '{"spec":{"externalIPs":[]}}10.10.8.211始终保持不变。 - Stefan

26

如果这只是为了测试,那就试试看

kubectl port-forward service/nginx-service 80:80

然后你可以

curl http://localhost:80

1
我使用了 kubectl port-forward --address 0.0.0.0 pod/<我的pod> 6666:6666 命令将Pod上的6666端口暴露给外部世界。curl http://<公共IP>:6666 可以正常工作,但如果我尝试在浏览器中访问相同的链接,则会出现“无法访问此网站”的错误。 有任何想法是什么原因导致了这个问题吗? - rakesh
最简单的测试“端口转发”的方法是使用公共地址,例如ngrok(https://ngrok.com/)。启动代理: kubectl port-forward po/myapp 8080:3000启动ngrok代理: ngrok http 8080ngrok将提供2个公共URL(http / https),将请求路由到您机器的端口8080。 - Chuk Lee

7

您只需打补丁即可使用外部IP

CMD: $ kubectl patch svc 服务名称 -p '{"spec":{"externalIPs":["您的外部IP"]}}'

示例: $ kubectl patch svc kubernetes -p '{"spec":{"externalIPs":["10.2.8.19"]}}'


5
一种可行的解决方案(不仅用于测试,虽然它有其缺点)是将 Pod 设置为使用 hostNetwork 规范字段映射主机网络,并将其设置为 true
这意味着您无需通过服务来暴露 Pod,因为始终可以通过单个端口(您在清单中指定的 containerPort)在主机上访问它。在这种情况下,无需保留 DNS 映射记录。
这也意味着您只能在给定节点上运行一个此类 Pod(谈到缺点...)。因此,它成为DaemonSet对象的良好候选者。
如果您的 Pod 仍然需要访问/解析内部 Kubernetes 主机名,则需要将 dnsPolicy 规范字段设置为 ClusterFirstWithNoHostNet。此设置将使您的 Pod 可以访问 K8S DNS 服务。
示例:
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nginx
spec:
  template:
    metadata:
      labels:
        app: nginx-reverse-proxy
    spec:
      hostNetwork: true
      dnsPolicy: ClusterFirstWithHostNet
      tolerations:  # allow a Pod instance to run on Master - optional
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      containers:
      - image: nginx
        name: nginx
        ports:
        - name: http
          containerPort: 80
        - name: https
          containerPort: 443

编辑:感谢ingress-nginx文档,让我找到了这个方法。


1

0
您可以尝试在 YAML 文件中添加 "type: NodePort" 到服务中,然后您就可以通过 Web 浏览器或外部访问端口。对于我的情况,这很有帮助。

0

在部署和服务中,基于命名空间的作用域是适用的,因此始终在服务名称之前或之后使用命名空间标志,并指向标记为特定命名空间的服务。

kubectl patch svc service-name -n namespace -p '{"spec":{"externalIPs":["IP"]}}'

-1

我不知道这是否适用于您的特定情况,但我所做的(并且我在一个裸机集群上)是使用LoadBalancer,将loadBalancerIP以及externalIPs设置为我的服务器IP,正如您所做的那样。

之后,负载均衡器显示了正确的外部IP。


1
这就是我需要的,你能否请举例扩展一下答案? - fde-capu

-2

只需添加额外选项即可。

kubectl expose deployment hello-world --type=LoadBalancer --name=my-service --external-ip=1.1.1.1

1
这是一个我曾经遇到的相当老的问题。但那时由于它是一个裸机集群,我无法使用LoadBalancer类型。此外,在这个例子中使用--external-ip=1.1.1.1并不是最好的选择,因为这个IP地址现在是Cloudflare的公共DNS。 - Jérôme Pin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接