在没有 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,我想做以下事情:
- 从 GCP 获取静态 IP,
- 通过入口资源使用它
- 在同一集群中托管负载均衡器(使用 nginx 负载均衡器)
- 避免为外部负载均衡器付费
有什么方法甚至可以使用 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: ClusterIP
的 service
的 externalIP
属性。乍一看,这似乎是一个理想的解决方案。但是,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-ingress
,type
为 NodePort
。
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
服务类型更糟糕。祝你好运!
所以我在一个副项目中使用 Kubernetes,它很棒。对于像我正在进行的项目这样的小项目,运行 更便宜(一个由 3-5 个实例组成的小型集群基本上可以满足我的所有需求,在 GCP 上每月只需 ~30 美元)。
我唯一遇到困难的领域是尝试使用 kubernetes Ingress 资源映射到集群并扇出到我的微服务(它们是小型 Go 或 Node 后端)。我有入口的配置设置以映射到不同的服务,那里没有问题。
我知道您可以在创建入口资源时轻松地让 GCP 启动 LoadBalancer。这很好,但它也意味着另外 20-ish/month 美元会增加项目成本。 Once/if 这件事得到了一些关注,可以忽略,但现在也是为了更好地理解 Kubernetes,我想做以下事情:
- 从 GCP 获取静态 IP,
- 通过入口资源使用它
- 在同一集群中托管负载均衡器(使用 nginx 负载均衡器)
- 避免为外部负载均衡器付费
有什么方法甚至可以使用 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: ClusterIP
的service
的externalIP
属性。乍一看,这似乎是一个理想的解决方案。但是,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-ingress
,type
为 NodePort
。
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)。您应该会看到您的网页。
我的设置使用这个 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
服务类型更糟糕。祝你好运!