From 571d7296e515ab1de6e24a0acb23d6c19c92e56b Mon Sep 17 00:00:00 2001 From: chengxi Date: Thu, 27 Aug 2026 20:50:28 -0400 Subject: [PATCH 1/2] chore(docs): provide detail for new configuration --- content/docs/introduction/getting-started.mdx | 3 ++- content/docs/sdk/node/examples.mdx | 1 + content/docs/sdk/node/intro.mdx | 1 + content/docs/sdk/php/intro.mdx | 1 + content/docs/sdk/python/examples.mdx | 1 + content/docs/sdk/python/intro.mdx | 1 + content/docs/server/configuration.mdx | 9 +++++++++ content/docs/server/docker.mdx | 10 ++++++++-- content/docs/web_ui/start.mdx | 3 +++ src/components/architecture-diagrams.tsx | 2 +- 10 files changed, 28 insertions(+), 4 deletions(-) diff --git a/content/docs/introduction/getting-started.mdx b/content/docs/introduction/getting-started.mdx index 7d012e120..e9df753ca 100644 --- a/content/docs/introduction/getting-started.mdx +++ b/content/docs/introduction/getting-started.mdx @@ -27,11 +27,12 @@ docker run --rm \ --cap-add=SYS_NICE --security-opt seccomp=unconfined --ulimit memlock=-1:-1 \ -p 8090:8090 \ -e IGGY_TCP_ADDRESS=0.0.0.0:8090 \ + -e IGGY_NODE_ADVERTISED_ADDRESS=localhost \ -e IGGY_ROOT_USERNAME=iggy -e IGGY_ROOT_PASSWORD=iggy \ apache/iggy:latest ``` -`SYS_NICE`, the seccomp setting and the memlock limit are all required by `io_uring` and the thread-per-core architecture; see [Docker & Helm](/docs/server/docker) for the details. `IGGY_TCP_ADDRESS` is needed because the server binds to `127.0.0.1` inside the container by default, which a published port cannot reach. Setting the root credentials explicitly means the username and password used later in this guide will work. +`SYS_NICE`, the seccomp setting and the memlock limit are all required by `io_uring` and the thread-per-core architecture; see [Docker & Helm](/docs/server/docker) for the details. `IGGY_TCP_ADDRESS` is needed because the server binds to `127.0.0.1` inside the container by default, which a published port cannot reach. `IGGY_NODE_ADVERTISED_ADDRESS` is needed because that wildcard leaves the server with no address to give clients, and it refuses to start rather than publish one nobody can dial. Here the port is published to the host, so `localhost` is that address. Setting the root credentials explicitly means the username and password used later in this guide will work. Alternatively, build from source by cloning the [repository](https://github.com/apache/iggy) and running: diff --git a/content/docs/sdk/node/examples.mdx b/content/docs/sdk/node/examples.mdx index 9adf48e9c..d3bd37250 100644 --- a/content/docs/sdk/node/examples.mdx +++ b/content/docs/sdk/node/examples.mdx @@ -23,6 +23,7 @@ docker run --rm \ --cap-add=SYS_NICE --security-opt seccomp=unconfined --ulimit memlock=-1:-1 \ -p 8090:8090 \ -e IGGY_TCP_ADDRESS=0.0.0.0:8090 \ + -e IGGY_NODE_ADVERTISED_ADDRESS=localhost \ -e IGGY_ROOT_USERNAME=iggy -e IGGY_ROOT_PASSWORD=iggy \ apache/iggy:latest diff --git a/content/docs/sdk/node/intro.mdx b/content/docs/sdk/node/intro.mdx index bca8e7fd4..f0c55253e 100644 --- a/content/docs/sdk/node/intro.mdx +++ b/content/docs/sdk/node/intro.mdx @@ -22,6 +22,7 @@ docker run --rm \ --cap-add=SYS_NICE --security-opt seccomp=unconfined --ulimit memlock=-1:-1 \ -p 8090:8090 \ -e IGGY_TCP_ADDRESS=0.0.0.0:8090 \ + -e IGGY_NODE_ADVERTISED_ADDRESS=localhost \ -e IGGY_ROOT_USERNAME=iggy -e IGGY_ROOT_PASSWORD=iggy \ apache/iggy:latest diff --git a/content/docs/sdk/php/intro.mdx b/content/docs/sdk/php/intro.mdx index 3b1e08ee1..c542522eb 100644 --- a/content/docs/sdk/php/intro.mdx +++ b/content/docs/sdk/php/intro.mdx @@ -41,6 +41,7 @@ docker run --rm \ --cap-add=SYS_NICE --security-opt seccomp=unconfined --ulimit memlock=-1:-1 \ -p 8090:8090 \ -e IGGY_TCP_ADDRESS=0.0.0.0:8090 \ + -e IGGY_NODE_ADVERTISED_ADDRESS=localhost \ -e IGGY_ROOT_USERNAME=iggy -e IGGY_ROOT_PASSWORD=iggy \ apache/iggy:latest diff --git a/content/docs/sdk/python/examples.mdx b/content/docs/sdk/python/examples.mdx index 02afce36d..5d630f047 100644 --- a/content/docs/sdk/python/examples.mdx +++ b/content/docs/sdk/python/examples.mdx @@ -18,6 +18,7 @@ docker run --rm \ --cap-add=SYS_NICE --security-opt seccomp=unconfined --ulimit memlock=-1:-1 \ -p 8090:8090 \ -e IGGY_TCP_ADDRESS=0.0.0.0:8090 \ + -e IGGY_NODE_ADVERTISED_ADDRESS=localhost \ -e IGGY_ROOT_USERNAME=iggy -e IGGY_ROOT_PASSWORD=iggy \ apache/iggy:latest diff --git a/content/docs/sdk/python/intro.mdx b/content/docs/sdk/python/intro.mdx index 8913702e8..b42c457b9 100644 --- a/content/docs/sdk/python/intro.mdx +++ b/content/docs/sdk/python/intro.mdx @@ -22,6 +22,7 @@ docker run --rm \ --cap-add=SYS_NICE --security-opt seccomp=unconfined --ulimit memlock=-1:-1 \ -p 8090:8090 \ -e IGGY_TCP_ADDRESS=0.0.0.0:8090 \ + -e IGGY_NODE_ADVERTISED_ADDRESS=localhost \ -e IGGY_ROOT_USERNAME=iggy -e IGGY_ROOT_PASSWORD=iggy \ apache/iggy:latest diff --git a/content/docs/server/configuration.mdx b/content/docs/server/configuration.mdx index 94a95bf07..23400ec40 100644 --- a/content/docs/server/configuration.mdx +++ b/content/docs/server/configuration.mdx @@ -35,6 +35,7 @@ Every configuration key can be overridden with an `IGGY_` variable. The name is ```bash IGGY_TCP_ADDRESS=0.0.0.0:8090 # [tcp] address +IGGY_NODE_ADVERTISED_ADDRESS=iggy-1 # [node] advertised_address IGGY_HTTP_ENABLED=true # [http] enabled IGGY_SYSTEM_PATH=/var/lib/iggy # [system] path IGGY_SYSTEM_LOGGING_LEVEL=debug # [system.logging] level @@ -410,6 +411,14 @@ Tunables for the internal bus that ships consensus traffic between replicas and |-----|---------|-------------| | `rebalancing_timeout` | `"30s"` | Maximum time a partition can remain in pending revocation before being force-transferred to the target member. | +### `[node]` + +This node's own client-facing identity, read only while `cluster.enabled = false`. In cluster mode the roster answers the same question per node, so a value here takes no effect and the server says so at startup. + +| Key | Default | Description | +|-----|---------|-------------| +| `advertised_address` | unset | The address clients dial, published in cluster metadata. A literal IP or a DNS hostname. Left unset, the server derives it from the bind address of the first enabled listener; that fails when the listener binds a wildcard, and the server refuses to start rather than publish an address no client can use. Declaring the unspecified address (`0.0.0.0`, `::`) is refused for the same reason. | + ### `[cluster]` Cluster mode is configured here but documented in [Clustering](/docs/clustering/vsr). The section contains: diff --git a/content/docs/server/docker.mdx b/content/docs/server/docker.mdx index 08d075909..fc9bebf20 100644 --- a/content/docs/server/docker.mdx +++ b/content/docs/server/docker.mdx @@ -10,6 +10,7 @@ Two properties of the published image matter for any deployment: - The working directory is `/app` and the `iggy-server` and `iggy` binaries are on `PATH` (`/usr/local/bin`). The default data directory `local_data` therefore resolves to `/app/local_data` - **mount your volume there**, or set `IGGY_SYSTEM_PATH` and mount that path instead. - The image bakes in no address overrides, so the server binds the loopback defaults (`127.0.0.1`) and is **unreachable from outside the container** even with published ports. Set `IGGY_TCP_ADDRESS=0.0.0.0:8090` (and the equivalent for every other transport you expose) alongside the `-p` flags. +- The wildcard says nothing about where clients reach the container, so the server refuses to start until `IGGY_NODE_ADVERTISED_ADDRESS` supplies that address. Use `localhost` when the ports are published to the host, the compose service name when the clients are containers on the same network, and the external hostname or load balancer name when they are further away. The value reaches clients through cluster metadata, which they read to follow redirects and to learn where to reconnect. Below is an example `docker-compose.yml` which overrides the default configuration (see [Configuration](/docs/server/configuration)) with environment variables. If you prefer using the configuration file, you can mount it as a volume and provide the path to it with the `IGGY_CONFIG_PATH` environment variable. @@ -34,6 +35,7 @@ services: - IGGY_ROOT_PASSWORD=Secret123 - IGGY_TCP_ADDRESS=0.0.0.0:8090 - IGGY_HTTP_ADDRESS=0.0.0.0:3000 + - IGGY_NODE_ADVERTISED_ADDRESS=localhost - IGGY_QUIC_ENABLED=false - IGGY_WEBSOCKET_ENABLED=false ports: @@ -53,6 +55,7 @@ docker run -d --name iggy \ --cap-add=SYS_NICE --security-opt seccomp=unconfined --ulimit memlock=-1:-1 \ -e IGGY_ROOT_USERNAME=iggy -e IGGY_ROOT_PASSWORD=Secret123 \ -e IGGY_TCP_ADDRESS=0.0.0.0:8090 -e IGGY_HTTP_ADDRESS=0.0.0.0:3000 \ + -e IGGY_NODE_ADVERTISED_ADDRESS=localhost \ -p 8090:8090 -p 3000:3000 \ -v iggy:/app/local_data \ apache/iggy:latest @@ -84,7 +87,7 @@ The repository root carries its own `Dockerfile` and `docker-compose.yml` for bu docker build -t iggy . ``` -Or use `docker compose up` directly from the repository root. That image **differs from the published one**: it sets the `0.0.0.0` listener addresses via `ENV` and keeps its data at `/local_data`. +Or use `docker compose up` directly from the repository root. That image **differs from the published one**: it sets the `0.0.0.0` listener addresses via `ENV` and keeps its data at `/local_data`. Its compose file publishes the ports to the host, so it declares `IGGY_NODE_ADVERTISED_ADDRESS=localhost`. ### Running the CLI inside the container @@ -106,7 +109,7 @@ helm install iggy ./helm/charts/iggy ### Chart components -- **Server Deployment** - runs `apache/iggy` with the pod security context the server needs: seccomp profile `Unconfined` (for `io_uring`) plus the `IPC_LOCK` capability (for memory locking). Listener addresses are set to `0.0.0.0` via `server.env`, and the data volume mounts at `/app/local_data`. +- **Server Deployment** - runs `apache/iggy` with the pod security context the server needs: seccomp profile `Unconfined` (for `io_uring`) plus the `IPC_LOCK` capability (for memory locking). Listener addresses are set to `0.0.0.0` via `server.env`, and the data volume mounts at `/app/local_data`. The chart supplies `IGGY_NODE_ADVERTISED_ADDRESS` as the in-cluster Service DNS name; override it with `server.advertisedAddress` when clients arrive through a LoadBalancer or an Ingress. Images that predate the setting, including the `0.7.0` pinned by default, log the variable as unknown and start anyway. - **Server Service** - exposes the `http` (3000), `quic` (8080), and `tcp` (8090) ports. WebSocket is not exposed by the chart. - **Web UI Deployment + Service** - a separate `apache/iggy-web-ui` deployment on port 3050, enabled by default (`ui.enabled`). - **Secret** - root user credentials from `server.users.root` (default `iggy`/`changeit`). Point `existingSecret` at your own Secret in production. @@ -120,6 +123,9 @@ helm install iggy ./helm/charts/iggy # values.yaml (excerpt, chart defaults) server: replicaCount: 1 + # The address clients dial, published in cluster metadata. Empty falls + # back to the in-cluster Service DNS name. + advertisedAddress: "" image: repository: apache/iggy tag: "0.7.0" diff --git a/content/docs/web_ui/start.mdx b/content/docs/web_ui/start.mdx index c43cf7132..b6c85e806 100644 --- a/content/docs/web_ui/start.mdx +++ b/content/docs/web_ui/start.mdx @@ -94,6 +94,9 @@ services: - IGGY_HTTP_ADDRESS=0.0.0.0:80 - IGGY_TCP_ENABLED=true - IGGY_TCP_ADDRESS=0.0.0.0:3000 + # The init container below reaches this service by its compose name, + # so publish that name rather than localhost. + - IGGY_NODE_ADVERTISED_ADDRESS=iggy - IGGY_QUIC_ENABLED=false - IGGY_WEBSOCKET_ENABLED=false ports: diff --git a/src/components/architecture-diagrams.tsx b/src/components/architecture-diagrams.tsx index 99e023306..b6c8cbfe7 100644 --- a/src/components/architecture-diagrams.tsx +++ b/src/components/architecture-diagrams.tsx @@ -1070,7 +1070,7 @@ export function WhyIggy() { export function QuickStartSnippet() { const steps = [ - { n: "1", label: "Start the server", code: "docker run --cap-add=SYS_NICE --security-opt seccomp=unconfined --ulimit memlock=-1:-1 -p 8090:8090 -e IGGY_TCP_ADDRESS=0.0.0.0:8090 -e IGGY_ROOT_USERNAME=iggy -e IGGY_ROOT_PASSWORD=iggy apache/iggy" }, + { n: "1", label: "Start the server", code: "docker run --cap-add=SYS_NICE --security-opt seccomp=unconfined --ulimit memlock=-1:-1 -p 8090:8090 -e IGGY_TCP_ADDRESS=0.0.0.0:8090 -e IGGY_NODE_ADVERTISED_ADDRESS=localhost -e IGGY_ROOT_USERNAME=iggy -e IGGY_ROOT_PASSWORD=iggy apache/iggy" }, { n: "2", label: "Add the SDK", code: "cargo add iggy" }, { n: "3", label: "Connect and send", code: 'let client = IggyClient::from_connection_string("iggy://iggy:iggy@localhost:8090")?;\nclient.connect().await?;' }, ]; From 833b10b42fbe2b80529a29afcb46aedc99df4c5b Mon Sep 17 00:00:00 2001 From: chengxi Date: Tue, 1 Sep 2026 15:05:36 -0400 Subject: [PATCH 2/2] fix-review --- content/docs/server/configuration.mdx | 7 ++++++- content/docs/server/docker.mdx | 10 ++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/content/docs/server/configuration.mdx b/content/docs/server/configuration.mdx index 23400ec40..b9171a5a2 100644 --- a/content/docs/server/configuration.mdx +++ b/content/docs/server/configuration.mdx @@ -10,6 +10,9 @@ A config file doesn't have to be complete. It is **merged over the embedded defa [system] path = "/var/lib/iggy" +[node] +advertised_address = "iggy-1" + [tcp] address = "0.0.0.0:8090" @@ -17,6 +20,8 @@ address = "0.0.0.0:8090" address = "0.0.0.0:3000" ``` +Both listeners here bind a wildcard, which tells the server nothing about where clients reach it, so [`[node]`](#node) has to name that address explicitly - without it this file is refused at boot. + ## How configuration loads Configuration is resolved in three layers. Later layers win: @@ -413,7 +418,7 @@ Tunables for the internal bus that ships consensus traffic between replicas and ### `[node]` -This node's own client-facing identity, read only while `cluster.enabled = false`. In cluster mode the roster answers the same question per node, so a value here takes no effect and the server says so at startup. +This node's own client-facing identity. The address is read only while `cluster.enabled = false`: in cluster mode the roster answers the same question per node, so the address itself is ignored and the server says so at startup. The key is still validated in every mode, so a malformed value refuses boot even with `cluster.enabled = true`. | Key | Default | Description | |-----|---------|-------------| diff --git a/content/docs/server/docker.mdx b/content/docs/server/docker.mdx index fc9bebf20..ee76e8cad 100644 --- a/content/docs/server/docker.mdx +++ b/content/docs/server/docker.mdx @@ -10,7 +10,7 @@ Two properties of the published image matter for any deployment: - The working directory is `/app` and the `iggy-server` and `iggy` binaries are on `PATH` (`/usr/local/bin`). The default data directory `local_data` therefore resolves to `/app/local_data` - **mount your volume there**, or set `IGGY_SYSTEM_PATH` and mount that path instead. - The image bakes in no address overrides, so the server binds the loopback defaults (`127.0.0.1`) and is **unreachable from outside the container** even with published ports. Set `IGGY_TCP_ADDRESS=0.0.0.0:8090` (and the equivalent for every other transport you expose) alongside the `-p` flags. -- The wildcard says nothing about where clients reach the container, so the server refuses to start until `IGGY_NODE_ADVERTISED_ADDRESS` supplies that address. Use `localhost` when the ports are published to the host, the compose service name when the clients are containers on the same network, and the external hostname or load balancer name when they are further away. The value reaches clients through cluster metadata, which they read to follow redirects and to learn where to reconnect. +- The wildcard says nothing about where clients reach the container, so the server refuses to start until `IGGY_NODE_ADVERTISED_ADDRESS` supplies that address. Use `localhost` when the ports are published to the host, the compose service name when the clients are containers on the same network, and the external hostname or load balancer name when they are further away. The value reaches clients through cluster metadata, where it is the endpoint they reconnect through. Below is an example `docker-compose.yml` which overrides the default configuration (see [Configuration](/docs/server/configuration)) with environment variables. If you prefer using the configuration file, you can mount it as a volume and provide the path to it with the `IGGY_CONFIG_PATH` environment variable. @@ -87,7 +87,7 @@ The repository root carries its own `Dockerfile` and `docker-compose.yml` for bu docker build -t iggy . ``` -Or use `docker compose up` directly from the repository root. That image **differs from the published one**: it sets the `0.0.0.0` listener addresses via `ENV` and keeps its data at `/local_data`. Its compose file publishes the ports to the host, so it declares `IGGY_NODE_ADVERTISED_ADDRESS=localhost`. +Or use `docker compose up` directly from the repository root. That image **differs from the published one**: it sets the `0.0.0.0` address of all four listeners via `ENV` and keeps its data at `/local_data`. Those wildcards are baked into the image, so a plain `docker run` of it refuses to start until you pass `IGGY_NODE_ADVERTISED_ADDRESS` yourself. The repository's compose file publishes the ports to the host, so it declares `IGGY_NODE_ADVERTISED_ADDRESS=localhost`. ### Running the CLI inside the container @@ -123,8 +123,10 @@ helm install iggy ./helm/charts/iggy # values.yaml (excerpt, chart defaults) server: replicaCount: 1 - # The address clients dial, published in cluster metadata. Empty falls - # back to the in-cluster Service DNS name. + # The address clients dial, published in cluster metadata. Declaring + # IGGY_NODE_ADVERTISED_ADDRESS in server.env instead also works, but + # setting both is refused at render time. Empty falls back to the + # in-cluster Service DNS name. advertisedAddress: "" image: repository: apache/iggy