Add Docker to macOS installation

Description of the feature request

Add Docker as a default installation to all VMs running macOS/Xcode.

Use case / for what or how I would use it

Allows easy use of supporting services that are used in testing an application. Will cut down on installations that might be involved and expensive (due to installation time). This will also negate the possible challenges of trying to run the same services in different environments.

Hi @aroswell,

Thanks for the #feature-request!

For now we don’t plan to preinstall docker on the Mac stacks, but if this request gets enough votes we’ll definitely consider it.

Why we don’t plan to preinstall it (for now): as discussed in How to use your own Docker image for your builds Docker for Mac, which is the current preferred official solution, doesn’t really work in a virtualized environment and has some other issues too.

The older Docker Toolkit does work, but it’s marked as semi-deprecated, although there are still quite a few docker tools which only work with that (e.g. docker-machine) and does not with Docker for Mac.

Other than the stability / deprecation issue resource constraints are also a factor. If an iOS build doesn’t need Docker, the resources consumed by Docker are a waste. Why does docker consume resources? Because Docker on the Mac uses a virtualized Linux to run the docker commands, as there is no native Mac support in docker. The standard Docker is built on Linux (kernel) technologies.

That said, if you need Docker on the Mac stacks, it’s definitely possible to install and use it. It takes about 30 seconds to install with brew and another ~80 seconds to boot the required host (linux virtual machine).

An example configuration using Script steps to install and start docker-toolkit:

---
format_version: 3
default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git
trigger_map:
- push_branch: "*"
  workflow: primary
- pull_request_source_branch: "*"
  workflow: primary
workflows:
  primary:
    steps:
    - script@1.1.4:
        title: brew cask install docker-toolbox
        inputs:
        - content: |-
            #!/bin/bash
            set -ex

            brew cask install docker-toolbox
    - script@1.1.4:
        title: docker-machine create
        inputs:
        - content: |-
            #!/bin/bash
            set -ex

            docker-machine create --driver "virtualbox" default
    - script@1.1.4:
        title: use docker
        inputs:
        - content: |-
            #!/bin/bash
            set -ex

            eval $(docker-machine env default)

            docker version
            docker run hello-world

Note: you have to run the eval $(docker-machine env default) command in every Script where you want to use docker, as it only sets the environments for the script it was invoked in!

2 Likes

Thanks. I was trying with brew cask install docker, but hit a wall when launching docker because the docker app needs root permission after it’s initial installation.
I’ve taken your suggestion and it seems to work (slowly but surely).

1 Like

Root permission shouldn’t be an issue (passwordless sudo is enabled on all stacks), but indeed Docker for Mac can’t be used right now on the Mac stacks it seems. We’ll try to find a solution for it eventually, if they don’t fix the related issues, but in the meantime docker-toolbox should be a suitable solution :slight_smile:

The docker installation as per your instructions worked like a charm. However, I’ve not been able to connect to the service inside the container. I’ve posted this in the slack channel but also thought it would benefit others here as well. If I find a solution or you come up with one, I will make it known here.

+ docker run -d -p 8888:8888 -p 8500:8500 --name hoverfly azohra/hoverfly
36a154bae98b8c2eafd71542f26b602aa66527c939245e3a09450d15ef775331
+ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED                  STATUS                  PORTS                                            NAMES
36a154bae98b        azohra/hoverfly     "/go/bin/hoverfly ..."   Less than a second ago   Up Less than a second   0.0.0.0:8500->8500/tcp, 0.0.0.0:8888->8888/tcp   hoverfly
+ docker logs hoverfly
INFO[2017-07-26T15:40:17Z] Using memory backend                         
INFO[2017-07-26T15:40:17Z] Webserver prepared...                         Destination=. Mode=simulate WebserverPort=8500
INFO[2017-07-26T15:40:17Z] current proxy configuration                   destination=. mode=simulate port=8500
INFO[2017-07-26T15:40:17Z] Admin interface is starting...                AdminPort=8888
INFO[2017-07-26T15:40:17Z] serving proxy                                
+ curl http://0.0.0.0:8888/api/v2/logs
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0curl: (7) Failed to connect to 0.0.0.0 port 8888: Connection refused

Simple curl command using localhost and 0.0.0.0 returns with a connection error.

@aroswell it seems that Docker Toolbox does not expose the port for localhost automatically (technically, there’s no automatic port forwarding set up from the host (macOS) to the VM docker is running inside (a Linux VM in VirtualBox)).

You can get the IP of the docker host VM with:

docker_host_ip="$(docker-machine ip default)"

(default is the name of the VM created with docker-machine in the example at Add Docker to macOS installation - if you use another name you should change it to that)

Then you can curl it like in the same Script:

curl "$docker_host_ip"

If you need it in another script you should export it as an env var with envman (http://devcenter.bitrise.io/tips-and-tricks/expose-environment-variable/):

envman add --key DOCKER_HOST_IP --value "$docker_host_ip"

Note: the “default” machine’s IP seems to be a predefined IP, 192.168.99.100, so you can use that directly too in most cases. (See e.g. https://forums.docker.com/t/using-localhost-for-to-access-running-container/3148/6 and I also tested docker-machine ip default in a quick Bitrise.io build and returned the same IP). You can of course set up a port forwarding for the IP too, so that you can just “localhost:IP” to address it.

@viktorbenei This worked well. No issues. Thanks.

1 Like

I’m using macOS to get access to both Android and iOS toolbox to build React Native project. This project as multiple facets as a website and backend is also being built in it.

As such, having Docker pre-installed to at least build images would be a nice gain of time. Voted +1 :slight_smile:

Cheers,
Matt

2 Likes

Keep the votes coming! :wink: We definitely do keep this in mind, just waiting for more votes & to see how the Docker on Mac story evolves (e.g. whether Docker Toolkit remains or will be deprecated/removed).

Would be great to have docker toolbox and the virtualbox VM pre-installed. Would shave a couple minutes off our build with docker times. E.g.:

brew cask install docker-toolbox
docker-machine create --driver “virtualbox” default

Added my up-vote. Thanks!

1 Like

Hello!

I am trying to access a docker service for testing purposes and unfortunately i am not able to access it through localhost. The script i am using is:

docker-machine create --driver "virtualbox" default
eval $(docker-machine env default)
docker run --privileged --env CI=false -d -p 4040:8080 --name wiremock rodolpheche/wiremock:latest

docker exec -i $(docker ps | awk 'END {print $1}') bash -c "curl localhost:8080/__admin/mappings"

I am getting the following error:

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0curl: (7) Failed to connect to localhost port 8080: Connection refused

I have tried also

docker-machine create --driver "virtualbox" default
eval $(docker-machine env default)
docker run --privileged --env CI=false -d -p 4040:8080 --name wiremock rodolpheche/wiremock:latest
curl http://localhost:4040/__admin/mappings

I have tried also:

brew cask install docker-toolbox
docker-machine create --driver "virtualbox" default
# docker_host_ip="$(docker-machine ip default)"
eval $(docker-machine env default)
docker pull rodolpheche/wiremock:latest
docker run --privileged --env CI=false  -d -p 4040:8080 --name wiremock rodolpheche/wiremock:latest
vboxmanage controlvm default natpf1 "tcp-port4040,tcp,127.0.0.1,4040,,4040"
docker-machine ip
curl http://localhost:4040/__admin/mappings

I have tried also:

brew cask install docker-toolbox
docker-machine create --driver "virtualbox" default
docker_host_ip="$(docker-machine ip default)"
eval $(docker-machine env default)
docker pull rodolpheche/wiremock:latest
docker run --privileged --env CI=false  -d -p 4040:4040 -p 8080:8080 --name wiremock rodolpheche/wiremock:latest
vboxmanage controlvm default natpf1 "tcp-port4040,tcp,127.0.0.1,4040,,4040"
docker ps -a
docker-machine ip
docker-machine ls

curl "$docker_host_ip":4040/__admin/mappings

Nothing seems to work.

Could you please advice?

I’ve voted for this feature!

Hey @viktorbenei, could you provide an example configuration for installing docker using the hyperkit driver rather than virtualbox? I would like to utilize a more optimal docker driver for macOS when running my test workflows.

Thanks :slight_smile:

Sadly docker-toolbox no longer seems to be a solution:

[07:12:53]: $ brew install --cask docker-toolbox
[07:12:57]: â–¸ ==> Caveats
[07:12:57]: â–¸ docker-toolbox has been officially discontinued upstream.
[07:12:57]: â–¸ It may stop working correctly (or at all) in recent versions of macOS.

Later it completely fails with:

[07:14:56]: â–¸ (default) Creating a new host-only adapter produced an error: /usr/local/bin/VBoxManage hostonlyif create failed:
[07:14:56]: â–¸ (default) Progress state: NS_ERROR_FAILURE
[07:14:56]: â–¸ (default) VBoxManage: error: Failed to create the host-only adapter
[07:14:56]: â–¸ (default) VBoxManage: error: VBoxNetAdpCtl: Error while adding new interface: failed to open /dev/vboxnetctl: No such file or directory
[07:14:56]: â–¸ (default) VBoxManage: error: Details: code NS_ERROR_FAILURE (0x80004005), component HostNetworkInterfaceWrap, interface IHostNetworkInterface
[07:14:56]: â–¸ (default) VBoxManage: error: Context: "RTEXITCODE handleCreate(HandlerArg *)" at line 95 of file VBoxManageHostonly.cpp
[07:14:56]: â–¸ (default) This is a known VirtualBox bug. Let's try to recover anyway...
[07:15:10]: â–¸ Error creating machine: Error in driver during machine creation: Error setting up host only network on machine start: The host-only adapter we just created is not visible. This is a well known VirtualBox bug. You might want to uninstall it and reinstall at least version 5.0.12 that is is supposed to fix this issue
[07:15:11]: Exit status of command 'docker-machine create --driver "virtualbox" default' was 1 instead of 0.

Are there any suggestions for alternatives?

I believe the reason that fails atm with the more recent build stacks that are based on Monterey and further introduced additional security requirements. There are kernel extensions that virtualbox needs to be able to start virtualized adapters in the host environment. If you try to add them:

+ sudo kextload -b org.virtualbox.kext.VBoxDrv
Executing: /usr/bin/kmutil load -b org.virtualbox.kext.VBoxDrv
Error Domain=KMErrorDomain Code=27 "Extension with identifiers org.virtualbox.kext.VBoxDrv,org.virtualbox.kext.VBoxNetFlt,org.virtualbox.kext.VBoxUSB,org.virtualbox.kext.VBoxNetAdp not approved to load. Please approve using System Preferences." UserInfo={NSLocalizedDescription=Extension with identifiers org.virtualbox.kext.VBoxDrv,org.virtualbox.kext.VBoxNetFlt,org.virtualbox.kext.VBoxUSB,org.virtualbox.kext.VBoxNetAdp not approved to load. Please approve using System Preferences.}

I’ve scoured the internet and cannot find any way to bypass this other than by providing permissions to Virtualbox in the MacOS GUI, which we cannot access in the build stacks.