NVMe over TCP (NVMe/TCP) Proxmox ortamlarında blok depolama erişimi için giderek daha çok tercih edilen bir yöntem.
Dell-EMC PowerStore gibi kurumsal dizilerle birlikte kullanıldığında performansı ve sadeliği oldukça tatmin edici.
Ancak bu teknolojiyi üretim ortamında konumlandıran herkesin er ya da geç karşılaştığı sinir bozucu bir ayrıntı var sunucu yeniden başlatıldığında NVMe/TCP aygıtlarının kalıcı olmaması.
Bu makalemde bu sorunun kaynağını, neden tam olarak yeniden başlatma sırasında ortaya çıktığını ve hem basit hem de daha zarif iki çözüm yöntemini ele alıyoruz.
Sorun Nereden Kaynaklanıyor?
Proxmox, NVMe-oF altyapısının önyükleme sırasında otomatik olarak bağlanması için nvmf-autoconnect.service adında bir servis kullanıyor.
Servisin tanımı şu şekilde;
[Unit]
Description=Connect NVMe-oF subsystems automatically during boot
ConditionPathExists=!/etc/nvme/config.json
ConditionPathExists=/etc/nvme/discovery.conf
After=network-online.target
Before=remote-fs-pre.target
[Service]
Type=oneshot
ExecStartPre=/sbin/modprobe nvme-fabrics
ExecStart=/usr/sbin/nvme connect-all
[Install]
WantedBy=default.target
Burada dikkat edilmesi gereken bir nokta var servis ya config.json ya da discovery.conf dosyasının varlığını arıyor ikisi aynı anda bulunamaz.
Daha yaygın kullanım olduğu için bu senaryoda discovery.conf tercih ediliyor.
Kullanılan discovery.conf dosyası ise şöyle:
# Used for extracting default parameters for discovery
# Example:
# --transport=<trtype> --traddr=<traddr> --trsvcid=<trsvcid> --host-traddr=<host-traddr> --host-iface=<host-iface>
-t tcp -a 192.168.110.40 -s 4420
-t tcp -a 192.168.110.41 -s 4420
Sorunun özü tam da burada başlıyor.
Servis tanımında After=network-online.target ifadesi yer alıyor yani teoride ağ hazır olduktan sonra çalışması bekleniyor.
Ancak pratikte bu hedef TCP ağ yığınının gerçekten hizmet verebilir hale gelmesini her zaman garanti etmiyor.
Özellikle NVMe/TCP için kullanılan depolama ağı sistemin genel ağ arayüzlerinden bağımsız olarak biraz daha geç ayağa kalkabiliyor. Üstelik servis Type=oneshot olarak tanımlandığından yalnızca bir kez çalışıyor başarısız olduğunda kendiliğinden tekrar denemiyor.
İşin bir başka can sıkıcı yanı servisin başarılı olup olmadığını kullanıcıya bildirecek herhangi bir geri bildirim mekanizmasının olmaması.
Servis sessizce başarısız oluyor ve sistem açıldığında depolama aygıtlarının basitçe ortada olmadığını fark ediyorsunuz.
Sorunu Yerinde Gözlemlemek
Davranışı doğrulamanın en iyi yolu süreci elle adım adım çalıştırmak.
EMC PowerStore üzerinden 10 GB’lık tek bir aygıt sunulduktan sonra şu sıra izlenebilir;
- Önce hiçbir NVMe aygıtının görünmediği
nvme listile teyit edilir. - Ardından
systemctl restart nvmf-autoconnect.serviceile servis yeniden başlatılır. systemctl status nvmf-autoconnect.serviceile servisin durumu kontrol edilir.- Son olarak
nvme listtekrar çalıştırıldığında,dellemc-powerstoreaygıtının artık/dev/nvme1n1olarak listelendiği görülür.
Bu adımlar manuel olarak çalıştırıldığında her şey kusursuz işliyor.
Çünkü o anda ağ zaten ayakta ve erişilebilir durumda.
Sorun yalnızca yeniden başlatma sırasında, yani servisin TCP ağı henüz hazır olmadan tetiklendiği anda ortaya çıkıyor.

Çözüm 1: Basit Bir Gecikme Eklemek
Akla gelen ilk ve en pratik çözümdür. Servise küçük bir gecikme eklemek. nvmf-autoconnect.service tanımına aşağıdaki satırı koyarak bağlanma denemesi öncesinde 15 saniyelik bir bekleme süresi tanımlanabilir.
ExecStartPre=/bin/sleep 15
Bu yaklaşım işe yarıyor ancak son derece kaba bir yöntem.
Hiçbir zarafeti yok ve daha da önemlisi 15 saniyenin her ortam için yeterli olacağına dair hiçbir garanti vermiyor.
Ağın daha yavaş ayağa kalktığı bir senaryoda bu süre yetersiz kalabilir. “Garanti olsun” diye süreyi çok daha uzun tutmak ise sistem açılışını gereksiz yere yavaşlatmak anlamına gelir yani verimsizdir.
Kısacası bu çözüm sorunu çözer ama altında bir belirsizlik bırakır.
Çözüm 2: Ağı Gerçekten Test Etmek
Çok daha sağlıklı bir yaklaşımdır sabit bir süre beklemek yerine ağın gerçekten hazır olup olmadığını test etmek.
Bu fikir Proxmox forumlarında paylaşılan ve gecikme yöntemine göre çok daha akıllı bir çözümden geliyor.
Mantık şu: Varsayılan nvmf-autoconnect.service‘i doğrudan değiştirmek yerine onu bir bağımlılık olarak kullanan yeni bir servis oluşturuluyor.
Bu yeni servis DNS çözümlemesi tamamlandıktan sonra (nss-lookup.target) devreye giriyor ve TCP ağı erişilebilir hale gelene kadar hedef adrese ping atmaya devam ediyor.
Ağ yanıt verir vermez bekleme sona eriyor ve ancak o noktada otomatik bağlanma servisi çalışıyor.
Böylece varsayılan servisin başarılı olacağı garanti altına alınmış oluyor.
test-tcp-network.service dosyasının içeriği şöyle:
[Unit]
DefaultDependencies=no
After=nss-lookup.target
Before=nvmf-autoconnect.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=sh -c 'until ping -c 1 192.168.110.41; do sleep 1; done'
[Install]
WantedBy=nvmf-autoconnect.service
Burada tanımın inceliklerine değinmek gerekir.
Before=nvmf-autoconnect.service ifadesi bu servisin otomatik bağlanmadan önce tamamlanmasını sağlıyor.
ExecStart satırındaki until ping -c 1 192.168.110.41; do sleep 1; done döngüsü ise hedefe başarılı bir ping atılana dek saniyede bir denemeye devam ediyor yani ağ kesin olarak hazır olana kadar bir sonraki adıma geçilmiyor.
RemainAfterExit=yes sayesinde servis, bir kez başarıyla tamamlandığında “aktif” kabul ediliyor ve WantedBy=nvmf-autoconnect.service ile de doğru bağımlılık zinciri kuruluyor.
Servisin Devreye Alınması
Yeni servis dosyası oluşturulduktan sonra üç adım yeterli:
- Dosyayı
/etc/systemd/system/test-tcp-network.serviceyoluna oluşturunuz. - Çalıştırma izinlerini veriniz.
- Servisi etkinleştiriniz. (
systemctl enable test-tcp-network.service).
Servis elle çalıştırıldığında (systemctl start test-tcp-network.service), ardından durumu kontrol edildiğinde ağı nasıl test ettiği net biçimde görülebilir servis active (exited) durumunda ping çıktısında ise hedefe 64 bytes from 192.168.110.41: icmp_seq=1 ttl=64 yanıtı ve 0% packet loss ifadesi yer alır. Yani ağ doğrulandığı an döngü sonlanıyor ve otomatik bağlanma için yol açılıyor.
