KVM (تحت) VDI مع الأجهزة الافتراضية لمرة واحدة باستخدام باش

من هو هذا المقال ل؟


قد تكون هذه المقالة ذات أهمية لمسؤولي النظام الذين واجهوا مهمة إنشاء خدمة وظائف "لمرة واحدة".

فاتحة


طُلب من قسم دعم تكنولوجيا المعلومات بشركة نامية تتطور ديناميكياً ولديها شبكة إقليمية صغيرة تنظيم "محطات خدمة ذاتية" لاستخدامها من قبل عملائها الخارجيين. كان من المفترض أن يتم استخدام بيانات المحطة للتسجيل على بوابات الشركة الخارجية وتنزيل البيانات من الأجهزة الخارجية والعمل مع البوابات الحكومية.

كان الجانب المهم هو حقيقة أن معظم البرامج يتم "شحذها" لنظام MS Windows (على سبيل المثال ، "الإعلان") ، وعلى الرغم من التحرك نحو التنسيقات المفتوحة ، يظل MS Office هو المعيار المهيمن في تبادل المستندات الإلكترونية. وبالتالي ، لم نتمكن من رفض MS Windows عند حل هذه المشكلة.

كانت المشكلة الرئيسية هي إمكانية تجميع البيانات المختلفة من جلسات المستخدم ، مما قد يؤدي إلى تسربها إلى جهات خارجية. هذا الموقف بالفعل السماح MFC لأسفل . ولكن على عكس مؤسسة التمويل الأصغر شبه القضائية (مؤسسة الحكم الذاتي) ، سيتم معاقبة المنظمات غير الحكومية أكثر من هذا النوع من أوجه القصور. كانت المشكلة الحرجة التالية هي الحاجة إلى العمل مع وسائط التخزين الخارجية ، والتي سيكون عليها ، بكل الوسائل ، مجموعة من البرامج الضارة. تم اعتبار احتمال دخول البرامج الضارة من الإنترنت أقل ترجيحًا بسبب تقييد الوصول إلى الإنترنت عبر قائمة بيضاء من العناوين ، وانضم موظفو الإدارات الأخرى إلى وضع المتطلبات ، وجعل متطلباتهم ورغباتهم ، وكانت المتطلبات النهائية تبدو كما يلي:

هو متطلبات

  • بعد الاستخدام ، يجب حذف جميع بيانات المستخدم (بما في ذلك الملفات المؤقتة ومفاتيح التسجيل).
  • يجب الانتهاء من جميع العمليات التي أطلقها المستخدم في نهاية العمل.
  • الوصول إلى الإنترنت من خلال قائمة بيضاء من العناوين.
  • قيود على القدرة على تشغيل كود الطرف الثالث.
  • إذا كانت الجلسة في وضع الخمول لأكثر من 5 دقائق ، فيجب أن تنتهي الجلسة تلقائيًا ، ويجب أن تجري المحطة عملية تنظيف.

متطلبات العملاء

  • عدد محطات العميل لكل فرع لا يزيد عن 4.
  • الحد الأدنى لوقت الانتظار لاستعداد النظام ، من اللحظة التي جلست فيها على الكرسي إلى بداية العمل مع برنامج العميل.
  • القدرة على توصيل الأجهزة الطرفية (الماسحات الضوئية ، محركات أقراص فلاش) مباشرة من موقع التثبيت لـ "محطة الخدمة الذاتية".
  • رغبات العملاء
  • مظاهرة مواد إعلانية (صور) في وقت إغلاق المجمع.

دقيق الإبداع


بعد لعبنا بما فيه الكفاية مع Windows livecd ، توصلنا إلى نتيجة بالإجماع بأن الحل الناتج لا يفي بثلاث نقاط مهمة على الأقل. يتم تحميلها إما لفترة طويلة ، أو غير حية تمامًا ، أو يرتبط تخصيصها بالألم البري. ربما بحثنا بشكل سيئ ، ويمكنك تقديم المشورة لمجموعة من بعض الأدوات ، وسأكون ممتنا.

علاوة على ذلك ، بدأنا نتطلع إلى VDI ، ولكن بالنسبة لهذه المهمة ، فإن معظم الحلول إما مكلفة للغاية أو تتطلب عناية وثيقة. وأردت أداة بسيطة بأدنى قدر من السحر ، يمكن حل معظم المشكلات الخاصة بها بمجرد إعادة تشغيل / إعادة تشغيل الخدمة. لحسن الحظ ، كان لدينا أجهزة الخادم ، فئة منخفضة النهاية في الفروع ، من الخدمة التي توقفت عن العمل ، والتي يمكننا استخدامها للقاعدة التكنولوجية.

ما هي النتيجة؟ لكنني لن أكون قادرًا على إخبارك بما حدث في النهاية ، لأن التجمع الوطني الديمقراطي ، ولكن في عملية البحث ، قمنا بتطوير مخطط مثير للاهتمام أظهر نفسه جيدًا في الاختبارات المعملية ، رغم أنه لم يدخل في سلسلة.

بعض إخلاء المسئولية: لا يدعي المؤلف أن الحل المقترح يحل جميع المهام تمامًا ويفعلها طوعًا ومع الأغنية. يوافق المؤلف مقدمًا على التصريح الذي مفاده أن سين إنجليش برش هي زهرة شليخت. نظرًا لأن الحل لم يعد قيد التطوير ، لا يمكنك الاعتماد على إصلاح الخلل أو التغيير في الوظيفة ، فكل شيء في يديك. يفترض المؤلف أنك على الأقل على دراية بـ KVM وقرأت مقالة مراجعة على بروتوكول Spice ، وأنك عملت قليلاً مع Centos أو توزيع GNU Linux آخر.

في هذه المقالة ، أود تحليل العمود الفقري للحل الناتج ، أي تفاعل العميل والخادم وجوهر العمليات على دورة حياة الأجهزة الافتراضية ضمن إطار الحل المعني. إذا كانت المقالة مثيرة للاهتمام للجمهور ، فسوف أصف تفاصيل تنفيذ الصور الحية لإنشاء عملاء رفيعين على أساس Fedora وأخبرهم عن تفاصيل ضبط الأجهزة الافتراضية وخوادم KVM لتحسين الأداء والأمان.

إذا كنت تأخذ ورقة ملونة ،
الدهانات والفرش والغراء ،
وأكثر من ذلك ببراعة ...
يمكنك جعل مائة روبل!

مخطط ووصف اختبار مقاعد البدلاء




تقع جميع المعدات داخل الشبكة الفرعية ، فقط قناة الإنترنت تنطفئ. تاريخياً ، كان هناك بالفعل خادم وكيل ، إنه شيء غير عادي. ولكن من بين الأشياء الأخرى ، سيتم تصفية حركة المرور من الأجهزة الظاهرية (abbr. VM لاحقًا في النص). لا شيء يمنع وضع هذه الخدمة على خادم KVM ، الشيء الوحيد الذي تحتاج إلى مشاهدته هو كيف يتغير الحمل منه على النظام الفرعي للقرص.

محطة العميل - في الواقع ، "محطات الخدمة الذاتية" ، "الواجهة الأمامية" لخدمتنا. هي صافرة لينوفو IdeaCentre. ما هي هذه الوحدة جيدة ل؟ نعم ، الجميع تقريبا ، سعداء بشكل خاص بالعدد الكبير من موصلات USB وقارئات البطاقات على اللوحة الأمامية. في مخططنا ، يتم إدخال بطاقة SD مع حماية ضد كتابة الأجهزة في قارئ البطاقات ، حيث يتم تسجيل الصورة الحية المعدلة لـ Fedora 28. بالطبع ، يتم توصيل الشاشة ولوحة المفاتيح والماوس بالشبكة.

Switch - مفتاح تبديل غير ملحوم بالأجهزة من المستوى الثاني ، يوجد في غرفة الخادم ويومض بالأضواء. إنه غير متصل بأي شبكات باستثناء شبكة "محطات الخدمة الذاتية".

KVM_Server هو جوهر الدائرة ، ففي اختبارات مقاعد البدلاء ، قام Core 2 Quad Q9650 بسعة 8 جيجابايت من ذاكرة الوصول العشوائي بسحب 3 من الأجهزة الظاهرية بنظام Windows 10 بثقة. النظام الفرعي للقرص - adaptec 3405 2 محركات Raid 1 + SSD. في التجارب الميدانية لجهاز Xeon 1220 ، تمكنت محركات LSI 9260 + SSD الأكثر خطورة من سحب 5-6 VMs بسهولة. سوف نحصل على الخادم من الخدمة المتقاعدة ، لن يكون هناك الكثير من التكاليف الرأسمالية. يتم نشر نظام المحاكاة الافتراضية KVM مع pool_Vm pool machine الظاهري على هذا الخادم (الخوادم).

Vm هو الجهاز الظاهري ، الخلفية من خدمتنا. هذا هو عمل المستخدم.

Enp5s0 هي واجهة شبكة تتطلع إلى شبكة "محطات الخدمة الذاتية" و dhcpd و ntpd و httpd مباشرة على ذلك ، وتستمع xinetd إلى منفذ "الإشارة".

Lo0 هو واجهة الاسترجاع الزائفة. المعيار.

Spice_console - شيء مثير للاهتمام للغاية ، والحقيقة هي أنه ، على عكس RDP الكلاسيكية ، عند تشغيل حزمة بروتوكول KVM + Spice ، يظهر كيان إضافي - منفذ وحدة التحكم في الجهاز الظاهري. في الواقع ، عند الاتصال بمنفذ TCP هذا ، نحصل على وحدة Vm ، دون الحاجة للاتصال بـ Vm من خلال واجهة شبكتها. كل التفاعل مع Vm لنقل الإشارات ، الخادم يأخذ. أقرب التناظرية في وظيفة هو IPKVM. أي يتم نقل صورة لشاشة VM إلى هذا المنفذ ، ويتم إرسال البيانات المتعلقة بحركة الماوس إليها ، ويسمح لك التفاعل (الأهم من ذلك) عبر بروتوكول Spice بإعادة توجيه أجهزة USB بسلاسة إلى جهاز افتراضي ، كما لو كان هذا الجهاز متصلاً بـ Vm نفسه. تم اختباره لمحركات الأقراص المحمولة والماسحات الضوئية وكاميرات الويب.

Vnet0 ، virbr0 وبطاقات الشبكة الافتراضية Vm تشكل شبكة من الأجهزة الافتراضية.

كيف يعمل؟


من محطة العميل

يتم تحميل محطة العميل في الوضع الرسومي من صورة حية معدلة من فيدورا 28 ، يتلقى عنوان IP عن طريق dhcp من مساحة عنوان الشبكة 169.254.24.0/24. أثناء عملية التمهيد ، يتم إنشاء قواعد جدار الحماية التي تسمح بالاتصال بمنافذ خادم "الإشارة" و "التوابل". بعد اكتمال التنزيل ، تنتظر المحطة إذن مستخدم العميل. بعد إذن المستخدم ، يتم تشغيل مدير سطح المكتب "openbox" ويتم تنفيذ البرنامج النصي لبدء التشغيل التلقائي نيابة عن المستخدم المعتمد. من بين أشياء أخرى ، يقوم برنامج التشغيل التلقائي بتشغيل البرنامج النصي remote.sh.

$ HOME / .config / openbox / scripts / remote.sh
#!/bin/sh server_ip=$(/usr/bin/cat /etc/client.conf |/usr/bin/grep "server_ip" \ |/usr/bin/cut -d "=" -f2) vdi_signal_port=$(/usr/bin/cat /etc/client.conf |/usr/bin/grep "vdi_signal_port" \ |/usr/bin/cut -d "=" -f2) vdi_spice_port=$(/usr/bin/cat /etc/client.conf |/usr/bin/grep "vdi_spice_port" \ |/usr/bin/cut -d "=" -f2) animation_folder=$(/usr/bin/cat /etc/client.conf |/usr/bin/grep "animation_folder" \ |/usr/bin/cut -d "=" -f2) process=/usr/bin/remote-viewer while true do if [ -z `/usr/bin/pidof feh` ] then /usr/bin/echo $animation_folder /usr/bin/feh -N -x -D1 $animation_folder & else /usr/bin/echo fi /usr/bin/nc -i 1 $server_ip $vdi_signal_port |while read line do if /usr/bin/echo "$line" |/usr/bin/grep "RULE ADDED, CONNECT NOW!" then /usr/bin/killall feh pid_process=$($process "spice://$server_ip:$vdi_spice_port" \ "--spice-disable-audio" "--spice-disable-effects=animation" \ "--spice-preferred-compression=auto-glz" "-k" \ "--kiosk-quit=on-disconnect" | /bin/echo $!) /usr/bin/wait $pid_process /usr/bin/killall -u $USER exit else /usr/bin/echo $line >> /var/log/remote.log fi done done 


/etc/client.conf
 server_ip=169.254.24.1 vdi_signal_port=5905 vdi_spice_port=5906 animation_folder=/usr/share/backgrounds/animation background_folder=/usr/share/backgrounds2/fedora-workstation 


وصف متغيرات ملف client.conf
server_ip - عنوان KVM_Server
vdi_signal_port - منفذ KVM_Server الذي xinetd "يجلس"
vdi_spice_port - منفذ الشبكة KVM_Server ، حيث سيتم إعادة توجيه طلب الاتصال من عميل المشاهد عن بعد إلى منفذ التوابل الخاص بـ Vm المحدد (التفاصيل أدناه)
animation_folder - المجلد حيث يتم التقاط الصور من الرسوم المتحركة للرسوم المتحركة الهراء
background_folder - المجلد حيث يتم التقاط الصور من أجل العروض الاحتياطية. المزيد عن الرسوم المتحركة في الجزء التالي من المقالة.

يأخذ البرنامج النصي remote.sh الإعدادات من ملف التكوين /etc/client.conf ويستخدم nc للاتصال بمنفذ "vdi_signal_port" لخادم KVM ويتلقى دفق بيانات من الخادم ، ومن بينها يتوقع سلسلة "RULE ADDED ، CONNECT NOW". عند استلام الخط المرغوب ، تبدأ عملية العارض عن بُعد في وضع الكشك ، مما يؤدي إلى إنشاء اتصال بمنفذ الخادم "vdi_spice_port". يتم تعليق تنفيذ البرنامج النصي حتى نهاية تنفيذ العارض عن بعد.

يقوم المشاهد عن بعد الذي يتصل بمنفذ "vdi_spice_port" ، نظرًا لإعادة التوجيه من جانب الخادم ، بالوصول إلى منفذ "spice_console" في الواجهة lo0 ، أي إلى وحدة تحكم الجهاز الظاهري وعمل المستخدم يتم مباشرة. أثناء انتظار الاتصال ، يتم عرض رسوم متحركة هزلية للمستخدم ، في شكل عرض شرائح لملفات jpeg ، يتم تحديد المسار إلى الدليل مع الصور بواسطة قيمة متغير animation_folder من ملف التكوين.

في حالة فقد الاتصال بمنفذ "spice_console" الخاص بالجهاز الظاهري ، مما يشير إلى إيقاف تشغيل / إعادة تشغيل الجهاز الظاهري (أي النهاية الفعلية لجلسة المستخدم) ، يتم إنهاء جميع العمليات التي تعمل نيابة عن المستخدم المصرح به ، مما يؤدي إلى إعادة تشغيل lightdm والعودة إلى شاشة التفويض .

من جانب خادم KVM


على منفذ "الإشارة" في بطاقة الشبكة ، ينتظر enp5s0 اتصال xinetd. بعد الاتصال بمنفذ "الإشارة" ، يقوم xinetd بتشغيل البرنامج النصي vm_manager.sh دون تمرير أي معلمات إدخال إليه وإعادة توجيه نتيجة البرنامج النصي إلى جلسة nc لمحطة العميل.

/etc/xinetd.d/test-server
 service vdi_signal { port = 5905 socket_type = stream protocol = tcp wait = no user = root server = /home/admin/scripts_vdi_new/vm_manager.sh } 


/home/admin/scripts_vdi_new/vm_manager.sh
 #!/usr/bin/sh #<SET LOCAL VARIABLES FOR SCRIPT># SRV_SCRIPTS_DIR=$(/usr/bin/cat /etc/vm_manager.conf \ |/usr/bin/grep "srv_scripts_dir" |/usr/bin/cut -d "=" -f2) /usr/bin/echo "SRV_SCRIPTS_DIR=$SRV_SCRIPTS_DIR" export SRV_SCRIPTS_DIR=$SRV_SCRIPTS_DIR SRV_POOL_SIZE=$(/usr/bin/cat /etc/vm_manager.conf \ |/usr/bin/grep "srv_pool_size" |/usr/bin/cut -d "=" -f2) /usr/bin/echo "SRV_POOL_SIZE=$SRV_POOL_SIZE" export "SRV_POOL_SIZE=$SRV_POOL_SIZE" SRV_START_PORT_POOL=$(/usr/bin/cat /etc/vm_manager.conf \ |/usr/bin/grep "srv_start_port_pool" |/usr/bin/cut -d "=" -f2) /usr/bin/echo SRV_START_PORT_POOL=$SRV_START_PORT_POOL export SRV_START_PORT_POOL=$SRV_START_PORT_POOL SRV_TMP_DIR=$(/usr/bin/cat /etc/vm_manager.conf \ |/usr/bin/grep "srv_tmp_dir" |/usr/bin/cut -d "=" -f2) /usr/bin/echo "SRV_TMP_DIR=$SRV_TMP_DIR" export SRV_TMP_DIR=$SRV_TMP_DIR date=$(/usr/bin/date) #</SET LOCAL VARIABLES FOR SCRIPT># /usr/bin/echo "# $date START EXECUTE VM_MANAGER.SH #" make_connect_to_vm() { #<READING CLEAR.LIST AND CHECK PORT FOR NETWORK STATE># /usr/bin/echo "READING CLEAN.LIST AND CHECK PORT STATE" #<CHECK FOR NO ONE PORT IN CLEAR.LIST># if [ -z `/usr/bin/cat $SRV_TMP_DIR/clear.list` ] then /usr/bin/echo "NO AVALIBLE PORTS IN CLEAN.LIST FOUND" /usr/bin/echo "Will try to make housekeeper, and create new vm" make_housekeeper else #<MINIMUN ONE PORT IN CLEAR.LIST FOUND># /usr/bin/cat $SRV_TMP_DIR/clear.list |while read line do clear_vm_port=$(($line)) /bin/echo "FOUND PORT $clear_vm_port IN CLEAN.LIST. TRY NETSTAT" \ "CHECK FOR PORT=$clear_vm_port" #<NETSTAT LISTEN CHECK FOR PORT FROM CLEAN.LIST># if /usr/bin/netstat -lnt |/usr/bin/grep ":$clear_vm_port" > /dev/null then /bin/echo "$clear_vm_port IS LISTEN" #<PORT IS LISTEN. CHECK FOR IS CONNECTED NOW># if /usr/bin/netstat -nt |/usr/bin/grep ":$clear_vm_port" \ |/usr/bin/grep "ESTABLISHED" > /dev/null then #<PORT LISTEN AND ALREADY CONNECTED! MOVE PORT FROM CLEAR.LIST # TO WASTE.LIST># /bin/echo "$clear_vm_port IS ALREADY CONNECTED, MOVE PORT TO WASTE.LIST" /usr/bin/sed -i "/$clear_vm_port/d" $SRV_TMP_DIR/clear.list /usr/bin/echo $clear_vm_port >> $SRV_TMP_DIR/waste.list else #<PORT LISTEN AND NO ONE CONNECT NOW. MOVE PORT FROM CLEAR.LIST TO # CONN_WAIT.LIST AND CREATE IPTABLES RULES>## /usr/bin/echo "OK, $clear_vm_port IS NOT ALREADY CONNECTED" /usr/bin/sed -i "/$clear_vm_port/d" $SRV_TMP_DIR/clear.list /usr/bin/echo $clear_vm_port >> $SRV_TMP_DIR/conn_wait.list $SRV_SCRIPTS_DIR/vm_connect.sh $clear_vm_port #<TRY TO CLEAN VM IN WASTE.LIST AND CREATE NEW WM># /bin/echo "TRY TO CLEAN VM IN WASTE.LIST AND CREATE NEW VM" make_housekeeper /usr/bin/echo "# $date STOP EXECUTE VM_MANAGER.SH#" exit fi else #<PORT IS NOT A LISTEN. MOVE PORT FROM CLEAR.LIST TO WASTE.LIST># /bin/echo " "$clear_vm_port" is NOT LISTEN. REMOVE PORT FROM CLEAR.LIST" /usr/bin/sed -i "/$clear_vm_port/d" $SRV_TMP_DIR/clear.list /usr/bin/echo $clear_vm_port >> $SRV_TMP_DIR/waste.list make_housekeeper fi done fi } make_housekeeper() { /usr/bin/echo "=Execute housekeeper=" /usr/bin/cat $SRV_TMP_DIR/waste.list |while read line do /usr/bin/echo "$line" if /usr/bin/netstat -lnt |/usr/bin/grep ":$line" > /dev/null then /bin/echo "port_alive, vm is running" if /usr/bin/netstat -nt |/usr/bin/grep ":$line" \ |/usr/bin/grep "ESTABLISHED" > /dev/null then /bin/echo "port_in_use can't delete vm!!!" else /bin/echo "port_not in use. Deleting vm" /usr/bin/sed -i "/$line/d" $SRV_TMP_DIR/waste.list /usr/bin/echo $line >> $SRV_TMP_DIR/recycle.list $SRV_SCRIPTS_DIR/vm_delete.sh $line fi else /usr/bin/echo "posible vm is already off. Deleting vm" /usr/bin/echo "MOVE VM IN OFF STATE $line FROM WASTE.LIST TO" \ "RECYCLE.LIST AND DELETE VM" /usr/bin/sed -i "/$line/d" $SRV_TMP_DIR/waste.list /usr/bin/echo $line >> $SRV_TMP_DIR/recycle.list $SRV_SCRIPTS_DIR/vm_delete.sh "$line" fi done create_clear_vm } create_clear_vm() { /usr/bin/echo "=Create new VM=" while [ $SRV_POOL_SIZE -gt 0 ] do new_vm_port=$(($SRV_START_PORT_POOL+$SRV_POOL_SIZE)) /usr/bin/echo "new_vm_port=$new_vm_port" if /usr/bin/grep "$new_vm_port" $SRV_TMP_DIR/clear.list > /dev/null then /usr/bin/echo "$new_vm_port port is already defined in clear.list" else if /usr/bin/grep "$new_vm_port" $SRV_TMP_DIR/waste.list > /dev/null then /usr/bin/echo "$new_vm_port port is already defined in waste.list" else if /usr/bin/grep "$new_vm_port" $SRV_TMP_DIR/recycle.list > /dev/null then /usr/bin/echo "$new_vm_port PORT IS ALREADY DEFINED IN RECYCLE LIST" else if /usr/bin/grep "$new_vm_port" $SRV_TMP_DIR/conn_wait.list > /dev/null then /usr/bin/echo "$new_vm_port PORT IS ALREADY DEFINED IN CONN_WAIT LIST" else /usr/bin/echo "PORT IN NOT DEFINED IN NO ONE LIST WILL CREATE" \ "VM ON PORT $new_vm_port" /usr/bin/echo $new_vm_port >> $SRV_TMP_DIR/recycle.list $SRV_SCRIPTS_DIR/vm_create.sh $new_vm_port fi fi fi fi SRV_POOL_SIZE=$(($SRV_POOL_SIZE-1)) done /usr/bin/echo "# $date STOP EXECUTE VM_MANAGER.SH #" } make_connect_to_vm |/usr/bin/tee -a /var/log/vm_manager.log 


/etc/vm_manager.conf
srv_scripts_dir = / home / admin / scripts_vdi_new
srv_pool_size = 4
srv_start_port_pool = 5920
srv_tmp_dir = / tmp / vm_state
base_host = win10_2
input_iface = enp5s0
vdi_spice_port = 5906
count_conn_tryes = 10


وصف متغيرات ملف التكوين vm_manager.conf
srv_scripts_dir - مجلد موقع البرنامج النصي vm_manager.sh ، vm_connect.sh ، vm_delete.sh ، vm_create.sh ، vm_clear.sh
srv_pool_size - حجم تجمع Vm
srv_start_port_pool - المنفذ الأولي ، وبعد ذلك ستبدأ منافذ التوابل الخاصة بوحدات التحكم في الجهاز الظاهري
srv_tmp_dir - مجلد للملفات المؤقتة
base_host - base Vm (صورة ذهبية) يتم من خلالها استنساخ Vm في التجمع
input_iface - واجهة شبكة الخادم ، تتطلع نحو محطات العميل
vdi_spice_port - منفذ شبكة الخادم الذي سيتم منه إعادة توجيه طلب الاتصال من عميل العارض البعيد إلى منفذ التوابل الخاص بـ Vm المحدد
count_conn_tryes - مؤقت انتظار ، وبعد ذلك يعتبر أن اتصال Vm لم يحدث (للحصول على التفاصيل ، راجع vm_connect.sh)

يقرأ البرنامج النصي vm_manager.sh ملف التكوين من ملف vm_manager.conf ، ويقيم حالة الأجهزة الظاهرية في التجمع وفقًا لعدة معلمات ، وهي: كم عدد أجهزة VM التي يتم نشرها ، ما إذا كانت هناك VMs نظيفة مجانية. للقيام بذلك ، يقوم بقراءة ملف clear.list الذي يحتوي على أرقام منافذ "spice_console" الخاصة بالأجهزة الظاهرية "التي تم إنشاؤها حديثًا" (انظر دورة إنشاء VM أدناه) ويتحقق من وجود اتصال ثابت بها. إذا تم الكشف عن منفذ به اتصال شبكة مؤسس (والذي يجب ألا يكون مطلقًا) ، يتم عرض تحذير ويتم نقل المنفذ إلى النفايات. قائمة عند العثور على المنفذ الأول من ملف clear.list الذي لا يوجد به اتصال حاليًا ، يقوم vm_manager.sh باستدعاء البرنامج النصي vm_connect.sh ويمر له كمعلمة عدد هذا المنفذ.

/home/admin/scripts_vdi_new/vm_connect.sh
 #!/bin/sh date=$(/usr/bin/date) /usr/bin/echo "#" "$date" "START EXECUTE VM_CONNECT.SH#" #<SET LOCAL VARIABLES FOR SCRIPT># free_port="$1" input_iface=$(/usr/bin/cat /etc/vm_manager.conf |/usr/bin/grep "input_iface" \ |/usr/bin/cut -d "=" -f2) /usr/bin/echo "input_iface=$input_iface" vdi_spice_port=$(/usr/bin/cat /etc/vm_manager.conf \ |/usr/bin/grep "vdi_spice_port" |/usr/bin/cut -d "=" -f2) /usr/bin/echo "vdi_spice_port=$vdi_spice_port" count_conn_tryes=$(/usr/bin/cat /etc/vm_manager.conf \ |/usr/bin/grep "count_conn_tryes" |/usr/bin/cut -d "=" -f2) /usr/bin/echo "count_conn_tryes=$count_conn_tryes" #</SET LOCAL VARIABLES FOR SCRIPT># #<CREATE IPTABLES RULES AND SEND SIGNAL TO CONNECT># /usr/bin/echo "create rule for port" $free_port /usr/sbin/iptables -I INPUT -i $input_iface -p tcp -m tcp --dport \ $free_port -j ACCEPT /usr/sbin/iptables -I OUTPUT -o $input_iface -p tcp -m tcp --sport \ $free_port -j ACCEPT /usr/sbin/iptables -t nat -I PREROUTING -p tcp -i $input_iface --dport \ $vdi_spice_port -j DNAT --to-destination 127.0.0.1:$free_port /usr/bin/echo "RULE ADDED, CONNECT NOW!" #</CREATE IPTABLES RULES AND SEND SIGNAL TO CONNECT># #<WAIT CONNECT ESTABLISHED AND ACTIVATE CONNECT TIMER># while [ $count_conn_tryes -gt 0 ] do if /usr/bin/netstat -nt |/usr/bin/grep ":$free_port" \ |/usr/bin/grep "ESTABLISHED" > /dev/null then /bin/echo "$free_port NOW in use!!!" /usr/bin/sleep 1s /usr/sbin/iptables -t nat -D PREROUTING -p tcp -i $input_iface --dport \ $vdi_spice_port -j DNAT --to-destination 127.0.0.1:$free_port /usr/sbin/iptables -D INPUT -i $input_iface -p tcp -m tcp --dport \ $free_port -j ACCEPT /usr/sbin/iptables -D OUTPUT -o $input_iface -p tcp -m tcp --sport \ $free_port -j ACCEPT /usr/bin/sed -i "/$free_port/d" $SRV_TMP_DIR/conn_wait.list /usr/bin/echo $free_port >> $SRV_TMP_DIR/waste.list return else /usr/bin/echo "$free_port NOT IN USE" /usr/bin/echo "RULE ADDED, CONNECT NOW!" /usr/bin/sleep 1s fi count_conn_tryes=$((count_conn_tryes-1)) done #</WAIT CONNECT ESTABLISED AND ACTIVATE CONNECT TIMER># #<IF COUNT HAS EXPIRED. REMOVE IPTABLES RULE AND REVERT \ # VM TO CLEAR.LIST># /usr/bin/echo "REVERT IPTABLES RULE AND REVERT VM TO CLEAN \ LIST $free_port" /usr/sbin/iptables -t nat -D PREROUTING -p tcp -i $input_iface --dport \ $vdi_spice_port -j DNAT --to-destination 127.0.0.1:$free_port /usr/sbin/iptables -D INPUT -i $input_iface -p tcp -m tcp --dport $free_port \ -j ACCEPT /usr/sbin/iptables -D OUTPUT -o $input_iface -p tcp -m tcp --sport \ $free_port -j ACCEPT /usr/bin/sed -i "/$free_port/d" $SRV_TMP_DIR/conn_wait.list /usr/bin/echo $free_port >> $SRV_TMP_DIR/clear.list #</COUNT HAS EXPIRED. REMOVE IPTABLES RULE AND REVERT VM \ #TO CLEAR.LIST># /usr/bin/echo "#" "$date" "END EXECUTE VM_CONNECT.SH#" # Attention! Must Be! sysctl net.ipv4.conf.all.route_localnet=1 


يقدم البرنامج النصي vm_connect.sh قواعد جدار الحماية التي تنشئ إعادة توجيه "vdi_spice_port" لمنفذ الخادم بواجهة enp5s0 إلى "منفذ وحدة التحكم في spice" من VM الموجود على واجهة خادم lo0 ، وتمريرها كمعلمة بدء التشغيل. يتم نقل المنفذ إلى conn_wait.list ، ويعتبر VM في انتظار الاتصال. يتم إرسال خط RULE ADDED ، CONNECT NOW إلى جلسة محطة العميل على منفذ "الإشارة" الخاص بالخادم ، والذي يتوقعه البرنامج النصي البعيد. تبدأ دورة انتظار الاتصال بعدد المحاولات التي تحددها قيمة المتغير "count_conn_tryes" من ملف التكوين. كل ثانية في جلسة nc ، سيتم إعطاء السلسلة "RULE ADDED ، CONNECT NOW" وسيتم التحقق من الاتصال الذي تم تأسيسه على منفذ "spice_console".

إذا فشل الاتصال لعدد معين من المحاولات ، فسيتم نقل منفذ spice_console مرة أخرى لمسح. قائمة اكتمال تنفيذ vm_connect.sh ، يتم استئناف تنفيذ vm_manager.sh ، والذي يبدأ دورة التنظيف.

إذا كانت "محطة العميل" تتصل بمنفذ spice_console على الواجهة lo0 ، فسيتم حذف قواعد جدار الحماية التي تنشئ إعادة توجيه بين منفذ خادم spice ومنفذ spice_console ويتم الحفاظ على الاتصال بشكل أكبر من خلال آلية لتحديد حالة جدار الحماية. في حالة وجود اتصال غير متصل ، ستفشل إعادة الاتصال بمنفذ spice_console. يتم نقل منفذ spice_console إلى قائمة النفايات. تعتبر VM متسخة ولا يمكنها العودة إلى مجموعة الأجهزة الظاهرية النظيفة دون المرور عبر التنظيف. اكتمال تنفيذ vm_connect.sh ، واستئناف تنفيذ vm_manager.sh ، والذي يبدأ دورة التنظيف.

تبدأ دورة التنظيف من خلال النظر إلى ملف قائمة النفايات ، حيث يتم نقل أرقام وحدة التحكم في spice من منافذ الجهاز الظاهري التي تم تأسيس الاتصال بها. يتم تحديد وجود اتصال نشط على كل منفذ spice_console من القائمة. إذا لم يكن هناك اتصال ، فيُعتبر أن الجهاز الظاهري لم يعد قيد الاستخدام وأنه تم نقل المنفذ إلى قائمة التدوير ، وبدأت عملية حذف الجهاز الظاهري (انظر أدناه) الذي ينتمي إليه هذا المنفذ. إذا تم اكتشاف اتصال شبكة نشط على المنفذ ، فمن المفترض أن الجهاز الظاهري قيد الاستخدام ، ولا يتم اتخاذ أي إجراء بشأنه. إذا لم يتم استغلال المنفذ ، فمن المفترض أن يتم إيقاف تشغيل VM ولم تعد هناك حاجة إليه. يتم نقل المنفذ إلى recycle.list وتبدأ عملية إزالة الجهاز الظاهري. للقيام بذلك ، يتم استدعاء البرنامج النصي vm_delete.sh ، حيث يتم نقل رقم "spice_console" إلى منفذ VM كمعلمة ، والتي يجب حذفها.

/home/admin/scripts_vdi_new/vm_delete.sh
 #!/bin/sh #<Set local VARIABLES># port_to_delete="$1" date=$(/usr/bin/date) #</Set local VARIABLES># /usr/bin/echo "# $date START EXECUTE VM_DELETE.SH#" /usr/bin/echo "TRY DELETE VM ON PORT: $vm_port" #<VM NAME SETUP># vm_name_part1=$(/usr/bin/cat /etc/vm_manager.conf |/usr/bin/grep 'base_host' \ |/usr/bin/cut -d'=' -f2) vm_name=$(/usr/bin/echo "$vm_name_part1""-""$port_to_delete") #</VM NAME SETUP># #<SHUTDOWN AND DELETE VM># /usr/bin/virsh destroy $vm_name /usr/bin/virsh undefine $vm_name /usr/bin/rm -f /var/lib/libvirt/images_write/$vm_name.qcow2 /usr/bin/sed -i "/$port_to_delete/d" $SRV_TMP_DIR/recycle.list #</SHUTDOWN AND DELETE VM># /usr/bin/echo "VM ON PORT $vm_port HAS BEEN DELETE AND REMOVE" \ "FROM RECYCLE.LIST. EXIT FROM VM_DELETE.SH" /usr/bin/echo "# $date STOP EXECUTE VM_DELETE.SH#" exit 


تعتبر إزالة الجهاز الظاهري عملية تافهة إلى حد ما ، ويحدد البرنامج النصي vm_delete.sh اسم الجهاز الظاهري الذي يملك المنفذ الذي تم تمريره كمعلمة بدء التشغيل. يتم فرض VM للتوقف ، تتم إزالة VM من برنامج Hypervisor ، ويتم حذف القرص الثابت الظاهري لهذا الجهاز. تتم إزالة منفذ spice_console من قائمة التدوير. ينتهي تنفيذ vm_delete.sh ، يستأنف تنفيذ vm_manager.sh

يبدأ البرنامج النصي vm_manager.sh ، في نهاية العمليات لتنظيف الأجهزة الظاهرية غير الضرورية من قائمة النفايات. قائمة دورة إنشاء أجهزة افتراضية في التجمع.

تبدأ العملية بتحديد منافذ spice_console المتاحة للاستضافة. للقيام بذلك ، استنادًا إلى معلمة ملف التكوين "srv_start_port_pool" الذي يعين منفذ البدء للتجمع "spice_console" من الأجهزة الظاهرية والمعلمة "srv_pool_size" ، التي تحدد الحد الأقصى لعدد الأجهزة الظاهرية ، يتم تعداد كافة متغيرات المنفذ الممكنة بالتسلسل. لكل منفذ محدد ، يتم البحث عنه في clear.list، waste.list، conn_wait.list، recycle.list. إذا تم العثور على منفذ في أي من هذه الملفات ، يعتبر المنفذ مشغولاً ويتم تخطيه. إذا لم يتم العثور على المنفذ في الملفات المحددة ، فسيتم إدخاله في ملف recycle.list وتبدأ عملية إنشاء جهاز افتراضي جديد. للقيام بذلك ، يتم استدعاء البرنامج النصي vm_create.sh الذي يتم من خلاله تمرير رقم spice_console للمنفذ الذي تريد إنشاء VM له كمعلمة.

/home/admin/scripts_vdi_new/vm_create.sh
 #!/bin/sh /usr/bin/echo "#" "$date" "START RUNNING VM_CREATE.SH#" new_vm_port=$1 date=$(/usr/bin/date) a=0 /usr/bin/echo SRV_TMP_DIR=$SRV_TMP_DIR #<SET LOCAL VARIABLES FOR SCRIPT># base_host=$(/usr/bin/cat /etc/vm_manager.conf |/usr/bin/grep "base_host" \ |/usr/bin/cut -d "=" -f2) /usr/bin/echo "base_host=$base_host" #</SET LOCAL VARIABLES FOR SCRIPT># hdd_image_locate() { /bin/echo "Run STEP 1 - hdd_image_locate" hdd_base_image=$(/usr/bin/virsh dumpxml $base_host \ |/usr/bin/grep "source file" |/usr/bin/grep "qcow2" |/usr/bin/head -n 1 \ |/usr/bin/cut -d "'" -f2) if [ -z "$hdd_base_image" ] then /bin/echo "base hdd image not found!" else /usr/bin/echo "hdd_base_image found is a $hdd_base_image. Run next step 2" #< CHECK FOR SNAPSHOT ON BASE HDD ># if [ 0 -eq `/usr/bin/qemu-img info "$hdd_base_image" | /usr/bin/grep -c "Snapshot"` ] then /usr/bin/echo "base image haven't snapshot, run NEXT STEP 3" else /usr/bin/echo "base hdd image have a snapshot, can't use this image" exit fi #</ CHECK FOR SNAPSHOT ON BASE HDD ># #< CHECK FOR HDD IMAGE IS LINK CLONE ># if [ 0 -eq `/usr/bin/qemu-img info "$hdd_base_image" |/usr/bin/grep -c "backing file" then /usr/bin/echo "base image is not a linked clone, NEXT STEP 4" /usr/bin/echo "Base image check complete!" else /usr/bin/echo "base hdd image is a linked clone, can't use this image" exit fi fi #</ CHECK FOR HDD IMAGE IS LINK CLONE ># cloning } cloning() { # <Step_1 turn the base VM off ># /usr/bin/virsh shutdown $base_host > /dev/null 2>&1 # </Step_1 turn the base VM off ># #<Create_vm_config># /usr/bin/echo "Free port for Spice VM is $new_vm_port" #<Setup_name_for_new_VM># new_vm_name=$(/bin/echo $base_host"-"$new_vm_port) #</Setup_name_for_new_VM># #<Make_base_config_as_clone_base_VM># /usr/bin/virsh dumpxml $base_host > $SRV_TMP_DIR/$new_vm_name.xml #<Make_base_config_as_clone_base_VM># ##<Setup_New_VM_Name_in_config>## /usr/bin/sed -i "s%<name>$base_host</name>%<name>$new_vm_name</name>%g" $SRV_TMP_DIR/$new_vm_name.xml #</Setup_New_VM_Name_in_config># #<UUID Changing># old_uuid=$(/usr/bin/cat $SRV_TMP_DIR/$new_vm_name.xml |/usr/bin/grep "<uuid>") /usr/bin/echo old UUID $old_uuid new_uuid_part1=$(/usr/bin/echo "$old_uuid" |/usr/bin/cut -d "-" -f 1,2) new_uuid_part2=$(/usr/bin/echo "$old_uuid" |/usr/bin/cut -d "-" -f 4,5) new_uuid=$(/bin/echo $new_uuid_part1"-"$new_vm_port"-"$new_uuid_part2) /usr/bin/echo $new_uuid /usr/bin/sed -i "s%$old_uuid%$new_uuid%g" $SRV_TMP_DIR/$new_vm_name.xml #</UUID Changing># #<Spice port replace># old_spice_port=$(/usr/bin/cat $SRV_TMP_DIR/$new_vm_name.xml \ |/usr/bin/grep "graphics type='spice' port=") /bin/echo old spice port $old_spice_port new_spice_port=$(/usr/bin/echo "<graphics type='spice' port='$new_vm_port' autoport='no' listen='127.0.0.1'>") /bin/echo $new_spice_port /usr/bin/sed -i "s%$old_spice_port%$new_spice_port%g" $SRV_TMP_DIR/$new_vm_name.xml #</Spice port replace># #<MAC_ADDR_GENERATE># mac_new=$(/usr/bin/hexdump -n6 -e '/1 ":%02X"' /dev/random|/usr/bin/sed s/^://g) /usr/bin/echo New Mac is $mac_new #</MAC_ADDR_GENERATE># #<GET OLD MAC AND REPLACE># mac_old=$(/usr/bin/cat $SRV_TMP_DIR/$new_vm_name.xml |/usr/bin/grep "mac address=") /usr/bin/echo old mac is $mac_old /usr/bin/sed -i "s%$mac_old%$mac_new%g" $SRV_TMP_DIR/$new_vm_name.xml #<GET OLD MAC AND REPLACE># #<new_disk_create># /usr/bin/qemu-img create -f qcow2 -b $hdd_base_image /var/lib/libvirt/images_write/$new_vm_name.qcow2 #</new_disk_create># #<attach_new_disk_in_confiig># /usr/bin/echo hdd base image is $hdd_base_image /usr/bin/sed -i "s%<source file='$hdd_base_image'/>%<source file='/var/lib/libvirt/images_write/$new_vm_name.qcow2'/>%g" $SRV_TMP_DIR/$new_vm_name.xml #</attach_new_disk_in_confiig># starting_vm #</Create_vm config># } starting_vm() { /usr/bin/virsh define $SRV_TMP_DIR/$new_vm_name.xml /usr/bin/virsh start $new_vm_name while [ $a -ne 1 ] do if /usr/bin/virsh list --all |/usr/bin/grep "$new_vm_name" |/usr/bin/grep "running" > /dev/null 2>&1 then a=1 /usr/bin/sed -i "/$new_vm_port/d" $SRV_TMP_DIR/recycle.list /usr/bin/echo $new_vm_port >> $SRV_TMP_DIR/clear.list /usr/bin/echo "#" "$date" "VM $new_vm_name IS STARTED #" else /usr/bin/echo "#VM $new_vm_name is not ready#" a=0 /usr/bin/sleep 2s fi done /usr/bin/echo "#$date EXIT FROM VM_CREATE.SH#" exit } hdd_image_locate 


عملية إنشاء جهاز افتراضي جديد

يقرأ البرنامج النصي vm_create.sh من ملف التكوين قيمة المتغير "base_host" الذي يحدد نموذج الجهاز الظاهري الذي سيتم إجراء عملية الاستنساخ عليه. إلغاء تحميل تكوين xml من VM من قاعدة بيانات برنامج Hypervisor ، ويقوم بإجراء سلسلة من الاختبارات qcow لصورة قرص VM ، وعند الانتهاء بنجاح ، يقوم بإنشاء ملف تكوين xml لـ VM الجديد وصورة قرص "clone مرتبط" من VM الجديد. بعد ذلك ، يتم تحميل تكوين xml الخاص بـ VM الجديد في قاعدة بيانات برنامج hypervisor ويبدأ تشغيله. يتم نقل منفذ spice_console من قائمة التدوير إلى قائمة. ينتهي تنفيذ vm_create.sh وينتهي تنفيذ vm_manager.sh.
في المرة التالية التي تتصل فيها ، تبدأ من البداية.

بالنسبة لحالات الطوارئ ، تشتمل المجموعة على برنامج نصي vm_clear.sh والذي يتم تشغيله قسريًا عبر جميع أجهزة VM من التجمع وإزالتها بتصفير قيم القوائم. يتيح لك الاتصال به في مرحلة التحميل بدء (تحت) VDI من نقطة الصفر.

/home/admin/scripts_vdi_new/vm_clear.sh
 #!/usr/bin/sh #set VARIABLES# SRV_SCRIPTS_DIR=$(/usr/bin/cat /etc/vm_manager.conf \ |/usr/bin/grep "srv_scripts_dir" |/usr/bin/cut -d "=" -f2) /usr/bin/echo "SRV_SCRIPTS_DIR=$SRV_SCRIPTS_DIR" export SRV_SCRIPTS_DIR=$SRV_SCRIPTS_DIR SRV_TMP_DIR=$(/usr/bin/cat /etc/vm_manager.conf \ |/usr/bin/grep "srv_tmp_dir" |/usr/bin/cut -d "=" -f2) /usr/bin/echo "SRV_TMP_DIR=$SRV_TMP_DIR" export SRV_TMP_DIR=$SRV_TMP_DIR SRV_POOL_SIZE=$(/usr/bin/cat /etc/vm_manager.conf \ |/usr/bin/grep "srv_pool_size" |/usr/bin/cut -d "=" -f2) /usr/bin/echo "SRV_POOL_SIZE=$SRV_POOL_SIZE" SRV_START_PORT_POOL=$(/usr/bin/cat /etc/vm_manager.conf \ |/usr/bin/grep "srv_start_port_pool" |/usr/bin/cut -d "=" -f2) /usr/bin/echo SRV_START_PORT_POOL=$SRV_START_PORT_POOL #Set VARIABLES# /usr/bin/echo "= Cleanup ALL VM=" /usr/bin/mkdir $SRV_TMP_DIR /usr/sbin/service iptables restart /usr/bin/cat /dev/null > $SRV_TMP_DIR/clear.list /usr/bin/cat /dev/null > $SRV_TMP_DIR/waste.list /usr/bin/cat /dev/null > $SRV_TMP_DIR/recycle.list /usr/bin/cat /dev/null > $SRV_TMP_DIR/conn_wait.list port_to_delete=$(($SRV_START_PORT_POOL+$SRV_POOL_SIZE)) while [ "$port_to_delete" -gt "$SRV_START_PORT_POOL" ] do $SRV_SCRIPTS_DIR/vm_delete.sh $port_to_delete port_to_delete=$(($port_to_delete-1)) done /usr/bin/echo "= EXIT FROM VM_CLEAR.SH=" 


في هذا أود أن أنهي الجزء الأول من قصتي. يجب أن يكون ما سبق كافياً لمسؤولي النظام لمحاولة underVDI في العمل. إذا وجد المجتمع هذا الموضوع مثيرًا للاهتمام ، في الجزء الثاني ، سأتحدث عن تعديل قرص حي Fedora وتحوله إلى كشك.

Source: https://habr.com/ru/post/ar462203/


All Articles