Deploying Apps Using Manifests

An application manifest is a plain text file that defines a set of deployment attributes, such as:

  • Application (and package) name
  • Maximum memory allocation
  • Namespace
  • Number of instances to start on app creation
  • Staging pipeline to use
  • Runtime template to call

You use a manifest in place of some or all of the flags you would otherwise specify on the command line when you create an app. Using a manifest file is the preferred approach for creating and deploying apps because it allows you to script easily reproducible deployment settings.

Writing a manifest

To write a manifest, you create a plain text file named continuum.conf with the desired attributes, and save it in the working directory of your app. The manifest below specifies deployment settings for a Ruby app named sample-ruby-manifest.

name: "sample-ruby-manifest"
namespace: "/"
instances: 2
staging_pipeline: "/apcera::ruby"
start_cmd: "bundle exec rackup config.ru -p $PORT"
resources {
  memory: "512MB"
  network_bandwidth: "100Mbps"
}
start: true

When you deploy the app with this manifest, Apcera does the following:

  • Names the app "sample-ruby-manifest"
  • Creates the app in the root namespace
  • Creates two instances of the app
  • Uses the "ruby" staging pipeline
  • Uses the specified command to start the app
  • Exposes port 0 (default port setting)
  • Assigns the route http:\\sample-ruby-manifest.<domain> (default route setting)
  • Allocates resources to the app: 512MB RAM and 100Mbps network bandwidth
  • Starts the app on successful creation

Refer to the manifest tutorial for an end-to-end app deployment using a manifest.

Considerations for writing and using manifest files

When you write and use manifest files, keep in mind the following considerations:

  • By default, APC looks for a manifest file named continuum.conf in the working directory of your app. If the continuum.conf manifest is not in the app working directory, during app creation you must specify the file path to the manifest using the --config flag. For example:

    apc app create --config /path-to-manifest/continuum.conf

  • You can use a manifest file with commands apc app create and apc app deploy (with some limitations). You can also use a manifest with apc app delete to delete an app, where the name of the app in the manifest file. You can specify the path to the manifest file the same as you do when creating an app from manifest.

  • Any flags you specify on the command line take precedence over those parameters in the manifest file. If an attribute required by apc app create is not provided by either the manifest or a command-line argument, app creation will fail.

  • Make sure you use a good plain text editor to author manifest files, such as Atom or Sublime. Word processing applications use embedded characters (such as Smart Quotes) that can get included in the app name or other attribute values requiring quotes.

Currently, the type of manifest file discussed in this page only supports a single app per manifest file.

Manifest attributes

The following table lists and describes all attributes you can specify in a manifest, as well as the default setting for each attribute. Also see the sample manifest.

Not every attribute is recognized by the apc app deploy command, though; these attributes are marked with an * in the following table. This is a current limitation of that command.

Attribute Description Data Type Default
name Application (and package) name. string None
namespace Namespace in which the app will be created or deployed. string Current namespace
instances * Number of app instances to start on creation or deployment. int 1
staging_pipeline Staging pipeline to use when staging the app. string Auto-detect
path Path to the app. If unset and not in the current working directory, APC will prompt. string Current working directory
start_cmd Command Apcera will call to start the app. The start command process is expected to run in the foreground for the lifetime of the application. If the specified process exits, or is run as a background process, the platform will assume the job has errored and tear it down. string Auto-detect based on the framework used
resources * Resources allocated to the app, including:
cpu calculated in ms/s
disk_space in MB
memory in MB
network_bandwidth in Mbps
map
cpu: 0 (uncapped)
disk_space: 1GiB
memory: 256MiB
network_bandwidth: 5Mbps
package_dependencies Instruct the Package Manager what packages to resolve for a fully-functioning app. You can specify os, package, and runtime versions, or let the stager detect. array None, stager picks for you
ports * An array of ports exposed on the job. Each port object must include a number field that specifies the port at which the job is listening. By default, if nothing is listening at an exposed port then Apcera assumes the job is not functioning normally and will mark it as being unhealthy. To prevent this include optional: true in the port definition. A route may be added per-port. Each route is of a type corresponding to the router that picks it up, either "tcp" or "http". For each route you specify the endpoint and optionally a route weight which determines how much traffic is delivered to the route, between 0 and 100. Note that TCP routes can be IP address format only. array > map Port number "0" is exposed of type "http" for endpoint "app-name.domain". The optional property defaults to false.
allow_egress * If true, this attribute grants full outbound network traffic to the app. boolean False
disable_routes * Boolean flag to disable routes, useful for non-webapps. boolean False
env * Environment variables for the app; names must be enclosed in quotes. map None
package_env * Environment variables to set on the application package; names must be enclosed in quotes. map None
services * Services to create and bind to the app. Providers must be registered prior to app creation. If implemented, the elements are provider_name (optional), type, and service_name. See services below. array > map None
stager_options Specifies services required by stagers (in a staging pipeline); provide a service name if the service should be persisted, otherwise ephemeral. Use for stagers that must consume services while staging an application. See example. array > map None
timeout * Time (in seconds) allocated to an app before it times out when starting. int 5 seconds
start Boolean flag to start the app after creation or deployment. boolean False
log_drains * An array of log drains to associate with the job. Each object must include a url property whose value is the log drain URL. You can optionally specify a max_size property whose value is the maximum log item size in bytes. array > map Default max_size value is 2048 bytes.
templates One or more file paths to be evaluated as templates. Using this attribute lets you to configure your app from Apcera job environments. Apcera writes the template evaluation results before starting a Job. Options available are path, left_delimiter, and right_delimiter. The default delimiter is curly braces ({...}). See example. None  

Manifest file format

The manifest file format is a proprietary configuration file format used by Apcera. This file format is a flexible format that combines the best of traditional configuration formats and newer styles such as JSON and YAML.

The format supports mixed Arrays [], nested Maps {}, and multiple comment types (# and //). In addition, the format also supports key value assignments using '=' or ':' or whitespace, for example: foo = 2, foo : 2, foo 2. Maps can be assigned with no key separator as well. Semicolons as value terminators in key/value assignments are optional.

Sample manifest file

The following sample manifest includes example values for all manifest attributes. For an actual implementation of a similar manifest, refer to the continuum.conf file that is provided with sample app named example-ruby-manifest which you can download from the Apcera sample-apps repo.

# Name of job (and package)
# Default: None
name: "example-ruby-manifest"

# Namespace the job belongs to.
# Default: Current Namespace
namespace: "/"

# Number of application instances to start on creation.
# Default: 1
instances: 2

# Staging pipeline name to use when staging the application.
# Default: Auto-detect
staging_pipeline: "/apcera::ruby"

# Path to the application. If unset apc will prompt.
# Default: Current working directory
path: "/path/to/app"

# The command to start the app. If unset the stager will
# attempt to auto detect the start command based on the
# app framework used.
start_cmd: "bundle exec rackup config.ru -p $PORT"

# The command to stop the app.
stop_cmd: "echo 'foo'"

# Restart behavior for instances, valid values are "no", "failure", or "always"
restart: "always"

# Number of attempts to make for the restart behavior
restart_attempts: 10

# Resources allocated to the job.
resources {
  # CPU allocated to the job. Calculated in ms/s.
  # Default: 0 ms/s (uncapped)
  cpu: "300"

  # Disk space to allow for the application.
  # Default: 1024MB
  disk_space: "256MB"

  # Memory the job can use.
  # Default: 256MB
  memory: "256MB"

  # Network bandwidth allocated to the job.
  # Default: 5Mbps
  network_bandwidth: "5Mbps"

  # Network maximum permitted to the job.
  # Default: 30Gbps
  network_max: "30Gbps"
}

# Dependencies on the application package instruct the package manager what it
# needs to resolve for a fully-functioning app. Here, you can specify specific
# OS, package, and runtime versions, or let the stager detect.
# Default: none (stager picks for you)
package_dependencies: [
  "os.ubuntu",
  "runtime.ruby-1.9.3"
]

# AllowEgress, if true, binds the app to the outside egress service.
allow_egress: true

# Ports exposed on the job. These may be optional if the job is not listening on
# the port number specified. Routes may be added per-port. Routes have types
# corresponding to the router that picks them up. Currently supported are types
# of 'tcp' and 'http'. Route weight determines how much traffic is delivered
# to each route, between 0 and 100.
# Defaults: port 0 exposed with an http route of <app-name>.<current/namespace>.<domain>
ports: [
  {
    number: 1234,
    routes: [
      {
        type: "http",
        endpoint: "app.apcera.me",
        weight: 30.0
      },
      {
        type: "tcp",
        endpoint: "10.0.0.1:80"
      }
    ]
  },
  {
    number: 8102,
    optional: true
  },
  {
    optional: true,
    number: 8103
  }
]

# Disable routes, this is useful if you are deploying a non-web
# application.
# Default: false
disable_routes: false

# Environment variables for the job. This sample app will show
# the current ENV variables when deployed.
# Default: None
env {
  "ENV_NAME": "env value"
  "ANOTHER_ENV": "secondary value"
}

# Environment variables to set on the application's package.
# Default: None
package_env {
  "PKG_ENV_NAME": "package env value"
  "PKG_ANOTHER_ENV": "package secondary value"
}

# Set of template files to evaluate. This can contain the path
# to the template file, as well as the left and right delimiters.
# The default delimiters are "{{" and "}}"
templates: [
  {
    path: "/path/to/sometemplated/file.txt"
  },
  {
    path: "/path/to/another/file.txt"
    left_delimiter: "<%%"
    right_delimiter: "%%>"
  }
]

# Services to create and bind to the job upon creation.
# Providers must be registered prior to app creation.
# Default: none
services [
  {
    provider_name: "postgres",
    type: "postgres",
    service_name: "mydb1",
  },
  {
    provider_name: "postgres",
    type: "postgres",
    service_name: "mydb2",
  },
]

# Services to create and bind to the stager job. Unless given a name, these
# services are ephemeral and exist only during the lifetime of the named stager.
# Default: none
stager_options [
  { stager_name: "db-prepare",
    services [
      {
        provider_name: "mysql-capsule",
        type: "mysql",
        # Persist the named service.
        service_name: "foo-sql",
      },
      {
        provider_name: "postgres",
        type: "postgres",
        # Autogenerate a name and do not persist the service.
        service_name: "",
      },
    ],
  },
  { stager_name: "ruby-rspec",
    services [
      {
        provider_name: "postgres",
        type: "postgres",
        # Autogenerate a name and do not persist the service.
        service_name: "",
      },
    ],
  },
]

# Timeout is the number of seconds allocated to the app before it times out when
# starting.
timeout: 8

# Stop timeout is the number of seconds a stop command can run before we tear down
# the container
stop_timeout: 20

# Start key determines if the app should start when created.
# Default: false
start: true

# UpdateEndpoint is where the job created from this manifest will receive
# dynamic updates. This is not required for jobs.
update_endpoint: {
  port_number: 8181,
  path: "/v1/updates"
}

# An array of log drains to associate with the job. Each log drain must
# specify a 'url' property whose value is the log drain URL.
# You can optionally specify a 'max_size' property whose value is the
# maximum log item size in bytes (defaults to 2048 bytes).
log_drains: [
  {
    url: "syslog://test.test.com:80"
  },
  {
    url: "syslog://test1.test.com:80"
    max_size: 3072
  }
]

Additional example manifests

In addition to the above sample manifest file, refer to the following examples for writing manifests:

  • Working with Apps implements a basic manifest example.
  • This example shows use a manifest to create and bind a service.
  • This example shows how to use a manifest to bind stagers to services.
  • This example shows how to use a runtime template with a manifest.

Using the start command

You can concatenate commands in the start command, and call one or more scripts, for example:

start_cmd: 'chmod 755 /app/classes/parseDb.sh && export MYSQL_JDBC="$(/app/classes/parseDb.sh)" && env && ./start_app.sh'

However:

  • Consider using templates to populate runtime values.
  • If concatenated commands are necessary, use && instead of ; as the operator to avoid race conditions.

Example manifest that creates and binds to services during app creation

The manifest services.conf, provided with the example-ruby-manifest app (available with the Apcera sample-apps repo), demonstrates how to use a manifest to create and bind to services at app creation time.

The following snippet is culled from this example and demonstrates how to use a manifest to create a service and bind to the job.

In this example, the postgres provider has been registered prior to app (and service) creation, which is required for service creation by manifest.

services [
  {
    provider_name: "postgres",
    type: "postgres",
    service_name: "mydb1"
  }
]

Example manifest that binds stagers to services

You use the stager_options manifest attribute for stagers that must consume services while staging an application.

The following example stages an application using the ruby staging pipeline. The ruby-rspec stager binds to a postgres service while staging the app.

  1. Clone the rspec-consuming-db app from GitHub.

  2. cd to the rspec-consuming-db directory.

  3. Note that continuum.conf specifies the services required by the ruby-rspec stager:

    # Name of job (and package)
    name: "rspec-consuming-db"
    
    # Staging pipeline FQN
    staging_pipeline: "continuum-stagers/ruby"
    
    # Unlisted stagers will not have services.
    stager_options [
      { stager_name: "ruby-rspec",
        services [
          {
            provider_name: "postgres",
            type: "postgres",
            service_name: "" # auto-generate
          }
        ]
      }
    ]
    
  4. Deploy the application with command apc app create rubyapp.

Note the following about using a manifest to bind stagers to services using a manifest:

  • You can provide a service name if you want the service to persist.
  • Each stager in the staging pipeline can have any number of services created for, and bound to it. Any stager that is not included in the manifest cannot bind to a service.
  • A service that requires a provider must have that provider already registered before staging.
  • By default, services are cleaned up post-staging.

Example manifest that uses runtime templates

The templates manifest attribute is a list of file paths that will be evaluated as templates. Templates expose information about the container runtime environment to applications running inside the container. Applications need access to this information to complete their configuration when running within a container. Templates enable you to configure your app from Apcera job environments and are usually used with frameworks that expect configuration files to reside on disk (for example, the Rails database.yml file).

The Apcera sample app example-ruby-manifest includes a continuum.conf manifest that implements the templates attribute which references the app.rb template file. This app is available in the Apcera sample apps repo.

For example, the following manifest snippet references the app.rb template file:

templates: [
  {
    path: "app.rb"
  },
]

The app.rb template file contains parameters whose values will be populated at runtime by Apcera, for example:

scalars:
uuid: {{uuid}}
name: {{name}}
num_instances: {{num_instances}}
cpu: {{cpu}}
memory: {{memory}}
disk: {{disk}}

When you go to start an app, before the Instance Manager calls the app start command, Apcera evaluates the attributes and replaces them with the actual runtime values.

Refer to the Working with Templates for details on the values that you can template.