OSDN Git Service

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