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
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ jobs:
- name: Check deployment script syntax
run: |
make deploy-script-check
python -m unittest discover -s builder/tests -v

standalone-e2e:
name: Standalone E2E
Expand Down
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[submodule "src/sandboxd"]
path = src/sandboxd
url = https://github.com/inclusionAI/sandboxd.git
url = https://github.com/mhsong1998-dot/sandboxd.git
[submodule "src/distill-fs"]
path = src/distill-fs
url = https://github.com/inclusionAI/distill-fs.git
Expand Down
7 changes: 7 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,13 @@ the sandbox bridge. YuanRong receives `INSTANCE_IP` in Kubernetes or the
default-route interface address in standalone mode; `AKERNEL_NODE_IP` is the
explicit override for multi-homed environments.

Node deployments keep openYuanRong's in-node address aligned with sandboxd's
actual bridge state. Kubernetes renders `node.sandboxIPRange` into sandboxd's
`ip_range`; standalone reads the same setting from `sandboxd_config.toml` when
preparing networking. The sandboxd systemd startup waits with a bounded
timeout for `sandbox0`; YuanRong starts afterward and passes the bridge's
assigned IPv4 address through `values.local_ip` in the Python CLI config.

The standalone sandboxd filestore is a loop-mounted ext4 image under the
bind-mounted `deploy/standalone/data/` directory. Explicit `storage_mb`
quotas for runsc and Firecracker use this local-disk filestore. Without an
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ deploy-script-check:
@set -euo pipefail; \
while IFS= read -r -d '' script; do \
bash -n "$$script"; \
done < <(git ls-files -z -- 'deploy/**/*.sh'); \
done < <(git ls-files -z -- 'deploy/**/*.sh' 'builder/**/*.sh'); \
while IFS= read -r -d '' template; do \
if ! bash -n <( \
sed \
Expand Down
30 changes: 30 additions & 0 deletions builder/config/openyuanrong-core-0.10.1rc4.constraints.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Runtime dependency lock for openyuanrong-core 0.10.1rc4 on Python 3.12.
# Regenerate and validate this file for both linux/amd64 and linux/arm64 when
# OPEN_YR_VERSION changes.
aiohappyeyeballs==2.7.1
aiohttp==3.14.3
aiosignal==1.4.0
anyio==4.14.2
attrs==26.1.0
certifi==2026.7.22
charset-normalizer==3.5.1
click==8.4.2
cloudpickle==3.1.2
frozenlist==1.8.0
h11==0.16.0
httpcore==1.0.9
httpx==0.28.1
idna==3.19
jinja2==3.1.6
markupsafe==3.0.3
msgpack==1.2.1
multidict==6.7.1
propcache==0.5.2
protobuf==7.36.0
pyyaml==6.0.3
requests==2.34.2
tomli-w==1.2.0
typing-extensions==4.16.0
urllib3==2.7.0
websockets==17.0.1
yarl==1.24.5
193 changes: 193 additions & 0 deletions builder/config/yr/config.toml.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
{#
AKernel runtime profile template.

Deployment values are resolved from the CLI-provided env mapping. Strings
containing Python CLI runtime expressions remain escaped for its second
rendering pass.
#}
{% macro toml_string(value) -%}
"{%- for char in value -%}
{%- set encoded = char | tojson -%}
{{- char if encoded | length == 14 else encoded[1:-1] -}}
{%- endfor -%}"
{%- endmacro %}
{% set role = env["AKERNEL_ROLE"] %}
{% set cluster_roles = ["master", "frontend"] %}
{% set node_roles = ["node", "standalone"] %}
{% if role not in cluster_roles + node_roles %}
{{ unsupported_akernel_role }}
{% endif %}
{% set is_cluster = role in cluster_roles %}
{% set is_node = role in node_roles %}
{% set is_agent = role == "node" %}
{% set is_standalone = role == "standalone" %}
{% set has_master_mode = not is_agent %}
{% set enable_metrics = env.get("ENABLE_METRICS", "false") | lower %}
{% set enable_trace = env.get("ENABLE_TRACE", "false") | lower %}
{% set traefik_enable_tls = "true" if env.get("TRAEFIK_ENABLE_TLS", "false") | lower == "true" else "false" %}
{% set configured_host_ip = env.get("YR_NODE_IP", "") | trim %}
{% set configured_local_ip = env.get("YR_LOCAL_IP", "") | trim %}
{% set enable_faas_frontend = env.get("ENABLE_FAAS_FRONTEND", "true") | lower %}
{% set enable_iam_server = env.get("ENABLE_IAM_SERVER", "true") | lower %}
{% set runtime_hostname = "{{ hostname }}" %}
{% set deploy_path_value = env["DEPLOY_PATH"] | trim %}
{% set component_log_path = env["YR_LOG_PATH"] | trim %}

# Generated at startup from builder/config/yr/config.toml.jinja.

[values]
node_id = "{{ runtime_hostname }}"
deploy_path = {{ toml_string(deploy_path_value) }}
{% if configured_host_ip %}
host_ip = {{ toml_string(configured_host_ip) }}
{% endif %}
{% if configured_local_ip %}
local_ip = {{ toml_string(configured_local_ip) }}
{% endif %}
{% if is_cluster %}
cpu_num = 1
memory_num = 3904
shared_memory_num = 4096
{% endif %}

[values.fs.log]
path = {{ toml_string(component_log_path) }}

[values.fs.tls]
base_path = "/home/yuanrong/.cert"

{% if not is_standalone %}
[values.etcd]
enable_multi_master = true
{% endif %}

{% if is_cluster or is_node %}
[[values.etcd.address]]
ip = {{ toml_string(configured_host_ip if is_standalone else env["ETCD_ADDRESS"]) }}
port = {{ env.get("ETCD_PORT", "2379") }}
peer_port = {{ env.get("ETCD_PEER_PORT", "2378") }}
{% endif %}

[values.frontend]
ssl_enable = true
client_auth_type = "NoClientCert"
frontend_lease_bypass = true
enable_function_token_auth = true
enable_func_token_auth = true
{% if role == "frontend" %}
meta_service_address = {{ toml_string(env["META_SERVICE_ADDRESS"]) }}
{% endif %}
iam_server_address = "127.0.0.1:31113"

[values.meta_service]
port = 31111

{% if has_master_mode %}
[mode.master]
etcd = {{ "true" if is_standalone else "false" }}
ds_master = {{ "true" if is_standalone else "false" }}
frontend = {{ enable_faas_frontend if role == "master" else "true" if role in ["frontend", "standalone"] else "false" }}
function_master = {{ "true" if role in ["master", "standalone"] else "false" }}
function_scheduler = false
meta_service = {{ "true" if role in ["master", "standalone"] else "false" }}
iam_server = {{ enable_iam_server if role == "master" else "true" if role in ["frontend", "standalone"] else "false" }}
{% endif %}

[ds_worker.args]
{% if is_cluster %}
rpc_thread_num = 128
node_timeout_s = 10
node_dead_timeout_s = 30
heartbeat_interval_ms = 3000
{% endif %}
{% if is_node %}
node_timeout_s = 30
client_dead_timeout_s = 60
heartbeat_interval_ms = 1000
node_dead_timeout_s = 120
log_dir = {{ toml_string(component_log_path ~ "/data_system/worker") }}
{% endif %}

[ds_master.args]
log_dir = {{ toml_string(component_log_path ~ "/data_system/master") }}

[function_master.args]
services_path = "/home/yuanrong/deploy/process/services.yaml"
metrics_config_file = "/home/yuanrong/metrics/metrics_config.json"
traefik_enable_tls = {{ traefik_enable_tls }}
traefik_http_entry_point = {{ toml_string(env.get("TRAEFIK_HTTP_ENTRYPOINT", "websecure")) }}
traefik_forward_timeout_ms = 3000
{% if enable_metrics == "true" and (is_cluster or is_standalone) %}
enable_metrics = true
{% endif %}
{% if enable_trace == "true" and (is_cluster or is_standalone) %}
enable_trace = true
trace_config = {{ toml_string(env["YR_TRACE_CONFIG_CONTENT"]) }}
{% endif %}
{% if is_cluster or is_standalone %}
enable_traefik_provider = {{ "true" if env.get("TRAEFIK_MODE", "etcd") == "http" else "false" }}
{% endif %}
{% if is_cluster %}
system_timeout = 300000
schedule_relaxed = 20
{% elif is_standalone %}
system_timeout = 60000
{% endif %}

[function_proxy.args]
services_path = "/home/yuanrong/deploy/process/services.yaml"
enable_inherit_env = false
npu_collection_mode = "off"
metrics_config_file = "/home/yuanrong/metrics/metrics_config.json"
enable_direct_routing = false
force_low_reliability_instance = true
traefik_enable_tls = {{ traefik_enable_tls }}
{% if enable_metrics == "true" %}
enable_metrics = true
{% endif %}
{% if enable_trace == "true" %}
enable_trace = true
trace_config = {{ toml_string(env["YR_TRACE_CONFIG_CONTENT"]) }}
{% endif %}
{% if is_node %}
enable_traefik_registry = {{ "true" if env.get("TRAEFIK_MODE", "etcd") == "etcd" else "false" }}
traefik_http_entrypoint = {{ toml_string(env.get("TRAEFIK_HTTP_ENTRYPOINT", "websecure")) }}
{% endif %}
log_expiration_enable = true
log_expiration_time_threshold = {{ 10 if is_agent else 7200 }}
log_expiration_cleanup_interval = {{ 10 if is_agent else 600 }}
log_expiration_max_file_count = {{ 50 if is_agent else 256 }}
{% if is_cluster %}
system_timeout = 300000
pseudo_data_plane = true
{% elif is_node %}
system_timeout = 60000
fc_agent_mgr_retry_times = 30
fc_agent_mgr_retry_cycle = 60000
{% endif %}
runtime_logs_dir = {{ toml_string(component_log_path) }}
{% if is_node %}
metrics_collector_type = "external"
snapshot_storage_mode = "local_only"
checkpoint_dir = "/home/akernel/checkpoints"
{% endif %}

# The CLI exposes the meta-service component port separately from values.meta_service.
[meta_service]
port = 31111

[iam_server.args]
token_expired_time_span = 604800
ssl_enable = true
iam_ssl_enable = true
local_listen_port = 31113
local_ip = "127.0.0.1"
{% if enable_trace == "true" and (is_cluster or is_standalone) %}
enable_trace = true
{% endif %}

{% if enable_trace == "true" and (is_cluster or is_standalone) %}
[frontend.env]
ENABLE_TRACE = "true"
TRACE_CONFIG = {{ toml_string(env["YR_TRACE_CONFIG_CONTENT"]) }}
{% endif %}
45 changes: 34 additions & 11 deletions builder/node.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ RUN apt-get update && \
procps \
python3 \
python3-pip \
python3-venv \
systemd \
systemd-sysv \
tzdata \
Expand Down Expand Up @@ -296,6 +297,11 @@ RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \


ENV YR_INSTALLATION_DIR=/home/yuanrong
ENV PATH=/opt/openyuanrong/bin:${PATH}

COPY ./builder/config/yr/config.toml.jinja /etc/yuanrong/config.toml.jinja
COPY ./builder/config/openyuanrong-core-0.10.1rc4.constraints.txt /tmp/openyuanrong-core.constraints.txt
COPY ./builder/scripts/patch_openyuanrong_core.py /tmp/patch_openyuanrong_core.py

# Install the complete, language-runtime-free openYuanRong control plane from
# its checksum-pinned core wheel. A URL and checksum pair may override the
Expand Down Expand Up @@ -325,21 +331,36 @@ RUN set -eux; \
test -z "${OPEN_YR_CORE_WHEEL_SHA256}"; \
fi; \
wheel="/tmp/${wheel_name}"; \
target=/tmp/openyuanrong-core; \
curl -fSL --retry 10 --retry-delay 2 --retry-all-errors \
"${wheel_url}" -o "${wheel}"; \
echo "${wheel_sha} ${wheel}" | sha256sum -c -; \
python3 -m pip install \
--break-system-packages \
python3 -m venv /opt/openyuanrong; \

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why we need to use venv?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The venv is retained because the Python CLI wheel now installs its complete runtime dependency set. It keeps those dependencies isolated from Ubuntu system Python and avoids mutating the externally managed system environment with --break-system-packages.

/opt/openyuanrong/bin/python -m pip install \
--no-cache-dir \
--no-deps \
--target "${target}" \
--index-url "${PIP_INDEX_URL}" \
--constraint /tmp/openyuanrong-core.constraints.txt \
"${wheel}"; \
test -x "${target}/yr/functionsystem/bin/yr"; \
mkdir -p "${YR_INSTALLATION_DIR}"; \
cp -a "${target}/yr/." "${YR_INSTALLATION_DIR}/"; \
rm -rf "${target}" "${wheel}"; \
ln -sfn "${YR_INSTALLATION_DIR}/functionsystem/bin/yr" /usr/bin/yr
site_packages="$(/opt/openyuanrong/bin/python -c 'import site; print(site.getsitepackages()[0])')"; \
/opt/openyuanrong/bin/python /tmp/patch_openyuanrong_core.py "${site_packages}"; \
base_py="${site_packages}/yr/cli/component/base.py"; \
launcher_py="${site_packages}/yr/cli/system_launcher.py"; \
grep -Fq 'logger.info(f"Environment: {full_env}")' "${base_py}"; \
sed -i \
's/logger.info(f"Environment: {full_env}")/logger.info(f"Environment keys: {sorted(full_env)}")/' \
"${base_py}"; \
grep -Fq 'logger.info(f"Environment keys: {sorted(full_env)}")' "${base_py}"; \
! grep -Fq 'logger.info(f"Environment: {full_env}")' "${base_py}"; \
grep -Fq '"env_vars": comp.env_vars,' "${launcher_py}"; \
sed -i 's/"env_vars": comp.env_vars,/"env_vars": {},/' "${launcher_py}"; \
grep -Fq '"env_vars": {},' "${launcher_py}"; \
! grep -Fq '"env_vars": comp.env_vars,' "${launcher_py}"; \
test -x /opt/openyuanrong/bin/yr; \

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Those changes for what needs?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Retained as a security hardening required by the earlier review in discussion_r3756876315. The 0.10.1 wheel still logs the full component environment and persists component env_vars in session JSON. The exact grep checks make the build fail if an upstream source change causes either redaction patch to stop applying, rather than silently exposing values such as LITEBUS_DATA_KEY.

/opt/openyuanrong/bin/python -m py_compile \
"${site_packages}/yr/cli/component/ds_worker.py"; \
rm -f \
"${wheel}" \
/tmp/openyuanrong-core.constraints.txt \
/tmp/patch_openyuanrong_core.py

COPY --from=runtime-image /yr-runtime-rootfs.img ${YR_INSTALLATION_DIR}/yr-runtime-rootfs.img

Expand All @@ -358,6 +379,7 @@ RUN if [ "${AKERNEL_ENABLE_KATA}" = "true" ]; then \
COPY ./builder/scripts/akernel-entrypoint.sh /usr/local/bin/akernel-entrypoint
COPY ./builder/scripts/ensure-component-cert.sh /usr/local/bin/ensure-component-cert
COPY ./builder/scripts/sandboxd_network_prepare.sh /usr/local/bin/sandboxd-network-prepare
COPY ./builder/scripts/sandboxd_network_ready.sh /usr/local/bin/sandboxd-network-ready
RUN chmod 0755 \
/usr/local/bin/runsc \
/usr/local/bin/sandboxd \
Expand All @@ -366,7 +388,8 @@ RUN chmod 0755 \
/usr/local/bin/distill_fs \
/usr/local/bin/akernel-entrypoint \
/usr/local/bin/ensure-component-cert \
/usr/local/bin/sandboxd-network-prepare
/usr/local/bin/sandboxd-network-prepare \
/usr/local/bin/sandboxd-network-ready
RUN if [ "${AKERNEL_ENABLE_KATA}" = "true" ]; then chmod 0755 /usr/local/bin/containerd-shim-kata-v2; fi
RUN if [ "${AKERNEL_ENABLE_RUNC}" = "true" ]; then \
chmod 0755 /usr/local/bin/runc /usr/local/bin/runc-shim; \
Expand Down
22 changes: 12 additions & 10 deletions builder/scripts/akernel-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,8 @@ set -euo pipefail
role="${AKERNEL_ROLE:-}"

if [ -z "${role}" ] && [ "$#" -gt 0 ]; then
case "$1" in
master|frontend|node|standalone)
role="$1"
shift
;;
esac
role="$1"
shift
fi

if [ -z "${role}" ]; then
Expand All @@ -25,6 +21,16 @@ if [ -z "${role}" ]; then
fi
fi

case "${role}" in

@WenYuLuo WenYuLuo Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Seems to be a duplicate of line 10.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Updated in 7485d18. The entrypoint now consumes the role argument once, validates the resulting role once, and then exports AKERNEL_ROLE; the duplicate role-selection case is gone.

master|frontend|node|standalone)
;;
*)
echo "unsupported AKERNEL_ROLE: ${role}; expected master, frontend, node, or standalone" >&2
exit 1
;;
esac
export AKERNEL_ROLE="${role}"

case "${role}" in
master|frontend)
/usr/local/bin/ensure-component-cert
Expand All @@ -38,8 +44,4 @@ case "${role}" in
/usr/local/bin/ensure-component-cert
exec /usr/sbin/init "$@"
;;
*)
echo "unsupported AKERNEL_ROLE: ${role}" >&2
exit 1
;;
esac
Loading