<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jérôme Dx</title>
    <description>The latest articles on DEV Community by Jérôme Dx (@jdxlabs).</description>
    <link>https://dev.to/jdxlabs</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F647867%2F2fca01e3-6927-48dd-b966-3e52e1deee8c.jpeg</url>
      <title>DEV Community: Jérôme Dx</title>
      <link>https://dev.to/jdxlabs</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jdxlabs"/>
    <language>en</language>
    <item>
      <title>Mise : The ultimate Dev Tool Manager for seamless workflows</title>
      <dc:creator>Jérôme Dx</dc:creator>
      <pubDate>Mon, 26 Jan 2026 09:00:00 +0000</pubDate>
      <link>https://dev.to/jdxlabs/mise-the-ultimate-dev-tool-manager-for-seamless-workflows-2lm0</link>
      <guid>https://dev.to/jdxlabs/mise-the-ultimate-dev-tool-manager-for-seamless-workflows-2lm0</guid>
      <description>&lt;p&gt;Tired of juggling multiple versions of your favorite tools, or just want to stay up to date with the latest CLI tools, programming languages, and more ?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mise.jdx.dev/" rel="noopener noreferrer"&gt;Mise&lt;/a&gt; (mise-en-place) is a utility written in Rust, that allows you to manage the versions of your developer tools on different projects. It’s very fast and very complete, with different ways to use it :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://mise.jdx.dev/dev-tools/" rel="noopener noreferrer"&gt;&lt;strong&gt;Dev Tools&lt;/strong&gt;&lt;/a&gt; : A version manager for developer tools (alternative to &lt;a href="https://asdf-vm.com/" rel="noopener noreferrer"&gt;ASDF&lt;/a&gt;, &lt;a href="https://dev.to/jdxlabs/pienv-to-handle-different-versions-of-python-1859"&gt;Pyenv&lt;/a&gt;, &lt;a href="https://dev.to/jdxlabs/tfenv-to-handle-different-versions-of-terraform-4k6p"&gt;Tfenv/Tenv&lt;/a&gt;, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://mise.jdx.dev/environments/" rel="noopener noreferrer"&gt;&lt;strong&gt;Environments&lt;/strong&gt;&lt;/a&gt; : Allows to load your environment variables, by projects (alternative to &lt;a href="https://direnv.net/" rel="noopener noreferrer"&gt;Direnv&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://mise.jdx.dev/tasks/" rel="noopener noreferrer"&gt;&lt;strong&gt;Tasks&lt;/strong&gt;&lt;/a&gt; : Allows to run defined tasks for your projects (alternative to &lt;a href="https://www.gnu.org/software/make/" rel="noopener noreferrer"&gt;Make&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fltjqxjsuc1xzkwlnuz17.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fltjqxjsuc1xzkwlnuz17.png" alt="different-options" width="800" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s explore how it can streamline your daily workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started with Mise
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Installation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Mise is available on &lt;a href="https://mise.jdx.dev/installing-mise.html" rel="noopener noreferrer"&gt;all platforms that support Rust&lt;/a&gt;, i.e. Linux, Windows or MacOS.&lt;/p&gt;

&lt;p&gt;For shell users, start by installing Mise with a single command :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://mise.run | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, add the following line to your &lt;code&gt;.zshrc&lt;/code&gt; to enable Mise in your shell :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"eval &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;/home/user/.local/bin/mise activate zsh&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"/home/user/.zshrc"&lt;/span&gt;
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Dev Tools&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;As a version manager, Mise handle the different version of your tools for development. It can be used for local development and inside your CICD pipelines.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Basic Commands&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Check your Mise version :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;mise version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Get help :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;mise --help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Installing Tools&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Install the latest versions of your favorite tools effortlessly :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mise use python@latest
mise use go@latest
mise use terraform@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Need cloud tools? Mise has you covered :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mise use gcloud@latest
mise use scaleway@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Managing Your Tools&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;List installed software :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mise &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwhe5wix7q44zfuno0n8m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwhe5wix7q44zfuno0n8m.png" alt="mise-ls" width="639" height="529"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Explore available versions :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mise ls-remote terraform
mise ls-remote terraform@1.11
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4q0311fjgda3iswxllig.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4q0311fjgda3iswxllig.png" alt="Mise ls-remote" width="327" height="126"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Search for tools :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mise search jq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Staying Up to Date&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Update your tools interactively :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mise up &lt;span class="nt"&gt;--interactive&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd9mar9o1nhjverfitz8z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd9mar9o1nhjverfitz8z.png" alt="mise update" width="800" height="169"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also update Mise itself :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mise self-update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Environments
&lt;/h2&gt;

&lt;p&gt;Mise allows you to manage environment variables per project, ensuring your tools and scripts always run in the correct context. This is especially useful for projects requiring specific configurations or secrets.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set environment variables for a project
&lt;/h3&gt;

&lt;p&gt;Create a &lt;code&gt;.mise.toml&lt;/code&gt; file in your project root and define your environment variables :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[env]&lt;/span&gt;
&lt;span class="py"&gt;DATABASE_HOST&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"localhost:5432"&lt;/span&gt;
&lt;span class="py"&gt;API_KEY&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"your_api_key_here"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mise automatically loads these variables when you enter the project directory, thanks to its shell integration, you just need to trust the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mise trust
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Handle multiple environments
&lt;/h3&gt;

&lt;p&gt;File &lt;code&gt;.mise.dev.toml&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;env&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
DATABASE_HOST &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"dev-db:5432"&lt;/span&gt;
API_KEY &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"dev_key"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;File &lt;code&gt;.mise.prd.toml&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;env&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
DATABASE_HOST &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"prd-db:5432"&lt;/span&gt;
API_KEY &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"prd_key"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can switch between environments like this :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;MISE_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev mise &lt;span class="nb"&gt;env&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;API_KEY
&lt;span class="nv"&gt;MISE_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;prd mise &lt;span class="nb"&gt;env&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;API_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Tasks&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Mise simplifies running repetitive or complex tasks by allowing you to define and execute them directly from your project configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Define tasks&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Add a &lt;code&gt;[tasks]&lt;/code&gt; section to your &lt;code&gt;.mise.toml&lt;/code&gt; file :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[tasks]&lt;/span&gt;
&lt;span class="py"&gt;start&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"docker-compose up"&lt;/span&gt;
&lt;span class="py"&gt;test&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"pytest"&lt;/span&gt;
&lt;span class="py"&gt;build&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"cargo build --release"&lt;/span&gt;
&lt;span class="py"&gt;deploy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"make deploy"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Run a task&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Execute any defined task with :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mise run &amp;lt;task_name&amp;gt;

&lt;span class="c"&gt;# Examples:&lt;/span&gt;
mise run &lt;span class="nb"&gt;test
&lt;/span&gt;mise run deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;List available tasks&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To see all tasks defined in your project :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mise tasks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Why Mise?&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simple&lt;/strong&gt; : Clear and intuitive syntax.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Versatile&lt;/strong&gt; : Replaces many tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lightweight&lt;/strong&gt; : Written in Rust, fast and resource-efficient.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Efficient&lt;/strong&gt; : Effortlessly manages versions and dependencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is a &lt;a href="https://github.com/jdxlabs/cheatsheets/blob/main/sheets/os-config/mise.md" rel="noopener noreferrer"&gt;Mise cheatsheet&lt;/a&gt; you can consult to remember some common commands.&lt;/p&gt;

&lt;p&gt;There are still a lot of &lt;a href="https://mise.jdx.dev/cli/" rel="noopener noreferrer"&gt;possibilities you can explore&lt;/a&gt; with this tool, like securing your variables, execute hooks or even use &lt;a href="https://mise.jdx.dev/plugins.html" rel="noopener noreferrer"&gt;plugins&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now you’re all set ! Try it out and see how Mise simplifies your workflow.&lt;/p&gt;

</description>
      <category>devtools</category>
      <category>devops</category>
      <category>cli</category>
      <category>productivity</category>
    </item>
    <item>
      <title>GCP-Nuke to clean your sandbox projects</title>
      <dc:creator>Jérôme Dx</dc:creator>
      <pubDate>Mon, 25 Aug 2025 17:00:00 +0000</pubDate>
      <link>https://dev.to/jdxlabs/gcp-nuke-to-clean-your-sandbox-projects-5d03</link>
      <guid>https://dev.to/jdxlabs/gcp-nuke-to-clean-your-sandbox-projects-5d03</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/ekristen/gcp-nuke" rel="noopener noreferrer"&gt;GCP Nuke&lt;/a&gt; is a tool you can use to clean up your GCP Projects. It’s a Go client, under MIT licence, that will remove all the resources from your project, or you can restrict them with filters.&lt;/p&gt;

&lt;p&gt;As “nuke” let you guess, it can be a very destructive tool.&lt;/p&gt;

&lt;p&gt;Some equivalents exist for &lt;a href="https://github.com/ekristen/aws-nuke" rel="noopener noreferrer"&gt;AWS&lt;/a&gt; and &lt;a href="https://github.com/ekristen/azure-nuke" rel="noopener noreferrer"&gt;Azure&lt;/a&gt;, provided by the same author.&lt;/p&gt;

&lt;p&gt;It is particularly interesting, by example, if you have a Sandbox project you want to clean regularly, for cost reasons or even sustainibility considerations.&lt;/p&gt;

&lt;p&gt;I will show you concretly how you can use it, for this kind of use.&lt;/p&gt;

&lt;h1&gt;
  
  
  A basic Sandbox usage
&lt;/h1&gt;

&lt;p&gt;FIrst you can install it simply with brew :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;ekristen/tap/gcp-nuke
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ensure you have all this services enabled :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud services &lt;span class="nb"&gt;enable &lt;/span&gt;cloudresourcemanager.googleapis.com
gcloud services &lt;span class="nb"&gt;enable &lt;/span&gt;compute.googleapis.com
gcloud services &lt;span class="nb"&gt;enable &lt;/span&gt;storage.googleapis.com
gcloud services &lt;span class="nb"&gt;enable &lt;/span&gt;run.googleapis.com
gcloud services &lt;span class="nb"&gt;enable &lt;/span&gt;cloudfunctions.googleapis.com
gcloud services &lt;span class="nb"&gt;enable &lt;/span&gt;pubsub.googleapis.com
gcloud services &lt;span class="nb"&gt;enable &lt;/span&gt;iam.googleapis.com

&lt;span class="c"&gt;# to check everything is correct :&lt;/span&gt;
gcloud services list &lt;span class="nt"&gt;--enabled&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will have the possibility to customize the behavior of the tool with a config file.&lt;/p&gt;

&lt;p&gt;Here is the &lt;a href="https://gcp-nuke.ekristen.dev/resources/" rel="noopener noreferrer"&gt;list of available resources&lt;/a&gt; handle by the tool.&lt;/p&gt;

&lt;p&gt;For my usage, I choosed to select some resources :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cloud Functions&lt;/li&gt;
&lt;li&gt;CloudRun&lt;/li&gt;
&lt;li&gt;GKE&lt;/li&gt;
&lt;li&gt;Compute Instances &amp;amp; disks&lt;/li&gt;
&lt;li&gt;Storage Buckets&lt;/li&gt;
&lt;li&gt;BigQuery Datasets&lt;/li&gt;
&lt;li&gt;CloudSQL instances&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It will parse the 3 regions I use most, and it let me choose to keep some resources with this labels :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;managed_by: terraform&lt;/li&gt;
&lt;li&gt;gcp-nuke: ignore
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;regions:
  - global
  - us-east1 &lt;span class="c"&gt;# US: South Carolina&lt;/span&gt;
  - europe-west1 &lt;span class="c"&gt;# EU: Belgium&lt;/span&gt;
  - europe-west9 &lt;span class="c"&gt;# EU: Paris&lt;/span&gt;

accounts:
  my-gcp-project:
      includes:
        - CloudFunction
        - CloudFunction2
        - CloudRun
        - GKECluster
        - ComputeInstance
        - ComputeFirewall
        - ComputeForwardingRule
        - ComputeSSLCertificate
        - ComputeDisk
        - StorageBucket
        - BigQueryDataset
        - CloudSQLInstance

    filters:
      __global__:
        - property: label:gcp-nuke
          value: &lt;span class="s2"&gt;"ignore"&lt;/span&gt;
        - property: label:managed_by
          value: &lt;span class="s2"&gt;"terraform"&lt;/span&gt;
      ComputeFirewall:
        - property: &lt;span class="s2"&gt;"name"&lt;/span&gt;
          value: &lt;span class="s2"&gt;"default-*"&lt;/span&gt;
          invert: &lt;span class="nb"&gt;true&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To authenticate, you can create a Service Account and declare the environment variable, or connect with the "auth login" option :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GOOGLE_APPLICATION_CREDENTIALS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;creds.json
&lt;span class="c"&gt;# or&lt;/span&gt;
gcloud auth login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can do a “dry-run” launch to see what will be destroyed (dry-run is defined by default to limit the risks) :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcp-nuke run &lt;span class="nt"&gt;--config&lt;/span&gt; config.yml &lt;span class="nt"&gt;--no-prompt&lt;/span&gt; &lt;span class="nt"&gt;--project-id&lt;/span&gt; &amp;lt;current-gcp-project-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you’re sure, you can launch the “nuke” 💥 :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcp-nuke run &lt;span class="nt"&gt;--config&lt;/span&gt; config.yml &lt;span class="nt"&gt;--no-prompt&lt;/span&gt; &lt;span class="nt"&gt;--no-dry-run&lt;/span&gt; &lt;span class="nt"&gt;--project-id&lt;/span&gt; &amp;lt;current-gcp-project-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Automation
&lt;/h1&gt;

&lt;p&gt;If you want, you can define a regular job that will clear up the resources, once a day at 2 am, for instance.&lt;/p&gt;

&lt;p&gt;This can be achieved with a CLoudRun job.&lt;/p&gt;

&lt;p&gt;Here is the Dockerfile :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;docker.io/library/golang:1.23&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;builder&lt;/span&gt;

&lt;span class="c"&gt;# Install gcp-nuke&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;go &lt;span class="nb"&gt;install &lt;/span&gt;github.com/ekristen/gcp-nuke@latest

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; docker.io/library/debian:bookworm-slim&lt;/span&gt;

&lt;span class="c"&gt;# Install ca-certificates for HTTPS requests and gcloud CLI&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; ca-certificates curl gnupg &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main"&lt;/span&gt; | &lt;span class="nb"&gt;tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; /etc/apt/sources.list.d/google-cloud-sdk.list &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key &lt;span class="nt"&gt;--keyring&lt;/span&gt; /usr/share/keyrings/cloud.google.gpg add - &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; google-cloud-cli &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /go/bin/gcp-nuke /usr/local/bin/gcp-nuke&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; config.yml .&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; entrypoint.sh .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x entrypoint.sh

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["./entrypoint.sh"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the entrypoint.sh :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Setting project..."&lt;/span&gt;
gcloud config &lt;span class="nb"&gt;set &lt;/span&gt;project &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_ID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Running gcp-nuke..."&lt;/span&gt;
gcp-nuke run &lt;span class="nt"&gt;--config&lt;/span&gt; config.yml &lt;span class="nt"&gt;--no-prompt&lt;/span&gt; &lt;span class="nt"&gt;--no-dry-run&lt;/span&gt; &lt;span class="nt"&gt;--project-id&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_ID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"gcp-nuke completed."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Push it on the Artifact Registry&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud artifacts repositories create gcp-nuke-repo &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repository-format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;docker &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;europe-west9 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Docker Repo for gcp-nuke"&lt;/span&gt;

podman build &lt;span class="nt"&gt;-t&lt;/span&gt; europe-west9-docker.pkg.dev/&amp;lt;your-project-id&amp;gt;/gcp-nuke-repo/gcp-nuke-job:latest &lt;span class="nb"&gt;.&lt;/span&gt;

gcloud auth configure-docker europe-west9-docker.pkg.dev
podman push europe-west9-docker.pkg.dev/&amp;lt;your-project-id&amp;gt;/gcp-nuke-repo/gcp-nuke-job:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the Terraform for deployement, that will create the CloudRun Job, the Service Account and the Cloud Scheduler :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ----------------------------&lt;/span&gt;
&lt;span class="c1"&gt;# Cloud Run Job&lt;/span&gt;
&lt;span class="c1"&gt;# ----------------------------&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"google_cloud_run_v2_job"&lt;/span&gt; &lt;span class="s2"&gt;"gcp_nuke_job"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"gcp-nuke-job"&lt;/span&gt;
  &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;region&lt;/span&gt;

  &lt;span class="nx"&gt;deletion_protection&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

  &lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;service_account&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;google_service_account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gcp_nuke&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;

      &lt;span class="nx"&gt;containers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;image&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${var.region}-docker.pkg.dev/${var.project_id}/gcp-nuke-repo/gcp-nuke-job:latest"&lt;/span&gt;

        &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;name&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"PROJECT_ID"&lt;/span&gt;
          &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project_id&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nx"&gt;resources&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;limits&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;cpu&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"1"&lt;/span&gt;
            &lt;span class="nx"&gt;memory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"512Mi"&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nx"&gt;max_retries&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
      &lt;span class="nx"&gt;timeout&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"300s"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;parallelism&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="nx"&gt;labels&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;managed_by&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"terraform"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# ----------------------------&lt;/span&gt;
&lt;span class="c1"&gt;# Service account&lt;/span&gt;
&lt;span class="c1"&gt;# ----------------------------&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"google_service_account"&lt;/span&gt; &lt;span class="s2"&gt;"gcp_nuke"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;account_id&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"sa-gcp-nuke"&lt;/span&gt;
  &lt;span class="nx"&gt;display_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Service Account for gcp-nuke"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"google_project_iam_member"&lt;/span&gt; &lt;span class="s2"&gt;"gcp_nuke_owner"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;project&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project_id&lt;/span&gt;
  &lt;span class="nx"&gt;role&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"roles/owner"&lt;/span&gt;
  &lt;span class="nx"&gt;member&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"serviceAccount:${google_service_account.gcp_nuke.email}"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# ----------------------------&lt;/span&gt;
&lt;span class="c1"&gt;# Cloud Scheduler&lt;/span&gt;
&lt;span class="c1"&gt;# ----------------------------&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"google_cloud_scheduler_job"&lt;/span&gt; &lt;span class="s2"&gt;"gcp_nuke_schedule"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"gcp-nuke-schedule"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Run gcp-nuke every day at 2am"&lt;/span&gt;
  &lt;span class="nx"&gt;schedule&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"0 2 * * *"&lt;/span&gt;
  &lt;span class="nx"&gt;time_zone&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Europe/Paris"&lt;/span&gt;

  &lt;span class="nx"&gt;http_target&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;http_method&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"POST"&lt;/span&gt;
    &lt;span class="nx"&gt;uri&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://${var.region}-run.googleapis.com/apis/run.googleapis.com/v1/namespaces/${var.project_id}/jobs/${google_cloud_run_v2_job.gcp_nuke_job.name}:run"&lt;/span&gt;

    &lt;span class="nx"&gt;oauth_token&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;service_account_email&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;google_service_account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gcp_nuke&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GCP-Nuke is a convenient tool to clean up a GCP Project, you have now some keys to use it locally, or to automate it. &lt;/p&gt;

&lt;p&gt;If you want to regularly clean up a Sandbox project, this is a case where it's particularly suitable, as it reduces financial costs and the ecological footprint, always with the same idea to build only what you really consume.&lt;/p&gt;

</description>
      <category>googlecloud</category>
      <category>cloud</category>
      <category>greenit</category>
      <category>finops</category>
    </item>
    <item>
      <title>Cloud Run: Container management made simple</title>
      <dc:creator>Jérôme Dx</dc:creator>
      <pubDate>Wed, 02 Jul 2025 22:00:00 +0000</pubDate>
      <link>https://dev.to/jdxlabs/cloud-run-container-management-made-simple-13kh</link>
      <guid>https://dev.to/jdxlabs/cloud-run-container-management-made-simple-13kh</guid>
      <description>&lt;p&gt;If you are looking for a simpler service than Kubernetes to deploy and manage containers on an environment (even in prod), Google Cloud offers a turnkey service that could be used, which is called Cloud Run.&lt;/p&gt;

&lt;p&gt;The purpose of this article is to go a little further than the Quickstart, to show you how to deploy a simple python container, via Terraform.&lt;/p&gt;

&lt;h1&gt;
  
  
  Prerequisites for the demo
&lt;/h1&gt;

&lt;p&gt;First, you will need this elements :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Terraform:&lt;/strong&gt; &lt;a href="https://learn.hashicorp.com/tutorials/terraform/install-cli" rel="noopener noreferrer"&gt;Install Terraform&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Cloud SDK:&lt;/strong&gt; &lt;a href="https://cloud.google.com/sdk/docs/install" rel="noopener noreferrer"&gt;Install gcloud&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A Google Cloud Platform (GCP) Project:&lt;/strong&gt; &lt;a href="https://cloud.google.com/resource-manager/docs/creating-managing-projects" rel="noopener noreferrer"&gt;Create a GCP project&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, create the Cloudbuild trigger in the GCP console :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the &lt;a href="https://console.cloud.google.com/cloud-build/triggers" rel="noopener noreferrer"&gt;Cloud Build Triggers page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Create Trigger&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Set the following options:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name:&lt;/strong&gt; &lt;code&gt;your-github-trigger&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event:&lt;/strong&gt; &lt;code&gt;Push to a branch&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source:&lt;/strong&gt; &lt;code&gt;GitHub&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repository:&lt;/strong&gt; Select the repository you created for this project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Branch:&lt;/strong&gt; &lt;code&gt;main&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build Configuration:&lt;/strong&gt; &lt;code&gt;Cloud Build configuration file (yaml or json)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create&lt;/strong&gt; to finish setting up the trigger.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : create a service account with the name &lt;code&gt;sa-cloudbuild&lt;/code&gt; and assign it the &lt;code&gt;Cloud Build Service Account&lt;/code&gt; and &lt;code&gt;Storage Admin&lt;/code&gt; roles. This service account will be used by Cloud Build to deploy the application to Cloud Run.&lt;/p&gt;

&lt;h1&gt;
  
  
  Terraform resources
&lt;/h1&gt;

&lt;p&gt;To create a repository in Artifact Registry :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resource &lt;span class="s2"&gt;"google_artifact_registry_repository"&lt;/span&gt; &lt;span class="s2"&gt;"repo"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  location      &lt;span class="o"&gt;=&lt;/span&gt; var.region
  repository_id &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"flask-repo"&lt;/span&gt;
  description   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Repository for Flask app"&lt;/span&gt;
  format        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"DOCKER"&lt;/span&gt;

  labels &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    managed_by &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"terraform"&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the simple app :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# main.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Example Hello World route.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NAME&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;World&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.0.0.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PORT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this requirements :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# requirements.txt&lt;/span&gt;
&lt;span class="nv"&gt;Flask&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;3.0.3
&lt;span class="nv"&gt;gunicorn&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;23.0.0
&lt;span class="nv"&gt;Werkzeug&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;3.0.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this Dockerfile :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;3.12&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;slim&lt;/span&gt;

&lt;span class="n"&gt;WORKDIR&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;

&lt;span class="n"&gt;COPY&lt;/span&gt; &lt;span class="n"&gt;requirements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;txt&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;

&lt;span class="n"&gt;RUN&lt;/span&gt; &lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;no&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;dir&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="n"&gt;requirements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;txt&lt;/span&gt;

&lt;span class="n"&gt;EXPOSE&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;

&lt;span class="n"&gt;ENV&lt;/span&gt; &lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;World&lt;/span&gt;
&lt;span class="n"&gt;ENV&lt;/span&gt; &lt;span class="n"&gt;PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;

&lt;span class="n"&gt;CMD&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gunicorn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--bind&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.0.0.0:8080&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main:app&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the terraform code to build &amp;amp; push the container with Cloud Build :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"null_resource"&lt;/span&gt; &lt;span class="s2"&gt;"build_image"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;triggers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;dockerfile_hash&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;filemd5&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"${path.root}/app/Dockerfile"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;main_py_hash&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;filemd5&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"${path.root}/app/main.py"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;requirements_hash&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;filemd5&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"${path.root}/app/requirements.txt"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;provisioner&lt;/span&gt; &lt;span class="s2"&gt;"local-exec"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;-&lt;/span&gt;&lt;span class="no"&gt;EOT&lt;/span&gt;&lt;span class="sh"&gt;
      gcloud builds submit ${path.root}/app \
        --tag ${var.region}-docker.pkg.dev/${var.project_id}/${google_artifact_registry_repository.repo.repository_id}/flask-app:latest \
        --project ${var.project_id}
&lt;/span&gt;&lt;span class="no"&gt;    EOT
&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;depends_on&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;google_artifact_registry_repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repo&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For our example, I choosed to launch it directly from Terraform, without the necessity to have Docker or Podman installed, just Gcloud Cli.&lt;/p&gt;

&lt;p&gt;And finally the Terraform code to create the Cloud Run Service :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Cloud Run Service&lt;/span&gt;
&lt;span class="c1"&gt;##&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"google_cloud_run_v2_service"&lt;/span&gt; &lt;span class="s2"&gt;"flask_service"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;service_name&lt;/span&gt;
  &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;region&lt;/span&gt;

  &lt;span class="nx"&gt;labels&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;managed_by&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"terraform"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;labels&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;managed_by&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"terraform"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;containers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;image&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${var.region}-docker.pkg.dev/${var.project_id}/${google_artifact_registry_repository.repo.repository_id}/flask-app:latest"&lt;/span&gt;

      &lt;span class="nx"&gt;ports&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;container_port&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;name&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"NAME"&lt;/span&gt;
        &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Cloud Run"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nx"&gt;resources&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;limits&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;cpu&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"1000m"&lt;/span&gt;
          &lt;span class="nx"&gt;memory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"512Mi"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;scaling&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;min_instance_count&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
      &lt;span class="nx"&gt;max_instance_count&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;depends_on&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;null_resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;build_image&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# IAM policy to allow public access&lt;/span&gt;
&lt;span class="c1"&gt;##&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"google_cloud_run_service_iam_member"&lt;/span&gt; &lt;span class="s2"&gt;"public_access"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;service&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;google_cloud_run_v2_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flask_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
  &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;google_cloud_run_v2_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flask_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;
  &lt;span class="nx"&gt;role&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"roles/run.invoker"&lt;/span&gt;
  &lt;span class="nx"&gt;member&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"allUsers"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This outputs will give you the urls generated for your service, and the registry :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"service_url"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"URL of the Cloud Run service"&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;google_cloud_run_v2_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flask_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uri&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"artifact_registry_url"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Artifact Registry repository URL"&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;google_artifact_registry_repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can launch a plan and apply your code, you have a container you can work on, handle a service managed by Google Cloud.&lt;/p&gt;

&lt;p&gt;All the code is available in &lt;a href="https://github.com/jdxlabs/gcp-cloudrun-demo" rel="noopener noreferrer"&gt;this github repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There is an &lt;a href="https://github.com/steren/awesome-cloud-run" rel="noopener noreferrer"&gt;“Awesome CloudRun” page&lt;/a&gt; where you will find a lot of interesting usages for Cloud Run.&lt;/p&gt;

&lt;p&gt;Google also offers some &lt;a href="https://codelabs.developers.google.com/?product=cloudrun" rel="noopener noreferrer"&gt;Codelabs&lt;/a&gt; where you can get trained and explore advanced use cases with Cloud Run.&lt;/p&gt;

&lt;p&gt;Now you can use and improve your configuration to work with your containers, have fun with it.&lt;/p&gt;

</description>
      <category>googlecloud</category>
      <category>containers</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Python: The Nim game</title>
      <dc:creator>Jérôme Dx</dc:creator>
      <pubDate>Mon, 17 Mar 2025 14:00:00 +0000</pubDate>
      <link>https://dev.to/jdxlabs/python-the-nim-game-m43</link>
      <guid>https://dev.to/jdxlabs/python-the-nim-game-m43</guid>
      <description>&lt;p&gt;Today we are going to look at a small algorithm exercise in python, through the game called the nim game.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule
&lt;/h2&gt;

&lt;p&gt;This is a two-player game. We have n matches to start with (for example 10).&lt;br&gt;
In turn, each player will take 1, 2 or 3 matches. The player who takes the last match loses.&lt;/p&gt;
&lt;h2&gt;
  
  
  The algorithm
&lt;/h2&gt;

&lt;p&gt;This is a fairly deterministic game, in the sense that when you know the trick, you can't lose (unless you started from a losing position).&lt;/p&gt;

&lt;p&gt;Here is a table of the right number of matches to take (x representing a losing position):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F03f96c45fj71y4hwn695.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F03f96c45fj71y4hwn695.png" alt="periodicity" width="800" height="69"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can therefore observe an infinite periodic loop, with a period of 4.&lt;/p&gt;

&lt;p&gt;The player has lost (if the other plays well), when we have a modulo 4 = 1 (in other words the remainder of the division is equal to 1).&lt;/p&gt;

&lt;p&gt;The winning strategy is therefore to send the other player to a losing position.&lt;/p&gt;
&lt;h2&gt;
  
  
  1-player version
&lt;/h2&gt;

&lt;p&gt;We will formalize this in the algorithm, using the modulo function, to write the computer's AI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Enter the initial number of matches: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Number of matches : &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;P1 turn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;How much do you take ? (1-3) &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You lost !&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;P2 turn (cpu)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Remaining &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;I take some&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Remaining &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;I lost !&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Two-players version
&lt;/h2&gt;

&lt;p&gt;Here is a version if you want experiment with a friend, keeping in mind this strategy :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;nim_game&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Welcome to the Nim Game!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Rules: Players take turns removing 1 to 3 objects from the pile.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The player forced to take the last object loses.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Initialize the pile
&lt;/span&gt;    &lt;span class="n"&gt;pile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Enter the initial number of objects in the pile: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;pile&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The pile must contain at least 1 object.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;pile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Enter the initial number of objects in the pile: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="c1"&gt;# Player names
&lt;/span&gt;    &lt;span class="n"&gt;player1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Enter Player 1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s name: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;player2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Enter Player 2&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s name: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Start the game
&lt;/span&gt;    &lt;span class="n"&gt;current_player&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;player1&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;pile&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;There are &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pile&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; objects in the pile.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;current_player&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s turn.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Get the number of objects to remove
&lt;/span&gt;        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;remove&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;How many objects will you take (1-3)? &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;remove&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;remove&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid move. You can only take 1, 2, or 3 objects.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;remove&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid move. You cannot take more objects than are in the pile.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid input. Please enter a number between 1 and 3.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;

        &lt;span class="c1"&gt;# Update the pile
&lt;/span&gt;        &lt;span class="n"&gt;pile&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;remove&lt;/span&gt;

        &lt;span class="c1"&gt;# Check if the game is over
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pile&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;current_player&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; is forced to take the last object and loses!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;

        &lt;span class="c1"&gt;# Switch players
&lt;/span&gt;        &lt;span class="n"&gt;current_player&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;player2&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current_player&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;player1&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;player1&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Game over. Thanks for playing!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Run the game
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;nim_game&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is a little logic exercise, that you can use to practice algorithms in Python.&lt;/p&gt;

&lt;p&gt;Also, you know the secret and will not be fooled by this game anymore, have fun!&lt;/p&gt;

</description>
      <category>python</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>Create spot instances on GCP &amp; AWS</title>
      <dc:creator>Jérôme Dx</dc:creator>
      <pubDate>Mon, 13 Jan 2025 18:00:00 +0000</pubDate>
      <link>https://dev.to/jdxlabs/create-spot-instances-on-gcp-aws-57b8</link>
      <guid>https://dev.to/jdxlabs/create-spot-instances-on-gcp-aws-57b8</guid>
      <description>&lt;p&gt;When you create virtual machines on Cloud providers, the price depends on the size on the machine and the region where you create it.&lt;/p&gt;

&lt;p&gt;You have the possibility to reserve capacity for a long period of time (1 year for instance), to have reductions from the provider.&lt;/p&gt;

&lt;p&gt;Another way to have reductions is to get Spot instances : it offers reduced price machines based on spare resources not used by other machines. &lt;/p&gt;

&lt;p&gt;The advantage is that you have very interesting price for you virtual machines, the downside is that you should consider this resources can break at any moment.&lt;/p&gt;

&lt;p&gt;For developement and testing environments, that’s a very good option. &lt;/p&gt;

&lt;p&gt;You have to handle the automated rebuild of the instances to work properly. That’s why we will build a Managed Instance Group on GCP and an Autoscaling Group on AWS.&lt;/p&gt;

&lt;p&gt;We are going to see how to implement that on both providers.&lt;/p&gt;

&lt;h2&gt;
  
  
  On Google Cloud
&lt;/h2&gt;

&lt;p&gt;First, you need to create an Instance Template, in the Compute Engine section :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqtq9u79gcginqz3mqarh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqtq9u79gcginqz3mqarh.png" alt="gcp step 1" width="724" height="215"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give a name to this Instance Template, and select a region (we choose one where there are free credits) : &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxvhgovbqrquvim4dqybt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxvhgovbqrquvim4dqybt.png" alt="gcp step 2" width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We choose e2-micro instance (General purpose with 1 Gb RAM), we can see that the cost is very low for one month, including storage : $3.44 :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F66e912buzfcluiflscin.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F66e912buzfcluiflscin.png" alt="gcp step 3" width="800" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can set some firewall rules : &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F70431imb3h1modkntvq1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F70431imb3h1modkntvq1.png" alt="gcp step 4" width="453" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And assign to your prefered VPC, then create :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj6b8leozt0kh1v33md3l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj6b8leozt0kh1v33md3l.png" alt="gcp step 5" width="557" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you will create a MIG (Managed Instance Group), to create the VMs according to this template :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmtma33byamja98x1ahs3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmtma33byamja98x1ahs3.png" alt="gcp step 6" width="800" height="166"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a stateless Instance Group, give a name and select the template :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxshdxni9jsei22m4ju0x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxshdxni9jsei22m4ju0x.png" alt="gcp step 7" width="800" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Set a location with multiple zones, set an Autoscaling to have permanently 2 machines running, then create the MIG :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkyeax51pdpmgwduygqan.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkyeax51pdpmgwduygqan.png" alt="gcp step 8" width="800" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you can access your VMs, by clicking “Connect SSH” : &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fooc6bngw55o7uznv4u8h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fooc6bngw55o7uznv4u8h.png" alt="gcp step 9" width="800" height="131"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  On AWS
&lt;/h2&gt;

&lt;p&gt;First, you need to create a Launch Template, in the EC2 section :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz2udxlzwe62jspl5y4bv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz2udxlzwe62jspl5y4bv.png" alt="aws step 1" width="800" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give a name to this Launch Template :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1r3uh7b331g32ye8sb3w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1r3uh7b331g32ye8sb3w.png" alt="aws step 2" width="792" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select an AMI from the catalog, Amazon Linux will allow to easily connect with session manager, and Arm will use less resources and cheaper :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flymmhgxf3yjivbfk00oq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flymmhgxf3yjivbfk00oq.png" alt="aws step 3" width="800" height="259"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select t4g.nano, that is an optimized general purpose instance, with a base price of 0.0046 USD per hour :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F14ml16jfabju3r1cuac6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F14ml16jfabju3r1cuac6.png" alt="aws step 4" width="800" height="225"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select the VPC and Security group you want to use (for the SG, just allow All traffic in Outbound, for now) : &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy2vqb5kub3eqigyqgb3o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy2vqb5kub3eqigyqgb3o.png" alt="aws step 5" width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Specify a tag “Name” for your instances to recognize them in the list later :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fliusbxg554dnxzzlozv0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fliusbxg554dnxzzlozv0.png" alt="aws step 6" width="800" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Advanced details, specify an IAM role for SSM acces, and that you want Spot instances, then create the template :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftal2zrvj1faxzp2kub8n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftal2zrvj1faxzp2kub8n.png" alt="aws step 7.1" width="800" height="316"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4y9078e8l5og4kywyqfr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4y9078e8l5og4kywyqfr.png" alt="aws step 7.2" width="800" height="101"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F72o024pieuze9hhjpamz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F72o024pieuze9hhjpamz.png" alt="aws step 7.3" width="489" height="147"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, create an Auto Scaling Group (ASG) :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwzx96uf82hvc4q96vwlx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwzx96uf82hvc4q96vwlx.png" alt="aws step 8" width="800" height="162"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Name it and select the template just created :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxlve0qcve3yo5y858mxv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxlve0qcve3yo5y858mxv.png" alt="aws step 9" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select the network options you prefer :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffx0sp4ud9iigohx57koq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffx0sp4ud9iigohx57koq.png" alt="aws step 10" width="800" height="594"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select the scaling policies you want, then you can create the ASG :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F072cnd2h24zpatvqftch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F072cnd2h24zpatvqftch.png" alt="aws step 11" width="800" height="602"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you can access your VMs, using Session Manager :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk4y2akjcimwdlfmc92ol.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk4y2akjcimwdlfmc92ol.png" alt="aws step 12" width="800" height="257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You can see that this mechanism is really similar on both of these cloud providers and Spot instances are really easy to implement.&lt;/p&gt;

&lt;p&gt;Of course, the best option will be to automate it an IaC tool like Terraform or OpenTofu and to optimize it according to your needs.&lt;/p&gt;

&lt;p&gt;You now have the keys to implement them on your projects, to have low-cost computing resources for any development objective.&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>finops</category>
      <category>googlecloud</category>
      <category>aws</category>
    </item>
    <item>
      <title>Set budget alerts on GCP &amp; AWS</title>
      <dc:creator>Jérôme Dx</dc:creator>
      <pubDate>Mon, 16 Dec 2024 15:28:19 +0000</pubDate>
      <link>https://dev.to/jdxlabs/set-budget-alerts-on-gcp-aws-42lc</link>
      <guid>https://dev.to/jdxlabs/set-budget-alerts-on-gcp-aws-42lc</guid>
      <description>&lt;p&gt;To manage costs on your cloud infrastructure, you can use an external tool (like &lt;a href="https://dev.to/jdxlabs/tailwarden-3d83"&gt;Tailwarden&lt;/a&gt; for instance), but you can also work with native tools from your cloud provider.&lt;/p&gt;

&lt;p&gt;This is the goal of this article, we will see how to do it simply on Google Cloud and AWS.&lt;/p&gt;

&lt;p&gt;The main advantages are that you will be very close to the vendor's philosophy and you will limit the number of tools you use.&lt;/p&gt;

&lt;h2&gt;
  
  
  On Google Cloud
&lt;/h2&gt;

&lt;p&gt;The goal here is simply to set a budget limit and you will be alerted if it is exceeded.&lt;/p&gt;

&lt;p&gt;First, go to the “Budget &amp;amp; alerts” section and clic on “Create a budget” :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw1j9zhybesytqlmctt0f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw1j9zhybesytqlmctt0f.png" alt="gcp step 1" width="800" height="215"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : You should select the Billing account associated to the project you want to manage.&lt;/p&gt;

&lt;p&gt;Then enter a name for your alert and delimit according to your needs, by projects and services (in our case we will make a global alert) :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbpswzt68cxhitgsd0ic2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbpswzt68cxhitgsd0ic2.png" alt="gcp step 2" width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select an amount to be alerted :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkz5rkjz2m6p3h3qmzllg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkz5rkjz2m6p3h3qmzllg.png" alt="gcp step 3" width="800" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can configure some thresholds and define who receives the alerts (the users can be setup in the Billing account management section) :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fftyuy6nrt37yfj7rkpej.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fftyuy6nrt37yfj7rkpej.png" alt="gcp step 4" width="564" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now your alert is ready and you will be notified if necessary :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0pye7u7shq17g40lnukd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0pye7u7shq17g40lnukd.png" alt="gcp step 5" width="800" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  On AWS
&lt;/h2&gt;

&lt;p&gt;First, go to the “Billing and Cost Management” section and clic on “Create budget” :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnb3dsubc6hqubuq7xc64.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnb3dsubc6hqubuq7xc64.png" alt="aws step 1" width="800" height="111"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then choose the template “Monthly cost budget” and enter a name for your alert :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffmegfysztyjn884iv79b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffmegfysztyjn884iv79b.png" alt="aws step 2" width="800" height="282"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select an amount to be alerted and email recipients, by default this template applies to all AWS services in the current account, and thresolds are defined (you can customize them later) :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjef3mf5moq3n7xxmq28r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjef3mf5moq3n7xxmq28r.png" alt="aws step 3" width="800" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now your alert is ready and you will be notified if necessary :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft4g31wmr76jd95vlg6pp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft4g31wmr76jd95vlg6pp.png" alt="aws step 4" width="800" height="136"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You now have the keys to manage your budget alerts simply on these two cloud providers.&lt;/p&gt;

&lt;p&gt;The advantage with native tools is that you have reduced costs and you directly adhere to the philosophy of the cloud provider. In return, you will not have a centralized interface for a multi-cloud context.&lt;/p&gt;

&lt;p&gt;It's now up to you to decide what is most interesting in your case.&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>finops</category>
      <category>googlecloud</category>
      <category>aws</category>
    </item>
    <item>
      <title>Bootstrap your projects with Docker init</title>
      <dc:creator>Jérôme Dx</dc:creator>
      <pubDate>Mon, 18 Nov 2024 18:00:00 +0000</pubDate>
      <link>https://dev.to/jdxlabs/bootstrap-your-projects-with-docker-init-1po3</link>
      <guid>https://dev.to/jdxlabs/bootstrap-your-projects-with-docker-init-1po3</guid>
      <description>&lt;p&gt;In may 2023, &lt;a href="https://www.docker.com/blog/docker-init-initialize-dockerfiles-and-compose-files-with-a-single-cli-command/" rel="noopener noreferrer"&gt;Docker announced&lt;/a&gt; a new command line &lt;code&gt;docker init&lt;/code&gt;, that could simplify your life when creating new projects.&lt;/p&gt;

&lt;p&gt;It is aimed to quickly &lt;strong&gt;generate Dockerfile&lt;/strong&gt; and &lt;strong&gt;Docker-compose file&lt;/strong&gt; for your projects, following the best practices pushed by the editor himself.&lt;/p&gt;

&lt;p&gt;Let's see how it works, with a &lt;strong&gt;simple example&lt;/strong&gt;, running on &lt;a href="https://flask.palletsprojects.com/" rel="noopener noreferrer"&gt;Flask&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the app
&lt;/h2&gt;

&lt;p&gt;Create a &lt;code&gt;my-api.py&lt;/code&gt; file :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/python3&lt;/span&gt;
from flask import Flask, jsonify

app &lt;span class="o"&gt;=&lt;/span&gt; Flask&lt;span class="o"&gt;(&lt;/span&gt;__name__&lt;span class="o"&gt;)&lt;/span&gt;

@app.route&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
def hello_world&lt;span class="o"&gt;()&lt;/span&gt;:
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;"API is running..."&lt;/span&gt;

@app.route&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/users"&lt;/span&gt;, &lt;span class="nv"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;
def caracters&lt;span class="o"&gt;()&lt;/span&gt;:
    &lt;span class="k"&gt;return &lt;/span&gt;jsonify&lt;span class="o"&gt;({&lt;/span&gt;
        &lt;span class="s2"&gt;"users"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
            &lt;span class="s2"&gt;"Luke"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Leia"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Han"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Chewi"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Darth"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Obi"&lt;/span&gt;,
        &lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="o"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;__name__ &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'__main__'&lt;/span&gt;:
    app.run&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3000, &lt;span class="nv"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;True&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a &lt;code&gt;requirements.txt&lt;/code&gt; file :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flask&amp;gt;&lt;span class="o"&gt;=&lt;/span&gt;2.2.2
gunicorn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Generate the files
&lt;/h2&gt;

&lt;p&gt;Execute &lt;code&gt;docker init&lt;/code&gt; and answer the questions.&lt;/p&gt;

&lt;p&gt;It will generate you the following files :&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Dockerfile&lt;/code&gt; - The instructions to build your image&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# syntax=docker/dockerfile:1&lt;/span&gt;

&lt;span class="c"&gt;# Comments are provided throughout this file to help you get started.&lt;/span&gt;
&lt;span class="c"&gt;# If you need more help, visit the Dockerfile reference guide at&lt;/span&gt;
&lt;span class="c"&gt;# https://docs.docker.com/go/dockerfile-reference/&lt;/span&gt;

&lt;span class="c"&gt;# Want to help us make this template better? Share your feedback here: https://forms.gle/ybq9Krt8jtBL3iCk7&lt;/span&gt;

ARG &lt;span class="nv"&gt;PYTHON_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3.12.4
FROM python:&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PYTHON_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-slim&lt;/span&gt; as base

&lt;span class="c"&gt;# Prevents Python from writing pyc files.&lt;/span&gt;
ENV &lt;span class="nv"&gt;PYTHONDONTWRITEBYTECODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1

&lt;span class="c"&gt;# Keeps Python from buffering stdout and stderr to avoid situations where&lt;/span&gt;
&lt;span class="c"&gt;# the application crashes without emitting any logs due to buffering.&lt;/span&gt;
ENV &lt;span class="nv"&gt;PYTHONUNBUFFERED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1

WORKDIR /app

&lt;span class="c"&gt;# Create a non-privileged user that the app will run under.&lt;/span&gt;
&lt;span class="c"&gt;# See https://docs.docker.com/go/dockerfile-user-best-practices/&lt;/span&gt;
ARG &lt;span class="nv"&gt;UID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10001
RUN adduser &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--disabled-password&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--gecos&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--home&lt;/span&gt; &lt;span class="s2"&gt;"/nonexistent"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--shell&lt;/span&gt; &lt;span class="s2"&gt;"/sbin/nologin"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--no-create-home&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--uid&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;UID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    appuser

&lt;span class="c"&gt;# Download dependencies as a separate step to take advantage of Docker's caching.&lt;/span&gt;
&lt;span class="c"&gt;# Leverage a cache mount to /root/.cache/pip to speed up subsequent builds.&lt;/span&gt;
&lt;span class="c"&gt;# Leverage a bind mount to requirements.txt to avoid having to copy them into&lt;/span&gt;
&lt;span class="c"&gt;# into this layer.&lt;/span&gt;
RUN &lt;span class="nt"&gt;--mount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cache,target&lt;span class="o"&gt;=&lt;/span&gt;/root/.cache/pip &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--mount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;bind&lt;/span&gt;,source&lt;span class="o"&gt;=&lt;/span&gt;requirements.txt,target&lt;span class="o"&gt;=&lt;/span&gt;requirements.txt &lt;span class="se"&gt;\&lt;/span&gt;
    python &lt;span class="nt"&gt;-m&lt;/span&gt; pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt

&lt;span class="c"&gt;# Switch to the non-privileged user to run the application.&lt;/span&gt;
USER appuser

&lt;span class="c"&gt;# Copy the source code into the container.&lt;/span&gt;
COPY &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# Expose the port that the application listens on.&lt;/span&gt;
EXPOSE 3000

&lt;span class="c"&gt;# Run the application.&lt;/span&gt;
CMD gunicorn &lt;span class="s1"&gt;'my-api:app'&lt;/span&gt; &lt;span class="nt"&gt;--bind&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.0.0.0:3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;.dockerignore&lt;/code&gt; - The files you don’t want to copy to your container&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Include any files or directories that you don't want to be copied to your&lt;/span&gt;
&lt;span class="c"&gt;# container here (e.g., local build artifacts, temporary files, etc.).&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# For more help, visit the .dockerignore file reference guide at&lt;/span&gt;
&lt;span class="c"&gt;# https://docs.docker.com/go/build-context-dockerignore/&lt;/span&gt;

&lt;span class="k"&gt;**&lt;/span&gt;/.DS_Store
&lt;span class="k"&gt;**&lt;/span&gt;/__pycache__
&lt;span class="k"&gt;**&lt;/span&gt;/.venv
&lt;span class="k"&gt;**&lt;/span&gt;/.classpath
&lt;span class="k"&gt;**&lt;/span&gt;/.dockerignore
&lt;span class="k"&gt;**&lt;/span&gt;/.env
&lt;span class="k"&gt;**&lt;/span&gt;/.git
&lt;span class="k"&gt;**&lt;/span&gt;/.gitignore
&lt;span class="k"&gt;**&lt;/span&gt;/.project
&lt;span class="k"&gt;**&lt;/span&gt;/.settings
&lt;span class="k"&gt;**&lt;/span&gt;/.toolstarget
&lt;span class="k"&gt;**&lt;/span&gt;/.vs
&lt;span class="k"&gt;**&lt;/span&gt;/.vscode
&lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.&lt;span class="k"&gt;*&lt;/span&gt;proj.user
&lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.dbmdl
&lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.jfm
&lt;span class="k"&gt;**&lt;/span&gt;/bin
&lt;span class="k"&gt;**&lt;/span&gt;/charts
&lt;span class="k"&gt;**&lt;/span&gt;/docker-compose&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;**&lt;/span&gt;/compose.y&lt;span class="k"&gt;*&lt;/span&gt;ml
&lt;span class="k"&gt;**&lt;/span&gt;/Dockerfile&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;**&lt;/span&gt;/node_modules
&lt;span class="k"&gt;**&lt;/span&gt;/npm-debug.log
&lt;span class="k"&gt;**&lt;/span&gt;/obj
&lt;span class="k"&gt;**&lt;/span&gt;/secrets.dev.yaml
&lt;span class="k"&gt;**&lt;/span&gt;/values.dev.yaml
LICENSE
README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;README.Docker.md&lt;/code&gt; - The Readme associated to Docker elements&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;### Building and running your application&lt;/span&gt;

When you&lt;span class="s1"&gt;'re ready, start your application by running:
`docker compose up --build`.

Your application will be available at http://localhost:3000.

### Deploying your application to the cloud

First, build your image, e.g.: `docker build -t myapp .`.
If your cloud uses a different CPU architecture than your development
machine (e.g., you are on a Mac M1 and your cloud provider is amd64),
you'&lt;/span&gt;ll want to build the image &lt;span class="k"&gt;for &lt;/span&gt;that platform, e.g.:
&lt;span class="sb"&gt;`&lt;/span&gt;docker build &lt;span class="nt"&gt;--platform&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;linux/amd64 &lt;span class="nt"&gt;-t&lt;/span&gt; myapp .&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

Then, push it to your registry, e.g. &lt;span class="sb"&gt;`&lt;/span&gt;docker push myregistry.com/myapp&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

Consult Docker&lt;span class="s1"&gt;'s [getting started](https://docs.docker.com/go/get-started-sharing/)
docs for more detail on building and pushing.

### References
* [Docker'&lt;/span&gt;s Python guide]&lt;span class="o"&gt;(&lt;/span&gt;https://docs.docker.com/language/python/&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;compose.yaml&lt;/code&gt; - The file to execute Docker-compose&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Comments are provided throughout this file to help you get started.&lt;/span&gt;
&lt;span class="c"&gt;# If you need more help, visit the Docker Compose reference guide at&lt;/span&gt;
&lt;span class="c"&gt;# https://docs.docker.com/go/compose-spec-reference/&lt;/span&gt;

&lt;span class="c"&gt;# Here the instructions define your application as a service called "server".&lt;/span&gt;
&lt;span class="c"&gt;# This service is built from the Dockerfile in the current directory.&lt;/span&gt;
&lt;span class="c"&gt;# You can add other services your application may depend on here, such as a&lt;/span&gt;
&lt;span class="c"&gt;# database or a cache. For examples, see the Awesome Compose repository:&lt;/span&gt;
&lt;span class="c"&gt;# https://github.com/docker/awesome-compose&lt;/span&gt;
services:
  server:
    build:
      context: &lt;span class="nb"&gt;.&lt;/span&gt;
    ports:
      - 3000:3000

&lt;span class="c"&gt;# The commented out section below is an example of how to define a PostgreSQL&lt;/span&gt;
&lt;span class="c"&gt;# database that your application can use. `depends_on` tells Docker Compose to&lt;/span&gt;
&lt;span class="c"&gt;# start the database before your application. The `db-data` volume persists the&lt;/span&gt;
&lt;span class="c"&gt;# database data between container restarts. The `db-password` secret is used&lt;/span&gt;
&lt;span class="c"&gt;# to set the database password. You must create `db/password.txt` and add&lt;/span&gt;
&lt;span class="c"&gt;# a password of your choosing to it before running `docker compose up`.&lt;/span&gt;
&lt;span class="c"&gt;#     depends_on:&lt;/span&gt;
&lt;span class="c"&gt;#       db:&lt;/span&gt;
&lt;span class="c"&gt;#         condition: service_healthy&lt;/span&gt;
&lt;span class="c"&gt;#   db:&lt;/span&gt;
&lt;span class="c"&gt;#     image: postgres&lt;/span&gt;
&lt;span class="c"&gt;#     restart: always&lt;/span&gt;
&lt;span class="c"&gt;#     user: postgres&lt;/span&gt;
&lt;span class="c"&gt;#     secrets:&lt;/span&gt;
&lt;span class="c"&gt;#       - db-password&lt;/span&gt;
&lt;span class="c"&gt;#     volumes:&lt;/span&gt;
&lt;span class="c"&gt;#       - db-data:/var/lib/postgresql/data&lt;/span&gt;
&lt;span class="c"&gt;#     environment:&lt;/span&gt;
&lt;span class="c"&gt;#       - POSTGRES_DB=example&lt;/span&gt;
&lt;span class="c"&gt;#       - POSTGRES_PASSWORD_FILE=/run/secrets/db-password&lt;/span&gt;
&lt;span class="c"&gt;#     expose:&lt;/span&gt;
&lt;span class="c"&gt;#       - 5432&lt;/span&gt;
&lt;span class="c"&gt;#     healthcheck:&lt;/span&gt;
&lt;span class="c"&gt;#       test: [ "CMD", "pg_isready" ]&lt;/span&gt;
&lt;span class="c"&gt;#       interval: 10s&lt;/span&gt;
&lt;span class="c"&gt;#       timeout: 5s&lt;/span&gt;
&lt;span class="c"&gt;#       retries: 5&lt;/span&gt;
&lt;span class="c"&gt;# volumes:&lt;/span&gt;
&lt;span class="c"&gt;#   db-data:&lt;/span&gt;
&lt;span class="c"&gt;# secrets:&lt;/span&gt;
&lt;span class="c"&gt;#   db-password:&lt;/span&gt;
&lt;span class="c"&gt;#     file: db/password.txt&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Now you can launch your app
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Directly&lt;/strong&gt; on your machine :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;flask &lt;span class="nt"&gt;--user&lt;/span&gt;
flask &lt;span class="nt"&gt;--app&lt;/span&gt; my-api &lt;span class="nt"&gt;--debug&lt;/span&gt; run &lt;span class="nt"&gt;-p&lt;/span&gt; 3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;strong&gt;Docker&lt;/strong&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; my-api &lt;span class="nb"&gt;.&lt;/span&gt;
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:3000 &lt;span class="nt"&gt;--name&lt;/span&gt; my-api my-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;strong&gt;Docker-compose&lt;/strong&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker init
docker compose up &lt;span class="nt"&gt;--build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  What about Podman ?
&lt;/h1&gt;

&lt;p&gt;Nowadays, we can’t talk about Docker without mentioning it’s alternative &lt;a href="https://podman.io/" rel="noopener noreferrer"&gt;Podman&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Both provide very similar commands overall, but the Init command is an exception.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.podman.io/en/latest/markdown/podman-init.1.html" rel="noopener noreferrer"&gt;Podman-init&lt;/a&gt; has a different purpose : it creates a new container from an image and prepares it to run as a Podman container.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Docker-init is a handy little utility integrated into the command-line.&lt;/p&gt;

&lt;p&gt;Consider using it when you need to create new projects (or update old ones), it can save you a few precious minutes, while helping you to be compliant by following best practices.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>containers</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Create your K3S lab on Google Cloud</title>
      <dc:creator>Jérôme Dx</dc:creator>
      <pubDate>Mon, 21 Oct 2024 15:00:00 +0000</pubDate>
      <link>https://dev.to/jdxlabs/create-your-k3s-lab-on-google-cloud-2pim</link>
      <guid>https://dev.to/jdxlabs/create-your-k3s-lab-on-google-cloud-2pim</guid>
      <description>&lt;p&gt;If you study Kubernetes, it may interest you to have a little laboratory to experiment the concepts you learned.&lt;/p&gt;

&lt;p&gt;You can use a local solution, like &lt;a href="https://dev.to/jdxlabs/a-local-kubernetes-cluster-in-seconds-with-kind-31lc"&gt;Kind&lt;/a&gt;, fast and easy to handle, but it may be interesting too to make it work on a Cloud provider, closer to production context.&lt;/p&gt;

&lt;h1&gt;
  
  
  Our choices
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Google Cloud
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://cloud.google.com/?hl=en" rel="noopener noreferrer"&gt;Google Cloud&lt;/a&gt; is the only one among the major providers to offer a free tier for life (unless the terms and conditions change, which remains to be seen, but for now we can enjoy it).&lt;/p&gt;

&lt;p&gt;Among the &lt;a href="https://cloud.google.com/free/docs/free-cloud-features?hl=en#free-tier" rel="noopener noreferrer"&gt;services eligible for the Free Tier&lt;/a&gt;, here are those which will interest us :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Compute Engine&lt;/strong&gt; : 1 non-preemptible e2-micro VM instance in South Carolina (us-east1), the region closest to France&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Storage&lt;/strong&gt; :  5 GB-months of regional storage (us-east1) per month, which is more than enough storage capacity for a homelab&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Artifact Registry&lt;/strong&gt; : 0.5 GB storage per month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secret Manager&lt;/strong&gt; : 6 active secret versions per month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Logging&lt;/strong&gt; : Free monthly logging allotment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Monitoring&lt;/strong&gt; : Free monthly metrics allotment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Shell&lt;/strong&gt; : Free access to Cloud Shell, including 5 GB of persistent disk storage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are 3 regions eligible for this free tier but living in France, I personally chose the closest geographically : us-east1.&lt;/p&gt;

&lt;p&gt;In any case, the prices are interesting on this provider, we will see that we can also use &lt;a href="https://cloud.google.com/spot-vms" rel="noopener noreferrer"&gt;spot instances&lt;/a&gt; to reduce costs.&lt;/p&gt;

&lt;p&gt;This lab will also be an opportunity to improve your skills on Google Cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  K3S
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://k3s.io/" rel="noopener noreferrer"&gt;K3S&lt;/a&gt; is a Kubernetes distribution made by &lt;a href="https://www.rancher.com/" rel="noopener noreferrer"&gt;Rancher&lt;/a&gt;, made to be as lightweight as possible while being compatible with Kubernetes production standards.&lt;/p&gt;

&lt;p&gt;This is the perfect tool for our lab, because we want to have the lightest instances possible to keep costs down, while having the ability to test production concepts. &lt;/p&gt;

&lt;p&gt;Even GKE (Google Kubernetes Engine) will cost you at least around $70 per month.&lt;/p&gt;

&lt;p&gt;With K3S you can simply setup an e2-micro instance, with the free-tier (but it will be very limited). &lt;/p&gt;

&lt;p&gt;If you want more capacity, you can create an e2-small instance, which will cost you less than $10 per month (with spot instance).&lt;/p&gt;

&lt;p&gt;K3S will still be interesting for all the usecases where you want to reduce the size of the instances.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenTofu
&lt;/h2&gt;

&lt;p&gt;If you haven't been following the news, Hashicorp has changed the license of Terraform and has had some issues with the community. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://opentofu.org/" rel="noopener noreferrer"&gt;OpenTofu&lt;/a&gt; is a fork of Terraform, aimed to remain open-source and the changelog is driven by the community. &lt;/p&gt;

&lt;p&gt;Currently, at version 1.8, OpenTofu is slightly the same as Terraform, just change the binary, you can install it with &lt;a href="https://github.com/tofuutils/tenv" rel="noopener noreferrer"&gt;Tenv&lt;/a&gt; (differences will appear as the respective roadmaps will evolve).&lt;/p&gt;

&lt;p&gt;This lab is therefore an opportunity to familiarize yourself with the use of this tool.&lt;/p&gt;

&lt;h1&gt;
  
  
  Setting up the lab
&lt;/h1&gt;

&lt;p&gt;Now we will see how to implement this solution, the usecase is to deploy the resources on Google Cloud, create the K3S cluster on the VM, then create an API accessible from outside.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the Google Cloud project
&lt;/h2&gt;

&lt;p&gt;First, if you haven't already, you need to &lt;a href="https://developers.google.com/workspace/guides/create-project?hl=en" rel="noopener noreferrer"&gt;create a Google Cloud project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At the creation of the project, you can activate a &lt;a href="https://cloud.google.com/free/docs/free-cloud-features?hl=en#free-trial" rel="noopener noreferrer"&gt;90-day $300 Free Trial offer&lt;/a&gt;, on a large panel of services, with some limitations though.&lt;/p&gt;

&lt;p&gt;After this period ends, you will still be eligible for the free tier we already mentioned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy the infrastructure
&lt;/h2&gt;

&lt;p&gt;Here are the resources you will create with OpenTofu :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Compute&lt;/span&gt;
&lt;span class="c1"&gt;// ----------------------------------&lt;/span&gt;

&lt;span class="c1"&gt;// The instance for K3S&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"google_compute_instance"&lt;/span&gt; &lt;span class="s2"&gt;"k3s"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"k3s-vm-1"&lt;/span&gt;
  &lt;span class="nx"&gt;machine_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"e2-small"&lt;/span&gt; &lt;span class="c1"&gt;# This instance will have 2 Gb of RAM&lt;/span&gt;
  &lt;span class="nx"&gt;zone&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;zone&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"web"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="c1"&gt;// Set the boot disk and the image (10 Gb)&lt;/span&gt;
  &lt;span class="nx"&gt;boot_disk&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;initialize_params&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;image&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"debian-cloud/debian-12"&lt;/span&gt;
      &lt;span class="nx"&gt;size&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Configuration to be a Spot Instance, to reduce costs&lt;/span&gt;
  &lt;span class="nx"&gt;scheduling&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;preemptible&lt;/span&gt;                 &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="nx"&gt;automatic_restart&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;provisioning_model&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"SPOT"&lt;/span&gt;
    &lt;span class="nx"&gt;instance_termination_action&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"STOP"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// attach a disk for K3S&lt;/span&gt;
  &lt;span class="nx"&gt;attached_disk&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;google_compute_disk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;k3s_disk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
    &lt;span class="nx"&gt;device_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"k3s-disk"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;network_interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;network&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"default"&lt;/span&gt;

    &lt;span class="nx"&gt;access_config&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Ephemeral public IP&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;labels&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;env&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;
    &lt;span class="nx"&gt;region&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;region&lt;/span&gt;
    &lt;span class="nx"&gt;app&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;app_name&lt;/span&gt;
    &lt;span class="nx"&gt;sensitive&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"false"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;metadata_startup_script&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"scripts/k3s-vm-startup.sh"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;allow_stopping_for_update&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Firewall&lt;/span&gt;
&lt;span class="c1"&gt;// ----------------------------------&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"google_compute_firewall"&lt;/span&gt; &lt;span class="s2"&gt;"allow_http"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"allow-http"&lt;/span&gt;
  &lt;span class="nx"&gt;network&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"default"&lt;/span&gt;

  &lt;span class="nx"&gt;allow&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;ports&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="s2"&gt;"80"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"443"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// http/https&lt;/span&gt;
      &lt;span class="s2"&gt;"30080"&lt;/span&gt;      &lt;span class="c1"&gt;// ports opened to access the API via NodePort&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;source_ranges&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;target_tags&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"web"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Storage&lt;/span&gt;
&lt;span class="c1"&gt;// ----------------------------------&lt;/span&gt;

&lt;span class="c1"&gt;// The disk attached to the instance (15 Gb)&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"google_compute_disk"&lt;/span&gt; &lt;span class="s2"&gt;"k3s_disk"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"k3s-disk"&lt;/span&gt;
  &lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"pd-standard"&lt;/span&gt;
  &lt;span class="nx"&gt;zone&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;zone&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// The bucket where you can store other data&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"google_storage_bucket"&lt;/span&gt; &lt;span class="s2"&gt;"k3s-storage"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_name&lt;/span&gt;
  &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;region&lt;/span&gt;

  &lt;span class="nx"&gt;labels&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;env&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;
    &lt;span class="nx"&gt;region&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;region&lt;/span&gt;
    &lt;span class="nx"&gt;app&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;app_name&lt;/span&gt;
    &lt;span class="nx"&gt;sensitive&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"false"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Registry&lt;/span&gt;
&lt;span class="c1"&gt;// ----------------------------------&lt;/span&gt;

&lt;span class="c1"&gt;// The Artifact Registry repository for our app&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"google_artifact_registry_repository"&lt;/span&gt; &lt;span class="s2"&gt;"app-repo"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;location&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-east1"&lt;/span&gt;
  &lt;span class="nx"&gt;repository_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"app-repo"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"App Docker repository"&lt;/span&gt;
  &lt;span class="nx"&gt;format&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"DOCKER"&lt;/span&gt;

  &lt;span class="nx"&gt;docker_config&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;immutable_tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Env vars&lt;/span&gt;
&lt;span class="c1"&gt;// ----------------------------------&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"env"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dev"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Environment"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"region"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-east1"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"GCP Region"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"zone"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-east1-a"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"GCP Zone"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"app_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;name-of-your-cluster&amp;gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Application name"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"project_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;name-of-your-gcp-project&amp;gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"GCP Project name"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"bucket_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;name-of-your-bucket&amp;gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Bucket name"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Provider&lt;/span&gt;
&lt;span class="c1"&gt;// ----------------------------------&lt;/span&gt;

&lt;span class="c1"&gt;// Connect to the GCP project&lt;/span&gt;
&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"google"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;credentials&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;my-gcp-creds&amp;gt;.json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;project&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project_name&lt;/span&gt;
  &lt;span class="nx"&gt;region&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;region&lt;/span&gt;
  &lt;span class="nx"&gt;zone&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;zone&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;# Use a shared bucket (wich allows collaborative work)&lt;/span&gt;
  &lt;span class="nx"&gt;backend&lt;/span&gt; &lt;span class="s2"&gt;"gcs"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;bucket&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;my-bucket-for-states&amp;gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;prefix&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"k3s-infra"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Set versions&lt;/span&gt;
  &lt;span class="nx"&gt;required_version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;gt;=1.8.0"&lt;/span&gt;
  &lt;span class="nx"&gt;required_providers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;google&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"hashicorp/google"&lt;/span&gt;
      &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;gt;=4.0.0"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The startup script (in “scripts/k3s-vm-startup.sh”), which will install K3S automatically :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="c"&gt;# Format the disk if not already formatted&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; lsblk | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="s2"&gt;"/mnt/disks/k3s"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;mkfs.ext4 &lt;span class="nt"&gt;-m&lt;/span&gt; 0 &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="nv"&gt;lazy_itable_init&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0,lazy_journal_init&lt;span class="o"&gt;=&lt;/span&gt;0,discard /dev/disk/by-id/google-k3s-disk
    &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /mnt/disks/k3s
    mount &lt;span class="nt"&gt;-o&lt;/span&gt; discard,defaults /dev/disk/by-id/google-k3s-disk /mnt/disks/k3s
    &lt;span class="nb"&gt;chmod &lt;/span&gt;a+w /mnt/disks/k3s
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# ensure only run once&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; /etc/startup_was_launched &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then &lt;/span&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;0&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;fi
&lt;/span&gt;&lt;span class="nb"&gt;touch&lt;/span&gt; /etc/startup_was_launched

&lt;span class="c"&gt;# apt install&lt;/span&gt;
apt update
apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; ncdu htop

&lt;span class="c"&gt;# helm install&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
&lt;span class="nb"&gt;chmod &lt;/span&gt;700 get_helm.sh
/bin/bash get_helm.sh

&lt;span class="c"&gt;# bashrc config&lt;/span&gt;
&lt;span class="nv"&gt;rc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/root/.bashrc
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"alias l='ls -lah'"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$rc&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"alias ll='ls -lh'"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$rc&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"alias k=kubectl"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$rc&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"export dry='--dry-run=client'"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$rc&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"export o='-oyaml'"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$rc&lt;/span&gt;

&lt;span class="c"&gt;# Install k3s and configure it to use the persistent disk for data storage&lt;/span&gt;
curl &lt;span class="nt"&gt;-sfL&lt;/span&gt; https://get.k3s.io | &lt;span class="nv"&gt;INSTALL_K3S_EXEC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"--data-dir /mnt/disks/k3s"&lt;/span&gt; sh -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a &lt;a href="https://cloud.google.com/iam/docs/service-account-overview" rel="noopener noreferrer"&gt;ServiceAccount&lt;/a&gt; to connect to GCP with OpenTofu, restricted to this services :&lt;/p&gt;

&lt;p&gt;(For least privileges compliance, you must restrict the elements with &lt;a href="https://cloud.google.com/iam/docs/conditions-overview?hl=en" rel="noopener noreferrer"&gt;IAM conditions&lt;/a&gt;)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Artifact Registry Administrator&lt;/li&gt;
&lt;li&gt;Artifact Registry Repository Administrator&lt;/li&gt;
&lt;li&gt;Cloud Functions Admin&lt;/li&gt;
&lt;li&gt;Compute Admin&lt;/li&gt;
&lt;li&gt;Compute Instance Admin&lt;/li&gt;
&lt;li&gt;Compute Network Admin&lt;/li&gt;
&lt;li&gt;Compute Security Admin&lt;/li&gt;
&lt;li&gt;Secret Manager Admin&lt;/li&gt;
&lt;li&gt;Service Account User&lt;/li&gt;
&lt;li&gt;Storage Admin&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, the commands to create the infrastructure :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# OpenTofu setup&lt;/span&gt;
tofu init &lt;span class="nt"&gt;-get&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="nt"&gt;-upgrade&lt;/span&gt;
tofu workspace new dev
tofu workspace &lt;span class="k"&gt;select &lt;/span&gt;dev

&lt;span class="c"&gt;# Plan (to preview what will be changed)&lt;/span&gt;
tofu plan

&lt;span class="c"&gt;# Apply (to create the infrastructure described in the IaC code)&lt;/span&gt;
tofu apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Build the app
&lt;/h2&gt;

&lt;p&gt;Create a Dockerfile for your app, we will use the &lt;a href="https://httpbin.org/" rel="noopener noreferrer"&gt;HttpBin API&lt;/a&gt; which allows to test all the request we can make to a Rest API :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; python:3.12-slim&lt;/span&gt;

&lt;span class="c"&gt;# Install dependencies&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-cache-dir&lt;/span&gt; gunicorn httpbin

&lt;span class="c"&gt;# Expose the application port&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 80&lt;/span&gt;

&lt;span class="c"&gt;# Launch the application&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["gunicorn", "-b", "0.0.0.0:80", "httpbin:app"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make the build and push the image to Artifact Registry&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Build&lt;/span&gt;
docker build -t httpbin .

# Push to the registry
gcloud auth configure-docker us-east1-docker.pkg.dev
docker tag httpbin us-east1-docker.pkg.dev/&amp;lt;my-project&amp;gt;/app-repo/httpbin:v1
docker push us-east1-docker.pkg.dev/&amp;lt;my-project&amp;gt;/app-repo/httpbin:v1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Set the secret to connect to the registry
&lt;/h2&gt;

&lt;p&gt;Create a Service Account, with the right “Artifact Registry Reader”.&lt;/p&gt;

&lt;p&gt;It will allow you to pull the image from Kubernetes.&lt;/p&gt;

&lt;p&gt;First, connect to your instance :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud compute ssh &lt;span class="nt"&gt;--zone&lt;/span&gt; &lt;span class="s2"&gt;"us-east1-a"&lt;/span&gt; &lt;span class="s2"&gt;"k3s-vm-1"&lt;/span&gt; &lt;span class="nt"&gt;--project&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;my-project&amp;gt;”
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, store the credentials on Kubernetes like this :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;echo&lt;/span&gt; &lt;span class="nx"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;json_value&amp;gt;"&lt;/span&gt; &lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;registry_key&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;

&lt;span class="nx"&gt;k&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt; &lt;span class="nx"&gt;docker-registry&lt;/span&gt; &lt;span class="nx"&gt;artifact-read&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
    &lt;span class="nx"&gt;--docker-server&lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;us-east1-docker&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pkg&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dev&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
    &lt;span class="nx"&gt;--docker-username&lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;_json_key&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
    &lt;span class="nx"&gt;--docker-password&lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"$(cat registry_key.json)"&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
    &lt;span class="nx"&gt;--docker-email&lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;valid-email&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deploy the app on Kubernetes
&lt;/h2&gt;

&lt;p&gt;Here is the code to deploy your app :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# The deployment that will pull the image on Artifact Registry&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;httpbin&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;httpbin&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;httpbin&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;imagePullSecrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;artifact-read&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;httpbin&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-east1-docker.pkg.dev/&amp;lt;my-project&amp;gt;/app-repo/httpbin:v1&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="c1"&gt;# The Service, configured as a NodePort to allow external access on some ports&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;httpbin-service&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NodePort&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;nodePort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30080&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;httpbin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then deploy it :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# deploy the app&lt;/span&gt;
k apply &lt;span class="nt"&gt;-f&lt;/span&gt; httpbin.yaml

&lt;span class="c"&gt;# Ensure the app is running&lt;/span&gt;
k get po &lt;span class="nt"&gt;-w&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Access the API
&lt;/h2&gt;

&lt;p&gt;Once it’s running, you can access the API inside the VM :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-I&lt;/span&gt; http://localhost:30080/get
&lt;span class="c"&gt;# HTTP/1.1 200 OK&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or outside, from your local machine :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-I&lt;/span&gt; http://&amp;lt;my-ephemeral-ip&amp;gt;:30080/get
&lt;span class="c"&gt;# HTTP/1.1 200 OK&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;We’ve just seen how to deploy quickly and with minimal costs a modern lightweight Kubernetes on your Google Cloud project.&lt;/p&gt;

&lt;p&gt;There will be other workshops that may be interesting to improve this lab, like : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a Traefik reverse proxy to access to several apps&lt;/li&gt;
&lt;li&gt;Add Cloudflare to protect exposed urls&lt;/li&gt;
&lt;li&gt;Set a multi-masters, multi-workers pattern&lt;/li&gt;
&lt;li&gt;Set a Backup/Restore strategy&lt;/li&gt;
&lt;li&gt;Setup Cilium&lt;/li&gt;
&lt;li&gt;Add monitoring and alerting tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And many other things.&lt;/p&gt;

&lt;p&gt;Looking forward to exploring these different topics with you next time.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>k3s</category>
      <category>cloud</category>
      <category>iac</category>
    </item>
    <item>
      <title>Managing Cloud Costs and Security with Tailwarden</title>
      <dc:creator>Jérôme Dx</dc:creator>
      <pubDate>Mon, 09 Sep 2024 15:00:00 +0000</pubDate>
      <link>https://dev.to/jdxlabs/tailwarden-3d83</link>
      <guid>https://dev.to/jdxlabs/tailwarden-3d83</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Warning&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This article is kept as an archive;&lt;br&gt;unfortunately, the development of this service has been discontinued.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;When working on the cloud, the question of costs is essential.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.tailwarden.com/" rel="noopener noreferrer"&gt;Tailwarden&lt;/a&gt; is a tool designed to help you have a &lt;strong&gt;global supervision of your costs&lt;/strong&gt; and also supports you on the &lt;strong&gt;security part&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It supports the 3 main cloud providers (AWS, Google Cloud and Azure), it will be all the more effective in a &lt;strong&gt;multi-account&lt;/strong&gt; and &lt;a href="https://en.wikipedia.org/wiki/Hybrid_cloud_storage" rel="noopener noreferrer"&gt;&lt;strong&gt;hybrid strategy&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I will give you a demonstration of the different functionalities that the tool will offer you.&lt;/p&gt;

&lt;h1&gt;
  
  
  Connect your cloud accounts
&lt;/h1&gt;

&lt;p&gt;At the beginning, you have access to a "&lt;a href="https://help.tailwarden.com/en/articles/9006524-getting-started-with-tailwarden" rel="noopener noreferrer"&gt;Getting started&lt;/a&gt;".&lt;/p&gt;

&lt;p&gt;You will be able to connect your different accounts, in my case an AWS account and a GCP account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff3akrr508ft82423o4kx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff3akrr508ft82423o4kx.png" alt="Cloud Providers" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want detailled informations, you have to enable the &lt;a href="https://help.tailwarden.com/en/articles/8015522-connect-an-aws-account-get-granular-insights-on-costs" rel="noopener noreferrer"&gt;cost insight&lt;/a&gt; feature :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu0yum3jevsdqb03udcvf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu0yum3jevsdqb03udcvf.png" alt="Cost Insight" width="521" height="553"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  The main dashboard
&lt;/h1&gt;

&lt;p&gt;You will have direct access to the main dashboard, which gives you an overall view of your costs per month. &lt;/p&gt;

&lt;p&gt;You will be able to classify them by cloud provider, regions and resource types.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm28e9pb1fn5fmzkj2a1p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm28e9pb1fn5fmzkj2a1p.png" alt="The main dashboard" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  The assets inventory
&lt;/h1&gt;

&lt;p&gt;The inventory is &lt;a href="https://help.tailwarden.com/en/articles/8985633-discover-the-inventory-the-foundation-of-tailwarden" rel="noopener noreferrer"&gt;the heart of Tailwarden&lt;/a&gt;, that’s where you will find all the resources handled by the software. You can consult, classify them, know the cost of each one and export them for your needs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpqubjlk2mb637mv24f36.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpqubjlk2mb637mv24f36.png" alt="The inventory" width="800" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Create your first custom view
&lt;/h1&gt;

&lt;p&gt;From the inventory, you can apply filters, to obtain &lt;a href="https://help.tailwarden.com/en/articles/8899629-views-organize-your-cloud-infrastructure-effectively" rel="noopener noreferrer"&gt;Custom views&lt;/a&gt;, which will allow you to organize the vision of your infrastructure, according to the criteria that interest you.&lt;/p&gt;

&lt;p&gt;In the following example, I simply display the list of S3 buckets :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftfcoqy5lriobohuozpd1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftfcoqy5lriobohuozpd1.png" alt="Custom view" width="800" height="260"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Tagging
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Identify untagged resources
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://help.tailwarden.com/en/articles/9014973-step-1-assessing-your-current-tagging-landscape" rel="noopener noreferrer"&gt;Tags audit&lt;/a&gt; page will allow you to explore the tags of your resources.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzuktx838gefehr80sl54.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzuktx838gefehr80sl54.png" alt="Tags audit" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In order to find your untagged resources, you can create a Custom view by selecting the "Empty tags" filter :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fev9ylry33926lnyt7hc9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fev9ylry33926lnyt7hc9.png" alt="Empty tags filter" width="271" height="99"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Focj0mduk35000j2z69n6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Focj0mduk35000j2z69n6.png" alt="Empty tags" width="800" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Set a tagging strategy
&lt;/h2&gt;

&lt;p&gt;It is important to establish a tagging strategy, you can follow the &lt;a href="https://help.tailwarden.com/en/articles/9015011-step-0-definition-of-a-good-tagging-strategy" rel="noopener noreferrer"&gt;Tagging Best Practices&lt;/a&gt; shared by Tailwarden.&lt;/p&gt;

&lt;p&gt;We can discern 4 main categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Technical tags&lt;/li&gt;
&lt;li&gt;Automation tags&lt;/li&gt;
&lt;li&gt;Business tags&lt;/li&gt;
&lt;li&gt;Security tags&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Consider that your fleet will potentially be hybrid one day, it is better to put provider-agnostic tags.&lt;/p&gt;

&lt;p&gt;For the demonstration, we will choose a very basic tagging strategy, with this tags : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Env (Dev/Prod/Shared)&lt;/li&gt;
&lt;li&gt;Region&lt;/li&gt;
&lt;li&gt;Sensitive (true/false)&lt;/li&gt;
&lt;li&gt;Project (null by default)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can &lt;a href="https://help.tailwarden.com/en/articles/8922206-tag-management-policies" rel="noopener noreferrer"&gt;set a policy&lt;/a&gt; to show which resources are in compliance or not :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9mx9b4093nus6ktnqjvk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9mx9b4093nus6ktnqjvk.png" alt="Tag detection" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Apply and monitor your tagging strategy
&lt;/h2&gt;

&lt;p&gt;You can modify directly the provider’s tags, or define &lt;a href="https://help.tailwarden.com/en/articles/8909069-virtual-tags-simplifying-resource-organization-and-cost-allocation" rel="noopener noreferrer"&gt;virtual tags&lt;/a&gt; inside Tailwarden.&lt;/p&gt;

&lt;p&gt;Virtual tags allow you to quickly edit your resources in groups and to comply.&lt;/p&gt;

&lt;p&gt;You will then have the possibility to either synchronize the provider tags, or to apply a different strategy within the provider.&lt;/p&gt;

&lt;p&gt;Compliance is monitored and you have the possibility to put alerting, in case there are drifts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyw1q57xe2xh50mok627m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyw1q57xe2xh50mok627m.png" alt="Tag detection OK" width="800" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Enable Cost insights
&lt;/h1&gt;

&lt;p&gt;You must &lt;a href="https://help.tailwarden.com/en/articles/8015522-connect-an-aws-account-get-granular-insights-on-costs" rel="noopener noreferrer"&gt;setup CUR&lt;/a&gt; (Cost and Usage Report), to activate Cost Insights :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7jxivft1nna1yzhm97ys.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7jxivft1nna1yzhm97ys.png" alt="Enable CUR" width="565" height="557"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will allow for more cost detail, more accurately for your resources.&lt;/p&gt;

&lt;h1&gt;
  
  
  Create your first Cost report
&lt;/h1&gt;

&lt;p&gt;In the &lt;a href="https://help.tailwarden.com/en/articles/9038395-tailwarden-cost-explorer-guide" rel="noopener noreferrer"&gt;Cost Report&lt;/a&gt; section, you will have a global view on your costs, for each provider :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F627cz43gq5t6v0yjl9o8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F627cz43gq5t6v0yjl9o8.png" alt="Cost report" width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Set your first Budget alert
&lt;/h1&gt;

&lt;p&gt;From a view in the inventory, you have the possibity to &lt;a href="https://help.tailwarden.com/en/articles/8899741-alerts-proactive-cloud-management-for-precision-control" rel="noopener noreferrer"&gt;setup notifications&lt;/a&gt; by mail, on different triggers : &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5mormr2ibyj537aztyx9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5mormr2ibyj537aztyx9.png" alt="Notifications" width="513" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example, you can set an email notification when your overall costs exceed an amount you decide, withe the Budget alert:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmgbr1vjdkzi4oqc5sgzk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmgbr1vjdkzi4oqc5sgzk.png" alt="Budget alert" width="537" height="268"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  View Compliance insights
&lt;/h1&gt;

&lt;p&gt;In the Risk Assessment section, you can consult different &lt;a href="https://help.tailwarden.com/en/articles/9038272-understanding-compliance-frameworks-in-tailwarden" rel="noopener noreferrer"&gt;compliance frameworks&lt;/a&gt; to apply on your resources : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/securityhub/latest/userguide/cis-aws-foundations-benchmark.html#cis1v4-standard" rel="noopener noreferrer"&gt;AWS CIS (Center for Internet Security) v1.4.0&lt;/a&gt; : The security framework from AWS&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://gdpr-info.eu" rel="noopener noreferrer"&gt;GPDR (General Data Protection Regulation)&lt;/a&gt; : The european privacy data protection&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.pcisecuritystandards.org/standards/pci-dss" rel="noopener noreferrer"&gt;PCI DSS (Payment Card Industry Data Security Standard)&lt;/a&gt; : A framework you must follow if you host credit card informations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fys4lo6m9e4lqc89ha32w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fys4lo6m9e4lqc89ha32w.png" alt="Security compliance rules" width="800" height="417"&gt;&lt;/a&gt;    &lt;/p&gt;

&lt;h1&gt;
  
  
  Custom dashboards
&lt;/h1&gt;

&lt;p&gt;In the Reports sections, you can set specific dashboards for your needs, you can totally customize your dashboards and widgets, but you can also select pre-defined templates.&lt;/p&gt;

&lt;p&gt;For instance, there is an Invoice Breakdown dashboard, to see the costs specific to each resource :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9fvyvcgf5sf83ecne3kd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9fvyvcgf5sf83ecne3kd.png" alt="Custom dashboard" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Pricing
&lt;/h1&gt;

&lt;p&gt;Tailwarden is a managed service aimed at businesses, it offers a starter package at $500/month, with additional costs if there are more than 3 cloud accounts.&lt;/p&gt;

&lt;p&gt;It can also offer more support for larger companies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz7m5lprjc0zd5yy7m3cn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz7m5lprjc0zd5yy7m3cn.png" alt="Pricing" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another option is a similar product offered by Tailwarden, which is open source. It will offer a few different options and the hosting part will be up to you. This is &lt;a href="https://www.komiser.io/" rel="noopener noreferrer"&gt;&lt;strong&gt;Komiser&lt;/strong&gt;&lt;/a&gt;, whose code is available on &lt;a href="https://github.com/tailwarden/komiser" rel="noopener noreferrer"&gt;Github&lt;/a&gt;, and which provides a &lt;a href="https://docs.komiser.io/getting-started/quickstart#docker" rel="noopener noreferrer"&gt;Docker image&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  What’s next
&lt;/h1&gt;

&lt;p&gt;To manage your costs and monitor the security of your infrastructure, Tailwarden is a good option that will give you a global vision very easily.&lt;/p&gt;

&lt;p&gt;It is a young product but also very active and promising, with a &lt;a href="https://roadmap.tailwarden.com/" rel="noopener noreferrer"&gt;public roadmap&lt;/a&gt; available, which promises new features in particular on the Anomaly detection and Custom dashboard parts.&lt;/p&gt;

</description>
      <category>monitoring</category>
      <category>finops</category>
      <category>cloud</category>
      <category>security</category>
    </item>
    <item>
      <title>A state of AI in 2024</title>
      <dc:creator>Jérôme Dx</dc:creator>
      <pubDate>Mon, 15 Jul 2024 14:00:00 +0000</pubDate>
      <link>https://dev.to/jdxlabs/a-state-of-ai-in-2024-2cgj</link>
      <guid>https://dev.to/jdxlabs/a-state-of-ai-in-2024-2cgj</guid>
      <description>&lt;p&gt;If I tell you that about 2 years ago, &lt;a href="https://en.wikipedia.org/wiki/Generative_artificial_intelligence" rel="noopener noreferrer"&gt;GenAI&lt;/a&gt; arrived with &lt;a href="https://openai.com/chatgpt/" rel="noopener noreferrer"&gt;ChatGPT&lt;/a&gt; and that now we almost only hear about Artificial Intelligence, in every way, I probably don't tell you much.&lt;/p&gt;

&lt;p&gt;I would therefore like, in this article, to bring clarity to the subject, by summarizing the implications of AI today, what are the current issues that we are facing, but also, the concrete and useful applications from which we can benefit.&lt;/p&gt;

&lt;h1&gt;
  
  
  An abstract definition
&lt;/h1&gt;

&lt;p&gt;AI (Articial Intelligence) is a field of computer science that focuses on creating systems capable of performing tasks that typically require human intelligence. These tasks include learning from experience, recognizing patterns, solving problems, understanding natural language and making decisions.&lt;/p&gt;

&lt;p&gt;Pay attention to one thing, it is important to realize that this is a very generic expression and that it is nothing more or less about computer, algorithmic techniques which are actually used, far from replacing the functioning of a human brain.&lt;/p&gt;

&lt;p&gt;In other words, what we call “AI” depends entirely on our perception of it, and should rather be called “algorithmic techniques”. So much so that Luc Julia, who created Siri, came to say that “&lt;a href="https://www.youtube.com/watch?v=6prCHASkavM" rel="noopener noreferrer"&gt;There is no such thing as AI&lt;/a&gt;”.&lt;/p&gt;

&lt;h1&gt;
  
  
  A technical definition
&lt;/h1&gt;

&lt;p&gt;Systems commonly associated to AI are designed to learn from data, adapt to new inputs, and improve over time. This key components and subfields include :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Machine Learning (ML)&lt;/strong&gt;: A subset of AI that involves training algorithms to recognize patterns and make decisions based on data. ML models are built using statistical techniques to enable systems to improve their performance on a given task with more data over time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deep Learning (DL)&lt;/strong&gt;: A specialized branch of ML that employs neural networks with many layers (hence "deep") to model complex patterns in large datasets. DL is particularly effective in tasks such as image and speech recognition.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Large Language Models (LLMs)&lt;/strong&gt;: These are deep learning models that are trained on vast amounts of text data to understand and generate human language. Examples include GPT (Generative Pre-trained Transformer) and BERT (Bidirectional Encoder Representations from Transformers).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generative AI (GenAI)&lt;/strong&gt;: A type of AI focused on creating new content, such as text, images, or music, that is indistinguishable from human-generated content. This includes techniques like Generative Adversarial Networks (GANs) and autoregressive models like GPT.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retrieval-Augmented Generation (RAG)&lt;/strong&gt;: A hybrid approach combining retrieval-based and generative techniques. RAG systems first retrieve relevant documents or information from a large corpus and then generate responses based on the retrieved content. This approach enhances the accuracy and relevance of generated outputs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In essence, AI leverages these advanced techniques to build systems that can perform sophisticated tasks, ranging from data analysis and prediction to natural language understanding and content generation.&lt;/p&gt;

&lt;p&gt;Two things should be noted: on the one hand, &lt;strong&gt;these are only statistical and analysis tools&lt;/strong&gt;, which go through large sets of data, very far from the functioning of a human brain. The other thing is that, for the end user, what is important is still the perception, to qualify as AI, so &lt;strong&gt;these techniques will not necessarily be used in the product&lt;/strong&gt; that is sold as such.&lt;/p&gt;

&lt;h1&gt;
  
  
  Just another buzzword ?
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhehmkgdym57r6ek9y2h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhehmkgdym57r6ek9y2h.png" alt="Google Trends AI" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It has become the latest hype in IT, GenAI has propelled AI onto the podium, as have blockchain, VR headsets, or even 3D TVs, which, as we know, left the front of the stage as they came.&lt;/p&gt;

&lt;p&gt;It is also good to remember that AI is a subject as old as computing itself, periods of craze followed by disinterest, called "&lt;a href="https://en.wikipedia.org/wiki/AI_winter" rel="noopener noreferrer"&gt;AI winters&lt;/a&gt;", have been regularly observed, the first dating from 1966.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fulg1jkxn32hvl3nfit23.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fulg1jkxn32hvl3nfit23.jpeg" alt="AI Marketing" width="700" height="766"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The hype is such that in recent times, the term "AI" has been attached to most computer products, whether it has any real meaning or not, sometimes in a truly ridiculous or inappropriate way. Each application wants its "AI feature".&lt;/p&gt;

&lt;p&gt;The same goes for computer conferences that were twisted into being on the topic of AI, even though the real topics were completely different.&lt;/p&gt;

&lt;p&gt;One truth remains, this enthusiasm unlocks research funding, which allows us to believe that we will be able to see real progress emerge in the future.&lt;/p&gt;

&lt;h1&gt;
  
  
  A threat ?
&lt;/h1&gt;

&lt;p&gt;I don't know if you've noticed, but our thoughts often move much faster than our ability to act.&lt;/p&gt;

&lt;p&gt;We are indeed witnessing progress currently, as well as an amplifying marketing and journalistic frenzy, of which we must not be fooled.&lt;/p&gt;

&lt;p&gt;I'm not going to dwell too much on the subject, but we can discern worrying scenarios, which are the loss of jobs and loss of control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Loss of jobs
&lt;/h2&gt;

&lt;p&gt;A widely talked about &lt;a href="https://www.imf.org/en/Blogs/Articles/2024/01/14/ai-will-transform-the-global-economy-lets-make-sure-it-benefits-humanity" rel="noopener noreferrer"&gt;study from the IMF&lt;/a&gt; indicates that &lt;strong&gt;40% of jobs would be affected&lt;/strong&gt; by AI. These predictions should be taken with a grain of salt for several reasons.&lt;/p&gt;

&lt;p&gt;On the one hand, certain jobs were assigned impressively quickly, such as graphic designers or developers. These professions generally know how &lt;strong&gt;to adapt to new technological&lt;/strong&gt; developments and &lt;strong&gt;take advantage of them&lt;/strong&gt; to gain productivity, we cannot therefore talk about job losses. Besides, in the next section, I will talk about the tools that I use daily as a developer.&lt;/p&gt;

&lt;p&gt;On the other hand, it must be taken into account that the development of new working methods, as all &lt;a href="https://en.wikipedia.org/wiki/Industrial_Revolution" rel="noopener noreferrer"&gt;industrial revolutions&lt;/a&gt; have demonstrated, have not led all of humanity to idleness, but have contributed to the &lt;a href="https://www.quora.com/The-Industrial-Revolution-generated-a-lot-of-new-jobs-to-counteract-the-lost-jobs-Would-the-same-happen-with-advanced-AI-and-robotics-soon" rel="noopener noreferrer"&gt;creation of new jobs&lt;/a&gt;, whether qualified or not. Even if unemployment issues are very real, they are also nuanced and contextual.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3etee9uvfhshoy0s3tul.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3etee9uvfhshoy0s3tul.png" alt="Civilization tree" width="800" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We must not hide our faces either, &lt;strong&gt;we will observe changes due to paradigm shifts induced by AI&lt;/strong&gt;, such as recently the &lt;a href="https://sh.reddit.com/r/duolingo/comments/18sx06i/big_layoff_at_duolingo/" rel="noopener noreferrer"&gt;elimination of jobs in Duolingo's translator teams&lt;/a&gt;, the &lt;a href="https://slate.com/technology/2024/05/deviantart-what-happened-ai-decline-lawsuit-stability.html" rel="noopener noreferrer"&gt;deterioration of the DeviantArt website&lt;/a&gt;, &lt;a href="https://blog.cloudflare.com/declaring-your-aindependence-block-ai-bots-scrapers-and-crawlers-with-a-single-click" rel="noopener noreferrer"&gt;AI Crawlers&lt;/a&gt;, or many other examples.&lt;/p&gt;

&lt;p&gt;What is certain is that jobs as we know them will evolve and the &lt;a href="https://www.talentlens.com/Insights/blog/2024/01/ai-influence-professional-skills.html" rel="noopener noreferrer"&gt;skills needed will be different&lt;/a&gt;, which concerns current and especially future generations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Loss of control
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz6o81ovvqk6id34fg3ry.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz6o81ovvqk6id34fg3ry.jpeg" alt="AI SciFi" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AI may take control of humans, betray them or even destroy them, that's what &lt;a href="https://en.wikipedia.org/wiki/Skynet_(Terminator)" rel="noopener noreferrer"&gt;Skynet&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/HAL_9000" rel="noopener noreferrer"&gt;HAL 9000&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/I,_Robot" rel="noopener noreferrer"&gt;I, Robot&lt;/a&gt;, or globally Hollywood and Pop Culture told us. We can also call it the "Hollywood AI".&lt;/p&gt;

&lt;p&gt;These are only &lt;strong&gt;extremely unlikely scenarios&lt;/strong&gt;. For this, the machine would have to truly emancipate itself from human command, have sufficient power of action, have a motive for such actions and above all &lt;strong&gt;work completely differently than the tools we develop today&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For the moment, all that's happening are &lt;strong&gt;clickbait publications&lt;/strong&gt;, such as, for example, that &lt;a href="https://www.quora.com/Did-Google-really-create-AIs-that-they-had-to-disconnect-because-they-created-their-own-language-and-refused-to-communicate-in-the-language-the-designers-made-for-them" rel="noopener noreferrer"&gt;Google AIs are plotting among themselves in an unknown language&lt;/a&gt;, or that a &lt;a href="https://www.youtube.com/watch?v=g7YJIpkk7KM" rel="noopener noreferrer"&gt;tool is working to destroy humanity&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;It is important to be alerted to the threats that these new tools may have (we will talk about them again, particularly on privacy and ecology), but we must also put things into perspective and carefully check the sources of the informations we consume, to demystify things and understand them.&lt;/p&gt;

&lt;h1&gt;
  
  
  Individual usage
&lt;/h1&gt;

&lt;p&gt;The opening of access to the general public to ChatGPT at the beginning of 2023 was successful and its popularization was impressive.&lt;/p&gt;

&lt;p&gt;The general public very quickly understood the services that it would provide them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Help with content generation (homework, articles, creations of all kinds)&lt;/li&gt;
&lt;li&gt;Search assistance, which replaces the Google engine&lt;/li&gt;
&lt;li&gt;Help with problem solving&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This use has become a new common model, for example, for this search, it is simpler to ask ChatGPT to give me the solution, rather than searching from page to page to find my answer (and that's very complete) :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqegi6cz8jw2j8s0iw7yr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqegi6cz8jw2j8s0iw7yr.png" alt="ChatGPT Prompt" width="705" height="652"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Google, which has long been at the forefront in the field of AI, &lt;a href="https://the-decoder.com/ex-googler-says-companys-ai-panic-is-like-google-fiasco-all-over-again/" rel="noopener noreferrer"&gt;suddenly found itself shaken up&lt;/a&gt; by the acquisition of ChatGPT by Microsoft. Google therefore finds itself in the situation of being confronted on the front line by these GenAI tools which aim to replace the classic Google search page, and it is not in a strong position.&lt;/p&gt;

&lt;p&gt;Now, Google offers &lt;a href="https://gemini.google.com/" rel="noopener noreferrer"&gt;Gemini&lt;/a&gt; (its ChatGPT competitor) on its home page and Bing offers &lt;a href="https://www.microsoft.com/en-us/microsoft-copilot" rel="noopener noreferrer"&gt;Copilot&lt;/a&gt; (which uses the ChatGPT engine):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwz3kdxtmbrbmq6xhgzk6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwz3kdxtmbrbmq6xhgzk6.png" alt="Google Search - Gemini" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzia6pogybm75qnhqd67k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzia6pogybm75qnhqd67k.png" alt="Bing Search - Copilot" width="800" height="321"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Many tools on GenAI have emerged recently and are referenced on the &lt;a href="https://www.futuretools.io/" rel="noopener noreferrer"&gt;futuretools&lt;/a&gt; site.&lt;/p&gt;

&lt;p&gt;The next developments revolve around improving the engine: the completeness of its dataset, the speed of execution, as well as the recent update of the engine training and its internet access.&lt;/p&gt;

&lt;p&gt;The other development is to be multimodal: this affects images, music and even video.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://openai.com/index/sora/" rel="noopener noreferrer"&gt;Sora&lt;/a&gt;, OpenAI's tool for generating video, unveiled a &lt;a href="https://www.youtube.com/watch?v=kHwFMFu9PhA" rel="noopener noreferrer"&gt;fairly impressive video in Japan&lt;/a&gt;, even if some imperfections were detected.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9i338nviipym85gw0g08.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9i338nviipym85gw0g08.png" alt="Sora - Japan Scene" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These tools are very practical and impressive, but require human validation (or even editing) and &lt;a href="https://roadmap.sh/prompt-engineering" rel="noopener noreferrer"&gt;require new skills&lt;/a&gt; to generate the most effective prompt possible.&lt;/p&gt;

&lt;p&gt;Like any tool, it can also be misused, which can lead to the deterioration of some content available online. It is up to us to also be vigilant about the quality of the content we consume.&lt;/p&gt;

&lt;h1&gt;
  
  
  Industry usage
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;For developers&lt;/strong&gt;, Microsoft has been offering &lt;a href="https://github.com/features/copilot" rel="noopener noreferrer"&gt;Github Copilot&lt;/a&gt; for several years now, which allows assistance with writing code (whether in autocomplete or via a prompt).&lt;/p&gt;

&lt;p&gt;GenAI is also very useful for debugging phases, because it gives food for thought, hence the &lt;a href="https://stackoverflow.blog/2023/07/27/announcing-overflowai/" rel="noopener noreferrer"&gt;reaction of Stack Overflow&lt;/a&gt;), which also offered an AI service.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdg6o40rswmmfy8mf2xyu.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdg6o40rswmmfy8mf2xyu.jpeg" alt="AI developer assistant" width="800" height="653"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For Cloud architecture&lt;/strong&gt; usage, today the challenge is no longer to build your own Machine Learning or LLM models, given that they are available off the shelf by Cloud providers.&lt;/p&gt;

&lt;p&gt;Each provider therefore offers a range of services to support the use of these technologies.&lt;/p&gt;

&lt;p&gt;For the moment &lt;strong&gt;&lt;a href="https://cloud.google.com/products/ai?hl=en" rel="noopener noreferrer"&gt;Google&lt;/a&gt; and &lt;a href="https://azure.microsoft.com/en-us/solutions/ai" rel="noopener noreferrer"&gt;Microsoft&lt;/a&gt; are in the lead&lt;/strong&gt;, AWS also offers a service called &lt;a href="https://aws.amazon.com/bedrock" rel="noopener noreferrer"&gt;Bedrock&lt;/a&gt; that can use different Foundation Models, including &lt;a href="https://mistral.ai" rel="noopener noreferrer"&gt;Mistral AI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuwds3ea87m0bnjebg2wf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuwds3ea87m0bnjebg2wf.jpg" alt="Google Cloud offer" width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS&lt;/strong&gt; also offers &lt;a href="https://aws.amazon.com/q/?nc1=h_ls" rel="noopener noreferrer"&gt;Amazon Q&lt;/a&gt;, a tool more focused on the &lt;a href="https://www.gartner.com/smarterwithgartner/how-to-get-started-with-aiops" rel="noopener noreferrer"&gt;AIOps&lt;/a&gt; approach, which aims to integrate AI into the operational part.&lt;/p&gt;

&lt;p&gt;It’s interesting to see that AWS, which has always been at the forefront of the market, &lt;strong&gt;seems to be behind its competitors on GenAI&lt;/strong&gt;. We don't know how it will evolve, but &lt;strong&gt;&lt;a href="https://venturebeat.com/ai/aws-ai-takeover-5-cloud-winning-plays-theyre-using-to-dominate-the-market/" rel="noopener noreferrer"&gt;they could surprise us&lt;/a&gt;&lt;/strong&gt;, they are &lt;a href="https://techcrunch.com/2024/06/13/amazon-says-itll-spend-230-million-on-generative-ai-startups/" rel="noopener noreferrer"&gt;investing actively&lt;/a&gt; in this domain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5cm6cs2mr2k8th92zr9n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5cm6cs2mr2k8th92zr9n.png" alt="AWS offer" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At a time when we are talking about &lt;a href="https://cloud.google.com/sovereign-cloud?hl=en" rel="noopener noreferrer"&gt;sovereign cloud&lt;/a&gt; and &lt;a href="https://gdpr-info.eu" rel="noopener noreferrer"&gt;GDPR&lt;/a&gt; in Europe, GenAI represents an additional constraint in terms of data protection and will probably not be validated in all contexts (because usage means giving your data to the cloud provider that provides the service).&lt;/p&gt;

&lt;p&gt;Despite everything, GAFAM are at the forefront but today a lot of brands are trying to associate their image as being at the cutting edge of AI, this extends to &lt;a href="https://podcasts.apple.com/fr/podcast/stellantis-tech-ai/id1727315032" rel="noopener noreferrer"&gt;automobile&lt;/a&gt; or even &lt;a href="https://www.siroko.com/blog/c/artificial-intelligence-in-cycling/" rel="noopener noreferrer"&gt;cycling&lt;/a&gt; industry.&lt;/p&gt;

&lt;h1&gt;
  
  
  Limitations
&lt;/h1&gt;

&lt;p&gt;The technology has developed well, but creates new problems inherent in the way it works and requires increased supervision:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hallucinations&lt;/strong&gt;: To answer correctly, the model can very well invent informations from scratch with breathtaking confidence. This is why it is essential to scrupulously recheck everything before validating and ensuring that you have sufficient expertise for the area being addressed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bias&lt;/strong&gt;: For example in image generation, you type: “Show me a CEO”: the generator will only output images of tall brown men with white skin. These are clichés that can become even more ingrained in our way of thinking, instead of encouraging diversity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reasoning problems&lt;/strong&gt;: The model does not have our way of thinking and is capable of making grotesque errors, certain examples demonstrate this: “Making a sentence without the letter e", “Give a positive prime number after 2”, etc. The engine returns logical errors with the greatest confidence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These problems are however &lt;a href="https://www.lesswrong.com/posts/t9qvdjY5385MbzoYp/chatgpt-4-solved-all-the-gotcha-problems-i-posed-that" rel="noopener noreferrer"&gt;corrected with each version&lt;/a&gt;, but will never be corrected completely.&lt;/p&gt;

&lt;p&gt;We must also not forget the &lt;strong&gt;problems already inherent in computing&lt;/strong&gt;, which are greatly amplified by AI models and constitute, more than anything else, &lt;strong&gt;the real problems caused by AI&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Privacy&lt;/strong&gt;: Data models recover a large amount of information, of which we do not necessarily have the capacity to verify whether they are respectful of privacy or not, we have to trust the software provider. There is a particular &lt;a href="https://www.thejournal.ie/facebook-data-ai-6391876-May2024/" rel="noopener noreferrer"&gt;topic with Meta about the use of personal information&lt;/a&gt; to train its models.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ecology&lt;/strong&gt;: Climate issues are more than ever at the forefront, at a time when we could instead advocate a form of energy saving, AI models consume a lot of resources: even though this information is kept private, we can clearly imagine (confirmed among others by a &lt;a href="https://www.reuters.com/technology/openai-ceo-altman-says-davos-future-ai-depends-energy-breakthrough-2024-01-16/" rel="noopener noreferrer"&gt;Sam Altman declaration&lt;/a&gt;) that this represents &lt;a href="https://www.visualcapitalist.com/training-costs-of-ai-models-over-time/" rel="noopener noreferrer"&gt;astronomical quantities of GPUs running constantly&lt;/a&gt; (which &lt;a href="https://www.marketwatch.com/story/nvidia-has-added-1-8-trillion-of-market-cap-in-2024-heres-how-big-that-is-2147d7c4" rel="noopener noreferrer"&gt;makes Nvidia happy&lt;/a&gt;) and that it’s only growing, we can unfortunately &lt;a href="https://robertkwiatkowski01.medium.com/is-moores-law-dead-dying-or-still-alive-a931ad9475a9" rel="noopener noreferrer"&gt;no longer count on Moore's law&lt;/a&gt; to compensate.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Regulation
&lt;/h1&gt;

&lt;p&gt;Failing to be at the forefront in the field of creation, Europe has taken the step of being at the forefront in the field of regulation with the &lt;a href="https://www.europarl.europa.eu/topics/en/article/20230601STO93804/eu-ai-act-first-regulation-on-artificial-intelligence" rel="noopener noreferrer"&gt;AI Act&lt;/a&gt;. This is nevertheless a major advantage, because the problems posed are very real and complex in the regulation of such tools.&lt;/p&gt;

&lt;h1&gt;
  
  
  Related topics
&lt;/h1&gt;

&lt;p&gt;AI alone is not enough in itself, and makes it possible to develop other IT sectors such as the &lt;a href="https://en.wikipedia.org/wiki/Cloud_computing" rel="noopener noreferrer"&gt;cloud&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Data_(computer_science)" rel="noopener noreferrer"&gt;data&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Chatbot" rel="noopener noreferrer"&gt;chatbots&lt;/a&gt; or even &lt;a href="https://en.wikipedia.org/wiki/Robotics" rel="noopener noreferrer"&gt;robotics&lt;/a&gt;, which are very related subjects. For the years to come we can imagine that combined progress in these different sectors could once again change the situation in the technological field.&lt;/p&gt;

&lt;h1&gt;
  
  
  To conclude
&lt;/h1&gt;

&lt;p&gt;The IT market has found itself extremely shaken up recently: all software wants to release its AI feature, &lt;strong&gt;IT specialists suddenly have to be specialists in AI&lt;/strong&gt; and the big players are investing &lt;strong&gt;colossal sums&lt;/strong&gt; to corner the market.&lt;/p&gt;

&lt;p&gt;In this context, it is interesting to &lt;strong&gt;adapt to take advantage of these technologies&lt;/strong&gt;, to always marvel at the progress and the help it brings us, but also to &lt;strong&gt;be aware of the issues (particularly on the privacy and ecology side)&lt;/strong&gt;, hence the importance of regulation.&lt;/p&gt;

&lt;p&gt;Keep in mind that the use of these technologies requires &lt;strong&gt;reinforced supervision&lt;/strong&gt; in order to always produce quality work.&lt;/p&gt;

&lt;p&gt;The big development that makes many people dream, but which is probably &lt;a href="https://venturebeat.com/ai/yann-lecun-ai-pioneer-sharply-criticizes-elon-musk-over-treatment-of-scientists-and-spreading-of-misinformation/" rel="noopener noreferrer"&gt;not for tomorrow&lt;/a&gt;, contrary to what Elon Musk said, is the &lt;a href="https://aws.amazon.com/what-is/artificial-general-intelligence/" rel="noopener noreferrer"&gt;&lt;strong&gt;AGI (Artificial General Intelligence)&lt;/strong&gt;&lt;/a&gt;, maybe that will be the next breakthrough, or &lt;strong&gt;maybe we will just get tired of AI&lt;/strong&gt;, saturated from having talked about it too much, until the next real update.&lt;/p&gt;

&lt;p&gt;In any case, it is important to follow the news with full knowledge of the facts, by selecting your sources carefully and by following people who really practice AI and can talk about it without mystification, as do very well Yann Le Cun, Aurélie Jean and Luc Julia.&lt;/p&gt;

&lt;p&gt;More progress is still to come and it is very likely that I will write other articles on these algorithms which work on data sets, which some have decided to call “AI”.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>genai</category>
      <category>llm</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Tech radar: Keep an eye on the technology landscape</title>
      <dc:creator>Jérôme Dx</dc:creator>
      <pubDate>Mon, 17 Jun 2024 14:00:00 +0000</pubDate>
      <link>https://dev.to/jdxlabs/tech-radar-keep-an-eye-on-the-technology-landscape-2pnd</link>
      <guid>https://dev.to/jdxlabs/tech-radar-keep-an-eye-on-the-technology-landscape-2pnd</guid>
      <description>&lt;p&gt;If you've been working in technology for a while, you've probably noticed that there are so many technologies out there and things are constantly evolving.&lt;/p&gt;

&lt;p&gt;My goal here is to give you some keys to not miss essential information and find your way in the technological jungle, while having the ability to completely disconnect once your working time is over.&lt;/p&gt;

&lt;h1&gt;
  
  
  Shared tech radars
&lt;/h1&gt;

&lt;p&gt;Some companies share the tech radar they created, you can consult them whenever you want :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.thoughtworks.com/radar" rel="noopener noreferrer"&gt;ThoughtWorks&lt;/a&gt; - A global technology company&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://opensource.zalando.com/tech-radar/" rel="noopener noreferrer"&gt;Zalando Engineering&lt;/a&gt; - Company specializing in the sale of shoes and clothing&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cloud.theodo.com/tech-radar" rel="noopener noreferrer"&gt;Theodo Cloud&lt;/a&gt; - DevSecOps Experts&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://techradar.devoteam.com/" rel="noopener noreferrer"&gt;Devoteam&lt;/a&gt; - Technology consulting Agency&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://blog.ippon.fr/tech-radar/" rel="noopener noreferrer"&gt;Ippon&lt;/a&gt; - Another Technology consulting Agency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkuu6aaxjekm06ytp2ilt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkuu6aaxjekm06ytp2ilt.png" alt="Tech Radar" width="682" height="672"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main categories for a Tech radar are : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Adopt&lt;/strong&gt; : Approaches in which we have great confidence&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trial&lt;/strong&gt; : Approaches we've seen work successfully&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assess&lt;/strong&gt; : Approaches that are promising and have clear potential added value&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hold&lt;/strong&gt; : Approaches that are not recommended for use on new projects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can also mention Digital.ai which maintains a &lt;a href="https://digital.ai/learn/devsecops-periodic-table/" rel="noopener noreferrer"&gt;Periodic table of DevSecOps tools&lt;/a&gt; allowing you to explore technologies around devops in an original and practical way.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffkn8dy731tyy4535yhz9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffkn8dy731tyy4535yhz9.png" alt="Periodic Table" width="800" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Build your own tech radar
&lt;/h1&gt;

&lt;p&gt;For targeted and punctual needs for you or your company, you can create an Excel sheet to help you make choices, or adopt the Tech Radar approach. Some companies share their method and tools for building your own Tech Radar, like &lt;a href="https://www.thoughtworks.com/radar/byor" rel="noopener noreferrer"&gt;ThoughtWorks&lt;/a&gt; and &lt;a href="https://github.com/zalando/tech-radar" rel="noopener noreferrer"&gt;Zalando&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Be careful though, if you build your own knowledge base, it will be a real effort to update it, given the speed at which technologies evolve today.&lt;/p&gt;

&lt;h1&gt;
  
  
  Software dictionaries and comparators
&lt;/h1&gt;

&lt;p&gt;The common use case is that you hear about a new technology, and very quickly need to understand what it does, what are the alternatives and where it fits into the big picture.&lt;/p&gt;

&lt;p&gt;Luckily, there are community platforms which reference software and allow you to find your way around, here is a selection :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://alternativeto.net/" rel="noopener noreferrer"&gt;Alternativeto&lt;/a&gt; - References all types of software on all OS : Windows, Mac, Linux, Android, etc.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackshare.io/" rel="noopener noreferrer"&gt;Stackshare&lt;/a&gt; - Aimed for companies building their technical stack&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.trustradius.com/" rel="noopener noreferrer"&gt;Trust Radius&lt;/a&gt; - Software database with comparisons and reviews&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.producthunt.com/" rel="noopener noreferrer"&gt;Product Hunt&lt;/a&gt; - To discover and share new tech products&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://landscape.cncf.io/" rel="noopener noreferrer"&gt;Cloud Native Landscape&lt;/a&gt; - Tools referenced by the CNCF, concerning Kubernetes and containers&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.futuretools.io/" rel="noopener noreferrer"&gt;Future Tools&lt;/a&gt; - A curated list of new AI tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Obviously your favorite search engine or AI assistant are also tools of choice for finding information on technologies you want to discover. One tip to find alternatives for a product is to type on Google : &lt;code&gt;&amp;lt;product&amp;gt; vs&lt;/code&gt; and the autocomplete feature will help you diligently.&lt;/p&gt;

&lt;h1&gt;
  
  
  Trends
&lt;/h1&gt;

&lt;p&gt;To help you to make decisions, &lt;a href="https://trends.google.com" rel="noopener noreferrer"&gt;Google Trends&lt;/a&gt; shows you tendencies about the products, compared to others. It is very useful to have it in your toolbox.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdl0okojmx6kcnx4usb8j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdl0okojmx6kcnx4usb8j.png" alt="Google Trends" width="800" height="504"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can also cite &lt;a href="https://www.gartner.com/en" rel="noopener noreferrer"&gt;Gartner&lt;/a&gt; which provides analyzes and predictions, some of which are available for free.&lt;/p&gt;

&lt;h1&gt;
  
  
  Obsolescence management
&lt;/h1&gt;

&lt;p&gt;Once you have adopted the tools in your stack, you must monitor the life of the projects in order to always keep them up to date, with regularly scheduled updates.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://endoflife.date/" rel="noopener noreferrer"&gt;End-of-life&lt;/a&gt; website is made for this :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foaovnrgsqefi7pld33x1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foaovnrgsqefi7pld33x1.png" alt="End of life" width="800" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Learning roadmaps
&lt;/h1&gt;

&lt;p&gt;if you want to master all the technologies that make up your profession, there is the &lt;a href="http://roadmap.sh/" rel="noopener noreferrer"&gt;roadmap.sh&lt;/a&gt; site, which gives you learning paths for particular areas (Devops, Kubernetes, Python, etc.)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7dp2zju96c7ry17ehvvp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7dp2zju96c7ry17ehvvp.png" alt="Roadmap" width="800" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Tech blogs &amp;amp; feeds aggregation
&lt;/h1&gt;

&lt;p&gt;Some people enjoy sharing their knowledge on technical areas, blogs remain accessible and effective media.&lt;br&gt;
&lt;a href="https://feedly.com" rel="noopener noreferrer"&gt;Feedly&lt;/a&gt; or &lt;a href="https://www.inoreader.com/" rel="noopener noreferrer"&gt;Inoreader&lt;/a&gt; will allow you to follow the RSS feeds of these websites and consult them at your leisure, so you can follow the specific areas that interest you.&lt;/p&gt;

&lt;p&gt;Also think about the &lt;a href="http://dev.to/"&gt;Dev.to&lt;/a&gt; platform which allows developers to easily share on their topics.&lt;/p&gt;

&lt;p&gt;Other preferred media at the moment are &lt;a href="https://www.apple.com/apple-podcasts/" rel="noopener noreferrer"&gt;Podcasts&lt;/a&gt; and &lt;a href="https://www.youtube.com/" rel="noopener noreferrer"&gt;YouTube&lt;/a&gt;, that have a good base of quality content, and have the advantage of being able to be listened to in transport or during a running session.&lt;/p&gt;

&lt;h1&gt;
  
  
  Newsletters
&lt;/h1&gt;

&lt;p&gt;Newsletters can remain a good option for keeping up to date without searching for information yourself.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://tldr.tech/newsletters" rel="noopener noreferrer"&gt;TLDR Newsletter&lt;/a&gt; is an interesting option if you don't have a lot of time. It summarizes new developments in general, or in particular areas: Devops, AI, etc.&lt;/p&gt;

&lt;p&gt;This allows you to optimize your time and get the essentials without getting too lost.&lt;/p&gt;

&lt;h1&gt;
  
  
  Latest trends and interactions
&lt;/h1&gt;

&lt;p&gt;If you have a little more time to spare, you can connect on social networks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com" rel="noopener noreferrer"&gt;X (ex-Twitter)&lt;/a&gt; is the long-standing platform for getting and sharing early access to information, with a large user base and a uniquely fun feel. It's also a great way to stay up-to-date with tech events and conferences.&lt;/p&gt;

&lt;p&gt;You can favor other alternatives like &lt;a href="https://joinmastodon.org/" rel="noopener noreferrer"&gt;Mastodon&lt;/a&gt;, or &lt;a href="https://bsky.app/" rel="noopener noreferrer"&gt;Bluesky&lt;/a&gt;, which has recently made a breakthrough. Although the user base is still smaller than that of X, these are functional and promising microblogging platforms.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; is also used to share tech news these days.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.reddit.com/" rel="noopener noreferrer"&gt;Reddit&lt;/a&gt; is a platform with a strong user base, which provides exclusive news and technical knowledge.&lt;/p&gt;

&lt;p&gt;To share about specific technologies, &lt;a href="https://slack.com/" rel="noopener noreferrer"&gt;Slack&lt;/a&gt; or &lt;a href="https://discord.com/" rel="noopener noreferrer"&gt;Discord&lt;/a&gt; channels are quite common and effective ways to interact with the community.&lt;/p&gt;

&lt;h1&gt;
  
  
  To conclude
&lt;/h1&gt;

&lt;p&gt;We've seen tools and methodologies to keep tabs on what's happening in tech news and always have an overview of the tech landscape so you know how to navigate it.&lt;/p&gt;

&lt;p&gt;It's now up to you to take advantage of these tools in order to stay up to date with current events and different tools while maintaining a good life balance on a personal level.&lt;/p&gt;

&lt;p&gt;Enjoy your technological exploration, which is an exciting journey and an endless source of inspiration.&lt;/p&gt;

</description>
      <category>methodology</category>
      <category>cloud</category>
      <category>learning</category>
      <category>community</category>
    </item>
    <item>
      <title>Github Actions to deploy your Terraform code</title>
      <dc:creator>Jérôme Dx</dc:creator>
      <pubDate>Tue, 21 May 2024 09:41:28 +0000</pubDate>
      <link>https://dev.to/jdxlabs/github-actions-to-deploy-your-terraform-code-50n9</link>
      <guid>https://dev.to/jdxlabs/github-actions-to-deploy-your-terraform-code-50n9</guid>
      <description>&lt;p&gt;If you have chosen to host some of your codebases on &lt;a href="https://github.com/" rel="noopener noreferrer"&gt;Github&lt;/a&gt;, you should know that there is a built-in tool allowing you to implement &lt;a href="https://www.redhat.com/en/topics/devops/what-is-ci-cd" rel="noopener noreferrer"&gt;CI/CD&lt;/a&gt; workflows, called &lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;Github Actions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My goal in this article is to show you that with just a few clicks and writing yaml, you can properly deploy your Terraform code on your favorite cloud provider (in this example we will use Google Cloud).&lt;/p&gt;

&lt;h2&gt;
  
  
  Why CI/CD
&lt;/h2&gt;

&lt;p&gt;In short, the main advantages that I see of going through a CI/CD pattern (Continuous Integration / Continuous Deployment), rather than deploying the code directly from your computer, are :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Maintenance&lt;/strong&gt; : Your deployment code will be reproducible and versioned&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traceability&lt;/strong&gt; : You will have a history of different deployments and past errors&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Teamwork&lt;/strong&gt; : Deployment will be accessible to all those included in the project, without complicated configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a more exhaustive explanation, I refer you to the reference which is the &lt;a href="https://12factor.net/" rel="noopener noreferrer"&gt;12factor app&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Github Actions
&lt;/h2&gt;

&lt;p&gt;Github Actions has many competitors in its category that allow you to run all kinds of code running on containers, such as &lt;a href="https://about.gitlab.com/solutions/continuous-integration/" rel="noopener noreferrer"&gt;Gitlab&lt;/a&gt;, &lt;a href="https://www.jenkins.io/" rel="noopener noreferrer"&gt;Jenkins&lt;/a&gt;, &lt;a href="https://circleci.com/" rel="noopener noreferrer"&gt;CircleCI&lt;/a&gt;, etc.&lt;/p&gt;

&lt;p&gt;There are also more specialized tools in deploying IaC code, such as: &lt;a href="https://app.terraform.io/" rel="noopener noreferrer"&gt;HCP Terraform&lt;/a&gt;, &lt;a href="https://www.runatlantis.io/" rel="noopener noreferrer"&gt;Atlantis&lt;/a&gt;, &lt;a href="https://terramate.io/" rel="noopener noreferrer"&gt;Terramate&lt;/a&gt;, etc.&lt;/p&gt;

&lt;p&gt;My choice fell on Github Actions, aiming to have the &lt;strong&gt;lightest footprint possible&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Since my code is already on the Github platform, this gives me the ability to execute code, without having to connect to an additional tool. The possibilities are extensive, I can run all kinds of containers, whether for infrastructure or not.&lt;/p&gt;

&lt;p&gt;It is also a tool with a &lt;strong&gt;strong community&lt;/strong&gt;, which can be frequently encountered on consulting missions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing
&lt;/h2&gt;

&lt;p&gt;Considering the &lt;a href="https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions" rel="noopener noreferrer"&gt;billing documention&lt;/a&gt;, for personal use, you can use it free of charge within certain limitations per month for private repositories (2000 minutes of build and 500 Mo of package storage, by month). You also have the possibility to connect your own agents in addition.&lt;/p&gt;

&lt;p&gt;Good news is that Github encourages open-source by offering unlimited use for publicly exposed repositories.&lt;/p&gt;

&lt;p&gt;If you want to extend the possibilities of your personal account, you can take &lt;a href="https://docs.github.com/en/billing/managing-the-plan-for-your-github-account/upgrading-your-accounts-plan" rel="noopener noreferrer"&gt;Github Pro&lt;/a&gt;, for $4/month.&lt;/p&gt;

&lt;p&gt;If the company you work for has &lt;a href="https://github.com/pricing" rel="noopener noreferrer"&gt;subscribed to Github&lt;/a&gt;, you probably benefit from a more substantial offer with additional features (&lt;a href="https://github.com/team" rel="noopener noreferrer"&gt;GitHub Team&lt;/a&gt; or &lt;a href="https://github.com/enterprise" rel="noopener noreferrer"&gt;GitHub Enterprise&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s do the demo
&lt;/h2&gt;

&lt;p&gt;In our example, I only selected the basic features available in the free offer, which can therefore be used in all contexts.&lt;/p&gt;

&lt;p&gt;Here is the Terraform code you can use to create a Cloud function on Google Cloud :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# main.tf&lt;/span&gt;
resource &lt;span class="s2"&gt;"**google_storage_bucket_object**"&lt;/span&gt; &lt;span class="s2"&gt;"object"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  name   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"functions/test1.zip"&lt;/span&gt;
  bucket &lt;span class="o"&gt;=&lt;/span&gt; var.bucket_name
  &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./functions/test1.zip"&lt;/span&gt; &lt;span class="c"&gt;# Local path to the zipped function source code&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

resource &lt;span class="s2"&gt;"google_cloudfunctions2_function"&lt;/span&gt; &lt;span class="s2"&gt;"function"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  name        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"mycorp-test1"&lt;/span&gt;
  location    &lt;span class="o"&gt;=&lt;/span&gt; var.region
  description &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Test1 function"&lt;/span&gt;

  build_config &lt;span class="o"&gt;{&lt;/span&gt;
    runtime     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"python312"&lt;/span&gt;
    entry_point &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"main"&lt;/span&gt;
    &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      storage_source &lt;span class="o"&gt;{&lt;/span&gt;
        bucket &lt;span class="o"&gt;=&lt;/span&gt; var.bucket_name
        object &lt;span class="o"&gt;=&lt;/span&gt; google_storage_bucket_object.object.name
      &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  service_config &lt;span class="o"&gt;{&lt;/span&gt;
    max_instance_count &lt;span class="o"&gt;=&lt;/span&gt; 1
    available_memory   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"256M"&lt;/span&gt;
    timeout_seconds    &lt;span class="o"&gt;=&lt;/span&gt; 60
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# output.tf&lt;/span&gt;
output &lt;span class="s2"&gt;"function_uri"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  value &lt;span class="o"&gt;=&lt;/span&gt; google_cloudfunctions2_function.function.service_config[0].uri
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# provider.tf&lt;/span&gt;
provider &lt;span class="s2"&gt;"google"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  credentials &lt;span class="o"&gt;=&lt;/span&gt; file&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"credentials.json"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

  project &lt;span class="o"&gt;=&lt;/span&gt; var.project_name
  region  &lt;span class="o"&gt;=&lt;/span&gt; var.region
  zone    &lt;span class="o"&gt;=&lt;/span&gt; var.zone
&lt;span class="o"&gt;}&lt;/span&gt;

terraform &lt;span class="o"&gt;{&lt;/span&gt;
  backend &lt;span class="s2"&gt;"gcs"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    bucket      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"infra-mycorp-terraform-states"&lt;/span&gt;
    prefix      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"gha-demo"&lt;/span&gt;
    credentials &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"credentials.json"&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  required_version &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;gt;=1.7.0"&lt;/span&gt;
  required_providers &lt;span class="o"&gt;{&lt;/span&gt;
    google &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;source&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"hashicorp/google"&lt;/span&gt;
      version &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;gt;=4.0.0"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# variables.tf&lt;/span&gt;
variable &lt;span class="s2"&gt;"region"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;type&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; string
  default     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"europe-west1"&lt;/span&gt;
  description &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"GCP Region"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

variable &lt;span class="s2"&gt;"zone"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;type&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; string
  default     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"europe-west1-c"&lt;/span&gt;
  description &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"GCP Zone"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

variable &lt;span class="s2"&gt;"project_name"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;type&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; string
  default     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"infra-mycorp"&lt;/span&gt;
  description &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"GCP Project Name"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

variable &lt;span class="s2"&gt;"bucket_name"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;type&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; string
  default     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"mycorp-packages"&lt;/span&gt;
  description &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Bucket name"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may also &lt;a href="https://cloud.google.com/iam/docs/keys-create-delete" rel="noopener noreferrer"&gt;generate a json key&lt;/a&gt; for your Service Account.&lt;/p&gt;

&lt;p&gt;Here is the Python code you can use to create an example package for your Cloud Function, to store on a Cloud Storage bucket :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;functions_framework&lt;/span&gt;

&lt;span class="nd"&gt;@functions_framework.http&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;HTTP Cloud Function.
    Args:
        request (flask.Request): The request object.
        &amp;lt;https://flask.palletsprojects.com/en/1.1.x/api/#incoming-request-data&amp;gt;
    Returns:
        The response text, or any set of values that can be turned into a
        Response object using `make_response`
        &amp;lt;https://flask.palletsprojects.com/en/1.1.x/api/#flask.make_response&amp;gt;.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;request_json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;silent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;request_args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;request_json&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;request_json&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request_json&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;request_args&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;request_args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request_args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;World&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Hello {}!&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here the Github Actions workflows to execute your Terraform code :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/1_plan.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1. Plan&lt;/span&gt;
&lt;span class="na"&gt;run-name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Workflow ${{ github.run_id }} 🚀&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;plan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo "🚀 Plan launched"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install packages&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;sudo apt-get update&lt;/span&gt;
          &lt;span class="s"&gt;sudo apt-get install -y build-essential python3&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Homebrew&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"&lt;/span&gt;
          &lt;span class="s"&gt;rc=/tmp/rcfile &amp;amp;&amp;amp; touch $rc&lt;/span&gt;
          &lt;span class="s"&gt;echo 'eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv)' &amp;gt;&amp;gt; $rc&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Terraform&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;source /tmp/rcfile&lt;/span&gt;
          &lt;span class="s"&gt;brew install tfenv&lt;/span&gt;
          &lt;span class="s"&gt;tfenv install 1.8.3&lt;/span&gt;
          &lt;span class="s"&gt;tfenv use 1.8.3&lt;/span&gt;
          &lt;span class="s"&gt;terraform version&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Load credentials&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;echo -n '${{ secrets.GOOGLE_CREDENTIALS }}' | base64 -d &amp;gt; credentials.json&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Terraform Init&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;terraform init -get=true -upgrade&lt;/span&gt;
          &lt;span class="s"&gt;terraform workspace new ${{ vars.WORKSPACE_DEV }} || true&lt;/span&gt;
          &lt;span class="s"&gt;terraform workspace select ${{ vars.WORKSPACE_DEV }}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Terraform Format&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;terraform fmt&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Terraform Plan&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;terraform plan&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo "🍏 The job's status is ${{ job.status }}."&lt;/span&gt;

&lt;span class="c1"&gt;# .github/workflows/2_apply.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2. Apply&lt;/span&gt;
&lt;span class="na"&gt;run-name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Workflow ${{ github.run_id }} 🚀&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;apply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo "🚀 Plan launched"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install packages&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;sudo apt-get update&lt;/span&gt;
          &lt;span class="s"&gt;sudo apt-get install -y build-essential python3&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Homebrew&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"&lt;/span&gt;
          &lt;span class="s"&gt;rc=/tmp/rcfile &amp;amp;&amp;amp; touch $rc&lt;/span&gt;
          &lt;span class="s"&gt;echo 'eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv)' &amp;gt;&amp;gt; $rc&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Terraform&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;source /tmp/rcfile&lt;/span&gt;
          &lt;span class="s"&gt;brew install tfenv&lt;/span&gt;
          &lt;span class="s"&gt;tfenv install 1.8.3&lt;/span&gt;
          &lt;span class="s"&gt;tfenv use 1.8.3&lt;/span&gt;
          &lt;span class="s"&gt;terraform version&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Load credentials&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;echo -n '${{ secrets.GOOGLE_CREDENTIALS }}' | base64 -d &amp;gt; credentials.json&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Terraform Init&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;terraform init -get=true -upgrade&lt;/span&gt;
          &lt;span class="s"&gt;terraform workspace new ${{ vars.WORKSPACE_DEV }} || true&lt;/span&gt;
          &lt;span class="s"&gt;terraform workspace select ${{ vars.WORKSPACE_DEV }}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Terraform Apply&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;terraform apply -auto-approve&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo "🍏 The job's status is ${{ job.status }}."&lt;/span&gt;

&lt;span class="c1"&gt;# .github/workflows/3_destroy.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;3. Destroy&lt;/span&gt;
&lt;span class="na"&gt;run-name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Workflow ${{ github.run_id }} 🚀&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;destroy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo "🚀 Plan launched"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install packages&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;sudo apt-get update&lt;/span&gt;
          &lt;span class="s"&gt;sudo apt-get install -y build-essential python3&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Homebrew&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"&lt;/span&gt;
          &lt;span class="s"&gt;rc=/tmp/rcfile &amp;amp;&amp;amp; touch $rc&lt;/span&gt;
          &lt;span class="s"&gt;echo 'eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv)' &amp;gt;&amp;gt; $rc&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Terraform&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;source /tmp/rcfile&lt;/span&gt;
          &lt;span class="s"&gt;brew install tfenv&lt;/span&gt;
          &lt;span class="s"&gt;tfenv install 1.8.3&lt;/span&gt;
          &lt;span class="s"&gt;tfenv use 1.8.3&lt;/span&gt;
          &lt;span class="s"&gt;terraform version&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Load credentials&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;echo -n '${{ secrets.GOOGLE_CREDENTIALS }}' | base64 -d &amp;gt; credentials.json&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Terraform Init&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;terraform init -get=true -upgrade&lt;/span&gt;
          &lt;span class="s"&gt;terraform workspace new ${{ vars.WORKSPACE_DEV }} || true&lt;/span&gt;
          &lt;span class="s"&gt;terraform workspace select ${{ vars.WORKSPACE_DEV }}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Terraform Destroy&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;terraform apply -destroy -auto-approve&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo "🍏 The job's status is ${{ job.status }}."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Some explanations on the workflows
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Triggers
&lt;/h3&gt;

&lt;p&gt;In the &lt;a href="https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows" rel="noopener noreferrer"&gt;“on:” section&lt;/a&gt;, I created a rule to execute the “Plan” workflow, when there is a commit or a pull request on the “main” branch.&lt;/p&gt;

&lt;p&gt;I created 3 files (one file for each workflow, inside the “./.github/workflows” folder), with the &lt;a href="https://docs.github.com/en/actions/using-workflows/manually-running-a-workflow" rel="noopener noreferrer"&gt;“workflow_dispatch:” section&lt;/a&gt;, we have the possibility to trigger manually an “apply” or a “delete”, once the plan is done (or to relaunch the plan).&lt;/p&gt;

&lt;p&gt;Note that I didn’t use the &lt;a href="https://cloudlumberjack.com/posts/github-actions-approvals/" rel="noopener noreferrer"&gt;manual approval feature&lt;/a&gt;, to set manual validation inside a workflow, because it isn’t available in the free features.&lt;/p&gt;

&lt;p&gt;Here is what shows the interface for a basic plan :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu4o8481vq0v32upzlowp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu4o8481vq0v32upzlowp.png" alt="List of workflows" width="800" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv0taz29saseyhv0pmdcf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv0taz29saseyhv0pmdcf.png" alt="Plan workflow" width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Checkout
&lt;/h3&gt;

&lt;p&gt;Ensure you have the &lt;a href="https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions#create-an-example-workflow" rel="noopener noreferrer"&gt;step “uses: actions/checkout”&lt;/a&gt;, because it is required if you want to have your code inside your container.&lt;/p&gt;

&lt;h3&gt;
  
  
  Variables &amp;amp; secrets
&lt;/h3&gt;

&lt;p&gt;Go in the Settings of your project, to consult &lt;a href="https://docs.github.com/en/actions/learn-github-actions/variables" rel="noopener noreferrer"&gt;variables&lt;/a&gt; and &lt;a href="https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions" rel="noopener noreferrer"&gt;secrets&lt;/a&gt; you want to store for your workflow. Then you can call them with the “var.” and “secrets.” prefixes.&lt;/p&gt;

&lt;p&gt;There are some restrictions for secrets, once copied, you can’t consult them again from the interface. &lt;/p&gt;

&lt;p&gt;Another thing is that you a restricted to a certain number of characters for the value of your secret, a common trick I used is to encode it in base64, and decode it directly in the workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzb46ogicjn99dckqlbif.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzb46ogicjn99dckqlbif.png" alt="Variables" width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Packaging
&lt;/h3&gt;

&lt;p&gt;I used the &lt;a href="https://github.com/actions/runner-images" rel="noopener noreferrer"&gt;“ubuntu-latest” image&lt;/a&gt; which is Debian-based (with &lt;a href="https://www.debian.org/doc/manuals/debian-faq/pkgtools.en.html#apt-get" rel="noopener noreferrer"&gt;apt&lt;/a&gt;) and commonly available in the Github Actions workers, so it deploys very fast.&lt;/p&gt;

&lt;p&gt;I chose to install &lt;a href="https://docs.brew.sh/Homebrew-on-Linux" rel="noopener noreferrer"&gt;HomeBrew&lt;/a&gt;, because there are a lot of tools I like available on this package manager, including &lt;a href="https://dev.to/jdxlabs/tfenv-to-handle-different-versions-of-terraform-4k6p"&gt;tfenv&lt;/a&gt;, which allows me to install any version of Terraform very easily.&lt;/p&gt;

&lt;h3&gt;
  
  
  Validations and workspaces
&lt;/h3&gt;

&lt;p&gt;The only validation I have installed is the &lt;a href="https://developer.hashicorp.com/terraform/cli/commands/fmt" rel="noopener noreferrer"&gt;Terraform Format&lt;/a&gt; command, which indicates if the code is written according to the recommended formalism. It is of course possible and encouraged to install other validations.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://developer.hashicorp.com/terraform/cli/commands/workspace" rel="noopener noreferrer"&gt;workspace&lt;/a&gt; for Terraform allows you to compartmentalize the code according to different spaces and environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  To conclude
&lt;/h2&gt;

&lt;p&gt;Here is a very simple way to deploy infrastructure on Google Cloud with a Github free account and some Terraform code. &lt;/p&gt;

&lt;p&gt;You can use as you wish and improve according to your preferences and needs.&lt;/p&gt;

&lt;p&gt;It is also possible to interact Github Actions with a more specialized tool (like HCP Terraform or Terramate), which could be the subject of a future article.&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>terraform</category>
      <category>googlecloud</category>
    </item>
  </channel>
</rss>
