Kubernetes入口服务不适用于不同于root的url

时间:2020-01-02 09:33:49

标签: docker nginx kubernetes nginx-ingress

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

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

FE映像公开端口3000,而BE映像公开端口8080(具有根路径 / apptest ),使用docker运行映像将按预期运行,并在这些端口上回答请求。 / p>

对于k8s配置,我已经定义了两个映像的部署,其中FE的containerPort 3000和BE的containerPort 8080。然后,我创建了两个ClusterIP服务,一个用于具有端口3000和targetPort 3000的FE,一个用于具有端口8080和targetPort 8080的BE。

将入口服务配置为回答路径为 / 到servicePort 3000(FE)的任何请求,以及所有以 / api 开头的对servicePort 8080(BE的请求) ,在这种情况下,请删除“ api”位)。 FE配置为使用 / api 路径开始后端调用。

在k8s集群上应用文件时,所有文件都可以正确启动,并且在pod内没有错误,我可以在http://localhost上访问react应用程序。但是,如果我尝试使用网址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;
    }
}

BE 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 ClusterIP

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

BE ClusterIP

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映射到ingress服务中的/ app,以便检查问题是否出在容器内的nginx上。导航到http://localhost/app的React应用程序即使没有完全运行也可以运行,但是尝试与邮递员联系http://localhost/api/apptest仍然会出现502错误

3 个答案:

答案 0 :(得分:1)

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

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

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

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

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

答案 1 :(得分:1)

这不是入口问题,我转载了您的情况,并且您的语法正确。

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: test-ingress-service
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  rules:
  - host: hello-world.info
    http:
      paths:
      - path: /?(.*)
        backend:
          serviceName: web
          servicePort: 8080
      - path: /api/?(.*)
        backend:
          serviceName: webv2
          servicePort: 8080

测试输出:

user@minikube:~$ curl http://hello-world.info/aaa.any
Hello, world! Version: 1.0.0
Hostname: web-9bbd7b488-hlxd4

user@minikube:~$ curl http://hello-world.info/api/bbb.any
Hello, world! Version: 2.0.0
Hostname: web2-74cf4946cc-8c586

user@minikube:~$ curl http://hello-world.info/
Hello, world! Version: 1.0.0
Hostname: web-9bbd7b488-hlxd4

user@minikube:~$ curl http://hello-world.info/api/
Hello, world! Version: 2.0.0
Hostname: web2-74cf4946cc-8c586

Github Ingress-nginx Docs-入口路径匹配:

为了实现更精确的路径匹配,在将路径作为位置块写入NGINX模板之前,ingress-nginx首先按降序长度对路径进行排序

您的上一次更新明确表明问题出在您的后端应用程序中,因为它返回了相同的502 Bad Gateway。 请仔细检查。

答案 2 :(得分:0)

事实证明,问题在于分配给后端应用程序的资源。我将它们设置得很低,因为在我的PC上,pod无法启动。我向部署配置中添加了更多资源,现在一切都按预期工作。

让我认为问题出在其他方面是,即使资源不足,pod仍将正常启动(并保持启动状态),并且即使在spring boot应用程序中的tomcat也不报告容器内部的任何问题。显然没有正常运行。