mirror of
https://github.com/apricote/hcloud-upload-image.git
synced 2025-08-06 13:56:58 +02:00
feat: smaller snapshots by zeroing disk first (#101)
The base image used requires ~0.42Gi. Even if the uploaded image is smaller, those bytes are currently not overwritten and still part of the stored snapshot. By zeroing the root disk first, those unwanted bytes are removed and not stored with the snapshot. This has two benefits: 1. Snapshots are billed by their compressed (shown) size, so small images are now a bit cheaper. 2. The time it takes to create a server from the snapshot scales with the snapshot size, so smaller snapshots means the server can start more quickly. This reduces the size of an example Talos x86 image from 0.42Gi before, to 0.2Gi afterwards. An example Flatcar image was 0.47Gi before, and still has that size with this patch. There are two ways to zero out the disk: - `dd if=/dev/zero of=/dev/sda` actually writes zeroes to every block on the device. This takes around a minute to do. - `blkdiscard /dev/sda` talks to the disk direclty and instructs it to discard all blocks. This only takes around 5 seconds. As both have the same effect on image size, but `blkdiscard` is SO MUCH faster, I have decided to use it. Even though only small images benefit from this, this is now enabled by default as the downside (5 second slower upload) does not justify additional flags or options to enable/disable this. Closes #96
This commit is contained in:
parent
420dcf94c9
commit
fdfb284533
@ -329,8 +329,17 @@ func (s *Client) Upload(ctx context.Context, options UploadOptions) (*hcloud.Ima
|
|||||||
}
|
}
|
||||||
defer func() { _ = sshClient.Close() }()
|
defer func() { _ = sshClient.Close() }()
|
||||||
|
|
||||||
// 6. SSH On Server: Download Image, Decompress, Write to Root Disk
|
// 6. Wipe existing disk, to avoid storing any bytes from it in the snapshot
|
||||||
logger.InfoContext(ctx, "# Step 6: Downloading image and writing to disk")
|
logger.InfoContext(ctx, "# Step 6: Cleaning existing disk")
|
||||||
|
|
||||||
|
output, err := sshsession.Run(sshClient, "blkdiscard /dev/sda", nil)
|
||||||
|
logger.DebugContext(ctx, string(output))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to clean existing disk: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. SSH On Server: Download Image, Decompress, Write to Root Disk
|
||||||
|
logger.InfoContext(ctx, "# Step 7: Downloading image and writing to disk")
|
||||||
|
|
||||||
cmd, err := assembleCommand(options)
|
cmd, err := assembleCommand(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -339,23 +348,23 @@ func (s *Client) Upload(ctx context.Context, options UploadOptions) (*hcloud.Ima
|
|||||||
|
|
||||||
logger.DebugContext(ctx, "running download, decompress and write to disk command", "cmd", cmd)
|
logger.DebugContext(ctx, "running download, decompress and write to disk command", "cmd", cmd)
|
||||||
|
|
||||||
output, err := sshsession.Run(sshClient, cmd, options.ImageReader)
|
output, err = sshsession.Run(sshClient, cmd, options.ImageReader)
|
||||||
logger.InfoContext(ctx, "# Step 6: Finished writing image to disk")
|
logger.InfoContext(ctx, "# Step 7: Finished writing image to disk")
|
||||||
logger.DebugContext(ctx, string(output))
|
logger.DebugContext(ctx, string(output))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to download and write the image: %w", err)
|
return nil, fmt.Errorf("failed to download and write the image: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7. SSH On Server: Shutdown
|
// 8. SSH On Server: Shutdown
|
||||||
logger.InfoContext(ctx, "# Step 7: Shutting down server")
|
logger.InfoContext(ctx, "# Step 8: Shutting down server")
|
||||||
_, err = sshsession.Run(sshClient, "shutdown now", nil)
|
_, err = sshsession.Run(sshClient, "shutdown now", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO Verify if shutdown error, otherwise return
|
// TODO Verify if shutdown error, otherwise return
|
||||||
logger.WarnContext(ctx, "shutdown returned error", "err", err)
|
logger.WarnContext(ctx, "shutdown returned error", "err", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8. Create Image from Server
|
// 9. Create Image from Server
|
||||||
logger.InfoContext(ctx, "# Step 8: Creating Image")
|
logger.InfoContext(ctx, "# Step 9: Creating Image")
|
||||||
createImageResult, _, err := s.c.Server.CreateImage(ctx, server, &hcloud.ServerCreateImageOpts{
|
createImageResult, _, err := s.c.Server.CreateImage(ctx, server, &hcloud.ServerCreateImageOpts{
|
||||||
Type: hcloud.ImageTypeSnapshot,
|
Type: hcloud.ImageTypeSnapshot,
|
||||||
Description: options.Description,
|
Description: options.Description,
|
||||||
|
Loading…
Reference in New Issue
Block a user