How to deploy an app in an OpenStack instance with Ruby and Fog

Now that you know how to create and destroy instances, you can deploy the sample application. The instance that you create for the application is similar to the first instance that you created, but this time, we’ll briefly introduce a few extra concepts.

Note

Internet connectivity from your cloud instance is required to download the application.

When you create an instance for the application, you’ll want to give it a bit more information than you supplied to the bare instance that you just created and destroyed. We’ll go into more detail in later sections, but for now, simply create the following resources so that you can feed them to the instance:

  • A key pair. To access your instance, you must import an SSH public key into OpenStack to create a key pair. OpenStack installs this key pair on the new instance. Typically, your public key is written to .ssh/id_rsa.pub. If you do not have an SSH public key file, follow these instructions first.

In the following example, pub_key_file should be set to the location of your public SSH key file.

key_pair_name = "demokey"

pub_key_file = "~/.ssh/id_rsa.pub"

puts "Checking for existing SSH keypair"

for pair in conn.key_pairs.all()
    if pair.name == key_pair_name
        key_pair = pair
        puts "Key pair \"" + key_pair.name + "\" exists, skipping
import"
        break
    end
end

if not key_pair
    puts "Uploading keypair from ~/.ssh/id_rsa.pub"
    key_file = File.open(File.expand_path(pub_key_file))
    public_key = key_file.read
    key_pair = conn.key_pairs.create :name => key_pair_name,
                                     :public_key => public_key
end

  • Network access. DreamCompute has a default security group that will work for our purposes. If you want, you can create another security group by following along below. This security group allows HTTP and SSH access.
for security_group in conn.security_groups.all
    if security_group.name == 'all-in-one'
        all_in_one_security_group = security_group
        break
    end
end

if not all_in_one_security_group
    conn.create_security_group 'all-in-one',
                               'network access for all-in-one application.'
    for security_group in conn.security_groups.all
        if security_group.name == 'all-in-one'
            all_in_one_security_group = security_group
            break
        end
    end

    conn.security_group_rules.create :ip_protocol => 'TCP',
                               :from_port => 22,
                               :to_port => 22,
                               :parent_group_id => all_in_one_security_group.id
    conn.security_group_rules.create :ip_protocol => 'TCP',
                               :from_port => 80,
                               :to_port => 80,
                               :parent_group_id => all_in_one_security_group.id
end

  • User data. During instance creation, you can provide user data to OpenStack to configure instances after they boot. The cloud-init service applies the user data to an instance. You must pre-install the cloud-init service on your chosen image.
userdata = "#!/usr/bin/env bash
curl -L -s https://git.openstack.org/cgit/openstack/faafo/plain/contrib/install.sh \
| bash -s -- \ -i faafo -i messaging -r api -r worker -r demo"

Now, you can boot and configure the instance.

Boot and configure an instance

Use the image, flavor, key pair, and userdata to create an instance. After you request the instance, wait for it to build.

puts "Checking for existing instance"
for server in conn.servers.all
    if server.name == instance_name
        instance = server
        break
    end
end

if not instance
    puts "No test instance found, creating one now"
    instance = conn.servers.create :name => instance_name,
                              :flavor_ref => flavor.id,
                              :image_ref => image.id,
                              :key_name => key_pair.name,
                              :user_data => userdata,
                              :security_groups => all_in_one_security_group
end

until instance.ready?
    for server in conn.servers
        if server.name == instance.name
            instance = server
            break
        end
    end
end

When the instance boots, the ex_userdata variable value instructs the instance to deploy the Fractals application.

Associate a floating IP for external connectivity

To see the application running, you must know where to look for it. By default, your instance has outbound network access. To make your instance reachable from the Internet, you need an IP address. By default in some cases, your instance is provisioned with a publicly rout-able IP address. In this case, you’ll see an IP address listed under public_ips or private_ips when you list the instances. If not, you must create and attach a floating IP address to your instance.

puts "Checking for unused Floating IP..."
for address in conn.addresses.all()
    if not address.instance_id
        ip_address = address
        puts "Unused IP " + ip_address.ip + " found, it will be used
    instead of creating a new IP"
        break
    end
end

if not ip_address
    puts "Allocating new Floating IP"
    ip_address = conn.addresses.create()
end

This will get an ip address that you can assign to your instance with:

if instance.public_ip_addresses.length > 0
    puts "Instance already has a floating IP address"
else
    instance.associate_address(ip_address.ip)
end

Run the script to start the deployment.

Access the application

Deploying application data and configuration to the instance can take some time. Consider enjoying a cup of coffee while you wait. After the application deploys, you can visit the awesome graphic interface at the following link by using your preferred browser.

puts "Fractals app will be deployed to http://#{ip_address.ip}"

Note

If you do not use floating IPs, substitute another IP address as appropriate

screenshot of the webinterface

Complete code sample

The following file contains all of the code from this section of the tutorial. This comprehensive code sample lets you view and run the code as a single script.

Before you run this script, confirm that you have set your authentication information, the flavor ID, and image ID.

# step-1
require 'fog'

auth_username = 'your_auth_username'
auth_password = 'your_auth_password'
project_name = 'your_project_name_or_id'
auth_url = 'https://keystone.dream.io'
region_name = 'RegionOne'

conn = Fog::Compute.new({
    :provider            => 'openstack',
    :openstack_auth_url  => auth_url + '/v2.0/tokens',
    :openstack_username  => auth_username,
    :openstack_tenant    => project_name,
    :openstack_api_key   => auth_password,
})

# step-2
images = conn.images.all
print images

# step-3
flavors = conn.flavors.all
print flavors

# step-4
image_id = '90d5e049-aaed-4abc-aa75-60c2b1ed6516'
image = conn.images.get image_id
print image

# step-5
flavor_id = '100'
flavor = conn.flavors.get flavor_id
print flavor

# step-6
instance_name = 'testing'
testing_instance = conn.servers.create(:name => instance_name,
                                       :flavor_ref => flavor.id,
                                       :image_ref => image.id)

# step-7
print conn.servers

# step-8
testing_instance.destroy

# step-9
key_pair_name = "demokey"

pub_key_file = "~/.ssh/id_rsa.pub"

puts "Checking for existing SSH keypair"

for pair in conn.key_pairs.all()
    if pair.name == key_pair_name
        key_pair = pair
        puts "Key pair \"" + key_pair.name + "\" exists, skipping
import"
        break
    end
end

if not key_pair
    puts "Uploading keypair from ~/.ssh/id_rsa.pub"
    key_file = File.open(File.expand_path(pub_key_file))
    public_key = key_file.read
    key_pair = conn.key_pairs.create :name => key_pair_name,
                                     :public_key => public_key
end

# step-10
for security_group in conn.security_groups.all
    if security_group.name == 'all-in-one'
        all_in_one_security_group = security_group
        break
    end
end

if not all_in_one_security_group
    conn.create_security_group 'all-in-one',
                               'network access for all-in-one application.'
    for security_group in conn.security_groups.all
        if security_group.name == 'all-in-one'
            all_in_one_security_group = security_group
            break
        end
    end

    conn.security_group_rules.create :ip_protocol => 'TCP',
                               :from_port => 22,
                               :to_port => 22,
                               :parent_group_id => all_in_one_security_group.id
    conn.security_group_rules.create :ip_protocol => 'TCP',
                               :from_port => 80,
                               :to_port => 80,
                               :parent_group_id => all_in_one_security_group.id
end

# step-11
userdata = "#!/usr/bin/env bash
curl -L -s https://git.openstack.org/cgit/openstack/faafo/plain/contrib/install.sh \
| bash -s -- \ -i faafo -i messaging -r api -r worker -r demo"

# step-12
puts "Checking for existing instance"
for server in conn.servers.all
    if server.name == instance_name
        instance = server
        break
    end
end

if not instance
    puts "No test instance found, creating one now"
    instance = conn.servers.create :name => instance_name,
                              :flavor_ref => flavor.id,
                              :image_ref => image.id,
                              :key_name => key_pair.name,
                              :user_data => userdata,
                              :security_groups => all_in_one_security_group
end

until instance.ready?
    for server in conn.servers
        if server.name == instance.name
            instance = server
            break
        end
    end
end

# step-13
puts "Checking for unused Floating IP..."
for address in conn.addresses.all()
    if not address.instance_id
        ip_address = address
        puts "Unused IP " + ip_address.ip + " found, it will be used
    instead of creating a new IP"
        break
    end
end

if not ip_address
    puts "Allocating new Floating IP"
    ip_address = conn.addresses.create()
end

# step-14
if instance.public_ip_addresses.length > 0
    puts "Instance already has a floating IP address"
else
    instance.associate_address(ip_address.ip)
end

# step-15
puts "Fractals app will be deployed to http://#{ip_address.ip}"

Did this article answer your questions?

Article last updated .