diff --git a/templates/vine/desktop/Dockerfile.ubuntu b/templates/vine/desktop/Dockerfile.ubuntu index 7a7f5464..be5e88c1 100644 --- a/templates/vine/desktop/Dockerfile.ubuntu +++ b/templates/vine/desktop/Dockerfile.ubuntu @@ -25,6 +25,7 @@ ARG USER_UID ENV SHELL="${USER_SHELL}" ENV USER_SHELL="${USER_SHELL}" +ENV XDG_RUNTIME_DIR="/run/user/${USER_UID}" # Package Manager Configuration ARG DEBIAN_FRONTEND='noninteractive' @@ -37,6 +38,7 @@ STOPSIGNAL SIGRTMIN+3 WORKDIR /root/ ENTRYPOINT [ "/usr/bin/env" ] CMD [ "/usr/bin/systemctl", "init", "vine-desktop.service", "--user" ] +ENV NVIDIA_DRIVER_CAPABILITIES="all" # Volumes Configuration ## home.user @@ -331,6 +333,7 @@ RUN apt-get update && apt-get install -y \ libvulkan1 \ mesa-utils \ vulkan-icd \ + vulkan-tools \ # Core (Audio/PipeWire) libldacbt-abr2 libldacbt-enc2 \ libpipewire-0.3-common \ @@ -362,6 +365,13 @@ RUN apt-get update && apt-get install -y \ python3-yaml \ # Core (Scheduling) schedtool \ + # Core (Wayland) + wayland-protocols \ + # Core (Wayland RDP) + winpr-utils \ + # Core (Wayland Server) + weston \ + xwayland \ # Core (X11) dbus-x11 \ wmctrl \ @@ -461,6 +471,9 @@ RUN apt-get update && apt-get install -y \ && rm -f /etc/fonts/conf.d/65-nonlatin.conf \ # Remove conflicted repositories && rm -f /etc/apt/sources.list.d/vscode.list \ + # X11 Configuration + && mkdir -p /tmp/.X11-unix \ + && chmod 777 /tmp/.X11-unix \ # Cleanup && apt-get clean all \ && rm -rf /var/lib/apt/lists/* @@ -686,6 +699,9 @@ RUN /sbin/ldconfig.real \ && useradd -u "${USER_UID}" -g "${USER_GID}" -G "audio,cdrom,input,render,video" \ -s "/bin/${USER_SHELL}" -m -o "${USER_NAME}" \ && printf "${USER_UID}:2001:65535" > /etc/subuid \ - && printf "${USER_GID}:2001:65535" > /etc/subgid + && printf "${USER_GID}:2001:65535" > /etc/subgid \ + && mkdir -p "${XDG_RUNTIME_DIR}" \ + && chmod 700 "${XDG_RUNTIME_DIR}" \ + && chown "${USER_UID}:${USER_GID}" "${XDG_RUNTIME_DIR}" USER "${USER_NAME}" WORKDIR "/home/${USER_NAME}" diff --git a/templates/vine/desktop/apt/keyrings/kubernetes.gpg b/templates/vine/desktop/apt/keyrings/kubernetes.gpg index 909cd889..64f4d8f8 100644 --- a/templates/vine/desktop/apt/keyrings/kubernetes.gpg +++ b/templates/vine/desktop/apt/keyrings/kubernetes.gpg @@ -1,5 +1,5 @@ -----BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v2.0.15 (GNU/Linux) +Version: GnuPG v1.4.5 (GNU/Linux) mQENBGMHoXcBCADukGOEQyleViOgtkMVa7hKifP6POCTh+98xNW4TfHK/nBJN2sm u4XaiUmtB9UuGt9jl8VxQg4hOMRf40coIwHsNwtSrc2R9v5Kgpvcv537QVIigVHH @@ -8,13 +8,13 @@ qmREN+3Y9+5VcRZvQHeyBxCG+hdUGE740ixgnY2gSqZ/J4YeQntQ6pMUEhT6pbaE 10q2HUierj/im0V+ZUdCh46Lk/Rdfa5ZKlqYOiA2iN1coDPIdyqKavcdfPqSraKF Lan2KLcZcgTxP+0+HfzKefvGEnZa11civbe9ABEBAAG0PmlzdjprdWJlcm5ldGVz IE9CUyBQcm9qZWN0IDxpc3Y6a3ViZXJuZXRlc0BidWlsZC5vcGVuc3VzZS5vcmc+ -iQE+BBMBCAAoBQJjB6F3AhsDBQkEHrAABgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIX -gAAKCRAjRlTamilkNhnRCADud9iv+2CUtJGyZhhdzzd55wRKvHGmSY4eIAEKChmf -1+BHwFnzBzbdNtnglY2xSATqKIWikzXI1stAwi8qR0dK32CS+ofMS6OUklm26Yd1 -jBWFg4LCCh8S21GLcuudHtW9QNCCjlByS4gyEJ+eYTOo2dWp88NWEzVXIKRtfLHV -myHJnt2QLmWOeYTgmCzpeT8onl2Lp19bryRGla+Ms0AmlCltPn8j+hPeADDtR2bv -7cTLDi/nA46u3SLV1P6yjC1ejOOswtgxppTxvLgYniS22aSnoqm47l111zZiZKJ5 -bCm1Th6qJFJwOrGEOu3aV1iKaQmN2k4G2DixsHFAU3ZeiQIcBBMBAgAGBQJjB6F3 +iQE+BBMBCAAoBQJnFF34AhsDBQkIK2yBBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIX +gAAKCRAjRlTamilkNtOACACDK9dQ8CH2Ji9C3Q926nVMUiXdyJK1onCBrQSEBqdR +LJaT6hGx5pzxkQGgUDpS9p7LA0u920HKLwGb7yIAWtyE5TAj2CYprGgpq98sfsGC ++U5T9IrAdya/BaTAkkP6gNhfMjNaK3bOWsvuLRlluKMNch4ify+IwLqc1JLG40bj +2HnKBGYkC3m0VtQfUuPQMImSLta/NwRHJMPo8jfGyManqMMxp35/ecP2rXMfb/l1 +WjFDY7h+6nqXay20ljMXkN23W8wFTdvC6lq45wwM5IBnKNR/TjNNYAIizZoHFWz1 +c/ecMWWWCB2S7WbY4xI3JSCOD4XIff3ie7pc68/kgPytiQIcBBMBAgAGBQJjB6F3 AAoJEM8Lkoze1k873TQP/0t2F/jltLRQMG7VCLw7+ps5JCW5FIqu/S2i9gSdNA0E 42u+LyxjG3YxmVoVRMsxeu4kErxr8bLcA4p71W/nKeqwF9VLuXKirsBC7z2syFiL Ndl0ARnC3ENwuMVlSCwJO0MM5NiJuLOqOGYyD1XzSfnCzkXN0JGA/bfPRS5mPfoW @@ -26,5 +26,5 @@ GXzj9RCUaR6vtFVvqqo4fvbA99k4XXj+dFAXW0TRZ/g2QMePW9cdWielcr+vHF4Z qtscbfm5FVL36o7dkjA0x+TYCtqZIr4x3mmfAYFUqzxpfyXbSHqUJR2CoWxlyz72 XnJ7UEo/0UbgzGzscxLPDyJHMM5Dn/Ni9FVTVKlALHnFOYYSTluoYACF1DMt7NJ3 oyA0MELL0JQzEinixqxpZ1taOmVR/8pQVrqstqwqsp3RABaeZ80JbigUC29zJUVf -=F4EX +=Eplj -----END PGP PUBLIC KEY BLOCK----- diff --git a/templates/vine/desktop/scripts/entrypoint-desktop.sh b/templates/vine/desktop/scripts/entrypoint-desktop.sh index 6126a639..9a777c40 100755 --- a/templates/vine/desktop/scripts/entrypoint-desktop.sh +++ b/templates/vine/desktop/scripts/entrypoint-desktop.sh @@ -12,6 +12,17 @@ set -x trap "echo 'Gracefully terminating...'; exit" INT TERM trap "echo 'Terminated.'; exit" EXIT +# Configure environment variables +export __ENV_HOME='/tmp/.openark-vine-env' +rm -rf "${__ENV_HOME}" +touch "${__ENV_HOME}" + +# Initialize rootless container xdg session +"$(dirname "$0")/init-desktop-xdg.sh" + +# Initialize rootless container wayland session +"$(dirname "$0")/init-desktop-wayland.sh" + # Initialize rootless container environment "$(dirname "$0")/init-desktop-podman.sh" diff --git a/templates/vine/desktop/scripts/init-desktop-apps.sh b/templates/vine/desktop/scripts/init-desktop-apps.sh new file mode 100644 index 00000000..dcfa5b3f --- /dev/null +++ b/templates/vine/desktop/scripts/init-desktop-apps.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# Copyright (c) 2023 Ho Kim (ho.kim@ulagbulag.io). All rights reserved. +# Use of this source code is governed by a GPL-3-style license that can be +# found in the LICENSE file. + +# Prehibit errors +set -e -o pipefail +# Verbose +set -x + +# Configure environment variables +echo "export MOZ_ENABLE_WAYLAND=\"1\"" >>"${__ENV_HOME}" diff --git a/templates/vine/desktop/scripts/init-desktop-display.sh b/templates/vine/desktop/scripts/init-desktop-display.sh index 3fbaa35f..0963fdf0 100755 --- a/templates/vine/desktop/scripts/init-desktop-display.sh +++ b/templates/vine/desktop/scripts/init-desktop-display.sh @@ -8,19 +8,13 @@ set -e -o pipefail # Verbose set -x +# Apply environment variables +source "${__ENV_HOME}" + # Configure screen size function update_screen_size() { - echo "Finding displays..." - screens="$(xrandr --current | grep ' connected ' | awk '{print $1}')" - if [ "x${screens}" == "x" ]; then - echo 'Display not found!' - return - fi - - for screen in $(echo -en "${screens}"); do - echo "Fixing screen size to preferred (${screen})..." - xrandr --output "${screen}" --preferred || true - done + echo "Configuring screen size..." + xrandr --auto || true # Disable screen blanking echo "Disabling screen blanking..." diff --git a/templates/vine/desktop/scripts/init-desktop-im.sh b/templates/vine/desktop/scripts/init-desktop-im.sh index e396dc55..18d6fd57 100755 --- a/templates/vine/desktop/scripts/init-desktop-im.sh +++ b/templates/vine/desktop/scripts/init-desktop-im.sh @@ -8,5 +8,8 @@ set -e -o pipefail # Verbose set -x +# Apply environment variables +source "${__ENV_HOME}" + # Try to run nimf daemon nimf || true diff --git a/templates/vine/desktop/scripts/init-desktop-podman.sh b/templates/vine/desktop/scripts/init-desktop-podman.sh index cf5f411e..d4fce5d9 100755 --- a/templates/vine/desktop/scripts/init-desktop-podman.sh +++ b/templates/vine/desktop/scripts/init-desktop-podman.sh @@ -15,13 +15,13 @@ if which podman; then cp /etc/containers/podman-containers.conf "${HOME}/.config/containers/containers.conf" # Initialize rootless podman - podman system migrate + if podman system migrate; then + # Generate a CDI specification that refers to all NVIDIA devices + if ! nvidia-ctk cdi generate --device-name-strategy=type-index --format=json >/etc/cdi/nvidia.json; then + rm -f /etc/cdi/nvidia.json + fi - # Generate a CDI specification that refers to all NVIDIA devices - if ! nvidia-ctk cdi generate --device-name-strategy=type-index --format=json >/etc/cdi/nvidia.json; then - rm -f /etc/cdi/nvidia.json + # Ignore welcome warnings + podman version fi - - # Ignore welcome warnings - podman version fi diff --git a/templates/vine/desktop/scripts/init-desktop-storage.sh b/templates/vine/desktop/scripts/init-desktop-storage.sh index 6a6e5c8c..cb26c2dc 100755 --- a/templates/vine/desktop/scripts/init-desktop-storage.sh +++ b/templates/vine/desktop/scripts/init-desktop-storage.sh @@ -13,6 +13,10 @@ function _mount_overlayfs() { local dst=$2 local read_only="$3" + if [ ! -d "${src}" ]; then + return + fi + if [[ "x${read_only}" != 'xtrue' ]]; then rm -rf "${dst}" ln -sf "${src}" "${dst}" diff --git a/templates/vine/desktop/scripts/init-desktop-template.sh b/templates/vine/desktop/scripts/init-desktop-template.sh index 8e48addd..1bdef760 100755 --- a/templates/vine/desktop/scripts/init-desktop-template.sh +++ b/templates/vine/desktop/scripts/init-desktop-template.sh @@ -8,6 +8,11 @@ set -e -o pipefail # Verbose set -x +# Skip if template is not defined +if [ "x${KISS_DESKTOP_TEMPLATE_GIT}" == 'x' ]; then + exec true +fi + # Skip if already initialized LOCKFILE="${HOME}/.kiss-lock" if [ -f "${LOCKFILE}" ]; then diff --git a/templates/vine/desktop/scripts/init-desktop-wayland.sh b/templates/vine/desktop/scripts/init-desktop-wayland.sh new file mode 100755 index 00000000..72ee2f62 --- /dev/null +++ b/templates/vine/desktop/scripts/init-desktop-wayland.sh @@ -0,0 +1,64 @@ +#!/bin/bash +# Copyright (c) 2024 Ho Kim (ho.kim@ulagbulag.io). All rights reserved. +# Use of this source code is governed by a GPL-3-style license that can be +# found in the LICENSE file. + +# Prehibit errors +set -e -o pipefail +# Verbose +set -x + +# Configure environment variables +export DISPLAY="${DISPLAY:-:0}" +export WAYLAND_DISPLAY="${WAYLAND_DISPLAY:-wayland-0}" + +echo "export DISPLAY=\"${DISPLAY}\"" >>"${__ENV_HOME}" +# FIXME: Vulkan support is not stable on Wayland backend +# echo "export WAYLAND_DISPLAY=\"${WAYLAND_DISPLAY}\"" >>"${__ENV_HOME}" + +# Create an empty X11 socket directory, if not exists +mkdir -p "/tmp/.X11-unix" + +# Create a xwayland session, if not exists +if [ ! -S "/tmp/.X11-unix/X$(echo $DISPLAY | grep -Po '[0-9]+$')" ]; then + # Configure wayland + WAYLAND_BACKEND_RDP='rdp-backend.so' + + WAYLAND_ARGS="${WAYLAND_ARGS} --shell=kiosk-shell.so" + # FIXME: Vulkan support is not stable on Wayland backend + # WAYLAND_ARGS="${WAYLAND_ARGS} --socket=${WAYLAND_DISPLAY}" + WAYLAND_ARGS="${WAYLAND_ARGS} --xwayland" + WAYLAND_BACKEND="${WAYLAND_BACKEND:-$WAYLAND_BACKEND_RDP}" + + # Configure RDP + if [ "x${WAYLAND_BACKEND}" == "x${WAYLAND_BACKEND_RDP}" ]; then + # Generate a TLS key pair + WAYLAND_RDP_TLS_HOME="${HOME}/.rdp" + if [ ! -f "${WAYLAND_RDP_TLS_HOME}/${HOSTNAME}.crt" ] || + [ ! -f "${WAYLAND_RDP_TLS_HOME}/${HOSTNAME}.key" ]; then + mkdir -p "${WAYLAND_RDP_TLS_HOME}" + chmod 700 "${WAYLAND_RDP_TLS_HOME}" + winpr-makecert -rdp -path "${WAYLAND_RDP_TLS_HOME}" >/dev/null + fi + + # Register the RDP TLS key pair + WAYLAND_ARGS="${WAYLAND_ARGS} --rdp-tls-cert ${WAYLAND_RDP_TLS_HOME}/${HOSTNAME}.crt" + WAYLAND_ARGS="${WAYLAND_ARGS} --rdp-tls-key ${WAYLAND_RDP_TLS_HOME}/${HOSTNAME}.key" + fi + + # Detect GPU Devices + if nvidia-smi >/dev/null 2>/dev/null; then + export __GLX_VENDOR_LIBRARY_NAME="nvidia" + export __NV_PRIME_RENDER_OFFLOAD="1" + export VK_DRIVER_FILES="/usr/share/vulkan/icd.d/nvidia_icd.json" + export VK_ICD_FILENAMES="${VK_DRIVER_FILES}" + + # Make these environment variables persistent + echo "export __GLX_VENDOR_LIBRARY_NAME=\"${__GLX_VENDOR_LIBRARY_NAME}\"" >>"${__ENV_HOME}" + echo "export __NV_PRIME_RENDER_OFFLOAD=\"${__NV_PRIME_RENDER_OFFLOAD}\"" >>"${__ENV_HOME}" + echo "export VK_DRIVER_FILES=\"${VK_DRIVER_FILES}\"" >>"${__ENV_HOME}" + echo "export VK_ICD_FILENAMES=\"${VK_ICD_FILENAMES}\"" >>"${__ENV_HOME}" + fi + + weston --backend="${WAYLAND_BACKEND}" ${WAYLAND_ARGS} & +fi diff --git a/templates/vine/desktop/scripts/init-desktop-xdg.sh b/templates/vine/desktop/scripts/init-desktop-xdg.sh new file mode 100755 index 00000000..9662d954 --- /dev/null +++ b/templates/vine/desktop/scripts/init-desktop-xdg.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# Copyright (c) 2024 Ho Kim (ho.kim@ulagbulag.io). All rights reserved. +# Use of this source code is governed by a GPL-3-style license that can be +# found in the LICENSE file. + +# Prehibit errors +set -e -o pipefail +# Verbose +set -x + +# Configure environment variables +export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}" + +# Make these environment variables persistent +echo "export XDG_RUNTIME_DIR=\"${XDG_RUNTIME_DIR}\"" >>"${__ENV_HOME}" + +# Create an empty XDG runtime directory, if not exists +mkdir -p "${XDG_RUNTIME_DIR}" +chmod 700 "${XDG_RUNTIME_DIR}" diff --git a/templates/vine/desktop/scripts/init-desktop-xfce4.sh b/templates/vine/desktop/scripts/init-desktop-xfce4.sh index 5a56a1ed..42deac62 100755 --- a/templates/vine/desktop/scripts/init-desktop-xfce4.sh +++ b/templates/vine/desktop/scripts/init-desktop-xfce4.sh @@ -8,56 +8,10 @@ set -e -o pipefail # Verbose set -x -# Configure screen -function update_screen() { - echo "Finding monitors..." - monitors="$(xrandr --current | grep ' connected ' | awk '{print $1}')" - if [ "x${monitors}" == "x" ]; then - echo 'Display not found!' - return - fi - - local target_xml="${HOME}/.config/xfce4/xfconf/xfce-perchannel-xml/displays.xml" - for monitor in $(echo -en "${monitors}"); do - echo "Fixing monitor screen size to preferred (${monitor})..." - spec=$( - xrandr | - awk -v monitor="^${monitor} connected" '/disconnected/ {p = 0} $0 ~ monitor {p = 1} p' | - tail -n +2 - ) - - # Fix FHD if possible - monitor_resolution='1920x1080' - if ! echo "${spec}" | grep -q "${monitor_resolution}"; then - monitor_resolution="$(echo "${spec}" | grep -Po '^ *\K[0-9x]+' | head -n1)" - fi - echo "* Resolution = '${monitor_resolution}'" - - monitor_refresh_rate="$(echo "${spec}" | grep -Po "^ *${monitor_resolution} *\K[0-9.]+")" - echo "* Refresh Rate = '${monitor_refresh_rate}'" - - # Update screen size if primary - if [ "${monitor}" = "${monitors}" ]; then - xrandr --output "${monitor}" \ - --size "${monitor_resolution}" \ - --refresh "${monitor_refresh_rate}" || true - fi - - xmlstarlet edit \ - --inplace \ - --update "/channel/property/property[@name='${monitor}']/property[@name='Resolution']/@value" \ - --value "${monitor_resolution}" \ - "${target_xml}" - xmlstarlet edit \ - --inplace \ - --update "/channel/property/property[@name='${monitor}']/property[@name='RefreshRate']/@value" \ - --value "${monitor_refresh_rate}" \ - "${target_xml}" - done -} - -# Apply -update_screen +# Apply environment variables +source "${__ENV_HOME}" +rm -f "${__ENV_HOME}" +unset __ENV_HOME # Remove cached sessions (saved sessions, etc.) rm -rf "${HOME}/.cache/sessions/" || true diff --git a/templates/vine/templates/session/user-session.yaml.j2 b/templates/vine/templates/session/user-session.yaml.j2 index 54e208bd..bb1f4c0a 100644 --- a/templates/vine/templates/session/user-session.yaml.j2 +++ b/templates/vine/templates/session/user-session.yaml.j2 @@ -22,14 +22,14 @@ metadata: name: desktop namespace: "{{ metadata.namespace }}" labels: - name: desktop + app: desktop node: "{{ spec.node.metadata.name }}" spec: {% if spec.persistence %} replicas: 1 selector: matchLabels: - name: desktop + app: desktop node: "{{ spec.node.metadata.name }}" strategy: type: Recreate @@ -41,7 +41,7 @@ spec: template: metadata: labels: - name: desktop + app: desktop node: "{{ spec.node.metadata.name }}" spec: affinity: @@ -316,6 +316,12 @@ spec: - name: ssh protocol: TCP containerPort: 22 + - name: rdp-tcp + protocol: TCP + containerPort: 3389 + - name: rdp-udp + protocol: UDP + containerPort: 3389 - name: http protocol: TCP containerPort: 8080 @@ -511,7 +517,7 @@ metadata: name: novnc namespace: "{{ metadata.namespace }}" labels: - name: novnc + app: novnc node: "{{ spec.node.metadata.name }}" spec: replicas: 1 @@ -520,12 +526,12 @@ spec: maxUnavailable: 1 selector: matchLabels: - name: novnc + app: novnc node: "{{ spec.node.metadata.name }}" template: metadata: labels: - name: novnc + app: novnc node: "{{ spec.node.metadata.name }}" spec: affinity: @@ -602,13 +608,22 @@ metadata: name: desktop namespace: "{{ metadata.namespace }}" labels: - name: desktop + app: desktop node: "{{ spec.node.metadata.name }}" spec: selector: - name: desktop + app: desktop node: "{{ spec.node.metadata.name }}" ports: + - name: ssh + protocol: TCP + port: 22 + - name: rdp-tcp + protocol: TCP + port: 3389 + - name: rdp-udp + protocol: UDP + port: 3389 {% for port in spec.boxQuota.desktop.container.ports %} - {% if port is containing("name") %} @@ -630,11 +645,11 @@ metadata: name: novnc namespace: "{{ metadata.namespace }}" labels: - name: novnc + app: novnc node: "{{ spec.node.metadata.name }}" spec: selector: - name: novnc + app: novnc node: "{{ spec.node.metadata.name }}" ports: # - name: vnc @@ -664,7 +679,7 @@ metadata: vine.ulagbulag.io/is-service-system: "true" vine.ulagbulag.io/service-kind: noVNC ({{ spec.node.metadata.name }}) labels: - name: novnc + app: novnc node: "{{ spec.node.metadata.name }}" spec: ingressClassName: ingress-nginx-controller.vine.svc.ops.openark @@ -704,7 +719,7 @@ metadata: name: desktop namespace: "{{ metadata.namespace }}" labels: - name: desktop + app: desktop node: "{{ spec.node.metadata.name }}" spec: accessModes: