使用基于路径的应用程序负载均衡器路由到相同EKS中的不同服务



让我简要介绍一下这个问题。我们已经在EKS中部署了flask服务。以前,我们可以使用AWS中的经典负载平衡器根据路径路由到相同EKS中的不同服务。由于经典磅是弃用,我们迁移到应用程序磅。我们不能做瓶服务基于路径的路由。如何实现基于路径的路由在ALB烧瓶服务运行在不同的端口在同一个EKS集群?

详细描述如下所示。

aws eks --region eu-west-2 update-kubeconfig --name alb-check
kubectl create namespace check

之后我们安装了nginx

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install nginx-ingress ingress-nginx/ingress-nginx 
--namespace check 
--set controller.replicaCount=2 
--set controller.nodeSelector."beta.kubernetes.io/os"=linux 
--set defaultBackend.nodeSelector."beta.kubernetes.io/os"=linux

运行上述命令后,将在具有某些DNS名称的区域中创建一个经典入口控制器。然后我们使用下面的yaml.

部署了2个类似的服务。
#####
apiVersion: apps/v1
kind: Deployment
metadata:
name: console
namespace: check
labels:
app: console
spec:
replicas: 1
selector:
matchLabels:
app: console
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
type: RollingUpdate
template:
metadata:
labels:
app: console
spec:
containers:
- name: console
imagePullPolicy: Always
image: xxxxxx.dkr.ecr.eu-west-1.amazonaws.com/check:sample_1
---
---
apiVersion: v1
kind: Service
metadata:
name: console
namespace: check
spec:
selector:
app: console
ports:
- protocol: TCP
port: 3000
targetPort: 3000
type: ClusterIP

docker镜像的内容如下所示。

from flask import Flask
from flask import jsonify
app_name = "Check1"
app = Flask(app_name)
portVal =  3000
@app.route('/', methods=['GET'])
def api0():
data = {"code": 200, "source": "api1", "message": "This service 1", "port": portVal}
return jsonify(data)

@app.route('/api1', methods=['GET'])
def api1():
data = {"code": 200, "source": "api1", "port": portVal}
return jsonify(data)

@app.route('/api2', methods=['GET'])
def api2():
data = {"code": 200, "source": "api2", "port": portVal}
return jsonify(data)

if __name__ == "__main__":
app.run()

对应的docker文件。

FROM python:3.7
RUN mkdir /check
ADD ./s1/app_file.py /check/app_file.py
ADD ./s1/s1_requirements.txt /check/s1_requirements.txt
WORKDIR /check
RUN pip install -r ./s1_requirements.txt
EXPOSE 3000
CMD ["gunicorn", "-b", "0.0.0.0:3000", "app_file:app", "--workers", "3", "--threads", "25", "--timeout", "660"]

文件s1_requirements.txt只有两个要求。

Flask==2.1.2
gunicorn==19.9.0

我已经部署的另一个类似的服务唯一的区别是它是运行在不同的端口3001。在部署了两个服务之后,我使用下面的文件配置了入口。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: check-ingress
namespace: check
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
nginx.ingress.kubernetes.io/use-regex: "true"
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/cors-allow-headers: "Content-Type,authToken,sdk-Key,data,api-type,Authorization,userId,teamId"
nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE, OPTIONS"
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "600"
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
nginx.ingress.kubernetes.io/client-body-buffer-size: "16m"
nginx.ingress.kubernetes.io/proxy-body-size: "16m"
nginx.ingress.kubernetes.io/enable-modsecurity: "true"
spec:
rules:
- http:
paths:
- pathType: Prefix
backend:
service:
name: console
port:
number: 3000
path: /console/(.*)
- pathType: Prefix
backend:
service:
name: console2
port:
number: 3001
path: /console2/(.*)

kubectl apply -f ingress.yaml

到目前为止,一切正常。当我给DNSURL/console/api1 =>我能够从服务1的api1得到响应,它运行在端口3000上。

同样当我给DNSURL/console2/api1 =>我能够从运行在端口3001上的服务2的api1获得响应。

由于经典负载平衡器已被弃用,我们考虑在上述用例中使用应用程序负载平衡器。在这种情况下,我们无法根据路径实现到运行在不同端口上的服务的路由。

运行以下命令创建新的EKS集群并创建ALB。参考aws文档

eksctl create cluster --name alb3-check --region eu-west-2 --version 1.22
eksctl utils associate-iam-oidc-provider --region eu-west-2 --cluster alb3-check --approve
aws eks describe-cluster --name alb3-check --query "cluster.identity.oidc.issuer" --region eu-west-2 --output text
aws iam create-policy --policy-name alb3tqAWSLoadBalancerControllerIAMPolicy --policy-document file://iam-policy.json

eksctl create iamserviceaccount 
--cluster=alb3-check 
--namespace=kube-system 
--name=aws-load-balancer-controller 
--attach-policy-arn=arn:aws:iam::xxxxxxxxx74:policy/alb3tqAWSLoadBalancerControllerIAMPolicy 
--override-existing-serviceaccounts 
--approve
kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v1.5.4/cert-manager.yaml
curl -Lo v2_4_1_full.yaml https://github.com/kubernetes-sigs/aws-load-balancer-controller/releases/download/v2.4.1/v2_4_1_full.yaml
sed -i.bak -e 's|your-cluster-name|alb3-check|' ./v2_4_1_full.yaml
kubectl apply -f v2_4_1_full.yaml (Run this twice)

创建ALB后,我已经在这个EKS中部署了相同的服务。

apiVersion: apps/v1
kind: Deployment
metadata:
namespace: check
name: console
spec:
selector:
matchLabels:
app.kubernetes.io/name: console
replicas: 1
template:
metadata:
labels:
app.kubernetes.io/name: console
spec:
containers:
- name: console
imagePullPolicy: Always
image: "xxxxxx.dkr.ecr.eu-west-1.amazonaws.com/check:sample_1"
ports:
- containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
name: console
namespace: check
spec:
type: NodePort
selector:
app.kubernetes.io/name: console
ports:
- protocol: TCP
port: 3000
targetPort: 3000

在不同端口3001上运行的已部署的第二个服务。入口。以下是Yaml内容

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: check
name: ingress-check
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/load-balancer-name: t3
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/tags: product=check
alb.ingress.kubernetes.io/group.name: test
spec:
rules:
- host: t3-xxxxxx.eu-west-1.elb.amazonaws.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: console
port:
number: 3000

当我在上面的yaml中给出path为'/'时,服务1正在工作。我可以访问URL/api或URL/api2

当我将path设置为'/console'并应用yaml时,我无法访问api(在经典负载平衡器中,我们能够做到这一点)。<<strong> URL/控制台/api/strong>,URL/控制台/api2不可访问。

由于这个路径,问题是我们不能路由到多个服务运行在不同的端口基于路径。

我认为你想实现的是URL重写能力AWS ALB控制器。遗憾的是,目前还不支持此功能。

你可以在这里查看:

  • https://github.com/kubernetes-sigs/aws-load-balancer-controller/issues/835

还提到了一些您可以应用的解决方法,例如使用额外的后端将应用程序重定向到您的首选路径。

rules:
- host: main-app.net
http: 
paths:
- path: /app
pathType: Prefix
backend:
service:
name: main-app
port: 
number: 8080
- path: /
pathType: Exact
backend:
service:
name: redirect-to-main-app
port: 
name: use-annotation

或者您可以考虑另一种方法,即使用不同的Host为您的申请。例如:

  • console1.app.net
  • console2.app.net

多亏了@Binh Nguyen的回答,我们才知道ALB不支持URL重写。所以目前我们有一个解决方案,我在这里发布。

由于在重定向过程中没有删除给定的路径,因此我们在蓝图中为flask服务添加了与url前缀相同的路径。

from flask import Flask, Blueprint
from flask import jsonify
app_name = "Check1"
app_blueprint = Blueprint('app', __name__)
app = Flask(app_name)
curr_port = 3000

@app_blueprint.route('/', methods=['GET'])
def rootapi0():
data = {"code": 200, "source": "api1", "message": "This root service 1", "port": curr_port}
return jsonify(data)

@app_blueprint.route('/api1', methods=['GET'])
def api1():
data = {"code": 200, "source": "api1", "port": curr_port}
return jsonify(data)

@app_blueprint.route('/api2', methods=['GET'])
def api2():
data = {"code": 200, "source": "api2", "port": curr_port}
return jsonify(data)

app.register_blueprint(app_blueprint, url_prefix='/console')
if __name__ == "__main__":
app.run()

请注意,我们已经为api路由引入了蓝图,并为蓝图引入了url_prefix='/console'

同样,我们将第二个flask服务的url_prefix修改为/console2

在构建和部署此服务之后,对于路由,我们给出了以下ingress.yaml。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: check
name: ingress-check
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/load-balancer-name: t5
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/tags: product=check
alb.ingress.kubernetes.io/group.name: test
spec:
rules:
- http:
paths:
- path: /console
pathType: Prefix
backend:
service:
name: console
port:
number: 3000   
- path: /console2
pathType: Prefix
backend:
service:
name: console2
port:
number: 3001   

使用上面的yaml文件,我们可以重定向到相应的服务。