Thursday, June 29, 2017

Using Docker behind a proxy

Proxies directly affect three independent aspects of Docker's operation: 
  1. Docker daemon: for interacting with public repositories (e.g. `docker pull`)
  2. Image building: building images via the Docker client almost always requires remote artifacts (e.g. package managers, build tools, curl)
  3. Container runtime: running containers requiring internet access

Each of these aspects requires particular measures to operate correctly behind a proxy. The following sections explain configuration procedures for each of them.

Docker daemon

Docker daemon requires network access for pulling and pushing images from/to public repositories. To operate behind a proxy, the daemon must receive proxy settings as described below (applies to CentOS and related distributions -- for others, see applicable documentation).

Despite some claims in StackOverflow and other sites, Docker does not accept proxy configs in `/etc/docker/daemon.json` (https://docs.docker.com/engine/admin/systemd/#httphttps-proxy). Proxy variables must be set in the systemd startup configs for the service.

To update the daemon's proxy configuration, edit/create `proxy.conf` with your proxy settings, reload the configuration and restart the daemon:

sudo mkdir /etc/systemd/system/docker.service.d # not present by default

cat <<EOF > /etc/systemd/system/docker.service.d/proxy.conf
[Service]
Environment="HTTP_PROXY=http://your.proxy:3128/" "HTTPS_PROXY=https://your.proxy:3128/" "NO_PROXY=localhost,127.0.0.1,docker-registry.yourdomain.net"
EOF

sudo systemctl daemon-reload && sudo systemctl restart docker

The changes above will allow the daemon to access public registries to perform pull operations to retrieve images.

Image building

Image builds specified in Dockerfiles virtually always contain access operations on public resources, be it through curl, yum, npm or similar tools. For these operations to work behind a proxy, the container's build context must provide correct proxy settings.

The simplest but least flexible option is to hardcode proxy settings in your Dockerfile:


ENV http_proxy http://<PROXY_HOST>:<PORT>
ENV https_proxy https://
<PROXY_HOST>:<PORT>

Notice both HTTP and HTTPS values are specified to ensure both protocols are configured. Replace <PROXY_HOST> and <PORT> with your network's proxy settings, e.g. `https://proxy.my-domain:3128`.

Many Linux applications will honor the `http(s?)_proxy` variable (e.g. curl, wget, many http client libraries for Python, Ruby and other scripted languages). There are, however, exceptions and irregularities in this area. See the documentation for the particular tool you intend to use. The CentOS package manager, yum, for example, requires explicit configuration via `/etc/yum.conf`. To allow yum to access packages during image building, include the following entries in your Dockerfile before the first invocation of yum:

RUN echo "http_proxy=http://proxy.my-domain:3128" >> /etc/yum.conf
RUN echo "https_proxy=https://proxy.my-domain:3128" >> /etc/yum.conf
# Make sure YUM proxy is set up first
RUN yum update -y && yum install curl