<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Johannes Vitt</title>
    <description>The latest articles on DEV Community by Johannes Vitt (@johannesvitt).</description>
    <link>https://dev.to/johannesvitt</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F793921%2F939b4323-4391-45ad-8c7f-fde207c87a46.jpg</url>
      <title>DEV Community: Johannes Vitt</title>
      <link>https://dev.to/johannesvitt</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/johannesvitt"/>
    <language>en</language>
    <item>
      <title>A CI/CD pipeline for a React app with Google Cloud Build</title>
      <dc:creator>Johannes Vitt</dc:creator>
      <pubDate>Fri, 04 Feb 2022 14:20:28 +0000</pubDate>
      <link>https://dev.to/johannesvitt/a-cicd-pipeline-for-a-react-app-with-google-cloud-build-2cjf</link>
      <guid>https://dev.to/johannesvitt/a-cicd-pipeline-for-a-react-app-with-google-cloud-build-2cjf</guid>
      <description>&lt;p&gt;&lt;em&gt;This tutorial assumes you are familiar with triggers in Google Cloud Build and have connected your repo. You can find an easy tutorial how to set up your first trigger &lt;a href="https://dev.to/johannesvitt/first-cicd-pipeline-with-google-cloud-build-1am3"&gt;right here&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;So you understand the idea behind CI/CD pipelines and want to build your own but are wondering how your it looks in real life? If you have a React app that you want to deploy using Google Cloud Platform (GCP) this tutorial is made just for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;As a prerequisite, your application has to be dockerized. I have dockerized a React app in &lt;a href="https://dev.to/johannesvitt/deploy-a-react-app-on-gcp-with-google-cloud-run-il3"&gt;this tutorial&lt;/a&gt;, so check that out.&lt;/p&gt;

&lt;h2&gt;
  
  
  The code
&lt;/h2&gt;

&lt;p&gt;Our &lt;code&gt;yaml&lt;/code&gt; file consists of three steps: building the docker image, pushing the image to the container registry and deploying a new Cloud Run revision with that image.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a trigger
&lt;/h2&gt;

&lt;p&gt;First you need to create a trigger that has the repo, that your code is in as a source. You also need to select the event that triggers the trigger (e.g. push to branch). Then edit the yaml file of the trigger in the following way.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Building the Docker image
&lt;/h3&gt;

&lt;p&gt;We use the default Docker cloud build image that Cloud Build provides as a container where we execute the &lt;code&gt;docker build&lt;/code&gt; command. It creates an image that contains all your React code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;gcr.io/cloud-builders/docker'&lt;/span&gt;
      &lt;span class="s"&gt;args:['build', '-t', 'gcr.io/$PROJECT_ID/frontend:$COMMIT_SHA']&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Pushing to Container Registry
&lt;/h3&gt;

&lt;p&gt;Google Container Registry offers a simple place to store your images of your deployments. This step pushes the previously created image to Container Registry.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;gcr.io/cloud-builders/docker'&lt;/span&gt;
      &lt;span class="s"&gt;args:['push', 'gcr.io/$PROJECT_ID/frontend:$COMMIT_SHA']&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Deploying to Cloud Run
&lt;/h3&gt;

&lt;p&gt;Cloud Run offers a simple way to deploy dockerized apps. With the gcloud cloud-builder image you can execute any command that you  would run with the gcloud command locally. So this step does the same as running &lt;code&gt;gcloud run deploy...&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;gcr.io/cloud-builders/gcloud'&lt;/span&gt;
      &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;run'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;deploy'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;your&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;service&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;name&amp;gt;'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--image'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;gcr.io/$PROJECT_ID/frontend:$COMMIT_SHA'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--platform=managed'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--region=&amp;lt;your&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;service&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;region&amp;gt;'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hint: If this steps fails, you might need to give permissions to deploy with Cloud Run to the default Cloud Build service account in your GCP IAM section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing your trigger
&lt;/h2&gt;

&lt;p&gt;Once the yaml file is saved, you can go ahead and change some of the code of your react app. The commit and push the code with git to trigger the event you have specified. In the history of Cloud Build you will see your build running. After it has completed, you can access your deployment via it's url and see the changes. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>First CI/CD pipeline with Google Cloud Build</title>
      <dc:creator>Johannes Vitt</dc:creator>
      <pubDate>Fri, 04 Feb 2022 14:19:55 +0000</pubDate>
      <link>https://dev.to/johannesvitt/first-cicd-pipeline-with-google-cloud-build-1am3</link>
      <guid>https://dev.to/johannesvitt/first-cicd-pipeline-with-google-cloud-build-1am3</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;If you are working on any project there comes a time where you want to release it to (beta) users. Most likely you choose one of the big three cloud computing providers (AWS, GCP or Azure) to host your next SaaS solution or whatever you are working on. You complete all steps of some youtube/dev.to/medium tutorials (&lt;a href="https://dev.to/johannesvitt/deploy-a-react-app-on-gcp-with-google-cloud-run-il3"&gt;a nice one&lt;/a&gt; for Google Cloud Run) and, some debugging with Stackoverflow sprinkled in, your app is available to users.&lt;/p&gt;

&lt;p&gt;Let's say you are lucky. Many users find your program interesting and start to use it. You receive the first inquiries: "I love your solution but this buttons needs to be red" -  "This is awesome but please translate the program to German so that my grandma can use it". So you go ahead and implement all feature requests. Each time you are done with one of them, you update your service in the cloud. You use the same tutorials, try to remember commands and make some mistakes. This is frustrating and it takes up time you can spend coding.&lt;/p&gt;

&lt;p&gt;This is why Continuous Integration / Continuous Deployment was invented. Continuous as in "automated" as in "you no longer need to do it by hand and have typos in your commands". If you are using GCP as your cloud provider Cloud Build offers an easy solution to set up your CI/CD pipeline.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This tutorial assumes you have already set up your GCP environment. Also it assumes you have your code under version control in a git repository.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Basics
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Cloud Build can connect to your git repo, if it is hosted on BitBucket or GitHub.&lt;/li&gt;
&lt;li&gt;It can trigger your pipeline based on changes (e.g. commits) in the connected repo.&lt;/li&gt;
&lt;li&gt;There are 120 free minutes of build time per day. After that you are charged by the minute.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Connecting your repository
&lt;/h2&gt;

&lt;p&gt;Before you do anything with Cloud Build you need to connect your git repo. In the console of GCP head over to Cloud Build. After activating the service, you need to click "connect repository". &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo6nmxtwr8fyhx669juq6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo6nmxtwr8fyhx669juq6.png" alt="Image description" width="340" height="68"&gt;&lt;/a&gt;&lt;br&gt;
First you choose where your repo is hosted (currently BitBucket and GitHub are available). Choose your provider and hit "continue".&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feulqry8u39t4in0p4kqy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feulqry8u39t4in0p4kqy.png" alt="Image description" width="800" height="847"&gt;&lt;/a&gt;&lt;br&gt;
Cloud Build will try to authenticate with the service. So maybe you need to enter your credentials. In the third step you can choose one of the repos you are hosting with the chosen service. In the end you are asked if you want to create your first trigger. This step will be explained in the next section.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting up your first trigger
&lt;/h2&gt;

&lt;p&gt;A trigger in cloud build consists of three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a repository where the code is hosted. This is the "Source".&lt;/li&gt;
&lt;li&gt;a condition e.g. "every time there is a push to the develop branch". Cloud Build calls this "Event"&lt;/li&gt;
&lt;li&gt;a list of instructions in a yaml file. They are executed if the condition is met.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enough talking, let's get started! In order to create your first trigger you should click the "CREATE A TRIGGER" button in the last step of connecting your repository.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnx9ine8sa7r7gtzu1nrx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnx9ine8sa7r7gtzu1nrx.png" alt="Image description" width="798" height="85"&gt;&lt;/a&gt;&lt;br&gt;
First you select a name for your trigger.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9bbh49exx371d1d7i37r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9bbh49exx371d1d7i37r.png" alt="Image description" width="800" height="377"&gt;&lt;/a&gt;Choose "Push to a branch", then choose the source repo and branch (I chose "develop").&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc6bxxqdfo3nmdxb66iku.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc6bxxqdfo3nmdxb66iku.png" alt="Image description" width="800" height="662"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Define your actions
&lt;/h2&gt;

&lt;p&gt;Now comes the most important step. You have to add the "intelligence" of your trigger by editing the yaml file that describes the steps that need to be taken. In the configuration section of the trigger, choose "inline" as the location of the yaml file and click the "open editor" button that appears.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5wjyklqf6vxsppsb97rw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5wjyklqf6vxsppsb97rw.png" alt="Image description" width="800" height="633"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There you can edit the yaml file that defines the "actions" of the build pipeline. The default looks like the following lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu&lt;/span&gt;
    &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;hello world&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a very easy example. In Cloud Build every step of a yaml file is run in a &lt;strong&gt;seperate&lt;/strong&gt; docker container. With the &lt;code&gt;name:&lt;/code&gt; option we tell Cloud Build what docker image it should use. This example uses ubuntu. With the args we provide a command that is executed in the container once it was started. In this case &lt;code&gt;echo "hello world"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Go ahead and change the file to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu&lt;/span&gt;
    &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;hello world&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu&lt;/span&gt;
    &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;the second hello world&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hit "done" and create the trigger. The trigger will be listed in Cloud Build's list of active triggers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing your trigger
&lt;/h2&gt;

&lt;p&gt;Usually your trigger will be executed when you trigger the event, for example by pushing to the develop branch. There is a way to trigger a build manually by clicking "run" on the right side of the trigger list. Do that and head over to the "history" section of cloud build. In this section you can find the invocations (e.g. executions) of all triggers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2rv8cdlah473l2g9n87x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2rv8cdlah473l2g9n87x.png" alt="Image description" width="520" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you click on the top entry of the list, you will see the output of the build. It will look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
BUILD
Starting Step #0
Step #0: Pulling image: ubuntu
Step #0: Using default tag: latest
Step #0: latest: Pulling from library/ubuntu
Step #0: Digest: sha256:b5a61709a9a44284d88fb12e5c48db0409cfad5b69d4ff8224077c57302df9cf
Step #0: Status: Downloaded newer image for ubuntu:latest
Step #0: docker.io/library/ubuntu:latest
Step #0: hello world
Finished Step #0
Starting Step #1
Step #1: Already have image: ubuntu
Step #1: the second hello world
Finished Step #1
PUSH
DONE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that both steps were executed. In the last line with &lt;code&gt;Step #0&lt;/code&gt; and &lt;code&gt;Step #1&lt;/code&gt; you can find the output of the echo commands that you defined in your yaml file.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do next
&lt;/h2&gt;

&lt;p&gt;Congrats, you have successfully set up your first (simple) Cloud Run trigger! Below you can find some next steps you can take to make your own code deploy with a pipeline. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Head over to &lt;a href="https://dev.to/johannesvitt/a-cicd-pipeline-for-a-react-app-with-google-cloud-build-2cjf"&gt;this tutorial&lt;/a&gt; to learn how to set up a Cloud Build trigger for a React app.&lt;/li&gt;
&lt;li&gt;Learn about debugging, concurrency and other performance improvements for Cloud Build (coming soon).&lt;/li&gt;
&lt;li&gt;Use Cloud Build for your GitOps flow with terraform (tutorial coming soon).&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>googlecloud</category>
      <category>devops</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Deploy a React App on GCP with Google Cloud Run</title>
      <dc:creator>Johannes Vitt</dc:creator>
      <pubDate>Sun, 16 Jan 2022 16:03:46 +0000</pubDate>
      <link>https://dev.to/johannesvitt/deploy-a-react-app-on-gcp-with-google-cloud-run-il3</link>
      <guid>https://dev.to/johannesvitt/deploy-a-react-app-on-gcp-with-google-cloud-run-il3</guid>
      <description>&lt;p&gt;So you have created your first React project and now you are ready to try to deploy it? Fear not, Google offers Cloud Run, a very simple but powerful tool that helps you do just that. I will show you in three simple steps, how you can deploy a containerized React app with Cloud Run.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This tutorial assumes you have already setup your Google Cloud Project and have your React app running locally.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Can I simply upload my code into a bucket?
&lt;/h2&gt;

&lt;p&gt;When I tried to deploy my first React project, I was already experienced with Cloud Run for various other projects. When I wanted to deploy the app to GCP, my first idea was to run a simple &lt;code&gt;npm run build...&lt;/code&gt; and upload the compiled output folder into a Google Cloud Storage (GCS) bucket.&lt;/p&gt;

&lt;p&gt;After I was done, I realized that this approach would not work. GCS is trying to serve all routes from a path inside the bucket. So if you create a page &lt;code&gt;/login&lt;/code&gt; in React, GCS will try to serve a file located inside the subfolder of the GCS bucket. This will fail, because no such file exists. React is supposed to handle the routing client side. More info on this can be found &lt;a href="https://www.ackee.agency/blog/how-to-host-static-react-apps-in-google-storage-bucket-behind-cloudflare-cdn" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The "easiest" way to achieve a working routing is to use Google App Engine. However, I find App Engine not very scalable for multiple reasons. The major issue I faced is that the location of your App Engine can not be changed once it was activated for a project (Why?), and you can only have one App Engine location for the whole project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloud Run
&lt;/h2&gt;

&lt;p&gt;The better solution to go with is Google Cloud Run. Cloud Run is actually based on Knative, &lt;a href="https://knative.dev/docs/" rel="noopener noreferrer"&gt;a "Kubernetes-based platform to deploy and manage modern serverless workloads"&lt;/a&gt;. The main benefit of Knative is that it makes scaling of any stateless applications very easy. You simply provide a docker image and Knative will scale it up to as many instances as needed.&lt;/p&gt;

&lt;p&gt;In comparison to directly running Knative your own Kubernetes cluster, Cloud Run is easier to set up and maintain. It is also very cheap for projects, where you expect a small load of traffic, because Cloud Run is billed per usage (e.g. per request to the service). Another advantage of Cloud Run is the ability to revert your deployments within less than 10s. This feature saved me some headaches in the startup that I worked with.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Create a docker image that contains your compiled React app
&lt;/h3&gt;

&lt;p&gt;You need to create a file &lt;code&gt;Dockerfile&lt;/code&gt; in the root directory of your project. We will use a multi-stage docker file in this step so be sure to copy all of the following code &lt;strong&gt;into a single file&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:lts-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;builder&lt;/span&gt;

&lt;span class="c"&gt;# by only copying package.json, before running npm install. We can leverage dockers caching strategy for steps. Otherwise docker needs to run npm install every time you change any of the code.&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; /app-ui
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mv&lt;/span&gt; ./node_modules ./app-ui
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app-ui&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="c"&gt;# in this step the static React files are created. For more info see package.json&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the builder we have all our static files available. However we still need a way of serving them to the client. We use nginx for this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; nginx:alpine&lt;/span&gt;

&lt;span class="c"&gt;# copy the .conf template&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./.nginx/nginx.conf /etc/nginx/nginx.conf&lt;/span&gt;

&lt;span class="c"&gt;## Remove default nginx index page and replace it with the static files we created in the first step&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /usr/share/nginx/html/&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /app-ui/build /usr/share/nginx/html&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 80&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; nginx -g 'daemon off;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the first stage of the docker file (the "build" stage), we call the "build" script. This needs to be defined in your &lt;code&gt;package.json&lt;/code&gt;. It triggers the compilation of your react code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"react-scripts start"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"react-scripts build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the second stage of the docker file, we copy the configuration file of nginx into the server. So please create a file &lt;code&gt;.nginx/nginx.conf&lt;/code&gt; with the following content.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;worker_processes&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;events&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kn"&gt;worker_connections&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;http&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kn"&gt;gzip&lt;/span&gt; &lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;gzip_disable&lt;/span&gt; &lt;span class="s"&gt;"msie6"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kn"&gt;gzip_comp_level&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;gzip_min_length&lt;/span&gt; &lt;span class="mi"&gt;1100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;gzip_buffers&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt; &lt;span class="mi"&gt;8k&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;gzip_proxied&lt;/span&gt; &lt;span class="s"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;gzip_types&lt;/span&gt;
            &lt;span class="nc"&gt;text/plain&lt;/span&gt;
            &lt;span class="nc"&gt;text/css&lt;/span&gt;
            &lt;span class="nc"&gt;text/js&lt;/span&gt;
            &lt;span class="nc"&gt;text/xml&lt;/span&gt;
            &lt;span class="nc"&gt;text/javascript&lt;/span&gt;
            &lt;span class="nc"&gt;application/javascript&lt;/span&gt;
            &lt;span class="nc"&gt;application/json&lt;/span&gt;
            &lt;span class="nc"&gt;application/xml&lt;/span&gt;
            &lt;span class="nc"&gt;application/rss&lt;/span&gt;&lt;span class="s"&gt;+xml&lt;/span&gt;
            &lt;span class="nc"&gt;image/svg&lt;/span&gt;&lt;span class="s"&gt;+xml&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kn"&gt;root&lt;/span&gt;   &lt;span class="n"&gt;/usr/share/nginx/html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;index&lt;/span&gt;  &lt;span class="n"&gt;/index.html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;include&lt;/span&gt; &lt;span class="n"&gt;/etc/nginx/mime.types&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kn"&gt;try_files&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="n"&gt;/index.html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the configuration the line &lt;code&gt;try_files $uri $uri/ /index.html;&lt;/code&gt; tells the server to try to locate the requested file in the &lt;code&gt;/usr/share/nginx/html&lt;/code&gt; directory. If it is not found we serve the &lt;code&gt;index.html&lt;/code&gt; file.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Upload the Docker Image to Google Container Registry
&lt;/h3&gt;

&lt;p&gt;In the terminal navigate to your projects root folder and run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud builds submit &lt;span class="nt"&gt;--tag&lt;/span&gt; gcr.io/&amp;lt;your-project-id&amp;gt;/react-with-cloudrun
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will build the docker image using the Dockerfile that you have created in the previous step and upload it to the Container Registry.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Create the Cloud Run service
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3wj68130o21xbugxxve1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3wj68130o21xbugxxve1.png" alt="Navigating to Cloud Run in the GCP console" width="800" height="90"&gt;&lt;/a&gt;&lt;br&gt;
In the Google Cloud Console, navigate to the Cloud Run overview. There, create a new service. During the creation of the service select the image you uploaded in the previous step. Choose the port 80 because this is where our NGINX server is listening.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm5huhqbqut3fz4g3f6b5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm5huhqbqut3fz4g3f6b5.png" alt="Creating a new Cloud Run Service" width="800" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. (Optional) Map your custom domain to the service
&lt;/h3&gt;

&lt;p&gt;If you own a domain and want to make your React app available with that domain you can set it up with Cloud Run.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbu800q88mqnn1cu1z07w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbu800q88mqnn1cu1z07w.png" alt="Image description" width="800" height="309"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvt7lb4dorelnycihbaox.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvt7lb4dorelnycihbaox.png" alt="Image description" width="800" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to go from here
&lt;/h2&gt;

&lt;p&gt;You have successfully deployed your React app with Cloud Run! &lt;/p&gt;

&lt;p&gt;As a next step you can try to set up an automated CI/CD pipeline with Google Cloud Build. It fits perfectly with Cloud Run and Docker images.&lt;/p&gt;

&lt;p&gt;Instead of using the web GUI to create and manage the resources of Google Cloud Platform, you can also start using Terraform.&lt;/p&gt;

&lt;p&gt;When you have multiple services running in Cloud Run, &lt;a href="https://cloud.google.com/load-balancing" rel="noopener noreferrer"&gt;Google Cloud Load Balancing&lt;/a&gt; offers an efficient way of routing requests.&lt;/p&gt;

</description>
      <category>react</category>
      <category>googlecloud</category>
      <category>serverless</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
