Ubuntu(Linux)에서 OCI Object Storage로 디스크 이미지 백업

250GB의 SSD를 백업할 필요가 생겼다. 문제는 필자는 250GB의 디스크 이미지를 담을 여유공간이 없었다. 백업한 이미지를 어딘가 저장해야 하는데, 아무리 뒤져봐도 저장할 공간이 없었기 때문에 백업을 진행할 수 없었다.

이럴때, Oracle Cloud (또는 AWS 등도 가능)의 Object Storage를 이용할 수 있다. dd를 이용해서 디스크를 읽고, 이것을 stdin(pipe)로 바로 aws-cli, oci-cli로 쏴주면 별도의 파일 저장 없이 바로 Object Storage로 파일을 올릴 수 있다.

쉽게 말해서, 백업 이미지를 실시간으로 인터넷으로 업로드하는 방법이다. 하드 디스크 또는 SSD에 남아있는 용량이 0이어도 어짜피 인터넷에 저장하는 방식이므로 문제가 없다.

Oracle Cloud는 최대 10TiB의 단일 파일을 업로드 할 수 있고, GCPAWS는 최대 5TiB의 단일 파일을 업로드 할 수 있다. Azure는 최대 190TiB를 업로드 할 수 있다.

특히, Oracle Cloud는 Archive Tier의 스토리지를 제공한다. 해당 스토리지는 GB당 비용이 매우 저렴하다. 대신 읽기시에 미리 요청을 넣어야 하며, 몇시간 동안 대기해야 할 수 있다. 이런 점을 볼때, PTL (테이프 장치)를 이용하는듯 하다. 필자는 이미지를 오래 보관할 목적이며, 몇시간의 대기는 참을 수 있기 때문에, Archive tier의 Bucket을 만들었다.

OCI-CLI 설정

Oracle Cloud는 최대 10TB의 파일을 올릴 수 있다. 파일 크기가 5GB 이상일 때는, 5GB로 쪼개서 업로드 해야 한다. 최대 5GB짜리 파일을 최대 2048개로 쪼개서 올리면 OCI에서 단일 파일로 합쳐준다. (https://docs.oracle.com/en/cloud/cloud-at-customer/occ-get-started/upload-large-file.html)

파일이 5GB 이상일 때 하는 쪼개기 작업은 상당히 번거롭다. 그러므로, 우리는 oci-cli를 사용하려고 한다. oci-cli가 설치되어 있지 않으면 설치부터 한다.

sudo apt install python3-pip
pip3 install oci-cli --break-system-packages
oci setup keys
  • pip3가 설치되어 있지 않다면 pip3를 설치한다.
  • oci-cli는 python 패키지로 제공된다.
    단독 실행파일 형식은 apt install python3-oci-cli와 같은 형식으로 설치해라고 경고 메세지를 띄우는데, oci-cli는 apt에 없으므로, 강제로 설지한다.
  • oci-clioci 라는 명령어로 실행할 수 있다.
  • 가장 먼저해야 할 일은 API 인증 키를 만드는 것이다. oci setup keys를 실행하면 된다.
    • 공개키는 ~/.oci/oci_api_key_public.pem 에 저장된다.
    • 비밀키는 ~/.oci/oci_api_key.pem 에 저장된다.

이제, API 인증키를 OCI 콘솔(웹)에서 등록하고 oci-cli의 설정 파일을 만들어야 한다. oci setup config를 실행해도 된다. 필자의 경우에는 콘솔에 표시된 사용자 OCID와 API키에 등록된 사용자 OCID가 상이한 문제가 있었다. 그래서 아래와 같이 API키를 OCI에 먼저 등록한 후, 표시되는 설정파일 내용을 붙여넣는 방법을 추천한다.

오른쪽 상단의 프로필 My Profile에 들어간다
하단의 API Keys Add API key 버튼을 누른다.
Paste a public key 선택 → 아래의 public key를 입력 하단의 Add 버튼 클릭

Public key는 아래의 명령어로 읽을 수 있다.

cat ~/.oci/oci_api_key_public.pem
API keys에 키가 등록됐을 것이다. 키 오른쪽의 메뉴 → View configuration file 를 누른다.
configuration file preview 내용을 복사해서 ~/.oci/config 에 집어넣는다.
이때, 맨 마지막의 key_file 부분은 key_file=~/.oci/oci_api_key.pem 로 바꾼다.

아래의 명령어 실행시 오류가 발생하지 않는다면 제대로 설정된 것이다:

oci os ns get

bucket 생성

OCI에서 Object Storage를 만들어야 한다. Object Storage의 단위는 Bucket이다. 추후 Bucket 이름을 사용해야 하므로, 이름을 잘 적어두자.

Storage → Object Storage & Archive Storage → Buckets → Create Bucket 버튼을 누른다.
Default Storage Tier는 Archive로 설정하고, 아래의 Uncommitted Multipart Uploads Cleanup을 선택한다.

실제 디스크 백업 과정

gzip을 이용하면 디스크 이미지를 실시간으로 압축할 수 있다. 디스크에 빈 공간이 많을 경우에 효과가 크다.

250GB중, 실제 120GB의 용량을 사용하던 상황에서 아래와 같은 용량 사용이 나왔다:
* gzip 사용시 146GB
* gzip 미사용시 250GB

사용하지 않고 비어 있는 공간을 획기적으로 줄여주는것을 볼 수 있다. 디스크 단편화 정도와 숨어있는 파티션 등에 따라서 압축률은 달라질 수 있다.

GZip을 사용하지 않을 때

GZip을 사용하지 않으려면 다음과 같이 바로 명령어를 실행하면 된다:

sudo dd if=/dev/sdb bs=8M | oci os object put --bucket-name "버킷 이름" --name "파일명" --file - --parallel-upload-count=12 --part-size 768
  • 버킷 이름은 아까 만들었던 Object Storage의 Bucket name을 입력한다.
  • 파일명은 Object Storage내에 저장될 파일의 이름이다. 알아서 잘 짓자
  • parallel-upload-count는 동시에 몇개를 업로드할지 선택하는 것이다. 500Mbps 회선 기준으로 8개만 해도 충분했다. 혹시나 더 빠른 회선을 사용한다면 500Mbps당 8개 정도로 설정하자.
    (필자는 넉넉하게 12개를 했다.)
  • part-size는 업로드 파일의 단위 크기이다. MiB 단위이다. 쉽게 말해서, 768MB씩 끊어서 파일을 업로드 한다는 이야기이다.
  • parallel-upload-count * part-size 가 여유 메모리보다 적게 하자.
    • 예) 메모리 24GB중 Free는 16GB일때, 768M * 12 = 9GB이므로 안전하다.

명령어 예시

sudo dd if=/dev/sdb bs=8M | oci os object put --bucket-name esukmeans-backup --name "laptop-img" --file - --parallel-upload-count=12 --part-size 768

Gzip을 사용할 때

gzip을 사용하면 디스크에 남아있는 공간을 확 줄일 수 있다.

GZip은 CPU를 엄청 많이 사용한다. 그러므로, 단일 Gzip만 실행하면 백업 속도가 매우 떨어진다. 메모리는 10MB 내외로 사용하므로, 메모리에 대해서는 걱정할 필요 없다.

백업 작동시 btop의 모습.
빈 공간을 만나면 GZip이 빨리 끝나지만, 쓰여있는 공간을 만나면 GZip이 병목지점이 된다.

gzip은 단일 코어에서만 작동하므로 병목지점이 된다. 백업 속도를 엄청나게 떨어뜨린다. 그러므로, 여러 코어를 활용할 수 있는 pigz 를 사용하는게 좋다.

sudo apt install pigz

sudo dd if=/dev/sdb bs=8M | pigz -9 -p 7 | sudo oci os object put --bucket-name "버킷 이름" --name "파일명" --file - --parallel-upload-count=12 --part-size 768

pigz 뒤에 두개의 옵션이 붙었다. 각각 다음과 같다:

  • -9 : 최고의 압축률을 지향한다 (CPU를 많이 사용한다) -1을 입력하면 CPU를 덜 쓰는 대신 빠르게 압축한다.
    • (속도 우선) -1, -2, -3, -4, -5, -6, -7, -8, -9 (압축률 우선) 옵션을 사용할 수 있다.
  • -p 7 : 7개의 코어를 사용한다. 코어수가 많다면 코어수에서 1개를 뺀 수 정도로 입력하자.
    (엄밀하게는 쓰레드의 수이지만, 여기서는 편하게 말한다)
    • 16코어라면 -p 15, 8코어라면 -p 7 을 입력.

그 외 파라메터들은 gzip을 사용하지 않는 버전과 같다.

  • 버킷 이름은 아까 만들었던 Object Storage의 Bucket name을 입력한다.
  • 파일명은 Object Storage내에 저장될 파일의 이름이다. 알아서 잘 짓자
  • parallel-upload-count는 동시에 몇개를 업로드할지 선택하는 것이다. 500Mbps 회선 기준으로 8개만 해도 충분했다. 혹시나 더 빠른 회선을 사용한다면 500Mbps당 8개 정도로 설정하자.
    (필자는 넉넉하게 12개를 했다.)
  • part-size는 업로드 파일의 단위 크기이다. MiB 단위이다. 쉽게 말해서, 768MB씩 끊어서 파일을 업로드 한다는 이야기이다.
  • parallel-upload-count * part-size 가 여유 메모리보다 적게 하자.
    • 예) 메모리 24GB중 Free는 16GB일때, 768M * 12 = 9GB이므로 안전하다.

명령어 예시

sudo dd if=/dev/sdb bs=8M | pigz -9 -p 7 | oci os object put --bucket-name esukmeans-backup --name laptop.img.gz --file - --parallel-upload-count=12 --part-size 768

참고사항

다음은 Ryzen 5600U, 22GB 메모리, 10Gbps의 외장하드에 SN730 (250GB), 네트워크는 500Mbps의 상황 아래에서의 참고사항이다.

  • 데이터가 쓰여져 있는 부분은 6코어로 pigz를 돌려도 느리다.
    • 체감상 20초 업로드 하고 3초를 쉰다. 500Mbps 기준으로 업로드 속도가 더 빠르다.
    • 준수하게 500Mbps를 뽑고 싶다면 8코어 이상을 쓰도록 하자. (pigz -9 -p 8)
    • 1Gbps라면 16코어를 사용하는게 좋을것 같다. (pigz -9 -p 16)
  • 데이터가 없는 부분은 인터넷 속도가 병목 지점이다.
    • 압축 시간은 5초인데, 20초 동안 업로드 하는 느낌이다.
    • 빈 공간이 많다면 네트워크 속도가 전체 속도를 결정한다
  • 250GB (실사용 120GB) 기준으로 1시간 5분 정도가 소요됐다.
  • 민감한 파일이 디스크에 있다면, 디스크 이미지를 업로드 하는것이 보안상 문제가 될 수 있다.
    • 필자는 LUKS로 루트 파티션을 암호화 한 상태이다. 그래서 거리낌 없이 업로드 했다.
    • 디스크 이미지를 올리는게 보안상 괜찮을지 고려해 보자.
      (특히 본인이 업로드할 디스크에 암호화가 안되어 있다면)

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

댓글을 작성하기 위해 아래의 숫자를 입력해 주세요. *Captcha loading…

목차