Create and run shutdown scripts that execute commands right before a virtual machine (VM) instance is stopped or restarted. This is useful if you rely on automated scripts to start up and shut down instances, allowing instances time to clean up or perform tasks, such as exporting logs, or syncing with other systems.
Shutdown scripts are especially useful for VMs in a managed instance group with an autoscaler. If the autoscaler shuts down a VM in the group, the shutdown script runs before the VM stops and the shutdown script performs any actions that you define. The script runs during the limited shutdown period before the VM stops. For example, your shutdown script might copy processed data to Cloud Storage or back up any logs.
Shutdown scripts function very similarly to startup scripts. Much of the documentation for startup scripts also applies for shutdown scripts.
For both shutdown and reboot tasks, VMs always run shutdown scripts as follows:
- For Linux VMs, by using the
rootuser. - For Windows VMs, by using the
Systemaccount.
Prerequisites
To run scripts stored in metadata on a VM instance, the guest environment must be installed and running.
- The guest environment includes the guest agent (for example, google-guest-agent on Linux) that reads the script content or URL from the instance's metadata and initiates execution.
- All public Compute Engine images come with the guest environment preinstalled.
- If you create a custom image, you must manually install the Google Guest Environment to ensure scripts from metadata and other Google Cloud features function properly.
Before you begin
- Learn about Startup scripts.
- Understand what the metadata server is.
-
If you haven't already, set up authentication.
Authentication verifies your identity for access to Google Cloud services and APIs. To run
code or samples from a local development environment, you can authenticate to
Compute Engine by selecting one of the following options:
Select the tab for how you plan to use the samples on this page:
Console
When you use the Google Cloud console to access Google Cloud services and APIs, you don't need to set up authentication.
gcloud
-
Install the Google Cloud CLI, and then sign in to the gcloud CLI with your federated identity. After signing in, initialize the Google Cloud CLI by running the following command:
gcloud init - Set a default region and zone.
Terraform
To use the Terraform samples on this page in a local development environment, install and initialize the gcloud CLI, and then set up Application Default Credentials with your user credentials.
-
Install the Google Cloud CLI.
-
Configure the gcloud CLI to use your federated identity.
For more information, see Sign in to the gcloud CLI with your federated identity.
-
Create local authentication credentials for your user account:
gcloud auth application-default login
If an authentication error is returned, confirm that you have signed in to the gcloud CLI with your federated identity.
For more information, see Set up authentication for a local development environment.
REST
To use the REST API samples on this page in a local development environment, you use the credentials you provide to the gcloud CLI.
Install the Google Cloud CLI, and then sign in to the gcloud CLI with your federated identity.
For more information, see Authenticate for using REST in the Google Cloud authentication documentation.
-
Permissions required for this task
To perform this task, you must have the following permissions:
- All permissions required to create an instance
compute.instances.setMetadataon the instance
Specifications
The following sections outline the specifications for shutdown scripts.
Limitations
There are some limitations to note when using shutdown scripts:
- Compute Engine executes shutdown scripts only on a best-effort basis. In rare cases, Compute Engine cannot guarantee that the shutdown script will complete.
- On Windows, the Local Group Policy is used to launch the shutdown script.
- The installation package configures the Local Group Policy
Computer Configuration/Windows Setting/Scripts (Startup/Shutdown)setting to launch the script upon system shutdown.
- The installation package configures the Local Group Policy
Shutdown script invocation
Shutdown scripts are triggered when the instance shuts down after any of the following events happen:
You do the following:
Compute Engine stops an instance as part of a programmed stop or delete operation.
Compute Engine stops a Spot VM or preemptible instance as part of the preemption process.
A shutdown script can be of any file type. If there is a shutdown script present in the instance, then Compute Engine does the following:
- Copies the script to a local file in the instance.
- Sets permissions on the file to make the script executable.
- Executes the file when the instance shuts down.
You could, for example, provide a Python script instead of a bash script. Keep in mind that Compute Engine runs the script verbatim, regardless of the type of script.
To execute a script that is not bash, add a shebang line at the top of the file to let the operating system know which interpreter to use. For example, for a Python script, you can add a shebang line like:
#!/usr/bin/python
Shutdown script running time
Your shutdown scripts start running when Compute Engine sets the
instance state to STOPPING. Your scripts must complete before the instance
is fully stopped, which is when its state changes to TERMINATED. The time the
instance takes to reach the TERMINATED state varies depending on the
instance type.
If your scripts take longer than the time it takes for the instance to stop,
then Compute Engine forcefully stops the scripts, which can lead to
data loss or incomplete tasks. To prevent this,
stop the instance from within its guest OS.
This approach keeps the instance state to STOPPING until your shutdown scripts
finish running.
Use a local shutdown script
A local shutdown script is a script that lives on your local computer. Pass in a local shutdown script either as a file or by giving the contents directly to Compute Engine.
Shutdown scripts can perform as many actions as you need, but if you are passing in the file locally, your script cannot exceed the metadata value length limit of 256 KB. To use a script that exceeds the length limit, store your file on Cloud Storage. See Use shutdown script from Cloud Storage for more information.
Provide a shutdown script file
You can only pass in a local shutdown script file through the gcloud
command-line tool.
gcloud
To pass in a local shutdown script file, supply the --metadata-from-file
flag, followed by a metadata key pair, shutdown-script=PATH/TO/FILE, where
PATH/TO/FILE is a relative path to the shutdown script. For example:
gcloud compute instances create example-instance \
--metadata-from-file shutdown-script=examples/scripts/install.sh
Terraform
To specify a shutdown script directly, use the google_compute_instance
resource with the path to the shutdown script in the metadata.
To learn how to apply or remove a Terraform configuration, see Basic Terraform commands.
Provide shutdown script contents directly
Alternatively, you can pass in the contents of your shutdown script directly.
Console
In Google Cloud console, specify a shutdown script directly using the
shutdown-script metadata key:
Go to the Create an instance page.
Specify the VM details.
Expand the Advanced options section.
Expand Management, and do the following:
- In the Metadata section, click Add item.
- In the Key field, enter
shutdown-scriptfor the metadata key. - In the Value field, add the contents of your shutdown script.
Continue with the VM creation process.
gcloud
Using the Google Cloud CLI, use the --metadata flag to provide
the contents of your shutdown script, followed by the
shutdown-script=CONTENTS key pair, where CONTENTS is the content of your
shutdown script.
gcloud compute instances create example-instance --metadata shutdown-script="#! /bin/bash
> # Shuts down Apache server
> /etc/init.d/apache2 stop"
Terraform
To specify a shutdown script directly, use the google_compute_instance
resource with the shutdown script in the metadata.
To learn how to apply or remove a Terraform configuration, see Basic Terraform commands.
REST
In the API, provide a shutdown script as part of the metadata property in
your request when you create an instance. Use shutdown-script as the
metadata key:
POST https://compute.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances
{...
"metadata": {
"items": [
{
"key": "shutdown-script",
"value": "#! /bin/bash\n\n# Shuts down Apache server\n/etc/init.d/apache2 stop"
}
]
}...
}
Provide a shutdown script on Windows instances
Run shutdown scripts on Windows instances using the following Windows-specific metadata keys. Choose from any of the specialized keys listed below. Each key should match the type of script you want to run.
You can specify multiple shutdown scripts by passing in different keys to your instance but each key can only be specified once per virtual machine.
The following keys can be used with a local shutdown script, using the same instructions earlier in this document.
cmd shutdown scripts |
bat shutdown scripts |
ps1 shutdown scripts |
|---|---|---|
windows-shutdown-script-cmd |
windows-shutdown-script-bat |
windows-shutdown-script-ps1 |
Use a shutdown script from Cloud Storage
You can store and use a shutdown script from Cloud Storage. Follow
the instructions in the Startup scripts
documentation but replace startup-script-url with shutdown-script-url.
For Windows instances, replace windows-startup-script-url with
windows-shutdown-script-url.
Apply a shutdown script to running instances
To add a shutdown script to a running instance, follow the instructions in the Applying a startup script to running instances documentation but replace the metadata keys with one of the following keys:
shutdown-script: Supply the shutdown script contents directly with this key. Using the Google Cloud CLI, you can provide the path to a shutdown script file, using the--metadata-from-fileflag and theshutdown-scriptmetadata key.shutdown-script-url: Supply a Cloud Storage URL to the shutdown script file with this key.
Run a shutdown script during a graceful shutdown
By default, if a compute instance has graceful shutdown enabled, then any shutdown scripts that you configure in metadata keys run after the graceful shutdown ends.
To run commands during a graceful shutdown, you must use a custom watcher script that continuously polls the metadata server in the background, as shown in this section. To give your scripts enough time to complete and to avoid potential data loss or incomplete tasks, we recommend that you modify your shutdown scripts by moving your logic into this watcher script.
To run a shutdown script during a graceful shutdown, select one of the following options based on the guest OS that your compute instance uses:
Linux
If you haven't already, then connect to the compute instance.
Run a watcher script, or configure it to run at boot, such as the following. Add your specific shutdown logic where indicated:
#!/bin/bash # -------------------------------------------------------- # Script for graceful shutdown based on the metadata value # -------------------------------------------------------- # # This script monitors the metadata key `shutdown-status` and # waits for its value to change to `PENDING_STOP`. After the script # runs a series of user-defined commands, it runs `sudo shutdown -h now` # to signal to Compute Engine that the shutdown process is # complete. # # To run this script, you must have passwordless sudo privileges. METADATA_URL="http://metadata.google.internal/computeMetadata/v1/instance/attributes/shutdown-status" LAST_ETAG="0" echo "Starting shutdown status watcher" while true; do # Wait for the metadata value to change. # The metadata server blocks the request until a change occurs or a timeout is reached. RESPONSE=$(curl -H "Metadata-Flavor: Google" -s -i "${METADATA_URL}?wait_for_change=true&last_etag=${LAST_ETAG}") CURL_EXIT_STATUS=$? if [[ ${CURL_EXIT_STATUS} -ne 0 ]]; then echo "Error: curl command failed with exit status ${CURL_EXIT_STATUS}. Retrying in 5 seconds..." sleep 5 continue fi # Strip carriage returns (\r) immediately to prevent CRLF line endings from corrupting string comparisons RESPONSE=$(echo "$RESPONSE" | tr -d '\r') # Extract the HTTP status code from the first line of the response HTTP_STATUS=$(echo "$RESPONSE" | head -n 1 | awk '{print $2}') if [[ "${HTTP_STATUS}" -eq 200 ]]; then # Read the new etag value to re-subscribe on the next poll. NEW_ETAG=$(echo "$RESPONSE" | grep -i "^ETag:" | awk '{print $2}') if [[ -n "${NEW_ETAG}" ]]; then LAST_ETAG="${NEW_ETAG}" fi # Extract the value of the shutdown status from the last line of the response body. SHUTDOWN_STATUS=$(echo "$RESPONSE" | tail -n 1) echo "Metadata changed. New ETag: ${LAST_ETAG}, shutdown-status: '${SHUTDOWN_STATUS}'" if [[ "${SHUTDOWN_STATUS}" == "PENDING_STOP" ]]; then echo "Shutdown signal 'PENDING_STOP' received. Exiting watcher loop." break fi elif [[ "${HTTP_STATUS}" -eq 503 ]]; then # 503 Service Unavailable: wait_for_change timed out with no change. Sleep and loop again. echo "Service temporarily unavailable or request timed out. Retrying in 2 seconds..." sleep 2 continue else # Unexpected HTTP status echo "Warning: Unexpected HTTP status ${HTTP_STATUS}. Retrying in 5 seconds..." sleep 5 fi done # -------------------------------------------------------- # Graceful shutdown commands section # -------------------------------------------------------- echo "Watcher loop exited. Starting graceful shutdown procedures..." # --- ADD YOUR GRACEFUL SHUTDOWN COMMANDS HERE --- echo "Graceful shutdown commands executed." # -------------------------------------------------------- # Signal OS to stop # -------------------------------------------------------- echo "Shutting down the guest OS to turn off the compute instance..." sudo shutdown -h now
Windows
If you haven't already, then connect to the compute instance by using one of the following methods:
Run a watcher script, or configure it to run at boot, such as the following. Add your specific shutdown logic where indicated:
<# .SYNOPSIS pre-shutdown-script.ps1 #> # -------------------------------------------------------- # Script for graceful shutdown based on the metadata value # -------------------------------------------------------- # # This script monitors the metadata key `shutdown-status` and # waits for its value to change to `PENDING_STOP`. After the script # runs a series of user-defined commands, it runs `Stop-Computer -Force` # to signal to Compute Engine that the shutdown process is # complete. $METADATA_URL = "http://metadata.google.internal/computeMetadata/v1/instance/attributes/shutdown-status" $LAST_ETAG = "0" Write-Host "Starting shutdown status watcher" while ($true) { $Response = $null $HTTP_STATUS = 0 # Wait for the metadata value to change. # The metadata server blocks the request until a change occurs or a timeout is reached. try { $Response = Invoke-WebRequest ` -Headers @{"Metadata-Flavor" = "Google"} ` -Uri "${METADATA_URL}?wait_for_change=true&last_etag=${LAST_ETAG}" ` -TimeoutSec 320 ` -ErrorAction Stop if ($null -ne $Response) { $HTTP_STATUS = [int]$Response.StatusCode } } catch { # Invoke-WebRequest throws an error for non-2xx status codes or connection failures. $Exception = $_.Exception if ($null -ne $Exception -and $null -ne $Exception.Response) { $HTTP_STATUS = [int]$Exception.Response.StatusCode } else { $HTTP_STATUS = 0 } } if ($HTTP_STATUS -eq 0) { Write-Host "Error: Request failed. Retrying in 5 seconds..." Start-Sleep -Seconds 5 continue } if ($HTTP_STATUS -eq 200) { # Read the new etag value to re-subscribe on the next poll. $NEW_ETAG = $Response.Headers["ETag"] if ($null -ne $NEW_ETAG) { $LAST_ETAG = $NEW_ETAG } # Extract the value of the shutdown status from the response body. $SHUTDOWN_STATUS = $Response.Content.Trim() Write-Host "Metadata changed. New ETag: ${LAST_ETAG}, shutdown-status: '${SHUTDOWN_STATUS}'" if ($SHUTDOWN_STATUS -eq "PENDING_STOP") { Write-Host "Shutdown signal 'PENDING_STOP' received. Exiting watcher loop." break } } elseif ($HTTP_STATUS -eq 503) { # 503 Service Unavailable: wait_for_change timed out with no change. Sleep and loop again. Write-Host "Service temporarily unavailable or request timed out. Retrying in 2 seconds..." Start-Sleep -Seconds 2 continue } else { # Unexpected HTTP status Write-Host "Warning: Unexpected HTTP status ${HTTP_STATUS}. Retrying in 5 seconds..." Start-Sleep -Seconds 5 } } # -------------------------------------------------------- # Graceful shutdown commands section # -------------------------------------------------------- Write-Host "Watcher loop exited. Starting graceful shutdown procedures..." # --- ADD YOUR GRACEFUL SHUTDOWN COMMANDS HERE --- Write-Host "Graceful shutdown commands executed." # -------------------------------------------------------- # Signal OS to Halt # -------------------------------------------------------- Write-Host "Shutting down the guest OS to turn off the compute instance..." Stop-Computer -Force
Viewing the output of a shutdown script
Linux
You can view the output from a Linux shutdown script by doing any of the following:
Connecting to the instance and running the following command:
sudo journalctl -u google-shutdown-scripts.serviceViewing the output through serial port 1 in the Google Cloud console and checking for
google_metadata_script_runnerevents.IAP Desktop from a Windows workstation. For more information, see the GoogleCloudPlatform/iap-desktop repo on GitHub.
Windows
View the output from a Windows Server shutdown script by using any of the
following and checking for GCEMetadataScripts events:
Serial port 1 in the Google Cloud console. For more information, see Viewing serial port output.
Windows Event Viewer's Application Log.
IAP Desktop from a Windows workstation. For more information, see the GoogleCloudPlatform/iap-desktop repo on GitHub.