<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Google Cloud on Max Woolf&#39;s Blog</title>
    <link>https://minimaxir.com/tag/google-cloud/</link>
    <description>Recent content in Google Cloud on Max Woolf&#39;s Blog</description>
    <image>
      <title>Max Woolf&#39;s Blog</title>
      <url>https://minimaxir.com/android-chrome-512x512.png</url>
      <link>https://minimaxir.com/android-chrome-512x512.png</link>
    </image>
    <generator>Hugo</generator>
    <language>en</language>
    <copyright>Copyright Max Woolf © 2026</copyright>
    <lastBuildDate>Mon, 19 Nov 2018 09:00:00 -0700</lastBuildDate>
    <atom:link href="https://minimaxir.com/tag/google-cloud/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Run Any Scheduled Task/Cron Super-Cheap on Google Cloud Platform</title>
      <link>https://minimaxir.com/2018/11/cheap-cron/</link>
      <pubDate>Mon, 19 Nov 2018 09:00:00 -0700</pubDate>
      <guid>https://minimaxir.com/2018/11/cheap-cron/</guid>
      <description>Thanks to a few new synergies within GCP products, it&amp;rsquo;s possible to get the cost of running a scheduled task down to less than a dollar a month.</description>
      <content:encoded><![CDATA[<p>Let&rsquo;s say you want to make a <a href="https://twitter.com">Twitter</a> bot to tweet out a custom message every few hours or so, and the free-tier VMs offered by cloud services with fractional virtual CPUs and little RAM aren&rsquo;t sufficient. How do you host the bot? Many suggest you get a <a href="https://www.digitalocean.com">Digital Ocean</a> VM for <a href="https://www.digitalocean.com/pricing/">$5/mo</a>, which is not a bad price. But what if you want to run <em>multiple</em> bots? How do you easily coordinate multiple scheduled tasks?</p>
<p>In my case, I maintain three bots: a bot which <a href="https://twitter.com/MTGIFening">tweets GIFs</a> superimposed onto Magic: The Gathering cards, a bot which <a href="https://twitter.com/hackernews_nn">tweets AI-generated Hacker News submission titles</a>, and a bot which makes <a href="https://www.reddit.com/r/subredditnn">AI-generated Reddit submissions</a>. I found a clever solution to the multiple-bots problem: leveraging <a href="https://cloud.google.com/kubernetes-engine/docs/how-to/cronjobs">CronJobs</a> with <a href="https://cloud.google.com/kubernetes-engine/">Google Kubernetes Engine</a> + a single worker node. Each bot has its own CronJob which tells when GKE should schedule a Job for each task, and then the cluster executes the Jobs whenever compute capacity is available (i.e. no resource hogging/race conditions), and can ensure completion by restarting the task if it fails.</p>
<figure>

    <img loading="lazy" srcset="/2018/11/cheap-cron/kubecron_hu_257738fd32526fcd.webp 320w,/2018/11/cheap-cron/kubecron_hu_60eaa4e7513fc57f.webp 768w,/2018/11/cheap-cron/kubecron_hu_51e1e5c783f05f18.webp 1024w,/2018/11/cheap-cron/kubecron.png 1132w" src="kubecron.png"/> 
</figure>

<p>The cost of running a cluster in GKE is just the cost of the compute: using a preemptible n1-standard-1 (1 vCPU/3.75 GB RAM) worker node VM, the <a href="https://cloud.google.com/compute/pricing">cost</a> is about <strong>$7.30/mo</strong>, a bit more than the Digital Ocean server but can theoretically handle an unlimited number of scheduled tasks. The problem is the worker node needs to be up 24/7 even though the bots run sporadically.</p>
<p>But thanks to a few new synergies within GCP products, it&rsquo;s possible to get the cost of running a scheduled task down to <em>less than a dollar a month</em>.</p>
<h2 id="gcp-shenanigans">GCP Shenanigans</h2>
<p><a href="https://cloud.google.com/blog/products/application-development/announcing-cloud-scheduler-a-modern-managed-cron-service-for-automated-batch-jobs">A couple weeks ago</a>, Google released <a href="https://cloud.google.com/scheduler/">Cloud Scheduler</a>, which is a managed cron service that can perform tasks for other Google services. With that launch, Google also released a tutorial titled <a href="https://cloud.google.com/scheduler/docs/scheduling-instances-with-cloud-scheduler">Scheduling Instances with Cloud Scheduler</a>, demonstrating how you can programmatically start and stop instances using Cloud Scheduler in conjunction with <a href="https://cloud.google.com/functions/">Cloud Functions</a>. The demo use case is to schedule VMs during business hours, which gave me an idea; could this approach be used to boot up a VM, run a script, and then shut it down to minimize uptime?</p>
<p>I followed the tutorial instructions, which contains code to create a Cloud Function which boots up a specified VM, code for a Cloud Function to shut down a specified VM, and how to create cron jobs in Cloud Scheduler to invoke those two Functions at a specified time. For my scheduled tasks, I only need the instance up for a couple minutes: for example we can use a Cloud Scheduler job to start an instance every 4 hours at X:00 with the cron <code>0 */4 * * *</code>, and shut it down 2 minutes later at X:02 with the cron <code>2 */4 * * *</code>.</p>
<p>The next step is configuring a Google Compute Engine VM to run the scheduled task on boot. There are two ways to go about it: one is to use the <code>startup-script</code> field when configuring a VM, which specifies a command to run on boot and gets the job done. Another approach (which I use) is to package the scheduled task as a <a href="https://www.docker.com/resources/what-container">Docker Container</a>, and use a container-optimized OS which simply runs a specified container upon boot (although you should set restart to <code>On Failure</code> and give <code>Privileged Access</code> to the container). Additionally, the VM can be configured as a preemptible instance for massive cost savings, as the &ldquo;shut-down-at-anytime&rdquo; constraint is irrelevant for this use case!</p>
<figure>

    <img loading="lazy" srcset="/2018/11/cheap-cron/vm_hu_60ea09aeebe0f061.webp 320w,/2018/11/cheap-cron/vm_hu_5bae417d9bdcd8ce.webp 768w,/2018/11/cheap-cron/vm_hu_1d7bf6105857ee53.webp 1024w,/2018/11/cheap-cron/vm.png 1066w" src="vm.png"/> 
</figure>

<p>After the VMs are created, I created the start/stop tasks targeting those VMs as noted in the tutorial.</p>
<figure>

    <img loading="lazy" srcset="/2018/11/cheap-cron/scheduler_hu_f3821e91f9e5b9b.webp 320w,/2018/11/cheap-cron/scheduler_hu_b50652bfa915e2ea.webp 768w,/2018/11/cheap-cron/scheduler_hu_4245bc81e840ba03.webp 1024w,/2018/11/cheap-cron/scheduler.png 1446w" src="scheduler.png"/> 
</figure>

<p>I can verify that this workflow indeed works for all my bots, and the crons have been running successfully at the specified time, for only a couple minutes!</p>
<figure>

    <img loading="lazy" srcset="/2018/11/cheap-cron/working_hu_ff6618b7926cdd5b.webp 320w,/2018/11/cheap-cron/working_hu_b32d4c5569f2af3a.webp 768w,/2018/11/cheap-cron/working_hu_4917f0b4d5f52f8a.webp 1024w,/2018/11/cheap-cron/working.png 1790w" src="working.png"/> 
</figure>

<h2 id="crunching-the-numbers">Crunching the Numbers</h2>
<p>This approach incorporates many different Google products. Is it <em>actually</em> cheaper than just maintaining a simple $5/month server? Let&rsquo;s calculate the monthly cost of all these services.</p>
<p>Assuming that we run a scheduled task every 4 hours, and the server is up for 2 minutes each time (i.e. 12 minutes of uptime a day):</p>
<ul>
<li><strong>Compute Engine</strong>: A preemptible n1-standard-1 is <a href="https://cloud.google.com/compute/pricing">$0.01 an hour</a>. <code>$0.01 / 60 * 12 * 30 = $0.06</code></li>
<li><strong>VM Persistent Disk</strong>: Each GB of storage for a VM costs <a href="https://cloud.google.com/compute/pricing#disk">$0.04/month</a>, and the minimum storage size is 10GB. <code>$0.04 * 10 = $0.40</code></li>
<li><strong>Cloud Scheduler</strong>: Each rule is <a href="https://cloud.google.com/scheduler/pricing">$0.10/month</a>, and there are both a start and a stop rule. <code>$0.10 * 2 = $0.20</code></li>
<li><strong>Cloud Functions</strong>: It takes about 60 seconds total to turn on and off a VM, and with the default 256MB provision, during which it costs <a href="https://cloud.google.com/functions/pricing">$.000000463/100ms</a>. <code>0.000000463 * 10 * 60 * 12 * 30 = $0.10</code></li>
</ul>
<p>$0.06 + $0.40 + $0.20 + $0.10 = <strong>$0.76/month to run the scheduled task</strong>! That&rsquo;s not even counting the free tier bonuses if you just want to create one scheduled task; in that case, the only price you pay is the $0.06/mo for the VM. And even in the case where you run the task every hour (like in the images above), the cost is $1.24/month; still not bad.</p>
<p>It&rsquo;s worth noting that these pricing economics wouldn&rsquo;t have worked years ago. Back then <a href="https://aws.amazon.com">Amazon Web Services</a>, the leader in web services, charged for a minimum of 1 hour every time a VM was booted. Google Compute Engine innovated by only requiring a minimum of 10 minutes, which is much better but still would have had unnecessary overhead (in this example, it would increase compute monthly costs by $0.24/31%). <a href="https://cloud.google.com/blog/products/gcp/extending-per-second-billing-in-google">As of September 2017</a>, Google Compute Engine charges a minimum of <strong>1 minute</strong>, which makes this workflow possible and cheap (AWS made the same change <a href="https://aws.amazon.com/blogs/aws/new-per-second-billing-for-ec2-instances-and-ebs-volumes/">a week earlier</a>).</p>
<p>It&rsquo;s also possible that similar workflows exist for AWS and <a href="https://azure.microsoft.com/en-us/">Azure Cloud</a>, although I&rsquo;m less familiar with those platforms (and it may not necessarily be better/cheaper). Sure, if you have a very simple task to practice making bots in the cloud, the free tier of any cloud service might suffice (where you run the server all the time, and schedule the cron on the server itself). If you&rsquo;re planning many scheduled tasks, then a centralized approach like my initial Kubernetes implementation might actually be more cost effective. But if you&rsquo;re somewhere <em>in between</em>, then giving each scheduled task its own VM makes more sense for both ease of use and cost-effectiveness. And there&rsquo;s still many further optimizations to be done too (for example, by allowing the script in the VM to ping a HTTP Cloud Function endpoint and shut <em>itself</em> off when complete instead of using a scheduled cron rule).</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
