Dockerizing Vue.js App on Google Compute Engine

Bahar Shah
5 min readFeb 5, 2021
Vue.js, Docker and Google Cloud present a solution to deploying and hosting webapps.

Deciding how to host and deploy your frontend webapps is a common question these days. From handling via an existing all-in-one platform like Netlify to hosting the compiled assets in something like S3 and serving via CloudFront there are many options available to choose from.

The method I’m discussing here will outline how to run your app in a Docker container, push the Docker image to the Google Container Registry, deploy the gcr.io image to a Google Cloud GCE VM leveraging instance groups and finally show how to configure a load balancer in front of your webapp.

Vue.js is a Javascript framework that is versatile, performant and very easy to use. The example outlined here is specifically for a Vue.js app however a similar process of configuring a Dockerfile that builds the app assets will work for other frameworks like React.

Please note: this article assumes that your Vue.js app already exists and so will not discuss the setup/creation of the webapp itself.

1. Configure Dockerfile

Create the Dockerfile in your root folder. Note this Dockerfile is utilizing multiple stages via the Docker multi-stage builds. The build stage here is responsible for building the Vue.js app artifacts and the production stage is responsible for serving using NGINX. You do not need to use NGINX to actually serve the app. The simple http server is great for simple scenarios and prototyping but NGINX is well known and extremely performant for production usecases.

# build stage
FROM node:14 as build-stage
WORKDIR .# copy package.json and package-lock.json (for more details on why we copy both these files and the project files and folders check this link out.
COPY package*.json ./
# install project dependencies
RUN npm install
# copy project directory to the working directory
COPY . .
# build app
RUN npm run build
# production stage
FROM nginx:stable-alpine as production-stage
COPY --from=build-stage dist /usr/share/nginx/html# specify port to access webapp through
EXPOSE 80
CMD [ "http-server", "dist", "-p", "80"]

You can build the Docker image and run the Vue.js app in a Docker container locally to verify it works as expected using the docker build . -t <project name>and docker run -it -p 8080:80 — rm — name <name> <project name>commands. You should be able to confirm your app is running locally at localhost:8080 at this point.

2. Push the Docker image to Google Container Registry

Ok, we have the Docker image. Now what? We want to push it to Google Container Registry since that is how Google Cloud has built-in support for images. Make sure your project id is correctly set (gcloud config get-value core/project) and that you have configured gcloud docker auth if needed (gcloud auth configure-docker ).

# create a tag for the Docker image
docker tag <project name> gcr.io/$PROJECT_ID/<project name>:<version>
# enable the containerregistry.googleapis.com service
gcloud services enable containerregistry.googleapis.com
# push the docker image to gcr.io
docker push gcr.io/$PROJECT_ID/<project name>:<version>

3. Deploy the gcr.io image to GCE

We now have our gcr.io image and need to actually deploy it to a Google Cloud GCE VM.

Some variables you will need to define include the Project ID, the machine type for the VM, the boot disk size, a service account that has been configured, your container image name, the instance template name and the base instance name as well as the zone you want the VM to run in.

# build and push the image if it hasn't already been done
docker build -f Dockerfile -t <image name> .
docker push <image name>
# create the instance template
gcloud compute instance-templates create-with-container \
<image name>-template-<Unique Tag> \
--project=$PROJECT \
--machine-type=$MACHINE_TYPE \
--boot-disk-size=$BOOT_DISK_SIZE \
--service-account=$SERVICE_ACCOUNT \
--scopes=https://www.googleapis.com/auth/cloud-platform \
--container-image=<image name>
# create instance group
gcloud compute instance-groups managed create \
<instance group name>\
--project=$PROJECT \
--base-instance-name=<instance name> \
--size=1 \
--template <instance template name>\
--zone=<zone>
# if the instance group already exists you can update it instead
gcloud compute instance-groups managed rolling-action start-update \
<instance group name>\
--project=$PROJECT \
--version template=<instance template name> \
--zone=<zone>

4. Configure a load balancer in Google Cloud

At this point you should be able to confirm that your app is running successfully by accessing the external ip for your instance. If you are planning on running this in a production environment however you will most likely want to set up load balancing and your own public IP and domain.

The configuration of the load balancer can be done in the Google Cloud Console quite easily.

Manually setup HTTP(S) Load Balancer in GCP console

You want to create a HTTP(S) Load Balancer that is internet facing, and then configure the backend services for the incoming traffic, the host and path rules to specify how your traffic will be directed and the frontend IP for your client.

You can also specify health checks for your load balancer and service configurations.

If there is enough interest on this, I may do a separate post deep diving into some of the nuances in load balancing because there are many details and things to configure here.

If all goes well at this point you should have an external IP that loads the webapp fully hosted on GCE!

Benefits of Dockerizing your Vue.js App

There are a few clear pros to Dockerize your Vue.js app:

  • Building your frontend app as a separate service that is independently deployable allows you to decouple your frontend and backend deployments from each other. It also fits well with the microservices architectural style overall.
  • Versioning is easily done with tags.
  • Running the service locally on a laptop versus in the production environment is basically the same and allows for faster iteration and development.
  • Eventually hooking up to CI/CD where the Docker image is the final build artifact and so can be verified against a continuous delivery pipeline easily.

--

--

Bahar Shah

Software engineer/manager by day. Baker, reader and wannabe film critic by night.