Bỏ qua

Operations

Tài liệu này là runbook cho rendering runtime của Code To UML trên local và VPS. Các ứng dụng VS Code, GitLab browser extension và Confluence gọi Gateway qua HTTPS nhưng không chạy trong rendering container.

1. Artifact triển khai

Dockerfile.render tạo image gồm:

  • Java 21 core được build từ server/.
  • Node.js Gateway.
  • Mermaid, BPMN, Excalidraw và diagrams.net companions.
  • Shared Google Chrome.
  • Native renderer từ base image Kroki.
  • tini và process supervisor entrypoint.

Playground web assets nằm trong Java JAR và được Gateway phục vụ tại /playground. Pydia dùng image riêng từ Dockerfile.pydia và giao tiếp với rendering container qua Unix socket trong named volume.

2. Compose profiles

Profile File Mục đích
Local compose.code-to-uml.yml Build runtime và expose localhost:8000
Production VPS compose.vps.yml Đọc .env, dùng gVisor cho Pydia và đặt production resource/log limits

Local map container port 10000 sang host port 8000. Production bind 127.0.0.1:${PORT:-10000}:10000 để TLS ingress trên VPS chuyển tiếp request tới Gateway mà không public trực tiếp application port.

Local dùng .env.example; Production VPS dùng deploy/vps.env.example. Hai template khác nhau ở port mapping, proxy trust, JVM limits và release image tag.

3. Yêu cầu và secret

  • Docker Engine hỗ trợ multi-stage build.
  • Docker Compose.
  • Đủ RAM và disk cho Java, Node dependencies, Chrome và renderer.
  • Shared rendering token ngẫu nhiên.

Production Pydia còn yêu cầu Linux x86_64 hoặc aarch64 và runtime runsc-pydia đã được đăng ký với Docker. Script cài đặt hiện dùng apt-get, vì vậy host phải có trình quản lý gói này. Cơ chế systrap được dùng nên host không cần KVM.

Tạo cấu hình local từ repository root:

Copy-Item .env.example .env

Đặt RENDER_API_KEYS thành một hoặc nhiều token phân cách bằng dấu phẩy. Không commit .env, ghi token vào URL/log hoặc dùng token mẫu. Trên Linux, giới hạn quyền đọc file hoặc dùng secret manager của môi trường triển khai.

4. Cấu hình runtime chính

Các biến runtime được chia theo lớp tiếp nhận request và lớp thực thi để thuận tiện đối chiếu giữa môi trường local với Production VPS.

Gateway

Biến Local Production VPS Ý nghĩa
PORT Container 10000, host 8000 Container và loopback host 10000 Gateway port
RENDER_API_KEYS Bắt buộc Bắt buộc Danh sách shared token
TRUST_PROXY 0 1 Express trust proxy
KROKI_TRUST_PROXY false true Core trust proxy
POST_RATE_LIMIT 120/phút 120/phút POST limit theo IP
GET_RATE_LIMIT 20/phút 20/phút Encoded GET limit theo IP
CACHE_TTL_MS 86400000 86400000 Result cache TTL
CACHE_MAX_ENTRIES 500 500 Số cache entry
CACHE_MAX_BYTES 16777216 16777216 Tổng dung lượng cache
CACHE_MAX_ENTRY_BYTES 2097152 2097152 Dung lượng tối đa mỗi entry
MAX_RESPONSE_BYTES 20971520 20971520 Response cap từ core
UPSTREAM_TIMEOUT_MS 35000 35000 Timeout gọi core

Đặt CACHE_MAX_BYTES=0 để tắt lưu result cache; request coalescing vẫn hoạt động. Chỉ bật TRUST_PROXYKROKI_TRUST_PROXY khi request đi qua proxy tin cậy. Production template bật hai biến này vì Gateway chỉ nhận traffic từ TLS ingress qua loopback; deployment có topology khác phải đặt theo trust boundary thực tế.

Core và universal pipeline

Biến Local Production VPS Ý nghĩa
KROKI_BODY_LIMIT 2097152 2097152 Request body limit
KROKI_SAFE_MODE secure secure Renderer safe mode
KROKI_ENABLE_PYDIA false false Đăng ký Pydia renderer
KROKI_UNIVERSAL_UNSUPPORTED_MODE warn warn ignore, warn hoặc error
KROKI_UNIVERSAL_POLICY_MODE preferred preferred preferred hoặc enforced
KROKI_UNIVERSAL_MAX_PIXELS 8000000 8000000 Raster pixel limit
KROKI_UNIVERSAL_MAX_OUTPUT_BYTES 20971520 20971520 Universal output cap

KROKI_UNIVERSAL_DEFAULT_OPTIONSKROKI_UNIVERSAL_POLICY_OPTIONS nhận JSON object. JSON không hợp lệ làm startup thất bại.

5. State, restart và scaling

Rendering service không có database lưu diagram. Các state sau nằm trong RAM của từng Gateway process:

State Mất khi restart Chia sẻ giữa replica Ảnh hưởng vận hành
Result cache Không Cache cold sau restart; cùng request có thể được render lại
Rate-limit bucket Không Limit áp dụng độc lập theo process nếu scale ngang
In-flight và coalesced request Không Request đang chạy bị hủy khi process dừng
Metrics process Không Counter reset; hệ thống giám sát phải tổng hợp theo instance

Mã sơ đồ gốc vẫn nằm trong workspace, repository hoặc Confluence page. Token nằm trong secret store của client/backend và RENDER_API_KEYS của deployment, không nằm trong result cache.

Khi restart hoặc rollout:

  1. Tôn trọng stop grace period để supervisor chuyển signal tới child process.
  2. Chấp nhận cache warm-up và theo dõi render latency, error, queue cùng memory.
  3. Tránh retry đồng loạt từ client khi instance vừa quay lại.
  4. Kiểm tra authenticated POST và encoded GET sau health check.

Khi scale nhiều Gateway replica, cache và rate limit không tự đồng bộ. Load balancer có thể phân phối cùng source tới nhiều replica, làm giảm hit rate và tăng tổng limit hiệu dụng. Chỉ scale sau khi xác định rõ yêu cầu về cache identity, rate-limit policy và metric aggregation; không mô tả state trong RAM như một store dùng chung.

6. Pydia sandbox

Pydia mặc định không được đăng ký. Sandbox chạy trong container riêng với network_mode: none, root filesystem read-only, giới hạn CPU, memory, PID, timeout, source và output. Rendering container chỉ gọi sidecar qua Unix socket. Pydia container không nhận .env hoặc RENDER_API_KEYS.

Local Compose dùng runtime Docker mặc định. Production Compose bắt buộc Pydia dùng runsc-pydia, được cấu hình với systrap và quyền tạo Unix socket trên host. Runtime riêng này chỉ áp dụng cho Pydia, không thay đổi Gateway hoặc các renderer khác.

Để bật Pydia:

  1. Xác nhận pydia-sandbox healthy và rendering container truy cập được Unix socket.
  2. Đặt KROKI_ENABLE_PYDIA=true.
  3. Recreate rendering container.
  4. Kiểm tra catalog, authenticated POST và encoded GET bằng source không nhạy cảm.
  5. Xác nhận sandbox không có IP network.

/healthz không thay thế smoke test Pydia.

7. Build và chạy local

docker compose -f compose.code-to-uml.yml config
docker compose -f compose.code-to-uml.yml up -d --build
docker compose -f compose.code-to-uml.yml ps
Invoke-RestMethod http://localhost:8000/healthz
Invoke-WebRequest http://localhost:8000/metrics

Dừng local profile:

docker compose -f compose.code-to-uml.yml down

8. Deploy production VPS

  1. Checkout đúng release hoặc tag.
  2. Trên host mới, cài và đăng ký runtime dành riêng cho Pydia:
sudo bash deploy/gvisor/install-runsc.sh

Script này khởi động lại Docker sau khi đăng ký runtime. Chỉ chạy khi host đã được chuẩn bị cho việc gián đoạn các container đang hoạt động.

  1. Kiểm tra Pydia trong gVisor và kết nối Unix socket từ container runc:
sudo bash deploy/gvisor/verify-pydia.sh
  1. Tạo .env từ production template:
cp deploy/vps.env.example .env
chmod 600 .env
  1. Đặt IMAGE_TAGRENDER_API_KEYS; giữ PORT=10000 với Compose manifest hiện tại và đặt proxy trust theo topology của VPS.
  2. Chạy docker compose -f compose.vps.yml config.
  3. Chạy docker compose -f compose.vps.yml up -d --build.
  4. Kiểm tra hai container healthy và xác nhận Pydia dùng đúng runtime:
docker inspect code-to-uml-pydia --format '{{.HostConfig.Runtime}}'

Kết quả phải là runsc-pydia.

  1. Smoke test health, authenticated POST và encoded GET qua HTTPS Gateway URL.
  2. Nếu bật Pydia, chạy thêm Pydia smoke test và kiểm tra network isolation.

Entrypoint khởi động Chrome, companions, core rồi Gateway. Khi nhận TERM hoặc INT, supervisor chuyển signal đến các child process; production rendering container có stop grace period 45 giây.

9. Health, metrics và logs

  • Endpoint /healthz trả ok khi Gateway kết nối được core, nếu không trả 503.
  • Các endpoint /health/v1/health trả health cùng version thành phần của core.
  • Endpoint /metrics gộp Prometheus metrics của Gateway và core.
  • Pydia image kiểm tra Unix socket bằng healthcheck riêng.

Healthcheck bên trong Pydia không chứng minh rendering container dùng runc có thể mở socket do gVisor tạo. deploy/gvisor/verify-pydia.sh kiểm tra riêng ranh giới này và phải chạy thành công trước khi bật Pydia trên Production VPS.

Theo dõi Gateway RSS/heap, cache bytes/entries, hit/miss/eviction, in-flight và coalesced requests, upstream count, render failure/timeout/duration, output size, worker queue và Pydia limits khi bật.

Không ghi token hoặc mã sơ đồ vào log. Dùng X-Request-Id để liên kết log của cùng một request. Production Compose rotate Docker JSON logs theo giới hạn đã khai báo.

10. Quản trị GitLab

Phần này dành cho operator quản lý GitLab Markdown Integration trên self-managed GitLab. MR Browser Extension là artifact cài trên workstation và không được build hoặc deploy vào GitLab server.

Build và pin version

Custom image hiện pin trên gitlab/gitlab-ce:19.2.0-ce.0. Build từ repository root:

docker build --file deploy/gitlab-krokup/Dockerfile --tag gitlab-ce-kroki:19.2.0-ce.0-krokup deploy/gitlab-krokup

Docker build xác nhận vị trí Markdown pipeline, chèn KrokupFenceFilter trước MarkdownFilter và chạy unit test. Build phải dừng nếu cấu trúc của base image không còn khớp; không bỏ kiểm tra để ép upgrade.

Chạy kiểm tra rewriter độc lập:

ruby deploy/gitlab-krokup/test/krokup_fence_rewriter_test.rb

Cấu hình và rollout

deploy/gitlab-krokup/compose.vps.yml là profile của instance hiện tại. Trước khi áp dụng ở môi trường khác, thay hostname, ingress, image tag và volume theo instance đích. Giữ GitLab config, log và data trong volume bền vững; không copy data vào image.

  1. Build image bằng đúng GitLab base version đang chạy.
  2. Chạy unit test và khởi động một instance thử nghiệm.
  3. Cấu hình GitLab Kroki integration trỏ tới Code To UML Gateway.
  4. Smoke test repository blob và wiki với fence không params.
  5. Smoke test theme/scale, title, Mermaid init block và source có %%krokup.
  6. Thử renderer bị tắt, fence không đóng và params vượt giới hạn để xác nhận filter fail open.
  7. Pin image tag đã kiểm tra, rollout và theo dõi GitLab log.

GitLab Markdown Integration không giữ rendering token. Trình duyệt của người đọc gọi public encoded GET nên Gateway origin phải được phép trong CSP img-src. Chỉ bật Pydia khi Gateway đã có sandbox và policy repository cho phép thực thi Python source.

Upgrade và rollback

Mỗi GitLab version có thể thay đổi Markdown pipeline nội bộ. Khi upgrade:

  1. Cập nhật base image.
  2. Build lại để kiểm tra patch target.
  3. Chạy unit test và deploy/gitlab-krokup/test/run_gitlab_smoke.sh.
  4. Kiểm tra blob, wiki và document không có diagram.
  5. Rollout có tag mới.

Rollback về image tag trước đó mà không xóa volume GitLab. Sau rollback, kiểm tra login, repository, wiki và encoded diagram. Hướng dẫn end user nằm trong GitLab Documents.

11. Quản trị Confluence

Phần này dành cho operator triển khai Forge app và quản lý rendering policy.

Build và kiểm tra

Set-Location confluence-code-to-uml-poc
npm.cmd install
npm.cmd --prefix static/code-to-uml install
npm.cmd test
npm.cmd run build
forge.cmd lint

Secret và policy

Đặt token riêng cho Confluence dưới dạng encrypted Forge variable:

forge.cmd variables set --encrypt RENDER_API_TOKEN "DEDICATED_CONFLUENCE_TOKEN"

Để bật Pydia cho một số space:

forge.cmd variables set ALLOW_PYDIA true
forge.cmd variables set PYDIA_ALLOWED_SPACE_IDS "123456,789012"

Dùng numeric space ID. Tránh wildcard * vì mọi editor trong mọi space có thể gửi Python source tới sandbox. Forge chỉ áp dụng variable mới sau deployment.

Render cache

Viewer của trang đã publish dùng Forge KVS để giảm số lần gọi Gateway khi mã sơ đồ không đổi. Cache bật mặc định, dùng key svg:v1:{renderer}:{sourceHash} và hết hạn sau 24 giờ. Live preview không dùng cache.

Chỉ SVG không vượt 220 KiB mới được lưu. Pydia bị loại khỏi cache vì cùng mã Python có thể cho kết quả khác nhau giữa các lần chạy. Mọi SVG đọc từ KVS được kiểm tra lại MIME, kích thước và active content trước khi trả về viewer. Lỗi đọc hoặc ghi KVS được coi như cache miss và không làm request render thất bại.

Để tắt cache khi cần kiểm soát KVS usage hoặc xử lý sự cố:

forge.cmd variables set ENABLE_RENDER_CACHE false
forge.cmd deploy

Đặt biến thành giá trị khác false rồi deploy lại để bật cache. Key phụ thuộc renderer và SHA-256 của source nên khi nội dung thay đổi, Resolver không trả SVG cũ. Entry của phiên bản trước tự hết hạn; không cần xóa cache khi chỉnh sửa macro.

Deploy và install

npm.cmd run build
forge.cmd lint
forge.cmd deploy
forge.cmd install --product Confluence

Khi thay scope hoặc permission, dùng forge.cmd install --upgrade trên site đã cài. Scope storage:app là bắt buộc để dùng Forge KVS. Khi đổi Gateway host, cập nhật cả RENDER_BASE_URLpermissions.external.fetch.backend trong manifest.yml rồi deploy lại.

Sau deploy:

  1. Tạo macro và kiểm tra live preview.
  2. Publish page và kiểm tra viewer.
  3. Tạo code block để kiểm tra page-event conversion.
  4. Xác nhận non-diagram code block và prose không đổi.
  5. Kiểm tra token không xuất hiện trong ADF, macro config hoặc browser request.
  6. Mở viewer hai lần với cùng một macro và xác nhận invocation response chuyển từ cached=false sang cached=true.
  7. Xác nhận Download SVG hoạt động trong viewer và live preview.
  8. Thử Pydia trong space được phép và bị từ chối, đồng thời xác nhận response Pydia luôn có cached=false.

Resolver giới hạn source 200 KiB, SVG 4 MiB và timeout 25 giây; response phải là image/svg+xml và không chứa active content. Không nới policy chỉ để chấp nhận SVG có script, event handler hoặc external URI.

Rollback bằng Forge deployment đã biết tốt và khôi phục variables/policy tương ứng, sau đó chạy lại macro preview/view smoke test. Hướng dẫn end user nằm trong Confluence.

12. Xử lý sự cố

Hiện tượng Kiểm tra Hành động
Health 503 Core process và loopback health Xem container log, để supervisor restart
Gateway 502 Core connection và response cap Kiểm tra core và upstream log
Gateway 504 Renderer duration và timeout Kiểm tra renderer/Chrome, tránh retry storm
Nhiều 429 Rate-limit metrics và client Giảm tần suất trước khi tăng limit
Cache memory tăng Bytes, entries, eviction Giảm cache limit hoặc đặt bytes về 0
Mermaid queue đầy Queue, pool và latency Giảm tải hoặc tăng pool khi đủ RAM
Chrome crash Supervisor log, shared memory Xác nhận restart và memory limit
Pydia vắng trong catalog Opt-in và socket health Xác nhận sidecar trước khi bật lại core
Pydia không khởi động Runtime của container và danh sách runtime của Docker Cài hoặc đăng ký lại runsc-pydia, không chuyển production về runc
Gateway không gọi được Pydia Named volume, socket group và gVisor host-uds Chạy lại deploy/gvisor/verify-pydia.sh
Forge KVS usage tăng bất thường Macro view traffic, SVG size và cache key Đặt ENABLE_RENDER_CACHE=false, deploy lại và kiểm tra request vẫn render trực tiếp
OOM Docker events và RSS Rollback config, giảm cache/JVM/concurrency
Output quá lớn Scale và dimension Giảm option thay vì nới limit ngay

13. Rotation, rollback và CI

Token rotation:

  1. Thêm token mới bên cạnh token cũ trong RENDER_API_KEYS.
  2. Recreate container và chuyển client sang token mới.
  3. Xác nhận các client đã chuyển.
  4. Xóa token cũ và recreate container.

Rollback image tag và environment cùng nhau, sau đó chạy health và render smoke test. Cache nằm trong RAM nên không cần migration. Lưu an toàn secret, image tag/digest và deployment manifest.

Nếu script kiểm tra Pydia hoặc render smoke test thất bại, rollback toàn bộ release thay vì chạy Pydia trên production bằng runtime mặc định. runsc-pydia là thay đổi một lần trên host và không bị gỡ khi rollback phiên bản ứng dụng.

CI cài runsc-pydia rồi chạy deploy/gvisor/verify-pydia.sh để kiểm tra sandbox, kết quả render và đường Unix socket giữa container gVisor với container runc.

Workflow deploy-vps sử dụng GitHub environment production-vps. Các biến bắt buộc là VPS_HOST, VPS_PORT, VPS_USER, VPS_RENDER_URL; secrets bắt buộc là VPS_SSH_PRIVATE_KEY, VPS_KNOWN_HOSTS. Job triển khai đúng commit SHA và kiểm tra {VPS_RENDER_URL}/healthz sau deploy.