Dela via


Skapa generaliserade avbildningar utan en etableringsagent

Gäller för: ✔️ Flexibla skalningsuppsättningar för virtuella Linux-datorer ✔️

Microsoft Azure tillhandahåller etableringsagenter för virtuella Linux-datorer i form av walinuxagent eller cloud-init (rekommenderas). Men det kan finnas ett scenario när du inte vill använda något av dessa program för din etableringsagent, till exempel:

  • Din Linux-distribution/-version stöder inte cloud-init/Linux-agenten.
  • Du måste ange specifika VM-egenskaper, till exempel värdnamn.

Kommentar

Om du inte kräver att några egenskaper anges eller om någon form av etablering sker bör du överväga att skapa en specialiserad avbildning.

Den här artikeln visar hur du kan konfigurera den virtuella datoravbildningen så att den uppfyller kraven för Azure-plattformen och ange värdnamnet, utan att installera en etableringsagent.

Nätverks- och rapporteringsklar

För att din virtuella Linux-dator ska kunna kommunicera med Azure-komponenter krävs en DHCP-klient. Klienten används för att hämta en värd-IP, DNS-matchning och routningshantering från det virtuella nätverket. De flesta distributioner levereras med dessa verktyg out-of-the-box. Verktyg som testas på Azure av Linux-distributionsleverantörer är dhclient, network-managersystemd-networkd och andra.

Kommentar

För närvarande har generaliserade avbildningar utan en etableringsagent endast stöd för DHCP-aktiverade virtuella datorer.

När nätverk har konfigurerats väljer du "rapportklar". Detta talar om för Azure att den virtuella datorn har etablerats.

Viktigt!

Om du inte rapporterar redo till Azure kommer den virtuella datorn att startas om!

Demo/exempel

En befintlig Marketplace-avbildning (i det här fallet en virtuell Debian Buster-dator) med Linux-agenten (walinuxagent) borttagen och ett anpassat Python-skript som lagts till är det enklaste sättet att berätta för Azure att den virtuella datorn är "klar".

Skapa resursgruppen och den virtuella basdatorn:

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

Skapa den virtuella basdatorn:

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

Ta bort avbildningsetableringsagenten

När den virtuella datorn har etablerats kan du ansluta till den via SSH och ta bort Linux-agenten:

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

Lägga till nödvändig kod till den virtuella datorn

Även i den virtuella datorn, eftersom vi har tagit bort Azure Linux-agenten måste vi tillhandahålla en mekanism för att rapportera redo.

Python-skript

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

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

Allmänna steg (om de inte använder Python eller Bash)

Om den virtuella datorn inte har Python installerat eller tillgängligt kan du programmatiskt återskapa det här ovanstående skriptlogik med följande steg:

  1. ContainerIdHämta , InstanceIdoch Incarnation genom att parsa svaret från WireServer: curl -X GET -H 'x-ms-version: 2012-11-30' http://168.63.129.16/machine?comp=goalstate.

  2. Konstruera följande XML-data och mata in parsade ContainerId, InstanceIdoch Incarnation från ovanstående steg:

    <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. Publicera dessa data till 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

Automatisera körning av koden vid första starten

Den här demonstrationen använder systemd, vilket är det vanligaste init-systemet i moderna Linux-distributioner. Så det enklaste och mest inbyggda sättet att se till att den här rapportklara mekanismen körs vid rätt tidpunkt är att skapa en systembaserad tjänstenhet. Du kan lägga till följande enhetsfil /etc/systemd/system i (i det här exemplet namnges enhetsfilen 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

Den här systemd-tjänsten gör tre saker för grundläggande etablering:

  1. Rapporter som är redo för Azure (för att indikera att det har kommit upp).
  2. Byter namn på den virtuella datorn baserat på namnet på den virtuella datorn som angetts av användaren genom att hämta dessa data från Azure Instance Metadata Service (IMDS). Obs! IMDS innehåller även andra instansmetadata, till exempel offentliga SSH-nycklar, så att du kan ange mer än värdnamnet.
  3. Inaktiverar sig själv så att den bara körs vid första starten och inte vid efterföljande omstarter.

Med enheten i filsystemet kör du följande för att aktivera det:

$ sudo systemctl enable azure-provisioning.service

Nu är den virtuella datorn redo att generaliseras och få en avbildning skapad från den.

Slutföra förberedelsen av bilden

Tillbaka på utvecklingsdatorn kör du följande för att förbereda för att skapa avbildningar från den virtuella basdatorn:

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

Och skapa avbildningen från den här virtuella datorn:

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

Nu är vi redo att skapa en ny virtuell dator från avbildningen. Detta kan också användas för att skapa flera virtuella datorer:

$ 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

Kommentar

Det är viktigt att ange --enable-agent till false eftersom walinuxagent inte finns på den virtuella datorn som kommer att skapas från avbildningen.

Den virtuella datorn bör etableras korrekt. När du har loggat in på den nyligen etablerade virtuella datorn bör du kunna se utdata från den rapportklara systemtjänsten:

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

Support

Om du implementerar din egen etableringskod/agent äger du supporten för den här koden. Microsoft-supporten undersöker endast problem som rör att etableringsgränssnitten inte är tillgängliga. Vi gör kontinuerligt förbättringar och ändringar på det här området, så du måste övervaka ändringar i cloud-init och Azure Linux Agent för etablering av API-ändringar.

Nästa steg

Mer information finns i Linux-etablering.