
Sommaire :
Le protocole iSCSI est un protocole mis au point en 1998 (date du 1er prototype). Ce protocole sert à fournir une interface standardisée pour transporter du SCSI sur de l’IP (iSCSI = Internet Small Computer System Interface).
1° – Introduction
Appuyé par Cisco & IBM, ils soumettent à l’IETF une proposition de normalisation du protocole en se basant sur les recherches effectuées chez IBM en 2000 mais il faudra attendre 2004 pour que l’IETF valide la norme. Il s’agit donc d’un protocole d’encapsulation : il sert à transporter un protocole de plus haut niveau, le protocole SCSI. Il permet donc d’assurer le transfert de blocs de données à haute vitesse sur un réseaux Ethernet IP. Son plus gros concurrent est le Channel Fiber (beaucoup plus onéreux). L’ iSCSI est utilisé principalement dans le cadre d’une baie de stockage SAN ou d’un serveur NAS voir un DAS.
2° – Un peu de vocabulaire et le contexte !
Alors bien que ça ne nous servira pas des masses ici, qu’est ce qu’un SAN, NAS et DAS :
- SAN (Storage Area Network) : Réseau dédié au stockage . Il permet la mutualisation des systèmes de stockage sur un réseau dédié ne permettant que le transport des informations par blocs (SCSI)
- NAS (Network Attached Storage) : Périphérique de stockage relié à un réseau dans la fonction principale est le stockage centralisé de gros volumes de données. Il partage le même réseau que les serveurs contrairement au SAN qui est sur un réseau dédié.
- DAS (Direct Attached Storage) : Système de disque en attachement direct, par opposition au NAS qui est en attachement réseau. En effet, seuls les ordinateurs auquel il est raccordé y accède, le plus souvent grâce au protocole iSCSI
Ensuite voici la terminologie concernant notre affaire, c’est à dire l’iSCSI :
- Target : Serveur cible qui contient les disques réseau. Autrement dit, celui qui va gérer l’espace de stockage. Il est aussi appelé « Cible ».
- Initiator : Client qui va accueillir le disque réseau qui sera fourni par la « target »
Voici un petit schéma bien plus parlant pour poser le contexte : Mise en garde importante :
- Étant donné que le protocole iSCSI est un protocole réseau en mode block et qu’il est vu comme local par le système, il n’est pas possible de partager un même volume entre plusieurs machines (sauf avec un système de fichier distribué tèl que GFS.
- Ici, même principe que le SAN : il faudra au minimum autant de volume que d’initiateur
Ce que j’appelle « VOLUME » peut être :
- Un fichier en mode block créé avec DD par exemple (cf exemple plus bas)
- Un volume LVM
- Un périphérique disque tel que /dev/sdb ou /dev/sdb1 par exemple
3° – Installation sur le « NAS » ou « SAN » enfin celui qui a les disques :
Dans le monde de l’Open Source, le protocole iSCSI est fournit par l’utilitaire iSCSI Enterprise Target appelé iscsitarget ou daemon « ietd ». Voici la procédure d’installation sur Debian et sur CentOS.
A – Sur debian
# apt-get install iscsitarget iscsitarget-modules-`uname -r`
Il faut ensuite charger le module :
# modprobe iscsi_trgt iSCSI Enterprise Target Software - version 0.4.15 iotype_init(92) register fileio iotype_init(92) register blockio iotype_init(92) register nullio
Puis démarrer le service iSCSI :
# /etc/init.d/iscsitarget start
Pour vérifier si le service est bien démarré :
# /etc/init.d/iscsitarget status iSCSI enterprise target is running at pid 9855
B – Sur CentOS
La, va falloir compiler le module à la mano !! mais ne prenons pas peur :p Tout d’abord, on installe l’environnement nécessaire à la compilation :
# yum install kernel-devel openssl-devel gcc rpm-build
Ensuite, nous allons créer le répertoire qui va nous servir à la compilation et se positionner dedans :
# mkdir /usr/src/iscsitarget# cd /usr/src/iscsitarget
Nous pouvons maintenant récupérer les sources et les dé-tarrer :
# wget [http://dfn.dl.sourceforge.net/sourceforge/iscsitarget/iscsitarget-0.4.15.tar.gz->http://dfn.dl.sourceforge.net/sourceforge/iscsitarget/iscsitarget-0.4.15.tar.gz] # tar xvf iscsitarget-0.4.15.tar.gz
Enfin il ne reste plus qu’a se placer dans le répertoire contenant les sources et de lancer la compilation :
# cd iscsitarget-0.4.15 # make # make install
Nous pouvons maintenant charger le driver :
# modprobe iscsi_trgt iSCSI Enterprise Target Software - version 0.4.15 iotype_init(92) register file ioiotype_init(92) register blockio iotype_init(92) register nullio
4° – Configuration de la « target » ou Cible !! :p
On considèrera ici que nos périphériques iSCSI sont des images sur un disque. Ces images ont été créé par exemple comme suit :
# dd if=/dev/zero of=disk.img bs=1k count=1000
Les fichiers de configuration du démon IET (iSCSI Entreprise Target) se trouvent ici :
- /etc/ietd.conf : fichier contenant la description des différents volumes.
- /etc/initiators.allow : fichier contenant les hôtes autorisés à se connecter
- /etc/default/iscsitarget : sur debian uniquement, pour activer le démarrage du service
Tout d’abord le fichier /etc/ietd.conf. Ce fichier contient donc la description de chaque ressource iSCSI. Voici sa structure :
Target iqn.2010-04.fr.freenux:storage.serveur1.root #IncomingUser Utilisateur monmotdepasse Lun 0 Path=/home/vmfs/serveur1/disk.img,Type=fileio Alias serveur1.root HeaderDigest CRC32C,None DataDigest CRC32C,None MaxConnections 1 InitialR2T No ImmediateData Yes MaxRecvDataSegmentLength 8192 MaxXmitDataSegmentLength 8192 MaxBurstLength 262144 FirstBurstLength 65536 MaxOutstandingR2T 8 HeaderDigest CRC32C,None DataDigest CRC32C,None Wthreads 8
Détaillons un peu plus précisément cette déclaration : Target iqn.2010-04.fr.freenux:storage.serveur1.root Le 1er paramètre, le nom du périphérique ou plutôt son adresse normalisé sous le nom. Il en existe 2 formats :
- Le format IQN (iSCSI Qualified Name). Il est constitué selon le modèle suivant : iqn . Date ( format AAAA-MM) . Domaine . Chaîne unique identifiant le noeud.Par exemple : iqn.2010-04.fr.freenux:storage.serveur1.root
- Le format eui (Enterprise Unique Identifier). Il est constitué de la façon suivante : eui . 16 chiffres hexadécimauxPar exemple : eui.a7502b8efa5903c0
IncomingUser Utilisateur monmotdepasse : Permet de spécifier un login / mot de passe pour accèder à la ressource. (voir 4° Petites notes) Lun 0 Path=/home/vmfs/serveur1/disk.img,Type=fileio : Chemin vers le volume, le périphérique de stockage, ou un périphérique de type LVM.
- Le Type fileio permet de faire le mappage entre le Lun et un périphériques de bloc de type sdX ou hdX ou encore un périphérique de bloc virtuel comme LVM ou même un fichier régulier.
- Le Type blockio lui va effectuer des I/O directs sans passer par le « page-cache » pour tout les opération de lecture / écriture. Cela permet des traitements plus efficace durant le transfert des secteurs dans un environnement virtualisé.
Alias serveur1.root : Optionnel : définition d’un alias afin d’avoir un nom plus « sexy » Les autres options sont les suivantes : MaxConnections 1 : Spécifie le nombre maximum de connexion simultané InitialR2T No : Positionner à YES, l’initiateur doit attendre la target pour être solicité avant d’envoyer les données. En le positionnant à NO, on autorise l’initiateur à envoyer une rafale de bit non sollicité avec une commande avant ou après (en fonction de l’option ImmediateData) afin d’envoyer les données. Afin d’amélioré les performances, le positionner à NO. ImmediateData Yes : Permet à l’initiateur d’envoyer de données non solicité à une commande. Afin d’améliorer les performances, le possionner à Yes MaxRecvDataSegmentLength 8192 Définit la taille maximum du segment de donnée qui peut être reçut. Le valeur devrait être fixé avec un multiples de PAGE_SIZE. La configuration d’une valeur trop grandes peut entraîner des problèmes d’allocation mémoire. La valeur par defaut est de 8 192 MaxXmitDataSegmentLength 8192 Définit la taille maximum du segment de donnée qui peut être envoyé. Même principe que ci-dessus MaxBurstLength 262144 Définit la valeur maximal qu’un message sollicité ou non peut envoyer en un seul burst. FirstBurstLength 65536 Définit la quantité de données non sollicitées que l’initiateur peut transmettre à la première rafale soit avec la commande ou juste après, en fonction des paramètres de InitialR2T et ImmediateData MaxOutstandingR2T 8 Contrôle le nombre maximum de transferts de données que la cible peut demander à la fois HeaderDigest CRC32C,None Active le checksum du header afin de valider son intégrité. DataDigest CRC32C,None Active le checksum des données afin de valider son intégrité wthreads 8 La cible iSCSI utilise plusieurs threads pour exécuter les fonctions d’entrée et sortie sur le périphérique de bloc. En fonction du matériel et de la charge induite, le nombre de ces fils peuvent être soigneusement réglée. 8 semble suffisant dans la majorité des cas Passons ensuite le fichier /etc/initiators.allow. Ce fichier contient les hôtes autorisés, un peu à la manière du fichiere host.allow. Voici un extrait :
iqn.2001-04.com.example:storage.disk1.sys1.xyz ALL iqn.2001-04.com.example:storage.disk1.sys2.xyz 192.168.12.2, 192.168.3.0/24, 192.167.1.16/28 iqn.2001-04.com.example:storage.disk1.sys4.xyz [3ffe:302:11:1:211:43ff:fe31:5ae2], [3ffe:505:2:1::]/64 ALL ALL
L’exemple parle de lui même. On y met l’adresse IQN du périphérique iSCSI, puis l’adress IP v4 ou v6 de l’hôte autorisé ou un plage réseau entière, séparé entre eux par une virgule. Il est possible également de mettre ALL ALL comme ça tout le monde y’ a le droit !!! Pas très sécure en tout cas ! Bref Une fois ces fichiers correctement configurés, il suffit de redémarrer le service iSCSI : IET (iSCSI Entreprise Target) :
# /etc/init.d/iscsitarget restart
Pour vérifier si les volumes apparaisent bien :
# cat /proc/net/iet/volume tid:5 name:iqn.2010-04.fr.freenux:storage.srv2.swap lun:0 state:0 iotype:fileio iomode:wt path:/home/vmfs/srv2/swap.img tid:4 name:iqn.2010-04.fr.freenux:storage.srv2.home lun:0 state:0 iotype:fileio iomode:wt path:/home/vmfs/srv2/home.img tid:3 name:iqn.2010-04.fr.freenux:storage.srv2.root lun:0 state:0 iotype:fileio iomode:wt path:/home/vmfs/srv2/disk.img tid:2 name:iqn.2010-04.fr.freenux:storage.srv1.swap lun:0 state:0 iotype:fileio iomode:wt path:/home/vmfs/srv2/swap.img tid:1 name:iqn.2010-04.fr.freenux:storage.srv1.root lun:0 state:0 iotype:fileio iomode:wt path:/home/vmfs/srv2/disk.img
Nous pouvons voir ici 5 volumes déclarés.
5° – Installation de l’initiateur (client)
Sous Debian, l’installation de l’initiateur est très simple :
# apt-get install open-iscsi iscsitarget-modules-`uname -r`
Les fichiers de configuration se trouvent dans le répertoire /etc/iscsi. Tout d’abord, donnons un petit nom à l’initiateur :
emacs /etc/iscsi/initiatorname.iscsi InitiatorName=iqn.2010-04.fr.frenux.srv1:01:ae1ab85a3718
Le nom se compose comme suit, selon la norme IQN définit plus haut : iqn . Date (format AAAA-MM) . Le nom du serveur à l’envers : un id unique Ensuite il ne reste plus qu’a lancer la découverte des périphérique iSCSI en donnant l’adresse de la TARGET via le mode « SendTargets », seul mode implémenté sous linux aujourd’hui. Les autres modes sont le mode SLP (utilisé par CUPS par ex) et le mode iSNS (comme le SNS pour le fiber channel) :
# iscsiadm -m discovery -t st -p 192.168.1.1192.168.1.1:3260,1 iqn.2010-04.fr.freenux:storage.srv2.home192.168.1.1:3260,1 iqn.2010-04.fr.freenux:storage.srv2.swap192.168.1.1:3260,1 iqn.2010-04.fr.freenux:storage.srv2.root192.168.1.1:3260,1 iqn.2010-04.fr.freenux:storage.srv1.home192.168.1.1:3260,1 iqn.2010-04.fr.freenux:storage.srv1.root
La découverte se passe ainsi :
- L’initiator effectue des requêtes de découverte (SendTargets) vers les targets qu’il connait grâce au fichier de configuration.
- Chaque target iSCSI retourne les noms des cibles disponibles à l’initiateur.
- L’initiateur essaye de se connecter et reçoit les ID des cibles.
- L’initiateur iSCSI demande les infos pour chaque périphérique.
- Il crée enfin une table des périphériques disponibles.
Enfin il ne reste plus qu’a rattacher le périphérique à l’initiateur :
# iscsiadm -m node -T iqn.2010-04.fr.freenux:storage.srv1.root -p 192.168.1.1 -l
Pour vérifier s’il est bien vu par l’OS, dans les logs du noyau vous devez voir ceci :
dmesg | less [41.246371] scsi 2:0:0:0: Direct-Access IET VIRTUAL-DISK 0 PQ: 0 ANSI: 4 [41.246371] sd 2:0:0:0: [sdb] 2097152 512-byte hardware sectors (1074 MB) [41.250383] sd 2:0:0:0: [sdb] Write Protect is off [41.250383] sd 2:0:0:0: [sdb] Mode Sense: 77 00 00 08 [41.250383] sd 2:0:0:0: [sdb] Write cache: disabled, read cache: enabled, doesn't support DPO or FUA [41.250383] sd 2:0:0:0: [sdb] 2097152 512-byte hardware sectors (1074 MB) [41.250383] sd 2:0:0:0: [sdb] Write Protect is off[41.250383] sd 2:0:0:0: [sdb] Mode Sense: 77 00 00 08 [41.250383] sd 2:0:0:0: [sdb] Write cache: disabled, read cache: enabled, doesn't support DPO or FUA [41.250383] sdb: unknown partition table [41.257320] sd 2:0:0:0: [sdb] Attached SCSI disk
Obtenir des infos sur le périphérique iSCSI :
# udevinfo -q symlink -n /dev/sdb block/8:16 disk/by-id/scsi-14945540000000000000000000600000011a0650301008000 disk/by-path/ip-192.168.1.20:3260-iscsi-iqn.2010-04.fr.freenux:storage.srv1.swap-lun-0 disk/by-uuid/089a79df-2cd1-470f-b470-8d5ebb2a64b2
Lister les périphériques vu par le système :
# cat /proc/scsi/scsi Attached devices: Host: scsi0 Channel: 00 Id: 00 Lun: 00 Vendor: ATA Model: Maxtor 6L080M0 Rev: BANC Type: Direct-Access ANSI SCSI revision: 05 Host: scsi2 Channel: 00 Id: 00 Lun: 00 Vendor: IET Model: VIRTUAL-DISK Rev: 0 Type: Direct-Access ANSI SCSI revision: 04 Host: scsi4 Channel: 00 Id: 00 Lun: 00 Vendor: IET Model: VIRTUAL-DISK Rev: 0 Type: Direct-Access ANSI SCSI revision: 04
Pour démonter le disque :
# iscsiadm –m node –T iqn.2010-04.fr.freenux:storage.srv1.root –p 192.168.1.1 -u
6° – Petites notes
Pour tout déconnecter d’un seul coup :
# iscsiadm -m node -p 192.168.1.1 -u
Pour tout connecter d’un seul coup :
# iscsiadm -m node -p 192.168.1.1 -l
A priori, à chaque reboot, on aimerait bien que les volumes soient de nouveau la ! Pour faire cela, il faut rendre le montage des volumes persistant :
# iscsiadm -m node -T iqn.2010-04.fr.freenux:storage.srv1.root -p 192.168.1.1 -o update -n 'node.conn[0].startup' -v automatic
Il est important de refaire un discover à chaque ajout de volume sur la target :
# iscsiadm --mode discovery --type sendtargets --portal 192.168.1.1
Pour voir les sessions lancées sur la TARGET :
# cat /proc/net/iet/session
Pour avoir des infos sur le périphérique vu par l’initiateur :
# iscsiadm -m node -T iqn.2010-04.fr.freenux:storage.srv2.home -p 192.168.1.1 node.name = iqn.2010-04.fr.freenux:storage.srv2.home node.tpgt = 1 node.startup = automaticiface.hwaddress = default iface.iscsi_ifacename = default iface.net_ifacename = default iface.transport_name = tcp iface.initiatorname = node.discovery_address = 192.168.1.1 node.discovery_port = 3260 node.discovery_type = send_targets node.session.initial_cmdsn = 0 node.session.initial_login_retry_max = 8 node.session.cmds_max = 128 node.session.queue_depth = 32 node.session.auth.authmethod = None node.session.auth.username = node.session.auth.password = node.session.auth.username_in = node.session.auth.password_in = node.session.timeo.replacement_timeout = 120 node.session.err_timeo.abort_timeout = 15 node.session.err_timeo.lu_reset_timeout = 20 node.session.err_timeo.host_reset_timeout = 60 node.session.iscsi.FastAbort = Yes node.session.iscsi.InitialR2T = No node.session.iscsi.ImmediateData = Yes node.session.iscsi.FirstBurstLength = 262144 node.session.iscsi.MaxBurstLength = 16776192 node.session.iscsi.DefaultTime2Retain = 0 node.session.iscsi.DefaultTime2Wait = 2 node.session.iscsi.MaxConnections = 1 node.session.iscsi.MaxOutstandingR2T = 1 node.session.iscsi.ERL = 0 node.conn[0].address = 192.168.1.1 node.conn[0].port = 3260 node.conn[0].startup = manual node.conn[0].tcp.window_size = 524288 node.conn[0].tcp.type_of_service = 0 node.conn[0].timeo.logout_timeout = 15 node.conn[0].timeo.login_timeout = 15 node.conn[0].timeo.auth_timeout = 45 node.conn[0].timeo.noop_out_interval = 5 node.conn[0].timeo.noop_out_timeout = 5 node.conn[0].iscsi.MaxRecvDataSegmentLength = 131072 node.conn[0].iscsi.HeaderDigest = None node.conn[0].iscsi.DataDigest = None node.conn[0].iscsi.IFMarker = No node.conn[0].iscsi.OFMarker = No
Connexion d’un volume avec authentification : Si vous avez renseigner dans le fichier de conf de la target un IncomingUser avec login / mot de passe, vous devez vous identifier auprès de la Target :
# iscsiadm -m node -T iqn.2010-04.fr.freenux:storage.srv1.root -p 192.168.1.1 -o update -n node.session.auth.authmethod -v CHAP # iscsiadm -m node -T iqn.2010-04.fr.freenux:storage.srv1.root -p 192.168.1.1 -o update -n node.session.auth.username -v utilisateur # iscsiadm -m node -T iqn.2010-04.fr.freenux:storage.srv1.root -p 192.168.1.1 -o update -n node.session.auth.password -v monmotdepasse
Informations à partir de l’initiateur sur un volume :
# iscsiadm -m session -r 2 --stats Stats for session [sid: 2, target: iqn.2010-04.fr.freenux:storage.srv1.home, portal : 192.168.1.1,3260] iSCSI SNMP: txdata_octets: 1995827400 rxdata_octets: 267972740 noptx_pdus: 0 scsicmd_pdus: 249551 tmfcmd_pdus: 0 login_pdus: 0 text_pdus: 0 dataout_pdus: 87558 logout_pdus: 0 snack_pdus: 0 noprx_pdus: 0 scsirsp_pdus: 249551 tmfrsp_pdus: 0 textrsp_pdus: 0 datain_pdus: 32906 logoutrsp_pdus: 0 r2t_pdus: 35420 async_pdus: 0 rjt_pdus: 0 digest_err: 0 timeout_err: 0 iSCSI Extended: tx_sendpage_failures: 0 rx_discontiguous_hdr: 0 eh_abort_cnt: 0
Pour tout les périphériques :
# iscsiadm -m session --stats
Pour avoir des infos sur les sessions établies :
# iscsiadm -m session tcp: [1] 192.168.1.1:3260,1 iqn.2010-04.fr.freenux:storage.srv1.swap tcp: [2] 192.168.1.1:3260,1 iqn.2010-04.fr.freenux:storage.srv1.root tcp: [3] 192.168.1.1:3260,1 iqn.2010-04.fr.freenux:storage.srv2.swap tcp: [4] 192.168.1.1:3260,1 iqn.2010-04.fr.freenux:storage.srv2.root tcp: [5] 192.168.1.1:3260,1 iqn.2010-04.fr.freenux:storage.srv2.home
7° – Udev pour fixer le nom des volumes
Le souci c’est qu’en fonction de l’ordre ou les périphériques sont détecté, le nom peut varier d’un reboot à l’autre. Afin de fixer cela, on va demander à Udev de renommer le périphérique de sorte qu’a chaque reboot, il garde son petit nom. Pour faire ceci, créez le fichier suivant :
# emacs /etc/udev/rules.d/95-iscsi.rules
Et ajoutez dedans :
KERNEL=='sd*', BUS=='scsi', PROGRAM='/lib/udev/iscsidev.sh %b', SYMLINK+='iscsi/%c{1}'
Ensuite nous allons ajouter le script iscsidev.sh :
# emacs /lib/udev/iscsidev.sh
Voici le script en question :
#!/bin/sh BUS=${1} HOST=${BUS%%:*} file='/sys/class/scsi_host/host${HOST}/device/session*/iscsi_session*/targetname' target_name=`echo $(cat ${file}) | sed -r -e 's/(^.*-[^-]*)$/\1/'` if [ -z '${target_name}' ]; then exit 1 fi echo '${target_name}'
On n’oublie pas de rendre le script exécutable :
# chmod 711 /lib/udev/iscsidev.sh
Et de redémarrer udev et l’initiateur :
# /etc/init.d/udev restart && /etc/init.d/open-iscsi restart
On peut maintenant lister les divers périphériques iSCSI dans le répertoire /dev/iscsi :
# ls /dev/iscsi/ iqn.2010-04.fr.freenux:storage.srv1.root iqn.2010-04.fr.freenux:storage.srv1.home iqn.2010-04.fr.freenux:storage.srv2.root iqn.2010-04.fr.freenux:storage.srv1.swap iqn.2010-04.fr.freenux:storage.srv2.home iqn.2010-04.fr.freenux:storage.srv2.swap
8° – Conclusion
Voilou un petit tour d’horizon rapide de l’implémentation du protocole iSCSI sur une plate-forme Linux. Tout les aspects n’ont pas été abordés dans cette article. En effet le sujet est bien plus vaste et l’implémentation d’un tel protocole se fait dans un contexte bien particulier en général (infrastructure réseau avec redondance et tolérance de panne).
Article lu 3303 fois
Merci beaucoup!! Je teste depuis 3 jours, et c’est top!!
Très instructif merci pour le travail je vais tester de ce pas