├── assets └── djocker.png ├── Formula ├── docker-machine-pf.rb ├── docker-machine-nfs-generic.rb └── docker-virtualbox.rb ├── bin ├── docker ├── docker-compose └── docker-machine-init └── README.md /assets/djocker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergeycherepanov/homebrew-docker-virtualbox/HEAD/assets/djocker.png -------------------------------------------------------------------------------- /Formula/docker-machine-pf.rb: -------------------------------------------------------------------------------- 1 | require 'formula' 2 | 3 | class DockerMachinePf < Formula 4 | url 'https://github.com/johanhaleby/docker-machine-port-forwarder/archive/d58e7b8f267b6d9e4156f0c5939c01a84afb52ec.tar.gz' 5 | homepage 'https://github.com/johanhaleby/docker-machine-port-forwarder' 6 | sha256 '0acd6f61c71b4f719613c92e2b5df5231ec5d76816ef4e321c2b7c2150d1fcdf' 7 | version "0.0.1" 8 | revision 2 9 | 10 | def install 11 | bin.install "pf" 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /Formula/docker-machine-nfs-generic.rb: -------------------------------------------------------------------------------- 1 | class DockerMachineNfsGeneric < Formula 2 | desc "Activates NFS on docker-machine (with generic driver support)" 3 | homepage "https://github.com/sergeycherepanov/docker-machine-nfs" 4 | url "https://github.com/sergeycherepanov/docker-machine-nfs/archive/0.5.4.2.tar.gz" 5 | sha256 "5067da89d8ba1205883cfa0087106cbbe5bc4140ee4b9f45ed1a7b772363417b" 6 | license "MIT" 7 | version "0.5.4" 8 | revision 2 9 | 10 | def install 11 | bin.install "docker-machine-nfs.sh" => "docker-machine-nfs-generic" 12 | end 13 | 14 | test do 15 | system "#{bin}/docker-machine-nfs-generic" 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /bin/docker: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | #set -x 4 | LIMIT=90 5 | if [[ -f /tmp/docker-virtualbox.starting ]]; then 6 | >&2 echo -e "\033[93mWaiting while Docker starting..." 7 | >&2 echo -e "\033[0m" 8 | i=0 9 | while [[ -f /tmp/docker-virtualbox.starting ]]; do 10 | if [[ "$i" -gt "$LIMIT" ]]; then 11 | >&2 echo -e "Default \e[91mThe timeout reached, please verify the vm log for errors: /tmp/docker-virtualbox.log\e[39m" 12 | fi 13 | i=$(($i+1)) 14 | sleep 1; 15 | done 16 | fi 17 | 18 | [[ -f /tmp/docker-virtualbox.env && -f /tmp/docker-virtualbox-machine.env ]] || { 19 | echo -e "\033[91m" 20 | echo -e "\033[91mLooks like docker-virtualbox doesn't work" 21 | echo -e "" 22 | echo -e "\033[0mYou have to start it by following command:" 23 | echo -e "" 24 | echo -e "\033[96mbrew services start docker-virtualbox " 25 | echo -e "\033[0m" 26 | exit 1 27 | } 28 | 29 | source /tmp/docker-virtualbox.env 30 | 31 | [[ -z "${DOCKER_HOST}" ]] && { 32 | source /tmp/docker-virtualbox-machine.env 33 | } 34 | 35 | exec ${DOCKER_CLI_BIN_PATH} "$@" 36 | -------------------------------------------------------------------------------- /bin/docker-compose: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | #set -x 4 | LIMIT=90 5 | if [[ -f /tmp/docker-virtualbox.starting ]]; then 6 | >&2 echo -e "\033[93mWaiting while Docker starting..." 7 | >&2 echo -e "\033[0m" 8 | i=0 9 | while [[ -f /tmp/docker-virtualbox.starting ]]; do 10 | if [[ "$i" -gt "$LIMIT" ]]; then 11 | >&2 echo -e "Default \e[91mThe timeout reached, please verify the vm log for errors: /tmp/docker-virtualbox.log\e[39m" 12 | fi 13 | i=$(($i+1)) 14 | sleep 1; 15 | done 16 | fi 17 | 18 | [[ -f /tmp/docker-virtualbox.env && -f /tmp/docker-virtualbox-machine.env ]] || { 19 | echo -e "\033[91m" 20 | echo -e "\033[91mLooks like docker-virtualbox doesn't work" 21 | echo -e "" 22 | echo -e "\033[0mYou have to start it by following command:" 23 | echo -e "" 24 | echo -e "\033[96mbrew services start docker-virtualbox " 25 | echo -e "\033[0m" 26 | exit 1 27 | } 28 | 29 | source /tmp/docker-virtualbox.env 30 | 31 | [[ -z "${DOCKER_HOST}" ]] && { 32 | source /tmp/docker-virtualbox-machine.env 33 | } 34 | 35 | exec ${DOCKER_COMPOSE_BIN_PATH} "$@" 36 | -------------------------------------------------------------------------------- /Formula/docker-virtualbox.rb: -------------------------------------------------------------------------------- 1 | require 'formula' 2 | 3 | class DockerVirtualbox < Formula 4 | url "https://github.com/sergeycherepanov/homebrew-docker-virtualbox.git", :using => :git 5 | version "0.0.7" 6 | revision 1 7 | 8 | depends_on 'coreutils' 9 | depends_on 'curl' 10 | depends_on 'jq' 11 | depends_on 'terminal-notifier' 12 | depends_on 'docker' 13 | depends_on 'docker-compose' 14 | depends_on 'docker-credential-helper' 15 | depends_on 'docker-machine' 16 | depends_on 'docker-machine-nfs-generic' 17 | 18 | keg_only "this package may conflict with official docker client" 19 | 20 | resource "gobetween" do 21 | url "https://github.com/yyyar/gobetween/releases/download/0.8.0/gobetween_0.8.0_darwin_amd64.zip" 22 | sha256 "15efec9cef9dc01c4e195042df62def95f189090e470678d5b6f024afa71e1b0" 23 | end 24 | 25 | def install 26 | resource("gobetween").stage do 27 | bin.install "gobetween" 28 | end 29 | (buildpath/"gobetween.toml").write <<~EOS 30 | [api] 31 | enabled = true 32 | bind = "127.0.0.1:8181" 33 | EOS 34 | (etc/"docker-virtualbox").mkpath 35 | etc.install "gobetween.toml" => 'docker-virtualbox/gobetween.toml' 36 | 37 | bin.install "bin/docker" 38 | bin.install "bin/docker-compose" 39 | bin.install "bin/docker-machine-init" 40 | prefix.install "assets/djocker.png" 41 | end 42 | 43 | def caveats 44 | s = <<~EOS 45 | Docker Virtualbox was installed 46 | 47 | Please don't forget to configure your PATH variable 48 | EOS 49 | s 50 | end 51 | 52 | def plist; <<~EOS 53 | 54 | 55 | 56 | 57 | KeepAlive 58 | 59 | Label 60 | #{plist_name} 61 | ProgramArguments 62 | 63 | #{opt_bin}/docker-machine-init 64 | 65 | RunAtLoad 66 | 67 | WorkingDirectory 68 | /tmp 69 | 70 | 71 | EOS 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Homebrew Docker Virtualbox (But not VirtualBox only) 2 | This formula resolves the Docker issue on AMD based MacOS (Ryzentosh). Also can be used on any Mac. 3 | 4 | *PLEASE READ FIRST THE NOTICE: https://gist.github.com/slykar/e92732be9bf81a71e08068245656d70e?permalink_comment_id=4105556#gistcomment-4105556* 5 | 6 | ## Installation 7 | 8 | ### Install Virtualbox from Oracle website 9 | https://www.virtualbox.org/wiki/Downloads. 10 | > Please don't forget to remove all previous installations. 11 | > This step required only if you want to use VirtualBox driver, otherwise see below how to start with another driver. 12 | 13 | ### Virtualbox 6.1.28+ Note 14 | Due the changes of virtualbox networking, you need to allow docker-machine host in order to use 192.168.99.0/8 network. [More Details](https://www.virtualbox.org/manual/ch06.html#network_hostonly) 15 | 16 | Add this line into 17 | `/etc/vbox/networks.conf` 18 | ```bash 19 | * 192.168.99.0/8 20 | ``` 21 | 22 | ### Install the docker-virtualbox via Homebrew 23 | ```bash 24 | brew tap serhiicherepanov/docker-virtualbox 25 | brew install docker-virtualbox 26 | ``` 27 | 28 | ### Configure the docker-virtualbox requirements 29 | > WARNING: Only this commands requires root permissions, all next should be run under your user 30 | 31 | Ensure the NFS exports file exists 32 | ```bash 33 | sudo touch /etc/exports 34 | ``` 35 | 36 | Allow the staff group to configure NFS shares and run the balancer without a password prompt 37 | ```bash 38 | sudo tee /etc/sudoers.d/docker-machine-nfs < Reboot your system to be sure that sudoers applied 48 | 49 | ### Configure the environment 50 | 51 | If you didn't install Docker for Mac you can link binaries instead of PATH update 52 | ``` 53 | brew link --force --overwrite docker-virtualbox 54 | ``` 55 | 56 | Otherwise configure the PATH variable 57 | ```bash 58 | # For the bash 59 | echo "export PATH=\"$(brew --prefix docker-virtualbox)/bin:\$PATH\"" >> ~/.bash_profile 60 | # For the zsh 61 | echo "export PATH=\"$(brew --prefix docker-virtualbox)/bin:\$PATH\"" >> ~/.zshrc 62 | ``` 63 | 64 | Reload the shell 65 | ``` 66 | exec $SHELL 67 | ``` 68 | 69 | ### Initialize the docker machine 70 | In the first run according to the permissions policy you need to run it manually and approve permissions. 71 | 72 | ```bash 73 | docker-machine-init initialize 74 | ``` 75 | > This is will download, create and configure the VirtualBox-based machine if the machine was not configured before. If the machine was created manually this will only set up NFS mount. 76 | 77 | 78 | ### Start the docker-virtualbox service 79 | When initialization will be finished you are ready to enable the service 80 | > The log file will be always available in `/tmp/docker-virtualbox.log`. 81 | ```bash 82 | brew services start docker-virtualbox 83 | ``` 84 | 85 | ### Verify installation 86 | 87 | Test the Docker by running Nginx 88 | ```bash 89 | docker run -d -p 8989:80 nginx 90 | curl -v localhost:8989 91 | ``` 92 | 93 | ## Additional information 94 | 95 | If you don't want to use the VirtualBox as docker-machine driver you need to create a machine manually before initialization by similar command: 96 | ```bash 97 | docker-machine create --driver generic --generic-ip-address=192.168.24.108 --generic-ssh-user=developer --generic-ssh-key=$HOME/.ssh/id_rsa docker 98 | ``` 99 | > Please note the docker-machine-nfs plugin supports only Debian based Linux as the target system. For more information read the [documentation](https://github.com/sergeycherepanov/docker-machine-nfs/blob/master/README.md) 100 | 101 | Read the log when the docker doesn't work properly 102 | ```bash 103 | tail -n 1000 -f /tmp/docker-virtualbox.log 104 | ``` 105 | 106 | SSH connection to the docker-machine 107 | ```bash 108 | docker-machine ssh docker 109 | ``` 110 | 111 | To stop the service just run 112 | ```bash 113 | brew services stop docker-virtualbox 114 | ``` 115 | 116 | To setup environment for 3rd party tools ([`ctop`](https://github.com/bcicen/ctop) as example) 117 | ``` 118 | source /tmp/docker-virtualbox.env 119 | source /tmp/docker-virtualbox-machine.env 120 | ``` 121 | 122 | ## Known issues 123 | 1. The system won't sleep when the NFS server runs 124 | 2. The port forwarding doesn't work for UDP proto (improvement needed) 125 | -------------------------------------------------------------------------------- /bin/docker-machine-init: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | [[ $1 == "debug" ]] && { 4 | set -x 5 | } 6 | if [[ $(id -u ${USER}) -eq 0 ]]; then 7 | echo "Please don't run this script under the root user!" 8 | exit 1 9 | fi 10 | LOGDIR="/tmp"; 11 | 12 | [[ $1 != "initialize" ]] && [[ $1 != "debug" ]] && { 13 | exec > ${LOGDIR}/docker-virtualbox.log 14 | exec 2>&1 15 | } 16 | 17 | START_TIME=$(date +%s) 18 | 19 | if [[ -n "${BREW_BIN}" ]]; then 20 | BREW_BIN=$BREW_BIN 21 | elif [[ "Darwin" == "$(uname)" ]]; then 22 | BREW_BIN=/usr/local/bin 23 | else 24 | BREW_BIN=/home/linuxbrew/.linuxbrew/bin 25 | fi 26 | 27 | PATH="${PATH}:${BREW_BIN}" 28 | GOBETWEEN_BIN=$(brew --prefix)/opt/docker-virtualbox/bin/gobetween 29 | TERMINAL_NOTIFIER_BIN="$(brew --prefix terminal-notifier)/bin/terminal-notifier -appIcon $(brew --prefix docker-virtualbox)/djocker.png" 30 | JQ_BIN="$(brew --prefix jq)/bin/jq" 31 | DOCKER_MACHINE_BIN=$(brew --prefix docker-machine)/bin/docker-machine 32 | DOCKER_MACHINE_NFS_BIN=$(brew --prefix docker-machine-nfs-generic)/bin/docker-machine-nfs-generic 33 | 34 | DOCKER_MACHINE_DRIVER=${DOCKER_DRIVER-virtualbox} 35 | DOCKER_MACHINE_MACHINE_NAME=${DOCKER_MACHINE_NAME-docker} 36 | 37 | function stop() 38 | { 39 | [[ -f /tmp/docker-virtualbox.env ]] && rm /tmp/docker-virtualbox.env 40 | [[ -f /tmp/docker-virtualbox-machine.env ]] && rm /tmp/docker-virtualbox-machine.env 41 | echo "===> Stopping docker machine: ${DOCKER_MACHINE_MACHINE_NAME}" 42 | ${TERMINAL_NOTIFIER_BIN} -title "Docker Virtualbox" -message "Stopping virtual machine: '${DOCKER_MACHINE_MACHINE_NAME}'" 43 | ${DOCKER_MACHINE_BIN} stop ${DOCKER_MACHINE_MACHINE_NAME} 44 | exit 0 45 | } 46 | 47 | trap stop SIGKILL 48 | trap stop SIGTERM 49 | trap stop SIGINT 50 | 51 | 52 | ${TERMINAL_NOTIFIER_BIN} -title "Docker Virtualbox" -message "Initialize..." 53 | sleep 1 54 | 55 | if [[ -z ${DOCKER_MACHINE_DISK_SIZE} ]]; then 56 | DOCKER_MACHINE_DISK_SIZE="16000" 57 | if [[ $($(brew --prefix coreutils)/libexec/gnubin/df --block-size=1073741824 | grep '\/$' | awk '{print $2}') -gt 200 ]]; then 58 | DOCKER_MACHINE_DISK_SIZE="32000" 59 | fi 60 | fi 61 | 62 | if [[ -z ${DOCKER_MACHINE_CPU_COUNT} ]]; then 63 | if [[ "Darwin" == "$(uname)" ]]; then 64 | DOCKER_MACHINE_CPU_COUNT=$(sysctl -n hw.ncpu | awk 'function ceil(x, y){y=int(x); return(x>y?y+1:y)} { print ceil($1*0.25) }') 65 | else 66 | DOCKER_MACHINE_CPU_COUNT=$(grep ^cpu\\scores /proc/cpuinfo | uniq | awk '{print $4}' | awk 'function ceil(x, y){y=int(x); return(x>y?y+1:y)} { print ceil($1*0.25) }') 67 | fi 68 | fi 69 | 70 | if [[ -z ${DOCKER_MACHINE_MEMORY_COUNT} ]]; then 71 | if [[ "Darwin" == "$(uname)" ]]; then 72 | DOCKER_MACHINE_MEMORY_COUNT=$(sysctl -n hw.memsize | awk '{ mem=($1 * 0.25 / 1024 / 1024 ); print int(mem > 4096 ? 4096 : mem) }') 73 | else 74 | DOCKER_MACHINE_MEMORY_COUNT=$(free -b | grep Mem | awk '{ mem=($2 * 0.25 / 1024 / 1024 ); print int(mem > 4096 ? 4096 : mem) }') 75 | fi 76 | fi 77 | 78 | [[ "Running" == $(${DOCKER_MACHINE_BIN} status ${DOCKER_MACHINE_MACHINE_NAME}) ]] && { 79 | touch /tmp/docker-virtualbox.starting 80 | echo "===> Virtual machine '${DOCKER_MACHINE_MACHINE_NAME}' already started" 81 | ${TERMINAL_NOTIFIER_BIN} -title "Docker Virtualbox" -message "Virtual machine '${DOCKER_MACHINE_MACHINE_NAME}' started" 82 | } || { 83 | touch /tmp/docker-virtualbox.starting 84 | [[ "Stopped" == $(${DOCKER_MACHINE_BIN} status ${DOCKER_MACHINE_MACHINE_NAME}) ]] && { 85 | ${TERMINAL_NOTIFIER_BIN} -title "Docker Virtualbox" -message "Starting virtual machine: ${DOCKER_MACHINE_MACHINE_NAME}" 86 | echo "===> Starting docker machine: ${DOCKER_MACHINE_MACHINE_NAME}" 87 | ${DOCKER_MACHINE_BIN} start ${DOCKER_MACHINE_MACHINE_NAME} 88 | } || { 89 | echo "===> Creating docker machine: ${DOCKER_MACHINE_MACHINE_NAME}" 90 | ${TERMINAL_NOTIFIER_BIN} -title "Docker Virtualbox" -message "Creating virtual machine: ${DOCKER_MACHINE_MACHINE_NAME}" 91 | ${DOCKER_MACHINE_BIN} create --driver ${DOCKER_MACHINE_DRIVER} \ 92 | --virtualbox-cpu-count ${DOCKER_MACHINE_CPU_COUNT} \ 93 | --virtualbox-memory ${DOCKER_MACHINE_MEMORY_COUNT} \ 94 | --virtualbox-disk-size ${DOCKER_MACHINE_DISK_SIZE} \ 95 | ${DOCKER_MACHINE_MACHINE_NAME} 96 | } 97 | 98 | # Extra vm options 99 | ${DOCKER_MACHINE_BIN} ssh ${DOCKER_MACHINE_MACHINE_NAME} sudo sysctl -w vm.max_map_count=262144 100 | } 101 | 102 | ${TERMINAL_NOTIFIER_BIN} -title "Docker Virtualbox" -message "Configuring NFS mount for: '${DOCKER_MACHINE_MACHINE_NAME}'" 103 | 104 | ${DOCKER_MACHINE_NFS_BIN} ${DOCKER_MACHINE_MACHINE_NAME} 105 | 106 | [[ $1 == "initialize" ]] && { 107 | echo "" 108 | echo -e "\033[91m>>>>> \033[92m *** CONGRATULATION *** DOCKER READY TO USE *** \033[91m<<<<<" 109 | echo -e "\033[0m" 110 | echo "Please start the service by following command:" 111 | echo -e "\033[0m" 112 | echo -e "\033[0m" 113 | echo -e " \033[96mbrew services start docker-virtualbox" 114 | echo -e "\033[0m" 115 | exit 0 116 | } 117 | 118 | echo "===> Starting Gobetween..." 119 | [[ -f /tmp/docker-virtualbox-gobetween.pid ]] && ps -p $(cat /tmp/docker-virtualbox-gobetween.pid) > /dev/null && { 120 | echo "---> Gobetween already started, disabling outdated port forwarding..." 121 | servers=$(curl --silent http://127.0.0.1:8181/servers | ${JQ_BIN} -r '. | keys | .[]') 122 | for server in $servers; do 123 | echo "Disabling port forwarding for: ${server}" 124 | curl --silent -X DELETE http://127.0.0.1:8181/servers/${server} 125 | done 126 | } || { 127 | sudo ${GOBETWEEN_BIN} -c $(brew --prefix)/etc/docker-virtualbox/gobetween.toml > ${LOGDIR}/docker-virtualbox-gobetween.log 2>&1 & 128 | echo $! > /tmp/docker-virtualbox-gobetween.pid 129 | echo "---> Gobetween started" 130 | } 131 | 132 | # setup env 133 | echo "export DOCKER_CLI_BIN_PATH=\"$(brew --prefix docker)/bin/docker\"" > /tmp/docker-virtualbox.env 134 | echo "export DOCKER_COMPOSE_BIN_PATH=\"$(brew --prefix docker-compose)/bin/docker-compose\"" >> /tmp/docker-virtualbox.env 135 | echo "export DOCKER_MACHINE_IP=\"$(${DOCKER_MACHINE_BIN} ip ${DOCKER_MACHINE_MACHINE_NAME})\"" >> /tmp/docker-virtualbox.env 136 | ${DOCKER_MACHINE_BIN} env ${DOCKER_MACHINE_MACHINE_NAME} --shell bash >> /tmp/docker-virtualbox-machine.env 137 | ${TERMINAL_NOTIFIER_BIN} -title "Docker Virtualbox" -message "Virtual machine '${DOCKER_MACHINE_MACHINE_NAME}' ready for work" 138 | 139 | 140 | source /tmp/docker-virtualbox.env 141 | source /tmp/docker-virtualbox-machine.env 142 | 143 | echo "" 144 | echo "===> Configuring port forwarding for alrady running containers..." 145 | while read -r subjectid 146 | do 147 | ports="$(${DOCKER_CLI_BIN_PATH} inspect -f '{{range $p, $conf := .NetworkSettings.Ports }} {{ if $conf}} {{$conf}} {{end}} {{end}}' "${subjectid}" | sed -nE 's:\[\{[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}[^0-9]*([0-9]{1,})\}\]:\1:pg' | xargs echo -n)" 148 | [[ -z ${ports} ]] || { 149 | for port in $ports; do 150 | echo "" 151 | echo "Enabling port forwarding: ${port} -> ${DOCKER_MACHINE_IP}:${port}" 152 | >&2 curl --silent -X POST --data "@-" http://127.0.0.1:8181/servers/${subjectid_short}_${port} < Listen for events..." 175 | [[ -f /tmp/docker-virtualbox.starting ]] && rm /tmp/docker-virtualbox.starting 176 | while read -r event; 177 | do 178 | subject=$(echo $event | awk '{ print $2 }') 179 | action=$(echo $event | awk '{ print $3 }') 180 | subjectid=$(echo $event | awk '{ print $4 }') 181 | subjectid_short=$(echo $subjectid | cut -c -8) 182 | if [[ "container" == ${subject} ]]; then 183 | case $action in 184 | "start") 185 | ports="$(${DOCKER_CLI_BIN_PATH} inspect -f '{{range $p, $conf := .NetworkSettings.Ports }} {{ if $conf}} {{$conf}} {{end}} {{end}}' "${subjectid}" | sed -nE 's:\[\{[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}[^0-9]*([0-9]{1,})\}\]:\1:pg' | xargs echo -n)" 186 | [[ -z ${ports} ]] || { 187 | for port in $ports; do 188 | echo "" 189 | echo "Enabling port forwarding: ${port} -> ${DOCKER_MACHINE_IP}:${port}" 190 | >&2 curl --silent -X POST --data "@-" http://127.0.0.1:8181/servers/${subjectid_short}_${port} < service terminated" 229 | --------------------------------------------------------------------------------