Using ASTRA to Manage Docker
ASTRA includes a library that allows agents to pull and deploy Docker images. The guide below provides basic information on how to use this support for Docker. It assumes you already know how Docker works.
Getting started
To use the ASTRA Docker API add the following dependency to your project pom.xml:
<dependency>
<groupId>com.astralanguage</groupId>
<artifactId>astra-docker</artifactId>
<version>1.5.0</version>
</dependency>
To create your own Docker agent, simply create an agent that extends the astra.Docker agent class. Add any initial beliefs relevant to the images you want to load (see the Docker Domain Model below) and declare the !container(...) goal. For example, to deploy the "tic-tac-toe" semantic service, you can use the following:
agent MyAgent extends astra.Docker {
constant string TIC_TAC_TOE = "registry.gitlab.com/mams-ucd/examples/semantic-environments/tic-tac-toe" ;
initial image(TIC_TAC_TOE);
initial binding(TIC_TAC_TOE, "8083:8083");
rule +!main(list args) {
!container(TIC_TAC_TOE, string id);
}
}
Docker Domain Model
The docker Domain Model consists of a number of beliefs that are used to describe the docker images the agent is able to deploy. Details of each belief are provided below.
Image Belief
Docker Images are unique name that may be relative (to known docker respositories) or qualified (where the image is stored on a private repository). This name acts as a key for the domain model. The agent maintains a set of beliefs about the images it will use in the deployment. This is modelled in ASTRA by the image predicate:
image(<name>)
For example, to declare a belief about the tic-tac-toe semantic environment, we can create the following initial belief:
initial image("registry.gitlab.com/mams-ucd/examples/semantic-environments/tic-tac-toe");
If the environment is stored in a public repository, then a less qualified name can be used, for example, the hello world application (for ARM64 devices):
initial image("arm64v8/hello-world");
Because the image name can be quite long and is used as a key in the domain model, a constant value is often used:
constant string TIC_TAC_TOE = "registry.gitlab.com/mams-ucd/examples/semantic-environments/tic-tac-toe";
initial image(TIC_TAC_TOE);
Repository & Username Beliefs
Docker Images are stored in repositories that sometimes require authentication for access. In Docker, authentication requires knowledge of the URL of the repository, your username and a passkey. For security purposes, passkeys are stored in a credentials file that is loaded when the agent is created via the credentials module. The default behaviour for pulling a secured image uses this module. The Docker ASTRA program automatically detects when credentials are required based on two beliefs:
The first belief relates to the repository url:
repository(<name>, <repository_url>)
The second belief relates to the username:
username(<name>,<username>)
An example of these beliefs (using the TIC_TAC_TOE image defined above) is:
initial repository(TIC_TAC_TOE, "registry.gitlab.com");
initial username(TIC_TAC_TOE, "MY_USERNAME");
Port Binding (Mapping) Beliefs
Some Docker images provide services that need to be accessible externally. This is done through port mapping (the -p flag in docker). In the domain model, you can do the same thing by adding binding beliefs:
binding(<name>,<port-mapping>)
For example, to make port 8083 of the TIC_TAC_TOE service available, you can add the following belief:
initial binding(TIC_TAC_TOE, "8083:8083");
Shared Volume Beliefs
Some Docker Images store data or require access to external data. To provide support for this, Docker has the concept of volumes. This concept is included in the domain model through the volume belief:
volume(<name>,<local_folder>, <image_folder>)
For example, to map the /target subfolder of the folder that is root for the running application to the /test folder in the container, you use the following belief:
initial volume(TIC_TAC_TOE, "/target", "/test");
The credentials file
The credentials file is used to provide secure access to any passkeys needed to download images to be used by the agent. Credentials files are simple text files with a .cred extension. Each line contains a single credentials that consists of three pieces of information: the base url of the repository, the username, and the passkey. It is encoded using a : as a delimiter:
MY_REPOSITORY:MY_USERNAME:MY-PASS-KEY
MY_OTHER_REPOSITORY:MY_OTHER_USERNAME:MY-OTHER-PASS-KEY
Overloading the secure pull behaviour
As described in the domain model, by default, credentials are stored in a credentials file (see above). If you want to add credentials manually, you can do this by adding the credentials to the file as shown below:
agent Test extends Docker {
rule +!main(list args) {
credentials.add("MY_REPOSITORY", "MY_USERNAME", "MY_PASSKEY");
}
}
As an alternative, you can add additional rules that remove the need to use the credentials module at all:
agent Test extends Docker {
rule +?local(string name) {
AuthConfig authConfig = docker.createAuthConfig(
"MY_REPOSITORY",
"MY_USERNAME",
"MY_PASSKEY"
);
docker.auth(authConfig);
+authConfig(name, authConfig);
?local(name);
}
}
This would force the agent to use the above authentication when pulling any image.