Configurar NTP en Red Hat 7

Estoy empezando a montar servidores con Red Hat 7 y hay muchas cosas nuevas. Una de ellas ha sido el servicio de NTP, que deja e ser controlado por el demonio ntpd. Ahora el servicio es Chrony. Si no lo sabes es posible que estés un rato intentando configurando el ntpd y tras reiniciar el servidor lo encuentres parado.

[root@jupiter ~]# systemctl status ntp

ntpd.service - Network Time Service

Loaded: loaded (/usr/lib/systemd/system/ntpd.service; enabled)

Active: inactive (dead)

Viendo como esta definido el servicio chronyd vemos que es incompatible con el servicio ntpd. Por tanto deberemos elegir entre uno u otro:

[root@jupiter ~]# more /usr/lib/systemd/system/chronyd.service [Unit] Description=NTP client/server After=ntpdate.service sntp.service ntpd.service Conflicts=ntpd.service

[Service]
Type=forking
EnvironmentFile=-/etc/sysconfig/chronyd
ExecStart=/usr/sbin/chronyd -u chrony $OPTIONS
ExecStartPost=/usr/libexec/chrony-helper add-dhclient-servers

[Install]
WantedBy=multi-user.target

Tras reiniciar el servidor este servicio arranca al estar habilitado y no tener incompatibilidades con otros servicios :

[root@jupiter ~]# systemctl status chronyd
chronyd.service - NTP client/server
Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled)
Active: active (running) since jue 2015-04-23 14:29:00 CEST; 1min 52s ago
Process: 2257 ExecStartPost=/usr/libexec/chrony-helper add-dhclient-servers (code=exited, status=0/SUCCESS)
Process: 2250 ExecStart=/usr/sbin/chronyd -u chrony $OPTIONS (code=exited, status=0/SUCCESS)
Main PID: 2254 (chronyd)
CGroup: /system.slice/chronyd.service
└─2254 /usr/sbin/chronyd -u chrony

El fichero de configuración es el siguiente:

[root@jupiter ~]# more /etc/chrony.conf
# These servers were defined in the installation:
server 0.rhel.pool.ntp.org iburst
server 1.rhel.pool.ntp.org iburst
server 2.rhel.pool.ntp.org iburst
server 3.rhel.pool.ntp.org iburst

stratumweight 0

# Record the rate at which the system clock gains/losses time.
driftfile /var/lib/chrony/drift

# Enable kernel RTC synchronization.
rtcsync

# In first three updates step the system clock instead of slew
# if the adjustment is larger than 10 seconds.
makestep 10 3

# Listen for commands only on localhost.
bindcmdaddress 127.0.0.1
bindcmdaddress ::1

keyfile /etc/chrony.keys

# Specify the key used as password for chronyc.
commandkey 1

# Generate command key if missing.
generatecommandkey

# Disable logging of client accesses.
noclientlog

# Send a message to syslog if a clock adjustment is larger than 0.5 seconds.
logchange 0.5


logdir /var/log/chrony

En la documentación de Red Hat nos recomiendan en que casos usar un demonio u otro:
– En sistemas que se reinicien a menudo o que entren en hibernación recomiendan utilizar Chronyd.
– En sistemas que estén permanentemente encendidos recomiendan utilizar Ntpd.
Según cada caso instalaremos uno u otro, pero no los dos.

Para más información:

1. Documentación oficial de Red Hat
2. http://www.certdepot.net/rhel7-set-ntp-service/

Nginx como proxy inverso con SSL

Hace unos días me plantearon la necesidad de publicar en Internet u servicio que estaba corriendo sin ningún tipo de encriptacion, con lo que los passwords se estaban transmitiendo en claro.
Dándole vueltas encontré este tutorial donde se exponía un caso similar con la aplicación Jenkins:
(por cierto, muy buena la página de tutoriales de Digital Ocean)

La idea de este tutorial es la de montar un nginx delante del servicio que se quiere securizar de forma que encripte las comunicaciones que van por la red publica. Esta configuración se conoce como “reverse proxy” y el diagrama seria el mostrado a continuación:

Instalación de nginx

Para instalar nginx descargaremos el rpm ccorrespondiente desde la web del proyecto Nginx . Éste rpm nos configurara el repositorio lo que nos permitira instalarlo con yum:

[root@nginxprxy tmp]# yum -y install nginx-release-rhel-6-0.el6.ngx.noarch.rpm [root@nginxprxy tmp]# yum install -y nginx

Configuración del proxy reverso con ssl 

Como este servidor va a servir exclusivamente para la securización de un servicio no seguro editaremos el fichero de configuración default.conf. Lo deberemos dejar de la siguiente forma:
[root@nginxprxy tmp]# cd /etc/nginx/conf.d 
[root@nginxprxy conf.d]# cat default.conf 
server {
listen 80;
return 301 https://$host$request_uri;
}


# HTTPS server
#
server {
listen 443;
server_name service.enterprise.com;

ssl_certificate /etc/nginx/certs/service.enterprise.com.crt;
ssl_certificate_key /etc/nginx/certs/service.enterprise.comm.key;

ssl on;
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
ssl_prefer_server_ciphers on;

access_log /var/log/nginx/service.access.log;

location / {

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

# Fix the “It appears that your reverse proxy set up is broken" error.
proxy_pass http://
unsecureservice.enterprise.com;
proxy_read_timeout 90;

proxy_redirect http://unsecureservice.enterprise.com https://service.enterprise.com;
}
}
En la primera parte, se redigirán todas las peticiones a la misma URL pero al puerto de HTTPS. Así, cualquier petición al puerto por defecto de HTTP será redirigida, sin posibilidad de servir contenido que no esté cifrado.
En la segunda parte, es donde se especifica el puerto de escucha HTTPS, los certificados y varias opciones del protocolo SSL. 

Por último se establecen las reglas de redirección del proxy de forma que todo lo que entre a través de la URL https://service.enterprise.com; lo redirija a la http://unsecureservice.enterprise.com.

Antes de arrancar el servidor deberemos conseguir los certificados. Lo primero será generar el CSR en el directorio que hemos especificado en el fichero de configuración:

[root@nginxprxy tmp]# cd /etc/nginx/
[root@nginxprxy tmp]# mkdir certs
[root@nginxprxy certs]# openssl req -new -newkey rsa:2048 -nodes -keyout service.enterprise.com.key -out service.enterprise.com.csr
Generating a 2048 bit RSA private key
……………………………………….+++
…+++
writing new private key to ‘service.enterprise.com.key’
—–
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter ‘.’, the field will be left blank.
—–
Country Name (2 letter code) [XX]:XX
State or Province Name (full name) []:XXXX
Locality Name (eg, city) [Default City]:XXXX 
Organization Name (eg, company) [Default Company Ltd]:XXXX
Organizational Unit Name (eg, section) []:XXXX
Common Name (eg, your name or your server’s hostname) []:service.enterprise.com
Email Address []:XXXX@enterprise.com

Please enter the following ‘extra’ attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Una vez obtengamos el certificado deberemos crear el fichero crt con el contenido del certificado: 

[root@nginxprxy certs]# vi service.enterprise.com.crt  —–BEGIN CERTIFICATE—– MIIFWjCCBEKgAwIBAgIDCmMEMA0GCSqGSIb3DQEBBQUAMGExCzAJBgNVBAYTAlVT8WjFirPK7+2Gbq+9w4DpJ+a5FJjTOKfcRvIrZION 

—–END CERTIFICATE—–

Será el momento de arrancar el servidor Nginx y probar la conexión desde un navegador, donde deberemos ver que inmediatamente se redirecciona a un puerto seguro y que el certificado es válido:

[root@nginxprxy conf.d]# service nginx stop Stopping nginx: [FAILED] [root@nginxprxy conf.d]# service nginx start  Starting nginx: [ OK ]

Fallo al arrancar máquinas virtuales despues de migrar oVirt a 3.5

Recientemente he actualizado una instalación de oVirt de la versión 3.4 a la versión 3.5. El proceso es bastante trasparente y básicamente consiste en actualizar el repositorio y seguir los mismos pasos que durante la instalación. Una vez con la nueva versión podemos actualizar la compatibilidad del cluster que tengamos configurado a la versión 3.5. Para ello es recomendable poner los hosts en mantenimiento. Una vez actualizado se pueden actualizar también los Hosts. Ya con todo actualizado vemos que hay funcionalidades nuevas, como la gestión de memoria con NUMA. 
Esta funcionalidad puede ser interesante en entornos que requieren un uso intensivo de CPU y Memoria, pero debe estar bien configurado. Si, como en mi caso, tenemos un entorno mas estándar no es necesario configurarlo, pero al intentar arrancar las máquinas de nuevo podemos tener el siguiente error:
VM compute1 is down with error. Exit message: internal error internal error NUMA memory tuning in ‘preferred’ mode only supports single node.
Para solucionarlo basta seguir los pasos que se indican en la lista de distribución:
Resumiendo, hay que editar la máquina virtual que presenta los problemas y acceder a la opción Host:
Allí veremos que el “Tune Mode” esta deshabilitado y configurado por defecto en “Preferred”. Para poder cambiarlo seleccionaremos un host sobre el que correrá esta máquina y deshabilitaremos las migraciones. En ese momento ya podemos seleccionar la opción “Interleave” como “Tune Mode”:
Una vez cambiado podemos volver los parámetros por defecto. Una vez aplicados podremos arrancar la máquina

Agilizando la Infraestructura IV: Trabajando con oVirt

En el post anterior vimos como instalar y configurar oVirt dejándolo preparado para el despliegue de máquinas virtuales. En este post explicaré como configurar el repositorio de imágenes ISO, de forma que podamos arrancar una máquina virtual y asignarle una imagen de instalación por ejemplo. A continuación veremos como integrarlo con Foreman de forma que el despliegue de las máquinas virtuales lo hagamos desde Foreman como si fuese una máquina física.

Repositorio de imágenes

Durante la instalación se ha creado un Storage Domain que debemos configurar y que aparece como “Unattached”. Al seleccionarlo, en la consola inferior seleccionamos la pestaña “Data Center” y a continuación lo activamos con el boton de “Attach”:

A continuación nos aparecerá una ventana donde indicaremos al “Data Center” donde lo queremos añadir, en nuestro caso, al solo tener uno no tendremos mas opción:

En este punto ya podremos subir imágenes. No he encontrado otra forma de subirlas, y al parecer hay que hacerlo desde la línea de comandos con la herramienta engine-iso-uploader:


[root@ovirt ~]# engine-iso-uploader upload -i ISO_DOMAIN /var/lib/exports/iso/ubuntu-14.04-desktop-amd64.iso
Please provide the REST API password for the admin@internal oVirt Engine user (CTRL+D to abort):
Uploading, please wait…
INFO: Start uploading /var/lib/exports/iso/ubuntu-14.04-desktop-amd64.iso  

A los pocos minutos la imagen estará subida y disponible para añadirla a alguna máquina virtual. Así mismo, podemos ver el listado de imágenes que tenemos subidas desde la interfaz web:

Integración con Foreman

La integración con Foreman es bidireccional. Por una parte una vez integrado, desde Foreman, seremos capaces de provisionar máquinas virtuales y aplicarle las clases que hayamos definido como si de una máquina física se tratara. Por otro lado, desde oVirt, podremos acceder al inventario de máquinas de Foreman para el caso de que quisieramos añadir mas hosts, por ejempo.
Para el primer caso, desde la consola de Foreman accederemos al menú “Infraestructure/Compute Resources” y configuraremos la URL de la API de oVirt. También deberemos especificar el usuario administrador y su password. Finalmente probaremos la conexión para poder obtener el certificado e importarlo:
Para la integración en el otro sentido, desde la consola de oVirt añadiremos en este caso la URL de la API de Foreman desde la rama “External Providers” y con el botón de “Add”:

Creación de máquinas virtuales

Para la creación de máquinas virtuales podríamos seguir el método clásico de crear una nueva máquina e instalarle el sistema operativo desde el CD que le hayamos asignado. Sin embargo, aprovechando que tenemos nuestra instalación de Foreman, realizaremos el aprovisionamiento de las máquinas virtuales con el.
En la interfaz de Foreman, iremos a añadir un nuevo Host, y tras ponerle el nombre y asignarle el Host Group le pondremos que el despliegue se realice sobre oVirt. Esta opción se ha habilitado gracias a la integración que hemos configurado anteriormente. Veremos además que aparece una nueva pestaña de “Virtual Machine” donde podremos configurar parámetros específicos:

En la pestaña “Virtual Machine” le asignaremos los recursos que queremos que tenga nuestra máquina virtual: número de cores y memoria. También deberemos añadirle una interfaz de red y uno o mas discos, marcando que uno de ellos sea bootable:

En este punto ya veremos en la interfaz de oVirt que se ha creado una nueva máquina con el nombre que le hemos especificado y empezará la instalación de la misma.
Para poder ver la consola, desde Ubuntu deberemos instalar el paquete virt-viewer. Al acceder a la consola con Firefox nos pedirá con que programa abrirlo, a lo que deberemos seleccionar “Remote viewer”

julian@ubuntu:~$ sudo apt-get install virt-viewer  

Agilizando la Infraestructura II: Despliegue de sistemas con Foreman

Ya vimos en la entrada anterior cómo instalar y configurar Foreman para poder realizar despliegues de una manera desatendida. Veamos a continuación como se despliega un sistema.

En la pantalla principal de Foreman accederemos al menú Hosts y seleccionaremos New host.  


Nos aparecerá un wizard muy sencillo donde especificaremos algunos datos, como la MAC de la interfaz de red configurada para arrancar el servidor. También le indicaremos el “host group” y el entorno que le queremos asignar.  Esto nos permitirá aplicar al servidor unas clases de Puppet u otras.
Como se puede ver, también se puede indicar qué tipo de despliegue se quiere hacer, en este caso Bare Metal, para instalar un servidor físico, pero podríamos integrar Foreman con Openstack o con oVirt por ejemplo, y nos serviría para desplegar instancias virtuales.

 En la pestaña de Network especificaremos la MAC de la interfaz de red así como la dirección IP que queremos asignarle al servidor. En cualquier caso nos sugerirá una IP del rango DHCP que hayamos configurado, pero siempre podremos cambiarla:

En la pestaña Operating System indicamos el sistema operativo a instalar, el repositorio que debe utilizar, la tabla de partición que le queramos aplicar y finalmente la password del usuario root.

 Podemos darle ya al botón Submit para que quede configurado el servidor. En el próximo reinicio el servidor arrancará por red (si no arranca verificar la configuración de la BIOS) e iniciará la instalación del sistema operativo:

 

 A medida que vayamos instalando servidores se irán añadiendo a la lista de servidores y se le irán aplicando las clases que hayamos configurado al Host Group asignado:

En próximas entradas veremos cómo integrarlo con oVirt.

Jugando con Docker

Últimamente se esta oyendo mucho hablar de Docker. Se trata de una tecnología similar a la que ya existía en Solaris con las zonas, y en Linux con LXC (de hecho utiliza LXC por debajo). Parece que viene patrocinado por algunas de las grandes en internet como eBay, Spotify e incluso Google parece que venia utilizando algo parecido desde hace tiempo.
Docker
La gran ventaja, como en el caso de las zonas, es que te permite “virtualizar” sin depender de un hipervisor y con un overhead mínimo en comparación a la virtualización tradicional.

Instalación

Como todo en Linux es muy fácil de instalar y ya viene preparado en la mayoría de distribuciones. En el caso de CentOS hay que habilitar el repositorio EPEL editando el fichero de configuración del repositorio y poniendo la variable enabled a 1:

[root@centos1 ~]# vi /etc/yum.repos.d/epel.repo

[epel]
name=Extra Packages for Enterprise Linux 6 – $basearch
#baseurl=http://download.fedoraproject.org/pub/epel/6/$basearch
mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-6&arch=$basearch
failovermethod=priority
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6
A continuación ya podemos instalar docker con yum. Como veremos, una de las dependencias es LXC:
[root@centos1 ~]# yum install docker-io
Dependencies Resolved

================================================================================
 Package            Arch            Version                 Repository     Size
================================================================================
Installing:
 docker-io          x86_64          1.0.0-3.el6             epel          4.5 M
Installing for dependencies:
 lxc                x86_64          0.9.0-2.el6             epel           78 k
 lxc-libs           x86_64          0.9.0-2.el6             epel          116 k

Transaction Summary
================================================================================
Install       3 Package(s)

Total download size: 4.7 M
Installed size: 24 M
Is this ok [y/N]: y

Así de sencillo es instalarlo. Y como vemos, la versión es la primera estable que se ha publicado recientemente:
[root@centos1 ~]# docker -v
Docker version 1.0.0, build 63fe64c/1.0.0
Para empezar a utilizarlo se debe iniciar el servicio y configurarlo para que arranque en el runlevel predeterminado:
[root@centos1 ~]# service docker start
Starting cgconfig service:                                 [  OK  ]
Starting docker:                                                [  OK  ]
[root@centos1 ~]# chkconfig docker on

Imágenes y contenedores

Con el servicio ya en marcha podemos descargar las imágenes que docker mantiene, así como imágenes que la comunidad ha creado y ha subido. Por ejemplo descargaremos las últimas para centos y para ubuntu:

[root@centos1 ~]# docker pull centos:latest
Pulling repository centos
0c752394b855: Download complete
511136ea3c5a: Download complete
34e94e67e63a: Download complete

[root@centos1 ~]# docker pull ubuntu:latest
Pulling repository ubuntu
e54ca5efa2e9: Download complete
511136ea3c5a: Download complete
d7ac5e4f1812: Download complete
2f4b4d6a4a06: Download complete
83ff768040a0: Download complete
6c37f792ddac: Download complete
Para ver las imágenes que tenemos descargadas y disponibles para utilizar bastará con ejecutar el subcomando “images”:
[root@centos1 ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ubuntu              latest              e54ca5efa2e9        41 hours ago        276.1 MB
centos              latest              0c752394b855        10 days ago         124.1 MB
Pasando el parámetro -a podemos ver el historial de versiones de cada imagen:
[root@centos1 ~]# docker images -a
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ubuntu              latest              e54ca5efa2e9        41 hours ago        276.1 MB
                            6c37f792ddac        41 hours ago        276.1 MB
                            83ff768040a0        41 hours ago        192.7 MB
                            2f4b4d6a4a06        41 hours ago        192.7 MB
                            d7ac5e4f1812        41 hours ago        192.5 MB
centos              latest              0c752394b855        10 days ago         124.1 MB
                            34e94e67e63a        2 weeks ago         0 B
                            511136ea3c5a        12 months ago       0 B
Podremos arrancar instancias o contenedores con las imágenes que queramos de la siguiente manera:
[root@centos1 ~]# docker run -i -t centos /bin/bash
bash-4.1# more /etc/centos-release
CentOS release 6.5 (Final)
bash-4.1# hostname
3ce460cbb9d8

[root@centos1 ~]# docker run -i -t ubuntu /bin/bash
root@60d6e0455be0:/# more /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION=”Ubuntu 14.04 LTS”
root@60d6e0455be0:/# hostname
60d6e0455be
Al pasar el parámetro -i al comando run se ejecutará el contenedor de forma interactiva, de forma que, en cuanto termine el comando que pasamos como parámetro la ejecución del contenedor terminará.
Mientras estemos ejecutando la shell, veremos que el contenedor está ejecutándose:
[root@centos1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
49087a343e7f        centos:latest       /bin/bash           12 seconds ago      Up 11 seconds                           dreamy_curie   
Si quisiesemos ver un historial de las instancias ejecutadas pasaríamos el parámetro -a:
 [root@centos1 ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
15dc7c59189c        centos:latest       /bin/bash           27 seconds ago      Up 26 seconds                                   compassionate_fermi  
49087a343e7f        centos:latest       /bin/bash           12 minutes ago      Exited (0) 17 seconds ago                       dreamy_curie         
9e69f5b64254        ubuntu:latest       uname -r            15 minutes ago      Exited (0) 15 minutes ago                       high_engelbart       
f5aa352a5ce9        centos:latest       uname -r            15 minutes ago      Exited (0) 15 minutes ago                       jovial_meitner       
60d6e0455be0        ubuntu:latest       /bin/bash           17 minutes ago      Exited (0) 16 minutes ago                       cocky_leakey         
961b10b9bbbf        ubuntu:latest       hostname            17 minutes ago      Exited (0) 17 minutes ago                       insane_mayer         
3ce460cbb9d8        centos:latest       /bin/bash           19 minutes ago      Exited (0) 17 minutes ago                       loving_yonath  
Si por contra, quisiesemos ejecutar un contenedor en background o demonizado, como sucede en Solaris con las zonas, al comando run le pasaríamos el parámetro -d. En el siguiente ejemplo arrancaríamos una instancia de la imagen ubuntu y dos instancias de la imagen de centos y finalmente veríamos que se están ejecutando las tres:
[root@centos1 ~]# docker run -d -t ubuntu  /bin/bash
abc254ab2e8eb392ce80938c8f2b8fa8cb1603ab6935b2121b7cb0cddbdd64c3
[root@centos1 ~]# docker run -d -t centos  /bin/bash
59adfe1998cc678cf2c9db964f1b57e60a301ffa2139c7a4635ebe315db2b718
[root@centos1 ~]# docker run -d -t centos  /bin/bash
6714217732adadec19f47399fe5f7252823787869a96e8fed72457cd5106589c
[root@centos1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
6714217732ad        centos:latest       /bin/bash           3 seconds ago       Up 2 seconds                            romantic_shockley 
59adfe1998cc        centos:latest       /bin/bash           7 seconds ago       Up 6 seconds                            thirsty_bartik    
abc254ab2e8e        ubuntu:latest       /bin/bash           14 seconds ago      Up 13 seconds                           naughty_yonath 
Al arrancar cada contenedor nos devuelve un número muy largo. Este número es el container_id que mas adelante vemos en la primera columna del comando ps. La última columna es un nombre que se asigna automáticamente y servirá para identificar las instancias de una forma mas amigable. Para parar las zonas que están corriendo podríamos pasar como identificador tanto el container_id como el nombre:

[root@centos1 ~]# docker stop romantic_shockley
romantic_shockley
[root@centos1 ~]# docker stop thirsty_bartik
thirsty_bartik
[root@centos1 ~]# docker stop naughty_yonath
naughty_yonath
[root@centos1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 

Como vemos, el kernel que se está ejecutando es el del host:

[root@centos1 ~]# uname -r
2.6.32-431.el6.x86_64
[root@centos1 ~]# docker run -i -t centos uname -r
2.6.32-431.el6.x86_64
[root@centos1 ~]# docker run -i -t ubuntu uname -r
2.6.32-431.el6.x86_64

Otra forma de arrancar un contenedor es con el comando start y pasando como parámetro el id del contenedor o el nombre que docker le asigno en su momento (lo podemos encontrar con docker ps -a)
 [root@centos1 ~]# docker start romantic_shockley
romantic_shockley
[root@centos1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
6714217732ad        centos:latest       /bin/bash           15 minutes ago      Up 3 seconds                            romantic_shockley
Para acceder a la consola del contenedor ejecutaríamos el comando attach:
 [root@centos1 ~]# docker attach romantic_shockley

Obtener información

Existe una serie de comandos que nos servirán para obtener información, tanto de docker, como de las imagenes o contenedores que tenemos creados. El comando info nos devolverá información general de la instalación actual de docker:
[root@centos1 ~]# docker info
Containers: 6
Images: 8
Storage Driver: devicemapper
 Pool Name: docker-8:1-132310-pool
 Data file: /var/lib/docker/devicemapper/devicemapper/data
 Metadata file: /var/lib/docker/devicemapper/devicemapper/metadata
 Data Space Used: 784.9 Mb
 Data Space Total: 102400.0 Mb
 Metadata Space Used: 1.4 Mb
 Metadata Space Total: 2048.0 Mb
Execution Driver: native-0.2
Kernel Version: 2.6.32-431.el6.x86_64
Con el comando history veremos el historial de versiones de la imagen que le hayamos especificado:
[root@centos1 ~]# docker history centos
IMAGE               CREATED             CREATED BY                                      SIZE
0c752394b855        10 days ago         /bin/sh -c #(nop) ADD file:ce8fdb737386beb5fd   124.1 MB
34e94e67e63a        2 weeks ago         /bin/sh -c #(nop) MAINTAINER The CentOS Proje   0 B
511136ea3c5a        12 months ago                                                       0 B
También tendremos el comando inspect, que nos devolverá un objeto JSON con información detallada de la imagen. Tambien sirve para obetner información de un contenedor.

[root@centos1 ~]# docker inspect centos
[{
    “Architecture”: “amd64”,
    “Author”: “The CentOS Project \u003ccloud-ops@centos.org\u003e – ami_creator”,
    “Comment”: “”,
    “Config”: {
        “AttachStderr”: false,
        “AttachStdin”: false,
        “AttachStdout”: false,
        “Cmd”: null,
        “CpuShares”: 0,
        “Cpuset”: “”,
        “Domainname”: “”,
        “Entrypoint”: null,
        “Env”: [
            “HOME=/”,
            “PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin”
        ],
        “ExposedPorts”: null,
        “Hostname”: “b2d0f1281acd”,
        “Image”: “34e94e67e63a0f079d9336b3c2a52e814d138e5b3f1f614a0cfe273814ed7c0a”,
        “Memory”: 0,
        “MemorySwap”: 0,
        “NetworkDisabled”: false,
        “OnBuild”: [],
        “OpenStdin”: false,
        “PortSpecs”: null,
        “StdinOnce”: false,
        “Tty”: false,
        “User”: “”,
        “Volumes”: null,
        “WorkingDir”: “”
    },
    “Container”: “b2d0f1281acd040292b36f6623feca10a89df1637c8d86e54079d473da4d05e3”,
    “ContainerConfig”: {
        “AttachStderr”: false,
        “AttachStdin”: false,
        “AttachStdout”: false,
        “Cmd”: [
            “/bin/sh”,
            “-c”,
            “#(nop) ADD file:ce8fdb737386beb5fd9aff7c9bbe9e6c9e60db290809dd6407c61b377e444b59 in /”
        ],
        “CpuShares”: 0,
        “Cpuset”: “”,
        “Domainname”: “”,
        “Entrypoint”: null,
        “Env”: [
            “HOME=/”,
            “PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin”
        ],
        “ExposedPorts”: null,
        “Hostname”: “b2d0f1281acd”,
        “Image”: “34e94e67e63a0f079d9336b3c2a52e814d138e5b3f1f614a0cfe273814ed7c0a”,
        “Memory”: 0,
        “MemorySwap”: 0,
        “NetworkDisabled”: false,
        “OnBuild”: [],
        “OpenStdin”: false,
        “PortSpecs”: null,
        “StdinOnce”: false,
        “Tty”: false,
        “User”: “”,
        “Volumes”: null,
        “WorkingDir”: “”
    },
    “Created”: “2014-06-09T21:38:41.281490617Z”,
    “DockerVersion”: “0.10.0”,
    “Id”: “0c752394b855e8f15d2dc1fba6f10f4386ff6c0ab6fc6a253285bcfbfdd214f5”,
    “Os”: “linux”,
    “Parent”: “34e94e67e63a0f079d9336b3c2a52e814d138e5b3f1f614a0cfe273814ed7c0a”,
    “Size”: 124078508
}

Para obtener informacion específica de un contenedor especificaremos al comando inspect la clave que queremos que nos devuelva, como por ejemplo el hostname o la dirección IP:
[root@centos1 ~]# docker run -d -t centos  /bin/bash
d7e7938ab7e98ff8e2413179d5222201de6a0c66716b99aafb35a0805fbf279e
[root@centos1 ~]# docker  ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
d7e7938ab7e9        centos:latest       /bin/bash           11 seconds ago      Up 11 seconds                           nostalgic_newton   

[root@centos1 ~]# docker inspect -f ‘{{ .Config.Hostname }}’ nostalgic_newton
d7e7938ab7e9
[root@centos1 ~]# docker inspect -f ‘{{ .NetworkSettings.IPAddress }}’ nostalgic_newton
172.17.0.22

Borrado de contenedores

Para norrar contenedores utilizaremos el comando rm. Le podremos pasar un único identificador de contenedor o varios en el mismo comando:
[root@centos1 ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                       PORTS               NAMES
abc254ab2e8e        ubuntu:latest       /bin/bash           22 minutes ago      Exited (0) 18 minutes ago                        naughty_yonath      
90ae553f4384        centos:latest       /bin/bash           23 minutes ago      Exited (-1) 22 minutes ago                       ecstatic_mcclintock

[root@centos1 ~]# docker rm ecstatic_mcclintock naughty_yonath
ecstatic_mcclintock
naughty_yonath

Creación de módulos para puppet

Una vez puesto en marcha un servidor de Puppet es importante tener bien organizado la estructura de directorios para que no se convierta en un caos. Hay tres directorios importantes, el manifests, el modules y el files. Mi estructura actual es la siguiente:

[root@puppet puppet]# tree /etc/puppet/
/etc/puppet/
├── auth.conf
├── files
│   ├── limits.conf
│   ├── motd
│   ├── nicstat-linux
│   ├── nicstat-solarisx86
│   ├── ntp.conf
│   └── sysctl.conf
├── fileserver.conf
├── manifests
│   ├── nodes.pp
│   ├── site.pp
├── modules
│   ├── ftp
│   │   └── manifests
│   │   └── init.pp
│   ├── nicstat
│   │   └── manifests
│   │   └── init.pp
│   ├── ntp
│   │   └── manifests
│   │   └── init.pp
│   ├── sysconf
│   │   └── manifests
│   │   └── init.pp
│   └── users
│   └── manifests
│   └── init.pp
└── puppet.conf
En el manifests se ubican los principales scripts. Yo lo organizo en un site.pp que incluye el fichero nodes.pp que es donde defino las configuraciones específicas para cada nodo. En el directorio modules habrá un subdirectorio por cada módulo y dentro de este otro subdirectorio manifests y un fichero init.pp donde esta la propia definición del módulo. El último directorio importante es el files que utilizo para almacenar los ficheros de configuración estandarizados o binarios que quiero desplegar en los nodos.
Voy a analizar algunos de los ficheros comentados:
site.pp:
La idea de este fichero es que esté lo mas limpio posible para que de un vistazo sea intuitivo ver que scripts se están aplicando. En mi caso únicamente importo el nodes.pp.
[root@puppet manifests]# more site.pp
import ‘nodes.pp’
En el nodes.pp defino los nodos, filtrando por el nombre (se podría filtrar por algún otro parámetro). En cada definición de nodo incluyo los módulos que les quiero aplicar.
[root@puppet manifests]# more nodes.pp
node puppet {
    include ntp
    include nicstat
    include users
}
node /linux[1-3].enterprise.com/ {
    include ntp
    include nicstat
    include sysconf
    include users
    notice(“I am running on node ${fqdn}”)
}
node ‘solaris[1-2].enterprise.com‘ {
    include ftp
    include nicstat
    include users
    notice(“I am running on node ${fqdn}”)
}
Modulos
Para crear un módulo hay que crear una subcarpeta con el nombre del módulo. Dentro de este nuevo subdirectorio puede haber una estructura similar a la general en /etc/puppet. Como requisito fundamental es la existencia del fichero init.pp. En dicho fichero deberá existir una definición de clase (class) que será la que se importa en el nodes.pp.
He creado varios módulos para configurar determinadas funcionalidades, por ejemplo:
FTP
me aseguro que este parado por temas de seguridad.
[root@puppet manifests]# more /etc/puppet/modules/ftp/manifests/init.pp
class ftp {
    service { ‘ftp’:
        ensure => stopped,
    }
}
NTP
Existe en Puppet Forge algún módulo mas completo para el ntp, sin embargo para lo que yo busco este me es suficiente. Me aseguro de que el paquete esté instalado, el servicio arrancado y que el fichero de configuración es el mismo en todos los servidores.
[root@puppet manifests]# more /etc/puppet/modules/ntp/manifests/init.pp
class ntp {
    package { ‘ntp’:
        ensure => installed,
    }
    service { ‘ntpd’:
        ensure => running,
        require => Package[‘ntp’],
    }
    file { ‘/etc/ntp.conf’:
        notify => Service[“ntpd”],
        source => “puppet:///files/ntp.conf”,
        require => Package[‘ntp’],
    }
}
NICSTAT
Se trata de un binario para obtener estadísticas avanzadas de red. Me interesa desplegarlo en todos los nodos y ademas hay que tener en cuenta que el binario es diferente para Solaris y Linux:
[root@puppet manifests]# more /etc/puppet/modules/nicstat/manifests/init.pp
class nicstat{
    if $::osfamily == ‘Solaris’ {
        file { ‘/opt/utils/’:
            ensure => directory,
        }
        file { ‘/opt/utils/nicstat’:
            source => “puppet:///files/nicstat-solarisx86”,
        }
    } elsif $::osfamily == ‘RedHat’ {
        file { ‘/opt/utils/’:
            ensure => directory,
        }
        file { ‘/opt/utils/nicstat’:
        source => “puppet:///files/nicstat-linux”,
        }
    }
}
USERS
Con este módulo pretendo estandarizar la creación de usuarios. Podríamos crear todos los usuarios de los administradores por ejemplo o asegurarnos de que no exista determinado usuario.
[root@puppet puppet]# more /etc/puppet/modules/users/manifests/init.pp
class users{
    user { ‘jsotoca’:
        ensure => present,
        comment => ‘Julian Garcia-Sotoca’,
        home => $operatingsystem ?{
            Solaris => ‘/export/home/jsotoca’,
            default => ‘/home/jsotoca’,
        },
        managehome => true,
    }

    user { ‘baduser’:
        ensure => absent,
    }

Instalación de squid como proxy para YUM

En entornos con multitud de servidores GNU/Linux la gestión de las actualizaciones debe ser un proceso a tener en cuenta. Si queremos actualizar una gran cantidad de servidores, la conexión a Internet puede no ser suficiente o incluso podemos afectar a servicios productivos saturando el ancho de banda. Para solventar este punto está la opción de utilizar repositorios locales. En algunos casos, como las distribuciones derivadas de Debian, se puede poner un proxy cache de los paquetes(aptProxy), el cual se descargará únicamente los paquetes que no se haya descargado con anterioridad.

A diferencia de los sistemas Debian y sus derivados, con Red Hat, no tenemos la opción de tener un proxy cache de paquetes . Siempre podemos tener una copia del repositorio de la distribución que usemos pero es una opción que requiere de un servidor con gran cantidad de espacio en disco y con paquetes que muy probablemente no vayamos a necesitar.
Para tener una solución parecida a la del aptProxy, se puede utilizar Squid como proxy al cual lo configuraremos en el fichero yum.conf de nuestros servidores. 
La instalación es muy sencilla desde yum:
[root@yumrepo ~]# yum install squid 
A continuación lo configuraremos editando el fichero /etc/squid/squid.conf. Básicamente lo que haremos será crear una ACL (localnet) para controlar quien puede utilizar el proxy y donde especificaremos los segmentos donde tenemos servidores instalados. También crearemos una ACL (GoodSites) para controlar a donde se puede conectar el proxy para descargar paquetes.Esta ACL leerá de un fichero los dominios permitidos:
[root@yumrepo ~]# vi /etc/squid/squid.conf
#
# Recommended minimum configuration:
#
acl manager proto cache_object
acl localhost src 127.0.0.1/32 ::1
acl to_localhost dst 127.0.0.0/8 0.0.0.0/32 ::1

# Example rule allowing access from your local networks.
# Adapt to list your (internal) IP networks from where browsing
# should be allowed
acl localnet src 192.168.1.0/24 # RFC1918 possible internal network
acl localnet src 192.168.2.0/24 # RFC1918 possible internal network
acl localnet src 192.168.3.0/24 # RFC1918 possible internal network
acl localnet src 192.168.4.0/24 # RFC1918 possible internal network
acl localnet src 192.168.5.0/24 # RFC1918 possible internal network
acl localnet src 10.0.0.0/8 # RFC1918 possible internal network

acl SSL_ports port 443
acl Safe_ports port 80 # http
acl Safe_ports port 21 # ftp
acl Safe_ports port 443 # https
acl Safe_ports port 70 # gopher
acl Safe_ports port 210 # wais
acl Safe_ports port 1025-65535 # unregistered ports
acl Safe_ports port 280 # http-mgmt
acl Safe_ports port 488 # gss-http
acl Safe_ports port 591 # filemaker
acl Safe_ports port 777 # multiling http
acl CONNECT method CONNECT

#
# Recommended minimum Access Permission configuration:
#
# Only allow cachemgr access from localhost
http_access allow manager localhost
http_access deny manager

# Deny requests to certain unsafe ports
http_access deny !Safe_ports

# Deny CONNECT to other than secure SSL ports
#http_access deny CONNECT !SSL_ports

# We strongly recommend the following be uncommented to protect innocent
# web applications running on the proxy server who think the only
# one who can access services on “localhost” is a local user
#http_access deny to_localhost

#
# INSERT YOUR OWN RULE(S) HERE TO ALLOW ACCESS FROM YOUR CLIENTS
#
acl GoodSites dstdomain “/etc/squid/allowed-sites.squid”
# Example rule allowing access from your local networks.
# Adapt localnet in the ACL section to list your (internal) IP networks
# from where browsing should be allowed
http_access allow localnet GoodSites
http_access allow localhost GoodSites

# And finally deny all other access to this proxy
http_access deny all

# Squid normally listens to port 3128
http_port 3128

# set visible_hostname
visible_hostname yumrepo.enterprise.com

# We recommend you to use at least the following line.
hierarchy_stoplist cgi-bin ?

# Uncomment and adjust the following to add a disk cache directory.
cache_dir ufs /var/spool/squid 25000 16 256

# Leave coredumps in the first cache dir
coredump_dir /var/spool/squid
# Add any of your own refresh_pattern entries above these.
refresh_pattern ^ftp: 1440 20% 10080
refresh_pattern ^gopher: 1440 0% 1440
refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
refresh_pattern . 0 20% 4320

El fichero de la ACL GoodSites será el siguiente:
[root@yumrepo ~]# vi /etc/squid/allowed-sites.squid
.centos.com
.oracle.com
.vmware.com

De esta forma, solo podrá bajar paquetes RPM de esos dominios.

A continuación configuraremos el servicio para que arranque tras un reinicio del servidor:

[root@yumrepo ~]# chkconfig squid –list
squid 0:off 1:off 2: off 3: off 4: off 5: off 6:off
[root@yumrepo ~]# chkconfig squid on
[root@yumrepo ~]# chkconfig squid –list
squid 0:off 1:off 2:on 3:on 4:on 5:on 6:off

Un tema importante es la cache. El directorio donde estará ubicada se especifica en el archivo de configuración, así como el tamaño máximo que puede tener y el periodo de validez de la misma. En nuestro caso, al tratarse de un servicio que se usará para descargar software, se presupone que el volumen necesario será alto, por tanto optamos por asignar un disco y especificar el directorio de la cache como punto de montaje. Crearemos un volumen lógico para poder ser ampliado en un futuro con facilidad y editaremos el /etc/fstab para que se monte tras un reinicio:

[root@yumrepo ~]# fdisk /dev/sdb
[root@yumrepo ~]# partprobe -s

[root@yumrepo ~]# pvcreate /dev/sdb1
[root@yumrepo ~]# vgcreate repo-vg /dev/sdb1
[root@yumrepo ~]# vgdisplay
— Volume group —
VG Name repo-vg
System ID
Format lvm2
Metadata Areas 1
Metadata Sequence No 3
VG Access read/write
VG Status resizable
MAX LV 0
Cur LV 1
Open LV 1
Max PV 0
Cur PV 1
Act PV 1
VG Size 30,00 GiB
PE Size 4,00 MiB
Total PE 7679
Alloc PE / Size 7679 / 30,00 GiB
Free PE / Size 0 / 0
VG UUID qapuNn-QQv4-psKa-lSTh-JsJZ-hS3j-Js6bjf
[root@yumrepo ~]# lvcreate -l 100%FREE repo-vg
[root@yumrepo ~]# lvrename /dev/repo-vg/lvol0 /dev/repo-vg/repo-lv01
[root@yumrepo ~]# lvdisplay
— Logical volume —
LV Path /dev/repo-vg/repo-lv01
LV Name repo-lv01
VG Name repo-vg
LV UUID nG55k1-k62o-UGZf-B6Pi-WTb6-vlI5-FRqzWL
LV Write Access read/write
LV Creation host, time ol6Template, 2014-04-14 14:43:56 +0200
LV Status available
# open 1
LV Size 30,00 GiB
Current LE 7679
Segments 1
Allocation inherit
Read ahead sectors auto
– currently set to 256
Block device 252:2
[root@yumrepo ~]# mkfs.ext4 /dev/repo-vg/repo-lv01
[root@yumrepo ~]# mount /dev/repo-vg/repo-lv01 /var/spool/squid
[root@yumrepo ~]# vi /etc/fstab
/dev/repo-vg/repo-lv01 /var/spool/squid ext4 defaults 1 1Arranque del servicio

Una vez montado el directorio de la cache se crean los directorios que utilizará squid:
[root@yumrepo ~]# squid -z
[root@yumrepo ~]# ls -l /var/spool/squid
total 68
drwxr-x—. 258 squid squid 4096 abr 14 15:05 00
drwxr-x—. 258 squid squid 4096 abr 14 15:05 01
drwxr-x—. 258 squid squid 4096 abr 14 15:05 02
drwxr-x—. 258 squid squid 4096 abr 14 15:05 03
drwxr-x—. 258 squid squid 4096 abr 14 15:05 04
drwxr-x—. 258 squid squid 4096 abr 14 15:05 05
drwxr-x—. 258 squid squid 4096 abr 14 15:05 06
drwxr-x—. 258 squid squid 4096 abr 14 15:05 07
drwxr-x—. 258 squid squid 4096 abr 14 15:05 08
drwxr-x—. 258 squid squid 4096 abr 14 15:05 09
drwxr-x—. 258 squid squid 4096 abr 14 15:05 0A
drwxr-x—. 258 squid squid 4096 abr 14 15:05 0B
drwxr-x—. 258 squid squid 4096 abr 14 15:05 0C
drwxr-x—. 258 squid squid 4096 abr 14 15:05 0D
drwxr-x—. 258 squid squid 4096 abr 14 15:05 0E
drwxr-x—. 258 squid squid 4096 abr 14 15:05 0F
-rw-r—–. 1 squid squid 2880 abr 28 18:20 swap.state
El último paso será arrancar el servicio y verificar que está escuchando en el puerto por defecto.

[root@yumrepo ~]# service squid start
Starting squid: . [ OK ]
[root@yumrepo ~]# netstat -ant | grep 3128
tcp 0 0 :::3128 :::* LISTEN

En los clientes bastará con añadir la siguiente línea en el fichero /etc/yum.conf:
proxy=http://X.X.X.X:3128 

Si lanzamos dos actualizaciones en clientes diferentes veremos que la segunda va mucho mas rápido que la primera y que los directorios de la cache empiezan a tener uso.

Instalación de sistemas linux (Derivados de Red Hat) con kickstart

Cuando se instala un sistema Red Hat (o derivados) el instalador deja en el directorio /root un fichero de configuración con la configuración que se ha utilizado a la hora de realizar la instalación. Dicho fichero se puede utilizar si se necesitan instalar varios servidores idénticos. 
El fichero de configuración deberá ser accesible desde el nuevo servidor, en teoría se puede compartir por nfs, ftp o http. La forma que me ha ido mejor a mi ha sido por http. He instalado un simple apache en un servidor y he puesto el fichero accesible. 
Para lanzar la instalación debemos arrancar con el DVD de la distribución y cuando aparezca el menú del GRUB pulsar la tecla ESC. En ese momento nos aparece un promt donde especificaremos donde se encuentra el fichero de configuración y la configuración de red para ese sistema:
linux ks=http://X.X.X.X/ks.cfg ksdevice=eth0 ip=X.X.X.Y netmask=255.255.255.0 gateway=X.X.X.Z
 

El proceso de instalación arrancará y automáticamente instalará el sistema hasta que nos pida reiniciar el servidor ya con el sistema operativo instalado.
El fichero de configuración está dividido en bloques. Una primera parte donde se especifican las opciones globales de configuración. A continuación se indican que paquetes se van a instalar en un bloque identificado con la etiqueta “%packages”. Adicionalmente se pueden indicar comandos que se ejecutarán antes de arrancar la instalación y otros que se ejecutarán una vez la instalación haya terminado, identificados con las etiquetas “%pre” y “%post” respectivamente.

La parte que me ha parecido mas cómoda es la de la configuración de los discos. En mi caso quería montar un Raid-1 por software con los dos discos que tiene el servidor. Para ello se especifica de la siguiente manera:

zerombr 

clearpart –all –drives=sda,sdb 
part raid.008001 –asprimary –ondrive=sda –size=500 
part raid.008002 –asprimary –ondrive=sda –size=98304 
part raid.008003 –asprimary –ondrive=sda –size=100000 
part raid.008005 –asprimary –ondrive=sda –grow –size=755060 
part raid.008011 –asprimary –ondrive=sdb –size=500 
part raid.008012 –asprimary –ondrive=sdb –size=98304 
part raid.008013 –asprimary –ondrive=sdb –size=100000 
part raid.008015 –asprimary –ondrive=sdb –grow –size=755060 
raid /boot –fstype=ext4 –level=1 –device=md0 raid.008001 raid.008011 
raid / –fstype=ext4 –level=1 –device=md1 raid.008003 raid.008013 
raid /var –fstype=ext4 –level=1 –device=md2 raid.008005 raid.008015 
raid swap –level=1 –device=md3 raid.008002 raid.008012
Estoy utilizando cada disco, creando cuatro particiones y luego creando los meta-dispositivos raid-1 con una partición de cada disco.

Dejo en github una copia del fichero que me ha servido durante mis instalaciones