How to create and rotate Automatic Snapshot?

My solution is slightly simpler. I want to snapshot all disks not just the primary disk.

By listing all disks in the project this handles all servers from one single script - as long as it is run within a gcloud project (and could be modified to run outside a project server too.

To tidy up older snapshots doesn't need such complex date processing as it can be handled from the gcloud command line using a filter

https://gitlab.com/alan8/google-cloud-auto-snapshot

#!/bin/bash
# loop through all disks within this project  and create a snapshot
gcloud compute disks list | tail -n +2 | while read DISK_NAME ZONE c3 c4; do
  gcloud compute disks snapshot $DISK_NAME --snapshot-names auto-$DISK_NAME-$(date "+%s") --zone $ZONE 
done
#
# snapshots are incremental and dont need to be deleted, deleting snapshots will merge snapshots, so deleting doesn't loose anything
# having too many snapshots is unwieldy so this script deletes them after 60 days
#
gcloud compute snapshots list --filter="creationTimestamp<$(date -d "-60 days" "+%Y-%m-%d") AND (auto.*)" --uri | while read SNAPSHOT_URI; do
  gcloud compute snapshots delete --quiet $SNAPSHOT_URI
done
#

Also note that for OSX users you have to use something like

$(date -j -v-60d "+%Y-%m-%d")

for the the creationTimestamp filter


Update Google Cloud has scheduled backups that can be configured per disk. See Creating scheduled snapshots for persistent disk in the Google Cloud documentation.

Original Answer

Documentation is pretty clear about how to do it:

gcloud compute disks snapshot DISK

Note, that

Snapshots are always created based on the last successful snapshot taken

And before you will remove any of your snapshots -- take a look on that diagram: enter image description here

More information about API.


UPDATE:

The script has changed a lot since I first gave this answer - please see Github repo for latest code: https://github.com/jacksegal/google-compute-snapshot

ORIGINAL ANSWER:

I had the same problem, so I created a simple shell script to take a daily snapshot and delete all snapshots over 7 days: https://github.com/Forward-Action/google-compute-snapshot

#!/usr/bin/env bash
export PATH=$PATH:/usr/local/bin/:/usr/bin

#
# CREATE DAILY SNAPSHOT
#

# get the device name for this vm
DEVICE_NAME="$(curl -s "http://metadata.google.internal/computeMetadata/v1/instance/disks/0/device-name" -H "Metadata-Flavor: Google")"

# get the device id for this vm
DEVICE_ID="$(curl -s "http://metadata.google.internal/computeMetadata/v1/instance/id" -H "Metadata-Flavor: Google")"

# get the zone that this vm is in
INSTANCE_ZONE="$(curl -s "http://metadata.google.internal/computeMetadata/v1/instance/zone" -H "Metadata-Flavor: Google")"

# strip out the zone from the full URI that google returns
INSTANCE_ZONE="${INSTANCE_ZONE##*/}"

# create a datetime stamp for filename
DATE_TIME="$(date "+%s")"

# create the snapshot
echo "$(gcloud compute disks snapshot ${DEVICE_NAME} --snapshot-names gcs-${DEVICE_NAME}-${DEVICE_ID}-${DATE_TIME} --zone ${INSTANCE_ZONE})"


#
# DELETE OLD SNAPSHOTS (OLDER THAN 7 DAYS)
#

# get a list of existing snapshots, that were created by this process (gcs-), for this vm disk (DEVICE_ID)
SNAPSHOT_LIST="$(gcloud compute snapshots list --regexp "(.*gcs-.*)|(.*-${DEVICE_ID}-.*)" --uri)"

# loop through the snapshots
echo "${SNAPSHOT_LIST}" | while read line ; do

   # get the snapshot name from full URL that google returns
   SNAPSHOT_NAME="${line##*/}"

   # get the date that the snapshot was created
   SNAPSHOT_DATETIME="$(gcloud compute snapshots describe ${SNAPSHOT_NAME} | grep "creationTimestamp" | cut -d " " -f 2 | tr -d \')"

   # format the date
   SNAPSHOT_DATETIME="$(date -d ${SNAPSHOT_DATETIME} +%Y%m%d)"

   # get the expiry date for snapshot deletion (currently 7 days)
   SNAPSHOT_EXPIRY="$(date -d "-7 days" +"%Y%m%d")"

   # check if the snapshot is older than expiry date
if [ $SNAPSHOT_EXPIRY -ge $SNAPSHOT_DATETIME ];
        then
     # delete the snapshot
         echo "$(gcloud compute snapshots delete ${SNAPSHOT_NAME} --quiet)"
   fi
done