docker / docker-py

A Python library for the Docker Engine API
https://docker-py.readthedocs.io/
Apache License 2.0
6.81k stars 1.67k forks source link

docker-compose-up fails to fetch remote images #2482

Open davidje13 opened 4 years ago

davidje13 commented 4 years ago

Originally reported in https://github.com/docker/compose/issues/6939 but traced to code in this repository.

When using docker on a machine without logging in, running docker-compose up (with images which are not downloaded locally but are publicly available on dockerhub) will work on linux but fail on mac.

Steps to reproduce the issue

Output of docker-compose version

docker-compose version 1.24.1, build 4667896b
docker-py version: 3.7.3
CPython version: 3.6.8
OpenSSL version: OpenSSL 1.1.0j  20 Nov 2018

Output of docker version

Client: Docker Engine - Community
 Version:           19.03.2
 API version:       1.40
 Go version:        go1.12.8
 Git commit:        6a30dfc
 Built:             Thu Aug 29 05:26:49 2019
 OS/Arch:           darwin/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.2
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.12.8
  Git commit:       6a30dfc
  Built:            Thu Aug 29 05:32:21 2019
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          v1.2.6
  GitCommit:        894b81a4b802e4eb2a91d1ce216b8817763c29fb
 runc:
  Version:          1.0.0-rc8
  GitCommit:        425e105d5a03fabd737a126ad93d62a9eeede87f
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

Output of docker-compose config

services:
  anything:
    image: nginx
version: '2.0'

(nginx is used as an example here but any docker hub image will do)

  1. Ensure you are not logged in and do not have the configured image locally
  2. Run docker-compose up

Stacktrace / full error message

Pulling anything (nginx:)...
Traceback (most recent call last):
  File "site-packages/dockerpycreds/store.py", line 80, in _execute
  File "subprocess.py", line 356, in check_output
  File "subprocess.py", line 438, in run
subprocess.CalledProcessError: Command '['/usr/local/bin/docker-credential-desktop', 'get']' returned non-zero exit status 1.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "site-packages/docker/auth.py", line 264, in _resolve_authconfig_credstore
  File "site-packages/dockerpycreds/store.py", line 35, in get
  File "site-packages/dockerpycreds/store.py", line 93, in _execute
dockerpycreds.errors.StoreError: Credentials store docker-credential-desktop exited with "No stored credential for https://index.docker.io/v1/".

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "docker-compose", line 6, in <module>
  File "compose/cli/main.py", line 71, in main
  File "compose/cli/main.py", line 127, in perform_command
  File "compose/cli/main.py", line 1085, in up
  File "compose/cli/main.py", line 1081, in up
  File "compose/project.py", line 527, in up
  File "compose/service.py", line 354, in ensure_image_exists
  File "compose/service.py", line 1222, in pull
  File "compose/progress_stream.py", line 102, in get_digest_from_pull
  File "compose/service.py", line 1187, in _do_pull
  File "site-packages/docker/api/image.py", line 381, in pull
  File "site-packages/docker/auth.py", line 48, in get_config_header
  File "site-packages/docker/auth.py", line 322, in resolve_authconfig
  File "site-packages/docker/auth.py", line 235, in resolve_authconfig
  File "site-packages/docker/auth.py", line 281, in _resolve_authconfig_credstore
docker.errors.DockerException: Credentials store error: StoreError('Credentials store docker-credential-desktop exited with "No stored credential for https://index.docker.io/v1/".',)
[3629] Failed to execute script docker-compose

It appears that an attempt has been made to handle this situation:

https://github.com/docker/docker-py/blob/a0b9c3d0b38abd4af1880ca3dde2845556dd2f70/docker/auth.py#L276

Note that the exception type thrown by store.get does not match the expected type, so the wrapping logic in lines 279–282 applies instead, resulting in the observed docker.errors.DockerException: Credentials store error: StoreError('Credentials store docker-credential-desktop exited with "No stored credential for https://index.docker.io/v1/".',).

solintllc-robert commented 4 years ago

Could be causing this error downstream.

felixfontein commented 4 years ago

The problem is not the exception handling in auth.py, but this test: https://github.com/docker/docker-py/blob/master/docker/credentials/errors.py#L15

The message it looks for is defined here: https://github.com/docker/docker-credential-helpers/blob/master/credentials/error.go#L6

For some reasons, docker-credential-desktop seems to return No stored credential for https://index.docker.io/v1/ though.

(I now see that @davidje13 also reported this in https://github.com/shin-/dockerpy-creds/issues/13; @davidje13 that repository is inactive, since it was inclued in docker-py some time ago via a823acc2cae10c4635db2fb963cc37d8a23cc0c4)

Anyway, I guess the main question is why docker-credentials-desktop does not return the expected error message. I'm wondering what program this actually is. I first assumed it would be one of the programs in https://github.com/docker/docker-credential-helpers (probably the macOS version), but that hasn't been changed in years. The only idea I have is that the hardcoded macOS error message: https://github.com/docker/docker-credential-helpers/blob/master/osxkeychain/osxkeychain_darwin.go#L22 has changed in macOS. (It returns the message returned by macOS itself if it doesn't find this one.) I guess that now it returns No stored credential for https://index.docker.io/v1/ instead of The specified item could not be found in the keychain....

That leads to the C call to SecKeychainFindInternetPassword that is made (https://developer.apple.com/documentation/security/1397763-seckeychainfindinternetpassword?language=objc). Instead of working with the error codes (https://developer.apple.com/documentation/security/1542001-security_framework_result_codes?language=objc), the code in https://github.com/docker/docker-credential-helpers/blob/master/osxkeychain/osxkeychain_darwin.c#L71 uses SecCopyErrorMessageString (https://developer.apple.com/documentation/security/1394686-seccopyerrormessagestring?language=objc) to get a human-readable string. Which I guess changed over time.

So this should be a bug in https://github.com/docker/docker-credential-helpers, not in this repository.

davidje13 commented 4 years ago

Glad to see this issue is slowly-but-surely navigating the labyrinth of docker repositories!

felixfontein commented 4 years ago

Someone posted a workaround in docker/docker-credential-helpers#177, maybe that helps you.