cover

Rails on Docker:Docker 入门

💡 Rails on Docker 系列文章是面向 Rails 程序员的 Docker 教程,描述了如何从开发环境到部署环境中应用 Docker。这是系列文章的第一篇。

什么是 Docker

Docker 是一种容器格式。容器是一种虚拟化技术,可以给应用提供一个相互隔离的运行环境。容器有点像虚拟机,但是比虚拟机更轻量,启动时间和占用空间都比虚拟机要小。

截屏2021-07-05 19.12.25.png 图片来源:https://www.docker.com/resources/what-container

相比于虚拟机,容器更好扩容,并且配置方式更标准化。目前云服务商大多提供了容器化部署方式或托管容器集群的服务。

Docker 用于开发环境也能提供不少好处,例如隔离不同应用的系统需求,让开发环境与线上环境等价。在开发时熟悉 Docker 的操作方式,可以减少部署到容器平台时的摩擦。

安装 Docker

Docker 提供了多种操作系统的安装包,可以在 https://www.docker.com/products/docker-desktop 找到适合自己操作系统的安装方式。

安装完毕后,在命令行中执行 docker 命令:

$ docker --version
Docker version 20.10.6, build 370c289

启动一个容器

现在我们来启动一个容器,在命令行输入以下命令:

$ docker run -it ruby:3.0 bash

这个命令会基于 ruby:3.0 镜像启动一个容器,在容器内打开 bash shell。-it 参数表示需要一个可交互的命令行,不然容器在打开 bash shell 之后因为没有输入就会关闭进程。

首次使用 ruby:3.0 镜像需要一些时间下载,启动完成后会看到以下命令提示:

root@970472afca4a:/#

现在终端就已经进入了容器内的 shell,类似于用 ssh 连接到另一台 Linux 主机。容器内的文件、系统应用都是跟宿主机隔离的,我们可以在容器内部安装应用和修改文件而不影响宿主机。

要注意的是目前因为没有设置持久化的方式,在关闭容器后所有更改都会消失。

输入 exit 或者按 ctrl-d 可以退出容器,容器会在发现没有输入后会关闭:

root@970472afca4a:/# exit
exit

挂载 Volume

上面提到,容器跟宿主机环境是隔离的,如果需要在宿主机和容器间共享文件怎么办呢?这时可以通过 Volume 解决。

用以下命令启动一个容器:

$ docker run -it -v $(pwd):/app -w /app ruby:3.0 bash

这里新增了两个参数,我们逐个理解。

  • -v $(pwd):/app 把宿主机当前目录(通过 pwd 命令获取)挂载到容器内的 /app 目录。
  • -w /app 把工作目录设到 /app,这样一启动容器初始路径就在 /app 里。

启动后查看 /app 目录,会显示宿主机当前目录的文件:

root@970472afca4a:/# ls
# ...host files

要注意现在这个目录里的修改都会同步到宿主机上。

小技巧

我经常启动一次性容器做测试,于是在 ~/.bash_profile 内设置了以下函数:

sandbox() {
  docker run -it -v $(pwd):/app -w /app $1 bash
}

这样我只要输入 sandbox ruby:3.0 就能打开一个已挂载 volume 的临时容器。

用 Dockerfile 定制镜像

前面我们都使用了 ruby:3.0 镜像,这个镜像内只有基础的 Ruby 运行环境,如果需要个别工具,我们在容器内另外安装:

root@2ad3490c73d1:/app# gem install nokogiri
Fetching nokogiri-1.11.7-x86_64-linux.gem
Successfully installed nokogiri-1.11.7-x86_64-linux
1 gem installed

但在退出容器后,容器内的修改都会消失,下次启动的时候又是一个干净的环境。有没有办法保存这些修改呢?其中一个办法是用 docker commit 把运行中的容器保存成镜像,但实际中很少用这个命令,因为有更好的选择——Dockerfile。

Dockerfile 可用于构建 Docker 镜像,现在直接看一个例子。新建一个命名为 Dockerfile 的文件,内容为:

FROM ruby:3.0

RUN gem install nokogiri

WORKDIR /app

然后在同目录下运行命令:

docker build . -t myimage

Docker 就会开始构建镜像,构建完成后,用以下命令查看镜像列表:

$ docker images
REPOSITORY  TAG     IMAGE ID      CREATED        SIZE
myimage     latest  f248af249511  5 seconds ago  863MB

可以看到,本地镜像中已经多了一个 myimage 镜像。

接着用这个镜像启动一个容器:

$ docker run -it myimage bash
root@879af3165a43:/app# nokogiri -v
# Nokogiri (1.11.7)
# ...

可以看到镜像内已经按照构建配置安装了 nokogiri。

Dockerfile 的命令很多,这里只解释几个常用的:

  • FROM 指定构建的基础镜像。
  • RUN 构建过程执行命令。
  • COPY 从构建目录复制文件到镜像内。
  • WORKDIR 指定工作目录。
  • ENV 设置环境变量。
  • CMD 设置默认的启动命令。

完整的命令列表可以查看 Dockerfile reference,另外关于镜像的优化也需要查看 Best practices for writing Dockerfiles。这里不重复叙述。

总结

这一节介绍了 Docker 是什么,如何用 Docker 启动一次性容器,以及如何用 Dockerfile 构建自己的镜像。

下一节我们将了解如何用 Docker 搭建 Rails 开发环境

9
8