我想根据命名空间(dev 或 prod)的环境提供两个外部 IP。我的想法是在 dev 和 prod 命名空间上托管相同的 fqdns。例如,如果客户端解析www.mywebsite.lan在 192.168.171.1 上,那么他正在开发环境中工作,如果他在 192.168.171.10 上解析,那么他的目标是生产。
请注意,我仍然是 k8s 的初学者,并且我认为我犯了一些错误或误解。
我已经建立了两个 metallb IP 池,每个池都有单独的 IP 地址:
NAME AUTO ASSIGN AVOID BUGGY IPS ADDRESSES
ac3-dev-ippool true false ["192.168.171.1/32"]
ac3-prod-ippool true false ["192.168.171.10/32"]
我有一个 nginx 入口控制器(默认配置,除处于集群模式的 externalTrafficPolicy 和启用了 appProtocol https 外):
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx-controller-68fb8cf9cc-vkbfz 1/1 Running 2 (34h ago) 5d23h 10.244.3.2 ktux-130 <none> <none>
以及 prod 和 dev 命名空间上的两个入口:
$ k get ingress -n ac3
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress nginx www.mywebsite-prod.lan 192.168.171.1 80, 443 19h
$ k get ingress -n ac3-dev
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress nginx www.mywebsite-dev.lan 192.168.171.1 80, 443 13d
但是,正如您所注意到的,两个入口都具有相同的 IP 地址 (192.168.171.1),我不明白为什么。请注意,这样可以正常工作,但我希望能够重命名虚拟主机以同时为两者提供服务www.mywebsite.lan。
以下是入口配置:
(...)
metadata:
name: ingress
namespace: ac3
annotations:
metallb.universe.tf/address-pool: ac3-prod-ippool
kubernetes.io/ingress.class: nginx
spec:
ingressClassName: nginx
tls:
- secretName: tls-certs-mywebsite-prod
hosts:
- "www.mywebsite-prod.lan"
rules:
- host: "www.mywebsite-prod.lan"
http:
(...)
---
(...)
metadata:
name: ingress
namespace: ac3-dev
annotations:
metallb.universe.tf/address-pool: ac3-dev-ippool
kubernetes.io/ingress.class: nginx
spec:
ingressClassName: nginx
tls:
- secretName: tls-certs-mywebsite-dev
hosts:
- "www.mywebsite-dev.lan"
rules:
- host: "www.mywebsite-dev.lan"
http:
(...)
令我不安的是,入口控制器仅从 metallb 获取一个 IP 地址:
$ k get svc -n ingress-nginx ingress-nginx-controller -oyaml | tail -5
type: LoadBalancer
status:
loadBalancer:
ingress:
- ip: 192.168.171.1
我认为它会获得两个 IP 地址,每个范围一个?
nginx ingress controller 服务是默认服务:
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.8.1
name: ingress-nginx-controller-admission
namespace: ingress-nginx
spec:
ports:
- appProtocol: https
name: https-webhook
port: 443
targetPort: webhook
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
type: ClusterIP
所以现在我的想法是创建两个入口控制器,一个在命名空间 ac3 上,另一个在 ac3-dev 上?但我想知道是否还有其他方法,更简单、更“符合 k8s 标准”来实现我的目标。
所以,k8s 专家们,您能给我建议或者告诉我我的错误在哪里吗?
谢谢
答案1
与您的 Ingress 资源关联的 IP 地址是来自入口控制器;它并不是 Ingress 本身所特有的东西。
您正在运行 nginx 入口控制器,因此在某处您有一个与ingress-nginx-controller-68fb8cf9cc-vkbfz
pod 关联的 LoadBalancer 类型的服务。分配给该服务的地址就是您将看到的由该入口控制器提供服务的所有入口资源的地址。
metallb.universe.tf/address-pool
在 Ingress 上设置注释没有任何意义;这仅对服务资源有意义。
如果您想要在多个地址上公开 Ingress,则需要通过创建多个服务资源(每个地址一个)为您的入口控制器分配多个地址。
一个例子
我正在使用 Traefik 入口控制器运行 k3s。在这个例子中,我有一个部署:
apiVersion: apps/v1
kind: Deployment
metadata:
name: example
spec:
template:
spec:
containers:
- name: whoami
image: docker.io/traefik/whoami:latest
ports:
- name: http
containerPort: 80
服务:
apiVersion: v1
kind: Service
metadata:
name: example
spec:
ports:
- name: http
port: 80
targetPort: http
最后是 Ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example
spec:
rules:
- host: example.k3s.virt
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: example
port:
name: http
开箱即用,在kube-system
命名空间中,我有:
$ kubectl -n kube-system get service traefik
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
traefik LoadBalancer 10.43.215.182 192.168.124.201 80:32271/TCP,443:32683/TCP 15d
您可以看到该服务已分配地址192.168.124.201
;这就是我们所说的“内部”地址池。查看我的示例应用程序,我们可以在 Ingress 资源中看到来自上述服务的 IP 地址:
$ kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
example traefik example.k3s.virt 192.168.124.201 80 22m
我可以通过给定的地址访问该应用程序:
$ curl -s http://192.168.124.201 -H host:example.k3s.virt
Hostname: example-758b5cd967-5gk7h
...
我有一个使用范围的“公共”池192.168.126.0/24
;为了在该网络上公开入口,我将在与入口控制器相同的命名空间中创建一个新服务:
apiVersion: v1
kind: Service
metadata:
annotations:
metallb.universe.tf/address-pool: public
name: traefik-public
spec:
allocateLoadBalancerNodePorts: true
internalTrafficPolicy: Cluster
ports:
- name: web
port: 80
targetPort: web
- name: websecure
port: 443
targetPort: websecure
selector:
app.kubernetes.io/instance: traefik-kube-system
app.kubernetes.io/name: traefik
type: LoadBalancer
我们可以看到它从“公共”池中分配了一个地址:
$ kubectl -n kube-system get service traefik traefik-public
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
traefik LoadBalancer 10.43.215.182 192.168.124.201 80:32271/TCP,443:32683/TCP 15d
traefik-public LoadBalancer 10.43.30.212 192.168.126.11 80:32452/TCP,443:32082/TCP 13m
现在我的应用程序可以访问两个都地址:
$ curl -s http://192.168.124.201 -H host:example.k3s.virt
Hostname: example-758b5cd967-5gk7h
...
$ curl -s http://192.168.126.11 -H host:example.k3s.virt
Hostname: example-758b5cd967-5gk7h
...
答案2
您遵循的过程是正确的,但需要进行一些修改。Metallb IP 池因环境prod
而异dev
。Nginx Ingress Controller 仅从 metal lb 获取一个 IP 地址,但您希望根据环境为同一主机名设置不同的 IP 地址。
由于 Nginx 控制器部署在单个命名空间中,metal lb 仅向控制器分配一个 IP 地址,这是预期行为。此外,入口资源具有不同的主机名(“www.mywebsite-prod.lan”和“www.mywebsite-dev.lan”),但它们指向相同的 IP 地址,这就是您没有获得预期行为的原因。
您可以尝试按照以下步骤解决该问题:
尝试动态主机解析您不需要为两个环境指定不同的主机名,而可以使用相同的主机名(“www.mywebsite.lan”)。
使用 Kubernetes 功能配置图或者环境变量确定应用程序内的环境。然后,您可以根据环境解析服务的 IP 地址。
在 Nginx Config 中,根据主机名动态地将流量路由到与不同 IP 地址关联的不同后端服务。
对于每个环境,创建指向不同后端服务的单独 kubernetes 服务。确保每个服务都使用来自 metallb 的适当 IP 池。
例如,‘ingress-nginx’
命名空间中有一个 Nginx Ingress Controller,其中包含两个 kubernetes 服务,每个服务都有从 Metallb 池分配的自己的 IP 地址。在 Nginx 配置中,根据主机名将流量路由到适当的服务。