How to push image with dockerode? (image not pushed but no error)

884 Views Asked by At

I have this code:

import * as Docker from 'dockerode'
const docker = new Docker()
const remoteDockerImage = docker.getImage(`${awsRepoUrl}:${version}`)

await remoteDockerImage.push({
  authconfig: { base64: 'auth token from aws' },
  tag: version,
})

After I run this there is no error, even if I put a on("error") on the return of .push.

And this creates the following in docker logs

[18:47:06.056][ApiProxy       ][Info   ] time="2019-01-18T18:47:06+08:00" msg="proxy >> POST /images/284135xxxxxx.dkr.ecr.us-east-1.amazonaws.com/xxxx:v0.1.200/push?tag=v0.1.200\n"
[18:49:18.018][DnsUpdater     ][Error  ] Unable to update dns settings: Value cannot be null.
Parameter name: first
[18:49:18.018][DnsUpdater     ][Info   ] Network configuration change detected
[18:49:19.068][DnsUpdater     ][Error  ] Unable to update dns settings: Value cannot be null.

And nothing happens, no image is pushed. not sure what are those dns errors...

But now when I go to the CMD line and I run docker login -u AWS -p secretAWSkey https://284135xxxxxx.dkr.ecr.us-east-1.amazonaws.com and then docker push my-image I see in the logs:

[18:57:17.517][ApiProxy       ][Info   ] time="2019-01-18T18:57:17+08:00" msg="proxy << POST /v1.39/auth (5.1241041s)\n"
[18:57:17.694][ApiProxy       ][Info   ] time="2019-01-18T18:57:17+08:00" msg="proxy >> GET /_ping\n"
[18:57:17.699][ApiProxy       ][Info   ] time="2019-01-18T18:57:17+08:00" msg="proxy << GET /_ping (3.9935ms)\n"
[18:57:18.107][ApiProxy       ][Info   ] time="2019-01-18T18:57:18+08:00" msg="proxy >> POST /v1.39/images/284135xxxxxx.dkr.ecr.us-east-1.amazonaws.com/app-repo/push?tag=v0.1.206\n"

Now the image is pushed and working.

Differences (working vs not working):

  • /v1.39/images/ vs /images/
  • call to /v1.39/auth vs no call

Not sure what to do, as the api for dockerode is really bad or missing and I can't figure out how to do it. Any help is appreciated. thank you

3

There are 3 best solutions below

0
On

As per dockerode's README.md file, you might need to swap "base64" for "key" in the authconfig object.

Please look a the pull example here : https://github.com/apocas/dockerode/blob/master/README.md#pull-from-private-repos

2
On

I know this is an old question, but I found the answer for myself to be that the stream needs to be listened to.

const repoImage = docker.getImage(imageName)
const isErrorMessage = (message) => 'error' in message && !!message.error;
const followProgress = async (
  stream,
  docker,
  onProgress,
) => {
  await new Promise((resolve, reject) => {
    docker.modem.followProgress(
      stream,
      (err, result) => err ? reject(err) : resolve(result),
      (progress) => {
        if (isErrorMessage(progress)) {
          reject(new Error(progress.error));
        } else {
          onProgress(progress);
        }
      },
    );
  });
}

const stream = await repoImage.push({ authconfig, tag });
const onProgress = (progress) => logger.debug(`${progress.id ? `(${progress.id})` : ''}: ${progress.status}${progress.progress ? ` ${progress.progress}` : ''}`);
await followProgress(stream, docker, onProgress);

1
On

I was able to push to ECR using dockerode with the following code:

The image name needs to be your repo URL

const repo = '1111111111.dkr.ecr.us-east-1.amazonaws.com/my-repository-name'
const name = repo
const tag = generateGuid()

When building the image, set the name and tag as below:

        const buildStream = await docker.buildImage(path, { t: `${name}:${tag}` })

Listen to the buildstream so that you know when it's complete.

buildStream.pipe(process.stdout)
const imageStream: any = await new Promise((resolve, reject) => {
   docker.modem.followProgress(
      buildStream,
      (err: Error | null, res: any) => (err ? reject(err) : resolve(res))
   )
})

You can extract the image hash from the buildStream if needed

const hash = imageStream.find((p: any) => Object.keys(p)[0] === 'aux').aux.ID

Get the authconfig using ECR Client

const ecrClient = new ECRClient({ region: 'us-east-1' })
const data = await ecrClient.send(new GetAuthorizationTokenCommand({}))
if (!data?.authorizationData) throw new Error('No authorizationData')
    
let authInfo = data.authorizationData[0]
let [user, pass] = Buffer.from(authInfo.authorizationToken ?? '', 'base64')
   .toString()
   .split(':')
const authconfig  = {
   username: user,
   password: pass,
   serveraddress: authInfo?.proxyEndpoint || '',
}
console.log('authconfig : ', authconfig)

const image = docker.getImage(name)

tag and push your image. You'll want to listen to the pushStream so that you know when the push is complete. Otherwise the process will exit early

console.log('tagging')
await image.tag({
   repo,
   tag,
})

console.log('pushing')
const pushStream = await image.push({
   authconfig,
   tag,
})
pushStream.pipe(process.stdout)
await new Promise((resolve, reject) => {
   docker.modem.followProgress(pushStream, (err: Error | null, res: any) =>
      err ? reject(err) : resolve(res)
   )
})