你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

为 Azure 运营商关系虚拟机创建映像

本文介绍如何创建可用于在运营商关系中创建虚拟机的容器映像。 具体而言,你将了解如何向容器映像添加虚拟磁盘。 生成容器映像并将其推送到 Azure 容器注册表后,可将其用于在运营商关系中创建虚拟机。

先决条件

在开始创建虚拟机 (VM) 映像之前,请确保已满足以下先决条件:

  • 安装必需的 Azure CLI 扩展的最新版本。

  • 本文需要 2.61.0 或更高版本的 Azure CLI。 如果使用 Azure Cloud Shell,则最新版本已安装。

  • Azure 容器注册表 (ACR):设置一个可正常运行的 Azure 容器注册表,用于存储和管理容器映像。 ACR 提供了一个安全的专用注册表,用于存储在 VM 映像创建过程中使用的 Docker 映像。 可以按照 Azure 容器注册表文档的官方文档中的步骤创建 ACR。

  • Docker:在本地计算机上安装 Docker。 Docker 是一个平台,可用于将应用程序生成、打包并分发为轻量级容器。 使用 Docker 生成和打包 VM 映像。 可以从 Docker 的官方网站下载 Docker。

注意

可以使用 az login 命令向 Azure 进行身份验证,脚本将使用提供的 ACR 名称和订阅 ID 自动执行 ACR 登录。 如果计算机上未安装 Azure CLI,可以改为提供用户名和密码进行 ACR 登录。

在继续创建 VM 映像之前,请确保计算机上安装了可运行的 Azure 容器注册表 (ACR) 和 Docker。 熟悉 ACR 和 Docker 的使用和功能,因为它们对于管理容器映像和生成 VM 映像至关重要。

虚拟机映像要求

  • 确保虚拟化网络功能 (VNF) 映像为 qcow2 格式,并且可以使用 cloud-init 启动。

  • 需要在映像中配置引导加载程序、内核和初始化系统,以启用基于文本的串行控制台。 若要为虚拟机 (VM) 启用控制台支持,必须进行此配置。 确保系统和终端上的串行端口设置相匹配,以建立正确的通信。

  • 需要确保 VM 映像支持 cloud-init 版本 2,以便在 VM 初始化过程中启用高级配置选项。

  • 需要确保 VM 映像包含包含带有 nocloud 数据源的 cloud-init。 nocloud 数据源允许在 VM 预配期间进行初始配置和自定义。

  • 磁盘必须放置在容器内的 /disk 目录中。

  • 支持 raw 格式和 qcow2 格式。 建议使用 qcow2 来减小容器映像的大小。

  • 容器磁盘应基于 scratch 映像,这是一个空的基础映像,除映像本身外不包含任何文件或目录。 使用 scratch 作为基础映像可确保容器映像尽可能小,并且仅包含 VNF 所需的文件。

为运营商关系虚拟机创建映像的步骤

可以使用提供的脚本为 VNF 创建映像。 它会生成一个 Dockerfile,用于将 VNF 磁盘映像文件复制到容器的 /disk 目录中。

注意

以下提供的脚本是一个示例。 如果愿意,可以手动创建并推送容器映像,而不是按照脚本操作。

以下环境变量用于配置为 VNF 创建虚拟机 (VM) 映像的脚本。 在执行脚本之前,请使用自己的值修改并导出这些变量:


# Azure subscription ID (provide if not using username-password)
export SUBSCRIPTION="your_subscription_id"

# (Mandatory) Azure Container Registry name
export ACR_NAME="your_acr_name"

# (Mandatory) Name of the container image
export CONTAINER_IMAGE_NAME="your_container_image_name"

# (Mandatory) Tag for the container image
export CONTAINER_IMAGE_TAG="your_container_image_tag"

# (Mandatory) VNF image (URL, local file, or full local path)
export VNF_IMAGE="your_vnf_image"

# (Optional) ACR URL (leave empty to derive from ACR_NAME)
export ACR_URL=""

# (Optional) ACR login username (provide if not using subscription)
export USERNAME=""

# (Optional) ACR login password (provide if not using subscription)
export PASSWORD=""

若要为虚拟化网络功能 (VNF) 创建 VM 映像,请将提供的脚本另存为 create-container-disk.sh,设置所需的环境变量,然后执行脚本。

#!/bin/bash

# Define the required environment variables
required_vars=(
    "ACR_NAME"                  # Azure Container Registry name
    "CONTAINER_IMAGE_NAME"      # Name of the container image
    "CONTAINER_IMAGE_TAG"       # Tag for the container image
    "VNF_IMAGE"                 # VNF image (URL or file path)
)

# Verify if required environment variables are set
for var in "${required_vars[@]}"; do
    if [ -z "${!var}" ]; then
        echo "Error: $var environment variable is not set."
        exit 1
    fi
done

# Check if either SUBSCRIPTION or USERNAME with PASSWORD is provided
if [ -z "$SUBSCRIPTION" ] && [ -z "$USERNAME" ] && [ -z "$PASSWORD" ]; then
    echo "Error: Either provide SUBSCRIPTION or USERNAME with PASSWORD."
    exit 1
fi

# Set default value for DOCKERFILE_NAME if not set
if [ -z "$DOCKERFILE_NAME" ]; then
    DOCKERFILE_NAME="nexus-vm-img-dockerfile"
fi

# Check if ACR_URL is already set by the user
if [ -z "$ACR_URL" ]; then
    # Derive the ACR URL from the ACR_NAME
    ACR_URL="$ACR_NAME.azurecr.io"
fi

# Initialize variables for downloaded/copied files
downloaded_files=()

# Function to clean up downloaded files
cleanup() {
    for file in "${downloaded_files[@]}"; do
        if [ -f "$file" ]; then
            rm "$file"
        fi
    done
}

# Register the cleanup function to be called on exit
trap cleanup EXIT

# Check if the VNF image is a URL or a local file
if [[ "$VNF_IMAGE" == http* ]]; then
    # Use curl to download the file
    filename=$(basename "$VNF_IMAGE")
    # Download the VNF image file and save the output to a file
    curl -f -Lo "$filename" "$VNF_IMAGE"
    if [ $? -ne 0 ]; then
        echo "Error: Failed to download file."
        exit 1
    fi
    # Add the downloaded file to the list for cleanup
    downloaded_files+=("$filename")
elif [[ "$VNF_IMAGE" == /* ]]; then
    # Use the provided full local path
    filename=$(basename "$VNF_IMAGE")
    # Copy the VNF image file to the current directory for cleanup
    cp "$VNF_IMAGE" "./$filename"
    # Add the copied file to the list for cleanup
    downloaded_files+=("$filename")
else
    # Assume it's a local file in the current directory
    filename="$VNF_IMAGE"
fi

# Check if the file exists
if [ ! -f "$filename" ]; then
    echo "Error: File $filename does not exist."
    exit 1
fi

# Create a Dockerfile that copies the VNF image file into the container's /disk directory
# The containerDisk needs to be readable for the user with the UID 107 (qemu).
cat <<EOF > "$DOCKERFILE_NAME"
FROM scratch
ADD --chown=107:107 "$filename" /disk/
EOF

# Build the Docker image and tag it to the Azure Container Registry
docker build -f "$DOCKERFILE_NAME" -t "$CONTAINER_IMAGE_NAME:$CONTAINER_IMAGE_TAG" .

# Log in to Azure Container Registry
if [ -n "$USERNAME" ] && [ -n "$PASSWORD" ]; then
    docker login "$ACR_NAME.azurecr.io" -u "$USERNAME" -p "$PASSWORD"
else
    az acr login --name "$ACR_NAME" --subscription "$SUBSCRIPTION"
fi

docker tag "$CONTAINER_IMAGE_NAME:$CONTAINER_IMAGE_TAG" "$ACR_URL/$CONTAINER_IMAGE_NAME:$CONTAINER_IMAGE_TAG"
docker push "$ACR_URL/$CONTAINER_IMAGE_NAME:$CONTAINER_IMAGE_TAG"

# Remove the downloaded/copied files
cleanup

rm "$DOCKERFILE_NAME"

echo "VNF image $ACR_URL/$CONTAINER_IMAGE_NAME:$CONTAINER_IMAGE_TAG created successfully!"

执行脚本后,将获得一个为虚拟化网络功能 (VNF) 定制的 VM 映像。 可以使用此映像来部署 VNF。

注意

若要确保可正确拉取 VNF 映像,请确保 ACR URL 位于将用于运营商关系虚拟机的云服务网络的出口允许列表中。

用法示例

  1. 设置所需的环境变量。

    export SUBSCRIPTION=""00000000-0000-0000-0000-000000000000""
    export ACR_NAME="myvnfacr"
    export CONTAINER_IMAGE_NAME="ubuntu"
    export CONTAINER_IMAGE_TAG="20.04"
    export VNF_IMAGE="https://cloud-images.ubuntu.com/releases/focal/release/ubuntu-20.04-server-cloudimg-amd64.img"
    
  2. 将提供的脚本另存为 create-container-disk.sh 并使其可执行。

    chmod +x create-container-disk.sh
    
  3. 执行该脚本。

    $ ./create-container-disk.sh
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
    100  622M  100  622M    0     0  24.7M      0  0:00:25  0:00:25 --:--:-- 26.5M
    [+] Building 36.6s (5/5) FINISHED
     => [internal] load .dockerignore                                                              0.1s
     => => transferring context: 2B                                                                0.0s
     => [internal] load build definition from nexus-vm-img-dockerfile                              0.1s
     => => transferring dockerfile: 137B                                                           0.0s
     => [internal] load build context                                                              36.4s
     => => transferring context: 652.33MB                                                          36.3s
     => CACHED [1/1] ADD --chown=107:107 ubuntu-20.04-server-cloudimg-amd64.img /disk/             0.0s
     => exporting to image                                                                         0.0s
     => => exporting layers                                                                        0.0s
     => => writing image sha256:5b5f531c132cdbba202136b5ec41c9bfe9d91beeb5acee617c1ef902df4ca772   0.0s
     => => naming to docker.io/library/ubuntu:20.04                                                0.0s
    Login Succeeded
    The push refers to repository [myvnfacr.azurecr.io/ubuntu]
    b86efae7de58: Layer already exists
    20.04: digest: sha256:d514547ee28d9ed252167d0943d4e711547fda95161a3728c44a275f5d9669a8 size: 529
    VNF image myvnfacr.azurecr.io/ubuntu:20.04 created successfully!
    

后续步骤

请参阅快速入门指南,使用创建的映像部署 VNF。