Azure Container Instances에서 Azure PowerShell 실행 및 보존

31867 단어

동기 부여



Azure 환경(예: 글로벌 대 중국)과 계정(기업, 개인 평가판) 간에 자주 전환해야 합니다. 전환할 때 원하는 구독을 다시 설정해야 합니다. 다른 임시 시나리오에 대해 이미 ACI를 사용하고 있습니다. Handling an ACME challenge response with a temporary Azure Container Instance 또는 Creating a Certificate Authority for testing with Azure Container Instances Azure 저장소에 대한 컨텍스트(로그 온 세션)를 보존하면서 Azure PowerShell을 실행하려고 시도하는 것에 대해 생각했습니다.

스크립트



위의 작업을 수행하기 위해 Azure Storage 파일 공유를 만들고 채우고 컨테이너 인스턴스를 시작, 초기화, 실행 및 삭제하는 이 스크립트를 만들었습니다.

param (
    [Switch]
    $SkipStartup
)

$aciName = "{my-desired-aci-name}"
$storageName = $aciName.Replace("-", "")
$resourceGroupName = "{my-desired-existing-resource-group-name}"

$storageContainerName = "state"
$storageShareName = $storageContainerName
$containerStateFolder = "/tmp/state"
$imageName = "mcr.microsoft.com/azure-powershell:latest"
$startupScriptName = "startup.ps1"

# Part 1 - Azure File Share creation

if (!$(az storage account list -g $resourceGroupName --query "[?name == '$storageName']" -o tsv)) {
    az storage account create -n $storageName -g $resourceGroupName
}

$storageConnectionString = $(az storage account show-connection-string -n $storageName -o tsv) 
$storageKey = $(az storage account keys list -n $storageName --query [0].value -o tsv)

if (!$(az storage share list --account-name $storageName --connection-string $storageConnectionString --query "[?name == '$storageShareName']"-o tsv)) {
    az storage share create --account-name $storageName --connection-string $storageConnectionString -n $storageShareName
}

# Part 2 - Startup script

$script = Join-Path $env:TEMP "azContainerStartup.ps1"
@'
foreach($linkName in ".Azure",".IdentityService") {
    if($linkName -eq ".Azure") {
        $linkPath = "$HOME/$linkName"
    } else {
        $linkPath = "$HOME/.local/share/$linkName"
    }
    $linkTargetPath = "{containerStateFolder}/$linkName"

    if(!(Test-Path $linkTargetPath -PathType Container)) {
        Write-Host "create" $linkTargetPath
        New-Item -Path $linkTargetPath -ItemType Directory
    }
    if((Get-ChildItem -Path $linkTargetPath -Force).Count -eq 0 -and (Test-Path -Path $linkPath -PathType Container)) {
        Write-Host "copy from" $linkPath "to" $linkTargetPath
        Copy-Item -Path "$linkPath/*" -Destination $linkTargetPath -Recurse -Force
    }

    $linkItem = Get-Item $linkPath -Force -ErrorAction SilentlyContinue
    if($linkItem) {
        if(!$($linkItem.LinkType)) {
            Write-Host "remove existing folder to create link" $linkPath
            Remove-Item $linkPath -Recurse -Force
        }
    }
    New-Item -ItemType SymbolicLink -Path $linkPath -Target $linkTargetPath
}
'@.Replace("{containerStateFolder}", $containerStateFolder) | Set-Content $script -Force

az storage file upload -s $storageShareName --source $script -p $startupScriptName `
    --account-name $storageName --connection-string $storageConnectionString

# Part 3 - Container startup

az container create --name $aciName `
    --resource-group $resourceGroupName `
    --image $imageName `
    --azure-file-volume-account-name $storageName `
    --azure-file-volume-account-key $storageKey `
    --azure-file-volume-share-name $storageShareName `
    --azure-file-volume-mount-path $containerStateFolder `
    --command-line "tail -f /dev/null"

if (!$SkipStartup) {
    az container exec  --name $aciName `
        --resource-group $resourceGroupName `
        --exec-command "pwsh $containerStateFolder/$startupScriptName"
}

# Part 4 - Container operation and destruction

az container exec  --name $aciName `
    --resource-group $resourceGroupName `
    --exec-command "pwsh"

az container delete --name $aciName `
    --resource-group $resourceGroupName 


I started with this PowerShell/Azure CLI combination to transfer from existing scripts more easily. Later I converted to a pure PowerShell/Azure PowerShell version but ran into problems during pwsh shell execution : terminal control sequences were not rendered correctly and did not allow viable operation of the container.



1부 - Azure 파일 공유 생성



아직 없는 경우 스토리지 계정 및/또는 파일 공유를 만듭니다.

파트 2 - 시작 스크립트



시작 스크립트startup.ps1를 생성하고 파일 공유에 업로드합니다.
  • Azure PowerShell 컨텍스트~/.Azure~/.local/share/.IdentityService를 나타내는 2개의 폴더용
  • 상태를 유지하기 위해 파일 공유(탑재된 볼륨)에 폴더를 생성합니다
  • .
  • 아직 채워지지 않은 경우 초기 컨테이너에서 마운트된 볼륨으로 내용 복사
  • 컨테이너에서 폴더 제거
  • ~에서 마운트된 볼륨
  • 으로 심볼릭 링크를 생성합니다.


    따라서 새로운 파일 공유를 사용하면 컨테이너에서 초기 콘텐츠를 복사한 다음 폴더를 연결합니다. 이미 채워진 파일 공유를 사용하면 폴더만 연결됩니다.

    파트 3 - 컨테이너 시작



    ACI(컨테이너 그룹)가 시작되고 볼륨이 마운트되고 컨테이너가 tail -f /dev/null와 함께 무한 루프로 전송되어 실제 명령을 실행하기 위해 다시 연결될 때까지 대기합니다.

    일단 시작되면 시작 스크립트startup.ps1가 실행됩니다(위 참조).

    파트 4 - 컨테이너 운영 및 폐기



    이제 PowerShell이 ​​실행되고 터미널 입력을 기다립니다.
    Connect-AzAccount -UseDeviceAuthentication(또는 제 경우에는 Connect-AzAccount -Environment AzureChinaCloud -UseDeviceAuthentication ) 이제 초기화하고 Azure에 로그인하는 데 사용할 수 있습니다.
    exit와 함께 Azure PowerShell 세션이 중지되고 컨테이너가 삭제됩니다.

    이 스크립트를 다시 실행할 때 동일한 환경 및 구독에서 계속 작업하는 것이 가능해야 합니다(액세스 토큰이 만료되지 않은 경우). 적어도 내 테스트 중에는 작동했습니다.

    very nice feature : auto completion is working within the container



    잠재적인 확장



    실제 작업의 경우 컨테이너 세션에서 스크립트 리포지토리를 사용할 수 없다는 점에서 이 접근 방식은 여전히 ​​부족합니다. 이는 필요한 스크립트를 파일 공유에 복사하고 적절한 위치에 연결하거나 az container create 매개변수--gitrepo-url ... --gitrepo-dir ... --gitrepo-mount-path ...를 사용하여 달성할 수 있습니다.

    Azure PowerShell 버전



    아마도 당신은 당신의 지역에서 더 운이 좋을 것이고 그것은 효과가 있을 것입니다. 과거에는 서로 다른 백플레인에서 ACI를 운영하는 여러 지역에서 문제가 있었습니다(그 중 하나는 "Atlas"이고 다른 하나는 기억이 나지 않습니다).

    이해관계자의 경우 - 다음과 같습니다.



    param (
        [Switch]
        $SkipStartup
    )
    
    $aciName = "{my-desired-aci-name}"
    $storageName = $aciName.Replace("-", "")
    $resourceGroupName = "{my-desired-existing-resource-group-name}"
    
    $storageContainerName = "state"
    $storageShareName = $storageContainerName
    $containerStateFolder = "/tmp/state"
    $imageName = "mcr.microsoft.com/azure-powershell:latest"
    $startupScriptName = "startup.ps1"
    
    # Part 1 - Azure File Share creation
    
    $resourceGroup = Get-AzResourceGroup -Name $resourceGroupName -ErrorAction Stop
    
    if (!(Get-AzStorageAccount -ResourceGroupName $resourceGroupName -Name $storageName -ErrorAction SilentlyContinue)) {
        New-AzStorageAccount -ResourceGroupName $resourceGroupName -Name $storageName `
            -Location $resourceGroup.Location `
            -SkuName Standard_RAGRS -Kind StorageV2
    }
    
    $storageKey = (Get-AzStorageAccountKey -ResourceGroupName $resourceGroupName -Name $storageName)[0].Value
    $storageContext = New-AzStorageContext -StorageAccountName $storageName -StorageAccountKey $storageKey
    
    if (!(Get-AzStorageShare -Context $storageContext -Name $storageShareName -ErrorAction SilentlyContinue)) {
        New-AzStorageShare -Context $storageContext -Name $storageShareName
    }
    
    # Part 2 - Startup script
    
    $script = Join-Path $env:TEMP "azContainerStartup.ps1"
    @'
    foreach($linkName in ".Azure",".IdentityService") {
        if($linkName -eq ".Azure") {
            $linkPath = "$HOME/$linkName"
        } else {
            $linkPath = "$HOME/.local/share/$linkName"
        }
        $linkTargetPath = "{containerStateFolder}/$linkName"
    
        if(!(Test-Path $linkTargetPath -PathType Container)) {
            Write-Host "create" $linkTargetPath
            New-Item -Path $linkTargetPath -ItemType Directory
        }
        if((Get-ChildItem -Path $linkTargetPath -Force).Count -eq 0 -and (Test-Path -Path $linkPath -PathType Container)) {
            Write-Host "copy from" $linkPath "to" $linkTargetPath
            Copy-Item -Path "$linkPath/*" -Destination $linkTargetPath -Recurse -Force
        }
    
        $linkItem = Get-Item $linkPath -Force -ErrorAction SilentlyContinue
        if($linkItem) {
            if(!$($linkItem.LinkType)) {
                Write-Host "remove existing folder to create link" $linkPath
                Remove-Item $linkPath -Recurse -Force
            }
        }
        New-Item -ItemType SymbolicLink -Path $linkPath -Target $linkTargetPath
    }
    '@.Replace("{containerStateFolder}", $containerStateFolder) | Set-Content $script -Force
    
    Set-AzStorageFileContent -Context $storageContext -ShareName $storageShareName `
        -Source $script -Path $startupScriptName `
        -Force
    
    # Part 3 - Container startup
    
    $volume = New-AzContainerGroupVolumeObject -Name "state" -AzureFileShareName $storageShareName `
        -AzureFileStorageAccountName $storageName `
        -AzureFileStorageAccountKey $(ConvertTo-SecureString $storageKey -AsPlainText -Force)
    $mount = New-AzContainerInstanceVolumeMountObject -MountPath $containerStateFolder -Name "state"
    
    $container = New-AzContainerInstanceObject -Name "pwsh" `
        -Image $imageName `
        -VolumeMount $mount `
        -Port @() `
        -Command "tail","-f","/dev/null"
    
    $containerGroup = New-AzContainerGroup -Name $aciName `
        -ResourceGroupName $resourceGroupName `
        -Location $resourceGroup.Location `
        -Container $container `
        -Volume $volume
    
    if (!$SkipStartup) {
        Invoke-AzContainerInstanceCommand -ContainerGroupName $aciName `
            -ResourceGroupName $resourceGroupName `
            -ContainerName "pwsh" `
            -Command "pwsh $containerStateFolder/$startupScriptName"
    }
    
    # Part 4 - Container operation and destruction
    
    Invoke-AzContainerInstanceCommand -ContainerGroupName $aciName `
        -ResourceGroupName $resourceGroupName `
        -ContainerName "pwsh" `
        -Command "pwsh"
    
    Remove-AzContainerGroup -ContainerGroupName $aciName `
        -ResourceGroupName $resourceGroupName
    


    It took me a while to figure out that New-AzContainerInstanceObject needed the command as an array and would not operate with the whole command in a string!

    좋은 웹페이지 즐겨찾기