2

我正在尝试输出在.sqlmariadb docker 容器中导入文件的进度。

我有以下文件/目录设置:

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

docker-compose.yml的很简单...

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

...使用以下 Dockerfile 安装pv(管道查看器)。pv应该给我一个进度条,目前导入有多远......

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

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"

现在,如果我运行docker-compose up它,它只会100%在导入结束时输出 pv 输出

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

如果我在容器执行相同的命令,它会起作用,它会给我一个移动的进度条:

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

我怎样才能打开这个进度条docker-compose up而不是长时间等待和100%输出?

4

2 回答 2

1

背景

首先让我们了解如何pv能够在终端的纯文本输出上呈现移动的进度条:pv实际上只是在每次进度更新时将纯文本打印到其标准输出:

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

这里的每一行代表一个进度更新,它输出引号pv的文本(所以没有引号)。

但这不会多行打印到终端:\r是一个回车符,它将光标移回行首而不开始新行。因此,下一个进度输出将覆盖先前的文本,从而产生进度条动画。

只有在最后一次更新之后pv才会打印换行符\n,从而在输出后产生最后的换行符。

现在的问题是docker-compose:启动一个应用程序docker-compose up将启动所有服务,附加到它们的输出并将其记录到它自己的输出中 - 以相应的服务名称为前缀:

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

为此,docker-compose将从每个容器中读取每个输出行,并在打印之前为其添加服务名称前缀。

但正如我们之前看到的,pv实际上只打印了一行!这就是为什么docker-compose在最终打印之前将输出缓冲到最后!


解决方案

我在这里看到两种可能的解决方案:

  1. 用于docker-compose run db初始化数据库:这将运行容器并将其输出直接附加到控制台并打印输出,而无需任何缓冲或后处理。

在这种情况下,您甚至可以省略该--force标志。

  1. 替换\r\n强制将每个进度更新打印在新行上,例如使用tr. 此外,要确保禁用您可能使用stdbuf的任何输出缓冲(请参阅关闭管道中的缓冲):
(pv --force -p "/docker-entrypoint-initdb.d/sql/test.sql" | mysql -uroot -proot "test") 2>&1 | stdbuf -o0 tr '\r' '\n'

将记录

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

演示

这是上面的一个小演示:

# 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'"

附录

根据评论,上述演示不适用于基于 ubuntu 的图像。在这样的图像中似乎tr会缓冲它的输出,并且只有在它退出后才打印所有内容。

但是,可以使用以下方法禁用输出缓冲区stdbuf(另请参阅关闭管道中的缓冲):

# 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'"
于 2021-02-24T14:27:11.563 回答
0

我找到了一个不错的解决方案:

--numeric标志添加到我的pv命令中。

从 pv 的手册页

-n,--数字

数字输出。pv 不会给出进度的视觉指示,而是给出一个整数百分比,每行一个,标准错误,适用于管道(通过复杂的重定向)进入对话框(1)。请注意,如果使用 -n,则不需要 -f。

所以我的命令import.sh是:

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

这给了我以下输出:

importing test.sql...
36
53
80
100

由于这不如pv这个答案的典型输出不完美......


我还尝试了没有换行符的更好的输出,例如:

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

附加awk命令:

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

但是同样的问题:这仅在容器内起作用,而不是在docker-compose up.

于 2021-02-24T10:09:02.593 回答