我在 AWS EC2 实例 (Elastic Beanstalk) 上运行 Docker。我想在容器中以交互方式运行 bash自动地使用脚本,我可以从我的 shell 运行,而不必每次都输入所有命令。
我使用超级用户关于基于正则表达式打印单个参数的答案完成了此操作。如果我在登录 AWS 时键入或粘贴它,它会运行良好。
sudo docker exec -it $(sudo docker ps | awk '{for(i=1;i<=NF;i++){if($i~/ecs-awseb-mything-.*/){print $i}}}') bash
这是我的 SSH 连接“脚本”:
#!/usr/bin/env bash
ssh -i /path/to/my.pem awsuser@myhost
我尝试使用 ssh -t 将两者结合起来,但没有成功:
#!/usr/bin/env bash
ssh -i /path/to/my.pem awsuser@myhost -t "sudo docker exec -it $(sudo docker ps | awk '{for(i=1;i<=NF;i++){if($i~/ecs-awseb-mything-.*/){print $i}}}') bash"
但运气不佳。以下是控制台会话的记录:
myuser@MYCOMPUTER:~$ ./myscript.sh
sudo: unable to resolve host MYCOMPUTER
[sudo] password for myuser:
myuser@MYCOMPUTER:~$
看起来它正在尝试执行命令然后连接?所以我把它换成了这样:
#!/usr/bin/env bash
ssh -i /path/to/my.pem -t "sudo docker exec -it $(sudo docker ps | awk '{for(i=1;i<=NF;i++){if($i~/ecs-awseb-mything-.*/){print $i}}}') bash" awsuser@myhost
仍然是同样的问题。谢谢帮助!
答案1
您说子命令在 ssh 发生之前运行是正确的。这是因为您的 shell 会$( ... )
先看到其中的文本并执行它。可以通过将整个命令括在单引号'
而不是双引号中来解决此问题"
,但如果尝试使用嵌套引号,这会变得很复杂。幸运的是,有一种更简单的方法。
我假设您想要连接到已在运行的容器,而不是为每个新连接启动一个新容器。我建议为您的容器指定一个一致的名称,以便您在连接时可以引用它。例如
docker rename dc66a6ad31ca container_shell
替换dc66a6ad31ca
为您正在运行的容器的名称(您可以通过运行获取docker ps
)
完成此操作后,像这样运行 ssh 命令:
ssh -i /path/to/my.pem awsuser@myhost -t "sudo docker exec -it container_shell bash"
这样就可以了。ssh-t
命令中的选项是强制分配 pty 所必需的,然后 docker 命令中的 -t 在容器内执行相同的操作。
如果您将用户置于 docker 组中,那么也可以取消命令中的 sudo,但这是可选步骤。
编辑
@OrgnlDave 指出 Elastic Beanstalk 不允许重命名容器,因此需要 grep 来查找。他的解决方案是这样做:
ssh -i /path/to/my.pem myuser@host -t 'sudo docker exec -it $(sudo docker ps | grep -o ecs-awseb-mything-.*) bash'
如果有多个容器与模式匹配,将 grep 的输出限制为第一个匹配项也很有用。这可以通过添加-m 1
到 grep 命令来实现,使命令行如下所示:
ssh -i /path/to/my.pem myuser@host -t 'sudo docker exec -it $(sudo docker ps | grep -om1 ecs-awseb-mything-.*) bash'
答案2
您不需要 -t 用于 tty,只需添加不带开关的远程命令。
#!/usr/bin/env bash
ssh -i /path/to/my.pem awsuser@myhost "sudo docker exec -it $(sudo docker ps | awk '{for(i=1;i<=NF;i++){if($i~/ecs-awseb-mything-.*/){print $i}}}') bash"