容器重建

未匹配的标注

如果编辑了 .devcontainer 文件夹里的东西,你需要重建容器才能使编辑的内容生效。使用 Remote-Containers: Rebuild Container 命令可以帮你更新容器。

不过,问题是,如果重建容器的话,之前手动安装的东西就都要重新安装了。要避免这个问题,devcontainer.json 文件中的 postCreateCommand 属性可以来帮忙。

postCreateCommand 会在容器运行起来之后,紧跟着运行。所以你也可以用它来运行一些命令,比如在源代码的树形结构中运行 npm install 命令,或是执行一个 shell 脚本。

“postCreateCommand”: “bash scripts/install-dev-tools.sh”

你也可以使用交互式 bash shell ,因为它会读取 .bashrc 文件,并自动为你的环境做 shell 自定义。

“postCreateCommand”: “bash -i scripts/install-dev-tools.sh”

留意一下命令中的 -i ,我们先按下不表。来展示一下久违的程序员礼仪:

man bash

跳到 INVOCATION 部分。我们看到 shell 分为 login shell 和 interactive shell 。

bash –login

光看上面这个命令,–login 是旗标也叫选项。看起来没有带参数,但实际上 “bash” 就是参数,而且它就是参数 0 。

在 bash –login 命令启动的 shell 中,运行 echo $0 命令来查看参数0,会发现它就是 bash 。

那么让我们退出这个 bash shell ,回到最初的 shell 中,再执行 echo $0 看看会得到什么结果呢?

竟然是 -bash 。这个初始状态的 bash shell 是我通过 ssh 命令远程登录的默认 shell 。

从上方 man 页面描述可以看出,ssh 登录进来的 shell ,由于其参数0是 -bash ,首字母为 - ,所以可以判断它就是 login shell;而我们手动启动 bash shell 的时候,因为带了 –login 旗标,所以也是 login shell 。

另外,我在查询相关内容的时候,还看到一个很喜欢的源码层面的描述:

argv[0][0] == ‘-‘

这行代码的意思就是:参数列表的0元素的首字母为 “-“。发现有的时候,代码真的比话语要简洁很多。

那么再来看 interactive shell 即 交互式shell ,撇开看不懂的内容,发现带上 -i 选项的,就是交互式shell。所以上面 postCreateCommand 属性中 -i 的目的,纯粹就是为了启动一个交互式的 bash shell。那么为什么一定要强调启动交互式的 bash shell 呢?man page也给出了解释:

如果启动的是 非login shell 的 交互式shell ,bash 就会读取 /etc/bash.bashrc 和 ~/.bashrc 文件的命令,并执行这些命令。这样就可以通过修改 ~/.bashrc 文件,把你的自定义命令放在里面,并且通过 postCreateCommand 自动执行它们了。

一些工具,比如 NVM ,如果不使用 -i 旗标,启动交互模式的话,是无法正常工作的:

“postCreateCommand”: “bash -i -c ‘nvm install –lts’”

查询 bash 的文档可以获知:它的作用是用来读取并执行 -c 右边,第一个非选项参数即 command_string 的。那么我们这里的 command_string 显然是 ‘nvm install –lts’ 了。

至于 nvm 的命令,我们可以到 nvm 仓库的 README 找到相应的介绍。我们知道 Node 会定期发布长期支持版(LTS)。如果你想安装最新的长期支持版,就是可以像上述命令一样,带上 –lts 旗标,就可以安装长期支持版了。也就是说,上述命令会在容器重构后,安装 node 最新的 LTS 版本。

另外,所指定的命令需要执行完毕并退出,这样容器才能够启动。比如说,如果你在 postCreateCommand 中,指定了一个启动应用的命令,那么应用通常会持续保持运行而不会运行完毕并退出。这样的话,容器是无法启动的。

还有另一个属性 postStartCommand ,会在每次容器启动时执行。参数的行为和 postCreateCommand 完全一样,唯一的区别在于这个属性所指定的命令,会在每次启动容器时执行,而不是创建容器时执行。

其实,在 devcontainer.json 中直接引用镜像也好,通过 postCreateCommand 或 postStartCommand 属性安装软件也罢,都有更高效的方式,那就是使用 Dockerfile 来实现这些操作。

我们下一期就来聊一聊:创建开发容器的过程中,Dockerfile 所起到的作用。如果喜欢我的文章,欢迎长按点赞,评论区留言和私信也是多多益善哦。我们下一期,不见不散。

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
秦晓武
讨论数量: 0
发起讨论 只看当前版本


暂无话题~