有些事情看起來很複雜,但想通了就會很簡單;不理解的時候很抽象,理解的時候就很直覺。最近在幫客戶搬遷 Azure Storage 儲存體帳戶,照理說透過 AzCopy 應該要非常簡單才是,但是偏偏就是這個客戶的訂用帳戶的儲存體帳戶無法複製檔案過去,而且錯誤訊息相當難以理解,搞了很久才釐清真相。
AzCopy v10 的檔案複製功能真的無比強大,真的比舊版還強太多,相對的使用參數也非常多,非常複雜。
使用方法可參考我的 使用新版 AzCopy v10 的注意事項與使用教學 文章教學。
基本上使用 azcopy cp
複製檔案,支援以下幾種情境:
- local <-> Azure Blob (SAS or OAuth authentication)
- local <-> Azure Files (Share/directory SAS authentication)
- local <-> ADLS Gen 2 (SAS, OAuth, or SharedKey authentication)
- Azure Blob (SAS or public) -> Azure Blob (SAS or OAuth authentication)
- Azure Blob (SAS or public) -> Azure Files (SAS)
- Azure Files (SAS) -> Azure Files (SAS)
- Azure Files (SAS) -> Azure Blob (SAS or OAuth authentication)
- AWS S3 (Access Key) -> Azure Block Blob (SAS or OAuth authentication)
- Google Cloud Storage (Service Account Key) -> Azure Block Blob (SAS or OAuth authentication) [Preview]
這篇文章所涵蓋的範圍,就是從 Azure Blob 複製到 Azure Blob 的某種特殊情況才會出問題,以就讓我娓娓道來這個問題是怎樣發生的。
問題描述
我先來說幾個官方文件上會提到的用法:
-
Azure Blob (public) -> Azure Blob (OAuth authentication)
# 先登入 Azure 透過 OAuth 取得 Access Token
azcopy login --tenant-id "$tenantId"
# 若是透過 Service Principal 取得 Access Token 則要用以下命令
# azcopy login --tenant-id "$tenantId" --service-principal --application-id "$clientId"
# 來源 Azure Blob 是公開的 Blob Container 並且具有 List 權限才能進行完整複製
azcopy cp "https://[storageaccount1].blob.core.windows.net/[container]" "https://[storageaccount2].blob.core.windows.net/[container]" --recursive=true
-
Azure Blob (SAS) -> Azure Blob (OAuth authentication)
# 先登入 Azure 透過 OAuth 取得 Access Token
azcopy login --tenant-id "$tenantId"
# 若是透過 Service Principal 取得 Access Token 則要用以下命令
# azcopy login --tenant-id "$tenantId" --service-principal --application-id "$clientId"
# 來源 Azure Blob 是公開的 Blob Container 並且具有 List 權限才能進行完整複製
azcopy cp "https://[storageaccount1].blob.core.windows.net/[container]?[SASToken]" "https://[storageaccount2].blob.core.windows.net/[container]" --recursive=true
-
Azure Blob (public) -> Azure Blob (SAS)
# 來源 Azure Blob 是公開的 Blob Container 並且具有 List 權限才能進行完整複製
azcopy cp "https://[storageaccount1].blob.core.windows.net/[container]" "https://[storageaccount2].blob.core.windows.net/[container]?[SASToken]" --recursive=true
-
Azure Blob (SAS) -> Azure Blob (SAS)
# 來源 Azure Blob 是公開的 Blob Container 並且具有 List 權限才能進行完整複製
azcopy cp "https://[storageaccount1].blob.core.windows.net/[container]?[SASToken]" "https://[storageaccount2].blob.core.windows.net/[container]?[SASToken]" --recursive=true
以下是產生 SAS Token 的方法:
PowerShell
# 取得 SAS Token 到期時間 ( 30 分鐘後 )
$expiry = (Get-Date).ToUniversalTime().AddMinutes(30).ToString("yyyy-MM-ddTHH:mmZ")
# 產生 SAS Token 的命令
$SASToken = az storage container generate-sas `
--account-name $storageAccountName `
--name $containerName `
--permissions acdlrw `
--expiry $expiry `
--auth-mode login `
--as-user `
-o tsv
Bash
# 取得 SAS Token 到期時間 ( 30 分鐘後 )
expiry = `date -u -d "30 minutes" '+%Y-%m-%dT%H:%MZ'`
# 產生 SAS Token 的命令
SASToken = az storage container generate-sas \
--account-name $storageAccountName \
--name $containerName \
--permissions acdlrw \
--expiry $expiry \
--auth-mode login \
--as-user \
-o tsv
其實這些用法都「感覺」很簡單,但是 Azure 儲存體這幾年推出了許多功能,但是這些新功能都被放在 StorageV2 版本下,早期的 Storage (V1) 版本雖然沒有明確的退役時間,但是在 Azure Portal 上其實已經不太容易找到建立的方法,所以大部分的人,只要是新建立的儲存體,通常都會是 StorageV2 的版本。
由於 StorageV2 有支援不同的存取等級 (Access Tier),有分 Hot
、Cool
與 Archive
三個等級:
-
Hot tier
(預設值)
An online tier optimized for storing data that is accessed or modified frequently. The Hot tier has the highest storage costs, but the lowest access costs.
-
Cool tier
An online tier optimized for storing data that is infrequently accessed or modified. Data in the Cool tier should be stored for a minimum of 30 days. The Cool tier has lower storage costs and higher access costs compared to the Hot tier.
-
Archive tier
An offline tier optimized for storing data that is rarely accessed, and that has flexible latency requirements, on the order of hours. Data in the Archive tier should be stored for a minimum of 180 days.
簡言之,當 AzCopy 在兩個儲存體帳戶搬移檔案時,預設會想要讓複製檔案時可以保留來源端的 存取等級 屬性,但是早期的 Storage (V1) 版本並沒有 存取等級 的概念,所以在複製檔案時,就會遇到錯誤。我從記錄檔中發現的錯誤訊息是:
RESPONSE Status: 400 Blob access tier is not supported on this storage account type.
完整的訊息如下:
2022/01/12 11:27:38 JobID=b9aecf80-b157-ad49-7c75-b3abf6fb1fdf, credential type: Anonymous
2022/01/12 11:27:38 scheduling JobID=b9aecf80-b157-ad49-7c75-b3abf6fb1fdf, Part#=0, Transfer#=0, priority=0
2022/01/12 11:27:38 Final job part has been scheduled
2022/01/12 11:27:38 INFO: [P#0-T#0] has worker 13 which is processing TRANSFER 0
2022/01/12 11:27:38 INFO: [P#0-T#0] Starting transfer: Source "https://[storage1].blob.core.windows.net/[container]?[SAS]" Destination "https://[storage2].blob.core.windows.net/[container]?[SAS]". Specified chunk size 8388608
2022/01/12 11:27:38 ==> REQUEST/RESPONSE (Try=1/65.3928ms, OpTime=260.8969ms) -- RESPONSE SUCCESSFULLY RECEIVED
GET https://[storage2].blob.core.windows.net/[container]?[SAS]&timeout=901
X-Ms-Request-Id: [499ae245-001e-0074-29a7-07777d000000]
2022/01/12 11:27:38 ==> REQUEST/RESPONSE (Try=1/63.6402ms, OpTime=63.6402ms) -- RESPONSE STATUS CODE ERROR
PUT https://[storage2].blob.core.windows.net/[container]?[SAS]&timeout=901
Content-Length: [0]
User-Agent: [AzCopy/10.13.0 Azure-Storage/0.14 (go1.16; Windows_NT)]
X-Ms-Access-Tier: [Hot]
X-Ms-Blob-Cache-Control: []
X-Ms-Blob-Content-Disposition: []
X-Ms-Blob-Content-Encoding: []
X-Ms-Blob-Content-Language: []
X-Ms-Blob-Content-Type: [application/octet-stream]
X-Ms-Blob-Type: [BlockBlob]
X-Ms-Client-Request-Id: [6adcf20f-29f8-4997-77f6-3d3149068148]
X-Ms-Copy-Source: [https://[storage1].blob.core.windows.net/[container]?[SAS]]
X-Ms-Version: [2020-08-04]
--------------------------------------------------------------------------------
RESPONSE Status: 400 Blob access tier is not supported on this storage account type.
Content-Length: [272]
Content-Type: [application/xml]
Date: [Wed, 12 Jan 2022 11:27:38 GMT]
Server: [Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0]
X-Ms-Client-Request-Id: [6adcf20f-29f8-4997-77f6-3d3149068148]
X-Ms-Error-Code: [BlobAccessTierNotSupportedForAccountType]
X-Ms-Request-Id: [499ae25d-001e-0074-3fa7-07777d000000]
X-Ms-Version: [2020-08-04]
Response Details: <Code>BlobAccessTierNotSupportedForAccountType</Code><Message>Blob access tier is not supported on this storage account type. </Message>
2022/01/12 11:27:38 ERR: [P#0-T#0] COPYFAILED: https://[storage1].blob.core.windows.net/[container]?[SAS] : 400 : 400 Blob access tier is not supported on this storage account type.. When Put Blob from URL. X-Ms-Request-Id: 499ae25d-001e-0074-3fa7-07777d000000
Dst: https://[storage2].blob.core.windows.net/[container]?[SAS]
基本上這個錯誤訊息跟權限沒甚麼關係,主要還是因為 AzCopy 預設會保留來源儲存體帳戶的 Access-Tier 資訊,當帶給目的端的 PUT
操作時,就發生了問題。
由於訊息還算清楚,所以順藤摸瓜還是可以找到蛛絲馬跡,我就依循這個線索,透過 azcopy cp -h
找到了 --s2s-preserve-access-tier
這個參數選項,想不到一試就通,檔案可以順利且快速的複製了! 😃
完整的命令如下:
azcopy cp "https://[storageaccount1].blob.core.windows.net/[container]?[SASToken]" "https://[storageaccount2].blob.core.windows.net/[container]?[SASToken]" --recursive=true --s2s-preserve-access-tier=false
總結
當你想從 Storage (V1) 的儲存體帳號,透過 AzCopy](https://github.com/Azure/azure-storage-azcopy) v10 複製 Blob 容器或檔案到 StorageV2 的儲存體帳戶,記得要加上 --s2s-preserve-access-tier=false
參數!
相關連結