xfyuan
xfyuan A Chinese software engineer living and working in Chengdu. I love creating the future in digital worlds, big and small.

让Docker-Compose如虎添翼的DIP

让Docker-Compose如虎添翼的DIP

前一篇博客“骑鲸之路——Docker模式下的Rails开发环境构筑(翻译)”的文章末尾,作者提到了一个叫 Dip 的工具,引起了我的兴趣。作为 Evil Martions 的开源作品,品质应该是有保证的,值得一试。我经过几天的试用后,感觉很是“惊艳”,觉得完全把它看作 Docker 本地开发环境的两大杀手级生产力工具:Docker-Compose + Dip,称为“帝国双璧”亦不为过。这篇博客就来简单介绍下 Dip 的使用。

要说 Dip,得先说 Docker-Compose 这个 Docker 容器的编排工具。一般来说,一个项目都会由多个 Docker 容器组成(几乎不可能只有单个容器),比如“Rails + DB + Redis + ElasticSearch”这样。而 Docker-Compose 则通过设定一个称为docker-compose.yml的配置文件,提供了把多个容器“串联”起来的能力,让我们不用手工输入繁琐的 Docker 命令去一个个单独启动容器,这已经大幅度提高了我们使用 Docker 的方便性。下面是个docker-compose.yml的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
version: '2'

services:
  app:
    image: ruby:2.4-buster
    environment:
      - GEM_HOME=/bundle
      - BUNDLE_PATH=/bundle
      - HISTFILE=/app/tmp/.bash_history
    working_dir: /app
    volumes:
      - .:/app
      - bundle:/bundle

volumes:
  bundle:

但是,当使用 Docker-Compose 稍微长一点时间后,你可能就会发现依然存在一些让你难受的地方。

比如,当每次要使用它时,都得敲下面这样的命令:

1
docker-compose run --rm web bundle exec rails c

docker-compose这个命令本身就太长,不便于输入。当然,你可以给它设置一个 alias(例如我本地就设为dp)。然而后面那一长串又怎么办呢?想想每天的日常开发,可能这种类似的命令要输入好几十次,无论对手指还是心理,都是一种折磨-_-

再比如,使用了 Docker 容器作为开发环境,由于代码的运行、数据库的存储等就都是在容器中了,那么要运行测试或者查看数据库内表中数据时,就都得先使用如下命令进入容器:

1
docker-compose run --rm app bash

然后在容器内才能再运行所需要的命令:

1
8523c2:/# bundle exec rspec

把一件事非得分成好几步来操作,这当然显得过于繁琐累赘了,一点也不简洁高效。

Evil Martins 的开发者们也发现了这一点。而他们则是想办法来尝试解决这个问题。所以,Dip 就应运而生。

Dip 的安装很简单,有三种方式,任选其一即可:

  • Homebrew 安装:Homebrew install dip

  • Gem 安装:gem install dip

  • 直接下载已编译版本:

    1
    
    curl -L https://github.com/bibendi/dip/releases/download/v6.0.0/dip-`uname -s`-`uname -m` > /usr/local/bin/dip chmod +x /usr/local/bin/dip
    

安装好之后,就可以针对你项目下的docker-compose.yml,在同级目录下添加 Dip 的配置文件dip.yml

比如对于上面的docker-compose.yml例子,对应的dip.yml可以是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
version: '4'

compose:
  files:
    - docker-compose.yml

interaction:
  bash:
    description: Open the Bash shell in app's container
    service: app
    command: /bin/bash

  pry:
    description: Open Pry console
    service: app
    command: ./bin/console

  bundle:
    description: Run Bundler commands
    service: app
    command: bundle

  rspec:
    description: Run Rspec commands
    service: app
    command: bundle exec rspec

  rubocop:
    description: Run Rubocop commands
    service: app
    command: bundle exec rubocop

provision:
  - rm -rf Gemfile.lock
  - dip bundle install

dip.yml配置妥当后,就可以开始“愉快”地使用 Dip 了。

首先,你能随时使用dip ls,显示配置好的可用命令,而无需每次都去打开文件查找有哪些。显示效果类似这样:

1
2
3
4
5
bash     # Open the Bash shell in app's container
pry      # Open Pry console
bundle   # Run Bundler commands
rspec    # Run Rspec commands
rubocop  # Run Rubocop commands

而象上文提到的测试场景,有了 Dip,只需输入这个命令:

1
dip rspec

即可随时运行所有测试。

重要的是,Dip 会在运行命令时,首先自动找到docker-compose.yml中相应的 Service,自动启动其容器(这里是app,如果有依赖的容器也会自动启动),然后在容器内运行设定好的命令(bundle exec rspec)。在命令运行结束之后,Dip 还会贴心地自动关闭刚才启动的所有容器,减少系统资源的占用。

由此可以看到,Dip 针对上面提到的“痛点”,让我们不用登入容器就可以进行各种工作,也不用再担心容器的启动状态,把那些繁琐的操作步骤进行了完美的精简,貌似已经少到“减无可减”的地步了。

但作者认为这还不够,并不满足于此,所以他给 Dip 添加了一个更加“黑科技”的技能点。当你在自己的.bashrc.zshrc中只要再加上这一行:

1
eval "$(dip console)"

甚至就可以把上面那些命令中的dip都省掉!比如dip rspec直接敲rspec就可以了。这样在项目下,你可以随时直接运行这些命令:

1
2
3
4
bundle install
rails s
rake routes | grep admin
rspec spec/models/user_spec.rb:16

而只看这些命令,别人还会以为你完全就是在原生环境而非 Docker 环境下开发呢!让你使用时根本感觉不到是在 Docker 环境下,这算是真正的大道至简了。

除此之外,Dip 还提供了诸如dip sshdip nginxdip dns之类的高级功能,本文这里就暂不讨论了,读者可以参看它的官方文档自行尝试。

总而言之,就像本文标题所说的那样,Dip 让 Docker-Compose 更加如虎添翼,也让本地以 Docker 作为开发环境的体验更加高效流畅、丝般顺滑。作为我个人而言,已经把 Dip 作为必备工具加入自己的日常开发工具箱了。

comments powered by Disqus