9 docker_min_version
='1.2.0'
10 docker_rec_version
='1.2.0'
12 config_file
=containers
/"$config".yml
13 cidfile
=cids
/"$config".cid
14 cidbootstrap
=cids
/"$config"_bootstrap.cid
15 local_discourse
=local_discourse
16 image
=samsaffron
/discourse
:1.0.7
17 docker_path
=`which docker.io || which docker`
19 if [ "${SUPERVISED}" = "true" ]; then
20 restart_policy
="--restart=no"
22 attach_on_run
="-a stdout -a stderr"
27 if [ -x "$(which ip 2>/dev/null)" ]; then
28 docker_ip
=`ip addr show docker0 | \
30 awk '{ split($2,a,"/"); print a[1] }';`
32 docker_ip
=`ifconfig | \
33 grep -B1 "inet addr" | \
34 awk '{ if ( $1 == "inet" ) { print $2 } else if ( $2 == "Link" ) { printf "%s:" ,$1 } }' | \
36 awk -F: '{ print $3 }';`
41 echo "Usage: launcher COMMAND CONFIG [--skip-prereqs]"
43 echo " start: Start/initialize a container"
44 echo " stop: Stop a running container"
45 echo " restart: Restart a container"
46 echo " destroy: Stop and remove a container"
47 echo " enter: Use nsenter to enter a container"
48 echo " ssh: Start a bash shell in a running container"
49 echo " logs: Docker logs for container"
50 echo " mailtest: Test the mail settings in a container"
51 echo " bootstrap: Bootstrap a container for the config based on a template"
52 echo " rebuild: Rebuild a container (destroy old, bootstrap, start new)"
53 echo " cleanup: Remove all containers that have stopped for > 24 hours"
56 echo " --skip-prereqs Don't check prerequisites"
57 echo " --docker-args Extra arguments to pass when running docker"
64 IFS
=.
read -a ver_a
<<< "$1"
65 IFS
=.
read -a ver_b
<<< "$2"
67 while [[ -n $ver_a ]]; do
68 if (( ver_a
> ver_b
)); then
70 elif (( ver_b
> ver_a
)); then
79 return 1 # They are equal
84 # 1. docker daemon running?
85 test=`$docker_path info >/dev/null`
87 if [[ $?
-ne 0 ]] ; then
88 echo "Cannot connect to the docker daemon - verify it is running and you have access"
92 # 2. running aufs or btrfs
93 test=`$docker_path info 2> /dev/null | grep 'Driver: '`
94 if [[ "$test" =~
[aufs|btrfs
] ]] ; then : ; else
95 echo "Your Docker installation is not using the recommended AuFS (union filesystem) and may be unstable."
96 echo "If you are unable to bootstrap / stop your image please report the issue at:"
97 echo "https://meta.discourse.org/t/discourse-docker-installation-without-aufs/15639"
100 # 3. running recommended docker version
101 test=($
($docker_path --version)) # Get docker version string
102 test=${test[2]//,/} # Get version alone and strip comma if exists
104 [[ "$test" =~
"0.12.0" ]] && echo "You are running a broken version of Docker, please upgrade ASAP. See: https://meta.discourse.org/t/the-installation-stopped-in-the-middle/16311/ for more details." && exit 1
106 # At least minimum version
107 if compare_version
"${docker_min_version}" "${test}"; then
108 echo "ERROR: Docker version ${test} not supported, please upgrade to at least ${docker_min_version}, or recommended ${docker_rec_version}"
112 # Recommend best version
113 if compare_version
"${docker_rec_version}" "${test}"; then
114 echo "WARNING: Docker version ${test} deprecated, recommend upgrade to ${docker_rec_version} or newer."
117 # 4. able to attach stderr / out / tty
118 test=`$docker_path run $user_args -i --rm -a stdout -a stderr $image echo working`
119 if [[ "$test" =~
"working" ]] ; then : ; else
120 echo "Your Docker installation is not working correctly"
122 echo "See: https://meta.discourse.org/t/docker-error-on-bootstrap/13657/18?u=sam"
127 if [ "$opt" != "--skip-prereqs" ] ; then
131 if [ "$opt" == "--docker-args" ] ; then
138 local ${ssh_key_locations}
140 ~
/.ssh
/id_ed25519.pub
144 ~core
/.ssh
/authorized_keys
148 for keyfile
in "${ssh_key_locations[@]}"; do
149 if [[ -e ${keyfile} ]] ; then
150 ssh_pub_key
="$(cat ${keyfile})"
156 echo "This user has no SSH key, but a SSH key is required to access the Discourse Docker container."
157 read -p "Generate a SSH key? (Y/n) " -n 1 -r
158 if [[ $REPLY =~ ^
[Nn
]$
]] ; then
160 echo WARNING
: You may not be able to log
in to your container.
164 echo Generating SSH key
165 mkdir
-p ~
/.
ssh && ssh-keygen
-f ~
/.ssh
/id_rsa
-t rsa
-N ''
167 ssh_pub_key
="$(cat ~/.ssh/id_rsa.pub)"
178 echo "Docker is not installed, make sure you are running on the 3.8 kernel"
179 echo "The best supported Docker release is Ubuntu 12.04.03 for it run the following"
181 echo "sudo apt-get update"
182 echo "sudo apt-get install linux-image-generic-lts-raring linux-headers-generic-lts-raring"
186 echo "sudo sh -c \"wget -qO- https://get.docker.io/gpg | apt-key add -\""
187 echo "sudo sh -c \"echo deb http://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list\""
188 echo "sudo apt-get update"
189 echo "sudo apt-get install lxc-docker"
195 read -r -d '' env_ruby
<< 'RUBY'
198 input
= STDIN.readlines.
join
199 yaml
= YAML.load
(input
)
201 if host_run
= yaml
['host_run']
202 params
= yaml
['params'] ||
{}
203 host_run.each
do |run|
205 run
= run.gsub
("$#{k}", v
)
207 STDOUT.
write "#{run}--SEP--"
212 host_run
=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e "$env_ruby"`
214 while [ "$host_run" ] ; do
215 iter
=${host_run%%--SEP--*}
217 echo "Host run: $iter"
220 host_run
="${host_run#*--SEP--}"
226 volumes
=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e \
227 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['volumes'].map{|v| '-v ' << v['volume']['host'] << ':' << v['volume']['guest'] << ' '}.join"`
231 links
=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e \
232 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['links'].map{|l| '--link ' << l['link']['name'] << ':' << l['link']['alias'] << ' '}.join"`
235 set_template_info
() {
237 templates
=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
238 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['templates']"`
241 arrTemplates
=(${templates// / })
242 config_data
=$
(cat $config_file)
247 for template
in "${arrTemplates[@]}"
249 [ ! -z $template ] && {
250 input
="$input _FILE_SEPERATOR_ $(cat $template)"
254 # we always want our config file last so it takes priority
255 input
="$input _FILE_SEPERATOR_ $config_data"
257 read -r -d '' env_ruby
<< 'RUBY'
260 input
=STDIN.readlines.
join
261 # default to UTF-8 for the dbs sake
262 env
= {'LANG' => 'en_US.UTF-8'}
263 input.
split('_FILE_SEPERATOR_').each
do |yml|
266 env.merge
!(YAML.load
(yml
)['env'] ||
{})
267 rescue Psych
::SyntaxError
=> e
275 puts env.map
{|k
,v|
"-e\n#{k}=#{v}" }.
join("\n")
278 raw
=`exec echo "$input" | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e "$env_ruby"`
283 if [ "$i" == "*ERROR." ]; then
285 elif [ -n "$i" ]; then
290 if [ "$ok" -ne 1 ]; then
292 echo "YAML syntax error. Please check your /var/discourse/containers/*.yml config files."
295 echo "Calculated ENV: ${env[@]}"
298 [ -z $docker_path ] && {
302 [ $command == "cleanup" ] && {
304 echo "The following command will"
305 echo "- Delete all docker images for old containers"
306 echo "- Delete all stopped and orphan containers"
308 read -p "Are you sure (Y/n): " -n 1 -r && echo
309 if [[ $REPLY =~ ^
[Yy
]$ ||
! $REPLY ]]
311 GetSpace
=$
(du
-sk |
awk '{print $1}');
312 echo "Starting Cleanup"
313 docker inspect
-f '{{.Id}},{{.State.Running}},{{.State.FinishedAt}}' $
(docker ps
-qa) | \
314 awk -F, 'BEGIN { TIME=strftime("%FT%T.000000000Z",systime()-60*60*24); } $2=="false" && $3 < TIME {print $1;}' | \
315 xargs --no-run-if-empty docker
rm >/dev
/null
2>/dev
/null
316 docker images
--no-trunc|
grep none |
awk '{print $3}' |
xargs -r docker rmi
317 let SpaceFreed
=$GetSpace-$
(du
-sk |
awk '{print $1}')
318 Output
="$SpaceFreed" |
awk '{sum=$1;hum[1024**3]="GB"; hum[1024**2]="MB"; hum[1024]="KB"; for (x=1024**3;x>=1024; x/=1024){ if (sum>=x) { printf "%.2f %s\n",sum/x,hum[x];break }}}'
319 [ -z "$Output" ] && {
320 [[ $SpaceFreed > 0 ]] && { echo "./launcher cleanup cleared up $SpaceFreed Bytes of disk space."; } ||
{ echo "./launcher cleanup has finished, no files were removed."; }
321 } ||
{ echo "./launcher cleanup cleared up $Output of disk space."; }
332 if [ ! -e $config_file ]
334 echo "Config file was not found, ensure $config_file exists"
336 echo "Available configs ( `cd containers && ls -dm *.yml | tr -s '\n' ' ' | awk '{ gsub(/\.yml/, ""); print }'`)"
341 docker_version
=($
($docker_path --version))
342 docker_version
=${test[2]//,/}
344 if compare_version
"1.2.0" "$docker_version"; then
345 echo "We recommend you upgrade docker, the version you are running has no restart policies, on reboot your container may not start up"
348 restart_policy
=${restart_policy:---restart=always}
353 if [ ! -e $config_file ]; then
354 echo "Config does not exist: $config_file" >&2
357 exec scripts
/mailtest
$config_file
366 $docker_path stop
-t 10 `cat $cidfile`
376 echo "No cid found, creating a new container"
377 ports
=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e \
378 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['expose'].map{|p| '-p ' << p.to_s << ' '}.join"`
384 existing
=`$docker_path ps -a | awk '{ print $1, $(NF) }' | grep "$config$" | awk '{ print $1 }'`
385 if [ ! -z $existing ]
387 echo "Found an existing container by its name, recovering cidfile, please rerun"
388 echo $existing > $cidfile
392 $docker_path run
$user_args $links $attach_on_run $restart_policy "${env[@]}" -h "`hostname`-$config" -e DOCKER_HOST_IP
=$docker_ip --name $config -t --cidfile $cidfile $ports \
393 $volumes $local_discourse/$config /sbin
/boot
401 echo "Detected empty cid file, deleting, please re-run"
406 found
=`$docker_path ps -q -a --no-trunc | grep $cid`
409 echo "Invalid cid file, deleting, please re-run"
414 echo "cid found, ensuring container is started"
415 $docker_path start
$attach_on_start `cat $cidfile`
427 # Is the image available?
428 # If not, pull it here so the user is aware what's happening.
429 $docker_path history $image >/dev
/null
2>&1 ||
$docker_path pull
$image
433 base_image
=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
434 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['base_image']"`
436 update_pups
=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
437 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['update_pups']"`
439 if [[ ! X
"" = X
"$base_image" ]]; then
448 run_command
="cd /pups &&"
449 if [[ ! "false" = $update_pups ]]; then
450 run_command
="$run_command git pull &&"
452 run_command
="$run_command /pups/bin/pups --stdin"
456 env
=("${env[@]}" "-e" "SSH_PUB_KEY=$ssh_pub_key")
458 (exec echo "$input" |
$docker_path run
$user_args $links "${env[@]}" -e DOCKER_HOST_IP
=$docker_ip --cidfile $cidbootstrap -i -a stdin
-a stdout
-a stderr
$volumes $image \
459 /bin
/bash
-c "$run_command") \
460 ||
($docker_path rm `cat $cidbootstrap` && rm $cidbootstrap)
462 [ ! -e $cidbootstrap ] && echo "FAILED TO BOOTSTRAP" && exit 1
466 $docker_path commit
`cat $cidbootstrap` $local_discourse/$config ||
echo 'FAILED TO COMMIT'
467 $docker_path rm `cat $cidbootstrap` && rm $cidbootstrap
473 echo "Successfully bootstrapped, to startup use ./launcher start $config"
490 if [ ! $UID -eq 0 ] ;
492 echo "enter command must run as root, will attempt to sudo"
496 if [ ! -e bin
/nsenter
]
498 echo "Downloading nsenter"
499 $docker_path pull samsaffron
/nsenter
500 ($docker_path run
$user_args --rm samsaffron
/nsenter
cat /nsenter
> bin
/nsenter1
) ||
exit 1
501 cp bin
/nsenter1 bin
/nsenter
505 PID
=$
($docker_path inspect
--format {{.State.Pid
}} `cat $cidfile`)
506 SHELL
=/bin
/bash sudo
-E bin
/nsenter
--target $PID --mount --uts --ipc --net --pid
518 address
="`$docker_path port $cid 22`"
519 split=(${address//:/ })
520 exec ssh -o StrictHostKeyChecking
=no root@
${split[0]} -p ${split[1]}
536 $docker_path logs
`cat $cidfile`
553 if [ "$(git symbolic-ref --short HEAD)" == "master" ]; then
554 echo "Updating discourse docker"
555 git pull ||
(echo 'failed to update' && exit 1)
559 echo "Stopping old container"
560 $docker_path stop
-t 10 `cat $cidfile`
567 $docker_path rm `cat $cidfile` && rm $cidfile
578 echo "destroying container $cidfile"
579 $docker_path stop
-t 10 `cat $cidfile`
580 $docker_path rm `cat $cidfile` && rm $cidfile
583 echo "nothing to destroy cidfile does not exist"