Configure Docker with proxy per host/url

3.1k views Asked by At

I use Docker Toolbox on Windows 7 in a corporate environment. My workflow requires pulling containers from one artifactory and pushing them to a different one (eg. external and internal). Each artifactory requires a different proxy to access it. Is there a way to configure Docker daemon to select proxy based on a URL? Or, if not, what else can I do to make this work?

1

There are 1 answers

0
Levi Haskell On BEST ANSWER

Since, as Pierre B. mentioned, Docker daemon does not support URL-based proxy selection, the solution is to point it to a local proxy configured to select the proper upstream proxy based on the URL.

While any HTTP[S] proxy capable of upstream selection would do, (pac4cli project being particularly interesting for it's advertised capability to select the upstream based on proxy-auto-discovery protocol used by most Web browsers a in corporate setting), I've chosen to use tinyproxy, as more mature and light-weight solution. Furthermore, I've decided to run my proxy inside the docker-machine VM in order to simplify it's deployment and make sure the proxy is always running when the Docker daemon needs it.

Below are the steps I used to set up my system. I'm especially grateful to phoenix for providing steps to set up Docker Toolbox on Windows behind a corporate proxy, and will borrow heavily from that answer.

From this point on I will assume either Docker Quickstart Terminal or GitBash, with docker in the PATH, as your command line console and that "username" is your Windows user name.

Step 1: Build tinyproxy on your target platform

Begin by pulling a clean Linux distribution, I used CentOS, and run bash inside it:

docker run -it --name=centos centos bash

Next, install the tools we'll need:

yum install -y make gcc

After that we pull the latest release of Tinyproxy from it's GitHub repository and extract it inside root's home directory (at the time of this writing the latest release was 1.10.0):

cd
curl -L https://github.com/tinyproxy/tinyproxy/releases/download/1.10.0/tinyproxy-1.10.0.tar.gz \
    | tar -xz
cd tinyproxy-1.10.0

Now let's configure and build it:

./configure --enable-upstream \
    --disable-filter\
    --disable-reverse\
    --disable-transparent\
    --disable-xtinyproxy
make

While --enable-upstream is obviously required, disabling other default features is optional but a good practice. To make sure it actually works run:

./src/tinyproxy -h

You should see something like:

Usage: tinyproxy [options]

Options are:
  -d        Do not daemonize (run in foreground).
  -c FILE   Use an alternate configuration file.
  -h        Display this usage information.
  -v        Display version information.

Features compiled in:
    Upstream proxy support

For support and bug reporting instructions, please visit
<https://tinyproxy.github.io/>.

We exit the container by pressing Ctrl+D and copy the executable to a special folder location accessible from the docker-machine VM:

docker cp centos://root/tinyproxy-1.10.0/src/tinyproxy \
    /c/Users/username/tinyproxy

Substitute "username" with your Windows user name. Please note that double slash — // before "root" is required to disable MINGW path conversion.

Now we can delete the container:

docker rm centos

Step 2: Point docker daemon to a local proxy port

Choose a TCP port number to run the proxy on. This can be any port that is not in use on the docker-machine VM. I will use number 8618 in this example.

First, let's delete the existing default Docker VM:
WARNING: This will permanently erase all currently stored containers and images

docker-machine rm -f default

Next, we re-create the default machine setting HTTP_PROXY and HTTPS_PROXY environment variables to the local host and the port we selected, and then refresh our shell environment:

docker-machine create default \
    --engine-env HTTP_PROXY=http://localhost:8618 \
    --engine-env HTTPS_PROXY=http://localhost:8618
eval $(docker-machine env)

Optionally, we could also set NO_PROXY environment variable to list hosts and/or wildcards (separated by ;) to which the daemon should connect directly, bypassing the proxy.

Step 3: Set up tinyproxy inside docker-machine VM

First, we will create two files in the /c/Users/username directory (this is where our tinyproxy binary should reside after Step 1 above) and then we'll copy them to the VM.

The first file is tinyproxy.conf, the exact syntax is documented on the Tinyproxy website, but the example below should have all the settings need:

# These settings can be customized to your liking,
# the port though must be the same we used in Step 2

listen 127.0.0.1
port 8618

user nobody
group nogroup
loglevel critical
syslog on

maxclients 50
startservers 2
minspareServers 2
maxspareServers 5

disableviaheader yes

# Here is the actual proxy selection, rules apply from top
# to bottom, and the last one is the default. More info on:
# https://tinyproxy.github.io/

upstream http proxy1.corp.example.com:80 ".foo.example.com"
upstream http proxy2.corp.example.com:80 ".bar.example.com"
upstream http proxy.corp.example.com:82

In the example above:

  • http://proxy1.corp.example.com:80 will be used to connect to URLs that end with "foo.example.com", such as http://www.foo.example.com
  • http://proxy2.corp.example.com:80 will be used to connect to URLs that end with "bar.example.com", such as http://www.bar.example.com, and
  • http://proxy.corp.example.com:80 will be used to connect all other URLs

It is also possible to match exact host names, IP addresses, subnets and hosts without domains.

The second file is as the shell script that will launch the proxy, its name must be bootlocal.sh:

#! /bin/sh

# Terminate on error
set -e

# Switch to the script directory
cd $(dirname $0)

# Launch proxy server
./tinyproxy -c tinyproxy.conf

Now, let's connect to the docker VM, get root, and switch to boot2docker directory:

docker-machine ssh
sudo -s
cd /var/lib/boot2docker

Next, we'll copy all three files over and a set their permissions:

cp /c/Users/username/boot2docker/{tinyproxy{,.conf},bootlocal.sh} .
chmod 755 tinyproxy bootlocal.sh
chmod 644 tinyproxy.conf

Exit VM session by pressing Ctrl+D twice and restart it:

docker-machine restart default

That's it! Now docker should be able pull and push images from different URLs automatically selecting the right proxy server.