遷移至 OCI 容器

本頁說明重現 Cloud Foundry 建構程序時,產生與 OCI 相容的應用程式映像檔所需的建構基礎架構。如果您已完成 Spring Music 遷移指南,可以深入瞭解應用程式的特定遷移設定。

說明如何使用新式工具建立 OCI 映像檔的圖表

事前準備

  1. 請確認您已按照 Cloud Run 設定頁面的說明,為 Cloud Run 設定新專案。
  2. 請確認您有 REGISTRY_URI 可儲存容器。Cloud Run 建議使用 Artifact Registry。Docker 用於建立中間映像檔,以建構專案。

設定與 Cloud Foundry 相容的建構程序

您必須建立兩個基礎 OCI 容器,才能支援這項新程序:

  • 建構工具映像檔:鏡像 Cloud Foundry 的建構程序,並可將應用程式原始碼建構為 Cloud Foundry droplet。
  • 與 Cloud Foundry 應用程式執行階段相符的執行階段映像檔

平台管理員至少要執行一次這個程序。建立程序後,所有需要遷移至 Cloud Run 的 Cloud Foundry 應用程式,都可以共用建構和執行映像檔。

建立建構工具映像檔

本節會使用 cflinux3 做為基本映像檔,建立建構映像檔。建構映像檔會做為建構環境,用於建立應用程式映像檔。

  1. 建立名為 build/cd 的目錄:

    mkdir build && cd build
    
  2. build/ 資料夾中,建立名為 Dockerfile 的新檔案,然後貼入下列程式碼:

    ARG CF_LINUX_FS=cloudfoundry/cflinuxfs3
    
    FROM golang:1.20-bullseye AS builder_build
    WORKDIR /build
    RUN ["git", "clone", "--depth=1", "https://github.com/cloudfoundry/buildpackapplifecycle.git"]
    WORKDIR /build/buildpackapplifecycle
    RUN ["go", "mod", "init", "code.cloudfoundry.org/buildpackapplifecycle"]
    RUN ["go", "mod", "tidy"]
    RUN CGO_ENABLD=0 go build -o /builder ./builder/
    
    FROM $CF_LINUX_FS
    # Set up container tools related to building applications
    WORKDIR /lifecycle
    COPY --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-env
    WORKDIR /staging/app
    WORKDIR /tmp
    ENV CF_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. 使用 Cloud Build 建構及發布 builder 映像檔

    gcloud builds \
        submit --tag "REGISTRY_URI/builder:stable"
    

    REGISTRY_URI 替換為要發布建構映像檔的 Artifact Registry 位址。例如: REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/builder:stable

建立執行階段映像檔

本節會使用 cflinux3 做為基礎映像檔,建立執行映像檔。建立最終應用程式映像檔時,系統會將執行映像檔做為基礎映像檔。

  1. 建立名為 run/cd 的目錄:

    mkdir run && cd run
    
  2. run/ 資料夾中,使用下列程式碼建立名為 entrypoint.bash 的新殼層指令碼:

    #!/usr/bin/env bash
    set -e
    
    if [[ "$@" == "" ]]; then
    exec /lifecycle/launcher "/home/vcap/app" "" ""
    else
    exec /lifecycle/launcher "/home/vcap/app" "$@" ""
    fi
    
  3. run/ 資料夾中,建立名為 Dockerfile 的新檔案,然後貼上以下程式碼:

    ARG CF_LINUX_FS=cloudfoundry/cflinuxfs3
    
    FROM golang:1.20-bullseye AS launcher_build
    WORKDIR /build
    RUN ["git", "clone", "--depth=1", "https://github.com/cloudfoundry/buildpackapplifecycle.git"]
    WORKDIR /build/buildpackapplifecycle
    RUN ["go", "mod", "init", "code.cloudfoundry.org/buildpackapplifecycle"]
    RUN ["go", "mod", "tidy"]
    RUN CGO_ENABLD=0 go build -o /launcher ./launcher/
    
    FROM $CF_LINUX_FS
    # Set up container tools related to launching the application
    WORKDIR /lifecycle
    COPY entrypoint.bash /lifecycle/entrypoint.bash
    RUN ["chmod", "+rx", "/lifecycle/entrypoint.bash"]
    COPY --from=launcher_build /launcher /lifecycle/launcher
    
    # Set up environment to match Cloud Foundry
    WORKDIR /home/vcap
    USER vcap:vcap
    ENTRYPOINT ["/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.
    EXPOSE 8080/tcp
    # Set up environment variables similar to Cloud Foundry.
    ENV CF_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. 使用 Cloud Build 建構及發布 runtime 映像檔:

    gcloud builds submit \
        --tag "REGISTRY_URI/runtime:stable"
    

    REGISTRY_URI 替換為要發布建構映像檔的 Artifact Registry 位址。例如:REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/runtime:stable.

將 Cloud Foundry 應用程式建構為 OCI 映像檔

遷移至 Cloud Run 的每個應用程式都需要專屬的 Dockerfile,與 Cloud Foundry 執行應用程式的方式相符。Dockerfile 會執行下列動作:

  • 載入建構工具映像檔。
  • 執行 v2 建構套件生命週期,建立 droplet。
  • 擷取水滴的內容。
  • 將執行映像檔上的微滴內容載入,建立可執行的應用程式映像檔。

最終的應用程式映像檔與 Cloud Foundry 和 Cloud Run 皆相容,因此您可以進行 A/B 測試,協助偵錯任何非預期行為。

應用程式團隊必須為每個需要遷移的應用程式執行這個程序。

從已部署的 Cloud Foundry 應用程式收集建構資訊

  1. 查看應用程式堆疊。堆疊是透過 cf push 中的 -s 標記或應用程式資訊清單的 stack 欄位提供。

    1. 如果堆疊是 Windows,應用程式可能與 Cloud Run 不相容。您必須先將應用程式移植到 Linux,才能繼續操作。
    2. 如果堆疊空白、cflinuxfs3cflinuxfs4,應用程式即可遷移至 Cloud Run。
  2. 收集應用程式建構套件清單。建構套件可透過 cf push 中的 -b 標記、應用程式資訊清單中的 buildpack 欄位,或應用程式資訊清單的 buildpacks 欄位提供。

    1. 如果未指定建構套件,表示系統會自動偵測。查看 Cloud Foundry 中最近一次應用程式部署作業偵測到的建構套件清單,或在知道路徑的情況下明確指定建構套件。
    2. 如果建構套件是網址,請記下這些網址,然後繼續下一個步驟。
    3. 如果建構套件使用簡稱,請參閱下表將簡稱對應至網址:

      簡稱 網址
      staticfile_buildpack https://github.com/cloudfoundry/staticfile-buildpack
      java_buildpack https://github.com/cloudfoundry/java-buildpack
      ruby_buildpack https://github.com/cloudfoundry/ruby-buildpack
      dotnet_core_buildpack https://github.com/cloudfoundry/dotnet-core-buildpack
      nodejs_buildpack https://github.com/cloudfoundry/nodejs-buildpack
      go_buildpack https://github.com/cloudfoundry/go-buildpack
      python_buildpack https://github.com/cloudfoundry/python-buildpack
      php_buildpack https://github.com/cloudfoundry/php-buildpack
      binary_buildpack https://github.com/cloudfoundry/binary-buildpack
      nginx_buildpack https://github.com/cloudfoundry/nginx-buildpack

      如要查看較不常見的建構包來源,請前往 Cloud Foundry GitHub 機構

  3. 收集圖片的原始碼位置。來源是透過應用程式資訊清單的 path 屬性或 cf push 指令的 -p 旗標提供。如果來源未定義,則是指目前的目錄。

  4. 判斷原始碼目錄中是否有 .cfignore 檔案。如果檔案存在,請將其移至名為 .gcloudignore. 的檔案

建構 Cloud Foundry 應用程式

在這個步驟中,您會將建構元素整理到下列資料夾結構中:

.
├── cloudbuild.yaml
├── Dockerfile
├── .gcloudignore
└── src
    ├── go.mod
    └── main.go
  • cloudbuild.yaml 為 Cloud Build 提供具體的建構指示
  • Dockerfile 會使用上一個步驟中的建構和執行映像檔,建立應用程式映像檔
  • src/ 包含應用程式原始碼
  1. 在目錄中建立名為 Dockerfile 的檔案,並在當中加入下列內容:

    ARG BUILD_IMAGE
    ARG RUN_IMAGE
    FROM $BUILD_IMAGE as build
    
    COPY src /staging/app
    COPY src /tmp/app
    
    ARG BUILDPACKS
    RUN /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_IMAGE
    COPY --from=build /tmp/droplet droplet
    RUN tar -xzf droplet && rm droplet
    
  2. 在目錄中建立名為 cloudbuild.yaml 的檔案,並在當中加入下列內容:

    steps:
    - name: gcr.io/cloud-builders/docker
      args:
      - '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
    
    • BUILD_IMAGE_URI 替換為先前步驟中建立的建構映像檔 URI。
    • RUN_IMAGE_URI 替換為先前步驟中建立的執行映像檔 URI。
    • BUILDPACK_URL 替換為應用程式使用的建構套件網址。這可以是半形逗號分隔的清單,內含多個建構套件。
  3. 如有 .cfignore 檔案,請複製到名為 .gcloudignore 的目錄。

  4. 在目錄中建立名為 src 的目錄。

  5. 將應用程式的內容複製到 src:

    1. 如果來源是 ZIP 檔案 (包括 .jar 檔案),請將內容解壓縮至 src
    2. 如果原始碼是目錄,請將內容複製到 src
  6. 執行 gcloud builds submit . 建構應用程式。

已知不相容情形

  • 依賴 Cloud Foundry 插入環境變數 (例如 VCAP_SERVICES) 的建構套件無法運作。您應改用語言的管理系統,明確宣告要注入的項目。
  • 如要修補以這種方式產生的映像檔,您必須使用較新版本的建構和執行映像檔,重新建構映像檔。如果您在 Cloud Foundry 上執行應用程式映像檔,更新 BOSH Stemcell 時,系統不會自動修補應用程式映像檔。
  • 建構作業會在與 Cloud Foundry 叢集不同的網路環境中進行,您可能必須設定可存取內部套件鏡像的自訂 Cloud Build 集區。

後續步驟