简体   繁体   中英

React App in Kubernetes is not connecting properly

I'm new to Kubernetes and I'm trying to deploy a React app to my cluster. Here's the basic info:

  • Docker Desktop, single-node Kubernetes cluster
  • React development frontend, exposing port 3000
  • Node.js/Express backend, exposing port 8080
  • NGINX Ingress Controller, serving my React frontend on "localhost:3000" and routing my Fetch API requests (fetch("localhost:3000/api/...", OPTIONS)) to the backend (which works)

I am having an issue when opening the React app. The Ingress Controller correctly routes to the app but the 3 bundles (bundle.js, main.chink.js, the third one which I don't remember) aren't loaded. I get the following error:

GET http://localhost/static/js/main.chunk.js net::ERR_ABORTED 404 (Not Found) ingress (one example)

I understand why this error happens. The Ingress Controller correctly routes the traffic but only loads the index.html file. In this file, there are calls to 3 scripts (referring to the bundles) which aren't loaded. I understand the error, the files don't get sent to the browser so the index.html file can't load them in, but do not know how to fix it. Does anyone have any suggestions? de and then pulled from Docker Hub. Does anybody know what a possible solution could be? For example, does deploying the build/ folder (built React app using "npm run build") fix this? Do I have to use nginx inside my Dockerfile to build the container?

Ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: titanic-ingress
  #labels:
      #name: titanic-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: localhost
    http:
      paths:
      - path: /
        pathType: Exact
        backend:
          service:
            name: titanicfrontendservice
            port:
              number: 3000
      - path: /api
        pathType: Exact
        backend:
          service:
            name: titanicbackendservice
            port:
              number: 8080

Ingress controller deployment yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-ingress
  namespace: nginx-ingress
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-ingress
  template:
    metadata:
      labels:
        app: nginx-ingress
     #annotations:
       #prometheus.io/scrape: "true"
       #prometheus.io/port: "9113"
    spec:
      serviceAccountName: nginx-ingress
      containers:
      - image: nginx/nginx-ingress:1.10.0
        imagePullPolicy: IfNotPresent
        name: nginx-ingress
        ports:
        - name: http
          containerPort: 80
        - name: https
          containerPort: 443
        - name: readiness-port
          containerPort: 8081
       #- name: prometheus
         #containerPort: 9113
        readinessProbe:
          httpGet:
            path: /nginx-ready
            port: readiness-port
          periodSeconds: 1
        securityContext:
          allowPrivilegeEscalation: true
          runAsUser: 101 #nginx
          capabilities:
            drop:
            - ALL
            add:
            - NET_BIND_SERVICE
        env:
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        args:
          - -nginx-configmaps=$(POD_NAMESPACE)/nginx-config
          - -default-server-tls-secret=$(POD_NAMESPACE)/default-server-secret
          #- -v=3 # Enables extensive logging. Useful for troubleshooting.
          - -report-ingress-status
          - -external-service=nginx-ingress
         #- -enable-prometheus-metrics
         #- -global-configuration=$(POD_NAMESPACE)/nginx-configuration

Ingress controller service yaml

apiVersion: v1
kind: Service
metadata:
  name: nginx-ingress
  namespace: nginx-ingress
spec:
  externalTrafficPolicy: Local
  type: LoadBalancer
  ports:
  - port: 3000
    targetPort: 80
    protocol: TCP
    name: http
  - port: 443
    targetPort: 443
    protocol: TCP
    name: https
  selector:
    app: nginx-ingress

The issue with your ingress.yaml is that the route for your ui should be /* and placed below the backend routing. Also, check your routing for APIs

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: titanic-ingress
  #labels:
      #name: titanic-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: localhost
    http:
      paths:
      - path: /api/*
        pathType: Exact
        backend:
          service:
            name: titanicbackendservice
            port:
              number: 8080
      - path: /*
        pathType: Exact
        backend:
          service:
            name: titanicfrontendservice
            port:
              number: 3000

TL;DR

Switch your pathType in both /api and / path to Prefix .

I've included some explanation with fixed Ingress resource below.


For the reproduction purposes I used the titanic manifests that you provided in the another question:

The issue with your configuration is with: pathType .

Using your Ingress resource with pathType: Exact showed me blank page.

Modifying your Ingress resource with pathType: Prefix solved the issue.

Side note!

The message: "Would you have survived the sinking of the Titanic?" showed.

The exact Ingress configuration should be following:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: titanic-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: localhost
    http:
      paths:
      - path: /
        pathType: Prefix # <-- IMPORTANT
        backend:
          service:
            name: titanicfrontendservice
            port:
              number: 3000
      - path: /api
        pathType: Prefix # <-- IMPORTANT
        backend:
          service:
            name: titanicbackendservice
            port:
              number: 8080

Why I think it happened?

Citing the official documentation:

Path types

Each path in an Ingress is required to have a corresponding path type. Paths that do not include an explicit pathType will fail validation. There are three supported path types:

  • ImplementationSpecific : With this path type, matching is up to the IngressClass. Implementations can treat this as a separate pathType or treat it identically to Prefix or Exact path types.

  • Exact : Matches the URL path exactly and with case sensitivity.

  • Prefix : Matches based on a URL path prefix split by /. Matching is case sensitive and done on a path element by element basis. A path element refers to the list of labels in the path split by the / separator. A request is a match for path p if every p is an element-wise prefix of p of the request path.

-- Kubernetes.io: Docs: Concepts: Services networking: Ingress: Path types (there are some examples on how the path matching is handled)

Ingress controller is forced to match only the / path leaving rest of the dependencies (apart from the index.html ) on other paths like /super.jpg and /folder/awesome.jpg to error with 404 code.

Side note!

You can test yourself this behavior by spawning an nginx Pod and placing example files in it. After applying the Ingress resource with / and pathType: Exact you won't be able to request it through the Ingress controller but you could access them within the cluster.


I encourage you to check the additional resources:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM