Delen via


Gegeneraliseerde installatiekopieën maken zonder een inrichtingsagent

Van toepassing op: ✔️ Flexibele schaalsets voor Linux-VM's ✔️

Microsoft Azure biedt inrichtingsagents voor Linux-VM's in de vorm van walinuxagent of cloud-init (aanbevolen). Er kan echter een scenario zijn wanneer u geen van deze toepassingen wilt gebruiken voor uw inrichtingsagent, zoals:

  • Uw Linux-distributie/-versie biedt geen ondersteuning voor cloud-init/Linux-agent.
  • U moet specifieke VM-eigenschappen instellen, zoals hostnaam.

Notitie

Als u geen eigenschappen hoeft in te stellen of als er een vorm van inrichting moet plaatsvinden, kunt u overwegen een gespecialiseerde installatiekopieën te maken.

In dit artikel wordt beschreven hoe u uw VM-installatiekopie kunt instellen om te voldoen aan de vereisten van het Azure-platform en de hostnaam kunt instellen, zonder dat u een inrichtingsagent hoeft te installeren.

Netwerken en rapportage gereed

Als u uw Linux-VM wilt laten communiceren met Azure-onderdelen, is een DHCP-client vereist. De client wordt gebruikt om een host-IP, DNS-resolutie en routebeheer op te halen uit het virtuele netwerk. De meeste distributies verzenden met deze hulpprogramma's out-of-the-box. Hulpprogramma's die zijn getest op Azure door Linux-distributieleveranciers zijn onder anderedhclient, network-managersystemd-networkd en andere.

Notitie

Het maken van gegeneraliseerde installatiekopieën zonder een inrichtingsagent ondersteunt momenteel alleen VM's met DHCP-functionaliteit.

Nadat netwerken zijn ingesteld en geconfigureerd, selecteert u 'Rapport gereed'. Dit vertelt Azure dat de VIRTUELE machine is ingericht.

Belangrijk

Als u klaar voor Azure niet rapporteert, wordt uw VIRTUELE machine opnieuw opgestart.

Demo/voorbeeld

Een bestaande Marketplace-installatiekopieën (in dit geval een Debian Buster-VM) met de Linux-agent (walinuxagent) verwijderd en een aangepast Python-script toegevoegd, is de eenvoudigste manier om Azure te laten weten dat de VIRTUELE machine 'gereed' is.

Maak de resourcegroep en de basis-VM:

$ az group create --location eastus --name demo1

Maak de 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"

De inrichtingsagent voor installatiekopieën verwijderen

Zodra de VIRTUELE machine is ingericht, kunt u er verbinding mee maken via SSH en de Linux-agent verwijderen:

$ sudo apt purge -y waagent
$ sudo rm -rf /var/lib/waagent /etc/waagent.conf /var/log/waagent.log

Vereiste code toevoegen aan de VIRTUELE machine

Ook binnen de VIRTUELE machine, omdat we de Azure Linux-agent hebben verwijderd, moeten we een mechanisme bieden om gereed te rapporteren.

Python-script

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-script

#!/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

Algemene stappen (als u Python of Bash niet gebruikt)

Als op uw VM Python niet is geïnstalleerd of beschikbaar is, kunt u deze bovenstaande scriptlogica programmatisch reproduceren met de volgende stappen:

  1. Haal de ContainerId, InstanceIden Incarnation door het antwoord van wireserver te parseren: curl -X GET -H 'x-ms-version: 2012-11-30' http://168.63.129.16/machine?comp=goalstate.

  2. Maak de volgende XML-gegevens, injecteer de geparseerde ContainerIden InstanceIdIncarnation uit de bovenstaande stap:

    <Health>
      <GoalStateIncarnation>INCARNATION</GoalStateIncarnation>
      <Container>
        <ContainerId>CONTAINER_ID</ContainerId>
        <RoleInstanceList>
          <Role>
            <InstanceId>INSTANCE_ID</InstanceId>
            <Health>
              <State>Ready</State>
            </Health>
          </Role>
        </RoleInstanceList>
      </Container>
    </Health>
    
  3. Plaats deze gegevens op 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

Het uitvoeren van de code bij het eerste opstarten automatiseren

Deze demo maakt gebruik van systemd, het meest voorkomende init-systeem in moderne Linux-distributies. De eenvoudigste en meest systeemeigen manier om ervoor te zorgen dat dit rapportklare mechanisme op het juiste moment wordt uitgevoerd, is door een systeemservice-eenheid te maken. U kunt het volgende eenheidsbestand /etc/systemd/system toevoegen (in dit voorbeeld wordt het eenheidsbestand azure-provisioning.servicegenoemd):

[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

Deze systeemservice doet drie dingen voor basisinrichting:

  1. Rapporten die gereed zijn voor Azure (om aan te geven dat het is gelukt).
  2. Wijzigt de naam van de VIRTUELE machine op basis van de door de gebruiker opgegeven VM-naam door deze gegevens op te halen uit Azure Instance Metadata Service (IMDS). Opmerking IMDS biedt ook andere metagegevens van exemplaren, zoals openbare SSH-sleutels, zodat u meer kunt instellen dan de hostnaam.
  3. Schakelt zichzelf uit zodat deze alleen wordt uitgevoerd bij de eerste opstartbewerking en niet bij volgende herstarts.

Voer met de eenheid in het bestandssysteem het volgende uit om deze in te schakelen:

$ sudo systemctl enable azure-provisioning.service

De VIRTUELE machine is nu klaar om te worden gegeneraliseerd en er een installatiekopieën van gemaakt.

De voorbereiding van de afbeelding voltooien

Voer op uw ontwikkelcomputer het volgende uit om het maken van installatiekopieën vanaf de basis-VM voor te bereiden:

$ az vm deallocate --resource-group demo1 --name demo1
$ az vm generalize --resource-group demo1 --name demo1

En maak de installatiekopieën van deze VM:

$ az image create \
    --resource-group demo1 \
    --source demo1 \
    --location eastus \
    --name demo1img

Nu zijn we klaar om een nieuwe VIRTUELE machine te maken op basis van de installatiekopieën. Dit kan ook worden gebruikt om meerdere VM's te maken:

$ 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

Notitie

Het is belangrijk om in te stellen --enable-agent false op omdat walinuxagent niet bestaat op deze VM die wordt gemaakt op basis van de installatiekopieën.

De VIRTUELE machine moet worden ingericht. Nadat u zich hebt aangemeld bij de nieuwe inrichtings-VM, moet u de uitvoer van de rapportklare systeemservice kunnen zien:

$ 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.

Ondersteuning

Als u uw eigen inrichtingscode/agent implementeert, bent u eigenaar van de ondersteuning van deze code. Microsoft-ondersteuning onderzoekt alleen problemen met betrekking tot de inrichtingsinterfaces die niet beschikbaar zijn. We brengen voortdurend verbeteringen en wijzigingen in dit gebied aan, dus u moet controleren op wijzigingen in cloud-init en Azure Linux Agent voor het inrichten van API-wijzigingen.

Volgende stappen

Zie Linux-inrichting voor meer informatie.