Archives pour la catégorie ‘Debian’

Debian : désinstaller les services clients NFS

root@vm:~# apt-get --purge remove nfs-kernel-server nfs-common portmap

Debian : utilisation des cgroups sur un serveur web PHP mutualisé

Les cgroupsgroupes de contrôle – ont pour but de contrôler les ressources systèmes utilisées par un ou plusieurs processus. Les processus sous contrôle sont affectés dans des groupes sur lequels agissent des contrôleurs de ressources. Chaque contrôleur gère un type de ressources :

  • cpuset : allocation CPU (numéro CPU/core CPU).
  • cpuacct :  consommation CPU (nombre de cycles).
  • memory : contrôle de la mémoire vive et de la mémoire swap.
  • devices : contrôle l’accès aux périphériques.
  • blkio : contrôle l’accès aux périphériques de type bloc (ex disque dur).
  • net_cls : contrôle l’accès aux périphériques réseau.

Par défaut, la configuration s’effectue manuellement, ce qui est fastidieux et à réserver en cas d’état de saturation des ressources. Deux démons peuvent ainsi prendre la main pour automatiser la gestion :

  • cgconfig : qui créée la hiérarchie des cgroups.
  • cgrulesengd : qui classe les processus dans les cgroups en fonction de régles spécifiques.

Dans le cadre d’un serveur web, les cgroups sont utiles pour prioritiser les processus du serveur web, de MySQL, PHP (ou tout autre interpréteur), afin de garantir une réactivité du serveur. Ils peuvent également restreindre les ressources CPU de chaque utilisateur afin de garantir un partage équitable des ressources CPU entre chaque processus utilisateur (php, cron, ssh) et éviter une consommation anormale des ressources mémoire et bande passante.

Mon article détaille ainsi la mise en place d’un serveur web mutualisé sous cgroups avec les objectifs suivants :

  • garantir la priorité de toutes les tâches système.
  • limiter les ressources CPU de toutes les tâches des utilisateurs.
  • limiter l’utilisation mémoire vive des tâches utilisateurs et réserver 4 Go pour le système.
  • interdire l’utilisation de la mémoire swap pour les tâches utilisateurs.

Au niveau logiciel, la configuration est la suivante :

  • distribution Debian 6 Squeeze.
  • serveur web Nginx.
  • PHP 5.3.9 en configuration FPM (packages fournis par dotdeb).
  • accès SSH chrooté pour chaque utilisateur.

Chaque utilisateur (client1, client2, etc …) possède son pool de processus PHP attribué, processus qui s’exécutent donc sous son identité. L’ensemble des utilisateurs appartient au groupe secondaire clients. Ainsi, les cgroups vont s’appliquer sur ce groupe secondaire clients. Quant à Nginx, il fait partie automatiquement du cgroup par défaut ; il sera traité et prioritisé comme toute autre tâche système.

Compilation du noyau avec support cgroups

Le noyau fourni avec squeeze n’étant pas configuré pour la gestion des cgroups, il convient d’en compiler un spécifiquement, en veillant à ce que les options suivantes soient identiques. Je précise bien ne pas compiler en module mais en statique :

root@skinner:~# grep -e CONNECTOR -e PROC_EVENTS -e CGROUP /boot/config-2.6.32-bhuisgen
CONFIG_CGROUPS=y
CONFIG_CGROUP_NS=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_MEM_RES_CTLR=y
CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y
CONFIG_CGROUP_SCHED=y
CONFIG_NET_CLS_CGROUP=y
CONFIG_CONNECTOR=y
CONFIG_PROC_EVENTS=y

Pour la procédure de compilation noyau sous Debian, je vous renvoie à mon article précédent. J’ai également mis en ligne le noyau utilisé pour ce serveur, vous pouvez le télécharger ici.

Une fois le serveur redémarré avec le nouveau kernel, vous pouvez vérifier les contrôleurs de ressources disponibles :

root@skinner:/etc# cat /proc/cgroups
#subsys_name    hierarchy    num_cgroups    enabled
cpuset  0    1    1
ns      0    1    1
cpu     1    3    1
cpuacct 2    2    1
memory  4    3    1
devices 3    2    1
freezer 0    1    1
net_cls 0    1    1

Il reste à installer les démons userland pour gérer les cgroups :

root@skinner:~# apt-get install libcgroup cgroup-bin

Configuration des cgroups

root@skinner:~# more /etc/cgconfig.conf
# cgconfig.conf

mount {
   cpu = /mnt/cgroups/cpu;
   cpuacct = /mnt/cgroups/cpuacct;
   devices = /mnt/cgroups/devices;
   memory = /mnt/cgroups/memory;
}

group clients {

   cpu {
      cpu.shares = 512;
   }

   memory {
      memory.memsw.limit_in_bytes = 8G;
      memory.limit_in_bytes = 8G;
   }
}
root@skinner:~# more /etc/cgrules.conf
# /etc/cgrules.conf

@clients    cpu,memory    clients

Création d’un compte utilisateur

root@skinner:~# groupadd -g 2000 clients
root@skinner:~# groupadd -g 2001 client1
root@skinner:~# useradd -m client1 -p pa$$word -u 2001 -g 2001 -G clients -s /bin/false
root@skinner:~# mkdir -p /home/client1/www/{html,lib,logs,tmp}
root@skinner:~# chmod 755 /home/client1
root@skinner:~# chown -R root:root /home/client1
root@skinner:~# chown client1:client1/home/client1/www/html
root@skinner:~# chown client1:client1 /home/client1/www/lib
root@skinner:~# chown client1:client1 /home/client1/www/tmp
root@skinner:~# id client1
uid=2001(client1) gid=2001(client1) groups=2001(client1),2000(clients)

Configuration Nginx / PHP

root@skinner:~# more /etc/nginx/sites-available/client1
server {
    listen        192.168.1.173:80;
    server_name   client1.my.domain *.client1.my.domain;
    root          /home/client1/www/html/;
    access_log    /home/client1/www/logs/access.log main;
    error_log     /home/client1/www/logs/error.log;
    index         index.html index.php;

    location ~ \.php$ {
        fastcgi_pass  unix:/var/run/php-client1.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME /home/client1/www/html$fastcgi_script_name;
        include       fastcgi_params;
    }
}
root@skinner:~# more /etc/php5/fpm/pool.d/client1.conf
[client1]
listen = /var/run/php-$pool.sock
listen.backlog = -1
listen.owner = www-data
listen.group = www-data
listen.mode = 0600
user = $pool
group = $pool

pm = static
pm.max_children = 4
pm.max_requests = 500
access.log = /home/$pool/www/logs/php-$pool.access.log
access.format = %R - %u %t "%m %r%Q%q" %s %f %{mili}d %{kilo}M %C%%
request_terminate_timeout = 35
request_slowlog_timeout = 15
slowlog = /home/$pool/www/logs/php-$pool.log.slow

php_admin_value[disable_functions] = dl, exec, highlight_file, fsockopen, passthru, pcntl_exec, phpinfo, pclose, popen, system, shell_exec, set_time_limit, show_source
php_admin_value[memory_limit] = 64M
php_admin_value[open_basedir] = /home/$pool/www/html:/home/$pool/www/lib:/home/$pool/www/tmp:/home/$pool/www/awstats
php_admin_value[session.save_path] = /var/lib/php5
php_admin_value[upload_tmp_dir] = /home/$pool/www/tmp

Lancement des démons

root@skinner:~# /etc/init.d/cgconfig start
root@skinner:~# /etc/init.d/cgred start
root@skinner:~# /etc/init.d/php-fpm

On peut à présent vérifier que les processus PHP de client1 sont bien attribués à notre cgroup clients au niveau des contrôleurs de ressources CPU et mémoire (RAM+swap) :

root@skinner:~# ps -u client1
PID TTY          TIME CMD
19507 ?        00:00:00 php5-fpm
19508 ?        00:00:00 php5-fpm
19509 ?        00:00:00 php5-fpm
19510 ?        00:00:00 php5-fpm
root@skinner:~# cat /proc/19507/cgroup
8:memory:/clients
7:devices:/sysdefault
6:cpuacct:/sysdefault
5:cpu:/clients

Il est également possible de manipuler à chaud les cgroups en parcourant sa hiérarchie, montée sous Debian dans /mnt/cgroups :

root@skinner~# cd /mnt/cgroups
 root@skinner:/mnt/cgroups# ls -l
total 0
drwxr-xr-x 4 root root 0 Jan 16 11:45 cpu
drwxr-xr-x 3 root root 0 Jan 16 11:45 cpuacct
drwxr-xr-x 3 root root 0 Jan 16 11:45 devices
drwxr-xr-x 4 root root 0 Jan 16 11:45 memory
root@skinner:/mnt/cgroups# ls -l cpu
total 0
-r--r--r-- 1 root root 0 Jan 16 11:45 cgroup.procs
drwxrwxr-x 2 root root 0 Jan 16 11:45 clients
-rw-r--r-- 1 root root 0 Jan 16 11:45 cpu.shares
-rw-r--r-- 1 root root 0 Jan 16 11:45 notify_on_release
-rw-r--r-- 1 root root 0 Jan 16 11:45 release_agent
drwxrwxr-x 2 root root 0 Jan 16 11:45 sysdefault
-rw-r--r-- 1 root root 0 Jan 16 11:45 tasks

Il suffit ensuite de faire les commandes echo appropriées selon les besoins.

Les cgroups représentent donc la brique logicielle indispensable à tout serveur afin de partager et limiter les ressources.

Debian 6 : configuration dual-stack IPv4 / IPv6

root@skinner:~# more /etc/network/interfaces
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
    address 10.0.0.11
    netmask 255.0.0.0
    network 10.0.0.0
    broadcast 10.255.255.255
    gateway 10.0.0.1
    up ip -6 addr add fdfe:cd5e:234c:8277::8/64 dev eth0
    up ip -6 route add default via fdfe:cd5e:234c:8277::1
    down ip -6 addr del fdfe:cd5e:234c:8277::8/64 dev eth0
    down ip -6 route del default via fdfe:cd5e:234c:8277::1

Debian 6 : forcer l’umask par défaut

/etc/pam.d/common-session :

session optional pam_umask.so umask=027

Debian 6 : kernel 2.6.32 avec gestion des cgroups

linux-headers-2.6.32-bhuisgen_2_amd64.deb
linux-headers-2.6.32-bhuisgen_2_amd64.deb.sha1
linux-image-2.6.32-bhuisgen_2_amd64.deb
linux-image-2.6.32-bhuisgen_2_amd64.deb.sha1

Debian : compilation d’un kernel custom sous squeeze

Petit mode d’emploi de la compilation d’un noyau custom sous Debian…

Installation des sources et des dépendances

# apt-get install linux-source-2.6.32
# apt-get install fakeroot bzip2 kernel-package libncurses-dev
# apt-get build-dep linux-source-2.6.32
# cd /usr/src/
# tar xjf linux-source-2.6.32.tar.bz2
# ln -s linux-source-2.6.32 linux

Configuration du noyau

# cd linux
# make clean && make mrproper
# cp /boot/config-`uname -r` .config
# make menuconfig

Compilation du noyau

# make-kpkg clean
# fakeroot make-kpkg --append-to-version "bhuisgen" --revision "1" --us --uc --initrd kernel_image kernel_headers

Installation du noyau

# cd /usr/src
# dpkg -i linux-image-2.6.32-bhuisgen_1_amd64.deb linux-headers-2.6.32-bhuisgen_1_amd64.deb

Debian : serveur de fichiers AFP avec gestion LDAP

Installation et configuration de natatalk

# apt-get build-dep netatalk
# apt-get install libcrack2-dev fakeroot libssl-dev
# apt-get source netatalk
# cd netatalk-2.1.2/
# DEB_BUILD_OPTIONS=ssl dpkg-buildpackage -rfakeroot
# dpkg -i netatalk_2.1.2-2_amd64.deb
# nano /etc/netatalk/afpd.conf
- -tcp -ipaddr 192.168.1.166 -noddp -uamlist uams_dhx2.so -nosavepassword
# nano /etc/netatalk/AppleVolumes.default
/home/share/work work allow:@users perm:770
# mkdir /home/work
# chown root:users /home/share/work
# chmod 770 /home/share/work

Intégration avec Avahi

# apt-get install avahi-daemon libnss-mdns
# touch /etc/avahi/services/afpd.service
# nano /etc/avahi/services/afpd.service
<?xml version= "1.0" standalone='no'?><!--*-nxml-*-->
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
<name replace-wildcards= "yes">%h</name>
<service>
<type>_afpovertcp._tcp</type>
<port>548</port>
</service>
<service>
<type>_device-info._tcp</type>
<port>0</port>
<txt-record>model=Xserve</txt-record>
</service>
</service-group>

Intégration LDAP

# apt-get install libnss-ldap libpam-ldap
# nano /etc/libnss-ldap.conf
# nano /etc/libpam-ldap.conf
uri ldap://192.168.1.254/
base dc=my,dc=domain
ldap_version 3
binddn cn=proxy,dc=my,dc=domain
bindpw 123456
ssl start_tls
tls_checkpeer no
# nano /etc/pam/common-session
#
# /etc/pam.d/common-session - session-related modules common to all services
#
# This file is included from other service-specific PAM config files,
# and should contain a list of modules that define tasks to be performed
# at the start and end of sessions of *any* kind (both interactive and
# non-interactive).
#
# As of pam 1.0.1-6, this file is managed by pam-auth-update by default.
# To take advantage of this, it is recommended that you configure any
# local modules either before or after the default block, and use
# pam-auth-update to manage selection of other modules.  See
# pam-auth-update(8) for details.

# here are the per-package modules (the "Primary" block)
session    [default=1]            pam_permit.so
# here's the fallback if no module succeeds
session    requisite            pam_deny.so
# prime the stack with a positive return value if there isn't one already;
# this avoids us returning an error just because nothing sets a success code
# since the modules above will each just jump around
session    required            pam_permit.so
# and here are more per-package modules (the "Additional" block)
session    required    pam_unix.so
session    optional            pam_ldap.so
# end of pam-auth-update config

session required pam_mkhomedir.so skel=/etc/skel umask=0022

Mise à jour 09/11/2011 :

Si le démon afpd refuse de se lancer automatiquement au démarrage de votre machine, il convient de vérifier la sortie de debug du émon en ajoutant l’option -setuplog « default log_maxdebug ».

Dans le cas où la sortie syslog révèle cette  erreur :

Nov  9 15:44:27 patty afpd[1505]:  "patty"'s signature is  978C0D71D26955DDF9149364E6377FB8
Nov  9 15:44:27 patty afpd[1505]: DSIConfigInit: hostname: patty, ip/port: 192.168.2.200/548,
Nov  9 15:44:27 patty afpd[1505]: dsi_tcp_init: bind: Cannot assign requested address
Nov  9 15:44:27 patty afpd[1505]: dsi_tcp_init: no suitable network config for TCP socket
Nov  9 15:44:27 patty afpd[1505]: main: dsi_init: Cannot assign requested address

il convient d’appliquer ce patch au script de démarrage /etc/init.d/netatalk :

--- netatalk.old    2011-11-09 15:58:00.340749343 +0100
+++ netatalk    2011-11-09 15:48:01.460324452 +0100
@@ -63,6 +63,7 @@
fi

if [ x"$AFPD_RUN" = x"yes" ]; then
+    sleep 4
/usr/sbin/afpd $AFPD_UAMLIST -g $AFPD_GUEST -c $AFPD_MAX_CLIENTS \
-n "$ATALK_NAME$ATALK_ZONE"
echo -n " afpd"

Debian : script de démarrage spawn-fcgi / PHP

# more /etc/init.d/php-fcgi
#! /bin/sh -e
### BEGIN INIT INFO
# Provides:          glassfish
# Required-Start:    $local_fs $remote_fs $network $syslog
# Required-Stop:     $local_fs $remote_fs $network $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts PHP FastCGI
# Description:       starts PHP FastCGI
### END INIT INFO

PATH=/sbin:/usr/sbin:/bin:/usr/bin

NAME=php-fcgi
DESC=php-fcgi
PIDFILE=/var/run/$NAME.pid
USER=root
GROUP=root
SCRIPTNAME=/etc/init.d/$NAME

SPAWN_FCGI=/usr/bin/spawn-fcgi
PHP_FCGI=/usr/bin/php5-cgi
PHP_FCGI_CHILDREN=15
PHP_FCGI_MAX_REQUESTS=1000
PHP_FCGI_SOCKET=/var/run/php-fcgi.sock
PHP_FCGI_SOCKET_USER=www-data
PHP_FCGI_SOCKET_GROUP=www-data
PHP_FCGI_SOCKET_PERMS=600

test -x $SPAWN_FCGI || exit 0
test -x $PHP_FCGI || exit 0

. /lib/lsb/init-functions

SPAWN_FCGI_PARAMETERS="-s $PHP_FCGI_SOCKET -u $PHP_FCGI_SOCKET_USER -g $PHP_FCGI_SOCKET_GROUP -f $PHP_FCGI -C $PHP_FCGI_CHILDREN"

d_start() {
 FCGI_MAX_REQUESTS=$PHP_FCGI_MAX_REQUESTS start-stop-daemon --start \
 --pidfile $PIDFILE --make-pidfile --chuid $USER:$GROUP --chdir /tmp \
 --exec $SPAWN_FCGI -- $SPAWN_FCGI_PARAMETERS
}

d_stop() {
 rm -f $PIDFILE
 rm -f $PHP_FCGI_SOCKET
 killall -q -w -u $PHP_FCGI_SOCKET_USER $PHP_FCGI
 RETVAL=$?
}

d_status() {
 if [ -f "$PIDFILE" ] && ps `cat $PIDFILE` >/dev/null 2>&1; then
 return 0
 else
 return 1
 fi
}

case "$1" in
 start)
 echo "Starting $DESC ..."
 d_start
 ;;

 stop)
 echo "Stopping $DESC ..."
 d_stop
 ;;

 status)
 if d_status; then
 echo "$NAME is running."
 else
 echo "$NAME is not running."
 fi
 ;;

 restart|force-reload)
 echo "Restarting $NAME."
 d_stop
 sleep 1
 d_start
 ;;

 *)
 echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
 exit 1
 ;;
esac

exit 0
Haut de page