feat(docker): managed-mode env-var bootstrap - #32

Merged
moonming merged 1 commit into
mainfrom
feat/managed-env-bootstrap
Apr 23, 2026
Merged

feat(docker): managed-mode env-var bootstrap#32
moonming merged 1 commit into
mainfrom
feat/managed-env-bootstrap

Conversation

@moonming

Copy link
Copy Markdown
Member

Summary

Lets the same Docker image serve both standalone and managed (aisix.cloud tenant) deployments without re-templating config files.

  • `config.managed.yaml` — baked into the image at `/etc/aisix/config.managed.yaml`. Placeholder etcd endpoint (overwritten by the `/dp/register` response), `managed.enabled = true`, unbindable admin port (defence-in-depth).
  • `docker/entrypoint.sh` — picks the config via `AISIX_CONFIG_PATH`. Standalone: mount your config at the default `/etc/aisix/config.yaml`. Managed: point `AISIX_CONFIG_PATH` at the baked file and inject `AISIX_MANAGED__REGISTRATION_TOKEN` + `AISIX_MANAGED__CP_BASE_URL`.

The existing bootstrap from #30 + #31 already does the heavy lifting: register-and-persist on first boot, reload mTLS bundle on restart, spawn heartbeat worker.

Why now

Unblocks AISIX-Cloud E2E scenarios 2 / 3 / 4. The test harness can now `docker run ghcr.io/moonming/ai-gateway:aisix-e2e` with a deployment_token from the SaaS layer and the DP registers itself without any pre-baked certs.

Tests

  • New `parses_managed_block_with_register_fields` locks the YAML shape — any new required `ManagedConfig` field will fail CI loudly instead of silently breaking the image template.
  • `cargo fmt --check` + `cargo clippy --all-targets --locked -- -D warnings` clean.

Out of scope

  • DP-side local snapshot (offline_resilience prerequisite) — separate change.
  • `/dp/telemetry` worker — separate change.

Test plan

  • `cargo test -p aisix-core` (9 passing, +1 new)
  • `cargo clippy --all-targets --locked -- -D warnings`
  • `docker build -t aisix:dev .` succeeds
  • `docker run -e AISIX_CONFIG_PATH=/etc/aisix/config.managed.yaml aisix:dev` exits with the expected "missing token" error

The same Docker image now serves both standalone and managed
(aisix.cloud tenant) deployments. Two pieces:
- config.managed.yaml — bootstrap template baked at
/etc/aisix/config.managed.yaml. Has placeholder etcd endpoint
(overwritten by /dp/register response), managed.enabled = true,
and unbindable admin (defence-in-depth if managed mode somehow
flipped off). All real per-DP secrets come from env vars.
- docker/entrypoint.sh — picks the config file via AISIX_CONFIG_PATH
(default /etc/aisix/config.yaml). Standalone users mount their
config at the default path; managed users point AISIX_CONFIG_PATH
at the baked file and inject AISIX_MANAGED__REGISTRATION_TOKEN +
AISIX_MANAGED__CP_BASE_URL.
Existing main.rs bootstrap (PR #30 + #31) already does the rest:
register-and-persist on first boot, reload bundle on subsequent
boots, spawn heartbeat worker.
Tests: parses_managed_block_with_register_fields locks the YAML
shape so any new required field on ManagedConfig fails CI loudly
instead of silently breaking the image.
Docs: docs/managed-mode.md walks operators through first boot,
restart semantics, env-var override matrix, and common errors.
This unblocks AISIX-Cloud E2E scenarios 2/3/4 — the test harness
can now `docker run` aisix with a deployment_token and have the DP
register itself without prebaked certs.
CopilotAI review requested due to automatic review settings April 23, 2026 12:38
@moonming
moonming merged commit 8c2a727 into mainApr 23, 2026
8 of 10 checks passed

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Enables a single Docker image to support both standalone deployments (operator-mounted config) and managed-mode (aisix.cloud tenant) deployments by baking a managed bootstrap config into the image and selecting the config path at runtime via an entrypoint.

Changes:

  • Add a baked config.managed.yaml template intended for managed-mode bootstrapping.
  • Introduce docker/entrypoint.sh to choose the config file via AISIX_CONFIG_PATH and exec aisix --config ....
  • Add managed-mode documentation and a config parsing test to lock the managed YAML shape.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
docs/managed-mode.mdNew guide for running the official image in managed mode (register + heartbeat + env overrides).
docker/entrypoint.shNew container entrypoint that selects config path via AISIX_CONFIG_PATH and runs aisix.
crates/aisix-core/src/config.rsAdds a regression test ensuring managed-mode YAML shape remains valid as ManagedConfig evolves.
config.managed.yamlAdds a managed-mode bootstrap config intended to be baked into the image.
DockerfileBakes the managed config, adds the entrypoint script, and switches ENTRYPOINT to use it.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadconfig.managed.yaml
@@ -0,0 +1,72 @@
# aisix — managed-mode bootstrap config (aisix.cloud tenant).
#
# Used by the official Docker image as `/etc/aisix/config.yaml`.

CopilotAIApr 23, 2026

Copy link

Choose a reason for hiding this comment

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

The header comment says this file is used as /etc/aisix/config.yaml, but the Dockerfile copies it to /etc/aisix/config.managed.yaml and the docs/entrypoint reference that path. This mismatch is likely to confuse operators; update the comment (or the copy destination) so the documented path matches the image layout.

Suggested change
# Used by the official Docker image as `/etc/aisix/config.yaml`.
# Used by the official Docker image as `/etc/aisix/config.managed.yaml`.

Copilot uses AI. Check for mistakes.
Comment threaddocker/entrypoint.sh
exit 64
fi

exec /usr/local/bin/aisix --config "$CONFIG_PATH"

CopilotAIApr 23, 2026

Copy link

Choose a reason for hiding this comment

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

The entrypoint ignores any arguments passed to docker run because it always execs aisix --config ... with no "$@" forwarding. That prevents common uses like docker run <image> -- --help or passing additional CLI flags. Forward the args (and/or treat args as an override command) so the container remains composable.

Suggested change
exec /usr/local/bin/aisix --config "$CONFIG_PATH"
exec /usr/local/bin/aisix --config "$CONFIG_PATH""$@"

Copilot uses AI. Check for mistakes.
@jarvis9443
jarvis9443 deleted the feat/managed-env-bootstrap branch June 25, 2026 06:25
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(docker): managed-mode env-var bootstrap - #32

Merged
moonming merged 1 commit into
mainfrom
feat/managed-env-bootstrap
Apr 23, 2026
Merged

feat(docker): managed-mode env-var bootstrap#32
moonming merged 1 commit into
mainfrom
feat/managed-env-bootstrap

Conversation

@moonming

Copy link
Copy Markdown
Member

Summary

Lets the same Docker image serve both standalone and managed (aisix.cloud tenant) deployments without re-templating config files.

  • `config.managed.yaml` — baked into the image at `/etc/aisix/config.managed.yaml`. Placeholder etcd endpoint (overwritten by the `/dp/register` response), `managed.enabled = true`, unbindable admin port (defence-in-depth).
  • `docker/entrypoint.sh` — picks the config via `AISIX_CONFIG_PATH`. Standalone: mount your config at the default `/etc/aisix/config.yaml`. Managed: point `AISIX_CONFIG_PATH` at the baked file and inject `AISIX_MANAGED__REGISTRATION_TOKEN` + `AISIX_MANAGED__CP_BASE_URL`.

The existing bootstrap from #30 + #31 already does the heavy lifting: register-and-persist on first boot, reload mTLS bundle on restart, spawn heartbeat worker.

Why now

Unblocks AISIX-Cloud E2E scenarios 2 / 3 / 4. The test harness can now `docker run ghcr.io/moonming/ai-gateway:aisix-e2e` with a deployment_token from the SaaS layer and the DP registers itself without any pre-baked certs.

Tests

  • New `parses_managed_block_with_register_fields` locks the YAML shape — any new required `ManagedConfig` field will fail CI loudly instead of silently breaking the image template.
  • `cargo fmt --check` + `cargo clippy --all-targets --locked -- -D warnings` clean.

Out of scope

  • DP-side local snapshot (offline_resilience prerequisite) — separate change.
  • `/dp/telemetry` worker — separate change.

Test plan

  • `cargo test -p aisix-core` (9 passing, +1 new)
  • `cargo clippy --all-targets --locked -- -D warnings`
  • `docker build -t aisix:dev .` succeeds
  • `docker run -e AISIX_CONFIG_PATH=/etc/aisix/config.managed.yaml aisix:dev` exits with the expected "missing token" error

The same Docker image now serves both standalone and managed
(aisix.cloud tenant) deployments. Two pieces:
- config.managed.yaml — bootstrap template baked at
/etc/aisix/config.managed.yaml. Has placeholder etcd endpoint
(overwritten by /dp/register response), managed.enabled = true,
and unbindable admin (defence-in-depth if managed mode somehow
flipped off). All real per-DP secrets come from env vars.
- docker/entrypoint.sh — picks the config file via AISIX_CONFIG_PATH
(default /etc/aisix/config.yaml). Standalone users mount their
config at the default path; managed users point AISIX_CONFIG_PATH
at the baked file and inject AISIX_MANAGED__REGISTRATION_TOKEN +
AISIX_MANAGED__CP_BASE_URL.
Existing main.rs bootstrap (PR #30 + #31) already does the rest:
register-and-persist on first boot, reload bundle on subsequent
boots, spawn heartbeat worker.
Tests: parses_managed_block_with_register_fields locks the YAML
shape so any new required field on ManagedConfig fails CI loudly
instead of silently breaking the image.
Docs: docs/managed-mode.md walks operators through first boot,
restart semantics, env-var override matrix, and common errors.
This unblocks AISIX-Cloud E2E scenarios 2/3/4 — the test harness
can now `docker run` aisix with a deployment_token and have the DP
register itself without prebaked certs.
CopilotAI review requested due to automatic review settings April 23, 2026 12:38
@moonming
moonming merged commit 8c2a727 into mainApr 23, 2026
8 of 10 checks passed

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Enables a single Docker image to support both standalone deployments (operator-mounted config) and managed-mode (aisix.cloud tenant) deployments by baking a managed bootstrap config into the image and selecting the config path at runtime via an entrypoint.

Changes:

  • Add a baked config.managed.yaml template intended for managed-mode bootstrapping.
  • Introduce docker/entrypoint.sh to choose the config file via AISIX_CONFIG_PATH and exec aisix --config ....
  • Add managed-mode documentation and a config parsing test to lock the managed YAML shape.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
docs/managed-mode.mdNew guide for running the official image in managed mode (register + heartbeat + env overrides).
docker/entrypoint.shNew container entrypoint that selects config path via AISIX_CONFIG_PATH and runs aisix.
crates/aisix-core/src/config.rsAdds a regression test ensuring managed-mode YAML shape remains valid as ManagedConfig evolves.
config.managed.yamlAdds a managed-mode bootstrap config intended to be baked into the image.
DockerfileBakes the managed config, adds the entrypoint script, and switches ENTRYPOINT to use it.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadconfig.managed.yaml
@@ -0,0 +1,72 @@
# aisix — managed-mode bootstrap config (aisix.cloud tenant).
#
# Used by the official Docker image as `/etc/aisix/config.yaml`.

CopilotAIApr 23, 2026

Copy link

Choose a reason for hiding this comment

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

The header comment says this file is used as /etc/aisix/config.yaml, but the Dockerfile copies it to /etc/aisix/config.managed.yaml and the docs/entrypoint reference that path. This mismatch is likely to confuse operators; update the comment (or the copy destination) so the documented path matches the image layout.

Suggested change
# Used by the official Docker image as `/etc/aisix/config.yaml`.
# Used by the official Docker image as `/etc/aisix/config.managed.yaml`.

Copilot uses AI. Check for mistakes.
Comment threaddocker/entrypoint.sh
exit 64
fi

exec /usr/local/bin/aisix --config "$CONFIG_PATH"

CopilotAIApr 23, 2026

Copy link

Choose a reason for hiding this comment

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

The entrypoint ignores any arguments passed to docker run because it always execs aisix --config ... with no "$@" forwarding. That prevents common uses like docker run <image> -- --help or passing additional CLI flags. Forward the args (and/or treat args as an override command) so the container remains composable.

Suggested change
exec /usr/local/bin/aisix --config "$CONFIG_PATH"
exec /usr/local/bin/aisix --config "$CONFIG_PATH""$@"

Copilot uses AI. Check for mistakes.
@jarvis9443
jarvis9443 deleted the feat/managed-env-bootstrap branch June 25, 2026 06:25
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(docker): managed-mode env-var bootstrap - #32

Merged
moonming merged 1 commit into
mainfrom
feat/managed-env-bootstrap
Apr 23, 2026
Merged

feat(docker): managed-mode env-var bootstrap#32
moonming merged 1 commit into
mainfrom
feat/managed-env-bootstrap

Conversation

@moonming

Copy link
Copy Markdown
Member

Summary

Lets the same Docker image serve both standalone and managed (aisix.cloud tenant) deployments without re-templating config files.

  • `config.managed.yaml` — baked into the image at `/etc/aisix/config.managed.yaml`. Placeholder etcd endpoint (overwritten by the `/dp/register` response), `managed.enabled = true`, unbindable admin port (defence-in-depth).
  • `docker/entrypoint.sh` — picks the config via `AISIX_CONFIG_PATH`. Standalone: mount your config at the default `/etc/aisix/config.yaml`. Managed: point `AISIX_CONFIG_PATH` at the baked file and inject `AISIX_MANAGED__REGISTRATION_TOKEN` + `AISIX_MANAGED__CP_BASE_URL`.

The existing bootstrap from #30 + #31 already does the heavy lifting: register-and-persist on first boot, reload mTLS bundle on restart, spawn heartbeat worker.

Why now

Unblocks AISIX-Cloud E2E scenarios 2 / 3 / 4. The test harness can now `docker run ghcr.io/moonming/ai-gateway:aisix-e2e` with a deployment_token from the SaaS layer and the DP registers itself without any pre-baked certs.

Tests

  • New `parses_managed_block_with_register_fields` locks the YAML shape — any new required `ManagedConfig` field will fail CI loudly instead of silently breaking the image template.
  • `cargo fmt --check` + `cargo clippy --all-targets --locked -- -D warnings` clean.

Out of scope

  • DP-side local snapshot (offline_resilience prerequisite) — separate change.
  • `/dp/telemetry` worker — separate change.

Test plan

  • `cargo test -p aisix-core` (9 passing, +1 new)
  • `cargo clippy --all-targets --locked -- -D warnings`
  • `docker build -t aisix:dev .` succeeds
  • `docker run -e AISIX_CONFIG_PATH=/etc/aisix/config.managed.yaml aisix:dev` exits with the expected "missing token" error

The same Docker image now serves both standalone and managed
(aisix.cloud tenant) deployments. Two pieces:
- config.managed.yaml — bootstrap template baked at
/etc/aisix/config.managed.yaml. Has placeholder etcd endpoint
(overwritten by /dp/register response), managed.enabled = true,
and unbindable admin (defence-in-depth if managed mode somehow
flipped off). All real per-DP secrets come from env vars.
- docker/entrypoint.sh — picks the config file via AISIX_CONFIG_PATH
(default /etc/aisix/config.yaml). Standalone users mount their
config at the default path; managed users point AISIX_CONFIG_PATH
at the baked file and inject AISIX_MANAGED__REGISTRATION_TOKEN +
AISIX_MANAGED__CP_BASE_URL.
Existing main.rs bootstrap (PR #30 + #31) already does the rest:
register-and-persist on first boot, reload bundle on subsequent
boots, spawn heartbeat worker.
Tests: parses_managed_block_with_register_fields locks the YAML
shape so any new required field on ManagedConfig fails CI loudly
instead of silently breaking the image.
Docs: docs/managed-mode.md walks operators through first boot,
restart semantics, env-var override matrix, and common errors.
This unblocks AISIX-Cloud E2E scenarios 2/3/4 — the test harness
can now `docker run` aisix with a deployment_token and have the DP
register itself without prebaked certs.
CopilotAI review requested due to automatic review settings April 23, 2026 12:38
@moonming
moonming merged commit 8c2a727 into mainApr 23, 2026
8 of 10 checks passed

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Enables a single Docker image to support both standalone deployments (operator-mounted config) and managed-mode (aisix.cloud tenant) deployments by baking a managed bootstrap config into the image and selecting the config path at runtime via an entrypoint.

Changes:

  • Add a baked config.managed.yaml template intended for managed-mode bootstrapping.
  • Introduce docker/entrypoint.sh to choose the config file via AISIX_CONFIG_PATH and exec aisix --config ....
  • Add managed-mode documentation and a config parsing test to lock the managed YAML shape.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
docs/managed-mode.mdNew guide for running the official image in managed mode (register + heartbeat + env overrides).
docker/entrypoint.shNew container entrypoint that selects config path via AISIX_CONFIG_PATH and runs aisix.
crates/aisix-core/src/config.rsAdds a regression test ensuring managed-mode YAML shape remains valid as ManagedConfig evolves.
config.managed.yamlAdds a managed-mode bootstrap config intended to be baked into the image.
DockerfileBakes the managed config, adds the entrypoint script, and switches ENTRYPOINT to use it.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadconfig.managed.yaml
@@ -0,0 +1,72 @@
# aisix — managed-mode bootstrap config (aisix.cloud tenant).
#
# Used by the official Docker image as `/etc/aisix/config.yaml`.

CopilotAIApr 23, 2026

Copy link

Choose a reason for hiding this comment

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

The header comment says this file is used as /etc/aisix/config.yaml, but the Dockerfile copies it to /etc/aisix/config.managed.yaml and the docs/entrypoint reference that path. This mismatch is likely to confuse operators; update the comment (or the copy destination) so the documented path matches the image layout.

Suggested change
# Used by the official Docker image as `/etc/aisix/config.yaml`.
# Used by the official Docker image as `/etc/aisix/config.managed.yaml`.

Copilot uses AI. Check for mistakes.
Comment threaddocker/entrypoint.sh
exit 64
fi

exec /usr/local/bin/aisix --config "$CONFIG_PATH"

CopilotAIApr 23, 2026

Copy link

Choose a reason for hiding this comment

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

The entrypoint ignores any arguments passed to docker run because it always execs aisix --config ... with no "$@" forwarding. That prevents common uses like docker run <image> -- --help or passing additional CLI flags. Forward the args (and/or treat args as an override command) so the container remains composable.

Suggested change
exec /usr/local/bin/aisix --config "$CONFIG_PATH"
exec /usr/local/bin/aisix --config "$CONFIG_PATH""$@"

Copilot uses AI. Check for mistakes.
@jarvis9443
jarvis9443 deleted the feat/managed-env-bootstrap branch June 25, 2026 06:25
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(docker): managed-mode env-var bootstrap - #32

Merged
moonming merged 1 commit into
mainfrom
feat/managed-env-bootstrap
Apr 23, 2026
Merged

feat(docker): managed-mode env-var bootstrap#32
moonming merged 1 commit into
mainfrom
feat/managed-env-bootstrap

Conversation

@moonming

Copy link
Copy Markdown
Member

Summary

Lets the same Docker image serve both standalone and managed (aisix.cloud tenant) deployments without re-templating config files.

  • `config.managed.yaml` — baked into the image at `/etc/aisix/config.managed.yaml`. Placeholder etcd endpoint (overwritten by the `/dp/register` response), `managed.enabled = true`, unbindable admin port (defence-in-depth).
  • `docker/entrypoint.sh` — picks the config via `AISIX_CONFIG_PATH`. Standalone: mount your config at the default `/etc/aisix/config.yaml`. Managed: point `AISIX_CONFIG_PATH` at the baked file and inject `AISIX_MANAGED__REGISTRATION_TOKEN` + `AISIX_MANAGED__CP_BASE_URL`.

The existing bootstrap from #30 + #31 already does the heavy lifting: register-and-persist on first boot, reload mTLS bundle on restart, spawn heartbeat worker.

Why now

Unblocks AISIX-Cloud E2E scenarios 2 / 3 / 4. The test harness can now `docker run ghcr.io/moonming/ai-gateway:aisix-e2e` with a deployment_token from the SaaS layer and the DP registers itself without any pre-baked certs.

Tests

  • New `parses_managed_block_with_register_fields` locks the YAML shape — any new required `ManagedConfig` field will fail CI loudly instead of silently breaking the image template.
  • `cargo fmt --check` + `cargo clippy --all-targets --locked -- -D warnings` clean.

Out of scope

  • DP-side local snapshot (offline_resilience prerequisite) — separate change.
  • `/dp/telemetry` worker — separate change.

Test plan

  • `cargo test -p aisix-core` (9 passing, +1 new)
  • `cargo clippy --all-targets --locked -- -D warnings`
  • `docker build -t aisix:dev .` succeeds
  • `docker run -e AISIX_CONFIG_PATH=/etc/aisix/config.managed.yaml aisix:dev` exits with the expected "missing token" error

The same Docker image now serves both standalone and managed
(aisix.cloud tenant) deployments. Two pieces:
- config.managed.yaml — bootstrap template baked at
/etc/aisix/config.managed.yaml. Has placeholder etcd endpoint
(overwritten by /dp/register response), managed.enabled = true,
and unbindable admin (defence-in-depth if managed mode somehow
flipped off). All real per-DP secrets come from env vars.
- docker/entrypoint.sh — picks the config file via AISIX_CONFIG_PATH
(default /etc/aisix/config.yaml). Standalone users mount their
config at the default path; managed users point AISIX_CONFIG_PATH
at the baked file and inject AISIX_MANAGED__REGISTRATION_TOKEN +
AISIX_MANAGED__CP_BASE_URL.
Existing main.rs bootstrap (PR #30 + #31) already does the rest:
register-and-persist on first boot, reload bundle on subsequent
boots, spawn heartbeat worker.
Tests: parses_managed_block_with_register_fields locks the YAML
shape so any new required field on ManagedConfig fails CI loudly
instead of silently breaking the image.
Docs: docs/managed-mode.md walks operators through first boot,
restart semantics, env-var override matrix, and common errors.
This unblocks AISIX-Cloud E2E scenarios 2/3/4 — the test harness
can now `docker run` aisix with a deployment_token and have the DP
register itself without prebaked certs.
CopilotAI review requested due to automatic review settings April 23, 2026 12:38
@moonming
moonming merged commit 8c2a727 into mainApr 23, 2026
8 of 10 checks passed

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Enables a single Docker image to support both standalone deployments (operator-mounted config) and managed-mode (aisix.cloud tenant) deployments by baking a managed bootstrap config into the image and selecting the config path at runtime via an entrypoint.

Changes:

  • Add a baked config.managed.yaml template intended for managed-mode bootstrapping.
  • Introduce docker/entrypoint.sh to choose the config file via AISIX_CONFIG_PATH and exec aisix --config ....
  • Add managed-mode documentation and a config parsing test to lock the managed YAML shape.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
docs/managed-mode.mdNew guide for running the official image in managed mode (register + heartbeat + env overrides).
docker/entrypoint.shNew container entrypoint that selects config path via AISIX_CONFIG_PATH and runs aisix.
crates/aisix-core/src/config.rsAdds a regression test ensuring managed-mode YAML shape remains valid as ManagedConfig evolves.
config.managed.yamlAdds a managed-mode bootstrap config intended to be baked into the image.
DockerfileBakes the managed config, adds the entrypoint script, and switches ENTRYPOINT to use it.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadconfig.managed.yaml
@@ -0,0 +1,72 @@
# aisix — managed-mode bootstrap config (aisix.cloud tenant).
#
# Used by the official Docker image as `/etc/aisix/config.yaml`.

CopilotAIApr 23, 2026

Copy link

Choose a reason for hiding this comment

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

The header comment says this file is used as /etc/aisix/config.yaml, but the Dockerfile copies it to /etc/aisix/config.managed.yaml and the docs/entrypoint reference that path. This mismatch is likely to confuse operators; update the comment (or the copy destination) so the documented path matches the image layout.

Suggested change
# Used by the official Docker image as `/etc/aisix/config.yaml`.
# Used by the official Docker image as `/etc/aisix/config.managed.yaml`.

Copilot uses AI. Check for mistakes.
Comment threaddocker/entrypoint.sh
exit 64
fi

exec /usr/local/bin/aisix --config "$CONFIG_PATH"

CopilotAIApr 23, 2026

Copy link

Choose a reason for hiding this comment

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

The entrypoint ignores any arguments passed to docker run because it always execs aisix --config ... with no "$@" forwarding. That prevents common uses like docker run <image> -- --help or passing additional CLI flags. Forward the args (and/or treat args as an override command) so the container remains composable.

Suggested change
exec /usr/local/bin/aisix --config "$CONFIG_PATH"
exec /usr/local/bin/aisix --config "$CONFIG_PATH""$@"

Copilot uses AI. Check for mistakes.
@jarvis9443
jarvis9443 deleted the feat/managed-env-bootstrap branch June 25, 2026 06:25
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(docker): managed-mode env-var bootstrap - #32

Merged
moonming merged 1 commit into
mainfrom
feat/managed-env-bootstrap
Apr 23, 2026
Merged

feat(docker): managed-mode env-var bootstrap#32
moonming merged 1 commit into
mainfrom
feat/managed-env-bootstrap

Conversation

@moonming

Copy link
Copy Markdown
Member

Summary

Lets the same Docker image serve both standalone and managed (aisix.cloud tenant) deployments without re-templating config files.

  • `config.managed.yaml` — baked into the image at `/etc/aisix/config.managed.yaml`. Placeholder etcd endpoint (overwritten by the `/dp/register` response), `managed.enabled = true`, unbindable admin port (defence-in-depth).
  • `docker/entrypoint.sh` — picks the config via `AISIX_CONFIG_PATH`. Standalone: mount your config at the default `/etc/aisix/config.yaml`. Managed: point `AISIX_CONFIG_PATH` at the baked file and inject `AISIX_MANAGED__REGISTRATION_TOKEN` + `AISIX_MANAGED__CP_BASE_URL`.

The existing bootstrap from #30 + #31 already does the heavy lifting: register-and-persist on first boot, reload mTLS bundle on restart, spawn heartbeat worker.

Why now

Unblocks AISIX-Cloud E2E scenarios 2 / 3 / 4. The test harness can now `docker run ghcr.io/moonming/ai-gateway:aisix-e2e` with a deployment_token from the SaaS layer and the DP registers itself without any pre-baked certs.

Tests

  • New `parses_managed_block_with_register_fields` locks the YAML shape — any new required `ManagedConfig` field will fail CI loudly instead of silently breaking the image template.
  • `cargo fmt --check` + `cargo clippy --all-targets --locked -- -D warnings` clean.

Out of scope

  • DP-side local snapshot (offline_resilience prerequisite) — separate change.
  • `/dp/telemetry` worker — separate change.

Test plan

  • `cargo test -p aisix-core` (9 passing, +1 new)
  • `cargo clippy --all-targets --locked -- -D warnings`
  • `docker build -t aisix:dev .` succeeds
  • `docker run -e AISIX_CONFIG_PATH=/etc/aisix/config.managed.yaml aisix:dev` exits with the expected "missing token" error

The same Docker image now serves both standalone and managed
(aisix.cloud tenant) deployments. Two pieces:
- config.managed.yaml — bootstrap template baked at
/etc/aisix/config.managed.yaml. Has placeholder etcd endpoint
(overwritten by /dp/register response), managed.enabled = true,
and unbindable admin (defence-in-depth if managed mode somehow
flipped off). All real per-DP secrets come from env vars.
- docker/entrypoint.sh — picks the config file via AISIX_CONFIG_PATH
(default /etc/aisix/config.yaml). Standalone users mount their
config at the default path; managed users point AISIX_CONFIG_PATH
at the baked file and inject AISIX_MANAGED__REGISTRATION_TOKEN +
AISIX_MANAGED__CP_BASE_URL.
Existing main.rs bootstrap (PR #30 + #31) already does the rest:
register-and-persist on first boot, reload bundle on subsequent
boots, spawn heartbeat worker.
Tests: parses_managed_block_with_register_fields locks the YAML
shape so any new required field on ManagedConfig fails CI loudly
instead of silently breaking the image.
Docs: docs/managed-mode.md walks operators through first boot,
restart semantics, env-var override matrix, and common errors.
This unblocks AISIX-Cloud E2E scenarios 2/3/4 — the test harness
can now `docker run` aisix with a deployment_token and have the DP
register itself without prebaked certs.
CopilotAI review requested due to automatic review settings April 23, 2026 12:38
@moonming
moonming merged commit 8c2a727 into mainApr 23, 2026
8 of 10 checks passed

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Enables a single Docker image to support both standalone deployments (operator-mounted config) and managed-mode (aisix.cloud tenant) deployments by baking a managed bootstrap config into the image and selecting the config path at runtime via an entrypoint.

Changes:

  • Add a baked config.managed.yaml template intended for managed-mode bootstrapping.
  • Introduce docker/entrypoint.sh to choose the config file via AISIX_CONFIG_PATH and exec aisix --config ....
  • Add managed-mode documentation and a config parsing test to lock the managed YAML shape.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
docs/managed-mode.mdNew guide for running the official image in managed mode (register + heartbeat + env overrides).
docker/entrypoint.shNew container entrypoint that selects config path via AISIX_CONFIG_PATH and runs aisix.
crates/aisix-core/src/config.rsAdds a regression test ensuring managed-mode YAML shape remains valid as ManagedConfig evolves.
config.managed.yamlAdds a managed-mode bootstrap config intended to be baked into the image.
DockerfileBakes the managed config, adds the entrypoint script, and switches ENTRYPOINT to use it.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadconfig.managed.yaml
@@ -0,0 +1,72 @@
# aisix — managed-mode bootstrap config (aisix.cloud tenant).
#
# Used by the official Docker image as `/etc/aisix/config.yaml`.

CopilotAIApr 23, 2026

Copy link

Choose a reason for hiding this comment

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

The header comment says this file is used as /etc/aisix/config.yaml, but the Dockerfile copies it to /etc/aisix/config.managed.yaml and the docs/entrypoint reference that path. This mismatch is likely to confuse operators; update the comment (or the copy destination) so the documented path matches the image layout.

Suggested change
# Used by the official Docker image as `/etc/aisix/config.yaml`.
# Used by the official Docker image as `/etc/aisix/config.managed.yaml`.

Copilot uses AI. Check for mistakes.
Comment threaddocker/entrypoint.sh
exit 64
fi

exec /usr/local/bin/aisix --config "$CONFIG_PATH"

CopilotAIApr 23, 2026

Copy link

Choose a reason for hiding this comment

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

The entrypoint ignores any arguments passed to docker run because it always execs aisix --config ... with no "$@" forwarding. That prevents common uses like docker run <image> -- --help or passing additional CLI flags. Forward the args (and/or treat args as an override command) so the container remains composable.

Suggested change
exec /usr/local/bin/aisix --config "$CONFIG_PATH"
exec /usr/local/bin/aisix --config "$CONFIG_PATH""$@"

Copilot uses AI. Check for mistakes.
@jarvis9443
jarvis9443 deleted the feat/managed-env-bootstrap branch June 25, 2026 06:25
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(docker): managed-mode env-var bootstrap - #32

Merged
moonming merged 1 commit into
mainfrom
feat/managed-env-bootstrap
Apr 23, 2026
Merged

feat(docker): managed-mode env-var bootstrap#32
moonming merged 1 commit into
mainfrom
feat/managed-env-bootstrap

Conversation

@moonming

Copy link
Copy Markdown
Member

Summary

Lets the same Docker image serve both standalone and managed (aisix.cloud tenant) deployments without re-templating config files.

  • `config.managed.yaml` — baked into the image at `/etc/aisix/config.managed.yaml`. Placeholder etcd endpoint (overwritten by the `/dp/register` response), `managed.enabled = true`, unbindable admin port (defence-in-depth).
  • `docker/entrypoint.sh` — picks the config via `AISIX_CONFIG_PATH`. Standalone: mount your config at the default `/etc/aisix/config.yaml`. Managed: point `AISIX_CONFIG_PATH` at the baked file and inject `AISIX_MANAGED__REGISTRATION_TOKEN` + `AISIX_MANAGED__CP_BASE_URL`.

The existing bootstrap from #30 + #31 already does the heavy lifting: register-and-persist on first boot, reload mTLS bundle on restart, spawn heartbeat worker.

Why now

Unblocks AISIX-Cloud E2E scenarios 2 / 3 / 4. The test harness can now `docker run ghcr.io/moonming/ai-gateway:aisix-e2e` with a deployment_token from the SaaS layer and the DP registers itself without any pre-baked certs.

Tests

  • New `parses_managed_block_with_register_fields` locks the YAML shape — any new required `ManagedConfig` field will fail CI loudly instead of silently breaking the image template.
  • `cargo fmt --check` + `cargo clippy --all-targets --locked -- -D warnings` clean.

Out of scope

  • DP-side local snapshot (offline_resilience prerequisite) — separate change.
  • `/dp/telemetry` worker — separate change.

Test plan

  • `cargo test -p aisix-core` (9 passing, +1 new)
  • `cargo clippy --all-targets --locked -- -D warnings`
  • `docker build -t aisix:dev .` succeeds
  • `docker run -e AISIX_CONFIG_PATH=/etc/aisix/config.managed.yaml aisix:dev` exits with the expected "missing token" error

The same Docker image now serves both standalone and managed
(aisix.cloud tenant) deployments. Two pieces:
- config.managed.yaml — bootstrap template baked at
/etc/aisix/config.managed.yaml. Has placeholder etcd endpoint
(overwritten by /dp/register response), managed.enabled = true,
and unbindable admin (defence-in-depth if managed mode somehow
flipped off). All real per-DP secrets come from env vars.
- docker/entrypoint.sh — picks the config file via AISIX_CONFIG_PATH
(default /etc/aisix/config.yaml). Standalone users mount their
config at the default path; managed users point AISIX_CONFIG_PATH
at the baked file and inject AISIX_MANAGED__REGISTRATION_TOKEN +
AISIX_MANAGED__CP_BASE_URL.
Existing main.rs bootstrap (PR #30 + #31) already does the rest:
register-and-persist on first boot, reload bundle on subsequent
boots, spawn heartbeat worker.
Tests: parses_managed_block_with_register_fields locks the YAML
shape so any new required field on ManagedConfig fails CI loudly
instead of silently breaking the image.
Docs: docs/managed-mode.md walks operators through first boot,
restart semantics, env-var override matrix, and common errors.
This unblocks AISIX-Cloud E2E scenarios 2/3/4 — the test harness
can now `docker run` aisix with a deployment_token and have the DP
register itself without prebaked certs.
CopilotAI review requested due to automatic review settings April 23, 2026 12:38
@moonming
moonming merged commit 8c2a727 into mainApr 23, 2026
8 of 10 checks passed

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Enables a single Docker image to support both standalone deployments (operator-mounted config) and managed-mode (aisix.cloud tenant) deployments by baking a managed bootstrap config into the image and selecting the config path at runtime via an entrypoint.

Changes:

  • Add a baked config.managed.yaml template intended for managed-mode bootstrapping.
  • Introduce docker/entrypoint.sh to choose the config file via AISIX_CONFIG_PATH and exec aisix --config ....
  • Add managed-mode documentation and a config parsing test to lock the managed YAML shape.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
docs/managed-mode.mdNew guide for running the official image in managed mode (register + heartbeat + env overrides).
docker/entrypoint.shNew container entrypoint that selects config path via AISIX_CONFIG_PATH and runs aisix.
crates/aisix-core/src/config.rsAdds a regression test ensuring managed-mode YAML shape remains valid as ManagedConfig evolves.
config.managed.yamlAdds a managed-mode bootstrap config intended to be baked into the image.
DockerfileBakes the managed config, adds the entrypoint script, and switches ENTRYPOINT to use it.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadconfig.managed.yaml
@@ -0,0 +1,72 @@
# aisix — managed-mode bootstrap config (aisix.cloud tenant).
#
# Used by the official Docker image as `/etc/aisix/config.yaml`.

CopilotAIApr 23, 2026

Copy link

Choose a reason for hiding this comment

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

The header comment says this file is used as /etc/aisix/config.yaml, but the Dockerfile copies it to /etc/aisix/config.managed.yaml and the docs/entrypoint reference that path. This mismatch is likely to confuse operators; update the comment (or the copy destination) so the documented path matches the image layout.

Suggested change
# Used by the official Docker image as `/etc/aisix/config.yaml`.
# Used by the official Docker image as `/etc/aisix/config.managed.yaml`.

Copilot uses AI. Check for mistakes.
Comment threaddocker/entrypoint.sh
exit 64
fi

exec /usr/local/bin/aisix --config "$CONFIG_PATH"

CopilotAIApr 23, 2026

Copy link

Choose a reason for hiding this comment

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

The entrypoint ignores any arguments passed to docker run because it always execs aisix --config ... with no "$@" forwarding. That prevents common uses like docker run <image> -- --help or passing additional CLI flags. Forward the args (and/or treat args as an override command) so the container remains composable.

Suggested change
exec /usr/local/bin/aisix --config "$CONFIG_PATH"
exec /usr/local/bin/aisix --config "$CONFIG_PATH""$@"

Copilot uses AI. Check for mistakes.
@jarvis9443
jarvis9443 deleted the feat/managed-env-bootstrap branch June 25, 2026 06:25
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(docker): managed-mode env-var bootstrap - #32

Merged
moonming merged 1 commit into
mainfrom
feat/managed-env-bootstrap
Apr 23, 2026
Merged

feat(docker): managed-mode env-var bootstrap#32
moonming merged 1 commit into
mainfrom
feat/managed-env-bootstrap

Conversation

@moonming

Copy link
Copy Markdown
Member

Summary

Lets the same Docker image serve both standalone and managed (aisix.cloud tenant) deployments without re-templating config files.

  • `config.managed.yaml` — baked into the image at `/etc/aisix/config.managed.yaml`. Placeholder etcd endpoint (overwritten by the `/dp/register` response), `managed.enabled = true`, unbindable admin port (defence-in-depth).
  • `docker/entrypoint.sh` — picks the config via `AISIX_CONFIG_PATH`. Standalone: mount your config at the default `/etc/aisix/config.yaml`. Managed: point `AISIX_CONFIG_PATH` at the baked file and inject `AISIX_MANAGED__REGISTRATION_TOKEN` + `AISIX_MANAGED__CP_BASE_URL`.

The existing bootstrap from #30 + #31 already does the heavy lifting: register-and-persist on first boot, reload mTLS bundle on restart, spawn heartbeat worker.

Why now

Unblocks AISIX-Cloud E2E scenarios 2 / 3 / 4. The test harness can now `docker run ghcr.io/moonming/ai-gateway:aisix-e2e` with a deployment_token from the SaaS layer and the DP registers itself without any pre-baked certs.

Tests

  • New `parses_managed_block_with_register_fields` locks the YAML shape — any new required `ManagedConfig` field will fail CI loudly instead of silently breaking the image template.
  • `cargo fmt --check` + `cargo clippy --all-targets --locked -- -D warnings` clean.

Out of scope

  • DP-side local snapshot (offline_resilience prerequisite) — separate change.
  • `/dp/telemetry` worker — separate change.

Test plan

  • `cargo test -p aisix-core` (9 passing, +1 new)
  • `cargo clippy --all-targets --locked -- -D warnings`
  • `docker build -t aisix:dev .` succeeds
  • `docker run -e AISIX_CONFIG_PATH=/etc/aisix/config.managed.yaml aisix:dev` exits with the expected "missing token" error

The same Docker image now serves both standalone and managed
(aisix.cloud tenant) deployments. Two pieces:
- config.managed.yaml — bootstrap template baked at
/etc/aisix/config.managed.yaml. Has placeholder etcd endpoint
(overwritten by /dp/register response), managed.enabled = true,
and unbindable admin (defence-in-depth if managed mode somehow
flipped off). All real per-DP secrets come from env vars.
- docker/entrypoint.sh — picks the config file via AISIX_CONFIG_PATH
(default /etc/aisix/config.yaml). Standalone users mount their
config at the default path; managed users point AISIX_CONFIG_PATH
at the baked file and inject AISIX_MANAGED__REGISTRATION_TOKEN +
AISIX_MANAGED__CP_BASE_URL.
Existing main.rs bootstrap (PR #30 + #31) already does the rest:
register-and-persist on first boot, reload bundle on subsequent
boots, spawn heartbeat worker.
Tests: parses_managed_block_with_register_fields locks the YAML
shape so any new required field on ManagedConfig fails CI loudly
instead of silently breaking the image.
Docs: docs/managed-mode.md walks operators through first boot,
restart semantics, env-var override matrix, and common errors.
This unblocks AISIX-Cloud E2E scenarios 2/3/4 — the test harness
can now `docker run` aisix with a deployment_token and have the DP
register itself without prebaked certs.
CopilotAI review requested due to automatic review settings April 23, 2026 12:38
@moonming
moonming merged commit 8c2a727 into mainApr 23, 2026
8 of 10 checks passed

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Enables a single Docker image to support both standalone deployments (operator-mounted config) and managed-mode (aisix.cloud tenant) deployments by baking a managed bootstrap config into the image and selecting the config path at runtime via an entrypoint.

Changes:

  • Add a baked config.managed.yaml template intended for managed-mode bootstrapping.
  • Introduce docker/entrypoint.sh to choose the config file via AISIX_CONFIG_PATH and exec aisix --config ....
  • Add managed-mode documentation and a config parsing test to lock the managed YAML shape.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
docs/managed-mode.mdNew guide for running the official image in managed mode (register + heartbeat + env overrides).
docker/entrypoint.shNew container entrypoint that selects config path via AISIX_CONFIG_PATH and runs aisix.
crates/aisix-core/src/config.rsAdds a regression test ensuring managed-mode YAML shape remains valid as ManagedConfig evolves.
config.managed.yamlAdds a managed-mode bootstrap config intended to be baked into the image.
DockerfileBakes the managed config, adds the entrypoint script, and switches ENTRYPOINT to use it.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadconfig.managed.yaml
@@ -0,0 +1,72 @@
# aisix — managed-mode bootstrap config (aisix.cloud tenant).
#
# Used by the official Docker image as `/etc/aisix/config.yaml`.

CopilotAIApr 23, 2026

Copy link

Choose a reason for hiding this comment

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

The header comment says this file is used as /etc/aisix/config.yaml, but the Dockerfile copies it to /etc/aisix/config.managed.yaml and the docs/entrypoint reference that path. This mismatch is likely to confuse operators; update the comment (or the copy destination) so the documented path matches the image layout.

Suggested change
# Used by the official Docker image as `/etc/aisix/config.yaml`.
# Used by the official Docker image as `/etc/aisix/config.managed.yaml`.

Copilot uses AI. Check for mistakes.
Comment threaddocker/entrypoint.sh
exit 64
fi

exec /usr/local/bin/aisix --config "$CONFIG_PATH"

CopilotAIApr 23, 2026

Copy link

Choose a reason for hiding this comment

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

The entrypoint ignores any arguments passed to docker run because it always execs aisix --config ... with no "$@" forwarding. That prevents common uses like docker run <image> -- --help or passing additional CLI flags. Forward the args (and/or treat args as an override command) so the container remains composable.

Suggested change
exec /usr/local/bin/aisix --config "$CONFIG_PATH"
exec /usr/local/bin/aisix --config "$CONFIG_PATH""$@"

Copilot uses AI. Check for mistakes.
@jarvis9443
jarvis9443 deleted the feat/managed-env-bootstrap branch June 25, 2026 06:25
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(docker): managed-mode env-var bootstrap - #32

Merged
moonming merged 1 commit into
mainfrom
feat/managed-env-bootstrap
Apr 23, 2026
Merged

feat(docker): managed-mode env-var bootstrap#32
moonming merged 1 commit into
mainfrom
feat/managed-env-bootstrap

Conversation

@moonming

Copy link
Copy Markdown
Member

Summary

Lets the same Docker image serve both standalone and managed (aisix.cloud tenant) deployments without re-templating config files.

  • `config.managed.yaml` — baked into the image at `/etc/aisix/config.managed.yaml`. Placeholder etcd endpoint (overwritten by the `/dp/register` response), `managed.enabled = true`, unbindable admin port (defence-in-depth).
  • `docker/entrypoint.sh` — picks the config via `AISIX_CONFIG_PATH`. Standalone: mount your config at the default `/etc/aisix/config.yaml`. Managed: point `AISIX_CONFIG_PATH` at the baked file and inject `AISIX_MANAGED__REGISTRATION_TOKEN` + `AISIX_MANAGED__CP_BASE_URL`.

The existing bootstrap from #30 + #31 already does the heavy lifting: register-and-persist on first boot, reload mTLS bundle on restart, spawn heartbeat worker.

Why now

Unblocks AISIX-Cloud E2E scenarios 2 / 3 / 4. The test harness can now `docker run ghcr.io/moonming/ai-gateway:aisix-e2e` with a deployment_token from the SaaS layer and the DP registers itself without any pre-baked certs.

Tests

  • New `parses_managed_block_with_register_fields` locks the YAML shape — any new required `ManagedConfig` field will fail CI loudly instead of silently breaking the image template.
  • `cargo fmt --check` + `cargo clippy --all-targets --locked -- -D warnings` clean.

Out of scope

  • DP-side local snapshot (offline_resilience prerequisite) — separate change.
  • `/dp/telemetry` worker — separate change.

Test plan

  • `cargo test -p aisix-core` (9 passing, +1 new)
  • `cargo clippy --all-targets --locked -- -D warnings`
  • `docker build -t aisix:dev .` succeeds
  • `docker run -e AISIX_CONFIG_PATH=/etc/aisix/config.managed.yaml aisix:dev` exits with the expected "missing token" error

The same Docker image now serves both standalone and managed
(aisix.cloud tenant) deployments. Two pieces:
- config.managed.yaml — bootstrap template baked at
/etc/aisix/config.managed.yaml. Has placeholder etcd endpoint
(overwritten by /dp/register response), managed.enabled = true,
and unbindable admin (defence-in-depth if managed mode somehow
flipped off). All real per-DP secrets come from env vars.
- docker/entrypoint.sh — picks the config file via AISIX_CONFIG_PATH
(default /etc/aisix/config.yaml). Standalone users mount their
config at the default path; managed users point AISIX_CONFIG_PATH
at the baked file and inject AISIX_MANAGED__REGISTRATION_TOKEN +
AISIX_MANAGED__CP_BASE_URL.
Existing main.rs bootstrap (PR #30 + #31) already does the rest:
register-and-persist on first boot, reload bundle on subsequent
boots, spawn heartbeat worker.
Tests: parses_managed_block_with_register_fields locks the YAML
shape so any new required field on ManagedConfig fails CI loudly
instead of silently breaking the image.
Docs: docs/managed-mode.md walks operators through first boot,
restart semantics, env-var override matrix, and common errors.
This unblocks AISIX-Cloud E2E scenarios 2/3/4 — the test harness
can now `docker run` aisix with a deployment_token and have the DP
register itself without prebaked certs.
CopilotAI review requested due to automatic review settings April 23, 2026 12:38
@moonming
moonming merged commit 8c2a727 into mainApr 23, 2026
8 of 10 checks passed

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Enables a single Docker image to support both standalone deployments (operator-mounted config) and managed-mode (aisix.cloud tenant) deployments by baking a managed bootstrap config into the image and selecting the config path at runtime via an entrypoint.

Changes:

  • Add a baked config.managed.yaml template intended for managed-mode bootstrapping.
  • Introduce docker/entrypoint.sh to choose the config file via AISIX_CONFIG_PATH and exec aisix --config ....
  • Add managed-mode documentation and a config parsing test to lock the managed YAML shape.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
docs/managed-mode.mdNew guide for running the official image in managed mode (register + heartbeat + env overrides).
docker/entrypoint.shNew container entrypoint that selects config path via AISIX_CONFIG_PATH and runs aisix.
crates/aisix-core/src/config.rsAdds a regression test ensuring managed-mode YAML shape remains valid as ManagedConfig evolves.
config.managed.yamlAdds a managed-mode bootstrap config intended to be baked into the image.
DockerfileBakes the managed config, adds the entrypoint script, and switches ENTRYPOINT to use it.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadconfig.managed.yaml
@@ -0,0 +1,72 @@
# aisix — managed-mode bootstrap config (aisix.cloud tenant).
#
# Used by the official Docker image as `/etc/aisix/config.yaml`.

CopilotAIApr 23, 2026

Copy link

Choose a reason for hiding this comment

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

The header comment says this file is used as /etc/aisix/config.yaml, but the Dockerfile copies it to /etc/aisix/config.managed.yaml and the docs/entrypoint reference that path. This mismatch is likely to confuse operators; update the comment (or the copy destination) so the documented path matches the image layout.

Suggested change
# Used by the official Docker image as `/etc/aisix/config.yaml`.
# Used by the official Docker image as `/etc/aisix/config.managed.yaml`.

Copilot uses AI. Check for mistakes.
Comment threaddocker/entrypoint.sh
exit 64
fi

exec /usr/local/bin/aisix --config "$CONFIG_PATH"

CopilotAIApr 23, 2026

Copy link

Choose a reason for hiding this comment

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

The entrypoint ignores any arguments passed to docker run because it always execs aisix --config ... with no "$@" forwarding. That prevents common uses like docker run <image> -- --help or passing additional CLI flags. Forward the args (and/or treat args as an override command) so the container remains composable.

Suggested change
exec /usr/local/bin/aisix --config "$CONFIG_PATH"
exec /usr/local/bin/aisix --config "$CONFIG_PATH""$@"

Copilot uses AI. Check for mistakes.
@jarvis9443
jarvis9443 deleted the feat/managed-env-bootstrap branch June 25, 2026 06:25
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@moonming