Le Journal des Admins Sys

tail -f /var/log/sysblog

Aller au contenu | Aller au menu | Aller à la recherche

2013-04-23

Use flat network with OpenStack

In this tutorial, we will study how does the Openstack's Flat mode work, how to activate it and finally how to use it.

Introduction

Flat mode is a network mode used by Openstack to provide newtork connectivity to its instances.

As a reminder, this mode is used with the nova-network component. This network component currently cohabits with the new one: Quantum. These two components aim to provide all network functionnalities expected by instances. However we won't go deeper into the new component Quantum, as this article focuses on the flat mode.

With the historical nova-network component, there are three modes available:

  • Flat: The one we will describe
  • Flat DHCP: add a DHCP server to automatically give IP addresses to instances
  • VLAN Manager: add an isolation (OSI level 2), allowing to have distinct network by project

More information can be found here: http://docs.openstack.org/trunk/openstack-compute/admin/content/networking-options.html

Flat Mode

This mode aims to deploy OpenStack without taking care of the underlying network topology. This mode is very simple to use. Because of its simplicity, this mode is easy to configure, deploy and use in production environment.

Flat mode functioning is based on Linux bridging. The idea is to provide a bridge between the instance and the desired network. The network addressing is manual. It is by creating the instance that we attach the network(s).

Here is a schema explaining this mode (source: OpenStack documentation):

Interfaces eth1 correspond to the 'real' OpenStack network. It is on this network that the compute and controller nodes will directly communicate with each other.

During the launch of an instance, it will be attached to the bridge br100. Of course you can have multiple declared networks, and therfore use bridges on multiples VLAN.

In this tutorial, we will configure OpenStack and an instance using two network interfaces as shown on the picture (source: documentation OpenStack):

Netowk prerequisite

First of all, install the needed packages to build bridges and VLAN:

compute-node:~# apt-get install vlan ifenslave

Activate the VLAN module:

compute-node:~# modprobe 8021q

For example, you can configure the network interfaces of a compute-node the following way:

compute-node:~# vi /etc/network/interfaces
auto eth0
iface eth0 inet static
        address 10.0.0.1
        netmask 255.255.255.0
        gateway 10.0.0.254

auto eth1
iface eth1 inet manual

auto br100
iface br100 inet manual
        bridge_stp off
        bridge_fd 0
        bridge_maxwait 0
        bridge_ports eth1.100

auto br101
iface br101 inet manual
        bridge_stp off
        bridge_fd 0
        bridge_maxwait 0
        bridge_ports bond1.101

eth0 is the interface on the OpenStack network. eth1 is the second interface, allowing us to create bridges on the different VLANs. Obviously it is still to do some bonding by using multiple interface

OpenStack Configuration

Edit the OpenStack configuration:

compute-node:~# vi /etc/nova/nova.conf
[...]
# NETWORK -
network_manager=nova.network.manager.FlatManager
##For injected network informations in instance
flat_injected=true
firewall_driver=nova.virt.libvirt.firewall.IptablesFirewallDriver
# Have nova-network on each compute-node
multi_host=true
[...]

During this configuration, 2 very useful options have been added. OpenStack is now "injecting" the network configuration during the creation of instances instead of letting the image network configuration.

OpenStack Network Creation

Next step is to create 2 networks, that we want to use in OpenStack:

compute-node:~# nova-manage network create --multi_host=T --fixed_range_v4=172.16.100.0/24 --bridge=br100 --bridge_interface=br100 --num_networks=1 --network_size=256 --label=network100 --gateway=172.16.100.254 --dns1=172.16.100.254
compute-node:~# nova-manage network create --multi_host=T --fixed_range_v4=172.16.101.0/24 --bridge=br100 --bridge_interface=br101 --num_networks=1 --network_size=256 --label=network101 --gateway=172.16.101.254 --dns1=172.16.101.254

Let's check networks have been properly created:

compute-node:~# nova network-list
+--------------------------------------+----------+--------------------+
| ID                                   | Label    | Cidr               |
+--------------------------------------+----------+--------------------+
| 069dedb6-c97a-432c-bcf6-54b2b4311928 | network100    | 172.16.100.0/24    |
| 0c8bd87e-c824-439d-a567-5f37e724292c | network101   | 172.16.101.0/24    |
+--------------------------------------+----------+--------------------+

Note: This can also be checked on the controler node data base:

controller-node:~# mysql --defaults-extra-file=/etc/mysql/debian.cnf -e "select * from networks\G" nova
*************************** 1. row ***************************
         created_at: 2012-11-27 10:43:39
         updated_at: 2012-11-27 15:34:26
         deleted_at: NULL
            deleted: 0
                 id: 1
           injected: 1
               cidr: 172.16.100.0/24
            netmask: 255.255.255.0
             bridge: br100
            gateway: 172.16.100.254
          broadcast: 172.16.100.255
               dns1: 172.16.100.254
               vlan: NULL
 vpn_public_address: NULL
    vpn_public_port: NULL
vpn_private_address: NULL
         dhcp_start: NULL
         project_id: NULL
               host: NULL
            cidr_v6: NULL
         gateway_v6: NULL
              label: network100
         netmask_v6: NULL
   bridge_interface: br100
         multi_host: 1

*************************** 2. row ***************************
         created_at: 2012-12-26 08:34:13
         updated_at: 2012-12-26 08:42:18
         deleted_at: NULL
            deleted: 0
                 id: 2
           injected: 1
               cidr: 172.16.101.0/24
            netmask: 255.255.255.0
             bridge: br101
            gateway: 172.16.101.254
          broadcast: 172.16.101.255
               dns1: 172.16.101.254
               vlan: NULL
 vpn_public_address: NULL
    vpn_public_port: NULL
vpn_private_address: NULL
         dhcp_start: NULL
         project_id: NULL
               host: NULL
            cidr_v6: NULL
         gateway_v6: NULL
              label: iliad3
         netmask_v6: NULL
   bridge_interface: br101
         multi_host: 1

Creating instance with these 2 networks

Because of the previous OpenStack network configuration and the creation of the networks, we can boot an instance as following:

compute-node:~# nova boot --flavor 1 --image precise-cloud --nic net-id=069dedb6-c97a-432c-bcf6-54b2b4311928,v4-fixed-ip=172.16.100.2  --nic net-id=0c8bd87e-c824-439d-a567-5f37e724292c,v4-fixed-ip=172.16.101.2  --security_group default instance-nw100-101

Now that the instance is created, we can check its network configuration:

compute-node:~# nova show instance-nw100-101| grep network
| network100 network                       | 172.16.100.2                                            |
| inetwork101 network                       | 172.16.101.2                                           |

Finally, we check the bridges on the compute node:

compute-node:~# brctl show
bridge name	bridge id		STP enabled	interfaces
br100		8000.00137238fb51	no		eth1.100
                                                        vnet0
br101		8000.00137238fb51	no		bond1.101
							vnet1

Connect to the instance to insure network configuration is correct:

instance:~$ ping smile.fr -c 1
PING smile.fr (195.154.89.84) 56(84) bytes of data.
64 bytes from 195.154.89.84: icmp_req=1 ttl=46 time=7.24 ms
instance:~$ netstat -rn
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
0.0.0.0         172.16.100.254      0.0.0.0         UG        0 0          0 eth0
172.16.100.0      0.0.0.0         255.255.255.0   U         0 0          0 eth0
172.16.101.0      0.0.0.0         255.255.255.0   U         0 0          0 eth1

It works! However one of the two gateway has been witrdrawn by hand.

Limitations

In order to have proper metadata, we need to redirect bridges outgoing queries of type 169.254.169.254 on the port 80 to the server hosting the service nova-api. This routing is usually made on the instance's gateway.

The filtering of level 3 - made by iptables - does not work with thismode. The filtering offered by the OpenStack API will therfore not work.

Conclusion

That's it, you know now how to deploy and configure the OpenStack flat network mode...But there are all the OpenStack remaining components to explore!

2013-02-20

Migrate your OpenVZ containers to KVM (OpenStack)

In this article, we are presenting a way to migrate OpenVZ containers to KVM (and OpenStack).

Why migrate ?

The two main reasons are: isolation given by full virtualization, and the kernel features available.

For example, it's not possible to use IPSec tunnels in an OpenVZ container.

Process explanation

An OpenVZ container has no kernel, no grub, no disk. Those 3 elements are mandatory to turn the container into a virtual machine. This tutorial explains how to create a virtual disk and install the kernel and grub inside the container.

Requirements

The KVM host must have the following packages:

  • qemu-utils
  • qemu-kvm

You must have a VNC client. gvncviewer under gnome works just fine.

The migrated OpenVZ container is a Debian Squeeze.

1st step: creation of the disk for the new VM

Create an image in qcow2 format:

server-kvm:~# IMAGE=/tmp/ma_vm.img
server-kvm:~# kvm-img create -f qcow $IMAGE 20G
Formatting '/tmp/ma_vm.img', fmt=qcow size=21474836480 encryption=off

Mount the new image as a block peripheral:

server-kvm:~# qemu-nbd -c /dev/nbd1 $IMAGE

Create the partition(s):

server-kvm:~# cfdisk /dev/nbd1

Create the filesystem:

server-kvm:~# mkfs.ext3 /dev/nbd1p1

Mount the virtual disk partition:

server-kvm:~# MOUNT_POINT=/mnt/ma_vm
server-kvm:~# mount /dev/nbd1p1 $MOUNT_POINT

2nd step: copy the container to the virtual disk

Copy the container to the mount point:

server-kvm:~# CONTAINER_VZ=/tmp/mon_openvz
server-kvm:~# rsync -avz --numeric-ids ${CONTAINER_VZ}/* ${MOUNT_POINT}/

Note that rsync "numeric-ids" option is important to preserve the owners.

Once the container is transfered, we will use chroot to pre-configure the virtual machine.

3rd step: virtual machine pre-configuration

Chroot into VM:

server-kvm:~# chroot ${MOUNT_POINT} -s /bin/bash

Check that you really are into the chroot by checking that /etc/hosts information is from the OpenVZ container (and not from server-kvm).

server-kvm:~# cat /etc/hosts

Change the PS1 (to avoid using the bad console):

server-kvm:~# export PS1="(chroot) $PS1"

Generally, tty consoles are deactivated in an OpenVZ container. Reactivate them by adding (or uncomment the lines):

(chroot) server-kvm:~# vi /etc/inittab
1:2345:respawn:/sbin/getty 38400 tty1
2:23:respawn:/sbin/getty 38400 tty2
3:23:respawn:/sbin/getty 38400 tty3
4:23:respawn:/sbin/getty 38400 tty4
5:23:respawn:/sbin/getty 38400 tty5
6:23:respawn:/sbin/getty 38400 tty6

Configure the network as you wish. In our case, we use DHCP:

(chroot) server-kvm:~# cat /etc/network/interfaces
auto eth0
iface eth0 inet dhcp
(chroot) server-kvm:~# cat /etc/resolv.conf
nameserver 8.8.8.8

Add the mount point of the VM virtual disk to fstab:

(chroot) server-kvm:~# vi /etc/fstab
/dev/vda1 / ext3 rw,relatime 0 0

Be sure to reactivate root password as we will need it for console login:

(chroot) server-kvm:~# passwd

Then, quit the chroot:

(chroot) server-kvm:~# exit

Fourth step: start the Virtual Machine

Before starting the new VM, umount the virtual disk! Caution: if you skip this step you face data corruption of the virtual disk:

server-kvm:~# umount $MOUNT_POINT
server-kvm:~# qemu-nbd -d /dev/nbd1
/dev/nbd1 disconnected

Start the VM using KVM command. Note: this command do not return until the VM is stopped.

server-kvm:~# kvm -m 512 -kernel /boot/vmlinuz-$(uname -r) -initrd /boot/initrd.img-$(uname -r) -append "root=/dev/vda1" -drive file=${IMAGE},if=virtio -net nic,model=virtio -net user -vnc :20 -k fr

-kernel and -initrd options are part of KVM magic. This will allow to start the container even if it has no kernel and no grub yet.

Connect to the started VM with VNC:

client:~$ gncviewer server-kvm:20

Note: the keyboard map is probably qwerty.

Install required packages:

container-vz:~# aptitude install linux-image-amd64 grub console-tools console-data acpid acpi-support-base
container-vz:~# aptitude reinstall udev
container-vz:~# shutdown -h now

console-tools and console-data packages are needed if you want to fix the keyboard mapping.

acpid and acpi-support-base packages are important to handle KVM acpi signals correctly. For instance, if you reboot the KVM server, it will send an ACPI signal to stop the VM in a clean way.

We reinstall udev to be sure that ACPI is working properly.

5th step: VM check

To check that the migration worked fine, restart the VM without the kernel/initrd options:

server-kvm:~# kvm -m 512 -drive file=${IMAGE},if=virtio -net nic,model=virtio -net user -vnc :20 -k fr

6th step: upload image to OpenStack

Add image to OpenStack:

cloud-controller:~# glance image-create --name=my_image --disk-format=raw --container-format=ovf < ${IMAGE}
+------------------+--------------------------------------+
| Property         | Value                                |
+------------------+--------------------------------------+
| checksum         | abb4e2ab7ce9cafefeadfa5e1a78d347     |
| container_format | ovf                                  |
| created_at       | 2012-12-12T14:26:37                  |
| deleted          | False                                |
| deleted_at       | None                                 |
| disk_format      | raw                                |
| id               | 62410923-b8a7-4725-99fa-f06ae5cab6b3 |
| is_public        | False                                |
| min_disk         | 0                                    |
| min_ram          | 0                                    |
| name             | my_image                               |
| owner            | ab2519fd61b8425da392f228f54dc1c3     |
| protected        | False                                |
| size             | 8682160128                           |
| status           | active                               |
| updated_at       | 2012-12-12T14:29:39                  |
+------------------+--------------------------------------+

Here it is! You migrated you OpenVZ container to a KVM virtual machine.

2013-02-18

Utiliser le mode Flat avec OpenStack

Dans ce tutoriel, nous allons voir comment fonctionne, puis activer et utiliser le mode flat d'OpenStack.

Introduction

Le flat est un mode de réseau utilisé par OpenStack pour fournir la connectivité réseau aux instances.

Pour rappel, ce mode, flat, s'utilise avec le composant nova-network. Ce composant cohabite à l'heure actuelle avec le nouveau composant Quantum. Ces deux composants ont pour but de fournir toutes les fonctionnalités réseaux attendues pour les instances. Nous ne nous pencherons pas plus en avant sur le nouveau composant Quantum dans cette article.

Avec nova-network, le composant historique, 3 modes sont disponibles:

  • Flat: celui que nous allons voir;
  • Flat DHCP: ajoute un serveur DHCP pour l'attribution automatique d'IP des instances;
  • VLAN Manager: ajoute une isolation de niveau 2 et permet d'avoir des adressages distincts pour chaque projet.

Vous pourrez obtenir plus d'informations ici: http://docs.openstack.org/trunk/openstack-compute/admin/content/networking-options.html

Le mode flat

Ce mode a pour but de déployer OpenStack sans se soucier de la configuration et la topologie réseau sous-jacente. Ce mode est très simple à utiliser. Grâce à sa simplicité, ce mode est facile à configurer, déployer et utiliser dans un environnement de production.

Le fonctionnement est basé sur les ponts réseaux linux. L'idée est de fournir un pont entre l'instance et le réseau souhaité. L'adressage réseau offert est manuel. C'est en lançant la création d'une instance qu'on attache le(s) réseau(x).

Voici un schéma explicitant ce mode (source: documentation OpenStack):

Les interfaces eth1 correspondent au réseau OpenStack proprement dit. C'est sur ce réseau que les compute et le controller node vont communiquer directement.

Lors du lancement d'une instance, on l'attache au bridge br100. Il est bien entendu possible d'avoir plusieurs réseaux déclarés, donc utilisés des ponts sur plusieurs VLAN.

Nous allons ici configurer OpenStack et une instance pour utiliser deux cartes réseaux comme ceci (source: documentation OpenStack):

Pré-requis réseau

Dans un premier temps, installer les paquets nécessaires au fonctionnement des bridges et des VLAN:

compute-node:~# apt-get install vlan ifenslave

Activer le module VLAN:

compute-node:~# modprobe 8021q

Par exemple, configuré les interfaces réseaux d'un compute node comme ceci:

compute-node:~# vi /etc/network/interfaces
auto eth0
iface eth0 inet static
        address 10.0.0.1
        netmask 255.255.255.0
        gateway 10.0.0.254

auto eth1
iface eth1 inet manual

auto br100
iface br100 inet manual
        bridge_stp off
        bridge_fd 0
        bridge_maxwait 0
        bridge_ports eth1.100

auto br101
iface br101 inet manual
        bridge_stp off
        bridge_fd 0
        bridge_maxwait 0
        bridge_ports bond1.101

eth0 est l'interface relié au réseau OpenStack. eth1 est la deuxième interface nous servant à créer des bridges sur des réseaux VLAN. Il est bien entendu possible d'utiliser le bonding pour agréer plusieurs cartes réseaux.

Configuration d'OpenStack

Editer la configuration OpenStack:

compute-node:~# vi /etc/nova/nova.conf
[...]
# NETWORK
network_manager=nova.network.manager.FlatManager
##For injected network informations in instance
flat_injected=true
firewall_driver=nova.virt.libvirt.firewall.IptablesFirewallDriver
# Have nova-network on each compute-node
multi_host=true
[...]

Sur cette configuration, nous ajouté deux options biens pratiques. On demande à OpenStack d'"injecter" la configuration réseau des instances lors de la création de celles-ci et on va utiliser le service nova-network sur chaque noeud de calcul.

Création des réseaux OpenStack

La prochaine étape est de créer les deux réseaux qu'on veut utiliser avec OpenStack:

compute-node:~# nova-manage network create --multi_host=T --fixed_range_v4=172.16.100.0/24 --bridge=br100 --bridge_interface=br100 --num_networks=1 --network_size=256 --label=network100 --gateway=172.16.100.254 --dns1=172.16.100.254
compute-node:~# nova-manage network create --multi_host=T --fixed_range_v4=172.16.101.0/24 --bridge=br100 --bridge_interface=br101 --num_networks=1 --network_size=256 --label=network101 --gateway=172.16.101.254 --dns1=172.16.101.254

On vérifie que les réseaux sont bien créés:

compute-node:~# nova network-list
+--------------------------------------+----------+--------------------+
| ID                                   | Label    | Cidr               |
+--------------------------------------+----------+--------------------+
| 069dedb6-c97a-432c-bcf6-54b2b4311928 | network100    | 172.16.100.0/24    |
| 0c8bd87e-c824-439d-a567-5f37e724292c | network101   | 172.16.101.0/24    |
+--------------------------------------+----------+--------------------+

Note: on peut aussi vérifier la création de ces deux réseaux directement sur la base de données du noeud contrôleur:

controller-node:~# mysql --defaults-extra-file=/etc/mysql/debian.cnf -e "select * from networks\G" nova
*************************** 1. row ***************************
         created_at: 2012-11-27 10:43:39
         updated_at: 2012-11-27 15:34:26
         deleted_at: NULL
            deleted: 0
                 id: 1
           injected: 1
               cidr: 172.16.100.0/24
            netmask: 255.255.255.0
             bridge: br100
            gateway: 172.16.100.254
          broadcast: 172.16.100.255
               dns1: 172.16.100.254
               vlan: NULL
 vpn_public_address: NULL
    vpn_public_port: NULL
vpn_private_address: NULL
         dhcp_start: NULL
         project_id: NULL
               host: NULL
            cidr_v6: NULL
         gateway_v6: NULL
              label: network100
         netmask_v6: NULL
   bridge_interface: br100
         multi_host: 1

*************************** 2. row ***************************
         created_at: 2012-12-26 08:34:13
         updated_at: 2012-12-26 08:42:18
         deleted_at: NULL
            deleted: 0
                 id: 2
           injected: 1
               cidr: 172.16.101.0/24
            netmask: 255.255.255.0
             bridge: br101
            gateway: 172.16.101.254
          broadcast: 172.16.101.255
               dns1: 172.16.101.254
               vlan: NULL
 vpn_public_address: NULL
    vpn_public_port: NULL
vpn_private_address: NULL
         dhcp_start: NULL
         project_id: NULL
               host: NULL
            cidr_v6: NULL
         gateway_v6: NULL
              label: iliad3
         netmask_v6: NULL
   bridge_interface: br101
         multi_host: 1

Création d'une instance avec ces deux réseaux

Maintenant, grâce à la configuration réseau, d'OpenStack et la création des réseaux, nous pouvons lancer une instance comme suit:

compute-node:~# nova boot --flavor 1 --image precise-cloud --nic net-id=069dedb6-c97a-432c-bcf6-54b2b4311928,v4-fixed-ip=172.16.100.2  --nic net-id=0c8bd87e-c824-439d-a567-5f37e724292c,v4-fixed-ip=172.16.101.2  --security_group default instance-nw100-101

Une fois l'instance créée, nous pouvons vérifier sa configuration réseau:

compute-node:~# nova show instance-nw100-101| grep network
| network100 network                       | 172.16.100.2                                            |
| inetwork101 network                       | 172.16.101.2                                           |

Et enfin, vérification des bridges sur le compute node:

compute-node:~# brctl show
bridge name	bridge id		STP enabled	interfaces
br100		8000.00137238fb51	no		eth1.100
                                                        vnet0
br101		8000.00137238fb51	no		bond1.101
							vnet1

On se connecte à l'instance pour vérifier la connectivité réseau:

instance:~$ ping smile.fr -c 1
PING smile.fr (195.154.89.84) 56(84) bytes of data.
64 bytes from 195.154.89.84: icmp_req=1 ttl=46 time=7.24 ms
instance:~$ netstat -rn
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
0.0.0.0         172.16.100.254      0.0.0.0         UG        0 0          0 eth0
172.16.100.0      0.0.0.0         255.255.255.0   U         0 0          0 eth0
172.16.101.0      0.0.0.0         255.255.255.0   U         0 0          0 eth1

Tout est bon ! Par contre, une des deux passerelles a été enlever à la main.

Limitations

Pour que la fonctionnalité des metadatas fonctionnent, vous devez rediriger les requêtes sortant des bridges de type 169.254.169.254 sur le port 80 vers le serveur hébergeant le service nova-api. Ce routage de paquet s'effectue usuellement sur la passerelle du réseau sur lequel l'instance est attaché.

Le filtrage de niveau 3, opéré par iptables, ne fonctionnera pas avec ce mode. Le filtrage offert par l'API OpenStack ne fonctionnera donc pas.

Conclusion

Et voilà, vous savez maintenant comment fonctionne et comment déployer le mode flat network d'OpenStack. Il reste maintenant tous les autres composants OpenStack à voir.

Migrer vos conteneurs OpenVZ vers KVM (OpenStack)

Dans cet article, nous allons vous présenter comment migrer vos conteneurs OpenVZ vers KVM (OpenStack).

Intérêt de la migration

Les deux intérêts majeurs de cette migration sont l'isolation lié à une virtualisation complète de la machine virtuelle et les fonctionnalités noyaux disponible.

Par exemple, il n'est pas possible d'utiliser les tunnels IPSec avec un conteneur OpenVZ.

Explication sur la procédure

Un conteneur OpenVZ ne contient ni noyau, ni grub, ni disque. Ces trois éléments sont indispensables pour que le conteneur puisse être transformé en machine virtuelle. Ce tutoriel consistera principalement à créer un disque virtuel puis à installer le noyau et le grub sur le conteneur.

Pré-requis

Le serveur KVM doit avoir d'installé les paquets suivants:

  • qemu-utils
  • qemu-kvm

Votre client doit avoir un client VNC. Par exemple gvncviewer sous gnome fonctionne très bien.

Le conteneur OpenVZ migré est une debian squeeze.

Première étape: création du disque de la nouvelle VM

Créer une image au format qcow2:

serveur-kvm:~# IMAGE=/tmp/ma_vm.img
serveur-kvm:~# kvm-img create -f qcow $IMAGE 20G
Formatting '/tmp/ma_vm.img', fmt=qcow size=21474836480 encryption=off

Monter la nouvelle image comme un bloc périphérique:

serveur-kvm:~# qemu-nbd -c /dev/nbd1 $IMAGE

Créer la(es) partition(s):

serveur-kvm:~# cfdisk /dev/nbd1

Créer le système de fichier:

serveur-kvm:~# mkfs.ext3 /dev/nbd1p1

Monter la partition du disque virtuel créer:

serveur-kvm:~# MOUNT_POINT=/mnt/ma_vm
serveur-kvm:~# mount /dev/nbd1p1 $MOUNT_POINT

Deuxième étape: copie du conteneur vers le disque virtuel

Copier le conteneur vers le point de montage précédent:

serveur-kvm:~# CONTENEUR_VZ=/tmp/mon_openvz
serveur-kvm:~# rsync -avz --numeric-ids ${CONTENEUR_VZ}/* ${MOUNT_POINT}/

Noter l'usage important de l'opion rsync "numeric-ids" pour bien préserver les droits.

Une fois le conteneur copié, nous allons utilisé chroot pour pré-configuré la machine virtuelle.

Troisième étape: pré-configuration de la machine virtuelle

Chrooter dans la VM:

serveur-kvm:~# chroot ${MOUNT_POINT} -s /bin/bash

Vérifier que vous êtes bien chrooté en vérifiant que le fichier /etc/hosts renvoi bien les informations du conteneur OpenVZ et non du serveur-kvm.

serveur-kvm:~# cat /etc/hosts

Changer le PS1 pour ne pas se tromper de console:

serveur-kvm:~# export PS1="(chroot) $PS1"

Généralement les consoles tty sont désactivées dans un conteneur OpenVZ, réactivez les en ajoutant (ou en dé-commentant les lignes suivantes):

(chroot) serveur-kvm:~# vi /etc/inittab
1:2345:respawn:/sbin/getty 38400 tty1
2:23:respawn:/sbin/getty 38400 tty2
3:23:respawn:/sbin/getty 38400 tty3
4:23:respawn:/sbin/getty 38400 tty4
5:23:respawn:/sbin/getty 38400 tty5
6:23:respawn:/sbin/getty 38400 tty6

Configurer le réseau comme souhaité, dans notre cas, nous utilisons la fonctionnalité DHCP de KVM:

(chroot) serveur-kvm:~# cat /etc/network/interfaces
auto eth0
iface eth0 inet dhcp
(chroot) serveur-kvm:~# cat /etc/resolv.conf
nameserver 8.8.8.8

Ajouter le point de montage correspondant au disque virtuel de la VM:

(chroot) serveur-kvm:~# vi /etc/fstab
/dev/vda1 / ext3 rw,relatime 0 0

Réactiver le mot de passe root, celui-ci sera nécessaire par la suite pour se connecter:

(chroot) serveur-kvm:~# passwd

Et enfin, quitter le chroot:

(chroot) serveur-kvm:~# exit

Quatrième étape: démarrer la machine virtuelle

Avant de démarrer la nouvelle VM, démonter le disque virtuelle. Attention à bien respecter cet étape, sous peine de corrompre définitivement le disque virtuelle:

serveur-kvm:~# umount $MOUNT_POINT
serveur-kvm:~# qemu-nbd -d /dev/nbd1
/dev/nbd1 disconnected

Lancer la VM à l'aide de KVM. Note: cette commande ne rend la main qu'après avoir éteint la VM.

serveur-kvm:~# kvm -m 512 -kernel /boot/vmlinuz-$(uname -r) -initrd /boot/initrd.img-$(uname -r) -append "root=/dev/vda1" -drive file=${IMAGE},if=virtio -net nic,model=virtio -net user -vnc :20 -k fr

Ce qui fait la magie de KVM sont les options -kernel et -initrd. C'est ce qui permet de lancer le conteneur alors qu'il ne contient ni noyau, ni grub à cette étape.

Connecter vous à la VM lancée grâce à VNC:

client:~$ gncviewer serveur-kvm:20

Le clavier sera probablement en qwerty.

Installer les paquets nécessaires:

conteneur-vz:~# aptitude install linux-image-amd64 grub console-tools console-data acpid acpi-support-base
conteneur-vz:~# aptitude reinstall udev
conteneur-vz:~# shutdown -h now

Les paquets console-tools et console-data permettent de régler le mapping clavier.

Les paquets acpid et acpi-support-base sont importants pour gérer correctement les signaux utilisés par KVM. Par exemple, si on souhaite rebooter le serveur KVM, celui-ci enverra un signal ACPI pour éteindre proprement la VM.

Nous réinstallons udev pour être sûr qu'ACPI fonctionne correctement.

Cinquième étape: vérification de la VM

Pour vérifier que la migration a bien fonctionné, relancé la VM dans les options kernel et initrd:

serveur-kvm:~# kvm -m 512 -drive file=${IMAGE},if=virtio -net nic,model=virtio -net user -vnc :20 -k fr

Sixième étape: uploader l'image vers openStack

On ajoute l'image créer à OpenStack:

cloud-controller:~# glance image-create --name=mon_image --disk-format=raw --container-format=ovf < ${IMAGE}
+------------------+--------------------------------------+
| Property         | Value                                |
+------------------+--------------------------------------+
| checksum         | abb4e2ab7ce9cafefeadfa5e1a78d347     |
| container_format | ovf                                  |
| created_at       | 2012-12-12T14:26:37                  |
| deleted          | False                                |
| deleted_at       | None                                 |
| disk_format      | raw                                |
| id               | 62410923-b8a7-4725-99fa-f06ae5cab6b3 |
| is_public        | False                                |
| min_disk         | 0                                    |
| min_ram          | 0                                    |
| name             | mon_image                               |
| owner            | ab2519fd61b8425da392f228f54dc1c3     |
| protected        | False                                |
| size             | 8682160128                           |
| status           | active                               |
| updated_at       | 2012-12-12T14:29:39                  |
+------------------+--------------------------------------+

Et voilà, vous avez migré votre conteneur OpenVZ vers une machine virtuelle KVM et ajouter l'image créée vers OpenStack !

2012-09-27

Using SFTP with ProFTPd

ProFTPd is a daemon designed for FTP access. But did you know it also handles the SFTP protocol ? The main advantages over FTP are:

  • the flows are encrypted (auth and data)
  • there are no issues about active/passive modes

These reasons make SFTP more appealing than FTP (or FTPS: too complex)

Lire la suite...

2012-09-13

Quick Postfix install for CentOS/RedHat

Here is a quick way to get mail working on a CentOS/RedHat setup.

This is also useful for XenServer dom0 hosts.

Install postfix and mail commands:

yum install postfix mailx

If ssmtp is installed, remove it, then reinstall postfix to have the good newaliases command from alternatives.

yum remove ssmtp
yum reinstall postfix

Add a mail alias for the root user:

vi /etc/aliases
# Person who should get root's mail
root:           mail@example.com
newaliases # generate /etc/aliases.db, otherwise postfix won't start

Start postfix:

/etc/init.d/postfix start
# for postfix 2.3.el5_6, the default config is ok

Test:

echo test | mail -stest root
# with -v you will get a bonus debug mail to root

Notes:

  • Postfix should be enabled automatically at boot during install (you can check it with chkconfig --list postfix)
  • If email sent by the server go in the spam box, you may also want to configure the HELO in Postfix with the smtp_helo_name parameter (the HELO should match the reverse DNS of the server outgoing IP).

See also:

2011-07-08

Munin et LazyLoad des images

Je suis un grand fanatique de Munin (http://munin-monitoring.org/) c'est un outil de monitoring très simple (voire simplet parfois) qui fonctionne « tout seul ».

Je le préfère largement à Cacti et d'autres systèmes beaucoup plus complets car avec munin on est certain qu'il n'y aura jamais de maintenance à faire (pas de base de données à gérer, pas d'exécutable complexe à maintenir et mettre à jour...). J'aime aussi l'aspect simplissimme pour créer/ajouter un plugin : simple script à poser dans un dossier et « pouf le graphique apparaît ».

Un défaut que munin possède tout de même réside dans les pages HTML qu'il génère : elles contiennent rapidement un grand nombre d'images PNG et le navigateur rame pour les charger, surtout qu'il le fait plus ou moins de manière séquentielle. C'est embêtant, notamment quand on cherche à voir un graphique précis (par exemple en cliquant sur "System" en face d'une machine dans l'index général) : mais le navigateur charge toutes les images du host avant celle qui nous intéresse : on télécharge des Mo pour rien et on attend pour voir l'image qui nous intéresse... Gachis !

Une solution KISS (comme munin) à ce problème est d'ajouter un système de LazyLoad dans les pages générées par munin. L'idée est de mettre en place du javascript qui ne chargera que les images visibles à l'écran. Celles qui seront "en dessous ou au dessus" dans votre scroll ne seront téléchargées que lorsqu'elles deviennent visibles.

Pour cela c'est très simple... Il faut ajouter le plugin javascript lazyload dans le DocumentRoot :

mkdir /var/www/munin/js
cd /var/www/munin/js
wget http://www.appelsiini.net/projects/lazyload/jquery.lazyload.js

Puis modifier le template utilisé pour générer les pages. Editez le fichier /etc/munin/templates/partial/header.tmpl et ajoutez juste avant le </head>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript" charset="utf-8"></script>
<script src="/js/jquery.lazyload.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
    $(function() {         
        $("img").lazyload({
           effect      : "fadeIn"
        });
    });
</script>

Note : ici la librairie jquery reste téléchargée chez notre ami Google. Vous pouvez choisir de la stocker dans votre DocumentRoot pour éviter de hitter Google à chaque page de votre munin.

C'est tout ! C'est fini ! Il suffit d'attendre que munin regénère les pages HTML (par défaut toutes les 5 minutes sur une installation standard). Pour les impatients et ceux qui ont choisi de générer les HTML a une fréquence moindre vous pouvez regénérer les pages avec la commande su munin -s /bin/sh -c /usr/share/munin/munin-html.

Le résultat est bluffant, on a l'impression que tout va plus vite ! Je pense que cela doit être aussi TRES bénéfique pour ceux qui ont configuré munin pour générer les images à la volée (CGI).

Bien sûr tout le mérite revient à l'auteur de ce plugin jQuery : Mika Tuupola. Son site explique les détails d'utilisation du plugin : http://www.appelsiini.net/projects/lazyload Il nous informe que le plugin n'est pas maintenu et ne fonctionne pas avec les navigateurs récents, mais tous ceux que j'ai essayé fonctionnent parfaitement...

2011-01-24

Page bouchon "self contained"

Dans nos métiers il est classique d'avoir besoin d'une page bouchon que l'on peut mettre en place sur un site pendant sa maintenance pour ne pas montrer une vilaine page d'erreur, ou carément un "conncetion refused".

Il est fastidieux d'avoir toute une arborescence à conserver, et souvent même un VirtualHost à maintenir (que l'on active et désactive).

Souvent notre page bouchon doit être sur un reverse-proxy, et les logiciels classiques (comme varnish par exemple) permettent d'intégrer la page d'erreur dans leur configuration, mais cela reste un simple HTML qui doit "tirer" ses images d'ailleurs. D'autre fois (c'est le cas de squid) on a un dossier spécifique, mais de la même manière les images doivent être hébergées ailleurs...

Une solution simple à ce genre de petit casse tête est de produire la page en incluant dans le HTML tous les éléments nécessaires. Bien sûr pour les script JS et les CSS c'est facile. Pour les images, que ce soit dans le corps de la page ou dans la CSS on peut les intégrer directement dans le source en Base64. Tous les navigateurs décents savent gérer correctement cela. C'est d'ailleurs comme ça que Google distribue les vignettes de sites que l'on peut voir dans les dernières évolutions du moteur.

Dans le HTML on pourra par exemple utiliser :

  <img src="data:image/gif;base64,BASE64STRING" alt="une image" />

Dans le CSS ce sera par exemple :

  background: repeat-x top url("data:image/png;base64,BASE64STRING");

Ceci permet d'avoir une page bouchon "self contained" et transportable. Bien sûr le Base64 rajoute au poids du fichier (de l'ordre de 30%), mais pour des pages simples et des images légères cela reste une bonne solution.

Bien sûr la plupart des MUA en mode client lourd (Thunderbird, Outlook, et tous leurs amis) afficheront correctement les mails formatés de cette manière (puisqu'ils héritent du renderer html de leurs parents).

C'est intéressant car dans ce cas précis le surpoids de volume induit par le base64 n'est plus un argument contre cette solution : en effet si vous voulez envoyer des mails "riche", les images seront de toute façon encodées en Base64 pour le transport SMTP, peut-être qu'a les inclure dans le source du message vous gagneriez en temps de développement ! Pas de MIME à parser !

Pour convertir facilement votre fichier PNG en Base64, il suffit d'utiliser un script tout bête dans votre langage de prédiléction :

<?php
$data = file_get_contents($argv[1]);
$data = base64_encode($data);
file_put_contents($argv[2], $data);
?>

2010-12-24

[rsync] Ignorer les erreurs de fichiers vanished dans un cron

rsync est un excellent outil de sauvegarde et de transfert de fichier. Il est fréquemment appelé depuis la crontab, pour faire une sauvegarde journalière par exemple.

Problème : quand on sauvegarde une arborescence qui "vit", il arrive que des fichiers soient modifiés, ou disparaissent pendant l'exécution de rsync.

rsync gère correctement tous ces cas, mais il affiche des "warnings" sur la sortie d'erreur. Ainsi, la ligne cron suivante :

2 2 * * * rsync -av remote.server.example.com:/path/to/live/directory/ /path/to/backup/ > /path/to/logfile

Pourra envoyer des warnings par mail à l'administrateur du serveur. Exemples de warnings :

file has vanished: "/var/spool/postfix/active/DF00000A000"
rsync warning: some files vanished before they could be transferred (code 24) at main.c(1524) [generator=3.0.3]
WARNING: var/lib/munin/server/file.rrd failed verification -- update discarded (will try again).

Solution 1

Si c'est possible et souhaitable, on exclut les fichiers de la sauvegarde à l'aide d'options --exlude passées à rsync.

Solution 2

On envoie la sortie d'erreur dans un fichier pour l'afficher uniquement si rsync sort un code de retour d'erreur.

Dans un script :

rsync -av remote.server.example.com:/path/to/live/directory/ /path/to/backup/ 2>/tmp/rsync_stderr.log
RET=$?
if [ "$RET" = "24" -o "$RET" = "0" ]
then
    exit 0
else
    echo "rsync return code: $RET" >&2
    cat /tmp/rsync_stderr.log >&2
    exit "$RET"
fi

Si on veut pouvoir lancer plusieurs instances du script en parallèle, on passera par un fichier temporaire :

TEMPFILE=$(mktemp)
trap "rm -f $TEMPFILE" EXIT  # man mktemp; man tempfile
rsync -av remote.server.example.com:/path/to/live/directory/ /path/to/backup/ 2> $TEMPFILE
RET=$?
if [ "$RET" = "24" -o "$RET" = "0" ]
then
    exit 0
else
    echo "rsync return code: $RET" >&2
    cat $TEMPFILE >&2
    exit "$RET"
fi

Solution 3

On utilise un script d'encapsulation (wrapper), dérivé de l'exemple du site officiel de rsync (http://rsync.samba.org/FAQ.html#10).

La méthode utilisée procède par inversion des descripteurs de sortie standard et d'erreur, car un pipe agit uniquement sur la sortie standard.

(/usr/local/bin/rsync.sh)

#!/bin/bash
# filter some rsync error output

# note: 3>&1 1>&2 2>&3 just inverts stdout and stderr
{
rsync "$@" 3>&1 1>&2 2>&3 | grep -v \
        -e "^WARNING:.*update discarded.*" \
        -e "^file has vanished:" \
        -e "^rsync warning: some files vanished"
} 3>&1 1>&2 2>&3

# get return code of first command in pipes (bash only)
RET="${PIPESTATUS[0]}"

# when files vanished, rsync returns 24. We ignore it.
# also see http://rsync.samba.org/FAQ.html#10
if [ "$RET" = "24" ]
then
        exit 0
else
        exit "$RET"
fi

Cette dernière solution est plus "précise" dans le sens où elle affiche les erreurs de manière synchrone, et filtre uniquement les warnings connus. En revanche, elle est un peu plus compliquée.

Liens :

2010-10-21

[OpenBSD] ftp-proxy et le port 20 de la RFC

À coups de tcpdumps, nous avons découvert un comportement curieux du démon ftp-proxy sous OpenBSD.

Par défaut, le ftp-proxy ne respecte pas strictement la RFC du protocole FTP.

En mode actif, il n'utilise pas le port source 20, mais un port aléatoire (ephemeral).

De ce fait, certains clients FTP qui sont à cheval sur la RFC, ou qui sont derrière un firewall strict ne peuvent pas se connecter en mode actif.

La solution se trouve dans le man ftp-proxy d'OpenBSD :

     -r      Rewrite sourceport to 20 in active mode to suit ancient clients
             that insist on this RFC property.

Il suffit d'ajouter l'option -r au lancement du démon, et le tour est joué. Et la ligne ftpproxy_flags="-r" dans /etc/rc.conf.local.

Attention cependant, car dans le code source de ftp-proxy (http://ftp.fr.openbsd.org/pub/OpenB...), on trouve :

pick_proxy_port(void)
{
	/* Random should be good enough for avoiding port collisions. */
	return (IPPORT_HIFIRSTAUTO +
	    arc4random_uniform(IPPORT_HILASTAUTO - IPPORT_HIFIRSTAUTO));
}

Et dans les commentaires :

	 * 3)  Source and destination ports are rewritten to minimize
	 *     port collisions, to aid security (some systems pick weak
	 *     ports) or to satisfy RFC requirements (source port 20).
	 */

En cas de grand nombre de connexions simultanées en provenance d'une même IP, il est donc possible de rencontrer des cas de collisions.

Liens :

2010-08-12

Authentification Linux Debian sur un Active Directory

Voici comment s'authentifier sur un serveur Linux Debian/Ubuntu, avec des comptes utilisateurs stockés sur un serveur Active Directory.

En premier lieu, il convient de bien saisir la différence entre l'identification et l'authentification.

  • L'identification permet simplement l'accès aux informations de l'utilisateur, et l'association entre son UID et son nom. Elle est utilisée par exemple pour afficher le nom de l'utilisateur à partir de l'UID dans la commande ls -l. L'identification est gérée par la libnss.
  • L'authentification permet d'autoriser ou non l'accès au service à l'utilisateur. Elle est gérée par PAM (Pluggable Authentication Modules).

Il est donc nécessaire d'installer 2 paquets : libnss-ldap pour l'identification, et libpam-krb5 pour l'authentification :

aptitude install libnss-ldap libpam-krb5

La configuration de l'identification se fait dans les fichier /etc/libnss-ldap.conf et etc/nsswitch.conf :

Voici un exemple de fichier /etc/libnss-ldap.conf :

base dc=company,dc=com
uri ldap://ad1.intranet ldap://ad2.intranet
referrals no
ldap_version 3
pam_password md5
pam_password md5
nss_base_passwd ou=Users,dc=company,dc=com?sub?objectClass=user
nss_base_group          dc=company,dc=com?sub?&(gidNumber=*)
nss_map_attribute uid msSFU30Name
nss_map_objectclass posixAccount user
nss_map_objectclass shadowAccount user
nss_map_attribute homeDirectory unixHomeDirectory
nss_map_attribute shadowLastChange pwdLastSet
nss_map_objectclass posixGroup group
nss_map_attribute uniqueMember member
pam_login_attribute sAMAccountName
pam_filter objectclass=User
nss_initgroups_ignoreusers avahi,avahi-autoipd,backup,bin,couchdb,daemon,games,gdm,gnats,haldaemon,hplip,irc,kernoops,libuuid,list,lp,mail,man,messagebus,mysql,news,proxy,pulse,root,saned,speech-dispatcher,sshd,statd,sync,sys,syslog,uucp,www-data

Attention : sous Ubuntu le fichier /etc/libnss-ldap.conf est en fait /etc/ldap.conf (voir /usr/share/doc/libnss-ldap/README.Debian).

Et il faut ajouter les mots "ldap" dans /etc/nsswitch.conf :

passwd:         compat ldap
group:          compat ldap

On peut maintenant tester l'identification par :

getent passwd USER

Pour l'authentification, tout se passe dans /etc/krb5.conf et les fichiers /etc/pam.d/common-* :

[libdefaults]
        default_realm = COMPANY.COM

[realms]
        COMPANY.COM = {
                kdc = ad1.intranet
                kdc = ad2.intranet
        }

[domain_realm]
        .intranet = COMPANY.COM

[login]
        krb4_convert = true
        krb4_get_tickets = false

Et pour la configuration PAM, il suffit de rajouter les ligne suivante en haut des fichiers common-auth, common-session, common-account et common-passwd :

auth  sufficient  pam_krb5.so minimum_uid=1000
session  optional  pam_krb5.so minimum_uid=1000
account  required  pam_krb5.so minimum_uid=1000
password  sufficient  pam_krb5.so minimum_uid=1000

(Comme expliqué dans /usr/share/doc/libpam-krb5/README.Debian.)

Voila, on peut maintenant tester l'authentification à l'aide de la commande login, ou en SSH. En cas de problème, aller voir dans le fichier /var/log/auth.log.

Pour aller plus loin, on pourra ajouter la création automatique du dossier de l'utilisateur en ajoutant la ligne suivante dans /etc/pam.d/common-session :

session  required  pam_mkhomedir.so

On peut aussi restreindre l'accès à une liste blanche d'utilisateurs uniquement dans /etc/pam.d/common-auth :

auth  required    pam_listfile.so onerr=fail item=user sense=allow file=/etc/loginusers

Voir aussi man pam_krb5, man pam_mkhomedir et man pam_listfile.

2010-04-16

Des sessions persistantes sous Tomcat 5.5

Pour activer la persistance des sessions quand Tomcat redémarre, il faut ajouter les lignes suivantes dans l'environnement <Context> du fichier conf/context.xml dans le dossier de Tomcat :

<Manager className="org.apache.catalina.session.PersistentManager" saveOnRestart="true" distributable="true">
    <Store className="org.apache.catalina.session.FileStore" directory="sessions" />
</Manager>

Enfin, relancer Tomcat.

Le dossier "sessions" sera créé dans le dossier "work" de tomcat. Exemple : /usr/local/tomcat/work/Catalina/localhost/_/sessions

Notes :

  • Testé sous tomcat 5.5.20
  • Pour avoir des sessions qui durent plusieurs jours, il faut aussi changer la durée de vie du cookie JSESSIONID, ainsi que la durée des sessions dans Tomcat. Ces paramètres peuvent être modifiés dans le code Java de l'application.
  • Pour pouvoir être persistants, les paramètres à conserver en session doivent implémenter l'interface Serializable.

Lien :

2010-03-22

Réécriture de liens sous apache avec mod_substitute

Voici comment utiliser le module apache mod_substitute pour modifier à la volée le contenu envoyé par apache.

Note : cette pratique n'est à utiliser qu'en dernier recours. Il est toujours mieux de faire les modifications à la source (dans le site) quand c'est possible.

À partir de Debian Lenny (Apache 2.2.7 et plus), mod_substitute est installé par défaut avec Apache :

a2enmod substitute
/etc/init.d/apache2 restart

Puis ajouter une configuration de ce genre dans votre virtualhost :

<Location />
        AddOutputFilterByType SUBSTITUTE text/html
        AddOutputFilterByType SUBSTITUTE text/css

        Substitute "s/Hello/Hello world/"
        Substitute "s| src=\"([^\"\?]*)\"| src=\"$1?refresh\"|"
        Substitute "s|link href=\"([^\"\?]*)\"|link href=\"$1?refresh\"|"
        Substitute "s|url\(([^(]*)\)|url($1?refresh)|"
</Location>

Ensuite, on teste la configuration puis on la charge dans Apache.

apache2ctl -S
/etc/init.d/apache2 reload

Maintenant il ne reste plus qu'à tester !

La configuration en exemple remplace bien sûr tous les "Hello" par des "Hello world", mais elle permet aussi de rajouter des "?refresh" à la fin des chemins d'accès aux images et autres éléments du site. Exemple : <img src="monimage.png" /> sera remplacé par <img src="monimage.png?refresh" />.

Cette réécriture permet de changer les URLs des images d'un site, et donc de forcer les navigateurs clients à recharger les contenus. Très utile en cas de mauvaise utilisation de mod_expires et des directives du type : ExpiresByType image/png "access plus 2 years".

Notes :

  • Il existe aussi un module Apache mod_proxy_html dédié aux modifications de contenu HTML, basé sur un parseur SAX. Je n'ai pas réussi à faire fonctionner correctement ce module avec notre site (suppression de l'en-tête DTD, problème de codage). Il faudrait peut-être pousser plus en avant les tests.
  • Attention à vos règles de remplacement : elles peuvent peut-être causer des effets de bord ailleurs dans le site.

Sous version d'Apache antérieure à la 2.2.7 (Debian Etch), vous pouvez utiliser mod_line_edit, avec une configuration telle que :

SetOutputFilter line-editor
SetEnv  LineEdit "text/html;text/css"

LERewriteRule "Hello" "Hello world"
LERewriteRule " src=\"([^\"\?]*)\"" " src=\"$1?refresh\"" R
LERewriteRule "link href=\"([^\"\?]*)\"" "link href=\"$1?refresh\"" R
LERewriteRule "url\(([^(]*)\)" "url($1?refresh)" R

Note : on peut compiler le module Apache à l'aide de la commande apxs2.

2010-03-12

[Xorg] Changement de bureau en ligne de commande

LA commande pour changer de bureau en ligne de commande : wmctrl (window manager controller).

aptitude install wmctrl
wmctrl -s 0
wmctrl -s 1

On peut aussi faire tourner les bureaux par un petit script :

#!/bin/sh

while true
do
        for D in 0 1 2 3
        do
                wmctrl -s $D
                sleep 1
        done
done

Utile pour un écran de surveillance !

Liens :

MAJ 26/03/2010 :

Si vous utilisez les effets visuels 3D, wmctrl -s ne fonctionne pas.

Il faut utiliser @wmctrl -o @ avec des coordonnées X,Y

Voir https://bugs.launchpad.net/ubuntu/+... et man wmctrl.

2010-01-07

[OpenVZ] environnement vzctl enter

Quand on fait vzctl enter depuis un parent OpenVZ pour accéder à une machine virtuelle enfant, on obtient un environnement incomplet (pas d'historique des commandes, mauvaise locale...).

Il faut faire su - pour récupérer un environnement cohérent :

parent:~# vzctl enter enfant
entered into VE 101
enfant:/# echo $LANG

enfant:/# su -
enfant:~# echo $LANG
en_US.UTF-8

Pour palier à ce problème, nous ajoutons les lignes suivantes au début du fichier /root/.bashrc dans l'enfant :

# si l'environement n'est pas bon (vzctl enter ?)
# on lance un shell de login
if [ "$LANG" = "" ]
then
        exec su -
fi

À noter que dans la mesure du possible, il est préférable d'accéder au serveur enfant par SSH, ce qui est plus cohérent d'un point de vue de la virtualisation (isolation parent/enfant). En SSH, il n'y a pas ce problème d'environnement.

2009-12-21

PSSH

PSSH (parallel SSH) permet d'exécuter une commande sur plusieurs serveurs en parallèle. L'exécution d'une commande sur une grappe de serveur est très rapide.

Un avantage de PSSH sur ses alternatives comme DSH est la manière simple d'enregistrer les résultats de l'exécution : toutes les sorties sont envoyées dans un dossier contenant un fichier de sortie par serveur.

Pour installer PSSH sous Debian Lenny :

aptitude install pssh

On crée ensuite notre grappe de serveurs dans un fichier simple, chaque ligne étant de la forme host:port user :

vi /tmp/hosts.txt
serveur1
serveur2
serveur3:222
serveur4 admin

Maintenant, on crée deux dossiers de sortie : un pour les sorties standard, un autre pour les sorties d'erreur.

mkdir /tmp/output
mkdir /tmp/error

Enfin, on lance la commande sur notre grappe de serveurs. Pour tester, on utilise la commande ls :

parallel-ssh -h /tmp/hosts.txt -o /tmp/output/ -e /tmp/error/ ls

PSSH vous permettra d'exécuter votre commande sur plusieurs centaine de serveurs en quelques dizaines de secondes !

Test d'exécution de la commande uptime sur 316 serveurs : 15.548s

Notes :

  • Attention aux commandes destructrices comme parallel-ssh -h /tmp/hosts.txt rm -rf / !!
  • Pour ceux qui ont leur clé privée SSH chiffrée, PSSH ne le gère pas encore : http://code.google.com/p/parallel-s...

Liens :

2009-11-25

[Linux] Bonding

Le bonding est une technique qui permet d'agréger deux ports réseaux d'un serveur sous Linux en un seul.

L'objectif poursuivi est d'obtenir la redondance au niveau des ports réseau du serveur lui-même, en utilisant idéalement deux cartes réseau différentes, et non pas deux ports de la même carte, mais surtout de pouvoir utiliser deux commutateurs distincts et se mettre à l'abri de la panne d'un commutateur.

Il est également possible d'utiliser le bonding pour augmenter le débit, puisqu'on utilise deux ports, mais dans ce cas, il faut que les liens soient connectés au même commutateur. Ce mode ne répond pas à la problématique de haute disponibilité.

Chez Cisco, on parle de Etherchannel. Sous OpenBSD, on appelle ces interfaces des trunks (attention à ne pas confondre avec les liens trunk entre switchs quand on utilise des VLANS).

L'objectif du bonding dans nos infrastructures est d'avoir une infrastructure entièrement redondante en composants réseaux : commutateurs, firewalls, cablages, etc.... Dans notre cas, le bonding fonctionne en mode actif/passif, un seul des ports étant actif à un moment donné.

Avoir une infrastructure réseau redondante assure une haute disponibilité de fonctionnement, mais surtout, permet de procéder à la maintenance des commutateurs sans coupure réseau.

Voici la procédure pour faire du bonding sur une Debian Lenny.

Installation et configuration

  • On installe les outils qui vont nous permettre d'attacher/détacher une interface au bonding :
~# aptitude install ifenslave
  • On modifie ensuite le fichier de configuration réseau :
lenny:~# cat /etc/network/interfaces
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
auto bond0
iface bond0 inet static
      slaves eth0 eth2
      bond_mode active-backup
      bond_miimon 100
      bond_downdelay 200
      bond_updelay 200
      address xxx.xxx.xxx.xxx
      netmask xxx.xxx.xxx.xxx
      network xxx.xxx.xxx.xxx
      gateway xxx.xxx.xxx.xxx

Toutes références aux interfaces attachées au bonding (ici eth0 et eth2) sont supprimées.

Pour les paramètres :

  • slaves permet d'attacher les interfaces spécifiées au bonding. Dans notre cas eth0 et eth1 sont sur la carte mère et eth2 et eth3 sont sur une carte d'extension.
  • bond_mode permet de déterminer le mode d'utilisation : dans notre cas, actif / passif, mais on peut choisir par exemple balance_rr pour faire de l'équilibrage de charge. Voir les options possibles sur le site kernel.org.
  • bond_miimon est le temps en ms passé entre deux monitoring
  • bond_downdelay correspond au temps en ms entre le moment où la carte réseau est détectée comme défaillante et celui où on la retire du bonding.
  • bond_updelay correspond au temps en ms entre le moment où la carte réseau qui était défaillante revient à la vie et celui où elle est remise dans le bonding.

Un redémarrage plus tard (des /etc/init.d/networking restart à distance sur ce genre de manipulations nous ont donné d'assez mauvais résultats ;)), l'interface bond0 doit être visible via un ifconfig.

Références

http://www.kernel.org/doc/Documentation/networking/bonding.txt

2009-11-20

[PGDay.eu 2009] Notes sur les conférences

Nous avons assisté à plusieurs conférences du PostgreSQL Day 2009. Voici quelques éléments clés que nous avons relevés.

PostgreSQL : The Next 20 Years

http://2009.pgday.eu/simon_riggs

  • Long-terme : Un SGBD multi-lingue, capable de parler plusieurs version de SQL (MySQL, Oracle, SQL Server...).
  • Le MVCC implémenté dans Oracle vient en grande partie du projet PostgreSQL (ce dernier étant sous la licence BSD, qui est très permissive).
  • Quand une entreprise externe est prête à payer pour une nouvelle fonctionnalité, le faire plus rapidement (2 ans c'est trop long).
  • Gratifier/Remercier tout le monde et pas seulement ceux qui ont écrit le code (ceux qui documentent, rapportent les bugs, écrivent les tests unitaires...)
  • Il y a très peu de bogues dans PostgreSQL : c'est un produit de qualité.
  • Beaucoup de super idées sont codées par des chercheurs dans leur coin (labos universités). Il faut essayer d'intégrer plus rapidement ces idées dans Postgres.
  • Évidemment : les Forks importants ne sont pas profitables au projet Postgres. Par contre, les petits forks comme POC (Proof of Concept) avec 95% de code en commun, et l'utilisation de git pour gérer ces branches, c'est bien !
  • Plus besoin de VACUUM (aspiration littéralement) à l'avenir.

Retour d'expérience migration Oracle vers PostgresSQL

http://2009.pgday.eu/vincent_moreau

  • Migration des ~400 magasins Leroy Merlin de Oracle vers PostgreSQL par ADEO.
  • Chaque magasin ayant un serveur central sous Postgres, et chaque caisse enregistreuse sous Postgres.
  • Raison économique : Oracle Standard Edition 4000 euros par installation + 22% 4000 euros tous les ans de support.
  • Objectif : Obtenir des performances identiques à Oracle
  • L'opération a consisté à migrer de Oracle9i vers Postgres 9.2
  • Pour la migration des données, utilisation de Ora2Pg, un outil écrit en Perl qui se connecte simultanément aux bases Oracle et Postgres.
  • Pour accélérer la transformation : Utilisation de COPY pour les grosses tables. Création des clés/indexes après l'import, fsync=off et achivage=off dans la config, commit intermédiaire toutes les 20 000 lignes. Suite à ces optimisations, la migration est passée de 4h à 1h30.
  • Dans la crontab : scripts de sauvegarde à chaud + vacuumdb + reindexdb.
  • Quelques problèmes rencontrés (certains indexes non recréés, quelques problématiques de syntaxe sql...), mais rien de bloquant
  • PgFouine pour détecter les requêtes consommatrices (rapport html).

Data warehousing with PostgreSQL

http://2009.pgday.eu/gabriele_bartolini

  • Data warehousing = gros entrepôt de données
  • Ce que PostgreSQL peut apporter.
  • Conception du modèle de données : il est important de garder un modèle de données simple.
  • Postgres permet de placer indexes et données sur des tablespaces différents.
  • Partitionnement horizontal de tables : plusieurs tables héritent d'une table maître avec une règle de partitionnement spécifique. Exemple : une sous-table par année. Mais on peut ensuite faire toutes les requêtes de manière transparente sur la table maître. On peut aussi placer les vieilles tables sur un tablespace moins rapide.
  • On utilise PLProxy pour la "scalabitité" et le "load balancing".
  • PostgreSQL fonctionne sans problème en production avec plusieurs Teras de données.

Utilisation de Postgresql chez HiMedia

http://2009.pgday.eu/dimitri_fontaine

  • Utilisation de Debian pour le système, Nagios pour les alertes et Munin pour le monitoring.
  • Les outils annexes sont très importants dans le monde Postgres. Il ne faut pas hésiter à contribuer !
  • Chez HiMedia, forte utilisation des skytools :
    • londiste pour la replication croisée (répartition de charge)
    • walmgr pour la reprise d'activité avec les journaux de transaction : serveurs esclaves en warm standby, non accessible en lecture mais prêt à prendre la relève en cas de failover
    • pgq pour les traitements par lots
    • pgbouncer : programme de pooling de connexion pour supprimer le temps de création d'une connexion à la base. pgbouncer maintient des connexions actives vers Postgres et ces connexions sont réutilisables. HiMedia utilise pgbouncer devant tous les Postgresql.
    • plproxy pour la distribution des données
  • Utilisation de pgfouine pour traquer les requêtes lentes.

Scaling PostgreSQL Under Fire

http://2009.pgday.eu/gavin_m_roy

  • Par le CTO de myYearBook.com, dans le top 5 des réseaux sociaux aux US.
  • Utilisation de pgBouncer, pgPool II, pl/Proxy.
  • Avantage énorme du partitionnement des tables : permet de sortir facilement les données anciennes ou plus utilisées de la base. (mieux qu'une table que l'on remplit indéfiniment).
  • Postgres est préféré à Mysql car : avec posgreSQL, pas besoin de memcache (ex FaceBook) et les données sans schéma ont un usage limité.
  • Postgres tire parti du cache disque du noyau Linux. Avant d'envoyer des connexions à un frontal, parcours de la base pour charger les données en mémoire, sinon le frontal tombe dès le début.
  • Tirer aussi parti des performances en lecture du RAID disque.
  • Pour accélerer la réindexation, ils n'utilisent pas de clés primaires, mais UNIQUE.
  • Le plugin Nagios check_postgres.pl pour le monitoring fait plein de choses. Il leur est TRÈS utile.
  • Utilisation de [Staplr pour le graphage des perfs de Postgres.
  • Pour le reste : Cacti, Posuta, pgFouine.
  • Et privilégier une configuration avec des CHECKPOINTS (flush/écritures sur le disque) en continu dans le temps, plutôt que des pics.

Performance Enhancements In PostgreSQL 8.4

http://2009.pgday.eu/magnus_hagander

  • Attention aux ORM (Hibernate...), c'est bien, mais pour améliorer les perfs faut mettre les mains dans le camboui.
  • Dans beaucoup de cas, on peut aussi laisser Postgres se débrouiller.
  • Possibilité de VACUUM (aspiration littéralement) partiels uniquement sur les données qui changent.
  • Optimisation de la mise à jour des statistiques (suggestion : stat_temp_file sur un tmpfs ?)
  • pg_restore multi-threaded
  • WITH RECURSIVE permet de faire des requêtes récursives pour récupérer par exemple une arborescence à partir d'une table (id, id_parent).
  • migration pg8.2 -> 8.4 : utiliser pg_dump8.4 pour dumper la base 8.2

The Future of PostgreSQL HA

http://2009.pgday.eu/robert_hodges_simon_riggs

  • Tungsten Replicator, en Java, gère MySQL et Postgres
  • Complexity is the #1 enemy of HA
  • Hot Standby pour le futur : moins de 0,1% de performances en moins que la replication WAL (Write Ahead Logs) actuelle.
  • Impact quasi-nul pour les performances du maître.
  • Esclave en lecture seule : conflits de requêtes possibles mais très rares. Réplication prioritaire : on tuera la requête.
  • Dans la future version : Réplication continue synchrone par streaming de logs
  • Alternatives HA à Postgres, revue de l'existant :
    • MySQL en réplication Master-Master avec une VIP.
    • Réplication semi-synchrone Google (avec MySQL ?) : COMMIT OK s'il s'est fait sur au moins un esclave (pas encore disponible en telechargement).
    • Oracle Flash Back : 1 snapshot toutes les heures, et possibilité d'exécuter un SELECT sur n'importe quel Snapshot. Très pratique si effacement accidentel d'une donnée précise.
    • Drizzle (fork MySQL) : Pluggable replication : replication modulaire à base d'un plugin.
  • Objectif : implémenter un Flash Back dans Postgres, à base de "zoned snapshots"

Welcome to WAL (dev conference)

http://2009.pgday.eu/heikki_linnakangas

  • Conférence technique sur l'implémentation des WAL dans Postgres
  • Dans postgres un fichier de log fait 16Mo, même s'il est plein juste à 1%.
  • Mais possibilité de ne conserver que la partie utile à l'aide de pglesslog ou clearxlogtail.
  • Très utile pour garder beaucoup de logs et faire du PITR.

Bacula et PostgreSQL, optimisation et retour d'expérience

http://2009.pgday.eu/marc_cousin_eric_bollengier

  • Parle de l'utilisation de Postgres comme SGBD pour Bacula
  • Bacula fait BEAUCOUP d'INSERTs vu que chaque fichier a son entrée dans la base.
  • Pour améliorer les perfs : INSERTS dans une table temporaire, puis COPY de cette table à la fin de la sauvegarde dans la table fichiers.
  • En production, utilisation d'un DRBD+Heartbeat pour stocker la base Postgres.
  • YouTube : faroult sql practice

Clustering : la nouvelle donne

http://2009.pgday.eu/stephane_giron_gilles_rayrat

  • Tungsten : solution de clustering maison, basée sur Java, drivers ODBC
  • Gère plusieurs SGBD : MySQL, PostgreSQL, Oracle

Indexation d'une base documentaire pour le quotidien Libération

http://2009.pgday.eu/gael_le_mignot

  • +500 000 articles à indexer, +1 000 000 commentaires en moins de 2 ans
  • Pour un besoin de recherches en backoffice uniquement (PHP).
  • Remplacement d'un serveur d'indexation M$ TextML, par PostgreSQL + SeSQL (Python)
  • Problème de performance pour chercher des articles avec un mot clé trop fréquent comme "gauche".
  • Du coup, pour gérer ce cas il utilise une heuristique qui recherche dans les 2500 derniers articles par exemple (sous requête dans le FROM).
  • Petites lacunes de l'indexation plein texte PostgreSQL : recherche de "france 2" avec les guillemets. Pour la recherche d'une expression entière, postgres fait une recherche avec france, une recherche avec 2, puis fait un LIKE "%france 2%". C'est pas terrible mais ça marche bien dans la majorité des cas.
  • Dans une question à la fin de la conférence, on apprend que la recherche "france 2" est aussi la plus lente chez un fournisseur de blog français très connu !
  • Dommage : pas de comparaison avec Solr+Lucene

PITR made easy

http://2009.pgday.eu/joshua_drake

  • Point In Time Recovery : permet à partir du système de sauvegarde de revenir à un instant T.
  • PITR Tools outils Python très pratique pour gérer la replication par WAL, surtout pratique quand on a plusieurs esclaves.
  • Aussi, envoie un mail quand l'envoi du fichier de log échoue.
  • send_nsca pour le monitoring Nagios de l'envoi des logs.

Liens

2009-11-10

[PostgreSQL] Replication par les archive logs

Prérequis

Tout d'abord, les utilisateurs postgres sur les serveurs maîtres et esclave doivent pouvoir se connecter en ssh dans les deux sens sans mot de passe :

postgres@master~$ ssh slave
postgres@slave~$ ssh master

Il faut aussi installer le paquet postgresql-contrib pour bénéficier de l'outil pg_standby :

master:~# aptitude install postgresql-contrib-8.3
slave:~# aptitude install postgresql-contrib-8.3

Activation des archives logs

On crée le dossier pour les logs sur le slave :

postgres@slave:~$ mkdir /var/lib/postgresql/archivelog/

On active les journaux de transactions. Un journal de transaction est envoyé par rsync vers le serveur esclave dès que le fichier de log est plein (16Mo), ou que le timeout est atteint (1 minute ici).

master:~# vi /etc/postgresql/8.3/main/postgresql.conf
archive_mode = on
archive_command = 'rsync -a %p slave:/var/lib/postgresql/archivelog/%f'
archive_timeout = 60
master:~# /etc/init.d/postgresql-8.3 restart

À ce point, on voit les journaux de transactions locaux, et les journaux archivé à distance :

postgres@master:~$ ls -ltr /var/lib/postgresql/8.3/main/pg_xlog/
postgres@slave:~$ ls -ltr /var/lib/postgresql/archivelog/

En cas de problème, observer le fichier /var/log/postgresql/postgresql-8.3-main.log (problème de rsync...)

Note : un CHECKPOINT est nécessaire pour que le fichier de log soit archivé (toutes les 5min par défaut). On peut le forcer à l'aide de la commande SQL éponyme.

Sauvegarde à chaud du maître

Sur le maître :

postgres@master:~$ psql
postgres=# SELECT pg_start_backup('label');

Sur l'esclave :

postgres@slave:~$ /etc/init.d/postgresql-8.3 stop
postgres@slave:~$ rsync -av --delete --exclude="recovery.conf" master:/var/lib/postgresql/8.3/main/ /var/lib/postgresql/8.3/main/
# on efface les fichiers de logs en gardant le dossier archive_status
postgres@slave:~$ rm -f /var/lib/postgresql/8.3/main/pg_xlog/*

Sur le maître :

postgres=# SELECT pg_stop_backup();

Lancement de la réplication

postgres@slave:~$ vi /var/lib/postgresql/8.3/main/recovery.conf
restore_command = '/usr/lib/postgresql/8.3/bin/pg_standby -d -t /tmp/stopstandby /var/lib/postgresql/archivelog %f %p %r >> /var/log/postgresql/pg_standby.log 2>&1'
postgres@slave:~$ /etc/init.d/postgresql-8.3 start

Maintenant, on peut observer l'injection des fichiers de logs :

postgres@slave:~$ tail -f /var/log/postgresql/pg_standby.log
postgres@slave:~$ less /var/log/postgresql/pg_standby.log
postgres@slave:~$ ps -edf | grep "waiting"
postgres  2908  2907  0 15:22 ?        00:00:00 postgres: startup process   waiting for 000000010000000000000040          

Arrêt de la réplication

Une fois la réplication lancée, toute connexion au serveur est impossible :

postgres@slave:~$ psql
psql: FATAL:  the database system is starting up

On peut casser la réplication en créant le fichier stopstandby :

postgres@slave:~$ touch /tmp/stopstandby

À ce point, pour faire repartir la réplication, il faut refaire une sauvegarde à chaud.

Références

Ouverture du blog des Admins Sys

Bonjour,

Nous ouvrons ce jour le blog des administrateurs système de Smile, dédié aux trucs et astuces systèmes.