Membuat citra umum tanpa agen provisi
Berlaku untuk: ✔️ Mesin Virtual Linux ✔️ Set skala fleksibel
Microsoft Azure menyediakan agen provisi untuk VM Linux dalam bentuk walinuxagent atau cloud-init (disarankan). Tetapi mungkin ada skenario ketika Anda tidak ingin menggunakan salah satu aplikasi ini untuk agen provisi Anda, seperti:
- Distro/versi Linux Anda tidak mendukung cloud-init/Linux Agent.
- Anda memerlukan properti VM tertentu untuk di set, seperti nama host.
Catatan
Jika Anda tidak memerlukan properti apa pun untuk di set atau tidak ingin membuat semua bentuk provisi, Anda harus mempertimbangkan untuk membuat citra khusus.
Artikel ini memperlihatkan bagaimana Anda dapat menyiapkan gambar VM untuk memenuhi persyaratan platform Azure dan mengatur nama host, tanpa menginstal agen provisi.
Jaringan dan pelaporan siap
Agar VM Linux Anda berkomunikasi dengan komponen Azure, klien DHCP diperlukan. Klien digunakan untuk mengambil IP host, resolusi DNS, dan manajemen rute dari jaringan virtual. Sebagian besar distro dikirim dengan utilitas di luar kotaknya. Alat yang diuji di vendor distro Azure by Linux meliputi dhclient
, , network-manager
systemd-networkd
dan lainnya.
Catatan
Saat ini membuat citra umum tanpa agen provisi dan hanya mendukung VM dengan DHCP yang diaktifkan.
Setelah jaringan disiapkan dan dikonfigurasi, pilih "laporan siap". Ini memberi tahu Azure bahwa VM telah berhasil disediakan.
Penting
Gagal melapor siap ke Azure akan mengakibatkan VM Anda di-boot ulang!
Demo/sampel
Gambar Marketplace yang ada (dalam hal ini, Debian Buster VM) dengan Agen Linux (walinuxagent) dihapus dan skrip python kustom yang ditambahkan adalah cara termampu untuk memberi tahu Azure bahwa VM "siap".
Membuat grup sumber daya dan basis VM:
$ az group create --location eastus --name demo1
Membuat basis VM:
$ 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"
Hapus Agen provisi citra
Setelah VM diprovisikan, Anda dapat menyambungkannya melalui SSH dan menghapus Agen Linux:
$ sudo apt purge -y waagent
$ sudo rm -rf /var/lib/waagent /etc/waagent.conf /var/log/waagent.log
Tambahkan kode yang diperlukan ke VM
Kami juga telah menghapus Azure Linux Agent di dalam VM. Oleh karena itu, kami perlu menyediakan mekanisme untuk melapor siap.
"Hello world!"
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()
Skrip 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
Langkah-langkah umum (jika tidak menggunakan Python atau Bash)
Jika VM Anda tidak memiliki Python yang terpasang atau tersedia, Anda dapat mereproduksi logika skrip di atas ini secara terprogram dengan langkah-langkah berikut:
Ambil
ContainerId
,InstanceId
, danIncarnation
dengan menguraikan respons dari WireServer:curl -X GET -H 'x-ms-version: 2012-11-30' http://168.63.129.16/machine?comp=goalstate
.Buat data XML berikut, masukkan
ContainerId
,InstanceId
, danIncarnation
yang terurai dari langkah di atas:<Health> <GoalStateIncarnation>INCARNATION</GoalStateIncarnation> <Container> <ContainerId>CONTAINER_ID</ContainerId> <RoleInstanceList> <Role> <InstanceId>INSTANCE_ID</InstanceId> <Health> <State>Ready</State> </Health> </Role> </RoleInstanceList> </Container> </Health>
Posting data ini ke 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
Mengotomatiskan kode agar berjalan pada boot pertama
Demo ini menggunakan systemd, yang merupakan sistem init paling umum dalam distro Linux modern. Jadi cara termudah dan paling orisinal untuk memastikan mekanisme melapor siap ini berjalan pada waktu yang tepat adalah dengan membuat unit layanan systemd. Anda dapat menambahkan file unit berikut ke /etc/systemd/system
(contoh ini menamai file unit 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
Layanan systemd ini melakukan tiga hal untuk provisi dasar:
- Melapor siap ke Azure (untuk menunjukkan bahwa laporan berhasil muncul).
- Mengganti nama VM berdasarkan nama VM yang disediakan pengguna dengan menarik data ini dari Azure Instance Metadata Service (IMDS). Catatan IMDS juga menyediakan metadata instanslainnya, seperti Kunci umum SSH, sehingga Anda dapat set lebih dari sekedar nama host.
- Menonaktifkan sendiri sehingga sistem hanya berjalan pada boot pertama dan tidak pada pengulangan boot berikutnya.
Dengan unit pada filesystem, jalankan beberapa hal berikut ini untuk mengaktifkannya:
$ sudo systemctl enable azure-provisioning.service
Sekarang VM siap untuk digenaralisasi dan memiliki citra yang terbuat dari pengaturan tersebut.
Menyelesaikan persiapan citra
Kembali pada mesin pengembangan Anda, jalankan hal berikut untuk mempersiapkan pembuatan citra dari VM dasar:
$ az vm deallocate --resource-group demo1 --name demo1
$ az vm generalize --resource-group demo1 --name demo1
Dan buat citra dari VM ini:
$ az image create \
--resource-group demo1 \
--source demo1 \
--location eastus \
--name demo1img
Sekarang kita siap untuk membuat VM baru dari gambar. Ini juga dapat digunakan untuk membuat beberapa VM:
$ 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
Catatan
Pengaturan ini penting --enable-agent
karena false
walinuxagent tidak ada pada VM ini dan akan dibuat dari citra.
VM harus berhasil disediakan. Setelah Masuk ke VM yang baru diprovisikan, Anda akan dapat melihat output layanan systemd siap laporan:
$ 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.
Dukungan
Jika Anda menerapkan kode/agen provisi Anda sendiri, maka Anda memiliki dukungan kode ini, dukungan Microsoft hanya akan menginvestigasi masalah yang berkaitan dengan antarmuka provisi yang tidak tersedia. Kami terus melakukan penyempurnaan dan perubahan di area ini, jadi Anda harus memantau perubahan cloud-init dan Agen Linux Azure untuk memprovisikan perubahan API.
Langkah berikutnya
Untuk informasi selengkapnya, lihat Provisi Linux.