Migrate to OCI containers Stay organized with collections Save and categorize content based on your preferences.
This page describes the build infrastructure required to reproduce the CloudFoundry build process while generating OCI-compatible application images. If youhave already completed theSpring Music migration guideyou can use this a deep dive into specific migration configurations for yourapplication.
Before you start
- Make sure you have set up a new project for Cloud Run as describedin theCloud Run setup page.
- Make sure you have a
REGISTRY_URIfor storingcontainers. Cloud Run recommends using Artifact Registry. Docker is used to create intermediate images to build theproject.
Setting up a Cloud Foundry compatible build process
You must create two base OCI containers to support this new process:
- Abuilder image that mirrors Cloud Foundry's build process and iscapable of building application source code into Cloud Foundry droplets.
- Aruntime image that mirrors the Cloud Foundry application runtime.
This process needs to be done at least once by platform administrators. Oncethe process is established, the build and run images can can be shared by allCloud Foundry applications that need to migrate to Cloud Run.
Create the builder image
This section creates a build image usingcflinux3 as the baseimage. The build image is used as the build environment for creating theapplication image.
Create a directory called
build/andcdinto it:mkdirbuild &&cdbuildIn the
build/folder, create a new file calledDockerfileand paste inthe following code:ARGCF_LINUX_FS=cloudfoundry/cflinuxfs3FROMgolang:1.20-bullseyeASbuilder_buildWORKDIR/buildRUN["git","clone","--depth=1","https://github.com/cloudfoundry/buildpackapplifecycle.git"]WORKDIR/build/buildpackapplifecycleRUN["go","mod","init","code.cloudfoundry.org/buildpackapplifecycle"]RUN["go","mod","tidy"]RUNCGO_ENABLD=0gobuild-o/builder./builder/FROM$CF_LINUX_FS# Set up container tools related to building applicationsWORKDIR/lifecycleCOPY--from=builder_build/builder/lifecycle/builder# Set up environment to match Cloud Foundry's build.# https://docs.cloudfoundry.org/devguide/deploy-apps/environment-variable.html#app-system-envWORKDIR/staging/appWORKDIR/tmpENVCF_INSTANCE_ADDR=127.0.0.1:8080\CF_INSTANCE_IP=127.0.0.1\CF_INSTANCE_INTERNAL_IP=127.0.0.1\VCAP_APP_HOST=127.0.0.1\CF_INSTANCE_PORT=8080\LANG=en_US.UTF-8\INSTANCE_GUID=00000000-0000-0000-0000-000000000000\VCAP_APPLICATION={}\VCAP_SERVICES={}\CF_STACK=cflinuxfs3Use Cloud Build to build and publish the
builderimagegcloudbuilds\submit--tag"REGISTRY_URI/builder:stable"Replace
REGISTRY_URIwith the address of the Artifact Registry where youwant to publish the build image. For example:REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/builder:stable.
Create the runtime image
This section creates a run image usingcflinux3 as the baseimage. The run image is used as the base image when you create the finalapplication image.
Create a directory called
run/andcdinto it:mkdirrun &&cdrunIn the
run/folder, create a new shell script calledentrypoint.bashwith the following code:#!/usr/bin/env bashset-eif[["$@"==""]];thenexec/lifecycle/launcher"/home/vcap/app"""""elseexec/lifecycle/launcher"/home/vcap/app""$@"""fiIn the
run/folder, create a new file calledDockerfileand paste in thefollowing code:ARGCF_LINUX_FS=cloudfoundry/cflinuxfs3FROMgolang:1.20-bullseyeASlauncher_buildWORKDIR/buildRUN["git","clone","--depth=1","https://github.com/cloudfoundry/buildpackapplifecycle.git"]WORKDIR/build/buildpackapplifecycleRUN["go","mod","init","code.cloudfoundry.org/buildpackapplifecycle"]RUN["go","mod","tidy"]RUNCGO_ENABLD=0gobuild-o/launcher./launcher/FROM$CF_LINUX_FS# Set up container tools related to launching the applicationWORKDIR/lifecycleCOPYentrypoint.bash/lifecycle/entrypoint.bashRUN["chmod","+rx","/lifecycle/entrypoint.bash"]COPY--from=launcher_build/launcher/lifecycle/launcher# Set up environment to match Cloud FoundryWORKDIR/home/vcapUSERvcap:vcapENTRYPOINT["/lifecycle/entrypoint.bash"]# Expose 8080 to allow app to be run on Cloud Foundry,# and PORT so the container can be run locally.# These do nothing on Cloud Run.EXPOSE8080/tcp# Set up environment variables similar to Cloud Foundry.ENVCF_INSTANCE_ADDR=127.0.0.1:8080\CF_INSTANCE_IP=127.0.0.1\INSTANCE_IP=127.0.0.1\CF_INSTANCE_INTERNAL_IP=127.0.0.1\VCAP_APP_HOST=127.0.0.1\CF_INSTANCE_PORT=80\LANG=en_US.UTF-8\CF_INSTANCE_GUID=00000000-0000-0000-0000-000000000000\INSTANCE_GUID=00000000-0000-0000-0000-000000000000\CF_INSTANCE_INDEX=0\INSTANCE_INDEX=0\PORT=8080\VCAP_APP_PORT=8080\VCAP_APPLICATION={}\VCAP_SERVICES={}Use Cloud Build to build and publish the
runtimeimage:gcloudbuildssubmit\--tag"REGISTRY_URI/runtime:stable"Replace
REGISTRY_URIwith the address to the Artifact Registry where you wantto publish the build image. For example:REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/runtime:stable.
Building Cloud Foundry applications as OCI images
Each application migrated into Cloud Run needs itsown Dockerfile that matches how Cloud Foundry runs applications.The Dockerfile does the following:
- Loads the builder image.
- Runs the v2 buildpack lifecycle to create a droplet.
- Extracts the contents of the droplet.
- Loads the contents of the droplet on the run image to create the runnableapplication image.
The final application image is compatible with both Cloud Foundry andCloud Run so you can A/B test your migration to help debug anyunexpected behavior.
This process must be done by the application team for each applicationthat needs to be migrated.
Gather build information from a deployed Cloud Foundry application
Look at the application stack. The stack is provided via the
-sflag incf pushor thestackfield of the application manifest.- If the stack is Windows, the application is likely incompatible with Cloud Run.You must port the application to Linux before continuing.
- If the stack is blank,
cflinuxfs3, orcflinuxfs4the applicationcan be migrated to Cloud Run.
Gather the list of the application buildpacks. Buildpacks are provided viathe
-bflag incf push, thebuildpackfield in the applicationmanifest, or thebuildpacksfield of the application manifest.- If nobuildpacks are specified, it means they're being auto-detected. Look at thelist of detected buildpack in your most recent application deployment inCloud Foundry, or specify them explicitly if you know the paths.
- If the buildpacks are URLs, make note of the URLs and proceed to the next step.
For any buildpack that uses a short name, use the following table to map them to URLs:
Short Name URL staticfile_buildpackhttps://github.com/cloudfoundry/staticfile-buildpack java_buildpackhttps://github.com/cloudfoundry/java-buildpack ruby_buildpackhttps://github.com/cloudfoundry/ruby-buildpack dotnet_core_buildpackhttps://github.com/cloudfoundry/dotnet-core-buildpack nodejs_buildpackhttps://github.com/cloudfoundry/nodejs-buildpack go_buildpackhttps://github.com/cloudfoundry/go-buildpack python_buildpackhttps://github.com/cloudfoundry/python-buildpack php_buildpackhttps://github.com/cloudfoundry/php-buildpack binary_buildpackhttps://github.com/cloudfoundry/binary-buildpack nginx_buildpackhttps://github.com/cloudfoundry/nginx-buildpack The source for less common buildpacks can be found in theCloud FoundryGitHub organization.
Gather the source code location for the image. Source is provided via the
pathattribute of the application manifest or the-pflag of thecfpushcommand. If the source is undefined, it refers to the currentdirectory.Determine whether there is a
.cfignorefile in the source code directory. Ifit is there, move it to a file named.gcloudignore.
Build the Cloud Foundry application
In this step, you organize the build elements into the followingfolder structure:
.├── cloudbuild.yaml├── Dockerfile├── .gcloudignore└── src ├── go.mod └── main.gocloudbuild.yamlprovides Cloud Build with specific build instructionsDockerfilewill be using the build and run images from the previous stepsto create the application imagesrc/contains your application source code
Create a file named
Dockerfilein the directory with the following contents:ARGBUILD_IMAGEARGRUN_IMAGEFROM$BUILD_IMAGEasbuildCOPYsrc/staging/appCOPYsrc/tmp/appARGBUILDPACKSRUN/lifecycle/builder\-buildArtifactsCacheDir=/tmp/cache\-buildDir=/tmp/app\-buildpacksDir=/tmp/buildpacks\-outputBuildArtifactsCache=/tmp/output-cache\-outputDroplet=/tmp/droplet\-outputMetadata=/tmp/result.json\"-buildpackOrder=${BUILDPACKS}"\"-skipDetect=true"FROM$RUN_IMAGECOPY--from=build/tmp/dropletdropletRUNtar-xzfdroplet &&rmdropletCreate a file named
cloudbuild.yamlin the directory with the followingcontents:steps:-name:gcr.io/cloud-builders/dockerargs:-'build'-'--network'-'cloudbuild'-'--tag'-'${_TAG}'-'--build-arg'-'BUILD_IMAGE=${_BUILD_IMAGE}'-'--build-arg'-'RUN_IMAGE=${_RUN_IMAGE}'-'--build-arg'-'BUILDPACKS=${_BUILDPACKS}'-'.'images:-"${_TAG}"options:# Substitute build environment variables as an array of KEY=VALUE formatted strings here.env:[]substitutions:_BUILD_IMAGE:BUILD_IMAGE_URI_RUN_IMAGE:RUN_IMAGE_URI_BUILDPACKS:BUILDPACK_URL_TAG:APP_ARTIFACT_REGISTRY/APP_NAME:latest- Replace
BUILD_IMAGE_URIwith the URI of thebuild image created in previous steps. - Replace
RUN_IMAGE_URIwith the URI of therun image created in previous steps. - Replace
BUILDPACK_URLwith the URLs of the buildpacksused by your application. This can be a comma separated list with multiplebuildpacks.
- Replace
If you have a
.cfignorefile, copy it to the directory with the name.gcloudignore.Create a directory called
srcin the directory.Copy the contents of your application into
src:- If the source is a zip file (including
.jarfiles), unzip the contents intosrc. - If the source code is a directory, copy the contents into
src.
- If the source is a zip file (including
Run
gcloud builds submit .to build your application.
Known incompatibilities
- Buildpacks that rely on Cloud Foundry injected environment variables like
VCAP_SERVICESwon't work. You should instead explicitly declare a dependencyon what they inject using your language's management system. - To patch the images produced in this manner, you must rebuild the imageusing a newer version of the build and run image. Application images won't beautomatically patched by updating BOSH stemcells if you run them on Cloud Foundry.
- Builds will happen in a different network environment than your Cloud Foundrycluster, you may have to set up custom Cloud Build pools with access to yourinternal package mirrors.
What's Next
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-18 UTC.