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 .dockerignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Git metadata is not part of the image build. Component versions come from
# their source manifests, and exact revisions remain traceable through the
# parent repository's submodule gitlinks.
# parent repository's submodule gitlinks or checksum-pinned source archives.
.git
**/.git

Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ jobs:
run: |
gateway_ip="$(docker inspect \
--format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' \
akernel-traefik)"
akernel-node)"
test -n "${gateway_ip}"
token="$(cat deploy/standalone/data/token)"
export AKERNEL_TOKEN="${token}"
Expand Down Expand Up @@ -170,7 +170,7 @@ jobs:
run: |
gateway_ip="$(docker inspect \
--format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' \
akernel-traefik)"
akernel-node)"
test -n "${gateway_ip}"
token="$(cat deploy/standalone/data/token)"
export AKERNEL_TOKEN="${token}"
Expand All @@ -186,7 +186,7 @@ jobs:
if: failure()
run: |
docker ps -a
for container in akernel-node akernel-traefik; do
for container in akernel-node; do
if docker container inspect "${container}" >/dev/null 2>&1; then
echo "=== ${container}: docker logs ==="
docker logs --tail 500 "${container}" 2>&1 || true
Expand All @@ -204,5 +204,5 @@ jobs:
if [[ -x ./deploy/standalone/stop.sh ]]; then
./deploy/standalone/stop.sh
else
docker rm -f akernel-traefik akernel-node >/dev/null 2>&1 || true
docker rm -f akernel-node >/dev/null 2>&1 || true
fi
19 changes: 15 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,14 @@ runtimes and `openyuanrong_sdk`. `builder/node.Dockerfile` then compiles the
node components and produces the AKernel all-in-one image using the selected
runtime image and its matching service configuration.

The image also builds Edge, Node Proxy and the forwarding helper from a
checksum-pinned YuanRong source archive with its Cargo lockfile; their binaries
are installed under `data_plane/bin` for the Go CLI. The default Core wheel
and data-plane source are pinned to the matching YuanRong `2b54c26885c6`
build so the Core package includes Node Proxy address
registration and Edge process scripts. The RRT binary and sandbox SDK retain
their matching `0.10.2rc2` command protocol.

The control-plane and RRT release version is independent of the optional
actor-based `openyuanrong_sdk` installed in the Python runtime profile. This
actor backend is deprecated and retained only for compatibility with existing
Expand Down Expand Up @@ -175,7 +183,10 @@ source revisions are traceable through the AKernel commit's submodule gitlinks.

Use [`deploy/README.md`](./deploy/README.md) as the deployment entry point.
AKernel supports standalone, existing Kubernetes clusters via Helm, and
Terraform-based cloud provisioning.
Terraform-based cloud provisioning. The core chart enables Edge and Node Proxy
by default with an image containing the data-plane binaries and Go CLI support;
configure its TLS Secret and allowed CIDRs.
See `deploy/README.md` for ingress migration and SDK endpoint configuration.

Aliyun's aggregate Pod PID budget is configurable independently of the
per-sandbox limit; see `deploy/terraform/aliyun/README.md#pod-pid-budget`.
Expand Down Expand Up @@ -380,13 +391,13 @@ export AKERNEL_SERVER_ADDRESS="<server_address>"
export AKERNEL_TOKEN="<your_token>"
```

When the public Traefik dual-entrypoint mode is enabled, a host/IP-only
With the default Edge ingress, a host/IP-only
`AKERNEL_SERVER_ADDRESS` uses HTTPS/WSS on 443 for the frontend API and exec
websocket, and HTTP on 80 for sandbox port URLs. For standalone deployments,
use the Traefik container IP printed by `deploy/standalone/start.sh`:
use the AKernel container IP printed by `deploy/standalone/start.sh`:

```bash
export AKERNEL_SERVER_ADDRESS=<traefik-container-ip>
export AKERNEL_SERVER_ADDRESS=<akernel-container-ip>
```

No separate `AKERNEL_GATEWAY_ADDRESS` is required for the default standalone
Expand Down
2 changes: 1 addition & 1 deletion assets/akernel-architecture.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
52 changes: 41 additions & 11 deletions builder/node.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,17 @@ ARG AKERNEL_ENABLE_RUNC=false
ARG AKERNEL_ENABLE_FIRECRACKER=true
ARG SANDBOXD_BUILD_IMAGE=golang:1.25.5-bookworm
ARG DISTILL_FS_BUILD_IMAGE=rust:1.85.0-bookworm
ARG OPEN_YR_VERSION=0.10.2rc2
ARG DATA_PLANE_BUILD_IMAGE=rust:1.95.0-bookworm
ARG DATA_PLANE_SOURCE_URL=https://codeload.github.com/openYuanrong-mirror/yuanrong/tar.gz/2b54c26885c67535e7b5b80608812f0d5ed33244
ARG DATA_PLANE_SOURCE_SHA256=c57b633b3fe50802ec9fcd70cb1da24ac80bea54984ed8d5d2cff15e7781dcfb
ARG OPEN_YR_VERSION=0.7.0+2b54c26885c6
ARG OPEN_YR_CORE_WHEEL_URL=
ARG OPEN_YR_CORE_WHEEL_SHA256=
ARG OPEN_YR_RELEASE_BASE_URL=https://openyuanrong.obs.cn-southwest-2.myhuaweicloud.com/release
ARG OPEN_YR_CORE_AMD64_SHA256=8cdefba9a415a7a35b6f39bf847e7fb933ad6ca55b27b7dec2f377ece47198c4
ARG OPEN_YR_CORE_ARM64_SHA256=2e9d2d18922b87721fcc3e92fa959cdd2ce026a51b18512c7c71ab24ac6a6eaa
# Core includes the matching process scripts and FunctionProxy registration.
ARG OPEN_YR_CORE_AMD64_URL=https://openyuanrong.obs.cn-southwest-2.myhuaweicloud.com/daily/20260909023812/linux/amd64/openyuanrong_core-0.7.0%2B2b54c26885c6-py3-none-manylinux_2_31_x86_64.whl
ARG OPEN_YR_CORE_ARM64_URL=https://openyuanrong.obs.cn-southwest-2.myhuaweicloud.com/daily/20260909024016/linux/arm64/openyuanrong_core-0.7.0%2B2b54c26885c6-py3-none-manylinux_2_31_aarch64.whl
ARG OPEN_YR_CORE_AMD64_SHA256=b459e916e75d5ef6c59988ad7b4108fd15a19c8fd102f2ca7ab98b5e9fc7a09c
ARG OPEN_YR_CORE_ARM64_SHA256=0678dc164e371471665fa2468967c456055c5cbd2f24bb130384189f75fc7a2a
ARG GVISOR_DOWNLOAD_IMAGE=ubuntu:24.04
ARG GVISOR_RELEASE
ARG GVISOR_AMD64_URL
Expand All @@ -38,6 +43,29 @@ ARG OTELCOL_CONTRIB_URL=https://github.com/open-telemetry/opentelemetry-collecto
ARG AKERNEL_VERSION=unknown
ARG AKERNEL_REVISION=unknown

# The data plane is packaged independently from the Core wheel. Build the
# checksum-pinned source with its lockfile and include it in every node image.
FROM ${DATA_PLANE_BUILD_IMAGE} AS data-plane-builder
ARG DATA_PLANE_SOURCE_URL
ARG DATA_PLANE_SOURCE_SHA256
RUN apt-get update && \
apt-get install -y --no-install-recommends ca-certificates curl protobuf-compiler && \
rm -rf /var/lib/apt/lists/*
WORKDIR /src/data-plane-gateway
RUN set -eux; \
curl -fSL --retry 5 --retry-delay 2 \
"${DATA_PLANE_SOURCE_URL}" -o /tmp/data-plane-source.tar.gz; \
echo "${DATA_PLANE_SOURCE_SHA256} /tmp/data-plane-source.tar.gz" | sha256sum -c -; \
tar -xzf /tmp/data-plane-source.tar.gz --strip-components=2 \
--wildcards '*/data-plane-gateway/*'; \
rm /tmp/data-plane-source.tar.gz; \
cargo build --locked --release --all-features --bins; \
mkdir -p /output/bin; \
for binary in yr-edge-frontend yr-node-proxy yr-data-plane-forward; do \
install -m 0755 "target/release/${binary}" "/output/bin/${binary}"; \
strip "/output/bin/${binary}"; \
done

FROM ${GVISOR_DOWNLOAD_IMAGE} AS gvisor-runtime
ARG GVISOR_RELEASE
ARG GVISOR_AMD64_URL
Expand Down Expand Up @@ -223,7 +251,8 @@ ARG AKERNEL_REVISION
ARG OPEN_YR_VERSION
ARG OPEN_YR_CORE_WHEEL_URL
ARG OPEN_YR_CORE_WHEEL_SHA256
ARG OPEN_YR_RELEASE_BASE_URL
ARG OPEN_YR_CORE_AMD64_URL
ARG OPEN_YR_CORE_ARM64_URL
ARG OPEN_YR_CORE_AMD64_SHA256
ARG OPEN_YR_CORE_ARM64_SHA256
ARG GVISOR_RELEASE
Expand Down Expand Up @@ -299,21 +328,21 @@ ENV YR_INSTALLATION_DIR=/home/yuanrong

# Install the complete, language-runtime-free openYuanRong control plane from
# its checksum-pinned core wheel. A URL and checksum pair may override the
# release asset when validating an unreleased daily build.
# selected artifact when validating another build.
RUN set -eux; \
case "${TARGETARCH:-}" in \
amd64) wheel_arch=x86_64; wheel_platform=amd64; release_sha="${OPEN_YR_CORE_AMD64_SHA256}" ;; \
arm64) wheel_arch=aarch64; wheel_platform=arm64; release_sha="${OPEN_YR_CORE_ARM64_SHA256}" ;; \
amd64) wheel_arch=x86_64; default_core_url="${OPEN_YR_CORE_AMD64_URL}"; release_sha="${OPEN_YR_CORE_AMD64_SHA256}" ;; \
arm64) wheel_arch=aarch64; default_core_url="${OPEN_YR_CORE_ARM64_URL}"; release_sha="${OPEN_YR_CORE_ARM64_SHA256}" ;; \
"") \
case "$(uname -m)" in \
x86_64) wheel_arch=x86_64; wheel_platform=amd64; release_sha="${OPEN_YR_CORE_AMD64_SHA256}" ;; \
aarch64) wheel_arch=aarch64; wheel_platform=arm64; release_sha="${OPEN_YR_CORE_ARM64_SHA256}" ;; \
x86_64) wheel_arch=x86_64; default_core_url="${OPEN_YR_CORE_AMD64_URL}"; release_sha="${OPEN_YR_CORE_AMD64_SHA256}" ;; \
aarch64) wheel_arch=aarch64; default_core_url="${OPEN_YR_CORE_ARM64_URL}"; release_sha="${OPEN_YR_CORE_ARM64_SHA256}" ;; \
*) echo "unsupported openYuanRong target architecture: $(uname -m)" >&2; exit 1 ;; \
esac ;; \
*) echo "unsupported openYuanRong target architecture: ${TARGETARCH}" >&2; exit 1 ;; \
esac; \
wheel_name="openyuanrong_core-${OPEN_YR_VERSION}-py3-none-manylinux_2_31_${wheel_arch}.whl"; \
wheel_url="${OPEN_YR_RELEASE_BASE_URL}/${OPEN_YR_VERSION}/linux/${wheel_platform}/${wheel_name}"; \
wheel_url="${default_core_url}"; \
wheel_sha="${release_sha}"; \
if [ -n "${OPEN_YR_CORE_WHEEL_URL}" ]; then \
test -n "${OPEN_YR_CORE_WHEEL_SHA256}"; \
Expand Down Expand Up @@ -343,6 +372,7 @@ RUN set -eux; \

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

COPY --from=data-plane-builder /output/ ${YR_INSTALLATION_DIR}/data_plane/
COPY --from=gvisor-runtime /gvisor/runsc /usr/local/bin/runsc
COPY --from=sandboxd-builder /src/sandboxd/output/sandboxd /usr/local/bin/sandboxd
COPY --from=sandboxd-builder /src/sandboxd/output/sbox /usr/local/bin/sbox
Expand Down
31 changes: 30 additions & 1 deletion builder/scripts/akernel-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,36 @@ fi
case "${role}" in
master|frontend)
/usr/local/bin/ensure-component-cert
exec /bin/bash /home/yuanrong/entrypoint.sh "$@"
# The shared image uses systemd's stop signal for node/standalone.
# Translate it for the CLI and keep PID 1 alive until cleanup finishes.
child_pid=""
stop_requested=false
stop_control_plane() {
stop_requested=true
if [ -n "$child_pid" ]; then
kill -TERM "$child_pid" 2>/dev/null || true
fi
}
trap stop_control_plane TERM INT RTMIN+3
/bin/bash /home/yuanrong/entrypoint.sh "$@" &
child_pid=$!
if [ "$stop_requested" = true ]; then
stop_control_plane
fi
# A trapped signal interrupts wait before the child has exited.
status=0
while true; do
if wait "$child_pid"; then
status=0
break
else
status=$?
fi
if ! kill -0 "$child_pid" 2>/dev/null; then
break
fi
done
exit "$status"
;;
node)
/bin/bash /root/prepare_node.sh
Expand Down
48 changes: 48 additions & 0 deletions builder/scripts/edge-config.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/bash
# Copyright (c) 2026 Ant Group Corporation.
# SPDX-License-Identifier: Apache-2.0

configure_edge() {
EDGE_ARGS=()
if [ "${ENABLE_EDGE_FRONTEND:-false}" != true ]; then
return
fi
export EDGE_ADVERTISE_IP="${INSTANCE_IP:-${YR_NODE_IP:-127.0.0.1}}"
export YR_DATA_PLANE_EDGE_FRONTEND_PROXY_ROUTES_FILE=/run/akernel/edge-proxy-routes.json
mkdir -p /run/akernel/edge-http || return 1
python3 - <<'PY' || return 1
import json
import os
from pathlib import Path

Path('/run/akernel/edge-http/internal-stats').write_text(json.dumps({
'pod_ip': os.environ['EDGE_ADVERTISE_IP'],
'http_port': int(os.environ.get('EDGE_PLAIN_PORT', '80')),
'https_port': int(os.environ.get('EDGE_TLS_PORT', '443')),
}))
routes = [{'name': 'internal-stats', 'path_prefix': '/internal-stats',
'upstream': 'http://127.0.0.1:18081', 'strip_prefix': False}]
if os.environ.get('EDGE_GRAFANA_URL'):
routes.append({'name': 'grafana', 'path_prefix': '/grafana',
'upstream': os.environ['EDGE_GRAFANA_URL'], 'strip_prefix': False})
Path(os.environ['YR_DATA_PLANE_EDGE_FRONTEND_PROXY_ROUTES_FILE']).write_text(json.dumps(routes))
PY
python3 -m http.server 18081 --bind 127.0.0.1 --directory /run/akernel/edge-http &
EDGE_ARGS=(
--enable_edge_frontend true
--edge_frontend_tls_bind "0.0.0.0:${EDGE_TLS_PORT:-443}"
--edge_frontend_plain_bind "0.0.0.0:${EDGE_PLAIN_PORT:-80}"
--edge_frontend_health_bind "0.0.0.0:${EDGE_HEALTH_PORT:-18080}"
--edge_frontend_tls_cert "${EDGE_TLS_CERT:-/home/yuanrong/.cert/module.crt}"
--edge_frontend_tls_key "${EDGE_TLS_KEY:-/home/yuanrong/.cert/module.key}"
--edge_frontend_control_plane_address "${EDGE_ADVERTISE_IP}:8888"
--edge_frontend_iam_address 127.0.0.1:31113
--edge_frontend_validate_iam true
--edge_frontend_allowed_client_cidrs "${EDGE_ALLOWED_CLIENT_CIDRS:-0.0.0.0/0}"
--data_plane_log_dir "${DATA_PLANE_LOG_DIR:-/var/log/akernel-edge}"
--data_plane_log_stdout true
--edge_frontend_access_log_enabled true
)
FRONTEND_SSL_ENABLE=false
IAM_SSL_ENABLE=false
}
21 changes: 7 additions & 14 deletions builder/scripts/master_entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,6 @@ else
echo "otelcol watchdog skipped"
fi

# Set enable_traefik_provider based on TRAEFIK_MODE
if [ "${TRAEFIK_MODE:-etcd}" = "http" ]; then
ENABLE_TRAEFIK_PROVIDER=true
else
ENABLE_TRAEFIK_PROVIDER=false
fi

if [ -z "${LITEBUS_DATA_KEY:-}" ]; then
echo "LITEBUS_DATA_KEY is required for akernel master/frontend" >&2
exit 1
Expand All @@ -68,7 +61,10 @@ if [ ! -x "${YR_BIN}" ]; then
exit 1
fi

exec "${YR_BIN}" start --master --block true \
. /root/edge-config.sh
configure_edge || exit 1

exec "${YR_BIN}" start --master --block true "${EDGE_ARGS[@]}" \
-e -c 0 -m 8000 -s 4096 -n $HOSTNAME \
-d $DEPLOY_PATH \
--fs_health_check_retry_interval 1 \
Expand All @@ -79,7 +75,7 @@ exec "${YR_BIN}" start --master --block true \
--enable_iam_server ${ENABLE_IAM_SERVER:-true} \
--iam_token_expired_time_span 604800 \
--ssl_base_path=/home/yuanrong/.cert/ \
--frontend_ssl_enable=true \
--frontend_ssl_enable=${FRONTEND_SSL_ENABLE:-true} \
--frontend_client_auth_type NoClientCert \
--enable_function_token_auth ${ENABLE_FUNCTION_TOKEN_AUTH:-true} \
--enable_inherit_env false \
Expand All @@ -98,12 +94,9 @@ exec "${YR_BIN}" start --master --block true \
--ds_rpc_thread_num 128 \
--function_proxy_merge_process_enable true \
--force_low_reliability_instance true \
--enable_traefik_provider=${ENABLE_TRAEFIK_PROVIDER} \
--traefik_http_entry_point=${TRAEFIK_HTTP_ENTRYPOINT:-websecure} \
--traefik_enable_tls=${TRAEFIK_ENABLE_TLS:-false} \
--traefik_forward_timeout_ms=3000 \
--enable_traefik_provider=false \
--frontend_lease_bypass true \
--iam_ssl_enable true \
--iam_ssl_enable ${IAM_SSL_ENABLE:-true} \
--ssl_root_file ca.crt \
--ssl_cert_file module.crt \
--ssl_key_file module.key \
Expand Down
Loading
Loading