Introduction
In this guide I will deploy the containers from Twitch's TeoMeWhy system, which is currently on AWS, and place it on GCP.
Current structure at AWS
Architecture at GCP
No complex automation tools will be used, everything will be done via the console, integrating with Github and deploying the images with each commit to main.
We will use:
- Cloud Run - For web applications
- Cloud SQL - For MySQL database
- GCE - To run Teomebot
- Cloud Storage - Object Storage (S3)
- Cloud Build - To create application deployments
- Secret Manager - Save application credentials securely.
Getting the applications
- Visit TeoMeWhy's GitHub and fork of applications related to the project.
- On the repository page, click Starred and then Fork.
- On the fork page, give the fork a name and click Create fork.
- Repeat the process for the other repositories in the project if you want to replicate the entire environment.
- Make the clone of the fork to adjust the application as needed before sending it to GCP.
git clone git@github.com:cslemes/points-to-go.git
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Creating the Dockerfile to create the container image
Navigate to the cloned repository folder. The repository already contains a Dockerfile designed for Docker. Let's analyze it:
```
FROM golang:latest
WORKDIR /app/
COPY . .
RUN go build main.go
CMD ["./main"]
```
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
This Dockerfile is functional, but we will optimize it using multi-stage builds to reduce the size of the final image. Since Go doesn't require external dependencies, we can use a minimal base image like scratch.
-
Swap the build image with a lighter version and name it for reference at other stages.
FROM golang:1.23.1-alpine3.20 AS build
Copy after login
Copy after login
Copy after login
Copy after login
-
Add the go mod download command to cache the dependencies and go mod verify to ensure they match the checksums in the go.sum.
file
RUN go mod download && go mod verify
Copy after login
Copy after login
Copy after login
-
To optimize the binary for production, add the parameters below:
-
CGO_ENABLED=0: Disables CGO support. CGO is the functionality in Go that allows you to call C code, but when you disable it, you get a completely static binary, with no dependencies on external libraries.
-
GOARCH=amd64: Sets the target architecture for compilation. amd64 is the architecture used on machines with 64-bit processors, such as most modern servers and desktops.
-
GOOS=linux: Defines the target operating system for the compilation. Here it is configured for Linux, which means the generated binary will be executable on Linux systems.
-
go build -o /app/points: Compiles the code and saves the binary to the specified path (/app/points).
-
-a: Forces recompilation of all packages, including dependencies, even if they have not changed. It can be useful to ensure that everything is recompiled with the new flags and settings.
-
-ldflags="-s -w": These are size optimization flags.
-
-s removes the debug symbol table from the binary.
-
-w removes stack tracing information. These options reduce the size of the final binary.
-
-installsuffix cgo: Adds a suffix to the installation directory to differentiate binaries with CGO disabled. This can avoid conflicts with binaries that use CGO.
git clone git@github.com:cslemes/points-to-go.git
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
-
(optional) To make the image even smaller we can compress the binary using upx, upx (Ultimate Packer for eXecutables) is a tool that compresses executable binaries to reduce the size of files, such as Go binaries. The negative points are that There will be a longer build time, and a longer delay in container startup, so it must be evaluated which is most beneficial for its implementation. As the objective is to use it in Cloud Run which already has Cold Start, it pauses the container when it is not in use, we will not use it because it will increase the container's initialization time.
```
FROM golang:latest
WORKDIR /app/
COPY . .
RUN go build main.go
CMD ["./main"]
```
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
- Comparing builds
- Dockerfile optimization and use of upx results in an image up to 3 times smaller.
- Analysis of the original image with Trivy shows 904 CVEs, while the scratch image is free of CVEs.
Imagem |
Tipo |
Tamanho |
points-to-go |
Otimizado |
14MB |
points-to-go |
Com upx |
5.77MB |
points-to-go |
original |
1.76GB |
- Repeat these settings for the other repositories.
Deploying the database
- In the console, access SQL in the side menu.
- Or search for "SQL" in the search bar and select SQL from the list.
- On the Cloud SQL page, click Create Instance and choose MySQL.
- Select Enterprise under editing.
- Under "Editing Presets", choose Sandbox.
- Leave the database version at MySQL 8.0.
- Give the instance a name under Instance ID and set a password.
- you can specify password policies by expanding password policy
- Define the zone and region, and we will leave it in a single zone.
- In customize instance we can adjust the hardware according to our needs, the options will vary depending on the edition we choose.
- Adjust CPU to 1 and Disk to 10GB as needed.
- In connections, uncheck Public IP and check Private IP.
- In private access connection click Configure Connection
- Select use an automatically allocated range
- Click Continue
- Click Create connection
- Click Create Instance and wait for it to be created.
-
To connect to the instance, activate Cloud Shell and run:
git clone git@github.com:cslemes/points-to-go.git
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
- Enter the password assigned in the previous step.
- And then you will get a connection error, because the cloud shell does not have access to your private VPC.
- To simplify the connection via Cloud shell, let's edit the instance and mark public IP, in the appendix I will show how to create VPC peering to access the DB through Cloud Shell
- Try connecting again.
-
Create the application database:
```
FROM golang:latest
WORKDIR /app/
COPY . .
RUN go build main.go
CMD ["./main"]
```
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Cloud Shell still has a text editor based on VSCode, you can do some activities directly through it, it has 5GB of persistent volume in your /home , the hardware is an e2-small VM with 1vCPU and 1.7GB RAM.
Creating containers in Cloud Run
- In the Google Cloud console, access Cloud Run via the side menu or search bar.
- On the Cloud Run page, click Deploy Container and choose the Service option.
- Choosing the Deployment Method
- There are three options for deploying a service:
- Use a container image from a registry.
- Connect directly to a repository.
- Create a function (using Cloud Functions, integrated with Run).
- For this guide, select Continuous Deployment with GitHub, allowing Google to configure the CI/CD pipeline automatically.
Click Configure with Cloud Build.
Configuring Connection to GitHub
Click Authenticate to enable Google integration with your GitHub.
Authorize access, choosing between allowing access to all repositories or just a specific one.
After completing login, click Next.
Choosing Build Type
In the build step, select between using a Dockerfile or Supported Applications and Buildpacks from GCP.
Opt for Dockerfile and adjust the path/filename if necessary
Service Settings
-
Configure the following parameters:
-
Authentication: Select Allow unauthenticated calls.
-
CPU Allocation: Choose CPU is allocated only during request processing.
-
Input Control: Select Internal.
Adjust the container port as needed for the application.
In the security tab, under service account, click create New service account
-
Add roles
- Storage Object Administrator
- Cloud Run Administrator
- Secret Manager secret advisor
- Cloud SQL Client
- Cloud Build Service Account
- Artifact Registry Recorder
- Service account user
-
Analyzing the application code, we need to pass the environment variables to the database.
git clone git@github.com:cslemes/points-to-go.git
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
-
We will have to change the application code to the Cloud Sql standard that uses Unix sockets, and Cloud Run does not directly access the DB, it uses Cloud SQL Auth Proxy .
```
FROM golang:latest
WORKDIR /app/
COPY . .
RUN go build main.go
CMD ["./main"]
```
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
In the container, go to the variables and secrets tab and click on add variable.
Add the necessary variables.
The bank address follows the pattern, PROJECT_ID:REGION:INSTANCE_NAME, you can also get the name below, in item 16.
The bank password we will put in REFERENCE A SECRET
If the create new secret option is disabled, it is because you need to activate the Api.
Click on CREATE NEW SECRET
Define the secret name and click Create Secret
In Cloud SQL Connections we will add the URL of the bank we created
To create the application schema, the code requires us to pass the argument migrations=true.
We will add migrations=true to the function argument, then remove it in the next container revision.
Leave the other fields at default and click Create
Testing the application using Thunder Client.
creating a client
reading registered customers
Creating Teomebot service
The chatbot will not be deployed on Cloud Run, it will be installed on Google Compute Engine (GCE). Unlike Cloud Run, Compute Engine is ideal because the chatbot needs to be continuously active to interact with the chat.
Additionally, we will cover the use of containers, secret management and Cloud Build configuration for deployment automation.
Creating a VM on Google Compute Engine (GCE)
- Access Compute Engine in the GCP Console side menu.
- Click Create Instance.
- Enter a name for the instance (e.g. teomebot-instance).
- Configure the region and zone as needed and write down this information for later use.
- In Machine Setup, choose E2 type, and in Preset, select e2-micro.
- Click on the Container tab and click on Deploy Container.
- Temporarily use the nginx:latest image to complete the initial configuration.
- Add the environment variables:
-
TWITCH_BOT: Bot name.
-
TWITCH_CHANNEL: Twitch channel name.
-
HOST_DB: Private IP of the Cloud SQL database.
-
USER_DB: Bank user.
-
PORT_DB: Bank port.
-
URL_POINTS: Service endpoint Points-to-Go.
- Click Select
- Under Identity and API Access, select the service account configured for this project.
- Leave the rest of the settings at default and click Create.
Adding Secrets with Secret Manager
- You may have noticed that we didn't pass the secrets, in the compute engine there is no simple way to pass them like in cloud run. My solution was to add a function to the application code to read information directly from the secret manager.
- Access Secret Manager in the GCP Console.
- Click Create Secret
- Enter a descriptive name (e.g. twitch-token) and add the corresponding value.
- Copy the path of the generated secret (e.g.: projects/123456/secrets/twitch-token/versions/latest).
- Create a new utils/gcp.go file
-
Change utils/db.go to call the function, passing the secret manager path as a parameter.
git clone git@github.com:cslemes/points-to-go.git
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
-
Change main.go to get Twitch credentials
```
FROM golang:latest
WORKDIR /app/
COPY . .
RUN go build main.go
CMD ["./main"]
```
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
migration := flag.Bool("migrations", false, "Perform database migrations")
flag.Parse()
godotenv.Load()
user := os.Getenv("TWITCH_BOT")
// change
oauth := utils.AccessSecretVersion("projects/551619572964/secrets/twitch-token/versions/latest")
channel := os.Getenv("TWITCH_CHANNEL")
```
Cloud Build
Configuring Cloud Build
Cloud Build will be used to automate container image creation and deployment to Compute Engine.
- Create a cloudbuild.yaml file in the root of the repository with the content below:
-
Substitutions
FROM golang:1.23.1-alpine3.20 AS build
Copy after login
Copy after login
Copy after login
Copy after login
The _VERSION variable is set to a value that matches v1.0. with the hash of the current commit (${COMMIT_SHA}). This creates a unique version for each build, ensuring that each image is identifiable by version and commit.
Steps
The steps section defines the steps that Cloud Build must perform. Here, we have four steps: build, push (twice) and update.
-
Step 1: Build the Docker Image
RUN go mod download && go mod verify
Copy after login
Copy after login
Copy after login
This step runs a build of the Docker image:
-
"--no-cache": forces the build without using the cache.
-
"-t": defines tags for the created image:
-
gcr.io/$PROJECT_ID/teomebot:$_VERSION: image with the tag that uses the commit hash.
-
gcr.io/$PROJECT_ID/teomebot:latest: image with tag latest.
-
".": defines the current directory as the build context.
The id: Build tag is an optional identifier for the step, useful for reference and debugging.
-
Step 2: Image Push with Version Tag
RUN CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go build -o /app/points -a -ldflags="-s -w" -installsuffix cgo
Copy after login
Copy after login
This step pushes the image with the specific tag ($_VERSION) to the Google Container Registry, allowing the version generated in the build to be stored in the repository.
This step pushes the image with the latest tag to the Google Container Registry, updating the latest image with the latest version.
This step uses the gcloud command to update the container on a Google Compute Engine instance:
-
"teomebot-instance": specifies the name of the instance that runs the container.
-
--container-image: defines the container image that the instance should use. Here, use the latest version of the image.
-
--zone=$_DEPLOY_ZONE: uses a variable to specify the deployment zone.
-
--container-restart-policy=always: sets the container restart policy to always restart in case of failure.
-
Options
git clone git@github.com:cslemes/points-to-go.git
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
The logging: CLOUD_LOGGING_ONLY option specifies that Cloud Build should only log to Cloud Logging, saving data and focus on GCP logs.
-
Final file
```
FROM golang:latest
WORKDIR /app/
COPY . .
RUN go build main.go
CMD ["./main"]
```
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Creating Trigger for Container Image Creation
Setting Up the Service Account
- Go to Cloud Build in the Google Cloud console.
- Go to Settings.
- Click on Service Account Permissions.
- Locate the service account created for Cloud Run.
- Activate the option Set as preferred service account
- Enable the Compute Instance Administrator role for the service account.
Creating the Trigger
- In the side menu, click on Triggers and then on Create Trigger.
- Enter a descriptive name for the trigger.
- In Repositories, click Connect Repository and select the Teomebot repository.
- In Configuration, select the option Cloud Build Configuration File.
- Add the _DEPLOY_ZONE substitution variable with the value corresponding to the zone in which the instance was created.
- In service account, check the selected account if it is as configured in step 6.
- Click Save.
Running the Trigger
- On the overview screen, in the newly created trigger line, click execute to run the process manually.
- In the process details, follow the image build steps to check for possible errors.
Testing the Application
- In the Compute Engine panel, copy the ssh command to access the instance, or use the ssh web client, and connect the instance.
-
Connect to the instance and run the commands below to check the state of the container:
git clone git@github.com:cslemes/points-to-go.git
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Resolving Certificate Problems
-
If a certificate-related error occurs (caused by the scratch base image), replace it with the distroless image. In the Dockerfile, change the line that defines the base image from:
git clone git@github.com:cslemes/points-to-go.git
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
to:
```
FROM golang:latest
WORKDIR /app/
COPY . .
RUN go build main.go
CMD ["./main"]
```
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Dockerfile updated:
FROM golang:1.23.1-alpine3.20 AS build
Copy after login
Copy after login
Copy after login
Copy after login
Adjusting Permissions for Secret Manager
- Change service account scope to access Secret Manager.
- Go to the Google Cloud Console.
- In the side menu, go to Compute Engine > VM Instances.
- Find and click the name of your VM instance.
- On the VM details page, click Stop to shut down the instance (this step is necessary as the service account scope can only be modified when the instance is stopped).
- After the instance is stopped, click Edit at the top of the page.
- Scroll down to the Identity and Access API section.
- Under Service Account, select the service account that your application uses.
- Under API Access Scopes, select Allow Full Access to All Cloud APIs or click Set Specific API Access Scopes and add the scope https://www.googleapis.com/auth/cloud-platform.
- After adjusting the scope, click Save to apply the changes.
- Restart the instance by clicking Start.
-
Or via the command line, stopping the instance, running the command and starting afterwards.
RUN go mod download && go mod verify
Copy after login
Copy after login
Copy after login
Adding more containers
The other services follow the same points-to-go process, for services that communicate with each other, create environment variables to configure the endpoint addresses, which will always be https port 443.
For communication with other services, I adjusted the code to receive another environment variable with the service's url, in points for example it looked like this:
RUN CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go build -o /app/points -a -ldflags="-s -w" -installsuffix cgo
Copy after login
Copy after login
Testing the bot
Testing the bot's communication with Twitch.
Network Security Adjustment
After completing the tests, place the containers to be accessed only internally in the VPC.
Conclusion
With this we have completed the migration of the TeoMeWhy system, the guide serves as a basis for migrating the other TeoMeWhy services.
The main objectives achieved were:
Technical Achievements
- Migration of containerized applications to Cloud Run, allowing automatic scalability and cost reduction
- Docker image optimization through multi-stage builds, significantly reducing image size and vulnerabilities
- Implementation of a managed database with Cloud SQL, ensuring high availability and security
- Automated CI/CD configuration using Cloud Build, enabling automatic deployments from GitHub
- Secure credential management using Secret Manager
Architectural Improvements
- Clear separation of responsibilities between services
- Use of private connections for greater security
- Implementation of serverless standards for cost optimization
- Automation of build and deploy processes
- Seamless integration with GitHub repositories
Benefits Obtained
-
Costs: Cost reduction through the serverless model and resource optimization
-
Maintainability: Ease of maintenance with automated deployments
-
Security: Proper management of secrets and private connections
-
Scalability: Ability to automatically scale according to demand
-
Monitoring: Better infrastructure visibility through native GCP tools
Appendix
Enable the Secret Manager API
- In the Google Cloud console, search for Secret Manager API.
- Click on API in the search results.
- On the details screen, click Activate.
References
- Github TeoMeWhy
- Twitch Teo Me Why
- Cloud Run Docs
- Compute Engine Docs
- Cloud Build Docs
- Secret Manager Docs
The above is the detailed content of Deploying Serverless Applications on Google Cloud Run. For more information, please follow other related articles on the PHP Chinese website!