Working with Docker Images

Apcera provides first-class support for running Docker containers. You can create and run Docker images as native jobs in Apcera Platform. This lets you apply Apcera's policy-based governance and orchestration features to better secure and manage Docker workloads.

Apcera Platform release 2.4.0 expands support and testing for the top 100 images avilable on the public DockerHub repository. Refer to the Apcera 100 Docker images documentation for details.

Overview

Apcera Platform supports creating jobs and packages from Docker images that reside on the public Docker Hub, a private v2 or v1 Docker registry, Quay Enterprise and Quay.io registries, or Amazon EC2 Container Registry (ECR).

Apcera pulls Docker images from upstream registries and converts them into its native package format, keeping the original layer composition and Docker registry metadata. It extracts ports, start command, user, group, and environment variables from Docker image metadata and maps it to the Apcera container format. Once running, a Docker image runs like any other job in Apcera Platform. You can start and stop it, update it, monitor its health, apply policy to it, and connect it to other jobs and services. If the Docker image requires persistence, you can use an NFS provider for native volume support.

Note: Apcera does not run the Docker Engine or any other individual Docker components. See Docker compatibility for more information.

Docker image caching

By default, when you create a job from a Docker image, Apcera first looks for the newest package in the current namespace that is derived from the same Docker image, version tag and registry. If such a package exists then its Docker image metadata is used to create a new package for the newly created job. If no such package exists, the image's metadata is requested from the Docker registry and a new package is created from that image and assigned to the new job.

Note: Every Docker image consists of a set of layers which make up the final image; each layer is uniquely identified by a cryptographic content hash. Apcera maintains a global cache of image layers that have been downloaded for all Docker images. If you create an app from a Docker image that includes an image layer that already exists in this cache, Apcera will reuse the cached image layer. This is true even with the --pull flag described in this section, which only applies to image metadata. If the new image metadata indicates that the image contains new image layers, then just those new layers are downloaded.

You can force a pull of image metadata from the image registry even if a package derived from the same image, version and registry already exists. This is available as the --pull flag to the apc docker run command and the equivalent "pull" field available in multi-resource manifests.

For example, the following APC command creates a new job from the official CentOS image on Docker Hub with the "latest" tag. As this is the first time that this image was requested in the current namespace, its metadata is pulled from the registry, as the command output indicates:

apc docker run /myapps::mycentos --image centos:latest
...
[mycentos] -- Creating Docker package -- pulling image metadata from registry
...

If you then create another job in the same namespace from the same Docker image, version tag and registry, the Apcera cluster's locally cached image metadata is used to create the application package:

apc docker run /myapps::mycentos-2 --image centos:latest
...
[mycentos-2] -- Creating Docker package -- using local image metadata
...

To force a pull of the image's metadata, even if a package derived from the same image exists in the current namespace, you add the --pull flag to the apc docker run command, as shown below. Note the command's output indicates the image metadata is being pulled from the registry.

apc docker run /myapps::mycentos-3 --image centos --pull
...
[mycentos-3] -- Creating Docker package -- pulling image metadata from registry
...

You can also use equivalent "pull" : true field in a multi-resource manifest to force the apc manifest deploy command to pull image metadata from the registry, for example:

{
  "jobs": {
    "job::/myapps::mycentos-4": {
      "docker": {
        "image": "centos:latest",
        "pull": true
      }
    }
  }
}

This ensures that the version of the Docker image used to create (or update) the target job is always the most recently pushed version of centos:latest in the target registry.

If you delete all packages in a given namespace that were derived from the same image, tag and registry, subsequent apc docker run apc manifest deploy commands that refer to the same Docker image will pull the image metadata from the registry, even if the --pull flag is not specified.

Docker allow

To be able to run or create Docker jobs, or create packages from Docker images, you must define docker.allow policy for the desired registry, repository, and/or image. See Using Docker whitelisting for details.

Docker registry support

Apcera Platform supports importing Docker images from the public Docker Hub, private v1 and v2 Docker registries, Quay Enterprise and Quay.io registries, and Amazon EC2 Container Registry (ECR).

Creating a job from a Docker image

You use the apc docker run command to create an Apcera job from a Docker image. This command first creates a package from a specified Docker image, and then links that package to a newly created job. To create a package from a Docker image without creating a job, use the apc docker pull command (see Creating a package from a Docker image.

Prior to the Apcera Platform version 2.2.0 "Buffalo" release, Apcera supported the command apc docker create to create a Docker job without starting it. Beginning with version 2.2.0, the apc docker create command is deprecated in favor of apc docker pull (see Creating a package from a Docker image).

Creating jobs from public Docker Hub images

By default, Docker images are assumed to reside on the public Docker Hub. In this case, you simply specify the Docker image using the format repository/image-name:tag (tag is optional). For example, the following creates and starts an Apcera job named "nats-server" from the apcera/gnatsd image on Docker Hub.

apc docker run nats-server --image apcera/gnatsd

Or, to create but not start the job use the --no-start flag:

apc docker run nats-server -i apcera/gnatsd --no-start

The shortcut -i can be used for the --image parameter.

Creating jobs from private Docker registry images

If the Docker image you want to use is located at a supported private Docker registry, the value for the --image parameter must start with the repository's HTTP or HTTPS URL, for example:

apc docker run my-app --image http://203.0.113.24:5000/app

Where the IP address is the public IP of the host running the private Docker registry.

You can also create jobs from images that reside on private Quay registries. See Using Quay.io private Docker registries for more information. Refer to this Knowledgebase article for information on setting up Docker registry in a container.

Creating a package from a Docker image

The apc docker pull <package-name> command creates a package from a Docker image without creating a corresponding job (see Creating a job from a Docker image). For example, the following creates the /packages/docker::nats-server package from the latest NATS Docker image on Docker Hub:

apc docker pull /packages/docker::nats-server --image nats:latest

When you run this command Apcera checks if the Docker image would be allowed to run as a "hypothetical" job in the same namespace. For example, if the package being created is package::/namespace/pkg::mypackage then policy is checked for job::/namespace/pkg. Note that only the namespace is checked, not the resource's local name.

For example, consider the following apc docker pull command that fails because the proper policy is not in place:

apc docker pull /mypackages/docker::nats-pkg --image nats:0.9.4
[nats-pkg] -- Pulling Docker image -- checking policy
[error] -- Docker image "https://registry-1.docker.io/library/nats:0.9.4" not allowed by policy: 
missing claim "docker.allow \"https://registry-1.docker.io/library/nats:0.9.4\"" on "job::/mypackages/docker::nats-pkg"

Adding the following policy allows the user to create a package in the /mypackages/docker namespace. Note that policy is written on the job realm, not the package realm.

job::/mypackages/docker {
  { docker.allow "https://registry-1.docker.io/library/nats:0.9.4" }
}

This policy permits the authenticated user to pull the latest NATS Docker and create a package in the /mypackages/docker namespace.

Also see the policy examples of Docker Policy Examples.

Specifying options for Docker jobs

You can specify several options when creating a job from a Docker image. For example, the following creates a new Docker job and assigns a custom route to it using the --routes option:

apc docker run <app-name> --image <docker-image> --routes http://myapp.foobar.com

The --routes option can take multiple routes, separated by commas. The following assigns two routes to the same Docker job:

apc docker run <app-name> --image <docker-image> --routes http://myapp.foobar.com,http://myapp.foobar.net

Using Quay.io private Docker registries

The apc docker run and apc docker pull commands support pulling Docker images stored on the Quay private Docker registry. Access to a Quay registry requires that you provide a username and password, which you can either specify directly on the command line, or in interactive mode.

The --image (or -i) option must specify the full Quay registry URL in the form of https://quay.io/<user-account>/<image-name>:[image-tag], where image-tag defaults to "latest" if not specified.

Providing Quay registry credentials

Access to a Quay registry requires that you provide a username and password, which you can either specify directly on the command line or via APC prompt.

The following example provides Quay account credentials:

apc docker run my-ubuntu -I -i https://quay.io/nathan_loper/ubuntu:latest

Username: nathan_loper
Password: ****************************************************************

Alternatively, you can provide your Quay credentials on the command line. The following table lists the command line options for specifying Quay user credentials on the command line:

Option Description
--registry-username, -ru String that is the Docker registry username used for basic authentication. Must be supplied in conjunction with registry password. For Quay Enterprise Registries, registry username can be "$oauthtoken". Not applicable for Amazon EC2 Container Registry.
--registry-password, -rp String that is the Docker registry password used for basic authentication. Must be supplied in conjunction with registry username. For Quay Enterprise Registries, if --registry-username is "$oauthtoken" then --registry-password must be a valid OAuth token. Not applicable for Amazon EC2 Container Registry.

The above options are in addition to the standard set of Docker deployment options.

For example, the following example provides registry credentials on the command line:

apc docker run my-ubuntu -i https://quay.io/nathan_loper/ubuntu:latest --registry-username quay_username --registry-password quay_password

For Quay Enterprise Registries, if --registry-username is "$oauthtoken" then --registry-password must be a valid OAuth token.

Considerations for using Quay.io

  • Apcera recommends that you use the Quay.io web console feature to encrypt your credentials. Because encrypted credentials may contain characters such as / that break URL strings, the system needs to be able to escape them. As such, the registry username and password are passed as separate CLI parameters and not part of the registry URL.

  • The apc docker run and apc docker pull commands must supply the full URL to the Quay repository, for example: apc docker run memcached -i https://quay.io/<user_account>/memcached. You cannot specify only the base Docker image name as you do when you deploy a Docker image from the public repository (apc docker run nats-server --image apcera/gnatsd).

  • The -i (or --image) flag is synonymous with the RegistryURL. For the -i option, you can provide an image name (-i library/ubuntu) or the full Registry URL (-i https://quay.io/<username>/<repo>). The options are interpreted differently depending on input. If the input is the image name, the system constructs the full registry URL by defaulting to the DockerHub (https://registry-1.docker.io/library/ubuntu:latest). Thus, for quay.io (or any other private Docker registry), you must specify the full RegistryURL.

  • Registries provided in docker.allow for Docker whitelisting cannot contain the registry username or password.

  • Any private Docker repository such as Quay.io must exist outside of the subnet that is defined in the cluster.conf file for your Apcera Platform.

The image-name includes the repository and the user name. Check out this resource for a discussion on Docker image naming.

Using Amazon EC2 Container Registry

You can create apps and packages from Docker images hosted on the Amazon EC2 Container Registry (ECR). To pull an image that you have pushed to an Amazon ECR repository, you first need to obtain an ECR authentication token for the IAM user on whose behalf APC will make the request. The user must have AWS policy attached that enables it to pull images (such as the managed AmazonEC2ContainerRegistryReadOnly policy).

Once you've configured the AWS CLI for the IAM user, run the aws ecr get-authorization-token command:

aws ecr get-authorization-token              
{
    "authorizationData": [
        {
            "authorizationToken": "QVdTOkFRRUNBSGo2bGM0...", 
            "expiresAt": 1476426273.132, 
            "proxyEndpoint": "https://1234567890.dkr.ecr.us-west-2.amazonaws.com"
        }
    ]
}

Note the value of the authorizationToken field in the response, and create an environment value named ECR_AUTH_TOKEN that contains the field's value:

export ECR_AUTH_TOKEN=QVdTOkFRRUNBSGo2bGM0...

To create an application from an image from an ECR repository, run apc docker run, specifying the image repository's full URL in the --image parameter:

apc docker run myapache --image https://395162948718.dkr.ecr.us-west-2.amazonaws.com/testrepo:latest

To pull an image from Amazon ECR using the Web Console, you need to provide a username and password rather than the authorization token provided by get-authorization-token. You use the aws ecr get-login command to obtain the corresponding username and password:

aws ecr get-login
docker login -u AWS -p AQECAHj6lc4XH... -e none https://395162948718.dkr.ecr.us-west-2.amazonaws.com

Note: This command writes displays docker login commands to stdout with authentication credentials. Your credentials could be visible by other users on your system in a process list display or a command history.

The username (-u) and password (-p) options in the command output display your registry username and password. You can use these in the username and password fields in a multi-resource manifest or in the App from Docker Image form in the Web Console, for example:

Alt text

Or using a manifest:

{
  "jobs": {
    "job::/sandbox/admin::ottersay": {
      "docker": {
        "image": "https://123452948718.dkr.ecr.us-west-2.amazonaws.com/ottersay",
        "username": "AWS",
        "password": "AQECAHj6lc4XIJw..."
      }
    }
  }
}

Troubleshooting

Below are common error messages when creating apps or packages from images hosted on Amazon ECR.

  • Error: No auth token found for authenticating ECR – Indicates the ECR_AUTH_TOKEN environment variable has not been set.
  • Error: Bad response from registry: "403 Forbidden" – Indicates that the IAM user represented by the authentication token (obtained by calling the aws ecr get-authorization-token command) does not have permission to pull images from the ECR registry.

Docker job example

This example creates creates and starts a job named web using the training/webapp Docker image available on Docker Hub. This image contains a simple Python Flask web application that listens on port 5000 (by default) for incoming connections and returns a string.

To create and start an app from the training/webapp Docker image, run the following command:

$ apc docker run web -i training/webapp

The command output shows that the target Docker image contains 13 layers. The command creates a new package that contains multiple resources, one package resource for each layer. Lastly, it creates a job from the newly created package and starts the job.

[web] -- Pulling Docker image -- checking policy
[web] -- Pulling Docker image -- checking if package FQN is taken
[web] -- Pulling Docker image -- fetching image metadata
[web] -- Pulling Docker image -- preparing download
[web] -- Pulling Docker image -- fetching 13 layers
[web] -- Pulling Docker image -- creating package
[web] -- Pulling Docker image -- downloading layer a82efea9
[web] -- Pulling Docker image -- downloading layer e9e06b06
[web] -- Pulling Docker image -- downloading layer 07f8e8c5
...
[web] -- Pulling Docker image -- downloaded all layers
[web] -- Creating job
[web] -- Configuring job -- tagging package
[web] -- Starting job

You can use the apc app show command to view details for the newly created application:

$ apc app show web
╭────────────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Job:               │ web                                                                                                                  │
├────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ FQN:               │ job::/sandbox/user::web                                                                                              │
│ State:             │ started                                                                                                              │
│                    │                                                                                                                      │
│ Created by:        │ user@apcera.com                                                                                                      │
│ Created at:        │ 2015-11-24 18:39:05.142434206 +0000 UTC                                                                              │
│ Updated by:        │ user@apcera.com                                                                                                      │
│ Updated at:        │ 2015-11-24 18:39:05.560725876 +0000 UTC                                                                              │
│                    │                                                                                                                      │
│ Running Instances: │ 1/1 started                                                                                                          │
│                    │                                                                                                                      │
│ Restart:           │ no                                                                                                                   │
│                    │                                                                                                                      │
│ Resources          │                                                                                                                      │
│   CPU:             │ (no limit)                                                                                                           │
│   Memory:          │ 256MB                                                                                                                │
│   Disk:            │ 1GB                                                                                                                  │
│   Network:         │ 5Mbps                                                                                                                │
│   Netmax:          │ (no limit)                                                                                                           │
│                    │                                                                                                                      │
│ Process            │                                                                                                                      │
│   Name:            │ app                                                                                                                  │
│   Start Command:   │ /bin/sh -c if cd '/opt/webapp'; then exec "$@"; else echo >&2 "cd '/opt/webapp' failed"; exit 1; fi -- python app.py │
│   Start Timeout:   │ 30 (seconds)                                                                                                         │
│   Stop Timeout:    │ 5 (seconds)                                                                                                          │
│   Environment:     │ PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"                                                  │
│                    │                                                                                                                      │
│ Exposed Ports:     │ 222                                                                                                                  │
│                    │ 5000                                                                                                                 │
│                    │                                                                                                                      │
│ Routes:            │ none                                                                                                                 │
│                    │                                                                                                                      │
│ Tags:              │ app: web                                                                                                             │
│                    │ docker: web                                                                                                          │
│                    │ ssh: true                                                                                                            │
│                    │                                                                                                                      │
│ Packages:          │ package::/sandbox/user::web*                                                                                         │
╰────────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

Note that the Packages field in the above output shows that the application is represented by a single package (package::/sandbox/user::web) that was created from the Docker image. The apc package show command shows details about this package, including the Docker image's URL origin:

$ apc package show web
╭─────────────┬─────────────────────────────────────────────────────╮
│ Package:    │ web                                                 │
├─────────────┼─────────────────────────────────────────────────────┤
│ FQN:        │ package::/sandbox/user::web                         │
│ State:      │ ready                                               │
│             │                                                     │
│ Created by: │ user@apcera.com                                     │
│ Created at: │ 2015-11-24 23:28:22.704336102 +0000 UTC             │
│ Updated by: │ user@apcera.com                                     │
│ Updated at: │ 2015-11-24 23:28:45.962848107 +0000 UTC             │
│             │                                                     │
│             │                                                     │
│ Docker URL: │ https://registry-1.docker.io/training/webapp:latest │
╰─────────────┴─────────────────────────────────────────────────────╯

Also, note from the apc app show output that port 5000 has been exposed on the app, per the image's Dockerfile, where the app is listening for incoming connections. However, there is no route mapped to that port yet, so the application is not accessible from a browser. To add a route to that port, you can use the apc route add command as shown below (replace the route URL with one appropriate for your cluster):

apc route add http://web.user.sandbox.apcera-platform.io --app web --port 5000

You should now be able to access the webapp from a web browser at the specified route. Equivalently, you could have specified a route when creating the app with the --routes option, for example:

apc docker run web -i training/webapp --routes http://web.user.sandbox.apcera-platform.io --port 5000

If you created another app from the same Docker image, the process completes much faster because the image layers were cached by the Package Manager, for example:

apc docker run web-2 --image training/webapp
[web-2] -- Pulling Docker image -- checking policy
[web-2] -- Pulling Docker image -- checking if package FQN is taken
[web-2] -- Pulling Docker image -- fetching image metadata
[web-2] -- Pulling Docker image -- preparing download
[web-2] -- Pulling Docker image -- fetching 13 layers
[web-2] -- Pulling Docker image -- creating package
[web-2] -- Pulling Docker image -- all layers downloaded
[web-2] -- Creating job
[web-2] -- Configuring job -- tagging package
[web-2] -- Starting job

You can list all packages that provide a specific Docker image by passing the --docker-image parameter to the apc package list command. For instance, the following shows the two packages (web and web-2) that provide the training/webapp Docker image.

$ apc package list --docker-image training/webapp
Working in "/sandbox/user"
╭───────┬──────────────────────┬───────╮
│ Name  │ Namespace            │ State │
├───────┼──────────────────────┼───────┤
│ web   │ /sandbox/user        │ ready │
│ web-2 │ /sandbox/user        │ ready │
╰───────┴──────────────────────┴───────╯

You can also connect this job to another Docker job using a job link.

Using optional Docker arguments

Apcera Platform extracts ports, start command, user, group, and environment variables from Docker image metadata and maps it to the Apcera Platform container format. You can override any of these using the following optional arguments:

Option Effect
-i, --image <docker-image> Docker image to create application from. Default registry is the public Docker Hub. You can also use a private registry. See Using Docker registries for more information.
--restart <option> Restart behavior for Docker job. Valid values are no, failure, or always. Default is no for Docker jobs. See Docker Restart Policies.
-r, --routes <routes> Routes to register with the Docker job, as a comma-separated list. Routes must not contain any characters forbidden in URLs, per RFC 3986. Routes are applied on the chosen port.
-t, --tag TAG Docker image tag (default: 'latest').
-p, --port PORT Port to expose in the created application.
-I, --interactive Connect to your Docker job in an interactive prompt. Useful for running OS images. Some recent Docker Hub OS images, like Fedora, require this to be paired with the --unlock-root flag.
--unlock-root Replace the image's start command to unlock the root user account via usermod. Images with locked root user accounts disallow SSH ingress. A known flaw with the public CentOS:7 image's version of usermod does not allow this workaround.
-rm, --remove Remove container after the interactive shell is closed. Must be used with --interactive flag.
-v, --volume PATH Mount a new persisted volume inside the container at the specified path. May be supplied multiple times.
--ignore-volumes Ignore volumes specified in the image spec. (No data will be persisted.)
--provider NAME The provider from which volumes are created. Only NFS providers are currently supported.
-s, --start-cmd <cmd> Application's start command. 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.
--stop-cmd <cmd> Command to run when app is stopped.
--timeout <number> Time until the app starts up when attempting to start, in seconds. (Default is 30 seconds.)
--stop-timeout Time to allow the stop command to run, in seconds. (Default is 5 seconds.)
-ae, --allow-egress Allow fully open outbound network egress from the job.
-u, --user <user> User to run Docker image as (defaults to user in the image configuration, or 'root' if image doesn't have user configured).
-g, --group <group> Group to run Docker image as (default: picked by system runtime).
-e, --env-set <ENV=VAL> Sets an environment variables on the app. Multiple values can be supplied by invoking multiple times (e.g. --env-set 'HOME=/usr/local' --env-set 'PATH=/usr/bin:/opt/local')
-c, --cpus CPU Milliseconds of CPU time per second of physical time. May be greater than 1000ms/second in cases where time is across multiple cores. (Default is 0ms/second, uncapped.)
-m, --memory <number> Memory to use, in MB. (Default is 256MiB.)
-d, --disk <number> Amount of disk space to allocate, in MB. (Default is 1GiB.)
-net, --network <name> Name of virtual network to be joined when job is started.
-n, --netmin <number> Amount of network throughput to allocate (floor), in Mbps. (Default is 5Mbps.)
-nm, --netmax <number> Amount of network throughput to allow (ceiling), in Mbps. (Default is 5Mbps.)
-ht, --hard-tags Hard scheduling tags to add to the docker workload.
-st, --soft-tags Soft scheduling tags to add to the docker workload.
-rp, --registry-password Password for Docker registry from which image will be pulled. Must be supplied in conjunction with registry username. For Quay Enterprise Registries, if --registry-username is "$oauthtoken" then --registry-password must be a valid OAuth token.
-ru, --registry-username Username for Docker registry from which image will be pulled. Must be supplied in conjunction with registry password. For Quay Enterprise Registries, registry username can be "$oauthtoken".

Docker Restart Policies

The apc docker run command accepts a --restart option that lets you specify if a Docker instance is automatically restarted if it fails (exits with a non-zero exit code) or finishes (exits normally). This option takes the following values:

  • no – Never restart the application. This is the default value for Docker jobs.
  • always – Always restart the application, regardless of whether it failed or finished.
  • failure – Only restart on application failure (process exits with a non-zero exit code).

These behaviors are identical to the Restart Policies provided by the Docker daemon.

Using Docker connect

To open an SSH session with a Docker job, run the following APC command, where job-name is the name of the Docker job you created from a Docker image.

apc docker connect <job-name>

For example, to connect via SSH to the web Docker job you created previously, run the following command:

apc docker connect web

For Docker jobs with more than one instance, apc docker connect will not reliably connect to the same backend. Refer to the FAQs for more information.

Running Docker jobs interactively

Docker images can be run interactively using the -I flag. Running a Docker job in interactive mode may be useful for Docker images that provide operating systems. You can also launch another type of Docker image, such as MySQL, and specify the start command /bin/bash using interactive mode. In addition, you can also use interactive mode to provide credentials for connecting to private Docker registries.

For example, the following command connects you to bash as soon as the image boots:

apc docker run NAME -i IMAGE -I

Without the -I option, the Docker image's start command finishes.

Some recent OS images published on the Docker Hub lock the root user account, disallowing SSH, which will break both apc docker connect and the --interactive flag. Try using the --unlock-root flag alongside --interactive mode when creating your Docker job. Note that CentOS 7 is known to have a bug with its use of usermod today.

Linking to a Docker job

A Docker job runs like any other job in Apcera Platform. The Docker job is deployed to a container-based, parameterized environment. The environment contains information on how to connect the job to other jobs, services, and so forth. A common way to connect one job to another is using a job link. A job link is a direct connection to a destination job running in Apcera or an external entity. A link on the source job represents environment variables for the IP and Port of the destination job.

Because Docker images are just jobs in the system, assuming you have sufficient policy permissions, you can easily link Docker jobs with the following command:

apc job link <source-job> --to <target-job> --name <link-name> --port <port on target-job>

Job linking lets you link jobs (including Docker) and send connection information from the source job to the destination job. Refer to the Job link example for an additional Docker job link example.

To demonstrate linking between Docker jobs, you will download and run a second Docker job named db that runs a Postgres database, then link the db job to the web Docker job that you deployed previously:

First, create and start the new Docker image as a job using the following command:

apc docker run db -i training/postgres

You should see that the Docker image is downloaded to your namespace and the resulting job is started.

$ apc docker run db -i training/postgres
[db] -- Pulling Docker image -- checking policy
[db] -- Pulling Docker image -- checking if package FQN is taken
[db] -- Pulling Docker image -- fetching image metadata
[db] -- Pulling Docker image -- preparing download
[db] -- Pulling Docker image -- fetching 14 layers
[db] -- Pulling Docker image -- creating package
[db] -- Pulling Docker image -- downloading layer 511136ea
[db] -- Pulling Docker image -- downloading layer 7baf0ef6
[db] -- Pulling Docker image -- downloading layer e497c7c1
[db] -- Pulling Docker image -- downloading layer ...
...
[db] -- Pulling Docker image -- downloaded all layers
[db] -- Creating job
[db] -- Configuring job -- tagging package
[db] -- Starting job

Now, link the web Docker job to the db Docker job:

apc docker link web --to db --name pgdb --port 5432

You should see the following result:

apc job link web --to db --name pgdb --port 5432
Binding "job::/sandbox/temp::web" to "job::/sandbox/temp::db"... done
Starting the application... done
Waiting for the job to start...
Success!

The --port is optional if the job has exactly one port. If it has none or more than one, Apcera Platform reports an error.

Using policy for Docker whitelisting

Apcera requires you to use policy to control the creation of jobs and packages from Docker images. By default, you cannot create a job or package from a Docker image without having policy in place that allows it (docker.allow). For example, if you try to create an application from a Docker image without the required policy, you receive a policy error:

apc docker run myUbuntu --image ubuntu -it
Error: Docker image "https://registry-1.docker.io/library/ubuntu:latest" not allowed by policy: 
missing claim "docker.allow \"https://registry-1.docker.io/library/ubuntu:latest\"" 
on "job::/sandbox/user::myUbuntu"

You use docker.allow policy to whitelist specific Docker images (or entire registries or image repositories) and allow them to be downloaded and deployed to the system. Apcera recommends that you define tightly scoped policies that grant Docker permissions. For example:

job::/sandbox/user {
	{ permit read, create, update }
	{ docker.allow "https://quay.io/<quay_username>/<quay_repository>" }
}

Similarly, to create a package from a Docker image using apc docker pull <package-name> you must have policy on the corresponding job:: realm for the package you want to create. For example, consider the following APC command that creates a package with the FQN package::/mypackages/docker::nats-pkg from the official NATS Docker image:

apc docker pull /mypackages/docker::nats-pkg --image nats:0.9.4

For this command to succeed there must be docker.allow policy on the job::/ realm that permits access to the specified Docker image within the namespace specified in the APC command, for example:

job::/mypackages/docker {
  { docker.allow "https://registry-1.docker.io/library/nats:0.9.4" }
}

Note: Docker allow policy should only be written on the job:: realm, not on the package::/ realm.

See also:

Alternatively, there is a policy document that you can uncomment that will allow you to run or create any Docker image from a supported Docker repository:

job::/ {
	{ docker.allow "*" }
}

Notes:

  • By default, Apcera Platform Community Edition administrators can create jobs and packages from any Docker image.
  • You must explicitly whitelist the Docker repositories you want a user to be able to connect to. Apcera recommends creating fine-grained policies for creating and running Docker jobs. Alternatively, you can use a wildcard character * to grant full Docker job permissions.
  • Apcera Platform versions prior to version 449.3.0 used https://index.docker.io as the public Docker Hub URL. Version 449.3.0 and above must use https://registry-1.docker.io as the public Docker Hub URL due to changes around the URL structure on the Docker Hub.

Using Docker persistence

If the Docker image you are deploying to the system specifies or requires a persisted volume (persistence), you can bind the Docker job to an NFS provider and get native volume support. To use Docker persistence, you must first register an NFS provider with the system. Refer to Apcera File Share services for details on using NFS persistence.

If the specification for a Docker image (Dockerfile) specifies that the app requires persisted volumes, you must do one of the following when creating the job:

  • Include the --provider flag when you create or run the Docker job. You must include this flag if you include the --volume <PATH> flag when creating or running the Docker job.
  • Include the --ignore-volumes flag when you create or run the Docker job.

Docker persistence examples

For explicit native volume support, specify the --provider flag with commands apc docker run or apc docker create. To ignore volumes, include the --ignore-volumes parameter.

Here is a basic example that binds a Docker app to the Apcera NFS provider (APCFS) that ships with the Community Edition:

apc docker run web --image training/webapp --provider /apcera/providers::apcfs

For explicit native volume support, we specify the --provider flag with the apc docker run command. To use this app, see above Docker job example.

Here is a more elaborate example that pulls official MySQL Docker image and binds it to the Apcera NFS provider (APCFS) that ships with the Community Edition:

apc docker run docker-mysql-server --restart always --image mysql --tag 5.7.11 --port 3306 --provider /apcera/providers::apcfs --env-set MYSQL_ROOT_PASSWORD=password

From here you can register this app as a service provider and create services for it. See Creating MySQL Service from Docker.

To ignore volumes specified in the image specification, include the --ignore-volumes parameter. For example:

apc docker run web -i training/webapp --ignore-volumes
apc docker run docker-mysql-server --restart always -i tutum/mysql --port 3306 --ignore-volumes

Docker compatibility notes

Apcera does not run the Docker Engine under the hood, nor does it run any individual Docker components. When an image is pulled via apc docker run or apc docker pull, Apcera pulls the image from the upstream registry and converts it into the Apcera package format, keeping the original layer composition and Docker registry metadata.

Command-line differences

You use the apc docker run command to create an application on Apcera from a Docker image. This command does not map directly to the docker run command. Under the hood, Apcera operates differently from Docker in several ways, as explained in more detail in the sections below.

The apc docker run and docker run commands do share a few command-line options in name and general function, as listed below.

Option name Description
--env <value> Set environment variables on the container.
-I, --interactive Connect to your Docker-based job in an interactive prompt. See Connecting to a container below.
-v, --volume <PATH> Mount a new persisted volume inside the container at the specified path (see Volume management below).
--network NAME Name of a virtual network to be joined when job is started (see Networking below).
--restart-mode <mode> Restart behavior for instances, valid values are "no", "failure", or "always".
-rm, --remove Remove container after the interactive shell is closed. Must be used with --interactive flag.
--user <USER> User to run Docker image as (defaults to user in the image configuration, or 'root' if image doesn't have user configured).

Containers and Images; Jobs and Packages

In Docker, containers run images. In the Apcera Platform, jobs represent the runtime template that an instance inherits. Docker images are represented as packages. This allows us to horizontally scale an identical job into multiple containers easily by modifying the instance count.

Manifests

Today, we do not support Docker compose-styled manifests. Instead, we have our own multi-resource manifest functionality to orchestrate creation, update, and networking between jobs.

Connecting to a container

In our system, we connect to containers via SSH. When using apc docker run --interactive, users are dropped into an SSH shell connecting to the container. When the image you've pulled has its root user account locked, you'll also need to supply the --unlock-root flag to allow interactive mode.

By comparison, Docker allocates a pseudo-tty that attaches stdin and stdout.

Volume management

One other area of distinction is how we manage user data. We provide NFS volumes that may be bound to multiple jobs and scaled across multiple instances as well. Docker supports many different technologies for volume management, and also supports volumes mounted from a user's laptop. See Using Docker persistence for more information.

Networking

Apcera offers several technologies for networking between containers. apc job link and apc network * map directly to docker link and docker network *, allowing for similar levels of container orchestration. Apcera also offers control over the egress and ingress into the containers using networking service bindings.

Docker registry API support

Apcera Platform version 447.2.0 and earlier implements the v1 Docker Registry API. On December 7th 2015, the public Docker Hub will no longer support pull from Docker clients that implement the v1 Registry API. This means developers targeting Apcera release 447.2.0 or earlier will not be able to create jobs from Docker images on the public Docker Hub using the apc docker run command.

This change does not affect private registries not managed by Docker (such as Quay, for example).

Apcera release version 449 and later implements the v2 Registry API and is fully compatible with pulling images from the public Docker Hub. To re-enable pull from the public Docker Hub, please install the latest promoted release.

Cluster access to Docker repositories

An Apcera cluster's Package Manager (PM) manages the process of downloading a Docker image and converting it into an Apcera package. The PM creates internal jobs to download each image layer, one job per layer. The Package Manager and the "downloader" jobs it creates must have network access to the Docker registry where the Docker image resides. The downloader jobs are subject to package-realm stager scheduling tags and inherit http_proxy and https_proxy environment variables from the Package Manager process.