How to serve static contents in a kubernetes application

ghz 7months ago ⋅ 185 views

I have a small java webapp comprising of three microservices - api-service,book-service and db-service all of which are deployed on a kubernetes cluster locally using minikube.

I am planning to keep separate UIs for api-service and book-service , with the common static files served from a separate pod, probably an nginx:alpine image.

I was able to create a front end that serves the static files from nginx:alpine referring to this tutorial.

I would like to use ingress-nginx controller for routing requests to the two services.

The below diagram crudely shows where I am now.

I am confused as to where I should place the pod that serves the static content, and how to connect it to the ingress resource.I guess that keeping a front end pod before ingress defeats the purpose of ingress-nginx controller. What is the best practice to serve static files. Appreciate any help. Thanks.

[enter image description here

Answers

Looks like you are confusing the fact that users, browsing online, will trigger standard requests to both "download" your static content, and use your 2 APIs (book and api). It's not the NGINX service serving the static content that is accessing your APIs, but the users browsers/applications, and they do that exactly the same for both static content and APIs (former has more/specific headers and data, like auth...).

On your diagram you'll want to put your new static-service at the exact same level as your book-service and api-service, ie behind the ingress. But your static-service won't have a link with the db-service like the other 2. Then just complete your ingress rules, with the static-service at the end as in this example:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: your-global-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - path: /book-service
        backend:
          serviceName: book-service
          servicePort: 80
      - path: /api-service
        backend:
          serviceName: api-service
          servicePort: 80
      - path: /
        backend:
          serviceName: static-service
          servicePort: 80

You'll have to adjust your services names and ports, and pick the paths you want your users to access your APIs, in the example above you'd have:

  • foo.bar.com/book-service for your book-service
  • foo.bar.com/api-service for the api-service
  • foo.bar.com/ ie everything else going to the static-service

To serve static files efficiently in a Kubernetes setup using an Ingress controller, you can leverage the NGINX Ingress controller itself to serve the static files directly, eliminating the need for an additional NGINX pod. This approach simplifies the architecture and takes full advantage of the Ingress capabilities.

Here’s how you can set it up:

  1. Deploy your microservices and static files service:

    • Ensure your api-service, book-service, and db-service are deployed as individual services in your Kubernetes cluster.
    • Deploy an NGINX pod that serves your static files. This pod will be responsible for hosting your frontend assets.
  2. Create a ConfigMap for static files (optional):

    • If your static files are small and infrequently changed, you can include them in a ConfigMap. For larger or frequently changing files, use a PersistentVolume or a Docker image with the static files.
  3. Define the Ingress resource:

    • Configure the Ingress resource to route traffic to your api-service, book-service, and the static files service.

Here’s a step-by-step guide:

Step 1: Deploy the Microservices

Ensure you have your deployments and services set up for api-service and book-service. Here’s a simple example for one of the services:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-service
spec:
  replicas: 2
  selector:
    matchLabels:
      app: api-service
  template:
    metadata:
      labels:
        app: api-service
    spec:
      containers:
      - name: api-service
        image: your-docker-registry/api-service:latest
        ports:
        - containerPort: 8080

---
apiVersion: v1
kind: Service
metadata:
  name: api-service
spec:
  selector:
    app: api-service
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

Repeat this for the book-service and db-service.

Step 2: Deploy the Static Files Service

Create a deployment for the NGINX pod to serve static files. You can create a Docker image with your static files or use a PersistentVolume.

Using a Docker Image

Create a Dockerfile for your static files:

FROM nginx:alpine
COPY ./static-files /usr/share/nginx/html

Build and push the Docker image to your registry:

docker build -t your-docker-registry/static-files:latest .
docker push your-docker-registry/static-files:latest

Create a deployment for the static files service:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: static-files
spec:
  replicas: 1
  selector:
    matchLabels:
      app: static-files
  template:
    metadata:
      labels:
        app: static-files
    spec:
      containers:
      - name: static-files
        image: your-docker-registry/static-files:latest
        ports:
        - containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  name: static-files
spec:
  selector:
    app: static-files
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

Step 3: Create the Ingress Resource

Configure the Ingress resource to route traffic to your services and static files. Here’s an example:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: myapp.local
    http:
      paths:
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 80
      - path: /books
        pathType: Prefix
        backend:
          service:
            name: book-service
            port:
              number: 80
      - path: /static
        pathType: Prefix
        backend:
          service:
            name: static-files
            port:
              number: 80

Step 4: Test the Setup

  • Ensure the Ingress controller is running in your cluster.
  • Add an entry to your /etc/hosts file to map myapp.local to your Minikube IP:
echo "$(minikube ip) myapp.local" | sudo tee -a /etc/hosts
  • Access your services via the browser:

    • http://myapp.local/api for the api-service
    • http://myapp.local/books for the book-service
    • http://myapp.local/static for the static files

This setup uses the NGINX Ingress controller to route requests to your services and static files, ensuring a simple and efficient architecture.