创建自定义映像
通过创建自定义容器映像,可以自定义部署来满足你的要求。 你可以基于 ADE 示例映像创建自定义映像。
完成映像自定义后,你必须生成映像并将其推送到容器注册表。
你可以手动生成和推送映像,也可以使用 Microsoft 提供的脚本自动执行该过程。
你可以通过预安装在示例映像上的 ADE CLI 使用 ADE 示例映像作为基础来生成自定义映像。 若要详细了解 ADE CLI,请参阅 CLI 自定义运行程序映像参考。
本示例介绍如何生成 Docker 映像来利用 ADE 部署并访问 ADE CLI,使你的映像基于 ADE 创作的映像之一。
要创建为 ADE 配置的映像,请执行以下步骤:
- 创建一个基于示例映像的自定义映像。
- 安装所需的程序包。
- 配置操作 shell 脚本。
- 创建用于部署 ARM 或 Bicep 模板的操作 shell 脚本。
要创建为 ADE 配置的映像,请执行以下步骤:
- 创建一个基于示例映像的自定义映像。
- 安装所需的程序包。
- 配置操作 shell 脚本。
- 创建使用 Terraform CLI 的操作 shell 脚本。
要创建为 ADE 配置的映像,请执行以下步骤:
- 创建一个基于示例映像的自定义映像。
- 安装所需的程序包。
- 配置操作 shell 脚本。
- 创建使用 Pulumi CLI 的操作 shell 脚本。
1.创建一个基于示例映像的自定义映像
创建一个 DockerFile,在其中包括一个 FROM 语句,指向 Microsoft 工件注册表上托管的示例映像。
下面是引用示例核心映像的示例 FROM 语句:
FROM mcr.microsoft.com/deployment-environments/runners/core:latest
此语句拉取最近发布的核心映像,并使其成为你的自定义映像的基础。
2.安装所需的程序包
在此步骤中,你将在映像中安装所需的任何程序包,包括 Bicep。 可以使用 RUN 语句通过 Azure CLI 安装 Bicep 包,如以下示例所示:
RUN az bicep install
在此步骤中,你将在映像中安装所需的任何程序包,包括 Terraform。 可以将 Terraform CLI 安装到可执行文件位置,以便在部署和删除脚本中使用它。
下面是安装 Terraform CLI 版本 1.7.5 的过程示例:
RUN wget -O terraform.zip https://releases.hashicorp.com/terraform/1.7.5/terraform_1.7.5_linux_amd64.zip
RUN unzip terraform.zip && rm terraform.zip
RUN mv terraform /usr/bin/terraform
可以将 Pulumi CLI 安装到可执行文件位置,以便在部署和删除脚本中使用它。
下面是安装最新版 Pulumi CLI 的过程示例:
RUN apk add curl
RUN curl -fsSL https://get.pulumi.com | sh
ENV PATH="${PATH}:/root/.pulumi/bin"
可能需要安装一个或多个相应的运行时,具体取决于要用于 Pulumi 程序的编程语言。 Python 运行时已在基础映像中提供。
下面是安装 Node.js 和 TypeScript 的示例:
# install node.js, npm, and typescript
RUN apk add nodejs npm
RUN npm install typescript -g
ADE 示例映像基于 Azure CLI 映像,并且预安装了 ADE CLI 和 JQ 包。 可以详细了解 Azure CLI 和 JQ 包。
若要在映像中安装所需的任何其他包,请使用 RUN 语句。
3.配置操作 shell 脚本
在示例映像中,将根据操作名称来确定和执行操作。 目前,支持的两个操作名称是 deploy 和 delete。
若要设置自定义映像以利用此结构,请在名为 scripts 的 Dockerfile 级别指定一个文件夹,然后指定两个文件 deploy.sh 和 delete.sh。deploy shell 脚本在创建或重新部署环境时运行,delete shell 脚本在删除环境时运行。 可以在存储库中 ARM-Bicep 映像的 Runner-Images 文件夹下查看 shell 脚本的示例。
若要确保这些 shell 脚本是可执行的,请将以下行添加到 Dockerfile:
COPY scripts/* /scripts/
RUN find /scripts/ -type f -iname "*.sh" -exec dos2unix '{}' '+'
RUN find /scripts/ -type f -iname "*.sh" -exec chmod +x {} \;
4.创建用于部署 ARM 或 Bicep 模板的操作 shell 脚本
若要确保可以通过 ADE 成功部署 ARM 或 Bicep 基础结构,必须:
- 将 ADE 参数转换为 ARM 可接受的参数
- 解决在部署中使用的链接模板
- 使用特权托管标识执行部署
在核心映像的入口点期间,为当前环境设置的任何参数都存储在变量 $ADE_OPERATION_PARAMETERS
下。 若要将它们转换为 ARM 可接受的参数,则可以使用 JQ 运行以下命令:
# format the parameters as arm parameters
deploymentParameters=$(echo "$ADE_OPERATION_PARAMETERS" | jq --compact-output '{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": (to_entries | if length == 0 then {} else (map( { (.key): { "value": .value } } ) | add) end) }' )
接下来,若要解析基于 ARM JSON 的模板中使用的任何链接模板,可以反编译主模板文件,该文件可解析用于许多 Bicep 模块的所有本地基础结构文件。 然后,将这些模块重新生成回单个 ARM 模板,并将链接模板作为嵌套模板嵌入到主 ARM 模板中。 此步骤仅在部署操作期间是必需的。 可以使用核心映像入口点期间设置的 $ADE_TEMPLATE_FILE
指定主模板文件,应使用重新编译的模板文件重置此变量。 请参阅以下示例:
if [[ $ADE_TEMPLATE_FILE == *.json ]]; then
hasRelativePath=$( cat $ADE_TEMPLATE_FILE | jq '[.. | objects | select(has("templateLink") and (.templateLink | has("relativePath")))] | any' )
if [ "$hasRelativePath" = "true" ]; then
echo "Resolving linked ARM templates"
bicepTemplate="${ADE_TEMPLATE_FILE/.json/.bicep}"
generatedTemplate="${ADE_TEMPLATE_FILE/.json/.generated.json}"
az bicep decompile --file "$ADE_TEMPLATE_FILE"
az bicep build --file "$bicepTemplate" --outfile "$generatedTemplate"
# Correctly reassign ADE_TEMPLATE_FILE without the $ prefix during assignment
ADE_TEMPLATE_FILE="$generatedTemplate"
fi
fi
若要提供部署在订阅中执行部署和删除资源所需的权限,请使用与 ADE 项目环境类型关联的特权托管标识。 如果部署需要特殊权限才能完成,例如特定角色,请将这些角色分配给项目环境类型的标识。 有时,在进入容器时,托管标识不会立即可用;你可以重试,直到登录成功。
echo "Signing into Azure using MSI"
while true; do
# managed identity isn't available immediately
# we need to do retry after a short nap
az login --identity --allow-no-subscriptions --only-show-errors --output none && {
echo "Successfully signed into Azure"
break
} || sleep 5
done
若要开始部署 ARM 或 Bicep 模板,请运行 az deployment group create
命令。 在容器中运行此命令时,请选择不替代任何过去部署的部署名称,并使用 --no-prompt true
和 --only-show-errors
标志来确保部署不会在出现任何警告或等待用户输入时停止,如以下示例所示:
deploymentName=$(date +"%Y-%m-%d-%H%M%S")
az deployment group create --subscription $ADE_SUBSCRIPTION_ID \
--resource-group "$ADE_RESOURCE_GROUP_NAME" \
--name "$deploymentName" \
--no-prompt true --no-wait \
--template-file "$ADE_TEMPLATE_FILE" \
--parameters "$deploymentParameters" \
--only-show-errors
若要删除环境,请执行完整模式部署并提供一个空 ARM 模板,该模板会移除指定 ADE 资源组中的所有资源,如以下示例所示:
deploymentName=$(date +"%Y-%m-%d-%H%M%S")
az deployment group create --resource-group "$ADE_RESOURCE_GROUP_NAME" \
--name "$deploymentName" \
--no-prompt true --no-wait --mode Complete \
--only-show-errors \
--template-file "$DIR/empty.json"
可以通过运行以下命令来检查预配状态和详细信息。 ADE 使用一些特殊函数根据预配的详细信息读取和提供其他上下文,你可以在运行程序映像文件夹中找到这些详细信息。 一个简单的实现可能如下所示:
if [ $? -eq 0 ]; then # deployment successfully created
while true; do
sleep 1
ProvisioningState=$(az deployment group show --resource-group "$ADE_RESOURCE_GROUP_NAME" --name "$deploymentName" --query "properties.provisioningState" -o tsv)
ProvisioningDetails=$(az deployment operation group list --resource-group "$ADE_RESOURCE_GROUP_NAME" --name "$deploymentName")
echo "$ProvisioningDetails"
if [[ "CANCELED|FAILED|SUCCEEDED" == *"${ProvisioningState^^}"* ]]; then
echo -e "\nDeployment $deploymentName: $ProvisioningState"
if [[ "CANCELED|FAILED" == *"${ProvisioningState^^}"* ]]; then
exit 11
else
break
fi
fi
done
fi
最后,若要查看部署的输出并将其传递给 ADE,以便通过 Azure CLI 访问它们,可以运行以下命令:
deploymentOutput=$(az deployment group show -g "$ADE_RESOURCE_GROUP_NAME" -n "$deploymentName" --query properties.outputs)
if [ -z "$deploymentOutput" ]; then
deploymentOutput="{}"
fi
echo "{\"outputs\": $deploymentOutput}" > $ADE_OUTPUTS
4.创建使用 Terraform CLI 的操作 shell 脚本
通过 Terraform 部署基础结构分为三个步骤:
terraform init
- 初始化 Terraform CLI 以在工作目录中执行操作
terraform plan
- 根据传入的 Terraform 基础结构文件和变量以及任何现有状态文件制定计划,并制定创建或更新 .tf 文件中指定的基础结构所需的步骤
terraform apply
- 应用计划以在 Azure 中创建新的基础结构或更新现有基础结构
在核心映像的入口点内,任何现有状态文件都被拉取到容器中,目录保存在环境变量 $ADE_STORAGE
下。 此外,为当前环境设置的任何参数都存储在变量 $ADE_OPERATION_PARAMETERS
下。 若要访问现有状态文件并在 .tfvars.json 文件中设置变量,请运行以下命令:
EnvironmentState="$ADE_STORAGE/environment.tfstate"
EnvironmentPlan="/environment.tfplan"
EnvironmentVars="/environment.tfvars.json"
echo "$ADE_OPERATION_PARAMETERS" > $EnvironmentVars
此外,若要利用 ADE 的权限在订阅中部署基础结构,则在使用 Terraform AzureRM 提供程序预配基础结构时,脚本需要使用托管服务标识 (MSI)。 如果你的部署需要特殊权限才能完成部署(例如特定角色),请将这些权限分配给用于环境部署的项目环境类型的标识。 ADE 设置相关的环境变量,例如核心映像入口点内的客户端、租户和订阅 ID,因此请运行以下命令以确保提供程序使用 ADE 的 MSI:
export ARM_USE_MSI=true
export ARM_CLIENT_ID=$ADE_CLIENT_ID
export ARM_TENANT_ID=$ADE_TENANT_ID
export ARM_SUBSCRIPTION_ID=$ADE_SUBSCRIPTION_ID
如果要在模板中引用其他变量但并未在环境参数中指定这些变量,请使用前缀 TF_VAR 设置环境变量。 Azure 部署环境 CLI 变量参考中提供了提供的 ADE 环境变量的列表。 这些命令的示例如下:
export TF_VAR_resource_group_name=$ADE_RESOURCE_GROUP_NAME
export TF_VAR_ade_env_name=$ADE_ENVIRONMENT_NAME
export TF_VAR_env_name=$ADE_ENVIRONMENT_NAME
export TF_VAR_ade_subscription=$ADE_SUBSCRIPTION_ID
export TF_VAR_ade_location=$ADE_ENVIRONMENT_LOCATION
export TF_VAR_ade_environment_type=$ADE_ENVIRONMENT_TYPE
现在,可以运行前面列出的步骤来初始化 Terraform CLI,生成基础结构预配计划,并在部署脚本期间应用计划:
terraform init
terraform plan -no-color -compact-warnings -refresh=true -lock=true -state=$EnvironmentState -out=$EnvironmentPlan -var-file="$EnvironmentVars"
terraform apply -no-color -compact-warnings -auto-approve -lock=true -state=$EnvironmentState $EnvironmentPlan
在删除脚本中,可以将 destroy
标志添加到计划生成部分以删除现有资源,如以下示例中所示:
terraform init
terraform plan -no-color -compact-warnings -destroy -refresh=true -lock=true -state=$EnvironmentState -out=$EnvironmentPlan -var-file="$EnvironmentVars"
terraform apply -no-color -compact-warnings -auto-approve -lock=true -state=$EnvironmentState $EnvironmentPlan
最后,若要在通过 Azure CLI 访问环境时上传并访问部署的输出,请通过 JQ 包将输出对象从 Terraform 转换为 ADE 指定的格式。 设置 $ADE_OUTPUTS 环境变量的值,如以下示例中所示:
tfOutputs=$(terraform output -state=$EnvironmentState -json)
# Convert Terraform output format to ADE format.
tfOutputs=$(jq 'walk(if type == "object" then
if .type == "bool" then .type = "boolean"
elif .type == "list" then .type = "array"
elif .type == "map" then .type = "object"
elif .type == "set" then .type = "array"
elif (.type | type) == "array" then
if .type[0] == "tuple" then .type = "array"
elif .type[0] == "object" then .type = "object"
elif .type[0] == "set" then .type = "array"
else .
end
else .
end
else .
end)' <<< "$tfOutputs")
echo "{\"outputs\": $tfOutputs}" > $ADE_OUTPUTS
通过 Pulumi 部署基础结构有四个步骤:
pulumi login
- 连接到本地文件系统或 Pulumi Cloud 中的状态存储
pulumi stack select
- 创建或选择要用于特定环境的堆栈
pulumi config set
- 将部署参数作为 Pulumi 配置值传递
pulumi up
- 运行部署以在 Azure 中创建新的基础结构或更新现有基础结构
在核心映像的入口点内,任何现有本地状态文件都被拉取到容器中,目录保存在环境变量 $ADE_STORAGE
下。 若要访问现有状态文件,请运行以下命令:
mkdir -p $ADE_STORAGE
export PULUMI_CONFIG_PASSPHRASE=
pulumi login file://$ADE_STORAGE
若要改为登录到 Pulumi Cloud,请将 Pulumi 访问令牌设置为环境变量,并运行以下命令:
export PULUMI_ACCESS_TOKEN=YOUR_PULUMI_ACCESS_TOKEN
pulumi login
为当前环境设置的任何参数都存储在变量 $ADE_OPERATION_PARAMETERS
下。 此外,所选的 Azure 区域和资源组名称分别通过 ADE_ENVIRONMENT_LOCATION
和 ADE_RESOURCE_GROUP_NAME
传递。 若要设置 Pulumi 堆栈配置,请运行以下命令:
# Create or select the stack for the current environment
pulumi stack select $ADE_ENVIRONMENT_NAME --create
# Store configuration values in durable storage
export PULUMI_CONFIG_FILE=$ADE_STORAGE/Pulumi.$ADE_ENVIRONMENT_NAME.yaml
# Set the Pulumi stack config
pulumi config set azure-native:location $ADE_ENVIRONMENT_LOCATION --config-file $PULUMI_CONFIG_FILE
pulumi config set resource-group-name $ADE_RESOURCE_GROUP_NAME --config-file $PULUMI_CONFIG_FILE
echo "$ADE_OPERATION_PARAMETERS" | jq -r 'to_entries|.[]|[.key, .value] | @tsv' |
while IFS=$'\t' read -r key value; do
pulumi config set $key $value --config-file $PULUMI_CONFIG_FILE
done
此外,若要利用 ADE 权限在订阅中部署基础结构,则在使用 Pulumi Azure Native 或 Azure Classic 提供程序预配基础结构时,脚本需要使用 ADE 托管服务标识 (MSI)。 如果你的部署需要特殊权限才能完成部署(例如特定角色),请将这些权限分配给用于环境部署的项目环境类型的标识。 ADE 设置相关的环境变量,例如核心映像入口点内的客户端、租户和订阅 ID,因此运行以下命令以确保提供程序使用 ADE MSI:
export ARM_USE_MSI=true
export ARM_CLIENT_ID=$ADE_CLIENT_ID
export ARM_TENANT_ID=$ADE_TENANT_ID
export ARM_SUBSCRIPTION_ID=$ADE_SUBSCRIPTION_ID
现在,可以运行 pulumi up
命令来执行部署:
pulumi up --refresh --yes --config-file $PULUMI_CONFIG_FILE
在删除脚本期间,可以改为运行 destroy
命令,如以下示例所示:
pulumi destroy --refresh --yes --config-file $PULUMI_CONFIG_FILE
最后,若要在通过 Azure CLI 访问环境时上传并访问部署的输出,请通过 JQ 包将输出对象从 Pulumi 转换为 ADE 指定的格式。 设置 $ADE_OUTPUTS 环境变量的值,如以下示例中所示:
stackout=$(pulumi stack output --json | jq -r 'to_entries|.[]|{(.key): {type: "string", value: (.value)}}')
echo "{\"outputs\": ${stackout:-{\}}}" > $ADE_OUTPUTS