Deploying Vue apps to the cloud with Kubernetes
Published: 2023-07-29 22:31:57

by [Mercy Bassey](https://blog.openreplay.com/authors/mercy-bassey)

<blockquote><em>Vue.js has gained popularity among developers for its simplicity and flexibility in building dynamic and interactive front-end applications. However, in today's software development world, containers and orchestration have emerged as a powerful paradigm that is here to stay. In this article, we will delve into the deployment steps for applications in the cloud using Kubernetes. Let's dive in and uncover the benefits and workings of orchestrating Vue applications with Kubernetes.</em></blockquote>






While Kubernetes is widely known for its effectiveness in managing backend services, it also holds significant power in deploying a front-end containerized application. Containerization and orchestration have revolutionized application deployment and management, presenting front-end developers with newfound possibilities. By embracing containerization and orchestration, front-end developers can achieve easy deployability, scalability, and resilience across any infrastructure. This is where [Kubernetes](https://kubernetes.io/docs/concepts/overview/) comes in.

Before you embark on this tutorial, here are the requirements you must meet:

- **Docker Engine**: Make sure you have [Docker Engine](https://docs.docker.com/engine/) installed on your machine. Don't worry; the Docker Engine [documentation](https://docs.docker.com/engine/install/) has tailored installation instructions that perfectly match your operating system. So you'll be up and running in no time.

- **Docker Hub Account**: To share and store your Docker images, [create](https://docs.docker.com/docker-id/) an account on [DockerHub](hub.dockerhub.com). It's the hub for all things Docker-related. Follow the steps outlined in the Docker Hub documentation to set up a public [repository](https://docs.docker.com/docker-hub/repos/create/), where you can showcase your Docker images to the world. This article uses a repository called `vue-app`.

- **Docker CLI**: The docker engine comes with the Docker [CLI](https://docs.docker.com/engine/reference/commandline/cli/) that you can use to log in to your Docker Hub account from your machine. A simple [`docker login`](https://docs.docker.com/engine/reference/commandline/login/) command will do the trick. This step authenticates your Docker client, opening the door to endless possibilities and interactions with your Docker Hub repositories.

- **kubectl**: To communicate with Kubernetes, you'll need the [`kubectl`](https://kubernetes.io/docs/reference/kubectl/) command-line tool installed on your [machine](https://pwittrock.github.io/docs/tasks/tools/install-kubectl/). It's your trusty companion throughout this tutorial, enabling you to manage your Kubernetes cluster effortlessly.

- **Kubernetes Cluster**: You'll need a Kubernetes [cluster](https://kubernetes.io/docs/concepts/architecture/) to unleash the full power of your Vue.js app. It could be a cloud-based cluster provided by Google Kubernetes Engine [(GKE)](https://cloud.google.com/kubernetes-engine), AWS Elastic Kubernetes Service [(EKS)](https://aws.amazon.com/eks/), or Azure Kubernetes Service [(AKS)](https://azure.microsoft.com/en-us/products/kubernetes-service/). Alternatively, you can set up a local cluster using tools like [Minikube](https://minikube.sigs.k8s.io/docs/start/) or [Kind](https://kind.sigs.k8s.io/) for a more personalized experience.

By meeting these requirements, you're equipped with the essential tools and infrastructure to dive into the tutorial.


##  Building the Vue.js Application
To build a [VueJS](https://vuejs.org/guide/introduction.html) application efficiently, we'll utilize [Vite](https://vitejs.dev/guide/), a lightweight and fast build tool that optimizes and enables a seamless and rapid development experience.

Let's begin by setting up a Vue.js application using Vite. Open your terminal and run the following command:

```bash
npm create vue@3
```

This command will prompt you with a few questions. Make sure to set the project name as vue-k8s and enable vue-router as shown in the screenshot below:

![Building the Vue app with Vite](https://blog.openreplay.com/images/deploying-vue-apps-to-the-cloud-with-kubernetes/images/TYwvvh0.png)

Once the project is created, navigate into the working directory using the following command:
```bash
cd vue-k8s
```
Install all the dependencies required for the Vue application by running the following:
```bash
npm install 
```
![Going into the working directory and installing dependencies](https://blog.openreplay.com/images/deploying-vue-apps-to-the-cloud-with-kubernetes/images/R7EaJBu.png)


Once the application is set up, you can view the Vue application by running the command `npm run dev` from your working directory. After that, open up your preferred web browser and navigate to `localhost:5173`.

You should see the Vite welcome page and an `about` page, as shown in the screenshots below:

![Viewing the Vite welcome page](https://blog.openreplay.com/images/deploying-vue-apps-to-the-cloud-with-kubernetes/images/QudBEhr.png)

![Viewing the About page](https://blog.openreplay.com/images/deploying-vue-apps-to-the-cloud-with-kubernetes/images/qp137SB.png)

Now that you have a basic Vue application running, it's important to note that in a real-world scenario, it might consist of multiple routes, tests, and some form of state management. However, deploying the application to the cloud remains the same. For demonstration purposes, this current setup will suffice.


In the next section, you will explore the necessary steps to build and run the Vue application locally with Docker to confirm it works locally before heading to the cloud using Kubernetes.

##  Preparing the Vue.js App for Deployment

Every application running in the cloud requires containerization, which involves encapsulating it as a container image. The Vue.js application, in this case, is no exception. To prepare it for deployment with Kubernetes, you need to create a container image and ensure it runs smoothly as a Docker container on your local machine.

Docker utilizes a file called [`Dockerfile`](https://docs.docker.com/engine/reference/builder/) to build container images. Therefore, the first step is to create a `Dockerfile` at the root of the Vue project. This file will define the necessary instructions for building the Vue application image.

Inside the Dockerfile, you’ll need to specify the base image, copy the required files, configure [Nginx](https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/) as a reverse proxy, and expose the appropriate ports. These instructions ensure that the Vue application is properly configured and ready for deployment as a container.

```dockerfile
# Stage 1: Build Vue app
FROM node:18 as build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# Stage 2: Serve Vue app with Nginx
FROM nginx:1.25.1 as prod-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
```

I know you might be wondering why Nginx is included in the Dockerfile. Well, the reason is that Nginx, in this case, serves as a reverse proxy. But what does that mean?

In simple terms, a reverse proxy is a server that sits between clients and backend servers, acting as an intermediary for client requests. It receives incoming requests, forwards them to the appropriate backend server, and returns the response to the client.

In the Dockerfile, Nginx is included to fulfill this reverse proxy role. By utilizing Nginx as a reverse proxy, you leverage its capabilities to enhance request handling, load-balancing, scalability, serve static files effectively, and overall application performance.

To break things down properly, this Dockerfile comprises the `build-stage` and the `prod-stage` (also known as the production stage). In the build stage, we focus on building the Vue app, while in the production stage, we serve the built app using Nginx.

In the build stage, we are doing the following:
- We start with the base image `node:18`, which includes Node.js version 18. This stage is responsible for assembling the Vue app's dependencies and generating a production-ready build.
- We set the working directory inside the container to `/app`. This is where subsequent commands will be executed. 
- We copy the `package.json` and `package-lock.json` files (if present) from the local directory to the `/app` directory inside the container. This step allows Docker to cache the dependencies installation process for faster subsequent builds.
- We run `npm install` to install the project dependencies based on the `package.json file`. 
- We copy all the files and directories from the local directory into the current working directory inside the container. This includes the source code of the Vue app.
- Finally, to build the Vue app, we execute the `npm run build` command inside the container. This triggers the build process and typically generates a production-optimized app version in a dist directory.

Moving on to the production stage, we do the following:
- Switch to the base image `nginx:1.25.1`, which includes Nginx version 1.25.1. Here, our focus shifts to serving the Vue app using Nginx as a reverse proxy.
- We copy the contents of the dist directory (built in the previous stage) from the build-stage image to the `/usr/share/nginx/html` directory inside the current image. This step replaces the default Nginx files with our Vue app's production-optimized files.
- To allow incoming traffic, we expose port `80` in the container, which is the default port for HTTP traffic. 
- Finally, we use the `CMD` instruction to launch Nginx as the container's main process, using the "daemon off;" option to keep it running in the foreground.

With this Dockerfile, we can efficiently build our Vue app in the first stage and serve it with Nginx in the second stage, providing a streamlined and production-ready containerized deployment.

Docker provides a valuable isolated environment for building and running applications, although not as sophisticated as Kubernetes. However, if our application functions correctly using Docker, it is likely to exhibit the same behavior when deployed to Kubernetes.

> To push your Docker image successfully, you should already have a public repository on Docker Hub. If you haven't created one yet, follow the steps outlined in the Docker Hub documentation to create a public repository to store and share your Docker images.

To build and run the VueJS application, execute the following commands sequentially:

```bash
docker build -t <your_dockerhub_username>/<repository_name> .
```
The above command will build the Docker image for the Vue Application using the Dockerfile that was specified earlier in the current directory. The `-t` flag allows you to provide a tag for the image, and `<your_dockerhub_username>/<repository_name>` represents the desired image name and repository on Docker Hub.

Once the build is finished, though it might take some time, you should see the output similar to the following:

```bash
...
=> [build-stage 2/6] WORKDIR /app                                                                                                                        0.6s
=> [build-stage 3/6] COPY package*.json ./                                                                                                               0.2s
=> [build-stage 4/6] RUN npm install                                                                                                                     9.9s
=> [build-stage 5/6] COPY . .                                                                                                                            0.9s
=> [build-stage 6/6] RUN npm run build                                                                                                                   7.9s
=> [prod-stage 2/2] COPY --from=build-stage /app/dist /usr/share/nginx/html                                                                              0.2s
=> exporting to image                                                                                                                                    0.2s
=> => exporting layers                                                                                                                                   0.1s
=> => writing image sha256:ca8e02bd3bb75c1b5354488d8f552b42a36fe0e8a8769774f2015d67d0943fcd                                                              0.0s
=> => naming to docker.io/mercybassey/vue-app
```
Now, execute the following command to run the docker image as a container:

```bash
docker run -d -p 8080:80 <image_name>
```
From the command above, the `-d` flag detaches the container and runs it in the background, while the `-p` flag maps port `8080` on the host machine to port `80` inside the container. This enables access to the VueJS application via `localhost:8080` in your preferred web browser.

![Viewing the Vue App on port 8080](https://blog.openreplay.com/images/deploying-vue-apps-to-the-cloud-with-kubernetes/images/U9R1Tgl.png)

Once you have confirmed that the Vue App is working correctly, the next crucial step is pushing the image to Docker Hub. This step is essential to make the image accessible and shareable with others and allows for deployment to various environments.

Pushing the Docker image to Docker Hub makes it available in a centralized repository that other developers, collaborators, or deployment pipelines can access. It ensures that the image is readily available for deployment to Kubernetes clusters or other Docker-compatible infrastructures.

To push the Docker image to your Docker Hub repository, run the following command:

```bash
docker push <your_dockerhub_username>/<your_dockerhub_repository_name>:latest
```
This process may take some time, and once it is completed, you will receive an output similar to the following:

```bash
...
4ca29ffc4a01: Mounted from library/nginx 
a83110139647: Mounted from library/nginx 
ac4d164fef90: Mounted from library/nginx 
latest: digest: sha256:fb78ef251d5bd24ca84129cbbfbdbc0a2eb7936c5944a36bc2a7de3a9e2d15da size: 1987
```

![Viewing the Vue App docker image on docker hub](https://blog.openreplay.com/images/deploying-vue-apps-to-the-cloud-with-kubernetes/images/EMeEepx.png)

With the Docker image of your Vue App successfully pushed to Docker Hub, you are now ready to proceed with Kubernetes and begin the deployment process.


<div style="background-color:#efefef; border-radius:8px; padding:10px; display:block;">
<hr/>
<h3><em>Session Replay for Developers</em></h3> 
<p><em>Uncover frustrations, understand bugs and fix slowdowns like never before with <strong><a href="https://github.com/openreplay/openreplay" target="_blank">OpenReplay</a></strong> — an open-source session replay suite for developers. It can be <strong>self-hosted</strong> in minutes, giving you complete control over your customer data.</em></p>
<img alt="OpenReplay" style="margin-top:5px; margin-bottom:5px;" width="768" height="400" src="https://raw.githubusercontent.com/openreplay/openreplay/main/static/openreplay-git-hero.svg" class="astro-UXNKDZ4E" loading="lazy" decoding="async">
<p><em>Happy debugging! <a href="https://openreplay.com" target="_blank">Try using OpenReplay today.</a></em><p>
<hr/>
</div>


## Deploying to Kubernetes
To begin the deployment process to Kubernetes, the first thing to do is to create a Kubernetes [deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) object. This deployment object serves as an instruction set for Kubernetes, informing it on how to deploy your Vue application and any other application.

By defining the deployment object, you specify details such as the Docker image to use, the number of replicas (instances) of your application to run, networking configurations, and more. Kubernetes uses this information to ensure your application is deployed and managed effectively within the cluster.

Additionally, creating a deployment object allows Kubernetes to handle important aspects like scaling, load balancing, and self-healing. It ensures that your Vue.js app is always available and running smoothly, even in the face of failures or increased traffic.

To create a deployment object, create a file called `vue-deployment.yaml` from your terminal app or command prompt and paste the configuration settings below:

> In Kubernetes, YAML files are used for resource configuration; in this case, to define your applications' desired state, you need to define it using a `.yaml` file. This will allow you to specify how your application should be deployed and managed in a Kubernetes environment.

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
 name: my-vue-app
spec:
 replicas: 3
 selector:
   matchLabels:
     app: my-vue-app
 template:
   metadata:
     labels:
       app: my-vue-app
   spec:
     containers:
     - name: my-vue-app-container
       image: <your_dockerhub_username>/vue-app:latest
       ports:
       - containerPort: 8080

```

This deployment defines the following:
- Defines a deployment named `my-vue-app`.
- Instruct Kubernetes to create three instances of the Vue application using the command (`replicas: 3`).
- Specifies that it should match labels with the value `my-vue-app` to ensure proper selection.
- Specifies container details in the `template` block, such as the container name (my-vue-app-container) and the Docker image (`<your_dockerhub_username>/vue-app:latest`) from Docker Hub.

> For more information about Kubernetes deployments, see the following [guide](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) from the official Kubernetes documentation.

Now execute the `kubectl` command to create this deployment in your Kubernetes cluster:

```bash
kubectl apply -f vue-deployment.yaml
```
![Creating a deployment](https://blog.openreplay.com/images/deploying-vue-apps-to-the-cloud-with-kubernetes/images/jS0opUz.png)
To confirm if the deployment has been created successfully, execute the following kubectl command:

```bash
kubectl get deployments
```
![Viewing the deployment](https://blog.openreplay.com/images/deploying-vue-apps-to-the-cloud-with-kubernetes/images/dwvpzxR.png)
To see the instances of the Vue application (also called [pods](https://kubernetes.io/docs/concepts/workloads/pods/#what-is-a-pod)), execute the following `kubectl` command:

```bash
kubectl get pods
```
![Viewing the pods/instances created by the deployment](https://blog.openreplay.com/images/deploying-vue-apps-to-the-cloud-with-kubernetes/images/KBHXreW.png)

Now that you have successfully created the deployment, the next thing to do is create a Kubernetes [service](https://kubernetes.io/docs/concepts/services-networking/service/) object for the `my-vue-app` deployment so you can view the application.

> Kubernetes services are an abstraction layer that provides network connectivity and load balancing for applications running within a Kubernetes cluster. You can see the [official Kubernetes documentation](https://kubernetes.io/docs/concepts/services-networking/service/) to learn more.

Execute the following `kubectl` command:

```bash
kubectl expose deploy my-vue-app --port 8080 --target-port=80 --type=NodePort
```
The command above will expose the `my-vue-app` deployment with a service named "my-vue-app" with the type `NodePort`. It will expose the pods from the "my-vue-app" deployment on port `8080` and forward incoming traffic to the pods on port `80`. You should see the following output once the service is created:

> Kubernetes offers a wide range of service types to cater to various networking requirements. You can see the following [guide](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types).

![Viewing NodePort service for the *my-vue-app* deployment](https://blog.openreplay.com/images/deploying-vue-apps-to-the-cloud-with-kubernetes/images/TmlzKRk.png)

Next, execute the following command to view the service:
```bash
kubectl get services
```
![-](https://blog.openreplay.com/images/deploying-vue-apps-to-the-cloud-with-kubernetes/images/IP32zDW.png)

> By default, NodePort services in Kubernetes listen on a port range of `30000-32767`. In the provided image, the NodePort service is configured to listen on port `31370`. If the port is not explicitly specified during service creation, Kubernetes automatically assigns a port within the default range.

A NodePort exposes an application outside of the cluster on a specific port across all nodes in the cluster. It allows external access to the service using the IP address of any node in the cluster and the allocated port.

In this case, you should be able to view the Vue application on the following address `<node-ip>:<NodePort-port>`.

But before that, retrieve the IP of any of your cluster nodes using the following command:

```bash
kubectl get node <node-name> -o jsonpath='{.status.addresses[?(@.type=="InternalIP")].address}'
```
![-](https://blog.openreplay.com/images/deploying-vue-apps-to-the-cloud-with-kubernetes/images/bbwnIJb.png)

Now head to your preferred browser and visit the following address - `<node-ip>:<NodePort-port>` to view the Vue application. You should see the following outputs on both the `home` and `about` routes:

![Viewing the Vue applications' home page](https://blog.openreplay.com/images/deploying-vue-apps-to-the-cloud-with-kubernetes/images/c7wX135.png)

![Viewing the About page](https://blog.openreplay.com/images/deploying-vue-apps-to-the-cloud-with-kubernetes/images/TFd4RKh.png)

With this, you have successfully deployed a Vue application to the cloud using Kubernetes.

## Summary
Kubernetes is an awesome tool, I must say. And throughout this tutorial, you have seen how to use its container-wielding powers to deploy a Vue application to the cloud.

With this newfound knowledge and with Kubernetes by your side, you can now conquer the challenges of deploying and managing a Vue application in the cloud like a true champion.