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"_boostrap.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)"
55 echo " --skip-prereqs Don't check prerequisites"
56 echo " --docker-args Extra arguments to pass when running docker"
63 IFS
=.
read -a ver_a
<<< "$1"
64 IFS
=.
read -a ver_b
<<< "$2"
66 while [[ -n $ver_a ]]; do
67 if (( ver_a
> ver_b
)); then
69 elif (( ver_b
> ver_a
)); then
78 return 1 # They are equal
83 # 1. docker daemon running?
84 test=`$docker_path info >/dev/null`
86 if [[ $?
-ne 0 ]] ; then
87 echo "Cannot connect to the docker daemon - verify it is running and you have access"
91 # 2. running aufs or btrfs
92 test=`$docker_path info 2> /dev/null | grep 'Driver: '`
93 if [[ "$test" =~
[aufs|btrfs
] ]] ; then : ; else
94 echo "Your Docker installation is not using the recommended AuFS (union filesystem) and may be unstable."
95 echo "If you are unable to bootstrap / stop your image please report the issue at:"
96 echo "https://meta.discourse.org/t/discourse-docker-installation-without-aufs/15639"
98 read -p "Continue without proper filesystem? [yN]" yn
105 # 3. running recommended docker version
106 test=($
($docker_path --version)) # Get docker version string
107 test=${test[2]//,/} # Get version alone and strip comma if exists
109 [[ "$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
111 # At least minimum version
112 if compare_version
"${docker_min_version}" "${test}"; then
113 echo "ERROR: Docker version ${test} not supported, please upgrade to at least ${docker_min_version}, or recommended ${docker_rec_version}"
117 # Recommend best version
118 if compare_version
"${docker_rec_version}" "${test}"; then
119 echo "WARNING: Docker version ${test} deprecated, recommend upgrade to ${docker_rec_version} or newer."
122 # 4. able to attach stderr / out / tty
123 test=`$docker_path run $user_args -i --rm -a stdout -a stderr $image echo working`
124 if [[ "$test" =~
"working" ]] ; then : ; else
125 echo "Your Docker installation is not working correctly"
127 echo "See: https://meta.discourse.org/t/docker-error-on-bootstrap/13657/18?u=sam"
132 if [ "$opt" != "--skip-prereqs" ] ; then
136 if [ "$opt" == "--docker-args" ] ; then
143 local ${ssh_key_locations}
145 ~
/.ssh
/id_ed25519.pub
149 ~core
/.ssh
/authorized_keys
153 for keyfile
in "${ssh_key_locations[@]}"; do
154 if [[ -e ${keyfile} ]] ; then
155 ssh_pub_key
="$(cat ${keyfile})"
161 echo "This user has no SSH key, but a SSH key is required to access the Discourse Docker container."
162 read -p "Generate a SSH key? (Y/n) " -n 1 -r
163 if [[ $REPLY =~ ^
[Nn
]$
]] ; then
165 echo WARNING
: You may not be able to log
in to your container.
169 echo Generating SSH key
170 mkdir
-p ~
/.
ssh && ssh-keygen
-f ~
/.ssh
/id_rsa
-t rsa
-N ''
172 ssh_pub_key
="$(cat ~/.ssh/id_rsa.pub)"
183 echo "Docker is not installed, make sure you are running on the 3.8 kernel"
184 echo "The best supported Docker release is Ubuntu 12.04.03 for it run the following"
186 echo "sudo apt-get update"
187 echo "sudo apt-get install linux-image-generic-lts-raring linux-headers-generic-lts-raring"
191 echo "sudo sh -c \"wget -qO- https://get.docker.io/gpg | apt-key add -\""
192 echo "sudo sh -c \"echo deb http://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list\""
193 echo "sudo apt-get update"
194 echo "sudo apt-get install lxc-docker"
200 read -r -d '' env_ruby
<< 'RUBY'
203 input
= STDIN.readlines.
join
204 yaml
= YAML.load
(input
)
206 if host_run
= yaml
['host_run']
207 params
= yaml
['params'] ||
{}
208 host_run.each
do |run|
210 run
= run.gsub
("$#{k}", v
)
212 STDOUT.
write "#{run}--SEP--"
217 host_run
=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e "$env_ruby"`
219 while [ "$host_run" ] ; do
220 iter
=${host_run%%--SEP--*}
222 echo "Host run: $iter"
225 host_run
="${host_run#*--SEP--}"
231 volumes
=`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)['volumes'].map{|v| '-v ' << v['volume']['host'] << ':' << v['volume']['guest'] << ' '}.join"`
236 links
=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e \
237 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['links'].map{|l| '--link ' << l['link']['name'] << ':' << l['link']['alias'] << ' '}.join"`
240 set_template_info
() {
242 templates
=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
243 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['templates']"`
246 arrTemplates
=(${templates// / })
247 config_data
=$
(cat $config_file)
252 for template
in "${arrTemplates[@]}"
254 [ ! -z $template ] && {
255 input
="$input _FILE_SEPERATOR_ $(cat $template)"
259 # we always want our config file last so it takes priority
260 input
="$input _FILE_SEPERATOR_ $config_data"
262 read -r -d '' env_ruby
<< 'RUBY'
265 input
=STDIN.readlines.
join
266 # default to UTF-8 for the dbs sake
267 env
= {'LANG' => 'en_US.UTF-8'}
268 input.
split('_FILE_SEPERATOR_').each
do |yml|
271 env.merge
!(YAML.load
(yml
)['env'] ||
{})
272 rescue Psych
::SyntaxError
=> e
280 puts env.map
{|k
,v|
"-e\n#{k}=#{v}" }.
join("\n")
283 raw
=`exec echo "$input" | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e "$env_ruby"`
288 if [ "$i" == "*ERROR." ]; then
290 elif [ -n "$i" ]; then
295 if [ "$ok" -ne 1 ]; then
297 echo "YAML syntax error. Please check your /var/discourse/containers/*.yml config files."
300 echo "Calculated ENV: ${env[@]}"
303 [ -z $docker_path ] && {
312 if [ ! -e $config_file ]
314 echo "Config file was not found, ensure $config_file exists"
316 echo "Available configs ( `cd containers && ls -dm *.yml | tr -s '\n' ' ' | awk '{ gsub(/\.yml/, ""); print }'`)"
321 docker_version
=($
($docker_path --version))
322 docker_version
=${test[2]//,/}
324 if compare_version
"1.2.0" "$docker_version"; then
325 echo "We recommend you upgrade docker, the version you are running has no restart policies, on reboot your container may not start up"
328 restart_policy
=${restart_policy:---restart=always}
333 if [ ! -e $config_file ]; then
334 echo "Config does not exist: $config_file" >&2
337 exec scripts
/mailtest
$config_file
346 $docker_path stop
-t 10 `cat $cidfile`
356 echo "No cid found, creating a new container"
357 ports
=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e \
358 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['expose'].map{|p| '-p ' << p.to_s << ' '}.join"`
364 existing
=`$docker_path ps -a | awk '{ print $1, $(NF) }' | grep "$config$" | awk '{ print $1 }'`
365 if [ ! -z $existing ]
367 echo "Found an existing container by its name, recovering cidfile, please rerun"
368 echo $existing > $cidfile
372 $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 \
373 $volumes $local_discourse/$config /sbin
/boot
381 echo "Detected empty cid file, deleting, please re-run"
386 found
=`$docker_path ps -q -a --no-trunc | grep $cid`
389 echo "Invalid cid file, deleting, please re-run"
394 echo "cid found, ensuring container is started"
395 $docker_path start
$attach_on_start `cat $cidfile`
407 # Is the image available?
408 # If not, pull it here so the user is aware what's happening.
409 $docker_path history $image >/dev
/null
2>&1 ||
$docker_path pull
$image
413 base_image
=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
414 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['base_image']"`
416 update_pups
=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
417 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['update_pups']"`
419 if [[ ! X
"" = X
"$base_image" ]]; then
428 run_command
="cd /pups &&"
429 if [[ ! "false" = $update_pups ]]; then
430 run_command
="$run_command git pull &&"
432 run_command
="$run_command /pups/bin/pups --stdin"
436 env
=("${env[@]}" "-e" "SSH_PUB_KEY=$ssh_pub_key")
438 (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 \
439 /bin
/bash
-c "$run_command") \
440 ||
($docker_path rm `cat $cidbootstrap` && rm $cidbootstrap)
442 [ ! -e $cidbootstrap ] && echo "FAILED TO BOOTSTRAP" && exit 1
446 $docker_path commit
`cat $cidbootstrap` $local_discourse/$config ||
echo 'FAILED TO COMMIT'
447 $docker_path rm `cat $cidbootstrap` && rm $cidbootstrap
453 echo "Successfully bootstrapped, to startup use ./launcher start $config"
470 if [ ! $UID -eq 0 ] ;
472 echo "enter command must run as root, will attempt to sudo"
476 if [ ! -e bin
/nsenter
]
478 echo "Downloading nsenter"
479 $docker_path pull samsaffron
/nsenter
480 ($docker_path run
$user_args --rm samsaffron
/nsenter
cat /nsenter
> bin
/nsenter1
) ||
exit 1
481 cp bin
/nsenter1 bin
/nsenter
485 PID
=$
($docker_path inspect
--format {{.State.Pid
}} `cat $cidfile`)
486 SHELL
=/bin
/bash sudo
-E bin
/nsenter
--target $PID --mount --uts --ipc --net --pid
498 address
="`$docker_path port $cid 22`"
499 split=(${address//:/ })
500 exec ssh -o StrictHostKeyChecking
=no root@
${split[0]} -p ${split[1]}
516 $docker_path logs
`cat $cidfile`
533 if [ "$(git symbolic-ref --short HEAD)" == "master" ]; then
534 echo "Updating discourse docker"
535 git pull ||
(echo 'failed to update' && exit 1)
539 echo "Stopping old container"
540 $docker_path stop
-t 10 `cat $cidfile`
547 $docker_path rm `cat $cidfile` && rm $cidfile
558 echo "destroying container $cidfile"
559 $docker_path stop
-t 10 `cat $cidfile`
560 $docker_path rm `cat $cidfile` && rm $cidfile
563 echo "nothing to destroy cidfile does not exist"