在没有 GCP 负载均衡器的情况下创建 kubernetes nginx ingress

Create kubernetes nginx ingress without GCP load-balancer

所以我在一个副项目中使用 Kubernetes,它很棒。对于像我正在进行的项目这样的小项目,运行 更便宜(一个由 3-5 个实例组成的小型集群基本上可以满足我的所有需求,在 GCP 上每月只需 ~30 美元)。

我唯一遇到困难的领域是尝试使用 kubernetes Ingress 资源映射到集群并扇出到我的微服务(它们是小型 Go 或 Node 后端)。我有入口的配置设置以映射到不同的服务,那里没有问题。

我知道您可以在创建入口资源时轻松地让 GCP 启动 LoadBalancer。这很好,但它也意味着另外 20-ish/month 美元会增加项目成本。 Once/if 这件事得到了一些关注,可以忽略,但现在也是为了更好地理解 Kubernetes,我想做以下事情:

有什么方法甚至可以使用 Kubernetes 和入口资源来完成吗?

谢谢!

是的,这是可能的。部署入口控制器,并使用 NodePort 服务部署它。示例:

---
apiVersion: v1
kind: Service
metadata:
  name: nginx-ingress-controller
  namespace: kube-system
  labels:
    k8s-app: nginx-ingress-controller
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 80
    nodePort: 32080
    protocol: TCP
    name: http
  - port: 443
    targetPort: 443
    nodePort: 32443
    protocol: TCP
    name: https
  selector:
    k8s-app: nginx-ingress-controller

现在,创建一个带有 DNS 条目的入口:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-ingress
spec:
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        backend:
          serviceName: my-app-service #obviously point this to a valid service + port
          servicePort: 80

现在,假设您的静态 IP 连接到任何 kubernetes 节点 运行 kube-proxy,将 DNS 更新为指向静态 IP,您应该能够访问 myapp.example.com:32080 和ingress 会将您映射回您的应用。

一些额外的事情:

如果您想使用低于 32080 的端口,请记住如果您使用的是 CNI 网络,you'll have trouble with hostport。建议在端口 80 上侦听负载均衡器,我想你可以只设置 nginx 来执行代理传递,但这变得困难。这就是为什么建议您的云提供商使用负载均衡器的原因:)

你也可以制作一个 nginx-ingress 图表,让它拉一个临时 IP,然后将其升级为静态 IP。这将为您留下一个 L7 单区域负载均衡器。

本指南贯穿其中。如果你使用 kube-lego,你可以忽略 TLS 的东西,它与 nginx-ingress

一样有效

https://github.com/kubernetes/ingress-nginx/tree/master/docs/examples/static-ip

TLDR:如果您想在低于 3000 的端口上为您的 website/webservice 提供服务,那么不,这是不可能的。 如果有人找到了方法,我很想知道怎么做。

我尝试在低于 3000 的端口上提供服务时使用的两种主要方法包括:

  • 正在安装 nginx-ingress 类型为 NodePort 的控制器服务,侦听端口 80 和 443。但是,这会导致以下错误:
    Error: UPGRADE FAILED: Service "nginx-ingress-controller" is invalid:
    spec.ports[0].nodePort: Invalid value: 80: provided port is not in the
    valid range. The range of valid ports is 30000-32767
    
    解决此错误的方法是更改​​启动 kube-apiserver 时使用的 --service-node-port-range 标志。但是,无法在 GCP 上访问此配置。如果您想自己尝试,可以查看此处的说明:Kubernetes service node port range
  • 按照线程中的步骤进行操作 Expose port 80 and 443 on Google Container Engine without load balancer。这依赖于使用附加到 type: ClusterIPserviceexternalIP 属性。乍一看,这似乎是一个理想的解决方案。但是,externalIP 属性的工作方式存在一个错误。它不接受外部静态 IP,而是接受内部临时 IP。如果您在 externalIP 字段中硬编码一个内部临时 IP,然后通过 GCP 控制台将一个外部静态 IP 附加到集群中的一个节点,请求会成功路由.但是,这不是一个可行的解决方案,因为您现在已经在 service 定义中硬编码了一个临时 IP,因此随着节点的内部 IP 发生变化,您的网站将不可避免地离线。

如果您可以在 3000 以上的端口上提供服务,请参阅下面的说明。


如何删除 LoadBalancer(仅允许在大于 3000 的端口上提供服务)

我试过删除我的 LoadBalancer,这是我能想到的最佳解决方案。它有以下缺陷:

  • 用于访问网页的端口不是通常的 80 和 443,因为从节点公开这些端口并非易事。如果我弄明白了,我会稍后更新。

以及以下好处:

  • 没有负载均衡器。
  • website/webservice 的 IP 是静态的。
  • 它依赖于流行的 nginx-ingress helm 图表。
  • 它使用 ingress,允许根据请求的路径完全控制请求如何路由到您的 services

1。安装入口服务和控制器

假设您已经安装了 Helm(如果您不遵循此处的步骤:Installing Helm on GKE),请创建一个 nginx-ingresstypeNodePort

helm install \
  --name nginx-ingress \
  stable/nginx-ingress \
  --set rbac.create=true \
  --set controller.publishService.enabled=true \
  --set controller.service.type=NodePort \
  --set controller.service.nodePorts.http=30080 \
  --set controller.service.nodePorts.https=30443

2。创建入口资源

为您的路由创建入口定义。

# my-ingress-resource.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: reverse-proxy
  namespace: production # Namespace must be the same as that of target services below.
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/ssl-redirect: "false" # Set to true once SSL is set up.
spec:
  rules:
  - http:
      paths:
      - path: /api
        backend:
          serviceName: backend
          servicePort: 3000
      - path: /
        backend:
          serviceName: frontend
          servicePort: 80

然后用

安装
kubectl apply -f my-ingress-resource.yaml

3。创建防火墙规则

找到您的集群的标签。

gcloud compute instances list

如果您的集群实例的名称类似于

gke-cluster-1-pool-1-fee097a3-n6c8
gke-cluster-1-pool-1-fee097a3-zssz

那么你的集群标签是gke-cluster-1-pool-1-fee097a3

前往 the GCP firewall page确认您在导航栏中 select 编辑了正确的项目。

单击 "Create Firewall Rule"。给规则一个合适的名字。您可以将大部分设置保留为默认设置,但在 "Target tags" 下超过您的集群标签。将源 IP 范围设置为 0.0.0.0/0。在协议和端口下,将 "Allow all" 更改为 "Specified protocols and ports"。 选中 TCP 框,并在输入字段中输入 30080, 30443。单击 "Create"。

4。创建静态 IP

转到 https://console.cloud.google.com/networking/addresses/ 并单击 "Reserve Static Address"。给它起一个描述性的名称,然后 select 正确的区域。 select 选择正确的区域后,您应该能够单击 "Attached to" 下拉菜单和 select 您的 Kubernetes 节点之一。单击 "Reserve"。

5。测试配置

保留静态 IP 后,通过查看 External IP Address list 找出授予哪个静态 IP。

将其复制到您的浏览器中,然后添加一个端口(<your-ip>:30080 用于 HTTP 或 https://<your-ip>:30443 用于 HTTPS)。您应该会看到您的网页。

,但它包含我从未使用过的 Digital Ocean 详细信息。老实说,它救了我的命,可以使用 3000 以下的端口,但老实说,我不确定它是如何工作的。

我的设置使用这个 Nginx ingress controller. 使用 helm 安装它,并提供一个配置文件:

$ helm install my-nginx ingress-nginx/ingress-nginx -f config.yaml

配置文件应包含:

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

您可以找到默认值 here,但我不知道如何理解该配置。

之后您可以创建入口 yaml:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: web-app
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/proxy-body-size: "100m"
    cert-manager.io/cluster-issuer: "letsencrypt"
    nginx.ingress.kubernetes.io/server-alias: "example.com"
  labels:
    app: web-app
spec:
  tls:
    - hosts:
      - example.com
      secretName: prod-certs
  rules:
    - host: example.com
      http: 
        paths:
        - backend:
            serviceName: myservice
            servicePort: 443

这是我的,可能对你不起作用,但试试吧!

它指向的服务入口规则是NodePort类型:

apiVersion: v1
kind: Service
metadata:
  name: myservice
  labels:
    app: myservice
spec:
  type: NodePort
  ports:
  - port: 443
    targetPort: 80

但我相信 ClusterIP 也可以。

除此之外,其中一个虚拟机有一个 public 静态 IP,我们将该 IP 用作我们的域名。

所以我相信这个过程是。域名转换为该静态 IP。然后流量到达 Ingress 控制器,我不知道它是如何工作的,但是你的流量在那里匹配了一些规则,并被重定向到服务。这些端口在 Ingress 中定义,因此您也可以使用 3000 个以下的端口,但我不知道这个“解决方案”在性能方面是如何工作的,而且我也不知道 Ingress 控制器如何在不公开的情况下接受流量。

设置 Ingress 可能是我遇到的最糟糕的经历之一,实际上我采用了这种混乱的方法,因为使用 LoadBalancer 服务类型更糟糕。祝你好运!