<?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: Sergio Méndez</title>
    <description>The latest articles on DEV Community by Sergio Méndez (@sergioarmgpl).</description>
    <link>https://dev.to/sergioarmgpl</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%2F630275%2F69d6e3c0-98f7-427b-88f2-121e493b8fcb.jpg</url>
      <title>DEV Community: Sergio Méndez</title>
      <link>https://dev.to/sergioarmgpl</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sergioarmgpl"/>
    <language>en</language>
    <item>
      <title>Hello world example with gRPC and Go</title>
      <dc:creator>Sergio Méndez</dc:creator>
      <pubDate>Tue, 07 Jul 2026 17:13:19 +0000</pubDate>
      <link>https://dev.to/sergioarmgpl/hello-world-example-with-grpc-and-go-9j8</link>
      <guid>https://dev.to/sergioarmgpl/hello-world-example-with-grpc-and-go-9j8</guid>
      <description>&lt;p&gt;Hi, readers this time I want to show you how to implement the classic &lt;strong&gt;Hello World&lt;/strong&gt; example with &lt;strong&gt;gRPC&lt;/strong&gt;, but with a small change: instead of sending a &lt;code&gt;Name&lt;/code&gt; as a parameter, we are going to modify the protocol buffer definition and the generated code so the client sends a &lt;code&gt;Nickname&lt;/code&gt; and the server replies back with it. We are going to use the same style of environment I used in my &lt;a href="https://dev.to/sergioarmgpl/container-runtimes-for-cloud-native-projects-5c5c"&gt;previous post about Container Runtimes&lt;/a&gt;, this time running everything inside a Killercoda Ubuntu playground and a &lt;code&gt;golang&lt;/code&gt; container.&lt;/p&gt;

&lt;p&gt;This blog post will focus on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting up a gRPC + Protoc development environment in Go.&lt;/li&gt;
&lt;li&gt;Modifying the official &lt;code&gt;grpc-go&lt;/code&gt; Hello World example to use a &lt;code&gt;Nickname&lt;/code&gt; field.&lt;/li&gt;
&lt;li&gt;Running the gRPC server and invoking it from a client process.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What you will learn
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Prepare the environment for gRPC and Protoc&lt;/li&gt;
&lt;li&gt;Implement a gRPC service

&lt;ul&gt;
&lt;li&gt;Cloning and modifying the &lt;code&gt;grpc-go&lt;/code&gt; Hello World example&lt;/li&gt;
&lt;li&gt;Regenerating protobuf/gRPC Go code&lt;/li&gt;
&lt;li&gt;Running the gRPC server&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Invoke a gRPC service from a client&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Environment
&lt;/h2&gt;

&lt;p&gt;For this exercise we are going to use the &lt;a href="https://killercoda.com/playgrounds/scenario/ubuntu" rel="noopener noreferrer"&gt;Ubuntu playground on Killercoda&lt;/a&gt;, which gives us a disposable Ubuntu machine with Docker already available. As a reference, I'm following the &lt;a href="https://grpc.io/docs/languages/go/quickstart/" rel="noopener noreferrer"&gt;official gRPC Go quickstart guide&lt;/a&gt; and adapting it to this custom scenario.&lt;/p&gt;

&lt;h2&gt;
  
  
  Statement
&lt;/h2&gt;

&lt;p&gt;Implement the gRPC Hello World example so it accepts a &lt;code&gt;Nickname&lt;/code&gt; (instead of &lt;code&gt;Name&lt;/code&gt;) as a parameter, and invoke it from a client process, similar to the example on the official gRPC site.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prepare the environment for gRPC and Protoc
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Inside the Killercoda Ubuntu playground, create a container using the official Go image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; golang:1.25-bookworm /bin/bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Prepare the gRPC environment by running the following commands inside the container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apt-get update&lt;span class="p"&gt;;&lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;unzip&lt;span class="p"&gt;;&lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;nano vim &lt;span class="nt"&gt;-y&lt;/span&gt;
go &lt;span class="nb"&gt;install &lt;/span&gt;google.golang.org/protobuf/cmd/protoc-gen-go@latest
go &lt;span class="nb"&gt;install &lt;/span&gt;google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
apt-get update&lt;span class="p"&gt;;&lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;protobuf-compiler &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These commands install:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;unzip, nano, vim:&lt;/strong&gt; basic utilities to unpack files and edit code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;protoc-gen-go:&lt;/strong&gt; the Go plugin for the protobuf compiler.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;protoc-gen-go-grpc:&lt;/strong&gt; the Go plugin that generates gRPC service code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;protobuf-compiler (protoc):&lt;/strong&gt; the compiler itself, used to generate Go code from &lt;code&gt;.proto&lt;/code&gt; files.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implement a gRPC service
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Clone the &lt;code&gt;grpc-go&lt;/code&gt; repository and remove the pre-generated protobuf files, since we are going to regenerate them after our changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &lt;span class="nt"&gt;-b&lt;/span&gt; v1.77.0 &lt;span class="nt"&gt;--depth&lt;/span&gt; 1 https://github.com/grpc/grpc-go
&lt;span class="nb"&gt;cd &lt;/span&gt;grpc-go/examples/helloworld
&lt;span class="nb"&gt;rm &lt;/span&gt;helloworld/helloworld.pb&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Modify &lt;code&gt;SayHello&lt;/code&gt; so it uses a &lt;code&gt;Nickname&lt;/code&gt; parameter instead of &lt;code&gt;Name&lt;/code&gt;. We need to touch three files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;helloworld/helloworld.proto&lt;/code&gt;: change the &lt;code&gt;HelloRequest&lt;/code&gt; message to use &lt;code&gt;nickname&lt;/code&gt; instead of &lt;code&gt;name&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;greeter_server/main.go&lt;/code&gt;: update the &lt;code&gt;SayHello&lt;/code&gt; function to read and log the &lt;code&gt;Nickname&lt;/code&gt; field.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;greeter_client/main.go&lt;/code&gt;: update the &lt;code&gt;const&lt;/code&gt; and &lt;code&gt;var&lt;/code&gt; declarations to use &lt;code&gt;nickname&lt;/code&gt; (keep the final &lt;code&gt;GetMessage&lt;/code&gt; call as &lt;code&gt;GetMessage&lt;/code&gt;, since that is part of the &lt;code&gt;HelloReply&lt;/code&gt; message, not the request).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;helloworld/helloworld.proto&lt;/code&gt; should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="na"&gt;syntax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"proto3"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;option&lt;/span&gt; &lt;span class="na"&gt;go_package&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"google.golang.org/grpc/examples/helloworld/helloworld"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;option&lt;/span&gt; &lt;span class="na"&gt;java_multiple_files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;option&lt;/span&gt; &lt;span class="na"&gt;java_package&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"io.grpc.examples.helloworld"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;option&lt;/span&gt; &lt;span class="na"&gt;java_outer_classname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"HelloWorldProto"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;helloworld&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// The greeting service definition.&lt;/span&gt;
&lt;span class="kd"&gt;service&lt;/span&gt; &lt;span class="n"&gt;Greeter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Sends a greeting&lt;/span&gt;
  &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;SayHello&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HelloRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HelloReply&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;// The request message containing the nickname.&lt;/span&gt;
&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;HelloRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;nickname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// The response message containing the greetings&lt;/span&gt;
&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;HelloReply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&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;In &lt;code&gt;greeter_server/main.go&lt;/code&gt;, update the &lt;code&gt;SayHello&lt;/code&gt; implementation to read &lt;code&gt;in.GetNickname()&lt;/code&gt; and log it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// server is used to implement helloworld.GreeterServer.&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UnimplementedGreeterServer&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// SayHello implements helloworld.GreeterServer&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;SayHello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HelloRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HelloReply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Nickname Received: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetNickname&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HelloReply&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Hello "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetNickname&lt;/span&gt;&lt;span class="p"&gt;()},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;greeter_client/main.go&lt;/code&gt;, update the constants and flags to use &lt;code&gt;nickname&lt;/code&gt; instead of &lt;code&gt;name&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;address&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"localhost:50051"&lt;/span&gt;
    &lt;span class="n"&gt;defaultNickname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Linus"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;nickname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"nickname"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;defaultNickname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Nickname to send"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And when calling &lt;code&gt;SayHello&lt;/code&gt;, send the &lt;code&gt;Nickname&lt;/code&gt; field but keep reading the reply through &lt;code&gt;GetMessage&lt;/code&gt;, since the reply message was not modified:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SayHello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HelloRequest&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Nickname&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;nickname&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"could not greet: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Nickname: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetMessage&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Recompile the protobuf definition so the Go structs and gRPC stubs match our changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;protoc &lt;span class="nt"&gt;--go_out&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--go_opt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;paths&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;source_relative &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--go-grpc_out&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--go-grpc_opt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;paths&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;source_relative &lt;span class="se"&gt;\&lt;/span&gt;
    helloworld/helloworld.proto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; Run the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go run greeter_server/main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait until you see an output similar to this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;2026/01/21 22:05:25 server listening at [::]:50051
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Invoke a gRPC service from a client
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;5.&lt;/strong&gt; Open a new terminal and access the same running container using &lt;code&gt;docker exec&lt;/code&gt;. Once inside, run the client passing a &lt;code&gt;nickname&lt;/code&gt; value:&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;cd &lt;/span&gt;grpc-go/examples/helloworld
go run greeter_client/main.go &lt;span class="nt"&gt;--nickname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;linus2026
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Expected results
&lt;/h3&gt;

&lt;p&gt;Expected output on the server side:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Nickname Received: linus2026
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected output on the client side (or similar):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;2026/01/23 22:12:27 Nickname: linus2026
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion about gRPC Hello World
&lt;/h2&gt;

&lt;p&gt;This small exercise shows how easy it is to adapt the official gRPC Hello World example to fit a different use case, just by editing the &lt;code&gt;.proto&lt;/code&gt; file, regenerating the stubs with &lt;code&gt;protoc&lt;/code&gt;, and updating the server and client logic. Understanding this basic flow (proto definition → code generation → server implementation → client invocation) is the foundation for building more complex gRPC services in Go and other languages.&lt;/p&gt;

&lt;p&gt;Thanks for reading! Last to say, see you in my next blog post.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://killercoda.com/playgrounds/scenario/ubuntu" rel="noopener noreferrer"&gt;https://killercoda.com/playgrounds/scenario/ubuntu&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://grpc.io/docs/languages/go/quickstart/" rel="noopener noreferrer"&gt;https://grpc.io/docs/languages/go/quickstart/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/grpc/grpc-go" rel="noopener noreferrer"&gt;https://github.com/grpc/grpc-go&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>grpc</category>
      <category>cloudnative</category>
      <category>kubernetes</category>
      <category>containers</category>
    </item>
    <item>
      <title>Container Runtimes for Cloud Native Projects</title>
      <dc:creator>Sergio Méndez</dc:creator>
      <pubDate>Tue, 30 Jun 2026 01:46:31 +0000</pubDate>
      <link>https://dev.to/sergioarmgpl/container-runtimes-for-cloud-native-projects-5c5c</link>
      <guid>https://dev.to/sergioarmgpl/container-runtimes-for-cloud-native-projects-5c5c</guid>
      <description>&lt;p&gt;Hi, readers this time I want to show you different tools that you can use to create containers. We are going to explore Podman, Containerd and Youki, some projects coming from CNCF. The idea of this blog post is to use the best tool for containers based on your needs, and share some basics about how to use this tools in your cloud native projects.&lt;/p&gt;

&lt;p&gt;This blog post will focus on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Container Runtimes including Podman, Containerd and Youki.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  What you will learn
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Container Runtime Introduction&lt;/li&gt;
&lt;li&gt;Containerd installation&lt;/li&gt;
&lt;li&gt;Create a container with the containerd Go SDK&lt;/li&gt;
&lt;li&gt;Install nerdctl&lt;/li&gt;
&lt;li&gt;Using Compose with nerdctl&lt;/li&gt;
&lt;li&gt;Working with Podman&lt;/li&gt;
&lt;li&gt;Podman Compose&lt;/li&gt;
&lt;li&gt;Running Containers with youki&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Container Runtime Introduction
&lt;/h2&gt;

&lt;p&gt;For many developers, &lt;strong&gt;Docker&lt;/strong&gt; is synonymous with containers. It provides an excellent developer experience by combining image management, container execution, networking, and a familiar CLI into a single tool.&lt;/p&gt;

&lt;p&gt;However, modern Cloud Native platforms &lt;strong&gt;especially Kubernetes&lt;/strong&gt; have evolved beyond Docker as their default runtime. Today, most Kubernetes distributions rely on &lt;strong&gt;containerd&lt;/strong&gt;, while alternative tools like &lt;strong&gt;Podman&lt;/strong&gt; and &lt;strong&gt;nerdctl&lt;/strong&gt; provide different ways to build and manage containers. Underneath them all, OCI runtimes such as &lt;strong&gt;runc&lt;/strong&gt; and &lt;strong&gt;youki&lt;/strong&gt; are responsible for actually creating and running containers.&lt;/p&gt;

&lt;p&gt;Understanding how these technologies work together is an important skill for anyone working with Kubernetes, DevOps, or Platform Engineering.&lt;/p&gt;

&lt;p&gt;Let's summarize some container tools as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;containerd:&lt;/strong&gt; the container runtime used by most Kubernetes distributions.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;nerdctl:&lt;/strong&gt; A Docker-compatible CLI for containerd.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Podman:&lt;/strong&gt; A daemonless container engine with first-class rootless support.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;youki&lt;/strong&gt; A modern OCI runtime written in Rust.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's see how this tools are distributed in different abstraction layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;           Container CLI
      Docker CLI | nerdctl | Podman
                 │
          Container Engine
   Docker Engine | containerd
                 │
             OCI Runtime
            runc | youki
                 │
            Linux Kernel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each layer has a different responsibility:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Container Engine&lt;/strong&gt; manages images, networking, and container
lifecycle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OCI Runtime&lt;/strong&gt; creates and starts Linux containers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CLI tools&lt;/strong&gt; provide a user-friendly interface.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Containerd installation
&lt;/h2&gt;

&lt;p&gt;Let's asume that we are using Alpine, you have to activate the community repositories in order to install containerd for this run the following steps:&lt;br&gt;
&lt;strong&gt;1.&lt;/strong&gt; Edit &lt;strong&gt;/etc/apk/repositories&lt;/strong&gt; to uncomment the community repository&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vi /etc/apk/repositories
&lt;span class="c"&gt;# Uncomment the community repo for example the line will look like this&lt;/span&gt;
&lt;span class="c"&gt;# http://dl-cdn.alpinelinux.org/alpine/v3.23/community&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Update the repositories&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Install containerd&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apk add containerd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; Start containerd&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;service containerd start
containerd &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create a container with the containerd Go SDK
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Install Go in Alpine&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apk add git
apk add go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Create a directory to create your go code&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;cd&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;containerd-example
&lt;span class="nb"&gt;cd &lt;/span&gt;containerd-example
go mod init containerd/example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Install Containerd libraries to compile your example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go get github.com/containerd/containerd
go get github.com/containerd/containerd/cio
go get github.com/containerd/containerd/oci
go get github.com/containerd/containerd/namespaces
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; Create the code as &lt;strong&gt;main.go&lt;/strong&gt; file using the next content&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "context"
    "fmt"
    "log"
    "syscall"
    "time"

    "github.com/containerd/containerd"
    "github.com/containerd/containerd/cio"
    "github.com/containerd/containerd/oci"
    "github.com/containerd/containerd/namespaces"
)

func main() {
    if err := redisExample(); err != nil {
        log.Fatal(err)
    }
}

func redisExample() error {
    // create a new client connected to the default socket path for containerd
    client, err := containerd.New("/run/containerd/containerd.sock")
    if err != nil {
        return err
    }
    defer client.Close()

    // create a new context with an "example" namespace
    ctx := namespaces.WithNamespace(context.Background(), "example")

    // pull the redis image from DockerHub
    image, err := client.Pull(ctx, "docker.io/library/redis:alpine", containerd.WithPullUnpack)
    if err != nil {
        return err
    }

    // create a container
    container, err := client.NewContainer(
        ctx,
        "redis-server",
        containerd.WithImage(image),
        containerd.WithNewSnapshot("redis-server-snapshot", image),
        containerd.WithNewSpec(oci.WithImageConfig(image)),
    )
    if err != nil {
        return err
    }
    defer container.Delete(ctx, containerd.WithSnapshotCleanup)

    // create a task from the container
    task, err := container.NewTask(ctx, cio.NewCreator(cio.WithStdio))
    if err != nil {
        return err
    }
    defer task.Delete(ctx)

    // make sure we wait before calling start
    exitStatusC, err := task.Wait(ctx)
    if err != nil {
        fmt.Println(err)
    }

    // call start on the task to execute the redis server
    if err := task.Start(ctx); err != nil {
        return err
    }

    // sleep for a lil bit to see the logs
    time.Sleep(3 * time.Second)

    // kill the process and get the exit status
    if err := task.Kill(ctx, syscall.SIGTERM); err != nil {
        return err
    }

    // wait for the process to fully exit and print out the exit status

    status := &amp;lt;-exitStatusC
    code, _, err := status.Result()
    if err != nil {
        return err
    }
    fmt.Printf("redis-server exited with status: %d\n", code)

    return nil
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Install nerdctl
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Install nerdctl to use containerd&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apk add nerdctl
nerdctl &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Use nerdctl to create a container&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nerdctl run &lt;span class="nt"&gt;-d&lt;/span&gt; nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using Compose with nerdctl
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nerdctl compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
nerdctl compose ps
nerdctl compose logs &lt;span class="nt"&gt;-f&lt;/span&gt;
nerdctl compose build
nerdctl compose down
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Working with Podman
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Install Podman&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apk add podman
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Create a container using Podman&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;podman run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; List containers with Podman&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;podman ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Podman Compose
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;podman compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
podman compose ps
podman compose logs &lt;span class="nt"&gt;-f&lt;/span&gt;
podman compose down
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running Containers with youki
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Install youki dependencies&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apk add libseccomp curl

curl &lt;span class="nt"&gt;-sSfL&lt;/span&gt; https://github.com/youki-dev/youki/releases/download/v0.6.0/youki-0.6.0-&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="nt"&gt;-musl&lt;/span&gt;.tar.gz | &lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xzvC&lt;/span&gt; /usr/bin/ youki

youki &lt;span class="nt"&gt;--version&lt;/span&gt; &lt;span class="c"&gt;# Test youki installation&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; List containers created by youki&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;podman run &lt;span class="nt"&gt;--runtime&lt;/span&gt; /usr/bin/youki &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:80 nginx
youki list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion about Container Runtimes
&lt;/h2&gt;

&lt;p&gt;The Cloud Native ecosystem has become increasingly modular.&lt;br&gt;
Understanding how &lt;strong&gt;containerd&lt;/strong&gt;, &lt;strong&gt;nerdctl&lt;/strong&gt;, &lt;strong&gt;Podman&lt;/strong&gt;, and &lt;strong&gt;youki&lt;/strong&gt;&lt;br&gt;
work together helps you better understand how modern container&lt;br&gt;
platforms &lt;em&gt;and Kubernetes itself&lt;/em&gt; run workloads in production.&lt;/p&gt;

&lt;p&gt;Thanks for reading! Last to say, see you in my next blog post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Follow me
&lt;/h2&gt;

&lt;p&gt;These are my social networks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/sergioarmgpl" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/sergioarmgpl&lt;/a&gt;&lt;br&gt;
&lt;a href="https://sergiops.xyz" rel="noopener noreferrer"&gt;https://sergiops.xyz&lt;/a&gt;&lt;br&gt;
&lt;a href="https://x.com/sergioarmgpl" rel="noopener noreferrer"&gt;https://x.com/sergioarmgpl&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.instagram.com/sergioarmgpl/" rel="noopener noreferrer"&gt;https://www.instagram.com/sergioarmgpl/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please contribute to these awesome projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://containerd.io" rel="noopener noreferrer"&gt;https://containerd.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/containerd/nerdctl" rel="noopener noreferrer"&gt;https://github.com/containerd/nerdctl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://podman.io" rel="noopener noreferrer"&gt;https://podman.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youki-dev.github.io/youki" rel="noopener noreferrer"&gt;https://youki-dev.github.io/youki&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cloud</category>
      <category>devops</category>
      <category>tools</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>K3d &amp; K3s for local Kubernetes environments</title>
      <dc:creator>Sergio Méndez</dc:creator>
      <pubDate>Mon, 22 Jun 2026 22:59:10 +0000</pubDate>
      <link>https://dev.to/sergioarmgpl/k3d-k3s-for-local-kubernetes-environments-2611</link>
      <guid>https://dev.to/sergioarmgpl/k3d-k3s-for-local-kubernetes-environments-2611</guid>
      <description>&lt;p&gt;Hi, readers this time I want to explain how you can set up a local Kubernetes environment using K3s a lightweight distribution. For this we are going to use K3d to install K3s in you local machine. Specially if you are a developer would be nice to install this local and lightweight Kubernetes installed in your laptop.&lt;/p&gt;

&lt;p&gt;This blog post will focus on:&lt;br&gt;
Run a local Kubernetes environment using K3s&lt;/p&gt;
&lt;h2&gt;
  
  
  What you will learn
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Install K3d on a Linux environment&lt;/li&gt;
&lt;li&gt;Create a cluster using K3s with K3d&lt;/li&gt;
&lt;li&gt;Install Gateway API for the new cluster&lt;/li&gt;
&lt;li&gt;Create a Gateway and HttpRoute to expose a deployment&lt;/li&gt;
&lt;li&gt;Delete cluster using K3d&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are the topics that you will learn in this blog post.&lt;/p&gt;
&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Linux running on your device (Laptop, PC, etc)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Install K3s on a Linux environment
&lt;/h2&gt;

&lt;p&gt;Let's asume that you are using a Linux environment, for example Ubuntu. Now we are going to install k3d. For this follow the next steps:&lt;br&gt;
&lt;strong&gt;1.&lt;/strong&gt; Install K3d, the tool that we are going to use to run K3s using containers in your environment. For this run the following 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 &lt;span class="nt"&gt;-s&lt;/span&gt; https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Run the following command to return the K3d version installed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;k3d version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create a cluster using K3s with K3d
&lt;/h2&gt;

&lt;p&gt;With everything installed let's create a cluster with K3d which uses K3s internally to create a Kubernetes cluster using containers. For these follow the next steps:&lt;br&gt;
&lt;strong&gt;1.&lt;/strong&gt; Create a cluster with K3d without installing Traefik and the load balancer default service in K3s:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;k3d cluster create mycluster &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--no-lb&lt;/span&gt; &lt;span class="nt"&gt;--network&lt;/span&gt; host &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--k3s-arg&lt;/span&gt; &lt;span class="s1"&gt;'--disable=traefik@server:*'&lt;/span&gt; &lt;span class="nt"&gt;--k3s-arg&lt;/span&gt; &lt;span class="s1"&gt;'--disable=servicelb@server:*'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will show an output 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;INFO[0000] &lt;span class="o"&gt;[&lt;/span&gt;SimpleConfig] Hostnetwork selected - disabling injection of docker host into the cluster, server load balancer and setting the api port to the k3s default
INFO[0000] &lt;span class="o"&gt;[&lt;/span&gt;ClusterConfig] Hostnetwork selected - disabling injection of docker host into the cluster, server load balancer and setting the api port to the k3s default
INFO[0000] Prep: Network
INFO[0000] Re-using existing network &lt;span class="s1"&gt;'host'&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;....&lt;span class="o"&gt;)&lt;/span&gt;
INFO[0000] Created image volume k3d-mycluster-images
INFO[0000] Starting new tools node...
INFO[0000] Starting node &lt;span class="s1"&gt;'k3d-mycluster-tools'&lt;/span&gt;
INFO[0001] Creating node &lt;span class="s1"&gt;'k3d-mycluster-server-0'&lt;/span&gt;
INFO[0001] Using the k3d-tools node to gather environment information
INFO[0001] Starting cluster &lt;span class="s1"&gt;'mycluster'&lt;/span&gt;
INFO[0001] Starting servers...
INFO[0001] Starting node &lt;span class="s1"&gt;'k3d-mycluster-server-0'&lt;/span&gt;
INFO[0008] All agents already running.
INFO[0008] All helpers already running.
INFO[0008] Cluster &lt;span class="s1"&gt;'mycluster'&lt;/span&gt; created successfully!
INFO[0008] You can now use it like this:
kubectl cluster-info
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Troubleshoot the cluster with the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="c"&gt;#All the pods should appear with STATUS Running&lt;/span&gt;
kubectl get nodes &lt;span class="c"&gt;#Show all the nodes STATUS as Ready&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Install MetalLB to have a load balancer provisioner for your cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; https://raw.githubusercontent.com/metallb/metallb/v0.14.4/config/manifests/metallb-native.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; Found a range of IP Addresses to use for your load balancer for this, you can check the with the route command your available routes. Here is an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         sergioarmgpl.ms 0.0.0.0         UG    0      0        0 eth0
10.42.0.0       0.0.0.0         255.255.255.0   U     0      0        0 cni0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
172.29.192.0    0.0.0.0         255.255.240.0   U     0      0        0 eth0
192.168.122.0   0.0.0.0         255.255.255.0   U     0      0        0 virbr0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case we are going to use a cluster that use the internal network of the host that use the eth0 interface. You can also use an AI Tool(Like Gemini or Chatgpt to get a valid range to set for your IPAddressPool on MetalLB, in this case for the output &lt;br&gt;
"172.29.192.0    0.0.0.0         255.255.240.0   U     0      0        0 eth0" &lt;br&gt;
You can ask a valid range of 30 IP addresses. In this case we got the following range:&lt;br&gt;
172.29.206.120-172.29.206.150&lt;br&gt;
With that value we can create a IP address pool for MetalLB to have a range to assign for Load Balancer services in your cluster.&lt;br&gt;
&lt;strong&gt;5.&lt;/strong&gt; Create a IPAddress Pool with the previous range:&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;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl create -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: ip-pool
  namespace: metallb-system
spec:
  addresses:
  - 172.29.206.120-172.29.206.150
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: l2advertisement
  namespace: metallb-system
spec:
  ipAddressPools:
  - ip-pool
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Install Gateway API for the new cluster
&lt;/h2&gt;

&lt;p&gt;Now Let's install the Gateway API that is a common software used in the latest Kubernetes. For this follow the next steps:&lt;br&gt;
&lt;strong&gt;1.&lt;/strong&gt; Install the Gateway API CRDs for the NGINX Gateway Fabric, which is one of the Gateways available to expose application sharing a gateway for your applications:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl kustomize &lt;span class="s2"&gt;"https://github.com/nginx/nginx-gateway-fabric/config/crd/gateway-api/standard?ref=v2.4.2"&lt;/span&gt; | kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Install the NGINX Gateway Fabric:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm &lt;span class="nb"&gt;install &lt;/span&gt;ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric &lt;span class="nt"&gt;--create-namespace&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; nginx-gateway
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create a Gateway and HttpRoute to expose a deployment
&lt;/h2&gt;

&lt;p&gt;Now with everything installed let's create a Gateway and a HttpRoute to expose a webserver deployment. For this follow the next steps:&lt;br&gt;
&lt;strong&gt;1.&lt;/strong&gt; Create a deployment running NGINX called myapp, with a service using the port 80. The following commands create a namespace, a deployment, a service and a gateway:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: v1
kind: Namespace
metadata:
  creationTimestamp: null
  name: mynamespace
spec: {}
status: {}
---
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: myapp
  name: myapp
  namespace: mynamespace
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myapp
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: myapp
    spec:
      containers:
      - image: nginx
        name: nginx
        resources: {}
status: {}
---
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: myapp
  name: myapp
  namespace: mynamespace
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: myapp
  type: ClusterIP
status:
  loadBalancer: {}
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: mygateway
  namespace: mynamespace
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    port: 80
    protocol: HTTP
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Now create a HTTPRoute using the Load Balancer IP Created by the Service. For this run the following commands:&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;GW&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get svc mygateway-nginx &lt;span class="nt"&gt;-n&lt;/span&gt; mynamespace &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.status.loadBalancer.ingress[0].ip}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: approute
  namespace: mynamespace
spec:
  parentRefs:
  - name: mygateway
  hostnames:
  - "&lt;/span&gt;&lt;span class="nv"&gt;$GW&lt;/span&gt;&lt;span class="sh"&gt;.nip.io"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: myapp
      port: 80
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The previous commands set the IP Address created by the service in the variable GW, and use the value to create an HttpRoute, which uses nip.io free service to create a free URL as &lt;strong&gt;IP Address&lt;/strong&gt;.nip.io which resolves to the &lt;strong&gt;IP Address&lt;/strong&gt;.&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; Now access the NGINX deployment 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;curl http://&lt;span class="nv"&gt;$GW&lt;/span&gt;.nip.io 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a more advanced Gateway API configuration check the following link: &lt;a href="https://dev.to/sergioarmgpl/goodbye-ingress-hello-gateway-api-migrating-the-right-way-20k9"&gt;https://dev.to/sergioarmgpl/goodbye-ingress-hello-gateway-api-migrating-the-right-way-20k9&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Delete cluster using K3d
&lt;/h2&gt;

&lt;p&gt;To delete the cluster follow the next command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;k3d cluster delete mycluster
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; For more commands about K3d, you can run k3d in your CLI to get more commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion about K3d
&lt;/h2&gt;

&lt;p&gt;K3d is a nice tool that helps your to create quick and functional lightweight Kubernetes clusters using K3s. This tutorial covers the basics to create your how cluster. To customize it more, you need some basic of networking to play a little bit, but with this information you can do more than the basics. Also after writing this tutorial I discover that Talos Linux has a similar tool but doesn't include the metrics service in the cluster by default. Also not a big fan of MiniKube because runs slowly than K3s with K3d. Kind is also another good alternative but K3s feels more production ready. If you are looking to don't get your environment dirty with a lot of installation you can still have a clean system by using K3d, I can recommend it to use it for that quick dev environments using Kubernetes without using a lot of ran. Try to run K3s with K3d today, I am using this with my students in the university with really good results. Last to say, see you in my next blog post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Follow me
&lt;/h2&gt;

&lt;p&gt;These are my social networks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/sergioarmgpl" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/sergioarmgpl&lt;/a&gt;&lt;br&gt;
&lt;a href="https://sergiops.xyz" rel="noopener noreferrer"&gt;https://sergiops.xyz&lt;/a&gt;&lt;br&gt;
&lt;a href="https://x.com/sergioarmgpl" rel="noopener noreferrer"&gt;https://x.com/sergioarmgpl&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.instagram.com/sergioarmgpl/" rel="noopener noreferrer"&gt;https://www.instagram.com/sergioarmgpl/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please contribute to this awesome project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://k3d.io/" rel="noopener noreferrer"&gt;https://k3d.io/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Creating a RabbitMQ PubSub system with Dapr</title>
      <dc:creator>Sergio Méndez</dc:creator>
      <pubDate>Wed, 29 Apr 2026 16:09:22 +0000</pubDate>
      <link>https://dev.to/sergioarmgpl/creating-a-rabbit-pubsub-client-with-dapr-3h96</link>
      <guid>https://dev.to/sergioarmgpl/creating-a-rabbit-pubsub-client-with-dapr-3h96</guid>
      <description>&lt;p&gt;Hi, readers community, to continue with this series of blog posts, we are going to learn about how to use Dapr. Darp gives you a set of tools to write a event-driven runtime focusing on building resilient, stateless, and stateful applications that run on the cloud and edge. Also supports a   diversity of languages and developer frameworks. Thats more or less what Darp is based in the official documentation. So we can see it as a set of  building blocks to build your event-driven system. The idea in this blog post, is to give a quick tutorial about, how you can use Dapr to write a Publisher Subscriber system really fast and simple, without writing a lot of code. So Dapr, can speed your workday. This blog post will focus on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a PubSub System using Dapr SDK and RabbitMQ&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What you will learn
&lt;/h2&gt;

&lt;p&gt;In this blog post you will learn how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install Dapr in your cluster&lt;/li&gt;
&lt;li&gt;Install RabbitMQ to manage messages with Dapr&lt;/li&gt;
&lt;li&gt;Create a Publisher using the Golang Dapr SDK&lt;/li&gt;
&lt;li&gt;Create a Subscriber using the Golang Dapr SDK&lt;/li&gt;
&lt;li&gt;Use PubSub Dapr implementation
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are the topics that you will learn in this blog post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A Kubernetes cluster&lt;/li&gt;
&lt;li&gt;Access to the cluster using kubectl&lt;/li&gt;
&lt;li&gt;Internet Access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So let's get started with this tutorial. :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Dapr in your cluster:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Install the DAPR CLI with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget &lt;span class="nt"&gt;-q&lt;/span&gt; https://raw.githubusercontent.com/dapr/cli/master/install/install.sh &lt;span class="nt"&gt;-O&lt;/span&gt; - | /bin/bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Verify that the CLI was installed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dapr &lt;span class="nt"&gt;-h&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Install Dapr in Kubernetes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dapr init &lt;span class="nt"&gt;--kubernetes&lt;/span&gt;
dapr init &lt;span class="nt"&gt;--slim&lt;/span&gt; &lt;span class="c"&gt;# to install without default configurations&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; Verify the installation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dapr status &lt;span class="nt"&gt;-k&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5.&lt;/strong&gt; Access the Dashboard with the following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl port-forward svc/dapr-dashboard &lt;span class="nt"&gt;-n&lt;/span&gt; dapr-system 8080:8080 &lt;span class="nt"&gt;--address&lt;/span&gt; 0.0.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6.&lt;/strong&gt; Access the Dashboard in &lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt;   &lt;/p&gt;

&lt;h2&gt;
  
  
  Install RabbitMQ to manage messages with Dapr
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Install the RabbitMQ Operator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"https://github.com/rabbitmq/cluster-operator/releases/latest/download/cluster-operator.yml"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Create a cluster with the following YAML:&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;"apiVersion: rabbitmq.com/v1beta1
kind: RabbitmqCluster
metadata:
  name: mycluster"&lt;/span&gt; | kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you want labels you can use something 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="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"apiVersion: rabbitmq.com/v1beta1
kind: RabbitmqCluster
metadata:
  labels:
    app: rabbitmq
  annotations:
    some: annotation
  name: mycluster"&lt;/span&gt; | kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Get the user password for this RabbitMQ instance:&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;#To get the user&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; default get secret mycluster-default-user &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{.data.username}"&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;--decode&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;#To get the password&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; default get secret mycluster-default-user &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{.data.password}"&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;--decode&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; Now create the component to connect RabbitMQ to the Dapr installation using the previos USERNAME and PASSWORD:&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="s1"&gt;'apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: message-pub-sub
spec:
  type: pubsub.rabbitmq
  version: v1
  metadata:
  - name: connectionString
    value: "amqp://'&lt;/span&gt;&lt;span class="nv"&gt;$USERNAME&lt;/span&gt;:&lt;span class="nv"&gt;$PASSWORD&lt;/span&gt;@&lt;span class="s1"&gt;'mycluster:5672"
  - name: protocol
    value: amqp  
  - name: username
    value: '&lt;/span&gt;&lt;span class="nv"&gt;$USERNAME&lt;/span&gt;&lt;span class="s1"&gt;'
  - name: password
    value: '&lt;/span&gt;&lt;span class="nv"&gt;$PASSWORD&lt;/span&gt;&lt;span class="s1"&gt;'
  - name: hostname
    value: mycluster
  - name: durable
    value: "true"
  - name: maxLen
    value: 20
  - name: deletedWhenUnused
    value: "false"
  - name: autoAck
    value: "false"
  - name: reconnectWait
    value: "0"
  - name: concurrency
    value: parallel
scopes:
  - publisher
  - subscriber'&lt;/span&gt; | kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create a Publisher using the Golang Dapr SDK
&lt;/h2&gt;

&lt;p&gt;Now its time to create the publisher code and create a deployment with this code.&lt;br&gt;
&lt;strong&gt;1.&lt;/strong&gt; Create a container with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "net/http"   
    "context"
    "os"
    "log"
    "github.com/gin-gonic/gin"
    dapr "github.com/dapr/go-sdk/client"
)

type Message struct {
  Data     string    `json:"data"`
}

var (
    AppPort = getEnv("APP_PORT", "3500")
    PubsubName   = getEnv("PUBSUB_NAME", "mypubsub")
    TopicName    = getEnv("TOPIC_NAME", "mytopic")
)

func getEnv(key, fallback string) string {
    if value, ok := os.LookupEnv(key); ok {
        return value
    }
    return fallback
}

func publishHandler(c *gin.Context) {
    var message Message

    if err := c.ShouldBind(&amp;amp;message); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    log.Println("Published message with data: " + message.Data)
    PublishEvent(message.Data)

    c.JSON(http.StatusOK, gin.H{
        "message_data":     message.Data,
    })
}

func PublishEvent(data string) error {
    client, err := dapr.NewClient()
    if err != nil {
        panic(err)
    }
    defer client.Close()
    ctx := context.Background()
    //Using Dapr SDK to publish a topic
    if err := client.PublishEvent(ctx, PubsubName, TopicName, []byte(data)); err != nil {
        panic(err)
    }

    log.Println("Published %s to topic %s\n", data, TopicName)
    return nil
}

func main() {
    router := gin.Default()
    gin.SetMode(gin.DebugMode)
    router.Use(gin.Logger())
    router.POST("/publish", publishHandler)
    // Listen and serve on 0.0.0.0:&amp;lt;AppPort&amp;gt;
    router.Run(":"+AppPort)
    log.Println("Running Publisher Service")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Now create the deployment using the container that contains the previous code and applying the following YAML file:&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="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;creationTimestamp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&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;publisher&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;publisher&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;publisher&lt;/span&gt;
  &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&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;creationTimestamp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&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;publisher&lt;/span&gt;
      &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;dapr.io/enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
        &lt;span class="na"&gt;dapr.io/app-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;publisher"&lt;/span&gt;
        &lt;span class="na"&gt;dapr.io/app-port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;4500"&lt;/span&gt;
        &lt;span class="na"&gt;dapr.io/enable-api-logging&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&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;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;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;REGISTRY_USER&amp;gt;/&amp;lt;IMAGE&amp;gt;:TAG&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;dapr-go-publisher&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;4500&lt;/span&gt;
        &lt;span class="na"&gt;env&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;APP_PORT&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;4500"&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;PUBSUB_NAME&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message-pub-sub"&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;TOPIC_NAME&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages"&lt;/span&gt;
        &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;span class="nn"&gt;---&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;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;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;publisher&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;publisher&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;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;publisher&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;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&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;4500&lt;/span&gt;
    &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4500&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;ClusterIP&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This code creates the deployment and the service need to run the publisher. Take a look that we use the following annotations:&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="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;dapr.io/enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
        &lt;span class="na"&gt;dapr.io/app-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;publisher"&lt;/span&gt;
        &lt;span class="na"&gt;dapr.io/app-port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;4500"&lt;/span&gt;
        &lt;span class="na"&gt;dapr.io/enable-api-logging&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These annotations enable the integration of Dapr in your deployment without coding anything. Now your Publisher is ready and running. Let's continue with the Subscriber deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a Subscriber using the Golang Dapr SDK
&lt;/h2&gt;

&lt;p&gt;In this part you are going to run the subscriber. We also use the Dapr SDK to create a subscription using code and the SDK and not a declarative YAML file. &lt;br&gt;
&lt;strong&gt;1.&lt;/strong&gt; Create the subscriber container using the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "log"
    "net/http"
    "context"
    "os"
    "github.com/dapr/go-sdk/service/common"
    daprd "github.com/dapr/go-sdk/service/http"
)


var sub = &amp;amp;common.Subscription{
    PubsubName: getEnv("PUBSUB_NAME", "mypubsub"),
    Topic:      getEnv("TOPIC_NAME", "mytopic"),
    Route:      "/subscriber",
}

func getEnv(key, fallback string) string {
    if value, ok := os.LookupEnv(key); ok {
        return value
    }
    return fallback
}

func main() {
    s := daprd.NewService(":6002")
   //Subscribe to a topic
    if err := s.AddTopicEventHandler(sub, eventHandler); err != nil {
        log.Fatalf("error adding topic subscription: %v", err)
    }
    log.Printf("Subscriber listening")
    if err := s.Start(); err != nil &amp;amp;&amp;amp; err != http.ErrServerClosed {
        log.Fatalf("error listenning: %v", err)
    }
}

func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool, err error) {
    log.Printf("Subscriber message received: %s", e.Data)
    return false, nil
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Now create a deployment using the following YAML file:&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="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;creationTimestamp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&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;subscriber&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;subscriber&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;subscriber&lt;/span&gt;
  &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&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;creationTimestamp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&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;subscriber&lt;/span&gt;
      &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;dapr.io/enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
        &lt;span class="na"&gt;dapr.io/app-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;subscriber"&lt;/span&gt;
        &lt;span class="na"&gt;dapr.io/app-port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;6002"&lt;/span&gt;
        &lt;span class="na"&gt;dapr.io/enable-api-logging&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&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;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;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;REGISTRY_USER&amp;gt;/&amp;lt;IMAGE&amp;gt;:TAG&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;dapr-go-subscriber&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;6002&lt;/span&gt;
        &lt;span class="na"&gt;env&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;PUBSUB_NAME&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message-pub-sub"&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;TOPIC_NAME&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages"&lt;/span&gt;
        &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;span class="nn"&gt;---&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;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;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;subscriber&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;subscriber&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;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;subscriber&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;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&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;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6002&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;ClusterIP&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This code create the subscriber you can modify the code to change the topic and the pubsub name.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use PubSub Dapr implementation
&lt;/h2&gt;

&lt;p&gt;To use the system you have to run the following commands to check logs, access and access the API. Let's check these commands:&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;1.&lt;/em&gt; Check the logs of the subscriber and publisher on real time with following commands using different terminals:&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;#open logs for publisher&lt;/span&gt;
kubectl logs deploy/publisher &lt;span class="nt"&gt;--all-containers&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;-f&lt;/span&gt;
&lt;span class="c"&gt;#open logs for subscriber&lt;/span&gt;
kubectl logs deploy/subscriber--all-containers&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Expose the Publisher API to send data to the PubSub which uses RabbitMQ&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl port-forward svc/publisher 4500:4500 &lt;span class="nt"&gt;--address&lt;/span&gt; 0.0.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Use curl to insert data using the publisher running this 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 &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:4500/publish &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"data": "data1"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; Check the logs in your terminals you will see messages like these:&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;#for the subscriber&lt;/span&gt;
2026/04/30 00:30:11 Subscriber message received: somedata...
&lt;span class="c"&gt;#for the publisher&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;GIN] 2026/04/30 - 00:30:31 | 200 |   1.48ms |       127.0.0.1 | POST     &lt;span class="s2"&gt;"/publish"&lt;/span&gt;
2026/04/30 00:30:31 Successfully published to topic messages
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it, your system is running.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Repository
&lt;/h2&gt;

&lt;p&gt;If you can check the containers code, you can check the repo in the following link:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/sergioarmgpl/dapr-rabbit-example" rel="noopener noreferrer"&gt;https://github.com/sergioarmgpl/dapr-rabbit-example&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion about Dapr
&lt;/h2&gt;

&lt;p&gt;Dapr is an interesting project that can speed your work when you are designing and implementing an event-driven system. Also support different languages that developer can use to implement this kind of systems. Dapr can simplify the adoption of different technologies and solve architecture design and implementation to implement a robust system for your needs. Also I think that there is some lack of documentation for Kubernetes, but if you can take time to play with it you can achieve robust and nice implementation. At the end of this post there are some links including ones in the official documentation that I used to create this blog post. I want to mention that my students in USAC University in Guatemala in the operating systems courses are going to use this tutorial, that's so cool. Maybe my next blog post will be related to microcks to continue with the journey of cloud native stuff.&lt;/p&gt;

&lt;p&gt;See you in my next blog post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Follow me
&lt;/h2&gt;

&lt;p&gt;These are my social networks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/sergioarmgpl" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/sergioarmgpl&lt;/a&gt;&lt;br&gt;
&lt;a href="https://sergiops.xyz" rel="noopener noreferrer"&gt;https://sergiops.xyz&lt;/a&gt;&lt;br&gt;
&lt;a href="https://x.com/sergioarmgpl" rel="noopener noreferrer"&gt;https://x.com/sergioarmgpl&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.instagram.com/sergioarmgpl/" rel="noopener noreferrer"&gt;https://www.instagram.com/sergioarmgpl/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please contribute to this awesome project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dapr.io/" rel="noopener noreferrer"&gt;https://dapr.io/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Useful links:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://oneuptime.com/blog/post/2026-02-09-dapr-pubsub-event-driven-kubernetes/view" rel="noopener noreferrer"&gt;https://oneuptime.com/blog/post/2026-02-09-dapr-pubsub-event-driven-kubernetes/view&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dapr/quickstarts/tree/master/tutorials/hello-kubernetes/" rel="noopener noreferrer"&gt;https://github.com/dapr/quickstarts/tree/master/tutorials/hello-kubernetes/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.dapr.io/developing-applications/building-blocks/pubsub/howto-publish-subscribe/" rel="noopener noreferrer"&gt;https://docs.dapr.io/developing-applications/building-blocks/pubsub/howto-publish-subscribe/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.dapr.io/developing-applications/building-blocks/pubsub/pubsub-bulk/" rel="noopener noreferrer"&gt;https://docs.dapr.io/developing-applications/building-blocks/pubsub/pubsub-bulk/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.dapr.io/developing-applications/sdks/rust/rust-client/" rel="noopener noreferrer"&gt;https://docs.dapr.io/developing-applications/sdks/rust/rust-client/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>architecture</category>
      <category>microservices</category>
      <category>tutorial</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Goodbye Ingress, Hello Gateway API: Migrating the Right Way</title>
      <dc:creator>Sergio Méndez</dc:creator>
      <pubDate>Fri, 27 Mar 2026 00:48:48 +0000</pubDate>
      <link>https://dev.to/sergioarmgpl/goodbye-ingress-hello-gateway-api-migrating-the-right-way-20k9</link>
      <guid>https://dev.to/sergioarmgpl/goodbye-ingress-hello-gateway-api-migrating-the-right-way-20k9</guid>
      <description>&lt;p&gt;Hi, dear community of readers, continuing with this blog posts to learn called Learning Kubernetes, this time is the time to learn about how to use the Gateway API. Now all the teams are looking to migrate, so my goal with this post is to help you with a quick start guide to understand and use the Gateway API with the implementation created by NGINX. I know that a lot of people used the NGINX Ingress Controller in their clusters, so makes sense to continue in that way but using the Gateway API. So let's summarize my goals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start using Gateway API&lt;/li&gt;
&lt;li&gt;Setup a functional Gateway API with NGINX for your services
So let's start with this content, I know you want to now how to use the Gateway API.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What you will learn
&lt;/h2&gt;

&lt;p&gt;In this blog post you will learn how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install the Gateway API &amp;amp; NGINX Gateway Fabric&lt;/li&gt;
&lt;li&gt;Create and use Gateways and HTTP Routes&lt;/li&gt;
&lt;li&gt;Configure Cert-Manager for TLS for your Gateways&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A Kubernetes Cluster&lt;/li&gt;
&lt;li&gt;Access to the cluster using kubectl&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Install the Gateway API &amp;amp; NGINX Gateway Fabric
&lt;/h2&gt;

&lt;p&gt;To install the Gateway API &amp;amp; NGINX Gateway Fabric follow these steps:&lt;br&gt;
&lt;strong&gt;1.&lt;/strong&gt; Install Gateway API &amp;amp; NGINX Gateway Fabric CRDs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl kustomize &lt;span class="s2"&gt;"https://github.com/nginx/nginx-gateway-fabric/config/crd/gateway-api/standard?ref=v2.4.2"&lt;/span&gt; | kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Install the NGINX Gateway Fabric using Helm&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm &lt;span class="nb"&gt;install &lt;/span&gt;ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric &lt;span class="nt"&gt;--create-namespace&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; nginx-gateway
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create and use Gateways and HTTP Routes
&lt;/h2&gt;

&lt;p&gt;Now let's create a simple deployment wiht a Gateway and HTTP Route by following the next steps:&lt;br&gt;
&lt;strong&gt;1.&lt;/strong&gt; Install the following application waiting for the Public api created by the Gateway :&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;kubectl apply -f - &amp;lt;&amp;lt;EOF&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;Namespace&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;creationTimestamp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&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;mynamespace&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;span class="nn"&gt;---&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;creationTimestamp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&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;myapp&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;myapp&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mynamespace&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;myapp&lt;/span&gt;
  &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&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;creationTimestamp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&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;myapp&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;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;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&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;nginx&lt;/span&gt;
        &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;span class="nn"&gt;---&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;creationTimestamp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&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;myapp&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;myapp&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mynamespace&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;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;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
    &lt;span class="na"&gt;targetPort&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;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;myapp&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;ClusterIP&lt;/span&gt;
&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;loadBalancer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;span class="nn"&gt;---&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;gateway.networking.k8s.io/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;Gateway&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;mygateway&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mynamespace&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;gatewayClassName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
  &lt;span class="na"&gt;listeners&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;http&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;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HTTP&lt;/span&gt;
&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Get the IP assigned to the Gateway using the following command:&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;GW&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get svc mygateway-nginx &lt;span class="nt"&gt;-n&lt;/span&gt; mynamespace &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.status.loadBalancer.ingress[0].ip}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You have to wait for some minutes in order that the cloud provider assign an external IP to the Gateway created.&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; Create the route to expose the application:&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;kubectl apply -f - &amp;lt;&amp;lt;EOF&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;gateway.networking.k8s.io/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;HTTPRoute&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;approute&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mynamespace&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;parentRefs&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;mygateway&lt;/span&gt;
  &lt;span class="na"&gt;hostnames&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$GW.nip.io"&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path&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;PathPrefix&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
    &lt;span class="na"&gt;backendRefs&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;myapp&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="s"&gt;EOF&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; Test the Application by using curl as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://&lt;span class="nv"&gt;$GW&lt;/span&gt;.nip.io
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it now it works, now let's move on using TLS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure Cert-Manager for TLS for your Gateways
&lt;/h2&gt;

&lt;p&gt;Now let's configure the Cert-Manage to generate a certificate for your app by following these steps:&lt;br&gt;
&lt;strong&gt;0. (Optional)&lt;/strong&gt; Delete the previous gateway and route as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete gateway mygateway &lt;span class="nt"&gt;-n&lt;/span&gt; mynamespace
kubectl delete httproute approute &lt;span class="nt"&gt;-n&lt;/span&gt; mynamespace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Add the cert-manager helm chart&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm repo add jetstack https://charts.jetstack.io
helm repo update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Add the cert-manager helm chart&lt;br&gt;
Install the cert-manager, and enable the GatewayAPI feature gate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  cert-manager jetstack/cert-manager &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--namespace&lt;/span&gt; cert-manager &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--create-namespace&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; config.apiVersion&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"controller.config.cert-manager.io/v1alpha1"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; config.kind&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"ControllerConfiguration"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; config.enableGatewayAPI&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; crds.enabled&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Create a ClusterIssuer to use to generate your certicate:&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;EMAIL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your_name@domain.tld"&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    email: &lt;/span&gt;&lt;span class="nv"&gt;$EMAIL&lt;/span&gt;&lt;span class="sh"&gt;
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: issuer-account-key
    solvers:
    - http01:
        gatewayHTTPRoute:
          parentRefs:
          - name: gateway
            namespace: default
            kind: Gateway
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; For self signed TLS use this file:&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="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cert-manager.io/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;ClusterIssuer&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;selfsigned-issuer&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;selfSigned&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; Change your current Gateway as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: mygateway
  namespace: mynamespace
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    port: 80
    protocol: HTTP
  - name: https
    hostname: "&lt;/span&gt;&lt;span class="nv"&gt;$GW&lt;/span&gt;&lt;span class="sh"&gt;.nip.io"
    port: 443
    protocol: HTTPS
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        name: tls-secret
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; For internal TLS use self-signed certificates in the cert-manager.io/cluster-issuer as selfsigned-issuer, also use the previous GW value the first time, then check for the service called mygateway-nginx using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get svc &lt;span class="nt"&gt;-n&lt;/span&gt; mynamespace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then update the value GW with the following command:&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;GW&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get svc mygateway-nginx &lt;span class="nt"&gt;-n&lt;/span&gt; mynamespace &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.status.loadBalancer.ingress[0].ip}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And apply the YAML again to point to the correct URL.&lt;br&gt;
&lt;strong&gt;5.&lt;/strong&gt; Now modify your HTTP Route as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: approute
  namespace: mynamespace
spec:
  parentRefs:
  - name: mygateway
    sectionName: https
  hostnames:
  - "&lt;/span&gt;&lt;span class="nv"&gt;$GW&lt;/span&gt;&lt;span class="sh"&gt;.nip.io"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: myapp
      port: 80
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6.&lt;/strong&gt; Now test your application by running the following 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://&lt;span class="nv"&gt;$GW&lt;/span&gt;.nip.io
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it, now you have learned how to use the Gateway API with the NGINX Fabric Gateway implementation using also TLS with Cert-Manager. Take a look to the Links in the references for more theory and examples, of course if you need something more complicated :).&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gateway-api.sigs.k8s.io/" rel="noopener noreferrer"&gt;https://gateway-api.sigs.k8s.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.nginx.com/nginx-gateway-fabric/install/helm" rel="noopener noreferrer"&gt;https://docs.nginx.com/nginx-gateway-fabric/install/helm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.nginx.com/nginx-gateway-fabric/traffic-management/basic-routing/" rel="noopener noreferrer"&gt;https://docs.nginx.com/nginx-gateway-fabric/traffic-management/basic-routing/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.nginx.com/nginx-gateway-fabric/get-started/#install-nginx-gateway-fabric" rel="noopener noreferrer"&gt;https://docs.nginx.com/nginx-gateway-fabric/get-started/#install-nginx-gateway-fabric&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.nginx.com/nginx-gateway-fabric/traffic-security/integrate-cert-manager/" rel="noopener noreferrer"&gt;https://docs.nginx.com/nginx-gateway-fabric/traffic-security/integrate-cert-manager/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Ingress API itself is NOT deprecated. The GA Ingress API (&lt;code&gt;networking.k8s.io/v1&lt;/code&gt;) remains fully supported in Kubernetes. You can still create and use Ingress resources without any issue.&lt;br&gt;
• Ingress controllers as a category are NOT deprecated. Only the specific &lt;code&gt;ingress-nginx&lt;/code&gt; project (maintained by Kubernetes SIG Network) was retired. Alternatives like Traefik, Kong, HAProxy, and others are alive and well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion about the Gateway API with NGINX
&lt;/h2&gt;

&lt;p&gt;Well, a lot of companies are getting into chaos because that Kubernetes deprecate the ingress-nginx project maintained by Kubernetes SIG Network.  But Ingress API itself is NOT deprecated, (&lt;code&gt;networking.k8s.io/v1&lt;/code&gt;) remains fully supported in Kubernetes. I want to clarify that Ingress controllers as a category are NOT deprecated. Alternatives like Traefik, Kong, HAProxy, and others still alive. Also my experience configuring the Gateway API, it was not as complicated for simple configuration like the one I showed in the post. I hope this can help as an initial configuration that you can expand for your needs. Well this Gateway API is the future for Kubernetes to have something more stable to manage. I am curious to test another implementations. But it seems that works, maybe the documentation is not as well designed but you can find the necessary parts that you need in the links before. Thanks to Chad M. Crowell to clarify the whole context about how the state of the Gateway API and Ingress Controllers are right now.&lt;/p&gt;

&lt;p&gt;So what implementation of Gateway API are you going to use, write a comment below :). &lt;/p&gt;

&lt;p&gt;That a lot for me this time, see you the next one. I hope so hehehe.&lt;/p&gt;

&lt;h2&gt;
  
  
  Follow me
&lt;/h2&gt;

&lt;p&gt;These are my social networks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/sergioarmgpl" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/sergioarmgpl&lt;/a&gt;&lt;br&gt;
&lt;a href="https://sergiops.xyz" rel="noopener noreferrer"&gt;https://sergiops.xyz&lt;/a&gt;&lt;br&gt;
&lt;a href="https://x.com/sergioarmgpl" rel="noopener noreferrer"&gt;https://x.com/sergioarmgpl&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.instagram.com/sergioarmgpl/" rel="noopener noreferrer"&gt;https://www.instagram.com/sergioarmgpl/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>ingress</category>
      <category>nginx</category>
      <category>cloudnative</category>
    </item>
    <item>
      <title>KubeVirt to run VMs in your K8s cluster</title>
      <dc:creator>Sergio Méndez</dc:creator>
      <pubDate>Fri, 19 Dec 2025 23:23:14 +0000</pubDate>
      <link>https://dev.to/sergioarmgpl/kubevirt-to-run-vms-in-your-k8s-cluster-4jh4</link>
      <guid>https://dev.to/sergioarmgpl/kubevirt-to-run-vms-in-your-k8s-cluster-4jh4</guid>
      <description>&lt;p&gt;Hi, dear readers I am starting a new series of blog posts called Learning Kubernetes with different complementing the traditional knowledge of Kubernetes. In this first post that I am going to share with my students in the university is about how to use KubeVirt in Kubernetes. One of my main topics in my course is virtualization so let me summarize my goals for writing this blog post:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use VMs in container environments&lt;/li&gt;
&lt;li&gt;Test how easy to use is KubeVirt&lt;/li&gt;
&lt;li&gt;Customize my own VMs on a Kubernetes environment&lt;/li&gt;
&lt;li&gt;Install KubeVirt on any Cloud Provider(GCP in specific)
So let's start with the tutorial using KubeVirt. Let's have fun.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What you will learn
&lt;/h2&gt;

&lt;p&gt;In this blog post you will learn how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install KubeVirt bypassing the default requirements&lt;/li&gt;
&lt;li&gt;Create a custom VM image in qcow2 with Qemu&lt;/li&gt;
&lt;li&gt;Package your qcow2 image in a container image&lt;/li&gt;
&lt;li&gt;Create a VM and expose VM services in KubeVirt&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A GKE cluster (Kubernetes cluster managed by Google Cloud) with N1 virtual machine type with nested virtualization enabled&lt;/li&gt;
&lt;li&gt;Access to the cluster using kubectl&lt;/li&gt;
&lt;li&gt;Preinstalled qemu in your distro (Let's asume Ubuntu)
So let's get started with this tutorial. :)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Install KubeVirt bypassing the default requirements
&lt;/h3&gt;

&lt;p&gt;To install KubeVirt get the KubeVirt latest stable version running the following steps:&lt;br&gt;
&lt;strong&gt;1.&lt;/strong&gt; Download the kubevirt-operator.yaml file and remove the affinity and tolerations:&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;VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://storage.googleapis.com/kubevirt-prow/release/kubevirt/kubevirt/stable.txt&lt;span class="si"&gt;)&lt;/span&gt;
wget https://github.com/kubevirt/kubevirt/releases/download/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/kubevirt-operator.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This downloads the kubevirt-operator.yaml file that you have to change to install the operator in any cloud provider like GKE, AKS or EKS. You have to change this file to remove the affinity and tolerations that the operator looks to deploy its components. KubeVirt looks for a control-plane node for security reason to deploy the operator.&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; Install the operator with the modified kubevirt-operator.yaml file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create &lt;span class="nt"&gt;-f&lt;/span&gt; kubevirt-operator.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Create a KubeVirt definition to deploy the custom resource definitions:&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;cat &amp;lt;&amp;lt; END &amp;gt; kubevirt-cr.yaml&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;kubevirt.io/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;KubeVirt&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;kubevirt&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kubevirt&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;certificateRotateStrategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
  &lt;span class="na"&gt;configuration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;developerConfiguration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;featureGates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
  &lt;span class="na"&gt;customizeComponents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
  &lt;span class="na"&gt;imagePullPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;IfNotPresent&lt;/span&gt;
  &lt;span class="na"&gt;workloadUpdateStrategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
  &lt;span class="na"&gt;infra&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;nodePlacement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
  &lt;span class="na"&gt;workloads&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;nodePlacement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;span class="s"&gt;END&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you want emulation add the following configuration in developerConfiguration as follows:&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="na"&gt;developerConfiguration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;useEmulation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;featureGates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; Deploy the definitions&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; kubevirt-cr.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5.&lt;/strong&gt; Wait for the deployments to be ready you&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get all &lt;span class="nt"&gt;-n&lt;/span&gt; kubevirt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create a custom VM image in qcow2 with Qemu
&lt;/h3&gt;

&lt;p&gt;Assuming that you have an Ubuntu OS run the following steps:&lt;br&gt;
&lt;strong&gt;1.&lt;/strong&gt; Install Qemu:&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;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;qemu-kvm qemu-utils libvirt-daemon-system libvirt-clients bridge-utils
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; In a directory create a disk for your VM, we are going to use Alpine for our VM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;qemu-img create &lt;span class="nt"&gt;-f&lt;/span&gt; qcow2 alpine_disk.qcow2 1G
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Download the ISO image for your Alpine VM&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget https://dl-cdn.alpinelinux.org/alpine/v3.23/releases/x86_64/alpine-standard-3.23.2-x86_64.iso
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; Start the new Qemu VM and install the OS:&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;sudo &lt;/span&gt;qemu-system-x86_64 &lt;span class="nt"&gt;-enable-kvm&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; 2G &lt;span class="nt"&gt;-cpu&lt;/span&gt; host &lt;span class="nt"&gt;-smp&lt;/span&gt; 2 &lt;span class="nt"&gt;-cdrom&lt;/span&gt; alpine-standard-3.22.0-x86_64.iso &lt;span class="nt"&gt;-drive&lt;/span&gt; &lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;alpine_disk.qcow2,format&lt;span class="o"&gt;=&lt;/span&gt;qcow2 &lt;span class="nt"&gt;-boot&lt;/span&gt; d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5.&lt;/strong&gt; Boot from disk instead of the CD-ROM and install your software:&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;sudo &lt;/span&gt;qemu-system-x86_64   &lt;span class="nt"&gt;-enable-kvm&lt;/span&gt;   &lt;span class="nt"&gt;-m&lt;/span&gt; 2G   &lt;span class="nt"&gt;-cpu&lt;/span&gt; host   &lt;span class="nt"&gt;-smp&lt;/span&gt; 2   &lt;span class="nt"&gt;-drive&lt;/span&gt; &lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;alpine_disk.qcow2,format&lt;span class="o"&gt;=&lt;/span&gt;qcow2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6.&lt;/strong&gt; Your new image alpine_disk.qcow2 its ready to be used.&lt;/p&gt;

&lt;h3&gt;
  
  
  Package your qcow2 image in a container image
&lt;/h3&gt;

&lt;p&gt;Assuming that you have a Docker Hub user and you are login in your account run the following steps:&lt;br&gt;
&lt;strong&gt;1.&lt;/strong&gt; Create the Dockerfile to package for image&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;cat &amp;lt;&amp;lt; END &amp;gt; Dockerfile
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; scratch&lt;/span&gt;
&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="s"&gt; --chown=107:107 alpine_disk.qcow2 /disk/&lt;/span&gt;
END
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Tag you image with your Docker user&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; &amp;lt;docker_hub_user&amp;gt;/alpineimage:latest &lt;span class="nb"&gt;.&lt;/span&gt;
docker push &amp;lt;docker_hub_user&amp;gt;/alpineimage:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create a VM a expose VM services in KubeVirt
&lt;/h3&gt;

&lt;p&gt;To create a basic KubeVirt VM follow the next steps:&lt;br&gt;
&lt;strong&gt;1.&lt;/strong&gt; Create the KubeVirt VM definition&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;cat &amp;lt;&amp;lt; END &amp;gt; vm.yaml&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;kubevirt.io/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;VirtualMachine&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;alpinevm&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;runStrategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Halted&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;kubevirt.io/size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;medium&lt;/span&gt;
        &lt;span class="na"&gt;kubevirt.io/domain&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alpineso1&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;domain&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;devices&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;disks&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;containerdisk&lt;/span&gt;
              &lt;span class="na"&gt;disk&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;bus&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;virtio&lt;/span&gt;
          &lt;span class="na"&gt;interfaces&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;default&lt;/span&gt;
            &lt;span class="na"&gt;masquerade&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
        &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;cores&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;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1Gi&lt;/span&gt;
      &lt;span class="na"&gt;networks&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;default&lt;/span&gt;
        &lt;span class="na"&gt;pod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
      &lt;span class="na"&gt;volumes&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;containerdisk&lt;/span&gt;
          &lt;span class="na"&gt;containerDisk&lt;/span&gt;&lt;span class="pi"&gt;:&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;&amp;lt;docker_hub_user&amp;gt;/alpineimage&lt;/span&gt;
&lt;span class="s"&gt;END&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Apply the definition&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; vm.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Check for the vm to be created&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get vms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see the VM in the stopped state&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; Install virtctl CLI&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;VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get kubevirt.kubevirt.io/kubevirt &lt;span class="nt"&gt;-n&lt;/span&gt; kubevirt &lt;span class="nt"&gt;-o&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{.status.observedKubeVirtVersion}"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; | &lt;span class="nb"&gt;tr &lt;/span&gt;A-Z a-z&lt;span class="si"&gt;)&lt;/span&gt;-&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/x86_64/amd64/'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; windows-amd64.exe
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
curl &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; virtctl https://github.com/kubevirt/kubevirt/releases/download/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/virtctl-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;sudo install&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; 0755 virtctl /usr/local/bin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5.&lt;/strong&gt; Start 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;virtctl start alpinevm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6.&lt;/strong&gt; Expose any service you have on 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;virtctl expose vm alpinevm &lt;span class="nt"&gt;--port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;PORT_NUMBER&amp;gt; &lt;span class="nt"&gt;--name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;NEW_SERVICE_NAME&amp;gt; &lt;span class="nt"&gt;--type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ClusterIP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;7.&lt;/strong&gt; Now you can access the service of your VM in any Kubernetes Pod, Deployment, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion about KubeVirt
&lt;/h2&gt;

&lt;p&gt;KubeVirt is a technology that can be used when your applications are difficult to convert to containers or there is an specific situation where containers are not suitable to be used. Also for security reasons some systems prefer the use of VMs instead of containers and already have a Kubernetes environment that should interact with this VMs.&lt;/p&gt;

&lt;p&gt;KubeVirt its an option option for VMs. In the university, we are testing KubeVirt to run some experiments with cloud native technologies. It was nice to create a VM using Qemu again and see that virtual machines needs to be used also in containerized environments. So it was a nice experience playing with KubeVirt a little bit.&lt;/p&gt;

&lt;p&gt;See you on my next post with something interesting again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Follow me
&lt;/h2&gt;

&lt;p&gt;These are my social networks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/sergioarmgpl" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/sergioarmgpl&lt;/a&gt;&lt;br&gt;
&lt;a href="https://sergiops.xyz" rel="noopener noreferrer"&gt;https://sergiops.xyz&lt;/a&gt;&lt;br&gt;
&lt;a href="https://x.com/sergioarmgpl" rel="noopener noreferrer"&gt;https://x.com/sergioarmgpl&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.instagram.com/sergioarmgpl/" rel="noopener noreferrer"&gt;https://www.instagram.com/sergioarmgpl/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please contribute to this awesome project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kubevirt.io" rel="noopener noreferrer"&gt;https://kubevirt.io&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>beginners</category>
      <category>googlecloud</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Zot and ORAS to create &amp; manage edge container registries</title>
      <dc:creator>Sergio Méndez</dc:creator>
      <pubDate>Mon, 17 Mar 2025 06:00:00 +0000</pubDate>
      <link>https://dev.to/sergioarmgpl/zot-and-oras-to-create-manage-edge-container-registries-3kam</link>
      <guid>https://dev.to/sergioarmgpl/zot-and-oras-to-create-manage-edge-container-registries-3kam</guid>
      <description>&lt;p&gt;Hi dear readers after been busy the last two weeks, I am back for Day 3 of my series &lt;strong&gt;30DaysOfIoTEdge&lt;/strong&gt;. Now it's time to learn about a container registry that you can run on devices with ARM microprocessors and that is compatible with OCI artifacts.&lt;/p&gt;

&lt;p&gt;As the CNCF website on the &lt;strong&gt;sandbox projects&lt;/strong&gt; page says &lt;strong&gt;&lt;em&gt;"Zot is an OCI-native container registry for distributing container images and OCI artifacts"&lt;/em&gt;&lt;/strong&gt;. This means that you can not just only push containers or helm charts in your registry, but also you can push any type of file. For example, configuration files, ML models, images, etc. So you can deploy something similar to Docker Hub. But is completely free to use, as common in open source software. Check its official website for more in deep information about this project: &lt;a href="https://zotregistry.dev/" rel="noopener noreferrer"&gt;https://zotregistry.dev/&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Based on the edu.chainguard.dev website and OCI artifact is &lt;strong&gt;&lt;em&gt;"OCI artifacts are a way of using OCI registries, or container registries that are compliant with specifications set by the Open Container Initiative, to store arbitrary files."&lt;/em&gt;&lt;/strong&gt;. Now we are clear that we can use the registries as a way to store. Something similar to having your own S3 storage. So let's start with the technical side of my blog post.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you will learn
&lt;/h2&gt;

&lt;p&gt;In this blog post you will learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install Zot on ARM Devices (like a RPi).&lt;/li&gt;
&lt;li&gt;Push &amp;amp; Pull a container into Zot&lt;/li&gt;
&lt;li&gt;Push &amp;amp; Pull files as OCI artifacts into Zot using ORAS&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Raspberry Pi or ARM instance in the cloud.&lt;/li&gt;
&lt;li&gt;Ubuntu &amp;gt;= 22.04&lt;/li&gt;
&lt;li&gt;Install docker (default installation)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Let's put our hands on Zot.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Zot on ARM Devices
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Install &lt;strong&gt;containerd&lt;/strong&gt; running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt-get update
sudo apt-get install -y docker.io
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These commands install Docker as your container runtime.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Install Zot to run in the port 5000 running following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run --name=zot -p 5000:5000 -d ghcr.io/project-zot/zot-linux-arm64:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Push &amp;amp; Pull a container into Zot
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Pull the nginx image with the &lt;strong&gt;docker&lt;/strong&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker pull nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Tag the image to push it with the name &lt;strong&gt;webserver&lt;/strong&gt; into the Zot registry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker tag nginx localhost:5000/&amp;lt;NAMESPACE&amp;gt;/webserver:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;NAMESPACE:&lt;/strong&gt; Refers to any string that is going to simulate a project or user space in the registry. Because this is a basic installation you can use for it whatever string that you want.&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; Push the container into Zot as a image called &lt;strong&gt;webserver:latest&lt;/strong&gt;, for this run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker push localhost:5000/&amp;lt;NAMESPACE&amp;gt;/webserver:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; Pull the previous container from the Zot registry as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker pull localhost:5000/&amp;lt;NAMESPACE&amp;gt;/webserver:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see it works as any other registry. Let's move to work with OCI Artifacts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Push/Pull files as OCI artifacts into Zot using ORAS
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Install ORAS using snap:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;snap install oras --classic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Create 2 files in your current directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo 1 &amp;gt; file1.txt
echo 2 &amp;gt; file1.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Push the files as OCI artifacts into the repo as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;oras push localhost:5000/&amp;lt;NAMESPACE&amp;gt;/files:latest file1.txt file2.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see an output like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ Exists    application/vnd.oci.empty.v1+json                          2/2  B 100.00%     0s
  └─ sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a
✓ Exists    file1.txt                                                  2/2  B 100.00%     0s
  └─ sha256:4355a46b19d348dc2f57c046f8ef63d4538ebb936000f3c9ee954a27460dd865
✓ Exists    file2.txt                                                  2/2  B 100.00%     0s
  └─ sha256:53c234e5e8472b6ac51c1ae1cab3fe06fad053beb8ebfd8977b010655bfdd3c3
✓ Uploaded  application/vnd.oci.image.manifest.v1+json             795/795  B 100.00%    6ms
  └─ sha256:a3ca9cc257cce158f8d94674c70ce67ee8fa6f19eea3cebe368ce1c140be9dfd
Pushed [registry] localhost:5000/test1/files:latest
ArtifactType: application/vnd.unknown.artifact.v1
Digest: sha256:a3ca9cc257cce158f8d94674c70ce67ee8fa6f19eea3cebe368ce1c140be9dfd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command create an OCI artifact called files with the tag latest which contains the files file1.txt and file2.txt.&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; Pull the files inside the OCI artifacts files:latest using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;oras pull --plain-http localhost:5000/&amp;lt;NAMESPACE&amp;gt;/files:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see that the files will be unpackaged in your current directory and an output as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ Pulled      file2.txt                                                2/2  B 100.00%  472µs
  └─ sha256:53c234e5e8472b6ac51c1ae1cab3fe06fad053beb8ebfd8977b010655bfdd3c3
✓ Pulled      file1.txt                                                2/2  B 100.00%    2ms
  └─ sha256:4355a46b19d348dc2f57c046f8ef63d4538ebb936000f3c9ee954a27460dd865
✓ Pulled      application/vnd.oci.image.manifest.v1+json           795/795  B 100.00%  113µs
  └─ sha256:a3ca9cc257cce158f8d94674c70ce67ee8fa6f19eea3cebe368ce1c140be9dfd
Pulled [registry] localhost:5001/test1/files:latest
Digest: sha256:a3ca9cc257cce158f8d94674c70ce67ee8fa6f19eea3cebe368ce1c140be9dfd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try to run this command on an empty directory to check if the artifact is unpackaged in that directory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Zot UI
&lt;/h2&gt;

&lt;p&gt;Do you want to use UI? Zot provides a UI for you, it looks like this in the main page:&lt;br&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%2Fccj37maktiqdbq9y9p4x.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%2Fccj37maktiqdbq9y9p4x.png" alt=" " width="800" height="683"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And if you check an artifact looks like this:&lt;br&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%2Fp5orqp30pi0g3vw4uc2m.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%2Fp5orqp30pi0g3vw4uc2m.png" alt=" " width="800" height="541"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced options
&lt;/h2&gt;

&lt;p&gt;Zot also provides more advance options like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supports helm charts&lt;/li&gt;
&lt;li&gt;TLS support&lt;/li&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;OCI Compatible&lt;/li&gt;
&lt;li&gt;ARM support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just to mention some of the features that are included. Its pretty easy to use and lightweight for edge solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Are there another Registries that runs on ARM? Yes
&lt;/h2&gt;

&lt;p&gt;You can use Distribution which is another option that runs on ARM.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion about Zot and ORAS
&lt;/h2&gt;

&lt;p&gt;After testing Zot, its ARM compatible, lightweight and with enough features to implement a secure implementation for edge use cases. You can start quick to configure your own registry pretty quick with Zot. You can go wrong with it. Also with ORAS you can take advantage of pushing files like ML models, configurations and other kind of files that sometimes you need to store for temporary use, thats will be ideal for edge computing. So when using Zot and ORAS you get a full setup to create and manage your registries compatible with OCI artifacts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What do you think about Zot and ORAS? Tell me, post your comment.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;See you on my next post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Follow me
&lt;/h2&gt;

&lt;p&gt;These are mi social networks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/sergioarmgpl" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/sergioarmgpl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sergiops.xyz" rel="noopener noreferrer"&gt;https://sergiops.xyz&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://x.com/sergioarmgpl" rel="noopener noreferrer"&gt;https://x.com/sergioarmgpl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.instagram.com/sergioarmgpl/" rel="noopener noreferrer"&gt;https://www.instagram.com/sergioarmgpl/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This blog post is an extended version content of my book:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://amzn.to/3Vx6pnt" rel="noopener noreferrer"&gt;https://amzn.to/3Vx6pnt&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>containers</category>
      <category>docker</category>
      <category>kubernetes</category>
      <category>cloudnative</category>
    </item>
    <item>
      <title>Creating containers with containerd &amp; nerdctl on ARM</title>
      <dc:creator>Sergio Méndez</dc:creator>
      <pubDate>Mon, 24 Feb 2025 06:00:00 +0000</pubDate>
      <link>https://dev.to/sergioarmgpl/running-containerd-on-arm-575c</link>
      <guid>https://dev.to/sergioarmgpl/running-containerd-on-arm-575c</guid>
      <description>&lt;p&gt;Hi Folks, this is the &lt;strong&gt;Day 2&lt;/strong&gt; of my series &lt;strong&gt;30DaysOfIoTEdge&lt;/strong&gt;. Its time to learn more in deep how to create containers with a lightweight container runtime &lt;strong&gt;containerd&lt;/strong&gt; together with &lt;strong&gt;nerdctl&lt;/strong&gt; to create containers. nerdctl provides to the users to interact with the containerd to create containers as same as &lt;strong&gt;Docker&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;containerd provides similar functionalities like Docker but in a &lt;strong&gt;small memory and CPU footprint&lt;/strong&gt; which is ideal for IoT or edge solutions when using containers, also we are using &lt;strong&gt;ARM&lt;/strong&gt; microprocessor that has a good balance between energy and CPU consumption, so that's the reason about why containerd fits and match nicely with ARM.&lt;/p&gt;

&lt;p&gt;Also, Containers are the tool when you want to speed your process of updating your software and get modularity and portability when deploying your solutions. In this post you will learn how containerd together with nerdctl can help you with this use case scenario. Check their official websites for more info &lt;a href="https://containerd.io" rel="noopener noreferrer"&gt;https://containerd.io&lt;/a&gt; and &lt;a href="https://github.com/containerd/nerdctl" rel="noopener noreferrer"&gt;https://github.com/containerd/nerdctl&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you will learn
&lt;/h2&gt;

&lt;p&gt;In this blog post you will learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install the containerd container runtime on ARM Devices (Rasberry Pi).&lt;/li&gt;
&lt;li&gt;Install nerdctl to use containerd to create containers.&lt;/li&gt;
&lt;li&gt;Create a basic container with nerdctl command line.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Raspberry Pi or ARM instance in the cloud.&lt;/li&gt;
&lt;li&gt;Ubuntu &amp;gt;= 22.04&lt;/li&gt;
&lt;li&gt;Install containerd&lt;/li&gt;
&lt;li&gt;Install CNI plugin&lt;/li&gt;
&lt;li&gt;Install nerdctl&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;So Let's create containers with containerd.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating Python containers for ARM
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Install &lt;strong&gt;containerd&lt;/strong&gt; running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt-get update
sudo apt-get install -y containerd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This commands install containerd in your device.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Install &lt;strong&gt;nerdctl&lt;/strong&gt; with the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NERDCTL_VERSION=2.0.3
wget https://github.com/containerd/nerdctl/releases/download/v2.0.3/nerdctl-$NERDCTL_VERSION-linux-arm64.tar.gz 
tar -xzvf nerdctl-$NERDCTL_VERSION-linux-arm64.tar.gz -C /sbin
CNI_VERSION=1.6.2
wget https://github.com/containernetworking/plugins/releases/download/v$CNI_VERSION/cni-plugins-linux-arm64-v$CNI_VERSION.tgz
mkdir -p /opt/cni/bin
tar -xzvf cni-plugins-linux-arm64-v$CNI_VERSION.tgz -C /opt/cni/bin

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Create a container with &lt;strong&gt;nerdctl&lt;/strong&gt;&lt;br&gt;
Create an NGINX container exposing the port 80 to the 8080 in the host:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nerdctl run --restart always -d -p 80:80 --name=nginx nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; Test the container&lt;br&gt;
Create the file with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl localhost:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This returns &lt;strong&gt;It works&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extra commands
&lt;/h2&gt;

&lt;p&gt;You can use the following commands for containerd:&lt;br&gt;
&lt;strong&gt;1.&lt;/strong&gt; To restart the service run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl restart containerd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use the following commands for nerdctl:&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; List images&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nerdctl images
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Push images&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nerdctl images
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; Pull images&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nerdctl images
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5.&lt;/strong&gt; Build images in the current directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nerdctl build . 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6.&lt;/strong&gt; Tag images&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nerdctl tag old_image:old_tag new_image:new_tag
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Where is Podman, Docker and CRI-O?
&lt;/h2&gt;

&lt;p&gt;Wait a moment. Let me tell you that there are alternatives, but containerd in particular has a low memory and CPU footprint so it's ideal for IoT and Edge devices. Podman could fit these needs and interact directly with RunC, which is daemonless. Docker because has more options and its daemon consumes more resources maybe doesn't fit IoT needs. CRI-O it could be but was designed to be lightweight and fit OCI compliance. Also, ask yourself if you need ARM support. The final decision depends on how much energy you want to consume, features, etc. With containerd, you can go wrong with IoT and Edge. In the future, I will add some table of comparison about footprint consumption. But try this tutorial to see how containerd performs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thank you and follow me
&lt;/h2&gt;

&lt;p&gt;If you liked my blog post comment 😀&lt;br&gt;
Also follow me at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/sergioarmgpl" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/sergioarmgpl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sergiops.xyz" rel="noopener noreferrer"&gt;https://sergiops.xyz&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://x.com/sergioarmgpl" rel="noopener noreferrer"&gt;https://x.com/sergioarmgpl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.instagram.com/sergioarmgpl/" rel="noopener noreferrer"&gt;https://www.instagram.com/sergioarmgpl/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This blog post is an extended version of my book:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://amzn.to/3Vx6pnt" rel="noopener noreferrer"&gt;https://amzn.to/3Vx6pnt&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>docker</category>
      <category>arm</category>
      <category>iot</category>
    </item>
    <item>
      <title>Python containers for ARM</title>
      <dc:creator>Sergio Méndez</dc:creator>
      <pubDate>Tue, 18 Feb 2025 05:34:22 +0000</pubDate>
      <link>https://dev.to/sergioarmgpl/python-containers-for-arm-32bl</link>
      <guid>https://dev.to/sergioarmgpl/python-containers-for-arm-32bl</guid>
      <description>&lt;p&gt;Hi, this is the beginning of my blog post series called, &lt;strong&gt;30DaysOfIoTEdge&lt;/strong&gt;, you will learn about how to use Kubernetes, ARM, and container on the Edge, something that you can use to solve problems around Iot and Edge stuff. So, let's start with Day 1 creating a container for Python that runs on ARM.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you will learn
&lt;/h2&gt;

&lt;p&gt;In this blog post you will learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What you need to compile for ARM.&lt;/li&gt;
&lt;li&gt;Create a basic container for Python using Flask as a basic API.&lt;/li&gt;
&lt;li&gt;Adapt your container to run on ARM devices.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Raspberry Pi or ARM instance in the cloud.&lt;/li&gt;
&lt;li&gt;Docker installed&lt;/li&gt;
&lt;li&gt;Ubuntu &amp;gt;= 22.04&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;So Let's get started with this post.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating Python containers for ARM
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Install Docker with permission to execute the command without sudo. For this run the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt-get update
sudo apt-get install -y docker.io
sudo groupadd docker
sudo usermod -aG docker $USER
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This commands install Docker in your machine, then restarts your terminal, in order to run docker without sudo. This is something that you will like to do instead of putting sudo before the docker command every time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Create your &lt;strong&gt;Dockerfile&lt;/strong&gt;&lt;br&gt;
Create the file with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat &amp;gt; Dockerfile &amp;lt;&amp;lt;-EOF
FROM python:3-alpine

WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

CMD ["ash", "-c", "python main.py"]
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Create your &lt;strong&gt;main.py&lt;/strong&gt;&lt;br&gt;
Create the file with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat &amp;gt; main.py &amp;lt;&amp;lt;-EOF
from flask import Flask
import os
import socket

app = Flask(__name__)

@app.route('/')
def index():
    return "Hello ARM Container"


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000), debug=True)
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; Create the &lt;strong&gt;requeriments.txt&lt;/strong&gt;&lt;br&gt;
Create the file with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat &amp;gt; requeriments.txt &amp;lt;&amp;lt;-EOF
flask
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This file includes all the dependencies of libraries using in your code. In this case we just use Flask, the other libraries are by default included.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.&lt;/strong&gt; Login into your registry&lt;br&gt;
For this run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enter your user from DockerHub or specify the registry your are using to push your container like ECR, GCR, AZR or Harbor as an open source container or artifact registry.&lt;br&gt;
&lt;strong&gt;6.&lt;/strong&gt; Build and push your container&lt;br&gt;
For this run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker buildx build --platform linux/arm64 \
-t &amp;lt;USERNAME&amp;gt;/&amp;lt;CONTAINER_NAME&amp;gt;:&amp;lt;TAG&amp;gt; --push .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;strong&gt;--platform&lt;/strong&gt; specify the platform where the container is going to run. Common platforms used for ARM are &lt;strong&gt;linux/arm64&lt;/strong&gt; for ARM v8 and, &lt;strong&gt;linux/arm/v7&lt;/strong&gt; for v7. Also you can use &lt;strong&gt;x86_64&lt;/strong&gt; for Intel and Nuc devices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7.&lt;/strong&gt; Test your container.&lt;br&gt;
For this run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -it -p 5000:5000 &amp;lt;USERNAME&amp;gt;/&amp;lt;CONTAINER_NAME&amp;gt;:&amp;lt;TAG&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;8.&lt;/strong&gt; Test your API&lt;br&gt;
For this use curl to test the API running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl http://&amp;lt;HOST_IP&amp;gt;:5000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It shows the &lt;strong&gt;Hello ARM Container&lt;/strong&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Tricks
&lt;/h2&gt;

&lt;p&gt;In some cases, you can find precompiled packages or wheels for Python. Let's say for example that you are building for a Raspberry Pi device using Raspbian as its operating system. Raspbian uses some specific wheels precompiled for Raspbian but you can use it for another operating system. Why? Sometimes the libraries in Python are not compiled for ARM and when you build the container it detects that the library needs to be compiled for ARM and fails. You can solve it but it's easier to use the Python wheels precompiled for Raspbian. How you can use that wheels, just by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RUN pip install --index-url=https://www.piwheels.org/simple --no-cache-dir -r requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RUN pip install -r requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Thank you and follow me
&lt;/h2&gt;

&lt;p&gt;If you liked my blog post comment 😀&lt;br&gt;
Also follow me at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/sergioarmgpl" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/sergioarmgpl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sergiops.xyz" rel="noopener noreferrer"&gt;https://sergiops.xyz&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://x.com/sergioarmgpl" rel="noopener noreferrer"&gt;https://x.com/sergioarmgpl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.instagram.com/sergioarmgpl/" rel="noopener noreferrer"&gt;https://www.instagram.com/sergioarmgpl/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This blog post is an extender version of my book:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://amzn.to/3Vx6pnt" rel="noopener noreferrer"&gt;https://amzn.to/3Vx6pnt&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>arm</category>
      <category>containers</category>
      <category>docker</category>
      <category>iot</category>
    </item>
    <item>
      <title>My 2023 in review</title>
      <dc:creator>Sergio Méndez</dc:creator>
      <pubDate>Tue, 23 Jan 2024 03:31:46 +0000</pubDate>
      <link>https://dev.to/sergioarmgpl/my-2023-in-review-4jcj</link>
      <guid>https://dev.to/sergioarmgpl/my-2023-in-review-4jcj</guid>
      <description>&lt;p&gt;Hi, you all, this is my very first time writing this kind of post. So, I want to say how was my 2023 in context of tech content, speaking sessions and my tech career in general.&lt;/p&gt;

&lt;p&gt;I can summarize it like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;24 speaking sessions&lt;/li&gt;
&lt;li&gt;5 videos in my Youtube channel&lt;/li&gt;
&lt;li&gt;3 KCDs&lt;/li&gt;
&lt;li&gt;15 Working sessions for our Cloud Native Group.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also participated in working sessions and created content in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2 tags tag-environmental-sustainability, we were part of the sustainability week and for higher-ed (a future TAG), just participating to build something around university contents.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I participated in the several events or groups:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cloud Native Guatemala Chapter&lt;/li&gt;
&lt;li&gt;Cloud Native Amsterdam&lt;/li&gt;
&lt;li&gt;KCD Colombia&lt;/li&gt;
&lt;li&gt;KCD El Salvador&lt;/li&gt;
&lt;li&gt;KCD Guatemala&lt;/li&gt;
&lt;li&gt;Civo Navigate NA, Tampa&lt;/li&gt;
&lt;li&gt;Civo Navigate Europe, London&lt;/li&gt;
&lt;li&gt;KubeConNA, Chicago&lt;/li&gt;
&lt;li&gt;Sustainability Week Guatemala&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My best moments in the year:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I was selected to be a CNCF Ambassador after serveral years&lt;/li&gt;
&lt;li&gt;Hosted an in-person KCD with my students&lt;/li&gt;
&lt;li&gt;Talked with Bart Farrel about life and things&lt;/li&gt;
&lt;li&gt;Talked with Cortney Nickerson at KubeConNA, Chicago&lt;/li&gt;
&lt;li&gt;Talked with Ramiro Berrelleza in different events&lt;/li&gt;
&lt;li&gt;Christmas breakfast with Cloud Native Guatemala Chapter organizers&lt;/li&gt;
&lt;li&gt;Funny moments with Alessadro Civo, Dario Trankitela&lt;/li&gt;
&lt;li&gt;Met in person Kunal Kushwaha&lt;/li&gt;
&lt;li&gt;Shared in the KCD boot in the KCD about Guatemala in KubeConNA, Chicago&lt;/li&gt;
&lt;li&gt;In deep conversation about life with Tiffany Jatcha &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The event and moment I loved the most was Cloud Native Amsterdam.&lt;/p&gt;

&lt;p&gt;Also, I learned from Bart Farrel, that you are not alone when you have problems, your friends support you, also I have a lot of friends in the ecosystem that loves me.&lt;/p&gt;

&lt;p&gt;Now, this year 2024, for me is the year to thing about me, grow up, and explore new things, I want to try to create content by myself, I mean, be my own brand, like a kind of DevRel. I will take the advice of a close friend of mine, that said me about build a community around me. I will try, let's see if I can build that community.&lt;/p&gt;

&lt;p&gt;Finally, I want to visit Europe again to be in other events. If I am lucky I would like to be in Japan, but first I have to build that dream, let's see if the happens.&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%2Ffb1j5kch0kjsad81fwkj.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%2Ffb1j5kch0kjsad81fwkj.jpg" alt="My 2023 in a collage" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have a lot of pending videos to upload from 2023, a lot of content coming. So, that was my 2023 in review, what about yours? any 2024 resolutions?&lt;/p&gt;

&lt;p&gt;BTW, follow me on Twitter as &lt;a class="mentioned-user" href="https://dev.to/sergioarmgpl"&gt;@sergioarmgpl&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;See you the next time!&lt;/p&gt;

</description>
      <category>cloudnative</category>
      <category>kubernetes</category>
      <category>cncf</category>
      <category>devops</category>
    </item>
    <item>
      <title>How I became a Linkerd Hero?</title>
      <dc:creator>Sergio Méndez</dc:creator>
      <pubDate>Wed, 12 May 2021 21:49:11 +0000</pubDate>
      <link>https://dev.to/sergioarmgpl/how-i-became-a-linkerd-hero-1kca</link>
      <guid>https://dev.to/sergioarmgpl/how-i-became-a-linkerd-hero-1kca</guid>
      <description>&lt;p&gt;Hi, Dev.to community this is my first post, and I want to share how I became a Linkerd Hero. This is more or less a large story, let me introduce myself first. I am Sergio Méndez. I was born in Guatemala, I represent that part of underrepresented technology groups, actually, I am working as a DevOps Engineer at Yalo, and I am also an Operating Systems professor at USAC, Guatemala.  &lt;/p&gt;

&lt;p&gt;I remember that this story started when I talked at the 2018 OSCON conference, in that moment I was starting to experiment with Cloud Native technologies, some months before that, I was working for a Telco company here in Guatemala, I was building a tool to create custom chatbots using Kubernetes and OpenFaaS. I was a novice at that time and for sure it wasn’t my best experience talking in a conference, but it was challenging, me giving a talk in English outside my country, who would have imagined. As I mentioned it wasn’t my best experience. After that, I tried to prove to myself that I could do it better, so I was looking for another opportunity.&lt;/p&gt;

&lt;p&gt;Next year, influenced by one of the organizers of O'Reilly, the one who pushed me to talk for the first time, I decided to send a talk proposal to KubeConEU 2020, and by my surprise, my talk was selected. My talk was about how to implement canary deployments using OpenFaaS and Linkerd. I remember that the creator of &lt;a href="https://www.openfaas.com" rel="noopener noreferrer"&gt;OpenFaaS&lt;/a&gt; contacted me and introduced me to the CTO of Buoyant, Buoyant is the company behind &lt;a href="https://linkerd.io" rel="noopener noreferrer"&gt;Linkerd&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Later 2020 I decided to include Linkerd in the final project of my course, and give the challenge to my students to build a basic distributed system using Kubernetes and Linkerd, I also mentioned this project to the Linkerd people, because I was moving a lot of service meshes topics Linkerd invited me to their &lt;a href="https://linkerd.io/community/anchor/" rel="noopener noreferrer"&gt;Anchor Program&lt;/a&gt; to tell other what I was doing part of that was to participate on one of their Linkerd Community calls to share about our project.&lt;/p&gt;

&lt;p&gt;At the beginning of January 2021, we presented the project to the Linkerd community with my students with the challenge to speak in another language but it was a really nice experience. I felt that we broke the language gap at that moment. A month later the Linkerd community nominated me to be the &lt;a href="https://linkerd.io/community/heroes" rel="noopener noreferrer"&gt;Linkerd Hero&lt;/a&gt; of February and by my surprise, I won. &lt;/p&gt;

&lt;p&gt;Linkerd opened a lot of doors to be visible to the cloud native world. I really appreciate that, I love Linkerd is a really special community.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Things that I Learned:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Be ready when the moment and the opportunity comes&lt;/li&gt;
&lt;li&gt;You won’t be successful all the time but you have to persist&lt;/li&gt;
&lt;li&gt;Help others around to break technology frontiers&lt;/li&gt;
&lt;li&gt;Diversity and inclusion matters&lt;/li&gt;
&lt;li&gt;Nothing it's impossible if you are working to build it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;And my final thought is:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Contribute is not just coding it could be teaching, speaking and create content for people in other languages, don’t get frustrated&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Do you want to see the moment when we present the project with my students?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here is it:&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/XWlpS78wRks"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;And if you like the academic side feel free to contribute to our repo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/sergioarmgpl/operating-systems-usac-course" rel="noopener noreferrer"&gt;https://github.com/sergioarmgpl/operating-systems-usac-course&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks, Dev.to Community, I hope you enjoy my first post.&lt;/p&gt;

&lt;p&gt;Follow me if you liked this post :D.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Twitter:&lt;/strong&gt; &lt;a href="https://twitter.com/sergioarmgpl" rel="noopener noreferrer"&gt;https://twitter.com/sergioarmgpl&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="https://sergiops.xyz" rel="noopener noreferrer"&gt;https://sergiops.xyz&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href="https://twitter.com/jdorfman?lang=en" rel="noopener noreferrer"&gt;Justin Dorfman&lt;/a&gt; of &lt;a href="https://www.curiefense.io/" rel="noopener noreferrer"&gt;Curiefense&lt;/a&gt; for reviewing this post.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>servicemesh</category>
      <category>cloudnative</category>
    </item>
  </channel>
</rss>
