Show docker load progress bar over SSH

SSH上でもdocker loadのプログレスバーを表示する


Introduction

I often load large (several gigabytes) docker images over SSH. Locally I can see progress bar saying "Loading layer". However the it is gone when docker is loaded over SSH.


Method and Result


Understanding internal state

Firstly I analyzed docker.sock packet. Since unix domain socket is used to communicate with docker backend, usual wireshark does not work well. So, after sudo mv /var/run/docker.sock /var/run/docker.sock.temp, I used two proxies to utilize wireshark tcp.port == 10000.

sudo socat UNIX-LISTEN:/var/run/docker.sock,mode=777,reuseaddr,fork TCP-CONNECT:localhost:10000

socat -v TCP-LISTEN:10000,fork UNIX-CONNECT:/var/run/docker.sock.temp

Then, while I ssh localhost docker load < img.tar, in wireshark I see POST /v1.30/images/load?quiet=1 HTTP/1.1 packet. This indicates that quiet mode was specified even though I'm not specifying -q.


Understanding the call stack

[backend]

components/engine/image/tarexport/load.go Load()
components/engine/daemon/image_exporter.go LoadImage()
components/engine/api/server/router/image/image_routes.go postImagesLoad()
[frontend]
components/cli/cli/command/image/load.go runLoad()

Now I understand that runLoad()'s dockerCli.Out().IsTerminal() controls the state.


How is the terminal checked?

In components/engine/pkg/term/term.go IsTerminal(), I see return tcget(fd, &termios) == 0. If this condition becomes true, the console output should be recognized as terminal.


Conclusion

I found that tcget is the key to get the progress bar back. But I cannot find how to achieve it yet. This is not a personal project, so (unlike cTouch's safariextz signing date hack) custom LD_PRELOAD cannot be used. I also tried unbuffer as described in https://unix.stackexchange.com/questions/249723/how-to-trick-a-command-into-thinking-its-output-is-going-to-a-terminal , but it does not work well either. Suggestions are welcomed...


PS

angel_p_57's method worked like a charm!