Ship internal tools in hours, not weeks. Real auth, users, jobs, audit logs, and cohesive UI included. Early access $249 $499 → [Get it now]

How to deploy Angular on Kubernetes

Deploying an Angular application to Kubernetes is a standard requirement for modern, scalable web applications.
With over 25 years of experience in software development and as the creator of CoreUI, I have architected and deployed numerous enterprise-grade frontend applications using container orchestration.
The most efficient and modern approach involves creating a multi-stage Docker build to compile your app and then serving the static assets via Nginx within a Kubernetes cluster.
This method ensures your production environment is lightweight, secure, and easily manageable through declarative configuration files.

Containerize your Angular application using Nginx and deploy it using Kubernetes Deployment and Service manifests.

Building the Docker Image

The first step is creating a Dockerfile that uses a multi-stage build. This separates the build environment from the runtime environment, significantly reducing the final image size and improving security.

# Stage 1: Build the Angular application
FROM node:20-alpine as build-step
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build -- --configuration=production

# Stage 2: Serve the application using Nginx
FROM nginx:1.25-alpine
# Angular 17+: output is in dist/my-angular-app/browser
# Angular 16 and earlier: output is in dist/my-angular-app
COPY --from=build-step /app/dist/my-angular-app/browser /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

In this setup, we first use a Node.js image to install dependencies and run the production build. Once the dist folder is generated, we copy only those static files into a lightweight Nginx image. This ensures your Kubernetes pods don’t carry unnecessary build tools or source code. Save the nginx.conf file in the root of your project alongside the Dockerfile so the COPY instruction can find it.

Configuring Nginx for Angular Routing

Angular is a Single Page Application (SPA), which means the client-side router handles navigation. Without a proper Nginx configuration, refreshing the page on any route other than the root will result in a 404 error.

server {
  listen 80;
  server_name localhost;
  root /usr/share/nginx/html;
  index index.html;

  location / {
    try_files $uri $uri/ /index.html;
  }

  error_page 500 502 503 504 /50x.html;
  location = /50x.html {
    root /usr/share/nginx/html;
  }
}

This configuration tells Nginx to try serving the requested file as a static asset. If the file doesn’t exist (which is common with SPA routes), it redirects the request to index.html, allowing the Angular router to take over. This is a critical step for any Angular Dashboard Template deployment.

Defining the Kubernetes Deployment

The Deployment manifest defines the desired state for your application pods. It specifies which image to use, how many replicas should run, and how the containers should be configured.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: angular-app-deployment
  labels:
    app: angular-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: angular-app
  template:
    metadata:
      labels:
        app: angular-app
    spec:
      containers:
      - name: angular-container
        image: your-registry/angular-app:latest
        ports:
        - containerPort: 80
        resources:
          limits:
            cpu: '500m'
            memory: '512Mi'
          requests:
            cpu: '250m'
            memory: '256Mi'

This YAML file ensures that three instances (replicas) of your Angular app are always running. It also includes resource limits to prevent a single pod from consuming all cluster resources. By using labels and selectors, Kubernetes manages the lifecycle of these pods efficiently.

Exposing the App with a Service

A Kubernetes Service provides a stable IP address and DNS name for your pods. Since pods are ephemeral and can be restarted with different IPs, the Service acts as a load balancer for internal or external traffic.

apiVersion: v1
kind: Service
metadata:
  name: angular-app-service
spec:
  selector:
    app: angular-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: ClusterIP

Using ClusterIP exposes the service on a cluster-internal IP. This is ideal when you intend to use an Ingress controller to manage external access. If you need direct external access without an Ingress, you could change the type to LoadBalancer.

Managing Traffic with Ingress

Ingress is the most professional way to expose your Angular application to the internet. It allows you to manage SSL termination, path-based routing, and host-based virtual hosting.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: angular-app-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  rules:
  - host: my-angular-app.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: angular-app-service
            port:
              number: 80
  tls:
  - hosts:
    - my-angular-app.com
    secretName: angular-app-tls

The Ingress resource maps the external hostname my-angular-app.com to your internal Service. It also integrates with cert-manager to automatically provision and renew SSL certificates from Let’s Encrypt, ensuring your application is served over HTTPS.

Handling Configuration via ConfigMaps

Frontend applications often need different API URLs depending on the environment. Since Angular is compiled into static files, you can use a ConfigMap to inject a configuration file at runtime or use a script to replace placeholders.

apiVersion: v1
kind: ConfigMap
metadata:
  name: angular-config
data:
  env-config.json: |
    {
      "apiUrl": "https://api.production.com",
      "enableFeatureX": true
    }

By mounting this ConfigMap as a volume in your pod, you can make the JSON file available to your Nginx server. Your Angular application can then fetch this JSON file at startup to configure its services dynamically without needing to rebuild the Docker image for every environment.

Best Practice Note:

Always use health checks (liveness and readiness probes) in your Deployment manifests. This allows Kubernetes to know when your pod is ready to accept traffic or if it needs to be restarted. This is the same philosophy we follow in CoreUI to ensure high availability and reliability in production environments. For further optimization, consider using a CDN in front of your Kubernetes Ingress to cache static assets globally.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author

Subscribe to our newsletter
Get early information about new products, product updates and blog posts.
Passing props to child components in React function components
Passing props to child components in React function components

How to Use Bootstrap Tooltip in Vue 3 – The Right Way with CoreUI
How to Use Bootstrap Tooltip in Vue 3 – The Right Way with CoreUI

What are the three dots `...` in JavaScript do?
What are the three dots `...` in JavaScript do?

How to loop inside React JSX
How to loop inside React JSX

Answers by CoreUI Core Team