OSDN Git Service

a08c36ec93c51b7a360fd67f22ff20b97a0d7f85
[metasearch/grid-chef-repo.git] / cookbooks / docker-grid / recipes / engine.rb
1 #
2 # Cookbook Name:: docker-grid
3 # Recipe:: engine
4 #
5 # Copyright 2016-2018, whitestar
6 #
7 # Licensed under the Apache License, Version 2.0 (the "License");
8 # you may not use this file except in compliance with the License.
9 # You may obtain a copy of the License at
10 #
11 #     http://www.apache.org/licenses/LICENSE-2.0
12 #
13 # Unless required by applicable law or agreed to in writing, software
14 # distributed under the License is distributed on an "AS IS" BASIS,
15 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 # See the License for the specific language governing permissions and
17 # limitations under the License.
18 #
19
20 # https://dcos.io/docs/1.8/administration/installing/custom/system-requirements/
21
22 platform = node['platform']
23 platform_family = node['platform_family']
24 platform_version = node['platform_version']
25
26 install_flavor = node['docker-grid']['install_flavor']
27 override_apt_line = node['docker-grid']['apt_repo']['override_apt_line']
28 if !override_apt_line.nil? && !override_apt_line.empty? \
29   && override_apt_line.include?(node['docker-grid']['dockerproject']['apt_new_repo_url'])
30   Chef::Log.warn('This docker-grid::engine recipe uses the Docker new repository by the `override_apt_line` attribute.')
31   node.force_override['docker-grid']['dockerproject']['enable_new_repo'] = true
32 end
33 enable_new_repo = node['docker-grid']['dockerproject']['enable_new_repo']
34
35 engine_conf = node['docker-grid']['engine']
36 docker_ver = engine_conf['version']
37 docker_ver = '' if docker_ver.nil? || docker_ver == 'latest'
38 storage_driver = engine_conf['storage-driver']
39 userns_remap = engine_conf['userns-remap']
40
41 if engine_conf['skip_setup']
42   log 'Skip the Docker Engine setup.'
43   return
44 end
45
46 ::Chef::Recipe.send(:include, PlatformUtils::Helper)
47 ::Chef::Recipe.send(:include, PlatformUtils::VirtUtils)
48
49 [
50   'bridge-utils',
51 ].each {|pkg|
52   resources(package: pkg) rescue package pkg do
53     action :install
54   end
55 }
56
57 systemctl_daemon_reload = 'systemctl_daemon-reload'
58 resources(bash: systemctl_daemon_reload) rescue bash systemctl_daemon_reload do
59   code <<-EOH
60     systemctl daemon-reload
61   EOH
62   action :nothing
63 end
64
65 # https://docs.docker.com/engine/userguide/storagedriver/selectadriver/
66 if shell_out("cat /etc/mtab | grep -E '\s+/\s+zfs\s+'").exitstatus.zero?
67   if container_guest_node?
68     Chef::Log.warn('This node is running in the Linux container with ZFS, set the storage-driver to vfs as a fallback.')
69     node.override['docker-grid']['engine']['storage-driver'] = 'vfs'
70   else
71     Chef::Log.warn('This node is running on ZFS, set the storage-driver to zfs.')
72     node.override['docker-grid']['engine']['storage-driver'] = 'zfs'
73   end
74 end
75
76 if storage_driver == 'overlay2'
77   if !docker_ver.empty? && Gem::Version.create(docker_ver.tr('~', '-')) < Gem::Version.create('1.12')
78     # tr('~', '-') for Ubuntu.
79     Chef::Application.fatal!('Docker version must be 1.12 or later for overlay2 storage driver.')  # and exit.
80   end
81 end
82 load_kernel_module('overlay') if storage_driver =~ /overlay2?/
83
84 if !userns_remap.nil? && !userns_remap.empty?
85   if !docker_ver.empty? && Gem::Version.create(docker_ver.tr('~', '-')) < Gem::Version.create('1.10')
86     # tr('~', '-') for Ubuntu.
87     Chef::Application.fatal!('Docker version must be 1.10 or later for userns-remap.')  # and exit.
88   end
89
90   include_recipe 'platform_utils::kernel_user_namespace'
91
92   remap_user = userns_remap == 'default' ? 'dockremap' : userns_remap
93   notifies_conf = {
94     'action' => :restart,
95     'resource' => 'service[docker]',
96     'timer' => :delayed,
97   }
98   ::Chef::Recipe.send(:include, PlatformUtils::Helper)
99   append_subusers([remap_user], notifies_conf)
100 end
101
102 file '/etc/systemd/system/docker.service.d/override.conf' do
103   action :nothing
104 end
105
106 bash 'clean_up_docker0_bridge' do
107   code <<-"EOH"
108     if brctl show | grep docker0; then
109       ip link set docker0 down
110       brctl delbr docker0
111     fi
112     # https://github.com/docker/docker/issues/23630
113     if [ -d /var/lib/docker/network ]; then
114       rm -rf /var/lib/docker/network
115     fi
116   EOH
117   action :nothing
118 end
119
120 case platform_family
121 when 'rhel'
122   ex_enablerepo = node['docker-grid']['dockerproject']['yum_new_repo_extra_enablerepo']
123
124   if storage_driver == 'devicemapper'
125     [
126       #'yum-utils',
127       'device-mapper-persistent-data',
128       'lvm2',
129     ].each {|pkg|
130       resources(package: pkg) rescue package pkg do
131         action :install
132       end
133     }
134   end
135
136   if install_flavor == 'dockerproject'
137     # https://dcos.io/docs/1.8/administration/installing/custom/system-requirements/install-docker-centos/
138     old_repo_action = nil
139     new_repo_action = nil
140     pkgs = nil
141     if enable_new_repo
142       old_repo_action = :delete
143       new_repo_action = :create
144       pkgs = [
145         'docker-ce',
146       ]
147     else
148       old_repo_action = :create
149       new_repo_action = :delete
150       pkgs = [
151         'docker-engine-selinux',
152         'docker-engine',
153       ]
154     end
155
156     [
157       'docker.repo',
158       'docker-ce.repo',
159     ].each {|repo_file|
160       template "/etc/yum.repos.d/#{repo_file}" do
161         source  "etc/yum.repos.d/#{repo_file}"
162         owner 'root'
163         group 'root'
164         mode '0644'
165         action repo_file == 'docker.repo' ? old_repo_action : new_repo_action
166       end
167     }
168
169     [
170       'docker',
171       'docker-common',
172       #'container-selinux',
173       'docker-selinux',
174     ].each {|pkg|
175       resources(package: pkg) rescue package pkg do
176         action platform_family == 'debian' ? :purge : :remove
177         notifies :delete, 'file[/etc/systemd/system/docker.service.d/override.conf]', :immediately
178         notifies :run, 'bash[clean_up_docker0_bridge]', :immediately
179       end
180     }
181
182     # each repo of the new 'docker-ce-stable' and the old 'dockerrepo' is disabled by default to prevent automatic update.
183     enablerepos = enable_new_repo ? ['docker-ce-stable'] : ['dockerrepo']
184     enablerepos.push(ex_enablerepo) if enable_new_repo && !ex_enablerepo.nil? && !ex_enablerepo.empty?
185     pkgs.each {|pkg|
186       resources(yum_package: pkg) rescue yum_package pkg do
187         allow_downgrade true
188         action :install
189         version docker_ver unless docker_ver.empty?
190         options "--enablerepo=#{enablerepos.join(',')}"
191         notifies :run, 'bash[clean_up_docker0_bridge]', :before if pkg == 'docker-engine' || pkg == 'docker-ce'
192       end
193     }
194   else
195     # OS distribution
196     [
197       'docker-engine-selinux',
198       'docker-engine',
199     ].each {|pkg|
200       resources(package: pkg) rescue package pkg do
201         action platform_family == 'debian' ? :purge : :remove
202         notifies :delete, 'file[/etc/systemd/system/docker.service.d/override.conf]', :immediately
203         notifies :run, 'bash[clean_up_docker0_bridge]', :immediately
204       end
205     }
206
207     [
208       'docker',
209     ].each {|pkg|
210       resources(yum_package: pkg) rescue yum_package pkg do
211         allow_downgrade true
212         action :install
213         version docker_ver unless docker_ver.empty?
214         notifies :run, 'bash[clean_up_docker0_bridge]', :before
215       end
216     }
217
218     template '/etc/sysconfig/docker' do
219       source  'etc/sysconfig/docker'
220       owner 'root'
221       group 'root'
222       mode '0644'
223       notifies :restart, 'service[docker]'
224     end
225   end
226 when 'debian'
227   # https://docs.docker.com/engine/installation/linux/debian/
228   # https://docs.docker.com/engine/installation/linux/ubuntulinux/
229   pkgs = [
230     'apt-transport-https',
231     'ca-certificates',
232     'curl',
233     'gnupg2',
234     'software-properties-common',
235   ]
236
237   if storage_driver == 'aufs' \
238     && !container_guest_node?
239     if platform == 'debian'
240       pkgs += [
241         'aufs-dkms',
242       ]
243     elsif platform == 'ubuntu'
244       pkgs += [
245         "linux-image-extra-#{node['os_version']}",
246         'linux-image-extra-virtual',
247       ]
248     end
249   end
250
251   pkgs.each {|pkg|
252     resources(package: pkg) rescue package pkg do
253       action :install
254     end
255   }
256
257   apt_get_update = 'apt-get_update'
258   resources(execute: apt_get_update) rescue execute apt_get_update do
259     command 'apt-get update'
260     action :nothing
261   end
262
263   if install_flavor == 'dockerproject'
264     pkg_name_removed = 'docker.io'
265     pkg_name = node['docker-grid']['dockerproject']['package_name']
266
267     apt_repo_config = node['docker-grid']['apt_repo']
268     apt_key_add_cmd = nil
269     apt_key_name = nil
270     if enable_new_repo
271       apt_key_add_cmd = "curl -fsSL https://download.docker.com/linux/#{platform}/gpg | apt-key add -"
272       apt_key_name = 'Docker Release (CE deb)'
273     else
274       apt_key_add_cmd = "apt-key adv --keyserver #{apt_repo_config['keyserver']} --recv-keys #{apt_repo_config['recv-keys']}"
275       apt_key_name = 'Docker Release Tool (releasedocker)'
276     end
277     bash 'apt-key_adv_docker_tools_key' do
278       code <<-"EOH"
279         #{apt_key_add_cmd}
280       EOH
281       action :nothing
282       not_if "apt-key list 2>&1 | grep '#{apt_key_name}'"
283     end
284
285     template '/etc/apt/sources.list.d/docker.list' do
286       source  'etc/apt/sources.list.d/docker.list'
287       owner 'root'
288       group 'root'
289       mode '0644'
290       notifies :run, 'bash[apt-key_adv_docker_tools_key]', :before
291       notifies :run, "execute[#{apt_get_update}]", :immediately
292     end
293   else
294     # OS distribution
295     pkg_name_removed = node['docker-grid']['dockerproject']['package_name']
296     pkg_name = 'docker.io'
297   end
298
299   # Pinning Docker version
300   template '/etc/apt/preferences.d/docker.pref' do
301     source  'etc/apt/preferences.d/docker.pref'
302     owner 'root'
303     group 'root'
304     mode '0644'
305     action :delete if docker_ver.empty?
306     variables(
307       pkg_name: pkg_name
308     )
309   end
310
311   resources(package: pkg_name_removed) rescue package pkg_name_removed do
312     action platform_family == 'debian' ? :purge : :remove
313     notifies :delete, 'file[/etc/systemd/system/docker.service.d/override.conf]', :immediately
314     notifies :run, 'bash[clean_up_docker0_bridge]', :immediately
315   end
316
317   resources(package: pkg_name) rescue package pkg_name do
318     action :install
319     options "-o Dpkg::Options::='--force-confnew'" if platform_family == 'debian'
320     options '--allow-downgrades' if platform == 'debian' || platform_version >= '16.04'  # LTS (xenial)
321     options '--force-yes' if platform_version == '14.04'  # LTS (trusty)
322     version docker_ver unless docker_ver.empty?
323     notifies :run, 'bash[clean_up_docker0_bridge]', :before
324     notifies :run, 'bash[apt-key_adv_docker_tools_key]', :before
325     notifies :run, "execute[#{apt_get_update}]", :before
326   end
327 end
328
329 docker_opts = []
330 docker_opts.push("--storage-driver=#{storage_driver}") if !storage_driver.nil? && !storage_driver.empty?
331 docker_opts.push("--userns-remap=#{userns_remap}") if !userns_remap.nil? && !userns_remap.empty?
332
333 extra_options = engine_conf['daemon_extra_options']
334 # for docker-engine package on RHEL: remove '-H fd://'
335 # https://github.com/docker/docker/issues/22847
336 if platform_family == 'rhel' || platform == 'debian' || (platform == 'ubuntu' && platform_version == '14.04')
337   # Note: docker_ver.empty? -> the latest version
338   if docker_ver.empty? \
339     || Gem::Version.create(docker_ver.tr('~', '-')) >= Gem::Version.create('1.12')
340     extra_options = extra_options.gsub(%r{-H\sfd://}, '')  # for frozen string.
341   end
342 end
343
344 docker_opts.push(extra_options) if !extra_options.nil? && !extra_options.empty?
345
346 init_package = node['init_package']
347 if init_package == 'systemd'
348   directory '/etc/systemd/system/docker.service.d' do
349     owner 'root'
350     group 'root'
351     mode '0755'
352     action :create
353   end
354
355   template '/etc/systemd/system/docker.service.d/override.conf' do
356     source  'etc/systemd/system/docker.service.d/override.conf'
357     owner 'root'
358     group 'root'
359     mode '0644'
360     variables(
361       docker_opts: docker_opts
362     )
363     not_if { install_flavor == 'os-repository' && platform_family == 'rhel' }
364     notifies :run, "bash[#{systemctl_daemon_reload}]", :immediately
365     notifies :restart, 'service[docker]'
366   end
367 elsif init_package == 'init'  # for Ubuntu 14.04,...
368   template '/etc/default/docker' do
369     source  'etc/default/docker'
370     owner 'root'
371     group 'root'
372     mode '0644'
373     variables(
374       docker_opts: docker_opts
375     )
376     notifies :restart, 'service[docker]'
377   end
378 end
379
380 service 'docker' do
381   provider Chef::Provider::Service::Upstart if platform == 'ubuntu' && platform_version < '15.04'
382   action [:start, :enable]
383   subscribes :restart, 'execute[update-ca-certificates]', :delayed
384 end
385
386 users = engine_conf['users_allow']
387 group 'docker' do
388   members users unless users.empty?
389   action :create
390   append true
391 end
392
393 # utility scripts
394 [
395   'docker_containers_cleanup',
396   'docker_images_cleanup',
397   'docker_volumes_cleanup',
398 ].each {|script|
399   template "/usr/local/bin/#{script}" do
400     source  "usr/local/bin/#{script}"
401     owner 'root'
402     group 'root'
403     mode '0755'
404     action :create
405   end
406 }
407
408 # autopilot
409 srv = 'dockerd'
410 template "/etc/cron.d/#{srv}-local" do
411   source  "etc/cron.d/#{srv}-local"
412   owner 'root'
413   group 'root'
414   mode '0644'
415   action :delete unless engine_conf['autopilot']['enabled']
416 end