25.6 Building and modifying images
The only other section on this page is: Local development and testing with Docker
For general use, it is sufficient to use the pre-built PEcAn images hosted on Docker Hub (see Docker quickstart). However, there are cases where it makes sense to re-build the Docker images locally. The following is a list of PEcAn-specific images and reasons why you would want to rebuild them locally:
pecan/depends
– Rebuild if:- You modify the
docker/depends/Dockerfile
- You introduce new system dependencies (i.e. things that need to be installed with
apt-get
) - You introduce new R package dependencies, and you want those R package installations to be cached during future builds. For packages with fast build times, it may be fine to let them be installed as part of PEcAn’s standard build process (i.e.
make
).
- You modify the
pecan/base
– Rebuild if:- You built a new version of
pecan/depends
(on whichpecan/base
depends) - You modify the
docker/base/Dockerfile
- You made changes to the PEcAn R package source code, the Makefile, or
web/workflow.R
.- NOTE that changes to the web interface code affect
pecan/web
, notpecan/base
- NOTE that changes to the web interface code affect
- You built a new version of
pecan/executor
– Rebuild if:- You built a new version of
pecan/base
(on whichpecan/executor
depends) and/or,pecan/depends
(on whichpecan/base
depends) - You modified the
docker/executor/Dockerfile
- You modified the RabbitMQ Python script (e.g.
docker/receiver.py
)
- You built a new version of
pecan/web
– Rebuild if you modified any of the following:docker/web/Dockerfile
- The PHP/HTML/JavaScript code for the PEcAn web interface in
web/
(exceptweb/workflow.R
– that goes inpecan/base
) docker/config.docker.php
(theconfig.php
file for Docker web instances)documentation/index_vm.html
(the documentation HTML website)- NOTE: Because changes to this code are applied instantly (i.e. do not require compilation or installation), a more effective way to do local development may be to mount the
web/
or other relevant folders as a volume onto thepecan/web
container.
The easiest way to quickly re-build all of the images is using the docker.sh
script in the PEcAn source code root directory.
This script will build all of the docker images locally on your machine, and tag them as latest
.
This will not build the pecan/depends
image by default because that takes considerably longer.
However, you can force the script to build pecan/depends
as well by setting the DEPEND
environment variable to 1 (i.e. DEPEND=1 ./docker.sh
).
The following instructions provide details on how to build each image individually.
To build an image locally, use the docker build
command as described below.
For more details, see docker build --help
or the online Docker build documentation.
First, in a terminal window, navigate (cd
) into the PEcAn source code root directory.
From there, the general syntax for building an image looks like the following:
docker build -t pecan/<image name>:<image version> -f docker/base/Dockerfile.<image name> .
For instance, to build a local version of the pecan/depends:latest
image, you would run:
docker build -t pecan/depends:latest -f docker/depends/Dockerfile .
The breakdown of this command is as follows:
docker build
– This is the core command. The standard syntax isdocker build [OPTIONS] <PATH>
, where<PATH>
refers to the directory to be used as the “build context”. The “build context” is the working directory assumed by the Dockerfiles. In PEcAn, this is always the PEcAn source code root directory, which allows Dockerfiles to use instructions such asCOPY web/workflow.R /work/
. In this example, the<PATH>
is set to the current working directory, i.e..
because we are already in the PEcAn root directory. If you were located in a different directory, you would have to provide a path to the PEcAn source code root directory. Also, by default,docker build
will look for a Dockerfile located at<PATH>/Dockerfile
, but this is modified by the-f
option described below.-t pecan/depends:latest
– The-t/--tag
option specifies how the image will be labeled. By default, Docker only defines unique image IDs, which are hexidecimal strings that are unintuitive and hard to remember. Tags are useful for referring to specific images in a human-readable way. Note that the same unique image can have multiple tags associated with it, so it is possible for, e.g.pecan/depends:latest
,pecan/depends:custom
, and evenmypecan/somethingelse:20.0
to refer to the same exact image. To see a table of all local images, including their tags and IDs, rundocker image ls
.- NOTE: PEcAn’s
docker-compose.yml
can be configured via thePECAN
environment variable to point at different versions of PEcAn images. By default, it points to the:latest
versions of all images. However, if you wanted to, for instance, build:local
images corresponding to your local source code and then run that version of PEcAn, you would run:
PECAN=local docker-compose -p pecan up -d
This is an effective way to do local development and testing of different PEcAn versions, as described below.
- NOTE: PEcAn’s
-f docker/depends/Dockerfile
– The-f/--file
tag is used to provide an alternative location and file name for the Dockerfile.
25.6.1 Local development and testing with Docker
The following is an example of one possible workflow for developing and testing PEcAn using local Docker images.
The basic idea is to mount a local version of the PEcAn source code onto a running pecan/executor
image, and then send a special “rebuild” RabbitMQ message to the container to trigger the rebuild whenever you make changes.
NOTE: All commands assume you are working from the PEcAn source code root directory.
In the PEcAn source code directory, create a
docker-compose.override.yml
file with the following contents.:version: "3" services: executor: volumes: - .:/pecan
This will mount the current directory
.
to the/pecan
directory in theexecutor
container. The specialdocker-compose.override.yml
file is read automatically bydocker-compose
and overrides or extends any instructions set in the originaldocker-compose.yml
file. It provides a convenient way to host server-specific configurations without having to modify the project-wide (and version-controlled) default configuration. For more details, see the Docker Compose documentation.Update your PEcAn Docker stack with
docker-compose up -d
. If the stack is already running, this should only restart yourexecutor
instance while leaving the remaining containers running.To update to the latest local code, run
./scripts/docker_rebuild.sh
. Under the hood, this usescurl
to post a RabbitMQ message to a running Docker instance. By default, the scripts assumes that username and password are bothguest
and that the RabbitMQ URL ishttp://rabbitmq.pecan.localhost/
. All of these can be customized by setting the environment variablesRABBITMQ_USER
,RABBITMQ_PASSWORD
, andRABBITMQ_URL
, respectively (or running the script prefixed with those variables, e.g.RABBITMQ_USER=carya RABBITMQ_PASSWORD=illinois ./scripts/docker_rebuild.sh
). This step can be repeated whenever you want to trigger a rebuild of the local code.
NOTE: The updates with this workflow are specific to the running container session; restarting the executor
container will revert to the previous versions of the installed packages.
To make persistent changes, you should re-build the pecan/base
and pecan/executor
containers against the current version of the source code.
NOTE: The mounted PEcAn source code directory includes everything in your local source directory, including installation artifacts used by make.
This can lead to two common issues:
- Any previous make cache files (stuff in the .install
, .docs
, etc. directories) persist across container instances, even though the installed packages may not. To ensure a complete build, it’s a good idea to run make clean
on the host machine to remove these artifacts.
- Similarly, any installation artifacts from local builds will be carried over to the build. In particular, be wary of packages with compiled code, such as modules/rtm
(PEcAnRTM
) – the compiled .o
, .so
, .mod
, etc. files from compilation of such packages will carry over into the build, which can cause conflicts if the package was also built locally.
The docker-compose.override.yml
is useful for some other local modifications.
For instance, the following adds a custom ED2 “develop” model container.
services:
# ...
ed2devel:
image: pecan/model-ed2-develop:latest
build:
context: ../ED2 # Or wherever ED2 source code is found
networks:
- pecan
depends_on:
- rabbitmq
volumes:
- pecan:/data
restart: unless-stopped
Similarly, this snippet modifies the pecan
network to use a custom IP subnet mask.
This is required on the PNNL cluster because its servers’ IP addresses often clash with Docker’s default IP mask.
networks:
pecan:
ipam:
config:
- subnet: 10.17.1.0/24