Skip to content

Commit db5cbcc

Browse files
committed
Chef Server 12 - first cut
1 parent 2bc1722 commit db5cbcc

File tree

6 files changed

+302
-49
lines changed

6 files changed

+302
-49
lines changed

Dockerfile

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,28 @@
11
# -*- conf -*-
22

33
FROM ubuntu:12.04
4-
#TAG 11.1.1
4+
#TAG 12.0.0-rc.3
55
MAINTAINER Maciej Pasternacki <[email protected]>
66

7-
ENV PATH /opt/chef-server/embedded/sbin:/opt/chef-server/embedded/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
87
EXPOSE 80 443
9-
VOLUME /var/opt/chef-server
8+
VOLUME /var/opt/opscode
109

11-
ADD https://opscode-omnibus-packages.s3.amazonaws.com/ubuntu/12.04/x86_64/chef-server_11.1.1-1_amd64.deb /chef-server.deb
12-
RUN dpkg -i /chef-server.deb && rm -v /chef-server.deb
10+
ADD https://packagecloud.io/chef/stable/download?distro=precise&filename=chef-server-core_12.0.0-rc.3-1_amd64.deb /chef-server-core.deb
11+
12+
RUN set -e -x ; \
13+
export DEBIAN_FRONTEND=noninteractive ; \
14+
apt-get update -q --yes ; \
15+
apt-get install -q --yes logrotate vim-nox ; \
16+
dpkg -i /chef-server-core.deb ; \
17+
rm -rf /chef-server-core.deb /var/lib/apt/lists/* /var/cache/apt/archives/* ; \
18+
mkdir -p /etc/cron.hourly ; \
19+
ln -sfv /var/opt/opscode/log /var/log/opscode ; \
20+
ln -sfv /var/opt/opscode/etc /etc/opscode ; \
21+
ln -sfv /opt/opscode/sv/logrotate /opt/opscode/service ; \
22+
ln -sfv /opt/opscode/embedded/bin/sv /opt/opscode/init/logrotate
1323

1424
ADD init.rb /init.rb
15-
ADD chef-server.rb /etc/chef-server/chef-server.rb
25+
ADD chef-server.rb /.chef/chef-server.rb
26+
ADD logrotate /opt/opscode/sv/logrotate
1627

17-
CMD [ "/opt/chef-server/embedded/bin/ruby", "/init.rb" ]
28+
CMD [ "/opt/opscode/embedded/bin/ruby", "/init.rb" ]

README.md

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
Chef Server
2+
===========
3+
4+
This image runs
5+
[Chef Server core](https://downloads.getchef.com/chef-server/). The
6+
latest version is published as `3ofcoins/chef-server`. Git repository
7+
containing the Dockerfile lives at
8+
https://github.com/3ofcoins/docker-images/tree/master/public/chef-server
9+
10+
Environment Variables
11+
---------------------
12+
13+
- `PUBLIC_URL` - should be configured to a full public URL of the
14+
endpoint (e.g. `https://chef.example.com`)
15+
- `OC_AD_ADMINISTRATORS` - if set, it should be a comma-separated
16+
list of users that will be allowed to add oc_id applications
17+
18+
Ports
19+
-----
20+
21+
Ports 80 (HTTP) and 443 (HTTPS) are exposed.
22+
23+
Volumes
24+
-------
25+
26+
`/var/opt/opscode` directory, that holds all Chef server data, is a
27+
volume. Directories `/var/log/opscode` and `/etc/opscode` are linked
28+
there as, respectively, `log` and `etc`.
29+
30+
If there is a file `etc/chef-server-local.rb` in this volume, it will
31+
be read at the end of `chef-server.rb` and it can be used to customize
32+
Chef Server's settings.
33+
34+
Signals
35+
-------
36+
37+
- `docker kill -s HUP $CONTAINER_ID` will run `chef-server-ctl reconfigure`
38+
- `docker kill -s USR1 $CONTAINER_ID` will run `chef-server-ctl status`
39+
40+
Usage
41+
-----
42+
43+
### Prerequisites and first start
44+
45+
The `kernel.shmmax` and `kernel.shmall` sysctl values should be set to
46+
a high value on the host. You may also run Chef server as a privileged
47+
container to let it autoconfigure -- but the setting will propagate to
48+
host anyway, and it would be the only reason for making the container
49+
privileged, so it is better to avoid it.
50+
51+
First start will automatically run `chef-server-ctl
52+
reconfigure`. Subsequent starts will not run `reconfigure`, unless
53+
file `/var/opt/opscode/bootstrapped` has been deleted. You can run
54+
`reconfigure` (e.g. after editing `etc/chef-server.rb`) using
55+
`docker-enter` or by sending SIGHUP to the container: `docker kill
56+
-HUP $CONTAINER_ID`.
57+
58+
### Maintenance commands
59+
60+
Chef Server's design makes it impossible to wrap it cleanly in
61+
a container - it will always be necessary to run custom
62+
commands. While some of the management commands may work with linked
63+
containers with varying amount of ugly hacks, it is simpler to have
64+
one way of interacting with the software that is closest to
65+
interacting with a Chef Server installed directly on host (and thus
66+
closest to supported usage).
67+
68+
You will need `nsenter` utility and
69+
[`docker-enter`](https://github.com/jpetazzo/nsenter) script by
70+
[Jérôme Petazzoni](https://github.com/jpetazzo) on your Docker
71+
host. The easiest way to install it is to run the installer Docker
72+
image:
73+
74+
docker run --rm -v /usr/local/bin:/target jpetazzo/nsenter
75+
76+
Then, you can use the `docker-enter` script to run `chef-server-ctl`
77+
commands (note that the command is `ctl`, not `chef-server-ctl`; `ctl`
78+
is a wrapper that sets missing environment variables, lack of which
79+
would confuse `chef-server-ctl`):
80+
81+
docker-enter $CONTAINER_ID chef-server-ctl status
82+
docker-enter $CONTAINER_ID chef-server-ctl user-add …
83+
docker-enter $CONTAINER_ID chef-server-ctl org-add …
84+
docker-enter $CONTAINER_ID chef-server-ctl …
85+
86+
### Publishing the endpoint
87+
88+
This container is not supposed to listen on a publically available
89+
port. It is very strongly recommended to use a proxy server, such as
90+
[nginx](http://nginx.org/), as a public endpoint.
91+
92+
Unfortunately, Chef's logic for figuring out the absolute URL of
93+
various pieces (oc_id, bookshelf, erchef API, etc) for links and
94+
redirects is twisted and fragile. There are `chef-server.rb` settings,
95+
but some pieces insist on using the `Host:` header of the request, and
96+
it doesn't seem possible to use plain HTTP endpoint and have the Chef
97+
Server generate HTTPS redirects everywhere.
98+
99+
The main setting you need to configure is `PUBLIC_URL` environment
100+
variable. It needs to contain full public URL, as seen by `knife` and
101+
`chef-client` (e.g. `PUBLIC_URL=https://chef-api.example.com/`).
102+
103+
Then, you need to make sure that the proxy passes proper `Host:`
104+
header to the Chef Server, and talks with the Chef Server on
105+
the same protocol that the final endpoint will use (i.e. proxy that
106+
listens on HTTPS would need to use Chef Server's self-signed HTTPS
107+
endpoint; proxy that listens on plain HTTP would need to talk to HTTP
108+
endpoint).
109+
110+
If you prefer to avoid overhead of encrypting the connection between
111+
proxy and the Chef Server, it *should* be sufficient to rewrite the
112+
`Location:` headers (`proxy_redirect` in nginx, `ProxyPassReverse` in
113+
Apache). It works for me, but I can't guarantee you won't bump into
114+
a wrong URL generated by the server.
115+
116+
A sample nginx configuration looks like this:
117+
118+
server {
119+
listen 443 ssl;
120+
server_name chef.example.com;
121+
ssl_certificate /path/to/chef.example.com.pem;
122+
ssl_certificate_key /path/to/chef.example.com.key;
123+
client_max_body_size 4G;
124+
location / {
125+
proxy_pass http://127.0.0.1:5000;
126+
proxy_set_header Host $host;
127+
proxy_set_header X-Forwarded-Proto https;
128+
proxy_redirect default;
129+
proxy_redirect http://chef.example.com https://chef.example.com;
130+
}
131+
}
132+
133+
### Backup and restore
134+
135+
1. `docker stop chef-server`
136+
2. Archive `/var/opt/opscode` volume (delete the `bootstrapped` file
137+
from the archive to force `chef-server-ctl reconfigure` run on the
138+
new container)
139+
3. `docker start chef-server`
140+
141+
Same thing works for upgrades: just reuse container, remembering to
142+
remove the `bootstrapped` file. You may also need to remove the
143+
symlinks in `/var/opt/opscode/service` and/or run `chef-server-ctl
144+
upgrade` via `docker-enter`.
145+
146+
### Chef Plugins
147+
148+
**UNSUPPORTED.** No idea how to handle this (especially that this is
149+
the point at which licensing issues start to occur). Most likely, a
150+
separate image based off this one would be necessary.

chef-server.rb

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,35 @@
1+
# THIS FILE WILL BE OVERWRITTEN ON CONTAINER START. Please create a
2+
# new file named `chef-server-local.rb` for custom settings.
3+
4+
# Read parameters that originally came from Docker's environment
5+
# variables, and were saved to a file to support docker-enter
6+
7+
_env = Hash[ Dir['/.chef/env/*']
8+
.map { |f| [ File.basename(f), File.read(f).strip ] } ]
9+
110
require 'uri'
2-
_uri = ::URI.parse(ENV['PUBLIC_URL'] || 'https://127.0.0.1/')
11+
_uri = ::URI.parse(_env['PUBLIC_URL'] || 'https://127.0.0.1/')
312

4-
topology "standalone"
13+
# Set environment variables that may be missing when chef-server-ctl
14+
# runs from docker-enter
15+
ENV['HOME'] ||= '/'
16+
ENV['HOSTNAME'] ||= File.read('/etc/hostname').strip
17+
ENV['PATH'] ||= '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
18+
ENV['EDITOR'] ||= 'vim'
519

620
if _uri.port == _uri.default_port
721
api_fqdn _uri.hostname
822
else
923
api_fqdn "#{_uri.hostname}:#{_uri.port}"
1024
end
1125

12-
nginx['url'] = _uri.to_s
13-
bookshelf['url'] = _uri.to_s
1426
bookshelf['external_url'] = _uri.to_s
15-
erchef['base_resource_url'] = _uri.to_s
16-
27+
bookshelf['url'] = _uri.to_s
1728
nginx['enable_non_ssl'] = true
18-
chef_server_webui['enable'] = !ENV['DISABLE_WEBUI']
29+
nginx['url'] = _uri.to_s
30+
nginx['x_forwarded_proto'] = _uri.scheme
31+
oc_id['administrators'] = _env['OC_ID_ADMINISTRATORS'].to_s.split(',')
32+
opscode_erchef['base_resource_url'] = _uri.to_s
33+
34+
_local = File.join(File.dirname(__FILE__), 'chef-server-local.rb')
35+
instance_eval(File.read(_local), _local) if File.exist?(_local)

init.rb

Lines changed: 101 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8,58 +8,124 @@
88

99
STDOUT.sync = true
1010

11+
$processes = {}
12+
1113
def log(message)
1214
puts "[#{DateTime.now}] INIT: #{message}"
1315
end
1416

17+
def run!(*args, &block)
18+
log "Starting: #{args}" if ENV['DEBUG']
19+
pid = Process.spawn(*args)
20+
log "Started #{pid}: #{args.join ' '}"
21+
$processes[pid] = block || ->{ log "#{args.join ' '}: #{$?}" }
22+
pid
23+
end
24+
25+
def reconfigure! reason=nil
26+
if $reconf_pid
27+
if reason
28+
log "#{reason}, but cannot reconfigure: already running"
29+
else
30+
log "Cannot reconfigure: already running"
31+
end
32+
return
33+
end
34+
35+
if reason
36+
log "#{reason}, reconfiguring"
37+
else
38+
log "Reconfiguring"
39+
end
40+
41+
$reconf_pid = run! '/usr/bin/chef-server-ctl', 'reconfigure' do
42+
log "Reconfiguration finished: #{$?}"
43+
$reconf_pid = nil
44+
end
45+
end
46+
47+
def shutdown!
48+
unless $runsvdir_pid
49+
log "ERROR: no runsvdir pid at exit"
50+
exit 1
51+
end
52+
53+
if $reconf_pid
54+
log "Reconfigure running as #{$reconf_pid}, stopping..."
55+
Process.kill 'TERM', $reconf_pid
56+
(1..5).each do
57+
if $reconf_pid
58+
sleep 1
59+
else
60+
break
61+
end
62+
end
63+
if $reconf_pid
64+
Process.kill 'KILL', $reconf_pid
65+
end
66+
end
67+
68+
run! '/usr/bin/chef-server-ctl', 'stop' do
69+
log 'chef-server-ctl stop finished, stopping runsvdir'
70+
Process.kill('HUP', $runsvdir_pid)
71+
end
72+
end
73+
1574
log "Starting #{$PROGRAM_NAME}"
1675

17-
log 'Initializing sysctl for postgres'
18-
unless system 'sysctl -w kernel.shmmax=17179869184 kernel.shmall=4194304'
19-
fail 'sysctl FAIL'
76+
{ shmmax: 17179869184, shmall: 4194304 }.each do |param, value|
77+
if ( actual = File.read("/proc/sys/kernel/#{param}").to_i ) < value
78+
log "kernel.#{param} = #{actual}, setting to #{value}."
79+
begin
80+
File.write "/proc/sys/kernel/#{param}", value.to_s
81+
rescue
82+
log "Cannot set kernel.#{param} to #{value}: #{$!}"
83+
log "You may need to run the container in privileged mode or set sysctl on host."
84+
raise
85+
end
86+
end
87+
end
88+
89+
log 'Preparing configuration ...'
90+
FileUtils.mkdir_p %w'/var/opt/opscode/log /var/opt/opscode/etc /.chef/env', verbose: true
91+
FileUtils.cp '/.chef/chef-server.rb', '/var/opt/opscode/etc', verbose: true
92+
93+
%w'PUBLIC_URL OC_ID_ADMINISTRATORS'.each do |var|
94+
File.write(File.join('/.chef/env', var), ENV[var].to_s)
2095
end
2196

22-
{ '/var/log/chef-server' => 'log',
23-
'/etc/chef-server' => 'etc'
24-
}.each do |target, link|
25-
unless File.exist?(target) || File.symlink?(target)
26-
log "Linking #{target} as #{link}"
27-
FileUtils.mkdir_p "/var/opt/chef-server/#{link}"
28-
FileUtils.ln_s "/var/opt/chef-server/#{link}", target
97+
$runsvdir_pid = run! '/opt/opscode/embedded/bin/runsvdir-start' do
98+
log "runsvdir exited: #{$?}"
99+
if $?.success? || $?.exitstatus == 111
100+
exit
101+
else
102+
exit $?.exitstatus
29103
end
30104
end
31105

32-
log 'Starting runsvdir ...'
33-
$pid = Process.spawn(
34-
'/opt/chef-server/embedded/bin/runsvdir', '-P', '/opt/chef-server/sv',
35-
"log: #{'.' * 128}")
36-
log "Started runsvdir (#{$pid})"
106+
Signal.trap 'TERM' do
107+
shutdown!
108+
end
109+
110+
Signal.trap 'INT' do
111+
shutdown!
112+
end
37113

38-
Signal.trap('TERM') do
39-
log 'Got SIGTERM, shutting down runsvdir ...'
40-
Process.kill('HUP', $pid)
114+
Signal.trap 'HUP' do
115+
reconfigure! 'Got SIGHUP'
41116
end
42117

43-
Signal.trap('INT') do
44-
log 'Got SIGINT, shutting down runsvdir ...'
45-
Process.kill('HUP', $pid)
118+
Signal.trap 'USR1' do
119+
log 'Chef Server status:'
120+
run! '/usr/bin/chef-server-ctl', 'status'
46121
end
47122

48-
unless File.exist? '/var/opt/chef-server/bootstrapped'
49-
pid = Process.spawn '/usr/bin/chef-server-ctl', 'reconfigure'
50-
log "Not bootstrapped, running `chef-server-ctl reconfigure' (#{pid})"
123+
unless File.exist? '/var/opt/opscode/bootstrapped'
124+
reconfigure! 'Not bootstrapped'
51125
end
52126

53127
loop do
54-
chld = Process.wait
55-
if chld == $pid
56-
log "Runsvdir exited (#{$?}), exiting"
57-
if $?.success? || $?.exitstatus == 111
58-
break
59-
else
60-
exit $?.exitstatus
61-
end
62-
else
63-
log "Reaped PID #{chld} (#{$?})"
64-
end
128+
log $? if ENV['DEBUG']
129+
handler = $processes.delete(Process.wait)
130+
handler.call if handler
65131
end

logrotate/log/run

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/bin/sh
2+
set -e
3+
mkdir -p /var/log/opscode/logrotate
4+
exec svlogd -tt /var/log/opscode/logrotate

0 commit comments

Comments
 (0)