Dockerによる開発環境作成にはBargeの利用がオススメ
2017/09/22
IT docker

はじめに

最近、開発用の環境として私はDockerを多用している。

開発マシンはmacだがDocker for Macではなく、仮想マシン(VirtualBox)上でDockerを起動させている。

最初の頃はDocker for Macを利用していたが、コンテナの管理のしやすさから仮想マシンを介して利用することに変化した。

仮想マシンは、ある程度の単位で分割して複数作成している。

これにより管理のしやすさを向上している。

例えば実験的に何かのプロジェクトを始めるときには新たな仮想マシンを作成して、そこにDocker環境を構築する。プロジェクトが終了すれば、何も考えずに該当の仮想マシンを削除するだけで良い。

これであれば既存のプロジェクトで使用している重要なコンテナやボリューム(永続化されたデータなど)を削除する危険性をかなり低減できる。

Dockerホスト用OS: Barge

DockerホストにCentOSを利用すると、DockerホストOSの起動や終了に時間が結構かかってしまう。常時起動しておくのはリソースの無駄だし。

このような用途のために、軽量なDockerホスト用のOSがある。

私がよく使用しているのがBargeというOSだ。

下記の記事が参考になる(恐らくBargeの作者の方が記載していると思われる)。

Bargeは起動や終了などかなり高速に動作するので満足している。容量が小さいのも良い。

新しいDockerホストを作成するスクリプト

後述するスクリプトを作って、Vagrantを利用して新しいDockerホストを簡単に生成できるようにしている。

実行したディレクトリに以下の構成でファイルが生成される。

1
2
3
.
├── Vagrantfile
└── export

Vagrantfile は80→10080, 3306→13306のポートがデフォルトで設定されているが、スクリプトのオプションで変更可能にしている。

スクリプトのオプションの詳細は、 --help を付与して実行すれば表示される。

例えばポート番号を変更したい場合は、 -p 80:20080,3306:23306みたいにすればOK。

export ディレクトリに置いてあるファイルがVagrantの /home/bargee/common にマウントされる。この辺りもオプションで修正可能。

export ディレクトリに docker-compose.yml を置いてある状態であれば、このスクリプトを実行してローカルマシンで

1
2
vagrant up
vagrant ssh

を実行してvagrant内で、

1
2
cd common
docker-compose up

を実行すれば、Dokcerが起動できるようになる。

そしてこの環境が不要になれば vagrant destroy でVM毎削除できるので管理が簡単で便利。

スクリプト

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#! /usr/bin/env ruby

# require {{{
require 'pp'
require 'pry'

require 'optparse'
require 'fileutils'
# }}}
# Options {{{
class Options
  def initialize(argv)
    @is_help = false
    @options = self.class.default_options.merge(get_argument_options(argv))
  end

  public

  class << self
    def get_usages
      results = []
      results << "Usage: #{$0} [options]"
      all_options.each do |key, value|
        results << "  -#{key} VAL : #{value}(default: #{default_options[key]})"
      end
      results
    end

    def all_options
      {
        d: 'docker version',
        c: 'docker composer version',
        e: 'host path',
        v: 'guest path(vagrant)',
        g: 'guest path(docker)',
        p: 'Port forward settings(GUEST_PORT1:HOST_PORT1,GUEST_PORT2:HOST_PORT2,...)',
      }
    end

    def default_options
      {
        d: "v18.03.0-ce",  # DOCKER_VERSION
        c: "1.20.0",    # DOCKER_COMPOSER_VERSION
        e: "./export", # HOST_COMMON_PATH
        v: "/home/bargee/common", # VAGRANT_COMMON_PATH
        g: "/app",     # DOCKER_COMMON_PATH
        p: "80:10080,3306:13306", # PORT_FORWARDS
      }
    end
  end

  def is_help?
    @is_help
  end

  def docker_version
    @options[:d]
  end

  def docker_composer_version
    @options[:c]
  end

  def host_common_path
    @options[:e]
  end

  def vagrant_common_path
    @options[:v]
  end

  def docker_common_path
    @options[:g]
  end

  def port_forwardings
    @options[:p].split(',').map{|x| x.split(':')}
  end

  private

  def getopts_parameters
    results = []
    results << 'h' + self.class.all_options.keys.map{|x| x.to_s.concat(':')}.join
    results << 'help'
    results
  end

  def get_argument_options(argv)
    params = argv.getopts(*getopts_parameters)
    @is_help = true if params['h'] || params['help']
    results = {}
    self.class.all_options.keys.each do |key|
      value = params[key.to_s]
      next if value.nil?
      results[key] = value
    end
    results
  end
end
# }}}
# FileMaker {{{
class FileMaker
  def initialize(filename, options = nil)
    @filename = filename
    @options = options
  end

  def execute
    open(@filename, 'w') do |fw|
      fw.printf('%s', contents)
    end
  end

  private

  def contents
  end
end
# }}}
# VagrantFileMaker {{{
class VagrantFileMaker < FileMaker
  private

  def make_setting_for_port_forward
    results = []
    @options.port_forwardings.each do |port_forwarding|
      guest_port = port_forwarding[0]
      host_port = port_forwarding[1]
      results << "  config.vm.network \"forwarded_port\", guest: #{guest_port}, host: #{host_port}"
    end
    results.join("\n")
  end

  def contents
    results = <<"EOS"
Vagrant.configure("2") do |config|
  config.vm.box = "ailispaw/barge"

#{make_setting_for_port_forward}

  config.vm.synced_folder "#{@options.host_common_path}", "#{@options.vagrant_common_path}", mount_options: ['dmode=777', 'fmode=777']

  latest_docker_install_script = <<SCRIPT
    docker version
    /etc/init.d/docker restart #{@options.docker_version}

    wget -L https://github.com/docker/compose/releases/download/#{@options.docker_composer_version}/docker-compose-\`uname -s\`-\`uname -m\`
    mv docker-compose-\`uname -s\`-\`uname -m\` /opt/bin/docker-compose
    chmod +x /opt/bin/docker-compose
    chown root:root /opt/bin/docker-compose
SCRIPT

  ssh_setting_modify_script = <<SCRIPT
    sed -ie 's/#PermitUserEnvironment no/PermitUserEnvironment yes/' /etc/ssh/sshd_config
    sudo -i -u bargee echo 'PATH=/bin:/sbin:/usr/bin:/usr/sbin' > /home/bargee/.ssh/environment
    /etc/init.d/S50sshd restart
SCRIPT

  utility_install_script = <<SCRIPT
    pkg install vim
SCRIPT

  config.vm.provision :shell, :inline => latest_docker_install_script
  config.vm.provision :shell, :inline => ssh_setting_modify_script
  config.vm.provision :shell, :inline => utility_install_script
end
EOS
  end
end
# }}}
# Main {{{
VAGRANT_FILE = 'Vagrantfile'

if File.exist?(VAGRANT_FILE)
  $stderr.printf("#{VAGRANT_FILE} is Exist!\nSkipping.\n")
  exit 1
end

options = Options.new(ARGV)
if (options.is_help?)
  $stderr.printf(Options.get_usages.map{|x| x.concat("\n")}.join)
  exit 1
end

sources = {
  VagrantFileMaker: [VAGRANT_FILE, options]
}

system("mkdir -p #{options.host_common_path}")

sources.each do |key, source|
  object = Object.const_get(key.to_s).new(source[0], source[1])
  object.execute
end

# Get box
system('vagrant box add ailispaw/barge')
system('vagrant init -m ailispaw/barge')

$stderr.printf("\n")
$stderr.printf("Please confirm Vagrantfile : forwarded_port and other settings\n")
$stderr.printf("After that, you run 'vagrant up'\n")
# }}}
# vim: set ts=2 sw=2 ro fdm=marker:

生成されるVagrantfileのサンプル

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
Vagrant.configure("2") do |config|
  config.vm.box = "ailispaw/barge"

  config.vm.network "forwarded_port", guest: 80, host: 10080
  config.vm.network "forwarded_port", guest: 3306, host: 13306

  config.vm.synced_folder "./export", "/home/bargee/common", mount_options: ['dmode=777', 'fmode=777']

  latest_docker_install_script = <<SCRIPT
    docker version
    /etc/init.d/docker restart v1.13.1

    wget -L https://github.com/docker/compose/releases/download/1.14.0/docker-compose-`uname -s`-`uname -m`
    mv docker-compose-`uname -s`-`uname -m` /opt/bin/docker-compose
    chmod +x /opt/bin/docker-compose
    chown root:root /opt/bin/docker-compose
SCRIPT

  ssh_setting_modify_script = <<SCRIPT
    sed -ie 's/#PermitUserEnvironment no/PermitUserEnvironment yes/' /etc/ssh/sshd_config
    sudo -i -u bargee echo 'PATH=/opt/bin:/bin:/sbin:/usr/bin:/usr/sbin' > /home/bargee/.ssh/environment
    /etc/init.d/S50sshd restart
SCRIPT

  utility_install_script = <<SCRIPT
    pkg install vim
SCRIPT

  config.vm.provision :shell, :inline => latest_docker_install_script
  config.vm.provision :shell, :inline => ssh_setting_modify_script
  config.vm.provision :shell, :inline => utility_install_script
end