Unverified Commit 09a2ccd7 authored by Kroese's avatar Kroese Committed by GitHub
Browse files

Merge branch 'master' into dependabot/github_actions/docker/login-action-4

parents a9c30eb5 0d1044b4
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -5,8 +5,8 @@ FROM debian:trixie-slim
ARG TARGETARCH
ARG VERSION_ARG="0.0"
ARG VERSION_UTK="1.2.0"
ARG VERSION_VNC="1.7.0-beta"
ARG VERSION_PASST="2025_09_19"
ARG VERSION_VNC="1.7.0"
ARG VERSION_PASST="2026_01_20"

ARG DEBCONF_NOWARNINGS="yes"
ARG DEBIAN_FRONTEND="noninteractive"
@@ -42,7 +42,10 @@ RUN set -eu && \
        inotify-tools \
        netcat-openbsd \
        ca-certificates \
        qemu-system-x86 && \
        qemu-system-x86 \
        python3 \
        python3-pip && \
    pip3 install --no-cache-dir --break-system-packages qemu.qmp==0.0.6 && \
    wget "https://github.com/qemus/passt/releases/download/v${VERSION_PASST}/passt_${VERSION_PASST}_${TARGETARCH}.deb" -O /tmp/passt.deb -q && \
    dpkg -i /tmp/passt.deb && \
    apt-get clean && \

dynamic.md

0 → 100644
+31 −0
Original line number Diff line number Diff line
# Dynamic memory allocation

By default, the VM is allocated the full amount of RAM configured via `RAM_SIZE` for its entire lifetime.

If you want the container to dynamically reclaim unused guest RAM based on host memory pressure, you can enable memory ballooning. It is also used to prevent the guest from exceeding the container's memory limit, even when the limit is changed at runtime:

```yaml
environment:
  BALLOONING: "Y"
```

The following optional variables allow you to tune the ballooning behaviour:

| **Variable**              | **Default** | **Description**                                                    |
|---|---|---|
| `BALLOONING`              | _N_         | Set to `Y` to enable dynamic memory ballooning                     |
| `BALLOONING_MIN_MEM`      | `33%`       | Minimum balloon target, as a percentage of guest max memory (e.g. `33%`) or absolute size (e.g. `2G`) |
| `BALLOONING_RAM_THRESHOLD`| `80.0`      | Target host RAM usage percentage; the PI controller aims to keep host usage at or below this value |
| `BALLOONING_RAM_THRESHOLD_HARD`| `90.0` | Host RAM usage percentage above which the balloon target may drop below guest RAM usage, inducing guest memory pressure |
| `BALLOONING_PSI_PRESSURE` | `10.0`      | Host PSI `avg10` stall percentage at which the PSI ceiling begins to lower the balloon target |
| `BALLOONING_PSI_PRESSURE_MAX` | `50.0`  | Host PSI `avg10` stall percentage at which the PSI ceiling reaches the configured minimum balloon target |
| `BALLOONING_HYSTERESIS`   | `128M`      | Minimum balloon target change required before a resize is applied, as a percentage (e.g. `2%`) or absolute size (e.g. `256M`) |
| `BALLOONING_KP`           | `0.5`       | PI controller proportional gain; higher values react faster but may oscillate |
| `BALLOONING_KI`           | `0.05`      | PI controller integral gain; higher values correct steady-state error faster but risk overshoot |
| `BALLOONING_INTERVAL`     | `5`         | Polling interval in seconds                                        |

> [!NOTE]
> Memory ballooning uses Linux PSI (`/proc/pressure/memory`) for progressive pressure detection. Between `BALLOONING_PSI_PRESSURE` and `BALLOONING_PSI_PRESSURE_MAX` the PSI ceiling linearly lowers the maximum balloon target from guest max memory down to the configured minimum. If PSI is unavailable (kernel lacks `CONFIG_PSI`), both thresholds are silently skipped and ballooning continues using host memory usage alone.

> [!WARNING]
> If the container memory limit is reduced at runtime below the guest VM's current memory usage, the container may be killed by the OOM killer if the ballooning driver cannot reclaim memory from the guest fast enough.
+6 −0
Original line number Diff line number Diff line
@@ -364,6 +364,12 @@ kubectl apply -f https://raw.githubusercontent.com/qemus/qemu/refs/heads/master/

  Now the `./example` directory on the host will be available as `/mnt/example` in the guest.

### How do I enable dynamic memory allocation?

  By default, the VM is allocated the full amount of RAM configured via `RAM_SIZE` for its entire lifetime.

  However, you can enable [memory ballooning](dynamic.md) if you want the container to dynamically reclaim unused guest RAM based on host memory pressure.

### How can I provide custom arguments to QEMU?

  You can create the `ARGUMENTS` environment variable to provide additional arguments to QEMU at runtime:

src/balloon.py

0 → 100644
+758 −0

File added.

Preview size limit exceeded, changes collapsed.

src/balloon.sh

0 → 100644
+62 −0
Original line number Diff line number Diff line
#!/usr/bin/env bash
set -Eeuo pipefail

[[ "${BALLOONING:-}" != [Yy1]* ]] && return 0

# By default, the VM is allocated the full amount of RAM configured via RAM_SIZE for its entire lifetime, but if you want
# the container to dynamically reclaim unused guest RAM based on host memory pressure, you can enable memory ballooning.
# It is also used to prevent the guest from exceeding the container's memory limit, even when the limit is changed at runtime.

# The following optional variables allow you to tune the ballooning behaviour:

# BALLOONING	                     N	          Set to Y to enable dynamic memory ballooning
# BALLOONING_MIN_MEM	             33%	      Minimum balloon target, as a percentage of guest max memory (e.g. 33%) or absolute size (e.g. 2G)
# BALLOONING_RAM_THRESHOLD.  	     80.0	      Target host RAM usage percentage; the PI controller aims to keep host usage at or below this value
# BALLOONING_RAM_THRESHOLD_HARD	     90.0	      Host RAM usage percentage above which the balloon target may drop below guest RAM usage, inducing guest memory pressure
# BALLOONING_PSI_PRESSURE	         10.0	      Host PSI avg10 stall percentage at which the PSI ceiling begins to lower the balloon target
# BALLOONING_PSI_PRESSURE_MAX	     50.0	      Host PSI avg10 stall percentage at which the PSI ceiling reaches the configured minimum balloon target
# BALLOONING_HYSTERESIS	             128M	      Minimum balloon target change required before a resize is applied, as a percentage (e.g. 2%) or absolute size (e.g. 256M)
# BALLOONING_KP.             	     0.5	      PI controller proportional gain; higher values react faster but may oscillate
# BALLOONING_KI.            	     0.05	      PI controller integral gain; higher values correct steady-state error faster but risk overshoot
# BALLOONING_INTERVAL.      	     5	          Polling interval in seconds

# Note: memory ballooning uses Linux PSI (/proc/pressure/memory) for progressive pressure detection. Between BALLOONING_PSI_PRESSURE and 
# BALLOONING_PSI_PRESSURE_MAX the PSI ceiling linearly lowers the maximum balloon target from guest max memory down to the configured minimum.
# If PSI is unavailable (kernel lacks CONFIG_PSI), both thresholds are silently skipped and ballooning continues using host memory usage alone.

# Warning: if the container memory limit is reduced at runtime below the guest VM's current memory usage, the container
# may be killed by the OOM killer if the ballooning driver cannot reclaim memory from the guest fast enough.

ballooning() {

    # Wait for qemu PID file to be created
    while [ ! -f "$QEMU_PID" ]; do
        sleep 1
    done

    BALLOON_ARGS=()
    [[ -n "${BALLOONING_MIN_MEM:-}" ]] && BALLOON_ARGS+=(--min-mem "$BALLOONING_MIN_MEM")
    [[ -n "${BALLOONING_PSI_PRESSURE:-}" ]] && BALLOON_ARGS+=(--psi-pressure "$BALLOONING_PSI_PRESSURE")
    [[ -n "${BALLOONING_PSI_PRESSURE_MAX:-}" ]] && BALLOON_ARGS+=(--psi-pressure-max "$BALLOONING_PSI_PRESSURE_MAX")
    [[ -n "${BALLOONING_RAM_THRESHOLD:-}" ]] && BALLOON_ARGS+=(--ram-threshold "$BALLOONING_RAM_THRESHOLD")
    [[ -n "${BALLOONING_RAM_THRESHOLD_HARD:-}" ]] && BALLOON_ARGS+=(--ram-threshold-hard "$BALLOONING_RAM_THRESHOLD_HARD")
    [[ -n "${BALLOONING_HYSTERESIS:-}" ]] && BALLOON_ARGS+=(--hysteresis "$BALLOONING_HYSTERESIS")
    [[ -n "${BALLOONING_KP:-}" ]] && BALLOON_ARGS+=(--kp "$BALLOONING_KP")
    [[ -n "${BALLOONING_KI:-}" ]] && BALLOON_ARGS+=(--ki "$BALLOONING_KI")
    [[ -n "${BALLOONING_INTERVAL:-}" ]] && BALLOON_ARGS+=(--interval "$BALLOONING_INTERVAL")
    local _ballooning_debug="${BALLOONING_DEBUG:-${DEBUG:-}}"
    if [[ "$_ballooning_debug" == [Yy1]* ]]; then
        BALLOON_ARGS+=(--debug)
    elif [[ -n "$_ballooning_debug" && "$_ballooning_debug" != [Nn0]* ]]; then
        BALLOON_ARGS+=(--debug "$_ballooning_debug")
    fi

    python3 ./balloon.py --qmp-sock "$QEMU_DIR/qemu-qmp-ballooning.sock" --qemu-pid-file "$QEMU_PID" "${BALLOON_ARGS[@]}"
}

msg="Starting memory ballooning monitor..."
info "$msg"

( ballooning ) &

return 0
Loading