Introduction
Deploying a vue application on cloud run is as straight forward as deploying a node application on cloud run. Deploying a vue application with access to environment variables? not so much. In this article, we will take a look at how we can deploy a vue application on cloud run as well as how we can access environment variables at run time.
Prerequisites
This tutorial uses the following:
- Must have a user account on GCP (Google Cloud Platform)
- Must have Docker installed (version >= 18.09.0)
- Must have node installed (version >= 12.5.0)
- Must have npm installed (version >= 6.9.0)
- Must have vue-cli installed
- Must have a basic knowledge of vue
- Must have a basic knowledge of docker
- Must have a basic knowledge of bash
If you have the first six prerequisites sorted out you can proceed to the next section.
Create a Vue Application
In this section, we are going to set up our vue application and build it into a docker image.
Let's create a vue application by running the following commands:
$ vue create <app-name>
Since this tutorial is geared towards deploying a vue application on cloud run (CR) we are not going all out on features, we will keep it simple.
If your installation is right, you should see the very familiar vue welcome page when you run $ npm run serve
To demonstrate the use of environment variables we are going to tweak
App.vue
and HelloWorld.vue
respectively like so:
//App.vue
<template>
<div id="app">
<img v-if="imgUrl" alt="env gif" :src="imgUrl">
<img v-else="" alt="Vue logo" src="@/assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
</div>
</template>
...
In the code snippet above we are displaying the original vue logo if the variable imgUrl
is false. We are going to define imgUrl
in the created hook like so:
//App.vue
...
data(){
return {
imgUrl: ''
}
},
created(){
this.imgUrl = process.env.VUE_APP_IMG_URL
}
...
To keep things simple I cleaned up my HelloWorld
component like so:
// @/components/HelloWorld.vue
<template>
<div class="hello">
<h1>{{ msg }}</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
...
To use environment variables in your vue application
you should have a.env
file in the root directory of your project
and a variableVUE_APP_IMG_URL
which contains the URL to your image.
If you visit your vue application on http://localhost:8080
you should see an image like the one below:
This is because vue is compiled and bundled with webpack which means environment variables will only be made available at build time and not at run-time despite webpack's hot reload being used in development mode. To view changes to our env variables we will have to restart the dev server.
To deploy our vue app to cloud run, we will need a dockerise our application and we will know how to in the next section.
Build Application Image
In this section, we will learn how to build a docker image that can run our vue application in production.
To do this we will need a docker image with a web server (NGINX ) and node installed.
We can pull these packages in like so:
FROM nginx:alpine
# Install npm and node
RUN apk add --update npm
# Add bash
RUN apk add --no-cache bash
WORKDIR /app
COPY package.json ./
RUN npm install
COPY . .
# # Make our shell script executable
RUN chmod +x start.sh
COPY ./nginx.conf /etc/nginx/conf.d/default.conf
CMD ["/bin/bash", "-c", "/app/start.sh && nginx -g 'daemon off;'"]
This dockerfile has some dependencies; the nginx.conf
file and the bash script start.sh
that builds our application at run time which is triggered by the docker CMD command. We will fulfil these dependencies by creating the above-said files in the root directory of our vue application like so:
nginx.conf
server {
listen 8080;
server_name _;
charset utf-8;
root /usr/share/nginx/html;
index index.html index.htm;
location / {
root /usr/share/nginx/html;
autoindex on;
#try_files $uri $uri/ /index.html =404;
try_files $uri $uri/ /index.html =404;
}
}
We are listening on port
8080
because that's a cloud run requirement
as we can find in the cloud run contract.
start.sh
#!/bin/bash
if [ ! -d "/app/dist" ]
then
npm run build
echo "Build finished...";
echo "Delete node_modules folder";
rm -rf node_modules
echo "START COPY";
cp -rf /app/dist/. /usr/share/nginx/html/
echo "END COPY";
fi
In this file, Since we are building at runtime, we will wouldn't
want to build our application every single time a request is made to
our application. To avoid this, we will check if thedist
directory
exists before we build the static assets and copy them into the nginx
web directory.
Now we have fulfilled our dockerfile dependencies we can now build the docker image and push to GCR (google container registry).
To adhere to the 12 Factor app rule no. 3 we are going to populate
our.env
file with a default value which is going to be dynamic with
respect to different cloud run revisions.
In our application root directory, we will build the docker image like so:
$ docker build -t cr-tutorial .
When completed, we will tag the image and push it to gcr. To do so, you need to have auth for docker to use gcloud
. You can find out more information on how to do so on the container registry page. If that's sorted, we can tag and push to gcr like so:
$ docker tag cr-tutorial gcr.io/[PROJECT_ID]/cr-tutorial
Where
cr-tutorial
is the local image name and
[PROJECT_ID] is your GCP project id
$docker push gcr.io/[PROJECT_ID]/cr-tutorial
When push is completed, gcr.io/[PROJECT_ID]/cr-tutorial
will be your application image URL which will come in
handy soon.
Deploying to cloud run
To deploy our vue application image to cloud run, we will visit the cloud run page on GCP and click on the create service
option on the info panel.
In the create service panel, we are going to set our application settings as well as input the link to our application image (gcr.io/[PROJECT_ID]/cr-tutorial) like so:
If you're ok with the config, you can click the create button below to deploy your application to cloud run. When the deployment is done, when you visit your cloud run app URL, you should see a screen like so:
Now to demonstrate our use of .env
variables at run-time, we will deploy a new revision on cloud run and pass in our env variables.
Deploying a new CR revision
To deploy a new revision we will click on the Deploy revision
option on the deployed service info panel
Then we will fill up our VUE_APP_IMG_URL
(https://bit.ly/2MiYZT2) value in the env
section like so:
When the revision is done, you should see something that looks like the image below:
Conclusion
In this tutorial, we have been able to deploy a vue application which receives environment variables at run-time. This is because the application is being built at run-time as well. You can find the repository for this project on GitHub.
Top comments (7)
Doing the build as part of the start command likely hurts the startup time of your app.
You should do it as a line of your Dockerfile.
Yeah it does, but building the app at build time will mean the static assets will not have access to the environment variables passed at run time. One way to optimise the application startup time is optimising the code base such that build time is as fast as possible.
Hi, I'm gettings this error:
"Cloud Run error: Container failed to start. Failed to start and then listen on the port defined by the PORT environment variable. "
I just changed the port to 80 instead of 8080 in nginx.conf
You could have instead added
in your Dockerfile and you are golden...
How add caching for this deployed cloud run url using firebase hosting rewrites firbase.json
for firebase hosting hosted static files+ Cloud run with API we can use caching like this
"rewrites": [
{
"source": "/api/",
"run": {
"serviceId": "myservice-api",
"region": "europe-west1"
}
},
{
"source": "",
"destination": "/index.html"
}
]
and
[
{ "source":"/user/**", "headers": [{"key": "Cache-Control", "value": "no-cache, no-store"}] }
]
what is if whole dynamic Vue with node runtime hosted in the cloud run and firabase.json
have
"rewrites": [ {
"source": "/helloworld",
"run": {
"serviceId": "helloworld", // "service name" (from when you deployed the container image)
"region": "us-central1" // optional (if omitted, default is us-central1)
}
} ]
how to do caching when we are using dynamic webapp with web firebase SDK ? and liked to firebase hosting ?
Is there any reason to deploy it on an actual server rather than deploying it as a static website other than using environment variables?
No reason at all depending on your needs. If you're deploying on an actual server, you will need to take a different approach. Serverless helps take some work off your hands when deploying applications. But if your use-case demands an actual server, then you go for it.