DEV Community

Veerpal
Veerpal

Posted on • Originally published at veerpalbrar.github.io

Using a bash function to push a docker image

I've been learning a bit about docker and found myself repeating the same commands over and over again to push a docker image. I decided to see if I could create an alias for multiple commands in bash.

A quick google search shows that you can define functions in your .bashrc to run multiple commands at once. In the end, this is what I came up with.

function docker_push {
  LINE=$(docker build . 2>&1 | grep "writing image sha256")
  IMAGE_SHA=$(echo  $LINE |  awk '{print substr($0,26,10)}')
  docker tag $IMAGE_SHA $1
  docker push $1
}
Enter fullscreen mode Exit fullscreen mode

Then you can run docker_push username/repo:version to push your docker image.

If you're bash knowledge is as rusty as mine, here is a quick breakdown of how docker_push works.

Redirect docker build output to grep

First off, I knew I wanted to grep the output for docker build . for the docker image SHA256 code. I tried to do docker build . | grep "writing image sha256" but that resulted in an empty file.

Then I realized that docker build outputs to stderr, not stdout.

πŸ’‘ Bash automatically provides 3 types of file descriptors. There is stdout (file descriptor 1), stderr (file descriptor 2), and stdin (file descriptor 0). Commands read from stdin and then output to stdout or stdin.
When we use | in bash, we are piping the stdout of the first command as the stdin of the second command.

Therefore I used 2>&1 to redirect the stderr of docker build command to the stdout file descriptor instead. Then I could use | to redirect the stdout of docker build . to the stdin of the grep command.

This let me grep for the line with the SHA256 code. I save the output of grep into a variable for later use. This is done with MY_VAR=$(COMMAND) syntax, where the result of COMMAND is saved to MY_VAR.

For reference, the value of LINE is something like #11 writing image sha256:ee19794e19c05bfab071c3e3593379a20ae9b59cf0dd47ac0c39274e0333e6b2 done

Extracting the SHA256 code from the grep output

Next, I used awk to get the substring of the LINE that contains the beginning of the SHA256 code.

Since I know that LINE always starts with #11 writing image sha256:, I decided to get the substring starting at character 26, and get the next 10 characters, which are the starting of the SHA256 code. I did this with awk '{print substr($0,26,10)}' (full credit: stackoverflow)

Again, awk reads from stdin so I used echo $LINE to get the value of LINE and then I redirected that to stdin of awk. I save the result in $IMAGE_SHA.

Getting function arguments.

Now that I have the image SHA256 code, I can pass that as an argument to docker tag. The docker tag command needs the SHA256 code and the repo tag. Since the repo tag value changes based on which repo you are working with, I decided to pass that in as an argument to docker_push. Then I can use $1 to reference the first argument passed to my function.

So if I call docker_push username/repo:version then the value of $1 is "username/repo:version".

Sources:

Top comments (2)

Collapse
 
tbroyer profile image
Thomas Broyer • Edited

Any specific reason you go through this grep and awk rather than just passing the tag to the docker build? (or alternatively using --iidfile to get the SHA, but docker build -t username/repo:version . is much simpler)
docs.docker.com/engine/reference/c...

Collapse
 
veerpalb profile image
Veerpal

Simply because I didn't know that was an option :)

My method was largely motivated by "I'm writing these commands over and over again. Can I simplify it in a single command?" Since I already knew about grep and awk I went with those.