<?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: Alejandro FR</title>
    <description>The latest articles on DEV Community by Alejandro FR (@afr-dt).</description>
    <link>https://dev.to/afr-dt</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F141674%2F5534cbfe-f16d-432c-8aad-83354cad81af.jpg</url>
      <title>DEV Community: Alejandro FR</title>
      <link>https://dev.to/afr-dt</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/afr-dt"/>
    <language>en</language>
    <item>
      <title>Multipass with Cloud-init</title>
      <dc:creator>Alejandro FR</dc:creator>
      <pubDate>Sun, 26 Jul 2026 21:11:02 +0000</pubDate>
      <link>https://dev.to/afr-dt/multipass-cloud-init-1g38</link>
      <guid>https://dev.to/afr-dt/multipass-cloud-init-1g38</guid>
      <description>&lt;h2&gt;
  
  
  My reproducible Ubuntu DevOps VM in one command
&lt;/h2&gt;

&lt;p&gt;To avoid a local environment cluttered with manual installations and version conflicts in backend and DevOps, I use a lightweight and clean solution: an Ubuntu virtual machine (VM) in &lt;strong&gt;Multipass&lt;/strong&gt;, configured from the first boot with &lt;strong&gt;cloud-init&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This allows me to spin up a declarative, reproducible, and disposable environment in minutes. If something fails, I delete the VM and recreate it without affecting my host machine.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;GitHub repository: &lt;a href="https://github.com/afr-dt/cloud-init-config" rel="noopener noreferrer"&gt;afr-dt/cloud-init-config&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What problem am I solving?
&lt;/h2&gt;

&lt;p&gt;Working with multiple tools (Terraform, Kubernetes, cloud CLIs, and runtimes) directly on the host machine leads to common issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Conflicts between programming language versions (Python, Node.js, Go) and system packages.&lt;/li&gt;
&lt;li&gt;Difficulty updating AWS/GCP CLIs consistently.&lt;/li&gt;
&lt;li&gt;Lack of documentation on how tools were installed.&lt;/li&gt;
&lt;li&gt;Low reproducibility when changing computers or sharing setups.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is to achieve an &lt;strong&gt;isolated&lt;/strong&gt; environment that is &lt;strong&gt;declaratively&lt;/strong&gt; defined (version controlled in Git) and easy to &lt;strong&gt;destroy and recreate&lt;/strong&gt; in seconds.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Multipass + cloud-init?
&lt;/h2&gt;

&lt;p&gt;While containers are very useful, sometimes you need a complete development environment with a real operating system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multipass&lt;/strong&gt; allows you to create lightweight Ubuntu VMs quickly and easily. &lt;strong&gt;cloud-init&lt;/strong&gt; automates the initial installation and configuration using a declarative file (YAML), replacing long manual installation guides. In short: Multipass provides the machine, and cloud-init defines its state.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture of the approach
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;macOS / Linux host -&amp;gt; Multipass -&amp;gt; Ubuntu VM -&amp;gt; cloud-init -&amp;gt; Tools and Runtimes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This workflow keeps the host machine clean and the workspace isolated.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this DevOps instance includes
&lt;/h2&gt;

&lt;p&gt;The VM is automatically provisioned on its first boot with the following tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Languages and Runtimes&lt;/strong&gt;: Go, Python (managed with &lt;code&gt;uv&lt;/code&gt;), Node.js (managed with &lt;code&gt;nvm&lt;/code&gt;), and &lt;code&gt;build-essential&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud &amp;amp; Infrastructure&lt;/strong&gt;: Terraform, AWS CLI v2, and Google Cloud CLI (&lt;code&gt;gcloud&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kubernetes&lt;/strong&gt;: &lt;code&gt;kubectl&lt;/code&gt;, &lt;code&gt;k9s&lt;/code&gt;, &lt;code&gt;kubectx&lt;/code&gt;, &lt;code&gt;kubens&lt;/code&gt;, and &lt;code&gt;kubecolor&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment &amp;amp; Utilities&lt;/strong&gt;: Zsh with Starship, Neovim with LazyVim, &lt;code&gt;jq&lt;/code&gt;, &lt;code&gt;fzf&lt;/code&gt;, &lt;code&gt;htop&lt;/code&gt;, &lt;code&gt;tmux&lt;/code&gt;, &lt;code&gt;curl&lt;/code&gt;, and &lt;code&gt;git&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Launching and managing the VM
&lt;/h2&gt;

&lt;p&gt;With Multipass installed, clone the repository and run:&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;# Create the VM using our configuration&lt;/span&gt;
multipass launch lts &lt;span class="nt"&gt;--name&lt;/span&gt; devops-instance &lt;span class="nt"&gt;--cpus&lt;/span&gt; 2 &lt;span class="nt"&gt;--memory&lt;/span&gt; 4G &lt;span class="nt"&gt;--disk&lt;/span&gt; 28G &lt;span class="nt"&gt;--cloud-init&lt;/span&gt; ./cloud-config.yaml
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhy3mv40700iplw0rit7c.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhy3mv40700iplw0rit7c.png" alt=" " width="798" height="161"&gt;&lt;/a&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="c"&gt;# Enter the VM terminal&lt;/span&gt;
multipass shell devops-instance
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcybprdzw0bacnayeiuew.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcybprdzw0bacnayeiuew.png" alt=" " width="800" height="479"&gt;&lt;/a&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="c"&gt;# Clean up and delete the VM when you are done&lt;/span&gt;
multipass delete &lt;span class="nt"&gt;--purge&lt;/span&gt; devops-instance
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  First-boot experience
&lt;/h2&gt;

&lt;p&gt;Upon entering the VM for the first time, the &lt;code&gt;ubuntu&lt;/code&gt; user already has passwordless &lt;code&gt;sudo&lt;/code&gt; privileges, Zsh/Starship configured as the shell, and Neovim ready to use.&lt;br&gt;
This demonstrates the value of &lt;code&gt;cloud-init&lt;/code&gt;: instead of executing manual setup scripts, the entire system state is defined declaratively, reproducibly, and shareably in a single YAML file.&lt;/p&gt;


&lt;h2&gt;
  
  
  Checking that everything works
&lt;/h2&gt;

&lt;p&gt;Once inside the VM, you can confirm that everything works by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform version &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; aws &lt;span class="nt"&gt;--version&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; gcloud version &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; kubectl version &lt;span class="nt"&gt;--client&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; go version &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; node &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; python &lt;span class="nt"&gt;--version&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fos1k3ask1e0zxy0s0qll.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fos1k3ask1e0zxy0s0qll.png" alt=" " width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Common use cases
&lt;/h2&gt;

&lt;p&gt;This VM is ideal for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developing and deploying Terraform configurations in isolation.&lt;/li&gt;
&lt;li&gt;Authenticating and running tasks in AWS and GCP without persisting credentials on the host.&lt;/li&gt;
&lt;li&gt;Experimenting with Kubernetes (&lt;code&gt;kubectl&lt;/code&gt;, &lt;code&gt;k9s&lt;/code&gt;) safely.&lt;/li&gt;
&lt;li&gt;Testing Go, Python, or Node.js runtimes without altering local machine versions.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Trade-offs and limits
&lt;/h2&gt;

&lt;p&gt;This approach does not replace all local use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For simple tasks or a single runtime, a Docker container is usually faster and lighter.&lt;/li&gt;
&lt;li&gt;If you require graphical interfaces (GUI) or direct integration with host hardware, working natively is better.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, for DevOps and infrastructure tasks, the reproducibility and isolation of a real, code-based environment outweigh these limitations.&lt;/p&gt;




&lt;h2&gt;
  
  
  Closing thoughts
&lt;/h2&gt;

&lt;p&gt;Controlling your development environment as code is a major productivity boost. With Multipass and &lt;code&gt;cloud-init&lt;/code&gt;, you can easily experiment without cluttering your host system.&lt;/p&gt;

&lt;p&gt;The next step is to customize &lt;code&gt;cloud-config.yaml&lt;/code&gt; to fit your own needs: mount directories, install Docker, or configure personal dotfiles.&lt;/p&gt;

&lt;p&gt;Originally published at: &lt;a href="https://afr-dt.github.io/en/posts/multipass-cloud-init/" rel="noopener noreferrer"&gt;Multipass + cloud-init ☁️ ⚙️&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>cloudnative</category>
      <category>tutorial</category>
      <category>ubuntu</category>
    </item>
    <item>
      <title>🚀 UV, el nuevo estándar para Python</title>
      <dc:creator>Alejandro FR</dc:creator>
      <pubDate>Wed, 05 Nov 2025 07:27:01 +0000</pubDate>
      <link>https://dev.to/afr-dt/uv-el-nuevo-estandar-para-python-2j3p</link>
      <guid>https://dev.to/afr-dt/uv-el-nuevo-estandar-para-python-2j3p</guid>
      <description>&lt;p&gt;&lt;strong&gt;UV reemplaza pip, virtualenv y pipx con una sola herramienta ultrarrápida. Aprende cómo usarlo y por qué migrar hoy.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🧩 ¿Qué es UV?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://astral.sh/uv" rel="noopener noreferrer"&gt;&lt;code&gt;uv&lt;/code&gt;&lt;/a&gt; es una herramienta moderna creada por &lt;strong&gt;Astral&lt;/strong&gt; (los de &lt;code&gt;ruff&lt;/code&gt; 🦀) para reemplazar &lt;strong&gt;pip&lt;/strong&gt;, &lt;strong&gt;virtualenv&lt;/strong&gt;, &lt;strong&gt;pip-tools&lt;/strong&gt; y &lt;strong&gt;pipx&lt;/strong&gt; con un solo binario rápido y eficiente.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚙️ Instalación
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# En macOS &amp;amp; Linux.&lt;/span&gt;
curl &lt;span class="nt"&gt;-LsSf&lt;/span&gt; https://astral.sh/uv/install.sh | sh
&lt;span class="c"&gt;# o con Homebrew&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;uv

&lt;span class="c"&gt;# En Windows.&lt;/span&gt;
powershell &lt;span class="nt"&gt;-ExecutionPolicy&lt;/span&gt; ByPass &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"irm https://astral.sh/uv/install.ps1 | iex"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  📦 Crea tu entorno en segundos
&lt;/h2&gt;

&lt;p&gt;Antes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv
&lt;span class="nb"&gt;source &lt;/span&gt;venv/bin/activate
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ahora:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv venv
uv pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Modo moderno (recomendado):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv init myproject
uv add fastapi uvicorn
uv &lt;span class="nb"&gt;sync&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;uv crea .venv, pyproject.toml y uv.lock.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚡ Ejecuta sin activar el entorno
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run app.py
uv run pytest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🧪 Migrando desde requirements.txt
&lt;/h2&gt;

&lt;p&gt;Compatibilidad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Migración:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv init
uv add &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
uv &lt;span class="nb"&gt;sync&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto genera pyproject.toml y uv.lock&lt;/p&gt;

&lt;h2&gt;
  
  
  🧹 Limpieza y mantenimiento
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Acción&lt;/th&gt;
&lt;th&gt;Comando&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Limpiar caché&lt;/td&gt;
&lt;td&gt;&lt;code&gt;uv cache clean&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ver deps&lt;/td&gt;
&lt;td&gt;&lt;code&gt;uv pip list&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Actualizar desde requirements.txt&lt;/td&gt;
&lt;td&gt;&lt;code&gt;uv pip install --upgrade -r requirements.txt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  🔚 Conclusión
&lt;/h2&gt;

&lt;p&gt;uv es simple, rápido, compatible y moderno.&lt;br&gt;
Si pensabas que Python necesitaba un mejor gestor de entornos, este es el momento.&lt;/p&gt;

&lt;p&gt;Post original en: &lt;a href="https://afr-dt.github.io/posts/uv-python/" rel="noopener noreferrer"&gt;link&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>uv</category>
      <category>virtualenv</category>
    </item>
  </channel>
</rss>
