Reputation: 3035
My Python app is running fine locally. I've created a Dockerfile
and built an image. Inside the app I'm using the Python Google Cloud Logging library. When I try running the image I can see the following error from the Docker container logs:
File "/home/apprunner/app/./app/main.py", line 12, in <module>
2022-12-20 15:14:37 client = google.cloud.logging.Client()
2022-12-20 15:14:37 File "/home/apprunner/app/.venv/lib/python3.9/site-packages/google/cloud/logging_v2/client.py", line 122, in __init__
2022-12-20 15:14:37 super(Client, self).__init__(
2022-12-20 15:14:37 File "/home/apprunner/app/.venv/lib/python3.9/site-packages/google/cloud/client/__init__.py", line 320, in __init__
2022-12-20 15:14:37 _ClientProjectMixin.__init__(self, project=project, credentials=credentials)
2022-12-20 15:14:37 File "/home/apprunner/app/.venv/lib/python3.9/site-packages/google/cloud/client/__init__.py", line 271, in __init__
2022-12-20 15:14:37 raise EnvironmentError(
2022-12-20 15:14:37 OSError: Project was not passed and could not be determined from the environment.
I'm running the Docker container using the following commands where I pass in Application Default Credentials:
# Set shell variable
ADC=~/.config/gcloud/application_default_credentials.json \
docker run \
-d \
-v ${ADC}:/tmp/keys/application_default_credentials.json:ro \
-e GOOGLE_APPLICATION_CREDENTIALS=/tmp/keys/application_default_credentials.json \
IMAGE_NAME
I'm following the official guide on Docker with Google Cloud Access but using Application Default Credentials instead of a service account.
I've checked that my application_default_credentials.json
is present in that location and I've checked that ${ADC} has the correct value:
$ echo $ADC
/Users/ian/.config/gcloud/application_default_credentials.json
I see the stack trace points to the line in my code that calls the Logging library:
client = google.cloud.logging.Client()
And below it seems to suggest that it is expecting a project
as well as the credentials
:
_ClientProjectMixin.__init__(self, project=project, credentials=credentials)
Is this a problem with how I'm passing in my Application Default Credentials or should I be passing in some other project information?
If I explicitly pass in the project argument in my code I can get the Docker container to run successfully:
client = google.cloud.logging.Client(project='my-project')
However I don't want to make code changes for local development and this shouldn't be required. I don't understand why this isn't be pulled out of my ADC(?)
Upvotes: 0
Views: 1251
Reputation: 3035
I've been able to get it to run but only by explicitly passing in the project ID.
The GOOGLE_CLOUD_PROJECT
variable is an explicit requirement alongside GOOGLE_APPLICATION_CREDENTIALS
. The cleanest way is to pass both in as environment variables when running the container. This is the first place that is searched.
Set shell vars:
ADC=~/.config/gcloud/application_default_credentials.json \
PROJECT=my-project
Docker run:
$ docker run \
-v ${ADC}:/tmp/keys/application_default_credentials.json:ro \
-e GOOGLE_APPLICATION_CREDENTIALS=/tmp/keys/application_default_credentials.json \
-e GOOGLE_CLOUD_PROJECT=${PROJECT} \
IMAGE_NAME
The docs mention that the project should be inferred from the environment if not explicitly provided:
# if project not given, it will be inferred from the environment
client = google.cloud.logging.Client(project="my-project")
To be inferred from the environment you need to have:
gcloud auth application-default login
gcloud config set project PROJECT_ID
Passing ADC in to the locally running container through environment variables works for authentication but it doesn't pass in the active project as this is set in your local configuration (3)(~/.config/gcloud/configurations
on Mac/Linux). So no project can be inferred from the environment inside the container as it is not set and not passed. So it searches through the list of locations in order and doesn't find anything.
It's good practice to pass both authentication credentials and project identifier from the same place:
Credentials and project information must come from the same place (principle of least surprise).
Be explicit in setting them rather than relying on Application Default Credentials:
we really encourage people to explicitly pass credentials and project to the client constructor and not depend on the often surprising behavior of application default credentials.
Make the easy to find by setting them in the first place that will be searched:
GOOGLE_CLOUD_PROJECT
environment variableGOOGLE_APPLICATION_CREDENTIALS
JSON fileWith these in mind, passing them both in as environment variables ticks all the boxes.
Note: This looks to be the same throughout the Google Cloud Python Client Library and not just in Logging.
Upvotes: 2