docker-py: Cannot pull images from AWS ECR (login does not seem to work properly)
I’m currently using docker-py 3.7.0 on an Ubuntu VM running Docker version 17.09.0-ce.
I’m having difficulty in what appears to be properly logging into docker. I’ve tried to get the AWS ECR credentials one of two ways: via boto3 and calling a subprocess for aws ecr get-login.
What happens is that when I try and pull an image, I get the dreaded
repository does not exist or may require ‘docker login’
message.
I invoke this script with sudo (eg. sudo ./myscript.py). If, prior to running the script, I run
aws ecr get-login --no-include-email --region us-west2
and then run the results with sudo, the script will properly run.
I’ve tried variations and even used reauth during login. When I do that, I get the response
http://localhost:None “POST /v1.35/auth HTTP/1.1” 200 48 login_results {‘IdentityToken’: ‘’, ‘Status’: ‘Login Succeeded’}
I’ve even deleted the ~/.docker/config.json file but this doesn’t help (a new file isn’t even written).
here is a code snippet of what I’m doing for the login. It’s a little messy right now since I’ve been trying permutations
command = "aws ecr get-login --no-include-email --region us-west-2"
p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE,stderr=subprocess.PIPE)
(out, err) = p.communicate()
outstr = out.decode("utf-8")
errstr = err.decode("utf-8")
if p.returncode == 0:
# Remove prefix
outstr = outstr.lstrip('docker login ')
parts = outstr.split(' ')
print(parts)
# -u
username = parts[1].strip()
# -p
password = parts[3].strip()
registry_url = parts[len(parts)-1].strip()
else:
print(p.returncode)
'''
token = ecr_client.get_authorization_token()
username, password = base64.b64decode(token['authorizationData'][0]['authorizationToken']).decode('utf-8').split(":")
registry_url = token['authorizationData'][0]['proxyEndpoint']
'''
print('username {}'.format(username))
print('password {}'.format(password))
print('registry_url {}'.format(registry_url))
docker_client = docker.from_env()
treg = registry_url + '/'
login_results = docker_client.login(username=username, password=password, reauth=True, registry=treg)
print('login_results {}'.format(login_results))
About this issue
- Original URL
- State: open
- Created 5 years ago
- Comments: 16
Okay, I ran some experiments the last few days. Had to deal with the 12 hour AWS ECR ticket so it took a little longer to do.
It does seem that there is an issue with docker-py.
Based on my findings, I can either use
boto3or run a sub-process calling the command line toaws ecr. However the only permutation that seems to work with the following steps.docker login. This will result in theconfig.jsonfile being updated (not sure if this has any relevance at all or not).docker_client = docker.from_env(). I have found doing this prior to the sub-process results in it not working properly (unless you have an already validconfig.jsondocker_client.login(username=username, password=password, registry=registry_url)Whether or not this is expected or not or if I’m doing something wrong, I don’t know. This is what I’ve come up with as steps that work.
This seems like a significant bug that should at least be documented! Ideally,
loginwould throw an exception instead of silently doing nothing. The combination of removinghttps://(@mikeage) and settingreauth=True(@dugarsumit) solved the issue for me. Either of those on its own didn’t change the behavior at all.Looks like this is still an issue? My workaround has been to wrap the whole thing in a context manager that clears out the config.json first, then does the work, and finally returns it to the original state. It’s not pretty but it does the job. (updated to use the decorator)
the docker.login() response usually has a Status: Login Succeeded when it works, but when the user has a
~/.docker/config.jsonthen the reply will be a totally different payload, containing the username/password (AWS and the super long b64 string use for docker login) instead of actually performing the login.2 of my collegues had that issue, and after deleting the config.json the response was appropriate again.
I too recently ran into this issue, but I don’t think it’s a
docker-pybug per se. I discovered the following after digging through the docker source code (written in Go).If you refer to the Docker API documentation the
/authendpoint actually only tests that registry credentials are valid, and optionally returns a token if the tested registry responds with one for future authentication. There is nothing about credential storage because the daemon does not, in fact, store credentials ever. Any credential storage that takes place is handled by thedockerbinary itself externally to the API.When executing
docker loginon the command line yourconfig.jsonfile is checked for any configured credential store; whatever string is found there is appended todocker-credential-and executed. The Docker project maintains a repo for the most common helpers: https://github.com/docker/docker-credential-helpersI was specifically using this library for integration with ECR as well; my process now looks like this:
boto3ECR client to get Docker credentialsdocker-pyfunctionlogin(), if desiredsubprocessPython standard library to calldocker-credential-<some configured helper>and pass the ECR credentials onstdinThat being said, I think the
docker-pydocumentation should be updated to call out this fact, and could be patched with credential storage similar to the CLI binary. The way it’s currently described implies similar functionality todocker loginon the command line, which is simply not the case.I’m not sure if this is related to your issue, but I’m having the same problem, and I was able to resolve it by calling
docker_client.loginwithregistryequal toregistry_url = token['authorizationData'][0]['proxyEndpoint'].replace("https://", ""). Note that I’m removing the leading https://I’ve done the
https://removal as well as thereauth=Truebut I’m still running into issues. I have a python service I’m deploying to ECS. The heart of the service is:On my local mac, I can run the above in Pycharm, works great. I can take the same script an bundle it in a container and run the container on my local machine, works great. I then push the container to ECR, and launch the container in ECS. I try and pull the image and I get the dreaded
Ah, found the problem. I was missing
ecr:GetDownloadUrlForLayerin the policy for the task.