Sign up for our newsletter! →

Deploying Elixir/Phoenix Application on GCP Cloud Run

Written By
HanaByte blog, elixir, phoenix, google cloud partner, GCP, hanabyte

In this blog post, we will be deploying a containerized Elixir/Phoenix application to Google Cloud Run. Cloud Run is a managed compute platform that lets you run containers directly on top of Google’s scalable infrastructure. You may be asking yourself, why choose Cloud Run when there are so many serverless platforms? Well I’d say they’re all pretty similar but Cloud Run is one of the easiest to get started on with many benefits integrated. After a successful deployment, you get a fully-qualified domain URL, logging, metrics, and managed deployments. Cloud Run does have its caveats like any other serverless platform. The big one is that Cloud Run requires you to deploy a containerized application. While many of our workloads are containerized, there’s still plenty that are not. Ok–that’s enough about Cloud Run and its pros and cons. If you need more info on whether your specific workload will work on Cloud Run see the official GCP documentation. The goal of this post is to give a general overview of the steps required to get a functional phoenix application running on GCP Cloud Run.

Deployment Steps Overview

Let’s take a look at the steps required to get our application deployed.

  1. Create Elixir/Phoenix application

  2. Containerized application

  3. Build Container and Publish to Registry

  4. Deploy Containerized Application to Cloud Run

  5. Inject Environment Variables and Secrets

Create Elixir Application

The first step is hopefully the easiest (or hardest): get an elixir/phoenix application. I’ll be using a generic Phoenix application generated using mix “mix phx.new test_app –no-ecto”. Mix is the build tool for working with Elixir projects. I’ve chosen not to include a database connection for brevity. I’ll leave adding a database connection as an exercise for the user.

Containerize The Application

Step 2 is to containerize our application. You can write your own Dockerfile, or maybe like me, prefer to generate one using the mix command “mix phx.gen.release –docker” command. I have found that the generated dockerfile works in most cases. It also has the added benefit of providing a multi-stage docker build that can be useful in a CI/CD pipeline for caching the builder layer of our application.

Build Container And Publish To Registry

With both of the first 2 steps completed, we can move on to building and publishing the container image to a registry. I’ll be using Google’s Artifact Registry in this blog, but Google’s Container Registry and Docker Hub are also supported.

See https://cloud.google.com/run/docs/deploying for more information on supported repositories.

First, we need to login to the project we’re working on using gcloud.

				
					> gcloud auth login
> gcloud config set project PROJECT_ID

				
			

Next, we need to have the artifact registry API enabled for our project. This may take several minutes to complete.

				
					gcloud services enable artifactregistry.googleapis.com
				
			

After we have enabled the artifact registry, we need to create a repository. I’ll be naming it `my-phoenix-app`.

				
					gcloud artifacts repositories create my-phoenix-app \
	--repository-format=docker \
	--location=us-east1 \
	--description="phoenix-elixir-app" \
	--immutable-tags   
Create request issued for: [my-phoenix-app]
Waiting for operation [projects/blogs-407517/locations/us-east1/operations/9b1174ed-0006-4804-ad11-e2fc792b05b8] to complete...done.                                                                                                      	 
Created repository [my-phoenix-app].
				
			

Once created, grab the registry url. It will be in the structure of The URL has the shape

REGION-docker.pkg.dev/PROJECT_ID/REPO_NAME/PATH:TAG
				
					> gcloud artifacts repositories describe my-phoenix-app --location us-east1

Encryption: Google-managed key
Registry URL: us-east1-docker.pkg.dev/blogs-407517/my-phoenix-app
Repository Size: 0.000MB
createTime: '2023-12-08T18:01:57.112912Z'
description: phoenix-elixir-app
dockerConfig:
  immutableTags: true
format: DOCKER
mode: STANDARD_REPOSITORY
name: projects/blogs-407517/locations/us-east1/repositories/my-phoenix-app
				
			

To build the docker image, I’ll be using Cloud Build. (Using Cloud Build to build our image is not a requirement. You can build the image locally and push it to the registry). I’ll include a quick snippet on how to do that below. The only requirement for the image is for it to target the amd64 architecture. Images not targeting amd64 will fail to start in the Cloud Run environment.

 

Ok, let’s enable Cloud Build and use it to build our container.

				
					> gcloud services enable cloudbuild.googleapis.com
Operation "operations/acf.p2-182047168193-22266cc4-2e7a-4fe4-8008-ab0a1ea2a0b9" finished successfully.
				
			

Create a Cloud Build job with your registry URL as the tag.

				
					gcloud builds submit --tag 
us-east1-docker.pkg.dev/blogs-407517/my-phoenix-app/phoenix-app:latest
				
			

To build and create the docker image locally, you first need to configure the registry. Then, using docker, build the image and finally push it up. If you are building locally, make sure to target the amd64 architecture. You can read more about that in the official docker multi-platform documentation.

				
					> gcloud auth configure-docker us-east1-docker.pkg.dev
				
			
				
					> docker build . \
--tag us-east1-docker.pkg.dev/blogs-407517/my-phoenix-app/phoenix-app

> docker push us-east1-docker.pkg.dev/blogs-407517/my-phoenix-app/phoenix-app
				
			

Deploy Containerized Application to Cloud Run

With our image built and published we can now deploy it to Cloud Run. To deploy our image we need to reference it using its registry and tag. For Phoenix applications, we are also required to pass in the SECRET_KEY_BASE environment variable, which is a required environment variable to start Phoenix applications. You’ll also see –allow-unauthenicated flag set, this tells Cloud Run that we want to expose our application to the internet. If you want to deploy an internal service you will not want to set this flag.

				
					> gcloud run deploy phoenix-service --image us-east1-docker.pkg.dev/blogs-407517/my-phoenix-app/phoenix-app:latest --region us-east1 --allow-unauthenticated --set-env-vars "SECRET_KEY_BASE=va2g7x4g99VQWGqmpACxD9j9tFMfQMKRyzhA3ZkWExKISsZbn/Z+eB7GwUKCTQZC"

Deploying container to Cloud Run service [phoenix-service] in project [blogs-407517] region [us-east1]
✓ Deploying... Done.
  ✓ Creating Revision...
  ✓ Routing traffic...
  ✓ Setting IAM Policy...
Done.
Service [phoenix-service] revision [phoenix-service-00005-c8x] has been deployed and is serving 100 percent of traffic.
Service URL: https://phoenix-service-o3f2fulppq-ue.a.run.app
				
			

That’s it. With a successfully deployed application, it is now accessible using the Service URL, and we have logging and reporting metrics being reported.

Conclusion

In a couple of steps we can get a phoenix/elixir application running in Cloud Run. We get many of the benefits of serverless with our application for a relatively low level of complexity. Hopefully this has demonstrated how easy it is to deploy your containerized application to Cloud Run. This post has barely scratched the surface of Cloud Run’s capability. There’re plenty of avenues to expand on the basic service we deployed i.e. traffic splitting, rolling/gradual deployments, and custom domains. Cloud Run can be the middle group between using kubernetes or self-hosting your application. Thanks for reading and happy coding!

Relevant Blogs

hanabyte blog, HanaByte Hearts, Gwinnett County Parks and Rec
Corporate Outreach

HanaByte Hearts: Gwinnett County Parks & Recreation

Beyond the premises where the old data once existed, still exists people coding and working on security in the cloud from the comfort of their homes, and there the conversation started: must we not protect where we physically exist if we are to continue to protect what conceptually exists?…

Read More →
Hanabyte blog, HanaByte, FedRAMP, Containers
Compliance

An Overview of Container Security for FedRAMP

In this article, we will explore container vulnerability scanning, frame the vulnerability management requirements in a FedRAMP context, and provide commentary on the new FedRAMP PMO updates to container scanning requirements for cloud service providers (CSPs)…

Read More →
Disaster recovery blog image.
Cybersecurity

Master Your Disaster

Life is full of ups and downs, and no one can avoid them. This includes natural disasters, accidents, and loss of loved ones. The digital world operates on a similar principle. It’s not a question of if a cyber attack or system failure will happen; it’s when…

Read More →