Переглянути джерело

[MAJOR] Move noVNC to Apache Guacamole, support Ubuntu 18.04

ehfd 4 роки тому
батько
коміт
01923f2a4e
4 змінених файлів з 148 додано та 111 видалено
  1. 93 65
      Dockerfile
  2. 7 5
      README.md
  3. 40 30
      bootstrap.sh
  4. 8 11
      xgl.yaml

+ 93 - 65
Dockerfile

@@ -1,4 +1,6 @@
 FROM nvidia/opengl:1.2-glvnd-runtime-ubuntu20.04
+# Comment the line above and uncomment the line below for Ubuntu 18.04
+#FROM nvidia/opengl:1.2-glvnd-runtime-ubuntu18.04
 
 LABEL maintainer "https://github.com/ehfd"
 
@@ -8,9 +10,9 @@ ARG NVIDIA_VISIBLE_DEVICES=all
 ARG DEBIAN_FRONTEND=noninteractive
 ENV NVIDIA_DRIVER_CAPABILITIES all
 
-# Default options (password is 'vncpasswd')
+# Default options (password is "mypasswd")
 ENV TZ UTC
-ENV VNCPASS vncpasswd
+ENV PASSWD mypasswd
 ENV SIZEW 1920
 ENV SIZEH 1080
 ENV CDEPTH 24
@@ -19,94 +21,76 @@ ENV VIDEO_PORT DFP
 # Install locales to prevent errors
 RUN apt-get clean && \
     apt-get update && \
-    apt-get install --no-install-recommends -y locales && \
+    apt-get install -y --no-install-recommends locales && \
     rm -rf /var/lib/apt/lists/* && \
     locale-gen en_US.UTF-8
 ENV LANG en_US.UTF-8
 ENV LANGUAGE en_US:en
 ENV LC_ALL en_US.UTF-8
 
-# https://gitlab.com/nvidia/container-images/driver/-/blob/master/ubuntu20.04/Dockerfile
+# Install Xorg, MATE desktop, and others
 RUN dpkg --add-architecture i386 && \
-    apt-get update && apt-get install -y --no-install-recommends \
+    apt-get update && apt-get install -y \
+        software-properties-common \
         apt-utils \
         build-essential \
         ca-certificates \
-        curl \
         kmod \
-        file \
         libc6:i386 \
-        libelf-dev \
-        libglvnd-dev \
-        pkg-config && \
-    rm -rf /var/lib/apt/lists/*
-
-# Install Xorg, MATE desktop, and others
-RUN apt-get update && apt-get install -y \
-        software-properties-common \
+        libc6-dev \
+        curl \
+        file \
         wget \
         gzip \
         zip \
         unzip \
         gcc \
         git \
-        libc6-dev \
-        libglu1 \
-        libglu1:i386 \
-        libsm6 \
-        libxv1 \
-        libxv1:i386 \
         make \
         python \
         python-numpy \
         python3 \
         python3-numpy \
-        dbus-x11 \
-        libdbus-c++-1-0v5 \
-        x11-xkb-utils \
-        x11-xserver-utils \
-        xauth \
-        xinit \
-        xfonts-base \
-        xkb-data \
-        libxrandr-dev \
-        xorg-dev \
-        libxtst6 \
-        libxtst6:i386 \
         mlocate \
         nano \
         vim \
         htop \
         firefox \
-        libpci3 \
         supervisor \
         net-tools \
-        ubuntu-mate-core \
-        ubuntu-mate-desktop \
+        libpci3 \
+        libelf-dev \
+        libglvnd-dev \
+        pkg-config \
         mesa-utils \
-        x11vnc \
-        x11-apps && \
+        libglu1 \
+        libglu1:i386 \
+        libsm6 \
+        libxv1 \
+        libxv1:i386 \
+        libxtst6 \
+        libxtst6:i386 \
+        x11-xkb-utils \
+        x11-xserver-utils \
+        x11-apps \
+        dbus-x11 \
+        libdbus-c++-1-0v5 \
+        xauth \
+        xinit \
+        xfonts-base \
+        xkb-data \
+        libxrandr-dev \
+        xorg-dev \
+        ubuntu-mate-desktop && \
+    if [ "$(grep VERSION_CODENAME= /etc/os-release | cut -d= -f2)" = "bionic" ]; then apt-get install -y --no-install-recommends vulkan-utils; else apt-get install -y --no-install-recommends vulkan-tools; fi && \
     # Remove Bluetooth packages that throw errors
     apt-get autoremove --purge -y blueman bluez bluez-cups pulseaudio-module-bluetooth && \
     rm -rf /var/lib/apt/lists/*
 
-# Install Vulkan and fix containerization issues
-RUN apt-get update && apt-get install -y --no-install-recommends \
-        libvulkan-dev \
-        vulkan-validationlayers-dev \
-        vulkan-utils \
-        meson && \
-    rm -rf /var/lib/apt/lists/* && \
-    cd /tmp && \
-    git clone https://github.com/aejsmith/vkdevicechooser && \
-    cd vkdevicechooser && \
-    meson builddir --prefix=/usr && \
-    meson install -C builddir && \
-    rm -rf /tmp/*
-
 # Wine and Winetricks, comment out the below lines to disable
 ARG WINE_BRANCH=stable
-RUN curl -fsSL https://dl.winehq.org/wine-builds/winehq.key | APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key add - && \
+RUN if [ "$(grep VERSION_CODENAME= /etc/os-release | cut -d= -f2)" = "bionic" ]; then add-apt-repository ppa:cybermax-dexter/sdl2-backport; fi && \
+    curl -fsSL https://dl.winehq.org/wine-builds/winehq.key | APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key add - && \
     apt-add-repository "deb https://dl.winehq.org/wine-builds/ubuntu/ $(grep VERSION_CODENAME= /etc/os-release | cut -d= -f2) main" && \
     apt-get update && apt-get install -y --install-recommends winehq-${WINE_BRANCH} && \
     rm -rf /var/lib/apt/lists/* && \
@@ -114,31 +98,75 @@ RUN curl -fsSL https://dl.winehq.org/wine-builds/winehq.key | APT_KEY_DONT_WARN_
     chmod 755 /usr/bin/winetricks && \
     curl -fsSL -o /usr/share/bash-completion/completions/winetricks https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks.bash-completion
 
-# noVNC and Websockify
-ENV NOVNC_VERSION 1.2.0
-RUN curl -fsSL https://github.com/novnc/noVNC/archive/v${NOVNC_VERSION}.tar.gz | tar -xzf - -C /opt && \
-    mv /opt/noVNC-${NOVNC_VERSION} /opt/noVNC && \
-    ln -s /opt/noVNC/vnc.html /opt/noVNC/index.html && \
-    git clone https://github.com/novnc/websockify /opt/noVNC/utils/websockify
+# Apache Guacamole and x11vnc
+ENV TOMCAT_VERSION 9.0.50
+RUN apt-get update && apt-get install -y --no-install-recommends \
+    libcairo2-dev \
+    libjpeg-turbo8-dev \
+    libpng-dev \
+    libtool-bin \
+    libossp-uuid-dev \
+    libavcodec-dev \
+    libavformat-dev \
+    libavutil-dev \
+    libswscale-dev \
+    freerdp2-dev \
+    libpango1.0-dev \
+    libssh2-1-dev \
+    libtelnet-dev \
+    libvncserver-dev \
+    libwebsockets-dev \
+    libpulse-dev \
+    libssl-dev \
+    libvorbis-dev \
+    libwebp-dev \
+    autoconf \
+    automake \
+    autotools-dev \
+    pulseaudio \
+    pavucontrol \
+    openssh-server \
+    openssh-sftp-server \
+    default-jdk \
+    maven \
+    libxdamage-dev \
+    libxinerama-dev \
+    libxrandr-dev \
+    libxss-dev \
+    libxtst-dev \
+    libv4l-dev \
+    libavahi-client-dev \
+    chrpath \
+    debhelper && \
+    rm -rf /var/lib/apt/lists/* && \
+    git clone https://github.com/LibVNC/x11vnc.git /tmp/x11vnc && \
+    cd /tmp/x11vnc && autoreconf -fi && ./configure && make install && cd / && rm -rf /tmp/* && \
+    curl -fsSL https://archive.apache.org/dist/tomcat/tomcat-$(echo $TOMCAT_VERSION | cut -d "." -f 1)/v${TOMCAT_VERSION}/bin/apache-tomcat-${TOMCAT_VERSION}.tar.gz | tar -xzf - -C /opt && \
+    mv /opt/apache-tomcat-$TOMCAT_VERSION /opt/tomcat && \
+    git clone https://github.com/apache/guacamole-server.git /tmp/guacamole-server && \
+    cd /tmp/guacamole-server && autoreconf -fi && ./configure --with-init-dir=/etc/init.d && make install && ldconfig && cd / && rm -rf /tmp/* && \
+    git clone https://github.com/apache/guacamole-client.git /tmp/guacamole-client && \
+    cd /tmp/guacamole-client && JAVA_HOME=/usr/lib/jvm/default-java mvn package && rm -rf /opt/tomcat/webapps/* && mv guacamole/target/guacamole*.war /opt/tomcat/webapps/ROOT.war && chmod +x /opt/tomcat/webapps/ROOT.war && cd / && rm -rf /tmp/* && \
+    echo "load-module module-native-protocol-tcp auth-ip-acl=127.0.0.0/8 auth-anonymous=1" >> /etc/pulse/default.pa
 
-# Create user with password ${VNCPASS}
+# Create user with password ${PASSWD}
 RUN apt-get update && apt-get install -y --no-install-recommends \
         sudo && \
     rm -rf /var/lib/apt/lists/* && \
     groupadd -g 1000 user && \
     useradd -ms /bin/bash user -u 1000 -g 1000 && \
-    usermod -a -G adm,audio,cdrom,dialout,dip,fax,floppy,input,lp,lpadmin,netdev,plugdev,render,scanner,ssh,sudo,tape,tty,video,voice user && \
+    usermod -a -G adm,audio,cdrom,dialout,dip,fax,floppy,input,lp,lpadmin,netdev,plugdev,scanner,ssh,sudo,tape,tty,video,voice user && \
     echo "user ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers && \
-    chown -R user:user /home/user && \
-    echo "user:${VNCPASS}" | chpasswd && \
-    ln -snf "/usr/share/zoneinfo/$TZ" /etc/localtime && echo "$TZ" | tee /etc/timezone > /dev/null
+    chown -R user:user /home/user /opt/tomcat && \
+    echo "user:${PASSWD}" | chpasswd && \
+    ln -snf "/usr/share/zoneinfo/$TZ" /etc/localtime && echo "$TZ" > /etc/timezone
 
 COPY bootstrap.sh /etc/bootstrap.sh
 RUN chmod 755 /etc/bootstrap.sh
 COPY supervisord.conf /etc/supervisord.conf
 RUN chmod 755 /etc/supervisord.conf
 
-EXPOSE 5901
+EXPOSE 8080
 
 USER user
 WORKDIR /home/user

+ 7 - 5
README.md

@@ -1,10 +1,10 @@
 # docker-nvidia-glx-desktop
 
-MATE Desktop container supporting GLX/Vulkan for NVIDIA GPUs by spawning its own X Server and noVNC WebSocket interface instead of using the host X server. Does not require `/tmp/.X11-unix` host sockets or host configuration. Designed for Kubernetes.
+MATE Desktop container supporting GLX/Vulkan for NVIDIA GPUs by spawning its own X Server and Guacamole interface instead of using the host X server. Does not require `/tmp/.X11-unix` host sockets or host configuration. Designed for Kubernetes, also supporting audio forwarding.
 
 Use [docker-nvidia-egl-desktop](https://github.com/ehfd/docker-nvidia-egl-desktop) for a MATE Desktop container that directly accesses NVIDIA GPUs without using an X11 Server (but without Vulkan support unlike this container).
 
-Requires reasonably recent NVIDIA GPU drivers and corresponding container toolkits to be set up on the host for allocating GPUs. GPUs should have one or more DVI-D/HDMI/DisplayPort digital video ports instead of having only analog video ports (which mean very ancient GPUs). However, the ports to be used are recommended NOT to be connected with an actual monitor, unless the user wants the remote desktop screen to be shown in the monitor. If you need to connect a real monitor to the X server session spawned by the container, connect the monitor and set **VIDEO_PORT** to the the video port connected to the monitor. Manually specify a video port that is not connected to a monitor in **VIDEO_PORT**. **VIDEO_PORT** identifiers and their connection states can be obtained by typing `xrandr -q` when the `$DISPLAY` environment variable is set. **Do not start more than one X server for one GPU. Use a separate GPU (or do not use one) for the host X server, and do not make it available to the containers.**
+Requires reasonably recent NVIDIA GPU drivers and corresponding container toolkits to be set up on the host for allocating GPUs. GPUs should have one or more DVI-D/HDMI/DisplayPort digital video ports instead of having only analog video ports (which mean very ancient GPUs). However, the ports to be used are recommended NOT to be connected with an actual monitor, unless the user wants the remote desktop screen to be shown in the monitor. If you need to connect a real monitor to the X server session spawned by the container, connect the monitor and set **VIDEO_PORT** to the the video port connected to the monitor. Manually specify a video port that is not connected to a monitor in **VIDEO_PORT**. **VIDEO_PORT** identifiers and their connection states can be obtained by typing `xrandr -q` when the `$DISPLAY` environment variable is set to the spawned X display. **Do not start more than one X server for one GPU. Use a separate GPU (or do not use one) for the host X server, and do not make it available to the containers.**
 
 Since this container fakes the driver to simulate being plugged in to a monitor while it actually does not, make sure the resolutions specified with the environment variables **SIZEW** and **SIZEH** are within the maximum size supported by the GPU. The environment variable **VIDEO_PORT** can override which video port is used (defaults to DFP, the first port detected in the driver). Therefore, overriding **VIDEO_PORT** to an unplugged DisplayPort (for example numbered like DP-0, DP-1, and so on) is recommended for resolutions above 1920 x 1200, because of some driver restrictions applied when the default is set to a DVI-D or HDMI port. The maximum size that should work in all cases is 1920 x 1200 at 60 hz, mainly for when the default DFP **VIDEO_PORT** identifier is not set to DisplayPort. The sizes between 1920 x 1200 and the maximum size for each port supported by GPU specifications will be possible if the port is set to DisplayPort, or when a real monitor or dummy plug to any other type of display ports including DVI-D and HDMI has been connected. If all GPUs have DisplayPort and they are not connected to any monitors, simply setting **VIDEO_PORT** to DP-0 is recommended (but this is not set as default because of legacy compatibility reasons).
 
@@ -14,14 +14,16 @@ Datacenter GPUs (Tesla) seem to only support resolutions of up to around 2560 x
 
 Container startup could take some time at first launch as it automatically installs NVIDIA drivers with the same version as the host.
 
-Connect to the spawned noVNC WebSocket instance with a browser in port 5901, no installed VNC client is required (password for the default user is 'vncpasswd').
+Connect to the spawned Apache Guacamole instance with a web browser in port 8080 (the username is "user" and the default password is "mypasswd"). No VNC client installation is required. Press Ctrl+Alt+Shift to toggle the configuration option in Guacamole. Click the fullscreen button in your web browser settings or press F11 after pressing Ctrl+Alt+Shift to bring up fullscreen.
 
 Wine and Winetricks are bundled by default, comment out the installation section in **Dockerfile** if the user wants to remove them from the container.
 
-This container should not be used in privileged mode, and requires to provision one **/dev/ttyN** (N >= 8) virtual terminal device in unprivileged mode. All containers in a single node should be provisioned with the exact same virtual terminal device. Check out [smarter-device-manager](https://gitlab.com/arm-research/smarter/smarter-device-manager) or [k8s-hostdev-plugin](https://github.com/bluebeach/k8s-hostdev-plugin) for provisioning this in Kubernetes clusters without privileged access.
+For building Ubuntu 18.04 containers, in **Dockerfile** change `FROM nvidia/opengl:1.2-glvnd-runtime-ubuntu20.04` to `FROM nvidia/opengl:1.2-glvnd-runtime-ubuntu18.04`.
+
+For Docker this will be sufficient (the container must only be used in unprivileged mode, use `--tmpfs /dev/shm:rw` for a slight performance improvement):
 
 ```
-docker run --gpus 1 --device=/dev/tty63:rw -it -e SIZEW=1920 -e SIZEH=1080 -e SHARED=TRUE -e VNCPASS=vncpasswd -e VIDEO_PORT=DFP -p 5901:5901 ehfd/nvidia-glx-desktop:latest
+docker run --gpus 1 -it -e SIZEW=1920 -e SIZEH=1080 -e SHARED=TRUE -e PASSWD=mypasswd -e VIDEO_PORT=DFP -p 8080:8080 ehfd/nvidia-glx-desktop:latest
 ```
 
 This work was supported in part by NSF awards CNS-1730158, ACI-1540112, ACI-1541349, OAC-1826967, the University of California Office of the President, and the University of California San Diego’s California Institute for Telecommunications and Information Technology/Qualcomm Institute. Thanks to CENIC for the 100Gbps networks.

+ 40 - 30
bootstrap.sh

@@ -3,10 +3,15 @@ set -e
 
 trap "echo TRAPed signal" HUP INT QUIT KILL TERM
 
-echo "user:$VNCPASS" | sudo chpasswd
+sudo chown -R user:user /home/user /opt/tomcat
+echo "user:$PASSWD" | sudo chpasswd
 sudo ln -snf "/usr/share/zoneinfo/$TZ" /etc/localtime && echo "$TZ" | sudo tee /etc/timezone > /dev/null
+export PATH="${PATH}:/opt/tomcat/bin"
 
+sudo ln -snf /dev/ptmx /dev/tty7
+sudo /etc/init.d/ssh start
 sudo /etc/init.d/dbus start
+pulseaudio --start
 
 # Install NVIDIA drivers, including X graphic drivers by omitting --x-{prefix,module-path,library-path,sysconfig-path}
 if ! command -v nvidia-xconfig &> /dev/null; then
@@ -63,43 +68,48 @@ sudo nvidia-xconfig --virtual="${SIZEW}x${SIZEH}" --depth="$CDEPTH" --mode=$(ech
 sudo sed -i '/Driver\s\+"nvidia"/a\    Option         "ModeValidation" "NoMaxPClkCheck, NoEdidMaxPClkCheck, NoMaxSizeCheck, NoHorizSyncCheck, NoVertRefreshCheck, NoVirtualSizeCheck, NoExtendedGpuCapabilitiesCheck, NoTotalSizeCheck, NoDualLinkDVICheck, NoDisplayPortBandwidthCheck, AllowNon3DVisionModes, AllowNonHDMI3DModes, AllowNonEdidModes, NoEdidHDMI2Check, AllowDpInterlaced"\n    Option         "DPI" "96 x 96"' /etc/X11/xorg.conf
 sudo sed -i '/Section\s\+"Monitor"/a\    '"$MODELINE" /etc/X11/xorg.conf
 
-shopt -s extglob
-for TTY in $(ls -1 /dev/tty+([0-9]) | sort -rV); do
-  if [ -w "$TTY" ]; then
-    Xorg vt"$(echo "$TTY" | grep -Eo '[0-9]+$')" -sharevts :0 &
-    break
-  fi
-done
-sleep 1
+Xorg vt7 -novtswitch -sharevts +extension "MIT-SHM" :0 &
 
 if [ "x$SHARED" == "xTRUE" ]; then
   export SHARESTRING="-shared"
 fi
 
-x11vnc -display ":0" -passwd "$VNCPASS" -forever -repeat -xkb -xrandr "resize" -rfbport 5900 "$SHARESTRING" &
-sleep 1
-
-/opt/noVNC/utils/launch.sh --vnc localhost:5900 --listen 5901 &
-sleep 1
+sudo x11vnc -display ":0" -passwd "$PASSWD" -forever -repeat -xkb -xrandr "resize" -rfbport 5900 "$SHARESTRING" &
+
+mkdir -p ~/.guacamole
+echo "<user-mapping>
+    <authorize username=\"user\" password=\"$PASSWD\">
+        <connection name=\"VNC\">
+            <protocol>vnc</protocol>
+            <param name=\"hostname\">localhost</param>
+            <param name=\"port\">5900</param>
+            <param name=\"autoretry\">10</param>
+            <param name=\"password\">$PASSWD</param>
+            <param name=\"enable-sftp\">true</param>
+            <param name=\"sftp-hostname\">localhost</param>
+            <param name=\"sftp-username\">user</param>
+            <param name=\"sftp-password\">$PASSWD</param>
+            <param name=\"sftp-directory\">/home/user</param>
+            <param name=\"enable-audio\">true</param>
+            <param name=\"audio-servername\">localhost</param>
+        </connection>
+        <connection name=\"SSH\">
+            <protocol>ssh</protocol>
+            <param name=\"hostname\">localhost</param>
+            <param name=\"username\">user</param>
+            <param name=\"password\">$PASSWD</param>
+            <param name=\"enable-sftp\">true</param>
+        </connection>
+    </authorize>
+</user-mapping>
+" > ~/.guacamole/user-mapping.xml
+chmod 0600 ~/.guacamole/user-mapping.xml
+
+/opt/tomcat/bin/catalina.sh run &
+guacd -f &
 
 export DISPLAY=:0
-UUID_CUT=$(sudo nvidia-smi --query-gpu=uuid --id="$GPU_SELECT" --format=csv | sed -n 2p | cut -c 5-)
-if vulkaninfo | grep "$UUID_CUT" | grep -q ^; then
-  VK=0
-  while true; do
-    if ENABLE_DEVICE_CHOOSER_LAYER=1 VULKAN_DEVICE_INDEX=$VK vulkaninfo | grep "$UUID_CUT" | grep -q ^; then
-      export ENABLE_DEVICE_CHOOSER_LAYER=1
-      export VULKAN_DEVICE_INDEX="$VK"
-      break
-    fi
-    VK=$((VK + 1))
-  done
-else
-  echo "Vulkan is not available for the current GPU."
-fi
-
 mate-session &
-pulseaudio --start
 
 echo "Session Running. Press [Return] to exit."
 read

+ 8 - 11
xgl.yaml

@@ -27,8 +27,8 @@ spec:
           value: "24"
         - name: SHARED
           value: "TRUE"
-        - name: VNCPASS
-          value: "vncpasswd"
+        - name: PASSWD
+          value: "mypasswd"
 #          valueFrom:
 #            secretKeyRef:
 #              name: xgl-pass
@@ -38,27 +38,27 @@ spec:
         stdin: true
         tty: true
         ports:
-        - containerPort: 5901
+        - containerPort: 8080
           protocol: TCP
         resources:
           limits:
             memory: 64Gi
             cpu: "16"
             nvidia.com/gpu: 1
-# Deploy either https://gitlab.com/arm-research/smarter/smarter-device-manager or https://github.com/bluebeach/k8s-hostdev-plugin and increase allocatable resources of one same virtual terminal device to at least the number of GPUs
-#            smarter-devices/tty63: 1
-#            hostdev.k8s.io/dev_tty63: 1
           requests:
             memory: 100Mi
             cpu: 100m
         volumeMounts:
+        - mountPath: /dev/shm
+          name: dshm
         - mountPath: /cache
           name: xgl-cache-vol
         - mountPath: /home/user
           name: xgl-root-vol
-        - mountPath: /dev/shm
-          name: dshm
       volumes:
+      - name: dshm
+        emptyDir:
+          medium: Memory
       - name: xgl-cache-vol
         emptyDir: {}
 #        persistentVolumeClaim:
@@ -67,6 +67,3 @@ spec:
         emptyDir: {}
 #        persistentVolumeClaim:
 #          claimName: xgl-root-vol
-      - name: dshm
-        emptyDir:
-          medium: Memory