4

I am writing a program that speaks with Cloud Spanner in Postgres Dialect. My application is a gin server and I am using pgadapter to connect as mentioned in this doc.

My application runs fine locally. But when I deploy it to cloud run, I get the following log. enter image description here

The error basically comes from the StartPGAdapterWithCredentials function.

func StartPGAdapter(ctx context.Context, project, instance string) (port int, cleanup func(), err error) {
    credentials, err := google.FindDefaultCredentials(ctx)
    fmt.Println("credentials " + (credentials.ProjectID) + "json " + utils.ToString(credentials.JSON) + "ts " + utils.ToString(credentials.TokenSource))
    if err != nil {
        return 0, func() {}, err
    }
    return StartPGAdapterWithCredentials(ctx, project, instance, credentials)
}
func StartPGAdapterWithCredentials(ctx context.Context, project, instance string, credentials *google.Credentials) (port int, cleanup func(), err error) {
    if credentials == nil {
        return 0, func() {}, fmt.Errorf("credentials cannot be nil")
    }
    if credentials.JSON == nil || len(credentials.JSON) == 0 {
        return 0, func() {}, fmt.Errorf("only JSON based credentials are supported")
    }
    credentialsFile, err := os.CreateTemp(os.TempDir(), "pgadapter-credentials")
    if err != nil {
        return 0, func() {}, err
    }

On my local system, GOOGLE_APPLICATION_CREDENTIALS is set and hence it is able to get the credentials. However, this is not working in cloud run.

How do I get it to run in cloud run?

Additional Info : followed the example present here.

Knut Olav Løite
  • 2,964
  • 7
  • 19
positron
  • 134
  • 1
  • 10
  • Be sure the `GOOGLE_APPLICATION_CREDENTIALS` point to a valid json file that contains the service account credentials. See also https://github.com/GoogleCloudPlatform/golang-samples/blob/b4e5aa87903747985c8c096f29598d0de5b6cbbc/monitoring/README.md#using-a-service-account – Matteo Apr 04 '23 at 12:53
  • 1
    Hi @Matteo, thanks for the comment. But as mentioned in the question, the code working fine on the local setup. It fails in cloud run. I am not setting any GOOGLE_APPLICATION_CREDENTIALS there. I guess it should fetch from the well-known file or metadata server or something... – positron Apr 04 '23 at 12:59
  • How do you start PGAdapter? In your container? Can you show this part? – guillaume blaquiere Apr 04 '23 at 14:03
  • I am following this example https://github.com/GoogleCloudPlatform/pgadapter/blob/postgresql-dialect/samples/golang/pgx/pgx_sample.go – positron Apr 04 '23 at 18:01
  • The Cloud Run metadata server does not return JSON credentials. It returns an OAuth token. I am not familiar with that library but the code requires JSON credentials (a service account JSON file). – John Hanley Apr 04 '23 at 18:49
  • I am calling this function (FindDefaultCredentials) https://pkg.go.dev/golang.org/x/oauth2/google#FindDefaultCredentials. Are you saying this requires a service account JSON file to work? How will I deploy this to cloud run then? There should be a way for applications to get access to the service account associated with the revision I think... – positron Apr 04 '23 at 19:11
  • Cloud Run does not provide access to the underlying service account JSON credentials. Cloud Run provides OAuth and OIDC tokens. The code you are using requires JSON credentials. – John Hanley Apr 04 '23 at 19:25

1 Answers1

2

It seems that you are trying to start PGAdapter in an embedded container on Cloud Run, and then copy the service account credentials from your environment to the PGAdapter embedded container. The problem is that Cloud Run does not provide access to the underlying service account file. Instead, you should just let the Google Cloud libraries get the default credentials of the environment.

The difficult part in your example is that you are starting PGAdapter in an embedded container, which means that there are no default credentials in that environment. The recommended way to run PGAdapter on Cloud Run is to include it in your main container. That will make it possible for PGAdapter to just fetch the default credentials that are provided by Cloud Run. That means that you should not specify the -c /path/to/credentials.json argument when starting PGAdapter.

There are (at least) two ways that you can include PGAdapter in your main container:

  1. Add the Java .jar file build to your Docker image and start PGAdapter in your container. See [this example] for how to start PGAdapter directly from .jar files. This also requires you to add a Java JRE to your Docker image.
  2. Let your Docker build extend the PGAdapter base Docker image. This will automatically include all dependencies that are needed for PGAdapter. You will have to override the ENTRYPOINT of the base image.

See PGAdapter Cloud Run Sample for Go for an extensive (runnable) sample for the latter option.

Knut Olav Løite
  • 2,964
  • 7
  • 19