Cómo configurar el proxy en Docker para construir imágenes

Los que trabajamos en grandes empresas o administraciones públicas sufrimos a menudo para configurar herramientas para que usen el proxy corporativo. Si ya el proxy tiene autenticación CNTLM se puede dedicar un día entero a estar haciendo pruebas.

Por ello, voy a explicar todos los pasos necesarios para configurar Docker de modo que podamos ejecutar contenedores y construir imágenes pasando a través del proxy. El tutorial está probado en un equipo con Linux Mint 18.1 (cualquier sistema operativo con systemctl debería funcionar), Docker 17.06.0-ce y proxy sin autenticación HTTP (si tu proxy es más complejo, te recomiendo instalarte cntlm).

Los pasos necesarios son:

  • Crear un fichero de configuración para el servicio systemctl en el que especifiquemos la URL del proxy y el servidor de DNS corporativo.
  • Al ejecutar un contenedor, pasarle el proxy por parámetro
  • Utilizar el parámetro “–build-arg” para pasarle el proxy al contexto de la imagen que queremos construir.

Configurar el proxy y DNS para el servicio

Para ello, basta con crear un fichero /etc/systemd/system/docker.service.d/custom.conf en el que incluir:

# Ponemos las IPs de los servidores DNS en el arrranque del demonio
ExecStart=
ExecStart=/usr/bin/dockerd --dns $IP_DNS_1 --dns $IP_DNS_2 -H fd://

# Configuramos el proxy y las excepciones
Environment="HTTP_PROXY=http://$IP_PROXY:$PUERTO_PROXY/"
Environment="HTTPS_PROXY=http://$IP_PROXY:$PUERTO_PROXY/"
Environment="NO_PROXY=$EXCEPCIONES_SEPARADAS_POR_COMAS"

Tras ello, hay que recargar la configuración y reiniciar el demonio:

sudo systemctl daemon-reload
sudo systemctl restart docker

Con estos pasos el demonio docker de nuestro equipo ya puede acceder a Internet, lo que podemos comprobar con un docker info

$ docker info
Containers: 0
 Running: 0
 Paused: 0
 Stopped: 0
Images: 15
Server Version: 17.06.0-ce
Storage Driver: aufs
 Root Dir: /var/lib/docker/aufs
 Backing Filesystem: extfs
 Dirs: 38
 Dirperm1 Supported: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins: 
 Volume: local
 Network: bridge host macvlan null overlay
 Log: awslogs fluentd gcplogs gelf journald json-file logentries splunk syslog
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: cfb82a876ecc11b5ca0977d1733adbe58599088a
runc version: 2d41c047c83e09a6d61d464906feb2a2f3c52aa4
init version: 949e6fa
Security Options:
 apparmor
 seccomp
  Profile: default
Kernel Version: 4.4.0-53-generic
Operating System: Linux Mint 18.1
OSType: linux
Architecture: x86_64
CPUs: 4
Total Memory: 7.68GiB
Name: areig
ID: G7MN:ZZNU:DA3A:DQJK:KCXL:DCI6:66JT:XAPC:PWVS:XMCN:DGPC:7U6B
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Http Proxy: http://proxy-XXXXX:8080/
Https Proxy: http://proxy-XXXXX:8080/
No Proxy: localhost,127.0.0.1,XXXXXX
Registry: https://index.docker.io/v1/
Experimental: false
Insecure Registries:
 127.0.0.0/8
Live Restore Enabled: false

O descargando una imagen:

$docker pull hello-world
Using default tag: latest
latest: Pulling from library/hello-world
b04784fba78d: Pull complete 
Digest: sha256:f3b3b28a45160805bb16542c9531888519430e9e6d6ffc09d72261b0d26ff74f
Status: Downloaded newer image for hello-world:latest

Probar la configuración al ejecutar un contenedor

Sin embargo, si ejecutamos un comando en un contenedor vemos que no llega:

$ docker run --rm  phpdockerio/php7-fpm curl -v https://www.google.es/
* Hostname was NOT found in DNS cache
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying 108.177.119.94...
*   Trying 2a00:1450:4013:c02::5e...
* Immediate connect fail for 2a00:1450:4013:c02::5e: Cannot assign requested address
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying 2a00:1450:4013:c02::5e...

El error parece apuntar a un problema de DNS, pero si miramos el resolv.conf está correcto:

docker run --rm  phpdockerio/php7-fpm cat /etc/resolv.conf
nameserver $LA_IP_DNS_CONFIGURADA_PREVIAMENTE_1
nameserver $LA_IP_DNS_CONFIGURADA_PREVIAMENTE_1

En cambio, si buscamos el proxy no está configurado:

$ docker run --rm  phpdockerio/php7-fpm env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=d16664b545e8
TERM=linux
HOME=/root

Por lo que la conclusión es: los contenedores “heredan” la configuración DNS del host, pero no el proxy. Por ello, hay que pasarla explícitamente. Desde línea de comando, con el flag –env:

docker run --rm --env http_proxy=http://XXXXX --env https_proxy=http://YYYYY phpdockerio/php7-fpm curl https://www.google.es/
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="es"><head><meta content="Google.es permite acceder a la informacion mundial en castellano, catalan, gallego, euskara e ingles." name="description"><meta content="noodp" name="robots"><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"><meta content="/images/branding/googleg/1x/googleg_standard_color_128dp.png" itemprop="image"><title>Google</title><script>(function(){window.google=

Si estuviéramos usando docker-compose, habría que utilizar la opción environment.

Probar la configuración al construir una imagen

Falta comprobar que podemos construir imágenes. Vamos a hacer la prueba con un Dockerfile sencillo:

FROM phpdockerio/php7-fpm:latest

# Test conection
RUN curl -v https://www.google.es/
# Install selected extensions and other stuff
RUN apt-get update \
&& curl -sL https://deb.nodesource.com/setup_6.x | bash - \
&& apt-get -y --no-install-recommends install  php7.0-memcached php7.0-mysql php7.0-mbstring php7.0-xdebug git zip unzip nodejs \
&& apt-get clean; rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*


WORKDIR "/var/www/"

Al tratar de construir esa imagen, volvemos a no llegar a Internet:

$ docker build . -t prueba
Sending build context to Docker daemon  3.072kB
Step 1/4 : FROM phpdockerio/php7-fpm:latest
 ---> b0418cd41732
Step 2/4 : RUN curl -v https://www.google.es/
 ---> Running in 95d9f5d7d462
* Hostname was NOT found in DNS cache
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying 74.125.128.94...
*   Trying 2a00:1450:4009:807::2003...
* Immediate connect fail for 2a00:1450:4009:807::2003: Cannot assign requested address

La solución es la misma que antes, hay que especificar el proxy en el contexto de la creación de la imagen. Eso lo podemos hacer especificando la variable de entorno en el Dockerfile con el flag ENV, o por linea de comando con el flag –build-arg:

docker build -t prueba --build-arg http_proxy="http://XXXX" --build-arg https_proxy="http://XXXX" --build-arg HTTP_PROXY="http://XXXX" --build-arg HTTPS_PROXY="http://XXXX" .
Sending build context to Docker daemon  3.072kB
Step 1/4 : FROM phpdockerio/php7-fpm:latest
 ---> b0418cd41732
Step 2/4 : RUN curl https://www.google.es/
 ---> Running in 635b8d0b632e
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="es"><head><meta content="Google.es permite acceder a la informaci�n mundial en castellano, catal�n, gallego, euskara e ingl�s." name="description"><meta content="noodp" name="robots"><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"><meta content="/images/branding/googleg/1x/googleg_standard_color_128dp.png" itemprop="image"><title>Google</title><script>(functio (etc....)
 ---> 92e6fb39a745
Removing intermediate container 635b8d0b632e
Step 3/4 : RUN apt-get update && curl -sL https://deb.nodesource.com/setup_6.x | bash - && apt-get -y --no-install-recommends install  php7.0-memcached php7.0-mysql php7.0-mbstring php7.0-xdebug git zip unzip nodejs && apt-get clean; rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*
 ---> Running in edfd74289096
Get:1 http://packages.dotdeb.org jessie InRelease [9839 B]
Get:2 http://security.debian.org jessie/updates InRelease [63.1 kB]
Ign http://deb.debian.org jessie InRelease
Get:3 http://deb.debian.org jessie-updates InRelease [145 kB]
Get:4 http://deb.debian.org jessie Release.gpg [2373 B]

Comprobamos que tanto el curl como el apt-get funcionan correctamente. Como cada software busca la configuración del proxy dónde le parece, he especificado la clave tanto en mayúsculas como en minúsculas (http_proxy, HTTP_PROXY). Tampoco hubiera sido raro que apt-get no consiguiera llegar, en ese caso dentro del Dockerfile hubiéramos especificado la configuración del proxy en un archivo personalizado, por ejemplo:

cat /etc/apt/apt.conf.d/99proxy 
Acquire::http::Proxy "http://YYYY";
Acquire::https::Proxy "http://XXXXX";

Con estos pasos no debería darnos mayores problemas.

Publicado en tutoriales Etiquetado con: , , ,

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

*