إنشاء صور معممة دون عامل تزويد
ينطبق على: ✔️ أجهزة Linux الظاهرية ✔️ مجموعات مقياس مرنة
يوفر Microsoft Azure عامل تزويد لأجهزة Linux الظاهرية في شكل walinuxagent أو cloud-init (مستحسن). ولكن قد يكون هناك سيناريو لا تريد فيه استخدام أي من هذه التطبيقات لعامل التزويد الخاص بك، مثل:
- لا يدعم توزيعة/إصدار Linux cloud-init/Linux Agent.
- تحتاج إلى تعيين خصائص VM محددة، مثل اسم المضيف.
إشعار
إذا كنت لا تحتاج إلى تعيين أي خصائص أو حدوث أي شكل من أشكال التزويد، فيجب عليك التفكير في إنشاء صورة مخصصة.
توضح هذه المقالة كيف يمكنك إعداد صورة الجهاز الظاهري لتلبية متطلبات النظام الأساسي ل Azure وتعيين اسم المضيف، دون تثبيت عامل توفير.
الشبكات وإبلاغ الجاهزية
لكي يتصل جهاز Linux الظاهري بمكونات Azure، يلزم وجود عميل DHCP. يتم استخدام العميل لاسترداد IP مضيف وتحليل DNS وإدارة المسار من الشبكة الظاهرية. تأتي معظم التوزيعات مع هذه الأدوات المساعدة غير التقليدية. تتضمن dhclient
الأدوات التي يتم اختبارها على Azure من قبل موردي توزيعات Linux ، network-manager
systemd-networkd
و، وغيرها.
إشعار
حالياً، لا يدعم إنشاء صور معممة بدون عامل تزويد سوى الأجهزة الظاهرية التي تدعم DHCP.
بعد إعداد الشبكات وتكوينها، حدد "report ready". يخبر هذا Azure أنه تم توفير الجهاز الظاهري بنجاح.
هام
سيؤدي الفشل في إبلاغ الجاهزية إلى Azure إلى إعادة تشغيل الجهاز الظاهري!
عرض توضيحي/عينة
صورة Marketplace الموجودة (في هذه الحالة، Debian Buster VM) مع إزالة عامل Linux (walinuxagent) وإضافة برنامج نصي python مخصص هو أسهل طريقة لإخبار Azure أن الجهاز الظاهري "جاهز".
إنشاء مجموعة موارد وجهاز ظاهري أساسي:
$ az group create --location eastus --name demo1
إنشاء الجهاز الظاهري الأساسي:
$ az vm create \
--resource-group demo1 \
--name demo1 \
--location eastus \
--ssh-key-value <ssh_pub_key_path> \
--public-ip-address-dns-name demo1 \
--image "debian:debian-10:10:latest"
إزالة عامل تزويد الصور
بمجرد توفير الجهاز الظاهري، يمكنك الاتصال به عبر SSH وإزالة عامل Linux:
$ sudo apt purge -y waagent
$ sudo rm -rf /var/lib/waagent /etc/waagent.conf /var/log/waagent.log
إضافة التعليمة البرمجية المطلوبة إلى الجهاز الظاهري
أيضاً داخل الجهاز الظاهري، نظراً لأننا أزلنا عامل Azure Linux، فإننا نحتاج إلى توفير آلية لإبلاغ الجاهزية.
البرنامج النصي Python
import http.client
import sys
from xml.etree import ElementTree
wireserver_ip = '168.63.129.16'
wireserver_conn = http.client.HTTPConnection(wireserver_ip)
print('Retrieving goal state from the Wireserver')
wireserver_conn.request(
'GET',
'/machine?comp=goalstate',
headers={'x-ms-version': '2012-11-30'}
)
resp = wireserver_conn.getresponse()
if resp.status != 200:
print('Unable to connect with wireserver')
sys.exit(1)
wireserver_goalstate = resp.read().decode('utf-8')
xml_el = ElementTree.fromstring(wireserver_goalstate)
container_id = xml_el.findtext('Container/ContainerId')
instance_id = xml_el.findtext('Container/RoleInstanceList/RoleInstance/InstanceId')
incarnation = xml_el.findtext('Incarnation')
print(f'ContainerId: {container_id}')
print(f'InstanceId: {instance_id}')
print(f'Incarnation: {incarnation}')
# Construct the XML response we need to send to Wireserver to report ready.
health = ElementTree.Element('Health')
goalstate_incarnation = ElementTree.SubElement(health, 'GoalStateIncarnation')
goalstate_incarnation.text = incarnation
container = ElementTree.SubElement(health, 'Container')
container_id_el = ElementTree.SubElement(container, 'ContainerId')
container_id_el.text = container_id
role_instance_list = ElementTree.SubElement(container, 'RoleInstanceList')
role = ElementTree.SubElement(role_instance_list, 'Role')
instance_id_el = ElementTree.SubElement(role, 'InstanceId')
instance_id_el.text = instance_id
health_second = ElementTree.SubElement(role, 'Health')
state = ElementTree.SubElement(health_second, 'State')
state.text = 'Ready'
out_xml = ElementTree.tostring(
health,
encoding='unicode',
method='xml'
)
print('Sending the following data to Wireserver:')
print(out_xml)
wireserver_conn.request(
'POST',
'/machine?comp=health',
headers={
'x-ms-version': '2012-11-30',
'Content-Type': 'text/xml;charset=utf-8',
'x-ms-agent-name': 'custom-provisioning'
},
body=out_xml
)
resp = wireserver_conn.getresponse()
print(f'Response: {resp.status} {resp.reason}')
wireserver_conn.close()
برنامج Bash النصي
#!/bin/bash
attempts=1
until [ "$attempts" -gt 5 ]
do
echo "obtaining goal state - attempt $attempts"
goalstate=$(curl --fail -v -X 'GET' -H "x-ms-agent-name: azure-vm-register" \
-H "Content-Type: text/xml;charset=utf-8" \
-H "x-ms-version: 2012-11-30" \
"http://168.63.129.16/machine/?comp=goalstate")
if [ $? -eq 0 ]
then
echo "successfully retrieved goal state"
retrieved_goal_state=true
break
fi
sleep 5
attempts=$((attempts+1))
done
if [ "$retrieved_goal_state" != "true" ]
then
echo "failed to obtain goal state - cannot register this VM"
exit 1
fi
container_id=$(grep ContainerId <<< "$goalstate" | sed 's/\s*<\/*ContainerId>//g' | sed 's/\r$//')
instance_id=$(grep InstanceId <<< "$goalstate" | sed 's/\s*<\/*InstanceId>//g' | sed 's/\r$//')
ready_doc=$(cat << EOF
<?xml version="1.0" encoding="utf-8"?>
<Health xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<GoalStateIncarnation>1</GoalStateIncarnation>
<Container>
<ContainerId>$container_id</ContainerId>
<RoleInstanceList>
<Role>
<InstanceId>$instance_id</InstanceId>
<Health>
<State>Ready</State>
</Health>
</Role>
</RoleInstanceList>
</Container>
</Health>
EOF
)
attempts=1
until [ "$attempts" -gt 5 ]
do
echo "registering with Azure - attempt $attempts"
curl --fail -v -X 'POST' -H "x-ms-agent-name: azure-vm-register" \
-H "Content-Type: text/xml;charset=utf-8" \
-H "x-ms-version: 2012-11-30" \
-d "$ready_doc" \
"http://168.63.129.16/machine?comp=health"
if [ $? -eq 0 ]
then
echo "successfully register with Azure"
break
fi
sleep 5 # sleep to prevent throttling from wire server
done
خطوات عامة (إذا لم تكن تستخدم Python أو Bash)
إذا لم يكن Python مثبتاً أو متوفراً على الجهاز الظاهري الخاص بك، فيمكنك إعادة إنتاج منطق البرنامج النصي أعلاه برمجياً من خلال الخطوات التالية:
استرداد
ContainerId
، وInstanceId
، وIncarnation
عن طريق تحليل الاستجابة من WireServer:curl -X GET -H 'x-ms-version: 2012-11-30' http://168.63.129.16/machine?comp=goalstate
.قم ببناء بيانات XML التالية، وإدخال
ContainerId
وInstanceId
وIncarnation
التي تم تحليلها من الخطوة أعلاه:<Health> <GoalStateIncarnation>INCARNATION</GoalStateIncarnation> <Container> <ContainerId>CONTAINER_ID</ContainerId> <RoleInstanceList> <Role> <InstanceId>INSTANCE_ID</InstanceId> <Health> <State>Ready</State> </Health> </Role> </RoleInstanceList> </Container> </Health>
انشر هذه البيانات إلى WireServer:
curl -X POST -H 'x-ms-version: 2012-11-30' -H "x-ms-agent-name: WALinuxAgent" -H "Content-Type: text/xml;charset=utf-8" -d "$REPORT_READY_XML" http://168.63.129.16/machine?comp=health
أتمتة تشغيل التعليمات البرمجية عند التمهيد الأول
يستخدم هذا العرض التوضيحي systemd، وهو نظام init الأكثر شيوعاً في توزيعات Linux الحديثة. لذا فإن الطريقة الأسهل والأكثر واقعية لضمان تشغيل آلية إبلاغ الجاهزية في الوقت المناسب هي إنشاء وحدة خدمة systemd. يمكنك إضافة ملف الوحدة التالي إلى /etc/systemd/system
(يسمى هذا المثال ملف الوحدة azure-provisioning.service
):
[Unit]
Description=Azure Provisioning
[Service]
Type=oneshot
ExecStart=/usr/bin/python3 /usr/local/azure-provisioning.py
ExecStart=/bin/bash -c "hostnamectl set-hostname $(curl \
-H 'metadata: true' \
'http://169.254.169.254/metadata/instance/compute/name?api-version=2019-06-01&format=text')"
ExecStart=/usr/bin/systemctl disable azure-provisioning.service
[Install]
WantedBy=multi-user.target
تقوم الخدمة systemd بثلاثة أشياء للتزويد الأساسي:
- إبلاغ الجاهزية لـ Azure (للإشارة إلى ظهورها بنجاح).
- يعيد تسمية الجهاز الظاهري استناداً إلى اسم الجهاز الظاهري الذي يوفره المستخدم عن طريق سحب هذه البيانات من خدمة Azure Instance Metadata (IMDS). ملاحظة يوفر IMDS أيضاً بيانات تعريف مثيل أخرى، مثل المفاتيح العامة لـ SSH؛ حتى تتمكن من تعيين أكثر من اسم المضيف.
- يعطل نفسه بحيث يعمل فقط على التشغيل الأول لا على عمليات إعادة التشغيل اللاحقة.
باستخدام الوحدة الموجودة على نظام الملفات، قم بتشغيل ما يلي لتمكينها:
$ sudo systemctl enable azure-provisioning.service
الآن الجهاز الظاهري جاهز للتعميم والحصول على صورة تم إنشاؤها منه.
استكمال إعداد الصورة
مرة أخرى على جهاز التطوير الخاص بك، قم بتشغيل ما يلي للتحضير لإنشاء صورة من الجهاز الظاهري الأساسي:
$ az vm deallocate --resource-group demo1 --name demo1
$ az vm generalize --resource-group demo1 --name demo1
وإنشاء الصورة من هذا الجهاز الظاهري:
$ az image create \
--resource-group demo1 \
--source demo1 \
--location eastus \
--name demo1img
الآن نحن مستعدون لإنشاء جهاز ظاهري جديد من الصورة. يمكن استخدام هذا أيضا لإنشاء أجهزة ظاهرية متعددة:
$ IMAGE_ID=$(az image show -g demo1 -n demo1img --query id -o tsv)
$ az vm create \
--resource-group demo12 \
--name demo12 \
--location eastus \
--ssh-key-value <ssh_pub_key_path> \
--public-ip-address-dns-name demo12 \
--image "$IMAGE_ID"
--enable-agent false
إشعار
من المهم تعيين --enable-agent
على false
؛ لأن walinuxagent غير موجود على الجهاز الظاهري الذي سيتم إنشاؤه من الصورة.
يجب توفير الجهاز الظاهري بنجاح. بعد تسجيل الدخول إلى الجهاز الظاهري للتوفير حديثا، يجب أن تكون قادرا على رؤية إخراج الخدمة النظامية الجاهزة للتقرير:
$ sudo journalctl -u azure-provisioning.service
-- Logs begin at Thu 2020-06-11 20:28:45 UTC, end at Thu 2020-06-11 20:31:24 UTC. --
Jun 11 20:28:49 thstringnopa systemd[1]: Starting Azure Provisioning...
Jun 11 20:28:54 thstringnopa python3[320]: Retrieving goal state from the Wireserver
Jun 11 20:28:54 thstringnopa python3[320]: ContainerId: 7b324f53-983a-43bc-b919-1775d6077608
Jun 11 20:28:54 thstringnopa python3[320]: InstanceId: fbb84507-46cd-4f4e-bd78-a2edaa9d059b._thstringnopa2
Jun 11 20:28:54 thstringnopa python3[320]: Sending the following data to Wireserver:
Jun 11 20:28:54 thstringnopa python3[320]: <Health><GoalStateIncarnation>1</GoalStateIncarnation><Container><ContainerId>7b324f53-983a-43bc-b919-1775d6077608</ContainerId><RoleInstanceList><Role><InstanceId>fbb84507-46cd-4f4e-bd78-a2edaa9d059b._thstringnopa2</InstanceId><Health><State>Ready</State></Health></Role></RoleInstanceList></Container></Health>
Jun 11 20:28:54 thstringnopa python3[320]: Response: 200 OK
Jun 11 20:28:56 thstringnopa bash[472]: % Total % Received % Xferd Average Speed Time Time Time Current
Jun 11 20:28:56 thstringnopa bash[472]: Dload Upload Total Spent Left Speed
Jun 11 20:28:56 thstringnopa bash[472]: [158B blob data]
Jun 11 20:28:56 thstringnopa2 systemctl[475]: Removed /etc/systemd/system/multi-user.target.wants/azure-provisioning.service.
Jun 11 20:28:56 thstringnopa2 systemd[1]: azure-provisioning.service: Succeeded.
Jun 11 20:28:56 thstringnopa2 systemd[1]: Started Azure Provisioning.
يدعم
إذا قمت بتنفيذ التعليمة البرمجية/عامل التزويد الخاص بك، فأنت تملك دعم هذه التعليمة البرمجية، ولن يقوم دعم Microsoft إلا بالتحقيق في المشكلات المتعلقة بعدم توفر واجهات التزويد. نحن نعمل باستمرار على إجراء تحسينات وتغييرات في هذا المجال، لذلك يجب عليك مراقبة التغييرات في cloud-init وAzure Linux Agent لتوفير تغييرات واجهة برمجة التطبيقات.
الخطوات التالية
لمزيد من المعلومات، راجع تزويد Linux.