Microsoft MVP성태의 닷넷 이야기
개발 환경 구성: 496. Azure - Blob Storage Account의 Location 이전 방법 [링크 복사], [링크+제목 복사],
조회: 19631
글쓴 사람
정성태 (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
정성태

... 136  [137]  138  139  140  141  142  143  144  145  146  147  148  149  150  ...
NoWriterDateCnt.TitleFile(s)
1630정성태2/5/201422814개발 환경 구성: 216. Hyper-V에 올려진 윈도우 XP VM에서 24bit 컬러 및 ClearType 활성화하는 방법
1629정성태2/5/201432631개발 환경 구성: 215. DOS batch - 하나의 .bat 파일에서 다중 .bat 파일을 (비동기로) 실행하는 방법 [1]
1628정성태2/4/201433957Windows: 87. 윈도우 8.1에서 .NET 3.5 설치가 안된다면? [2]
1627정성태2/4/201429014개발 환경 구성: 214. SQL Server Reporting Services를 이용해 간단한 리포트 제작하는 방법
1626정성태2/4/201421031Windows: 86. 윈도우 8.1의 Skydrive 내용이 동기화가 안된다면?
1625정성태2/2/201428195.NET Framework: 422. C++과 C#의 Event 공유파일 다운로드1
1624정성태2/2/201423810.NET Framework: 421. ASP.NET에서 Server.CreateObject와 COM Interop 클래스 생성의 차이점
1623정성태2/1/201428557개발 환경 구성: 213. x86/x64별로 나뉘어진 어셈블리를 한 프로젝트에서 참조하는 방법 [1]파일 다운로드1
1622정성태1/31/201429029VC++: 74. 어떤 것을 쓰면 좋을까요? wvnsprintf, _vsnwprintf_s, StringCbVPrintfW [4]
1621정성태1/31/201420853.NET Framework: 420. 베트남의 11학년(한국의 고2)이 45분만에 푼다는 알고리즘 문제파일 다운로드1
1620정성태1/30/201430668.NET Framework: 419. C# - BigDecimal파일 다운로드1
1619정성태1/30/201427411VS.NET IDE: 85. T4를 이용한 INotifyPropertyChanged 코드 자동 생성파일 다운로드1
1618정성태1/29/201443106Linux: 2. 우분투에서 Active Directory 계정을 이용한 파일 공유
1617정성태1/29/201424237.NET Framework: 418. Thread.Abort 호출의 hang 현상 [1]
1616정성태1/29/201424915디버깅 기술: 63. windbg 디버깅 사례: AppDomain 간의 static 변수 사용으로 인한 crash
1615정성태1/29/201426857.NET Framework: 417. WPF WebBrowser 컨트롤에서 SHDocVw.IWebBrowser2 인터페이스를 구하는 방법 및 순수 WPF 웹 브라우저 컨트롤 소개
1614정성태1/29/201423803.NET Framework: 416. System.Net.Sockets.NetworkStream이 Thread-safe할까?파일 다운로드1
1613정성태1/29/201425824.NET Framework: 415. IIS 작업자 프로세스 재생(recycle)하는 방법 [1]
1612정성태1/29/201422582오류 유형: 219. IIS 500 Internal Server Error - Skydrive에 공유된 경우
1611정성태1/27/201453992.NET Framework: 414. C# - 컴퓨터에서 알아낼 수 있는 고윳값 정리 [3]파일 다운로드1
1610정성태1/26/201437924.NET Framework: 413. C# - chromiumembedded 사용 [11]파일 다운로드1
1609정성태1/26/201420960오류 유형: 218. wsDualHttpBinding + Windows Server 2003인 경우 발생하는 오류
1608정성태1/26/201426263.NET Framework: 412. HttpContext.Current를 통해 이해하는 CallContext와 ExecutionContext [4]
1607정성태1/26/201426192.NET Framework: 411. 유니코드의 "compatibility character"가 뭘까요? [4]파일 다운로드1
1606정성태1/25/201424283오류 유형: 217. 델 베뉴 스타일러스 관련 업데이트 오류 - 5830_Firmware_X267N_WN_1.0.4.1_A01.EXE
1605정성태1/23/201421141개발 환경 구성: 212. Visual Studio Online과 "Monaco" 서비스 연동
... 136  [137]  138  139  140  141  142  143  144  145  146  147  148  149  150  ...