首页 > 解决方案 > Kubernetes 入口服务不适用于不同于 root 的 URL

问题描述

我正在由 React FE 和 Spring Boot BE 组成的本地 k8s 集群上测试一个简单的应用程序。集群在 1.14.8 版(docker desktop 2.1.0.5)的 windows 的 docker desktop 内运行。

我的问题是配置的入口服务似乎无法路由 BE 部署的流量,而 FE 的效果很好(我实际上可以在浏览器中看到 react 应用程序,但其余对 BE 的调用失败)。我尝试了不同的解决方案,但我无法理解我的配置有什么问题。

FE 镜像暴露了 3000 端口,BE 镜像暴露了 8080 端口(使用根路径/apptest),使用 docker run 运行镜像都按预期工作,响应这些端口上的请求。

对于 k8s 配置,我为这两个映像定义了一个部署,FE 使用 containerPort 3000,BE 使用 containerPort 8080。然后我创建了两个 ClusterIP 服务,一个用于 FE,端口为 3000 和 targetPort 3000,另一个用于 BE,端口为 8080 和 targetPort 8080。

入口服务被配置为响应任何带有路径/到 servicePort 3000(FE)的请求以及任何以/api开头的到 servicePort 8080(BE,在这种情况下删除“api”位)的请求。FE 配置为使用/api路径启动后端调用。

在 k8s 集群上应用文件时,它都可以正确启动,并且在 pod 内没有错误,我可以访问 http://localhost 上的 react 应用程序。但是,如果我尝试使用 url http://localhost/api/apptest 调用后端,它们会失败并给出 502 Bad Gateway 错误。

FE Dockerfile

FROM node:12-alpine as builder
WORKDIR /app
COPY ./package*.json ./
RUN npm install
COPY . .
RUN npm run build

FROM nginx
EXPOSE 3000
COPY ./nginx/default.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /app/build /usr/share/nginx/html

FE Nginx 配置

server {
    listen 3000;

    location / {
        root /usr/share/nginx/html;
        index index.html index.htm;
        try_files $uri $uri/ /index.html;
    }
}

是 Dockerfile

FROM java:8
VOLUME /tmp
ARG JAR_FILE
ADD ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

FE 部署

apiVersion: apps/v1
kind: Deployment
metadata:
  name: apptest-fe-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      component: apptest-fe # uguale al template specificato sotto
  template:
    metadata:
      labels:
        component: apptest-fe
    spec:
      containers:
        - name: apptest-fe
          imagePullPolicy: Always
          image: registryipaddress:5000/apptestgroup/apptest-fe:latest
          resources:
            limits:
              memory: "128Mi"
              cpu: "10m"
          ports:
            - containerPort: 3000

FE集群IP

apiVersion: v1
kind: Service
metadata:
  name: apptest-fe-cluster-ip
spec:
  type: ClusterIP
  selector:
    component: apptest-fe
  ports:
    - port: 3000
      targetPort: 3000

BE部署

apiVersion: apps/v1
kind: Deployment
metadata:
  name: apptest-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      component: apptest # uguale al template specificato sotto
  template:
    metadata:
      labels:
        component: apptest
    spec:
      containers:
        - name: apptest
          imagePullPolicy: Always
          # Di default kubernetes va su docker hub a recuperare l'immagine.
          # Se il tag dell'immagine inizia con un indirizzo ip, lo interpreta come
          # il registro da cui pullare l'immagine.
          image: registryipaddress:5000/apptestgroup/apptest:latest
          resources:
            limits:
              memory: "128Mi"
              cpu: "10m"
          ports:
            - containerPort: 8080

是集群IP

apiVersion: v1
kind: Service
metadata:
  name: apptest-cluster-ip
spec:
  type: ClusterIP
  selector:
    component: apptest
  ports:
    - port: 8080
      targetPort: 8080

入口服务

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: apptest-ingress-service
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  rules:
    - http:
        paths:
          - path: /?(.*)
            backend:
              serviceName: apptest-fe-cluster-ip
              servicePort: 3000
          - path: /api/?(.*)
            backend:
              serviceName: apptest-cluster-ip
              servicePort: 8080

来自 Chrome 的 502 错误

xhr.js:172 POST http://localhost/api/apptest/documents/base64/aaa333 502 (Bad Gateway)...
createError.js:16 Uncaught (in promise) Error: Request failed with status code 502
    at e.exports (createError.js:16)
    at e.exports (settle.js:17)
    at XMLHttpRequest.f.onreadystatechange (xhr.js:59)

我有点确信问题出在为 ReactApp 提供服务的 FE 容器中的 nginx,它以某种方式绕过入口服务并尝试将流量路由到它不知道的路径,但我不确定如何找到一种解决方法。

更新

我尝试将 FE 映射到入口服务中的 /app,以便检查问题是否出在容器内的 nginx 上。导航到 http://localhost/app 反应应用程序工作,即使不完全,但尝试与邮递员联系 http://localhost/api/apptest 仍然给出 502 错误

标签: dockernginxkubernetesnginx-ingress

解决方案


每次都会匹配第一个入口规则,请求不会到达 BE。检查位置块是如何生成的:https ://kubernetes.github.io/ingress-nginx/user-guide/ingress-path-matching/

您将在 nginx 中得到以下内容:

location ~* ^/?(.*) {
  ...
}

location ~* "^/api/?(.*)" {
  ...
}

作为遇到入口问题时的建议,请始终检查日志以查看哪个服务获取请求。并在调试时直接在浏览器中访问http://localhost/api/apptest/documents/base64/aaa333,比通过前端更不容易出错。


推荐阅读