├── Dockerfile ├── LICENSE ├── README.md ├── entrypoint.sh └── scripts └── teams-wrapper /Dockerfile: -------------------------------------------------------------------------------- 1 | # References: 2 | # https://gist.github.com/demaniak/c56531c8d673a6f58ee54b5621796548 3 | # https://github.com/mdouchement/docker-zoom-us 4 | # https://hub.docker.com/r/solarce/zoom-us 5 | # https://github.com/sameersbn/docker-skype 6 | FROM debian:buster 7 | MAINTAINER olberger 8 | 9 | ENV DEBIAN_FRONTEND noninteractive 10 | 11 | # Refresh package lists 12 | RUN apt-get update 13 | RUN apt-get -qy dist-upgrade 14 | 15 | # Dependencies for the client .deb 16 | 17 | RUN apt-get install -qy curl sudo pulseaudio apt-utils apt-transport-https \ 18 | libatk-bridge2.0-0 libcups2 libgtk-3-0 libnspr4 libnss3 libxss1 gpg libsecret-1-0 19 | 20 | # libasound2 libcairo2 libcups2 libgdk-pixbuf2.0-0 \ 21 | # libpango-1.0-0 libpangocairo-1.0-0 \ 22 | # libx11-xcb1 libxcomposite1 libxcomposite1 \ 23 | # libxkbfile1 24 | # desktop-file-utils lib32z1 \ 25 | # libx11-6 libegl1-mesa libxcb-shm0 \ 26 | # libglib2.0-0 libgl1-mesa-glx libxrender1 libxcomposite1 libxslt1.1 \ 27 | # libgstreamer1.0-0 libgstreamer-plugins-base1.0-0 libxi6 libsm6 \ 28 | # libfontconfig1 libpulse0 libsqlite3-0 \ 29 | # libxcb-shape0 libxcb-xfixes0 libxcb-randr0 libxcb-image0 \ 30 | # libxcb-keysyms1 libxcb-xtest0 ibus ibus-gtk \ 31 | # libnss3 libxss1 xcompmgr 32 | 33 | ARG TEAMS_URL="https://go.microsoft.com/fwlink/p/?LinkID=2112886&clcid=0x40c&culture=fr-fr&country=FR" 34 | 35 | # Grab the client .deb 36 | # Install the client .deb 37 | # Cleanup 38 | RUN curl -sSL $TEAMS_URL -o /tmp/teams.deb 39 | RUN dpkg -i /tmp/teams.deb 40 | RUN apt-get -f install 41 | 42 | COPY scripts/ /var/cache/teams/ 43 | COPY entrypoint.sh /sbin/entrypoint.sh 44 | RUN chmod 755 /sbin/entrypoint.sh 45 | 46 | ENTRYPOINT ["/sbin/entrypoint.sh"] 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 mdouchement 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This project is fully inspired of Marc Douchement's [docker-zoom-us](https://github.com/mdouchement/docker-zoom-us), which in turn was inspired by [sameersbn](https://github.com/sameersbn) [Skype](https://github.com/sameersbn/docker-skype)'s containerization. 2 | 3 | # olberger/docker-teams-linux 4 | 5 | # Introduction 6 | 7 | `Dockerfile` to create a [Docker](https://www.docker.com/) container image with [Teams](https://www.microsoft.com/en-us/microsoft-365/microsoft-teams/download-app) for Linux with support for audio/video calls. 8 | 9 | The image uses [X11](http://www.x.org) and [Pulseaudio](http://www.freedesktop.org/wiki/Software/PulseAudio/) unix domain sockets on the host to enable audio/video support in Teams. These components are available out of the box on pretty much any modern linux distribution. 10 | 11 | ## Contributing 12 | 13 | If you find this image useful here's how you can help: 14 | 15 | - Send a pull request with your awesome features and bug fixes 16 | - Help users resolve their [issues](https://github.com/olberger/docker-teams-linux/issues?q=is%3Aopen+is%3Aissue). 17 | 18 | # Getting started 19 | 20 | ## Installation 21 | 22 | Automated builds of the image are available on [Dockerhub](https://hub.docker.com/r/olberger/docker-teams-linux) and is the recommended method of installation. 23 | 24 | ```bash 25 | docker pull olberger/docker-teams-linux:latest 26 | ``` 27 | 28 | Alternatively you can build the image yourself. 29 | 30 | ```bash 31 | docker build -t olberger/docker-teams-linux github.com/olberger/docker-teams-linux 32 | ``` 33 | 34 | With the image locally available, install the wrapper scripts by running the following as root: 35 | 36 | ```bash 37 | docker run -it --rm \ 38 | --volume /usr/local/bin:/target \ 39 | olberger/docker-teams-linux:latest install 40 | ``` 41 | 42 | This will install a wrapper script to launch `teams`. 43 | 44 | ## Starting Teams 45 | 46 | Launch the teams-wrapper script to enter a shell inside the Docker container 47 | 48 | ```bash 49 | teams-wrapper bash 50 | ``` 51 | 52 | Then the prompt should be displayed like: 53 | ``` 54 | Adding user `teams' to group `sudo' ... 55 | Adding user teams to group sudo 56 | Done. 57 | bash 58 | teams@0b2fefbf45d2:~$ 59 | ``` 60 | 61 | then type `teams`. 62 | 63 | 64 | > **Note** 65 | > 66 | > If Teams is installed on the the host then the host binary is launched instead of starting a Docker container. To force the launch of Teams in a container use the `teams-wrapper` script. For example, `teams-wrapper teams` will launch Teams inside a Docker container regardless of whether it is installed on the host or not. 67 | 68 | 69 | ## How it works 70 | 71 | The wrapper scripts volume mount the X11 and pulseaudio sockets in the launcher container. The X11 socket allows for the user interface display on the host, while the pulseaudio socket allows for the audio output to be rendered on the host. 72 | 73 | When the image is launched the following directories are mounted as volumes 74 | 75 | - `${HOME}/.config/teams` 76 | - `${HOME}/.config/Microsoft` 77 | 78 | 79 | 80 | 81 | This makes sure that your profile details are stored on the host and files received via Teams are available on your host in the appropriate download directory. 82 | 83 | **Don't want to expose host's folders to Teams?** 84 | 85 | Add `TEAMS_HOME` environment variable to namespace all Teams folders: 86 | 87 | ```sh 88 | export TEAMS_HOME=${HOME}/teams 89 | ``` 90 | 91 | 92 | # Maintenance 93 | 94 | ## Upgrading 95 | 96 | To upgrade to newer releases: 97 | 98 | 1. Download the updated Docker image: 99 | 100 | ```bash 101 | docker pull olberger/docker-teams-linux:latest 102 | ``` 103 | 104 | 2. Run `install` to make sure the host scripts are updated. 105 | 106 | ```bash 107 | docker run -it --rm \ 108 | --volume /usr/local/bin:/target \ 109 | olberger/docker-teams-linux:latest install 110 | ``` 111 | 112 | ## Uninstallation 113 | 114 | ```bash 115 | docker run -it --rm \ 116 | --volume /usr/local/bin:/target \ 117 | olberger/docker-teams-linux:latest uninstall 118 | ``` 119 | 120 | ## Updating the image rebuild locally 121 | 122 | This should ensure to download again the client (and update any other 123 | bits in the image 124 | ```bash 125 | docker build --no-cache -t olberger/docker-teams-linux github.com/olberger/docker-teams-linux 126 | ``` 127 | 128 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | #set -x 5 | 6 | USER_UID=${USER_UID:-1000} 7 | USER_GID=${USER_GID:-1000} 8 | 9 | TEAMS_USER=teams 10 | 11 | install_teams() { 12 | echo "Installing teams-wrapper..." 13 | install -m 0755 /var/cache/teams/teams-wrapper /target/ 14 | echo "Installing teams..." 15 | ln -sf teams-wrapper /target/teams 16 | } 17 | 18 | uninstall_teams() { 19 | echo "Uninstalling teams-wrapper..." 20 | rm -rf /target/teams-wrapper 21 | echo "Uninstalling teams..." 22 | rm -rf /target/teams 23 | } 24 | 25 | create_user() { 26 | # create group with USER_GID 27 | if ! getent group ${TEAMS_USER} >/dev/null; then 28 | groupadd -f -g ${USER_GID} ${TEAMS_USER} >/dev/null 2>&1 29 | fi 30 | 31 | # create user with USER_UID 32 | if ! getent passwd ${TEAMS_USER} >/dev/null; then 33 | adduser --disabled-login --uid ${USER_UID} --gid ${USER_GID} \ 34 | --gecos 'Teams' ${TEAMS_USER} >/dev/null 2>&1 35 | fi 36 | chown ${TEAMS_USER}:${TEAMS_USER} -R /home/${TEAMS_USER} 37 | adduser ${TEAMS_USER} sudo 38 | } 39 | 40 | grant_access_to_video_devices() { 41 | for device in /dev/video* 42 | do 43 | if [[ -c $device ]]; then 44 | VIDEO_GID=$(stat -c %g $device) 45 | VIDEO_GROUP=$(stat -c %G $device) 46 | if [[ ${VIDEO_GROUP} == "UNKNOWN" ]]; then 47 | VIDEO_GROUP=teamsvideo 48 | groupadd -g ${VIDEO_GID} ${VIDEO_GROUP} 49 | fi 50 | usermod -a -G ${VIDEO_GROUP} ${TEAMS_USER} 51 | break 52 | fi 53 | done 54 | } 55 | 56 | launch_bash() { 57 | cd /home/${TEAMS_USER} 58 | # exec sudo -HEu ${TEAMS_USER} PULSE_SERVER=/run/pulse/native QT_GRAPHICSSYSTEM="native" xcompmgr -c -l0 -t0 -r0 -o.00 & 59 | # exec sudo -HEu ${TEAMS_USER} PULSE_SERVER=/run/pulse/native QT_GRAPHICSSYSTEM="native" $@ 60 | exec sudo -HEu ${TEAMS_USER} PULSE_SERVER=/run/pulse/native QT_GRAPHICSSYSTEM="native" /bin/bash 61 | } 62 | 63 | case "$1" in 64 | install) 65 | install_teams 66 | ;; 67 | uninstall) 68 | uninstall_teams 69 | ;; 70 | bash) 71 | create_user 72 | grant_access_to_video_devices 73 | echo "$1" 74 | launch_bash $@ 75 | ;; 76 | *) 77 | exec $@ 78 | ;; 79 | esac 80 | -------------------------------------------------------------------------------- /scripts/teams-wrapper: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #set -x 4 | 5 | PATH=/usr/sbin:/usr/bin:/sbin:/bin 6 | TEAMS_USER=teams 7 | 8 | # do we need to use sudo to start docker containers? 9 | ( id -Gn | grep -q docker ) || SUDO=sudo 10 | 11 | USER_UID=$(id -u) 12 | USER_GID=$(id -g) 13 | 14 | XSOCK=/tmp/.X11-unix 15 | XAUTH=/tmp/.docker.xauth 16 | 17 | DOWNLOAD_DIR=$(xdg-user-dir DOWNLOAD) 18 | if [ -z "${DOWNLOAD_DIR}" ]; then 19 | DOWNLOAD_DIR="${HOME}/Downloads" 20 | fi; 21 | DOCUMENTS_DIR=$(xdg-user-dir DOCUMENTS) 22 | if [ -z "${DOCUMENTS_DIR}" ]; then 23 | DOCUMENTS_DIR="${HOME}/Documents" 24 | fi; 25 | 26 | list_commands() { 27 | echo "" 28 | echo "Launch teams using:" 29 | echo " teams OR " 30 | echo " teams-wrapper bash" 31 | echo "" 32 | exit 1 33 | } 34 | 35 | cleanup_stopped_teams_instances(){ 36 | echo "Cleaning up stopped teams instances..." 37 | for c in $(${SUDO} docker ps -a -q) 38 | do 39 | image="$(${SUDO} docker inspect -f {{.Config.Image}} ${c})" 40 | if [ "${image}" == "olberger/docker-teams-linux:latest" ]; then 41 | running=$(${SUDO} docker inspect -f {{.State.Running}} ${c}) 42 | if [ "${running}" != "true" ]; then 43 | ${SUDO} docker rm "${c}" >/dev/null 44 | fi 45 | fi 46 | done 47 | } 48 | 49 | prepare_docker_env_parameters() { 50 | ENV_VARS+=" --env=USER_UID=${USER_UID}" 51 | ENV_VARS+=" --env=USER_GID=${USER_GID}" 52 | ENV_VARS+=" --env=DISPLAY=unix$DISPLAY" 53 | ENV_VARS+=" --env=XAUTHORITY=${XAUTH}" 54 | ENV_VARS+=" --env=TZ=$(date +%Z)" 55 | } 56 | 57 | prepare_docker_volume_parameters() { 58 | touch ${XAUTH} 59 | xauth nlist :0 | sed -e 's/^..../ffff/' | xauth -f ${XAUTH} nmerge - 60 | 61 | if [[ -z "${TEAMS_HOME}" ]]; then 62 | TEAMS_HOME=${HOME} # Default directory 63 | else 64 | DOWNLOAD_DIR=${DOWNLOAD_DIR/$HOME/$TEAMS_HOME} 65 | DOCUMENTS_DIR=${DOCUMENTS_DIR/$HOME/$TEAMS_HOME} 66 | mkdir -p {$DOWNLOAD_DIR,$DOCUMENTS_DIR} 67 | 68 | # mkdir -p ${TEAMS_HOME}/{.config,.cache} 69 | mkdir -p ${TEAMS_HOME}/.config 70 | fi 71 | 72 | echo "Using TEAMS_HOME: ${TEAMS_HOME}" 73 | 74 | # touch ${TEAMS_HOME}/.config/zoomus.conf # create if not exists 75 | 76 | # VOLUMES+=" --volume=${TEAMS_HOME}/.config/zoomus.conf:/home/${TEAMS_USER}/.config/zoomus.conf" 77 | VOLUMES+=" --volume=${TEAMS_HOME}/.config/teams:/home/${TEAMS_USER}/.config/teams" 78 | VOLUMES+=" --volume=${TEAMS_HOME}/.config/Microsoft:/home/${TEAMS_USER}/.config/Microsoft" 79 | # VOLUMES+=" --volume=${TEAMS_HOME}/.cache/zoom:/home/${TEAMS_USER}/.cache/zoom" 80 | # VOLUMES+=" --volume=${TEAMS_HOME}/.zoom:/home/${TEAMS_USER}/.zoom" 81 | # VOLUMES+=" --volume=${DOWNLOAD_DIR}:/home/${TEAMS_USER}/Downloads" 82 | # VOLUMES+=" --volume=${DOCUMENTS_DIR}:/home/${TEAMS_USER}/Documents" 83 | VOLUMES+=" --volume=${XSOCK}:${XSOCK}" 84 | VOLUMES+=" --volume=${XAUTH}:${XAUTH}" 85 | VOLUMES+=" --volume=/run/user/${USER_UID}/pulse:/run/pulse" 86 | } 87 | 88 | prepare_docker_device_parameters() { 89 | # enumerate video devices for webcam support 90 | VIDEO_DEVICES= 91 | for device in /dev/video* 92 | do 93 | if [ -c $device ]; then 94 | VIDEO_DEVICES="${VIDEO_DEVICES} --device $device:$device" 95 | fi 96 | done 97 | } 98 | 99 | prog=$(basename $0) 100 | exec=$(which $prog) 101 | 102 | if [[ ${prog} == "teams-wrapper" ]]; then 103 | case ${1} in 104 | # teams) 105 | # prog=${1} 106 | # shift 107 | # ;; 108 | bash) 109 | prog=${1} 110 | shift 111 | ;; 112 | *|help) 113 | list_commands 114 | exit 1 115 | ;; 116 | esac 117 | elif [[ -n ${exec} ]]; then 118 | # launch host binary if it exists 119 | exec ${exec} $@ 120 | fi 121 | 122 | cleanup_stopped_teams_instances 123 | prepare_docker_env_parameters 124 | prepare_docker_volume_parameters 125 | prepare_docker_device_parameters 126 | 127 | echo "Starting ${prog}..." 128 | #${SUDO} docker run -d \ 129 | ${SUDO} docker run -it \ 130 | ${ENV_VARS} \ 131 | ${VIDEO_DEVICES} \ 132 | --device /dev/dri \ 133 | ${VOLUMES} \ 134 | ${TEAMS_EXTRA_DOCKER_ARGUMENTS} \ 135 | --name teams \ 136 | olberger/docker-teams-linux:latest ${prog} $@ 137 | 138 | #>/dev/null 139 | --------------------------------------------------------------------------------