Getting docker to pull images via a corporate proxy with AD authentication

The bulk of this post is from Mike Mylonakis and his blog post Using docker behind an http proxy with authentication. I'm writing my own post with my modifications to aid in my learning

The problem

At my place of work, all internet traffic must go via a proxy server, and all requests must include authentication.

Following the official documentation whenever I did a docker pull I get this error:-

Error response from daemon: Get https://registry-1.docker.io/v2/: proxyconnect tcp: dial tcp: lookup http: Temporary failure in name resolution

My environment

$ cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.4 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.4 LTS"
VERSION_ID="18.04"
$ sudo docker version
Client: Docker Engine - Community
 Version:           19.03.6
 API version:       1.40
 Go version:        go1.12.16
 Git commit:        369ce74a3c
 Built:             Thu Feb 13 01:27:49 2020
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.6
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.12.16
  Git commit:       369ce74a3c
  Built:            Thu Feb 13 01:26:21 2020
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.2.10
  GitCommit:        b34a5c8af56e510852c35414db4c1f4fa6172339
 runc:
  Version:          1.0.0-rc8+dev
  GitCommit:        3e425f80a8c931f88e6d94a8c831b9d5aa481657
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683
  

TLDR; Solution

The authentication system is backed by Microsoft Active Directory, so usernames are in the form domain\username. The \ (backslash) symbol is not interpreted by systemd on Ubuntu and escaping it/urlencoding it fails to work too. I need to put the environment variables in a file and get systemd to read that file; this way special characters can be used

Detail

Pre-reqs

  • Install Docker as per the usual documentation

Steps to fix

  1. Create a system default folder

    $ sudo mkdir -p /etc/system/default
    
  2. Create an environment file

    $ sudo nano /etc/system/default/docker.env
    
  3. Put the following in (replace the <> placeholders as required (note the %5C which is a urlencoded \ character)

    http_proxy="http://<domain>%5C<username>:<password>@<proxy address>:<port>/"
    
  4. Create a systemd drop-in directory for the docker service:

    $ sudo mkdir -p /etc/systemd/system/docker.service.d
    
  5. Create a file called /etc/systemd/system/docker.service.d/environment.conf that specifies the EnvironmentFile location:

    [Service]
    EnvironmentFile=/etc/system/default/docker.env
    
  6. Reload the systemd and docker to pick up the new config

    $ sudo systemctl daemon-reload && sudo systemctl restart docker
    
  7. Check the environment variables for the running dockerd process

    $ sudo cat /proc/$(pgrep dockerd)/environ | tr '\0' '\n'
    

Extra notes

As systemd controls the startup of the docker daemon, I initially followed the docker official documentation to set the http_proxy environment variable for the docker daemon process. When this clearly wasn't working (a tcpdump showed me traffic from my machine was going direct to docker.io during docker pull and related commands), I hit the web search and came upon Mike Mylonakis and his blog post Using docker behind an http proxy with authentication, without which I would not have figured this out.