Working with Packages

A package is a runnable workload comprising binary data (typically a tarball) and JSON metadata. Apcera provides you with a base set of packages (system-provided packages), and you can create your own packages using a variety of methods.

This document describes packages using an example and provides considerations for working with packages.

Package contents

A package in Apcera comprises the following:

Package example

Here is an example package. The metadata is a JSON representation of the pre-bundled Ruby 2.0 runtime package.

{
  "uuid": "bab5805d-37a2-458d-a6ae-a16db4b2d8c3",
  "name": "Ruby 2.0.0-p195",
  "resource": {
    "uuid": "763664dd-572f-4f86-9122-d06899ede5d3",
    "digest": "sha1:6355c94ac6601b9fffb0a7ed3b6de4dc998fe4b1",
    "length": 24926087
  },
  "state": "ready",
  "environment": {
    "PATH": "/opt/apcera/ruby-2.0.0-p195/bin:$PATH"
  },
  "dependencies": [
    {
      "type": "os",
      "name": "linux"
    }
  ],
  "provides": [
    {
      "type": "runtime",
      "name": "ruby-2.0.0-p195"
    },
    {
      "type": "runtime",
      "name": "ruby-2.0.0"
    },
    {
      "type": "runtime",
      "name": "ruby-2.0"
    },
    {
      "type": "runtime",
      "name": "ruby"
    }
  ]
}

Binary data

The binary data that represents the data for the package is typically in the form of a tarball. The system determines at runtime if the data is gzip'd, bzip'd, or an uncompressed tar file. Within the system, the binary data is often referred to as the "resource" for a package. This is because a package object may exist before the binary data for it exists (such as when you are in the middle of uploading the binary data).

Metadata

The metadata for the package is comprised of a JSON document that details to the system what it provides for other packages to consume.

The metadata includes the uuid identifier for the package within the system, the package's name, and then the package's resource information, including its UUID, SHA1 sum, and length. All three bits of information are used within the system to identify and validate a package.

If the package's state is ready, the package is ready to be referenced by other packages or jobs within the system and has gone through any required staging processes.

Packages can specify environment variables that get applied at runtime. In the example, the Ruby runtime adds a directory onto the PATH so that an application that invokes ruby within the container will find this package's Ruby binary, which in this packaged version is at /opt/apcera/ruby-2.0.0-p195/bin/ruby.

The package dependencies and provides sections match requirements based on the combination of "type" and "name". In the Ruby example, the package's only dependency is the package that provides an operating system (OS) that is Linux. The dependency "type" is os and the "name" is linux. The values used can be almost anything, but the important aspect is that in order for the Ruby package to be used, the system must have another that includes a provides section for type OS and name Linux.

Package types

There are four possible values for type:

  • os - Intended to refer to an operating system dependency.
  • runtime - Refers to a runtime or language interpreter that is needed.
  • file - Used to refer to a specific file that is necessary.
  • package - A generic bucket for any other type of general use package.

Package naming

The name values can be any string, and are not tightly coupled to the type. The system doesn't automatically know if a package provides specific types, and it doesn't automatically expand the files list to provide "file" provides entries. It places the onus on the user to manage what aspects a package provides to the system. The types are intended for convenient associations.

See also Package Resolution.

Package Creation

See Creating Packages.

Importing packages

To import packages into the system you use the APC client.

1) CD to the directory where you have stored the packages you want to import, such as $HOME\apc-packages.

2) Import the packages using the following command:

apc import *.cntmp --batch

If you receive an error that a package already exists, use the --override or --skip-existing flags, for example: apc import *.cntmp --batch --skip-existing.

3) Verify package import.

Log in to the console UI and verify that the packages were successfully uploaded to the cluster.

Exporting packages

You may find that you want to reuse a package on a different cluster from where it was created.

To do this you can use Apcera's package export/import feature.

1) Create the package on the original cluster:

apc package build <config-file>

2) Export the package:

apc package export

This gives you the *.cntmp file.

3) Import the package to the target cluster.

apc package import *.cntmp

Package namespaces

If you export a package and then import it to the same or another cluster, the package will be imported to the same namespace from where it was exported. If you want to import an exported package to a different namespace, you first have to change to the desired namespace and then use the -o parameter to override the package's namespace reference to the locally targeted namespace.

For example, if you have exported the node-0.6.21 package from /apcera/pkg/runtimes, to import the package to /acme/pkg/runtimes you would do the following:

apc namespace /acme/pkg/runtimes
apc package import node-0.6.21.cntmp -o

On import the package will be placed in the /acme/pkg/runtimes namespace.

Renaming packages

You can change a package's local name with the apc package update command. For example, the following changes the local name of /prod/pkg::package-A to package-B:

apc package update /prod/pkg::package-A --name package-B

Note: You cannot change a package's namespace with this command. To you must recreate the package in the desired namespace.

Keep in mind that any policy written against the package's local name will need to be updated for the new package name. For example, consider the following package.allow policy that allows /prod/pkg::package-A to used by jobs in the /prod namespace:

job::/prod {
  { package.allow "package::/prod/pkg::package-A" }
}

If you change the local name of package-A to package-B you also need to update the FQN assigned to package.allow to match the new name.

Working with large packages

See creating large packages.