在没有负载均衡器的情况下,在 Digital Ocean 的托管 Kubernetes 上公开端口 80

Posted

技术标签:

【中文标题】在没有负载均衡器的情况下,在 Digital Ocean 的托管 Kubernetes 上公开端口 80【英文标题】:Expose port 80 on Digital Ocean's managed Kubernetes without a load balancer 【发布时间】:2019-06-04 18:35:43 【问题描述】:

我想在不使用 Digital Ocean 的负载均衡器的情况下,在端口 80 上公开我的 Kubernetes Managed Digital Ocean(单节点)集群的服务。这可能吗?我该怎么做?

这本质上是一个爱好项目(我从 Kubernetes 开始),只是想保持成本非常低。

【问题讨论】:

如果你对成本敏感,为什么不能使用 minikube kubernetes.io/docs/tasks/tools/install-minikube 因为应用程序仍然需要公开访问,所以可以考虑像个人网站或投资组合的网络应用程序。您包含的链接说 minikube 只允许您“在个人计算机上的虚拟机中”运行东西,这不足以实现这样的目标。 【参考方案1】:

您可以部署配置为使用主机网络和端口 80/443 的 Ingress。

    您的集群的 DO 防火墙默认没有打开 80/443 入站。

    如果您编辑自动创建的防火墙规则will eventually reset themselves。解决方案是创建一个单独的防火墙,也指向相同的 Kubernetes 工作节点:

$ doctl compute firewall create \
--inbound-rules="protocol:tcp,ports:80,address:0.0.0.0/0,address:::/0 protocol:tcp,ports:443,address:0.0.0.0/0,address:::/0" \
--tag-names=k8s:CLUSTER_UUID \
--name=k8s-extra-mycluster

(从仪表板获取CLUSTER_UUID 值或从doctl kubernetes cluster list 获取ID 列)

    使用主机网络创建nginx ingress。我在下面包含了helm chart 配置,但您也可以通过直接安装过程来完成。

编辑:上面链接中的 Helm 图表已被弃用,因此安装图表的正确方法是(as per the new docs):

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

添加和更新此 repo 后

# For Helm 2
$ helm install stable/nginx-ingress --name=myingress -f myingress.values.yml

# For Helm 3
$ helm install myingress stable/nginx-ingress -f myingress.values.yml

#EDIT: The New way to install in helm 3
helm install myingress ingress-nginx/ingress-nginx -f myingress.values.yaml

myingress.values.yml 用于图表:

---
controller:
  kind: DaemonSet
  hostNetwork: true
  dnsPolicy: ClusterFirstWithHostNet
  daemonset:
    useHostPort: true
  service:
    type: ClusterIP
rbac:
  create: true

    您应该能够通过任何工作程序节点 IP 访问 :80 和 :443 上的集群,它将流量路由到您的入口。

    由于节点 IP 可以并且确实可以更改,因此请考虑部署 external-dns 来管理 DNS 条目以指向您的工作节点。同样,使用掌舵图并假设您的 DNS 域由 DigitalOcean 托管(尽管任何受支持的 DNS 提供商都可以使用):

# For Helm 2
$ helm install --name=mydns -f mydns.values.yml stable/external-dns

# For Helm 3
$ helm install mydns stable/external-dns -f mydns.values.yml

mydns.values.yml 用于图表:

---
provider: digitalocean
digitalocean:
  # create the API token at https://cloud.digitalocean.com/account/api/tokens
  # needs read + write
  apiToken: "DIGITALOCEAN_API_TOKEN"
domainFilters:
  # domains you want external-dns to be able to edit
  - example.com
rbac:
  create: true
    创建一个 Kubernetes Ingress resource 将请求路由到现有的 Kubernetes 服务:
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: testing123-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
    - host: testing123.example.com             # the domain you want associated
      http:
        paths:
          - path: /
            backend:
              serviceName: testing123-service  # existing service
              servicePort: 8000                # existing service port
    大约一分钟后,您应该会看到 DNS 记录出现并且可以解析:
$ dig testing123.example.com             # should return worker IP address
$ curl -v http://testing123.example.com  # should send the request through the Ingress to your backend service

(编辑:编辑自动创建的防火墙规则最终会中断,改为添加单独的防火墙)。

【讨论】:

非常感谢您!花了超过 3 天的时间才找到这个好答案。 helm install myingress stable/nginx-ingress -f myingress.values.yml 用于 Helm 3 是否可以在不使用 Helm 等其他依赖项的情况下提供这些说明? 我发现这个配置导致DNS中的集群IP地址,而不是节点的可路由公共IP。我通过更改myingress.values.yml 解决了这个问题:将controller.publishService.enabled 设置为false。不确定这是不是“正确”的做法,但它修复了 DNS。 这个答案对我帮助很大,但使用 Cloudflare 时 external-dns 对我不起作用,因为它从 nginx 入口获取内部 CluserIP 地址,而不是节点的外部 IP。我使用的解决方案是使用github.com/calebdoxsey/kubernetes-cloudflare-sync,而不是将节点的外部IP直接同步到k8s.mydomain之类的东西。然后,每当我添加一个新的 nginx 入口时,我只需向该地址添加一个 CNAME。【参考方案2】:

NodePort Service 可以为所欲为。像这样的:

kind: Service
apiVersion: v1
metadata:
  name: my-service
spec:
  type: NodePort
  selector:
    app: MyApp
  ports:
  - protocol: TCP
    nodePort: 80
    targetPort: 80

这会将传入流量从节点的端口 80 重定向到您的 Pod 的端口 80。在 DNS 中发布节点 IP 即可。

一般像这样将服务暴露给外界是一个非常非常糟糕的主意,因为将所有流量传递给服务的单个节点既会收到不平衡的负载,也会成为单点故障。不过,这种考虑不适用于单节点集群,因此需要注意的是 LoadBalancer 和 Ingress 是执行您正在寻找的工作的容错方式,NodePort 最适合这种极其特殊的情况。

【讨论】:

感谢您的回复和示例!我读到 nodePort 仅限于非标准端口(30000-32767)。在这种情况下是这样吗? 你是对的,我读错了文档。我建议的解决方案行不通。 以下是将80 端口上的ingress controller service 暴露给没有LoadBalancer 的外部用户的唯一方法吗?当我使用NodePort 时,我必须使用NginxApache 将80 与NodePort(30000~32767 之间)绑定。

以上是关于在没有负载均衡器的情况下,在 Digital Ocean 的托管 Kubernetes 上公开端口 80的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在没有负载均衡器的情况下为 ECS 服务配置健康检查?

AWS Elastic Beanstalk - NodeJS:在没有 Beanstalk 负载均衡器的情况下从 Letsencrypt 获取证书 SSL

如何在没有负载均衡器的情况下使用配置文件在 Amazon Elastic Beanstalk 实例中配置 SSL?

AWS Beanstalk - 无法在没有来自 CLI 的负载均衡器的情况下在 VPC 中创建环境

是否可以在没有负载均衡器的情况下使用带有 SSL (HTTPS) 的 Amazon Elastic Beanstalk?

在没有负载平衡的情况下将 docker 部署到 AWS