Migrate to OCI containers

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.

Diagram describing how to create OCI images using moderntooling

Before you start

  1. Make sure you have set up a new project for Cloud Run as describedin theCloud Run setup page.
  2. Make sure you have aREGISTRY_URI for 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.

  1. Create a directory calledbuild/ andcd into it:

    mkdirbuild &&cdbuild
  2. In thebuild/ folder, create a new file calledDockerfile and 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=cflinuxfs3
  3. Use Cloud Build to build and publish thebuilder image

    gcloudbuilds\submit--tag"REGISTRY_URI/builder:stable"

    ReplaceREGISTRY_URI with 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.

  1. Create a directory calledrun/ andcd into it:

    mkdirrun &&cdrun
  2. In therun/ 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""$@"""fi
  3. In therun/ folder, create a new file calledDockerfile and 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={}
  4. Use Cloud Build to build and publish theruntime image:

    gcloudbuildssubmit\--tag"REGISTRY_URI/runtime:stable"

    ReplaceREGISTRY_URI with 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

  1. Look at the application stack. The stack is provided via the-s flag incf push or thestack field of the application manifest.

    1. If the stack is Windows, the application is likely incompatible with Cloud Run.You must port the application to Linux before continuing.
    2. If the stack is blank,cflinuxfs3, orcflinuxfs4 the applicationcan be migrated to Cloud Run.
  2. Gather the list of the application buildpacks. Buildpacks are provided viathe-b flag incf push, thebuildpack field in the applicationmanifest, or thebuildpacks field of the application manifest.

    1. 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.
    2. If the buildpacks are URLs, make note of the URLs and proceed to the next step.
    3. For any buildpack that uses a short name, use the following table to map them to URLs:

      Short NameURL
      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.

  3. Gather the source code location for the image. Source is provided via thepath attribute of the application manifest or the-p flag of thecfpush command. If the source is undefined, it refers to the currentdirectory.

  4. Determine whether there is a.cfignore file 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.go
  • cloudbuild.yaml provides Cloud Build with specific build instructions
  • Dockerfile will be using the build and run images from the previous stepsto create the application image
  • src/ contains your application source code
  1. Create a file namedDockerfile in 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 &&rmdroplet
  2. Create a file namedcloudbuild.yaml in 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
    • ReplaceBUILD_IMAGE_URI with the URI of thebuild image created in previous steps.
    • ReplaceRUN_IMAGE_URI with the URI of therun image created in previous steps.
    • ReplaceBUILDPACK_URL with the URLs of the buildpacksused by your application. This can be a comma separated list with multiplebuildpacks.
  3. If you have a.cfignore file, copy it to the directory with the name.gcloudignore.

  4. Create a directory calledsrc in the directory.

  5. Copy the contents of your application intosrc:

    1. If the source is a zip file (including.jar files), unzip the contents intosrc.
    2. If the source code is a directory, copy the contents intosrc.
  6. Rungcloud builds submit . to build your application.

Known incompatibilities

  • Buildpacks that rely on Cloud Foundry injected environment variables likeVCAP_SERVICES won'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.