Skip to content

Commit bb50ad0

Browse files
stttscarmstrong
authored andcommitted
feat(contrib): add DigitalOcean provisioner booting CoreOS via kexec
This introduces a provisioning script for Deis on DigitalOcean droplets. As DigitalOcean does not (currently) support CoreOS, we deploy CoreOS on top of Ubuntu 14.04 using kexec on boot to switch to the CoreOS kernel and initrd. The state filesystem is a loop mounted btrfs. The CoreOS bootstrapping is heavily based on Levi Aul's code: https://gist.github.com/tsutsu/490f35f48897df0f5173 We don't use Debian 7.0 as base distribution because kexec is unstable on the Debian kernel.
1 parent b113210 commit bb50ad0

8 files changed

Lines changed: 369 additions & 7 deletions

contrib/digitalocean/README.md

Lines changed: 67 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,69 @@
1-
Deis on DigitalOcean
2-
====================
1+
# How to Provision a Deis Controller on Digital Ocean
32

4-
Unfortunately, DigitalOcean does not yet provide CoreOS images. This
5-
prevents Deis from being deployed on DigitalOcean.
3+
Here are the steps to get started on Digital Ocean:
64

7-
If you use DigitalOcean, please
8-
[show your support](http://digitalocean.uservoice.com/forums/136585-digital-ocean/suggestions/4250154-suport-coreos-as-a-deployment-platform)
9-
for CoreOS and help us to support Deis on DO.
5+
## Customize cloud-config.yml
6+
Edit [user-data](../coreos/user-data) and add a discovery URL. This URL will be used by all nodes in this Deis cluster. You can get a new discovery URL by sending a request to http://discovery.etcd.io/new.
7+
8+
## Install DO command line client and authorize:
9+
```console
10+
$ gem install tugboat
11+
$ tugboat authorize
12+
```
13+
You can leave all but the client and API keys as the defaults.
14+
15+
Find out about the ID of your ssh key (import it into DO if it's not listed):
16+
```console
17+
$ tugboat keys
18+
```
19+
20+
## Create a controller image:
21+
```console
22+
$ ./provision-digitalocean-controller-image.sh <YOU SSH KEY ID>
23+
```
24+
25+
## Deploy controllers
26+
Use the created image to launch (an odd number) controller droplets, either via UI
27+
or on the command line using tugboat:
28+
```console
29+
$ tugboat create deis1 -r <REGION_ID> -i <IMAGE_ID> -p true -k <SSH_ID> -s 65
30+
```
31+
32+
Not all regions allow private networks. Choose one which does, e.g. NY 2, Amsterdam 2 or
33+
Singapore 1 at the time of this writing (check the web UI for the current private network
34+
support).
35+
36+
The provisioning script uses a 512 MB droplet by default because for iamge creation
37+
more memory is not needed. Deis controller nodes will need at least 2 GB to even start all
38+
the services. Add the memory requirements of deployed applications and choose an adequat
39+
droplet size, e.g. 8 GB (ID "65").
40+
41+
## Initialize the cluster
42+
Once the cluster is up, get the IPs of any of the machines using `tugboat droplets`, set
43+
FLEETCTL_TUNNEL to one of these IPs:
44+
```console
45+
$ export FLEETCTL_TUNNEL=23.253.219.94
46+
$ cd ../.. && make run
47+
```
48+
The script will deploy Deis and make sure the services start properly.
49+
50+
### Configure DNS
51+
You'll need to configure DNS records so you can access applications hosted on Deis. See [Configuring DNS](http://docs.deis.io/en/latest/operations/configure-dns/) for details.
52+
53+
### Use Deis!
54+
After that, register with Deis!
55+
```console
56+
$ deis register http://deis.example.org
57+
username: deis
58+
password:
59+
password (confirm):
60+
email: info@opdemand.com
61+
```
62+
63+
## Hack on Deis
64+
If you'd like to use this deployment to build Deis, you'll need to set `DEIS_HOSTS` to an array of your cluster hosts:
65+
```console
66+
$ export DEIS_HOSTS=10.21.12.1 10.21.12.2 10.21.12.3
67+
```
68+
69+
This variable is used in the `make build` command.
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#cloud-config
2+
3+
hostname: HOSTNAME
4+
5+
users:
6+
- name: core
7+
groups:
8+
- sudo
9+
- docker
10+
ssh-authorized-keys:
11+
- SSH_KEY
12+
13+
coreos:
14+
units:
15+
- name: public.network
16+
content: |
17+
[Match]
18+
Name=ens3
19+
20+
[Network]
21+
Address=PUBLIC_IP
22+
Gateway=GATEWAY
23+
DNS=8.8.8.8
24+
DNS=8.8.4.4
25+
- name: private.network
26+
content: |
27+
[Match]
28+
Name=ens4v1
29+
30+
[Network]
31+
Address=PRIVATE_IP
32+
- name: media-doroot.mount
33+
command: start
34+
content: |
35+
[Mount]
36+
What=/dev/vda
37+
Where=/media/doroot
38+
Type=ext4
39+
- name: format-docker-store.service
40+
command: start
41+
content: |
42+
[Unit]
43+
Requires=media-doroot.mount
44+
[Service]
45+
Type=oneshot
46+
RemainAfterExit=yes
47+
ExecStart=/usr/share/oem/bin/create-coreos-docker-store
48+
- name: var-lib-docker.mount
49+
command: start
50+
content: |
51+
[Unit]
52+
Requires=format-docker-store.service
53+
Before=docker.service
54+
[Mount]
55+
What=/dev/disk/by-label/docker
56+
Where=/var/lib/docker
57+
Type=btrfs
58+
- name: coreos-setup-environment.service
59+
command: restart
60+
runtime: yes
61+
content: |
62+
[Unit]
63+
Before=docker.service
64+
[Service]
65+
Type=oneshot
66+
ExecStart=/usr/share/oem/bin/coreos-setup-environment /etc/environment
67+
- name: coreos-apply-user-data.service
68+
command: restart
69+
runtime: yes
70+
content: |
71+
[Unit]
72+
After=coreos-setup-environment.service
73+
[Service]
74+
EnvironmentFile=/etc/environment
75+
Type=oneshot
76+
ExecStart=/usr/share/oem/bin/coreos-apply-user-data
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/bin/bash
2+
coreos-cloudinit --from-file=/usr/share/oem/user-data.yml
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/bin/bash -e
2+
3+
ENV=$1
4+
5+
if [ -z "$ENV" ]; then
6+
echo usage: $0 /etc/environment
7+
exit 1
8+
fi
9+
10+
touch $ENV
11+
if [ $? -ne 0 ]; then
12+
echo exiting, unable to modify: $ENV
13+
exit 1
14+
fi
15+
16+
sed -i -e '/^COREOS_PUBLIC_IPV4=/d;/^COREOS_PRIVATE_IPV4=/d' $ENV
17+
18+
COREOS_PUBLIC_IPV4=$(ip -4 -o addr show dev ens3 | awk '{ print $4; }' | cut -d / -f1)
19+
COREOS_PRIVATE_IPV4=$(ip -4 -o addr show dev ens4v1 | awk '{ print $4; }' | cut -d / -f1)
20+
echo COREOS_PUBLIC_IPV4=$COREOS_PUBLIC_IPV4 >> $ENV
21+
echo COREOS_PRIVATE_IPV4=$COREOS_PRIVATE_IPV4 >> $ENV
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/bin/sh
2+
mkdir -p /media/doroot/var/lib/coreos
3+
4+
if [ ! -f "/media/doroot/var/lib/coreos/docker.img" ]; then
5+
DOFORMAT=1
6+
fi
7+
8+
truncate -s 10G /media/doroot/var/lib/coreos/docker.img
9+
LODEV=`losetup -f --show /media/doroot/var/lib/coreos/docker.img`
10+
11+
if [ -n "$DOFORMAT" ]; then
12+
mkfs.btrfs -L docker "$LODEV"
13+
fi
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
THIS_DIR=$(cd $(dirname $0); pwd) # absolute path
6+
CONTRIB_DIR=$(dirname $THIS_DIR)
7+
8+
source $CONTRIB_DIR/utils.sh
9+
10+
if ! which tugboat &>/dev/null; then
11+
echo_red 'Digital Ocean command line client tugboat not found.'
12+
exit 1
13+
fi
14+
15+
function wait_ssh () {
16+
echo -n "Trying to ssh into $1@$2..."
17+
while ! $SSH -o ConnectTimeout=10 $1@$2 hostname &>/dev/null; do
18+
echo -n "."
19+
sleep 1
20+
done
21+
echo_green "done"
22+
}
23+
24+
# parse parameters
25+
if [ -z "$1" ]; then
26+
echo_red 'Usage: $0 SSH_ID [REGION_ID]'
27+
echo
28+
echo 'Use `tugboat keys` to list available SSH_IDs.'
29+
exit 1
30+
fi
31+
32+
SSH_ID="$1"
33+
REGION="${2:-5}" # Amsterdam 1 by default
34+
SIZE="66" # 512 MB
35+
NAME="deis-controller-image-$(date +%Y%m%d%H%M%S)"
36+
37+
BASE_IMAGE='Ubuntu 14.04 x64'
38+
BASE_IMAGE_ID=$(tugboat images -g | grep "$BASE_IMAGE" | sed 's/.*id: \([0-9]*\).*/\1/')
39+
SSH_OPTIONS="-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o PasswordAuthentication=no -o ConnectTimeout=1 -o ConnectionAttempts=10"
40+
SSH="ssh $SSH_OPTIONS"
41+
SCP="scp $SSH_OPTIONS -q"
42+
43+
# create droplet
44+
tugboat create "$NAME" -i $BASE_IMAGE_ID -p true -k $SSH_ID -s $SIZE -r $REGION
45+
46+
# destroy droplets on error
47+
function cleanup () {
48+
set +e
49+
tugboat destroy -c -n "$NAME"
50+
exit 1
51+
}
52+
trap cleanup ERR
53+
trap cleanup SIGINT
54+
55+
# wait for droplet to come up with ssh login
56+
tugboat wait -n "$NAME" --state active
57+
IP=$(tugboat info -n "$NAME" | egrep '^IP' | awk '{ print $2; }')
58+
wait_ssh root $IP
59+
60+
# bootstrap
61+
echo "Deploying CoreOS on top of $BASE_IMAGE..."
62+
(
63+
set -ex
64+
$SCP update-coreos root@$IP:/usr/sbin
65+
$SSH root@$IP mkdir -p /usr/share/oem/bin
66+
$SCP cloud-config.yml root@$IP:/usr/share/oem/cloud-config.yml.template
67+
$SCP ../coreos/user-data root@$IP:/usr/share/oem/user-data.yml
68+
$SCP create-coreos-docker-store coreos-setup-environment coreos-apply-user-data root@$IP:/usr/share/oem/bin
69+
$SCP rc.local root@$IP:/etc
70+
$SSH root@$IP <<EOF
71+
set -xe
72+
73+
DEBIAN_FRONTEND=noninteractive
74+
apt-get install debconf-utils -y
75+
echo "kexec-tools kexec-tools/load_kexec boolean false" | debconf-set-selections
76+
apt-get install squashfs-tools kexec-tools -y
77+
shutdown -h now
78+
EOF
79+
) 2>&1 | sed 's/^/ /'; test ${PIPESTATUS[0]} -eq 0
80+
81+
# switch off and make snapshot
82+
tugboat wait -n "$NAME" --state off
83+
tugboat snapshot $NAME -n $NAME
84+
85+
# wait for snapshot to finish
86+
echo -n "Waiting for snapsnot to appear..."
87+
while ! tugboat images | grep $NAME &>/dev/null; do
88+
sleep 5
89+
echo -n "."
90+
done
91+
IMAGE_ID=$(tugboat images | grep $NAME | awk '{print $3;}' | sed 's/,//')
92+
echo_green "done"
93+
94+
echo -n "Trying to destroy droplet..."
95+
while ! tugboat destroy -c -n $NAME &>/dev/null; do
96+
sleep 5
97+
echo -n "."
98+
done
99+
echo_green "done"
100+
101+
echo
102+
echo_green "Congratulations: The Deis controller image $NAME was created with ID $IMAGE_ID."
103+
echo
104+
echo "Spawn controllers with:"
105+
echo
106+
echo " tugboat create deis1 -i $IMAGE_ID -r $REGION -p true -k $SSH_ID -s 65"

contrib/digitalocean/rc.local

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/bin/bash
2+
3+
set -ex
4+
5+
function echo_red {
6+
echo -e "\033[0;31m$1\033[0m"
7+
}
8+
9+
function error_handler () {
10+
set +ex
11+
echo_red "An error occured while bootstrapping CoreOS."
12+
while true; do sleep 1; done
13+
exit 1
14+
}
15+
trap error_handler ERR
16+
17+
# create coreos cloud-config
18+
PUBLIC_IP=$(/sbin/ip -4 -o addr show dev eth0 | awk '{ print $4; }')
19+
PRIVATE_IP=$(/sbin/ip -4 -o addr show dev eth1 | awk '{ print $4; }')
20+
GATEWAY=$(/sbin/ip route | awk '/default/ { print $3 }')
21+
SSH_KEY="$(cat /root/.ssh/authorized_keys | head -n1)"
22+
sed "s,HOSTNAME,$HOSTNAME,;s,PUBLIC_IP,$PUBLIC_IP,;s,PRIVATE_IP,$PRIVATE_IP,;s,GATEWAY,$GATEWAY,;s,SSH_KEY,$SSH_KEY," /usr/share/oem/cloud-config.yml.template > /usr/share/oem/cloud-config.yml
23+
24+
# download coreos, kernel and create initrd
25+
/usr/sbin/update-coreos
26+
27+
# run CoreOS kernel
28+
/sbin/kexec --load /boot/coreos/vmlinuz --initrd /boot/coreos/initrd.cpio.gz
29+
/sbin/kexec --exec

contrib/digitalocean/update-coreos

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
COREOS_VERSION=349.0.0
6+
BASE_URL="http://storage.core-os.net/coreos/amd64-usr/$COREOS_VERSION"
7+
8+
KERNEL="/boot/coreos/vmlinuz"
9+
INITRD_IMAGE="/boot/coreos/initrd.cpio.gz"
10+
INITRD_TEMPLATE="/boot/coreos/initrd.template"
11+
CONFIG_LINK_DIR="/boot/coreos/initrd.template/usr/share/oem"
12+
13+
if [ "$1" = "-d" -o "$1" = "--download" ]; then
14+
shift
15+
REDOWNLOAD_KERNEL=1
16+
REDOWNLOAD_INITRD=1
17+
fi
18+
19+
mkdir -p "$CONFIG_LINK_DIR"
20+
21+
cp -avx /usr/share/oem/* "$CONFIG_LINK_DIR"
22+
23+
if [ ! -s "$KERNEL" ]; then
24+
REDOWNLOAD_KERNEL=1
25+
fi
26+
27+
if [ "$(find "$INITRD_TEMPLATE" -name "*.squashfs" -type f -size +0 | wc -l)" -eq 0 ]; then
28+
REDOWNLOAD_INITRD=1
29+
fi
30+
31+
if [ -n "$REDOWNLOAD_KERNEL" ]; then
32+
curl --retry 10 -f "$BASE_URL/coreos_production_pxe.vmlinuz" > "$KERNEL"
33+
fi
34+
35+
if [ -n "$REDOWNLOAD_INITRD" ]; then
36+
find "$INITRD_TEMPLATE" -name "*.squashfs" -type f -delete
37+
38+
TMP=`mktemp -d`
39+
pushd "$TMP" >/dev/null
40+
curl --retry 10 -f "$BASE_URL/coreos_production_pxe_image.cpio.gz" | zcat | cpio -id
41+
test ${PIPESTATUS[0]} -eq 0
42+
find "$TMP" -name "*.squashfs" -type f -exec 'mv' '{}' "${INITRD_TEMPLATE}/" ';'
43+
popd >/dev/null
44+
rm -rf "$TMP"
45+
fi
46+
47+
48+
rm -f "$INITRD_IMAGE"
49+
50+
pushd "$INITRD_TEMPLATE" >/dev/null
51+
rm -f ./manifest
52+
find . -name "*.squashfs" >> ./manifest
53+
find ./usr >> ./manifest
54+
cat ./manifest | cpio -o -H newc -L | gzip -nc - > "$INITRD_IMAGE"
55+
popd >/dev/null

0 commit comments

Comments
 (0)