简体   繁体   English

docker-compose 上 pv 的 Output 启动未按预期工作

[英]Output of pv on docker-compose startup not working as expected

I am trying to output the progress of an import of an .sql file inside a mariadb docker container.我正在尝试 output 在 mariadb Z05B6053C41A21430AFD6FC3B7Z 容器中导入.sql文件的进度。

I have the following file/directory setup:我有以下文件/目录设置:

│-  docker-compose.yml
│-  Dockerfile
│-  import.sh
└── sql
    -  test.sql (rather big: ~ 1GB)

My docker-compose.yml is as simple as...我的docker-compose.yml就像...

services:
  db:
    build: ./
    environment:
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - ./:/docker-entrypoint-initdb.d

...with the following Dockerfile to install pv (pipe viewer). ...使用以下 Dockerfile 安装pv (管道查看器)。 pv should give me a progress bar how far the import is currently... pv应该给我一个进度条,目前导入的距离...

FROM mariadb
RUN apt-get update && apt-get install -y pv

The import.sh will be executed through the mapped volume in /docker-entrypoint-initdb.d as described here . import.sh将通过/docker-entrypoint-initdb.d中的映射卷执行,如此处所述

#!/bin/bash
# create db
mysql -uroot -proot <<-EOF
  CREATE DATABASE test;
EOF
# import sql file and output progress with pv
echo "importing test.sql..."
pv --force "/docker-entrypoint-initdb.d/sql/test.sql" | mysql -uroot -proot "test"

Now, if I run docker-compose up it only outputs the 100% pv output at the end of the import :现在,如果我docker-compose up只会在导入结束时输出100% pv output

importing test.sql...
953MiB 0:01:24 [11.2MiB/s] [================================>] 100%    0:05:42

If I execute the same command inside the container it works and it gives me a moving progress bar:如果我在容器执行相同的命令,它会起作用,它会给我一个移动的进度条:

pv --force "/docker-entrypoint-initdb.d/sql/test.sql" | mysql -uroot -proot "test"
60.4MiB 0:00:14 [5.79MiB/s] [=>                              ]  6%     0:04:53

How can I get this progress bar on docker-compose up instead of the loong wait and the 100% output?如何在docker-compose up获得此进度条,而不是长时间等待和100% output?

Background背景

First let's understand how pv is able to render a moving progress bar on a text-only output to the terminal: pv actually just prints plain text to its stdout with each progress update:首先让我们了解pv如何能够将纯文本 output 上的移动进度条渲染到终端: pv实际上只是在每次进度更新时将纯文本打印到其标准输出:

"[==>           ] 25%\r"
"[======>       ] 50%\r"
"[=========>    ] 76%\r"
"[============>] 100%\n"

Each line here represents a single progress update for which pv outputs the text within the quotes (so no quotes).这里的每一行代表一个单独的进度更新, pv输出引号的文本(所以没有引号)。

But this will not print in multiple lines to the terminal: \r is a carriage return character which will move the cursor back to the beginning of the line without starting a new line .但这不会多行打印到终端: \r是一个回车符,它将把 cursor 移回行首而不开始新行 So the next progress output will override the previous text resulting in the progress bar animation.所以下一个进度 output 将覆盖前面的文本,导致进度条 animation。

Only after the last update pv will print the new line character \n resulting in a final line break after the output.只有在最后一次更新pv之后才会打印换行符\n ,从而导致 output 之后的最后一个换行符。

Now to the problem with docker-compose : starting an app with docker-compose up will start all services, attach to their output and log it to its own output - prefixed with the respective service name: Now to the problem with docker-compose : starting an app with docker-compose up will start all services, attach to their output and log it to its own output - prefixed with the respective service name:

app_1  | starting App...
db_1   | initializing database
....

To do this docker-compose will read each output line from each container and prefix it with the service name before printing it.为此, docker-compose将从每个容器中读取每个 output 行,并在打印之前为其添加服务名称前缀。

But as we saw before pv actually only prints a single line!但正如我们之前看到的pv实际上只打印一行! This is why docker-compose will buffer the output until the end before finally printing it!这就是为什么docker-compose会缓冲 output 直到最后才打印出来的原因!


Solutions解决方案

I see two possible solutions here:我在这里看到两种可能的解决方案:

  1. use docker-compose run db to initialize the database: this will run the container with its output directly attached to the console and print the output without any buffering or post-processing.使用docker-compose run db来初始化数据库:这将运行容器,其 output 直接连接到控制台并打印 output 而无需任何缓冲或后处理。

In this case you then can even omit the --force flag.在这种情况下,您甚至可以省略--force标志。

  1. replace \r with \n to force every progress update to be printed on a new line, eg using tr .\r替换为\n以强制将每个进度更新打印在新行上,例如使用tr Additionally to be sure to disable any output buffering you may use stdbuf with it (see turn off buffering in pipe ):此外,要确保禁用任何 output 缓冲,您可以使用stdbuf (请参阅pipe 中的关闭缓冲):
(pv --force -p "/docker-entrypoint-initdb.d/sql/test.sql" | mysql -uroot -proot "test") 2>&1 | stdbuf -o0 tr '\r' '\n'

will log将记录

db_1   | [==>           ] 25%
db_1   | [======>       ] 50%
db_1   | [=========>    ] 76%
db_1   | [============>] 100%

Demo演示

Here is a small demo of the above:这是上面的一个小演示:

# Dockerfile
FROM alpine
RUN apk add pv
# docker-compose.yml
services:
  app:
    build: .
    command: sh -c "pv --force -p -Ss 1024 -L 100 /dev/urandom 2>&1 > /dev/null | tr '\r' '\n'"

Addendum附录

As per comments the above demo does not work with an ubuntu based image.根据评论,上述演示不适用于基于 ubuntu 的图像。 It seems in such images tr will buffer its output and only print everything once it exits.在这样的图像中tr似乎会缓冲它的 output 并且只有在它退出后才打印所有内容。

The output buffer can however be disabled using stdbuf (see also turn off buffering in pipe ):但是,可以使用stdbuf禁用 output 缓冲区(另请参阅 pipe 中的关闭缓冲):

# Dockerfile
FROM ubuntu
RUN apt-get update && apt-get install -y pv
# docker-compose.yml
services:
  app:
    build: .
    command: sh -c "pv --force -p -Ss 1024 -L 100 /dev/urandom 2>&1 > /dev/null | stdbuf -o0 tr '\r' '\n'"

I found a somewhat okayish solution:我找到了一个不错的解决方案:

Adding the --numeric flag to my pv command.--numeric标志添加到我的pv命令中。

From the man page of pv :从 pv 的手册页

-n, --numeric -n,--数字

Numeric output.数字 output。 Instead of giving a visual indication of progress, pv will give an integer percentage, one per line , on standard error, suitable for piping (via convoluted redirection) into dialog(1). pv 不会给出进度的视觉指示,而是给出 integer 百分比,每行一个,标准错误,适合管道(通过卷积重定向)进入对话框(1)。 Note that -f is not required if -n is being used.请注意,如果使用 -n,则不需要 -f。

So the command in my import.sh would be:所以我的import.sh中的命令是:

pv --numeric "/docker-entrypoint-initdb.d/sql/test.sql" | mysql -uroot -proot "test"

This gives me the following output:这给了我以下 output:

importing test.sql...
36
53
80
100

Since this is not as nice as the typical output of pv this answer is not perfect...由于这不如pv的典型 output 好,所以这个答案并不完美......


I also tried a little nicer output without the newlines like:我还尝试了更好的 output 没有换行符,例如:

importing test.sql...
36% 53% 80% 100%

with appending an awk command:附加awk命令:

(pv --numeric "/docker-entrypoint-initdb.d/sql/test.sql" | mysql -uroot -proot "test") 2>&1 | awk '{printf "%s% ",$0}'

But again, same problem: this did only work inside the container and not on the output of docker-compose up .但是同样的问题:这仅在容器内部有效,而在docker-compose up的 output 上无效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM