Defined Type: service::docker

Defined in:
modules/service/manifests/docker.pp

Overview

Define service::docker

Allows pulling a docker image from our registry, and running it.

This is basically a shim to be able to run via puppet the containers we created for use with the new service pipeline in mind.

Parameters

image_name

Name of the Docker image. Default: $title

version

The docker image tag

namespace

The namespace of the image on the registry, if any

The fully qualified image name (FQIN) of the image
will be docker-registry.wikimedia.org/${namespace}/${image_name}
or docker-registry.wikimedia.org/${image_name} if the namespace
is undefined.
port

the IP port the service runs on, and that will be exposed

on. For now, the container port and the host port must be the same
and cannot be specified separately.
override_cmd

The command to run if different from what defined

in the images's CMD stanza.
environment

k-v hash of env variables to pass to the container

volume

Boolean. default false.

Whether a volume should be reserved for the configuration file. This is here
just to bypass a 64KB limitation of horizon, so don't use it for other
reasons. If set to true, then instead of bind mounting /etc/${title} from
the host, a named docker volume $title will be mounted. The entire lifecycle
management of that docker volume is left up to the user of the volume. So
precreate it and prepopulate it please
bind_mounts

Hash of strings. Defaults to empty.

The /etc dir (or variant see above) will always be mounted into
the container. $bind_mounts can be used to specify additional
mounts as src/dst pairs. For example:

{"/var/lib/puppet" => "/opt/puppetstuff",
 "/usr/lib/puppet" => "/opt/otherpuppetstuff"}

All paths must be absolute and all parent directories pre-existing
in the container.
host_network

Boolean. default false.

Bind the container to the host's network rather than the default bridge
nework. From a networking point of view, this provides the same level of
iolation as if the container's main process was running directly on the
host. Note: $port is ignored when running in host network mode. Ports
opened within the container will be opened directly on the host without
a NAT translation being involved.
runtime

String. default undef. If set, specifies the container runtime.

Parameters:

  • port (Stdlib::Port::User)
  • version (String)
  • ensure (Wmflib::Ensure) (defaults to: present)
  • namespace (Optional[String]) (defaults to: undef)
  • config (Hash) (defaults to: {})
  • override_cmd (String) (defaults to: '')
  • environment (Hash) (defaults to: {})
  • image_name (String) (defaults to: $title)
  • volume (Boolean) (defaults to: false)
  • bind_mounts (Hash[Stdlib::Unixpath, Stdlib::Unixpath]) (defaults to: {})
  • host_network (Boolean) (defaults to: false)
  • runtime (Optional[String]) (defaults to: undef)


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
# File 'modules/service/manifests/docker.pp', line 61

define service::docker(
    Stdlib::Port::User $port,
    String $version,
    Wmflib::Ensure $ensure = present,
    Optional[String] $namespace = undef,
    Hash $config = {},
    String $override_cmd = '',
    Hash $environment = {},
    String $image_name = $title,
    Boolean $volume = false,
    Hash[Stdlib::Unixpath, Stdlib::Unixpath] $bind_mounts = {},
    Boolean $host_network = false,
    Optional[String] $runtime = undef,
) {
    # Our docker registry is *not* configurable here.
    $registry = 'docker-registry.wikimedia.org'
    $image_full_name = $namespace ? {
        undef => "${registry}/${image_name}",
        default => "${registry}/${namespace}/${image_name}"
    }

    $fqin = "${image_full_name}:${version}"

    # The config file will be mounted as a read-only volume inside the container
    ensure_resource('file', "/etc/${title}", {
        ensure => stdlib::ensure($ensure, 'directory'),
        owner  => 'root',
        group  => 'root',
        mode   => '0755',
        force  => true,
    })

    if $volume == false {
        file { "/etc/${title}/config.yaml":
            ensure  => $ensure,
            content => to_yaml($config),
            owner   => 'root',
            group   => 'root',
            mode    => '0444',
            notify  => Service[$title],
        }
    }

    file { "/etc/${title}/env":
        ensure    => $ensure,
        content   => ($environment.map |$k, $v| { "${k}=${v}" } + ['']).join("\n"),
        owner     => 'root',
        group     => 'root',
        mode      => '0440',
        notify    => Service[$title],
        show_diff => false,
    }

    # Make sure the image has been pulled before starting the service
    # docker pull does not support a --dry-run. Therefore the actual pull is
    # done via the `unless` command.
    exec { "docker pull of ${fqin} for ${title}":
        command => '/usr/bin/true',
        unless  => "/usr/bin/docker pull '${fqin}' | grep -q 'up to date'",
        notify  => Service[$title],
    }

    systemd::service { $title:
        ensure  => $ensure,
        content => template('service/docker-service-shim.erb'),
        restart => true,
    }
}