Hi Angus,
Nice job on kicking off this thread ... we're definitely getting somewhere :)
On Wed, 2011-05-11 at 21:37 +0100, Angus Thomas wrote:
Below is a sketch of how we can approach adding support for services, with the goal of reaching a basic, functional implementation as soon as possible, given that we have few development iterations left before Cloud Engine ships.
Firstly, the services themselves: They will be implemented as:
You've laid out a design, but I'm having to guess at the thinking which lead to the design.
From your follow on mail, it sounds like the idea is that we want to
avoid baking puppet manifests into the template so that you don't end up with an image for each trivial revision of the service definition?
Taking a step back for minute, my understanding of what we're trying to achieve here is:
Template/service authors are distinct from self-service users - they create the content that is available to users defining a deployable.
Template authors want to allow users to configure certain aspects of the template at instantiation time - e.g. a template author may want to allow users to configure the timezone of the instance when defining a deployable
Template authors want to allow users to enable certain optional functionality with certain parameters at instantiation time - e.g. a template author may want to allow users to enable a mail server when defining a deployable
Derived from that, we need to:
- Allow users to choose from the set of templates templates, and the services available for those templates, in the "define a deployable" UI
- Allow users to define values for the template and service parameters in that UI
- Provide template authors with tools to define/test/register templates and services with conductor
- A packagegroup in pulp which includes the packages which the
implementation of the service requires
So, template authors define a new package group when creating a service which encapsulates the packages needed by the service?
- A set of puppet scripts to be executed on the instance at launch
(The puppet scripts will be deployed from the configuration server that all newly-launched instances will connect to)
To simplify what we're seeking to build, we can define services in the context of a deployable only.
So, templates won't be built for specific services. Users can define templates with one, or several, purposes in mind and will choose the packages that they want to include on that basis. When the user is deciding which packages to include in a template, they'll have the option of including the packagegroups that defines the requirements for particular services, to ensure that their template is capable of supporting those services.
Right, so the template and service authors are the same person.
And that author is describing the services that a template may provide by specifying package groups which includes the packages needed for each service.
We don't need to add any functionality for services at the assembly level.
At the deployable level, users will select the number of instances of various templates that they wish to launch, and then will associate services with each instance of a template. If the user assigns a service to a template that wasn't explicitly built to include the services' packagegroup the UI will show a warning that the template *may not* contain the packages to support the service, and the user will have the option to amend the template to make sure.
If the user is confident that the template does include the dependencies for the service, they'll carry on.
This is where things get messy, to my mind. The template author has described which services the template provides, but now we're playing a kind of guessing game to match all the available services (including ones which the template author didn't consider) against the packages in the template.
When preparing to launch the deployable, the user will prime the configuration server with the specific parameters to pass to the launched instances, along with the puppet scripts.
The instances will launch, receive the puppet scripts and parameters for the configuration server, and enable the services.
To give a use case:
A user wants to host php web apps, which connect to a mysql DB server. There are some one-off tasks before they can launch any deployables:
- Define a service which
-- Lists mysql as a package dependency
-- Contains a puppet script to enable mysqld and create an initial set of users, tables, constraints etc.
- Define a service that
-- Lists httpd, mod_ssl & php as required packages
-- Contains a puppet script which enable the httpd service, configure php's connection to a mysql instance and "git pull" the latest php files from the release branch of the developer's repo
- Define a template that includes httpd, mod_ssl, php & mysql, either by
listing those packages explicity or by referring to the two services above. The effect is the same in either case.
Having done those things, the following tasks are required to launch a deployable:
Pull two instances of the template into the deployable
Set one instance to provide the mysqld service,
Set one instance to provide the httpd/service
Supply the parameters that each puppet script requires, which define
the URL of the git repo to check out the php pages, the IP & credentials for the DB connection etc.
Nice use case, that tallies with my thinking.
- Launch.
The same template and service definition scripts would support deploying a range of web apps, or the same app to multiple hosts. With the addition of another service definition script the same template could support multiple DB instances for high availability etc..
So, this is another template/service author who just wants to take an existing template and allow it to offer another service, which happens to only require packages which are already in the template (perhaps because they were required by another service).
And you want to avoid a rebuild of the image where no packages are required to be installed.
<lame>This seems like premature optimization to me.</lame> :-)
Seriously, I'd like us to allow for this, but not by changing how template authors or users think about services e.g.
- When including a template in a deployable, I'd like users to only see services which the template author deemed suitable for the template.
- Adding new services to that list is a job for a template author, even if that is a template author specializing another template author's template.
- There should only be one workflow for adding new services to a template, and the system should optimize away unnecessary image builds.
- The template author shouldn't need to worry too much about image builds - i.e. when writing the puppet manifest for a new service, the template author might write:
package { 'postfix': ensure => installed }
Do we want the template author to do things one way if image builds already includes postfix and another way if it doesn't?
I think we have a lot of work to do in order to make life bearable for template authors. We need to make it easy to:
- do quick modify/test iterations on both the template itself and its services
- re-build and test images as relevant package updates become available
- purge old builds when they're no longer in use by existing instances and not interesting for new instances
- ...
- add new services without a re-builds where the image already includes the necessary packages
i.e. the last one wouldn't be highest on my list
Cheers, Mark.