docker-compose 启动时 pv 的输出未按预期工作
Output of pv on docker-compose startup not working as expected
我正在尝试输出在 mariadb docker 容器中导入 .sql
文件的进度。
我有以下 file/directory 设置:
│- 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
should give me 导入进度条...
FROM mariadb
RUN apt-get update && apt-get install -y pv
import.sh
将通过 /docker-entrypoint-initdb.d
as described here 中的映射卷执行。
#!/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%
输出?
我找到了一个还可以的解决方案:
将 --numeric
标记添加到我的 pv
命令中。
-n, --numeric
Numeric 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). Note
that -f is not required if -n is being used.
所以我的 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% ",[=13=]}'
但又是同样的问题:这只在容器内部起作用,而在docker-compose up
.
的输出上不起作用
背景
首先让我们了解 pv
如何能够在终端的纯文本输出上呈现移动进度条:pv
实际上只是在每次进度更新时将纯文本打印到其标准输出:
"[==> ] 25%\r"
"[======> ] 50%\r"
"[=========> ] 76%\r"
"[============>] 100%\n"
这里的每一行都代表一个进度更新,pv
在 引号内输出文本 (因此没有引号)。
但这不会分多行打印到终端:\r
是一个 carriage return 字符,它会将光标移回行首 而无需开始新行。因此下一个进度输出将覆盖导致进度条动画的前一个文本。
只有在上次更新后pv
才会打印换行符\n
导致输出后最后换行。
现在关于 docker-compose
的问题:使用 docker-compose up
启动应用程序将启动所有服务,附加到它们的输出并将其记录到它自己的输出 - 以相应的服务名称为前缀:
app_1 | starting App...
db_1 | initializing database
....
要执行此操作 docker-compose
将从每个容器读取每个输出行并在打印之前在其前面加上服务名称。
但是正如我们之前看到的 pv
实际上只打印一行!这就是为什么 docker-compose
会在最终打印之前缓冲输出直到结束!
解决方案
我在这里看到两种可能的解决方案:
- 使用
docker-compose run db
初始化数据库:这将 运行 容器及其输出直接连接到控制台并打印输出,无需任何缓冲或 post 处理。
在这种情况下,您甚至可以省略 --force
标志。
- 将
\r
替换为 \n
以强制在新行上打印每个进度更新,例如使用 tr
. Additionally to be sure to disable any output buffering you may use stdbuf
with it (see turn off buffering in pipe):
(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
(see also turn off buffering in 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'"
我正在尝试输出在 mariadb docker 容器中导入 .sql
文件的进度。
我有以下 file/directory 设置:
│- 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
should give me 导入进度条...
FROM mariadb
RUN apt-get update && apt-get install -y pv
import.sh
将通过 /docker-entrypoint-initdb.d
as described here 中的映射卷执行。
#!/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%
输出?
我找到了一个还可以的解决方案:
将 --numeric
标记添加到我的 pv
命令中。
-n, --numeric
Numeric 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). Note that -f is not required if -n is being used.
所以我的 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% ",[=13=]}'
但又是同样的问题:这只在容器内部起作用,而在docker-compose up
.
背景
首先让我们了解 pv
如何能够在终端的纯文本输出上呈现移动进度条:pv
实际上只是在每次进度更新时将纯文本打印到其标准输出:
"[==> ] 25%\r"
"[======> ] 50%\r"
"[=========> ] 76%\r"
"[============>] 100%\n"
这里的每一行都代表一个进度更新,pv
在 引号内输出文本 (因此没有引号)。
但这不会分多行打印到终端:\r
是一个 carriage return 字符,它会将光标移回行首 而无需开始新行。因此下一个进度输出将覆盖导致进度条动画的前一个文本。
只有在上次更新后pv
才会打印换行符\n
导致输出后最后换行。
现在关于 docker-compose
的问题:使用 docker-compose up
启动应用程序将启动所有服务,附加到它们的输出并将其记录到它自己的输出 - 以相应的服务名称为前缀:
app_1 | starting App...
db_1 | initializing database
....
要执行此操作 docker-compose
将从每个容器读取每个输出行并在打印之前在其前面加上服务名称。
但是正如我们之前看到的 pv
实际上只打印一行!这就是为什么 docker-compose
会在最终打印之前缓冲输出直到结束!
解决方案
我在这里看到两种可能的解决方案:
- 使用
docker-compose run db
初始化数据库:这将 运行 容器及其输出直接连接到控制台并打印输出,无需任何缓冲或 post 处理。
在这种情况下,您甚至可以省略 --force
标志。
- 将
\r
替换为\n
以强制在新行上打印每个进度更新,例如使用tr
. Additionally to be sure to disable any output buffering you may usestdbuf
with it (see turn off buffering in pipe):
(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
(see also turn off buffering in 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'"