SafeChildren Banner

Havoc Oracle Solaris Experts

lunes, 27 de julio de 2009

Introducción a los permisos en HDFS - Problema con DrWho en Solaris 10

Introducción
En la primera parte de la introducción a los permisos en HDFS concluí que era más fácil utilizar IPFilter. La verdad es que esta conclusión la saqué después de mucho tiempo con la configuración a vueltas y un pequeño código que creaba unos archivos y luego los borraba.

El problema de DrWho
Después de un buen rato investigando el código de Hadoop, he encontrado el problema :D y creo que lo he solucionado.

El problema era muy sencillo, cuando ejecutaba un código muy simple que creaba n archivos desde Solaris, siempre me ponía como usuario "DrWho" y como group "" así que por muchos permisos que yo asignaba el código se los saltaba ya que DrWho es supergroup y por lo tanto no evalua los permisos.

Bien, el problema viene por cómo se mira quién es el usuario que está definido en la clase Shell.USER_NAME_COMMAND ($HADOOP_HOME/src/core/org/apache/hadoop/security/) que hace la llamada a "whoami", este comando no existe en Solaris así, sino "who am i", sin embargo, este comando no puede ser llamado si no estás atacado a la consola, así que estoy evaluando las siguientes opciones
  • Modicar el path para incluir los binarios compatibles con BSD que se encuentran en /usr/ucb donde está whoami (Es necesario tener instalado el paquete SUNWscpu)
  • Instalar whoami desde Sunfreeware.
  • Crear un WhoAmI propio utilizando el comando id de Solaris. Esta solución que es la más complicada, es como no la que he seleccionado, ya que creo es más interesante.
Solución al problema
# echo "/usr/xpg4/bin/id -un" > /usr/bin/whoami
# chmod +x /usr/bin/whoami
Con este sencillo cambio, el sistema ya reconoce quien soy y por lo tanto evalúa los permisos correctamente. Por defecto los comando compatibles con BSD se encuentran en /usr/xpg4/, podíamos haber hecho un simple link para solucionar el problema, pero creo que es más correcto hacer que Hadoop se encargue de saber a que id llamar en función del OS.

A continuación os muestro una ejecución sin el parche y otra con el parche
[java] hdfs://namenode.hadoop.test.com:54310/
[java] hdfs://namenode.hadoop.test.com:54311/
[java] Get UserName: hadoop
[java] Creating PATH 1248715418585
[java] Creating FILE 1248715418622
[java] Creating PATH 1248715421131
[java] 27-jul-2009 19:23:41 com.sfchildren.sbcore.backup.Main createTmpFile
[java] INFO: File testfile Created with Size: 1717833
[java] Creating FILE 1248715421148
[java] Creating PATH 1248715432033
[java] 27-jul-2009 19:23:52 com.sfchildren.sbcore.backup.Main createTmpFile
[java] INFO: File testfile Created with Size: 8968960
[java] Creating FILE 1248715432055
....

El log del NameNode
$ tail -f $HADOOP_HOME/log/hadoop--namenode*
2009-07-27 19:19:00,082 INFO org.apache.hadoop.hdfs.server.namenode.FSNamesystem.audit: ugi=DrWho,postgres,dba ip=/10.80.1.82 cmd=create src=/user/DrWho/testdir/tres/testfile dst=null perm=DrWho:supergroup:rw-r--r--
Y la estructura HDFS que tengo sólo permite la escritura al usuario hadoop de la siguiente forma
$ hadoop fs -lsr /user/DrWho
drwxr-xr-x - hadoop hadoop 0 2009-07-27 19:22 /user/DrWho/testdir
Sin embargo, después de ejecutar el comando (sin el parche) no sólo no falla, sino que se salta la seguridad por completo, aquí está el resultado
$ hadoop fs -lsr /user/DrWho
drwxr-xr-x - hadoop hadoop 0 2009-07-27 19:25 /user/DrWho/testdir
drwxr-xr-x - DrWho hadoop 0 2009-07-27 19:25 /user/DrWho/testdir/cuatro
-rw-r--r-- 3 DrWho hadoop 0 2009-07-27 19:25 /user/DrWho/testdir/cuatro/testfile
drwxr-xr-x - DrWho hadoop 0 2009-07-27 19:24 /user/DrWho/testdir/dos
-rw-r--r-- 3 DrWho hadoop 7731334 2009-07-27 19:24 /user/DrWho/testdir/dos/testfile
drwxr-xr-x - DrWho hadoop 0 2009-07-27 19:25 /user/DrWho/testdir/tres
-rw-r--r-- 3 DrWho hadoop 9384206 2009-07-27 19:25 /user/DrWho/testdir/tres/testfile
drwxr-xr-x - DrWho hadoop 0 2009-07-27 19:24 /user/DrWho/testdir/uno
-rw-r--r-- 3 DrWho hadoop 5752383 2009-07-27 19:24 /user/DrWho/testdir/uno/testfile


Sin embargo, si activo el parche el resultado es muy diferente
[java] hdfs://namenode.hadoop.test.com:54310/
[java] hdfs://namenode.hadoop.test.com:54311/
[java] Get UserName: hadoop
[java] Result 0 Value: postgres
[java] Creating PATH 1248715876078
[java] Creating FILE 1248715876149
[java] 27-jul-2009 19:31:16 com.sfchildren.sbcore.backup.Main main
[java] GRAVE: null
[java] org.apache.hadoop.security.AccessControlException: org.apache.hadoop.security.AccessControlException: Permission denied: user=postgres, access=WRITE, inode="testfile":DrWho:hadoop:rw-r--r--
[java] at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
[java] at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
[java] at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
[java] at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
[java] at org.apache.hadoop.ipc.RemoteException.instantiateException(RemoteException.java:96)
[java] at org.apache.hadoop.ipc.RemoteException.unwrapRemoteException(RemoteException.java:58)
[java] at org.apache.hadoop.hdfs.DFSClient$DFSOutputStream.(DFSClient.java:2647)
[java] at org.apache.hadoop.hdfs.DFSClient.create(DFSClient.java:463)
[java] at org.apache.hadoop.hdfs.DistributedFileSystem.create(DistributedFileSystem.java:195)
[java] at org.apache.hadoop.fs.FileSystem.create(FileSystem.java:479)
[java] at org.apache.hadoop.fs.FileSystem.create(FileSystem.java:460)
[java] at org.apache.hadoop.fs.FileSystem.create(FileSystem.java:367)
[java] at org.apache.hadoop.fs.FileSystem.create(FileSystem.java:359)
[java] at com.sfchildren.sbcore.backup.Main.createTmpFile(Main.java:171)
[java] at com.sfchildren.sbcore.backup.Main.main(Main.java:100)
[java] Caused by: org.apache.hadoop.ipc.RemoteException: org.apache.hadoop.security.AccessControlException: Permission denied: user=postgres, access=WRITE, inode="testfile":DrWho:hadoop:rw-r--r--
[java] at org.apache.hadoop.hdfs.server.namenode.PermissionChecker.check(PermissionChecker.java:176)
[java] at org.apache.hadoop.hdfs.server.namenode.PermissionChecker.checkPermission(PermissionChecker.java:111)
[java] at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.checkPermission(FSNamesystem.java:4486)
[java] at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.checkPathAccess(FSNamesystem.java:4446)
[java] at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.startFileInternal(FSNamesystem.java:1011)
[java] at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.startFile(FSNamesystem.java:968)
[java] at org.apache.hadoop.hdfs.server.namenode.NameNode.create(NameNode.java:377)
[java] at sun.reflect.GeneratedMethodAccessor7.invoke(Unknown Source)
[java] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[java] at java.lang.reflect.Method.invoke(Method.java:597)
[java] at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:508)
[java] at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:959)
[java] at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:955)
[java] at java.security.AccessController.doPrivileged(Native Method)
[java] at javax.security.auth.Subject.doAs(Subject.java:396)
[java] at org.apache.hadoop.ipc.Server$Handler.run(Server.java:953)
[java]
[java] at org.apache.hadoop.ipc.Client.call(Client.java:739)
[java] at org.apache.hadoop.ipc.RPC$Invoker.invoke(RPC.java:220)
[java] at $Proxy0.create(Unknown Source)
[java] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[java] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[java] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[java] at java.lang.reflect.Method.invoke(Method.java:597)
[java] at org.apache.hadoop.io.retry.RetryInvocationHandler.invokeMethod(RetryInvocationHandler.java:82)
[java] at org.apache.hadoop.io.retry.RetryInvocationHandler.invoke(RetryInvocationHandler.java:59)
[java] at $Proxy0.create(Unknown Source)
[java] at org.apache.hadoop.hdfs.DFSClient$DFSOutputStream.(DFSClient.java:2644)
[java] ... 8 more

Conclusión
Voy a abrir un bug en Hadoop para informar de los problemas que tiene el usar "whoami" en Solaris, para que cuando la propiedad os.name de Java sea SunOS entonces que llame a /usr/xpg4/id -un en vez de whoami
if ( System.getProperty("os.name").equals("SunOS") )
shellCommand = "/usr/xpg4/id -un";
else
shellCommand = "/usr/bin/id -un";
Todavía tengo que ver todos los casos en los que se produce y crear un report para crear el bug en Hadoop, de todas formas, espero haber ayudado con el misterio de DrWho.

Introducción a los permisos en HDFS

Introducción
El sistema HDFS implementa un sistema de permisos muy similar a POSIX. Cada uno de los archivos tiene un propietario(user) y un grupo (group). Hasta aquí es similar a la implementación de POSIX, sin embargo HDFS no almacena el user_id y group_id sino que guarda un String con sus valores además el usuario root será aquel que lanze el proceso de Hadoop, es decir, que cualquiera con acceso local a la máquina puede ser root para Hadoop.

Esto supone que la configuración de la seguridad sea muy importante, como ya comenté en el post Instalación de Hadoop, una de las recomendaciones es que no se permita hacer login en el cluster a los usuarios.

Por ello, vamos a establecer unos niveles de seguridad mayores que nos permitan mantener en buenas condiciones nuestra instalación para poder llevarla a producción de una forma óptima.

Limitar el Acceso a nuestro NameNode
Hadoop nos permite incluir una lista de equipos permitidos (y equipos excluidos) los cuales pueden acceder a nuestro NameNode, las propiedades de configuración son las siguientes:
  • dfs.hosts, full path al archivo que contiene los hosts permitidos. Si está vacía (por defecto) todos los hosts pueden acceder
  • dfs.hosts.exclude, full path al archivo que contiene los hosts denegados. Si está vacía (por defecto) no hay ninguno denegado
  • hadoop.security.authorization, habilita el control de acceso al sistema de hadoop (es necesario editar el archivo $HADOOP_HOME/conf/hadoop-policy.xml)

Configuración de IPFilter para limitar el acceso al NameNode
Después de muchas horas con la configuración de Hadoop a vueltas, no he sido capaz de hacer funcionar de una forma sencilla el sistema de autorizaciones. Creo que existe algún tipo de incopatibilidades entre Solaris y la implementación aunque no lo veo muy claro.

Por lo tanto, he buscado la solución más sencilla que consite en activar el firewall IPFilter e incluir los DataNodes y NameNodes en un pool permitiendo su acceso y denegando al resto. Sé que es una solución muy drástica, sin embargo creo que es mucho más efectiva ya que no implica problemas con la resolución de userid o groupid, así que vamos allá.

Activación de IPFilter
Lo primero que debemos hacer es activar IPFilter para ello, ejecutaremos el siguiente comando
# ipf -E
Creamos el pool de nuestro cluster de Hadoop
La configuración de IPFilter nos permite crear un pool de direcciones y referirnos a ellos como pool/_id_ de esta forma es más sencillo gestionar un cluster. También es cierto que con nuestra configuración podemos incluir todas las reglas sin pool ya que son sólo 3 datanode y 1 namenode
# vi /etc/ipf/ipf.conf

# permitimos el acceso a nuestro NameNode
pass in quick from pool/20 to any
pass out quick from any to pool/20

# denegamos el acceso al NameNode
block in quick from any to any port=54310
block in quick from any to any port=54311

:wq!
Y creamos el Pool
# vi /etc/ipf/ippool.conf

table role = ipf type = tree number = 20
{ 10.1.1.3/32, 10.1.1.4/32, 10.1.1.5/32, 10.1.1.6/32 };

:wq
Ya está, cargamos los pool y las reglas y ya está
# ipf -E
# ipf -Fa
# ippool -F
0 objects flushed
# ippool -f /etc/ipf/ippool.conf
# ipf -f /etc/ipf/ipf.conf
He utilizado los comando ipf -Fa para hacer un flush de las reglas al igual que un ippool -F de esta forma todos los filtros están desde cero.

Conclusiones
La conclusión que obtenido es que la implementación de ACL actual en Hadoop no está tan pulida como otras, además de que la documentación es ambigua y difusa. Todo esto me ha hecho perder mucho tiempo en investigación sobre la definición de los parámetros. Sin embargo, IPFilter es un firewall muy maduro que aporta muchas soluciones (no tantas como pf de OpenBSD) para limitar el acceso al NameNode.

Espero que la configuración os sirva de startup ya que como siempre, cada Solaris es un Mundo.


Refrencias

jueves, 23 de julio de 2009

Gestión básica de Zonas en Solaris 10 aplicado a Hadoop

Introducción

Vamos a introducir algunos comandos básicos de administración de zonas que nos ayudarán a mantener nuestra instalación de Hadoop en óptimas condiciones. Este post lo escribo no para ser un referente en la administración de las zonas de Solaris, más bien, debido a que un amigo me ha pedido algunas nociones básicas para la gestión, así que ahí va.

Para la gestión de las zonas en Solaris contamos con los siguientes comandos:
  • zonecfg nos permite configurar los parámetros de la zona (Nombre, IP, Packages, Resources, ...)
  • zoneadm nos permite administrar la zona (Iniciar, Detener, Reiniciar)
  • zlogin nos permite conectarnos a la sesión de una zona
  • zonename nos permite saber el nombre de la zona en la que nos encontramos
Una zona es una instancia nueva de Solaris ejecutándose de forma aislada del kernel principal. Esto expresado de una forma más simple, significa que si una zona produce un kernel panic las demás no se verán afectadas además, se pueden establecer niveles de uso de recursos por lo tanto, una zona no podrá nunca sobrepasar los límites asignados.

Si ha esto le sumamos que las partes constantes del O.S. se encuentran compartidas (/dev, /lib) podemos ver cómo la utilización de Solaris Zones puede darnos una gran ventaja en las arquitecturas Web.

Puedes ver una imagen de la arquitectura obtenida desde http://www.solarisinternals.com/wiki/index.php/Zones_Best_Practices donde explican con detalle el funcionamiento y estructura de Solaris Zones

Solaris siempre tendrá una zona especial llamada Global correspondiente a la instalación del sistema operativo, es decir, la principal y sobre la cual deberemos realizar las tareas de administración de las Zonas Hijas (non-global zone).

Cada zona necesita una ubicación local donde almacenar aquellas partes que no se encuentren compartidas (Shared) y este path debe pertenecer a root y sólo él debe poder escribir. Esto que parece algo tonto es de vital importancia, como hemos comentado al principio, las zonas son aisladas unas de otras, a excepción de la zona Global que gestiona todas las demás, por lo tanto, si "alguien" tomase el control de la zona global, tendrá control sobre las non-global zones.

Por lo tanto, podremos ver el estado de todas las non-global desde la zona global para ello Solaris ha incorporado una opción -Z que hace referencia a todas las zonas en los comandos ps y prstat

Este tema, aunque la gente parece no tener en cuenta es de vital importancia y creo que si merece un post sobre cómo Gestionar la Seguridad en Zonas de Solaris 10 para Hadoop (os lo prometo)

Creación de una Zona
Vamos a crear una zona que nos servirá como template para la creación de datanodes de forma automatizada, para ello desde la zona global haremos lo siguiente
# mkdir -p /opt/zones
# chmod 700 /opt/zones
# zonecfg -z node-template
node-template: No se ha configurado esa zona
Use 'create' para comenzar a configurar una zona nueva.
zonecfg:node-template> create
zonecfg:node-template> set zonepath=/opt/zones/node-template
zonecfg:node-template> set autoboot=false
zonecfg:node-template> add net
zonecfg:node-template:net> set physical=e1000g0
zonecfg:node-template:net> set address=10.1.1.7/24
zonecfg:node-template:net> set defrouter=10.1.1.254
zonecfg:node-template:net> end
zonecfg:node-template> verify
zonecfg:node-template> commit
zonecfg:node-template> exit
Fácil no? Yo he establecido el valor de la propiedad autoboot a false ya que mi intención es mantener esta zona apagada como un template para desplegar datanodes, sin embargo, si quieres que Solaris inicie la zona automáticamente sólo tienes que poner el valor a true


Configuración de una Zona Existente

# zonecfg -z node-template
zonecfg:node-template> info
zonename: node-template
zonepath: /opt/zones/node-template
brand: native
autoboot: false
bootargs:
pool:
limitpriv:
scheduling-class:
ip-type: shared
inherit-pkg-dir:
dir: /lib
inherit-pkg-dir:
dir: /platform
inherit-pkg-dir:
dir: /sbin
inherit-pkg-dir:
dir: /usr
net:
address: 10.1.1.7/24
physical: e1000g0
defrouter: 10.1.1.254
zonecfg:node-template> exit
Y si queremos borrar una propiedad?
zonecfg:node-template> remove net
zonecfg:node-template> info
zonename: node-template
zonepath: /opt/zones/node-template
brand: native
autoboot: false
bootargs:
pool:
limitpriv:
scheduling-class:
ip-type: shared
inherit-pkg-dir:
dir: /lib
inherit-pkg-dir:
dir: /platform
inherit-pkg-dir:
dir: /sbin
inherit-pkg-dir:
dir: /usr

Instalación de una Zona
Una vez ya hemos configurado la zona, podemos comenzar la instalación con el siguiente comando
# zoneadm -z node-template install
Preparing to install zone .
Creating list of files to copy from the global zone.
Copying <8137> files to the zone.
Initializing zone product registry.
Determining zone package initialization order.
Preparing to initialize <1194> packages on the zone.
Initialized <1194> packages on zone.
Zone is initialized.
Ya hemos instalado la zona, podemos comprobar su estado utilizando el comando zoneadm list
# zoneadm list -cv
ID NAME STATUS PATH BRAND IP
0 global running / native shared
1 node2 running /opt/zones/node2 native shared
2 node3 running /opt/zones/node3 native shared
3 node1 running /opt/zones/node1 native shared
- node-template installed /opt/zones/node-template native shared
Todavía nos queda un último paso que es configurar el sistema, para ello, deberemos conectarnos a la consola de la zona utilizando la opción -C

Nota: zlogin -C utiliza como secuencia de escape ~. sin embargo, es posible cambiarla por la que queramos utilizando -e

Nos conectamos a la consola y finalizamos la instalación de Solaris como siempre (he puesto como caracter de escape #. en vez de
~.)
# zoneadm -z node-template boot
# zlogin -C -e\# node-template
[Conectado a la consola de la zona 'node-template']
Una vez concluida la identificación del sistema nuestra zona ya está preparada

boot/reboot/halt de una Zona
Para las tareas de administración de la zona utilizaremos el comando zoneadm, a continuación podemos ver la opciones que tiene
# zoneadm
sintaxis: zoneadm help
zoneadm [-z ] [-u ] list
zoneadm {-z |-u }

Subórdenes:

help
boot [-- boot_arguments]
halt
ready
reboot [-- boot_arguments]
list [-cipv]
verify
install [-x nodataset] [brand-specific args]
uninstall [-F]
clone [-m method] [-s ] zonename
move zonepath
detach [-n]
attach [-F] [-n ] [-b patchid]* [-u]
mark incomplete
Para ver las zonas disponibles y sus estados utilizaremos
# zoneadm list -cv
Si queremos bootar una zona ejecutaremos el siguiente comando
# zoneadm -z _nombre_zona_ boot
Si queremos parar una zona ejecutaremos el siguiente comando
# zoneadm -z _nombre_zona halt
Si queremos rebootar una zona ejecutaremos el siguiente comando
# zoneadm -z _nombre_zona reboot
Si queremos que una zona deje de estar disponible para su gestión, pero no borrarla
# zoneadm -z _nombre_zona detach
Si queremos que una zona vuelva a estar disponible para su gestión
# zoneadm -z _nombre_zona attach
Clonación de una Zona
Para poder clonar una zona, ésta debe estar halted y attached para ello, procederemos a clonar nuestra node-template a una nueva zona node4. Cuando clonamos una zona ésta (la clonada) se clona en estado unconfigured y por lo tanto es necesario conectarse a la consola para concluir la instalación. En cierta medida, la única diferencia entre crear una zona desde cero y una clonación es el origen de los paquetes (básicamente)

Obtenemos la configuración de la zona node-template (source)
# zonecfg -z node-template > node-template.cfg
A continuación editamos el archivo de configuración y cambiamos los parámetros
zonename, zonepath y net, p
or ejemplo, con los siguientes valores
zonename: node4
zonepath: /opt/zones/node4
brand: native
autoboot: false
bootargs:
pool:
limitpriv:
scheduling-class:
ip-type: shared
inherit-pkg-dir:
dir: /lib
inherit-pkg-dir:
dir: /platform
inherit-pkg-dir:
dir: /sbin
inherit-pkg-dir:
dir: /usr
net:
address: 10.1.1.8/24
physical: e1000g0
defrouter: 10.1.1.254
Crearemos la nueva zona con la configuración que hemos modificado
# zonecfg -z node4 -f node-template.cfg
Detenemos la zona de la cual vamos a clonar
# zoneadm -z node-template halt
Iniciaremos el proceso de Clonación

# zoneadm -z node4 clone node-template
Una vez concluido el proceso de clonación, podemos conectarnos a la consola de la nueva zona node4 y finalizar el proceso de identificación del sistema como hemos visto en el paso de Instalación

Espero que aunque sé que es muy breve, os sirva para recordar y perder el miedo a las zonas.

Más información sobre Administración de Solaris Zones

martes, 21 de julio de 2009

HDFS Primeros Pasos - Solaris 10

Introducción
Durante los post anteriores, hemos Instalado y Configurado Hadoop en un cluster de tres nodos. Ahora bien, todavía no hemos empezado a exprimir Hadoop, ....

Primeros Pasos
La iteración con el cluster se realiza utilizando el comando $HADOOP_HOME/bin/hadoop si
tecleamos el comando sin parámetros, nos muestra una ayuda de los comandos principales disponibles como se muestra a continuación
$ hadoop
Usage: hadoop [--config confdir] COMMAND
where COMMAND is one of:
namenode -format format the DFS filesystem
secondarynamenode run the DFS secondary namenode
namenode run the DFS namenode
datanode run a DFS datanode
dfsadmin run a DFS admin client
mradmin run a Map-Reduce admin client
fsck run a DFS filesystem checking utility
fs run a generic filesystem user client
balancer run a cluster balancing utility
jobtracker run the MapReduce job Tracker node
pipes run a Pipes job
tasktracker run a MapReduce task Tracker node
job manipulate MapReduce jobs
queue get information regarding JobQueues
version print the version
jar run a jar file
distcp copy file or directories recursively
archive -archiveName NAME * create a hadoop archive
daemonlog get/set the log level for each daemon
or
CLASSNAME run the class named CLASSNAME
Most commands print help when invoked w/o parameters.
En esta primera entrega, vamos a ver los principales comandos de FileSystem que se encuentran divididos en tres subcategorías: fs, fsck y dfsadmin
  • fs, nos permite interactuar con el sistema de fichero. Implementa las principales utilidades de UNIX como "ls, cat, rm, mkdir, mv"
  • fsck, nos permite verificar el sistema de ficheros
  • dfsadmin, nos permite obtener información de los clientes y del sistema de ficheros
Vamos a empezar con un pequeño ejemplo, será nuestro HolaMundo de HDFS, para ello, vamos a crear un directorio "helloworld" y vamos a copiar en el nuestro "HolaMundo!"

$ cat >helloworld<
> HolaMundo
> EOF
$ hadoop fs -mkdir helloworld
$ hadoop fs -put helloworld helloworld/holamundo.dfs
$ hadoop fs -ls helloworld
Found 1 items
-rw-r--r-- 3 DrWho supergroup 10 2009-07-20 18:43 /user/DrWho/helloworld/holamundo.dfs
$ hadoop fs -cat helloworld/holamundo.dfs
HolaMundo
Sencillo no? El único comando que merece explicación es -put que nos permite poner un archivo/directorio local en el sistema de ficheros remoto.

Puedes encontrar más detalle en esta dirección

Verificar el estado de nuestro HDFS
Los fallos suceden. Esta es una premisa que debes tener muy en cuenta ya que la probabilidad de tener fallos en los nodos cuando estamos hablando de muchos, muchos nodos, es más probable que la que no falle ninguno. Esto hace que sea necesario comprobar la estructura del sistema HDFS, para ello, utilizaremos el siguiente comando:
$ hadoop fsck /
......Status: HEALTHY
Total size: 116417442 B
Total dirs: 10
Total files: 6
Total blocks (validated): 6 (avg. block size 19402907 B)
Minimally replicated blocks: 6 (100.0 %)
Over-replicated blocks: 0 (0.0 %)
Under-replicated blocks: 0 (0.0 %)
Mis-replicated blocks: 0 (0.0 %)
Default replication factor: 3
Average block replication: 2.8333333
Corrupt blocks: 0
Missing replicas: 0 (0.0 %)
Number of data-nodes: 4
Number of racks: 1


The filesystem under path '/' is HEALTHY

Nota: En HDFS el pathSepartor es "/" siempre

Administrar el Cluster HDFS
Dentro de las tareas de administración podemos destacar Ver el estado de los nodos, Espacio Libre, Volver a leer la configuración, Liberar espacio, todas estas opciones (y más) se encuentran en dfsadmin, vamos a ver algunos ejemplos

Para ver las opciones que tenemos dentro de dfsadmin introduciremos el siguiente comando (sin argumentos)
$ hadoop dfsadmin
Usage: java DFSAdmin
[-report]
[-safemode enter | leave | get | wait]
[-saveNamespace]
[-refreshNodes]
[-finalizeUpgrade]
[-upgradeProgress status | details | force]
[-metasave filename]
[-refreshServiceAcl]
[-setQuota ...]
[-clrQuota ...]
[-setSpaceQuota ...]
[-clrSpaceQuota ...]
[-help [cmd]]

Generic options supported are
-conf specify an application configuration file
-D use value for given property
-fs specify a namenode
-jt specify a job tracker
-files specify comma separated files to be copied to the map reduce cluster
-libjars specify comma separated jar files to include in the classpath.
-archives specify comma separated archives to be unarchived on the compute machines.

The general command line syntax is
bin/hadoop command [genericOptions] [commandOptions]

De todas las opciones disponibles, en esta primera parte, vamos a centrarnos en -report y -refreshNodes

Utilizaremos -report para ver el estado de los Nodos, es decir, espacio libre, nodos activos e inactivos, etc.
$ hadoop dfsadmin -report
Configured Capacity: 24784855040 (23.08 GB)
Present Capacity: 10768458752 (10.03 GB)
DFS Remaining: 10532012032 (9.81 GB)
DFS Used: 236446720 (225.49 MB)
DFS Used%: 2.2%
Under replicated blocks: 57
Blocks with corrupt replicas: 0
Missing blocks: 0

-------------------------------------------------
Datanodes available: 2 (2 total, 0 dead)

Name: 10.1.1.3:50010
Decommission Status : Normal
Configured Capacity: 12392427520 (11.54 GB)
DFS Used: 118223872 (112.75 MB)
Non DFS Used: 7008197632 (6.53 GB)
DFS Remaining: 5266006016(4.9 GB)
DFS Used%: 0.95%
DFS Remaining%: 42.49%
Last contact: Wed Jul 22 11:25:05 CEST 2009


Name: 10.1.1.5:50010
Decommission Status : Normal
Configured Capacity: 12392427520 (11.54 GB)
DFS Used: 118222848 (112.75 MB)
Non DFS Used: 7008198656 (6.53 GB)
DFS Remaining: 5266006016(4.9 GB)
DFS Used%: 0.95%
DFS Remaining%: 42.49%
Last contact: Wed Jul 22 11:25:06 CEST 2009
En la primera sección del report, podemos observar información sobre Capacidad, Espacio Libre, Espacio Usado sin embargo, una parte importante es Under replicated blocks que nos informa de aquellos chunks que no se encuentran replicados según su configuración, es decir. Si hemos establecido el valor de dfs.replication a 3 nos informa cuántos bloques no tienen ese valor en el cluster y por lo tanto, se encuentran por debajo del umbral de replicación

Para volver a leer la configuración de Hadoop utilizaremos -refreshNodes. Esta opción será interesante cuando actualicemos el número de nodos (añadir, eliminar) y la explicaremos con más detalle en Administración de Hadoop
$ hadoop dfsadmin -refreshNodes
Por último, vamos a introducir un comando (que explicaremos con más detalle en Administración de Hadoop) encargado de balancear los chunks entre los diferentes DataNodes

$ hadoop balancer
Time Stamp Iteration# Bytes Already Moved Bytes Left To Move Bytes Being Moved
09/07/22 11:32:17 INFO net.NetworkTopology: Adding a new node: /default-rack/10.1.1.3:50010
09/07/22 11:32:17 INFO net.NetworkTopology: Adding a new node: /default-rack/10.1.1.5:50010
09/07/22 11:32:17 INFO balancer.Balancer: 0 over utilized nodes:
09/07/22 11:32:17 INFO balancer.Balancer: 0 under utilized nodes:
The cluster is balanced. Exiting...
09/07/22 11:32:17 WARN conf.Configuration: mapred-default.xml:a attempt to override final parameter: mapred.job.tracker; Ignoring.
Balancing took 2.341 seconds


Un poco de resumen


Hemos visto muy por encima las diferentes secciones que Hadoop nos proporciona para Administrar HDFS. Entraremos en más detalle en el post dedicado a Administración de Hadoop sobre Solaris 10 hasta entonces espero que hagáis vuestras pruebas ....

lunes, 20 de julio de 2009

Instalación Hadoop sobre Solaris - Configurar SMF para DataNode y TaskTracker

Introducción
En post anteriores hemos concluido la primera parte de la Instalación y Configuración de Hadoop sobre Solaris 10, sin embargo, vamos a incluir alguna mejora en la configuración para evitar caídas de los DataNode

Configurar DataNode para arranque automático utilizando SMF
La configuración y estado de los servicio en Solaris 10 trajo una nueva característica llamada SMF, básicamente sustituye la antigua funcionalidad de los /etc/rc?.d por un framework más avanzado. Pues bien, vamos a utilizarlo para configurar el inicio de nuestros DataNodes de forma que se inicien solos.

Creación del descriptor SMF
Para ello, crearemos la siguiente estrucutra de directorios en los datanodes
# mkdir -p /var/svc/manifest/application/hadoop
# cd /var/svc/manifest/application/hadoop
# vi datanode.xml

He introducimos lo siguiente:

<service_bundle type="'manifest'" name="'HADOOP:DataNode'">
<service name="application/hadoop/datanode" type="service" version="1">
<create_default_instance enabled="'false'">
<single_instance>

<dependency name="multi-user-server" grouping="optional_all" type="service" restart_on="none">
<service_fmri value="'svc:/milestone/multi-user-server'">
</service_fmri>

<exec_method type="method" name="start" exec="/lib/svc/method/hadoop/datanode %m" timeout_seconds="60">
<method_context>
<method_credential user="'hadoop'">
</method_credential>
</method_context>

<exec_method type="method" name="restart" exec="/lib/svc/method/hadoop/datanode %m" timeout_seconds="60">
<method_context>
<method_credential user="'hadoop'">
</method_credential>
</method_context>

<exec_method type="method" name="stop" exec="/lib/svc/method/hadoop/datanode %m" timeout_seconds="60">
<method_context>
<method_credential user="'hadoop'">
</method_credential>
</method_context>

<property_group name="'startd'" type="'framework'">
<propval name="'duration'" type="'astring'" value="'contract'">
</propval>

<template>
<common_name>
<loctext lang="'C'">
HADOOP DataNode Service
</loctext>
</common_name>
<documentation>
<doc_link name="'hadoop_datanode_overview'" uri="'http://http://sparcki.blogspot.com/2009/07/apache-hadoop-que-es-y-para-que-sirve.html'/">
<doc_link name="'hadoop_datanode_install'" uri="'http://http://hadoop.apache.org/'">
</doc_link>
</doc_link>
</documentation>

Validamos e Importamos la definición

# svccfg
svc:> validate /var/svc/manifest/application/hadoop/datanode.xml
svc:> import /var/svc/manifest/application/hadoop/datanode.xml
svc:> quit


A continuación, crearemos el method que será llamado por el framework SMF

# mkdir -p /lib/svc/method/hadoop
# cd /lib/svc/method/hadoop
# vi datanode

He introducimos lo siguiente

#!/sbin/sh
# Start/stop Hadoop DataNode
#
.. /lib/svc/share/smf_include.sh
HADOOP_HOME=/opt/hadoop
HADOOP_DAEMON=hadoop-daemon.sh
CFG=$HADOOP_HOME/bin/$HADOOP_DAEMON
TYPE=datanode

case "$1" in
'start')
$CFG start $TYPE
sleep 2
;;
'restart')
$CFG stop $TYPE
sleep 2
$CFG start $TYPE
;;
'stop')
$CFG stop $TYPE
;;
*)
echo "Usage: $0 { start | stop | restart }"
exit 1
;;
esac
exit $SMF_EXIT_OK

Corregimos los permisos y propietario
# chown -R root:sys /var/svc/manifest/application/hadoop
# chown -R root:bin /lib/svc/method/hadoop/
# chmod 555 /lib/svc/method/hadoop/datanode

Ya podemos activar el servicio
# svcadm enable -t svc:/application/hadoop/datanode
# svcs -a|grep hadoop
online 17:39:20 svc:/application/hadoop/datanode:default

Ya está! Si ahora hacemos un kill -9 de nuestro PID, veremos como el framework SMF vuelve a iniciar el demonio

Os dejo a vuestra imaginación cómo hacer un servicio para el TaskTracker y de esta forma tener los datanodes con arranque automático.


Os he dejado los archivos de configuración completos para que los podais descargar en las siguientes direcciones: