Skapa en komplett virtuell Linux-dator med Azure CLI

Gäller för: ✔️ Virtuella Linux-datorer

Om du snabbt vill skapa en virtuell dator (VM) i Azure kan du använda ett enda Azure CLI-kommando som använder standardvärden för att skapa nödvändiga stödresurser. Resurser som ett virtuellt nätverk, offentlig IP-adress och regler för nätverkssäkerhetsgrupp skapas automatiskt. Om du vill ha mer kontroll över din miljö i produktionsanvändningen kan du skapa dessa resurser i förväg och sedan lägga till dina virtuella datorer i dem. Den här artikeln beskriver hur du skapar en virtuell dator och var och en av de resurser som stöds en i taget.

Kontrollera att du har installerat den senaste Azure CLI och loggat in på ett Azure-konto med az login.

I följande exempel ersätter du exempelparameternamn med dina egna värden. Exempelparameternamn är myResourceGroup, myVnet och myVM.

Skapa resursgrupp

En Azure-resursgrupp är en logisk container där Azure-resurser distribueras och hanteras. En resursgrupp måste skapas före en virtuell dator och stödja virtuella nätverksresurser. Skapa resursgruppen med az group create. I följande exempel skapas en resursgrupp med namnet myResourceGroup på platsen eastus :

az group create --name myResourceGroup --location eastus

Som standard finns utdata från Azure CLI-kommandon i JSON (JavaScript Object Notation). Om du till exempel vill ändra standardutdata till en lista eller tabell använder du az config set core.output=table. Du kan också lägga till --output ett kommando för en engångsändring i utdataformatet. I följande exempel visas JSON-utdata från az group create kommandot:

{
  "id": "/subscriptions/guid/resourceGroups/myResourceGroup",
  "location": "eastus",
  "name": "myResourceGroup",
  "properties": {
    "provisioningState": "Succeeded"
  },
  "tags": null
}

Skapa ett virtuellt nätverk och ett undernät

Sedan skapar du ett virtuellt nätverk i Azure och ett undernät där du kan skapa dina virtuella datorer. Använd az network vnet create för att skapa ett virtuellt nätverk med namnet myVnet med adressprefixet 192.168.0.0/16 . Du lägger också till ett undernät med namnet mySubnet med adressprefixet 192.168.1.0/24:

az network vnet create \
    --resource-group myResourceGroup \
    --name myVnet \
    --address-prefix 192.168.0.0/16 \
    --subnet-name mySubnet \
    --subnet-prefix 192.168.1.0/24

Utdata visar att undernätet skapas logiskt i det virtuella nätverket:

{
  "addressSpace": {
    "addressPrefixes": [
      "192.168.0.0/16"
    ]
  },
  "dhcpOptions": {
    "dnsServers": []
  },
  "etag": "W/\"e95496fc-f417-426e-a4d8-c9e4d27fc2ee\"",
  "id": "/subscriptions/guid/resourceGroups/myResourceGroup/providers/Microsoft.Network/virtualNetworks/myVnet",
  "location": "eastus",
  "name": "myVnet",
  "provisioningState": "Succeeded",
  "resourceGroup": "myResourceGroup",
  "resourceGuid": "ed62fd03-e9de-430b-84df-8a3b87cacdbb",
  "subnets": [
    {
      "addressPrefix": "192.168.1.0/24",
      "etag": "W/\"e95496fc-f417-426e-a4d8-c9e4d27fc2ee\"",
      "id": "/subscriptions/guid/resourceGroups/myResourceGroup/providers/Microsoft.Network/virtualNetworks/myVnet/subnets/mySubnet",
      "ipConfigurations": null,
      "name": "mySubnet",
      "networkSecurityGroup": null,
      "provisioningState": "Succeeded",
      "resourceGroup": "myResourceGroup",
      "resourceNavigationLinks": null,
      "routeTable": null
    }
  ],
  "tags": {},
  "type": "Microsoft.Network/virtualNetworks",
  "virtualNetworkPeerings": null
}

Skapa en offentlig IP-adress

Nu ska vi skapa en offentlig IP-adress med az network public-ip create. Med den här offentliga IP-adressen kan du ansluta till dina virtuella datorer från Internet. Eftersom standardadressen är dynamisk skapar du en namngiven DNS-post med parametern --domain-name-label . I följande exempel skapas en offentlig IP-adress med namnet myPublicIP med DNS-namnet mypublicdns. Eftersom DNS-namnet måste vara unikt anger du ditt eget unika DNS-namn:

az network public-ip create \
    --resource-group myResourceGroup \
    --name myPublicIP \
    --dns-name mypublicdns

Utdata:

{
  "publicIp": {
    "dnsSettings": {
      "domainNameLabel": "mypublicdns",
      "fqdn": "mypublicdns.eastus.cloudapp.azure.com",
      "reverseFqdn": null
    },
    "etag": "W/\"2632aa72-3d2d-4529-b38e-b622b4202925\"",
    "id": "/subscriptions/guid/resourceGroups/myResourceGroup/providers/Microsoft.Network/publicIPAddresses/myPublicIP",
    "idleTimeoutInMinutes": 4,
    "ipAddress": null,
    "ipConfiguration": null,
    "location": "eastus",
    "name": "myPublicIP",
    "provisioningState": "Succeeded",
    "publicIpAddressVersion": "IPv4",
    "publicIpAllocationMethod": "Dynamic",
    "resourceGroup": "myResourceGroup",
    "resourceGuid": "4c65de38-71f5-4684-be10-75e605b3e41f",
    "tags": null,
    "type": "Microsoft.Network/publicIPAddresses"
  }
}

Skapa en nätverkssäkerhetsgrupp

Om du vill styra trafikflödet in och ut från dina virtuella datorer använder du en nätverkssäkerhetsgrupp på ett virtuellt nätverkskort eller undernät. I följande exempel används az network nsg create för att skapa en nätverkssäkerhetsgrupp med namnet myNetworkSecurityGroup:

az network nsg create \
    --resource-group myResourceGroup \
    --name myNetworkSecurityGroup

Du definierar regler som tillåter eller nekar specifik trafik. Om du vill tillåta inkommande anslutningar på port 22 (för att aktivera SSH-åtkomst skapar du en regel för inkommande trafik med az network nsg rule create. I följande exempel skapas en regel med namnet myNetworkSecurityGroupRuleSSH:

az network nsg rule create \
    --resource-group myResourceGroup \
    --nsg-name myNetworkSecurityGroup \
    --name myNetworkSecurityGroupRuleSSH \
    --protocol tcp \
    --priority 1000 \
    --destination-port-range 22 \
    --access allow

Om du vill tillåta inkommande anslutningar på port 80 (för webbtrafik) lägger du till en annan regel för nätverkssäkerhetsgrupp. I följande exempel skapas en regel med namnet myNetworkSecurityGroupRuleHTTP:

az network nsg rule create \
    --resource-group myResourceGroup \
    --nsg-name myNetworkSecurityGroup \
    --name myNetworkSecurityGroupRuleWeb \
    --protocol tcp \
    --priority 1001 \
    --destination-port-range 80 \
    --access allow

Granska nätverkssäkerhetsgruppen och reglerna med az network nsg show:

az network nsg show --resource-group myResourceGroup --name myNetworkSecurityGroup

Utdata:

{
  "defaultSecurityRules": [
    {
      "access": "Allow",
      "description": "Allow inbound traffic from all VMs in VNET",
      "destinationAddressPrefix": "VirtualNetwork",
      "destinationPortRange": "*",
      "direction": "Inbound",
      "etag": "W/\"3371b313-ea9f-4687-a336-a8ebdfd80523\"",
      "id": "/subscriptions/guid/resourceGroups/myResourceGroup/providers/Microsoft.Network/networkSecurityGroups/myNetworkSecurityGroup/defaultSecurityRules/AllowVnetInBound",
      "name": "AllowVnetInBound",
      "priority": 65000,
      "protocol": "*",
      "provisioningState": "Succeeded",
      "resourceGroup": "myResourceGroup",
      "sourceAddressPrefix": "VirtualNetwork",
      "sourcePortRange": "*"
    },
    {
      "access": "Allow",
      "description": "Allow inbound traffic from azure load balancer",
      "destinationAddressPrefix": "*",
      "destinationPortRange": "*",
      "direction": "Inbound",
      "etag": "W/\"3371b313-ea9f-4687-a336-a8ebdfd80523\"",
      "id": "/subscriptions/guid/resourceGroups/myResourceGroup/providers/Microsoft.Network/networkSecurityGroups/myNetworkSecurityGroup/defaultSecurityRules/AllowAzureLoadBalancerInBou",
      "name": "AllowAzureLoadBalancerInBound",
      "priority": 65001,
      "protocol": "*",
      "provisioningState": "Succeeded",
      "resourceGroup": "myResourceGroup",
      "sourceAddressPrefix": "AzureLoadBalancer",
      "sourcePortRange": "*"
    },
    {
      "access": "Deny",
      "description": "Deny all inbound traffic",
      "destinationAddressPrefix": "*",
      "destinationPortRange": "*",
      "direction": "Inbound",
      "etag": "W/\"3371b313-ea9f-4687-a336-a8ebdfd80523\"",
      "id": "/subscriptions/guid/resourceGroups/myResourceGroup/providers/Microsoft.Network/networkSecurityGroups/myNetworkSecurityGroup/defaultSecurityRules/DenyAllInBound",
      "name": "DenyAllInBound",
      "priority": 65500,
      "protocol": "*",
      "provisioningState": "Succeeded",
      "resourceGroup": "myResourceGroup",
      "sourceAddressPrefix": "*",
      "sourcePortRange": "*"
    },
    {
      "access": "Allow",
      "description": "Allow outbound traffic from all VMs to all VMs in VNET",
      "destinationAddressPrefix": "VirtualNetwork",
      "destinationPortRange": "*",
      "direction": "Outbound",
      "etag": "W/\"3371b313-ea9f-4687-a336-a8ebdfd80523\"",
      "id": "/subscriptions/guid/resourceGroups/myResourceGroup/providers/Microsoft.Network/networkSecurityGroups/myNetworkSecurityGroup/defaultSecurityRules/AllowVnetOutBound",
      "name": "AllowVnetOutBound",
      "priority": 65000,
      "protocol": "*",
      "provisioningState": "Succeeded",
      "resourceGroup": "myResourceGroup",
      "sourceAddressPrefix": "VirtualNetwork",
      "sourcePortRange": "*"
    },
    {
      "access": "Allow",
      "description": "Allow outbound traffic from all VMs to Internet",
      "destinationAddressPrefix": "Internet",
      "destinationPortRange": "*",
      "direction": "Outbound",
      "etag": "W/\"3371b313-ea9f-4687-a336-a8ebdfd80523\"",
      "id": "/subscriptions/guid/resourceGroups/myResourceGroup/providers/Microsoft.Network/networkSecurityGroups/myNetworkSecurityGroup/defaultSecurityRules/AllowInternetOutBound",
      "name": "AllowInternetOutBound",
      "priority": 65001,
      "protocol": "*",
      "provisioningState": "Succeeded",
      "resourceGroup": "myResourceGroup",
      "sourceAddressPrefix": "*",
      "sourcePortRange": "*"
    },
    {
      "access": "Deny",
      "description": "Deny all outbound traffic",
      "destinationAddressPrefix": "*",
      "destinationPortRange": "*",
      "direction": "Outbound",
      "etag": "W/\"3371b313-ea9f-4687-a336-a8ebdfd80523\"",
      "id": "/subscriptions/guid/resourceGroups/myResourceGroup/providers/Microsoft.Network/networkSecurityGroups/myNetworkSecurityGroup/defaultSecurityRules/DenyAllOutBound",
      "name": "DenyAllOutBound",
      "priority": 65500,
      "protocol": "*",
      "provisioningState": "Succeeded",
      "resourceGroup": "myResourceGroup",
      "sourceAddressPrefix": "*",
      "sourcePortRange": "*"
    }
  ],
  "etag": "W/\"3371b313-ea9f-4687-a336-a8ebdfd80523\"",
  "id": "/subscriptions/guid/resourceGroups/myResourceGroup/providers/Microsoft.Network/networkSecurityGroups/myNetworkSecurityGroup",
  "location": "eastus",
  "name": "myNetworkSecurityGroup",
  "networkInterfaces": null,
  "provisioningState": "Succeeded",
  "resourceGroup": "myResourceGroup",
  "resourceGuid": "47a9964e-23a3-438a-a726-8d60ebbb1c3c",
  "securityRules": [
    {
      "access": "Allow",
      "description": null,
      "destinationAddressPrefix": "*",
      "destinationPortRange": "22",
      "direction": "Inbound",
      "etag": "W/\"9e344b60-0daa-40a6-84f9-0ebbe4a4b640\"",
      "id": "/subscriptions/guid/resourceGroups/myResourceGroup/providers/Microsoft.Network/networkSecurityGroups/myNetworkSecurityGroup/securityRules/myNetworkSecurityGroupRuleSSH",
      "name": "myNetworkSecurityGroupRuleSSH",
      "priority": 1000,
      "protocol": "Tcp",
      "provisioningState": "Succeeded",
      "resourceGroup": "myResourceGroup",
      "sourceAddressPrefix": "*",
      "sourcePortRange": "*"
    },
    {
      "access": "Allow",
      "description": null,
      "destinationAddressPrefix": "*",
      "destinationPortRange": "80",
      "direction": "Inbound",
      "etag": "W/\"9e344b60-0daa-40a6-84f9-0ebbe4a4b640\"",
      "id": "/subscriptions/guid/resourceGroups/myResourceGroup/providers/Microsoft.Network/networkSecurityGroups/myNetworkSecurityGroup/securityRules/myNetworkSecurityGroupRuleWeb",
      "name": "myNetworkSecurityGroupRuleWeb",
      "priority": 1001,
      "protocol": "Tcp",
      "provisioningState": "Succeeded",
      "resourceGroup": "myResourceGroup",
      "sourceAddressPrefix": "*",
      "sourcePortRange": "*"
    }
  ],
  "subnets": null,
  "tags": null,
  "type": "Microsoft.Network/networkSecurityGroups"
}

Skapa ett virtuellt nätverkskort

Nätverkskort (Virtual Network Interface Cards) är programmatiskt tillgängliga eftersom du kan tillämpa regler för deras användning. Beroende på storleken på den virtuella datorn kan du koppla flera virtuella nätverkskort till en virtuell dator. I följande az network nic create-kommando skapar du ett nätverkskort med namnet myNic och associerar det med nätverkssäkerhetsgruppen. Den offentliga IP-adressen myPublicIP är också associerad med det virtuella nätverkskortet.

az network nic create \
    --resource-group myResourceGroup \
    --name myNic \
    --vnet-name myVnet \
    --subnet mySubnet \
    --public-ip-address myPublicIP \
    --network-security-group myNetworkSecurityGroup

Utdata:

{
  "NewNIC": {
    "dnsSettings": {
      "appliedDnsServers": [],
      "dnsServers": [],
      "internalDnsNameLabel": null,
      "internalDomainNameSuffix": "brqlt10lvoxedgkeuomc4pm5tb.bx.internal.cloudapp.net",
      "internalFqdn": null
    },
    "enableAcceleratedNetworking": false,
    "enableIpForwarding": false,
    "etag": "W/\"04b5ab44-d8f4-422a-9541-e5ae7de8466d\"",
    "id": "/subscriptions/guid/resourceGroups/myResourceGroup/providers/Microsoft.Network/networkInterfaces/myNic",
    "ipConfigurations": [
      {
        "applicationGatewayBackendAddressPools": null,
        "etag": "W/\"04b5ab44-d8f4-422a-9541-e5ae7de8466d\"",
        "id": "/subscriptions/guid/resourceGroups/myResourceGroup/providers/Microsoft.Network/networkInterfaces/myNic/ipConfigurations/ipconfig1",
        "loadBalancerBackendAddressPools": null,
        "loadBalancerInboundNatRules": null,
        "name": "ipconfig1",
        "primary": true,
        "privateIpAddress": "192.168.1.4",
        "privateIpAddressVersion": "IPv4",
        "privateIpAllocationMethod": "Dynamic",
        "provisioningState": "Succeeded",
        "publicIpAddress": {
          "dnsSettings": null,
          "etag": null,
          "id": "/subscriptions/guid/resourceGroups/myResourceGroup/providers/Microsoft.Network/publicIPAddresses/myPublicIP",
          "idleTimeoutInMinutes": null,
          "ipAddress": null,
          "ipConfiguration": null,
          "location": null,
          "name": null,
          "provisioningState": null,
          "publicIpAddressVersion": null,
          "publicIpAllocationMethod": null,
          "resourceGroup": "myResourceGroup",
          "resourceGuid": null,
          "tags": null,
          "type": null
        },
        "resourceGroup": "myResourceGroup",
        "subnet": {
          "addressPrefix": null,
          "etag": null,
          "id": "/subscriptions/guid/resourceGroups/myResourceGroup/providers/Microsoft.Network/virtualNetworks/myVnet/subnets/mySubnet",
          "ipConfigurations": null,
          "name": null,
          "networkSecurityGroup": null,
          "provisioningState": null,
          "resourceGroup": "myResourceGroup",
          "resourceNavigationLinks": null,
          "routeTable": null
        }
      }
    ],
    "location": "eastus",
    "macAddress": null,
    "name": "myNic",
    "networkSecurityGroup": {
      "defaultSecurityRules": null,
      "etag": null,
      "id": "/subscriptions/guid/resourceGroups/myResourceGroup/providers/Microsoft.Network/networkSecurityGroups/myNetworkSecurityGroup",
      "location": null,
      "name": null,
      "networkInterfaces": null,
      "provisioningState": null,
      "resourceGroup": "myResourceGroup",
      "resourceGuid": null,
      "securityRules": null,
      "subnets": null,
      "tags": null,
      "type": null
    },
    "primary": null,
    "provisioningState": "Succeeded",
    "resourceGroup": "myResourceGroup",
    "resourceGuid": "b3dbaa0e-2cf2-43be-a814-5cc49fea3304",
    "tags": null,
    "type": "Microsoft.Network/networkInterfaces",
    "virtualMachine": null
  }
}

Skapa en tillgänglighetsuppsättning

Tillgänglighetsuppsättningar hjälper dig att sprida dina virtuella datorer över feldomäner och uppdatera domäner. Även om du bara skapar en virtuell dator just nu är det bästa praxis att använda tillgänglighetsuppsättningar för att göra det enklare att expandera i framtiden.

Feldomäner definierar en gruppering av virtuella datorer som delar en gemensam strömkälla och nätverksväxel. Som standard avgränsas de virtuella datorer som är konfigurerade i din tillgänglighetsuppsättning mellan upp till tre feldomäner. Ett maskinvaruproblem i någon av dessa feldomäner påverkar inte alla virtuella datorer som kör din app.

Uppdateringsdomäner anger grupper av virtuella datorer och underliggande fysisk maskinvara som kan startas om samtidigt. Under planerat underhåll kanske inte den ordning i vilken uppdateringsdomäner startas om är sekventiell, men endast en uppdateringsdomän startas om i taget.

Azure distribuerar automatiskt virtuella datorer över fel- och uppdateringsdomänerna när de placeras i en tillgänglighetsuppsättning. Mer information finns i Hantera tillgängligheten för virtuella datorer.

Skapa en tillgänglighetsuppsättning för den virtuella datorn med az vm availability-set create. I följande exempel skapas en tillgänglighetsuppsättning med namnet myAvailabilitySet:

az vm availability-set create \
    --resource-group myResourceGroup \
    --name myAvailabilitySet

Utdata noterar feldomäner och uppdateringsdomäner:

{
  "id": "/subscriptions/guid/resourceGroups/myResourceGroup/providers/Microsoft.Compute/availabilitySets/myAvailabilitySet",
  "location": "eastus",
  "managed": null,
  "name": "myAvailabilitySet",
  "platformFaultDomainCount": 2,
  "platformUpdateDomainCount": 5,
  "resourceGroup": "myResourceGroup",
  "sku": {
    "capacity": null,
    "managed": true,
    "tier": null
  },
  "statuses": null,
  "tags": {},
  "type": "Microsoft.Compute/availabilitySets",
  "virtualMachines": []
}

Skapa en virtuell dator

Du har skapat nätverksresurserna för att stödja internettillgängliga virtuella datorer. Skapa nu en virtuell dator och skydda den med en SSH-nyckel. I det här exemplet ska vi skapa en virtuell Ubuntu-dator baserat på den senaste LTS. Du hittar ytterligare avbildningar med az vm image list, enligt beskrivningen i hitta Azure VM-avbildningar.

Ange en SSH-nyckel som ska användas för autentisering. Om du inte har ett offentligt SSH-nyckelpar kan du skapa dem eller använda parametern --generate-ssh-keys för att skapa dem åt dig. Om du redan har ett nyckelpar använder den här parametern befintliga nycklar i ~/.ssh.

Skapa den virtuella datorn genom att sammanföra alla resurser och all information med kommandot az vm create . I följande exempel skapas en virtuell dator med namnet myVM:

az vm create \
    --resource-group myResourceGroup \
    --name myVM \
    --location eastus \
    --availability-set myAvailabilitySet \
    --nics myNic \
    --image Ubuntu2204 \
    --admin-username azureuser \
    --generate-ssh-keys

SSH till den virtuella datorn med dns-posten som du angav när du skapade den offentliga IP-adressen. Detta fqdn visas i utdata när du skapar den virtuella datorn:

{
  "fqdns": "mypublicdns.eastus.cloudapp.azure.com",
  "id": "/subscriptions/guid/resourceGroups/myResourceGroup/providers/Microsoft.Compute/virtualMachines/myVM",
  "location": "eastus",
  "macAddress": "00-0D-3A-13-71-C8",
  "powerState": "VM running",
  "privateIpAddress": "192.168.1.5",
  "publicIpAddress": "13.90.94.252",
  "resourceGroup": "myResourceGroup"
}
ssh azureuser@mypublicdns.eastus.cloudapp.azure.com

Utdata:

The authenticity of host 'mypublicdns.eastus.cloudapp.azure.com (13.90.94.252)' can't be established.
ECDSA key fingerprint is SHA256:SylINP80Um6XRTvWiFaNz+H+1jcrKB1IiNgCDDJRj6A.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'mypublicdns.eastus.cloudapp.azure.com,13.90.94.252' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 16.04.3 LTS (GNU/Linux 4.11.0-1016-azure x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  Get cloud support with Ubuntu Advantage Cloud Guest:
    https://www.ubuntu.com/business/services/cloud

0 packages can be updated.
0 updates are security updates.


The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

azureuser@myVM:~$

Du kan installera NGINX och se trafikflödet till den virtuella datorn. Installera NGINX på följande sätt:

sudo apt-get install -y nginx

Om du vill se hur NGINX-standardwebbplatsen fungerar öppnar du webbläsaren och anger ditt fullständiga domännamn:

NGINX-standardwebbplats på den virtuella datorn

Exportera som en mall

Vad händer om du nu vill skapa en ytterligare utvecklingsmiljö med samma parametrar eller en produktionsmiljö som matchar den? Resource Manager använder JSON-mallar som definierar alla parametrar för din miljö. Du skapar hela miljöer genom att referera till den här JSON-mallen. Du kan skapa JSON-mallar manuellt eller exportera en befintlig miljö för att skapa JSON-mallen åt dig. Använd az group export för att exportera resursgruppen på följande sätt:

az group export --name myResourceGroup > myResourceGroup.json

Det här kommandot skapar myResourceGroup.json filen i den aktuella arbetskatalogen. När du skapar en miljö från den här mallen uppmanas du att ange alla resursnamn. Du kan fylla i dessa namn i mallfilen genom att lägga till parametern --include-parameter-default-value i az group export kommandot . Redigera JSON-mallen för att ange resursnamnen eller skapa en parameters.json-fil som anger resursnamnen.

Om du vill skapa en miljö från mallen använder du az deployment group create på följande sätt:

az deployment group create \
    --resource-group myNewResourceGroup \
    --template-file myResourceGroup.json

Du kanske vill läsa mer om hur du distribuerar från mallar. Lär dig mer om att stegvis uppdatera miljöer, använda parameterfilen och komma åt mallar från en enda lagringsplats.

Nästa steg

Nu är du redo att börja arbeta med flera nätverkskomponenter och virtuella datorer. Du kan använda den här exempelmiljön för att bygga ut ditt program med hjälp av de kärnkomponenter som introduceras här.