It’s probably a good idea to be familar with a few core Chef concepts, though digging deeply into Chef is definitely not something I encourage Python developers to do.
Resource: The basic building block in Chef (and also Ansible); defines files, directories, installed packaes, services, etc.
Recipe: A collection of resource definitions with some logic to connect them. These can be very simple or extraordinarily complex; A recipe can depend on other recipes. These basically play the same role as
Cookbook: A collection of recipes required to setup a service or similar. These play a similar role to
Rolesin Ansible. These generally can be found in the Chef Supermarket like Roles from the Ansible Galaxy.
Berkshelf: A single file configuration defining the set of cookbooks needed for a deployment. It consists of a
Berksfilewhich defines locations and versions of all cookbooks required for a deployment.
Attributes: The deployment specific configuration for the cookbook and recipes. This is essentially a collection of JSON like primitives, similar to YAML group/host
Amazon Opsworks takes this basic configuration framework and provides its own set of concepts, to implement cluster orchestration. When using Opsworks, you will be making use built-in Opsworks Chef Cookbooks provided by Amazon. These built-in Cookbooks provide a number of Recipes for configuring and deploying many types of applications using simple TTW configuration from the Opsworks control panel. These include Node.js, Rails, PHP, and Java applications, but not Python [*].
I’ve created a couple supplemental Cookbooks that extend the existing Opsworks deployment recipes to support Python and Plone along with other supporting services that are useful when making production deployments of Plone.
Opsworks has its own vocabulary of concepts related to deploying and orchestrating clusters of servers. The building blocks of Opsworks are:
Stack: The fundamental container for your configuration, this lives in a particular EC2 region and contains all the configuration for your cluster. Typically you would have a separate production stack and development stack. Creating this is the first step in the process of defining your cluster. Stacks can be cloned to replicate configuration across regions.
Layers: A Layer defines a discrete set of functionality that may be provided by a server Instance. For example, a Plone cluster may have a front end Layer running an Nginx web server, Varnish proxy cache and HAProxy load balancer [†] , an Application Layer for your ZEO client instances, an Application Layer for your ZEO server, and a maintenance layer to manage database backups and packs. Layers define what recipes will be run on an instance, and which OS packages it requires, along with any Amazon resources and permssions are required to provide a service (e.g. static IP addresses, additional EBS storage volumes).
Instances: An OpsWorks Instance is similar to an EC2 instance, it has a type (e.g. from micro to xlarge), an OS and an Availability Zone, but it is an abstraction. It becomes an actual EC2 instance once it’s been started, but before that it’s simply a metadata about a desired server. Instances are assigned to one or more Layers, and come in three varieties, 24/7, time-based and load-based.
Apps: An App points to a code repository (in our case a buildout) which you want to deploy to a specific Application Layer. Typically you would have an App for your Plone instances and another for your Zeoserver. Both these Apps would typically point to the same buildout repository. You might also create an App to configure a Plone specific Solr server or to run a additional applications within the cluster.
Resources: A set of Amazon EC2 resources that will be used by the stack by being attached/assigned to Instances when they are started. These include Elastic IP addresses, EBS storage volumes and RDS databases (useful you are running Relstorage).
A Stack can be configured with a single Instance running all the Layers, or multiple Instances each running different Layers. You might, for example, have a production stack with five Instances running the Plone ZEO client Application Layer, a single instance running the ZEO server Application Layer, and two Instances running the front end proxy/loadbalancer Layer (with an Elastic Load Balancer in front of those). You might also have a staging stack with all the same Layers applied to a single modest server. Other than the Instance definitions (and perhaps the App repository branch), these Stacks would be essentially identical.
|[†]||Though you could separate each of these front end services into their own layers if you really wanted to, we combine them by default under a customized HAProxy layer which already provides a nice UI for a few HAProxy features.|
Each Opsworks Instance goes through a few phases during its lifecycle:
Each of these lifecycle phases runs recipes assigned to that phase in the assigned Layers. When these recipes are run, the Stack configuration is passed to the server. This configuration includes complete information about the state of the entire Stack and all of its running Instances.
When an Instance starts, it first goes through a
setup phase: installing
all package dependencies for all assigned Layers and running all the recipes
assigned to the
setup phase of those Layers.
setup phase is complete, a
deploy phase is automatically
started. running all the recipes assigned to the
deploy phase of any
assigned Layers. Subsequently, you may manually run a
deploy for a
specific Application on any or all of the instances to update the application
code and reconfigure services.
shutdown phase is run automatically before an instance is stopped.
undeploy phase is rarely used. It is triggered when an application is
manually removed from an instance.
Whenever an Instance is started or stopped and it’s
phase has completed a
configure phase is initiated on all running
instances. As with all recipe runs, the
configure phase recipes are passed
data about all the curently running Instances and their Layers so that they
can automatcially reconfigure themselves based on the updated state of the
Stack. For example, a load balancer may need to automatically add or remove
Plone ZEO clients from it’s list of active backends, a ZEO client may need to
change its ZEO server or its Relstorage Memcache if configuration for those
services have changed.
configure phase, during which the current cluster state is
automatically shared with all the instances, is where the orchestration magic