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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ jobs:
test -f website/build/docs/apisix/plugins/cors/index.md
grep -q 'index.md' website/build/llms.txt
test -f website/build/img/integrations/icon-prometheus.svg
test -f website/build/img/architecture.svg
test -f website/build/img/architecture.png

- name: Generate final sitemaps
run: |
Expand Down
1 change: 1 addition & 0 deletions next/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Prototype rebuild of [apisix.apache.org](https://apisix.apache.org) as a **fully
- `src/pages/` — routes; `/zh/**` mirrors are thin wrappers passing `locale="zh"`.
- `scripts/generate-sitemaps.mjs` — emits `sitemap.xml` + `zh/sitemap.xml` post-build.
- `scripts/check-parity.mjs` — asserts every URL in the live sitemaps exists in `dist/` (exact, case-sensitive string comparison).
- `scripts/architecture/`: source for the homepage architecture diagram. `arch.html` is the drawing (absolutely-positioned boxes plus an SVG wire layer); `bash scripts/architecture/render.sh` shoots it in headless Chrome at 2x and overwrites `public/img/architecture.png`. Edit the HTML and re-render; the PNG is generated output.

## Build

Expand Down
Binary file added next/public/img/architecture.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion next/public/img/architecture.svg

This file was deleted.

219 changes: 219 additions & 0 deletions next/scripts/architecture/arch.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
<!doctype html>
<meta charset="utf-8" />
<title>Apache APISIX architecture diagram (source)</title>
<!--
Source for public/img/architecture.png. Render with ./render.sh.

Geometry is absolute so the boxes and the SVG connectors share one
coordinate space: the canvas is 1200x738 CSS px, exported at 2x.
Move a box and you must move the wire that lands on it.
-->
<style>
:root {
--ink: #1c1e21;
--ink-soft: #525860;
--panel-bg: #f7f8fa;
--panel-border: #ebeef2;
--box-border: #e3e7ec;
--wire: #8a939e;

--red: #b8342f;
--red-band: #fceded;
--red-border: #f3c9c7;
--red-dot: #d63b36;

--blue: #175ba1;
--blue-band: #e8f0fb;
--blue-border: #cfe0f5;
--blue-dot: #1a5da8;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

body {
width: 1200px;
height: 738px;
background: #fff;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
color: var(--ink);
-webkit-font-smoothing: antialiased;
}

.canvas { position: relative; width: 1200px; height: 738px; }
.at { position: absolute; }

.panel {
top: 24px;
height: 690px;
width: 560px;
background: var(--panel-bg);
border: 1px solid var(--panel-border);
border-radius: 24px;
}
.panel.data { left: 24px; }
.panel.control { left: 616px; }

/* panel caption: dot + tracked-out uppercase label */
.caption {
top: 44px;
display: flex;
align-items: center;
gap: 12px;
font-size: 15px;
font-weight: 700;
letter-spacing: .12em;
text-transform: uppercase;
}
.caption.data { left: 52px; color: #a32d2d; }
.caption.control { left: 644px; color: var(--blue); }
.caption::before {
content: "";
width: 11px;
height: 11px;
border-radius: 50%;
background: currentColor;
}
.caption.data::before { background: var(--red-dot); }
.caption.control::before { background: var(--blue-dot); }

/* free-standing white node (Client / service, Admin, the API tiers) */
.node {
display: flex;
align-items: center;
justify-content: center;
background: #fff;
border: 1px solid var(--box-border);
border-radius: 12px;
box-shadow: 0 1px 2px rgb(16 24 39 / 5%), 0 6px 16px rgb(16 24 39 / 6%);
font-size: 20px;
}

/* titled card: tinted header band over a white body of chips */
.card { border-radius: 16px; overflow: hidden; background: #fff; }
.card .band {
height: 80px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 4px;
}
.card .band b { font-size: 26px; }
.card .band span { font-size: 15px; }
.card .body { padding: 14px; }

.card.red { border: 1px solid var(--red-border); }
.card.red .band { background: var(--red-band); }
.card.red .band b { color: var(--red); }
.card.red .band span { color: #a3564f; }
.card.blue { border: 1px solid var(--blue-border); }
.card.blue .band { background: var(--blue-band); }
.card.blue .band b { color: var(--blue); }
.card.blue .band span { color: #3d6c9e; }

.chip {
display: flex;
align-items: center;
justify-content: center;
background: #fff;
border-radius: 10px;
font-size: 18px;
}
.card.red .chip { border: 1px solid var(--red-border); }
.card.blue .chip { border: 1px solid var(--blue-border); }

.grid3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.row { display: flex; justify-content: center; gap: 12px; }
/* auto-width chips: the row is tuned to fit on one line, so never wrap */
.row .chip { padding: 0 18px; white-space: nowrap; }

.wires { top: 0; left: 0; width: 1200px; height: 738px; }
</style>

<div class="canvas">
<div class="at panel data"></div>
<div class="at panel control"></div>

<div class="at caption data">Data plane</div>
<div class="at caption control">Control plane</div>

<!-- data plane -->
<div class="at node" style="left: 164px; top: 92px; width: 280px; height: 54px;">Client / service</div>

<div class="at card red" style="left: 52px; top: 190px; width: 504px;">
<div class="band"><b>Apache APISIX</b><span>Hot-reloadable plugin pipeline</span></div>
<div class="body grid3" style="grid-auto-rows: 48px;">
<div class="chip">Rate limit</div>
<div class="chip">Auth</div>
<div class="chip">Security</div>
<div class="chip">Logging</div>
<div class="chip">Tracing</div>
<div class="chip">Traffic split</div>
<div class="chip">Transformation</div>
<div class="chip">Custom plugin</div>
<div class="chip">100+ more</div>
</div>
</div>

<div class="at node" style="left: 52px; top: 544px; width: 160px; height: 60px;">Partner APIs</div>
<div class="at node" style="left: 224px; top: 544px; width: 160px; height: 60px;">Private APIs</div>
<div class="at node" style="left: 396px; top: 544px; width: 160px; height: 60px;">Public APIs</div>

<!-- control plane -->
<div class="at node" style="left: 756px; top: 92px; width: 280px; height: 54px;">Admin</div>

<div class="at card blue" style="left: 644px; top: 178px; width: 504px;">
<div class="band"><b>Dashboard</b><span>Configure routes and plugins</span></div>
<div class="body row"><div class="chip" style="height: 46px;">Manager API</div></div>
</div>

<div class="at card blue" style="left: 644px; top: 358px; width: 504px;">
<div class="band"><b>etcd cluster</b><span>Configuration store</span></div>
<div class="body grid3" style="grid-auto-rows: 50px;">
<div class="chip">etcd</div>
<div class="chip">etcd</div>
<div class="chip">etcd</div>
</div>
</div>

<div class="at card blue" style="left: 644px; top: 530px; width: 504px;">
<div class="band"><b>Observability</b><span>Metrics, traces, and logs</span></div>
<div class="body row">
<div class="chip" style="height: 50px;">Apache SkyWalking</div>
<div class="chip" style="height: 50px;">Prometheus</div>
<div class="chip" style="height: 50px;">Grafana</div>
</div>
</div>

<svg class="at wires" viewBox="0 0 1200 738" fill="none">
<defs>
<!-- userSpaceOnUse keeps the head a fixed size regardless of stroke-width;
refX at the tip puts the point exactly on the path's last vertex -->
<marker id="head-gray" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" refX="11" refY="5.5" orient="auto">
<path d="M0 0 L11 5.5 L0 11 z" fill="#8a939e" />
</marker>
<marker id="head-blue" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" refX="11" refY="5.5" orient="auto">
<path d="M0 0 L11 5.5 L0 11 z" fill="#1a5da8" />
</marker>
<marker id="head-red" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" refX="11" refY="5.5" orient="auto">
<path d="M0 0 L11 5.5 L0 11 z" fill="#d63b36" />
</marker>
</defs>

<g stroke="#8a939e" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M304 146 V190" marker-end="url(#head-gray)" />
<path d="M896 146 V178" marker-end="url(#head-gray)" />
<path d="M896 332 V358" marker-end="url(#head-gray)" />
<!-- fan-out bus under APISIX: trunk + rail carry no head, the drops do -->
<path d="M304 470 V500 M132 500 H476" />
<path d="M132 500 V544" marker-end="url(#head-gray)" />
<path d="M304 500 V544" marker-end="url(#head-gray)" />
<path d="M476 500 V544" marker-end="url(#head-gray)" />
</g>

<!-- etcd pushes config into the gateway -->
<path d="M644 398 H556" stroke="#1a5da8" stroke-width="2.5" stroke-linecap="round" marker-end="url(#head-blue)" />
<!-- the gateway emits telemetry -->
<path d="M556 452 H600 V572 H644" stroke="#d63b36" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" marker-end="url(#head-red)" />
</svg>
</div>
81 changes: 81 additions & 0 deletions next/scripts/architecture/render.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#!/usr/bin/env bash
# Re-render public/img/architecture.png from arch.html.
#
# Usage: bash scripts/architecture/render.sh
# Requires: Google Chrome (override with CHROME=/path/to/chrome)
#
# arch.html is authored at 1200x738 CSS px and shot at 2x, so the PNG is
# 2400x1476. Keep that in sync with the width/height on the <img> in
# src/components/HomePage.astro if you change the canvas size.
#
# The diagram uses the system sans stack, so text metrics follow whatever the
# rendering machine has installed. Re-render on macOS to match the committed
# PNG; elsewhere expect small label-width shifts.
set -euo pipefail

ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
SRC="$ROOT/scripts/architecture/arch.html"
OUT="$ROOT/public/img/architecture.png"

CHROME="${CHROME:-/Applications/Google Chrome.app/Contents/MacOS/Google Chrome}"
if [ ! -x "$CHROME" ]; then
echo "Chrome not found at: $CHROME (set CHROME=/path/to/chrome)" >&2
exit 1
fi

TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT

SHOT="$TMP/shot.png"

# A throwaway profile plus the no-networking flags keep Chrome off the network,
# which it otherwise hits on startup for first-run and component-update chores.
"$CHROME" \
--headless \
--disable-gpu \
--hide-scrollbars \
--no-first-run \
--no-default-browser-check \
--disable-background-networking \
--disable-component-update \
--disable-extensions \
--user-data-dir="$TMP/profile" \
--force-device-scale-factor=2 \
--window-size=1200,738 \
--virtual-time-budget=3000 \
--default-background-color=ffffffff \
--screenshot="$SHOT" \
"file://$SRC" </dev/null >/dev/null 2>&1 &
CHROME_PID=$!

# Chrome writes the shot and then can sit there instead of exiting (seen under
# sandboxed shells), so wait on the file rather than on the process.
for _ in $(seq 1 60); do
if [ -s "$SHOT" ]; then
sleep 1 # let the last write land before we read it
break
fi
kill -0 "$CHROME_PID" 2>/dev/null || break
sleep 1
done
kill "$CHROME_PID" 2>/dev/null || true
wait "$CHROME_PID" 2>/dev/null || true

if [ ! -s "$SHOT" ]; then
echo "Chrome produced no screenshot" >&2
exit 1
fi

# Flat fills and text palette-reduce cleanly: the raw shot is ~200 KB, 256-color
# ~70 KB. Either optimizer is fine; without one the raw shot still works.
# magick's -quality 95 is zlib level 9 + adaptive filtering, worth ~50 KB here.
if command -v pngquant >/dev/null 2>&1; then
pngquant --quality 80-98 --speed 1 --force --output "$OUT" "$SHOT"
elif command -v magick >/dev/null 2>&1; then
magick "$SHOT" -strip -colors 256 -depth 8 -quality 95 "PNG8:$OUT"
else
echo "no pngquant/magick, writing the unoptimized shot" >&2
cp "$SHOT" "$OUT"
fi

echo "wrote $OUT ($(wc -c <"$OUT" | tr -d ' ') bytes)"
2 changes: 1 addition & 1 deletion next/src/components/HomePage.astro
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ const SOFTWARE_APPLICATION_SCHEMA = {
'Requests flow through a hot-reloadable plugin pipeline; etcd distributes configuration across the cluster in real time, with no restarts.',
'请求流经可热加载的插件流水线;etcd 将配置实时分发到整个集群,无需重启。')}</p>
<figure class="arch-visual reveal">
<img src="/img/architecture.svg" alt={t(locale, 'Apache APISIX architecture diagram', 'Apache APISIX 架构图')} loading="lazy" width="1713" height="996" />
<img src="/img/architecture.png" alt={t(locale, 'Apache APISIX architecture diagram', 'Apache APISIX 架构图')} loading="lazy" width="2400" height="1476" />
<figcaption>{t(locale,
'Apache APISIX is based on NGINX and etcd. Compared with traditional API Gateways, APISIX has features like dynamic routing and hot-loading plugins, etc.',
'Apache APISIX 基于 NGINX 与 etcd,相较于传统的 API 网关,它提供了动态路由、插件热加载等诸多能力。')}</figcaption>
Expand Down
7 changes: 4 additions & 3 deletions next/src/styles/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -382,11 +382,12 @@ section.endcta.alt { background: transparent; padding: 4rem 1rem 0; }
.arch-visual { max-width: 980px; margin: 2rem auto 0; background: #fff; border: 1px solid rgba(16,24,39,.06); border-radius: 16px; padding: clamp(1.25rem, 3vw, 2.5rem); box-shadow: 0 1px 2px rgb(0 0 0 / 4%), 0 12px 32px rgb(0 0 0 / 10%); }
.arch-visual img { width: 100%; max-width: 100%; height: auto; display: block; margin-inline: auto; }
.arch-visual figcaption { max-width: 34rem; margin: 1rem auto 0; text-align: center; font-size: .95rem; color: var(--color-text-soft); }
/* On phones the 1713px-wide diagram would shrink below legibility (~14%);
let it pan horizontally at >=37% scale instead. */
/* The diagram is authored 1200 CSS px wide (exported at 2x). On phones let it
pan horizontally rather than shrink past the point where labels stop being
readable; 720px is the narrowest that still holds the plugin grid legible. */
@media (max-width: 700px) {
.arch-visual { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.arch-visual img { min-width: 640px; }
.arch-visual img { min-width: 720px; }
}
.pillar-section { background: #fff8f6; }
.pillar-section + .pillar-section { border-top: 1px solid #f2e8e4; }
Expand Down
12 changes: 0 additions & 12 deletions website/i18n/zh/code.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,18 +107,6 @@
"message": "阅读博客",
"description": "Read Blog"
},
"architecture.component.title.name": {
"message": "适用于超大规模、复杂的业务系统",
"description": "Building for large-scale, high value systems"
},
"architecture.component.title.subtitle": {
"message": "Apache APISIX 作为云原生架构的开源 API 网关,可以为海量 API 和微服务提供安全可靠的动态、高性能、可扩展的管理平台。",
"description": "Apache APISIX lets you build Cloud-Native Microservices API gateways, delivering the ultimate performance, security, open source and scalable platform for all your APIs and microservices."
},
"architecture.component.card.caption": {
"message": "Apache APISIX 基于 NGINX 与 etcd,相较于传统的 API 网关,它提供了动态路由、插件热加载等诸多能力。",
"description": "Apache APISIX is based on NGINX and etcd. Compared with traditional API gateways, APISIX has dynamic routing and hot-loading plugins"
},
"features.component.why.title": {
"message": "为什么选择 APISIX API 网关?"
},
Expand Down
1 change: 0 additions & 1 deletion website/src/assets/images/PatternGrouped-min.svg

This file was deleted.

1 change: 0 additions & 1 deletion website/src/assets/images/infographs/Architecture-min.svg

This file was deleted.

Loading