特别的往 Docker Container 中上传代码的技巧

折腾服务器的时候常常会遇到一些将本地写的代码传上服务器的需求,利用 SFTP 工具(Filezilla、WinSCP 之类)较为麻烦,所以我通常的做法是先使用 Vim 编辑器打开目标的文件,再将本地的代码粘贴到终端,然后保存、运行。

但这种做法在某些特殊环境下会遇到问题。最近我常常通过 Docker 在服务器部署代码,容器技术是个好东西,可以让你随时可以切换代码的执行环境而不需要在重新配置机器以致于搞得乱七八糟。有时候希望基于服务器端的 Docker 容器的环境执行一些临时写的脚本代码,但许多 Docker 镜像的制作者为了减小镜像的体积,实际上并没有给它安装文本编辑器这种东西。什么 Vi、Vim、Nano 统统不存在的。

在没有文本编辑器的情况下,想把代码传进 Docker 容器,很容易想到的一个方案是,在宿主机打开 Vim,通过往常的方式粘贴代码保存,再用 Docker 本身提供的 docker cp 命令拷贝进去。这个方案固然可以实现,但还是依赖着我先前的习惯去操作。这也引起了我的一个思考,我能不能不依赖文本编辑器,直接快速完成这个操作呢?

特别的技巧

想起了此前为了处理日志,通过 sed 和 awk 处理各种数据流的操作,脑洞一开,想到了一个直接从终端操作的简单办法。

方法很简单:
首先进入目标环境的 Shell,执行 cat > 目标文件名,此时终端处于等待输入的状态,然后我们在终端粘贴需要上传的代码,最后再按 Ctrl+D 发送一个 EOF 关闭输入即可。

原理是利用 cat 命令将终端的输入转化为数据流的输出(stream),然后使用I/O重定向符号 > 把 cat 的输出导向目标文件。

从此摆脱对编辑器的依赖了哈哈哈。

新的问题

当我在宿主机尝试这个技巧的时候遇到了一个新的问题:当我需要直接把程序粘贴到一个需要用 sudo 程序提升超级用户权限才能操作的文件的时候,想当然地 sudo cat > xxx.txt,会出现如下的 Permission denied 的情况。

$ sudo cat > /test.txt
-bash: /test.txt: Permission denied

由报错信息可以知道,这是 bash 报的错误,bash 是大多数 Linux 系统默认的 shell 程序。仔细思考,>bash 本身的语法指令,这条指令的执行者是 bash;通过 sudo 程序提权执行的 cat,具有超级用户的权限,而 cat 在这里只负责输出,并没有读写功能,真正写文件的操作者 bash 还是当前的没有权限的用户,自然会 Permission denied 了。

在 Docker 容器里面,默认都是超级用户,所以我此前的操作中并未遇到这个问题。

把这段命令的各个执行者的关系理清楚,这个需求的解决方案自然也浮出水面。我们只需要另外启动一个具备超级用户权限的 bash shell,就可以正常运行这段脚本了,sudo bash,或者 sudo su 都可以。

但这还需要另外多打一行命令,跑完还需要退出这个 bash,有些麻烦,有没有一条命令执行完就跑的办法呢?

想到 Python 可以利用 -c 参数,通过 python -c "需要一次性执行的Python命令" 来直接在命令行运行一些一次性完成的操作。bash 有没有这样的操作呢?通过 man bash 查看 bash 的帮助文档,发现还真的可以!而且就在 OPTIONS 的第一条。

OPTIONS
       All  of  the  single-character shell options documented in the descrip‐
       tion of the set builtin command can be used as options when  the  shell
       is invoked.  In addition, bash interprets the following options when it
       is invoked:

       -c        If the -c option is present, then commands are read from  the
                 first non-option argument command_string.  If there are argu‐
                 ments after the command_string,  they  are  assigned  to  the
                 positional parameters, starting with $0.

所以要这么实现的话,我们直接用:

sudo bash -c "cat > test.txt"

这时启动了一个具有超级用户权限、只执行 cat > test.txt 的 bash,就能实现在当前用户不可写入的目录写入一个 test.txt 了,看来 Python 的参数的设计也有模仿 bash 的啊。

最后

整理这篇笔记的过程中,想起了前两天在一个群里有个学中医的群友所说:

我们知道了不少技巧,但有时候就是不知道怎么应用起来,是因为技巧的层级没有得到确认,所以应用的时候无所适从。

大概这就是一个确认层级,把零散的概念逐渐归位的过程吧。

就像数据库,数据实体之间的关系,同数据实体一样重要。

已有 2 条评论
  1. Kay Kay

    基本操作🌸🐔

    1. 有时候脑子就是一下转不过来哈哈哈

添加新评论