OSDN Git Service

adds the Docker project new repository support.
[metasearch/grid-chef-repo.git] / cookbooks / docker-grid / recipes / engine.rb
index 88ee3ef..473180f 100644 (file)
@@ -2,7 +2,7 @@
 # Cookbook Name:: docker-grid
 # Recipe:: engine
 #
-# Copyright 2016, whitestar
+# Copyright 2016-2017, whitestar
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 
 # https://dcos.io/docs/1.8/administration/installing/custom/system-requirements/
 
+platform = node['platform']
+platform_family = node['platform_family']
+platform_version = node['platform_version']
+
+install_flavor = node['docker-grid']['install_flavor']
+override_apt_line = node['docker-grid']['apt_repo']['override_apt_line']
+if !override_apt_line.nil? && !override_apt_line.empty? \
+  && override_apt_line.include?(node['docker-grid']['dockerproject']['apt_new_repo_url'])
+  Chef::Log.warn('This docker-grid::engine recipe uses the Docker new repository by the `override_apt_line` attribute.')
+  node.force_override['docker-grid']['dockerproject']['enable_new_repo'] = true
+end
+enable_new_repo = node['docker-grid']['dockerproject']['enable_new_repo']
+docker_ver = node['docker-grid']['engine']['version']
+docker_ver = '' if docker_ver.nil?
+storage_driver = node['docker-grid']['engine']['storage-driver']
+userns_remap = node['docker-grid']['engine']['userns-remap']
+
+if node['docker-grid']['engine']['skip_setup']
+  log 'Skip the Docker Engine setup.'
+  return
+end
+
+::Chef::Recipe.send(:include, PlatformUtils::Helper)
+::Chef::Recipe.send(:include, PlatformUtils::VirtUtils)
+
+[
+  'bridge-utils',
+].each {|pkg|
+  resources(package: pkg) rescue package pkg do
+    action :install
+  end
+}
+
 bash 'systemctl_daemon-reload' do
   code <<-EOH
     systemctl daemon-reload
@@ -26,180 +59,232 @@ bash 'systemctl_daemon-reload' do
   action :nothing
 end
 
-if node['docker-grid']['engine']['storage-driver'] == 'overlay'
-  bash 'load_overlayfs_kernel_module' do
-    code <<-EOH
-      modprobe overlay
-    EOH
-    not_if 'lsmod | grep overlay'
-  end
-
-  template '/etc/modules-load.d/overlay.conf' do
-    source  'etc/modules-load.d/overlay.conf'
-    owner 'root'
-    group 'root'
-    mode '0644'
+# https://docs.docker.com/engine/userguide/storagedriver/selectadriver/
+if shell_out("cat /etc/mtab | grep -E '\s+/\s+zfs\s+'").exitstatus.zero?
+  if container_guest_node?
+    Chef::Log.warn('This node is running in the Linux container with ZFS, set the storage-driver to vfs as a fallback.')
+    node.override['docker-grid']['engine']['storage-driver'] = 'vfs'
+  else
+    Chef::Log.warn('This node is running on ZFS, set the storage-driver to zfs.')
+    node.override['docker-grid']['engine']['storage-driver'] = 'zfs'
   end
 end
 
-log 'reboot_message' do
-  message 'Please reboot this machine because of kernel boot option modified.'
-  level :warn
-  action :nothing
+if storage_driver == 'overlay2'
+  if !docker_ver.empty? && Gem::Version.create(docker_ver.tr('~', '-')) < Gem::Version.create('1.12')
+    # tr('~', '-') for Ubuntu.
+    Chef::Application.fatal!('Docker version must be 1.12 or later for overlay2 storage driver.')  # and exit.
+  end
 end
+load_kernel_module('overlay') if storage_driver =~ /overlay2?/
 
-userns_remap = node['docker-grid']['engine']['userns-remap']
 if !userns_remap.nil? && !userns_remap.empty?
-  unless Gem::Version.create(node['docker-grid']['engine']['version'].tr('~', '-')) >= Gem::Version.create('1.10')
+  if !docker_ver.empty? && Gem::Version.create(docker_ver.tr('~', '-')) < Gem::Version.create('1.10')
     # tr('~', '-') for Ubuntu.
     Chef::Application.fatal!('Docker version must be 1.10 or later for userns-remap.')  # and exit.
   end
-  # By default user namespace feature is inactive in RHEL family (>= 7.2).
-  if node['platform_family'] == 'rhel'
-    unless Gem::Version.create(node['platform_version']) >= Gem::Version.create('7.2')
-      Chef::Application.fatal!('Platform version must be 7.2 or later for kernel user namespace feature.')  # and exit.
-    end
 
-    bash 'enable_user_namespace_feature_of_kernerl' do
-      code <<-"EOH"
-        grubby --args='user_namespace.enable=1' --update-kernel=/boot/vmlinuz-#{node['kernel']['release']}
-      EOH
-      not_if "grubby --info=/boot/vmlinuz-#{node['kernel']['release']} | grep 'user_namespace.enable=1'"
-      notifies :write, 'log[reboot_message]'
-    end
-  end
-
-  subid_files = [
-    '/etc/subuid',
-    '/etc/subgid',
-  ]
+  include_recipe 'platform_utils::kernel_user_namespace'
 
-  subid_files.each {|subid_file|
-    file subid_file do
-      owner 'root'
-      group 'root'
-      mode '0644'
-      action :touch
-      not_if { File.exist?(subid_file) }
-    end
-  }
-
-  this_recipe = self
   remap_user = userns_remap == 'default' ? 'dockremap' : userns_remap
-  ruby_block 'adds_subid_entries' do
-    action :run
-    not_if "cat /etc/subuid | grep #{remap_user}"
-    not_if "cat /etc/subgid | grep #{remap_user}"
-    notifies :restart, 'service[docker]'
-    block do
-      subid_files.each {|subid_file|
-        max_start_id = 100_000
-        offset = 0
-        already_exist = false
-
-        begin
-          File.open(subid_file) {|file|
-            file.each_line {|line|
-              entry = line.split(':')
-              if entry[0] == remap_user
-                already_exist = true
-                break
-              end
-              if entry[1].to_i >= max_start_id
-                max_start_id = entry[1].to_i
-                offset = entry[2].to_i
-              end
-            }
-          }
-
-          if already_exist
-            this_recipe.log "#{remap_user} already exists in #{subid_file}"
-          else
-            File.open(subid_file, 'a') {|file|
-              entry_str = "#{remap_user}:#{max_start_id + offset}:65536"
-              this_recipe.log "#{remap_user} (#{entry_str}) is added in #{subid_file}"
-              file.puts entry_str
-            }
-          end
-        rescue IOError => e
-          puts e
-        end
-      }
-    end
-  end
-end
-
-directory '/etc/systemd/system/docker.service.d' do
-  owner 'root'
-  group 'root'
-  mode '0755'
-  action :create
+  notifies_conf = {
+    'action' => :restart,
+    'resource' => 'service[docker]',
+    'timer' => :delayed,
+  }
+  ::Chef::Recipe.send(:include, PlatformUtils::Helper)
+  append_subusers([remap_user], notifies_conf)
 end
 
-template '/etc/systemd/system/docker.service.d/override.conf' do
-  source  'etc/systemd/system/docker.service.d/override.conf'
-  owner 'root'
-  group 'root'
-  mode '0644'
-  notifies :run, 'bash[systemctl_daemon-reload]'
-  notifies :restart, 'service[docker]'
+bash 'clean_up_docker0_bridge' do
+  code <<-"EOH"
+    if brctl show | grep docker0; then
+      ip link set docker0 down
+      brctl delbr docker0
+    fi
+    # https://github.com/docker/docker/issues/23630
+    if [ -d /var/lib/docker/network ]; then
+      rm -rf /var/lib/docker/network
+    fi
+  EOH
+  action :nothing
 end
 
-case node['platform_family']
+case platform_family
 when 'rhel'
-  # https://dcos.io/docs/1.8/administration/installing/custom/system-requirements/install-docker-centos/
-  template '/etc/yum.repos.d/docker.repo' do
-    source  'etc/yum.repos.d/docker.repo'
-    owner 'root'
-    group 'root'
-    mode '0644'
+  if storage_driver == 'devicemapper'
+    [
+      #'yum-utils',
+      'device-mapper-persistent-data',
+      'lvm2',
+    ].each {|pkg|
+      resources(package: pkg) rescue package pkg do
+        action :install
+      end
+    }
   end
 
-  [
-    'docker-engine-selinux',
-    'docker-engine',
-  ].each {|pkg|
-    package pkg do
-      action :install
-      version node['docker-grid']['engine']['version']
-      # dockerrepo is disabled by default to prevent automatic update.
-      options '--enablerepo=dockerrepo'
+  if install_flavor == 'dockerproject'
+    # https://dcos.io/docs/1.8/administration/installing/custom/system-requirements/install-docker-centos/
+    old_repo_action = nil
+    new_repo_action = nil
+    pkgs = nil
+    if enable_new_repo
+      old_repo_action = :delete
+      new_repo_action = :create
+      pkgs = [
+        'docker-ce',
+      ]
+    else
+      old_repo_action = :create
+      new_repo_action = :delete
+      pkgs = [
+        'docker-engine-selinux',
+        'docker-engine',
+      ]
     end
-  }
+
+    [
+      'docker.repo',
+      'docker-ce.repo',
+    ].each {|repo_file|
+      template "/etc/yum.repos.d/#{repo_file}" do
+        source  "etc/yum.repos.d/#{repo_file}"
+        owner 'root'
+        group 'root'
+        mode '0644'
+        action repo_file == 'docker.repo' ? old_repo_action : new_repo_action
+      end
+    }
+
+    [
+      'docker',
+      'docker-common',
+      #'container-selinux',
+      'docker-selinux',
+    ].each {|pkg|
+      resources(package: pkg) rescue package pkg do
+        action platform_family == 'debian' ? :purge : :remove
+        notifies :run, 'bash[clean_up_docker0_bridge]', :immediately
+      end
+    }
+
+    pkgs.each {|pkg|
+      resources(yum_package: pkg) rescue yum_package pkg do
+        allow_downgrade true
+        action :install
+        version docker_ver unless docker_ver.empty?
+        # dockerrepo is disabled by default to prevent automatic update.
+        options '--enablerepo=dockerrepo' unless enable_new_repo
+        notifies :run, 'bash[clean_up_docker0_bridge]', :before if pkg == 'docker-engine' || pkg == 'docker-ce'
+      end
+    }
+  else
+    # OS distribution
+    [
+      'docker-engine-selinux',
+      'docker-engine',
+    ].each {|pkg|
+      resources(package: pkg) rescue package pkg do
+        action platform_family == 'debian' ? :purge : :remove
+        notifies :run, 'bash[clean_up_docker0_bridge]', :immediately
+      end
+    }
+
+    file '/etc/systemd/system/docker.service.d/override.conf' do
+      action :delete
+    end
+
+    [
+      'docker',
+    ].each {|pkg|
+      resources(yum_package: pkg) rescue yum_package pkg do
+        allow_downgrade true
+        action :install
+        version docker_ver unless docker_ver.empty?
+        notifies :run, 'bash[clean_up_docker0_bridge]', :before
+      end
+    }
+
+    template '/etc/sysconfig/docker' do
+      source  'etc/sysconfig/docker'
+      owner 'root'
+      group 'root'
+      mode '0644'
+      notifies :restart, 'service[docker]'
+    end
+  end
 when 'debian'
+  # https://docs.docker.com/engine/installation/linux/debian/
   # https://docs.docker.com/engine/installation/linux/ubuntulinux/
   pkgs = [
     'apt-transport-https',
     'ca-certificates',
+    'curl',
+    'gnupg2',
+    'software-properties-common',
   ]
 
-  if node['docker-grid']['engine']['storage-driver'] == 'aufs'
-    pkgs += [
-      "linux-image-extra-#{node['os_version']}",
-      'linux-image-extra-virtual',
-    ]
+  if storage_driver == 'aufs' \
+    && !container_guest_node?
+    if platform == 'debian'
+      pkgs += [
+        'aufs-dkms',
+      ]
+    elsif platform == 'ubuntu'
+      pkgs += [
+        "linux-image-extra-#{node['os_version']}",
+        'linux-image-extra-virtual',
+      ]
+    end
   end
 
   pkgs.each {|pkg|
-    package pkg do
+    resources(package: pkg) rescue package pkg do
       action :install
     end
   }
 
-  template '/etc/apt/sources.list.d/docker.list' do
-    source  'etc/apt/sources.list.d/docker.list'
-    owner 'root'
-    group 'root'
-    mode '0644'
+  apt_get_update = 'apt-get_update'
+  resources(execute: apt_get_update) rescue execute apt_get_update do
+    command 'apt-get update'
+    action :nothing
   end
 
-  apt_repo_config = node['docker-grid']['apt_repo']
-  bash 'apt-key_adv_docker_tools_key' do
-    code <<-"EOH"
-      apt-key adv --keyserver #{apt_repo_config['keyserver']} --recv-keys #{apt_repo_config['recv-keys']}
-      apt-get update
-    EOH
-    not_if 'apt-key list | grep -i docker'
+  if install_flavor == 'dockerproject'
+    pkg_name_removed = 'docker.io'
+    pkg_name = node['docker-grid']['dockerproject']['package_name']
+
+    apt_repo_config = node['docker-grid']['apt_repo']
+    apt_key_add_cmd = nil
+    apt_key_name = nil
+    if enable_new_repo
+      apt_key_add_cmd = "curl -fsSL https://download.docker.com/linux/#{platform}/gpg | apt-key add -"
+      apt_key_name = 'Docker Release (CE deb)'
+    else
+      apt_key_add_cmd = "apt-key adv --keyserver #{apt_repo_config['keyserver']} --recv-keys #{apt_repo_config['recv-keys']}"
+      apt_key_name = 'Docker Release Tool (releasedocker)'
+    end
+    bash 'apt-key_adv_docker_tools_key' do
+      code <<-"EOH"
+        #{apt_key_add_cmd}
+      EOH
+      action :nothing
+      not_if "apt-key list 2>&1 | grep '#{apt_key_name}'"
+    end
+
+    template '/etc/apt/sources.list.d/docker.list' do
+      source  'etc/apt/sources.list.d/docker.list'
+      owner 'root'
+      group 'root'
+      mode '0644'
+      notifies :run, 'bash[apt-key_adv_docker_tools_key]', :before
+      notifies :run, "execute[#{apt_get_update}]", :immediately
+    end
+  else
+    # OS distribution
+    pkg_name_removed = node['docker-grid']['dockerproject']['package_name']
+    pkg_name = 'docker.io'
   end
 
   # Pinning Docker version
@@ -208,18 +293,104 @@ when 'debian'
     owner 'root'
     group 'root'
     mode '0644'
+    action :delete if docker_ver.empty?
+    variables(
+      pkg_name: pkg_name
+    )
   end
 
-  [
-    'docker-engine',
-  ].each {|pkg|
-    package pkg do
-      action :install
-      version node['docker-grid']['engine']['version']
-    end
-  }
+  resources(package: pkg_name_removed) rescue package pkg_name_removed do
+    action platform_family == 'debian' ? :purge : :remove
+    notifies :run, 'bash[clean_up_docker0_bridge]', :immediately
+  end
+
+  resources(package: pkg_name) rescue package pkg_name do
+    action :install
+    options "-o Dpkg::Options::='--force-confnew'" if platform_family == 'debian'
+    options '--allow-downgrades' if platform == 'debian' || platform_version >= '16.04'  # LTS (xenial)
+    options '--force-yes' if platform_version == '14.04'  # LTS (trusty)
+    version docker_ver unless docker_ver.empty?
+    notifies :run, 'bash[clean_up_docker0_bridge]', :before
+    notifies :run, 'bash[apt-key_adv_docker_tools_key]', :before
+    notifies :run, "execute[#{apt_get_update}]", :before
+  end
+end
+
+docker_opts = []
+docker_opts.push("--storage-driver=#{storage_driver}") if !storage_driver.nil? && !storage_driver.empty?
+docker_opts.push("--userns-remap=#{userns_remap}") if !userns_remap.nil? && !userns_remap.empty?
+
+extra_options = node['docker-grid']['engine']['daemon_extra_options']
+# for docker-engine package on RHEL: remove '-H fd://'
+# https://github.com/docker/docker/issues/22847
+if platform_family == 'rhel' || platform == 'debian' || (platform == 'ubuntu' && platform_version == '14.04')
+  # Note: docker_ver.empty? -> the latest version
+  if docker_ver.empty? \
+    || Gem::Version.create(docker_ver.tr('~', '-')) >= Gem::Version.create('1.12')
+    extra_options = extra_options.gsub(%r{-H\sfd://}, '')  # for frozen string.
+  end
+end
+
+docker_opts.push(extra_options) if !extra_options.nil? && !extra_options.empty?
+
+init_package = node['init_package']
+if init_package == 'systemd'
+  directory '/etc/systemd/system/docker.service.d' do
+    owner 'root'
+    group 'root'
+    mode '0755'
+    action :create
+  end
+
+  template '/etc/systemd/system/docker.service.d/override.conf' do
+    source  'etc/systemd/system/docker.service.d/override.conf'
+    owner 'root'
+    group 'root'
+    mode '0644'
+    variables(
+      docker_opts: docker_opts
+    )
+    not_if { install_flavor == 'os-repository' && platform_family == 'rhel' }
+    notifies :run, 'bash[systemctl_daemon-reload]', :immediately
+    notifies :restart, 'service[docker]'
+  end
+elsif init_package == 'init'  # for Ubuntu 14.04,...
+  template '/etc/default/docker' do
+    source  'etc/default/docker'
+    owner 'root'
+    group 'root'
+    mode '0644'
+    variables(
+      docker_opts: docker_opts
+    )
+    notifies :restart, 'service[docker]'
+  end
 end
 
 service 'docker' do
+  provider Chef::Provider::Service::Upstart if platform == 'ubuntu' && platform_version < '15.04'
   action [:start, :enable]
+  subscribes :restart, 'execute[update-ca-certificates]', :delayed
 end
+
+users = node['docker-grid']['engine']['users_allow']
+group 'docker' do
+  members users unless users.empty?
+  action :create
+  append true
+end
+
+# utility scripts
+[
+  'docker_containers_cleanup',
+  'docker_images_cleanup',
+  'docker_volumes_cleanup',
+].each {|script|
+  template "/usr/local/bin/#{script}" do
+    source  "usr/local/bin/#{script}"
+    owner 'root'
+    group 'root'
+    mode '0755'
+    action :create
+  end
+}