Daniel Watrous on Software Engineering

A Collection of Software Problems and Solutions

Posts tagged openstack

Software Engineering

Kubernetes vs. Docker Datacenter

I found this article on serverwatch today: http://www.serverwatch.com/server-trends/why-kubernetes-is-all-conquering.html

It’s not technically deep, but it does highlight the groundswell of interest for and adoption of kubernetes. It’s also worth noting that GCE and Azure will now both have a native, fully managed kubernetes offering. I haven’t found a fully managed docker datacenter offering, but I’m sure there is one. It would be interesting to compare the two from a public cloud offering perspective.

I’ve worked a lot with OpenStack for on premises clouds. This naturally leads to the idea of using OpenStack as a platform for container orchestration platforms (yes, I just layered platforms). As of today, the process of standing up Docker Datacenter or kubernetes still needs to mature. Last month eBay mentioned that it created its own kubernetes deployment tool on top of openstack: http://www.zdnet.com/article/ebay-builds-its-own-tool-to-integrate-kubernetes-and-openstack/. While it does plan to open source the new tool, it’s not available today.

One OpenStack Vendor, Mirantis, provides support for kubernetes through Murano as their preferred container solution: https://www.mirantis.com/solutions/container-technologies/. I’m not sure how reliable Murano is for long term management of kubernetes. For organizations that have an OpenStack vendor, support like this could streamline the evaluation and adoption of containers in the enterprise.

I did find a number of demo, PoC, kick the tires examples of Docker datacenter on OpenStack, but not much automation or production support. I still love the idea of using the Docker trusted registry. I know that kubernetes provides a private registry component (https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/registry), but it’s not as sophisticated as Docker Trusted Registry in terms of signing, scanning, etc. However, this functionality is quickly making its way into kubernetes, with some functionality already available in alpha: https://github.com/kubernetes/kubernetes/issues/22888

On the whole, I’m more drawn to kubernetes from a wholistic point of view, but Docker is effectively keying into some real enterprise concerns. Given the open source community and vendor investment in kubernetes, I expect the enterprise gap (like a trusted registry for kubernetes) will close this year.

Software Engineering

Do Humans or Machines consume IaaS (REST API)

Infrastructure as a Service, like OpenStack and AWS, have made it possible to consume infrastructure on demand. It’s important to understand the ways in which both humans and machines interact with IaaS offerings in order to design optimal systems that leverage all possible automation opportunities. I drew the diagram below to help illustrate.

terraform-stackato-automation0001

Everything is an API

At the heart of IaaS are REST APIs that provide granular access to every resource type, such as compute, storage and network. These APIs provide clarity about which resources are being managed and accommodate the type of independent evolution of each resource offering that keeps responsibilities focused. APIs include things like Nova for compute on the OpenStack side and EC2 for compute on the AWS side. Other IaaS providers have similar APIs with similar delineations between resource types.

Consume the API RAW

Since REST today is typically done over HTTP and makes use of the HTTP methods and response codes, it is relatively straight forward to use a tool such as curl, fiddler or a REST client to craft individual calls to APIs. This works fine for humans who want to understand the APIs better, but it is slow and doesn’t scale well. Machines (by way of software, obviously) can make those same calls using HTTP request libraries (e.g. python requests, Go http package, Java URLConnection, etc.).

Abstractions

After a couple of hours sending raw requests against the IaaS REST APIs, you’ll be thrilled to know that there are well designed abstractions that provide a more friendly interface to IaaS. The openstack Command Line Interface (CLI) allows you to operate against openstack APIs by typing concise commands at a shell prompt. The Horizon web console provides a web based user experience to manage those same resources. In both cases, the CLI and Horizon console are simply translating your commands or clicks into sequences of REST API calls. This means the ultimate interaction with IaaS is still based on the REST API, but you, the human, have a more human like interface.

Since machines don’t like to type on a keyboard or click on web pages, it makes sense to have abstractions for them too. The machines I’m talking about are the ones we ask to automatically test our code, deploy our software, monitor and scale and heal our applications. For them, we have other abscrations, such including HEAT and terraform. This allows us to provide the machine with a plain text description (often in YAML or similar markup), of what we want our infrastructure to look like. These orchestration tools then analyze the current state of our infrastructure and decide whether any actions are necessary. They then translate those actions into REST API calls, just like the CLI and Horizon panel did for the human. So again, all interaction with IaaS happens by way of the REST API, but the machine too gets an abstraction that humans can craft and read.

Automation is the end goal

Whichever method you pursue, the end goal is to automate as many of the IaaS interactions as possible. The more the machine can do without human interaction, the more time humans have to design the software running on top of IaaS and the more resilient the end system will be to failures and fluctuations. If you find yourself using the human abstractions more than telling machines what to do by way of infrastructure definitions, you have a great opportunity to change and gain some efficiency.

Software Engineering

HEAT or Ansible in OpenStack? Both!

Someone asked me today whether he should use HEAT or Ansible to automate his OpenStack deployment. My answer is that he should use both! It’s helpful to understand the original design decisions for each tool in order to use each effectively. OpenStack HEAT and Ansible were designed to do different things, although in the opensource tradition, they have been extended to accommodate some overlapping functionalities.

Cloud Native

In my post on What is Cloud Native, I show the five elements of application life cycle that can be automated in the cloud (image shown below). The two life cycle elements in blue, provision and configure, correspond to the most effective use of HEAT and Ansible.

application-lifecycle-elements

OpenStack HEAT for Provisioning

HEAT is designed to capture details related to infrastructure and accommodate provisioning of that infrastructure on OpenStack. CloudFormation does the same thing in AWS and Terraform is an abstraction that has providers for both OpenStack and AWS (and many others).

HEAT provides vocabulary to define compute, storage, network and other infrastructure related resources. This includes the interrelationships between infrastructure resources, such as associating floating IPs with compute resources or binding a compute resource to a specific network. This also includes some bookkeeping items, like assigning key pairs for authentication and naming resources.

The end result of executing a heat template is a collection of one or more infrastructure resources based on existing images (VM, or volume).

Ansible for Configuration

Ansible, on the other hand, is designed to configure infrastructure after it has been provisioned. This includes activities like installing libraries and setting up a specific run time environment. System details like firewalls and log management, as well as application stack, databases, etc. are easily managed from Ansible.

Ansible can also easily accommodate application deployment. Activities such as moving application artifacts into specific places, managing users/groups and file permissions, tweaking configuration files, etc. are all easily done in Ansible.

The end result of executing an Ansible playbook is ready-to-use infrastructure.

Where is the Overlap?

Ansible can provision resources in openstack. HEAT can send a cloud-init script to a new server to perform configuration of the server. In the case of Ansible for provisioning, it is not nearly as articulate or granular for the purpose of defining infrastructure as HEAT. In the case of HEAT configuring infrastructure through cloud-init, you still need to find some way to dynamically manage the cloud-init scripts to configure each compute resource to fit into your larger system. I do use cloud-init with HEAT, but I generally find more value in leaving the bulk of configuration to Ansible.

Ansible inventory from HEAT

When using HEAT and Ansible together, it is necessary to generate the ansible inventory file from HEAT output. To accomplish this, you want to make sure HEAT outputs necessary information, like IP addresses. You can use your favorite scripting language to query HEAT and write the inventory file.

Example using both HEAT and Ansible

A while ago I published two articles that showed how I develop the Ansible configuration, and then extend that to work with HEAT for deploying complex, multi-server environments.

Install and configure a Multi-node Hadoop cluster using Ansible

Bulid a multi-server Hadoop cluster in OpenStack in minutes

The first article lays the foundation for deploying a complex system with Ansible. The second article builds on this by introducing HEAT to provision the infrastructure. The Ansible inventory file is dynamically generated using a python script and the OpenStack CLI.

Conclusion

While there is some ambiguity around the term provision in cloud parlance, I consider provision to be the process of creating infrastructure resources that are not generally configured. I refer to configuration as the process of operating against those provisioned resources to prepare them for a specific use case, such as running an application or a database. HEAT is a powerful tool for provisioning resources in OpenStack and Ansible is a great fit for configuring existing infrastructure resources.

Software Engineering

Bulid a multi-server Hadoop cluster in OpenStack in minutes

In a previous post I demonstrated a method to deploy a multi-node Hadoop cluster using Vagrant and Ansible. This post builds on that and shows how to deploy a Hadoop cluster with an arbitrary number of slave nodes in minutes on OpenStack. This process makes use of the OpenStack orchestration layer HEAT to provision the resources, after which Ansible use used to configure those resources.

All the scripts to do this yourself is available on github to clone and fork:
https://github.com/dwatrous/hadoop-multi-server-ansible

I have recorded a video demonstrating the entire process, including scaling the cluster after initial deployment:

Scope

The scope of this article is to create a Hadoop cluster with an arbitrary number of slave nodes, which can be automatically scaled up or down to accommodate changes in capacity as workloads change. The following diagram illustrates this:
hadoop-design-openstack

Build the servers

For convenience, this process still uses Vagrant to create a server that will function as the heat and ansible controller. It’s also possible create a server in OpenStack to fill this role. In this case you could simply use the bootstrap-master.sh script to configure that server. The steps to create the servers in OpenStack using heat are:

  1. Install openstack clients (we do this in a python virtual environment)
  2. Download and source the openrc file from your OpenStack environment
  3. Use the openstack clients to get details about keypairs, images, networks, etc.
  4. Update the heat template for your environment
  5. Use heat to build your servers

Install and Run Hadoop

Once the servers are provisioned, it’s time to install Hadoop. This is done using Ansible and can be run from the same host where heat was used (the vagrant created server in this case). Ansible requires an inventory file to run. Since heat is aware of the server resources it created, I added a python script to request information about provisioned servers from heat and write an inventory file. Any time you update your stack using heat, be sure to run the heat-inventory.py script so Ansible is working against the current state. Keep in mind that if you have a proxied environment, you may need to update group_vars/all.

When the Ansible scripts complete, remember to connect to the master node in openstack. From the Hadoop master node, the same process as before can be followed to start Hadoop and run a job.

Security and Configuration

In this example, a floating IP is attached to every server so the local vagrant server can connect via SSH and configure them. If a server was manually prepared in the same openstack environment, the SSH connectivity could leverage IP addresses on the private network. This would eliminate all but one floating IP address, which is still required for the master node.

Future work might include additional automation to tie together the steps I’ve demonstrated. These can also be executed as part of a CI/CD tool chain for fully automated deployments.

Software Engineering

OpenStack REST API

There are some high quality resources that already cover the OpenStack API, so this is a YEA (yet another example) post. See the resources section below for some helpful links.

OpenStack APIs provide access to all OpenStack components, such as nova (compute), glance (VM images), swift (object storage), cinder (block storage), keystone (authentication) and neutron (networking). Authentication tokens are valid for a fixed duration, after which they expire and must be replaced. Each service requires it’s own token. Services that are hosted on the same logical server are typically accessible over different ports.

OpenStack APIs are RESTful, which means there are many ways to use them. In this post I’ll demonstrate three approaches that should provide clarity into their structure.

  • Command Line Interface (CLI)
  • cURL
  • REST Client

In this post I don’t cover programming against the REST APIs, but instead focus just on how they work. This work builds on my OpenStack development post.

Command Line Interface (CLI)

Command Line Interfaces used to manage OpenStack components make use of the REST APIs behind the scenes: a rather smart design choice on the part of the OpenStack community. This brings consistency to OpenStack management efforts and discourages disparity between standard tooling (CLI) and custom tooling (direct API access).

Credentials are required to access the REST APIs. For the command line client, these credentials are stored as environment variables. If you’re using DevStack, you can use the openrc script to automatically setup your environment.

source openrc admin admin

Some clients support a debug option that will output full details about the request and response cycle. Raw request and response details can be helpful when learning the APIs or creating programmatic access libraries that wrap the APIs. Here’s an example that will list the flavors available.

$ nova --debug flavor-list
REQ: curl -i 'http://openstack.danielwatrous.com:5000/v2.0/tokens' -X POST -H "Accept: application/json" -H "Content-Type: application/json" -H "User-Agent: python-novaclient" -d '{"auth": {"tenantName": "admin", "passwordCredentials": {"username": "admin", "password": "{SHA1}95397c42a173838417806ce19d78f133ae6baa24"}}}'
INFO (connectionpool:258) Starting new HTTP connection (1): proxy.company.com
DEBUG (connectionpool:375) Setting read timeout to 600.0
DEBUG (connectionpool:415) "POST http://openstack.danielwatrous.com:5000/v2.0/tokens HTTP/1.1" 200 6823
RESP: [200] CaseInsensitiveDict({'content-length': '6823', 'proxy-connection': 'Keep-Alive', 'vary': 'X-Auth-Token', 'server': 'Apache/2.4.7 (Ubuntu)', 'connection': 'Keep-Alive', 'date': 'Thu, 21 Aug 2014 19:09:21 GMT', 'content-type': 'application/json'})
RESP BODY: {"access": {"token": {"issued_at": "2014-08-21T19:09:21.692110", "expires": "2014-08-21T20:09:21Z", "id": "{SHA1}99ff604f28f5706bfd82a00c21e099cba7fafab2", "tenant": {"enabled": true, "description": null, "name": "admin", "id": "32c13e88d51e49179c28520f688fa74d"}}, "serviceCatalog": [{"endpoints_links": [], "endpoints": [{"adminURL": "http://openstack.danielwatrous.com:8774/v2/32c13e88d51e49179c28520f688fa74d", "region": "RegionOne", "publicURL": "http://openstack.danielwatrous.com:8774/v2/32c13e88d51e49179c28520f688fa74d", "internalURL": "http://openstack.danielwatrous.com:8774/v2/32c13e88d51e49179c28520f688fa74d", "id": "03d570ce41c04daeb7ffa274c20435f0"}], "type": "compute", "name": "nova"}, {"endpoints_links": [], "endpoints": [{"adminURL": "http://openstack.danielwatrous.com:8776/v2/32c13e88d51e49179c28520f688fa74d", "region": "RegionOne", "publicURL": "http://openstack.danielwatrous.com:8776/v2/32c13e88d51e49179c28520f688fa74d", "internalURL": "http://openstack.danielwatrous.com:8776/v2/32c13e88d51e49179c28520f688fa74d", "id": "20d2caebf4814e1bb2c05f30a4802a2c"}], "type": "volumev2", "name": "cinderv2"}, {"endpoints_links": [], "endpoints": [{"adminURL": "http://openstack.danielwatrous.com:8774/v3", "region": "RegionOne", "publicURL": "http://openstack.danielwatrous.com:8774/v3", "internalURL": "http://openstack.danielwatrous.com:8774/v3", "id": "47f43a622264422f8980f3b0fbac5f00"}], "type": "computev3", "name": "novav3"}, {"endpoints_links": [], "endpoints": [{"adminURL": "http://openstack.danielwatrous.com:3333", "region": "RegionOne", "publicURL": "http://openstack.danielwatrous.com:3333", "internalURL": "http://openstack.danielwatrous.com:3333", "id": "149e00e61cc543cf94ae6162f79d9f00"}], "type": "s3", "name": "s3"}, {"endpoints_links": [], "endpoints": [{"adminURL": "http://openstack.danielwatrous.com:9292", "region": "RegionOne", "publicURL": "http://openstack.danielwatrous.com:9292", "internalURL": "http://openstack.danielwatrous.com:9292", "id": "1b7a45b6d1c840978491250fd1a67204"}], "type": "image", "name": "glance"}, {"endpoints_links": [], "endpoints": [{"adminURL": "http://openstack.danielwatrous.com:8000/v1", "region": "RegionOne", "publicURL": "http://openstack.danielwatrous.com:8000/v1", "internalURL": "http://openstack.danielwatrous.com:8000/v1", "id": "0b8abc323d884a0aa657bcb2f0274ee5"}], "type": "cloudformation", "name": "heat-cfn"}, {"endpoints_links": [], "endpoints": [{"adminURL": "http://openstack.danielwatrous.com:8776/v1/32c13e88d51e49179c28520f688fa74d", "region": "RegionOne", "publicURL": "http://openstack.danielwatrous.com:8776/v1/32c13e88d51e49179c28520f688fa74d", "internalURL": "http://openstack.danielwatrous.com:8776/v1/32c13e88d51e49179c28520f688fa74d", "id": "63675bf8e9a04d199cffafb7b8354b05"}], "type": "volume", "name": "cinder"}, {"endpoints_links": [], "endpoints": [{"adminURL": "http://openstack.danielwatrous.com:8773/services/Admin", "region": "RegionOne", "publicURL": "http://openstack.danielwatrous.com:8773/services/Cloud", "internalURL": "http://openstack.danielwatrous.com:8773/services/Cloud", "id": "520de40a96ea47c4a08c3ae5e0a8243c"}], "type": "ec2", "name": "ec2"}, {"endpoints_links": [], "endpoints": [{"adminURL": "http://openstack.danielwatrous.com:8004/v1/32c13e88d51e49179c28520f688fa74d", "region": "RegionOne", "publicURL": "http://openstack.danielwatrous.com:8004/v1/32c13e88d51e49179c28520f688fa74d", "internalURL": "http://openstack.danielwatrous.com:8004/v1/32c13e88d51e49179c28520f688fa74d", "id": "0dcff3f004ff4c9b9b96d012e47d2edb"}], "type": "orchestration", "name": "heat"}, {"endpoints_links": [], "endpoints": [{"adminURL": "http://openstack.danielwatrous.com:35357/v2.0", "region": "RegionOne", "publicURL": "http://openstack.danielwatrous.com:5000/v2.0", "internalURL": "http://openstack.danielwatrous.com:5000/v2.0", "id": "6f43e35702844e149dde900124c352bf"}], "type": "identity", "name": "keystone"}], "user": {"username": "admin", "roles_links": [], "id": "b9936b16c5d343588f5a19d31a55c1ea", "roles": [{"name": "_member_"}, {"name": "heat_stack_owner"}, {"name": "admin"}], "name": "admin"}, "metadata": {"is_admin": 0, "roles": ["9fe2ff9ee4384b1894a90878d3e92bab", "c28444beb7e64b4ea2ea223a6efcba6a", "3ea10423929b47779f977e11015fe480"]}}}
 
REQ: curl -i 'http://openstack.danielwatrous.com:8774/v2/32c13e88d51e49179c28520f688fa74d/flavors/detail' -X GET -H "Accept: application/json" -H "User-Agent: python-novaclient" -H "X-Auth-Project-Id: admin" -H "X-Auth-Token: {SHA1}99ff604f28f5706bfd82a00c21e099cba7fafab2"
INFO (connectionpool:258) Starting new HTTP connection (1): proxy.company.com
DEBUG (connectionpool:375) Setting read timeout to 600.0
DEBUG (connectionpool:415) "GET http://openstack.danielwatrous.com:8774/v2/32c13e88d51e49179c28520f688fa74d/flavors/detail HTTP/1.1" 200 3337
RESP: [200] CaseInsensitiveDict({'content-length': '3337', 'proxy-connection': 'Keep-Alive', 'x-compute-request-id': 'req-802ef8c9-d4a3-41e5-a93d-7ab2120089db', 'connection': 'Keep-Alive', 'date': 'Thu, 21 Aug 2014 19:09:24 GMT', 'content-type': 'application/json', 'age': '0'})
RESP BODY: {"flavors": [{"name": "m1.tiny", "links": [{"href": "http://openstack.danielwatrous.com:8774/v2/32c13e88d51e49179c28520f688fa74d/flavors/1", "rel": "self"}, {"href": "http://openstack.danielwatrous.com:8774/32c13e88d51e49179c28520f688fa74d/flavors/1", "rel": "bookmark"}], "ram": 512, "OS-FLV-DISABLED:disabled": false, "vcpus": 1, "swap": "", "os-flavor-access:is_public": true, "rxtx_factor": 1.0, "OS-FLV-EXT-DATA:ephemeral": 0, "disk": 1, "id": "1"}, {"name": "m1.small", "links": [{"href": "http://openstack.danielwatrous.com:8774/v2/32c13e88d51e49179c28520f688fa74d/flavors/2", "rel": "self"}, {"href": "http://openstack.danielwatrous.com:8774/32c13e88d51e49179c28520f688fa74d/flavors/2", "rel": "bookmark"}], "ram": 2048, "OS-FLV-DISABLED:disabled": false, "vcpus": 1, "swap": "", "os-flavor-access:is_public": true, "rxtx_factor": 1.0, "OS-FLV-EXT-DATA:ephemeral": 0, "disk": 20, "id": "2"}, {"name": "m1.medium", "links": [{"href": "http://openstack.danielwatrous.com:8774/v2/32c13e88d51e49179c28520f688fa74d/flavors/3", "rel": "self"}, {"href": "http://openstack.danielwatrous.com:8774/32c13e88d51e49179c28520f688fa74d/flavors/3", "rel": "bookmark"}], "ram": 4096, "OS-FLV-DISABLED:disabled": false, "vcpus": 2, "swap": "", "os-flavor-access:is_public": true, "rxtx_factor": 1.0, "OS-FLV-EXT-DATA:ephemeral": 0, "disk": 40, "id": "3"}, {"name": "m1.large", "links": [{"href": "http://openstack.danielwatrous.com:8774/v2/32c13e88d51e49179c28520f688fa74d/flavors/4", "rel": "self"}, {"href": "http://openstack.danielwatrous.com:8774/32c13e88d51e49179c28520f688fa74d/flavors/4", "rel": "bookmark"}], "ram": 8192, "OS-FLV-DISABLED:disabled": false, "vcpus": 4, "swap": "", "os-flavor-access:is_public": true, "rxtx_factor": 1.0, "OS-FLV-EXT-DATA:ephemeral": 0, "disk": 80, "id": "4"}, {"name": "m1.nano", "links": [{"href": "http://openstack.danielwatrous.com:8774/v2/32c13e88d51e49179c28520f688fa74d/flavors/42", "rel": "self"}, {"href": "http://openstack.danielwatrous.com:8774/32c13e88d51e49179c28520f688fa74d/flavors/42", "rel": "bookmark"}], "ram": 64, "OS-FLV-DISABLED:disabled": false, "vcpus": 1, "swap": "", "os-flavor-access:is_public": true, "rxtx_factor": 1.0, "OS-FLV-EXT-DATA:ephemeral": 0, "disk": 0, "id": "42"}, {"name": "m1.heat", "links": [{"href": "http://openstack.danielwatrous.com:8774/v2/32c13e88d51e49179c28520f688fa74d/flavors/451", "rel": "self"}, {"href": "http://openstack.danielwatrous.com:8774/32c13e88d51e49179c28520f688fa74d/flavors/451", "rel": "bookmark"}], "ram": 512, "OS-FLV-DISABLED:disabled": false, "vcpus": 1, "swap": "", "os-flavor-access:is_public": true, "rxtx_factor": 1.0, "OS-FLV-EXT-DATA:ephemeral": 0, "disk": 0, "id": "451"}, {"name": "m1.xlarge", "links": [{"href": "http://openstack.danielwatrous.com:8774/v2/32c13e88d51e49179c28520f688fa74d/flavors/5", "rel": "self"}, {"href": "http://openstack.danielwatrous.com:8774/32c13e88d51e49179c28520f688fa74d/flavors/5", "rel": "bookmark"}], "ram": 16384, "OS-FLV-DISABLED:disabled": false, "vcpus": 8, "swap": "", "os-flavor-access:is_public": true, "rxtx_factor": 1.0, "OS-FLV-EXT-DATA:ephemeral": 0, "disk": 160, "id": "5"}, {"name": "m1.micro", "links": [{"href": "http://openstack.danielwatrous.com:8774/v2/32c13e88d51e49179c28520f688fa74d/flavors/84", "rel": "self"}, {"href": "http://openstack.danielwatrous.com:8774/32c13e88d51e49179c28520f688fa74d/flavors/84", "rel": "bookmark"}], "ram": 128, "OS-FLV-DISABLED:disabled": false, "vcpus": 1, "swap": "", "os-flavor-access:is_public": true, "rxtx_factor": 1.0, "OS-FLV-EXT-DATA:ephemeral": 0, "disk": 0, "id": "84"}]}
 
+-----+-----------+-----------+------+-----------+---------+-------+-------------+-----------+
| ID  | Name      | Memory_MB | Disk | Ephemeral | Swap_MB | VCPUs | RXTX_Factor | Is_Public |
+-----+-----------+-----------+------+-----------+---------+-------+-------------+-----------+
| 1   | m1.tiny   | 512       | 1    | 0         |         | 1     | 1.0         | True      |
| 2   | m1.small  | 2048      | 20   | 0         |         | 1     | 1.0         | True      |
| 3   | m1.medium | 4096      | 40   | 0         |         | 2     | 1.0         | True      |
| 4   | m1.large  | 8192      | 80   | 0         |         | 4     | 1.0         | True      |
| 42  | m1.nano   | 64        | 0    | 0         |         | 1     | 1.0         | True      |
| 451 | m1.heat   | 512       | 0    | 0         |         | 1     | 1.0         | True      |
| 5   | m1.xlarge | 16384     | 160  | 0         |         | 8     | 1.0         | True      |
| 84  | m1.micro  | 128       | 0    | 0         |         | 1     | 1.0         | True      |
+-----+-----------+-----------+------+-----------+---------+-------+-------------+-----------+

The first two sections are calls the REST APIs, first for the keystone service to Authenticate and receive a token. Responses come as JSON due to the Accept header of application/json. If you look closely, you’ll see that the response actually included an access token and entry point URLs for each of the services that are integrated with keystone. These make up the ServiceCatalog and in this case there are ten.

The second section is the actual call to the nova API. In this case it returns a list of eight flavors. The final section is a tabular view of the JSON response created by the nova command line client.

cURL

If you look closely at the debug output of the examples above, you’ll see that the command line clients use cURL to make HTTP requests. We can already see what the authentication call looks like. Calls directly to cURL look similar. For example, here I call the keystone service to get a list of tenants.

$ curl -i -X GET http://openstack.danielwatrous.com:35357/v2.0/tenants -H "User-Agent: linux-command-line" -H "X-Auth-Token: TOKEN"
HTTP/1.1 200 OK
Date: Thu, 21 Aug 2014 20:05:39 GMT
Server: Apache/2.4.7 (Ubuntu)
Vary: X-Auth-Token
Content-Length: 546
Content-Type: application/json
Proxy-Connection: Keep-Alive
Connection: Keep-Alive
 
{"tenants_links": [], "tenants": [{"description": null, "enabled": true, "id": "1b7f733fa1394b9fb96838d3d7c6feea", "name": "service"}, {"description": null, "enabled": true, "id": "298cfcec9e9e49858e9b8e83d6b7d14e", "name": "demo"}, {"description": null, "enabled": true, "id": "32c13e88d51e49179c28520f688fa74d", "name": "admin"}, {"description": null, "enabled": true, "id": "8536da0aee8149d48e1fe6078dade4bf", "name": "alt_demo"}, {"description": null, "enabled": true, "id": "e66e6a80a6014dd28c7b4c1fcad19448", "name": "invisible_to_admin"}]}

REST Client

On Windows, the tool Fiddler can be used to create REST calls. When fiddler is first started, you may need to turn off capturing of traffic. You can do this from the File menu or by pressing F12. In the right side of the window, choose the composer tab. There you can provide the URL, headers and other HTTP request details. Below you can see a call to Keystone for tokens.

openstack-rest-api-fiddler-1

The response can be viewed by selecting the resulting request in the left pane and choosing the Inspectors tab in the right pane. The results can be viewed raw, as shown here.

openstack-rest-api-fiddler-2

Fiddler also provides various parsers, including JSON, to make the content easier to visualize.

openstack-rest-api-fiddler-3

Resources

The quality of the documentation available for OpenStack APIs is really amazing. Here are a couple of starting points for you.

http://developer.openstack.org/
http://docs.openstack.org/api/quick-start/content/

Software Engineering

OpenStack Development using DevStack

I’ve been sneaking up on CloudFoundry for a few weeks now. Each time I try to get a CloudFoundry test environment going I find a couple more technologies that serve either as foundation or support to CloudFoundry. For example, Vagrant, Ansible and Docker all feed into CloudFoundry. Today I come to OpenStack, by way of DevStack (see resources below for more links).

Objectives

My objectives for this post are get OpenStack up and running by way of DevStack so that I can begin to explore the OpenStack API. CloudFoundry uses the OpenStack API to provision new VMs, so understanding the API is essential to troubleshooting CloudFoundry issues.

Some deviations from out of the box DevStack include:

  • Enable higher overcommit allocation ratios
  • Add Ubuntu image for new VMs
  • Remove quotas

Environment

For these experiments I am using a physical server with 8 physical cores, 16GB RAM and 1TB disk. The host operating system is Ubuntu 14.04 LTS. I’m following the DevStack instructions for a single machine. It may be possible to duplicate these experiments in a Vagrant environment, but the nested networking and resource constraints for spinning up multiple guests would muddle the effort.

Configuration

DevStack looks for a local.conf in the same directory as the stack.sh script. This makes it possible to override default settings for any of the OpenStack components that will be started as part of the DevStack environment.

Passwords for Quick Resets

I found that I was frequently unstack.shing and clean.shing and stack.shing. To speed up this process I added the following lines to my local.conf to set passwords with default values. This prevented the prompts for these values so the script would run without any input.

[[local|localrc]]
ADMIN_PASSWORD=secret
MYSQL_PASSWORD=$ADMIN_PASSWORD
RABBIT_PASSWORD=$ADMIN_PASSWORD
SERVICE_PASSWORD=$ADMIN_PASSWORD
SERVICE_TOKEN=$ADMIN_PASSWORD

Networking

I also included some networking defaults. NOTE: Even though I show [[local|localrc]] again in the snippet below, there is only one such section, so the values can be added to the above if you decide to use them.

[[local|localrc]]
FLOATING_RANGE=192.168.1.224/27
FIXED_RANGE=10.11.12.0/24
FIXED_NETWORK_SIZE=256
FLAT_INTERFACE=eth0
GIT_BASE=${GIT_BASE:-https://git.openstack.org}
VOLUME_BACKING_FILE_SIZE=200G

As always, you may have to handle proxy environment variables for your network. Some features of OpenStack may require local non-proxy access, so remember to set the no_proxy parameter for local traffic.

The line about GIT is to accommodate some environments where git:// protocols are blocked. This allows GIT to operate over HTTPS, which can leverage proxy settings.

The last line about the VOLUME_BACKING_FILE_SIZE is to allocate more space to cinder to create volumes (we’ll need this to work with CloudFoundry in the future).

Add Ubuntu Image

The IMAGE_URLS parameter accepts a comma separated list of images to pre-load into OpenStack. Ubuntu publishes many cloud images for ease of inclusion into OpenStack.

[[local|localrc]]
IMAGE_URLS="https://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-amd64-disk1.img,http://download.cirros-cloud.net/0.3.2/cirros-0.3.2-x86_64-disk.img,http://download.cirros-cloud.net/0.3.2/cirros-0.3.2-x86_64-uec.tar.gz"

Logging in DevStack

The Linux screen command allows multiple shell commands to be running at the same time and to survive a terminal exit. Adding the command below collects all log output into a single directory. This can be extremely helpful when troubleshooting.

[[local|localrc]]
SCREEN_LOGDIR=$DEST/logs/screen

The default location for $DEST is /opt/stack.

Overcommitting

OpenStack makes it easy to overcommit physical resources. This can be a valuable tool to increase hardware utilization, especially when loads are unevenly distributed. Setting the allocation ratios for CPU, RAM and DISK affects the nova scheduler. CPU is the most safely overcommitted, which RAM coming up next and DISK last. A post-config on the nova.conf file can be accomplished by adding the snippet below to local.conf.

[[post-config|$NOVA_CONF]]
[DEFAULT]
cpu_allocation_ratio = 16.0
ram_allocation_ratio = 4.0
disk_allocation_ratio = 1.0

Running DevStack

With a local.conf all set, OpenStack can be started and reset using the following DevStack commands from within the devstack directory.

./stack.sh
./unstack.sh
./clean.sh

Access OpenStack

At this point you should have a running OpenStack server. Depending on the IP address or DNS settings, you should be able to access it with a URL similar to the following:

http://openstack.yourdomain.com/auth/login/

Which should look something like this:

openstack-login

Remember that the credentials are whatever you set in your local.conf file (see above).

Troubleshooting

On a couple of occasions, unstack.sh and clean.sh were unable to properly reset the system and a subsequent stack.sh failed. In those cases it was necessary to manually remove some services. I accomplished this by manually calling apt-get remove package followed by apt-get autoremove. On one occasion, I finally tried a reboot, which corrected the issue (a first for me on Linux).

It’s very possible that I could have cycled through the running screen sessions or spent more time in the logs to discover the root cause.

Create and Use VMs

With a running OpenStack environment, we can now create some VMs and start testing the API. Security groups and key pairs can make it easy to work with newly created instances. You can manage both by navigating to Project -> Compute -> Access & Security -> Security Groups.

Create a Security Group

The first thing to do is add a security group. I called mine “standard”. After adding the security group, there is a short delay and then a new line item appears. Click “Manage Rules” for that line item.

I typically open up ICMP (for pings), SSH(22), HTTP(80) and HTTPS(443). This is what the rules look like.

openstack-security-group-rules

Key Pairs

Key pairs can be managed by navigating to Project -> Compute -> Access & Security -> Key Pairs. All you have to do is click “Create Key Pair”. Choose a name that represents where you’ll use that key to gain access (such as ‘laptop’ or ‘workstation’). It will then trigger a download of the resulting pem file.

If you have a range of IP addresses that will allow off box access to these hosts, they you can use puttygen to get a version of the key that you can import into putty, similar to what I did here.

Otherwise, the typical use case will require uploading the pem file to the host where you are running OpenStack. I store the file in ~/.ssh/onserver.pem. Set the permissions to 400 on the pem file.

chmod 400 ~/.ssh/onserver.pem

Remove Quotas (optional)

You can optionally disable quotas so that an unlimited number of VMs of any size can be created (or at least up to the allocation ratio limits). This is done from the command line using the nova client. First you set the environment so you can fun the nova client as admin. Then you identify the tenant and finally call quota-update to remove the quotas. From the devstack folder, you can use these commands.

stack@watrous:~/devstack$ source openrc admin admin
stack@watrous:~/devstack$ keystone tenant-list
+----------------------------------+--------------------+---------+
|                id                |        name        | enabled |
+----------------------------------+--------------------+---------+
| 14f42a9bc2e3479a91fb163807767dbc |       admin        |   True  |
| 88d670a4dc714e8b982b3ee8f7a95554 |      alt_demo      |   True  |
| 6c4be67d187c4dcab0fba70d6a004021 |        demo        |   True  |
| 5d1f69d120514caab75bcf27a202d358 | invisible_to_admin |   True  |
| 422e13e213e44f08a79f64440b56ee5c |      service       |   True  |
+----------------------------------+--------------------+---------+
stack@watrous:~/devstack$ nova quota-update --instances -1 --cores -1 --ram -1 --fixed-ips -1 --floating-ips -1 6c4be67d187c4dcab0fba70d6a004021

NOTE: Quotas can also be managed through the web interface as part of a project. When logged in as admin, navigate to “Admin -> Identity -> Projects”. Then for the project you want to update, click “More -> Modify Quotas”. Quotas will have to be modified for each project individually.

Launch a New Instance

Finally we can launch a new instance by navigating to Project -> Compute -> Instances and clicking the “Launch Instance” button. There are four tabs on the Launch Instance panel. The “Details” tab provides options related to the size of the VM and the image used to create it. The Access & Security tab makes it possible to choose a key pair to be automatically installed as well as any security groups that should apply.

openstack-launch-instance-details

openstack-launch-instance-access-security

You can see any running instances from the Instances view, including an assigned IP address to access the server. This should be on a private network and is based on the networking parameters you provided in local.conf above. If you have public IP addresses, you can assign those and perform other maintenance on your instance using the “More” menu for that instance line item, as shown here.

openstack-launch-instance-more

Connect to the Instance

Connect to the new instance from the host system by using the “-i” option to ssh to connect without needing a password.

ssh -i ~/.ssh/onserver.pem ubuntu@10.11.12.2

openstack-connect-instance

Connect to the Internet from Guests

Networking is complicated in OpenStack. The process I have outlined in this post sets up DevStack to use nova-network. In order to route traffic from guests in OpenStack and the internet, iptables needs to be updated to handle masquerading. You can typically do this by running the command below on the OpenStack host (not the guest).

sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

Depending on your setup, you may need to set this on eth1 instead of eth0 as shown.

NOTE: This iptables command is transient and will be required on each boot. It is possible to make iptables changes persistent on Ubuntu.

Comments

Networking remains the most complicated aspect of OpenStack to both manage and simulate for a development environment. It can feel awkward to have to connect to all instances by way of the host machine, but it greatly simplifies the setup. Everything is set now to explore the API.

Resources and related:

http://www.stackgeek.com/blog/kordless/post/taking-openstack-for-a-spin
http://docs.openstack.org/grizzly/openstack-image/content/ch_obtaining_images.html
http://docs.openstack.org/user-guide/content/dashboard_create_images.html
http://askubuntu.com/questions/471154/how-to-import-and-install-a-uec-image-on-openstack