Skip to content

Commit daa27a9

Browse files
author
scott coulton
committed
adding Docker services
1 parent 581361f commit daa27a9

File tree

7 files changed

+348
-3
lines changed

7 files changed

+348
-3
lines changed

README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,53 @@ docker::swarm {'cluster_worker':
499499
ensure => absent
500500
}
501501
```
502+
### Docker services
503+
Docker services allow to create distributed applications across multiple swarm nodes. A service is a set of containers that are replicated across your swarm.
504+
To configure a service with Puppet code please see the following examples
505+
506+
To create a service
507+
```puppet
508+
docker::services {'redis':
509+
create => true,
510+
service_name => 'redis',
511+
image => 'redis:latest',
512+
publish => '6379:639',
513+
replicas => '5',
514+
extra_params => ['--update-delay 1m', '--restart-window 30s']
515+
}
516+
```
517+
In this example we are creating a service called `redis`, as it is a new service we have set `create => true`. The `service_name` resource is the name which Docker knows the service as. The `image` resource is the image you want to base the service off, `publish` is the ports that want exposed to the outside world for the service to be consumed, `replicas` sets the amount of tasks (containers) that you want running in the service, `extra_params` allows you to configure any of the other flags that Docker gives you when you create a service for more info see `docker service create --help`
518+
519+
To update the service
520+
```puppet
521+
docker::services {'redis_update':
522+
create => false,
523+
update => true,
524+
service_name => 'redis',
525+
replicas => '3',
526+
}
527+
528+
In this example we have taken the service that we created earlier `redis` set the `create => false` and this time added `update => true`. We then decleared the service name `redis` we have then updated the servce to have only 3 replicas, not 5. The `extra_params` resource is also available in the update class.
529+
530+
To scale a service
531+
```puppet
532+
docker::services {'redis_scale':
533+
create => false,
534+
scale => true,
535+
service_name => 'redis',
536+
replicas => '10',
537+
}
538+
```
539+
In this example we have used the command `docker service scale` with Puppet code. We have taken our service `redis` set the `create => false` and `scale => true` When using scale you have to declare your `service_name` then the number of replicas that you want. In this example we are going to scale to `10`
540+
541+
To remove a service
542+
```puppet
543+
docker::services {'redis':
544+
ensure => 'absent',
545+
service_name => 'redis',
546+
}
547+
```
548+
To remove a a service from your swarm just set `ensure => absent` and the service_name of your service.
502549

503550
### Private registries
504551
By default images will be pushed and pulled from [index.docker.io](https://index.docker.io) unless you've specified a server. If you have your own private registry without authentication, you can fully qualify your image name. If your private registry requires authentication you may configure a registry:

Rakefile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ end
2222

2323
PuppetLint.configuration.relative = true
2424
PuppetLint.configuration.disable_80chars
25-
PuppetLint.configuration.log_format = "%{path}:%{linenumber}:%{check}:%{KIND}:%{message}"
2625
PuppetLint.configuration.fail_on_warnings = true
2726

2827
# Forsake support for Puppet 2.6.2 for the benefit of cleaner code.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
require 'shellwords'
2+
3+
module Puppet::Parser::Functions
4+
# Transforms a hash into a string of docker swarm init flags
5+
newfunction(:docker_service_flags, :type => :rvalue) do |args|
6+
opts = args[0] || {}
7+
flags = []
8+
9+
if opts['detach'].to_s != 'true'
10+
flags << '--detach'
11+
end
12+
13+
if opts['service_name'].to_s != 'undef'
14+
flags << "'#{opts['service_name']}'"
15+
end
16+
17+
if opts['env'].to_s != 'undef'
18+
flags << "--env '#{opts['env']}'"
19+
end
20+
21+
if opts['label'].to_s != 'undef'
22+
flags << "--label '#{opts['label']}'"
23+
end
24+
25+
if opts['publish'].to_s != 'undef'
26+
flags << "--publish '#{opts['publish']}'"
27+
end
28+
29+
if opts['replicas'].to_s != 'undef'
30+
flags << "--replicas '#{opts['replicas']}'"
31+
end
32+
33+
if opts['tty'].to_s != 'false'
34+
flags << '--tty'
35+
end
36+
37+
if opts['user'].to_s != 'undef'
38+
flags << "--user '#{opts['publish']}'"
39+
end
40+
41+
if opts['workdir'].to_s != 'undef'
42+
flags << "--workdir '#{opts['workdir']}'"
43+
end
44+
45+
if opts['extra_params'].each do |param|
46+
flags << param
47+
end
48+
end
49+
50+
if opts['image'].to_s != 'undef'
51+
flags << "'#{opts['image']}'"
52+
end
53+
54+
flags.flatten.join(" ")
55+
end
56+
end

lib/puppet/parser/functions/docker_swarm_init_flags.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ module Puppet::Parser::Functions
4545
if opts['snapshot_interval'].to_s != 'undef'
4646
flags << "--snapshot-interval '#{opts['snapshot_interval']}'"
4747
end
48-
48+
4949
flags.flatten.join(" ")
5050
end
5151
end

manifests/service.pp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@
148148
case $service_provider {
149149
'systemd': {
150150
file { '/etc/systemd/system/docker.service.d':
151-
ensure => directory
151+
ensure => directory,
152152
}
153153

154154
if $service_overrides_template {

manifests/services.pp

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
# == Define: docker::services
2+
#
3+
# A define that managers a Docker services
4+
#
5+
# == Paramaters
6+
#
7+
# [*ensure*]
8+
# This ensures that the service is present or not.
9+
# Defaults to present
10+
#
11+
# [*image*]
12+
# The Docker image to spwan the service from.
13+
# Defualts to undef
14+
#
15+
# [*detach*]
16+
# Exit immediately instead of waiting for the service to converge (default true)
17+
# Defaults to true
18+
#
19+
# [*env*]
20+
# Set environment variables
21+
# Defaults to undef
22+
#
23+
# [*label*]
24+
# Service labels.
25+
# This used as metdata to configure constraints etc.
26+
# Defaults to undef
27+
#
28+
# [*publish*]
29+
# Publish a port as a node port.
30+
# Defaults to undef
31+
#
32+
# [*replicas*]
33+
# Number of tasks (containers per service)
34+
# defaults to undef
35+
#
36+
# [*tty*]
37+
# Allocate a pseudo-TTY
38+
# Defaults to false
39+
#
40+
# [*user*]
41+
# Username or UID (format: <name|uid>[:<group|gid>])
42+
# Defaults to undef
43+
#
44+
# [*workdir*]
45+
# Working directory inside the container
46+
# Defaults to false
47+
#
48+
# [*extra_params*]
49+
# Allows you to pass any other flag that the Docker service create supports.
50+
# This must be passed as an array. See docker service create --help for all options
51+
# defaults to []
52+
#
53+
# [*update*]
54+
# This changes the docker command to
55+
# docker service update, you must pass a service name with this option
56+
#
57+
# [*scale*]
58+
# This changes the docker command to
59+
# docker service scale, this can only be used with service name and
60+
# replicas
61+
#
62+
63+
define docker::services(
64+
65+
$ensure = 'present',
66+
$image = undef,
67+
$detach = true,
68+
$env = undef,
69+
$service_name = undef,
70+
$label = undef,
71+
$publish = undef,
72+
$replicas = undef,
73+
$tty = false,
74+
$user = undef,
75+
$workdir = undef,
76+
$extra_params = [],
77+
$create = true,
78+
$update = false,
79+
$scale = false,
80+
){
81+
82+
include docker::params
83+
84+
$docker_command = "${docker::params::docker_command} service"
85+
validate_re($ensure, '^(present|absent)$')
86+
validate_string($docker_command)
87+
validate_string($image)
88+
validate_string($env)
89+
validate_string($service_name)
90+
validate_string($label)
91+
validate_string($publish)
92+
validate_string($replicas)
93+
validate_string($user)
94+
validate_string($workdir)
95+
validate_bool($detach)
96+
validate_bool($tty)
97+
validate_bool($create)
98+
validate_bool($update)
99+
validate_bool($scale)
100+
101+
if $ensure == 'absent' {
102+
if $update {
103+
fail('When removing a service you can not update it.')
104+
}
105+
if $scale {
106+
fail('When removing a service you can not update it.')
107+
}
108+
}
109+
110+
if $create {
111+
$docker_service_create_flags = docker_service_flags({
112+
detach => $detach,
113+
env => $env,
114+
service_name => $service_name,
115+
label => $label,
116+
publish => $publish,
117+
replicas => $replicas,
118+
tty => $tty,
119+
user => $user,
120+
workdir => $workdir,
121+
extra_params => any2array($extra_params),
122+
image => $image,
123+
})
124+
125+
$exec_create = "${docker_command} create --name ${docker_service_create_flags}"
126+
$unless_create = "docker service ls | grep -w ${service_name}"
127+
128+
exec { 'Docker service create':
129+
command => $exec_create,
130+
environment => 'HOME=/root',
131+
path => ['/bin', '/usr/bin'],
132+
timeout => 0,
133+
unless => $unless_create,
134+
}
135+
}
136+
137+
if $update {
138+
$docker_service_flags = docker_service_flags({
139+
detach => $detach,
140+
env => $env,
141+
service_name => $service_name,
142+
label => $label,
143+
publish => $publish,
144+
replicas => $replicas,
145+
tty => $tty,
146+
user => $user,
147+
workdir => $workdir,
148+
extra_params => any2array($extra_params),
149+
image => $image,
150+
})
151+
152+
$exec_update = "${docker_command} update ${docker_service_flags}"
153+
154+
exec { 'Docker service update':
155+
command => $exec_update,
156+
environment => 'HOME=/root',
157+
path => ['/bin', '/usr/bin'],
158+
timeout => 0,
159+
}
160+
}
161+
162+
if $scale {
163+
$docker_service_flags = docker_service_flags({
164+
service_name => $service_name,
165+
replicas => $replicas,
166+
extra_params => any2array($extra_params),
167+
})
168+
169+
$exec_scale = "${docker_command} scale ${docker_service_flags}"
170+
171+
exec { 'Docker service scale':
172+
command => $exec_scale,
173+
environment => 'HOME=/root',
174+
path => ['/bin', '/usr/bin'],
175+
timeout => 0,
176+
}
177+
}
178+
179+
if $ensure == 'absent' {
180+
exec { 'Remove service':
181+
command => "docker service rm ${service_name}",
182+
onlyif => "docker service ls | grep -w ${service_name}",
183+
path => ['/bin', '/usr/bin'],
184+
}
185+
}
186+
}

spec/defines/services_spec.rb

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
require 'spec_helper'
2+
3+
describe 'docker::services', :type => :define do
4+
let(:title) { 'create services' }
5+
let(:facts) { {
6+
:osfamily => 'Debian',
7+
:operatingsystem => 'Debian',
8+
:lsbdistid => 'Debian',
9+
:lsbdistcodename => 'jessie',
10+
:kernelrelease => '3.2.0-4-amd64',
11+
:operatingsystemmajrelease => '8',
12+
} }
13+
14+
context 'with ensure => present and service create' do
15+
let(:params) { {
16+
'create' => true,
17+
'service_name' => 'foo',
18+
'image' => 'foo:bar',
19+
'publish' => '80:80',
20+
'replicas' => '5',
21+
'extra_params' => ['--update-delay 1m', '--restart-window 30s']
22+
} }
23+
it { is_expected.to compile.with_all_deps }
24+
it { should contain_exec('Docker service create').with_command(/docker service create/) }
25+
end
26+
27+
context 'with ensure => present and service update' do
28+
let(:params) { {
29+
'create' => false,
30+
'update' => true,
31+
'service_name' => 'foo',
32+
'image' => 'bar:latest',
33+
} }
34+
it { is_expected.to compile.with_all_deps }
35+
it { should contain_exec('Docker service update').with_command(/docker service update/) }
36+
end
37+
38+
context 'with ensure => present and service scale' do
39+
let(:params) { {
40+
'create' => false,
41+
'scale' => true,
42+
'service_name' => 'bar',
43+
'replicas' => '5',
44+
} }
45+
it { is_expected.to compile.with_all_deps }
46+
it { should contain_exec('Docker service scale').with_command(/docker service scale/) }
47+
end
48+
49+
context 'with ensure => absent' do
50+
let(:params) { {
51+
'ensure' => 'absent',
52+
'service_name' => 'foo',
53+
} }
54+
it { is_expected.to compile.with_all_deps }
55+
it { should contain_exec('Remove service').with_command(/docker service rm/) }
56+
end
57+
end

0 commit comments

Comments
 (0)