Systemd units for docker containers

Make every docker container a standard systemd unit, allowing
it to be managed by standard way with systemctl.

Also add systemd support to dockercrl.

Blueprint: master-on-centos7

Breaks: nothing

Change-Id: I924534b43d083f93130d2af805609a81b302d7de
This commit is contained in:
Ivan Suzdal 2015-11-23 18:40:20 +03:00
parent 032c707ec8
commit a18e970e1d
10 changed files with 259 additions and 34 deletions

View File

@ -5,6 +5,7 @@ class docker::dockerctl (
$profile_dir = '/etc/profile.d', $profile_dir = '/etc/profile.d',
$admin_ipaddress = $::fuel_settings['ADMIN_NETWORK']['ipaddress'], $admin_ipaddress = $::fuel_settings['ADMIN_NETWORK']['ipaddress'],
$docker_engine = 'native', $docker_engine = 'native',
$use_systemd = false,
$release, $release,
$production, $production,
) { ) {

View File

@ -0,0 +1,53 @@
# == Class: docker::systemd
#
# Systemd units generator for docker containers
#
# === Parameters
#
# [*release*]
# (required) String. Determine MOS release.
# This release will use for correct docker container names,
# e.g. if release == '8.0' and container name is 'astute' -
# the full container name will be fuel-core-8.0-astute
#
# [*stop_timeout*]
# (required) Integer. Number of seconds to wait for the container
# to stop before killing it.
#
# [*containers*]
# (required) Array. This is an array of container names which should be start
# as systemd units.
#
# [*depends*]
# (optional) Hash. This is a hash of container dependencies.
# Key is a container name, value is a container name
# which should be started before.
#
class docker::systemd (
$release = undef,
$stop_timeout = 30,
$containers = ['astute', 'cobbler', 'keystone', 'mcollective', 'nailgun',
'nginx', 'ostf', 'postgres', 'rabbitmq', 'rsync', 'rsyslog'],
$depends = {
'astute' => 'rsync',
'cobbler' => 'nginx',
'keystone' => 'rabbitmq',
'mcollective' => 'cobbler',
'nailgun' => 'rsyslog',
'nginx' => 'ostf',
'ostf' => 'nailgun',
'rsync' => 'keystone',
'rsyslog' => 'astute',
'rabbitmq' => 'postgres'
},
) {
# No empty release allowed
validate_string($release)
docker::systemd::config {$containers:
release => $release,
depends => $depends,
timeout => $stop_timeout}
}

View File

@ -0,0 +1,35 @@
#
# docker::systemd::config resource deploys systemd units for fuel-related
# docker containers and enable to running a containers as a standard
# system service. This resource doesn't changes any state of a container.
# Variables:
#
# release - will use for correct docker container names
# e.g. if release == '8.0' and container name is 'astute' -
# the full container name will be fuel-core-8.0-astute
#
# depends - this is a hash which describes dependencies of containers
# Key is a container name which apply setting, value is a container name
# which should be started before.
#
# timeout - Number of seconds to wait for the container to stop before killing it.
#
define docker::systemd::config( $release, $depends, $timeout ) {
file { "/usr/lib/systemd/system/docker-${title}.service":
ensure => file,
content => template('docker/systemd/template.service.erb'),
owner => 'root',
group => 'root',
mode => '0644',
notify => Service["docker-${title}"]
}
# We use ensure => undef to prevent unnecessary start service
# because at first boot time, the container is launched by dockerctl
service { "docker-${title}":
enable => true,
ensure => undef,
}
}

View File

@ -16,6 +16,8 @@ if [ -z "$VERSION" ]; then
VERSION="_VERSION_" VERSION="_VERSION_"
fi fi
SYSTEMD="<%= @use_systemd.to_s %>"
IMAGE_PREFIX="fuel" IMAGE_PREFIX="fuel"
# busybox image for storage containers # busybox image for storage containers
BUSYBOX_IMAGE="busybox.tar.gz" BUSYBOX_IMAGE="busybox.tar.gz"

View File

@ -0,0 +1,16 @@
[Unit]
Name=<%= @title %> container
Requires=docker.service
After=docker.service <% if @depends[@title] -%>docker-<%= @depends[@title] -%>.service<% end %>
[Service]
Restart=on-failure
RestartSec=10
StartLimitBurst=5
StartLimitInterval=60
ExecStartPre=/usr/bin/dockerctl create <%= @title %>
ExecStart=/usr/bin/docker start -a fuel-core-<%= @release %>-<%= @title %>
ExecStop=/usr/bin/docker stop -t <%= @timeout %> fuel-core-<%= @release %>-<%= @title %>
[Install]
WantedBy=multi-user.target

View File

@ -18,13 +18,23 @@ $admin_network = ipcalc_network_wildcard(
$::fuel_settings['ADMIN_NETWORK']['netmask']) $::fuel_settings['ADMIN_NETWORK']['netmask'])
$extra_networks = $fuel_settings['EXTRA_ADMIN_NETWORKS'] $extra_networks = $fuel_settings['EXTRA_ADMIN_NETWORKS']
case $::osfamily {
'RedHat': {
if $::operatingsystemmajrelease >= '7' {
$use_systemd = true
} else {
$use_systemd = false
}
}
default: { $use_systemd = false }
}
Class['nailgun::packages'] -> Class['nailgun::packages'] ->
Class['nailgun::host'] -> Class['nailgun::host'] ->
Class['nailgun::client'] -> Class['nailgun::client'] ->
Class['docker::dockerctl'] -> Class['docker::dockerctl'] ->
Class['docker'] -> Class['docker'] ->
Class['openstack::logrotate'] -> Class['openstack::logrotate'] ->
Class['nailgun::supervisor'] ->
Class['monit'] -> Class['monit'] ->
Class['nailgun::bootstrap_cli'] Class['nailgun::bootstrap_cli']
@ -56,6 +66,7 @@ class { 'openstack::clocksync':
} }
class { 'docker::dockerctl': class { 'docker::dockerctl':
use_systemd => $use_systemd,
release => $::fuel_release, release => $::fuel_release,
production => $production, production => $production,
admin_ipaddress => $::fuel_settings['ADMIN_NETWORK']['ipaddress'], admin_ipaddress => $::fuel_settings['ADMIN_NETWORK']['ipaddress'],
@ -81,13 +92,6 @@ class { 'nailgun::client':
keystone_pass => $::fuel_settings['FUEL_ACCESS']['password'], keystone_pass => $::fuel_settings['FUEL_ACCESS']['password'],
} }
class { 'nailgun::supervisor':
nailgun_env => false,
ostf_env => false,
require => File['/etc/supervisord.d/current', "/etc/supervisord.d/${::fuel_release}"],
conf_file => 'nailgun/supervisord.conf.base.erb',
}
class { 'nailgun::bootstrap_cli': class { 'nailgun::bootstrap_cli':
settings => $::fuel_settings['BOOTSTRAP'], settings => $::fuel_settings['BOOTSTRAP'],
direct_repo_addresses => [ $::fuel_settings['ADMIN_NETWORK']['ipaddress'] ], direct_repo_addresses => [ $::fuel_settings['ADMIN_NETWORK']['ipaddress'] ],
@ -99,33 +103,47 @@ class { 'osnailyfacter::ssh':
password_auth => 'yes', password_auth => 'yes',
} }
if $use_systemd {
class { 'docker::systemd':
release => $::fuel_release,
}
Class['openstack::logrotate'] ->
Class['docker::systemd'] ->
Exec['sync_deployment_tasks']
} else {
class { 'nailgun::supervisor':
nailgun_env => false,
ostf_env => false,
require => File['/etc/supervisord.d/current', "/etc/supervisord.d/${::fuel_release}"],
conf_file => 'nailgun/supervisord.conf.base.erb',
}
file { '/etc/supervisord.d': file { '/etc/supervisord.d':
ensure => directory, ensure => directory,
} }
class { 'docker::supervisor': class { 'docker::supervisor':
release => $::fuel_release, release => $::fuel_release,
require => File["/etc/supervisord.d/${::fuel_release}"], require => File["/etc/supervisord.d/${::fuel_release}"],
} }
file { "/etc/supervisord.d/${::fuel_release}": file { "/etc/supervisord.d/${::fuel_release}":
ensure => directory, ensure => directory,
require => File['/etc/supervisord.d'], require => File['/etc/supervisord.d'],
owner => root, owner => 'root',
group => root, group => 'root',
} }
file { '/etc/supervisord.d/current': file { '/etc/supervisord.d/current':
ensure => link, ensure => link,
target => "/etc/supervisord.d/${::fuel_release}", target => "/etc/supervisord.d/${::fuel_release}",
require => File["/etc/supervisord.d/${::fuel_release}"], require => File["/etc/supervisord.d/${::fuel_release}"],
replace => true, replace => true,
} }
Class['openstack::logrotate'] ->
Class['docker::supervisor'] ->
Exec['sync_deployment_tasks']
}
exec {'sync_deployment_tasks': exec {'sync_deployment_tasks':
command => 'fuel rel --sync-deployment-tasks --dir /etc/puppet/', command => 'fuel rel --sync-deployment-tasks --dir /etc/puppet/',
path => '/usr/bin', path => '/usr/bin',
tries => 12, tries => 12,
try_sleep => 10, try_sleep => 10,
require => Class['nailgun::supervisor']
} }

View File

@ -68,6 +68,8 @@ case "$1" in
else else
check_ready $container check_ready $container
fi ;; fi ;;
create)
create_container $container;;
start) start)
if [[ "$container" == 'all' ]]; then if [[ "$container" == 'all' ]]; then
for service in $container_seq; do for service in $container_seq; do

View File

@ -17,6 +17,8 @@ if [ -z "$VERSION" ]; then
VERSION="_VERSION_" VERSION="_VERSION_"
fi fi
SYSTEMD="false"
IMAGE_PREFIX="fuel" IMAGE_PREFIX="fuel"
# busybox image for storage containers # busybox image for storage containers
BUSYBOX_IMAGE="busybox.tar.gz" BUSYBOX_IMAGE="busybox.tar.gz"

View File

@ -26,6 +26,7 @@ function show_usage {
echo "Available commands:" echo "Available commands:"
echo " help: show this message" echo " help: show this message"
echo " build: create all Docker containers" echo " build: create all Docker containers"
echo " create: create container without running (or starting) it"
echo " list: list container short names (-l for more output)" echo " list: list container short names (-l for more output)"
echo " start: start all Docker containers" echo " start: start all Docker containers"
echo " restart: restart one or more Docker containers" echo " restart: restart one or more Docker containers"
@ -57,7 +58,7 @@ function parse_options {
nonopts+=("$@") nonopts+=("$@")
return return
;; ;;
help|build|start|check|list|copy|restart|stop|revert|shell|upgrade|restore|backup|destroy|logs|post_start_hooks) help|build|create|start|check|list|copy|restart|stop|revert|shell|upgrade|restore|backup|destroy|logs|post_start_hooks)
nonopts+=("$@") nonopts+=("$@")
return return
;; ;;
@ -135,7 +136,12 @@ function check_ready {
echo "checking container $1" echo "checking container $1"
case $1 in case $1 in
nailgun) retry_checker "shell_container nailgun supervisorctl status nailgun | grep -q RUNNING" ;; nailgun) if [ "${SYSTEMD:-false}" == "true" ]; then
retry_checker "shell_container nailgun systemctl is-active nailgun"
else
retry_checker "shell_container nailgun supervisorctl status nailgun | grep -q RUNNING"
fi
;;
ostf) retry_checker "egrep -q ^[2-4][0-9]? < <(curl --connect-timeout 1 -s -w '%{http_code}' http://$ADMIN_IP:8777/ostf/not_found -o /dev/null)" ;; ostf) retry_checker "egrep -q ^[2-4][0-9]? < <(curl --connect-timeout 1 -s -w '%{http_code}' http://$ADMIN_IP:8777/ostf/not_found -o /dev/null)" ;;
#NOTICE: Cobbler console tool does not comply unix conversation: 'cobbler profile find' always return 0 as exit code #NOTICE: Cobbler console tool does not comply unix conversation: 'cobbler profile find' always return 0 as exit code
cobbler) retry_checker "shell_container cobbler ps waux | grep -q 'cobblerd -F' && pgrep dnsmasq" cobbler) retry_checker "shell_container cobbler ps waux | grep -q 'cobblerd -F' && pgrep dnsmasq"
@ -228,6 +234,30 @@ function commit_container {
image="$IMAGE_PREFIX/$1_$VERSION" image="$IMAGE_PREFIX/$1_$VERSION"
${DOCKER} commit $container_name $image ${DOCKER} commit $container_name $image
} }
function create_container() {
# wrapper for systemd unit
if [ -z "$1" ]; then
echo "Must specify a container name" 1>&2
exit 1
fi
if [ "$1" = "all" ]; then
for container in $CONTAINER_SEQUENCE; do
create_container $container
done
return
fi
opts="${CONTAINER_OPTIONS[$1]} ${CONTAINER_VOLUMES[$1]}"
container_name="${CONTAINER_NAMES[$1]}"
image="$IMAGE_PREFIX/$1_$VERSION"
if ! container_created $container_name; then
pre_setup_hooks $1
${DOCKER} create $opts --privileged --name=$container_name $image
post_setup_hooks $1
fi
return 0
}
function start_container { function start_container {
lock lock
if [ -z "$1" ]; then if [ -z "$1" ]; then

View File

@ -47,6 +47,72 @@ describe manifest do
}) })
end end
let(:params) { {
:containers => ['astute',
'cobbler',
'keystone',
'mcollective',
'nailgun',
'nginx',
'ostf',
'postgres',
'rabbitmq',
'rsync',
'rsyslog']
} }
context 'running on centos 6' do
let(:facts) do
Noop.centos_facts.merge({
:operatingsystemmajrelease => '6'
})
end end
it 'configure containers supervisor' do
release = facts[:fuel_release]
should contain_class('docker::supervisor').with({
:release => release,
:require => "File[/etc/supervisord.d/#{release}]",
})
params[:containers].each do |container|
should contain_file("/etc/supervisord.d/#{release}/#{container}.conf").with({
:owner => 'root',
:group => 'root',
:mode => '0644'
})
end
end #it do
end #context
context 'running on centos 7' do
let(:facts) do
Noop.centos_facts.merge({
:operatingsystemmajrelease => '7'
})
end
it 'configure containers systemd' do
release = facts[:fuel_release]
should contain_class('docker::systemd').with({
:release => release,
:containers => params[:containers]
})
params[:containers].each do |container|
should contain_file("/usr/lib/systemd/system/docker-#{container}.service").with({
:owner => 'root',
:group => 'root',
:mode => '0644',
})
should contain_service("docker-#{container}").with({
:ensure => nil, # we shouldn't start container from puppet
:enable => 'true',
})
end
end #it do
end #context
end #shared_examples
test_centos manifest test_centos manifest
end end