<?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>Forem: Sergio Méndez</title>
    <description>The latest articles on Forem by Sergio Méndez (@sergioarmgpl).</description>
    <link>https://forem.com/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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F630275%2F69d6e3c0-98f7-427b-88f2-121e493b8fcb.jpg</url>
      <title>Forem: Sergio Méndez</title>
      <link>https://forem.com/sergioarmgpl</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sergioarmgpl"/>
    <language>en</language>
    <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://forem.com/sergioarmgpl/goodbye-ingress-hello-gateway-api-migrating-the-right-way-20k9</link>
      <guid>https://forem.com/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;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; 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://forem.com/sergioarmgpl/kubevirt-to-run-vms-in-your-k8s-cluster-4jh4</link>
      <guid>https://forem.com/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;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;small&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;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;200M&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--port&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;PORT_NUMBER&amp;gt;--name&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://forem.com/sergioarmgpl/zot-and-oras-to-create-manage-edge-container-registries-3kam</link>
      <guid>https://forem.com/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://forem.com/sergioarmgpl/running-containerd-on-arm-575c</link>
      <guid>https://forem.com/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://forem.com/sergioarmgpl/python-containers-for-arm-32bl</link>
      <guid>https://forem.com/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://forem.com/sergioarmgpl/my-2023-in-review-4jcj</link>
      <guid>https://forem.com/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://forem.com/sergioarmgpl/how-i-became-a-linkerd-hero-1kca</link>
      <guid>https://forem.com/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>
