├── docker-search ├── examples ├── speedtest │ ├── launch │ └── Dockerfile ├── pandoc │ ├── launch │ └── Dockerfile ├── thunderbird │ ├── launch │ └── Dockerfile ├── firefox-esr │ ├── launch │ └── Dockerfile └── git │ ├── Dockerfile │ └── launch ├── docker ├── docker-machine ├── docker-build ├── docker.build.me ├── docker-compose ├── docker.x11 ├── docker-umount ├── docker-run ├── docker.ssh.pipe.cmd ├── docker.ssh.cmd ├── make_dockerfile ├── apt-docker ├── remove_docker_remote.sh ├── LICENSE ├── docker-mount ├── docker.config ├── install_docker_remote.sh └── README.md /docker-search: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker search --no-trunc "$@" 3 | -------------------------------------------------------------------------------- /examples/speedtest/launch: -------------------------------------------------------------------------------- 1 | docker run --rm itmaze/speedtest:latest "$@" 2 | -------------------------------------------------------------------------------- /examples/pandoc/launch: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | docker.x11 itmaze/pandoc:latest "$@" 4 | -------------------------------------------------------------------------------- /examples/thunderbird/launch: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | docker.x11 itmaze/thunderbird:latest "$@" 4 | -------------------------------------------------------------------------------- /examples/firefox-esr/launch: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd ~/Downloads 4 | 5 | docker.x11 --ipc=host --shm-size=2g itmaze/firefox-esr:latest --no-remote --sync "$@" 6 | -------------------------------------------------------------------------------- /docker: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | local_config_dir="$(dirname "$(readlink -f "$0")")" 3 | source "${local_config_dir}/docker.config" 4 | 5 | docker.ssh.cmd -tt docker "$@" 6 | -------------------------------------------------------------------------------- /docker-machine: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | local_config_dir="$(dirname "$(readlink -f "$0")")" 3 | source "${local_config_dir}/docker.config" 4 | 5 | docker.ssh.cmd -t "$@" 6 | 7 | -------------------------------------------------------------------------------- /docker-build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | local_config_dir="$(dirname "$(readlink -f "$0")")" 3 | source "${local_config_dir}/docker.config" 4 | 5 | tar -hzcf - . | docker.ssh.pipe.cmd docker build - "$@" 6 | -------------------------------------------------------------------------------- /docker.build.me: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | local_config_dir="$(dirname "$(readlink -f "$0")")" 3 | source "${local_config_dir}/docker.config" 4 | 5 | name=$(basename "$(pwd)") 6 | docker-build -t "${local_docker_repo}/${name}" "$@" 7 | -------------------------------------------------------------------------------- /docker-compose: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | local_config_dir="$(dirname "$(readlink -f "$0")")" 3 | source "${local_config_dir}/docker.config" 4 | 5 | docker-run -v "${remote_docker_socket}":/var/run/docker.sock -it "${remote_docker_container}" compose "$@" 6 | -------------------------------------------------------------------------------- /docker.x11: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | local_config_dir="$(dirname "$(readlink -f "$0")")" 3 | source "${local_config_dir}/docker.config" 4 | 5 | export script_origin=$(ps -o comm= $PPID) 6 | 7 | docker-run -e DISPLAY -e XAUTHORITY="/home/docker/.Xauthority" -e TZ="${remote_docker_timezone}" --net=host --volume="/home/docker/.Xauthority:/home/docker/.Xauthority:rw" "$@" 8 | -------------------------------------------------------------------------------- /examples/git/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:stable-slim 2 | LABEL maintainer="onno@itmaze.com.au" 3 | 4 | ARG DEBIAN_FRONTEND=noninteractive 5 | 6 | RUN apt-get update 7 | RUN apt-get -y upgrade 8 | RUN apt-get -y install git 9 | 10 | RUN ln -s $(which git) /usr/local/bin/git 11 | 12 | RUN useradd -ms /bin/bash docker 13 | USER docker 14 | 15 | ENTRYPOINT ["/usr/local/bin/git"] 16 | CMD ["--help"] 17 | -------------------------------------------------------------------------------- /docker-umount: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | local_config_dir="$(dirname "$(readlink -f "$0")")" 3 | source "${local_config_dir}/docker.config" 4 | 5 | if [ $# -ne 1 ] 6 | then 7 | echo "Usage: '$(basename "$0") volume'" 8 | exit 1 9 | fi 10 | 11 | mountVolume=$1 12 | 13 | dummy=$(docker volume rm "${mountVolume}") 14 | 15 | docker.ssh.cmd fusermount -zu "/home/docker/${mountVolume}" 16 | docker.ssh.cmd rmdir "${mountVolume}" 17 | 18 | -------------------------------------------------------------------------------- /examples/git/launch: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function remove_volume() { 4 | volumeName=$1 5 | docker-umount ${volumeName} >> /dev/stderr 6 | } 7 | 8 | if type docker-mount &> /dev/null 9 | then 10 | volumeName=$(uuidgen) 11 | trap "remove_volume ${volumeName}" EXIT 12 | docker-mount "${volumeName}" "/home/onno/.ssh" >> /dev/stderr 13 | fi 14 | 15 | docker-run --rm -v${volumeName}:"/home/docker/.ssh" itmaze/git:latest "$@" 16 | -------------------------------------------------------------------------------- /examples/speedtest/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:stable-slim 2 | 3 | ARG DEBIAN_FRONTEND=noninteractive 4 | ARG server=31363 5 | ENV env_var_name=$server 6 | 7 | RUN apt-get update 8 | RUN apt-get -y upgrade 9 | ADD https://install.speedtest.net/app/cli/install.deb.sh install.deb.sh 10 | RUN bash ./install.deb.sh 11 | RUN apt-get -y install speedtest 12 | RUN /usr/bin/speedtest --accept-license -s $env_var_name 13 | 14 | ENTRYPOINT ["/usr/bin/speedtest"] 15 | CMD ["--help"] 16 | -------------------------------------------------------------------------------- /examples/thunderbird/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bullseye-slim 2 | 3 | LABEL maintainer="onno@itmaze.com.au" 4 | 5 | ARG DEBIAN_FRONTEND=noninteractive 6 | 7 | RUN apt-get update 8 | RUN apt-get -y upgrade 9 | RUN apt-get -y install thunderbird 10 | RUN apt-get -y install libcanberra-gtk-module 11 | 12 | RUN ln -s $(which thunderbird) /usr/local/bin/thunderbird 13 | 14 | RUN useradd -ms /bin/bash docker 15 | USER docker 16 | 17 | ENTRYPOINT ["/usr/local/bin/thunderbird"] 18 | -------------------------------------------------------------------------------- /docker-run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | local_config_dir="$(dirname "$(readlink -f "$0")")" 3 | source "${local_config_dir}/docker.config" 4 | 5 | volumeName="$(uuidgen)" 6 | 7 | function remove_volume() { 8 | docker-umount "${volumeName}" 9 | } 10 | 11 | if type docker-mount &> /dev/null 12 | then 13 | trap "remove_volume" EXIT 14 | docker-mount "${volumeName}" 15 | docker run --rm -v"${volumeName}":"$(pwd)" -w"$(pwd)" "$@" 16 | else 17 | docker run --rm -v"$(pwd)":"$(pwd)" -w"$(pwd)" "$@" 18 | fi 19 | -------------------------------------------------------------------------------- /docker.ssh.pipe.cmd: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | local_config_dir="$(dirname "$(readlink -f "$0")")" 3 | source "${local_config_dir}/docker.config" 4 | 5 | declare -a parameters 6 | 7 | while [ "$#" -gt 0 ] 8 | do 9 | if [ "${1:0:1}" == '-' ] 10 | then 11 | parameters+=("$1") 12 | shift 13 | else 14 | break 15 | fi 16 | done 17 | 18 | printf -v remote_command '%q ' "$@" 19 | 20 | /usr/bin/ssh -C -e none -Y -o LogLevel=QUIET -l "${remote_docker_user}" "${parameters[@]}" "${remote_docker_host}" "${remote_command}" 21 | -------------------------------------------------------------------------------- /examples/pandoc/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bullseye-slim 2 | 3 | LABEL maintainer="onno@itmaze.com.au" 4 | 5 | ARG DEBIAN_FRONTEND=noninteractive 6 | 7 | RUN apt-get update 8 | RUN apt-get -y upgrade 9 | RUN apt-get -y install pandoc 10 | RUN apt-get -y install texlive-latex-base 11 | RUN apt-get -y install texlive-latex-recommended 12 | 13 | ADD https://github.com/jgm/pandoc/releases/download/3.1.3/pandoc-3.1.3-1-amd64.deb /tmp/pandoc.deb 14 | RUN apt-get -y install /tmp/pandoc.deb 15 | 16 | RUN ln -s $(which pandoc) /usr/local/bin/pandoc 17 | 18 | RUN useradd -ms /bin/bash docker 19 | USER docker 20 | 21 | ENTRYPOINT ["/usr/local/bin/pandoc"] 22 | CMD ["--help"] 23 | -------------------------------------------------------------------------------- /docker.ssh.cmd: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | local_config_dir="$(dirname "$(readlink -f "$0")")" 3 | source "${local_config_dir}/docker.config" 4 | 5 | declare -a parameters 6 | 7 | while [ "$#" -gt 0 ] 8 | do 9 | if [ "${1:0:1}" == '-' ] 10 | then 11 | parameters+=("$1") 12 | shift 13 | else 14 | break 15 | fi 16 | done 17 | 18 | printf -v remote_command '%q ' "$@" 19 | 20 | # Source: https://scripter.co/nim-check-if-stdin-stdout-are-associated-with-terminal-or-pipe/ 21 | if [[ -t 0 ]] 22 | then 23 | # terminal 24 | interactive_tty="" 25 | else 26 | # pipe 27 | interactive_tty="-n" 28 | fi 29 | 30 | if [[ -v DEBUG ]] 31 | then 32 | logging=("-v") 33 | else 34 | logging=("-o" "LogLevel=QUIET") 35 | fi 36 | 37 | /usr/bin/ssh ${interactive_tty} -C -e none -Y "${logging[@]}" -l "${remote_docker_user}" "${parameters[@]}" "${remote_docker_host}" "${remote_command}" 38 | -------------------------------------------------------------------------------- /make_dockerfile: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | local_config_dir="$(dirname "$(readlink -f "$0")")" 3 | source "${local_config_dir}/docker.config" 4 | 5 | container=$(basename "$(pwd)") 6 | 7 | if [ $# -eq 1 ] 8 | then 9 | executable="$1" 10 | else 11 | executable="${container}" 12 | fi 13 | 14 | cat <<-EOF > Dockerfile 15 | FROM debian:stable-slim 16 | 17 | LABEL maintainer="${local_docker_maintainer}" 18 | 19 | ARG DEBIAN_FRONTEND=noninteractive 20 | 21 | RUN apt-get update 22 | RUN apt-get -y upgrade 23 | RUN apt-get -y install ${container} 24 | 25 | RUN ln -s \$(which ${executable}) /usr/local/bin/${executable} 26 | 27 | RUN useradd -ms /bin/bash docker 28 | USER docker 29 | 30 | ENTRYPOINT ["/usr/local/bin/${executable}"] 31 | CMD ["--help"] 32 | EOF 33 | 34 | cat <<-EOF > launch 35 | #!/bin/bash 36 | 37 | docker.x11 "${local_docker_repo}/${container}:latest" "\$@" 38 | EOF 39 | chmod +x launch 40 | -------------------------------------------------------------------------------- /apt-docker: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | local_config_dir="$(dirname "$(readlink -f "$0")")" 3 | source "${local_config_dir}/docker.config" 4 | 5 | if [ $# -eq 2 ] 6 | then 7 | container="$1" 8 | executable="$2" 9 | else 10 | container="$1" 11 | executable="${container}" 12 | fi 13 | 14 | if [ -d "${local_docker_home}/${local_docker_repo}/${container}" ] 15 | then 16 | echo "Error: '${local_docker_home}/${local_docker_repo}/${container}' already exists, aborting." 17 | exit 1 18 | fi 19 | 20 | if [ -e "${local_bin_dir}/${executable}" ] 21 | then 22 | echo "Error: '${local_bin_dir}/${executable}' already exists, aborting." 23 | exit 1 24 | fi 25 | 26 | mkdir -p "${local_docker_home}/${local_docker_repo}/${container}" 27 | ( 28 | cd "${local_docker_home}/${local_docker_repo}/${container}" || exit 29 | make_dockerfile "${executable}" 30 | docker-build -t "${local_docker_repo}/${container}" 31 | ln -s "${local_docker_home}/${local_docker_repo}/${container}/launch" "${local_bin_dir}/${executable}" 32 | ) 33 | 34 | -------------------------------------------------------------------------------- /remove_docker_remote.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | local_config_dir="$(dirname "$(readlink -f "$0")")" 3 | source "${local_config_dir}/docker.config" 4 | 5 | # This will uninstall this project from the user default bin directory. 6 | 7 | function remove_link () { 8 | # Remove a symlink (or file if it's the same as the source) 9 | 10 | sourceFile="$(readlink -f "$1")" 11 | targetFile="${local_bin_dir}/$(basename "$1")" 12 | 13 | if [ "${targetFile}" == "${sourceFile}" ] 14 | then 15 | note "Warning: '${targetFile}' and '${sourceFile}' are the same file, '${targetFile}' was not removed." 16 | return 1 17 | fi 18 | 19 | if diff -q "${sourceFile}" "${targetFile}" 20 | then 21 | rm "${targetFile}" 22 | return 0 23 | fi 24 | note "Warning: '${targetFile}' and '${sourceFile}' differ, '${targetFile}' was not removed." 25 | } 26 | 27 | while read -r sourceFile <&3 28 | do 29 | remove_link "${sourceFile}" 30 | done 3< <( 31 | find "${local_config_dir}" \ 32 | -maxdepth 1 \ 33 | -type f \ 34 | -executable \ 35 | ! -name '*.sh' 36 | ) 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Onno Benschop, ITmaze 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 | 23 | -------------------------------------------------------------------------------- /docker-mount: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | local_config_dir="$(dirname "$(readlink -f "$0")")" 3 | source "${local_config_dir}/docker.config" 4 | 5 | if [ $# -eq 1 ] 6 | then 7 | mountVolume=$1 8 | mountPath=$(pwd) 9 | elif [ $# -ne 2 ] 10 | then 11 | echo "Usage: '$(basename "$0") volume [path]'" 12 | exit 1 13 | else 14 | mountVolume=$1 15 | mountPath=$2 16 | fi 17 | 18 | if docker volume list -q | fromdos | grep -q ^"${mountVolume}"$ 19 | then 20 | echo "Warning: Volume exists: ${mountVolume}, skipped." 21 | exit 1 22 | fi 23 | 24 | me=$(whoami) 25 | myIP=$(hostname -I | cut -d ' ' -f1) 26 | 27 | docker.ssh.cmd mkdir -p "${mountVolume}" 28 | 29 | docker.ssh.cmd /usr/bin/sshfs \ 30 | -o reconnect \ 31 | -o ServerAliveInterval=15 \ 32 | -o ServerAliveCountMax=3 \ 33 | -o UserKnownHostsFile=/dev/null \ 34 | -o allow_other \ 35 | -o StrictHostKeyChecking=no \ 36 | -o auto_unmount \ 37 | -o uid=0 \ 38 | -o gid=0 \ 39 | -o idmap=user \ 40 | "${me}@${myIP}":"${mountPath}" "${mountVolume}" 41 | 42 | dummy=$(docker volume create --name "${mountVolume}" -o type=none -o device="/home/docker/${mountVolume}" -o o=bind --label sshfs=yes --label host="${me}@${myIP}" --label path="${mountPath}" --label script_origin="${script_origin}") 43 | -------------------------------------------------------------------------------- /docker.config: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [[ -v DEBUG ]] 3 | then 4 | set -x 5 | set -o xtrace 6 | set -v 7 | fi 8 | 9 | # Update these variables to suit your set-up 10 | 11 | # Used to store symbolic links to containers built with apt-docker. 12 | local_bin_dir=~/bin 13 | 14 | # Used to store the repository directory 15 | local_docker_home=~/docker 16 | 17 | # Used to store the local repository of conainters 18 | local_docker_repo="$(hostname)" 19 | 20 | # Used in a Dockerfile generated by apt-docker 21 | local_docker_maintainer="$(whoami)@$(hostname -A)" 22 | 23 | # Used to run actual docker commands over ssh 24 | remote_docker_host="docker.local" 25 | remote_docker_user="docker" 26 | remote_docker_timezone="${TZ:Etc/UTC}" 27 | 28 | # Docker socket 29 | remote_docker_container=docker.io/library/docker:latest 30 | remote_docker_socket=/var/run/docker.sock 31 | 32 | function note () { 33 | echo "$@" | fold -s -w $(tput cols) 34 | } 35 | 36 | function stop () { 37 | note "$@" 38 | exit 1 39 | } 40 | 41 | function checkDir () { 42 | if [ ! -d "$1" ] 43 | then 44 | stop "The directory '$1' does not exist, check your remote-docker configuration at '${BASH_SOURCE[0]}', aborting." 45 | fi 46 | } 47 | 48 | checkDir "${local_bin_dir}" 49 | checkDir "${local_docker_home}/${local_docker_repo}" 50 | 51 | -------------------------------------------------------------------------------- /install_docker_remote.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | local_config_dir="$(dirname "$(readlink -f "$0")")" 3 | source "${local_config_dir}/docker.config" 4 | 5 | # This will prompt the user to install symbolic links pointing at this project 6 | # in their default bin directory (~/bin) 7 | 8 | response='No' 9 | 10 | function default_prompt_string () { 11 | # Based on previous user response, show that as the default in square brackets. 12 | 13 | previous_response="${1^^}" 14 | 15 | for word in 'Yes' 'No' 'All' 16 | do 17 | if [[ "${previous_response:0:1}" == "${word:0:1}" ]] 18 | then 19 | echo -n "[${word}]" 20 | else 21 | echo -n "${word}" 22 | fi 23 | echo -n '/' 24 | done 25 | echo -n 'Cancel' 26 | } 27 | 28 | function ask_to_make_symlink () { 29 | # Ask the user if they want to install a symlink 30 | 31 | default_response="${response}" 32 | 33 | while true 34 | do 35 | read -rp "Install link ($(default_prompt_string "${response}")):" response 36 | response="${response:-$default_response}" 37 | 38 | case "${response:0:1}" in 39 | y|Y ) 40 | response='Yes' 41 | return 0 42 | ;; 43 | a|A ) 44 | response='All' 45 | return 0 46 | ;; 47 | n|N ) 48 | response='No' 49 | return 1 50 | ;; 51 | c|C ) 52 | exit 1 53 | ;; 54 | * ) 55 | response="${default_response}" 56 | ;; 57 | esac 58 | done 59 | } 60 | 61 | function install_link () { 62 | # Install a symlink in the user's configured bin directory 63 | 64 | sourceFile="$(readlink -f "$1")" 65 | targetFile="${local_bin_dir}/$(basename "$1")" 66 | 67 | if [[ "$(readlink -f "${sourceFile}")" == "$(readlink -f "${targetFile}")" ]] 68 | then 69 | # Nothing to do 70 | return 0 71 | fi 72 | 73 | if [[ -L "${targetFile}" && -e "${targetFile}" ]] 74 | then 75 | alert="Warning: symbolic link '${targetFile}' exists and is pointing to a file." 76 | elif [[ -L "${targetFile}" && ! -e "${targetFile}" ]] 77 | then 78 | alert="Warning: broken symbolic link '${targetFile}' exists." 79 | elif [[ -f "${targetFile}" ]] 80 | then 81 | alert="Warning: file '${targetFile}' exists." 82 | else 83 | alert="" 84 | fi 85 | 86 | if [ "${response}" != 'All' ] && [ -n "${alert}" ] 87 | then 88 | note "${alert}" 89 | note "This will replace '${targetFile}' with a symbolic link to '${sourceFile}'?" 90 | if ! ask_to_make_symlink 91 | then 92 | return 99 93 | fi 94 | fi 95 | 96 | ln -sf "${sourceFile}" "${targetFile}" 97 | } 98 | 99 | while read -r sourceFile <&3 100 | do 101 | install_link "${sourceFile}" 102 | done 3< <( 103 | find "${local_config_dir}" -maxdepth 1 \ 104 | -type f \ 105 | -executable \ 106 | ! -name '*.sh' 107 | ) 108 | -------------------------------------------------------------------------------- /examples/firefox-esr/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:stable-slim 2 | 3 | ARG DEBIAN_FRONTEND=noninteractive 4 | 5 | RUN apt-get update 6 | RUN apt-get -y upgrade 7 | RUN apt-get -y install \ 8 | firefox-esr \ 9 | firefox-esr-l10n-en-gb \ 10 | fonts-wqy-microhei \ 11 | hunspell-en-au \ 12 | hunspell-en-gb \ 13 | hyphen-en-gb \ 14 | libcanberra-gtk3-module \ 15 | libcanberra-gtk-module \ 16 | libegl1 \ 17 | libpci3 \ 18 | webext-ublock-origin \ 19 | xterm 20 | 21 | RUN echo >> /etc/firefox-esr/firefox-esr.js 22 | RUN echo '// Set local preferences from Dockerfile' >> /etc/firefox-esr/firefox-esr.js 23 | RUN echo 'pref("app.normandy.first_run", false);' >> /etc/firefox-esr/firefox-esr.js 24 | RUN echo 'pref("browser.warnOnQuit", false);' >> /etc/firefox-esr/firefox-esr.js 25 | RUN echo 'pref("browser.startup.homepage", "about:blank");' >> /etc/firefox-esr/firefox-esr.js 26 | RUN echo 'pref("datareporting.policy.firstRunURL", "");' >> /etc/firefox-esr/firefox-esr.js 27 | RUN echo 'pref("app.update.enabled", false);' >> /etc/firefox-esr/firefox-esr.js 28 | RUN echo 'pref("app.update.auto", false);' >> /etc/firefox-esr/firefox-esr.js 29 | RUN echo 'pref("toolkit.cosmeticAnimations.enabled", false);' >> /etc/firefox-esr/firefox-esr.js 30 | RUN echo 'pref("toolkit.scrollbox.smoothScroll", false);' >> /etc/firefox-esr/firefox-esr.js 31 | RUN echo 'pref("image.animation_mode", "none");' >> /etc/firefox-esr/firefox-esr.js 32 | RUN echo 'pref("browser.startup.homepage_override.mstone", "ignore");' >> /etc/firefox-esr/firefox-esr.js 33 | RUN echo 'pref("intl.accept_languages","en-GB");' >> /etc/firefox-esr/firefox-esr.js 34 | RUN echo 'pref("intl.locale.requested","en-GB");' >> /etc/firefox-esr/firefox-esr.js 35 | RUN echo 'pref("ui.prefersReducedMotion", 1);' >> /etc/firefox-esr/firefox-esr.js 36 | RUN echo 'pref("toolkit.cosmeticAnimations.enabled", false);' >> /etc/firefox-esr/firefox-esr.js 37 | RUN echo 'pref("geo.enabled", false);' >> /etc/firefox-esr/firefox-esr.js 38 | RUN echo 'pref("datareporting.policy.dataSubmissionEnabled", false);' >> /etc/firefox-esr/firefox-esr.js 39 | RUN echo 'pref("toolkit.telemetry.unified", false);' >> /etc/firefox-esr/firefox-esr.js 40 | RUN echo 'pref("toolkit.telemetry.enabled", false);' >> /etc/firefox-esr/firefox-esr.js 41 | RUN echo 'pref("toolkit.telemetry.reportingpolicy.firstRun", false);' >> /etc/firefox-esr/firefox-esr.js 42 | RUN echo 'pref("datareporting.healthreport.uploadEnabled", false);' >> /etc/firefox-esr/firefox-esr.js 43 | RUN echo 'pref("toolkit.telemetry.server", "");' >> /etc/firefox-esr/firefox-esr.js 44 | 45 | RUN echo 'LANG="en_AU.UTF-8"' > /etc/default/locale 46 | RUN echo 'LANGUAGE="en_AU:en" ' >> /etc/default/locale 47 | 48 | RUN useradd -ms /bin/bash docker 49 | 50 | RUN ln -s /home/onno/Downloads/ /home/docker/Downloads 51 | 52 | USER docker 53 | 54 | ENTRYPOINT ["/usr/bin/firefox-esr"] 55 | CMD ["https://www.ecosia.org/"] 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Remote Docker 2 | 3 | This project uses Docker to create an environment where you can run containers on a remote host, in such a way that your local working directory is visible to the container and optionally use X11 to use a GUI. 4 | 5 | This allows you to for example launch Firefox inside a Docker container, using your local ~/Downloads directory, but without access to the rest of your file-system. 6 | 7 | You can use this same system to run the latest version of git - when for example your copy of openssh is out of date and github updates the formats of keys - again, or use apt to install an application as a Docker container, or trial some new source without impacting your local environment. 8 | 9 | If you want to run a specific version of Python, you can do that without needing to install it locally. 10 | 11 | This uses fuse sshfs to reverse mount the file-system (from the *docker-machine* to your *workstation*), create a docker-volume, then mount that on the container with the working directory set to the mount and taking care of UID and GID. 12 | 13 | 14 | # Terms and Assumptions 15 | 16 | The term *workstation* refers to your "local" environment, where your files live, where you search the web and do your work. 17 | 18 | The term *docker-machine* represents a "remote" environment, accessible via ssh that has Docker installed. I use a minimal Debian install, but it could be anything accessible via `ssh`. 19 | 20 | The *docker-machine* is by default called "docker.local" and can be connected to by the local user as "docker@docker.local". Similarly, the *workstation* can be resolved by its hostname from the *docker-machine* and you can connect to your username from the *docker-machine* to the *workstation*. 21 | 22 | Authentication via ssh must be passwordless - in *both* directions, use `ssh-copy-id` to set it up. 23 | 24 | The scripts in this project are written in `bash` and are expected to remain together in a single directory, typically the directory where you have cloned this repository. The `docker.config` file is required and you should edit it before installation. 25 | 26 | 27 | # How it works 28 | 29 | The underlying logic does not depend on a local installation of Docker. It uses `ssh` to run Docker commands on the remote host. The point of this is that it could run across the Internet, not just to a VM like I'm using it today. 30 | 31 | To share files between the Docker container and the local file-system, these scripts use `docker-mount` and `docker-umount` commands. These commands mount a local directory to a remote directory so it can be used as a Docker volume inside the container. This is achieved in several steps: 32 | 33 | 1. Connect to the *docker-machine* over ssh. 34 | 2. Create a unique empty directory (using uuidgen). 35 | 3. Use sshfs from the *docker-machine* to the *workstation* to mount the local directory to the new unique remote directory. 36 | 4. Create a Docker volume of that mounted directory. 37 | 5. Start a container with that Docker volume. 38 | 39 | The `docker-umount` does the reverse, removing the volume, un-mounting the sshfs mount, removing the directory. 40 | 41 | 42 | # Usage 43 | 44 | You should be able to run the `docker` command as if Docker is installed on your local machine and have it execute remotely. The `docker.x11` command should act as-if you launched an X11 application on your local machine. The `docker-run` command will mount the current directory inside the container and set the working directory to that same path. 45 | 46 | Use this by putting all these scripts in ~/bin. On the *workstation*, it uses ~/docker/{hostname}/ to store any containers built with `apt-docker`. All images built using this are tagged by default as {hostname}/{xyz}:latest. The "default" maintainer for such images are set to {login}@{hostname}. If you do upload any images, you should probably update the email address (and the tag). These values can be updated in the `docker.config` file. 47 | 48 | You can create more than one mount and use more than one volume in the same container at the same time. This is useful if you want to run the aws-cli or git command and provide access to ~/.ssh or ~/.aws as well as the current directory. 49 | 50 | 51 | # Scripts 52 | 53 | The commands are: 54 | 55 | - `docker`, runs Docker commands across ssh on the *docker-machine*. 56 | - `docker-run`, implements the `docker run` command by connecting the current directory to a Docker volume and then adding the volume mount to the `docker run` command. Uses `docker-mount` and `docker-umount`. 57 | - `docker-mount`, creates a unique directory on the *docker-machine* to use as a mount point for sshfs. Mounts the current *workstation* directory via sshfs, and creates a Docker volume from that mount. Uses `uuidgen`. 58 | - `docker-umount`, removes the Docker volume, un-mounts sshfs, removes the directory on the *docker-machine*. 59 | - `docker.x11`, uses ssh x-forwarding to get the X11 packets between the *docker-machine* and the *workstation*. __Security Warning__, this uses `--net=host` 60 | - `apt-docker`, attempts to create a minimal container that installs a single Debian application in a debian:stable-slim container and then creates a symlink between the container and your local ~/bin directory, making it look like you just installed an application locally. This command refuses to run if the container directory or symbolic link already exists. 61 | - `make_dockerfile`, create a minimal Dockerfile and launch command, used by `apt-docker`. 62 | - `docker-build`, implements `docker build`, using a tar file of the current directory, sent over ssh to the build command running on the *docker-machine*. 63 | - `docker.build.me`, build the current directory as a container, tagged with the directory name. Uses `docker-build`. 64 | - `docker-compose`, the local directory is mounted on the *docker-machine* and the docker-compose command is run inside that directory. Please read the docker-compose caveats below. Uses `docker-mount` and `docker-umount`. 65 | - `docker-machine`, execute `docker-machine` commands on the *docker-machine*. 66 | - `docker-search`, run `docker search --no-trunc` on the *docker-machine*. 67 | - `docker.ssh.cmd`, the underlying ssh command that actually sends the docker commands to the *docker-machine*. You can edit the 'userName' and 'hostName' variables here. 68 | 69 | 70 | # How to install (and uninstall) 71 | 72 | - `git clone https://github.com/ITmaze/remote-docker.git` 73 | - `cd remote-docker` 74 | - `vi docker.config` 75 | - `./install_docker_remote.sh` 76 | 77 | ## Notes on installation: 78 | 79 | - `docker.config` is requried and is expected to be located with all the other scripts. It's used by all commands. 80 | - `install_docker_remote.sh` creates symbolic links between the configured "bin" directory (by default "~/bin") and each of the scripts. 81 | - `remove_docker_remote.sh` removes the project from the configured "bin" directory. It will only do so if the files are either identical, or symbolic links to the script with the same name. 82 | 83 | 84 | # Docker-Compose Caveats 85 | 86 | This is a re-written version using the official Docker `docker.io/library/docker:latest` image which includes the `compose` plug-in. When you run it for the first time, it will pull the image, then launch. If you use the default image, you can refresh it using: 87 | 88 | - `docker pull docker` 89 | 90 | To operate, `docker-compose` maps the Docker socket on the *docker-machine* (by default `/var/run/docker.sock`) inside the `docker` container, where it then executes the `compose` sub-command using the parameters supplied. 91 | 92 | Note: This has not been thoroughly tested yet and the `stdout` output is a little mangled, patches welcome. 93 | 94 | 95 | # Requirements 96 | 97 | There are requirements for both the *docker-machine* and the *workstation*. These are different. 98 | 99 | One thing both have in common is that you need to be able to ssh between both without using a password. `ssh-copy-id` is the way to make that happen. If you get an error about missing an identity, create one using `ssh-keygen`. This is required, since we're using ssh from the *workstation* to the *docker-machine* to execute Docker commands and we're using ssh from the *docker-machine* to the *workstation* to mount a directory using sshfs. 100 | 101 | ## Workstation requirements: 102 | 103 | - ssh 104 | - sshd 105 | - uuidgen (uuid-runtime) 106 | - fromdos (tofrodos) 107 | 108 | ## Docker-Machine requirements: 109 | 110 | - docker 111 | - ssh 112 | - sshd 113 | - sshfs 114 | - write permission on the home directory of the docker user 115 | 116 | 117 | # Examples 118 | 119 | The examples directory shows some of the ways that this tool can be used. It is incomplete and as I go through my existing use of this code (70+ containers), the example directory will likely grow. 120 | 121 | To use a container, I add a symlink between my ~/bin and a launch file. For example: ~/bin/speedtest -> ./examples/speedtest/launch. Note, the `apt-docker` command creates this symbolic link automatically when you build a container with it. 122 | 123 | - __firefox-esr__, runs firefox across X11, linking the /home/docker/Downloads directory to the /home/onno/Downloads directory, so that the mount point inside the container has the same path as my actual ~/Downloads directory. Update the username to reflect your own user. 124 | - __git__, runs git in the current directory, but mounts the ~/.ssh directory so it can access your keys. 125 | - __speedtest__, simple example of running a docker command without any volume mounting. 126 | 127 | 128 | # Bugs and potential Security Issues 129 | 130 | - An sshfs mount exists while a container is running. Anyone with access to the *docker-machine* also has full access to all the sshfs mounts. 131 | - There are times when `docker-volume` volumes do not un-mount cleanly, root cause to be determined, but likely interrupted launch of a command. Note that these volumes don't actually take up any disk-space, since they're sshfs mounts from the *docker-machine* to the *workstation*. You can remove such a mount using `docker-umount {volumeName}`, but note that you can only use one {volumeName} at a time. 132 | - Fixed: 58546e7 The quote handling isn't clean, sometimes double quoting is required. This appears to be an ssh *feature*. Using a git container to commit for example requires some shenanigans: `git commit -m "'Initial commit.'"` 133 | - Fixed: 909ba1e Note that currently the console displays "Creating volume:" and "Removing volume:" messages. If you know how to make those go away, please provide a patch. (Yes, I'm aware that I'm echoing those strings, it's the volume id from Docker that really needs hiding that I cannot control.) 134 | 135 | 136 | # Kittens Clause 137 | 138 | - Fair warning: This isn't feature complete and probably kills kittens. 139 | - Until a few days ago this was a set of scripts on my workstation. Today it's a github project. If you break it, you get to keep both parts. 140 | - Naming isn't consistent. 141 | - There are times when a command doesn't "come back", likely the Docker console is "helping". You can kill the Docker container from another shell using `docker ps` and `docker kill`. 142 | - I have tested this on a bare machine to ensure that it should work for you out of the box, but it might not. If it doesn't please file an issue and I'll have a look. 143 | - Feel free to get in touch, but if you want to fix something or suggest a feature, please create an issue or supply a patch. 144 | - This was inspired by the pioneering hard work by [Jess Frazelle](https://github.com/jessfraz) who introduced me to the idea of running everything inside Docker. My workstation isn't quite there yet, but it's getting closer every day. 145 | - I blame [Corey Quinn](https://www.lastweekinaws.com/t/) for asking silly questions and my mother for teaching me not to keep my big mouth shut - enjoy! 146 | --------------------------------------------------------------------------------