Cloud Build for Docker Containers | GCP

Michael Dacanay
7 min readJul 24, 2023

--

Working with Cloud Build | Google Cloud Skills Boost
  • Use Cloud Build to build and push containers
  • Use Container Registry to store and deploy containers

Task 1: Enable APIs

☰ > APIs & Services > Enabled APIs & Services > + Enable APIs & Services > search for API

Make sure that both Cloud Build and Container Registry APIs are enabled.

https://console.cloud.google.com/apis/library/containerregistry.googleapis.com

Task 2. Building containers with DockerFile and Cloud Build

quickstart.sh

#!/bin/sh
echo "Hello, world! The time is $(date)."

Dockerfile

FROM alpine
COPY quickstart.sh /
CMD ["./quickstart.sh"]
gcloud builds submit — tag gcr.io/${GOOGLE_CLOUD_PROJECT}/quickstart-image .

gcloud builds submit is a command used to submit source code and build instructions to Cloud Build for building container images.

The tag flag specifies the name and optionally a tag to apply to the image resulting from the build.

Menu > Container Registry > Images.

Task 3. Building containers with a build configuration file and Cloud Build

Step 1

  1. Dockerfile : a file that when built using “docker build”, it creates a Docker image AKA snapshot of the file system.

It includes the type of operating system via base image (FROM alpine), any files in the project (quickstart.sh) that are copied over to the image environment (COPY quickstart.sh /), and any files that may be generated during any commands run during a “docker run” (a command that takes the resulting Docker image and uses it as the image for a Docker container).

Step 2

2. Instead of “docker build” in a traditional Docker setup, GCP Cloud Build uses gcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/quickstart-image .

The “.” at the end refers to the current directory and by default, looks for a file called Dockerfile. You should only have one Dockerfile in that location. You can also reference a Dockerfile in a different path, just need to modify this last argument. However, it is most common to run the “docker build/gcloud builds submit” command in the same directory as your Dockerfile.

Authorize Cloud Shell

However, why was the deployment resulting in an error?

Revision ‘michael-testing-mk5–00001-puf’ is not ready and cannot serve traffic. The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable.

When observing the logs from Cloud Run, it seems the logs with DEFAULT severity print output from the container. The logs with ERROR severity display all the errors. You can adjust the query from severity=DEFAULT to severity=ERROR to see the different results.

Log Explorer: severity=DEFAULT

Logging Query:

severity=DEFAULT
resource.type="cloud_run_revision"
resource.labels.service_name="quickstart-image-michael-mk2"

For some reason, the Docker container wasn’t properly configured to receive traffic (from port 8080, for the URL).

FROM nginx:alpine
COPY nginx.conf /etc/nginx/conf.d/configfile.template

# Copy the script or static files required for your application
COPY quickstart.sh /usr/share/nginx/html/

# Set the working directory
WORKDIR /usr/share/nginx/html/

# Start Nginx when the container starts
# CMD ["nginx", "-g", "daemon off;"]

ENV PORT 8080
ENV HOST 0.0.0.0
EXPOSE 8080
CMD sh -c "envsubst '\$PORT' < /etc/nginx/conf.d/configfile.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"

nginx.conf:

server {
listen $PORT;
server_name localhost;

location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri /index.html;
}

gzip on;
gzip_vary on;
gzip_min_length 10240;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml;
gzip_disable "MSIE [1-6]\.";
}

Cloud Run expects traffic on port 8080, instead of nginx default of port 80.

$ gcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/cra-cloud-run

Run these gcloud commands in the same directory as the Dockerfile.

Step 3

The previous step takes a Dockerfile and builds a Docker image that is stored in gcr.io, the Google Container Registry. Next, we take that Docker image and create/run a container that uses the image as a base. That means it will have the same files/packages as the image indicates.

$ gcloud run deploy --image gcr.io/${GOOGLE_CLOUD_PROJECT}/cra-cloud-run --platform managed

Region: us-east1

Allow unauthenticated invocations.

Cloud Run Service deployed successfully: https://console.cloud.google.com/run/detail/us-east1/michael-testing-ashton/metrics?project=cloud-build-393712
https://michael-testing-ashton-e4t4dstbwq-ue.a.run.app/

The nginx app probably will not still be up when you read this. I included screenshots so you can see what I’m seeing.

Dockerfile examples:

FROM alpine
COPY quickstart.sh /

ENV PORT 8080
ENV HOST 0.0.0.0
EXPOSE 8080
CMD ["./quickstart.sh"]

I’m not sure if this can be deployed on Cloud Run without an error because the CMD ['./quickstart.sh'] runs once. It is not designed to serve requests as they come in.

Invalid Express Dockerfile:

# Use the official Node.js image from Docker Hub
FROM node:latest

# Set the working directory inside the container
WORKDIR /app

# Copy only the package.json and package-lock.json (if exists) to leverage Docker cache
COPY package*.json ./

# Install project dependencies
RUN npm install

# Copy the rest of the application files to the container
COPY . .

ENV PORT 8080
ENV HOST 0.0.0.0
EXPOSE 8080

# Set the default command to run the application
CMD ["node", "app.js"]
Revision ‘michael-testing-express-00001-wev’ is not ready and cannot serve traffic. The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable.
$ gcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/express-testing
$ gcloud run deploy --image gcr.io/${GOOGLE_CLOUD_PROJECT}/express-testing --platform managed

I will update later as I debug and find out how to set up Dockerfile correctly.

Task 4. Building and testing containers with a build configuration file and Cloud Build

Cloud Build: CI/CD (continuous integration, continuous deployment) pipeline

cloudbuild.yaml:

steps:
- name: 'gcr.io/cloud-builders/docker'
args: [ 'build', '-t', 'gcr.io/$PROJECT_ID/quickstart-image', '-f', 'Dockerfile.nginx', '.' ]
images:
- 'gcr.io/$PROJECT_ID/quickstart-image'

To create image and push to GCR:

gcloud builds submit --config cloudbuild.yaml .

Google Cloud Build (GCP Cloud Build) is a fully managed service provided by Google Cloud Platform (GCP) that automates the process of building and deploying applications. It enables developers to create custom build configurations and pipelines to compile source code, run tests, and create container images, among other tasks. Cloud Build supports a variety of programming languages, build tools, and platforms, making it a versatile tool for modern software development and continuous integration/continuous deployment (CI/CD) workflows.

Key features and capabilities of Google Cloud Build include:

  1. Build Triggers: Cloud Build can automatically trigger builds in response to changes in a connected source code repository, such as Google Cloud Source Repositories, GitHub, or Bitbucket.
  2. Custom Build Steps: Cloud Build provides a flexible and extensible build configuration through YAML-based cloudbuild.yaml files. Developers can define custom build steps to execute complex build processes, including installing dependencies, running tests, and packaging applications.
  3. Docker Image Builds: Cloud Build seamlessly integrates with Docker, allowing you to build container images and push them to container registries like Google Container Registry (GCR) or other supported registries.
  4. Cache and Speed: Cloud Build optimizes build times by leveraging caching mechanisms. It saves build artifacts to cache between builds, resulting in faster subsequent builds by reusing cached layers.
  5. Parallel Builds: Cloud Build can distribute build tasks across multiple VMs in parallel, further reducing build times for large and complex projects.
  6. Integration with Google Cloud Services: Cloud Build works seamlessly with other Google Cloud services, enabling integration with Google Kubernetes Engine (GKE), Google App Engine, Cloud Functions, and more.
  7. Security and Isolation: Builds are performed in isolated environments, ensuring that dependencies and build processes do not interfere with each other. Cloud Build also provides secure and managed access to resources during the build process.
  8. Audit Logging and Monitoring: Cloud Build provides detailed logs and monitoring capabilities, helping developers and administrators track the build process and identify any issues.

Overall, Google Cloud Build is a powerful tool for automating build and deployment processes, enabling developers to build, test, and deploy their applications with ease and confidence on Google Cloud Platform. It is a key component in modern cloud-native development and CI/CD workflows.

Sources:

Future reading:

--

--

Michael Dacanay

Intern at Tesla, Fidelity. Student at North Carolina State University