Skip to main content

204.2 Ajustando o acesso aos dispositivos de Armazenamento


Este tópico mostra alguns tipos de dispositivos de armazenamento e fala principalmente sobre iSCI.



IDE/ATA


O ATA é a evolução do IDE, a maioria das placas dessa época possuiam duas conexões IDEs na placa, a conexão IDE é feita por meio de cabo flat, cada cabo possui três conexões, uma vai na placa mãe e duas são para os HDs, onde uma dessas conexões serão o master e a outra será o slave.

No LInux é reconhecido como /dev/hda, /dev/hdb e assim por diante.


ATA-IDE



Esse era o padrão, não é possível ter apenas um slave (sem master), mas é possível ter master (sem slave). Se tiver conectado apenas o master do IDE0 e o master do IDE1 o linux vai reconhecer apenas HDA e HDC.


IDE-SATA-1



SATA - Serial Advanced Technology Attachment


Sucessor do ATA/PATA, nesse novo padrão, podemos fazer a troca do disco em hot-swap (funciona com hotplug, então trocar o dispositivo com a maquina ligada é chamado de hot-swap).


Aqui só podemos ter 1 disco por cabo ou interface, é muito mais rápido que o ATA e seu reconhecimento é /dev/sda, /dev/sdb, /dev/sdc e assim por diante. Usa o mesmo mapeamento de discos SCSI, mesmo não sendo, isso acontece porque seu mapeamento original já acontece no formato de discos scsi.



SCSI


O SCSI (Small Computer System Interface) é um conjunto de padrões que define como dispositivos de armazenamento e periféricos se comunicam com computadores. Embora tenha surgido nos anos 80 como uma interface física (com cabos e conectores específicos), seu conceito evoluiu, e hoje o SCSI está mais vivo do que nunca em forma lógica, especialmente no Linux.


Mesmo que você esteja usando discos SATA, SAS, iSCSI ou NVMe, o kernel Linux frequentemente os expõe como dispositivos do subsistema SCSI. Isso significa que o gerenciamento de discos no Linux é feito em grande parte por meio da infraestrutura SCSI do kernel.


Por exemplo:

  • /dev/sda, /dev/sdb etc. são dispositivos tratados como discos SCSI.
  • /sys/class/scsi_device/ contém informações de dispositivos SCSI.
  • Ferramentas como sg_map, sg_inq, lsscsi, sdparm, sg3_utils operam sobre esse subsistema

Hoje, o termo "SCSI" é mais relacionado ao protocolo de comando do que ao barramento físico. Ou seja, tecnologias modernas como:

  • iSCSI (SCSI sobre IP)
  • USB Mass Storage (usa comandos SCSI)
  • SATA e SAS (podem encapsular comandos SCSI)
  • Fibre Channel (FC) com SCSI

Todos esses utilizam comandos SCSI, mesmo que fisicamente sejam outra coisa.



Barramento SCSI


O barramento físico clássico do SCSI, permitia a transferência de dados em altas velocidades. No modelo original de barramento físico SCSI paralelo, existiam duas variantes principais:

  • Barramento SCSI de 8 bits (narrow SCSI) Permitía conectar até 7 dispositivos a um único barramento, além da controladora (total de 8 IDs: 0 a 7).

  • Barramento SCSI de 16 bits (wide SCSI) Suportava até 15 dispositivos mais a controladora (total de 16 IDs: 0 a 15).

Em ambos os casos, cada dispositivo precisava de um ID exclusivo no barramento, e a controladora geralmente usava o ID mais alto disponível (7 no narrow, 15 no wide).


No modelo SCSI, cada dispositivo é identificado logicamente por três elementos: Canal, ID e LUN (Logical Unit Number). Esses identificadores ainda são utilizados no Linux moderno, mesmo com tecnologias como SATA, USB ou iSCSI, pois o subsistema SCSI do kernel mantém esse esquema.


Você pode visualizar esses identificadores com comandos como lsscsi, scsi_info ou cat /proc/scsi/scsi.

  • Canal (Channel ID) Representa o adaptador ou barramento detectado pelo sistema.

  • ID (Target ID ou SCSI ID) Identifica o dispositivo dentro daquele canal. No barramento físico, esse valor variava de 0 a 7 (8 bits) ou de 0 a 15 (16 bits).

  • LUN – Logical Unit Number Identifica a unidade lógica dentro de um mesmo ID, por exemplo, um volume lógico ou partição em uma controladora RAID.


O mapeamento desses dispositivos no Linux moderno é semelhante ao SATA, e as informações podem ser encontradas em /proc/scsi/scsi ou nos diretórios do sysfs, como /sys/class/scsi_device/.



hdparm


Usado para verificar e até mesmo configurar parâmetros em dispositivos SATA/IDE. As opções mais comuns são:


OpçãoDescrição
-iMostra a identificação do dispositivo.
-tFaz teste de velocidade de leitura.
-TFaz teste de velocidade de leitura de cache.
-dExibe ou configura a flag using_dma para um dispositivo.
-WExibe ou configura o write-caching.
-vSimilar ao rodar sem opção alguma.

Vamos ver alguns exemplos:

# Configurando o disco para usar DMA (não funciona para Sata):
$ sudo hdparm -vd 1 /dev/vda1

/dev/vda1:
setting using_dma to 1 (on)


# Desativando o DMA (não funciona para Sata):
$ sudo hdparm -vd 0 /dev/vda1

/dev/vda1:
setting using_dma to 0 (off)


# Fazendo testes de velocidade de leitura de cache:
$ sudo hdparm -T /dev/vda1

/dev/vda1:
Timing cached reads: 21160 MB in 1.99 seconds = 10625.40 MB/sec


# Fazendo testes de velocidade de leitura:
$ sudo hdparm -t /dev/vda1

/dev/vda1:
Timing buffered disk reads: 486 MB in 1.02 seconds = 476.54 MB/sec


sdparm


Similar ao hdparm, mas nesse caso é usado para SCSI (precisa instalar o pacote sdparm).



sysctl


Reveja esse comando aqui.



Write Caching


O cache de gravação (ou write cache) é um recurso disponível na maioria dos discos rígidos que permite coletar todos os dados na memória de cache HD, antes de serem gravados permanentemente no disco. Depois que os dados são coletados vão ser transferidos e armazenados (escritos no disco) num único evento; é como agrupar todos os dados que precisam ser escrito no disco num grande pacote e escrever todo esse pacote lá ao invés de realizar diversos eventos de escrita (diminui a taxa de escrita).


Por padrão já vem habilitado, essa função é de extrema importância para os SSDs pois eles possuem um número de clicos de escrita e remoção dos dados. Ativar esse recurso prolonga a vida útil do dispositivo. SSDs utilizam memória flash, que tem um número finito de ciclos de escrita/apagamento por célula. Otimizar o uso dessas células com mecanismos como o write cache (e também wear leveling, TRIM, etc.) é essencial para garantir maior durabilidade.


Vale observar que há riscos em manter o write cache ativado sem mecanismos adequados de proteção contra perda de energia. Se o sistema desligar de forma abrupta (queda de energia, por exemplo), dados ainda não gravados no disco (mas que estavam na cache) podem ser perdidos. Por isso, em servidores críticos, é comum combinar write cache com baterias de proteção (BBU) ou usar sistemas de arquivos com journaling robusto e sincronização forçada (fsync).


# Verificar se o write cache está ativado:
sudo hdparm -W /dev/sdX

Se estiver ativado, a saída será algo como:

write-caching =  1 (on)

Para ativar o write cache, faça:

sudo hdparm -W1 /dev/sdX

Para desativar o write cache, faça:

sudo hdparm -W0 /dev/sdX

Usando o SDPARM:

# Verificar o write cache. '1' = ativado e '0' = desativado:
sudo sdparm -a /dev/sdX | grep WCE

# Ativar:
sudo sdparm --set=WCE /dev/sdX

# Desativar:
sudo sdparm --clear=WCE /dev/sdX

Outra forma de ativar é usando o comando smartctl (disponível no pacote smartmontools):

smartctl -s wcache,on /dev/sda

Para configurar via smartclt, vai depender do firmware e do driver do disco/controladora. O -s (ou --set) serve para modificar parâmetros do dispositivo, e a opção wcache,on tenta ligar o write cache via ATA/SCSI passthrough.



NVME


Reveja esse comando aqui.


Podemos instalar um utilitário para gerenciar o nvme:

$ sudo apt install nvme-cli

# Podemos listar os NVMEs do sistema:
$ sudo nvme list
Node SN Model Namespace Usage Format FW Rev
---------------- -------------------- ---------------------------------------- --------- -------------------------- ---------------- --------
/dev/nvme0n1 EJ78N696610108S3N PC300 NVMe SK hynix 512GB 1 512,11 GB / 512,11 GB 512 B + 0 B 20005A00


FSTRIM


Quando você deleta um arquivo em um sistema de arquivos (como ext4, btrfs, xfs, etc.), o sistema marca aquele espaço como "livre", mas o SSD ainda enxerga os blocos como ocupados, porque não foi avisado explicitamente de que pode reutilizá-los. É aí que entra o TRIM.


O comando fstrim (ou a opção discard) informa ao SSD quais blocos não estão mais em uso, permitindo que o dispositivo:

  • limpe esses blocos internamente (o que ele precisa fazer antes de poder escrever neles de novo);
  • melhore o desempenho futuro de escrita (porque não vai precisar apagar blocos antes de escrever neles);
  • ajuda no balanceamento de desgaste (wear leveling), prolongando a vida útil do SSD.

O TRIM ativa operações internas no SSD, o que pode gerar escrita adicional em alguns modelos de baixa qualidade. Mas isso é exceção. Para SSDs decentes, rodar fstrim uma vez por semana está ótimo e não deve causar problemas.


O dispositivo de armazenamento deve suportar o Trim para que possa ser aplicado. Ele pode conseguir recuperar blocos que estão sendo usados.


# Para aplicar manualmente:
sudo fstrim -v /

# Para agendar automaticamente (recomendado):
sudo systemctl enable fstrim.timer
sudo systemctl start fstrim.timer

# Rodando em todos os filesystems montados:
$ sudo fstrim -a

# Rodando num único filesystem:
$ sudo fstrim /mnt/folder


tune2fs


Reveja aqui.


Veja abaixo opções adicionais:

OpçõesDescrição
-e (erro)Muda o comportamento do Kernel de acordo com o código de erro.
continue - Continua com a execução normal (mas avisa do erro).
remount-ro - Vai remontar o filesystem como read-only.
panic - Causa um Kernel Panic.
-s (sparse-superblocks)Economiza espaço em filesystem grande, melhorando o uso dos blocos.
-O (opção)Usado para definir opções de montagem (as mesmas do fstab, porém, as opções do fstab possuem preferência com relação ao tune2fs).

Blocos

No contexto de sistemas de arquivos, um bloco (ou block) é a menor unidade de alocação de dados no disco. Quando você formata uma partição (por exemplo, com ext4), o sistema de arquivos define um tamanho fixo para cada bloco, normalmente 4 KB (isso é definido no tipo do disco).


Isso significa que cada arquivo ocupará no mínimo 4 KB no disco, mesmo que o conteúdo seja menor (ex: um arquivo de 1 byte ainda vai usar 4 KB em disco).


E se o arquivo for maior que um bloco? A resposta é simples, ele será dividido em vários blocos. Por exemplo, um arquivo de 12 KB ocupará 3 blocos (3 × 4 KB). Um arquivo de 5.5 KB ocupará 2 blocos (um inteiro + um com sobra).


Esses blocos nem sempre ficam um ao lado do outro fisicamente no disco, principalmente se o disco já estiver mais cheio, e aí temos o problema da fragmentação (mais perceptível em HDDs do que em SSDs).


O conteúdo de um bloco lógico (definido pelo sistema de arquivos) é armazenado fisicamente em setores no disco. Quando dizemos que um disco possui setores de 4096 bytes, estamos afirmando que cada setor físico tem exatamente 4 KB de capacidade. Por isso, é importante que o tamanho dos blocos lógicos (quantidade de dados que o FS vai gravar) esteja alinhado com o tamanho dos setores físicos, esse alinhamento evita sobrecarga desnecessária e melhora o desempenho geral.


Por exemplo, se o sistema de arquivos usa blocos de 4096 bytes e o arquivo também tem exatamente esse tamanho, ele será gravado em um único setor do disco, de forma direta e eficiente. Mas se o sistema de arquivos estiver configurado com blocos menores do que 4096 bytes, isso pode resultar em operações extras de leitura e escrita (como read-modify-write), afetando negativamente a performance.


Além disso, como cada arquivo ocupa pelo menos um bloco inteiro, arquivos menores que o tamanho do bloco acabam desperdiçando espaço, o famoso problema da fragmentação interna.


O sistema de arquivos trabalha com blocos porque isso simplifica muito o gerenciamento do espaço e é compatível com a forma como os discos funcionam. Os discos (HDDs ou SSDs) já trabalham com setores, que são pedaços fixos de dados, então o sistema de arquivos também usa pedaços fixos, chamados blocos, para acompanhar isso.


Se o sistema tentasse controlar byte por byte, o controle seria muito mais complicado, pesado e lento. Usando blocos de tamanho fixo (como 4 KB), fica muito mais fácil saber o que está ocupado, o que está livre, e como armazenar os arquivos. E como os arquivos geralmente são maiores que um bloco, o sistema só precisa dividir o arquivo em blocos e rastrear onde cada parte está.


Além disso, essa abordagem funciona bem com qualquer tipo de disco, seja um HD antigo, um SSD moderno ou até armazenamento em rede, porque todos trabalham com algum tipo de bloco ou setor por baixo.



NAS - Network-Attached Storage


É uma storage que compartilha armazenamento para a rede, para os servidores isso é transparente.


NAS



SAN - Storage Area Network


É uma rede que fornece acesso ao NAS, normalmente uma rede de fibra (deixa o acesso de leitura e escrita das informações mais rápidas), também é uma boa estratégia colocar numa vlan separada.


Suporta os protocolos:

  • FCP - Fiber Channel Protocol

    Faz mapeamento de SCSI sobre a fibra óptica.

    SCSI é um protocolo de comunicação entre o host e o dispositivo de armazenamento.


  • AoE

    Ata over Ethernet.


  • FCoE

    Fibre Channel over Ethernet.


  • iSCSI

    Mapeamento do SCSI sobre o IP.



FCP


Se usar o FCP deve-se ter uma rede de fibra apenas para o SAN.


SAN



FCoE


Os servidores que vão acessar a storage não precisam ter fibra, ela será usada apenas entre o switch e os storages NAS.


NAS-FCoE



AoE


Similar ao iSCSI, mas trabalha apenas em cima do ethernet e não do IP.



SAN - WWID e WWN


Em ambientes de SAN (Storage Area Network), os identificadores WWID e WWN são usados para garantir a identificação única de dispositivos em uma rede de armazenamento, especialmente quando se usa Fibre Channel (FC) ou FCoE (Fibre Channel over Ethernet).


Ambos são comparáveis a um "MAC address para storage", já que são identificadores globais e exclusivos, atribuídos pelo fabricante.


  • WWN - World Wide Name

    • Identifica elementos da infraestrutura SAN, como HBAs (Host Bus Adapters), portas de switches, controladoras de storage, etc.
    • É o termo mais usado quando se fala de endereçamento em redes Fibre Channel.
    • Cada HBA, por exemplo, tem um WWPN (World Wide Port Name) e um WWNN (World Wide Node Name), análogos ao MAC address da porta e do nó, respectivamente.
  • WWID - World Wide Identifier

    • Termo mais comum em nível de sistema operacional, especialmente no Linux.
    • Representa o identificador único de um disco ou volume apresentado ao host.
    • Pode ser baseado no WWN do dispositivo, mas também pode incorporar outros dados, como número de série e tipo de volume, dependendo da tecnologia usada (Fibre Channel, iSCSI, etc.).
    • Usado em ferramentas como ls -l /dev/disk/by-id/ e por multipath para identificar LUNs.

Ambos são identificadores únicos globais, mas WWN é o nome mais comum no nível de hardware/Fibre Channel. Já WWID é mais voltado ao nível do sistema operacional/volume apresentado.


Exemplo prático:

ls -l /dev/disk/by-id/ | grep wwid

Você pode ver entradas como:

wwid-0x600508b1001c6b1a3c3454a2d3f44a32 -> ../../sdb

Esse WWID identifica exclusivamente aquele disco na SAN, independentemente da controladora ou porta pela qual chegou.



SAN - LUN (Logical Unit Number)


O LUN é o identificador de uma unidade lógica em um ambiente SAN (Storage Area Network). Ele representa o que o host enxerga como um "disco", mas esse disco pode ser:

  • Um único HD físico
  • Uma partição de um disco
  • Um volume lógico dentro de um array RAID
  • Um conjunto de discos agrupados e apresentados como um único dispositivo
  • Ou até mesmo, em casos raros, o storage inteiro

As LUNs são associados a um WWPN da controladora de storage e são apresentados ao host via Fibre Channel, FCoE ou iSCSI. O acesso é controlado via zoneamento (em switches FC) e mascaramento de LUN (no storage).



SAN - Comandos


Listar o WWN (World Wide Name):

$ ls -la /dev/disk/by-id/ | grep wwn

Mostra os discos identificados por WWID/WWN, úteis para garantir persistência de nomes de dispositivos, independente de /dev/sdX.


Exibir os mapeamentos de multiplos paths para dispositivos:

$ sudo multipath -l

Exibe os vários caminhos que podem existir para um mesmo dispositivo. Muito usado em ambientes com multipath I/O, onde um mesmo LUN pode ser acessado por diferentes HBAs, switches ou controladoras. O multipathd resolve esses caminhos e apresenta um único dispositivo mapeado (ex: /dev/mapper/mpatha).


Ver identificador SCSI de um disco:

$ sudo /lib/udev/scsi_id -g /dev/sdb
350004cf4015bfc44

Retorna o identificador SCSI único daquele dispositivo. É usado, por exemplo, para regras persistentes do udev, ou para configurar aliases em /etc/multipath.conf.



iSCSI


É um dos protocolos para se trabalhar com SAN, tudo é feito usando Ethernet sobre o IP, pode usar cabo métalico (RJ45) ou óptico (fibra) para interligar os equipamentos.


Nesse layout temos um cliente e um servidor, para o servidor é dado o nome de target, sua função é fornecer os targets. Já o cliente é conhecido como initiator, é ele quem inicia a conexão.


SAN-iSCSI


Agora vamos ver como configurar o iSCSI (lembrando que ele roda em cima da Ethernet usando o protocolo IP). Podemos configurar isso num Linux normal ou usando uma storage, o que vai mudar é a parte do servidor, já que storages físicas com vários discos de alta performance são equipamentos que possuem uma configuração e interface própria da fabricante desses equipamentos.


Para isso vamos usar dois pacotes, um para cliente e outro para servidor.

  • Servidor

    Para servidores padrão Debian precisamos instalar o pacote tgt.

    Para servidores padrão RedHat precisamos instalar o pacote target-cli.

  • Cliente

    Para clientes padrão Debian vamos instalar o pacote open-iscsi.

    Para clientes padrão RedHat precisamos instalar o pacote iscsi-initiator-utils.

Lembrando que existem outros pacotes para essa mesma finalidade.


Farei todo o processo no Ubuntu, mas pode ver como é feito na RedHat usando este link.



No servidor


Para configurar o servidor, vamos usar o arquivo /etc/tgt/targets.conf para estar configurando os discos para que sejam visíveis na rede.

Você pode instalar um file system antes, ou pode exportar o disco zerado.

### Veja como ficou minha configuração:
$ cat /etc/tgt/targets.conf
# Empty targets configuration file -- please see the package
# documentation directory for an example.
#
# You can drop individual config snippets into /etc/tgt/conf.d
include /etc/tgt/conf.d/*.conf

<target iqn.2022-07.iscsi-test.linux-ubuntu20:target1>
backing-store /dev/vde
</target>

Sempre que alterar esse arquivo reinicie o daemon sudo systemctl restart tgt. Onde tem target1 pode ser qualquer nome, alí será o nome desse "compartilhamento".

Além discos, podemos compartilhar arquivos, qualquer tipo, como .iso, .img, .txt e por ai vai.


É possível adicionar vários dispositivos dentro do mesmo target ou podemos configurar mais targets, isso depende do objetivo, normalmente cada target é relacionado com um projeto e adicionar mais de um dispositivo significa dar mais HD para esse mesmo projeto.


Perceba que configuramos o IQN que significa iSCSI Qualified Name, é como se fosse o nome do Target, é por meio desse iqn que o initiator (cliente) vai conseguir se comunicar com o target (servidor).

Existe uma ordem padronizada para criação do iqn, é iqn.ANO-MES.FQDN_CONTRA.

FQDN é a sigla para Full Qualified Domain Name, ou seja, é o nome do dominio completo, incluindo o nome da máquina, por exemplo server1.exemplo.com.br.

É possível usar uma ferramenta para criar um IQN:

$ iscsi-iname -p iqn.2022-07.iscsi-test.linux-ubuntu20
iqn.2022-07.iscsi-test.linux-ubuntu20:5ac87a9d95e2

$ iscsi-iname -p iqn.2022-07.iscsi-test.linux-ubuntu20
iqn.2022-07.iscsi-test.linux-ubuntu20:b7bf97fc25df

Com o serviço restartado e previamento configurado, podemos verificar o status dos targets:

$ sudo tgt-admin --show
Target 1: iqn.2022-07.iscsi-test.linux-ubuntu20:target1
System information:
Driver: iscsi
State: ready
I_T nexus information:
LUN information:
LUN: 0
Type: controller
SCSI ID: IET 00010000
SCSI SN: beaf10
Size: 0 MB, Block size: 1
Online: Yes
Removable media: No
Prevent removal: No
Readonly: No
SWP: No
Thin-provisioning: No
Backing store type: null
Backing store path: None
Backing store flags:
LUN: 1
Type: disk
SCSI ID: IET 00010001
SCSI SN: beaf11
Size: 10737 MB, Block size: 512
Online: Yes
Removable media: No
Prevent removal: No
Readonly: No
SWP: No
Thin-provisioning: No
Backing store type: rdwr
Backing store path: /dev/vde
Backing store flags:
Account information:
ACL information:
ALL


No cliente


Para configurar o cliente primeiro devemos procurar no target a(s) LUN(s) e depois temos que conectar nelas. Para isso siga os passos abaixo:

# Descubra os Targets (lun) disponível (se quiser omitir a porta é possível):
$ sudo iscsiadm -m discovery -t st -p 192.168.121.172:3260
192.168.121.172:3260,1 iqn.2022-07.iscsi-test.linux-ubuntu20:target1

# -m = Modo (nesse caso é o modo de descoberta "discovery");
# -t = Tipo, existem alguns, 'st' é a abreviação de 'sendtargets';

Agora podemos testar a conexão nesse target:

$ sudo iscsiadm -m node --targetname iqn.2022-07.iscsi-test.linux-ubuntu20:target1 -p 192.168.121.172
# BEGIN RECORD 2.0-874
node.name = iqn.2022-07.iscsi-test.linux-ubuntu20:target1
node.tpgt = 1
node.startup = manual
node.leading_login = No
iface.hwaddress = <empty>
iface.ipaddress = <empty>
iface.iscsi_ifacename = default
iface.net_ifacename = <empty>
iface.gateway = <empty>
iface.subnet_mask = <empty>
iface.transport_name = tcp
iface.initiatorname = <empty>
iface.state = <empty>
iface.vlan_id = 0
iface.vlan_priority = 0
iface.vlan_state = <empty>
iface.iface_num = 0
iface.mtu = 0
iface.port = 0
iface.bootproto = <empty>
iface.dhcp_alt_client_id_state = <empty>
iface.dhcp_alt_client_id = <empty>
iface.dhcp_dns = <empty>
iface.dhcp_learn_iqn = <empty>
iface.dhcp_req_vendor_id_state = <empty>
iface.dhcp_vendor_id_state = <empty>
iface.dhcp_vendor_id = <empty>
iface.dhcp_slp_da = <empty>
iface.fragmentation = <empty>
iface.gratuitous_arp = <empty>
iface.incoming_forwarding = <empty>
iface.tos_state = <empty>
iface.tos = 0
iface.ttl = 0
iface.delayed_ack = <empty>
iface.tcp_nagle = <empty>
iface.tcp_wsf_state = <empty>
iface.tcp_wsf = 0
iface.tcp_timer_scale = 0
iface.tcp_timestamp = <empty>
iface.redirect = <empty>
iface.def_task_mgmt_timeout = 0
iface.header_digest = <empty>
iface.data_digest = <empty>
iface.immediate_data = <empty>
iface.initial_r2t = <empty>
iface.data_seq_inorder = <empty>
iface.data_pdu_inorder = <empty>
iface.erl = 0
iface.max_receive_data_len = 0
iface.first_burst_len = 0
iface.max_outstanding_r2t = 0
iface.max_burst_len = 0
iface.chap_auth = <empty>
iface.bidi_chap = <empty>
iface.strict_login_compliance = <empty>
iface.discovery_auth = <empty>
iface.discovery_logout = <empty>
node.discovery_address = 192.168.121.172
node.discovery_port = 3260
node.discovery_type = send_targets
node.session.initial_cmdsn = 0
node.session.initial_login_retry_max = 8
node.session.xmit_thread_priority = -20
node.session.cmds_max = 128
node.session.queue_depth = 32
node.session.nr_sessions = 1
node.session.auth.authmethod = None
node.session.auth.username = <empty>
node.session.auth.password = <empty>
node.session.auth.username_in = <empty>
node.session.auth.password_in = <empty>
node.session.timeo.replacement_timeout = 120
node.session.err_timeo.abort_timeout = 15
node.session.err_timeo.lu_reset_timeout = 30
node.session.err_timeo.tgt_reset_timeout = 30
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.session.scan = auto
node.conn[0].address = 192.168.121.172
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.MaxXmitDataSegmentLength = 0
node.conn[0].iscsi.MaxRecvDataSegmentLength = 262144
node.conn[0].iscsi.HeaderDigest = None
node.conn[0].iscsi.DataDigest = None
node.conn[0].iscsi.IFMarker = No
node.conn[0].iscsi.OFMarker = No
# END RECORD

Agora vamos realmente fazer a conexão nesse target (para desconectar mude de --login para --logout):

# Fazendo login:
$ sudo iscsiadm -m node --targetname iqn.2022-07.iscsi-test.linux-ubuntu20:target1 -p 192.168.121.172 --login
Logging in to [iface: default, target: iqn.2022-07.iscsi-test.linux-ubuntu20:target1, portal: 192.168.121.172,3260] (multiple)
Login to [iface: default, target: iqn.2022-07.iscsi-test.linux-ubuntu20:target1, portal: 192.168.121.172,3260] successful.

# Desconectando sem usar o comando acima com '--logout' isso vai desconectar todos os targets:
$ sudo iscsiadm -m node -u
Logging out of session [sid: 1, target: iqn.2022-07.iscsi-test.linux-ubuntu20:target1, portal: 192.168.121.172,3260]
Logout of [sid: 1, target: iqn.2022-07.iscsi-test.linux-ubuntu20:target1, portal: 192.168.121.172,3260] successful.

Podemos verificar se deu certo com o comando abaixo:

$ sudo iscsiadm -m session -P3
iSCSI Transport Class version 2.0-870
version 2.0-874
Target: iqn.2022-07.iscsi-test.linux-ubuntu20:target1 (non-flash)
Current Portal: 192.168.121.172:3260,1
Persistent Portal: 192.168.121.172:3260,1
**********
Interface:
**********
Iface Name: default
Iface Transport: tcp
Iface Initiatorname: iqn.1993-08.org.debian:01:5762609dd215
Iface IPaddress: 192.168.121.249
Iface HWaddress: <empty>
Iface Netdev: <empty>
SID: 1
iSCSI Connection State: LOGGED IN
iSCSI Session State: LOGGED_IN
Internal iscsid Session State: NO CHANGE
*********
Timeouts:
*********
Recovery Timeout: 120
Target Reset Timeout: 30
LUN Reset Timeout: 30
Abort Timeout: 15
*****
CHAP:
*****
username: <empty>
password: ********
username_in: <empty>
password_in: ********
************************
Negotiated iSCSI params:
************************
HeaderDigest: None
DataDigest: None
MaxRecvDataSegmentLength: 262144
MaxXmitDataSegmentLength: 8192
FirstBurstLength: 65536
MaxBurstLength: 262144
ImmediateData: Yes
InitialR2T: Yes
MaxOutstandingR2T: 1
************************
Attached SCSI devices:
************************
Host Number: 2 State: running
scsi2 Channel 00 Id 0 Lun: 0
scsi2 Channel 00 Id 0 Lun: 1
Attached scsi disk sda State: running

# Verifique se apareceu mais discos no sistema:
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 10G 0 disk
vda 252:0 0 128G 0 disk
├─vda1 252:1 0 487M 0 part /boot
├─vda2 252:2 0 1.9G 0 part [SWAP]
└─vda3 252:3 0 125.6G 0 part /

# Verifique também no arquivo abaixo:
$ cat /proc/scsi/scsi
Attached devices:
Host: scsi2 Channel: 00 Id: 00 Lun: 00
Vendor: IET Model: Controller Rev: 0001
Type: RAID ANSI SCSI revision: 05
Host: scsi2 Channel: 00 Id: 00 Lun: 01
Vendor: IET Model: VIRTUAL-DISK Rev: 0001
Type: Direct-Access ANSI SCSI revision: 05


Servidor iSCSI


Vamos ver mais algumas configurações possíveis:

$ cat /etc/tgt/targets.conf
# Empty targets configuration file -- please see the package
# documentation directory for an example.
#
# You can drop individual config snippets into /etc/tgt/conf.d
include /etc/tgt/conf.d/*.conf

<target iqn.2022-07.iscsi-test.linux-ubuntu20:target1>
backing-store /dev/vde
lun 10
</target>

<target iqn.2022-07.iscsi-test.linux-ubuntu20:target2>
backing-store /dev/vdc
lun 50
</target>

Aqui estamos com dois targets e ainda estamos definindo o número de cada LUN.


$ cat /etc/tgt/targets.conf
# Empty targets configuration file -- please see the package
# documentation directory for an example.
#
# You can drop individual config snippets into /etc/tgt/conf.d
include /etc/tgt/conf.d/*.conf

<target iqn.2022-07.iscsi-test.linux-ubuntu20:target1>
<backing-store /dev/vde>
lun 10
</backing-store>

<backing-store /dev/vdc>
lun 50
</backing-store>
</target>

Mesma configuração que está mais acima, mas dessa forma temos apenas um target e configuramos informações específicas para cada backing-store.



Vamos adicionar autenticação po senha e liberação por IP:

$ cat /etc/tgt/targets.conf
# Empty targets configuration file -- please see the package
# documentation directory for an example.
#
# You can drop individual config snippets into /etc/tgt/conf.d
include /etc/tgt/conf.d/*.conf

<target iqn.2022-07.iscsi-test.linux-ubuntu20:target2>
backing-store /dev/vdb
incominguser test 12345
initiator-address 192.168.121.150
</target>

Mais de um IP e mais de uma senha podem ser criadas.


Agora no cliente faça:

# Execute o discovery:
$ sudo iscsiadm -m discovery -t st -p 192.168.121.120
192.168.121.120:3260,1 iqn.2022-07.iscsi-test.linux-ubuntu20:target1
192.168.121.120:3260,1 iqn.2022-07.iscsi-test.linux-ubuntu20:target2

# Tente conectar no target 2 (vai dar erro!):
$ sudo iscsiadm -m node --targetname iqn.2022-07.iscsi-test.linux-ubuntu20:target2 -p 192.168.121.120 --login
Logging in to [iface: default, target: iqn.2022-07.iscsi-test.linux-ubuntu20:target2, portal: 192.168.121.120,3260] (multiple)
iscsiadm: Could not login to [iface: default, target: iqn.2022-07.iscsi-test.linux-ubuntu20:target2, portal: 192.168.121.120,3260].
iscsiadm: initiator reported error (24 - iSCSI login failed due to authorization failure)
iscsiadm: Could not log into all portals

# Adicione autenticação chap para o target2:
$ sudo iscsiadm -m node -T iqn.2022-07.iscsi-test.linux-ubuntu20:target2 -p 192.168.121.120 --op update -n node.session.auth.authmethod -v CHAP -n node.session.auth.username -v test -n node.session.auth.password -v 12345

# Tente conectar no target 2:
$ sudo iscsiadm -m node --targetname iqn.2022-07.iscsi-test.linux-ubuntu20:target2 -p 192.168.121.120 --login
Logging in to [iface: default, target: iqn.2022-07.iscsi-test.linux-ubuntu20:target2, portal: 192.168.121.120,3260] (multiple)
Login to [iface: default, target: iqn.2022-07.iscsi-test.linux-ubuntu20:target2, portal: 192.168.121.120,3260] successful.


Cliente iSCSI


No cliente temos um processo chamado iscsid, ele é um daemon que fica monitorando a conexão no initiator com o target.

Existem uma configuração no arquivo /etc/iscsi/iscsid.conf chamada node.startup, ela define se a conexão vai ser realizada automaticamente assim que o iscsid for iniciado ou se será manual (padrão é manual).

Isso determina se vai subir os targets no boot ou não (automatic sobe no boot).

É possível configurar para o initiator para subir o target no boot de duas formas.



Configurando o boot como padrão - Cliente iSCSI


Nesse método todo target que for encontrado durante o discovery vai subir automaticamente no boot. Outra resalva é, certifique-se de apagar os targets que você não quer que suba no boot.

# Primeiro edite o arquivo abaixo
$ sudo vim /etc/iscsi/iscsid.conf

## Defina 'node.startup = automatic'.
## Defina 'node.session.iscsi.InitialR2T = Yes'.
## Defina 'node.session.iscsi.FastAbort = No'.

# Se quiser pode usar o script abaixo:
sudo sed -i '/node.startup/ s/^node.startup.*/node.startup = automatic/g; /node.session.iscsi.InitialR2T/ s/^node.session.iscsi.InitialR2T.*/node.session.iscsi.InitialR2T = Yes/; /node.session.iscsi.FastAbort/ s/^node.session.iscsi.FastAbort.*/node.session.iscsi.FastAbort = No/' /etc/iscsi/iscsid.conf

Se você só definir a primeira variável pode ser que dê erro no boot.


Agora faça o discover:

$ sudo iscsiadm -m discovery -t st -p 192.168.121.120:3260
192.168.121.120:3260,1 iqn.2022-07.iscsi-test.linux-ubuntu20:target1
192.168.121.120:3260,1 iqn.2022-07.iscsi-test.linux-ubuntu20:target2

Sempre que editar o arquivo /etc/iscsi/iscsid.conf você deve fazer o discovery para aplicar a nova configuração!


Depois do discover, foram criados arquivos para cada target em /etc/iscsi/nodes/ e /etc/iscsi/send_targets/, esses arquivos já vão subir no boot:

### Estou logado como root!
$ ls -l /etc/iscsi/nodes/
total 8
drw------- 3 root root 4096 Jul 14 22:03 iqn.2022-07.iscsi-test.linux-ubuntu20:target1
drw------- 3 root root 4096 Jul 14 22:03 iqn.2022-07.iscsi-test.linux-ubuntu20:target2

$ ls -l /etc/iscsi/send_targets/192.168.121.120,3260/
total 12
lrwxrwxrwx 1 root root 85 Jul 14 22:03 iqn.2022-07.iscsi-test.linux-ubuntu20:target1,192.168.121.120,3260,1,default -> /etc/iscsi/nodes/iqn.2022-07.iscsi-test.linux-ubuntu20:target1/192.168.121.120,3260,1
lrwxrwxrwx 1 root root 85 Jul 14 22:03 iqn.2022-07.iscsi-test.linux-ubuntu20:target2,192.168.121.120,3260,1,default -> /etc/iscsi/nodes/iqn.2022-07.iscsi-test.linux-ubuntu20:target2/192.168.121.120,3260,1
-rw------- 1 root root 549 Jul 14 22:03 st_config

# Veja se estão automaticos:
grep -Hinr 'node.startup' /etc/iscsi/nodes/*
/etc/iscsi/nodes/iqn.2022-07.iscsi-test.linux-ubuntu20:target1/192.168.121.120,3260,1/default:4:node.startup = automatic
/etc/iscsi/nodes/iqn.2022-07.iscsi-test.linux-ubuntu20:target2/192.168.121.120,3260,1/default:4:node.startup = automatic

# Apague o arquivo do target1 para ele não subir no boot (estou logado com root):
rm -r /etc/iscsi/nodes/iqn.2022-07.iscsi-test.linux-ubuntu20:target2/

Agora é só reiniciar que já vai subir no boot!

Se for rodado do discovery ele vai automaticamente colocar os targets apagados para subir no boot.



Remover do boot - Cliente iSCSI

Para remover um target do boot basta remover o automatic do arquivo dele em /etc/iscsi/nodes/ e depois desconectar:

# Mude a configuração do arquivo para manual:
$ sudo iscsiadm -m node -T iqn.2022-07.iscsi-test.linux-ubuntu20:target2 -p 192.168.121.120 --op update -n node.startup -v manual

# Desconecte do target:
$ sudo iscsiadm -m node --targetname iqn.2022-07.iscsi-test.linux-ubuntu20:target2 -p 192.168.121.120 --logout

Você pode apagar a pasta do target em /etc/iscsi/nodes/ mas eu acho bom deixar lá.

CUIDADO: Ao rodar o comando para `discovery` a configuração do *startup* volta a ser automatic.

Configuração de boot feita por target - Cliente iSCSI


Nesse método vamos deixar a configuração padrão como manual e vamos configurar os targets individualmente para que eles consigam iniciar no boot.


# Primeiro edite o arquivo abaixo
$ sudo vim /etc/iscsi/iscsid.conf

## Defina 'node.session.iscsi.InitialR2T = Yes'.
## Defina 'node.session.iscsi.FastAbort = No'.

# Se quiser pode usar o script abaixo:
sudo sed -i '/node.session.iscsi.InitialR2T/ s/^node.session.iscsi.InitialR2T.*/node.session.iscsi.InitialR2T = Yes/; /node.session.iscsi.FastAbort/ s/^node.session.iscsi.FastAbort.*/node.session.iscsi.FastAbort = No/' /etc/iscsi/iscsid.conf

Agora faça o discover:

$ sudo iscsiadm -m discovery -t st -p 192.168.121.120:3260
192.168.121.120:3260,1 iqn.2022-07.iscsi-test.linux-ubuntu20:target1
192.168.121.120:3260,1 iqn.2022-07.iscsi-test.linux-ubuntu20:target2

Sempre que editar o arquivo /etc/iscsi/iscsid.conf você deve fazer o discovery para aplicar a nova configuração!


Depois do discover, foram criados arquivos para cada target em /etc/iscsi/nodes/ e /etc/iscsi/send_targets/, esses arquivos já vão subir no boot:

### Estou logado como root!
$ ls -l /etc/iscsi/nodes/
total 8
drw------- 3 root root 4096 Jul 14 22:17 iqn.2022-07.iscsi-test.linux-ubuntu20:target1
drw------- 3 root root 4096 Jul 14 22:17 iqn.2022-07.iscsi-test.linux-ubuntu20:target2

$ ls -l /etc/iscsi/send_targets/192.168.121.120,3260/
total 12
lrwxrwxrwx 1 root root 85 Jul 14 22:17 iqn.2022-07.iscsi-test.linux-ubuntu20:target1,192.168.121.120,3260,1,default -> /etc/iscsi/nodes/iqn.2022-07.iscsi-test.linux-ubuntu20:target1/192.168.121.120,3260,1
lrwxrwxrwx 1 root root 85 Jul 14 22:13 iqn.2022-07.iscsi-test.linux-ubuntu20:target2,192.168.121.120,3260,1,default -> /etc/iscsi/nodes/iqn.2022-07.iscsi-test.linux-ubuntu20:target2/192.168.121.120,3260,1
-rw------- 1 root root 549 Jul 14 22:17 st_config

# Veja se estão manual:
grep -Hinr 'node.startup' /etc/iscsi/nodes/*
/etc/iscsi/nodes/iqn.2022-07.iscsi-test.linux-ubuntu20:target1/192.168.121.120,3260,1/default:4:node.startup = manual
/etc/iscsi/nodes/iqn.2022-07.iscsi-test.linux-ubuntu20:target2/192.168.121.120,3260,1/default:4:node.startup = manual

Durante o login é que vamos colocar para subir no boot:

# Faça o login normalmente no target2:
$ sudo iscsiadm -m node --targetname iqn.2022-07.iscsi-test.linux-ubuntu20:target1 -p 192.168.121.120 --login
Logging in to [iface: default, target: iqn.2022-07.iscsi-test.linux-ubuntu20:target1, portal: 192.168.121.120,3260] (multiple)
Login to [iface: default, target: iqn.2022-07.iscsi-test.linux-ubuntu20:target1, portal: 192.168.121.120,3260] successful.

# Atualize o 'node.startup' do target2 para automatico, assim irá subir no boot:
$ sudo iscsiadm -m node -T iqn.2022-07.iscsi-test.linux-ubuntu20:target2 -p 192.168.121.120 --op update -n node.startup -v automatic

# Veja se mudou:
grep -Hinr 'node.startup' /etc/iscsi/nodes/*
/etc/iscsi/nodes/iqn.2022-07.iscsi-test.linux-ubuntu20:target1/192.168.121.120,3260,1/default:4:node.startup = manual
/etc/iscsi/nodes/iqn.2022-07.iscsi-test.linux-ubuntu20:target2/192.168.121.120,3260,1/default:4:node.startup = automatic

Uma outra forma de fazer é editando o arquivo diretamente em /etc/iscsi/nodes/iqn.2022-07.iscsi-test.linux-ubuntu20:target1/192.168.121.120,3260,1/default e mude a linha 4 node.startup = manual para node.startup = automatic.

CUIDADO: Ao rodar o comando para `discovery` a configuração do startup automático é perdida.

Remover do boot - Cliente iSCSI

Para remover um target do boot basta remover o automatic do arquivo dele em /etc/iscsi/nodes/ e depois desconectar:

# Mude a configuração do arquivo para manual:
$ sudo iscsiadm -m node -T iqn.2022-07.iscsi-test.linux-ubuntu20:target2 -p 192.168.121.120 --op update -n node.startup -v manual

# Desconecte do target:
$ sudo iscsiadm -m node --targetname iqn.2022-07.iscsi-test.linux-ubuntu20:target2 -p 192.168.121.120 --logout

Você pode apagar a pasta do target em /etc/iscsi/nodes/ mas eu acho bom deixar lá.

CUIDADO: Ao rodar o comando para `discovery` a configuração do *startup* volta a ser manual.

FSTAB - Cliente iSCSI

Vamos montar o boot no fstab, para isso vamos usar a opção

# Edite o fstab:
$ sudo vim /etc/fstab

# Adicione a linha abaixo (não esqueça de mudar o UUID):
# HD para iscsi:
UUID="2e36c3e6-8a3d-423c-85df-a5b3c25bb0cc" /mnt auto _netdev,rw 0 0

# Pode reiniciar!

A opção _netdev é necessária para que o sistema não fique tentando montar o filesystem que está em um dispositivo na rede, se não fizer isso, quando iniciar o servidor ele vai ficar tentando montar esse filesystem até que a rede esteja habilitada no sistema. Isso evita problema de travar no boot caso não tenha rede.