Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions deploy/docker/base.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ RUN set -o xtrace \
software-properties-common \
git \
&& add-apt-repository -y ppa:git-core/ppa \
# Install MongoDB v6, PostgreSQL v14
&& curl -fsSL https://www.mongodb.org/static/pgp/server-6.0.asc | gpg --dearmor -o /usr/share/keyrings/mongodb-server-6.0.gpg \
&& echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-6.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/6.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-6.0.list \
# Install MongoDB v7, PostgreSQL v14
# Note: MongoDB 7.0 does not publish apt packages for Ubuntu 24.04 (noble) yet, so we use the jammy (22.04) packages — same pattern used for the previous 6.0 install.
&& curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | gpg --dearmor -o /usr/share/keyrings/mongodb-server-7.0.gpg \
&& echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-7.0.list \
&& echo "deb http://apt.postgresql.org/pub/repos/apt $(grep CODENAME /etc/lsb-release | cut -d= -f2)-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list \
&& curl --silent --show-error --location https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \
&& apt update \
Expand Down
75 changes: 75 additions & 0 deletions deploy/docker/fs/opt/appsmith/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,80 @@ init_replica_set() {
fi
}

# Pre-flight check for embedded MongoDB 7.0 upgrades on existing data.
#
# MongoDB 7.0 refuses to start on data whose featureCompatibilityVersion (FCV)
# is below 6.0. Without a check up front, supervisord would retry mongod a few
# times and give up, leaving the container in a confusing degraded state with
# no clear error for the administrator.
#
# Fast path: marker file ($MONGO_DB_PATH/.appsmith-mongo-fcv-min) is written by
# mongodb-fixer.sh only after mongod is confirmed running under this Appsmith
# release. Its presence proves this release has already booted successfully on
# this data, so the probe can be skipped with zero overhead. Contents record
# the FCV floor this release commits to, for future upgrade decisions; they
# aren't consulted here.
#
# First boot after upgrade: no marker yet. Do a one-time mongod --fork probe
# to verify the data is compatible. If it starts, proceed; the fixer will
# write the marker after supervisord brings mongod up for real. If it fails,
# print an actionable error and exit.
ensure_mongodb_fcv_compatible() {
# Only applies to existing local-Mongo data — fresh installs have nothing to
# check, and external Mongo is out of our control.
if [[ $shouldPerformInitdb -gt 0 || $isUriLocal -gt 0 ]]; then
return
fi

local marker="$MONGO_DB_PATH/.appsmith-mongo-fcv-min"
if [[ -f "$marker" ]]; then
tlog "MongoDB FCV marker present; skipping pre-flight check"
return
fi

tlog "No MongoDB FCV marker found on existing data; running one-time compatibility probe"
# Persist the probe log inside the Mongo data directory so it survives container
# restarts. $TMP would be wiped, leaving no forensic trail when an admin comes
# back to investigate why their container exited. Append rather than truncate so
# repeated probe runs (e.g. multiple failed upgrade attempts) all stay on record.
local probe_log="$MONGO_DB_PATH/fcv-probe.log"
printf '\n===== Appsmith MongoDB FCV pre-flight probe @ %s =====\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$probe_log" 2>/dev/null || true
if mongod --fork --port 27017 --dbpath "$MONGO_DB_PATH" --logpath "$probe_log" --logappend --bind_ip localhost >/dev/null 2>&1; then
if ! mongod --dbpath "$MONGO_DB_PATH" --shutdown >/dev/null 2>&1; then
tlog "ERROR: Pre-flight mongod probe started but shutdown failed. The probe mongod may still hold port 27017 or the data lock, which would prevent supervisord from starting mongod. Aborting. See $probe_log for details." >&2
exit 1
fi
tlog "Pre-flight probe succeeded; mongodb-fixer will write the FCV marker after supervisord starts mongod"
return
fi

local probe_err
probe_err="$(grep -Ei 'featurecompatibilityversion|upgrade|downgrade' "$probe_log" 2>/dev/null | tail -n 1 || true)"
tlog "====================================================================================================" >&2
tlog "==" >&2
tlog "== ERROR: Embedded MongoDB 7.0 failed to start on the existing data. The most common cause is that the data is at featureCompatibilityVersion below the required 6.0 minimum." >&2
if [[ -n "$probe_err" ]]; then
tlog "== mongod log: $probe_err" >&2
fi
tlog "==" >&2
tlog "== About this error:" >&2
tlog "== Appsmith 2.x ships with MongoDB 7.x, which requires the database to be at featureCompatibilityVersion (FCV) 6.0 or higher. Appsmith releases 1.96 to 1.99 automatically raise FCV to 6.0 on boot, so any instance that has run one of those releases is fine. Instances that have only ever run Appsmith older than 1.70 may still be at FCV 5.0, which MongoDB 7.x refuses to load." >&2
tlog "==" >&2
tlog "== This check only runs for instances using the embedded MongoDB. Instances configured with an external MongoDB are not affected." >&2
tlog "==" >&2
tlog "== The failure happens during MongoDB pre-flight, before any Appsmith service comes online. No Appsmith database migrations have been attempted, so rolling back to a 1.x release is simply a matter of changing the image version on your deployment." >&2
tlog "==" >&2
tlog "== To recover:" >&2
tlog "==" >&2
tlog "== 1. Alter your Appsmith deployment to use a release in the 1.96 to 1.99 range (we recommend the latest, 1.99). These ship with MongoDB 6.x and will raise the compatibility version automatically." >&2
tlog "== 2. Let the container start fully so the MongoDB FCV upgrade completes." >&2
tlog "== 3. Shut down, then alter your Appsmith deployment to use this version again." >&2
tlog "==" >&2
tlog "== Full mongod log: $probe_log" >&2
Comment thread
wyattwalter marked this conversation as resolved.
tlog "====================================================================================================" >&2
exit 1
}

use-mongodb-key() {
# We copy the MongoDB key file to `$MONGODB_TMP_KEY_PATH`, so that we can reliably set its permissions to 600.
# Why? When the host machine of this Docker container is Windows, file permissions cannot be set on files in volumes.
Expand Down Expand Up @@ -633,6 +707,7 @@ if [[ -z "${DYNO}" ]]; then
tlog "Initializing MongoDB"
init_mongodb
init_replica_set
ensure_mongodb_fcv_compatible
fi
else
# These functions are used to limit heap size for Backend process when deployed on Heroku
Expand Down
46 changes: 42 additions & 4 deletions deploy/docker/fs/opt/appsmith/mongodb-fixer.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,67 @@
set -o errexit
set -o nounset

# Marker file recording the minimum MongoDB featureCompatibilityVersion that
# this Appsmith release commits to preserve. Written once mongod is confirmed
# RUNNING under this release; read (presence only) by entrypoint.sh on
# subsequent boots to fast-path the pre-flight compatibility check. See
# entrypoint.sh::ensure_mongodb_fcv_compatible.
#
# The marker value is a release-level contract, not a live reading of mongod's
# current FCV. Use `mongosh` if you want the live value.
MONGO_FCV_MIN_MARKER="/appsmith-stacks/data/mongodb/.appsmith-mongo-fcv-min"

# Minimum FCV this Appsmith release commits to preserve. We deliberately do
# NOT raise FCV to 7.0 — keeping it at 6.0 preserves the ability to roll back
# to a 6.x Appsmith release if something goes wrong. When MongoDB 8 arrives,
# bump this constant to 7.0; the ensure_fcv_floor block below will handle the
# `setFeatureCompatibilityVersion` call automatically.
FCV_MIN="6.0"

write_fcv_marker() {
local value="$1"
local tmp="${MONGO_FCV_MIN_MARKER}.tmp"
if ! printf '%s\n' "$value" > "$tmp" 2>/dev/null; then
tlog "warning: failed to write FCV marker temp file"
return 0
fi
mv -f "$tmp" "$MONGO_FCV_MIN_MARKER" 2>/dev/null || tlog "warning: failed to move FCV marker into place"
}

{

while [[ ! -S "$TMP/supervisor.sock" ]]; do
sleep 1
done
tlog "supervisor.sock found"

while supervisorctl status mongodb | grep -q RUNNING; do
while ! supervisorctl status mongodb | grep -q RUNNING; do
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a max attempt counter here to avoid unbounded looping?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't get to supervisord at least running, it'll kill the container because the health checks will fail anyway. I think it's not worth the risk of this dying too early.

sleep 1
done
tlog "MongoDB is RUNNING"

# Ensure FCV is at the floor this release commits to. In the steady state this
# is a no-op — entrypoint.sh's pre-flight probe already guarantees mongod won't
# come up on data below the supported FCV. The check is kept active so the
# upgrade scaffolding is exercised and the next major-version bump is just a
# constant change.
tlog "Ensuring MongoDB featureCompatibilityVersion is at least $FCV_MIN"
for _ in {1..60}; do
if mongosh --quiet "$APPSMITH_DB_URL" --eval '
parseFloat(db.adminCommand({getParameter: 1, featureCompatibilityVersion: 1}).featureCompatibilityVersion.version) < 6 &&
db.adminCommand({setFeatureCompatibilityVersion: "6.0"})
const floor = '"$FCV_MIN"';
const current = parseFloat(db.adminCommand({getParameter: 1, featureCompatibilityVersion: 1}).featureCompatibilityVersion.version);
if (current < floor) {
db.adminCommand({setFeatureCompatibilityVersion: "'"$FCV_MIN"'", confirm: true});
}
'; then
tlog "MongoDB version set to 6.0"
tlog "MongoDB featureCompatibilityVersion floor of $FCV_MIN confirmed"
break
fi
sleep 1
done

tlog "Recording committed FCV minimum: $FCV_MIN"
write_fcv_marker "$FCV_MIN"
tlog Done

} | sed -u 's/^/mongodb-fixer: /'
Loading