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.yaml
file that specifies the stack image itself (which is usually stored in a Docker repository)appsody-init.sh
(or appsody-init.bat
if 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 CLIYou 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:
ENV APPSODY_MOUNTS=.:/project/userapp
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 volumes
Volumes are created that are 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. The volumes are not mounted into the user directory, since access to that directory is not required outside of the Docker environment. The volumes to be created are specified by the Docker variable APPSODY_DEPS. For example:
ENV APPSODY_DEPS=/project/deps
would cause the creation of a volume that is mounted into the container file systems at /project/deps
.
Multiple dependency directory volumes can be specified by separating the mount path with a semicolon. For example:
ENV APPSODY_DEPS=/project/deps;/project/test/deps
would cause the creation of two volumes that are mounted into the container file systems at /project/deps
and /project/test/deps
.
appsody run
, 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 ENV
command.
When an 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:
ENV APPSODY_WATCH_DIR=/project/userapp
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.Dockerfile
in the project
directory of this extracted structure, resulting in a Docker image for the combined application.The 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.