Microsoft MVP성태의 닷넷 이야기
개발 환경 구성: 496. Azure - Blob Storage Account의 Location 이전 방법 [링크 복사], [링크+제목 복사]
조회: 11930
글쓴 사람
정성태 (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)
13507정성태1/2/20242787닷넷: 2191. C# - IPGlobalProperties를 이용해 netstat처럼 사용 중인 Socket 목록 구하는 방법파일 다운로드1
13506정성태12/29/20232357닷넷: 2190. C# - 닷넷 코어/5+에서 달라지는 System.Text.Encoding 지원
13505정성태12/27/20232904닷넷: 2189. C# - WebSocket 클라이언트를 닷넷으로 구현하는 예제 (System.Net.WebSockets)파일 다운로드1
13504정성태12/27/20232480닷넷: 2188. C# - ASP.NET Core SignalR로 구현하는 채팅 서비스 예제파일 다운로드1
13503정성태12/27/20232349Linux: 67. WSL 환경 + mlocate(locate) 도구의 /mnt 디렉터리 검색 문제
13502정성태12/26/20232445닷넷: 2187. C# - 다른 프로세스의 환경변수 읽는 예제파일 다운로드1
13501정성태12/25/20232261개발 환경 구성: 700. WSL + uwsgi - IPv6로 바인딩하는 방법
13500정성태12/24/20232327디버깅 기술: 194. Windbg - x64 가상 주소를 물리 주소로 변환
13498정성태12/23/20233011닷넷: 2186. 한국투자증권 KIS Developers OpenAPI의 C# 래퍼 버전 - eFriendOpenAPI NuGet 패키지
13497정성태12/22/20232429오류 유형: 885. Visual Studiio - error : Could not connect to the remote system. Please verify your connection settings, and that your machine is on the network and reachable.
13496정성태12/21/20232413Linux: 66. 리눅스 - 실행 중인 프로세스 내부의 환경변수 설정을 구하는 방법 (gdb)
13495정성태12/20/20232379Linux: 65. clang++로 공유 라이브러리의 -static 옵션 빌드가 가능할까요?
13494정성태12/20/20232524Linux: 64. Linux 응용 프로그램의 (C++) so 의존성 줄이기(ReleaseMinDependency) - 두 번째 이야기
13493정성태12/19/20232616닷넷: 2185. C# - object를 QueryString으로 직렬화하는 방법
13492정성태12/19/20232304개발 환경 구성: 699. WSL에 nopCommerce 예제 구성
13491정성태12/19/20232240Linux: 63. 리눅스 - 다중 그룹 또는 사용자를 리소스에 권한 부여
13490정성태12/19/20232362개발 환경 구성: 698. Golang - GLIBC 의존을 없애는 정적 빌드 방법
13489정성태12/19/20232146개발 환경 구성: 697. GoLand에서 ldflags 지정 방법
13488정성태12/18/20232078오류 유형: 884. HTTP 500.0 - 명령행에서 실행한 ASP.NET Core 응용 프로그램을 실행하는 방법
13487정성태12/16/20232394개발 환경 구성: 696. C# - 리눅스용 AOT 빌드를 docker에서 수행 [1]
13486정성태12/15/20232209개발 환경 구성: 695. Nuget config 파일에 값 설정/삭제 방법
13485정성태12/15/20232093오류 유형: 883. dotnet build/restore - error : Root element is missing
13484정성태12/14/20232169개발 환경 구성: 694. Windows 디렉터리 경로를 WSL의 /mnt 포맷으로 구하는 방법
13483정성태12/14/20232309닷넷: 2184. C# - 하나의 resource 파일을 여러 프로그램에서 (AOT 시에도) 사용하는 방법파일 다운로드1
13482정성태12/13/20232893닷넷: 2183. C# - eFriend Expert OCX 예제를 .NET Core/5+ Console App에서 사용하는 방법 [2]파일 다운로드1
13481정성태12/13/20232279개발 환경 구성: 693. msbuild - .NET Core/5+ 프로젝트에서 resgen을 이용한 리소스 파일 생성 방법파일 다운로드1
1  2  3  4  [5]  6  7  8  9  10  11  12  13  14  15  ...