Microsoft MVP성태의 닷넷 이야기
개발 환경 구성: 496. Azure - Blob Storage Account의 Location 이전 방법 [링크 복사], [링크+제목 복사]
조회: 11858
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일

Azure - Blob Storage Account의 Location 이전 방법

지난 글에도 언급했지만,

Azure - Location이 다른 웹/DB 서버의 경우 발생하는 성능 하락
; https://www.sysnet.pe.kr/2/0/12273

Azure는 Location 이전을 수작업으로 해야 합니다. 이에 대해 방법을 찾아보면 아래의 문서가 나오는데,

Azure Storage 계정을 다른 지역으로 이동
; https://learn.microsoft.com/ko-kr/azure/storage/common/storage-account-move?tabs=azure-portal

기존 Storage의 template을 내보내는 방법과 신규 Storage에서 가져오는 방법을 설명하는 것으로, 이것은 해당 Storage에 설정한 환경을 복사하는 것일 뿐 데이터를 마이그레이션하는 작업은 하지 않습니다. 즉, 데이터 이전은 별도로, 수작업으로 해야 합니다. ^^;

또한 "Azure Storage 계정을 다른 지역으로 이동" 문서의 마지막에 보면 "Azure Data Factory"를 사용하여 데이터를 이동할 수도 있습니다. 직관적인 사용자 인터페이스를 제공합니다."라는 설명으로 "Azure Data Factory"를 이용하면 왠지 간단한 절차만으로 해결될 것 같지만 해당 문서를 보면,

Copy and transform data in Azure Blob storage by using Azure Data Factory
; https://learn.microsoft.com/ko-kr/azure/data-factory/connector-azure-blob-storage

그냥 azcopy로 처리하는 것이 더 낫겠다는 생각을 (10초도 안되어서) 하게 될 것입니다. ^^; AzCopy의 사용법은,

Get started with AzCopy
; https://learn.microsoft.com/ko-kr/azure/storage/common/storage-use-azcopy-v10?toc=/azure/storage/blobs/toc.json

Transfer data with AzCopy and Blob storage
; https://learn.microsoft.com/ko-kr/azure/storage/common/storage-use-azcopy-blobs

그나마 직관적입니다. 일단, Azure Blob Storage에서 로컬로 복사한다면 다음과 같은 형식으로 실행할 수 있습니다.

azcopy copy 'https://<source-storage-account-name>.blob.core.windows.net/<container-name><SAS-token>' '<local-file-path>' --recursive

예를 들어,

source-storage-account-name == udb.blob.core.windows.net
local-file-path == d:\temp

위의 조건이라면 다음과 같이 실행할 수 있습니다.

azcopy copy "https://udb.blob.core.windows.net?...[SAS-token]..." "d:\temp" --recursive

여기서 아직 구하지 못한 것이 SAS(Shared access signature) token 값인데, 이것은 Azure Portal에서 다음의 화면을 통해,

sas_token_1.png

구할 수 있습니다. 예를 들어, SAS Token의 값이 다음과 같이 구해졌다면,

?sv=2019-10-10&ss=bfqt&srt=sco&sp=rwdlacupx&se=2020-07-18T14:51:29Z&st=2020-07-16T06:51:29Z&sip=168.126.144.30&spr=https&sig=QijTJGThP%3BEi3tSEgCnVZQylMY162FrIg9wafuuFU8E%3D

최종적으로 이렇게 실행하면 됩니다.

azcopy copy "https://udb.blob.core.windows.net?sv=2019-10-10&ss=bfqt&...[생략]..." "d:\temp" --recursive

만약, 전체 Storage가 아니라 하위 Container만 특정하고 싶다면 URL에 덧붙여 실행할 수 있습니다. 가령, 여러분들의 Storage에 "images"라는 이름의 container가 있다면 이렇게 실행할 수 있습니다.

azcopy copy "https://udb.blob.core.windows.net/images?sv=2019-10-10&ss=bfqt&...[생략]..." "d:\temp" --recursive

SAS Token 관련해서 좀 더 자세한 사항은 다음의 문서에서 확인할 수 있습니다.

Grant limited access to Azure Storage resources using shared access signatures (SAS)
; https://learn.microsoft.com/ko-kr/azure/storage/common/storage-sas-overview

How to Generate an Azure SAS Token to Access Storage Accounts
; https://adamtheautomator.com/azure-sas-token/




반대로 로컬의 디렉터리를 Azure Stroage에 넣는 것은 인자 값의 순서만 바꾸면 됩니다.

azcopy copy '<local-directory-path>\*' 'https://<storage-account-name>.<blob or dfs>.core.windows.net/<container-name>/<directory-path>'

단지, 다운로드할 때와는 달리 전체 blob을 올릴 수는 없습니다. 제가 방법을 모르는 걸 수도 있지만, 아래와 같이 오류가 발생합니다. (혹시, 방법을 아시는 분은 덧글 부탁드립니다. ^^)

C:\>azcopy copy  "d:\temp" "https://...[대상_stroage]....blob.core.windows.net?sv=2019-10-1...[생략]..." --recursive
INFO: Scanning...

failed to perform copy command due to error: cannot transfer individual files/folders to the root of a service. Add a container or directory to the destination URL

대신, 하위 Container 별로 올릴 수 있는데, 이때 미리 Container를 생성해 두어야 합니다. 그렇지 않고 실행하면 이번에도 실패합니다.

// 대상 storage에 "temp" container가 만들어져 있지 않은 경우

C:\> azcopy copy  "d:\temp" "https://...[대상_stroage]....blob.core.windows.net/temp?sv=2019-10-10&ss=bfqt&srt=sco&sp=rwdlacupx&se=2020-07-19T22:23:20Z&st=2020-07-17T14:23:20Z&spr=https&sig=wSw3VBfT%2FAmvSBVPNXhCNFOJ6eShzXewQIl%2BMb0qfNQ%3D" --recursive
INFO: Scanning...
INFO: Any empty folders will not be processed, because source and/or destination doesn't have full folder support

Job 92ee7705-2dfb-de48-6401-c71ddeb7c900 has started
Log file is located at: C:\Users\testusr\.azcopy\92ee7705-2dfb-de48-6401-c71ddeb7c900.log

0.0 %, 0 Done, 0 Failed, 56 Pending, 0 Skipped, 56 Total,

Job 92ee7705-2dfb-de48-6401-c71ddeb7c900 summary
Elapsed Time (Minutes): 0.0334
Number of File Transfers: 56
Number of Folder Property Transfers: 0
Total Number of Transfers: 56
Number of Transfers Completed: 0
Number of Transfers Failed: 56
Number of Transfers Skipped: 0
TotalBytesTransferred: 0
Final Job Status: Failed

따라서, 예를 들어, "d:\temp\images"의 하위 폴더/파일들을 업로드하고 싶다면 그 blob들이 위치할 container도 미리 생성해 놓고 실행해야 합니다. 대개의 경우, 이전에 "images" 컨테이너에 있던 내용들이라면 그 이름 그대로 옮기고 싶을 것이므로 이런 식으로 처리할 수 있습니다.

azcopy copy  "d:\temp\images\*" "https://...[대상_stroage]....blob.core.windows.net/images?sv=2019-10-10...[생략]..." --recursive

(위의 예에서 "*" 문자를 빼면, Azure Storage의 images 컨테이너 하위에 다시 "images" 폴더가 생성되고 그 하위에 파일 및 서브 디렉터리가 올라갑니다.)

자, 그럼 Azure Storage를 옮기는 방법은 다음과 같이 정리할 수 있습니다.

1. 원본 Storage에서 "azcopy copy ..."로 로컬에 모두 다운로드
2. 대상 Storage에 원본의 컨테이너들을 미리 생성해 놓고, 개별 컨테이너마다 "azcopy copy ..."로 업로드




위에서 로컬을 경유한 방법을 소개했지만, 사실 전체 Storage를 옮기는 것이라면 다음의 명령어 하나로 해결할 수 있습니다.

azcopy copy 'https://<source-storage-account-name>.blob.core.windows.net/<SAS-token>' 'https://<destination-storage-account-name>.blob.core.windows.net/' --recursive

문서 상으로는 위와 같이 SAS-token을 source-storage-account 측에만 제공하지만, 제가 해본 결과로는 destination-storage-account 측에도 지정해야 했었습니다. (아마 같은 storage 내에서라면 필요 없겠지만 다른 storage라면 필요할 것입니다. 그렇긴 한데 제가 이거저거 너무 테스트를 많이 해봐서 확실치 않습니다. ^^;) 어쨌든, 다음과 같은 명령어 하나로 storage 이전을 간단하게 마무리했습니다.

D:\temp\blob> azcopy copy "https://...source....blob.core.windows.net?sv=2019-10-10...[소스측_sas_token]..." "https://...dest....blob.core.windows.net?sv=2019-10-10...[목적지측_sas_token]..." --recursive
INFO: Scanning...
INFO: Any empty folders will not be processed, because source and/or destination doesn't have full folder support

Job 54c45f3e-5bc6-ae47-7e87-9a9dc3d575c4 has started
Log file is located at: C:\Users\testusr\.azcopy\54c45f3e-5bc6-ae47-7e87-9a9dc3d575c4.log

100.0 %, 9851 Done, 0 Failed, 6 Pending, 0 Skipped, 9857 Total, 2-sec Throughput (Mb/s): 7.7693

Job 54c45f3e-5bc6-ae47-7e87-9a9dc3d575c4 summary
Elapsed Time (Minutes): 25.3103
Number of File Transfers: 9857
Number of Folder Property Transfers: 0
Total Number of Transfers: 9857
Number of Transfers Completed: 9857
Number of Transfers Failed: 0
Number of Transfers Skipped: 0
TotalBytesTransferred: 2141323772
Final Job Status: Completed




참고로, azcopy 명령어 사용 전 login 작업은 해야 합니다.

C:\temp> azcopy login --tenant-id 9F848C20-BBDF-413D-B9AC-117390503A2E
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code DCNCEVAMF to authenticate.

INFO: Login succeeded.

C:\temp>

위에서 --tenant-id 값은 해당 서비스가 속해있는 azure 구독과 관련한 AAD의 tenant-id를 입력하면 됩니다. 이 값은 프로그램으로도 구할 수 있지만 Azure Portal 내의 "Azure Active Directory"에서도 구할 수 있습니다.

sas_token_2.png




지난 글과 마찬가지로,

Azure - Location이 다른 웹/DB 서버의 경우 발생하는 성능 하락
; https://www.sysnet.pe.kr/2/0/12273

Storage 역시 그것을 액세스하는 측과 같은 Location에 있는 것이 성능상 (당연하겠지만) 좋습니다. 이를 위해 다음과 같은 소스 코드로 측정을 해봤는데요.

using Azure.Storage.Blobs;
using System;
using System.Diagnostics;
using System.IO;

namespace ConsoleApp2
{

    // (deprecated)
    // Install-Package WindowsAzure.Storage

    // or

    // Install-Package Microsoft.Azure.Storage.Common
    // Install-Package Microsoft.Azure.Storage.Blob

    // or

    // .NETStandard,Version=v2.0
    // .NET Framework 4.6.1 or later
    // Install-Package Azure.Storage.Blobs
    class Program
    {
        static void Main(string[] args)
        {
            string blobConnectionString = "DefaultEndpointsProtocol=...[생략]...";

            Action<int, BlobClient, Action<int, BlobClient>> action = (loopCount, blobClient, work) =>
            {
                Stopwatch st = new Stopwatch();
                st.Start();

                work(loopCount, blobClient);

                st.Stop();

                Console.WriteLine(st.ElapsedMilliseconds);
            };

            BlobServiceClient bsc = new BlobServiceClient(blobConnectionString);

            BlobContainerClient bcc = bsc.GetBlobContainerClient("images");
            BlobClient bc = bcc.GetBlobClient("test.png");

            action(1, bc, RunCommand);
            action(1, bc, RunCommand);
            action(1, bc, RunCommand);
        }

        private static void RunCommand(int loopCount, BlobClient blobClient)
        {
            MemoryStream ms = new MemoryStream();
            blobClient.DownloadTo(ms);
        }
    }
}

Location이 달랐을 때는,

C:\temp\perf>ConsoleApp2.exe
805
41
41

C:\temp\perf>ConsoleApp2.exe
693
43
44

40ms 이상의 고정적인 지연 시간이 발생하지만 같은 Location에 있을 때는,

C:\temp\perf>ConsoleApp2.exe
573
4
2

C:\temp\perf>ConsoleApp2.exe
396
3
2

"Azure - Location이 다른 웹/DB 서버의 경우 발생하는 성능 하락" 글에서와 유사하게 지연 시간이 없어졌습니다.

(첨부 파일은 이 글의 예제 코드를 포함합니다.)




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 1/4/2023]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2021-02-18 10시33분
본문에서 "Azure Data Factory"를 언급하며 문서의 압박으로 인해 실습하진 않았는데요, 반면 아래의 강좌를 보면 상당히 절차가 간단하다는 것을 알 수 있습니다. (참고로 데모 작업을 곁들인 설명은 3번째 동영상에 있습니다.)

ETL의 끝판왕, 애저 데이터 팩토리 | ep0. 인트로 | 애저듣보잡
; https://www.youtube.com/watch?v=4GwCz7K-8qo

ETL의 끝판왕, 애저 데이터 팩토리 | ep1. 소개 | 애저듣보잡
; https://www.youtube.com/watch?v=B2ay3OlLq0k

ETL의 끝판왕, 애저 데이터 팩토리 | ep2. 데모 | 애저듣보잡
; https://www.youtube.com/watch?v=24zgXpTv-BI

ETL의 끝판왕, 애저 데이터 팩토리 | ep3. 클로징 | 애저듣보잡
; https://www.youtube.com/watch?v=2J0sEwjZxGA
정성태

1  2  3  4  5  6  7  8  9  10  [11]  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13349정성태5/11/20233685.NET Framework: 2120. C# - Semantic Kernel의 Skill과 Function 사용 예제파일 다운로드1
13348정성태5/10/20233577.NET Framework: 2119. C# - Semantic Kernel의 "Basic Loading of the Kernel" 예제
13347정성태5/10/20233941.NET Framework: 2118. C# - Semantic Kernel의 Prompt chaining 예제파일 다운로드1
13346정성태5/10/20233790오류 유형: 858. RDP 원격 환경과 로컬 PC 간의 Ctrl+C, Ctrl+V 복사가 안 되는 문제
13345정성태5/9/20235105.NET Framework: 2117. C# - (OpenAI 기반의) Microsoft Semantic Kernel을 이용한 자연어 처리 [1]파일 다운로드1
13344정성태5/9/20236356.NET Framework: 2116. C# - OpenAI API 사용 - 지원 모델 목록 [1]파일 다운로드1
13343정성태5/9/20234223디버깅 기술: 192. Windbg - Hyper-V VM으로 이더넷 원격 디버깅 연결하는 방법
13342정성태5/8/20234153.NET Framework: 2115. System.Text.Json의 역직렬화 시 필드/속성 주의
13341정성태5/8/20233917닷넷: 2114. C# 12 - 모든 형식의 별칭(Using aliases for any type)
13340정성태5/8/20233959오류 유형: 857. Microsoft.Data.SqlClient.SqlException - 0x80131904
13339정성태5/6/20234646닷넷: 2113. C# 12 - 기본 생성자(Primary Constructors)
13338정성태5/6/20234134닷넷: 2112. C# 12 - 기본 람다 매개 변수파일 다운로드1
13337정성태5/5/20234650Linux: 59. dockerfile - docker exec로 container에 접속 시 자동으로 실행되는 코드 적용
13336정성태5/4/20234427.NET Framework: 2111. C# - 바이너리 출력 디렉터리와 연관된 csproj 설정
13335정성태4/30/20234541.NET Framework: 2110. C# - FFmpeg.AutoGen 라이브러리를 이용한 기본 프로젝트 구성 - Windows Forms파일 다운로드1
13334정성태4/29/20234183Windows: 250. Win32 C/C++ - Modal 메시지 루프 내에서 SetWindowsHookEx를 이용한 Thread 메시지 처리 방법
13333정성태4/28/20233634Windows: 249. Win32 C/C++ - 대화창 템플릿을 런타임에 코딩해서 사용파일 다운로드1
13332정성태4/27/20233726Windows: 248. Win32 C/C++ - 대화창을 위한 메시지 루프 사용자 정의파일 다운로드1
13331정성태4/27/20233744오류 유형: 856. dockerfile - 구 버전의 .NET Core 이미지 사용 시 apt update 오류
13330정성태4/26/20233416Windows: 247. Win32 C/C++ - CS_GLOBALCLASS 설명
13329정성태4/24/20233626Windows: 246. Win32 C/C++ - 직접 띄운 대화창 템플릿을 위한 Modal 메시지 루프 생성파일 다운로드1
13328정성태4/19/20233268VS.NET IDE: 184. Visual Studio - Fine Code Coverage에서 동작하지 않는 Fake/Shim 테스트
13327정성태4/19/20233688VS.NET IDE: 183. C# - .NET Core/5+ 환경에서 Fakes를 이용한 단위 테스트 방법
13326정성태4/18/20235081.NET Framework: 2109. C# - 닷넷 응용 프로그램에서 SQLite 사용 (System.Data.SQLite) [1]파일 다운로드1
13325정성태4/18/20234425스크립트: 48. 파이썬 - PostgreSQL의 with 문을 사용한 경우 연결 개체 누수
13324정성태4/17/20234257.NET Framework: 2108. C# - Octave의 "save -binary ..."로 생성한 바이너리 파일 분석파일 다운로드1
1  2  3  4  5  6  7  8  9  10  [11]  12  13  14  15  ...