Permanently binding static IP to preemptible google cloud VM

I figured out a workaround to this (specifically, keeping a static IP address assigned to a preemptible VM instance between recreations), with the caveat that your managed instance group has the following properties:

  1. Not autoscaling.
  2. Max group size of 1 (i.e. there is only ever meant to be one VM in this group)
  3. Autohealing is default (i.e. only recreates VMs after they are terminated).

The steps you need to follow are:

  1. Reserve a static IP.
  2. Create an instance template, configured as preemptible.
  3. Create your managed group, assigning your template to the group.
  4. Wait for the group to spin up your VM.
  5. After the VM has spun up, assign the static IP that you reserved in step 1 to the VM.
  6. Create a new instance template derived from the VM instance via gcloud (see https://cloud.google.com/compute/docs/instance-templates/create-instance-templates#gcloud_1).
  7. View the newly create instance template in the Console, and note that you see your External IP assigned to the template.
  8. Update the MiG (Managed Instance Group) to use the new template, created in step 6.
  9. Perform a proactive rolling update on the MiG using the Replace method.
  10. Confirm that your VM was recreated with the same name, the disks were preserved (or not, depending on how you configured the disks in your original template), and the VM has maintained its IP address.

Regards to step 6, my gcloud command looked like this:

gcloud compute instance-templates create vm-template-with-static-ip \
    --source-instance=source-vm-id \
    --source-instance-zone=us-east4-c

Almost goes without saying, this sort of setup is only useful if you want to:

  1. Minimize your costs by using a single preemptible VM.
  2. Not have to deal with the hassle of turning on a VM again after it's been preempted, ensuring as much uptime as possible.

If you don't mind turning the VM back on manually (and possibly not being aware it's been shutdown for who knows how long) after it has been preempted, then do yourself a favor and don't bother with the MiG and just standup the singular VM.


I've found one way that ensures that all VM's in your network have the same outgoing IP address. Using Cloud NAT you can assign a static IP which all VM's will use, there is a downside though:

GCP forwards traffic using Cloud NAT only when there are no other matching routes or paths for the traffic. Cloud NAT is not used in the following cases, even if it is configured:

  • You configure an external IP on a VM's interface.

    If you configure an external IP on a VM's interface, IP packets with the VM's internal IP as the source IP will use the VM's external IP to reach the Internet. NAT will not be performed on such packets. However, alias IP ranges assigned to the interface can still use NAT because they cannot use the external IP to reach the Internet. With this configuration, you can connect directly to a GKE VM via SSH, and yet have the GKE pods/containers use Cloud NAT to reach the Internet.

    Note that making a VM accessible via a load balancer external IP does not prevent a VM from using NAT, as long as the VM network interface itself does not have an external IP address.

Removing the VM's external IP also prevents you from direct SSH access to the VM, even SSH access from the gcloud console itself. The quote above shows an alternative with a load balancer, another way is a bastion, but doesn't directly solve access from for example Kubernetes/kubectl.

If that's no problem for you, this is the way to go.


Answering your questions:

(A) It is not possible at the moment, and I am not sure if it will ever be possible. By design preemptible VMs are deleted to make space for normal VMs (if there are capacity constraints in the given zone) or regularly to differentiate them from normal VMs. In the latter case preemption might seem like a start/stop event, but in the former it may take a substantial amount of time before the VM is recreated.

(B) At the moment there is not good way to achieve it in generality.

  • If you have a special case where your group has only one instance you can hardcode the IP address in the Instance Template
  • Otherwise at the moment the only solution I can think of (other than using a Load Balancer) is to write a startup script that would attach the NAT IP.