Deployment Integration
The process by which events occur and decisions are made at deployment in order to provide the initiation scripts.
The following document describes the relationship between the compiled source code (ie AnyLog agent) and deployment-scripts which defines which services to run on a given AnyLog agent.
As such the document covers a few things:
- The break between AnyLog and deployment-scripts
- How to deploy AnyLog (simple)
- The connection between AnyLog &
deployment-scripts - Overriding the Entry Point
- Patches & Version Updates

The document discusses AnyLog, but the same logic also works when deploying EdgeLake.
The break between AnyLog and deployment-scripts
A running node is really two independent pieces:
┌─────────────────────────────────┐
│ AnyLog / EdgeLake binary │ ← the engine — compiled, never edited
├─────────────────────────────────┤
│ deployment-scripts (git repo) │ ← the configuration — yours to read, fork, or customize
└─────────────────────────────────┘
- The binary is the compiled AnyLog/EdgeLake runtime. It knows how to execute commands and
.alscript files, but it doesn’t know anything about what to run on its own. deployment-scriptsis what tells the binary what to actually do — which services to start, which database to connect, which policies to publish. It’s plain text, not compiled, and it’s designed to be read, forked, or edited.
This split is why you never need to rebuild the AnyLog image just to change how a node behaves — you only need to change the scripts it’s pointed at.
Initial Deployment
- User clones a repo called
docker-compose(orK8s-compose) containing a set of configuration files. - User updates the configuration files as needed.
Key configs:
LICENSE_KEYLEDGER_CONNNODE_TYPE
A user can skip the full config file (i.e. skip
make) and just rundocker runwith the 3 environment variables directly. - Deploy AnyLog / EdgeLake using
makeordocker run.
What Happens in the Docker Container
AnyLog is the actual source code. To configure its services, AnyLog agents use configuration policies driven by a set of
scripts called deployment-scripts. For the internals of how those policies and scripts actually communicate (and
the process vs. thread execution model behind them), see Deployment Scripts — Integration Reference.
By default, the docker image ships with the main deployment-scripts already baked in. Using the environment params
DEPLOYMENTS_REPO and DEPLOYMENTS_BRANCH, a user can point at a different set of deployment-scripts instead.
Resolution happens in two stages — build time (compose file generation, driven by make) and, for one of the four
options below, runtime (inside the running agent container).
Stage A — Build script (compose file generation)
The build script picks one of four modes, in order:
| # | Condition | Behavior |
|---|---|---|
| 1 | DEPLOYMENTS_REPO/DEPLOYMENTS_BRANCH unset, or explicitly set to the default (https://github.com/AnyLog-co/deployment-scripts @ main) |
Built-in default. Enables the ${CONTAINER_NAME}-local-scripts named volume. On first creation, Docker seeds it from the scripts baked into the image; after that it’s just a persistent volume. |
| 2 | DEPLOYMENTS_REPO is set and is an existing local directory on the host |
Host bind mount. Compose is rewritten to mount that directory directly at /app/deployment-scripts, and the named volume + init-service references are stripped out entirely. Fully static — no cloning, no copying. |
| 3 | DEPLOYMENTS_REPO is an http:// or https:// URL |
Reclone at startup. No volume is mounted at all at build time; the agent clones the repo itself when it starts (see Stage B below). |
| 4 | DEPLOYMENTS_REPO is set but matches none of the above (e.g. a docker image reference) |
Secondary deployment-scripts container. A one-shot helper service is injected into the compose file: image: ${DEPLOYMENTS_REPO}:${DEPLOYMENTS_BRANCH}, which copies /app/deployment-scripts out of that image into the shared ${CONTAINER_NAME}-local-scripts named volume, then exits. The main service waits on it (condition: service_completed_successfully) before starting. |
So if you’ve simply created your own repo with the same structure, option 3 (or option 2, if it’s a local
directory) is usually the one you want — point DEPLOYMENTS_REPO/DEPLOYMENTS_BRANCH at it and the rest of the
machinery (volumes, cloning) is handled for you.
The same build script also has an unrelated block detecting
DOCKER_SOCKETand settingDOCKER_GID(for Docker-in-Docker support). That’s a separate concern from deployment-scripts selection.
Important caveat — this entire table only applies when deploying via make. If a user runs docker run directly
instead (skipping make, using just the 3 core env vars), none of this build-time logic ever executes. It becomes the
user’s responsibility to configure everything themselves:
- volumes (highly recommended)
- branch selection for deployment-scripts, if changing from default at all
- anything else this script would otherwise have handled
Why “a pre-existing volume takes precedence” (the original point 0): Options 1 and 4 both mount the same named
volume, ${CONTAINER_NAME}-local-scripts. Docker does not recreate or repopulate an existing named volume just because
make reruns — it’s reused as-is. So if that volume already exists from a prior run, it keeps whatever content it has
regardless of what DEPLOYMENTS_REPO/DEPLOYMENTS_BRANCH currently say. This applies specifically to Options 1 & 4
(the two modes sharing that volume), not to Options 2 or 3.
Stage B — Runtime (inside the agent container, on startup — Option 3 only)
This clone logic only runs when Stage A resolved to Option 3 (URL, reclone-at-startup). Options 1, 2, and 4 are all static by the time the container starts — no git operations happen for them inside the agent.
if [[ CURRENT_REMOTE == DEPLOYMENTS_REPO ]] && [[ CURRENT_BRANCH == DEPLOYMENTS_BRANCH ]]; then
# already matches — skip reclone
elif git ls-remote --exit-code --heads "${DEPLOYMENTS_REPO}" "${DEPLOYMENTS_BRANCH}"; then
# branch exists on remote — wipe LOCAL_SCRIPTS and reclone fresh
else
# branch/repo not reachable — error, leave existing LOCAL_SCRIPTS untouched
fi
if [[ ! -d ${LOCAL_SCRIPTS} ]]; then
# still missing — hard fail, agent won't start
fi
- If the currently-recorded remote and branch already match
DEPLOYMENTS_REPO/DEPLOYMENTS_BRANCH→ skip re-cloning, reuse what’s on disk. ⚠️ This check only compares repo + branch name, not commit hash. See the Patches section below — this is the mechanism that determines whether a customer picks up a fix automatically. - Else, if that branch actually exists on the remote → delete the existing
LOCAL_SCRIPTSdirectory and clone fresh. - Else (repo/branch unreachable) → log an error and leave whatever’s currently in
LOCAL_SCRIPTSalone. - If
LOCAL_SCRIPTSstill doesn’t exist after all that → hard fail (exit 1). The agent will not start without deployment-scripts present.
(The “download the repo as a docker container, DEPLOYMENTS_BRANCH as the tag” behavior from the original description
is real — it’s Option 4 above, implemented at build time as a helper compose service rather than inside this runtime script.)
Overriding the Entry Point
Pointing DEPLOYMENTS_REPO/DEPLOYMENTS_BRANCH at your own repo (Stage A above) determines which copy of
deployment-scripts loads — but the container’s ENTRYPOINT (/app/deploy_anylog.sh) separately hardcodes the path it
runs once that repo is in place:
${ANYLOG_PATH}/${APP_NAME} process $ANYLOG_PATH/deployment-scripts/node-deployment/main.al
This path is fixed in the entrypoint script itself — it doesn’t follow $LOCAL_SCRIPTS/$ANYLOG_PATH the way
main.al’s internal references do. So if your own repo’s entry script isn’t named main.al, you have two options:
Simplest — no override needed: name (or copy) your custom entry script to node-deployment/main.al within your
repo. The entrypoint picks it up with zero further changes, regardless of which Stage A option loaded your repo.
If you need a genuinely different filename, override the container’s entrypoint so it calls your script’s actual
path instead of the hardcoded one. This bypasses deploy_anylog.sh’s other setup steps (OpenBao secret fetch,
version/arch detection, deployment-scripts resolution, the Kubernetes /etc/hosts patch, etc.) — only do this if
you’ve already handled those yourself, or if you maintain your own modified copy of deploy_anylog.sh that still does
them before calling your script.
Docker Compose:
services:
anylog-node:
image: your-anylog-image
environment:
- ANYLOG_PATH=/app
- APP_NAME=anylog_v1.0.0_x86_64 # or however your image derives this
entrypoint: ["/bin/bash", "-c"]
command:
- >
${ANYLOG_PATH}/${APP_NAME} process ${ANYLOG_PATH}/deployment-scripts/node-deployment/my_custom_main.al
Docker Run:
docker run \
--entrypoint /bin/bash \
your-anylog-image \
-c '${ANYLOG_PATH}/${APP_NAME} process ${ANYLOG_PATH}/deployment-scripts/node-deployment/my_custom_main.al'
Both forms replace deploy_anylog.sh entirely for that container, so double-check you don’t need anything it would
otherwise have done for you before reaching this line.
Patches & Version Updates
Standard process for any reported issue:
- Understand the issue.
- Check whether it still exists in the latest code.
- Fix it.
- Ask the customer to update to the newer build.
What “update to the newer build” actually does depends on where the bug lives, because a docker container bundles two different things — the AnyLog/EdgeLake agent binary and the deployment-scripts — and they update through different mechanisms.
A. Bug is in the agent itself
Customer pulls the new image and restarts. The agent code updates immediately, since the image itself is what’s being replaced. Deployment-scripts are untouched by this step — they live in a separate clone/volume/mount, not something baked fresh into every container restart.
B. Bug is in the deployment-scripts
This depends on which of the four build-time options (see Section 2) the customer is running:
- Option 1 — default, in-image
mainscripts: a new image pull brings fixed scripts along only if the${CONTAINER_NAME}-local-scriptsvolume doesn’t already exist. If it does (i.e. this isn’t the customer’s first run), the volume is reused as-is and the fix never lands — the customer needs to remove that volume (and ideally the associated configuration policy) so it gets reseeded from the new image. - Option 2 — local directory (bind mount): no clone/copy step exists at all here. The customer has to update that host directory themselves; pulling a new agent image has zero effect on it.
- Option 3 — URL, reclone at startup: ⚠️ if the fix is pushed to the same branch the customer is already tracking, a restart will NOT pick it up. The runtime match check only compares repo + branch strings — it has no concept of “is there a newer commit on this branch.” Since repo and branch are unchanged, the agent treats its existing clone as current and skips re-cloning.
- Workarounds until/unless this is fixed: point at a new branch or tag for the patched scripts, manually delete the
LOCAL_SCRIPTSdirectory/volume so nothing matches and a reclone is forced, ordocker execin andgit pullmanually.
- Workarounds until/unless this is fixed: point at a new branch or tag for the patched scripts, manually delete the
- Option 4 — secondary deployment-scripts container: the helper service runs once and copies into the shared named volume, then exits — it doesn’t run again on a plain restart. Same volume-reuse caveat as Option 1: if
${CONTAINER_NAME}-local-scriptsalready exists, a new image (even with a bumped tag) won’t get re-copied in unless the volume is cleared first (or the compose file is regenerated with a config that forces recreation).
Practical takeaway for triage: when a customer reports a deployment-scripts bug, first ask which of the four options
they’re in — that determines whether “just pull the new image” is actually sufficient, or whether they also need to clear
the local-scripts volume, bump a branch/tag, or manually sync a local directory. And if they’re deploying via bare
docker run instead of make, none of this is automatic in the first place — walk through their setup manually.