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!