Building leaner containers Stay organized with collections Save and categorize content based on your preferences.
This page describes how to build leaner Docker images.
Building leaner containers
When you containerize an application, files that are not needed at runtime, suchas build-time dependencies and intermediate files, can be inadvertently includedin the container image. These unneeded files can increase the size of thecontainer image and thus add extra time and cost as the image moves between yourDocker registry and your container runtime.
To help reduce the size of your container image, separate the building of theapplication, along with the tools used to build it, from the assembly of theruntime container.
Cloud Build provides aseries of Dockercontainers with commondeveloper tools such as Git, Docker, and the Google Cloud CLI. Usethese tools to define a build config file with one step to build theapplication, and another step to assemble its final runtime environment.
For example, if you're building a Java application, which requires files such asthe source code, application libraries, build systems, build systemdependencies, and the JDK, you might have a Dockerfile that looks like thefollowing:
FROM java:8COPY . workdir/WORKDIR workdirRUN GRADLE_USER_HOME=cache ./gradlew buildDeb -x testRUN dpkg -i ./gate-web/build/distributions/*.debCMD ["/opt/gate/bin/gate"]In the above example, Gradle, which is used to build the package, downloads alarge number of libraries in order to function. These libraries are essential tothe building of the package, but are not needed at runtime. All of the runtimedependencies are bundled up in the package.
Each command in theDockerfile creates a new layer in the container. If datais generated in that layer and is not deleted in the same command, that spacecannot be recovered. In this case Gradle is downloading hundreds of megabytes oflibraries to thecache directory in order to perform the build, but thelibraries are not deleted.
A more efficient way to perform the build is to use Cloud Build toseparate building the application from building its runtime layer.
The following example separates the step for building the Java application fromthe step for assembling the runtime container:
YAML
Build the application: In
cloudbuild.yaml, adda step to build the application.The following code adds a step that builds the
java:8image, which contains the Java code.steps:- name: 'java:8' env: ['GRADLE_USER_HOME=cache'] entrypoint: 'bash' args: ['-c', './gradlew gate-web:installDist -x test']
- Assemble the runtime container: In
cloudbuild.yaml,add a step to assemble the runtime container.The following code adds a step named
gcr.io/cloud-builders/dockerthat assembles the runtimecontainer. It defines the runtime container in a separate file namedDockerfile.slim.The example uses the Alpine Linux base layer
openjdk:8u111-jre-alpine, which is incredibly lean. Also, itincludes the JRE, instead of the bulkier JDK that was necessary to build theapplication.cloudbuild.yamlsteps:- name: 'java:8' env: ['GRADLE_USER_HOME=cache'] entrypoint: 'bash' args: ['-c', './gradlew gate-web:installDist -x test']- name: 'gcr.io/cloud-builders/docker' args: ['build', '-t', 'gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA', '-t', 'gcr.io/$PROJECT_ID/$REPO_NAME:latest', '-f', 'Dockerfile.slim', '.' ]Dockerfile.slimFROM openjdk:8-jre-alpineCOPY ./gate-web/build/install/gate /opt/gateCMD ["/opt/gate/bin/gate"]
- Create the Docker images: In
cloudbuild.yaml, add a stepto create the images.steps:- name: 'java:8' env: ['GRADLE_USER_HOME=cache'] entrypoint: 'bash' args: ['-c', './gradlew gate-web:installDist -x test']- name: 'gcr.io/cloud-builders/docker' args: ['build', '-t', 'gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA', '-t', 'gcr.io/$PROJECT_ID/$REPO_NAME:latest', '-f', 'Dockerfile.slim', '.']images:- 'gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA'- 'gcr.io/$PROJECT_ID/$REPO_NAME:latest'
JSON
Build the application: In
cloudbuild.json, add a step tobuild the application.The following code adds a step named
java:8forbuilding the Java code.{ "steps": [ {"name": "java:8", "env": [ "GRADLE_USER_HOME=cache" ], "entrypoint": "bash", "args": [ "-c", "./gradlew gate-web:installDist -x test" ] },}Assemble the runtime container: In
cloudbuild.json, add astep to assemble the runtime container.The following code adds a step named
gcr.io/cloud-builders/dockerthat assembles the runtimecontainer. It defines the runtime container in a separate file namedDockerfile.slim.The example uses the Alpine Linux base layer
openjdk:8u111-jre-alpine, which is incredibly lean. Also, itincludes the JRE, instead of the bulkier JDK that was necessary to build theapplication.cloudbuild.json:{ "steps": [ { "name": "java:8", "env": [ "GRADLE_USER_HOME=cache" ], "entrypoint": "bash", "args": [ "-c", "./gradlew gate-web:installDist -x test" ] }, {"name": "gcr.io/cloud-builders/docker", "args": [ "build", "-t", "gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA", "-t", "gcr.io/$PROJECT_ID/$REPO_NAME:latest", "-f", "Dockerfile.slim", "." ] } ],}Dockerfile.slim:FROM openjdk:8u111-jre-alpineCOPY ./gate-web/build/install/gate /opt/gateCMD ["/opt/gate/bin/gate"]- Create the Docker images: In
cloudbuild.json, add a step to create the images.{ "steps": [ { "name": "java:8", "env": [ "GRADLE_USER_HOME=cache" ], "entrypoint": "bash", "args": [ "-c", "./gradlew gate-web:installDist -x test" ] }, { "name": "gcr.io/cloud-builders/docker", "args": [ "build", "-t", "gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA", "-t", "gcr.io/$PROJECT_ID/$REPO_NAME:latest", "-f", "Dockerfile.slim", "." ] } ],"images": [ "gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA", "gcr.io/$PROJECT_ID/$REPO_NAME:latest" ]}
Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2026-02-19 UTC.