Skip to content

labcabrera/docker-apache2-sample-app

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Ejempos de proxy inverso en contenedores docker

Este proyecto contiene varios ejemplos utilizando docker del uso de Apache2 como proxy inverso de nuestras aplicaciones.

El primer ejemplo consistirá en exponer por el puerto 80 una aplicacion que escucha por HTTP en el puerto 8080. En el segundo expondremos una aplicacion que internamente utiza HTTPS para exponerla por el puerto 443. En el tercero utilizaremos el módulo de caché de contenidos.

Ejemplo usando HTTP

Ejemplo sencillo de como configurar una imagen docker para exponer una aplicación ejecutándose en el puerto 8080 a través de apache por el puerto 80

Para ello en primer lugar generamos el Dockerfile a partir de una imagen de debian

FROM debian:8.10

Instalamos apache2 junto con el módulo mod_proxy y ruby para hacer de servidor de aplicación en el puerto 8080. Despues simplemente activamos el módulo y generamos la configuración de apache en /etc/apache2/sites-enabled/000-default.conf.

Finalmente en el script de arranque arrancamos el servicio de apache2 e iniciamos nuestro servidor de ejemplo a través del script entrypoint.sh:

ruby -run -e httpd /opt/sample-app -p 8080

Desplegando localmente la imagen

En primer lugar ejecutaremos el script docker-create-image.sh que generará la imagen:

docker run \
  --interactive \
  --tty \
  --name $IMAGE_NAME \
  --hostname $IMAGE_NAME \
  --publish 80:80 \
  $IMAGE_USER/$IMAGE_NAME:${IMAGE_VERSION}

Una vez generada la imagen la arrancaremos con el script docker-create-container.sh

docker run \
  --interactive \
  --tty \
  --name $IMAGE_NAME \
  --hostname $IMAGE_NAME \
  --publish 80:80 \
  $IMAGE_USER/$IMAGE_NAME:${IMAGE_VERSION}

Si todo ha ido bien podremos acceder a nuestra aplicación: http://localhost/

Configuración de apache

En este ejemplo el fichero de configuración de apache es:

<VirtualHost *:*>
    ProxyPreserveHost On
    ProxyPass / http://0.0.0.0:8080/
    ProxyPassReverse / http://0.0.0.0:8080/
    ServerName localhost
</VirtualHost>

Ejecutando la imagen a través de un proxy

En este caso hemos creado dos argumentos IMAGE_PROXY y IMAGE_NO_PROXY en nuestra imagen para aquellos casos en los que no tengamos salida directa a internet de tal modo que podremos generar la imagen pasando estos parámetros:

--build-arg IMAGE_PROXY=$PROXY \
--build-arg IMAGE_NO_PROXY=$NO_PROXY \

Ejemplo usando HTTPS

En el segundo ejemplo expondremos un microservicio que escucha en el puerto 9009 usando su propia configuración de SSL.

En este caso es una aplicación Spring Boot de ejemplo (https://github.com/labcabrera/http-network-diagnostic/).

Básicamente es igual que la anterior exceptuando que la imagen la hemos generado a partir de

FROM openjdk:8u151-jdk

para evitar instalar la JDK. Después tendremos que copiar el certificado y la clave privada para la configuración de SSL de apache. También cambiaremos nuestro entrypoint.sh para tener:

java -jar /opt/sample-app/http-network-diagnostic-1.0.3.jar

Configuración de apache

En este ejemplo el fichero de configuración de apache es:

<VirtualHost *:443>
  ServerName localhost

  SSLEngine On
  SSLProxyEngine On
  SSLProxyCheckPeerCN Off
  SSLCertificateFile	/root/certificate.pem
  SSLCertificateKeyFile /root/key.pem

  ProxyRequests Off
  ProxyPreserveHost On
  ProxyPass / https://0.0.0.0:9009/
  ProxyPassReverse / https://0.0.0.0:9009/

  <Location />
    ProxyPassReverse /
    Options FollowSymLinks
    Require all granted
  </Location>

</VirtualHost>

Si accedemos a https://localhost veremos la página de Swagger de nuestra aplicación.

Ejemplo utilizando disk cache

Este ejemplo es una extensión de la segunda imagen en la que utilizaremos la cache en disco para servir el contenido estático (en este ejemplo serán los recursos de webjars) y evitando el uso de la caché en las llamadas a la API REST.

Para ello instalaremos el módulo cache_disk y lo activaremos a través del comando:

a2enmod cache_disk

Después modificaremos nuestro fichero de configuración de apache para incluir la siguiente configuración:

CacheHeader on
CacheEnable disk /webjars
CacheDisable "/api"
CacheQuickHandler off
CacheLock On
CacheRoot /tmp/cache/mod_cache
CacheLockPath /tmp/cache/mod_cache_lock
CacheIgnoreCacheControl On
CacheMaxFileSize 100000000
CacheIgnoreNoLastMod On
CacheMaxExpire 1209600
CacheIgnoreQueryString Off

Y activaremos este módulo para nuestro proxy inverso con la aplicación de Ruby que ejecutamos localmente:

<Location "/">
  ...
  CacheEnable disk
  CacheHeader on
</Location>

Al arrancar la imagen podremos comprobar el funcionamiento realizando peticiones a:

Si entramos en el contenedor veremos que ha creado la siguiente estructura de directorios:

root@apache-sample-cache:/tmp/cache# tree .
.
├── mod_cache
│   ├── 0D
│   │   └── @R
│   │       ├── A48aZby4l4TdtVbwdA.header
│   │       └── A48aZby4l4TdtVbwdA.header.vary
│   │           └── 1k
│   │               └── cF
│   │                   ├── 9cMtUUJYyh4n5gv39Q.data
│   │                   └── 9cMtUUJYyh4n5gv39Q.header
│   ├── 7T
│   │   └── @A
│   │       ├── Ddpii7mknOHLaj4umw.header
│   │       └── Ddpii7mknOHLaj4umw.header.vary
│   │           └── 9N
│   │               └── TK
│   │                   ├── 0YcoBvhzQwYfN3SosA.data
│   │                   └── 0YcoBvhzQwYfN3SosA.header
│   ├── Bs
│   │   └── 0p
│   │       ├── _wNe0@Rarv4M3JXWUQ.header
│   │       └── _wNe0@Rarv4M3JXWUQ.header.vary
│   │           └── mh
...

Y como hemos establecido el log a nivel de debug comprobaremos que al servir las peticiones recurre a la caché en lugar de realizar la llamada:

curl --insecure https://localhost/webjars/springfox-swagger-ui/swagger-ui-bundle.js

Primera llamada:

[Thu May 03 13:03:10.516389 2018] [ssl:info] [pid 1067:tid 139630301136640] [client 172.17.0.1:49168] AH01964: Connection to child 10 established (server localhost:443)
[Thu May 03 13:03:10.516584 2018] [ssl:debug] [pid 1067:tid 139630301136640] ssl_engine_kernel.c(2115): [client 172.17.0.1:49168] AH02043: SSL virtual host for servername localhost found
[Thu May 03 13:03:10.516612 2018] [ssl:debug] [pid 1067:tid 139630301136640] ssl_engine_kernel.c(2115): [client 172.17.0.1:49168] AH02043: SSL virtual host for servername localhost found
[Thu May 03 13:03:10.516617 2018] [core:debug] [pid 1067:tid 139630301136640] protocol.c(2219): [client 172.17.0.1:49168] AH03155: select protocol from , choices=h2,http/1.1 for server localhost
[Thu May 03 13:03:10.518709 2018] [socache_shmcb:debug] [pid 1067:tid 139630301136640] mod_socache_shmcb.c(495): AH00831: socache_shmcb_store (0x9d -> subcache 29)
[Thu May 03 13:03:10.518732 2018] [socache_shmcb:debug] [pid 1067:tid 139630301136640] mod_socache_shmcb.c(849): AH00847: insert happened at idx=0, data=(0:32)
[Thu May 03 13:03:10.518737 2018] [socache_shmcb:debug] [pid 1067:tid 139630301136640] mod_socache_shmcb.c(854): AH00848: finished insert, subcache: idx_pos/idx_used=0/1, data_pos/data_used=0/193
[Thu May 03 13:03:10.518741 2018] [socache_shmcb:debug] [pid 1067:tid 139630301136640] mod_socache_shmcb.c(516): AH00834: leaving socache_shmcb_store successfully
[Thu May 03 13:03:10.518751 2018] [ssl:debug] [pid 1067:tid 139630301136640] ssl_engine_kernel.c(2042): [client 172.17.0.1:49168] AH02041: Protocol: TLSv1.2, Cipher: ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
[Thu May 03 13:03:10.518937 2018] [ssl:debug] [pid 1067:tid 139630301136640] ssl_engine_kernel.c(366): [client 172.17.0.1:49168] AH02034: Initial (No.1) HTTPS request received for child 10 (server localhost:443)
[Thu May 03 13:03:10.518962 2018] [authz_core:debug] [pid 1067:tid 139630301136640] mod_authz_core.c(809): [client 172.17.0.1:49168] AH01626: authorization result of Require all granted: granted
[Thu May 03 13:03:10.518969 2018] [authz_core:debug] [pid 1067:tid 139630301136640] mod_authz_core.c(809): [client 172.17.0.1:49168] AH01626: authorization result of <RequireAny>: granted
[Thu May 03 13:03:10.518995 2018] [cache:debug] [pid 1067:tid 139630301136640] cache_storage.c(666): [client 172.17.0.1:49168] AH00698: cache: Key for entity /webjars/springfox-swagger-ui/swagger-ui-bundle.js?(null) is https://localhost:443/webjars/springfox-swagger-ui/swagger-ui-bundle.js?
[Thu May 03 13:03:10.519106 2018] [cache:debug] [pid 1067:tid 139630301136640] mod_cache.c(507): [client 172.17.0.1:49168] AH00757: Adding CACHE_SAVE filter for /webjars/springfox-swagger-ui/swagger-ui-bundle.js
[Thu May 03 13:03:10.519112 2018] [cache:debug] [pid 1067:tid 139630301136640] mod_cache.c(541): [client 172.17.0.1:49168] AH00759: Adding CACHE_REMOVE_URL filter for /webjars/springfox-swagger-ui/swagger-ui-bundle.js
[Thu May 03 13:03:10.519120 2018] [proxy:debug] [pid 1067:tid 139630301136640] mod_proxy.c(1228): [client 172.17.0.1:49168] AH01143: Running scheme https handler (attempt 0)
[Thu May 03 13:03:10.519124 2018] [proxy_ajp:debug] [pid 1067:tid 139630301136640] mod_proxy_ajp.c(738): [client 172.17.0.1:49168] AH00894: declining URL https://0.0.0.0:9009/webjars/springfox-swagger-ui/swagger-ui-bundle.js
[Thu May 03 13:03:10.519130 2018] [proxy:debug] [pid 1067:tid 139630301136640] proxy_util.c(2156): AH00942: HTTPS: has acquired connection for (0.0.0.0)
[Thu May 03 13:03:10.519134 2018] [proxy:debug] [pid 1067:tid 139630301136640] proxy_util.c(2209): [client 172.17.0.1:49168] AH00944: connecting https://0.0.0.0:9009/webjars/springfox-swagger-ui/swagger-ui-bundle.js to 0.0.0.0:9009
[Thu May 03 13:03:10.519139 2018] [proxy:debug] [pid 1067:tid 139630301136640] proxy_util.c(2418): [client 172.17.0.1:49168] AH00947: connected /webjars/springfox-swagger-ui/swagger-ui-bundle.js to 0.0.0.0:9009
[Thu May 03 13:03:10.519220 2018] [proxy:debug] [pid 1067:tid 139630301136640] proxy_util.c(2716): AH00951: HTTPS: backend socket is disconnected.
[Thu May 03 13:03:10.519269 2018] [proxy:debug] [pid 1067:tid 139630301136640] proxy_util.c(2884): AH02824: HTTPS: connection established with 0.0.0.0:9009 (0.0.0.0)
[Thu May 03 13:03:10.519280 2018] [proxy:debug] [pid 1067:tid 139630301136640] proxy_util.c(3051): AH00962: HTTPS: connection complete to 0.0.0.0:9009 (0.0.0.0)
[Thu May 03 13:03:10.519285 2018] [ssl:info] [pid 1067:tid 139630301136640] [remote 127.0.0.1:9009] AH01964: Connection to child 0 established (server localhost:443)
[Thu May 03 13:03:10.530140 2018] [ssl:debug] [pid 1067:tid 139630301136640] ssl_engine_kernel.c(1568): [remote 127.0.0.1:9009] AH02275: Certificate Verification, depth 0, CRL checking mode: none (0) [subject: emailAddress=lab.cabrera@gmail.com,CN=training,OU=Arquitectura,O=Mapfre,L=Majadahonda,ST=Madrid,C=ES / issuer: emailAddress=lab.cabrera@gmail.com,CN=training,OU=Arquitectura,O=Mapfre,L=Majadahonda,ST=Madrid,C=ES / serial: C7ED840F041E1CE9 / notbefore: Mar  6 09:33:04 2018 GMT / notafter: Mar  6 09:33:04 2019 GMT]
[Thu May 03 13:03:10.530195 2018] [ssl:debug] [pid 1067:tid 139630301136640] ssl_engine_kernel.c(1568): [remote 127.0.0.1:9009] AH02275: Certificate Verification, depth 0, CRL checking mode: none (0) [subject: emailAddress=lab.cabrera@gmail.com,CN=training,OU=Arquitectura,O=Mapfre,L=Majadahonda,ST=Madrid,C=ES / issuer: emailAddress=lab.cabrera@gmail.com,CN=training,OU=Arquitectura,O=Mapfre,L=Majadahonda,ST=Madrid,C=ES / serial: C7ED840F041E1CE9 / notbefore: Mar  6 09:33:04 2018 GMT / notafter: Mar  6 09:33:04 2019 GMT]
[Thu May 03 13:03:10.535345 2018] [ssl:debug] [pid 1067:tid 139630301136640] ssl_engine_kernel.c(2042): [remote 127.0.0.1:9009] AH02041: Protocol: TLSv1.2, Cipher: ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
[Thu May 03 13:03:10.644012 2018] [cache:debug] [pid 1067:tid 139630301136640] mod_cache.c(1348): [client 172.17.0.1:49168] AH00769: cache: Caching url https://localhost:443/webjars/springfox-swagger-ui/swagger-ui-bundle.js? for request /webjars/springfox-swagger-ui/swagger-ui-bundle.js
[Thu May 03 13:03:10.644039 2018] [cache:debug] [pid 1067:tid 139630301136640] mod_cache.c(1354): [client 172.17.0.1:49168] AH00770: cache: Removing CACHE_REMOVE_URL filter.
[Thu May 03 13:03:10.698260 2018] [proxy:debug] [pid 1067:tid 139630301136640] proxy_util.c(2171): AH00943: https: has released connection for (0.0.0.0)
[Thu May 03 13:03:10.699740 2018] [cache_disk:debug] [pid 1067:tid 139630301136640] mod_cache_disk.c(1362): [client 172.17.0.1:49168] AH00737: commit_entity: Headers and body for URL https://localhost:443/webjars/springfox-swagger-ui/swagger-ui-bundle.js? cached.
[Thu May 03 13:03:10.813555 2018] [ssl:debug] [pid 1067:tid 139630292743936] ssl_engine_io.c(1044): [client 172.17.0.1:49168] AH02001: Connection closed to child 11 with standard shutdown (server localhost:443)

Llamadas posteriores:

[Thu May 03 13:03:40.514172 2018] [ssl:info] [pid 1068:tid 139630292743936] [client 172.17.0.1:49176] AH01964: Connection to child 75 established (server localhost:443)
[Thu May 03 13:03:40.514372 2018] [ssl:debug] [pid 1068:tid 139630292743936] ssl_engine_kernel.c(2115): [client 172.17.0.1:49176] AH02043: SSL virtual host for servername localhost found
[Thu May 03 13:03:40.514399 2018] [ssl:debug] [pid 1068:tid 139630292743936] ssl_engine_kernel.c(2115): [client 172.17.0.1:49176] AH02043: SSL virtual host for servername localhost found
[Thu May 03 13:03:40.514404 2018] [core:debug] [pid 1068:tid 139630292743936] protocol.c(2219): [client 172.17.0.1:49176] AH03155: select protocol from , choices=h2,http/1.1 for server localhost
[Thu May 03 13:03:40.516630 2018] [socache_shmcb:debug] [pid 1068:tid 139630292743936] mod_socache_shmcb.c(495): AH00831: socache_shmcb_store (0x30 -> subcache 16)
[Thu May 03 13:03:40.516658 2018] [socache_shmcb:debug] [pid 1068:tid 139630292743936] mod_socache_shmcb.c(849): AH00847: insert happened at idx=0, data=(0:32)
[Thu May 03 13:03:40.516663 2018] [socache_shmcb:debug] [pid 1068:tid 139630292743936] mod_socache_shmcb.c(854): AH00848: finished insert, subcache: idx_pos/idx_used=0/1, data_pos/data_used=0/193
[Thu May 03 13:03:40.516673 2018] [socache_shmcb:debug] [pid 1068:tid 139630292743936] mod_socache_shmcb.c(516): AH00834: leaving socache_shmcb_store successfully
[Thu May 03 13:03:40.516684 2018] [ssl:debug] [pid 1068:tid 139630292743936] ssl_engine_kernel.c(2042): [client 172.17.0.1:49176] AH02041: Protocol: TLSv1.2, Cipher: ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
[Thu May 03 13:03:40.516868 2018] [ssl:debug] [pid 1068:tid 139630292743936] ssl_engine_kernel.c(366): [client 172.17.0.1:49176] AH02034: Initial (No.1) HTTPS request received for child 75 (server localhost:443)
[Thu May 03 13:03:40.516892 2018] [authz_core:debug] [pid 1068:tid 139630292743936] mod_authz_core.c(809): [client 172.17.0.1:49176] AH01626: authorization result of Require all granted: granted
[Thu May 03 13:03:40.516897 2018] [authz_core:debug] [pid 1068:tid 139630292743936] mod_authz_core.c(809): [client 172.17.0.1:49176] AH01626: authorization result of <RequireAny>: granted
[Thu May 03 13:03:40.516923 2018] [cache:debug] [pid 1068:tid 139630292743936] cache_storage.c(666): [client 172.17.0.1:49176] AH00698: cache: Key for entity /webjars/springfox-swagger-ui/swagger-ui-bundle.js?(null) is https://localhost:443/webjars/springfox-swagger-ui/swagger-ui-bundle.js?
[Thu May 03 13:03:40.516981 2018] [cache_disk:debug] [pid 1068:tid 139630292743936] mod_cache_disk.c(573): [client 172.17.0.1:49176] AH00709: Recalled cached URL info header https://localhost:443/webjars/springfox-swagger-ui/swagger-ui-bundle.js?
[Thu May 03 13:03:40.516988 2018] [cache_disk:debug] [pid 1068:tid 139630292743936] mod_cache_disk.c(897): [client 172.17.0.1:49176] AH00720: Recalled headers for URL https://localhost:443/webjars/springfox-swagger-ui/swagger-ui-bundle.js?
[Thu May 03 13:03:40.517000 2018] [cache:debug] [pid 1068:tid 139630292743936] mod_cache.c(656): [client 172.17.0.1:49176] AH00763: cache: running CACHE_OUT filter
[Thu May 03 13:03:40.517004 2018] [cache:debug] [pid 1068:tid 139630292743936] mod_cache.c(683): [client 172.17.0.1:49176] AH00764: cache: serving /webjars/springfox-swagger-ui/swagger-ui-bundle.js
[Thu May 03 13:03:40.721677 2018] [ssl:debug] [pid 1068:tid 139630284351232] ssl_engine_io.c(1044): [client 172.17.0.1:49176] AH02001: Connection closed to child 76 with standard shutdown (server localhost:443)

En cambio tenemos que asegurarnos que las llamadas a la API no están cacheadas para lo cual podemos probar el servicio REST que devuelve la fecha del sistema:

curl --insecure https://localhost/api/date

Obteniendo los siguientes resultados:

$ curl --insecure https://localhost/api/date
"2018-05-03T13:04:15.947+0000"
$ curl --insecure https://localhost/api/date
"2018-05-03T13:04:16.857+0000"
$ curl --insecure https://localhost/api/date
"2018-05-03T13:04:17.440+0000"
$ curl --insecure https://localhost/api/date
"2018-05-03T13:04:18.163+0000"
$ curl --insecure https://localhost/api/date
"2018-05-03T13:04:19.424+0000"

Para tener controlada nuestra cache podemos utilizar el binario htcacheclean que se encarga periodicamente de controlar el tamaño de nuestra caché:

$ htcacheclean -t -n -d1 -p /tmp/cache/mod_cache -l4000M
$ ps -fea | grep cache
root       156     0  0 09:43 ?        00:00:00 htcacheclean -t -n -d1 -p /tmp/cache/mod_cache -l4000M
root       158   106  0 09:44 pts/1    00:00:00 grep cache

Para saber más consultar la documentación oficial:

Releases

No releases published

Packages

No packages published