As Dustin mentioned in his blog posts here and here, we've been working with VMWare on a CloudFoundry deployment using Ubuntu Server and Juju.
Today, I would like to build on those posts and talk a bit about:
- deploying a CloudFoundry server environment using Ubuntu Server and Juju
- show how Juju charm can make it easy to horizontally scale your deployment
- deploy a sample application
The short version ( not really that short after all )
Dependencies
sudo apt-get install bzr wget grep sed gawk
Juju
sudo apt-add-repository ppa:juju/pkgs
sudo apt-get update
sudo apt-get install juju
Charms and supporting scripts
bzr branch lp:~canonical-sig/+junk/cloudfoundry-server
bzr branch lp:~canonical-sig/+junk/cloudfoundry-server-dea
bzr branch lp:~canonical-sig/+junk/cf-mysql
bzr branch lp:~canonical-sig/+junk/cf-mongodb
bzr branch lp:~canonical-sig/+junk/cf-redis
bzr branch lp:~kirkland/+junk/drawbridge
bzr branch lp:~negronjl/+junk/ubuntu-latest-image
chmod +x ./ubuntu-latest-image
juju
echo " default-image-id: `ubuntu-latest-image oneiric m1.large | grep Image | awk '{ print $3 }'`" >> ~/.juju/environments.yaml
echo " default-instance-type: m1.large" >> ~/.juju/environments.yaml
Bootstrap
juju bootstrap
Deploy
juju deploy --repository . cloudfoundry-server
juju deploy --repository . cloudfoundry-server-dea
juju deploy --repository . cf-mysql
juju deploy --repository . cf-redis
juju deploy --repository . cf-mongodb
Relationships
juju add-relation cloudfoundry-server cloudfoundry-server-dea
juju add-relation cloudfoundry-server cf-mysql
juju add-relation cloudfoundry-server cf-mongodb
juju add-relation cloudfoundry-server cf-redis
Scale
juju add-unit cloudfoundry-server-dea
juju add-unit cf-mysql
juju add-unit cf-mongodb
juju add-unit cf-redis
DrawBridge
cd drawbridge
vmc
vmc target <your hostname here>
vmc add-user
vmc push
Take it all down
juju destroy-environment
The video version ( better than the not so short version above but not enough details )
The details ( pretty much all of them )
This deployment will be a bit different as we'll be deploying everything in Ubuntu 11.10 ( Oneiric ) and we'll be using large instances in Amazon EC2. Let's get started...
Juju
sudo apt-add-repository ppa:juju/pkgs
sudo apt-get update
sudo apt-get install juju
Bazaar ( so we can download the charms )
sudo apt-get install bzr
CloudFoundry Juju charms
bzr branch lp:~canonical-sig/+junk/cloudfoundry-server
bzr branch lp:~canonical-sig/+junk/cloudfoundry-server-dea
bzr branch lp:~canonical-sig/+junk/cf-mysql
bzr branch lp:~canonical-sig/+junk/cf-mongodb
bzr branch lp:~canonical-sig/+junk/cf-redis
DrawBridge app ( Thanks Dustin )
bzr branch lp:~kirkland/+junk/drawbridge
Configure Juju
juju ( will create the configuration file if needed )
Get the latest Ubuntu Oneiric image from here or you can just use this little script that will do it for you:
#!/bin/bashCopy the above code and save it somewhere in your computer ( I named mine ubuntu-latest-image and saved it in ~/bin so it's in my PATH ). The script depends on wget, grep, sed and awk. All available in the repositories and more than likely already installed in your system. Just in case you don't have them installed, run sudo apt-get install wget grep sed awk.
release="$1"
size="$2"
[ -z "$release" ] && release="oneiric"
[ -z "$size" ] && size="t1.micro"
echo "Release: ${release}"
echo "Size: ${size}"
result=`wget -q -O - http://uec-images.ubuntu.com/$release/current/ | grep -m1 "$size.*us-east" | sed -e "s/^.*<tt>//" -e "s/ <\/tt>.*$//" -e 's/${EC2_KEYPAIR_US_EAST_1}//'`
image_id=`echo $result | awk '{ print $2 }'`
echo "Image ID: ${image_id}"
Execute the script as follows:
- ubuntu-latest-image oneiric m1.large
Release: oneiric
Size: m1.large
Image ID: ami-d131f2b8
We now need to modify our default juju configuration so we can deploy large (m1.large) oneiric ( ami-d131f2b8 ) instances.
Edit juju's configuration file (~/.juju/environments.yaml) and make it look something like this:
environments: sample: type: ec2 access-key: --removed-- secret-key: --removed-- control-bucket: --removed-- admin-secret: --removed-- default-image-id: ami-d131f2b8 default-instance-type: m1.large
The highlighted parts are the important ones, you should already have the other lines in your configuration.
Bootstrap Juju:
juju bootstrap
Make sure the environment has been bootstrapped by running:
juju status
The output should look similar the this:
2011-09-09 21:30:48,363 INFO Connecting to environment.
machines:
0: {dns-name: ec2-184-73-104-84.compute-1.amazonaws.com, instance-id: i-58f72138}
services: {}
2011-09-09 21:30:50,925 INFO 'status' command finished successfully
== DynDNS ==
If you want your CloudFoundry server to be accessible ( and usable ) remotely, you'll need to have a DNS entry that also creates a wildcard record. If you have a DynDNS account, you can enter your hostname and credentials right into this charm. Upon deployment, the configuration will be done for you. Edit cloudfoundry-server/hooks/install and change the following lines:
USE_DYNDNS="true" <---- make sure it is set to "true"
DYNDNS_USERNAME="dyndnsusername" <----- Your DynDNS username
DYNDNS_PASSWORD="dyndnspassword" <----- Your DynDNS password
DYNDNS_HOSTNAME="cf-host.dyndns.org" <--- The DyDNS host you created for this.
Deploy the cloudfoundry-server charm by typing the following:
ensmelbe deploy --repository . cloudfoundry-server
After a few minutes, the output of juju status should look similar to this:
2011-09-09 21:43:38,203 INFO Connecting to environment.
machines:
0: {dns-name: ec2-184-73-104-84.compute-1.amazonaws.com, instance-id: i-58f72138}
1: {dns-name: ec2-50-17-173-69.compute-1.amazonaws.com, instance-id: i-c6f224a6}
services:
cloudfoundry-server:
charm: local:cloudfoundry-server-26
relations: {}
units:
cloudfoundry-server/0:
machine: 1
relations: {}
state: started
In order to be able to connect to the cloudfoundry-server, we need to tell juju to expose (open) the ports specified in the charm ( 80, 443 and 4222 in this case ). Let's do that:
juju expose cloudfoundry-server
juju status should now look similar to this:
2011-09-09 21:46:01,008 INFO Connecting to environment.
machines:
0: {dns-name: ec2-184-73-104-84.compute-1.amazonaws.com, instance-id: i-58f72138}
1: {dns-name: ec2-50-17-173-69.compute-1.amazonaws.com, instance-id: i-c6f224a6}
services:
cloudfoundry-server:
exposed: true
charm: local:cloudfoundry-server-26
relations: {}
units:
cloudfoundry-server/0:
machine: 1
open-ports: [80/tcp, 443/tcp, 4222/tcp]
relations: {}
state: started
2011-09-09 21:46:05,037 INFO 'status' command finished successfully
We should now have ports 80, 443 and 4222 open to the world.
In order to connect to our CloudFoundry server, we need to install ruby-vmc ( available in Ubuntu 11.10 ). Let's install it by typing:
sudo apt-get install ruby-vmc
Once installed, connect to your CloudFoundry server by typing:
vmc target api.<your dns entry here>
ie: vmc target api.cf-host.dyndns.org
Create a user:
vmc add-user --email <some email address> --passwd <some password>
ie: vmc add-user --email 'test@example.com' --passwd 'test'
Deploy DrawBridge
cd drawbridge
vmc push
Would you like to deploy from the current directory? [Yn]: Y
Application Name: drawbridge
Application Deployed URL: 'drawbridge.cf-host.dyndns.org'?
Detected a Node.js Application, is this correct? [Yn]: Y
Memory Reservation [Default:64M] (64M, 128M, 256M, 512M, 1G or 2G)
Creating Application: OK
Would you like to bind any services to 'drawbridge'? [yN]: y
The following system services are available::
1. mongodb
2. mysql
3. redis
Please select one you wish to provision: 2
Specify the name of the service [mysql-ce0c8]:
Creating Service: OK
Binding Service: OK
Uploading Application:
Checking for available resources: OK
Processing resources: OK
Packing application: OK
Uploading (16M): OK
Push Status: OK
Staging Application: OK
Starting Application: OK
cd ..
Open your browser to URL you selected when pushing the app ( in this example: http://drawbridge.cf-host.dyndns.org )
That's all there is to that!! You have deployed CloudFoundry server via Ubuntu Server and Juju and, DrawBridge via vmc and CloudFoundry.
But wait!!! There's more!.
A single cloudfoundry-server is probably not your idea of scalability. Let's deploy a few more scalable components.
Let's add an extra DEA, MySQL node, MongoDB node and Redis node.
cd <directory where your charms are>
juju deploy --repository . cloudfoundry-server-dea
juju deploy --repository . cf-mysql
juju deploy --repository . cf-mongodb
juju deploy --repository . cf-redis
.... and connect them all together with the cloudfoundry-server
juju add-relation cloudfoundry-server cloudfoundry-server-dea
juju add-relation cloudfoundry-server cf-mysql
juju add-relation cloudfoundry-server cf-mongodb
juju add-relation cloudfoundry-server cf-redis
After a few minutes, run juju status again.... It should look something similar to this:
2011-09-09 22:36:40,991 INFO Connecting to environment.
machines:
0: {dns-name: ec2-184-73-104-84.compute-1.amazonaws.com, instance-id: i-58f72138}
1: {dns-name: ec2-50-17-173-69.compute-1.amazonaws.com, instance-id: i-c6f224a6}
2: {dns-name: ec2-107-20-82-210.compute-1.amazonaws.com, instance-id: i-7615c316}
3: {dns-name: ec2-107-20-98-149.compute-1.amazonaws.com, instance-id: i-4e15c32e}
4: {dns-name: ec2-184-72-209-9.compute-1.amazonaws.com, instance-id: i-5815c338}
5: {dns-name: ec2-50-19-63-40.compute-1.amazonaws.com, instance-id: i-0015c360}
services:
cf-mongodb:
charm: local:cf-mongodb-1
relations: {cf-server: cloudfoundry-server, mongodb-cluster: cf-mongodb}
units:
cf-mongodb/0:
machine: 4
relations:
cf-server: {state: up}
mongodb-cluster: {state: up}
state: started
cf-mysql:
charm: local:cf-mysql-1
relations: {cf-server: cloudfoundry-server, mysql-cluster: cf-mysql}
units:
cf-mysql/0:
machine: 3
relations:
cf-server: {state: up}
mysql-cluster: {state: up}
state: started
cf-redis:
charm: local:cf-redis-1
relations: {cf-server: cloudfoundry-server, redis-cluster: cf-redis}
units:
cf-redis/0:
machine: 5
relations:
cf-server: {state: up}
redis-cluster: {state: up}
state: started
cloudfoundry-server:
exposed: true
charm: local:cloudfoundry-server-26
relations: {cf-server: cf-mysql}
units:
cloudfoundry-server/0:
machine: 1
open-ports: [80/tcp, 443/tcp, 4222/tcp]
relations:
cf-server: {state: up}
state: started
cloudfoundry-server-dea:
charm: local:cloudfoundry-server-dea-26
relations: {cf-dea-cluster: cloudfoundry-server-dea, cf-server: cloudfoundry-server}
units:
cloudfoundry-server-dea/0:
machine: 2
relations:
cf-dea-cluster: {state: up}
cf-server: {state: up}
state: started
2011-09-09 22:36:57,701 INFO 'status' command finished successfully
It looks a bit different now doesn't it? :)
Here's what we just did:
- added a new DEA
- added a new MySQL
- added a new MongoDB
- added a new Redis
But wait!!! There's more!.
The newly deployed units can "grow" the deployment as needed. For example:
- juju add-unit cf-mysql
- juju add-unit cf-mongodb
- juju add-unit cf-redis
- juju add-unit cloudfoundry-server-dea
You may have noticed that I haven't gone into any details as to how these charms work ( especially if you have read any of my previous posts ). The idea I am trying to convey here is that with Ubuntu Server and Juju you really don't have to know how CloudFoundry needs to be installed and configured in order to be able to deploy and scale it. Juju charms neatly encapsulate all of the necessary knowledge so you don't have to. That is not to say that you shouldn't or are not able to. These charms are available for download, review, contributions and feedback ( <--- the emphasis means that I would really like comments, contributions and general feedback )
I look forward to your comments/questions and general feedback. Let me know what you think.
-Juan
http://blog.xtremeghost.com
I look forward to your comments/questions and general feedback. Let me know what you think.
-Juan
http://blog.xtremeghost.com