Serverless Containers vs Serverless Next.js SSR GCP Cloud Run
Tags: googlecloud, containers, nextjs, react
Published: 2022-09-03 11:50:13

Step 0 : check on the [summary](https://dev.to/hexfloor/serverless-containers-vs-serverless-nextjs-ssr-on-aws-gcp-and-vercel-470d)

#GCP Cloud Run
I got inspired by [the guide of Geshan Manandhar](https://blog.logrocket.com/how-to-deploy-next-js-on-google-cloud-run/), there are less examples on how to make it work the present guide might be one of the best in the universe on the subject :)

First thing you need to do is to [create a new project](https://cloud.google.com/resource-manager/docs/creating-managing-projects) : 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kyff4pq58v92do8pmj83.png)


 
 
Then go to the [source cloud](https://source.cloud.google.com/)
and create a repository : 

 


Now let's just to the [cloud ide](https://ide.cloud.google.com/) as it's awesome and it's already set up, otherwise you need to set up gcloud CLI locally.

On the repository page I'm just checking on how to clone the repo with `gcloud` : 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ku8peieb03w66viqbmas.png)

And doing it in the cloud shell available within the cloud ide : 
```
git config --global user.email "youremail@gmail.com"
git config --global user.name "Your Name"
git config --global init.defaultBranch main  

gcloud source repos clone nextgcp --project=nextgcp-356220
Cloning into '/home/hexfloor/nextgcp'...
warning: You appear to have cloned an empty repository.
Project [nextgcp-356220] repository [nextgcp] was cloned to [/home/hexfloor/nextgcp].

yarn create next-app
✔ What is your project named? … nextgcp

Success! Created nextgcp at /home/hexfloor/nextgcp

cd nextgcp/
git add -A
git commit -m "init"
git push --set-upstream origin main
``` 
After this you may open folder in the cloud ide and you should have this : 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d349gmb965ceec74qp3l.png)

Adding the `Dockerfile` with [multi stage build](https://docs.docker.com/develop/develop-images/multistage-build/). The is a [docker hub download rate limit](https://docs.docker.com/docker-hub/download-rate-limit/), thus we may need to use [gcp mirror](https://cloud.google.com/container-registry/docs/pulling-cached-images), I assume it's configured automatically in the GCP. If it's not broken - don't fix it :)

```
# Install dependencies only when needed
FROM node:alpine AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile

# If using npm with a `package-lock.json` comment out above and use below instead
# COPY package.json package-lock.json ./ 
# RUN npm ci

# Rebuild the source code only when needed
FROM node:alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the build.
# ENV NEXT_TELEMETRY_DISABLED 1

RUN yarn build

# Production image, copy all the files and run next
FROM node:alpine AS runner
WORKDIR /app

ENV NODE_ENV production
# Uncomment the following line in case you want to disable telemetry during runtime.
# ENV NEXT_TELEMETRY_DISABLED 1

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

# You only need to copy next.config.js if you are NOT using the default configuration
# COPY --from=builder /app/next.config.js ./
COPY --from=builder /app/public ./public
COPY --from=builder /app/package.json ./package.json

# Automatically leverage output traces to reduce image size 
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV PORT 3000

CMD ["node", "server.js"]

``` 
Adding `.dockerignore`
```
Dockerfile
.dockerignore
node_modules
npm-debug.log
README.md
.next
```
commit ;)

 Changing the `next.config.js` to add [standalone output](https://nextjs.org/docs/advanced-features/output-file-tracing)

```
/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
  output: 'standalone'
}

module.exports = nextConfig
```
commit ;)

Alright, let's set up continuous deployment following the guide [Deploying to Cloud Run using Cloud Build](https://cloud.google.com/build/docs/deploying-builds/deploy-cloud-run)

Enabling the API : 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/152ieq1v0v0y8gvemxxy.png)

Service account permissions : 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xn5jkm7m66tzv7mpnqfy.png)

Adding new file `cloudbuild.yaml` to the project, filling the template for the continuous deployment : 
```
steps:
  # Build the container image
  - name: 'gcr.io/cloud-builders/docker'
    args: ['build', '-t', 'gcr.io/$PROJECT_ID/nextgcp:$COMMIT_SHA', '.']
  # Push the container image to Container Registry
  - name: 'gcr.io/cloud-builders/docker'
    args: ['push', 'gcr.io/$PROJECT_ID/nextgcp:$COMMIT_SHA']
  # Deploy container image to Cloud Run
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: gcloud
    args:
    - 'run'
    - 'deploy'
    - 'nextgcp'
    - '--image'
    - 'gcr.io/$PROJECT_ID/nextgcp:$COMMIT_SHA'
    - '--region'
    - 'europe-west6'
images:
  - 'gcr.io/$PROJECT_ID/nextgcp:$COMMIT_SHA
```  

Creating a trigger : 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kkckyr6wir1d709vzmql.png)
 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4kbmyv42ajt6a8zwm109.png)
 
commit previously added `cloudbuild.yaml` and push to check the trigger

Sadly the build has failed : 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mc7r1lb9h7ei4ie1ohp4.png)

I've checked on the internet, it's due to the region setting in the trigger, let's change it to global : 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/28r0duy9pl6jhfkr1stv.png)

All good now : 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/90xyv8nrkxg8uyvouz04.png)
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u5w2mhj4ygoaonyf2nvw.png)

Let's add domain : 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ja73geffgx82pdmvj9un.png)
    
It seems we can't do it simple everywhere, see the [mapping domains](https://cloud.google.com/run/docs/mapping-custom-domains#run)
Changing the region to `europe-west1` in the `cloudbuild.yaml`, committing, building : 
 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oivn58068fawntesgq1r.png)

Now we can add a simple mapping :
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jvob2boiamygia9t00hy.png)
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2nd9mze5n0d2ioc4fehi.png)
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2tlptqizu9ykqcqyocn2.png)
 
Remember to set the `www` records as well, sleep 28800 : 
 ![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cbrb15kykcl06eyggw2i.png)
 


Checking the app url : 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fo027lx03zjxmykr94ps.png)

Checking the [troubleshooting](https://cloud.google.com/run/docs/troubleshooting)

Setting permissions : 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5htxn0h8iybgbmwuuubh.png)
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/83pavaxdbxqxj5cjt6ri.png)
 
Now it's better : 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wjtnuqc6w7js6tjxemsj.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5wemccrzkmyigwjg0bmh.png)

Success !

The second time it's easy-peasy, the first time it's a bit of a challenge to find a right doc. Now you have it :)