使用 GitHub Actions 和 Azure 生成自定义虚拟机映像

通过创建用于生成虚拟机映像的工作流来开始使用 GitHub Actions

在 GitHub Actions 中,可以通过使用工作流中的项目创建自定义虚拟机映像,从而加快 CI/CD 进程。 可以生成映像并将其分发到共享映像库

然后可以使用这些映像创建虚拟机虚拟机规模集

生成虚拟机映像将用到 Azure 映像生成器服务

先决条件

工作流文件概述

工作流通过存储库的 /.github/workflows/ 路径中的 YAML (.yml) 文件定义。 此定义包含组成工作流的各种步骤和参数。

此文件包含三个部分:

部分 任务
身份验证 1. 添加用户管理的标识。
2.设置服务主体或打开 ID 连接。
3. 创建 GitHub 机密。
生成 1.设置环境。
2. 生成应用。
图像 1. 创建 VM 映像。
2. 创建虚拟机。

创建用户管理的标识

需要对 Azure 映像生成器 (AIB) 使用用户管理的标识来分发映像。 将在映像生成过程中使用 Azure 用户分配的托管标识来读取映像并将其写入共享映像库。

  1. 使用 Azure CLIAzure 门户创建用户管理的标识。 记下托管标识的名称。

  2. 自定义此 JSON 代码。 请将 {subscriptionID}{rgName} 的占位符替换为你的订阅 ID 和资源组名称。

    {
    "properties": {
        "roleName": "Image Creation Role",
        "IsCustom": true,
        "description": "Azure Image Builder access to create resources for the image build",
        "assignableScopes": [
          "/subscriptions/{subscriptionID}/resourceGroups/{rgName}"
        ],
        "permissions": [
            {
                "actions": [
                    "Microsoft.Compute/galleries/read",
                    "Microsoft.Compute/galleries/images/read",
                    "Microsoft.Compute/galleries/images/versions/read",
                    "Microsoft.Compute/galleries/images/versions/write",
                    "Microsoft.Compute/images/write",
                    "Microsoft.Compute/images/read",
                    "Microsoft.Compute/images/delete"
                ],
                "notActions": [],
                "dataActions": [],
                "notDataActions": []
            }
        ]
        } 
    } 
    
  3. 使用此 JSON 代码通过 JSON 创建新的 自定义角色

  4. 在Azure 门户中,打开 Azure 计算库并转到访问控制(IAM)。

  5. 选择“ 添加角色分配 ”,并将映像创建角色分配给用户托管标识。

生成部署凭据

Azure CLI 中使用 az ad sp create-for-rbac 命令创建服务主体。 请使用 Azure 门户中的 Azure Cloud Shell 或选择“试用”按钮运行此命令。

az ad sp create-for-rbac --name "myML" --role contributor \
                            --scopes /subscriptions/<subscription-id>/resourceGroups/<group-name> \
                            --json-auth

参数 --json-auth 在 Azure CLI 版本 >= 2.51.0 中可用。 此版本之前的版本使用 --sdk-auth,带有弃用警告。

在上面的示例中,请将占位符替换为你的订阅 ID、资源组名称和应用名称。 输出是一个 JSON 对象,包含的角色分配凭据可提供对应用服务应用的访问权限,如下所示。 复制此 JSON 对象供以后使用。

  {
    "clientId": "<GUID>",
    "clientSecret": "<GUID>",
    "subscriptionId": "<GUID>",
    "tenantId": "<GUID>",
    (...)
  }

创建 GitHub 机密

  1. GitHub 中,转到存储库。

  2. 转到导航菜单中的“设置”。

  3. 选择“安全性”>“机密和变量”>“操作”。

    Screenshot of adding a secret

  4. 选择“新建存储库机密”。

  5. 将 Azure CLI 命令的整个 JSON 输出粘贴到机密的值字段中。 为机密指定名称 AZURE_CREDENTIALS

  6. 选择“添加机密”。

使用 Azure 登录操作

通过 Azure 登录操作使用 GitHub 机密向 Azure 进行身份验证。

在此工作流中,将结合使用 Azure 登录操作和存储在 secrets.AZURE_CREDENTIALS 中的服务主体详细信息进行身份验证。 然后,运行 Azure CLI 操作。 有关如何在工作流文件中引用 GitHub 机密的详细信息,请参阅 GitHub 文档中的在工作流中使用加密的机密

on: [push]

name: Create Custom VM Image

jobs:
  build-image:
    runs-on: ubuntu-latest
    steps:
      - name: Log in with Azure
        uses: azure/login@v1
        with:
          creds: '${{ secrets.AZURE_CREDENTIALS }}'

配置 Java

通过 Java 设置 SDK 操作来设置 Java 环境。 在此示例中,你将设置环境,使用 Maven 进行生成,然后输出项目。

GitHub 项目提供一种方法以在作业之间共享工作流中的文件。 将创建项目来保存 JAR 文件,然后将其添加到虚拟机映像。

on: [push]

name: Create Custom VM Image

jobs:
  build-image:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        java: [ '17' ]

    steps:
    - name: Checkout
      uses: actions/checkout@v3    

    - name: Login via Az module
      uses: azure/login@v1
      with:
        creds: ${{secrets.AZURE_CREDENTIALS}}

    - name: Set up JDK ${{matrix.java}}
      uses: actions/setup-java@v2
      with:
        java-version: ${{matrix.java}}
        distribution: 'adopt'
        cache: maven
    - name: Build with Maven Wrapper
      run: ./mvnw -B package
        
    - name: Build Java
      run: mvn --batch-mode --update-snapshots verify

    - run: mkdir staging && cp target/*.jar staging
    - uses: actions/upload-artifact@v2
      with:
        name: Package
        path: staging

生成映像

使用生成 Azure 虚拟机映像操作来创建自定义虚拟机映像。

{subscriptionID}{rgName}{Identity} 的占位符替换为订阅 ID、资源组名称和托管标识名称。 将 {galleryName}{imageName} 的值替换为映像库名称和映像名称。

注意

如果“创建应用烘焙映像”操作失败并出现权限错误,请验证是否已将映像创建角色分配给用户托管标识。

    - name: Create App Baked Image
      id: imageBuilder
      uses: azure/build-vm-image@v0
      with:
        location: 'eastus2'
        resource-group-name: '{rgName}'
        managed-identity: '{Identity}' # Managed identity
        source-os-type: 'windows'
        source-image-type: 'platformImage'
        source-image: MicrosoftWindowsServer:WindowsServer:2019-Datacenter:latest #unique identifier of source image
        dist-type: 'SharedImageGallery'
        dist-resource-id: '/subscriptions/{subscriptionID}/resourceGroups/{rgName}/providers/Microsoft.Compute/galleries/{galleryName}/images/{imageName}/versions/0.1.${{ GITHUB.RUN_ID }}' #Replace with the resource id of your shared image  gallery's image definition
        dist-location: 'eastus2'

虚拟机操作参数

输入 必须 说明
resource-group-name 用于在生成过程中存储和保存项目的资源组。
image-builder-template-name 使用的映像生成器模板资源的名称。
location Azure 映像生成器将运行的位置。 请参阅支持的位置
build-timeout-in-minutes 在此之后取消生成的时间。 默认为 240。
vm-size 可选 默认情况下,将使用 Standard_D1_v2。 请参阅虚拟机大小
managed-identity 之前创建的用户管理的标识。 如果标识位于不同的资源组,请使用完整的标识符。 如果它位于相同的资源组,请使用该名称。
source-os 基础映像的 OS 类型(Linux 或 Windows)
source-image-type 将用于创建自定义映像的基础映像类型。
source-image 基础映像的资源标识符。 源映像应出现在 location 输入值中所设置的同一 Azure 区域中。
customizer-source 可以在其中保留所有需要添加到基础映像以进行自定义的项目的目录。 默认情况下该值为 ${{ GITHUB.WORKSPACE }}/workflow-artifacts.
customizer-destination 这是自定义映像中项目所复制到的目录。
customizer-windows-update 仅限 Windows。 布尔值。 如果为 true,则映像生成器在自定义结束时将运行 Windows 更新。
dist-location 对于 SharedImageGallery,这是 dist-type
dist-image-tags 这些是用户定义的标记,它们将添加到创建的自定义映像(示例:version:beta)。

创建虚拟机

最后一步是从映像创建虚拟机。

  1. {rgName} 的占位符替换为资源组名称。

  2. 使用虚拟机密码 (VM_PWD) 添加 GitHub 机密。 请确保记下该密码,因为将无法再次查看它。 用户名为 myuser

    - name: CREATE VM
      uses: azure/CLI@v1
      with:
        azcliversion: 2.0.72
        inlineScript: |
        az vm create --resource-group ghactions-vMimage  --name "app-vm-${{ GITHUB.RUN_NUMBER }}"  --admin-username myuser --admin-password "${{ secrets.VM_PWD }}" --location  eastus2 \
            --image "${{ steps.imageBuilder.outputs.custom-image-uri }}"              

完成 YAML

  on: [push]

  name: Create Custom VM Image

  jobs:
    build-image:
      runs-on: ubuntu-latest    
      steps:
      - name: Checkout
        uses: actions/checkout@v2    

      - name: Login via Az module
        uses: azure/login@v1
        with:
          creds: ${{secrets.AZURE_CREDENTIALS}}

      - name: Setup Java 1.8.x
        uses: actions/setup-java@v1
        with:
          java-version: '1.8.x'
          
      - name: Build Java
        run: mvn --batch-mode --update-snapshots verify

      - run: mkdir staging && cp target/*.jar staging
      - uses: actions/upload-artifact@v2
        with:
          name: Package
          path: staging

      - name: Create App Baked Image
        id: imageBuilder
        uses: azure/build-vm-image@v0
        with:
          location: 'eastus2'
          resource-group-name: '{rgName}'
          managed-identity: '{Identity}' # Managed identity
          source-os-type: 'windows'
          source-image-type: 'platformImage'
          source-image: MicrosoftWindowsServer:WindowsServer:2019-Datacenter:latest #unique identifier of source image
          dist-type: 'SharedImageGallery'
          dist-resource-id: '/subscriptions/{subscriptionID}/resourceGroups/{rgName}/providers/Microsoft.Compute/galleries/{galleryName}/images/{imageName}/versions/0.1.${{ GITHUB.RUN_ID }}' #Replace with the resource id of your shared image  gallery's image definition
          dist-location: 'eastus2'

      - name: CREATE VM
        uses: azure/CLI@v1
        with:
          azcliversion: 2.0.72
          inlineScript: |
          az vm create --resource-group ghactions-vMimage  --name "app-vm-${{ GITHUB.RUN_NUMBER }}"  --admin-username myuser --admin-password "${{ secrets.VM_PWD }}" --location  eastus2 \
              --image "${{ steps.imageBuilder.outputs.custom-image-uri }}"              

后续步骤