Geoserver en entorno de producción (VI): Cacheando mediante MapProxy

Logo MapProxy

Si os fijáis, tener un servidor de mapas no es “ligero”, ya que por defecto, genera todas la capas al vuelo, reproyecta y cambia de formato… ¡Aunque pidamos dos veces lo mismo!.
Por lo tanto: usa mucha cantidad de CPU, memoria y incluso disco. Si pensamos en subirlo a la nube, y usar el Amazon para servir tus mapas, por poner un ejemplo, tendrías que pensar en controlar mucho el consumo  y de no encontrarnos con alguna sorpresa en la factura de algún mes.

Pero esto tiene solución, claro. La idea es cachear el trabajo, y lo vamos a hacer mediante un servicio de proxy geoespacial que guardará los mapas generados para no tener que volver a generarlos y gastar tiempo/recursos. Para esta tarea, usaré “MapProxy ya que es el desarrollo mas maduro y versátil que he encontrado. Está montado sobre Python, y su montaje es “relativamente” sencillo, si tienes una buena guía, como esta, por ejemplo.

Preparar el entorno

Empecemos, vamos a instalar todo lo necesario para empezar. Utilizaremos nuestro querido “apt-get” para bajar todas la librerías que necesitamos.

sudo aptitude install python-imaging python-yaml libproj0 libgeos-dev python-lxml libgdal1-dev python-shapelyy build-essential python-dev libjpeg-dev zlib1g-dev libfreetype6-dev

Aparte, bajamos la herramienta de creación de un entorno independiente de Python. ¿Que hace esto?, pues generar un entorno virtual Python dentro de un entorno real de Python, para que nos entendamos, tener siempre una versión de Python, aunque en el sistema este cambie.

wget https://raw.github.com/pypa/virtualenv/1.7.1.2/virtualenv.py

Creamos el entorno virtual, y le damos permisos para poder escribir sin ser root. Este paso no es necesario, pero es muy cómo para trabajar desde cualquier usuario normal.

virtualenv /var/local/mapproxy/venv
chmod ugo+x -R /var/local/mapproxy/venv

En este momento ya disponemos de un entorno virtual Python, y se encuentra dentro de “/var/local/mapproxy“, y lo usaremos  para trabajar e instalar MapProxy.

Para activarlo (esto significa que usaremos el Python virtual, no el real), tendremos que ejecutar el comando “source“. Si no hacemos este paso, será como si no existieran todas las herramientas que vamos instalar posteriormente. Por lo tanto este paso es muy importante.

source /var/local/mapproxy/venv/bin/activate
# Fijate como ha cambiado el prompt, y nos indica que estamos en un "venv" o entorno virtual.
(venv)admin@svrmapas:~$
# Si queremos salir del entorno virtual, NO lo uses aun, usa este comando:
deactivate

Usando PyIP para dejar nuestro Python perfecto

Este herramienta, que en adelante llamaremos PIP, es como el “apt-get” pero solo para Python. Es muy sencilla de usar, y de verdad, nos facilitará la instalación de todas las librerías Python. Pasemos a instalar todas las librerías:

pip install https://bitbucket.org/olt/pil-2009-raclette/get/default.tar.gz # Para uso avanzado de PNG
pip install flup # Servidor fcgi
pip install MapProxy
# Si MapProxy necesita dependencias que no tienes, se las bajará.
# Esto puede tardar.

Configuración básica para MapProxy y test del servicio

Ahora creamos una configuración por defecto para MapProxy. Esto es una configuración por defecto que consulta unos mapas (creo recordar que del OpenStreetMap, pero no estoy seguro) y nos sirve para testar que nuestra instalación de MapProxy funciona. No voy a entrar mucho más allá, pero puedes consultar el manual de MapProxy para configurarlo.

mapproxy-util create -t base-config /var/local/mapproxy

Vale, tenemos la configuración básica, pero quiero ver algo. La gente de MapProxy son muy listos y nos permiten lanzar un servicio de test, solo usando herramientas de Python.

cd /var/local/mapproxy
# Yo le he pasado la ip y el puerto de escucha ya que tengo un Tomcat
# escuchando por el puerto 8080 que es el defecto que usa.
mapproxy-util serve-develop -b 192.168.0.100:8081 mapproxy.yaml

Con este comando, tendremos un servidor escuchando por el puerto 8081, es decir se podrá acceder a dicha cache mediante la URL:

http://192.168.0.100:8081/service?

Este servicio lo podremos testar mediante el uso de algún cliente GIS que tenga soporte para WMS, como por ejemplo “gvSIG” que permite la consulta a servidores WMS.

Ahora, a producción

Ahora habrá que utilizar, algún método para desplegar el servicio de caché de manera que de el mejor rendimiento. Yo he optado por FastCGI sobre un servidor “Apache2”, ya que estoy muy familiarizado con este sistema, pero hay muchas otras formas de hacerlo como indican en la documentación oficial y en otras guías.

sudo apt-get install libapache2-mod-fcgid

Ahora creamos un fichero “mapproxy.fcgi” con el siguiente texto:

#!/var/local/mapproxy/venv/bin/python
# WSGI module for use with Apache mod_wsgi or gunicorn
# # uncomment the following lines for logging
# # create a log.ini with `mapproxy-util create -t log-ini`
# from logging.config import fileConfig
# import os.path
# fileConfig(r'/var/local/mapproxy/log.ini', {'here': os.path.dirname(__file__)$

from mapproxy.wsgiapp import make_wsgi_app
application = make_wsgi_app(r'/var/local/mapproxy/mapproxy.yaml')

if __name__ == '__main__':
    from flup.server.fcgi_fork import WSGIServer
    WSGIServer(application).run()

En este script, hay varias cosas a destacar:

  • La primera linea tiene que indicar donde está el fichero de python del entorno virtual. NO vale con el python que tiene instalado el servidor, ya que no tendrá instalada ninguna de las librerías anteriores.
  • Esta línea: make_wsgi_app(r’/var/local/mapproxy/mapproxy.yaml’) indica donde esta el fichero .yaml donde has configurado todas las capas que consultara MapProxy. Esto es muy extenso y te recomiendo el manual de la web de MapProxy.

Tras esto configuramos el servidor web Apache, incluyendo esta línea al final de fichero “/etc/apache2/mods-available/fcgid.conf“:

[...]
# Tiene que tener la configuración del módulo arriba
ScriptAlias /mapproxy /var/local/mapproxy/mapproxy.fcgi

Y ahora un paso muy oscuro, tiene que poner como propietario al usuario que maneja el servidor web de TODA la carpeta de MapProxy. No sé si se podrá solo dar permisos en ciertos lugares, pero es lo único que me ha funcionado.

chown apache /var/local/mapproxy/ -R

Reinicia Apache, y ahora tendrás que tener accesible la web de prueba de MapProxy en “http://server/mapproxy” y el servidor WMS está en “http://server/mapproxy/service?“.

Otra guerra, es la configuración correcta para servir mallas… no me veo con fuerza hoy de escribir, ya que ese si sería un gran manual.

Documentación usada:

Please follow and like us:

Openlayers, aplicando estilos propios a ArcGIS Server WMS

Una de funcionalidad muy interesante que nos ofrecen los servidores de mapas, con el protocolo “WMS” y mediante la petición “GetMap“, es poder aplicar nuestro propio “estilo” a las capas que nos ofrecen, solo suministrándole un archivo donde se detalla como cambiar el estilo visual de las capas que nos muestra mediante el estándar “Style Language Descriptor” o “SLD” para los amigos. Este estándar no deja de ser un “XML” con una estructura y etiquetas propias. No es muy complejo de entender. Además hay hasta editores para hacerte la vida mucho más sencilla escribiendo SLD, como este, que es totalmente visual.

Para que entendáis, que significa esto, si pedimos un capa a un servidor, de una cierta zona, podría devolvernos esto:

Capa antes de aplicar un estilo

Pero no nos gusta nada su presentación, y tras hacer un poco de magia, obtendríamos algo así:

Capa despues del estilo

Capa después de aplicar un estilo

Normalmente estos estilos están definidos en el servidor de mapas, y el usuario que consume dicho servicio le indica que estilo utilizar. Pero para completar un poco esta funcionalidad, se permitió que el usuario indique que estilo usar, dando en la petición una URL a un fichero de estilos, como por ejemplo:

http://servidor/GetMap?TRANSPARENT=true&LAYERS=RiverBasinDistrict&FORMAT=image%2Fpng&TILED=true&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&EXCEPTIONS=application%2Fvnd.ogc.se_inimage&SRS=EPSG%3A4326&BBOX=-1.69189453125,41.21172151054787,1.12060546875,43.29320031385282&WIDTH=256&HEIGHT=256&SLD=http://servidorPublico/misestilos.sld&STYLES=estilo

La parte en negrita, indica donde cambiamos el estilo, indicante el fichero de estilos, y el estilo a usar (que podría estar definido en dicho fichero o no). Si indicamos un estilo que no esta definido ni en el servidor ni en el fichero, obtendremos un bonito error, o obtendremos la capa con el estilo por defecto.

Existen grandes ejemplos para entender este capacidad, como por ejemplo esta web, donde se colorean los polígonos que representan los países según el nombre de dicho país. Bonito, y descriptivo.

Pero hay un problema, como casi con todos estos estándar. Cada uno lo implementa a su modo. Por ejemplo si vemos un fichero de estilo de un servidor de mapas “Geoserver”, este tiene una extensión “sld”, y una sintaxis muy relajada. ¿Pero y si trabajamos con ArcGIS Server WMS?, pues no es igual…

Ahora bien, tras esta larga introducción, no centramos en nuestro caso actual.

  • Openlayers, en mi caso, se uso la versión 2.7, con algunos retoques que no modificaban esta funcionalidad.
  • Servidor ArcGIS Server WMS sirviendo unas capas con un estilo horrible. Para estas pruebas, sólo se sabía que era ArcGIS, y aún no sabemos exactamente que versión exacta es.
  • Hojas de estilo sacadas de un servidor Geoserver en formato SLD. La hoja de estilos tiene que estar almacenada en un servidor web donde el servidor de mapas tenga acceso, es decir que si no está en tu red, tiene que estar en un servidor web conectado a internet.

Si tratas de incluir en OpenLayers el estilo, nos encontramos esto:

wms_1 = new OpenLayers.Layer.WMS( "Capa"
		,url_wms_GIS
		,{
		    transparent:'true',
		    layers: 'capa',
		    styles: 'estilopoligono',
		    sld: 'http://servidorPublico/poligono.sld',
		    format:'image/png',
		    tiled: 'true'
		},
		{
		    'reproject': true,
		    buffer: 0
		}
	);

Y nuestro fichero de estilo, el cual esta alojado en la URL “http://servidorPublico/poligono.sld”:

<?xml version="1.0" encoding="UTF-8"?>
<StyledLayerDescriptor version="1.0.0"
	xsi:schemaLocation="http://www.opengis.net/sld StyledLayerDescriptor.xsd"
	xmlns="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc"
	xmlns:xlink="http://www.w3.org/1999/xlink"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<NamedLayer>
		<Name>capa</Name>
		<UserStyle>
			<Name>estilopoligono</Name>
			<Title>Estilo de un poligono</Title>
			<FeatureTypeStyle>
			<Rule>
				<PolygonSymbolizer>
					<Fill>
						<CssParameter name="fill">#995599</CssParameter>
						<CssParameter name="fill-opacity">0.3</CssParameter>
					</Fill>
					<Stroke>
						<CssParameter name="stroke">#000000</CssParameter>
						<CssParameter name="stroke-opacity">1</CssParameter>
					</Stroke>
				</PolygonSymbolizer>
			</Rule>
			</FeatureTypeStyle>
		</UserStyle>
	</NamedLayer>
</StyledLayerDescriptor>

Como puedes leer, en el fichero “sld” he incluido el nombre de la capa, y el nombre del estilo, y tienen que concordar con los escritos en Openlayers.

Todo parece correcto, pero al usarlo contra el servidor ArcGIS Server… esto no funciona, sencillamente te dice que el tipo de estilo no esta definido. ¡Mi gozo en un pozo!.

Pero no todo esta perdido, tras mucho mirar, y releer, me doy cuenta de lo de siempre, ArcGIS tiene “peculiaridades”, y es muy estricto, aunque gracias a dios, todo se encuentra muy bien documentado en su página de ayuda. Hay que remarcar, que la extensión pasa a ser “.xml”, y que ahora todas las etiquetas tiene el prefijo “sld”, aunque respeta el resto del estándar.

Hacemos unos cambios y ya tenemos la nueva versión:

<?xml version="1.0" encoding="UTF-8"?>
<sld:StyledLayerDescriptor version="1.0.0" xmlns="http://www.opengis.net/ogc" xmlns:sld="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc" xmlns:gml="http://www.opengis.net/gml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd">
	<sld:NamedLayer>
		<sld:Name>capa</sld:Name>
		<sld:UserStyle>
			<sld:Name>estilopoligono</sld:Name>
			<sld:Title>Estilo de un poligono</sld:Title>
			<sld:FeatureTypeStyle>
				<sld:Rule>
					<sld:PolygonSymbolizer>
						<sld:Fill>
							<sld:CssParameter name="fill">#995599</sld:CssParameter>
							<sld:CssParameter name="fill-opacity">0.2</sld:CssParameter>
						</sld:Fill>
						<sld:Stroke>
							<sld:CssParameter name="stroke">#0000FF</sld:CssParameter>
							<sld:CssParameter name="stroke-opacity">1</sld:CssParameter>
							<sld:CssParameter name="stroke-width">1</sld:CssParameter>
						</sld:Stroke>
					</sld:PolygonSymbolizer>
				</sld:Rule>
			</sld:FeatureTypeStyle>
		</sld:UserStyle>
	</sld:NamedLayer>
</sld:StyledLayerDescriptor>

Y tras todo esto, ya podremos disfrutar de poder manejar el estilo con el que un servidor remoto nos sirva las imágenes de su cartografía.

Please follow and like us: