Package Resolution
Part of Apcera's process for deploying and governing applications is to ensure that each application's needs are satisfied accurately, subject to policies that you set. Packaging an application, or any executable unit in Apcera, entails identifying what it needs and bundling that information with it as metadata. This works because other packages can satisfy those needs. Packages that can satisfy needs carry that information as metadata too.
Metadata – provides and dependencies
A package's needs are called dependencies, and the needs a package can satisfy are called provides (singular, a provides). A package can have both dependencies and provides.
As metadata associated with a package, each dependency and each provides has the following elements:
type
(os
,package
,file
,runtime
)name
(a subtype or version of the type)
For example, you use a package with a provides of type os
to create a capsule.
Package provides and dependencies are generally represented with dot notation. For example,
os.ubuntu
describes a dependency or a provides for a package that needs or provides the Ubuntu operating system.
When you create a package you can specify dependencies and provides at different levels of granularity. For example, the Ubuntu-14.04 operating system package, provided by Apcera, has the following metadata:
Package: | ubuntu-14.04 |
---|---|
FQN: | package::/apcera/pkg/os::ubuntu-14.04 |
State: | ready |
Provides: | os: linux |
os: ubuntu | |
os: ubuntu-14.04 | |
Environment: | PATH="$PATH:/bin:/sbin:/usr/bin:/usr/sbin" |
Any package that depends on os.linux
, os.ubuntu
, or os.ubuntu-14.04
can use this package to satisfy that dependency.
APC resolves dependencies when it executes commands. For example, apc capsule create <your-capsule-name> -i linux
creates a capsule from a package that provides the Linux operating system.
Dependencies describe what a package needs to operate. For example, the Ruby v2.0.0 p481 runtime has the following metadata:
Package: | ruby-2.0.0-p481 |
---|---|
FQN: | package::/apcera/pkg/runtimes::ruby-2.0.0-p481 |
State: | ready |
Dependencies: | os: ubuntu |
Provides: | runtime: ruby |
runtime: ruby-2.0 | |
runtime: ruby-2.0.0 | |
runtime: ruby-2.0.0-p481 | |
Environment: | PATH="/opt/apcera/ruby-2.0.0-p481/bin:$PATH" |
Any app that depends on Ruby can use this package, but only if this package's dependency (os.ubuntu
) is met. Thus, a package that provides os.ubuntu
(for example, ubuntu-14.04
above) must be available.
Inspecting package metadata
The apc package show
command displays a package's dependencies and provides.
The apc package list --type <type>
command displays all packages of the specified type (os
, package
, file
, runtime
).
The apc package list --provides <name>
command displays all packages that provide the specified subtype.
For example, to see all packages in the /apcera
namespace with type os
:
$ apc package list --type os --namespace /apcera
Or, to see all packages in the /apcera
namespace that provide ubuntu
:
$ apc package list --provides ubuntu --namespace /apcera
How Apcera resolves package dependencies
When you upload your application's source code, Apcera stages it. The stager prepares the source code and locates and resolves its dependencies, so the app has an appropriate runtime and operating system in its isolation context.
The stager matches the app's dependencies with provides throughout the system. It creates and traverses a graph of dependencies and provides to resolve to a complete set of concrete packages.
You can set policies that control which packages the stager can use in the graph it builds. This enables you to govern the versions and types of packages and runtimes available to various teams in your organization.
The following diagram illustrates how Apcera resolves package dependencies. In this example, 'My App' has 2 dependencies, 'X' and 'Z'. The staging coordinator creates a graph of the dependencies and available package provides and then matches them to resolve the dependencies.
If you have two packages that satisfy the same dependency, the package that was imported first takes precedence, assuming there is no policy rule set up to specify otherwise.
How to specify application dependencies
You can set dependencies on a new application package in the following ways:
-
Let Apcera's built-in stagers choose the dependencies:
For most basic application runtimes, Apcera's stagers can inspect your source code and determine what dependencies are needed in order to stage your app. They place
depends
tags on your application for the runtimes and packages necessary to make your app work. -
Provide a runtime-specific file:
Apcera's stagers support inspecting files like
runtime.txt
orpackage.json
in order to determine what version best supports your app. -
Issue an APC command:
When you create an app using
apc app create
, you can specify additional dependencies using the--depends-on
option. For example, to test your app on the latestruby-2.1.0
version while your cluster's defaults point toruby-2.0.0
:$ apc app create my-ruby-app --depends-on runtime.ruby-2.1.0
You can supply multiple packages and runtimes as a space-separated list.
You do not need to tag every package dependency at create time; Apcera's resolution process ensures that your app works with the best option available.
Control package resolution with policy
You use policy to control package resolution. Policy offers a robust system to control the version and types of packages and runtimes available in the system. Using policy, you can allow a set of packages, lock or establish a default for a certain dependency, or retire a package so that it is no longer available for use by new apps.
Refer to the Policy documentation for details on using policy rules to control package resolution.