fix(docker): migrate single-node compose from host to bridge networking#2952
fix(docker): migrate single-node compose from host to bridge networking#2952bitflicker64 wants to merge 9 commits intoapache:masterfrom
Conversation
Replace network_mode: host with explicit port mappings and add configuration volumes for PD, Store, and Server services to support macOS/Windows Docker. - Remove host network mode from all services - Add explicit port mappings (8620, 8520, 8080) - Add configuration directories with volume mounts - Update healthcheck endpoints - Add PD peers environment variable Enables HugeGraph cluster to run on all Docker platforms.
|
Bridge networking changes have been validated successfully across environments:
Observed behavior:
No regressions were observed in the single-node deployment. Service discovery and inter-container communication function correctly under bridge networking. ARM64 Compatibility Fix —
|
There was a problem hiding this comment.
Pull request overview
This PR migrates the single-node Docker Compose configuration from Linux-specific host networking to cross-platform bridge networking. The change addresses a critical issue where Docker Desktop on macOS and Windows doesn't support host networking properly, causing services to advertise unreachable addresses and preventing cluster initialization.
Changes:
- Replaced host networking with bridge networking and explicit port mappings
- Added comprehensive environment-based configuration for PD, Store, and Server through new entrypoint scripts
- Implemented health-aware startup with PD REST endpoint polling in wait-storage.sh
- Added volume mounts for persistent data and deprecated variable migration guards
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| docker/docker-compose.yml | Migrated from host to bridge networking, added environment variables, updated healthchecks, exposed required ports |
| hugegraph-pd/hg-pd-dist/docker/docker-entrypoint.sh | New comprehensive entrypoint with SPRING_APPLICATION_JSON configuration, deprecation guards, and required variable validation |
| hugegraph-store/hg-store-dist/docker/docker-entrypoint.sh | New comprehensive entrypoint with SPRING_APPLICATION_JSON configuration, deprecation guards, and required variable validation |
| hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh | Refactored to use environment variables for backend and PD configuration with deprecation guards |
| hugegraph-server/hugegraph-dist/src/assembly/static/bin/wait-storage.sh | Replaced Gremlin-based storage detection with PD REST health endpoint polling, increased timeout to 300s |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Thank you for the review. I’ll take care of the suggested adjustments and will proceed with testing the 3 node cluster configuration next. |
…ecks, remove unused detect-storage script
| networks: | ||
| hg-net: | ||
| driver: bridge | ||
|
|
There was a problem hiding this comment.
build: in quickstart compose can unexpectedly trigger local source builds — prefer pull-only defaults
Using build: together with image: does not always force a local build. In Compose, the usual behavior (depending on pull_policy) is to try pulling first, then fall back to building if pull is unavailable.
That said, this is still risky for a quickstart file:
- If the image/tag cannot be pulled, users unexpectedly need the full source tree and Docker build context.
- Startup becomes much slower because services may be built locally.
- Locally built images can differ from official release artifacts, reducing reproducibility.
Since docker/docker-compose.yml is intended for quickstart usage, I recommend keeping it pull-only by default and moving build: blocks to a dev-specific override (for example, docker-compose.dev.yml).
| pd: | |
| image: hugegraph/pd:${HUGEGRAPH_VERSION:-1.7.0} | |
| container_name: hg-pd | |
| hostname: pd |
If local builds are needed for development, users can combine files explicitly, e.g.:
docker compose -f docker/docker-compose.yml -f docker/docker-compose.dev.yml up
There was a problem hiding this comment.
I’ve changed the compose setup so it’s pull-only and no longer builds locally. Right now, I’m bind-mounting the updated entrypoint scripts because the current published images don’t include these changes.
Once this PR is done and new images are available, I can remove the mounts. I’ll follow up with a small cleanup PR to switch completely to the official images.
hugegraph-server/hugegraph-dist/src/assembly/static/bin/wait-storage.sh
Outdated
Show resolved
Hide resolved
Replace weak PD only probe with hard pre start validation. Startup now blocks until PD health is OK and PD reports at least one Up store. Timeouts fail fast preventing server launch in broken cluster states. Partition stabilization remains a post start concern and does not gate boot.
|
PD readiness checks were failing even when the cluster was working correctly. In secured setups the PD service returns Unauthorized if no credentials are provided. The wait logic treated this response as a failure instead of a normal security behavior. This created false failures where PD and Store were actually healthy. As a result the readiness loop waited . The fix was to add authentication to the curl commands. After that the checks worked correctly and no longer timed out |
|
@imbajin Update on bridge network 3-node cluster investigation: Hi, I've been looking into why the 3-node PD cluster fails to form raft quorum in Docker bridge network mode. To rule out any config loading issues, I tried both the env var based entrypoint approach and a fully hardcoded config, both produced the same error, so I don't think it's config related. Both attempts show this in the logs: Tracing it back, I noticed this in IpAuthHandler.getInstance(
peers.stream()
.map(PeerId::getIp)
.collect(Collectors.toSet())
);I think Could you take a look and let me know if this diagnosis makes sense? I might be missing something still getting familiar with the codebase. If this does seem right, I'd be happy to try putting together a fix. Thanks! |
|
As a temporary workaround, assigning static IPs to PD containers via docker-compose |
|
@imbajin Happy Lantern Festival!🏮 |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 33 out of 37 changed files in this pull request and generated 13 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| pull_policy: always | ||
| restart: unless-stopped | ||
| entrypoint: ["/hugegraph-pd/docker-entrypoint.sh"] | ||
| healthcheck: |
There was a problem hiding this comment.
Same concern as the single-node compose: setting entrypoint: overrides the Dockerfile ENTRYPOINT (dumb-init) and can degrade shutdown/reaping behavior for these Java processes. Prefer keeping the image entrypoint (remove entrypoint:) or explicitly invoke dumb-init in the compose entrypoint.
| store0: { condition: service_healthy } | ||
| store1: { condition: service_healthy } | ||
| store2: { condition: service_healthy } | ||
| entrypoint: ["/hugegraph-server/docker-entrypoint.sh"] |
There was a problem hiding this comment.
x-server-common sets entrypoint: which overrides the Dockerfile ENTRYPOINT (dumb-init). For the server JVM this can cause slow/unclean stops and poor signal propagation. Prefer relying on the image entrypoint (remove entrypoint:) or call dumb-init explicitly in the compose entrypoint.
| entrypoint: ["/hugegraph-server/docker-entrypoint.sh"] |
| entrypoint: ["/hugegraph-server/docker-entrypoint.sh"] | ||
|
|
There was a problem hiding this comment.
entrypoint: here overrides the image ENTRYPOINT (dumb-init), which can prevent proper signal forwarding and leave the HugeGraph server JVM running after docker compose stop. Prefer relying on the image entrypoint (remove this) or use /usr/bin/dumb-init -- /hugegraph-server/docker-entrypoint.sh.
| pd0: { condition: service_healthy } | ||
| pd1: { condition: service_healthy } | ||
| pd2: { condition: service_healthy } | ||
| entrypoint: ["/hugegraph-store/docker-entrypoint.sh"] |
There was a problem hiding this comment.
x-store-common sets entrypoint: which overrides the image’s ENTRYPOINT (dumb-init). That can interfere with signal handling and leave orphaned JVMs/zombies. Prefer removing the compose entrypoint: (let the image’s entrypoint run) or explicitly wrap the script with dumb-init.
| entrypoint: ["/hugegraph-store/docker-entrypoint.sh"] |
| entrypoint: ["/hugegraph-store/docker-entrypoint.sh"] | ||
|
|
There was a problem hiding this comment.
entrypoint: overrides the image’s Dockerfile ENTRYPOINT (dumb-init), which can hurt signal handling/shutdown behavior for the Store JVM. Prefer removing this entrypoint: (the image already runs ./docker-entrypoint.sh) or wrap it with dumb-init explicitly.
| entrypoint: ["/hugegraph-store/docker-entrypoint.sh"] |
| esc_key=$(printf '%s' "$key" | sed -e 's/[][(){}.^$*+?|\\/]/\\&/g') | ||
| esc_val=$(printf '%s' "$val" | sed -e 's/[&|\\]/\\&/g') | ||
|
|
||
| if [ ! -f "${DOCKER_FOLDER}/${INIT_FLAG_FILE}" ]; then | ||
| # wait for storage backend | ||
| ./bin/wait-storage.sh | ||
| if [ -z "$PASSWORD" ]; then | ||
| echo "init hugegraph with non-auth mode" | ||
| if grep -qE "^[[:space:]]*${esc_key}[[:space:]]*=" "${file}"; then | ||
| sed -ri "s|^([[:space:]]*${esc_key}[[:space:]]*=).*|\\1${esc_val}|" "${file}" | ||
| else |
There was a problem hiding this comment.
The set_prop helper interpolates the untrusted val argument (for example from HG_SERVER_BACKEND or HG_SERVER_PD_PEERS) directly into a double-quoted sed -ri expression. If an attacker can control one of these environment variables, they can inject $(command) or backticks so that arbitrary shell commands run when sed is invoked. Refactor this to ensure the replacement value is treated as literal data�validate or whitelist accepted formats and avoid embedding it directly into a sed program that the shell parses.
hugegraph-server/hugegraph-dist/src/assembly/static/bin/wait-storage.sh
Outdated
Show resolved
Hide resolved
… blocks, fix network config
Purpose of the PR
Fix single node Docker deployment failing on macOS and Windows due to Linux only host networking.
close #2951
Main Changes
Remove network_mode host from single node docker compose setup
Use default bridge networking
Add explicit port mappings
Add configuration volume mounts
Replace localhost and non routable addresses with container hostnames
Update healthcheck endpoints
Problem
The original single node Docker configuration uses network_mode host.
This only works on native Linux. Docker Desktop on macOS and Windows does not implement host networking the same way. Containers start but HugeGraph services advertise incorrect addresses such as 127.0.0.1 or 0.0.0.0.
Resulting failures:
The issue is not process failure but invalid service discovery and advertised endpoints.
Root Cause
Solution
Switch to bridge networking and advertise container resolvable hostnames.
Docker DNS resolves service names automatically. Services bind normally while exposing correct internal endpoints.
Verification
Observed behavior after changes on Docker Desktop macOS:
Container state
Server startup sequence
Hugegraph server are waiting for storage backend Initializing HugeGraph Store Starting HugeGraphServer ... OK StartedEndpoints
Server:
Returns service metadata.
Store:
Returns non zero leader and partition count:
{"leaderCount":12,"partitionCount":12}PD:
Returns expected auth response, confirming service availability.
Cluster becomes operational after initialization delay.
Why This Works
Does this PR potentially affect the following parts
Documentation Status
Related fixes discovered during this work:
getLeaderGrpcAddress()NPE in bridge mode — follower PDs crash redirecting to leaderIpAuthHandlerhostname vs IP mismatch — cross-node raft connections silently blockedChanges Checklist
IpAuthHandlerhostname vs IP resolution inRaftEngine.java(currently worked around via static IPs in docker-compose)getLeaderGrpcAddress()NPEIpAuthHandleris fixed upstream