繁体   English   中英

从另一个命令获取一些环境变量后,在运行于远程主机上的docker容器中运行任意命令

[英]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.

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