Migración de ejemplo de Cloud Foundry a Cloud Run: Spring Music

En esta migración de ejemplo se usa el proyecto Spring Music para mostrar cómo se puede compilar una aplicación de Cloud Foundry como una imagen de aplicación compatible con OCI. En este ejemplo se usa la estrategia de migración lift and shift, que utiliza componentes de código abierto del ecosistema de Cloud Foundry. Una vez que hayas creado la imagen de la aplicación, tendrás que configurarla para desplegarla en Cloud Run.

Antes de empezar

  • Asegúrate de haber configurado un proyecto para Cloud Run tal como se describe en la página de configuración.
  • Asegúrate de tener un REGISTRY_URI para almacenar contenedores. Cloud Run recomienda usar Artifact Registry.
  • Si tu proyecto está sujeto a una política de organización de restricción de dominio que restringe las invocaciones no autenticadas, tendrás que acceder al servicio desplegado tal como se describe en la sección Probar servicios privados.

  • Instala Docker en tu estación de trabajo. Docker se usa para crear imágenes intermedias con las que compilar el proyecto.

Permisos necesarios para implementar

Para seguir esta guía, necesitas permisos para compilar, almacenar la imagen de contenedor compilada y desplegarla.

Debes tener los siguientes roles:

Estructura del proyecto

En esta guía, te recomendamos que crees un directorio de proyecto, por ejemplo, cr-spring-music/ y que crees subdirectorios a medida que avances en la guía.

cr-spring-music/
├── build
├── run
└── spring-music

Crea la imagen de compilación

En esta sección se crea una imagen de compilación usando cflinux3 como imagen base. La imagen de compilación se usa como entorno de compilación para crear la imagen de la aplicación.

  1. Crea un directorio llamado build/ y cd en él:

    mkdir build && cd build
    
  2. En la carpeta build/, crea un archivo llamado Dockerfile y pega el siguiente código:

    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. Usar Cloud Build para compilar y publicar la imagen builder

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

    Sustituye REGISTRY_URI por la dirección de Artifact Registry en la que quieras publicar la imagen de compilación. Por ejemplo: REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/builder:stable.

Crear la imagen de tiempo de ejecución

En esta sección se crea una imagen de ejecución usando cflinux3 como imagen base. La imagen de ejecución se usa como imagen base al crear la imagen de aplicación final.

  1. Crea un directorio llamado run/ y cd en él:

    mkdir run && cd run
    
  2. En la carpeta run/, crea una secuencia de comandos shell llamada entrypoint.bash con el siguiente código:

    #!/usr/bin/env bash
    set -e
    
    if [[ "$@" == "" ]]; then
    exec /lifecycle/launcher "/home/vcap/app" "" ""
    else
    exec /lifecycle/launcher "/home/vcap/app" "$@" ""
    fi
    
  3. En la carpeta run/, crea un archivo llamado Dockerfile y pega el siguiente código:

    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. Usa Cloud Build para compilar y publicar la imagen runtime:

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

    Sustituye REGISTRY_URI por la dirección de Artifact Registry en la que quieras publicar la imagen de compilación. Por ejemplo: REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/runtime:stable.

Compilar Spring Music para Cloud Foundry

Para clonar el proyecto Spring Music y ejecutar los comandos de compilación como si fuéramos a desplegar el proyecto en Cloud Foundry, haz lo siguiente:

  1. Clona el repositorio Spring Music:

    git clone https://github.com/cloudfoundry-samples/spring-music.git
    
  2. En esta guía, usaremos una versión anterior de la aplicación Spring Music que utiliza Java 8 y Spring Boot 2. Para ello, vamos a cambiar a una revisión anterior del proyecto Spring Music:

    git checkout 610ba471a643a20dee7a62d88a7879f13a21d6a3
    
  3. Ve al repositorio:

    cd spring-music
    
  4. Compila el archivo binario de Spring Music:

    ./gradlew clean assemble
    

Ahora tienes una carpeta build/ con la aplicación Spring Music compilada, lista para insertarse en una instancia de Cloud Foundry.

Convertir Spring Music en una aplicación compatible con Cloud Run

Debes usar el resultado del comando de compilación para preparar el artefacto de Spring Music para su despliegue en Cloud Run.

  1. Crea un directorio de ensayo cr-app y un subdirectorio src dentro de él:

    mkdir -p cr-app/src
    
  2. Imita cf push extrayendo el contenido del archivo JAR compilado en el directorio src:

    unzip build/libs/spring-music-1.0.jar -d cr-app/src
    
  3. Cambia al directorio cr-app/:

    cd cr-app/
    
  4. Crea un archivo llamado Dockerfile. Este Dockerfile usará la imagen de compilación y la imagen de tiempo de ejecución creadas en los pasos anteriores para crear la imagen de la aplicación ejecutable de Spring Music, mediante el paquete de compilación de Java.

  5. Pegue el siguiente código en el archivo 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
    

Compilar Spring Music como una imagen compatible con OCI

En este paso, le indicas a Cloud Build cómo crear una imagen compatible con OCI mediante la imagen de compilación, la imagen de tiempo de ejecución y el Dockerfile de la aplicación que has creado en los pasos anteriores.

Para crear la imagen compatible con OCI, sigue estos pasos:

  1. Crea un archivo llamado cloudbuild.yaml. Esta es una configuración de compilación que indicará a Cloud Build cómo compilar la aplicación.

  2. Pega la siguiente configuración en 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: REGISTRY_URI/builder:stable
      _RUN_IMAGE:  REGISTRY_URI/runtime:stable
      _BUILDPACKS: https://github.com/cloudfoundry/java-buildpack
      _TAG: REGISTRY_URI/spring-music:latest
    
    • Sustituye REGISTRY_URI por el URI del registro de contenedores en el que has publicado el compilador y el ejecutor.
  3. Crea la imagen de la aplicación con Cloud Build:

    gcloud builds submit .
    

    Cuando se complete la compilación, anota el URI de la imagen resultante. Lo necesitarás para implementar la aplicación en los pasos siguientes. La imagen resultante será una imagen de contenedor compatible con OCI para ejecutar la aplicación Spring Music, creada con componentes de código abierto de Cloud Foundry.

Desplegar en Cloud Run

Debes crear un archivo de definición de servicio para usarlo en Cloud Run:

  1. Crea una cuenta de servicio para tu aplicación:

    gcloud iam service-accounts create spring-music
    
  2. Crea un archivo service.yaml con el siguiente código:

    apiVersion: serving.knative.dev/v1
    kind: Service
    metadata:
      name: "spring-music"
      # Set this to be the project number of the project you're deploying to.
      namespace: "PROJECT_NUMBER"
      labels:
        cloud.googleapis.com/location: us-central1
        migrated-from: cloud-foundry
      annotations:
        run.googleapis.com/ingress: all
    spec:
      template:
        metadata:
          annotations:
            autoscaling.knative.dev/minScale: '1'
            autoscaling.knative.dev/maxScale: '1'
            run.googleapis.com/cpu-throttling: 'true'
            run.googleapis.com/startup-cpu-boost: 'true'
            run.googleapis.com/sessionAffinity: 'false'
        spec:
          containerConcurrency: 1000
          timeoutSeconds: 900
          serviceAccountName: spring-music@PROJECT_NUMBER.iam.gserviceaccount.com
          containers:
          - name: user-container
            # Set the following value to either:
            # - The image you built for your application in the last section of the guide.
            image: SPRING_IMAGE_URI
            ports:
            - name: http1
              containerPort: 8080
            env:
            - name: VCAP_APPLICATION
              value: |-
                    {
                        "application_id": "00000000-0000-0000-0000-000000000000",
                        "application_name": "spring-music",
                        "application_uris": [],
                        "limits": {
                        "disk": 0,
                        "mem": 1024
                        },
                        "name": "spring-music",
                        "process_id": "00000000-0000-0000-0000-000000000000",
                        "process_type": "web",
                        "space_name": "none",
                        "uris": []
                    }
            - name: MEMORY_LIMIT
              value: '1024M'
            resources:
              limits:
                memory: 1024Mi
                cpu: "1"
            startupProbe:
              httpGet:
                path: /
                port: 8080
              timeoutSeconds: 1
              failureThreshold: 30
              successThreshold: 1
              periodSeconds: 2
            livenessProbe:
              httpGet:
                path: /
                port: 8080
              timeoutSeconds: 1
              failureThreshold: 1
              successThreshold: 1
              periodSeconds: 30
      traffic:
      - percent: 100
        latestRevision: true
    
  3. Despliega el servicio en Cloud Run:

    gcloud run services replace service.yaml
    

    Una vez que se haya completado la implementación, podrás visitar la aplicación Spring Music en la URL implementada.

Siguientes pasos