
Adquire os discos EBS de uma AMI da AWS que você pode iniciar, transmitindo snapshots via APIs diretas do EBS para um bucket S3 privado com manifestos sha256 e descompactação opcional de imagem bruta.
Adquira os discos de uma AMI que você já pode iniciar em um bucket S3 privado. Sem catálogo, sem lista de produtos, sem ids de AMI embutidos. Você informa o id da AMI.
O S3 é o armazenamento. Boot, snapshot, compressão e upload são executados dentro da AWS. A largura de banda local só é usada se você posteriormente baixar um objeto específico.
graph LR
A[AMI you supply] -->|run-instances| B[boot instance]
B -->|every EBS disk| C[snapshots you own]
C --> D[terminate boot instance]
C -->|ListSnapshotBlocks / GetSnapshotBlock| E[helper]
E -->|raw then zstd| F[(S3 golden store)]
F -->|optional pull| G[local artifacts]
DeleteOnTermination.raw | zstd | aws s3 cp -. Nenhum volume é criado ou anexado.manifest.json.region.OptInRequired é um passo no console.Só faça dump de imagens que você tem direito de executar. Mantenha os artefatos privados. Uma taxa de software do Marketplace, se a listagem tiver uma, só é acumulada enquanto a instância de boot estiver em execução.
A AWS não fornece aos compradores o snapshot por trás de uma AMI do Marketplace. copy-image e create-volume contra esse snapshot falham. Iniciar a AMI cria um volume que esta conta possui, e esse volume pode receber snapshot.
Um volume que ainda carrega um product code do Marketplace só pode ser anexado como dispositivo raiz de uma instância parada, então anexá-lo a um helper como disco de dados não funciona. ListSnapshotBlocks + GetSnapshotBlock retornam os bytes via HTTPS sem anexação. Blocos não alocados são emitidos como zeros para que os offsets permaneçam corretos.
A API direta fala CBOR com membros em PascalCase. Checksum é base64 do digest bruto, não hex. ebs_snapshot_read.py lida com ambos.
jq, flock e credenciais que possam aplicar a stack e executar as chamadas de instance/snapshot/SSM/S3 abaixozstd apenas para unpack.shPermissões de operador usadas pelos scripts (a role do helper é separada e é criada pelo Terraform):
ec2:DescribeImages, DescribeInstances, DescribeSnapshots, RunInstances,
TerminateInstances, CreateSnapshot, DeleteSnapshot, CreateTags,
RegisterImageiam:PassRole no instance profile do helperssm:GetParameter, SendCommand, GetCommandInvocation,
DescribeInstanceInformations3:* no bucket de artefatos (get/put/list/delete/head)sts:GetCallerIdentitycd terraform && cp terraform.tfvars.example terraform.tfvars
# edit region / name_prefix if needed — still no AMI ids
cd ..
make init && make apply && make configure
make probe AMI=ami-0123456789abcdef0
make dump LABEL=my-image AMI=ami-0123456789abcdef0
make ls
ami-0123456789abcdef0 é um placeholder. Substitua por um id de AMI que esta conta possa iniciar.
make apply cria uma VPC, um security group somente de saída, um bucket S3 e a role IAM do helper. Ele não inicia computação faturável a menos que helper_enabled = true. A VPC não tem NAT gateway, então o custo ocioso é apenas o bucket (e ele fica vazio até você fazer dump de algo).
scripts/dump.sh --ami ami-0123456789abcdef0 --label my-image
scripts/dump.sh --ami ami-0123456789abcdef0 --label my-image --boot-type m5.2xlarge --dwell 60
scripts/dump.sh --ami ami-0123456789abcdef0 --label my-image --dry-run
scripts/dump.sh --ami ami-0123456789abcdef0 --label my-image --snapshot-id snap-0123456789abcdef0
--dry-run descreve a AMI e imprime o plano. Ele não inicia nada.
Padrões:
| Flag | Padrão | Observações |
|---|---|---|
--boot-type | m5.xlarge, ou m6g.xlarge se a AMI for arm64 | As listagens geralmente rejeitam outros tipos. O erro da AWS nomeia os que elas permitem. |
--dwell | 180 | Segundos que o guest executa antes do snapshot. 0 faz snapshot assim que a instância estiver em execução. |
--workers | 32 | Chamadas GetSnapshotBlock concorrentes por disco. |
Os labels devem corresponder a ^[A-Za-z0-9][A-Za-z0-9._-]{0,62}$. Eles se tornam chaves do S3.
Uma nova execução pula um label cujo objeto já está no S3 e cujo sha256 está no manifesto. --force busca novamente.
images.tsv, uma imagem por linha. Linhas em branco e comentários # são ignorados. O terceiro campo é um tipo de instância opcional.
# LABEL AMI BOOT_TYPE
my-image ami-0123456789abcdef0
other-image ami-0123456789abcdef0 m5.2xlarge
make dump-batch BATCH=images.tsv JOBS=2
--jobs N dá a cada worker seu próprio slot de helper. As atualizações do manifesto são protegidas com flock. Dois processos driver separados podem compartilhar manifest.json; dê a eles valores diferentes de DUMP_STATE_DIR se não puderem compartilhar um arquivo de slot de helper.
make probe AMI=ami-0123456789abcdef0
run-instances --dry-run é gratuito. DryRunOperation significa que a conta pode iniciá-la. OptInRequired significa aceitar essa listagem no console da AWS e depois testar novamente. Este repositório não aceitará os termos por você.
--snapshot-id pula o boot e lê um snapshot existente. Apenas uma imagem.--register-ami registra uma AMI iniciável nesta conta a partir dos snapshots recém-obtidos, e mantém esses snapshots. Eles são cobrados por GB-mês.--keep-snapshot mantém os snapshots sem registrar uma AMI. A limpeza pula snapshots marcados com Keep=true a menos que você passe --force.make ls # keys + manifest, no download
make watch # in-flight helper log, multipart upload size
make pull LABELS="my-image"
make pull LABELS="my-image" RAW=1 # also write a sparse .raw
scripts/unpack.sh my-image # partition metadata next to the raw
pull verifica o sha256 do objeto comprimido antes de registrar o label como baixado. unpack grava uma imagem raw esparsa em artifacts/raw/ e um .diskmeta.txt (file, sfdisk, blkid, parted). Monte com losetup -Pf --show artifacts/raw/<label>.raw.
s3://<bucket>/
golden/<label>/<label>.raw.zst
golden/<label>/<label>.raw.zst.sha256 # checksum of the compressed stream
golden/<label>/<label>.stats.json
golden/<label>/<label>.<device>.raw.zst # extra disks, root is the unsuffixed object
_scripts/snapshot_to_s3.sh
_scripts/ebs_snapshot_read.py
_status/<label>.json # expires after 7 days
_logs/<label>.log # expires
golden/ não tem expiração por lifecycle. Uploads multipart incompletos são abortados após 3 dias. terraform destroy exclui o bucket (force_destroy = true), incluindo golden/.
manifest.json (local, no gitignore) é o índice: id da AMI, nome, proprietário, arquitetura, product codes, chaves por disco, sha256, tamanhos, hora da busca.