The lifecycle of a stack can be broken down into 3 stages:
Initialization occurs when a user issues an
appsody init command in a new empty directory, in order to configure a new project. It might seem odd that there are any requirements on the stack for initialization, but since the goal is for the stack image to encapsulate all aspects of the stack, the configuration steps required (which are likely to be technology specific) are indeed contained within it. The following is a summary of what happens during initialization:
.appsody-config.yamlfile that specifies the stack image itself (which is usually stored in a Docker repository)
appsody-init.batif running on Windows). If this file exists, it is executed to set up any further configuration. Note that it not recommended that this initialization installs new packages or modules in user space of the local machine. Any dependencies should be handled by ensuring this happens during run and build, listed below.
During local development, when the stack image is run, it must build the appropriate local container runtime configuration. This will include:
run), which the controller will action, and then wait for further commands to be sent to it from the Appsody CLI
You will note that during local development, Docker does not run the user application on startup - it is the Appsody controller that is in charge (and will execute the user application when required). This is achieved with settings in the Dockerfile for the stack itself (
Dockerfile-stack), which are described next.
There are three types of volume/mounts used by Appsody:
Volume mounts specified in the
APPSODY_MOUNTS Docker variable
These will be processed by the Appsody CLI. The primary use of this is to mount the directory holding the user application into the container, so that the appsody-controller can have access to your application (and run it inside the container). For example:
would map the current directory (where the init was performed), into
/project/userapp in the container file system.
You can specify only directories in volume mounts, not single files.
Dependency directory volume
This creates a volume used to cache, for efficiency, the combined dependencies of the stack components and the user application between sequential runs of the application during local development. It is not mounted into the user directory, since access to this is not required outside of the Docker environment. This is specified via the Docker variable
APPSODY_DEPS. For example:
would cause the creation of a volume to be created and mounted into the container file systems at
Appsody controller mount
The Appsody CLI automatically creates the Appsody controller mount, as it knows which version of the controller needs to be used. When you run the
appsody debug, or
appsody test commands, the Appsody CLI creates a Docker volume, if it doesn't exist, named
appsody-controller-<version>, and installs appropriate Appsody controller, as indicated by
<version>. The volume is then mounted at
/.appsody in the container file system.
As the Appsody CLI is responsible for installing the appropriate version of the Appsody controller, the stack developer doesn't need to be aware of the Appsody controller version.
There are two types of dependencies that need to be handled by the stack.
Dependencies required for the technology components included in the stack
For efficiency, these only need to be installed when the image is launched. Hence, these are typically encoded as regular Docker commands. For example, in the python-flask stack, these dependencies are defined in a
Pipfile in the
image/project directory, and are processed by the following Docker commands:
RUN pipenv lock -r > requirements.txt RUN python -m pip install -r requirements.txt -t /project/deps
Dependencies added by the developer for their application
Since the developer might add these at any stage, these are generated each time an Appsody command is executed by the controller. This is achieved by setting the
ENV APPSODY_PREP Docker variable, which the Appsody controller will execute. For example, again in the python-flask stack, these dependencies are defined in the user directory (created by the template) and are referenced by:
ENV APPSODY_PREP="cd /project/userapp; pipenv lock -r > requirements.txt; python -m pip install -r requirements.txt -t /project/deps"
[Note that in older stacks this variable was called
APPSODY_INSTALL, which has since been deprecated]
Any environment variables required by the technology in the stack itself are typically set in the
Dockerfile-stack file, using the regular Docker
appsody run command is issued, the stack image is launched in the local Docker environment of the user machine and the appsody-controller is set as the entrypoint. The controller is also passed the Appsody command being executed (
run in this case). The Appsody controller processes the Appsody specific Docker variables, which determine how the user application is run and managed. These Appsody specific variables are described in more detail in Appsody Environment Variables, although the most important ones for the run case are as follows (with examples from the python-flask stack):
ENV APPSODY_RUN="python -m flask run --host=0.0.0.0 --port=8080"
which specifies the command to be run by the Appsody controller to start the user application, and:
which specifies the directory that the Appsody controller watches for changes, so that the user application can be automatically relaunched during local development. Since relaunching may require addition steps, the variable
APPSODY_RUN_ON_CHANGE specifies the command that will be run to relaunch the application.
The Appsody controller remains running during local development, and is terminated with the
appsody stop command (or by simply killing the running Appsody CLI process).
Build and deploy is designed to package up both the new user application and the technology components of the stack into a single Docker image that can be deployed and run in any Docker environment (often a local or public Kubernetes cluster). From a stack point of view, the key requirement is to include a Dockerfile which can build this combined image. This is the
Dockerfile in the
project directory in the stack source (as opposed to the
Dockerfile-stack file in the
image directory, which is used when you are creating the original stack image).
The steps undertaken when the
appsody build command is run are:
~/.appsody/extract) along with the user application.
projectdirectory of this extracted structure, resulting in a Docker image for the combined application.
Dockerfile needs to build the dependencies for both the stack technology components as well as the user application, and set the entrypoint (or
CMD) to an appropriate entrypoint for the user application. The Appsody controller is not involved in the final application image.