![](/img/trans.png)
[英]How can I run a complex docker command from host machine that runs in the docker host?
[英]Run an arbitrary command in a docker container that runs on a remote host after sourcing some environment variables from another command
为了展示我正在尝试做的事情,这是我到目前为止的bash脚本的一部分:
COMMAND="${@:1}"
CONTAINER_DOCKER_NAME=this-value-is-computed-prior
MY_IP=this-ip-is-computed-prior
ssh user@$MY_IP -t 'bash -c "docker exec -it $( docker ps -a -q -f name='$CONTAINER_DOCKER_NAME' | head -n 1 ) /bin/sh -c "eval $(echo export FOO=$BAR) && $COMMAND""'
因此,让我们分解一下长命令:
我正在将主机ssh-shing到主机中,在其中运行bash并使用docker ps
提取正确的容器,然后执行docker exec
在容器中运行外壳程序以加载$COMMAND
需要工作的一些环境变量。 需要注意的重要一点是$BAR
应该是container内 BAR
变量的值。
这就是我想要在理论上完成的事情。 但是,无论我如何设置大括号,引号或转义字符,运行此命令时-我总是遇到问题,要么Shell语法不正确,要么它运行的命令不正确(特别是当命令具有多个参数时)或加载$BAR
值来自我的本地桌面或远程主机,但不来自容器。
单壳单缸泵甚至可以做到吗?
我认为我们可以简化您的命令。
首先,这里不需要使用eval
,也不需要&&
运算符:
/bin/sh -c "eval $(echo export FOO=$BAR) && $COMMAND"
代替:
/bin/sh -c "FOO=$BAR $COMMAND"
这FOO
环境变量FOO
为$COMMAND
的持续时间。
接下来,您不需要此复杂的docker ps
表达式:
docker ps -a -q -f name="$CONTAINER_DOCKER_NAME"
Docker容器名称是唯一的。 如果您的容器名称存储在$CONTAINER_DOCKER_NAME
,则可以运行:
docker exec -it $CONTAINER_DOCKER_NAME ...
这将docker
命令简化为:
docker exec -it $CONTAINER_DOCKER_NAME \
/bin/sh -c "FOO=\$BAR $COMMAND"
请注意,我们是如何在$BAR
转义$
,因为我们希望在容器内部而不是当前的shell解释$BAR
。 现在我们只需要安排通过ssh
运行它。 有两种解决方案。 我们可以确保确保命令行上的所有内容都不会受到Shell扩展级别的影响,如下所示:
ssh user@$MY_IP "docker exec -it $CONTAINER_DOCKER_NAME \
/bin/sh -c \"FOO=\\\$BAR $COMMAND\""
我们需要将整个命令用双引号引起来,这意味着我们需要对命令内的所有引号进行转义(由于我们实际上想在本地扩展变量$CONTAINER_DOCKER_NAME
,因此不能使用单引号)。 我们将失去\\
扩展的一级,因此我们的\\$BAR
变为\\\\\\$BAR
。
如果您的命令不是交互式的,则可以通过将脚本管道化为bash而不是在命令行中包括它来使代码的工作量少一些,如下所示:
ssh user@$MY_IP docker exec -i $CONTAINER_DOCKER_NAME /bin/sh <<EOF
FOO=\$BAR $COMMAND
EOF
这简化了将事物传递到容器外壳所需的引用和转义。
多亏了Larsks的出色解释,我才能正常工作,我最后的一线工作是:
ssh -i $ECS_SSH_KEY ec2-user@$EC2_IP -t "bash -c \"docker exec -it \$( docker ps -a -q -f name=$CONTAINER_DOCKER_NAME | head -n 1 ) /bin/sh -c \\\"eval \\\\\\\$(AWS_ENV_PATH=/\\\\\\\$ENVIRONMENT /bin/aws-env) && $COMMAND\\\"\""
因此,基本上,您将所有内容都用双引号引起来,然后在其中也使用双引号,因为我们需要一些变量,例如主机中的$DOCKER_CONTAINER_NAME
。 转义您使用\\的引号和$符号。
但是因为我们有多个级别的外壳程序(主机,服务器,容器),所以我们还需要使用多个级别的转义。 因此,第一级只是\\ $,它将保护变量(或shell命令,如docker ps
)不在主机上而是在服务器上运行。
那么下一个转义级别是7倍。 每个\\都会使字符向右转义,因此最后在第二层(服务器)为\\\\\\$
\\$
,在第三层(容器)为\\$
。 这样可以确保在服务器上而不是容器中评估变量。 双引号的原理相同。 \\"
之间的所有内容都在第二级上运行, \\\\\\"
之间的所有内容都在第三级上运行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.