我已经准备好对Visual Studio Code的Remote-Container扩展进行第一次实验,以及一个更令人愉快的基于容器的Rails开发环境。正如本系列的第一部分所提到的,我不会在一篇文章中建立一个功能齐全的环境,而是慢慢地逐步建立一个。
当我完成这个特定的实验时,我希望我的Rails应用能够在开发容器中启动,既可以通过Rails控制台,也可以作为一个服务器程序,并且可以通过主机上的浏览器访问。还有很长的路要走,但启动应用程序似乎是很好的、可证明的进展。
我们走吧!
创建一个devcontainer配置
尽管Remote-Container插件提供了使用应用程序中可能存在的现有Docker配置的选项,但我还是抵制了使用它的诱惑,而是从新开始。在这个实验中,我想尽可能地依靠VS Code的功能,至少在最初,所以让我们用它为devcontainer提供的基本配置文件运行。通过命令调色板,选择添加开发容器配置文件,并从众多可用选项中选择Ruby on Rails。(看起来这个插件很聪明,如果它在工作目录中发现了常见的Ruby文件,就会自动为你缩小选择范围)。然后,选择你的项目使用的Ruby版本。在写这篇文章时,我没有看到对Ruby 3的支持,但由于我正在使用较老的应用程序,这对我来说还不是一个问题。
这产生了一个新的目录,.devcontainer,里面有两个文件。首先是一个简单的Docker文件:
# [Choice] Ruby version: 2, 2.7, 2.6, 2.5
ARG VARIANT=2
FROM mcr.microsoft.com/vscode/devcontainers/ruby:0-${VARIANT}
# Install Rails
RUN gem install rails webdrivers
ARG NODE_VERSION="lts/*"
RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"
# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# && apt-get -y install --no-install-recommends
# [Optional] Uncomment this line to install additional gems.
# RUN gem install
# [Optional] Uncomment this line to install global node packages.
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g " 2>&1
还有一个devcontainer.json文件,它将帮助VS Code与新容器集成:
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.158.0/containers/ruby-rails
{
"name": "Ruby on Rails",
"build": {
"dockerfile": "Dockerfile",
"args": {
// Update 'VARIANT' to pick a Ruby version: 2, 2.7, 2.6, 2.5
"VARIANT": "2.6",
"NODE_VERSION": "lts/*"
}
},
// Set *default* container specific settings.json values on container create.
"settings": {
"terminal.integrated.shell.linux": "/bin/bash"
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"rebornix.Ruby"
],
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "ruby --version",
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "vscode"
}
在这个实验的其余部分,至少在近期,我想看看我们能在这些默认的基础上走多远。
一小部分清理工作
由于这个实验的目标是一个现有的应用程序,让我们首先从Dockerfile中删除明确添加Rails和Webdrivers的默认设置。我们将根据应用的Gemfile的内容来安装这些东西,就像在老式开发环境中一样。我们不要担心Node的东西和注释过的东西;那是另一个时间。
除了devcontainer.js中默认的 "Ruby on Rails "之外,我还喜欢将devcontainer重命名为其他名称,也许可以将其命名为与应用程序的名称相匹配,或者与它的资源库名称相匹配。VS Code 会在它的用户界面上显示这个名字,在窗口的左下角,所以要把它命名为有用的名字,不要太冗长。文件中的其他内容现在可以保持不变:
{
"name": "Yet Another To-do List App",
// rest of file ...
}
让我们来看看我们已经走到了哪一步!回到命令调色板中,选择 "在容器中重新打开"来建立容器。这可能需要一些时间,但一旦完成,我们就有希望在VS Code终端窗格中看到一个新提示。根据你的项目名称和它的 Git 仓库的状态,它看起来会类似于这样:
vscode ➜ /workspaces/my_project (main) $
输入ls ,确认容器可以访问应用程序的文件。多亏了Remote-Container,我们不用输入docker-compose run 这个和docker-compose run 那个就可以做到这一点。我还在决定我对此的感觉,但现在看来,它相当整洁。我喜欢不用打那么多字,如果没有其他原因的话。让我们再继续运行一段时间,并安装一些宝石。
开始设置
你知道吗,多年来,Rails的安装都包括一个基本的引导脚本?不过,在我接手的很多传统项目中,自从项目第一次提交到版本控制后,它往往从未被触及。实际上,有一两个项目已经被删除了。这实在是太糟糕了,因为那些继续使Rails成为一个东西的聪明人把它放在那里是有原因的:它可以帮助开发人员更快进入项目工作状态我喜欢让Docker做Docker最擅长的事情,而让Ruby做Ruby最擅长的事情的想法。也许我们可以利用这个脚本来获得更好的开发体验。
默认情况下,bin/setup会安装宝石,准备数据库,并在开发环境中做一些小的内务工作。现在,让我们只担心安装宝石的部分:
#!/usr/bin/env ruby
require 'fileutils'
include FileUtils
# path to your application root.
APP_ROOT = File.expand_path('..', __dir__)
def system!(*args)
system(*args) || abort("\n== Command #{args} failed ==")
end
chdir APP_ROOT do
# This script is a starting point to setup your application.
# Add necessary setup steps to this file.
puts '== Installing dependencies =='
system! 'gem install bundler --conservative'
system('bundle check') || system!('bundle install')
# Comment out the rest of the script for now ...
# ...
end
运行railsbin/setup 脚本,将 gem 的依赖关系安装到容器中。快速浏览一下rails -v 应该会发现,你的项目的Gemfile中所显示的 Rails 版本现在应该已经安装完毕了!我认为我们可以做得更好。
不过,我认为我们可以做得更好。devcontainer.json有一个配置选项:postCreateCommand 。如果它被设置为在容器创建时自动运行bin/setup ,会发生什么?太有争议了吗?让我们来了解一下。对devcontainer.json进行修改,然后再次重建容器:
"postCreateCommand": "bin/setup",
现在,根据应用程序的Gemfile,运行rails -v 和gem list 应该可以提供合理的输出,而不需要先手动运行bin/setup 。
但这东西能启动吗?
在控制台中测试
到目前为止,我们所得到的应该足以让bin/rails console 在容器中启动。我说应该是因为,特别是对于一个应用程序,我不得不用一些环境配置建立一个原始的*.env*文件。这是该应用现有开发环境的产物,这与我在Rails中看到的任何其他情况都不一样。无论如何,让bin/rails console 去吧。应用程序启动了吗?棒极了!如果没有,你的应用程序可能有自己的不典型性。通过让控制台启动来解决这个问题,往往比直接进入浏览器要简单得多。
在浏览器中测试
在结束这个实验之前,让我们再测试一件事--我们能在实际的浏览器中看到我们基于容器的应用程序吗?如果你在Docker方面做了很多工作,你可能熟悉从主机到容器的端口转发的概念。我们需要这样做--Remote-Container不会自动设置它,但它会引导我们在哪里做一个小的配置改变。
我想在devcontainer.json中设置这个,至少现在是这样。我知道传统智慧建议在Dockerfile(或docker-compose.yml)中这样做,但事实上Remote-Container建议在devcontainer.json中设置它,这很耐人寻味。所以,请原谅我,我们以后可能会改变它:
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [3000],
再一次重建devcontainer。一旦启动,在VS Code终端窗格中用bin/rails server ,启动应用程序。然后在你最喜欢的浏览器中点击http://localhost:3000,它可能就会工作了。如果该应用程序的根页面依赖于数据库或其他一些我们尚未设置的服务,你可能会看到一个错误。但相信我,这就是进步。
开始编写文档
如果未来的开发者不知道你的项目存在,那么建立一个坡道来缓解他们的工作有什么用呢?在这个过程中,我一直在花额外的时间在每个应用程序的文档(通常是它的README)中添加一个注释,以提示他们去检查它。我指出它是实验性的,并邀请他们合作以帮助改进它。
接下来的步骤
让我们反思一下。有了三个生成的文件和一些调整,这个应用程序正在容器中构建并启动,我们可以看到它在控制台和浏览器中运行。我们已经了解到,VS Code的Remote-Container扩展抽象出了很多Docker的模板设置,但不是全部。我们也许可以利用Rails的bin/setup,以类似Ruby的方式来完成这项工作。
目前,我认为我们正处于一个良好的停顿点。离开电脑,如果可以的话,出去走走,思考一下我们所取得的成就和学到的东西。下一篇文章见,我们将尝试从容器中连接到数据库。