Skip to content

Deliver assets from Object Storage

Overview

This How-To will show you how to deliver assets from the S3 compatible Object Storage with ingress-nginx. As the Object Storage does not support CORS headers at this time, this is necessary to avoid CORS errors.

For more detailed information about CORS, check out Mozilla's great documentation.

Prerequisites

  • A MetaKube Cluster with ingress-nginx installed
  • A public Object Storage bucket (all assets need to be public, too), see the reference for details
  • (optional) A deployed application

For this configuration to work, your assets have to be served at one or more distinct paths, for example /assets or /img as all requests to those paths will be served from the S3 bucket.

Create a Service for the S3 bucket

To use the S3 bucket as upstream for the ingress-nginx, we need to make it available as a Service:

apiVersion: v1
kind: Service
metadata:
  name: assets
spec:
  type: ExternalName
  externalName: $BUCKET.s3.$REGION.cloud.syseleven.net

Replace

  • $BUCKET with the name of your bucket, for example assets-test
  • $REGION with the region where your bucket is located (for example dbl)

Create an ingress for the asset paths

Then we only need to add an Ingress resource for the paths that the assets have:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/backend-protocol: HTTPS
    nginx.ingress.kubernetes.io/upstream-vhost: $BUCKET.s3.$REGION.cloud.syseleven.net
  name: assets-ingress
spec:
  # No TLS config needed, only one ingress for a hostname needs to have the TLS config, see https://github.com/kubernetes/ingress-nginx/issues/4106#issuecomment-494305090
  rules:
    - host: $APPLICATION_HOSTNAME
      http:
        paths:
          - path: /img/
            backend:
              serviceName: assets
              servicePort: 443
          - path: /css/
            backend:
              serviceName: assets
              servicePort: 443

Replace

  • as above: $BUCKET with the name of your bucket, for example assets-test
  • as above: $REGION with the region where your bucket is located (for example dbl)
  • $APPLICATION_HOSTNAME with the hostname your application is served at

and add as many elements to path as you need.

Once you've applied both resources, all requests to the specified paths for your hostname will be served from the bucket, all other requests will still go to your application.

Please note that for this to work, the asset paths in the Ingress above must always be the most specific paths. If the Ingress resource of your application has for example configuration for the path /img/backend, requests to this path will still go to your application.

Additional notes

To use this in production, you need to consider that this adds the Object Storage bucket as a dependency on the server-side. Therefore, faults of the backend should be handled gracefully by tuning timeouts and retry values for the Ingress object.

For assets, allowing them to be cached for a very long time is usually desirable. Consider adding the relevant headers with a nginx.ingress.kubernetes.io/configuration-snippet annotation.

As resources are served indirectly from the bucket, this will introduce a small latency overhead.