<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Javi Vela Blog]]></title><description><![CDATA[Creo que el conocimiento debería ser compartido en la medida de lo posible.

Comparto conocimiento práctico sobre DevOps, Azure, AWS, CI/CD, Kubernetes, contenedores y arquitectura.]]></description><link>https://www.javivela.dev</link><image><url>https://www.javivela.dev/img/substack.png</url><title>Javi Vela Blog</title><link>https://www.javivela.dev</link></image><generator>Substack</generator><lastBuildDate>Sun, 12 Apr 2026 10:22:31 GMT</lastBuildDate><atom:link href="https://www.javivela.dev/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Javi Vela]]></copyright><language><![CDATA[es]]></language><webMaster><![CDATA[javiveladev@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[javiveladev@substack.com]]></itunes:email><itunes:name><![CDATA[Javi Vela]]></itunes:name></itunes:owner><itunes:author><![CDATA[Javi Vela]]></itunes:author><googleplay:owner><![CDATA[javiveladev@substack.com]]></googleplay:owner><googleplay:email><![CDATA[javiveladev@substack.com]]></googleplay:email><googleplay:author><![CDATA[Javi Vela]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Kubernetes admission controllers]]></title><description><![CDATA[Kubernetes permite validar y modificar objetos de forma nativa con CEL, sin webhooks ni herramientas externas. Las ValidatingAdmissionPolicy rechazan recursos que no cumplen tus reglas; las MutatingAd]]></description><link>https://www.javivela.dev/p/kubernetes-admission-controllers</link><guid isPermaLink="false">https://www.javivela.dev/p/kubernetes-admission-controllers</guid><dc:creator><![CDATA[Javi Vela]]></dc:creator><pubDate>Mon, 06 Apr 2026 09:11:57 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!6LqD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5104d171-7adc-490e-acbf-8514c4087810_1261x923.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hace unos d&#237;as os hablaba sobre <a href="https://blog.javivela.dev/p/common-expression-language-cel-en-kubernetes">Common Expression Language (CEL) en Kubernetes</a>.</p><blockquote><p><em>CEL es </em>un lenguaje de expresiones ligero creado por Google y dise&#241;ado para validaciones, evaluaciones l&#243;gicas r&#225;pidas y portabilidad. A diferencia de un lenguaje de programaci&#243;n completo, CEL es restringido y seguro: no permite ejecuci&#243;n de c&#243;digo arbitrario, lo que lo hace ideal para las APIs de Kubernetes.  </p></blockquote><p>Hoy os cuento c&#243;mo puedes utilizarlo para configurar un Validating Admission Policy o <strong>Mutating Admission Policy.</strong></p><div class="pullquote"><p>Si has trabajado con Kubernetes, es posible que esta informaci&#243;n te resuene.</p><p> Existen herramientas como Kyverno o OPA Gatekeeper para gestionar las pol&#237;ticas en tu cluster kubernetes</p></div><p>Validating Admission Policy y <strong>Mutating Admission Policy funcionan de forma declarativa y utilizan CEL para definir sus reglas, sin necesidad de desplegar webhooks ni aplicaciones externas.</strong></p><p><strong>Cualquier </strong>pol&#237;tica <strong>se ejecuta en el control-plane de nuestro cluster y podemos llegar a bloquear el propio control-plane dependiendo de las reglas definidas.</strong></p><p><strong>Cuando solicitamos la creaci&#243;n de un objeto en Kubernetes, el flujo funciona de la siguiente manera:</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6LqD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5104d171-7adc-490e-acbf-8514c4087810_1261x923.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6LqD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5104d171-7adc-490e-acbf-8514c4087810_1261x923.png 424w, https://substackcdn.com/image/fetch/$s_!6LqD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5104d171-7adc-490e-acbf-8514c4087810_1261x923.png 848w, https://substackcdn.com/image/fetch/$s_!6LqD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5104d171-7adc-490e-acbf-8514c4087810_1261x923.png 1272w, https://substackcdn.com/image/fetch/$s_!6LqD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5104d171-7adc-490e-acbf-8514c4087810_1261x923.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6LqD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5104d171-7adc-490e-acbf-8514c4087810_1261x923.png" width="1261" height="923" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5104d171-7adc-490e-acbf-8514c4087810_1261x923.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:923,&quot;width&quot;:1261,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:173697,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://blog.javivela.dev/i/188027340?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5104d171-7adc-490e-acbf-8514c4087810_1261x923.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6LqD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5104d171-7adc-490e-acbf-8514c4087810_1261x923.png 424w, https://substackcdn.com/image/fetch/$s_!6LqD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5104d171-7adc-490e-acbf-8514c4087810_1261x923.png 848w, https://substackcdn.com/image/fetch/$s_!6LqD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5104d171-7adc-490e-acbf-8514c4087810_1261x923.png 1272w, https://substackcdn.com/image/fetch/$s_!6LqD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5104d171-7adc-490e-acbf-8514c4087810_1261x923.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Cuando un cliente env&#237;a una petici&#243;n al cluster, el API Server primero verifica la identidad y permisos. Si la autenticaci&#243;n es correcta, la petici&#243;n pasa por el <strong>Mutating Admission</strong>, que puede modificar el objeto antes de continuar, y despu&#233;s por el <strong>Validating Admission</strong>, que eval&#250;a la expresi&#243;n CEL y toma la decisi&#243;n final. Si la expresi&#243;n se cumple, el objeto se persiste en etcd; si no, la petici&#243;n se rechaza con un <code>403 Forbidden</code> y el mensaje definido en la policy.</p><div class="pullquote"><p>&#161;Gracias por pasarte por aqu&#237;! &#128588;<br>Si te interesa seguir recibiendo gu&#237;as pr&#225;cticas sobre Kubernetes, Azure, DevOps y contenedores directamente en tu email&#8230;<br>Suscr&#237;bete gratis y no te pierdas ninguna novedad. &#128640;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/subscribe?&quot;,&quot;text&quot;:&quot;Suscr&#237;bete ahora&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.javivela.dev/subscribe?"><span>Suscr&#237;bete ahora</span></a></p></div><h2>Validating Admission Policy</h2><p>Este tipo de pol&#237;ticas nos van a permitir validar cualquier petici&#243;n realizada a nuestro cluster Kubernetes, no solo por nosotros, tambi&#233;n se incluyen cualquier llamada que pueda hacer el propio cluster o herramientas GitOps como <a href="https://argo-cd.readthedocs.io/en/stable/">Argo CD </a>o <a href="https://fluxcd.io/">Flux CD</a>.</p><p>Para desplegar una politica y hacer uso de ella debemos crear dos objetos.</p><h3>ValidatingAdmissionPolicy</h3><p>Definimos la pol&#237;tica.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;yaml&quot;,&quot;nodeId&quot;:&quot;9d3a4b95-79ce-4f1c-a6d0-8c79ee05655e&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-yaml">apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: require-memory-requests
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
      - apiGroups: ["apps"]
        apiVersions: ["v1"]
        operations: ["CREATE", "UPDATE"]
        resources: ["deployments"]
  validations:
    - expression: &gt;
        object.spec.template.spec.containers.all(c,
          has(c.resources) &amp;&amp;
          has(c.resources.requests) &amp;&amp;
          has(c.resources.requests.memory)
        )
      message: "Todos los contenedores deben tener requests.memory definido"</code></pre></div><h4><strong>failurePolicy</strong></h4><p>Define qu&#233; hacer si hay un error en la pol&#237;tica (por ejemplo, error de sintaxis CEL, error en tiempo de ejecuci&#243;n o configuraci&#243;n inv&#225;lida). Valores permitidos: </p><ul><li><p>Fail (valor por defecto): rechaza la petici&#243;n </p></li><li><p>Ignore: contin&#250;a como si la pol&#237;tica no existiera</p></li></ul><h4><strong>matchConstraints</strong></h4><p>Especifica <strong>a </strong>qu&#233; <strong>recursos</strong> se aplica esta pol&#237;tica. Es el filtro principal. Dentro de &#233;l, lo m&#225;s usado es <strong>resourceRules</strong>: una lista de reglas que definen:</p><ul><li><p><strong>apiGroups</strong>: grupo de la API (ej. [&#8220;apps&#8221;] o [&#8220;&#8220;] para core)</p></li><li><p><strong>apiVersions:</strong> versiones (ej. [&#8221;v1&#8221;])</p></li><li><p><strong>operations</strong>: operaciones a interceptar: CREATE, UPDATE, DELETE, *</p></li><li><p><strong>resources</strong>: tipo de recurso (ej. [&#8221;deployments&#8221;], [&#8221;pods&#8221;]). Tambi&#233;n puedes usar <strong>namespaceSelector</strong> y <strong>objectSelector</strong> para filtrar por labels</p></li></ul><h4><strong>validations</strong></h4><p>Aqu&#237; va la l&#243;gica real de validaci&#243;n usando <strong>CEL</strong> (Common Expression Language). Cada elemento tiene:</p><ul><li><p><strong>expression</strong>: la expresi&#243;n CEL que debe evaluarse a true. Si es false, se considera fallo de validaci&#243;n. Ejemplo: <code>object.spec.replicas &lt;= 5</code></p></li><li><p><strong>message</strong>: mensaje est&#225;tico que se devuelve al usuario si falla</p></li><li><p><strong>messageExpression</strong>: (opcional) expresi&#243;n CEL que genera un mensaje din&#225;mico</p></li><li><p><strong>reason</strong>: c&#243;digo de raz&#243;n HTTP (Invalid, Forbidden, etc.)</p></li></ul><h4>Otras propiedades &#250;tiles</h4><ul><li><p><strong>matchConditions</strong>: filtro adicional con CEL (se eval&#250;a antes de las validaciones). Muy &#250;til para excluir system namespaces o recursos internos.</p></li><li><p><strong>auditAnnotations</strong>: genera anotaciones en los eventos de auditor&#237;a cuando la validaci&#243;n pasa.</p></li><li><p><strong>variables</strong>: define variables reutilizables en CEL para no repetir expresiones complejas.</p></li><li><p><strong>paramKind</strong>: si quieres que la pol&#237;tica sea parametrizable (ej. el l&#237;mite de r&#233;plicas venga de un CRD).</p></li></ul><p>Un ejemplo m&#225;s completo con todas las propiedades disponibles:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;yaml&quot;,&quot;nodeId&quot;:&quot;df5f6e5a-8fdb-4865-97c1-40fdae369651&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-yaml">apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: enforce-production-deployment-standards.example.com
spec:
  # 1. Qu&#233; hacer si hay un error en la pol&#237;tica (sintaxis CEL, runtime error, etc.)
  failurePolicy: Fail

  # 2. Filtros iniciales: a qu&#233; recursos se aplica la pol&#237;tica
  matchConstraints:
    resourceRules:
      - apiGroups:   ["apps"]
        apiVersions: ["v1"]
        operations:  ["CREATE", "UPDATE"]
        resources:   ["deployments"]

  # 3. Condiciones adicionales con CEL (se eval&#250;an ANTES de las validaciones)
  matchConditions:
    - name: "only-production-namespaces"
      expression: "request.namespace.startsWith('prod-') || request.namespace == 'production'"
    - name: "exclude-system-resources"
      expression: "!(request.resource.group == 'coordination.k8s.io' &amp;&amp; request.resource.resource == 'leases')"

  # 4. Par&#225;metros (hace la pol&#237;tica reutilizable y configurable)
  paramKind:
    apiVersion: "rules.example.com/v1"
    kind: "DeploymentPolicyConfig"
  # El par&#225;metro se referenciar&#225; despu&#233;s en el Binding con paramRef

  # 5. Variables reutilizables en CEL (mejora la legibilidad y evita duplicaci&#243;n)
  variables:
    - name: "hasReadOnlyRootFS"
      expression: "object.spec.template.spec.containers.all(c, has(c.securityContext) &amp;&amp; has(c.securityContext.readOnlyRootFilesystem) &amp;&amp; c.securityContext.readOnlyRootFilesystem == true)"
    - name: "approvedRegistries"
      expression: "params.allowedRegistries.split(',').map(r, r.trim())"

  # 6. Las validaciones reales (l&#243;gica principal)
  validations:
    - name: "minimum-replicas"
      expression: "object.spec.replicas &gt;= params.minReplicas"
      messageExpression: "'Deployment debe tener al menos ' + string(params.minReplicas) + ' r&#233;plicas en producci&#243;n.'"
      reason: Invalid

    - name: "readonly-root-filesystem"
      expression: "variables.hasReadOnlyRootFS"
      message: "Todos los contenedores deben tener securityContext.readOnlyRootFilesystem = true por seguridad"
      reason: Forbidden

    - name: "approved-image-registries"
      expression: &gt;
        object.spec.template.spec.containers.all(c,
          variables.approvedRegistries.exists(r, c.image.startsWith(r))
        )
      message: "Todas las im&#225;genes deben provenir de registros aprobados"
      reason: Forbidden

  # 7. Anotaciones para auditor&#237;a (&#250;til para compliance y trazabilidad)
  auditAnnotations:
    - key: "policy.enforced"
      valueExpression: "'true'"
    - key: "policy.minReplicas"
      valueExpression: "string(params.minReplicas)"
    - key: "validated-by"
      valueExpression: "'validating-admission-policy'"</code></pre></div><h3>ValidatingAdmissionPolicyBinding</h3><p>Enlazamos la pol&#237;tica creada con uno o varios objetos de Kubernetes, en este caso queremos aplicarla &#250;nicamente a los recursos que se ejecutan en un namespace por la label <code>env: production</code>.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;yaml&quot;,&quot;nodeId&quot;:&quot;662bb81a-24fd-4f52-b703-50eb62272798&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-yaml"># Enlazar la pol&#237;tica a un namespace (o a todo el cluster)
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
  name: require-memory-requests-binding
spec:
  policyName: require-memory-requests
  validationActions: [Deny]
  matchResources:
    namespaceSelector:
      matchLabels:
        env: production</code></pre></div><h4><strong>policyName</strong> </h4><p>Nombre exacto de la ValidatingAdmissionPolicy que se va a aplicar. </p><h4><strong>validationActions</strong> </h4><p>C&#243;mo se aplica el fallo de validaci&#243;n.  No puedes combinar Deny + Warn. </p><ul><li><p>Deny: rechaza la petici&#243;n </p></li><li><p>Warn: avisa pero permite (emite un warning visible con <code>kubectl)</code> </p></li><li><p>Audit: solo registra en el audit log</p></li></ul><h4><strong>matchResources</strong></h4><p>Igual que en la pol&#237;tica, pero aqu&#237; puedes afinar a&#250;n m&#225;s el alcance (por ejemplo, aplicar solo a ciertos namespaces con namespaceSelector). Si lo omites, se aplica a todos los recursos que coincidan con los criterios de la pol&#237;tica.</p><h2><strong>Mutating Admission Policy</strong></h2><p>Esta funcionalidad se encuentra actualmente en beta y est&#225; previsto que pase a GA en Kubernetes 1.36.</p><p>Este tipo de pol&#237;ticas nos van a permitir modificar el contenido de un objeto de Kubernetes (ej. a&#241;adir un label).</p><h3>MutatingAdmissionPolicy</h3><p>Definimos la pol&#237;tica.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;yaml&quot;,&quot;nodeId&quot;:&quot;3ef3b606-6a53-4b34-83ad-f1399f7a856e&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-yaml"># 1. Definir la pol&#237;tica mutante
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: MutatingAdmissionPolicy
metadata:
  name: add-managed-by-label
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
      - apiGroups: [""]
        apiVersions: ["v1"]
        operations: ["CREATE"]
        resources: ["pods"]
  mutations:
    - patchType: ApplyConfiguration
      applyConfiguration:
        expression: &gt;
          Object{
            metadata: ObjectMeta{
              labels: {"managed-by": "platform-team"}
            }
          }
</code></pre></div><h4><strong>failurePolicy</strong></h4><p>Define el comportamiento cuando ocurre un error en la pol&#237;tica (error de sintaxis CEL, error en tiempo de ejecuci&#243;n, etc.). Valores permitidos:</p><ul><li><p>Fail (por defecto): rechaza la creaci&#243;n/actualizaci&#243;n del objeto</p></li><li><p>Ignore: contin&#250;a la operaci&#243;n ignorando esta pol&#237;tica</p></li></ul><h4><strong>matchConstraints</strong></h4><p>Es el filtro principal. Define a qu&#233; recursos y operaciones se aplica esta pol&#237;tica de mutaci&#243;n.</p><ul><li><p><strong>apiGroups</strong>: grupo de la API (ej. [&#8220;apps&#8221;] o [&#8220;&#8220;] para core)</p></li><li><p><strong>apiVersions:</strong> versiones (ej. [&#8221;v1&#8221;])</p></li><li><p><strong>operations</strong>: operaciones a interceptar: CREATE, UPDATE, DELETE, *</p></li><li><p><strong>resources</strong>: tipo de recurso (ej. [&#8221;deployments&#8221;], [&#8221;pods&#8221;]). Tambi&#233;n puedes usar <strong>namespaceSelector</strong> y <strong>objectSelector</strong> para filtrar por labels</p></li></ul><h4><strong>mutations</strong></h4><p>Es una <strong>lista</strong> de mutaciones que se aplicar&#225;n al objeto. Cada elemento de la lista representa una mutaci&#243;n independiente.</p><ul><li><p><strong>patchType: </strong>Indica el tipo de parche que se va a aplicar. Dos valores posibles:</p><ul><li><p><strong>ApplyConfiguration:</strong> Usa un estilo declarativo similar al Server-Side Apply. Es m&#225;s seguro y legible</p></li><li><p><strong>JSONPatch</strong>: Permite usar operaciones cl&#225;sicas de JSON Patch (add, remove, replace, etc.)</p></li></ul></li><li><p><strong>applyConfiguration.expression</strong> (cuando patchType: ApplyConfiguration) Expresi&#243;n CEL que devuelve un objeto con la configuraci&#243;n que se quiere <strong>fusionar</strong> (merge) en el objeto original. En el ejemplo:</p></li></ul><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;d1753f9d-bc70-4372-bff0-763f0e8d7dd2&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">Object{
  metadata: ObjectMeta{
    labels: {"managed-by": "platform-team"}
  }
}</code></pre></div><h4>Otras propiedades importantes</h4><ul><li><p><strong>reinvocationPolicy</strong> Controla si la pol&#237;tica debe volver a ejecutarse despu&#233;s de que otras mutaciones hayan modificado el objeto. Valores:</p><ul><li><p>IfNeeded: Se ejecuta en caso de que el objeto haya sido modificado por otra pol&#237;tica </p></li><li><p>Never (valor por defecto): la pol&#237;tica no se ejecuta si el objeto ya ha sido modificado por otra pol&#237;tica </p></li></ul></li><li><p><strong>matchConditions</strong> (lista) Filtros adicionales escritos en CEL que se eval&#250;an <strong>antes</strong> de aplicar las mutaciones. Muy &#250;til para a&#241;adir condiciones complejas, por ejemplo:</p><ul><li><p>No aplicar la mutaci&#243;n si el Pod ya tiene cierta etiqueta</p></li><li><p>Excluir Pods del sistema (kube-system, kube-node-lease, etc.</p></li></ul></li></ul><p>Un ejemplo m&#225;s completo con todas las propiedades disponibles:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;yaml&quot;,&quot;nodeId&quot;:&quot;3f4bc3c5-4aab-4ff0-8edb-6a9f8750e892&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-yaml">apiVersion: admissionregistration.k8s.io/v1beta1 
kind: MutatingAdmissionPolicy
metadata:
  name: add-platform-labels
spec:
  failurePolicy: Ignore
  reinvocationPolicy: IfNeeded

  # 1. matchConstraints &#8594; &#191;A qu&#233; recursos se aplica?
  matchConstraints:
    resourceRules:
      - apiGroups:   [""]
        apiVersions: ["v1"]
        operations:  ["CREATE"]
        resources:   ["pods"]

  # 2. matchConditions &#8594; Condiciones adicionales con CEL (opcional pero muy &#250;til)
  matchConditions:
    - name: "skip-system-namespaces"
      expression: "!(request.namespace in ['kube-system', 'kube-node-lease', 'kube-public'])"

  # 3. mutations &#8594; Aqu&#237; definimos los cambios
  mutations:
    - patchType: ApplyConfiguration
      applyConfiguration:
        expression: &gt;
          Object{
            metadata: ObjectMeta{
              labels: {
                "managed-by": "platform-team",
                "environment": "production"
              },
              annotations: {
                "mutated-by": "mutating-admission-policy",
                "mutation-timestamp": string(request.time)
              }
            }
          }</code></pre></div><h3>MutatingAdmissionPolicyBinding</h3><p>Enlazamos la pol&#237;tica creada con uno o varios objetos de Kubernetes, en este caso queremos aplicarla &#250;nicamente a los recursos que se ejecutan en un namespace por la label <code>env: production o staging.</code></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;yaml&quot;,&quot;nodeId&quot;:&quot;8ddc0f9c-425b-4fb6-a3eb-df51c9e5eb99&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-yaml"># 2. MutatingAdmissionPolicyBinding - Enlace de la pol&#237;tica
apiVersion: admissionregistration.k8s.io/v1beta1
kind: MutatingAdmissionPolicyBinding
metadata:
  name: add-platform-labels-binding
spec:
  policyName: add-platform-labels

  # Podemos restringir a qu&#233; namespaces se aplica
  matchResources:
    namespaceSelector:
      matchExpressions:
        - key: env
          operator: In
          values: ["production", "staging"]</code></pre></div><h4><strong>policyName</strong> </h4><p>Nombre exacto de la ValidatingAdmissionPolicy que se va a aplicar. </p><h4><strong>matchResources</strong></h4><p> Igual que en la pol&#237;tica, pero aqu&#237; puedes afinar a&#250;n m&#225;s el alcance (por ejemplo, aplicar solo a ciertos namespaces con namespaceSelector). Si lo omites, se aplica a todos los recursos que coincidan con los criterios de la pol&#237;tica.</p><p></p><div class="pullquote"><p>Si este post te ha ayudado o aclarado algo, me har&#237;as muy feliz con un &#10084;&#65039;<br>Y si crees que le puede servir a alguien m&#225;s&#8230; &#161;comp&#225;rtelo! &#128588;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/kubernetes-admission-controllers?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.javivela.dev/p/kubernetes-admission-controllers?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Compartir</span></a></p></div><h2>Conclusi&#243;n</h2><p>Kubernetes est&#225; apostando fuertemente por incorporar de forma nativa capacidades avanzadas de admisi&#243;n, reduciendo la dependencia de herramientas externas como Kyverno o Gatekeeper para casos de uso habituales. Esto permite simplificar el mantenimiento de la plataforma y disminuir su complejidad.</p><p>Por otro lado, la adopci&#243;n de <strong>Common Expression Language (CEL)</strong> como lenguaje de expresiones parece consolidarse, y no ser&#237;a extra&#241;o que termine convirti&#233;ndose en un est&#225;ndar dentro del ecosistema.</p><p>Validar y mutar objetos de manera declarativa es fundamental para mantener un cl&#250;ster consistente, seguro y alineado con las configuraciones deseadas, lo que finalmente nos facilita el trabajo diario y nos permite centrarnos en entregar valor real.</p><h2>Referencias</h2><ul><li><p>https://github.com/kubernetes/enhancements/issues/3962</p></li><li><p>https://github.com/kubernetes/kubernetes/issues/122936</p></li><li><p>https://github.com/kubernetes/kubernetes/pull/136039</p></li><li><p>https://kubernetes.io/docs/reference/access-authn-authz/mutating-admission-policy/</p></li><li><p>https://kubernetes.io/docs/reference/access-authn-authz/validating-admission-policy/</p></li></ul>]]></content:encoded></item><item><title><![CDATA[Common Expression Language (CEL) en Kubernetes]]></title><description><![CDATA[CEL lleva varias releases siendo adoptado en Kubernetes. Aprende sus operadores clave y escribe pol&#237;ticas de validaci&#243;n nativas sin componentes externos.]]></description><link>https://www.javivela.dev/p/common-expression-language-cel-en-kubernetes</link><guid isPermaLink="false">https://www.javivela.dev/p/common-expression-language-cel-en-kubernetes</guid><dc:creator><![CDATA[Javi Vela]]></dc:creator><pubDate>Mon, 23 Mar 2026 10:11:39 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!J7iJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F53e118c7-1aa1-4437-8c54-eb8ae9835c84_1220x1710.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>&#191;Que es <em>Common Expression Language (CEL)?</em></h2><p><em>Common Expression Language (CEL) </em>es un lenguaje de expresiones ligero creado por Google, dise&#241;ado para validaciones, evaluaciones l&#243;gicas r&#225;pidas y portabilidad. A diferencia de un lenguaje de programaci&#243;n completo, CEL es restringido y seguro: no permite ejecuci&#243;n de c&#243;digo arbitrario, lo que lo hace ideal para las APIs de Kubernetes.  </p><h2>Tendencia y adopci&#243;n en Kubernetes</h2><p>Durante los ultimos a&#241;os est&#225; habiendo una tendencia ascendente y fuerte a utilizar <em>Common </em>Expression <em>Language (CEL)</em> para las pol&#237;ticas de validaci&#243;n, gobernanza y admission en Kubernetes.</p><p>Kubernetes incopor&#243;  <em>Common Expression Language (CEL) </em>en la versi&#243;n 1.25 (CRD validation rules), extendiendo su uso a otras funcionalidad como el <code>ValidatingAdmissionPolicy </code>(GA en 1.30).</p><p>Los motivos que han impulsado su utilizaci&#243;n:</p><ul><li><p>Rendimiento: Se ejecuta directamente en el API Server, eliminando la necesidad del uso de webhooks externos, reduciendo as&#237; la latencia</p></li><li><p>Simplicidad y seguridad: Es un lenguaje de expresiones restringido y determinista. No se pueden realizar iteraciones (bucles), no hay acceso a sistemas externos ni ejecuci&#243;n de c&#243;digo arbitrario </p></li><li><p>Nativo: Las reglas se definen en los manifiestos YAML como parte de los propios objetos de Kubernetes (<code>ValidatingAdmissionPolicy </code>y <code>MutatingAdmissionPolicy</code>)</p></li><li><p>Portabilidad: Se est&#225; convirtiendo en un est&#225;ndar, proyectos como Kyverno han comenzado a integrarlo como motor de expresiones. Al igual que otros proyectos como <em><a href="https://docs.cloud.google.com/iam/docs/conditions-overview?hl=es-419#cel">Google Cloud IAM Conditions</a></em> o Envoy entre otros proyectos de la CNCF</p></li></ul><div class="pullquote"><p>&#161;Gracias por pasarte por aqu&#237;! &#128588;<br>Si te interesa seguir recibiendo gu&#237;as pr&#225;cticas sobre Kubernetes, Azure, DevOps y contenedores directamente en tu email&#8230;<br>Suscr&#237;bete gratis y no te pierdas ninguna novedad. &#128640;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/subscribe?&quot;,&quot;text&quot;:&quot;Suscr&#237;bete ahora&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.javivela.dev/subscribe?"><span>Suscr&#237;bete ahora</span></a></p></div><h2>9 ejemplos para comenzar a utilizar <em>Common Expression Language (CEL)</em></h2><h3>Comprobar que exista un m&#237;nimo y m&#225;ximo de replicas</h3><p>CEL soporta el operador ternario condition ? <code>valueIfTrue </code>: <code>valueIfFalse</code>. En este caso se aplica una regla diferente seg&#250;n el namespace. Es una forma poderosa de crear pol&#237;ticas contextuales.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;c130afc7-e33b-42f5-b57d-439b284f42cd&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">object.spec.replicas &gt;= params.minReplicas &amp;&amp; object.spec.replicas &lt;= params.maxReplicas

# Al menos 2 r&#233;plicas para alta disponibilidad
object.spec.replicas &gt;= 2

# Solo aplicar en namespace production
object.metadata.namespace == "production"
  ? object.spec.replicas &gt;= 3
  : object.spec.replicas &gt;= 1</code></pre></div><h3>Comprobar el prefijo y sufijo</h3><p><code>startsWith() </code>y <code>endsWith() </code>son funciones nativas de CEL sobre strings. Ideales para imponer convenciones de nomenclatura en recursos de Kubernetes.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;4691cf84-6c9e-4d70-990b-51035672865e&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext"># El nombre debe empezar con "app-"
object.metadata.name.startsWith("app-")

# El nombre debe terminar con "-prod"
object.metadata.name.endsWith("-prod")

# Combinaci&#243;n de ambos
object.metadata.name.startsWith("app-") &amp;&amp;
object.metadata.name.endsWith("-prod")
</code></pre></div><h3>Comprobar que la imagen tenga un tag</h3><p>Exige que todos los contenedores del Pod usen una imagen con tag expl&#237;cito y distinto de <code>:latest</code>.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;02af9bdd-9292-4a06-b4e6-008a874708d3&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">object.spec.containers.all(c, c.image.contains(&#8217;:&#8217;) &amp;&amp; !c.image.endsWith(&#8217;:latest&#8217;))</code></pre></div><h3>Comprobar la utilizaci&#243;n de contenedores con privilegios</h3><p>Cuando un campo es opcional, usar has() antes de acceder a &#233;l evita errores de evaluaci&#243;n. El cortocircuito de || hace que si !has() es true, la segunda parte no se eval&#250;a. Este patr&#243;n es clave en pol&#237;ticas reales.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;4ab5d85c-5474-429e-922f-9683fd99a799&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">object.spec.containers.all(c, 
  !has(c.securityContext) || 
  !has(c.securityContext.privileged) || 
  c.securityContext.privileged != true
)

# Si existe securityContext, debe tener runAsNonRoot=true
!has(object.spec.securityContext) ||
object.spec.securityContext.runAsNonRoot == true

# Patr&#243;n: campo opcional con valor por defecto
has(object.spec.priority)
  ? object.spec.priority &lt;= 10
  : true
</code></pre></div><h3>Comprobar que todos los contenedores usan request y limits de CPU y memoria</h3><p>Garantiza que cada contenedor del Pod defina expl&#237;citamente <code>requests</code> y <code>limits</code> tanto de CPU como de memoria, evitando pods sin restricciones que puedan afectar al resto del cluster.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;8771f214-ac2d-422c-8368-129689f1ce6b&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">object.spec.containers.all(c, 
  has(c.resources) &amp;&amp; 
  has(c.resources.requests) &amp;&amp; has(c.resources.requests.cpu) &amp;&amp; has(c.resources.requests.memory) &amp;&amp;
  has(c.resources.limits) &amp;&amp; has(c.resources.limits.cpu) &amp;&amp; has(c.resources.limits.memory)
)</code></pre></div><h3>Comprobar si se utilizan volumenes <code>hostPath </code>y <code>hostNetwork</code></h3><p>Impide que un Pod acceda directamente al sistema de archivos o a la red del nodo donde se ejecuta. Ambas capacidades pueden comprometer el aislamiento del cluster si caen en manos de un contenedor malicioso.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;5dff9368-7c08-478a-8036-a92005859de2&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">(!has(object.spec.hostNetwork) || object.spec.hostNetwork == false) &amp;&amp;
(!has(object.spec.volumes) || object.spec.volumes.all(v, !has(v.hostPath)))</code></pre></div><h3>Prohibir actualizar la imagen de un contenedor</h3><p>Garantiza que una vez desplegado un Pod, las im&#225;genes de sus contenedores no puedan cambiarse. &#218;til para entornos donde los cambios de imagen deben pasar por un nuevo despliegue controlado.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;3703907d-2874-44de-bb9f-cab3c9d7af29&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">request.operation != &#8216;UPDATE&#8217; || 
object.spec.template.spec.containers.all(newC, 
  oldObject.spec.template.spec.containers.exists(oldC, 
    oldC.name == newC.name &amp;&amp; oldC.image == newC.image
  )
)</code></pre></div><h3>Comprobar que existen una label con varios valores predeterminados</h3><p>Obliga a que todos los recursos tengan el label <code>tier</code> y que su valor sea uno de los permitidos por la organizaci&#243;n. </p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;ade90931-06cd-4603-a2cc-3ef1768515bc&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">has(object.metadata.labels.tier) &amp;&amp; 
object.metadata.labels.tier in ['frontend', 'backend', 'database']</code></pre></div><h3>Validar que un campo cumpla un patr&#243;n utilizando una expresi&#243;n regular</h3><p>matches() eval&#250;a una expresi&#243;n regular (el subconjunto de regex que usa Go).  No soporta lookaheads ni backreferences. Muy &#250;til para validar formatos de versiones, IPs, o nombres con convenciones estrictas.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;8aa9625d-cdf5-449c-8772-45884bda2767&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext"># Solo min&#250;sculas, n&#250;meros y guiones
object.metadata.name.matches("^[a-z0-9-]+$")

# Validar formato de versi&#243;n sem&#225;ntica
object.spec.version.matches(
  "^v[0-9]+\.[0-9]+\.[0-9]+$"
)</code></pre></div><div class="pullquote"><p>Si este post te ha ayudado o aclarado algo, me har&#237;as muy feliz con un &#10084;&#65039;<br>Y si crees que le puede servir a alguien m&#225;s&#8230; &#161;comp&#225;rtelo! &#128588;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/common-expression-language-cel-en-kubernetes?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.javivela.dev/p/common-expression-language-cel-en-kubernetes?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Compartir</span></a></p></div><p>Como agradecimiento por haber llegado hasta aqu&#237;, te dejo una tabla resumen con los operadores, macros y funciones m&#225;s comunes en CEL.</p><div id="datawrapper-iframe" class="datawrapper-wrap outer" data-attrs="{&quot;url&quot;:&quot;https://datawrapper.dwcdn.net/9DfGB/1/&quot;,&quot;thumbnail_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/53e118c7-1aa1-4437-8c54-eb8ae9835c84_1220x1710.png&quot;,&quot;thumbnail_url_full&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c1b179b3-9f3f-4778-8232-60c2dd749f22_1220x1710.png&quot;,&quot;height&quot;:676,&quot;title&quot;:&quot;kljl&quot;,&quot;description&quot;:&quot;&quot;}" data-component-name="DatawrapperToDOM"><iframe id="iframe-datawrapper" class="datawrapper-iframe" src="https://datawrapper.dwcdn.net/9DfGB/1/" width="730" height="676" frameborder="0" scrolling="no"></iframe><script type="text/javascript">!function(){"use strict";window.addEventListener("message",(function(e){if(void 0!==e.data["datawrapper-height"]){var t=document.querySelectorAll("iframe");for(var a in e.data["datawrapper-height"])for(var r=0;r<t.length;r++){if(t[r].contentWindow===e.source)t[r].style.height=e.data["datawrapper-height"][a]+"px"}}}))}();</script></div><h2>Conclusi&#243;n</h2><p>Creo que CEL no es una moda pasajera: Kubernetes lleva utilizando esta tecnolog&#237;a desde hace varias versiones, y la tendencia es que otros proyectos de la CNCF tambi&#233;n est&#225;n adopt&#225;ndola, consolid&#225;ndose como el motor de expresiones est&#225;ndar.</p><p>Con unos pocos operadores se pueden escribir la mayor&#237;a de las pol&#237;ticas que necesitamos en nuestro d&#237;a a d&#237;a, lo que hace que la curva de aprendizaje sea muy corta.</p><p>Creo que aprender CEL es una buena inversi&#243;n: la misma sintaxis y patrones nos van a servir en diferentes aplicaciones, como Kubernetes, Kyverno y otros proyectos del ecosistema.</p><h2>Referencias</h2><ul><li><p>https://github.com/google/cel-go</p></li><li><p>https://github.com/google/cel-spec/blob/master/doc/langdef.md</p></li><li><p>https://kubernetes.io/docs/reference/using-api/cel/</p></li></ul>]]></content:encoded></item><item><title><![CDATA[Domina Git Submodules en 9 comandos]]></title><description><![CDATA[De una duda en .NET Conf Zaragoza: c&#243;mo usar m&#250;ltiples repos en uno. 9 comandos para dominar Git submodules: init/add/update/sync/status/set-branch/foreach]]></description><link>https://www.javivela.dev/p/domina-git-submodules-en-9-comandos</link><guid isPermaLink="false">https://www.javivela.dev/p/domina-git-submodules-en-9-comandos</guid><dc:creator><![CDATA[Javi Vela]]></dc:creator><pubDate>Mon, 23 Feb 2026 10:11:19 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!4ImG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8320265-b73b-4e75-8ca0-a6badf3af98a_1220x1614.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Durante mi charla sobre las novedades Aspire (<a href="https://blog.javivela.dev/p/novedades-en-aspire-131">https://blog.javivela.dev/p/novedades-en-aspire-131</a>) en la <strong>.NET Conf 2025 Zaragoza</strong> uno de los asistentes (disculpa no recuerdo tu nombre) pregunt&#243; c&#243;mo poder organizar y hacer uso de varias aplicaciones almacenadas en varios repositorios desde otro repositorio. Una de las opciones que tenemos es <a href="https://git-scm.com/book/en/v2/Git-Tools-Submodules">Git Submodules</a>.</p><p>En el siguiente articulo te explico 9 comandos para que domines Git Submodules.</p><div class="pullquote"><p>&#161;Gracias por pasarte por aqu&#237;! &#128588;<br>Si te interesa seguir recibiendo gu&#237;as pr&#225;cticas sobre Kubernetes, Azure, DevOps y contenedores directamente en tu email&#8230;<br>Suscr&#237;bete gratis y no te pierdas ninguna novedad. &#128640;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/subscribe?&quot;,&quot;text&quot;:&quot;Suscr&#237;bete ahora&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.javivela.dev/subscribe?"><span>Suscr&#237;bete ahora</span></a></p></div><h2>Git submodules</h2><p>Son repositorios Git anidados dentro de otros repositorios Git. Permiten incluir proyectos externos en tu proyecto o soluci&#243;n como un subdirectorio.</p><p>Un Git Submodule es esencialmente un puntero a un commit espec&#237;fico de otro repositorio Git.</p><h3><strong>&#191;Por qu&#233; usar </strong>Git Submodules<strong>?</strong></h3><ul><li><p><strong>Reutilizaci&#243;n de c&#243;digo</strong>: Compartir bibliotecas o componentes entre m&#250;ltiples proyectos sin duplicar c&#243;digo</p></li><li><p><strong>Versionado preciso</strong>: Controlar exactamente qu&#233; versi&#243;n de una dependencia usas</p></li><li><p><strong>Separaci&#243;n de concerns</strong>: Mantener m&#243;dulos con ciclos de desarrollo independientes</p></li><li><p><strong>Colaboraci&#243;n multi-equipo</strong>: Diferentes equipos pueden trabajar en m&#243;dulos separados con sus propios permisos</p></li><li><p><strong>Dependencias de terceros</strong>: Incluir librer&#237;as externas manteniendo la trazabilidad de versiones</p></li></ul><div class="pullquote"><p>&#161;Recuerda!</p><p> Revisa el contexto de tu soluci&#243;n, requisitos, ventajas y desventajas de la utilizaci&#243;n de Git Submodules. </p><p>No son ideales para todo: si las dependencias cambian frecuentemente o requieren merges constantes, podr&#237;an complicar el workflow de tu d&#237;a a d&#237;a. </p><p>En esos casos, considera alternativas como paquetes (npm, pip) o Git subtrees.</p></div><h2>9 Comandos para dominar Git Submodules</h2><h3>Activa uno o varios Git Submodules</h3><p>Cuando clonas un repositorio con submodules, estos no est&#225;n activos por defecto. </p><p>Usa <code>init</code> para registrarlos en tu configuraci&#243;n local antes de descargar su c&#243;digo.</p><pre><code>git submodule init</code></pre><p>Activar submodules espec&#237;ficos</p><pre><code><code>git submodule init libs/utils
git submodule init libs/utils libs/auth</code></code></pre><h3>A&#241;ade un Git Submodule</h3><pre><code><code>git submodule add &lt;url-repositorio&gt; &lt;ruta-destino&gt;</code></code></pre><p>Si quieres fijar una rama concreta desde el principio:</p><pre><code><code>git submodule add -b main https://github.com/company/auth-lib.git libs/auth</code></code></pre><p>Recuerda realizar commit con los cambios:</p><pre><code><code>git commit -m &#8220;A&#241;adir submodule utils&#8221;</code></code></pre><h3>Eliminar un Git Submodule</h3><p>Desregistrar el Git Submodule</p><pre><code><code>git submodule deinit -f libs/old-module
git rm -f libs/old-module
rm -rf .git/modules/libs/old-module     # opcional pero muy recomendado
git commit -m "Eliminar submodule old-module"</code></code></pre><h3>Clonar un repositorio con Git Submodules</h3><p>Todo de una vez (opci&#243;n recomendada):</p><pre><code><code>git clone --recursive &lt;url-repositorio&gt;</code></code></pre><p>Si ya clonaste sin <code>--recursive</code>:</p><pre><code><code>git submodule update --init --recursive</code></code></pre><h3>Sincronizar contenido</h3><p>Utiliza el comando <code>git submodule </code>update para sincronizar el contenido.</p><p>Actualizar TODOS los Git Submodules a su &#250;ltimo commit remoto</p><pre><code><code>git submodule update --remote --recursive</code></code></pre><p>Actualizar UN Git Submodule espec&#237;fico:</p><pre><code><code>git submodule update --remote libs/utils</code></code></pre><p>Con merge o rebase autom&#225;tico:</p><pre><code><code>git submodule update --remote --merge
git submodule update --remote --rebase</code></code></pre><p>Despu&#233;s de actualizar, commitea el cambio de referencia:</p><pre><code><code>git add .
git commit -m &#8220;Actualizar submodules a &#250;ltima versi&#243;n&#8221;</code></code></pre><h3>Sincronizar URLs y configuraci&#243;n</h3><p>Utiliza el comando sync en los siguientes supuestos:</p><ol><li><p>La URL del repositorio remoto cambi&#243;</p></li><li><p>Cambias entre HTTPS y SSH</p></li><li><p>El repositorio se movi&#243; a otro servido<strong>r</strong></p></li><li><p>Acabas de hacer <code>git pull</code> y <code>.gitmodules</code> tiene URLs nuevas</p></li></ol><pre><code>git submodule sync</code></pre><h3>Comprueba el estado de los Git Submodules</h3><p>Ver estado b&#225;sico de todos los Git Submodules</p><pre><code><code>git submodule status</code></code></pre><p>Ver resumen de cambios</p><pre><code><code>git submodule summary</code></code></pre><p>Ver status m&#225;s detallado</p><pre><code><code>git status</code></code></pre><h3>Configurar rama a seguir en un Git Submodule</h3><p>Establece que el Git Submodules siga una rama espec&#237;fica (en vez de commit fijo). Actualiza .gitmodules.</p><pre><code><code>git submodule set-branch -b develop libs/utils</code></code></pre><h3>Ejecuta comandos en todos los Git Submodules</h3><pre><code><code>git submodule foreach</code></code></pre><p>Hacer pull en todos los Git Submodules</p><pre><code><code>git submodule foreach 'git pull origin main'</code></code></pre><p>Crear rama en todos  los Git Submodules</p><pre><code><code>git submodule foreach 'git checkout -b feature/update'</code></code></pre><p>Si usas Git Submodules anidados, la opci&#243;n<code>--recursive</code> recorrer&#225; todo</p><pre><code><code>git submodule foreach --recursive 'git status'</code></code></pre><p>Limpiar TODO (cuidado &#8211; destructivo)</p><pre><code><code>git submodule foreach --recursive 'git clean -fdx &amp;&amp; git reset --hard'</code></code></pre><div class="pullquote"><p>Si este post te ha ayudado o aclarado algo, me har&#237;as muy feliz con un &#10084;&#65039;<br>Y si crees que le puede servir a alguien m&#225;s&#8230; &#161;comp&#225;rtelo! &#128588;</p></div><h2>Conclusi&#243;n</h2><p>Los Git Submodules son una herramienta poderosa cuando se usan con criterio, pero no son la soluci&#243;n m&#225;gica para todas las situaciones de dependencias. Valora bien el tradeoff entre control preciso vs. complejidad operativa.</p><div id="datawrapper-iframe" class="datawrapper-wrap outer" data-attrs="{&quot;url&quot;:&quot;https://datawrapper.dwcdn.net/WNqQF/1/&quot;,&quot;thumbnail_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d8320265-b73b-4e75-8ca0-a6badf3af98a_1220x1614.png&quot;,&quot;thumbnail_url_full&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/67c7bdc8-18cf-4c69-b2ec-8c7e7cbdf16e_1220x1614.png&quot;,&quot;height&quot;:831,&quot;title&quot;:&quot;Created with Datawrapper&quot;,&quot;description&quot;:&quot;&quot;}" data-component-name="DatawrapperToDOM"><iframe id="iframe-datawrapper" class="datawrapper-iframe" src="https://datawrapper.dwcdn.net/WNqQF/1/" width="730" height="831" frameborder="0" scrolling="no"></iframe><script type="text/javascript">!function(){"use strict";window.addEventListener("message",(function(e){if(void 0!==e.data["datawrapper-height"]){var t=document.querySelectorAll("iframe");for(var a in e.data["datawrapper-height"])for(var r=0;r<t.length;r++){if(t[r].contentWindow===e.source)t[r].style.height=e.data["datawrapper-height"][a]+"px"}}}))}();</script></div><h2>Referencias</h2><ul><li><p>https://git-scm.com/book/en/v2/Git-Tools-Submodules</p></li></ul>]]></content:encoded></item><item><title><![CDATA[Optimización y seguridad en Dockerfiles]]></title><description><![CDATA[Im&#225;genes ligeras, builds r&#225;pidos, seguridad real. Las pr&#225;cticas que reducen costos de almacenamiento, aceleran Kubernetes y eliminan vulnerabilidades]]></description><link>https://www.javivela.dev/p/optimizacion-y-seguridad-en-dockerfiles</link><guid isPermaLink="false">https://www.javivela.dev/p/optimizacion-y-seguridad-en-dockerfiles</guid><dc:creator><![CDATA[Javi Vela]]></dc:creator><pubDate>Mon, 09 Feb 2026 10:11:18 GMT</pubDate><content:encoded><![CDATA[<p>En este post te cuento mis recomendaciones para optimizar el tama&#241;o y a&#241;adir la seguridad b&#225;sica a tus Dockerfiles y en consecuencia a las imagenes que generas para distribuir y ejecutar tus aplicaciones.</p><blockquote><p><em>Los tiempos y tama&#241;os son ilustrativos pero no universales. Otras dependencias externas pueden afectar al tiempo de build.</em></p></blockquote><div class="pullquote"><p>&#161;Gracias por pasarte por aqu&#237;! &#128588;<br>Si te interesa seguir recibiendo gu&#237;as pr&#225;cticas sobre Kubernetes, Azure, DevOps y contenedores directamente en tu email&#8230;<br>Suscr&#237;bete gratis y no te pierdas ninguna novedad. &#128640;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/subscribe?&quot;,&quot;text&quot;:&quot;Suscr&#237;bete ahora&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.javivela.dev/subscribe?"><span>Suscr&#237;bete ahora</span></a></p></div><h2>Invalidaci&#243;n de cach&#233; en capas por dependencias silenciosas</h2><p>El mayor error es el orden de las instrucciones en Dockerfiles. Veamos el problema:</p><pre><code><code>FROM python:3.11-slim
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
RUN python build.py</code></code></pre><p>&#191;Ves el problema? </p><p>Cuando copias todo el c&#243;digo primero y luego instalas dependencias, cualquier cambio en tu c&#243;digo invalida la capa completa de <code>pip install</code>. </p><p>En un equipo que ejecuta m&#225;s de 20 builds diarias, esto es brutal.</p><pre><code>FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
RUN python build.py</code></pre><p>Ahora un cambio en el c&#243;digo equivale a reconstruir solo la &#250;ltima capa.</p><p><strong>El impacto:</strong> Cambios de c&#243;digo que tardaban 90 segundos ahora tardan 3. Si ejecutas 20 builds diarios, son 29 minutos recuperados. Semanalmente, casi 3 horas de CI/CD sin hacer nada.</p><h2>Utiliza imagenes base Distroless o Slim (Bloat binario)</h2><p>Hay tres tipos de im&#225;genes base. Solo dos son justificables en producci&#243;n.</p><ul><li><p>node:20  ~950MB(incluye npm, compiladores, herramientas de sistema)</p></li><li><p>node:20-slim  ~220MB (Debian slim, solo runtime)</p></li><li><p>node:20-distroless ~150MB (solo aplicaci&#243;n, sin shell ni herramientas)~950M</p></li></ul><p><strong>&#191;Cu&#225;l elegir?</strong></p><p><code>node:20-slim</code> tiene Debian con glibc, package manager b&#225;sico, herramientas de debugging. Es el balance perfecto: peque&#241;o pero no roto.</p><p><code>node:20-distroless</code> es extremo: solo la aplicaci&#243;n, sin shell, sin package manager, sin nada. No puedes debuggear. Pero es m&#225;s peque&#241;o y 100% m&#225;s seguro. Zero ataque surface.</p><pre><code><code># Builder pesado, sin restricciones
FROM node:20 AS builder
WORKDIR /app
COPY package*.json .
RUN npm ci
COPY . .
RUN npm run build

# Runtime minimal
FROM node:20-distroless
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package.json .
EXPOSE 3000
CMD ["node", "dist/index.js"]</code></code></pre><p>Distroless no tiene <code>bash</code>, no tiene <code>sh</code>, no tiene <code>apt</code>. Esto es una ventaja en seguridad, pero una desventaja en debugging. Tu elecci&#243;n depende de tu pol&#237;tica de acceso a contenedores.</p><blockquote><p><em>Hay varias t&#233;cnicas para depurar contenedores. Si te interesa saber c&#243;mo depurar aplicaciones con contenedores ef&#237;meros, &#233;chale un vistazo a mi art&#237;culo:</em></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;dcf246fe-a850-4a47-9f50-2f6154a30f38&quot;,&quot;caption&quot;:&quot;Introducci&#243;n&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Kubernetes: depurando aplicaciones con contenedores ef&#237;meros&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:13405922,&quot;name&quot;:&quot;Javi Vela&quot;,&quot;bio&quot;:&quot;Desde desarrollador .NET a Senior Platform Engineer. Comparto conocimiento sobre Devops, Azure, AWS, CI/CD, K8S, contenedores y arquitectura. &#127942; 9x certified (Azure &amp; K8s) &#128483;&#65039; DotNetters Speaker&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c3aa290a-f8ed-41b8-bd9f-a4cd3b734e4c_768x768.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2022-02-17T07:00:00.000Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!wChm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ab24930-fca3-4f60-9c32-abf82d474671_1026x1190.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://blog.javivela.dev/p/kubernetes-depurando-aplicaciones&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:167294281,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:5488647,&quot;publication_name&quot;:&quot;Javi Vela Blog&quot;,&quot;publication_logo_url&quot;:&quot;&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div></blockquote><h2>Evita <code>COPY . .</code> y utiliza<code>.dockerignore</code></h2><p>Este es el error silencioso que infla tus builds sin que lo notes.</p><pre><code><code>FROM node:20-slim
WORKDIR /app
COPY . .
RUN npm ci
CMD ["npm", "start"]</code></code></pre><p>&#191;Qu&#233; est&#225; en ese .? Todo. node_modules locales (50-500MB), .git (100MB+), coverage reports, logs, archivos de CI, temporales. Todo entra en la capa de construcci&#243;n.</p><p>La mayor&#237;a de eso invalida tu cach&#233; innecesariamente. Cambias un archivo <code>.md</code> en el repo? Reconstruyes. Actualizas <code>.env</code>? Reconstruyes. Ejecutas tests locales? Reconstruyes.</p><p><strong>Dos soluciones: no utilices el </strong><code>COPY . . </code><strong>y utiliza </strong><code>.dockerignore</code></p><pre><code><code># .dockerignore
node_modules/
.git/
.gitignore
.dockerignore
.env
.env.local
coverage/
dist/
build/
*.log
.DS_Store
.vscode/
.idea/
__pycache__/
.pytest_cache/
venv/
.tox/</code></code></pre><p><strong>El impacto:</strong> Tu contexto de build puede pasar de 800MB a 120MB. Las capas se reconstruyen solo por cambios de tu c&#243;digo. En equipos con repositorios grandes (monorepos, proyectos legacy), esto es la diferencia entre 30 segundos y 5 minutos de build.</p><p><strong>Casos comunes que olvidas:</strong></p><ul><li><p><code>.git/</code> &#8212; Puede ser 100MB+ en repos antiguos</p></li><li><p><code>node_modules/</code> &#8212; Tu m&#225;quina local tiene dependencias que no necesita la imagen</p></li><li><p><code>coverage/</code> &#8212; Tests locales generan artifacts que invalidan el cach&#233;</p></li><li><p><code>.env</code> y archivos de configuraci&#243;n local &#8212; No pertenecen a la imagen de producci&#243;n</p></li></ul><p><code>.dockerignore</code> es tan importante como <code>.gitignore</code>. La mayor&#237;a de equipos lo ignora (literalmente).</p><h2>Multi-stage builds: Separa construcci&#243;n de ejecuci&#243;n</h2><p>Construye tu aplicaci&#243;n en un contenedor con todas las herramientas, luego copia <em>solo</em> los binarios al contenedor final. Los ficheros inecesarios desaparecen.</p><pre><code><code>FROM node:20
WORKDIR /app
COPY package*.json .
RUN npm ci
COPY . .
RUN npm run build
CMD ["npm", "start"]

# Imagen final: incluye npm, node-gyp, compiladores, todo</code></code></pre><pre><code><code># Fase de construcci&#243;n
FROM node:20 AS builder
WORKDIR /app
COPY package*.json .
RUN npm ci
COPY ./src ./src
RUN npm run build

# Imagen Runtime (solo lo necesario)
FROM node:20-slim
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package.json .
EXPOSE 3000
CMD ["node", "dist/index.js"]</code></code></pre><p><strong>Desglose del tama&#241;o:</strong></p><ul><li><p><code>node:20</code> : ~950MB</p></li><li><p><code>node:20-slim</code>: ~220MB</p></li><li><p>Multi-stage: ~220MB  (solo runtime + c&#243;digo compilado)</p></li></ul><p><strong>Por qu&#233; funciona:</strong></p><ul><li><p>La etapa builder construye todo, genera artifacts (dist/, node_modules/)</p></li><li><p>La etapa runtime copia solo lo que necesita</p></li><li><p>Docker descarta la etapa builder autom&#225;ticamente</p></li><li><p>Tu imagen final no contiene: compiladores C++, headers, archivos temporales, dependencias de desarrollo</p></li></ul><p><strong>Ejemplo con Phyton</strong></p><pre><code><code>FROM python:3.11
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
RUN python setup.py build_ext --inplace
CMD ["python", "app.py"]</code></code></pre><p>Imagen optimizada:</p><pre><code><code>FROM python:3.11 AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
RUN python setup.py build_ext --inplace

FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /app /app
RUN useradd -m -u 1001 appuser &amp;&amp; chown -R appuser:appuser /app
USER appuser
CMD ["python", "app.py"]</code></code></pre><p><strong>Cu&#225;ndo es cr&#237;tico:</strong></p><ul><li><p>Lenguajes compilados (Go, Rust, C++): El builder es 10x m&#225;s grande que el binario final</p></li><li><p>Proyectos con compilaci&#243;n lenta: Cambios de c&#243;digo no invalidan la etapa builder si las dependencias no cambian</p></li><li><p>Im&#225;genes con m&#250;ltiples pasos de build: Tests, linting, optimizaciones ocurren en etapas descartables</p></li></ul><p><strong>Combinado con </strong><code>.dockerignore</code><strong>:</strong> Tu contexto es peque&#241;o, tu builder es r&#225;pido, tu imagen final es m&#237;nima.</p><h2>Uso de versiones fijas</h2><p>La soluci&#243;n necesita ubuntu y la aplicaci&#243;n <code>curl</code>, instalas la &#250;ltima versi&#243;n disponible:</p><pre><code><code>FROM ubuntu:latest
RUN apt-get update &amp;&amp; apt-get install -y curl</code></code></pre><p>Dos problemas: <code>ubuntu:latest</code> es dinamica, no sabes que versi&#243;n de <code>curl </code>est&#225;s utilizando. Tu build funciona hoy, falla en 3 semans cuando una nueva version de Ubuntu o curl son lanzadas y alquien genera una nueva versi&#243;n de la aplici&#243;n.</p><p>Versiona todo expl&#237;citamente:</p><pre><code><code>FROM ubuntu:24.04
RUN apt-get update &amp;&amp; apt-get install -y curl=8.5.0</code></code></pre><p>Pruebas contra versi&#243;n fija localmente. Upgrades son deliberados, no accidentales. Tu pipeline es reproducible.</p><h2>Minimiza el n&#250;mero de capas (cada RUN es una capa)</h2><p>Una capa en Docker es cada instrucci&#243;n que modifica el filesystem. Cada <code>RUN</code>, <code>COPY</code>, <code>ADD</code>, <code>ENV</code> crea una nueva capa. M&#225;s capas = im&#225;genes m&#225;s grandes porque cada capa guarda todos los cambios, incluso si los eliminas despu&#233;s.</p><p>apt-get clean borra, pero la capa anterior con 400MB sigue existiendo (7 capas en total):</p><pre><code><code>FROM debian:bookworm-slim
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y git
RUN apt-get install -y build-essential
RUN apt-get clean
RUN rm -rf /var/lib/apt/lists/*</code></code></pre><p>Docker file agrupando comandos, total 2 capas:</p><pre><code><code>FROM debian:bookworm-slim
RUN apt-get update &amp;&amp; \
    apt-get install -y curl git build-essential &amp;&amp; \
    apt-get clean &amp;&amp; \
    rm -rf /var/lib/apt/lists/*</code></code></pre><p><strong>&#191;Por qu&#233; importa?</strong></p><p>Cuando haces <code>apt-get install -y curl</code> en una capa, puede generar 45MB de archivos. Si luego en otra capa haces <code>rm -rf /var/lib/apt/lists/*</code>, borra los archivos pero la capa anterior sigue ocupando 45MB en la imagen final.</p><p>Al combinar con <code>&amp;&amp;</code> y limpiar en el <strong>mismo RUN</strong>, Docker descarta los temporales dentro de esa capa.</p><h2>Filtraci&#243;n de secretos en el historial de capas</h2><p>Esto es cr&#237;tico. No copies claves, tokens o credenciales a tu imagen.</p><pre><code><code>RUN AWS_ACCESS_KEY_ID=xxx docker build .</code></code></pre><p>Esa credencial est&#225; grabada en la imagen. Posiblemente este en el registro. Accesible a cualquiera con acceso a <code>docker history</code> o a tu container registry.</p><p>Puedes utilizar <a href="https://docs.docker.com/build/building/secrets/">build secrets</a>:</p><pre><code><code>docker buildx build --secret id=aws,src=$HOME/.aws/credentials .</code></code></pre><p>En el Dockerfile:</p><pre><code><code>RUN --mount=type=secret,id=aws \
    AWS_SHARED_CREDENTIALS_FILE=/run/secrets/aws \
    aws s3 cp ...</code></code></pre><h2>Seguridad en tiempo de ejecuci&#243;n: Tu app corriendo como root</h2><p>La mayor&#237;a de Dockerfiles hace esto:</p><pre><code><code>FROM debian:bookworm-slim
RUN apt-get update &amp;&amp; apt-get install -y myapp
CMD ["myapp"]</code></code></pre><p>&#191;Notas que no hay <code>USER</code>? Tu aplicaci&#243;n corre como root. Si hay una vulnerabilidad remota (y habr&#225;), el atacante tiene acceso root.</p><p>Tres l&#237;neas arreglan esto:</p><pre><code><code>FROM debian:bookworm-slim
RUN apt-get update &amp;&amp; apt-get install -y myapp &amp;&amp; \
    useradd -m -u 1001 appuser &amp;&amp; \
    chown -R appuser:appuser /app
USER appuser
CMD ["myapp"]</code></code></pre><p><strong>El impacto de seguridad:</strong> Una vulnerabilidad ya no significa compromiso total del host. Significa un usuario sandbox limitado. Tu threat model cambia fundamentalmente.</p><div class="pullquote"><p>Si este post te ha ayudado o aclarado algo, me har&#237;as muy feliz con un &#10084;&#65039;<br>Y si crees que le puede servir a alguien m&#225;s&#8230; &#161;comp&#225;rtelo! &#128588;</p></div><h2>Conclusi&#243;n</h2><p>Con una peque&#241;a inversi&#243;n de tiempo para reordenar capas, usar <code>.dockerignore</code>, multi-stage y non-root puedes pasar de tener una imagen muy grande a una muy ligera. No solo ver&#225;s una disminuci&#243;n en el tiempo de tus builds, tambi&#233;n ver&#225;s que la imagen tarda menos en cargarse en Kubernetes y, sumado a todo ello, reduces la superficie de ataque y vulnerabilidades de tus contenedores.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Novedades en Aspire 13.1]]></title><description><![CDATA[Aprovecho la .NET Conf 2025 que acabamos de celebrar en DotNetters Zaragoza, para contarte las &#250;ltimas novedades en Aspire 13.1 y Aspire 13.0]]></description><link>https://www.javivela.dev/p/novedades-en-aspire-131</link><guid isPermaLink="false">https://www.javivela.dev/p/novedades-en-aspire-131</guid><dc:creator><![CDATA[Javi Vela]]></dc:creator><pubDate>Mon, 26 Jan 2026 10:11:14 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/aXouOsBh4ro" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Si no sabes de qu&#233; va Aspire, te recomiendo que leas mi art&#237;culo sobre c&#243;mo desarrollar aplicaciones distribuidas utilizando Aspire: <a href="https://blog.javivela.dev/p/desarrolla-aplicaciones-distribuidas">https://blog.javivela.dev/p/desarrolla-aplicaciones-distribuidas</a></p><p>Si vas con prisa:</p><blockquote><p><em>Microsoft ha creado .NET Aspire (ahora ha sido renombrado simplemente como Aspire), un framework que agiliza el desarrollo de aplicaciones distribuidas, observables y listas para ser desplegadas en producci&#243;n. Los desarrolladores pueden concentrarse en la l&#243;gica de negocio, mientras Aspire se encarga de tareas como la orquestaci&#243;n de servicios y su configuraci&#243;n.</em></p></blockquote><p><br>Si te interesa recibir contenido sobre Kubernetes, DevOps o contentenedores directamente en tu email&#8230; suscr&#237;bete gratis y no te pierdas ninguna novedad. &#128640;</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/subscribe?&quot;,&quot;text&quot;:&quot;Suscribirse&quot;,&quot;language&quot;:&quot;es&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">&#161;GRACIAS por pasarte por aqu&#237;! &#128588;, si te interesa recibir contenido pr&#225;ctico sobre Kubernetes, DevOps o contenedores directamente en tu email&#8230; suscr&#237;bete gratis y no te pierdas ninguna novedad. &#128640;</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Escribe tu correo electr&#243;nico..." tabindex="-1"><input type="submit" class="button primary" value="Suscribirse"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>Rebranding y nueva Web</h2><p>La primera novedad es que .NET Aspire ha sido renombrado simplemente como Aspire,  ahora dispone de su propia p&#225;gina web para consultar toda la documentaci&#243;n: https://aspire.dev/</p><h2>Soporte Pol&#237;glota</h2><p>Python y JavaScript se pueden utilizar junto con .NET.</p><h3><strong>Python</strong></h3><ul><li><p><code>AddPythonApp</code>, <code>AddPythonModule</code>, <code>AddPythonExecutable</code> para diferentes modelos de aplicaci&#243;n</p></li><li><p><code>AddUvicornApp</code> para aplicaciones ASGI (FastAPI, Starlette, Quart)</p></li><li><p>Gesti&#243;n flexible de paquetes: detecci&#243;n autom&#225;tica, soporte para <code>uv</code>, <code>pip</code> y <code>venv</code></p></li><li><p>Generaci&#243;n autom&#225;tica de Dockerfiles</p></li><li><p>Soporte completo de depuraci&#243;n en VS Code</p></li></ul><h3><strong>JavaScript</strong></h3><ul><li><p><code>AddJavaScriptApp</code> como m&#233;todo unificado (reemplaza <code>AddNpmApp</code>)</p></li><li><p>Soporte mejorado para Vite con <code>AddViteApp</code></p></li><li><p>Detecci&#243;n autom&#225;tica de gestores de paquetes (npm, yarn, pnpm)</p></li><li><p>Generaci&#243;n din&#225;mica de Dockerfiles</p></li></ul><h3><strong>Infraestructura</strong></h3><ul><li><p>Propiedades de conexi&#243;n en m&#250;ltiples formatos (URI, JDBC, propiedades individuales)</p></li><li><p>Confianza autom&#225;tica de certificados en todos los lenguajes</p></li><li><p>Variables de entorno simplificadas para descubrimiento de servicios</p></li></ul><h2>AI</h2><p>La versi&#243;n 13.0 de Aspire a&#241;ade el servidor MCP (<a href="https://modelcontextprotocol.io/">Model Context Protocol</a>) el cual nos permite ofrecer informaci&#243;n (recursos, logs y trazas) sobre nuestra soluci&#243;n a nuestros herramientas de AI.</p><p>Aspire 13.1 incluye el comando <code>aspire mcp init</code>, detecta autom&#225;ticamente nuestro entorno de desarrollo y configura todo autom&#225;ticamente.</p><ul><li><p>Descubrimiento de integraciones: los agentes de IA pueden listar las integraciones disponibles de Aspire y recuperar la documentaci&#243;n de cualquier paquete</p></li><li><p>AppHost: listar y cambiar entre proyectos AppHost en tu espacio de trabajo</p></li><li><p>Dashboard: consultar el estado de los recursos, ver logs e inspeccionar trazas de tu aplicaci&#243;n en ejecuci&#243;n</p></li></ul><h2>Azure</h2><ul><li><p>Selecci&#243;n de tenant durante el aprovisionamiento para manejar cuentas multi-tenant</p></li><li><p>Dashboard de Aspire incluido por defecto en Azure App Service</p></li><li><p>Integraci&#243;n con Application Insights para monitoreo y telemetr&#237;a completa</p></li></ul><h2>Developer experience</h2><h3><strong>CLI</strong></h3><ul><li><p><code>aspire init</code> para inicializar soluciones Aspire de forma interactiva</p></li><li><p>Mejoras en <code>aspire update</code> con flag <code>--self</code> para actualizar el CLI</p></li><li><p>Soporte para AppHost de archivo &#250;nico</p></li><li><p>Modo no interactivo para CI/CD</p></li></ul><h3><strong>Extensi&#243;n de VS Code</strong></h3><ul><li><p>Depuraci&#243;n de proyectos Python y C# dentro de VS Code</p></li><li><p>Gesti&#243;n de integraciones</p></li><li><p>Configuraci&#243;n de launch</p></li><li><p>Comandos de publish y deploy (preview)</p></li></ul><h3>Pipelines y Deployment</h3><ul><li><p>aspire do: Nuevo sistema de pipelines para coordinar operaciones de build, publicaci&#243;n y despliegue</p></li><li><p>Soporte para ejecuci&#243;n paralela, seguimiento de dependencias y flujos de trabajo extensibles</p></li><li><p>Reemplaza la infraestructura de publishing anterior con un modelo m&#225;s flexible</p></li></ul><h2>Otros</h2><ul><li><p><strong>Container Files como Artefactos: </strong>Permite extraer archivos del contenedor de un recurso (por ejemplo, frontend compilado) y copiarlos en otro contenedor (backend) usando <code>PublishWithContainerFiles()</code>, ideal para servir aplicaciones SPA desde el backend</p></li><li><p><strong>Construcci&#243;n de Im&#225;genes Utilizando C# (Beta): </strong>API experimental <code>WithDockerfileBuilder()</code> que permite generar Dockerfiles de forma program&#225;tica usando C#, con soporte para multi-stage builds y una API fluida y type-safe</p></li><li><p><strong>Integraci&#243;n con .NET MAUI: </strong>Nueva integraci&#243;n que permite orquestar aplicaciones m&#243;viles MAUI junto a servicios cloud, con soporte para Windows, Mac Catalyst, iOS y Android mediante <code>AddMauiProject()</code> y m&#233;todos como <code>AddAndroidEmulator()</code>, <code>AddiOSSimulator()</code></p></li><li><p>El paquete <code>Aspire.Hosting.DevTunnels</code> ha pasado de experimental a estable, permitiendo exponer tus aplicaciones locales a Internet de forma segura</p></li></ul><div><hr></div><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/novedades-en-aspire-131?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">&#191;Te ha resultado &#250;til o interesante? Un &#10084;&#65039; o un compartir con alg&#250;n compa&#241;ero me ayudar&#237;an much&#237;simo a seguir creando contenido. &#161;Gracias! &#128640;</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/novedades-en-aspire-131?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.javivela.dev/p/novedades-en-aspire-131?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Compartir</span></a></p></div><div><hr></div><p></p><h2>Referencias</h2><ul><li><p><a href="https://blog.javivela.dev/p/desarrolla-aplicaciones-distribuidas">https://blog.javivela.dev/p/desarrolla-aplicaciones-distribuidas</a></p></li><li><p><a href="https://www.youtube.com/watch?v=dJdXdRiIfDw"> Aspire Unplugged with David and Maddy </a></p></li></ul><div id="youtube2-aXouOsBh4ro" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;aXouOsBh4ro&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/aXouOsBh4ro?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div>]]></content:encoded></item><item><title><![CDATA[Kubernetes - Quality of Service (QoS)]]></title><description><![CDATA[Descubre c&#243;mo Kubernetes utiliza los requests y limits de CPU y memoria para asignar la clasificaci&#243;n QoS. Conociendo esta clasificaci&#243;n, puedes evitar posibles reinicios innecesarios en tus Pods.]]></description><link>https://www.javivela.dev/p/kubernetes-quality-of-service-qos</link><guid isPermaLink="false">https://www.javivela.dev/p/kubernetes-quality-of-service-qos</guid><dc:creator><![CDATA[Javi Vela]]></dc:creator><pubDate>Mon, 12 Jan 2026 10:11:21 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!R-ha!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08784498-2344-4903-aaa8-a8436967aef2_1240x1364.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Kubernetes utiliza las requests y limits de CPU y memoria de los contenedores para asignar la clasificaci&#243;n Quality of Service (QoS).</p><p>Dependiendo del tipo de QoS asignado, Kubernetes puede mover el Pod a otro nodo, lo que provoca un reinicio del mismo.</p><p>Cuando definimos estos valores, es un comportamiento que debemos tener en cuenta si queremos evitar que nuestros Pods y contenedores se reinicien en caso de que un nodo no tenga recursos suficientes.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/subscribe?&quot;,&quot;text&quot;:&quot;Suscribirse&quot;,&quot;language&quot;:&quot;es&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">&#161;GRACIAS por dedicar unos minutos tan valiosos a leer los art&#237;culos que escribo! Suscr&#237;bete para no perderte ninguna novedad y tener toda la informaci&#243;n directamente en tu email.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Escribe tu correo electr&#243;nico..." tabindex="-1"><input type="submit" class="button primary" value="Suscribirse"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>Requests y Limits</h2><p>Cuando escribimos la definici&#243;n de un Pod, tenemos la posibilidad de configurar la memoria y CPU asignada a cada uno de los contenedores que lo componen.</p><div><hr></div><p><em>Un Pod se compone de uno o m&#225;s contenedores</em></p><div><hr></div><p>Kubernetes ofrece la posibilidad de hacerlo en las propiedades:</p><ul><li><p><code>spec.containers[].resources.requests</code>: Memoria y CPU m&#237;nima asignada al contenedor.</p></li><li><p><code>spec.containers[].resources.limits</code>: Memoria y CPU m&#225;xima asignada  al contenedor.</p></li></ul><h2>Valores Quality of Service (QoS)</h2><p>Utilizando los valores de memoria y CPU, Kubernetes asigna un estado a cada Pod. Los valores del estado Quality of Service (QoS) son tres y se utilizan para asignar el nodo donde se ejecutar&#225; el Pod y sus contenedores, as&#237; como para priorizar los Pods que se pueden mover a otro nodo en caso de que el nodo necesite liberar recursos.</p><h3>Guaranteed</h3><p>Se asigna este estado cuando todos los contenedores que componen el Pod tienen configurados tanto los requests como los limits y los valores de memoria y CPU son iguales.</p><p>Los Pods con este estado asignado no se mueven a otros nodos cuando se necesitan recursos en el nodo.</p><blockquote><p><em>Se pueden reiniciar y mover en caso de que el nodo no se encuentre disponible o sea eliminado del cl&#250;ster.</em></p></blockquote><p>Esta configuraci&#243;n se aplica a cargas de trabajo cr&#237;ticas para reducir posibles reinicios de los Pods o los contenedores.</p><p>A partir de <a href="https://blog.javivela.dev/p/kubernetes-v134-of-wind-and-will?open=false#%C2%A7resource-management">Kubernetes 1.34 (Of Wind &amp; Will - O&#180;WaW)</a>, no es necesario definir la memoria y CPU en cada uno de los contenedores. Podemos hacerlo a nivel del Pod a trav&#233;s de la propiedad <code>spec.resources.limits</code> y <code>spec.resources.requests</code>.</p><blockquote><p><em>La definici&#243;n de la memoria y CPU se encuentra en estado Beta, aseg&#250;rate que est&#225; activada en tu cl&#250;ster si quieres hacer uso de ella. </em></p><p>Puedes comprobarlo utilizando el endpoint <code>/metrics</code>: <code>kubectl get --raw /metrics | grep kubernetes_feature_enabled</code></p></blockquote><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;yaml&quot;,&quot;nodeId&quot;:&quot;aecf990f-79ac-4afb-b79a-31fc79a461a2&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-yaml">apiVersion: v1
kind: Pod
metadata:
  name: pod-guaranteed
spec:
  containers:
  - name: container
    image: nginx
    resources:
      requests:
        memory: "100Mi"
        cpu: "100m"
      limits:
        memory: "100Mi"
        cpu: "100m"</code></pre></div><p>Comprobamos el QoS asignado por Kubernetes: </p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;fab3485b-fd1e-4bbe-8a85-aa374339a1fc&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">kubectl get pods -n qos -o custom-columns=NAME:.metadata.name,QOS:.status.qosClass</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oEgH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oEgH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png 424w, https://substackcdn.com/image/fetch/$s_!oEgH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png 848w, https://substackcdn.com/image/fetch/$s_!oEgH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png 1272w, https://substackcdn.com/image/fetch/$s_!oEgH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oEgH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png" width="1456" height="194" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:194,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:135323,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.javivela.dev/i/182619123?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!oEgH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png 424w, https://substackcdn.com/image/fetch/$s_!oEgH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png 848w, https://substackcdn.com/image/fetch/$s_!oEgH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png 1272w, https://substackcdn.com/image/fetch/$s_!oEgH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h3>Burstable</h3><p>Kubernetes asigna este estado cuando al Pod no se le asigna el estado Guaranteed y se define la CPU o memoria en los limits o requests de uno de los contenedores que componen el Pod (no es necesario que sean iguales).</p><p>Con este tipo de configuraci&#243;n, podemos hacer un mejor uso de la memoria y CPU compartidas.</p><p>Los Pods en este estado pueden ser reiniciados y movidos a otro nodo despu&#233;s de haber movido los Pods en estado BestEffort.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;yaml&quot;,&quot;nodeId&quot;:&quot;963cff29-1f81-4f0d-bfa6-56b0f1dc1759&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-yaml">apiVersion: v1
kind: Pod
metadata:
  name: pod-burstable
spec:
  containers:
  - name: container
    image: nginx
    resources:
      requests:
        memory: "100Mi"
        cpu: "100m"
      limits:
        memory: "200Mi"
        cpu: "200m"</code></pre></div><h3>Comprobamos el QoS asignado por Kubernetes: </h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;9a04f4b4-dae1-44c6-aa99-ecc930428282&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">kubectl get pods -n qos -o custom-columns=NAME:.metadata.name,QOS:.status.qosClass</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oEgH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oEgH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png 424w, https://substackcdn.com/image/fetch/$s_!oEgH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png 848w, https://substackcdn.com/image/fetch/$s_!oEgH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png 1272w, https://substackcdn.com/image/fetch/$s_!oEgH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oEgH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png" width="1456" height="194" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:194,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:135323,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.javivela.dev/i/182619123?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!oEgH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png 424w, https://substackcdn.com/image/fetch/$s_!oEgH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png 848w, https://substackcdn.com/image/fetch/$s_!oEgH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png 1272w, https://substackcdn.com/image/fetch/$s_!oEgH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h3>BestEffort</h3><p>Se aplica este estado cuando no se define ning&#250;n request ni limit en los contenedores del Pod.</p><p>Los Pods con este estado son los primeros en ser eliminados y movidos de nodo en caso de que sea necesario.</p><p>Aplicamos esta configuraci&#243;n a aplicaciones que se pueden reiniciar sin provocar un impacto importante en nuestra soluci&#243;n.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;yaml&quot;,&quot;nodeId&quot;:&quot;6a91a4fe-e4ee-457b-ab5c-7efbd45935ee&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-yaml">apiVersion: v1
kind: Pod
metadata:
  name: pod-besteffort
spec:
  containers:
  - name: container
    image: nginx</code></pre></div><p>Comprobamos el QoS asignado por Kubernetes: </p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;b61d3ba2-34e7-425c-8e4c-c349c6b6d367&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">kubectl get pods -n qos -o custom-columns=NAME:.metadata.name,QOS:.status.qosClass</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oEgH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oEgH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png 424w, https://substackcdn.com/image/fetch/$s_!oEgH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png 848w, https://substackcdn.com/image/fetch/$s_!oEgH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png 1272w, https://substackcdn.com/image/fetch/$s_!oEgH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oEgH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png" width="1456" height="194" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:194,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:135323,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.javivela.dev/i/182619123?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!oEgH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png 424w, https://substackcdn.com/image/fetch/$s_!oEgH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png 848w, https://substackcdn.com/image/fetch/$s_!oEgH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png 1272w, https://substackcdn.com/image/fetch/$s_!oEgH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d12fcc-53b8-4e89-9a15-9b39dfcacc7b_1722x230.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h2>Conclusion</h2><p>Kubernetes utiliza las clases Quality of Service para priorizar qu&#233; Pods permanecen en ejecuci&#243;n cuando un nodo necesita liberar recursos (Node-pressure Eviction). Entender la diferencia entre Guaranteed, Burstable y BestEffort es esencial para configurar correctamente nuestras aplicaciones.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!R-ha!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08784498-2344-4903-aaa8-a8436967aef2_1240x1364.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!R-ha!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08784498-2344-4903-aaa8-a8436967aef2_1240x1364.png 424w, https://substackcdn.com/image/fetch/$s_!R-ha!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08784498-2344-4903-aaa8-a8436967aef2_1240x1364.png 848w, https://substackcdn.com/image/fetch/$s_!R-ha!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08784498-2344-4903-aaa8-a8436967aef2_1240x1364.png 1272w, https://substackcdn.com/image/fetch/$s_!R-ha!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08784498-2344-4903-aaa8-a8436967aef2_1240x1364.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!R-ha!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08784498-2344-4903-aaa8-a8436967aef2_1240x1364.png" width="1240" height="1364" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/08784498-2344-4903-aaa8-a8436967aef2_1240x1364.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1364,&quot;width&quot;:1240,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:269289,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.javivela.dev/i/182619123?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08784498-2344-4903-aaa8-a8436967aef2_1240x1364.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!R-ha!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08784498-2344-4903-aaa8-a8436967aef2_1240x1364.png 424w, https://substackcdn.com/image/fetch/$s_!R-ha!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08784498-2344-4903-aaa8-a8436967aef2_1240x1364.png 848w, https://substackcdn.com/image/fetch/$s_!R-ha!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08784498-2344-4903-aaa8-a8436967aef2_1240x1364.png 1272w, https://substackcdn.com/image/fetch/$s_!R-ha!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08784498-2344-4903-aaa8-a8436967aef2_1240x1364.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><div><hr></div><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/kubernetes-quality-of-service-qos?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">&#161;Te AGRADEZCO enormemente que hayas dedicado tu valioso tiempo a leer lo que escribo! Si te ha gustado y crees que puede ayudar a otras personas, puedes compartirlo.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/kubernetes-quality-of-service-qos?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.javivela.dev/p/kubernetes-quality-of-service-qos?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Compartir</span></a></p></div><div><hr></div><h2>Referencias</h2><ul><li><p>https://kubernetes.io/docs/concepts/workloads/pods/pod-qos/</p></li><li><p>https://kubernetes.io/docs/tasks/configure-pod-container/assign-pod-level-resources/</p></li><li><p>https://kubernetes.io/docs/tasks/configure-pod-container/quality-service-pod/</p></li></ul><p></p>]]></content:encoded></item><item><title><![CDATA[Kubernetes Gateway API]]></title><description><![CDATA[Gateway API es el nuevo est&#225;ndar para gesti&#243;n de tr&#225;fico en Kubernetes. Reemplaza a NGINX Ingress con mejor dise&#241;o, m&#225;s flexibilidad y soporte para L4/L7.]]></description><link>https://www.javivela.dev/p/kubernetes-gateway-api</link><guid isPermaLink="false">https://www.javivela.dev/p/kubernetes-gateway-api</guid><dc:creator><![CDATA[Javi Vela]]></dc:creator><pubDate>Mon, 29 Dec 2025 10:11:25 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!UMET!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd309308b-e1bb-4339-88fd-242de281bf94_856x908.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hoy hablamos sobre Kubernetes Gateway API, el reemplazo para NGINX Ingress Controller.</p><p><strong>NGINX Ingress Controller es un Ingress controller.</strong> Un ingress controller es un load balancer que se utiliza en los orquestadores de contenedores (como Kubernetes), permiti&#233;ndonos gestionar el tr&#225;fico externo hacia los contenedores de nuestro cl&#250;ster. En resumen, es un reverse proxy en el que podemos configurar diferentes reglas para dirigir el tr&#225;fico de entrada hacia nuestros contenedores.</p><p>El pasado 11 de noviembre de 2025, el grupo de trabajo Kubernetes SIG Network y el comit&#233; Security Response anunciaron que el proyecto NGINX Ingress Controller no se mantendr&#225; a partir de marzo de 2026. Su recomendaci&#243;n es migrar a Gateway API o a otro Ingress Controller (puedes consultar una lista aqu&#237;: <a href="https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/">https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/</a>).</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/subscribe?&quot;,&quot;text&quot;:&quot;Suscribirse&quot;,&quot;language&quot;:&quot;es&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">&#161;GRACIAS por dedicar unos minutos tan valiosos a leer los art&#237;culos que escribo! Suscr&#237;bete para no perderte ninguna novedad y tener toda la informaci&#243;n directamente en tu email.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Escribe tu correo electr&#243;nico..." tabindex="-1"><input type="submit" class="button primary" value="Suscribirse"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>Kubernetes Gateway API</h2><p>Es un proyecto oficial de Kubernetes para gestionar el tr&#225;fico de red en las capas L4 y L7. Proporciona un dise&#241;o gen&#233;rico y basado en roles.</p><blockquote><p>Capa L4: Su objetivo es garantizar la transferencia de datos de extremo a extremo entre dispositivos, gestionando la confiabilidad, el control de flujo y la multiplexaci&#243;n.</p></blockquote><blockquote><p>Capa L7: Es la capa de aplicaci&#243;n. Siendo la capa superior del modelo OSI, interact&#250;a directamente con el software del usuario, proporcionando servicios para aplicaciones como el correo electr&#243;nico o la navegaci&#243;n web.</p></blockquote><p>El proyecto lo mantiene el grupo de trabajo <a href="https://github.com/kubernetes/community/tree/master/sig-network">SIG-Network (Network Special Interest Group)</a>, siendo sus principales objetivos los de mejorar y  proporcionar est&#225;ndares a nivel de red (networking).</p><p>Nos permite configurar y gestionar el tr&#225;fico de red en todas las direcciones:</p><ul><li><p>Norte / Sur (Ingress): Tr&#225;fico desde el exterior hacia el cl&#250;ster (y viceversa).</p></li><li><p>Este / Oeste (Mesh): Tr&#225;fico entre contenedores dentro del cl&#250;ster.</p></li></ul><p>Es f&#225;cil confundir API Gateway y Gateway API, la primera es una herramienta que agrupa y unifica diferentes APIs en una &#250;nica API. De esta manera es posible gestionar y configurar las diferentes APIs en un &#250;nico punto. Algunos servicios como Az<a href="https://learn.microsoft.com/en-us/azure/api-management/api-management-gateways-overview">ure API Management</a> o <a href="https://aws.amazon.com/api-gateway/">Amazon API Gateway</a>.</p><p>Gateway API es una interfaz definida utilizando recursos de Kubernetes y su dise&#241;o se ha basado en los siguientes principios:</p><ul><li><p>Basada en roles</p></li><li><p>Portable</p></li><li><p>Expresiva</p></li><li><p>Extensible</p></li></ul><blockquote><p><em>El dise&#241;o orientado a roles (role-oriented) separa las responsabilidades entre diferentes personas para mejorar la usabilidad, flexibilidad y control en entornos de infraestructura compartida.</em></p></blockquote><h3><strong>GatewayClass</strong></h3><p>Este es un recurso a nivel de cl&#250;ster que define una plantilla para instanciar Gateways, cada GatewayClass utiliza un proveedor diferente (Traefik, Istio, Cilium, entre otros)</p><p>Nos permite desacoplar la implementaci&#243;n de la utilizaci&#243;n, pudiendo definir diferentes GatewayClasses dependiendo de los requisitos de nuestra aplicaci&#243;n.</p><p>En definitiva, describe los posibles Gateways disponibles en el cl&#250;ster para que puedan ser utilizados por el usuario.</p><p>Un ejemplo t&#237;pico ser&#237;a separar las aplicaciones internas de las aplicaciones externas, o utilizar diferentes implementaciones (como Traefik o Istio).</p><pre><code><code>kind: GatewayClass
metadata:
  name: internet
spec:
  controllerName: &#8220;example.net/gateway-controller&#8221;
  parametersRef:
    group: example.net
    kind: Config
    name: internet-gateway-config
---
apiVersion: example.net/v1alpha1
kind: Config
metadata:
  name: internet-gateway-config
spec:
  ip-address-pool: internet-vips</code></code></pre><p></p><h3><strong>Gateway</strong></h3><p>Nos permite definir c&#243;mo vamos a gestionar el tr&#225;fico de nuestra red: endpoints, hostnames, filtrados, etc.</p><p>Cuando un usuario crea un Gateway en Kubernetes, la capa de infraestructura puede crear recursos de load balancer a trav&#233;s del controlador asociado al GatewayClass.</p><p>Un Gateway se define a partir de los siguientes elementos:</p><ul><li><p>GatewayClassName: Define el nombre del GatewayClass a ser utilizado.</p></li><li><p>Listener: Define los nombres de host (hostnames), puertos (ports), protocolos (ej. http o https), TLS (Transport Layer Security), y rutas que pueden ser utilizadas.</p></li><li><p>Address: Define las direcciones IP requeridas para el Gateway.</p></li></ul><pre><code><code>apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: gateway
spec:
  gatewayClassName: internet
  listeners:
  - name: default
    hostname: &#8220;*.my-custom-domain.com&#8221;
    port: 80
    protocol: HTTP</code></code></pre><p>Dependiendo del GatewayClass desplegado, la creaci&#243;n de un Gateway puede implicar la ejecuci&#243;n de algunas acciones para crear diferentes elementos en la infraestructura para poder recibir y redirigir el tr&#225;fico de red:</p><ul><li><p>Uso de las APIs del proveedor cloud para crear un nuevo Load Balancer.</p></li><li><p>Actualizar la configuraci&#243;n de un Load Balancer existente.</p></li><li><p>Configurar el SDN (Software-Defined Networking) para actualizar la configuraci&#243;n existente. </p></li></ul><h3><strong>HTTPRoute</strong></h3><p>Define la ruta de una petici&#243;n HTTP desde un Gateway listener hasta un elemento del cl&#250;ster (API Object, p. ej., a un Service - SVC).</p><p>Se define a partir de los siguientes elementos:</p><ul><li><p>ParentRefs: Define qu&#233; Gateways van a estar asociados a este elemento. Se utiliza el Namespace de donde se ha creado el Gateway y el nombre del Gateway.</p></li><li><p>Hostnames (opcional): Define el nombre o nombres del host (no se pueden utilizar IPs, se pueden utilizar comodines como *) que ser&#225;n enrutados en la definici&#243;n cuando el valor de la cabecera Host de la petici&#243;n coincida.</p></li><li><p>Rules: Permite definir una lista de reglas para enrutar la petici&#243;n hacia los servicios definidos cuando esta coincida con la expresi&#243;n definida:</p><ul><li><p>Matches: Define las condiciones que debe cumplir la petici&#243;n para poder hacer uso del HTTPRoute; el match se har&#225; efectivo si solo una de las condiciones se cumple. </p></li><li><p>Filters: Se utiliza para a&#241;adir informaci&#243;n adicional (p. ej., headers).</p></li><li><p>BackendRefs (opcional): Si no se define, la respuesta a la petici&#243;n recibir&#225; un c&#243;digo de error 404. Permite definir el objeto de Kubernetes que recibir&#225; la petici&#243;n (p. ej., Service).</p></li><li><p>Timeouts (opcional / experimental a la hora de escribir el art&#237;culo): En caso de no especificarse, los timeouts ser&#225;n los definidos en la implementaci&#243;n. Permite definir dos timeouts:</p><ul><li><p>Request: El tiempo m&#225;ximo que tiene el Gateway API para enviar una respuesta al cliente que ha iniciado la petici&#243;n.</p></li><li><p>BackendRequest: Es el tiempo m&#225;ximo que tiene el Gateway para enviar la petici&#243;n al backend.</p></li></ul></li><li><p>Name (opcional): Permite especificar un nombre a la regla definida.</p></li><li><p>sessionPersistence (opcional / experimental a la hora de escribir el art&#237;culo): Define y configurar el tipo de persistencia a utilizar.</p></li><li><p>retry (opcional / experimental a la hora de escribir el art&#237;culo): Define la pol&#237;tica de reintentos para la petici&#243;n.</p></li></ul></li></ul><pre><code><code>apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: bar-route
spec:
  parentRefs:
    - name: gateway
  hostnames:
    - &#8220;bar.example.com&#8221;
  rules:
    - matches:
        - headers:
            - type: Exact
              name: env
              value: canary
      backendRefs:
        - name: bar-svc-canary
          port: 8080
    - backendRefs:
        - name: bar-svc
          port: 8080</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UMET!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd309308b-e1bb-4339-88fd-242de281bf94_856x908.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UMET!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd309308b-e1bb-4339-88fd-242de281bf94_856x908.png 424w, https://substackcdn.com/image/fetch/$s_!UMET!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd309308b-e1bb-4339-88fd-242de281bf94_856x908.png 848w, https://substackcdn.com/image/fetch/$s_!UMET!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd309308b-e1bb-4339-88fd-242de281bf94_856x908.png 1272w, https://substackcdn.com/image/fetch/$s_!UMET!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd309308b-e1bb-4339-88fd-242de281bf94_856x908.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UMET!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd309308b-e1bb-4339-88fd-242de281bf94_856x908.png" width="856" height="908" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d309308b-e1bb-4339-88fd-242de281bf94_856x908.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:908,&quot;width&quot;:856,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:107390,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.javivela.dev/i/179039042?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd309308b-e1bb-4339-88fd-242de281bf94_856x908.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!UMET!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd309308b-e1bb-4339-88fd-242de281bf94_856x908.png 424w, https://substackcdn.com/image/fetch/$s_!UMET!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd309308b-e1bb-4339-88fd-242de281bf94_856x908.png 848w, https://substackcdn.com/image/fetch/$s_!UMET!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd309308b-e1bb-4339-88fd-242de281bf94_856x908.png 1272w, https://substackcdn.com/image/fetch/$s_!UMET!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd309308b-e1bb-4339-88fd-242de281bf94_856x908.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h3>GRPCRoute</h3><p>Al igual que HTTPRoute,  GRPCRoute permite definir  la ruta de una petici&#243;n <a href="https://grpc.io/">gRPC</a> desde un Gateway listener hasta un elemento del cl&#250;ster (API Object, p. ej., a un Service - SVC).</p><div class="pullquote"><p>Las implementaciones que soporten <a href="https://grpc.io/">gRPC</a> fuerzan que los dominios entre HTTPRoutes y gRPCRoutes sean &#250;nicos.</p><p>Se recomienda utilizar hostnames diferentes para el trafico HTTP y <a href="https://grpc.io/">gRPC</a>.  En el caso que sea  necesario utilizar el mismo hostname, se deber&#225; realizar el tipo HTTPRoute para gestionar ambos.</p></div><p>Se define a partir de los siguientes elementos:</p><ul><li><p>ParentRefs: Define qu&#233; Gateways van a estar asociados a este elemento. Se utiliza el Namespace de donde se ha creado el Gateway y el nombre del Gateway.</p></li><li><p>Hostnames (opcional): Define el nombre o nombres del host (no se pueden utilizar IPs, se pueden utilizar comodines como *) que ser&#225;n enrutados en la definici&#243;n cuando el valor de la cabecera Host de la petici&#243;n coincida.</p></li><li><p>Rules: Permite definir una lista de reglas para enrutar la petici&#243;n hacia los servicios definidos cuando esta coincida con la expresi&#243;n definida:</p><ul><li><p>Matches: Define las condiciones que debe cumplir la petici&#243;n para poder hacer uso del HTTPRoute; el match se har&#225; efectivo si solo una de las condiciones se cumple. </p></li><li><p>Filters: Se utiliza para a&#241;adir informaci&#243;n adicional (p. ej., headers).</p></li><li><p>BackendRefs (opcional): Si no se define, la respuesta a la petici&#243;n recibir&#225; un c&#243;digo de error 404. Permite definir el objeto de Kubernetes que recibir&#225; la petici&#243;n (p. ej., Service).</p></li><li><p>Timeouts (opcional / experimental a la hora de escribir el art&#237;culo): En caso de no especificarse, los timeouts ser&#225;n los definidos en la implementaci&#243;n. Permite definir dos timeouts:</p><ul><li><p>Request: El tiempo m&#225;ximo que tiene el Gateway API para enviar una respuesta al cliente que ha iniciado la petici&#243;n.</p></li><li><p>BackendRequest: Es el tiempo m&#225;ximo que tiene el Gateway para enviar la petici&#243;n al backend.</p></li></ul></li><li><p>Name (opcional / experimental a la hora de escribir el art&#237;culo): Permite especificar un nombre a la regla definida.</p></li><li><p>sessionPersistence (opcional / experimental a la hora de escribir el art&#237;culo): Define y configurar el tipo de persistencia a utilizar.</p></li></ul></li></ul><pre><code><code>apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
  name: foo-route
spec:
  parentRefs:
    - name: gateway
  hostnames:
    - &#8220;foo.example.com&#8221;
  rules:
    - matches:
        - method:
            service: com.example
            method: &#8220;*&#8221;
      backendRefs:
        - name: foo-svc
          port: 50051</code></code></pre><h2>Policies</h2><h3>BackendTLSPolicy</h3><p>Nos permite cifrar el tr&#225;fico entre el Gateway y el backend al cual se redirige el tr&#225;fico.</p><h3>BackendTrafficPolicy</h3><p><em>Experimental a la hora de escribir el art&#237;culo </em></p><p>Esta extensi&#243;n nos permite configurar la pol&#237;tica de reintentos de una conexi&#243;n en caso de que la petici&#243;n falle.</p><p>Para poder hacer uso de ella necesitamos especificar:</p><ul><li><p>TargetRefs: Permite definir los objetos de Kubernetes que recibir&#225; la petici&#243;n (p. ej., Service).</p></li><li><p>RetryConstraint: Permite configurar una pol&#237;tica de reintentos <em>Budget retries</em>, la cual permite no saturar el backend cuando este no puede atender todas las peticiones.</p></li><li><p>SessionPersistence: Permite configurar la persistencia de la sesi&#243;n para el target o targets definidos.  Los posibles valores a configurar son Permanent y Persistence (valor por defecto).</p></li></ul><h2>Implementaciones</h2><p>Gateway API es un est&#225;ndar creado por el grupo de trabajo <a href="https://github.com/kubernetes/community/tree/master/sig-network">SIG-Network (Network Special Interest Group)</a>.  A partir de este est&#225;ndar, diferentes proyectos open source y empresas han desarrollado sus implementaciones, gracias al est&#225;ndar y la compatibilidad podr&#237;amos cambiar de proveedor sin necesidad de cambiar ninguno de los recursos creados previamente.</p><p>Antes de elegir una implementaci&#243;n es necesario entender el nivel de conformidad para elegir el que mejor se adapte a nuestros requerimientos. Existen 3 niveles:</p><ul><li><p>Conformant: Han superado pruebas completas para al menos una combinaci&#243;n de Ruta y Perfil (ej. Mesh + HTTPRoute o Gateway + TLSRoute), incluyendo extensiones, en una de las dos versiones m&#225;s nuevas. Deben cubrir al menos un perfil y ruta con todas las pruebas principales.</p></li><li><p>Partially Conformant: Implementaciones que se est&#225;n desarrollando y que al menos han obtenido un informe de conformidad positivo en una de las &#250;ltimas tres versiones.</p></li><li><p>Stale: Implementaciones que posiblemente no se est&#233;n actualizando, se eliminar&#225;n en la siguiente versi&#243;n a no ser que env&#237;en un informe para poder obtener un nivel superior de conformidad.</p></li></ul><p>Puedes consultar una lista de las mismas en el siguiente enlace: https://gateway-api.sigs.k8s.io/implementations/#implementations_1</p><h2>Comparaci&#243;n NGINX Ingress Controller vs Gateway API</h2><p>A continuaci&#243;n, puedes ver una tabla comparativa entre el NGINX Ingress Controller (basado en la API Ingress de Kubernetes) y la Gateway API. Esta comparaci&#243;n se basa en aspectos clave como caracter&#237;sticas, ventajas, limitaciones y evoluci&#243;n.</p><p>En la tabla puedes comprobar por qu&#233; Gateway API representa una evoluci&#243;n m&#225;s flexible y portable para la gesti&#243;n de tr&#225;fico en cl&#250;steres Kubernetes.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QXOg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30be9fb8-9106-436b-9335-9f022efecd17_1610x1970.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QXOg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30be9fb8-9106-436b-9335-9f022efecd17_1610x1970.png 424w, https://substackcdn.com/image/fetch/$s_!QXOg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30be9fb8-9106-436b-9335-9f022efecd17_1610x1970.png 848w, https://substackcdn.com/image/fetch/$s_!QXOg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30be9fb8-9106-436b-9335-9f022efecd17_1610x1970.png 1272w, https://substackcdn.com/image/fetch/$s_!QXOg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30be9fb8-9106-436b-9335-9f022efecd17_1610x1970.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QXOg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30be9fb8-9106-436b-9335-9f022efecd17_1610x1970.png" width="1456" height="1782" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/30be9fb8-9106-436b-9335-9f022efecd17_1610x1970.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1782,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:533197,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.javivela.dev/i/179039042?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30be9fb8-9106-436b-9335-9f022efecd17_1610x1970.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!QXOg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30be9fb8-9106-436b-9335-9f022efecd17_1610x1970.png 424w, https://substackcdn.com/image/fetch/$s_!QXOg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30be9fb8-9106-436b-9335-9f022efecd17_1610x1970.png 848w, https://substackcdn.com/image/fetch/$s_!QXOg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30be9fb8-9106-436b-9335-9f022efecd17_1610x1970.png 1272w, https://substackcdn.com/image/fetch/$s_!QXOg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30be9fb8-9106-436b-9335-9f022efecd17_1610x1970.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h2>Conclusi&#243;n / Resumen</h2><p>Gateway API representa la evoluci&#243;n de la gesti&#243;n de tr&#225;fico externo en Kubernetes. Mientras que Ingress NGINX cumpli&#243; su prop&#243;sito durante a&#241;os, sus limitaciones en extensibilidad y su dise&#241;o lo han convertido en una soluci&#243;n obsoleta para las necesidades actuales de las arquitecturas cloud-native, adem&#225;s de que su mantenimiento terminar&#225; el pr&#243;ximo mes de marzo de 2026.</p><p>La arquitectura basada en roles proporciona una separaci&#243;n clara de responsabilidades entre administradores de infraestructura y desarrolladores. Adem&#225;s, su dise&#241;o expresivo y extensible permite configuraciones avanzadas de L4 y L7 que antes requer&#237;an anotaciones personalizadas o soluciones alternativas. </p><p>&#191;Quieres ver un ejemplo de funcionamiento con Gateway API? Escribe en comentarios y estar&#233; encantado de prepararlo.</p><div><hr></div><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/kubernetes-gateway-api?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">&#161;Te AGRADEZCO enormemente que hayas dedicado tu valioso tiempo a leer lo que escribo! Si te ha gustado y crees que puede ayudar a otras personas, puedes compartirlo.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/kubernetes-gateway-api?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.javivela.dev/p/kubernetes-gateway-api?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Compartir</span></a></p></div><div><hr></div><p></p><h2>Referencias</h2><ul><li><p><a href="https://gateway-api.sigs.k8s.io/">https://gateway-api.sigs.k8s.io/ </a></p></li><li><p><a href="https://kubernetes.io/docs/concepts/services-networking/gateway/">https://kubernetes.io/docs/concepts/services-networking/gateway/</a></p></li></ul><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Kubernetes v1.35: Timbernetes (The World Tree Release)]]></title><description><![CDATA[Kubernetes v1.35, released on December 17, 2025, introduces a range of enhancements focused on improving workload identity, scheduling, security, and resource management.]]></description><link>https://www.javivela.dev/p/kubernetes-v135-timbernetes-the-world</link><guid isPermaLink="false">https://www.javivela.dev/p/kubernetes-v135-timbernetes-the-world</guid><dc:creator><![CDATA[Javi Vela]]></dc:creator><pubDate>Sat, 20 Dec 2025 11:35:34 GMT</pubDate><content:encoded><![CDATA[<p>Inspired by Yggdrasil, the World Tree from Norse mythology, this release emphasizes growth through new features (&#8221;grafting&#8221;) and maintenance by removing outdated ones (&#8221;pruning&#8221;). Below is a comprehensive overview, including key highlights, feature graduations, new additions, and notable changes.</p><h2>Release Cycle</h2><p>The Kubernetes v1.35 release cycle lasted 14 weeks, from September 15, 2025, to December 17, 2025. It delivered 60 enhancements in total, comprising 17 stable, 19 beta, and 22 alpha features. The process focuses on maintaining high-quality, consistent releases through a collaborative global community effort, including the addition of new features, removal of outdated APIs, and overall project maintenance.</p><h2>Contributors</h2><p>This release involved contributions from 85 companies and 419 individuals specifically for v1.35. Across the wider cloud native ecosystem, 281 companies and 1,769 contributors participated. Contributions encompassed code commits, reviews, issue creation, PR handling (including documentation and blogs), and discussions.</p><h2>Ecosystem</h2><p>The release draws inspiration from Yggdrasil (the World Tree), symbolizing community growth through &#8220;grafting&#8221; new features and &#8220;pruning&#8221; old ones. It highlights integrations with projects like MultiKueue for advanced Job handling and Gateway API as a successor to the retiring Ingress NGINX. There&#8217;s a final reminder to upgrade from containerd v1.X to v2.0+. Community engagement includes events such as KubeCon and Kubernetes Community Days (KCD), with invitations to join Special Interest Groups (SIGs) or community forums for involvement.</p><h2>Key Spotlight Features</h2><h3>In-place update of Pod resources</h3><ul><li><p>Short description: Allows adjusting CPU and memory resources without restarting Pods or Containers, enabling nondisruptive vertical scaling.</p></li><li><p>Details: Kubernetes has graduated in-place updates for Pod resources to General Availability (GA). This feature allows users to adjust CPU and memory resources without restarting Pods or Containers. Previously, such modifications required recreating Pods, which could disrupt workloads, particularly for stateful or batch applications. Earlier Kubernetes releases allowed you to change only infrastructure resource settings (requests and limits) for existing Pods. The new in-place functionality allows for smoother, nondisruptive vertical scaling, improves efficiency, and can also simplify development. (GA)</p></li><li><p>KEP <a href="https://kep.k8s.io/1287">#1287</a></p></li></ul><h3>Pod certificates for workload identity and security</h3><ul><li><p>Short description: Enables native workload identity with automated certificate rotation via kubelet and PodCertificateRequest, simplifying service mesh and zero-trust architectures.</p></li><li><p>Details: Previously, delivering certificates to pods required external controllers (cert-manager, SPIFFE/SPIRE), CRD orchestration, and Secret management, with rotation handled by sidecars or init containers. Kubernetes v1.35 enables native workload identity with automated certificate rotation, drastically simplifying service mesh and zero-trust architectures. Now, the kubelet generates keys, requests certificates via PodCertificateRequest, and writes credential bundles directly to the Pod&#8217;s filesystem. The kube-apiserver enforces node restriction at admission time, eliminating the most common pitfall for third-party signers: accidentally violating node isolation boundaries. This enables pure mTLS flows with no bearer tokens in the issuance path. (Beta)</p></li><li><p>KEP <a href="https://kep.k8s.io/4317">#4317</a></p></li></ul><h3>Node declared features before scheduling</h3><ul><li><p>Short description: Allows nodes to declare supported Kubernetes features via <code>.status.declaredFeatures</code>, enabling scheduler and admission controllers to enforce compatible scheduling.</p></li><li><p>Details: When control planes enable new features but nodes lag behind (permitted by Kubernetes skew policy), the scheduler can place pods requiring those features onto incompatible older nodes. The node-declaration features framework allows nodes to declare their supported Kubernetes features. With the new alpha feature enabled, a Node reports the features it supports, publishing this information to the control plane via a new .status.declaredFeatures field. Then, the kube-scheduler, admission controllers, and third-party components can use these declarations. For example, you can enforce scheduling and API validation constraints to ensure that Pods run only on compatible nodes. (Alpha)</p></li><li><p>KEP <a href="https://kep.k8s.io/5328">#5328</a></p></li></ul><h2>Features Graduating to Stable (17 total)</h2><h3>PreferSameNode traffic distribution</h3><ul><li><p>Short description: Introduces PreferSameNode option for Services to prioritize local node endpoints, and renames PreferClose to PreferSameZone for clarity.</p></li><li><p>Details: The trafficDistribution field for Services has been updated to provide more explicit control over traffic routing. A new option, PreferSameNode, has been introduced to let services strictly prioritize endpoints on the local node if available, falling back to remote endpoints otherwise. Simultaneously, the existing PreferClose option has been renamed to PreferSameZone. This change makes the API self-explanatory by explicitly indicating that traffic is preferred within the current availability zone. While PreferClose is preserved for backward compatibility, PreferSameZone is now the standard for zonal routing, ensuring that both node-level and zone-level preferences are clearly distinguished. (Stable)</p></li><li><p>KEP <a href="https://kep.k8s.io/3015">#3015</a></p></li></ul><h3>Job API managed-by mechanism</h3><ul><li><p>Short description: Adds managedBy field to Job API for external controllers like MultiKueue to handle status synchronization without built-in Job controller interference.</p></li><li><p>Details: The Job API now includes a managedBy field that allows an external controller to handle Job status synchronization. This feature, which graduates to stable in Kubernetes v1.35, is primarily driven by MultiKueue, a multi-cluster dispatching system where a Job created in a management cluster is mirrored and executed in a worker cluster, with status updates propagated back. To enable this workflow, the built-in Job controller must not act on a particular Job resource so that the Kueue controller can manage status updates instead. The goal is to allow clean delegation of Job synchronization to another controller. It does not aim to pass custom parameters to that controller or modify CronJob concurrency policies. (Stable)</p></li><li><p>KEP <a href="https://kep.k8s.io/4368">#4368</a></p></li></ul><h3>Reliable Pod update tracking with .metadata.generation</h3><ul><li><p>Short description: Adds metadata.generation and status.observedGeneration to Pod API for verifying spec updates and kubelet processing.</p></li><li><p>Details: Historically, the Pod API lacked the metadata.generation field found in other Kubernetes objects such as Deployments. Because of this omission, controllers and users had no reliable way to verify whether the kubelet had actually processed the latest changes to a Pod&#8217;s specification. This ambiguity was particularly problematic for features like In-Place Pod Vertical Scaling, where it was difficult to know exactly when a resource resize request had been enacted. Kubernetes v1.33 added .metadata.generation fields for Pods, as an alpha feature. That field is now stable in the v1.35 Pod API, which means that every time a Pod&#8217;s spec is updated, the .metadata.generation value is incremented. As part of this improvement, the Pod API also gained a .status.observedGeneration field, which reports the generation that the kubelet has successfully seen and processed. Pod conditions also each contain their own individual observedGeneration field that clients can report and / or observe. Because this feature has graduated to stable in v1.35, it is available for all workloads. (Stable)</p></li><li><p>KEP <a href="https://kep.k8s.io/5067">#5067</a></p></li></ul><h3>Configurable NUMA node limit for topology manager</h3><ul><li><p>Short description: Makes max-allowable-numa-nodes option configurable to support servers with more than 8 NUMA nodes.</p></li><li><p>Details: The topology manager historically used a hard-coded limit of 8 for the maximum number of NUMA nodes it can support, preventing state explosion during affinity calculation. (There&#8217;s an important detail here; a <em>NUMA node</em> is not the same as a Node in the Kubernetes API.) This limit on the number of NUMA nodes prevented Kubernetes from fully utilizing modern high-end servers, which increasingly feature CPU architectures with more than 8 NUMA nodes. Kubernetes v1.31 introduced a new, beta max-allowable-numa-nodes option to the topology manager policy configuration. In Kubernetes v1.35, that option is stable. Cluster administrators who enable it can use servers with more than 8 NUMA nodes. Although the configuration option is stable, the Kubernetes community is aware of the poor performance for large NUMA hosts, and there is a proposed enhancement (KEP-5726) that aims to improve on it. (Stable)</p></li><li><p>KEP <a href="https://kep.k8s.io/4622">#4622</a></p></li></ul><h3>Comparable resource version semantics</h3><ul><li><p>Short description: Updates resource version comparison to support numeric operations.</p></li><li><p>Details: Resource versions are now decimal numbers, allowing client-side comparisons (e.g., newer/older). Enables use cases like storage migration and informer performance. (Stable)</p></li><li><p>KEP <a href="https://kep.k8s.io/5504">#5504</a></p></li></ul><h3>Add CPUManager policy option to restrict reservedSystemCPUs to system daemons and interrupt processing</h3><ul><li><p>Short description: Policy option for CPUManager to reserve CPUs.</p></li><li><p>Details: Enhances resource management for daemons. (Stable)</p></li><li><p>KEP <a href="https://kep.k8s.io/4540">#4540</a></p></li></ul><h3>Invariant Testing</h3><ul><li><p>Short description: Supports testing invariants in Kubernetes components.</p></li><li><p>Details: Improves reliability. (Stable)</p></li><li><p>KEP <a href="https://kep.k8s.io/5468">#5468</a></p></li></ul><h3>Fine-grained SupplementalGroups control</h3><ul><li><p>Short description: Better control over supplemental groups in Pods.</p></li><li><p>Details: Enhances security and flexibility. (Stable)</p></li><li><p>KEP <a href="https://kep.k8s.io/3619">#3619</a></p></li></ul><h3>Add support for a drop-in kubelet configuration directory</h3><ul><li><p>Short description: Supports drop-in configuration for kubelet.</p></li><li><p>Details: Simplifies management. (Stable)</p></li><li><p>KEP <a href="https://kep.k8s.io/3983">#3983</a></p></li></ul><h3>Remove gogo protobuf dependency for Kubernetes API types</h3><ul><li><p>Short description: Removes dependency to modernize API.</p></li><li><p>Details: Reduces maintenance overhead. (Stable)</p></li><li><p>KEP <a href="https://kep.k8s.io/5589">#5589</a></p></li></ul><h3>Pod Generation</h3><ul><li><p>Short description: Tracks Pod spec updates via generation fields.</p></li><li><p>Details: Part of broader Pod API improvements. (Stable)</p></li><li><p>KEP <a href="https://kep.k8s.io/5067">#5067</a></p></li></ul><h3>In-Place Update of Pod Resources</h3><ul><li><p>Short description: Supports nondisruptive resource adjustments for Pods.</p></li><li><p>Details: Highlighted in spotlight. (Stable)</p></li><li><p>KEP <a href="https://kep.k8s.io/1287?">#1287</a></p></li></ul><h3>Add a TopologyManager policy option for MaxAllowableNUMANodes</h3><ul><li><p>Short description: Configurable limit for NUMA nodes in topology manager.</p></li><li><p>Details: As above. (Stable)</p></li><li><p>KEP <a href="https://kep.k8s.io/4622">#4622</a></p></li></ul><h3>PreferSameNode Traffic Distribution (aka PreferLocal)</h3><ul><li><p>Short description: Node-level traffic prioritization in Services.</p></li><li><p>Details: As above. (Stable)</p></li><li><p>KEP <a href="https://kep.k8s.io/3015?">#3015</a></p></li></ul><h3>Job API managed-by mechanism</h3><ul><li><p>Short description: As above.</p></li><li><p>Details: As above. (Stable)</p></li><li><p>KEP <a href="https://kep.k8s.io/4368">#4368</a></p></li></ul><h3>Add support for a drop-in kubelet configuration directory</h3><ul><li><p>Short description: Supports drop-in configuration for kubelet.</p></li><li><p>Details: Simplifies management. (Stable)</p></li><li><p>KEP <a href="https://kep.k8s.io/3983">#3983</a></p></li></ul><h3>Remove gogo protobuf dependency for Kubernetes API types</h3><ul><li><p>Short description: Removes dependency to modernize API.</p></li><li><p>Details: Reduces maintenance overhead. (Stable)</p></li><li><p>KEP <a href="https://kep.k8s.io/5589">#5589</a></p></li></ul><h2>New Features in Beta (19 total)</h2><h3>Expose node topology labels via Downward API</h3><ul><li><p>Short description: Injects topology labels like zone and region into Pods as environment variables or projected volumes for safer topology awareness.</p></li><li><p>Details: Accessing node topology information, such as region and zone, from within a Pod has typically required querying the Kubernetes API server. While functional, this approach creates complexity and security risks by necessitating broad RBAC permissions or sidecar containers just to retrieve infrastructure metadata. Kubernetes v1.35 promotes the capability to expose node topology labels directly via the Downward API to beta. The kubelet can now inject standard topology labels, such as topology.kubernetes.io/zone and topology.kubernetes.io/region, into Pods as environment variables or projected volume files. The primary benefit is a safer and more efficient way for workloads to be topology-aware. This allows applications to natively adapt to their availability zone or region without dependencies on the API server, strengthening security by upholding the principle of least privilege and simplifying cluster configuration. Note: Kubernetes now injects available topology labels to every Pod so that they can be used as inputs to the downward API. With the v1.35 upgrade, most cluster administrators will see several new labels added to each Pod; this is expected as part of the design. (Beta)</p></li><li><p>KEP <a href="https://kep.k8s.io/4742">#4742</a></p></li></ul><h3>Native support for storage version migration</h3><ul><li><p>Short description: Integrates migration logic into core control plane for automatic handling of updates and conflicts.</p></li><li><p>Details: In Kubernetes v1.35, the native support for storage version migration graduates to beta and is enabled by default. This move integrates the migration logic directly into the core Kubernetes control plane (&#8221;in-tree&#8221;), eliminating the dependency on external tools. Historically, administrators relied on manual &#8220;read/write loops&#8221;&#8212;often piping kubectl get into kubectl replace&#8212;to update schemas or re-encrypt data at rest. This method was inefficient and prone to conflicts, especially for large resources like Secrets. With this release, the built-in controller automatically handles update conflicts and consistency tokens, providing a safe, streamlined, and reliable way to ensure stored data remains current with minimal operational overhead. (Beta)</p></li><li><p>KEP <a href="https://kep.k8s.io/4192">#4192</a></p></li></ul><h3>Mutable Volume attach limits</h3><ul><li><p>Short description: Makes CSINode.spec.drivers[*].allocatable.count mutable for dynamic volume attachment capacity updates, with configurable refresh interval.</p></li><li><p>Details: A CSI driver is a Kubernetes plugin that provides a consistent way for storage systems to be exposed to containerized workloads. The CSINode object records details about all CSI drivers installed on a node. However, a mismatch can arise between the reported and actual attachment capacity on nodes. When volume slots are consumed after a CSI driver starts up, the kube-scheduler may assign stateful pods to nodes without sufficient capacity, ultimately getting stuck in a ContainerCreating state. Kubernetes v1.35 makes CSINode.spec.drivers[*].allocatable.count mutable so that a node&#8217;s available volume attachment capacity can be updated dynamically. It also allows CSI drivers to control how frequently the allocatable.count value is updated on all nodes by introducing a configurable refresh interval, defined through the CSIDriver object. Additionally, it automatically updates CSINode.spec.drivers[*].allocatable.count on detecting a failure in volume attachment due to insufficient capacity. Although this feature graduated to beta in v1.34 with the feature flag MutableCSINodeAllocatableCount disabled by default, it remains in beta for v1.35 to allow time for feedback, but the feature flag is enabled by default. (Beta)</p></li><li><p>KEP <a href="https://kep.k8s.io/4876">#4876</a></p></li></ul><h3>Opportunistic batching</h3><ul><li><p>Short description: Improves scheduler performance by batching compatible Pods based on scheduling signatures for shared filtering and scoring.</p></li><li><p>Details: Historically, the Kubernetes scheduler processes pods sequentially with time complexity of O(num pods &#215; num nodes), which can result in redundant computation for compatible pods. This KEP introduces an opportunistic batching mechanism that aims to improve performance by identifying such compatible Pods via Pod scheduling signature and batching them together, allowing shared filtering and scoring results across them. The pod scheduling signature ensures that two pods with the same signature are &#8220;the same&#8221; from a scheduling perspective. It takes into account not only the pod and node attributes, but also the other pods in the system and global data about the pod placement. This means that any pod with the given signature will get the same scores/feasibility results from any arbitrary set of nodes. The batching mechanism consists of two operations that can be invoked whenever needed - <em>create</em> and <em>nominate</em>. Create leads to the creation of a new set of batch information from the scheduling results of Pods that have a valid signature. Nominate uses the batching information from create to set the nominated node name from a new Pod whose signature matches the canonical Pod&#8217;s signature. (Beta)</p></li><li><p>KEP <a href="https://kep.k8s.io/5598">#5598</a></p></li></ul><h3>maxUnavailable for StatefulSets</h3><ul><li><p>Short description: Adds maxUnavailable field to StatefulSet rollingUpdate for controlling unavailable Pods during updates, enabling faster rollouts.</p></li><li><p>Details: A StatefulSet runs a group of Pods and maintains a sticky identity for each of those Pods. This is critical for stateful workloads requiring stable network identifiers or persistent storage. When a StatefulSet&#8217;s .spec.updateStrategy.&lt;type&gt; is set to RollingUpdate, the StatefulSet controller will delete and recreate each Pod in the StatefulSet. It will proceed in the same order as Pod termination (from the largest ordinal to the smallest), updating each Pod one at a time. Kubernetes v1.24 added a new alpha field to a StatefulSet&#8217;s rollingUpdate configuration settings, called maxUnavailable. That field wasn&#8217;t part of the Kubernetes API unless your cluster administrator explicitly opted in. In Kubernetes v1.35 that field is beta and is available by default. You can use it to define the maximum number of pods that can be unavailable during an update. This setting is most effective in combination with .spec.podManagementPolicy set to Parallel. You can set maxUnavailable as either a positive number (example: 2) or a percentage of the desired number of Pods (example: 10%). If this field is not specified, it will default to 1, to maintain the previous behavior of only updating one Pod at a time. This improvement allows stateful applications (that can tolerate more than one Pod being down) to finish updating faster. (Beta)</p></li><li><p>KEP <a href="https://kep.k8s.io/961">#961</a></p></li></ul><h3>Configurable credential plugin policy in .kuberc</h3><ul><li><p>Short description: Adds credentialPluginPolicy and allowlist fields to kuberc for controlling credential plugins.</p></li><li><p>Details: The optional kuberc file is a way to separate server configurations and cluster credentials from user preferences without disrupting already running CI pipelines with unexpected outputs. As part of the v1.35 release, kuberc gains additional functionality which allows users to configure credential plugin policy. This change introduces two fields credentialPluginPolicy, which allows or denies all plugins, and allows specifying a list of allowed plugins using credentialPluginAllowlist. (Beta)</p></li><li><p>KEP <a href="https://kep.k8s.io/3104">#3104</a></p></li></ul><h3>KYAML</h3><ul><li><p>Short description: Promotes KYAML to beta for safer YAML subset in Kubernetes, enabled by default, with optional disable via KUBECTL_KYAML=false.</p></li><li><p>Details: KYAML is a less ambiguous subset of YAML designed for Kubernetes, addressing issues like whitespace and type coercion. Introduced as opt-in alpha in v1.34, it graduates to beta in v1.35 and is enabled by default (can be disabled via KUBECTL_KYAML=false). All KYAML files remain valid YAML. (Beta)</p></li><li><p>KEP <a href="https://kep.k8s.io/5295">#5295</a></p></li></ul><h3>Configurable tolerance for HorizontalPodAutoscalers</h3><ul><li><p>Short description: Allows custom tolerance in HPA behavior field for per-resource scaling sensitivity control.</p></li><li><p>Details: Replaces the fixed 10% global tolerance with a configurable value in the HPA behavior field on a per-resource basis (e.g., 0.05 for 5%). Graduates to beta and enabled by default, preventing unnecessary scaling or blocking sensitive workloads. (Beta)</p></li><li><p>KEP <a href="https://kep.k8s.io/4951">#4951</a></p></li></ul><h3>Support for user namespaces in Pods</h3><ul><li><p>Short description: Enables isolated user and group ID mappings in Pods for improved security.</p></li><li><p>Details: Allows pods to run with isolated IDs, mapping root containers to unprivileged host users, reducing privilege escalation risks. Supports stateless and stateful pods via id-mapped mounts. (Beta)</p></li><li><p>KEP <a href="https://kep.k8s.io/127">#127</a></p></li></ul><h3>VolumeSource: OCI artifact and/or image</h3><ul><li><p>Short description: Supports pulling OCI images into volumes for data-only artifacts, requiring compatible runtime like containerd v2.1+.</p></li><li><p>Details: Allows declarative pulling of OCI artifacts (e.g., configs, binaries) into volumes, separating data from container images. In beta since v1.33, enabled by default in v1.35; requires compatible runtime like containerd v2.1+. (Beta)</p></li><li><p>KEP <a href="https://kep.k8s.io/4639">#4639</a></p></li></ul><h3>Enforced kubelet credential verification for cached images</h3><ul><li><p>Short description: Requires credential checks for cached images to prevent unauthorized access in multi-tenant clusters.</p></li><li><p>Details: For imagePullPolicy: IfNotPresent, the kubelet verifies pod credentials before allowing cached image use, preventing unauthorized access to private images. Graduates to beta, enabled by default; configurable via feature gate and policy flag. (Beta)</p></li><li><p>KEP <a href="https://kep.k8s.io/2535">#2535</a></p></li></ul><h3>Fine-grained Container restart rules</h3><ul><li><p>Short description: Allows restartPolicy and rules at container level for independent restarts based on error codes.</p></li><li><p>Details: Introduces restartPolicy and restartPolicyRules in container specs for granular control (e.g., restart on specific error codes). Graduates to beta, enabled by default; optimizes recovery for complex workloads like AI/ML jobs without pod rescheduling. (Beta)</p></li><li><p>KEP <a href="https://kep.k8s.io/5307">#5307</a></p></li></ul><h3>CSI driver opt-in for service account tokens via secrets field</h3><ul><li><p>Short description: Enables secure ServiceAccount token delivery via secrets field in NodePublishVolume, opt-in via CSIDriver.</p></li><li><p>Details: Drivers set serviceAccountTokenInSecrets to true in CSIDriver objects to get tokens via the secrets field in NodePublishVolume requests, avoiding exposure in volume_context. Maintains backward compatibility. (Beta)</p></li><li><p>KEP <a href="https://kep.k8s.io/5538">#5538</a></p></li></ul><h3>Deployment status: count of terminating replicas</h3><ul><li><p>Short description: Adds terminatingReplicas field to Deployment status for counting Pods in deletion process.</p></li><li><p>Details: Introduces terminatingReplicas in Deployment status (beta) to show Pods with deletion timestamps but not yet removed. Improves observability for lifecycle management and rollouts. (Beta)</p></li><li><p>KEP <a href="https://kep.k8s.io/3973">#3973</a></p></li></ul><h2>New Features in Alpha (22 total)</h2><h3>Gang scheduling support in Kubernetes</h3><ul><li><p>Short description: Introduces Workload API and PodGroup for all-or-nothing scheduling of interdependent workloads.</p></li><li><p>Details: Ensures groups of interdependent Pods (e.g., AI/ML jobs) schedule only if all fit, preventing deadlocks and waste. (Alpha)</p></li><li><p>KEP <a href="https://kep.k8s.io/4671">#4671</a></p></li></ul><h3>Constrained impersonation</h3><ul><li><p>Short description: Adds secondary authorization check for impersonation with fine-grained verbs like impersonate-on:&lt;mode&gt;:&lt;verb&gt;.</p></li><li><p>Details: With ConstrainedImpersonation feature gate, verifies impersonators for specific actions via new verb prefixes (e.g., impersonate-on:&lt;mode&gt;:&lt;verb&gt;), enforcing least privilege. (Alpha)</p></li><li><p>KEP <a href="https://kep.k8s.io/5284">#5284</a></p></li></ul><h3>Flagz for Kubernetes components</h3><ul><li><p>Short description: Enhances /flagz endpoint to support structured JSON output for component configurations.</p></li><li><p>Details: Allows versioned JSON responses via HTTP content negotiation for automated parsing and auditing of command-line options. (Alpha)</p></li><li><p>KEP <a href="https://kep.k8s.io/4828">#4828</a></p></li></ul><h3>Statusz for Kubernetes components</h3><ul><li><p>Short description: Enhances /statusz endpoint to support structured JSON output for component status and health.</p></li><li><p>Details: Supports machine-readable JSON for health indicators and versions via content negotiation, improving automated debugging. (Alpha)</p></li><li><p>KEP <a href="https://kep.k8s.io/4827">#4827</a></p></li></ul><h3>CCM: watch-based route controller reconciliation using informers</h3><ul><li><p>Short description: Introduces event-driven reconciliation for route updates in Cloud Controller Manager using informers.</p></li><li><p>Details: Uses informers to watch Node events instead of polling, reducing API calls and improving responsiveness for route updates. (Alpha)</p></li><li><p>KEP <a href="https://kep.k8s.io/5237">#5237</a></p></li></ul><h3>Extended toleration operators for threshold-based placement</h3><ul><li><p>Short description: Adds numeric comparison operators to tolerations for SLA-aware node placement.</p></li><li><p>Details: Allows Pods to match/avoid nodes based on SLA taints using comparisons, enhancing scheduler precision for reliability and cost. (Alpha)</p></li><li><p>KEP <a href="https://kep.k8s.io/5471">#5471</a></p></li></ul><h3>Mutable container resources when Job is suspended</h3><ul><li><p>Short description: Allows updating resource requests and limits for suspended Jobs via feature gate.</p></li><li><p>Details: Via MutableJobPodResourcesForSuspendedJobs feature gate, allows pausing Jobs, modifying Pod templates, and resuming with fixes (e.g., for OOM errors). (Alpha)</p></li><li><p>KEP <a href="https://kep.k8s.io/5440">#5440</a></p></li></ul><h3>Extended Resource Requests via DRA</h3><ul><li><p>Short description: Addresses gaps in Extended Resource requests for Device Plugins in DRA.</p></li><li><p>Details: Improves scoring and reuse of devices in init containers under DRA (core stable in v1.34, always enabled in v1.35). Part of continued DRA innovations. (Alpha)</p></li><li><p>KEP <a href="https://kep.k8s.io/4381">#4381</a></p></li></ul><h3>Device Taints and Tolerations</h3><ul><li><p>Short description: Introduces &#8220;None&#8221; effect for DeviceTaintRule to report issues without eviction.</p></li><li><p>Details: Allows dry-run eviction checks via status; supports ongoing eviction status. Part of DRA improvements. (Alpha)</p></li><li><p>KEP not specified</p></li></ul><h3>Partitionable Devices</h3><ul><li><p>Short description: Allows defining partitionable devices across multiple ResourceSlices.</p></li><li><p>Details: Enhances flexibility in DRA for device partitioning. (Alpha)</p></li><li><p>KEP not specified</p></li></ul><h3>Consumable Capacity, Device Binding Conditions</h3><ul><li><p>Short description: Fixes bugs and adds tests for consumable capacity and binding conditions in DRA.</p></li><li><p>Details: Improves reliability in DRA resource management. (Alpha)</p></li><li><p>KEP not specified</p></li></ul><h2>Deprecations and Removals</h2><ul><li><p><strong>Ingress NGINX retirement:</strong> Best-effort maintenance until March 2026, after which it will be archived; users should migrate to Gateway API.</p></li><li><p><strong>Removal of cgroup v1 support:</strong> The kubelet will fail to start on nodes without cgroup v2; migration to cgroup v2 is required.</p></li><li><p><strong>Deprecation of ipvs mode in kube-proxy:</strong> Emits warnings upon use; transition to nftables mode is recommended.</p></li><li><p><strong>Final call for containerd v1.X:</strong> Last supported in v1.35; upgrade to containerd 2.0 or later is necessary.</p></li></ul><p>For more details, refer to the official <a href="https://kubernetes.io/blog/2025/12/17/kubernetes-v1-35-release/">Kubernetes v1.35 release blog post</a>.</p>]]></content:encoded></item><item><title><![CDATA[Diferencias entre RUN, CMD y ENTRYPOINT ]]></title><description><![CDATA[Si est&#225;s containerizando aplicaciones, entender las instrucciones CMD, RUN y ENTRYPOINT en un fichero Dockerfile es fundamental. Estas tres instrucciones definen c&#243;mo se construye y ejecuta tu contenedor, pero cada una tiene un prop&#243;sito espec&#237;fico y se ejecuta en&#160;momentos diferentes del ciclo de vida del contenedor.]]></description><link>https://www.javivela.dev/p/diferencias-entre-run-cmd-y-entrypoint</link><guid isPermaLink="false">https://www.javivela.dev/p/diferencias-entre-run-cmd-y-entrypoint</guid><dc:creator><![CDATA[Javi Vela]]></dc:creator><pubDate>Thu, 30 Oct 2025 10:11:38 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!k8tP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23f9268e-31c3-41c3-8803-eb0352b7ab49_1220x1766.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Si est&#225;s containerizando aplicaciones, entender las instrucciones RUN, CMD y ENTRYPOINT en un fichero Dockerfile es fundamental.</p><p>Con estas instrucciones defines c&#243;mo se construye y ejecuta tu contenedor, impactando en el tama&#241;o de la imagen creada y la flexibilidad a la hora de cambiar una configuraci&#243;n.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/subscribe?&quot;,&quot;text&quot;:&quot;Suscribirse&quot;,&quot;language&quot;:&quot;es&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">&#161;GRACIAS por dedicar unos minutos tan valiosos a leer los art&#237;culos que escribo! Suscr&#237;bete para no perderte ninguna novedad y tener toda la informaci&#243;n directamente en tu email.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Escribe tu correo electr&#243;nico..." tabindex="-1"><input type="submit" class="button primary" value="Suscribirse"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>Maneras de definir los par&#225;metros de las instrucciones</h2><p>Podemos definir los par&#225;metros de las instrucciones RUN, CMD y ENTRYPOINT de dos maneras diferentes: <code>exec form </code> y <code>shell form</code>.</p><h3>Shell form</h3><p>Utiliza una shell (<code>/bin/sh -c</code>) para ejecutar los comandos definidos como una cadena de texto. Las caracter&#237;sticas principales son:</p><ul><li><p>Permite usar variables de entorno: $HOME, $PATH</p></li><li><p>Permite operadores shell: &amp;&amp;, ||, pipes |, redirecciones</p></li><li><p>El PID 1 es el shell, no tu aplicaci&#243;n</p></li><li><p>No procesa se&#241;ales correctamente (problemas con SIGTERM)</p></li></ul><p>Puedes definir el uso de una shell diferente con la instrucci&#243;n <code>SHELL</code>.</p><pre><code>CMD comando parametro1 parametro2
RUN apt-get update</code></pre><h3>Exec form</h3><p>Ejecuta el comando directamente sin una shell intermedia. Se utiliza un array JSON para definir cada comando, flag o argumento. Las caracter&#237;sticas principales son:</p><ul><li><p>Tu aplicaci&#243;n es PID 1</p></li><li><p>Procesa se&#241;ales correctamente (SIGTERM, SIGKILL)</p></li><li><p>NO expande variables de entorno directamente</p></li><li><p>NO permite operadores shell</p></li><li><p>M&#225;s eficiente (un proceso menos)</p></li></ul><pre><code>CMD [&#8221;ejecutable&#8221;, &#8220;parametro1&#8221;, &#8220;parametro2&#8221;]
RUN [&#8221;apt-get&#8221;, &#8220;update&#8221;]</code></pre><h2>RUN</h2><p>Nos permite ejecutar comandos en la fase de construcci&#243;n de la imagen (<code>docker build</code>). Cada ejecuci&#243;n crea una nueva capa en la imagen. </p><p>Se utiliza para instalar dependencias, compilar aplicaciones o aplicar configuraciones.</p><pre><code>RUN dotnet restore
RUN apt-get update &amp;&amp; apt-get install -y curl</code></pre><h2>CMD</h2><p>Define el comando y argumentos predeterminados al iniciar el contenedor. Se puede sobreescribir pasando argumentos al comando <code>docker run</code>.</p><pre><code>CMD [&#8221;dotnet&#8221;, &#8220;MiApp.dll&#8221;]</code></pre><h2>ENTRYPOINT</h2><p>Te permite configurar el contenedor como un ejecutable. Puedes a&#241;adir argumentos adicionales al final del mismo con el comando <code>docker run &lt;ARGS&gt;</code>. Se puede sobreescribir con el par&#225;metro <code>--entrypoint</code>.</p><pre><code>ENTRYPOINT [&#8221;dotnet&#8221;, &#8220;MiApp.dll&#8221;] </code></pre><h2>Conclusi&#243;n</h2><p>Utiliza <strong>RUN</strong> para instalar paquetes, configurar el sistema o compilar tu c&#243;digo. </p><p>Utiliza <strong>CMD</strong> para aplicaciones donde necesites flexibilidad, comandos que puedan cambiar o para definir los par&#225;metros de ENTRYPOINT. </p><p>Utiliza <strong>ENTRYPOINT</strong> para configurar tu contenedor como un ejecutable. </p><p>Puedes combinar el uso de ENTRYPOINT y CMD para tener una mayor flexibilidad: ENTRYPOINT define el comando fijo y CMD te proporciona los argumentos por defecto, permitiendo que puedan ser modificados.</p><p>Ejemplo de fichero Dockerfile para compilar y ejecutar una aplicaci&#243;n dotnet:</p><pre><code>FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
RUN dotnet restore &#8220;MiApi.csproj&#8221;
RUN dotnet publish &#8220;MiApi.csproj&#8221; -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT [&#8221;dotnet&#8221;, &#8220;MiApi.dll&#8221;]
CMD [&#8221;--urls&#8221;, &#8220;http://0.0.0.0:8080&#8221;]</code></pre><div id="datawrapper-iframe" class="datawrapper-wrap outer" data-attrs="{&quot;url&quot;:&quot;https://datawrapper.dwcdn.net/0z0R6/2/&quot;,&quot;thumbnail_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/23f9268e-31c3-41c3-8803-eb0352b7ab49_1220x1766.png&quot;,&quot;thumbnail_url_full&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/965ef595-63b5-4c49-8581-898d93e386c7_1220x1836.png&quot;,&quot;height&quot;:942,&quot;title&quot;:&quot;Diferencias entre RUN, CMD y ENTRYPOINT&nbsp;&quot;,&quot;description&quot;:&quot;&quot;}" data-component-name="DatawrapperToDOM"><iframe id="iframe-datawrapper" class="datawrapper-iframe" src="https://datawrapper.dwcdn.net/0z0R6/2/" width="730" height="942" frameborder="0" scrolling="no"></iframe><script type="text/javascript">!function(){"use strict";window.addEventListener("message",(function(e){if(void 0!==e.data["datawrapper-height"]){var t=document.querySelectorAll("iframe");for(var a in e.data["datawrapper-height"])for(var r=0;r<t.length;r++){if(t[r].contentWindow===e.source)t[r].style.height=e.data["datawrapper-height"][a]+"px"}}}))}();</script></div><div><hr></div><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/diferencias-entre-run-cmd-y-entrypoint?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">&#161;Te AGRADEZCO enormemente que hayas dedicado tu valioso tiempo a leer lo que escribo! Si te ha gustado y crees que puede ayudar a otras personas, puedes compartirlo.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/diferencias-entre-run-cmd-y-entrypoint?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.javivela.dev/p/diferencias-entre-run-cmd-y-entrypoint?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Compartir</span></a></p></div><div><hr></div><h2>Referencias</h2><p>https://docs.docker.com/reference/dockerfile/</p><p>https://docs.docker.com/build/building/best-practices/</p>]]></content:encoded></item><item><title><![CDATA[Kubernetes v1.34: Of Wind & Will (O' WaW)]]></title><description><![CDATA[Release Summary: 58 total enhancements - 23 graduated to Stable, 22 entered Beta, 13 entered Alpha]]></description><link>https://www.javivela.dev/p/kubernetes-v134-of-wind-and-will</link><guid isPermaLink="false">https://www.javivela.dev/p/kubernetes-v134-of-wind-and-will</guid><dc:creator><![CDATA[Javi Vela]]></dc:creator><pubDate>Sat, 30 Aug 2025 14:50:01 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/e4373b81-a37c-402f-b9fa-0b1d353cb493_3299x4210.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Key Spotlight Features</h2><h3>Stable: Dynamic Resource Allocation (DRA) Core GA</h3><ul><li><p><strong>Description:</strong> Core DRA functionality for selecting, allocating, sharing, and configuring GPUs, TPUs, NICs and other devices</p></li><li><p><strong>Details:</strong> Based on structured parameters with ResourceClaim, DeviceClass, ResourceClaimTemplate, and ResourceSlice API types</p></li><li><p><strong>KEP:</strong> <a href="https://kep.k8s.io/4381">KEP #4381</a></p></li></ul><h3>Beta: Projected ServiceAccount Tokens for Kubelet Image Credential Providers</h3><ul><li><p><strong>Description:</strong> Short-lived, audience-bound ServiceAccount tokens for authenticating to container registries</p></li><li><p><strong>Benefits:</strong> Eliminates long-lived Secrets, reduces attack surface, simplifies credential management</p></li><li><p><strong>KEP:</strong> <a href="https://kep.k8s.io/4412">KEP #4412</a></p></li></ul><h3>Alpha: KYAML Support - Kubernetes Dialect of YAML</h3><ul><li><p><strong>Description:</strong> Safer, less ambiguous YAML subset designed specifically for Kubernetes</p></li><li><p><strong>Usage:</strong> Available as kubectl output format with <code>KUBECTL_KYAML=true</code> environment variable</p></li><li><p><strong>KEP:</strong> <a href="https://kep.k8s.io/5295">KEP #5295</a></p></li></ul><h2>Features Graduating to Stable (23 total)</h2><h3>Job and Pod Management</h3><ul><li><p><strong>Delayed creation of Job's replacement Pods</strong> - Prevents resource contention by creating replacement Pods only when original Pod fully terminates (<a href="https://kep.k8s.io/3939">KEP #3939</a>)</p></li><li><p><strong>Sleep action for Container lifecycle hooks</strong> - PreStop and PostStart lifecycle hooks with configurable sleep duration (<a href="https://kep.k8s.io/3960">KEP #3960</a>, <a href="https://kep.k8s.io/4818">KEP #4818</a>)</p></li><li><p><strong>Ordered Namespace deletion</strong> - Structured deletion process ensuring security dependencies are respected (<a href="https://kep.k8s.io/5080">KEP #5080</a>)</p></li></ul><h3>Storage Enhancements</h3><ul><li><p><strong>Recovery from volume expansion failure</strong> - Cancel and retry volume expansions with smaller values (<a href="https://kep.k8s.io/1790">KEP #1790</a>)</p></li><li><p><strong>VolumeAttributesClass for volume modification</strong> - Generic API for modifying volume parameters like provisioned IO (<a href="https://kep.k8s.io/3751">KEP #3751</a>)</p></li></ul><h3>Authentication and Authorization</h3><ul><li><p><strong>Structured authentication configuration</strong> - Configuration file format for API server client authentication (<a href="https://kep.k8s.io/3331">KEP #3331</a>)</p></li><li><p><strong>Finer-grained authorization based on selectors</strong> - Authorization decisions based on field and label selectors (<a href="https://kep.k8s.io/4601">KEP #4601</a>)</p></li><li><p><strong>Restrict anonymous requests with fine-grained controls</strong> - Configure specific endpoints for unauthenticated requests (<a href="https://kep.k8s.io/4633">KEP #4633</a>)</p></li></ul><h3>Scheduling and Performance</h3><ul><li><p><strong>More efficient requeueing through plugin-specific callbacks</strong> - Accurate decisions about when to retry scheduling unschedulable Pods (<a href="https://kep.k8s.io/4247">KEP #4247</a>)</p></li><li><p><strong>Streaming list responses</strong> - Streaming encoding mechanism for large list responses to reduce memory pressure (<a href="https://kep.k8s.io/5116">KEP #5116</a>)</p></li><li><p><strong>Resilient watch cache initialization</strong> - More robust watch cache initialization during API server startup (<a href="https://kep.k8s.io/4568">KEP #4568</a>)</p></li></ul><h3>Node and Container Runtime</h3><ul><li><p><strong>Linux node swap support</strong> - Configurable per-node swap support with LimitedSwap mode (<a href="https://kep.k8s.io/2400">KEP #2400</a>)</p></li><li><p><strong>Allow special characters in environment variables</strong> - Support for nearly all printable ASCII characters in variable names (<a href="https://kep.k8s.io/4369">KEP #4369</a>)</p></li><li><p><strong>Taint management separated from Node lifecycle</strong> - TaintManager refactored as separate controller (<a href="https://kep.k8s.io/3902">KEP #3902</a>)</p></li></ul><h3>Network and Windows</h3><ul><li><p><strong>Relaxing DNS search path validation</strong> - More flexible DNS search path configuration (<a href="https://kep.k8s.io/4427">KEP #4427</a>)</p></li><li><p><strong>Support for Direct Service Return (DSR) in Windows kube-proxy</strong> - Performance optimizations for Windows load balancing (<a href="https://kep.k8s.io/5100">KEP #5100</a>)</p></li></ul><h3>Additional Stable Features</h3><ul><li><p><strong>API Server tracing</strong> (<a href="https://kep.k8s.io/647">KEP #647</a>)</p></li><li><p><strong>AppArmor support</strong> (<a href="https://kep.k8s.io/24">KEP #24</a>)</p></li><li><p><strong>Consistent Reads from Cache</strong> (<a href="https://kep.k8s.io/2340">KEP #2340</a>)</p></li><li><p><strong>Discover cgroup driver from CRI</strong> (<a href="https://kep.k8s.io/4033">KEP #4033</a>)</p></li><li><p><strong>Kubelet OpenTelemetry Tracing</strong> (<a href="https://kep.k8s.io/2831">KEP #2831</a>)</p></li></ul><h2>New Features in Beta (22 total)</h2><h3>Resource Management</h3><ul><li><p><strong>Pod-level resource requests and limits</strong> - Resource budgets at Pod level shared among containers, with HPA support (<a href="https://kep.k8s.io/2837">KEP #2837</a>)</p></li><li><p><strong>In-place Pod resize improvements</strong> - Support for decreasing memory usage and Pod-level resource integration (<a href="https://kep.k8s.io/1287">KEP #1287</a>)</p></li></ul><h3>CLI and Configuration</h3><ul><li><p><strong>.kuberc file for kubectl user preferences</strong> - Configuration file for kubectl preferences and command aliases (<a href="https://kep.k8s.io/3104">KEP #3104</a>)</p></li></ul><h3>Authentication and Security</h3><ul><li><p><strong>External ServiceAccount token signing</strong> - Integration with external key management solutions for token signing (<a href="https://kep.k8s.io/740">KEP #740</a>)</p></li><li><p><strong>Mutating admission policies</strong> - Declarative, in-process alternative to mutating admission webhooks using CEL (<a href="https://kep.k8s.io/3962">KEP #3962</a>)</p></li></ul><h3>DRA Beta Features</h3><ul><li><p><strong>Admin access for secure resource monitoring</strong> - Controlled administrative access to in-use devices for monitoring (<a href="https://kep.k8s.io/5018">KEP #5018</a>)</p></li><li><p><strong>Prioritized alternatives in ResourceClaims</strong> - Ordered list of resource alternatives with <code>firstAvailable</code> field (<a href="https://kep.k8s.io/4816">KEP #4816</a>)</p></li><li><p><strong>Kubelet reports allocated DRA resources</strong> - PodResourcesAPI reporting of DRA allocations (<a href="https://kep.k8s.io/3695">KEP #3695</a>)</p></li></ul><h3>Scheduling and Performance</h3><ul><li><p><strong>kube-scheduler non-blocking API calls</strong> - Asynchronous API handling with prioritized queue system (<a href="https://kep.k8s.io/5229">KEP #5229</a>)</p></li><li><p><strong>Snapshottable API server cache</strong> - Serve list requests from cache snapshots instead of etcd (<a href="https://kep.k8s.io/4988">KEP #4988</a>)</p></li><li><p><strong>Streaming informers for list requests</strong> - Memory-efficient streaming for large datasets using WatchList mechanism (<a href="https://kep.k8s.io/3157">KEP #3157</a>)</p></li></ul><h3>Platform Support</h3><ul><li><p><strong>Graceful node shutdown handling for Windows nodes</strong> - Windows nodes can detect shutdown events and gracefully terminate Pods (<a href="https://kep.k8s.io/4802">KEP #4802</a>)</p></li></ul><h3>Validation and Development</h3><ul><li><p><strong>Tooling for declarative validation of Kubernetes-native types</strong> - CEL-based validation rules for native Kubernetes types (<a href="https://kep.k8s.io/5073">KEP #5073</a>)</p></li></ul><h3>Network Improvements</h3><ul><li><p><strong>Traffic distribution enhancements</strong> - <code>PreferSameZone</code> and <code>PreferSameNode</code> options, deprecating <code>PreferClose</code> (<a href="https://kep.k8s.io/3015">KEP #3015</a>)</p></li></ul><h2>New Features in Alpha (13 total)</h2><h3>Security and Authentication</h3><ul><li><p><strong>Pod certificates for mTLS authentication</strong> - X.509 certificates for Pods via PodCertificateRequests (<a href="https://kep.k8s.io/4317">KEP #4317</a>)</p></li><li><p><strong>"Restricted" Pod security standard forbids remote probes</strong> - Security enhancement preventing probe misuse (<a href="https://kep.k8s.io/4940">KEP #4940</a>)</p></li></ul><h3>Scheduling</h3><ul><li><p><strong>Use .status.nominatedNodeName to express Pod placement</strong> - Scheduler indicates Pod placement intentions to help autoscalers (<a href="https://kep.k8s.io/5278">KEP #5278</a>)</p></li></ul><h3>DRA Alpha Features</h3><ul><li><p><strong>Resource health status for DRA</strong> - Expose health status of devices allocated to Pods (<a href="https://kep.k8s.io/4680">KEP #4680</a>)</p></li><li><p><strong>Extended resource mapping</strong> - Simple alternative to DRA using familiar container resource syntax (<a href="https://kep.k8s.io/5004">KEP #5004</a>)</p></li><li><p><strong>DRA consumable capacity</strong> - Share devices or device slices across multiple ResourceClaims (<a href="https://kep.k8s.io/5075">KEP #5075</a>)</p></li><li><p><strong>Device binding conditions</strong> - Delay Pod binding until external resources are confirmed ready (<a href="https://kep.k8s.io/5007">KEP #5007</a>)</p></li></ul><h3>Container Management</h3><ul><li><p><strong>Container restart rules</strong> - Per-container restart policies and rules based on exit codes (<a href="https://kep.k8s.io/5307">KEP #5307</a>)</p></li><li><p><strong>Load environment variables from files created in runtime</strong> - Runtime environment variable generation from files (<a href="https://kep.k8s.io/3721">KEP #3721</a>)</p></li></ul><h2>Deprecations and Removals</h2><h3>Deprecated</h3><ul><li><p><strong>Manual cgroup driver configuration</strong> - <code>cgroupDriver</code> configuration setting and <code>--cgroup-driver</code> flag deprecated, removal planned for v1.36+ (<a href="https://kep.k8s.io/4033">KEP #4033</a>)</p></li><li><p><strong>PreferClose traffic distribution</strong> - Deprecated in favor of <code>PreferSameZone</code> and <code>PreferSameNode</code> (<a href="https://kep.k8s.io/3015">KEP #3015</a>)</p></li></ul><h3>End of Support Timeline</h3><ul><li><p><strong>containerd 1.x support</strong> - Kubernetes v1.35 will be the last release supporting containerd 1.x, upgrade to 2.0+ recommended (<a href="https://kep.k8s.io/4033">KEP #4033</a>)</p></li></ul><div><hr></div><p><strong>Release Cycle:</strong> 15 weeks (May 19 - August 27, 2025)<br><strong>Contributors:</strong> 491 individuals from 106 companies<br><strong>Ecosystem:</strong> 2,235 contributors from 370 companies across cloud native projects</p>]]></content:encoded></item><item><title><![CDATA[Contenedores: Desde el kernel hasta la orquestación - kubernetes]]></title><description><![CDATA[Parece trivial ejecutar un contenedor, pero la realidad es mucho m&#225;s compleja. En la tercera parte de la saga &#8220;Desde el kernel hasta la orquestaci&#243;n&#8221; nos adentramos en la orquestaci&#243;n de contedores.]]></description><link>https://www.javivela.dev/p/kubernetes-desde-el-kernel-hasta-la-orquestacion</link><guid isPermaLink="false">https://www.javivela.dev/p/kubernetes-desde-el-kernel-hasta-la-orquestacion</guid><dc:creator><![CDATA[Javi Vela]]></dc:creator><pubDate>Sun, 20 Jul 2025 09:11:16 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!9Kw3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4e2fec6-7a49-41a2-bbd5-4340935225a0_2396x2890.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introducci&#243;n</h2><p>En la tercera parte de la saga &#8220;Desde el kernel hasta la orquestaci&#243;n&#8221; nos adentramos en la orquestaci&#243;n de contenedores.</p><p>Si todav&#237;a no has le&#237;do los art&#237;culos anteriores, te recomiendo empezar por el primero, donde hablo de <em>namespaces</em> (Linux) y <em>control groups</em> (cgroups), herramientas de bajo nivel incluidas en el kernel de Linux para aislar procesos y limitar el acceso a los recursos del host: <a href="https://blog.javivela.dev/p/namespaces-y-control-groups-desde-el-kernel-hasta-la-orquestacion">cgroups y namespaces</a>.</p><p>En el segundo art&#237;culo de la saga, explico c&#243;mo herramientas de m&#225;s alto nivel como <code>runc</code> y <code>containerd</code> crean una capa de abstracci&#243;n que permite ejecutar &#8220;contenedores&#8221; de manera m&#225;s sencilla y segura: <a href="https://blog.javivela.dev/p/runc-y-containerd-desde-el-kernel-hasta-la-orquestacion">runc y containerd</a>.</p><p>En este post voy a explicar c&#243;mo Kubernetes interact&#250;a con todas estas herramientas para orquestar contenedores de manera eficiente y escalable.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/subscribe?&quot;,&quot;text&quot;:&quot;Suscribirse&quot;,&quot;language&quot;:&quot;es&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">&#161;<strong>GRACIAS</strong> por dedicar unos minutos tan valiosos a leer los art&#237;culos que escribo! Suscr&#237;bete para no perderte ninguna novedad y tener toda la informaci&#243;n directamente en tu email.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Escribe tu correo electr&#243;nico..." tabindex="-1"><input type="submit" class="button primary" value="Suscribirse"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>Kubernetes</h2><p>Kubernetes es un orquestador de contenedores que monitoriza su estado y ejecuta las acciones necesarias para mantenerlos en el estado deseado. Permite escalar y actualizar aplicaciones de forma autom&#225;tica, facilitando la orquestaci&#243;n de soluciones complejas.</p><p>Kubernetes dispone de dos tipos de nodos:</p><ul><li><p><strong>Control Plane</strong>: se encarga de ejecutar los procesos que gestionan y orquestan los contenedores de usuario.</p></li><li><p><strong>Worker</strong>: ejecuta los contenedores de usuario.</p></li></ul><p>En los nodos de tipo <em>control plane</em> se ejecutan los procesos cr&#237;ticos de Kubernetes que permiten monitorizar y ejecutar las acciones necesarias para mantener los contenedores en el estado definido. Estos procesos son:</p><ul><li><p><strong>etcd</strong>: almacenamiento distribuido de datos clave-valor donde Kubernetes guarda toda la informaci&#243;n de estado del cl&#250;ster.</p></li><li><p><strong>kube-apiserver</strong>: expone la API de Kubernetes y es el punto de entrada para todas las operaciones (ej. crear un Pod o consultar su estado).</p></li><li><p><strong>kube-scheduler</strong>: asigna los pods a los nodos disponibles seg&#250;n las necesidades de recursos y restricciones.</p></li><li><p><strong>kube-controller-manager</strong>: ejecuta los controladores que monitorizan el estado del cl&#250;ster y realizan acciones para mantener el estado deseado.</p></li></ul><p>En cada nodo de tipo worker se ejecutan dos procesos principales:</p><ul><li><p><strong>kubelet</strong>: agente que se encarga de gestionar los pods y contenedores en el nodo, asegurando que se ejecuten correctamente.</p></li><li><p><strong>kube-proxy</strong>: gestiona la red y el balanceo de carga para exponer los servicios de Kubernetes dentro y fuera del cl&#250;ster.</p></li></ul><blockquote><p>Un <strong>Pod</strong> es la unidad m&#225;s peque&#241;a de despliegue en Kubernetes. Representa uno o varios contenedores que comparten el mismo espacio de red, almacenamiento y configuraci&#243;n. Todos los contenedores de un Pod se ejecutan en el mismo nodo y pueden comunicarse entre s&#237; a trav&#233;s de <code>localhost</code>.</p></blockquote><p>El flujo de creaci&#243;n de un Pod en Kubernetes ser&#237;a el siguiente:</p><ul><li><p>Cuando un usuario crea un nuevo Pod (uno o m&#225;s contenedores trabajando entre s&#237;), interact&#250;a con <code>kube-apiserver</code>. Una vez procesada la solicitud, <code>kube-scheduler</code> decide en qu&#233; nodo de tipo worker debe ejecutarse.</p></li><li><p>La solicitud es recibida por <code>kubelet</code>, que realiza las operaciones necesarias para comenzar la ejecuci&#243;n de los contenedores a trav&#233;s del Container Runtime Interface (CRI).</p></li></ul><p>El siguiente diagrama muestra la arquitectura que vamos a explorar en el post, desde el control plane de Kubernetes hasta los procesos del kernel:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9Kw3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4e2fec6-7a49-41a2-bbd5-4340935225a0_2396x2890.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9Kw3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4e2fec6-7a49-41a2-bbd5-4340935225a0_2396x2890.png 424w, https://substackcdn.com/image/fetch/$s_!9Kw3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4e2fec6-7a49-41a2-bbd5-4340935225a0_2396x2890.png 848w, https://substackcdn.com/image/fetch/$s_!9Kw3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4e2fec6-7a49-41a2-bbd5-4340935225a0_2396x2890.png 1272w, https://substackcdn.com/image/fetch/$s_!9Kw3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4e2fec6-7a49-41a2-bbd5-4340935225a0_2396x2890.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9Kw3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4e2fec6-7a49-41a2-bbd5-4340935225a0_2396x2890.png" width="1456" height="1756" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4e2fec6-7a49-41a2-bbd5-4340935225a0_2396x2890.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1756,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:696777,&quot;alt&quot;:&quot;Diagrama funcionamiento: Kubernetes, CRI, containerd, cgroups y namespaces&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.javivela.dev/i/167831092?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4e2fec6-7a49-41a2-bbd5-4340935225a0_2396x2890.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Diagrama funcionamiento: Kubernetes, CRI, containerd, cgroups y namespaces" title="Diagrama funcionamiento: Kubernetes, CRI, containerd, cgroups y namespaces" srcset="https://substackcdn.com/image/fetch/$s_!9Kw3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4e2fec6-7a49-41a2-bbd5-4340935225a0_2396x2890.png 424w, https://substackcdn.com/image/fetch/$s_!9Kw3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4e2fec6-7a49-41a2-bbd5-4340935225a0_2396x2890.png 848w, https://substackcdn.com/image/fetch/$s_!9Kw3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4e2fec6-7a49-41a2-bbd5-4340935225a0_2396x2890.png 1272w, https://substackcdn.com/image/fetch/$s_!9Kw3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4e2fec6-7a49-41a2-bbd5-4340935225a0_2396x2890.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Diagrama funcionamiento: Kubernetes, CRI, containerd, cgroups y namespaces</figcaption></figure></div><h2>Container Runtime Interface (CRI)</h2><p>Una de las principales caracter&#237;sticas de Kubernetes es la interoperabilidad con diferentes runtimes de contenedores. Para lograrlo, Kubernetes define Container Runtime Interface (CRI), un est&#225;ndar basado en <a href="https://grpc.io/">gRPC</a> que permite a <code>kubelet</code> comunicarse con distintos motores de ejecuci&#243;n de contenedores (como containerd, CRI-O, Docker, etc.) de manera uniforme y desacoplada.</p><p>CRI facilita la integraci&#243;n de nuevos runtimes sin necesidad de modificar el c&#243;digo, promoviendo as&#237; la flexibilidad y la evoluci&#243;n del ecosistema de contenedores.</p><p>Una vez que <code>kubelet</code> recibe la petici&#243;n para ejecutar un nuevo Pod, realiza las siguientes acciones:</p><ul><li><p>Crear el namespace, cgroups y configurar la red.</p></li><li><p>Realizar pull de la imagen o im&#225;genes en caso de que fuera necesario.</p></li><li><p>Crear el container</p></li><li><p>Ejecutar el container</p></li></ul><p>Para ello, la interfaz proporciona las siguientes interfaces a trav&#233;s de los servicios <code>RuntimeService</code> e <code>ImageService</code>.</p><p></p><blockquote><p>Puedes encontrar la definici&#243;n de las interfaces en el siguiente enlace: </p><p>https://github.com/kubernetes/cri-api/blob/master/pkg/apis/runtime/v1/api.proto</p></blockquote><p></p><p>A continuaci&#243;n te describo algunos de los m&#233;todos m&#225;s importantes:</p><p>El PodSandbox es el entorno compartido donde vivir&#225;n todos los contenedores del Pod:</p><ul><li><p><code>RunPodSandbox</code> &#8211; Crea los namespaces, configura la red y prepara el entorno.</p></li><li><p><code>StopPodSandbox</code> &#8211; Detiene todos los procesos y libera los recursos de red.</p></li><li><p><code>RemovePodSandbox</code> &#8211; Limpia completamente el sandbox.</p></li></ul><p>Gesti&#243;n individual de cada contenedor dentro del PodSandbox:</p><ul><li><p><code>CreateContainer</code> &#8211; Prepara el contenedor con su configuraci&#243;n espec&#237;fica.</p></li><li><p><code>StartContainer</code> &#8211; Inicia la ejecuci&#243;n del proceso principal.</p></li><li><p><code>StopContainer</code> &#8211; Detiene el contenedor con un per&#237;odo de gracia.</p></li><li><p><code>RemoveContainer</code> &#8211; Elimina completamente el contenedor.</p></li></ul><p>Monitoreo continuo del estado y rendimiento:</p><ul><li><p><code>ContainerStatus</code> / <code>PodSandboxStatus</code> &#8211; Estado actual de los componentes.</p></li><li><p><code>ContainerStats</code> / <code>PodSandboxStats</code> &#8211; M&#233;tricas de CPU, memoria, I/O.</p></li><li><p><code>ListContainers</code> / <code>ListPodSandbox</code> &#8211; Inventario de componentes activos.</p></li></ul><p>Interacci&#243;n directa con contenedores en ejecuci&#243;n:</p><ul><li><p><code>ExecSync</code> - Ejecutar comandos s&#237;ncronos (<code>kubectl exec</code>)</p></li><li><p><code>Attach</code> - Conectarse a la salida est&#225;ndar del contenedor</p></li><li><p><code>PortForward</code> - Redirecci&#243;n de puertos para acceso externo</p></li></ul><p><code>containerd</code> permite el uso de plugins para extender su funcionalidad. Existen varios tipos: snapshotter, almacenamiento o interfaces gRPC.</p><p>Para habilitar la comunicaci&#243;n entre <code>kubelet</code> y containerd, es necesario utilizar el plugin <code>CRI</code>.</p><p>La configuraci&#243;n de containerd en <code>/etc/containerd/config.toml</code> muestra c&#243;mo est&#225; habilitado el plugin CRI y configurado para usar runc como runtime por defecto:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8SMk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8cc5330c-3fbd-4235-9a85-4fe2742533a4_937x673.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8SMk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8cc5330c-3fbd-4235-9a85-4fe2742533a4_937x673.png 424w, https://substackcdn.com/image/fetch/$s_!8SMk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8cc5330c-3fbd-4235-9a85-4fe2742533a4_937x673.png 848w, https://substackcdn.com/image/fetch/$s_!8SMk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8cc5330c-3fbd-4235-9a85-4fe2742533a4_937x673.png 1272w, https://substackcdn.com/image/fetch/$s_!8SMk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8cc5330c-3fbd-4235-9a85-4fe2742533a4_937x673.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8SMk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8cc5330c-3fbd-4235-9a85-4fe2742533a4_937x673.png" width="937" height="673" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8cc5330c-3fbd-4235-9a85-4fe2742533a4_937x673.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:673,&quot;width&quot;:937,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:200861,&quot;alt&quot;:&quot;Archivo configuraci&#243;n containerd en un Azure Kubernetes Cluster&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.javivela.dev/i/167831092?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8cc5330c-3fbd-4235-9a85-4fe2742533a4_937x673.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Archivo configuraci&#243;n containerd en un Azure Kubernetes Cluster" title="Archivo configuraci&#243;n containerd en un Azure Kubernetes Cluster" srcset="https://substackcdn.com/image/fetch/$s_!8SMk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8cc5330c-3fbd-4235-9a85-4fe2742533a4_937x673.png 424w, https://substackcdn.com/image/fetch/$s_!8SMk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8cc5330c-3fbd-4235-9a85-4fe2742533a4_937x673.png 848w, https://substackcdn.com/image/fetch/$s_!8SMk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8cc5330c-3fbd-4235-9a85-4fe2742533a4_937x673.png 1272w, https://substackcdn.com/image/fetch/$s_!8SMk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8cc5330c-3fbd-4235-9a85-4fe2742533a4_937x673.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Archivo configuraci&#243;n containerd en un Azure Kubernetes Cluster</figcaption></figure></div><h2>Pause container</h2><p>Un Pod puede contener uno o varios contenedores que comparten recursos, configuraci&#243;n y tienen la posibilidad de comunicarse entre s&#237;.</p><p>Para poder lograrlo, es necesario que se ejecuten en el mismo namespace y control group. Para ello, introducimos el componente <code>pause container</code>.</p><p><code>pause container</code> es un componente esencial en Kubernetes. Su funci&#243;n principal es mantener activo el <em>namespace</em> y el <em>control group</em> asociados a un Pod, incluso si los contenedores fallan o se reinician. De esta manera, varios contenedores comparten el mismo espacio de red y otros recursos.</p><p>Es extremadamente ligero (por ejemplo, la imagen <code>mcr.microsoft.com/oss/kubernetes/pause:3.6</code> ocupa solo 484 kB). Ejecuta un bucle infinito escrito en C y gestiona se&#241;ales como:</p><ul><li><p><strong>SIGINT/SIGTERM</strong>: se&#241;ales que indican al proceso que debe finalizar de forma ordenada. El <code>pause container</code> las gestiona para permitir una parada controlada del Pod.</p></li><li><p><strong>SIGCHLD</strong>: se&#241;al recibida cuando un proceso hijo termina. El <code>pause container</code> la maneja para limpiar correctamente los procesos hijos y evitar procesos zombis.</p></li></ul><p>Estas se&#241;ales permiten que el <code>pause container</code> act&#250;e como un proceso init dentro del Pod, gestionando el ciclo de vida de los contenedores y asegurando la correcta recolecci&#243;n de procesos hijos.</p><p>En resumen, el <code>pause container</code> act&#250;a como el proceso &#8220;padre&#8221; de todos los contenedores de un Pod, asegurando que los <em>namespaces</em> y <em>cgroups</em> permanezcan activos mientras el Pod exista. Si los procesos de los contenedores fallan o se reinician, el <code>pause container</code> mantiene el entorno aislado y listo para que los nuevos procesos se inicien en el mismo contexto.</p><h2>Ejemplo pr&#225;ctico</h2><p>En el siguiente ejemplo voy a mostrar c&#243;mo ver las diferentes jerarqu&#237;as de procesos, <em>cgroups</em> y <em>namespaces</em> que se crean cuando ejecutamos un pod en un cl&#250;ster de Kubernetes.</p><p>He desplegado un cl&#250;ster de Kubernetes en Azure. En el siguiente enlace puedes ver c&#243;mo crear uno: <a href="https://learn.microsoft.com/en-us/azure/aks/learn/quick-kubernetes-deploy-portal">https://learn.microsoft.com/en-us/azure/aks/learn/quick-kubernetes-deploy-portal</a>.</p><p>Desplegamos el siguiente Pod en el cl&#250;ster AKS: </p><pre><code>kubectl create ns develop


cat &lt;&lt;EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: web-with-logger
  namespace: develop
spec:
  containers:
  - name: web-server
    image: nginx:alpine
    ports:
    - containerPort: 80
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/nginx

  - name: log-reader
    image: busybox
    command: ["sh", "-c"]
    args:
    - |
      while true; do
        if [ -f /logs/access.log ]; then
          tail -n 5 /logs/access.log
        fi
        sleep 10
      done
    volumeMounts:
    - name: shared-logs
      mountPath: /logs
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"
  volumes:
  - name: shared-logs
    emptyDir: {}
EOF</code></pre><p>Para poder acceder a la shell del nodo del cl&#250;ster (s&#237;, con los permisos correctos puedes acceder a la shell del nodo), utilizo el plugin <a href="https://github.com/kvaps/kubectl-node-shell">kubectl node-shell</a>.</p><p>El comando <code>ps --forest -ef</code> nos proporciona una vista completa del &#225;rbol de procesos, mostrando c&#243;mo todos los componentes se relacionan jer&#225;rquicamente desde systemd hasta nuestros contenedores de aplicaci&#243;n:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!AQlr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05b0a544-9982-47c6-9b0e-b2a6c44c3827_1837x1443.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!AQlr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05b0a544-9982-47c6-9b0e-b2a6c44c3827_1837x1443.png 424w, https://substackcdn.com/image/fetch/$s_!AQlr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05b0a544-9982-47c6-9b0e-b2a6c44c3827_1837x1443.png 848w, https://substackcdn.com/image/fetch/$s_!AQlr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05b0a544-9982-47c6-9b0e-b2a6c44c3827_1837x1443.png 1272w, https://substackcdn.com/image/fetch/$s_!AQlr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05b0a544-9982-47c6-9b0e-b2a6c44c3827_1837x1443.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!AQlr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05b0a544-9982-47c6-9b0e-b2a6c44c3827_1837x1443.png" width="1456" height="1144" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/05b0a544-9982-47c6-9b0e-b2a6c44c3827_1837x1443.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1144,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:736608,&quot;alt&quot;:&quot;Resultado ejecuci&#243;n comando ps --forest -ef&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.javivela.dev/i/167831092?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05b0a544-9982-47c6-9b0e-b2a6c44c3827_1837x1443.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Resultado ejecuci&#243;n comando ps --forest -ef" title="Resultado ejecuci&#243;n comando ps --forest -ef" srcset="https://substackcdn.com/image/fetch/$s_!AQlr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05b0a544-9982-47c6-9b0e-b2a6c44c3827_1837x1443.png 424w, https://substackcdn.com/image/fetch/$s_!AQlr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05b0a544-9982-47c6-9b0e-b2a6c44c3827_1837x1443.png 848w, https://substackcdn.com/image/fetch/$s_!AQlr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05b0a544-9982-47c6-9b0e-b2a6c44c3827_1837x1443.png 1272w, https://substackcdn.com/image/fetch/$s_!AQlr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05b0a544-9982-47c6-9b0e-b2a6c44c3827_1837x1443.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Resultado ejecuci&#243;n comando ps --forest -ef</figcaption></figure></div><p>Podemos comprobar que el proceso padre de nuestro contenedor es el PID <code>14132</code> (este valor es del ejemplo y puede variar en cada entorno).</p><p>Ejecutando el comando <code>pstree -pa</code> se muestra la jerarqu&#237;a de procesos:</p><ul><li><p>systemd es el proceso ra&#237;z</p></li><li><p>containerd gestiona el runtime</p></li><li><p>containerd-shim-runc-v2 (un proceso por pod)</p></li><li><p>pause mantiene los namespaces del pod</p></li><li><p>web-server (nginx) / log-reader son los contenedores de aplicaci&#243;n</p></li></ul><p>Ejecutando el comando <code>pstree -pa -H 14132 -p 14132 --show-parents</code> podemos ver claramente la jerarqu&#237;a de procesos, donde systemd act&#250;a como proceso ra&#237;z, containerd gestiona el runtime, y containerd-shim-runc-v2 maneja cada pod individual:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yv0K!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F085416cd-170a-4ae9-9bb0-722f93756a3b_1544x518.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yv0K!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F085416cd-170a-4ae9-9bb0-722f93756a3b_1544x518.png 424w, https://substackcdn.com/image/fetch/$s_!yv0K!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F085416cd-170a-4ae9-9bb0-722f93756a3b_1544x518.png 848w, https://substackcdn.com/image/fetch/$s_!yv0K!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F085416cd-170a-4ae9-9bb0-722f93756a3b_1544x518.png 1272w, https://substackcdn.com/image/fetch/$s_!yv0K!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F085416cd-170a-4ae9-9bb0-722f93756a3b_1544x518.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yv0K!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F085416cd-170a-4ae9-9bb0-722f93756a3b_1544x518.png" width="1456" height="488" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/085416cd-170a-4ae9-9bb0-722f93756a3b_1544x518.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:488,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:130600,&quot;alt&quot;:&quot;Resultado ejecuci&#243;n comando pstree -pa -H 14132 -p 14132 --show-parents&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.javivela.dev/i/167831092?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F085416cd-170a-4ae9-9bb0-722f93756a3b_1544x518.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Resultado ejecuci&#243;n comando pstree -pa -H 14132 -p 14132 --show-parents" title="Resultado ejecuci&#243;n comando pstree -pa -H 14132 -p 14132 --show-parents" srcset="https://substackcdn.com/image/fetch/$s_!yv0K!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F085416cd-170a-4ae9-9bb0-722f93756a3b_1544x518.png 424w, https://substackcdn.com/image/fetch/$s_!yv0K!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F085416cd-170a-4ae9-9bb0-722f93756a3b_1544x518.png 848w, https://substackcdn.com/image/fetch/$s_!yv0K!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F085416cd-170a-4ae9-9bb0-722f93756a3b_1544x518.png 1272w, https://substackcdn.com/image/fetch/$s_!yv0K!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F085416cd-170a-4ae9-9bb0-722f93756a3b_1544x518.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Resultado ejecuci&#243;n comando pstree -pa -H 14132 -p 14132 --show-parents</figcaption></figure></div><p><code>crictl</code> es una aplicaci&#243;n de l&#237;nea de comandos que permite interactuar con la interfaz CRI (Container Runtime Interface). Podemos utilizarla para inspeccionar los contenedores, consultar informaci&#243;n o depurar un contenedor.</p><p>El comando <code>crictl pods</code> nos muestra todos los pods ejecut&#225;ndose en el nodo, incluyendo tanto nuestro pod <code>web-with-logger</code> en el namespace <code>develop</code> como los pods del sistema:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CI4O!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23ec5d1b-5245-4483-97ef-4e2aef0720f7_1724x495.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CI4O!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23ec5d1b-5245-4483-97ef-4e2aef0720f7_1724x495.png 424w, https://substackcdn.com/image/fetch/$s_!CI4O!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23ec5d1b-5245-4483-97ef-4e2aef0720f7_1724x495.png 848w, https://substackcdn.com/image/fetch/$s_!CI4O!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23ec5d1b-5245-4483-97ef-4e2aef0720f7_1724x495.png 1272w, https://substackcdn.com/image/fetch/$s_!CI4O!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23ec5d1b-5245-4483-97ef-4e2aef0720f7_1724x495.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CI4O!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23ec5d1b-5245-4483-97ef-4e2aef0720f7_1724x495.png" width="1456" height="418" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/23ec5d1b-5245-4483-97ef-4e2aef0720f7_1724x495.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:418,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:209638,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.javivela.dev/i/167831092?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23ec5d1b-5245-4483-97ef-4e2aef0720f7_1724x495.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!CI4O!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23ec5d1b-5245-4483-97ef-4e2aef0720f7_1724x495.png 424w, https://substackcdn.com/image/fetch/$s_!CI4O!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23ec5d1b-5245-4483-97ef-4e2aef0720f7_1724x495.png 848w, https://substackcdn.com/image/fetch/$s_!CI4O!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23ec5d1b-5245-4483-97ef-4e2aef0720f7_1724x495.png 1272w, https://substackcdn.com/image/fetch/$s_!CI4O!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23ec5d1b-5245-4483-97ef-4e2aef0720f7_1724x495.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>El comando <code>crictl ps --pod bb3b311a34072</code> podemos ver los contenedores nuestro Pod (no se muestra el pause container).</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kkSz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ebe6c66-ca20-404b-8016-59b409c82f16_1731x170.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kkSz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ebe6c66-ca20-404b-8016-59b409c82f16_1731x170.png 424w, https://substackcdn.com/image/fetch/$s_!kkSz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ebe6c66-ca20-404b-8016-59b409c82f16_1731x170.png 848w, https://substackcdn.com/image/fetch/$s_!kkSz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ebe6c66-ca20-404b-8016-59b409c82f16_1731x170.png 1272w, https://substackcdn.com/image/fetch/$s_!kkSz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ebe6c66-ca20-404b-8016-59b409c82f16_1731x170.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kkSz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ebe6c66-ca20-404b-8016-59b409c82f16_1731x170.png" width="1456" height="143" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4ebe6c66-ca20-404b-8016-59b409c82f16_1731x170.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:143,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:57381,&quot;alt&quot;:&quot;Resultado ejecuci&#243;n comando crictl pods&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.javivela.dev/i/167831092?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ebe6c66-ca20-404b-8016-59b409c82f16_1731x170.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Resultado ejecuci&#243;n comando crictl pods" title="Resultado ejecuci&#243;n comando crictl pods" srcset="https://substackcdn.com/image/fetch/$s_!kkSz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ebe6c66-ca20-404b-8016-59b409c82f16_1731x170.png 424w, https://substackcdn.com/image/fetch/$s_!kkSz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ebe6c66-ca20-404b-8016-59b409c82f16_1731x170.png 848w, https://substackcdn.com/image/fetch/$s_!kkSz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ebe6c66-ca20-404b-8016-59b409c82f16_1731x170.png 1272w, https://substackcdn.com/image/fetch/$s_!kkSz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ebe6c66-ca20-404b-8016-59b409c82f16_1731x170.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Resultado ejecuci&#243;n comando crictl pods</figcaption></figure></div><p>Tambi&#233;n nos permite obtener la configuraci&#243;n de todos los Pods que se est&#225;n ejecutando en un namespace de Kubernetes: <code>crictl inspectp --namespace develop</code>.</p><blockquote><p>El fichero contiene m&#225;s de 800 l&#237;neas, puedes ver el archivo completo en el siguiente gist: </p><p>https://gist.github.com/fjvela/5374b33184c4ecbd39259e2d45dcf09d#file-crictl-inspectp-json</p></blockquote><p>A continuaci&#243;n te muestro algunas de los datos m&#225;s importantes que puedes encontrar en el fichero:</p><p>Configuraci&#243;n de Red:</p><ul><li><p>IP del Pod: <code>10.244.0.153</code></p></li><li><p>Gateway: <code>169.254.1.1</code></p></li><li><p>DNS: Configurado para resolver servicios dentro del cl&#250;ster</p></li><li><p>Namespace de red: <code>/var/run/netns/cni-d47bdb8a-6641-6cd2-d33e-55eb78bc2407</code></p></li></ul><p>Jerarqu&#237;a de Control Groups:</p><ul><li><p>Ruta: <code>/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podf07700a5_b996_4b1a_a3af_5f99ecb29549.slice</code></p></li><li><p>L&#237;mite de memoria: 268 MB (256 Mi total del Pod)</p></li><li><p>L&#237;mite de CPU: 100000/100000 (1 CPU core m&#225;ximo)</p></li></ul><p>Configuraci&#243;n de Seguridad:</p><ul><li><p>Pol&#237;tica Seccomp: Activa con 100+ syscalls permitidas</p></li><li><p>Capabilities: Conjunto restringido (CAP_CHOWN, CAP_SETUID, etc.)</p></li><li><p>Namespaces aislados: PID, IPC, UTS, Mount, Network</p></li></ul><p>Otros datos importantes:</p><ul><li><p>Logs: <code>/var/log/pods/develop_web-with-logger_f07700a5-b996-4b1a-a3af-5f99ecb29549</code></p></li><li><p>Imagen pause: <code>mcr.microsoft.com/oss/kubernetes/pause:3.6</code></p></li></ul><p></p><p>Entre los datos que nos muestra el comando, podemos observar la propiedad <code>io.kubernetes.cri.sandbox-log-directory</code>. El valor de la propiedad especifica d&#243;nde se almacenan los logs. Al explorar este directorio, encontramos los logs individuales de cada contenedor:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kIWo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0f8ad66-5c10-4c31-acbd-2fa5bc278cc3_1371x699.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kIWo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0f8ad66-5c10-4c31-acbd-2fa5bc278cc3_1371x699.png 424w, https://substackcdn.com/image/fetch/$s_!kIWo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0f8ad66-5c10-4c31-acbd-2fa5bc278cc3_1371x699.png 848w, https://substackcdn.com/image/fetch/$s_!kIWo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0f8ad66-5c10-4c31-acbd-2fa5bc278cc3_1371x699.png 1272w, https://substackcdn.com/image/fetch/$s_!kIWo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0f8ad66-5c10-4c31-acbd-2fa5bc278cc3_1371x699.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kIWo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0f8ad66-5c10-4c31-acbd-2fa5bc278cc3_1371x699.png" width="1371" height="699" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c0f8ad66-5c10-4c31-acbd-2fa5bc278cc3_1371x699.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:699,&quot;width&quot;:1371,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:208849,&quot;alt&quot;:&quot;Contenido directorio logs&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.javivela.dev/i/167831092?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0f8ad66-5c10-4c31-acbd-2fa5bc278cc3_1371x699.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Contenido directorio logs" title="Contenido directorio logs" srcset="https://substackcdn.com/image/fetch/$s_!kIWo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0f8ad66-5c10-4c31-acbd-2fa5bc278cc3_1371x699.png 424w, https://substackcdn.com/image/fetch/$s_!kIWo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0f8ad66-5c10-4c31-acbd-2fa5bc278cc3_1371x699.png 848w, https://substackcdn.com/image/fetch/$s_!kIWo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0f8ad66-5c10-4c31-acbd-2fa5bc278cc3_1371x699.png 1272w, https://substackcdn.com/image/fetch/$s_!kIWo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0f8ad66-5c10-4c31-acbd-2fa5bc278cc3_1371x699.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Contenido directorio logs</figcaption></figure></div><p>La carpeta <code>/proc</code> contiene el sistema de archivos virtual que almacena informaci&#243;n de los procesos que se est&#225;n ejecutando.</p><p>En esta carpeta se encuentra la informaci&#243;n sobre los cgroups de nuestro proceso. El comando <code>cat /proc/14132/cgroup</code> muestra la ruta donde se almacena la configuraci&#243;n de cgroups:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!RcPs!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc8ec75d-07d9-4b29-9a59-a01ce5653542_1323x562.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!RcPs!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc8ec75d-07d9-4b29-9a59-a01ce5653542_1323x562.png 424w, https://substackcdn.com/image/fetch/$s_!RcPs!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc8ec75d-07d9-4b29-9a59-a01ce5653542_1323x562.png 848w, https://substackcdn.com/image/fetch/$s_!RcPs!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc8ec75d-07d9-4b29-9a59-a01ce5653542_1323x562.png 1272w, https://substackcdn.com/image/fetch/$s_!RcPs!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc8ec75d-07d9-4b29-9a59-a01ce5653542_1323x562.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!RcPs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc8ec75d-07d9-4b29-9a59-a01ce5653542_1323x562.png" width="1323" height="562" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dc8ec75d-07d9-4b29-9a59-a01ce5653542_1323x562.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:562,&quot;width&quot;:1323,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:83906,&quot;alt&quot;:&quot;Contenido directorio cgroup y cgroup.procs&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.javivela.dev/i/167831092?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc8ec75d-07d9-4b29-9a59-a01ce5653542_1323x562.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Contenido directorio cgroup y cgroup.procs" title="Contenido directorio cgroup y cgroup.procs" srcset="https://substackcdn.com/image/fetch/$s_!RcPs!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc8ec75d-07d9-4b29-9a59-a01ce5653542_1323x562.png 424w, https://substackcdn.com/image/fetch/$s_!RcPs!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc8ec75d-07d9-4b29-9a59-a01ce5653542_1323x562.png 848w, https://substackcdn.com/image/fetch/$s_!RcPs!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc8ec75d-07d9-4b29-9a59-a01ce5653542_1323x562.png 1272w, https://substackcdn.com/image/fetch/$s_!RcPs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc8ec75d-07d9-4b29-9a59-a01ce5653542_1323x562.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Contenido directorio cgroup y cgroup.procs</figcaption></figure></div><p>Podemos observar que todos los procesos iniciados por containerd est&#225;n dentro de la jerarqu&#237;a de cgroups de containerd.</p><p>A continuaci&#243;n, comprobamos si los l&#237;mites de memoria y CPU est&#225;n configurados en los ficheros de configuraci&#243;n de cgroups. Al examinar los archivos de configuraci&#243;n, podemos verificar que los l&#237;mites de memoria (134217728 bytes = 128Mi) y CPU (50000/100000 = 500m) est&#225;n correctamente aplicados:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7SWg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc003b1-fb12-46c9-a0c7-bef539ba0511_1724x260.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7SWg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc003b1-fb12-46c9-a0c7-bef539ba0511_1724x260.png 424w, https://substackcdn.com/image/fetch/$s_!7SWg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc003b1-fb12-46c9-a0c7-bef539ba0511_1724x260.png 848w, https://substackcdn.com/image/fetch/$s_!7SWg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc003b1-fb12-46c9-a0c7-bef539ba0511_1724x260.png 1272w, https://substackcdn.com/image/fetch/$s_!7SWg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc003b1-fb12-46c9-a0c7-bef539ba0511_1724x260.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7SWg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc003b1-fb12-46c9-a0c7-bef539ba0511_1724x260.png" width="1456" height="220" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dbc003b1-fb12-46c9-a0c7-bef539ba0511_1724x260.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:220,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:100401,&quot;alt&quot;:&quot;Configuraci&#243;n limites memoria y CPU del contenedor&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.javivela.dev/i/167831092?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc003b1-fb12-46c9-a0c7-bef539ba0511_1724x260.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Configuraci&#243;n limites memoria y CPU del contenedor" title="Configuraci&#243;n limites memoria y CPU del contenedor" srcset="https://substackcdn.com/image/fetch/$s_!7SWg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc003b1-fb12-46c9-a0c7-bef539ba0511_1724x260.png 424w, https://substackcdn.com/image/fetch/$s_!7SWg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc003b1-fb12-46c9-a0c7-bef539ba0511_1724x260.png 848w, https://substackcdn.com/image/fetch/$s_!7SWg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc003b1-fb12-46c9-a0c7-bef539ba0511_1724x260.png 1272w, https://substackcdn.com/image/fetch/$s_!7SWg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc003b1-fb12-46c9-a0c7-bef539ba0511_1724x260.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Configuraci&#243;n limites memoria y CPU del contenedor</figcaption></figure></div><p>El comando <code>systemd-cgls</code> nos ayuda a visualizar la jerarqu&#237;a de cgroups de forma gr&#225;fica y sencilla. Permite ver c&#243;mo est&#225;n organizados los procesos y recursos dentro de los diferentes grupos de control, facilitando la identificaci&#243;n de los procesos hijos y su relaci&#243;n con los recursos asignados.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oD90!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7827b2c6-8ce9-42c6-8dfa-4652f37ff38e_1724x549.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oD90!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7827b2c6-8ce9-42c6-8dfa-4652f37ff38e_1724x549.png 424w, https://substackcdn.com/image/fetch/$s_!oD90!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7827b2c6-8ce9-42c6-8dfa-4652f37ff38e_1724x549.png 848w, https://substackcdn.com/image/fetch/$s_!oD90!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7827b2c6-8ce9-42c6-8dfa-4652f37ff38e_1724x549.png 1272w, https://substackcdn.com/image/fetch/$s_!oD90!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7827b2c6-8ce9-42c6-8dfa-4652f37ff38e_1724x549.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oD90!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7827b2c6-8ce9-42c6-8dfa-4652f37ff38e_1724x549.png" width="1456" height="464" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7827b2c6-8ce9-42c6-8dfa-4652f37ff38e_1724x549.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:464,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:265702,&quot;alt&quot;:&quot;Resultado ejecuci&#243;n comando systemd-cgls directorio cgroups containerd&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.javivela.dev/i/167831092?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7827b2c6-8ce9-42c6-8dfa-4652f37ff38e_1724x549.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Resultado ejecuci&#243;n comando systemd-cgls directorio cgroups containerd" title="Resultado ejecuci&#243;n comando systemd-cgls directorio cgroups containerd" srcset="https://substackcdn.com/image/fetch/$s_!oD90!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7827b2c6-8ce9-42c6-8dfa-4652f37ff38e_1724x549.png 424w, https://substackcdn.com/image/fetch/$s_!oD90!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7827b2c6-8ce9-42c6-8dfa-4652f37ff38e_1724x549.png 848w, https://substackcdn.com/image/fetch/$s_!oD90!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7827b2c6-8ce9-42c6-8dfa-4652f37ff38e_1724x549.png 1272w, https://substackcdn.com/image/fetch/$s_!oD90!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7827b2c6-8ce9-42c6-8dfa-4652f37ff38e_1724x549.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Resultado ejecuci&#243;n comando systemd-cgls directorio cgroups containerd</figcaption></figure></div><p>Por &#250;ltimo, y no menos importante, comprobamos la configuraci&#243;n de los namespaces. Recordemos que su objetivo es aislar y compartir los recursos del sistema.</p><p>El siguiente script muestra los namespaces configurados para cada uno de los procesos que componen el Pod <code>web-with-logger (pid 14132)</code>:</p><pre><code><code>SHIM_PID=14132
for pid in $(ps --ppid $SHIM_PID --no-headers -o pid); do
    echo "PID $pid namespaces:"
    ls -la /proc/$pid/ns/ | grep -E "(net|pid|uts|ipc)" | awk '{print "  " $9 ": " $11}'
    echo ""
done</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2-P8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24e97590-43ce-40fd-aab1-ce32737135fb_889x652.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2-P8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24e97590-43ce-40fd-aab1-ce32737135fb_889x652.png 424w, https://substackcdn.com/image/fetch/$s_!2-P8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24e97590-43ce-40fd-aab1-ce32737135fb_889x652.png 848w, https://substackcdn.com/image/fetch/$s_!2-P8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24e97590-43ce-40fd-aab1-ce32737135fb_889x652.png 1272w, https://substackcdn.com/image/fetch/$s_!2-P8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24e97590-43ce-40fd-aab1-ce32737135fb_889x652.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2-P8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24e97590-43ce-40fd-aab1-ce32737135fb_889x652.png" width="889" height="652" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/24e97590-43ce-40fd-aab1-ce32737135fb_889x652.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:652,&quot;width&quot;:889,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:119511,&quot;alt&quot;:&quot;Resultado ejecuci&#243;n script namespaces utilizados&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.javivela.dev/i/167831092?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24e97590-43ce-40fd-aab1-ce32737135fb_889x652.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Resultado ejecuci&#243;n script namespaces utilizados" title="Resultado ejecuci&#243;n script namespaces utilizados" srcset="https://substackcdn.com/image/fetch/$s_!2-P8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24e97590-43ce-40fd-aab1-ce32737135fb_889x652.png 424w, https://substackcdn.com/image/fetch/$s_!2-P8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24e97590-43ce-40fd-aab1-ce32737135fb_889x652.png 848w, https://substackcdn.com/image/fetch/$s_!2-P8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24e97590-43ce-40fd-aab1-ce32737135fb_889x652.png 1272w, https://substackcdn.com/image/fetch/$s_!2-P8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24e97590-43ce-40fd-aab1-ce32737135fb_889x652.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Resultado ejecuci&#243;n script namespaces utilizados</figcaption></figure></div><p>Podemos comprobar que los tres contenedores comparten los siguientes namespaces:</p><ul><li><p><strong>ipc</strong>: Permite que los contenedores compartan mecanismos de comunicaci&#243;n entre procesos (IPC), como sem&#225;foros y colas de mensajes.</p></li><li><p><strong>net</strong>: Todos los contenedores del Pod comparten la misma pila de red, interfaces y direcci&#243;n IP, lo que posibilita la comunicaci&#243;n interna mediante <code>localhost</code>.</p></li><li><p><strong>uts</strong>: Compartir este namespace permite que todos los contenedores tengan el mismo hostname y nombre de dominio, facilitando la identificaci&#243;n dentro del Pod.</p></li></ul><p>Gracias al uso de namespaces compartidos, los contenedores de un mismo Pod pueden comunicarse y compartir recursos de manera eficiente y segura.</p><p>Comprobamos la configuraci&#243;n de red de cada uno de los procesos:</p><pre><code><code>SHIM_PID=14132
for pid in $(ps --ppid $SHIM_PID --no-headers -o pid); do
    echo "Network interfaces from PID $pid:"
    nsenter -t $pid -n ip addr show eth0 | grep inet
    echo ""
done</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!A5BQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2be8cfac-8022-4cf4-aa10-3ea410407d0c_687x459.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!A5BQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2be8cfac-8022-4cf4-aa10-3ea410407d0c_687x459.png 424w, https://substackcdn.com/image/fetch/$s_!A5BQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2be8cfac-8022-4cf4-aa10-3ea410407d0c_687x459.png 848w, https://substackcdn.com/image/fetch/$s_!A5BQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2be8cfac-8022-4cf4-aa10-3ea410407d0c_687x459.png 1272w, https://substackcdn.com/image/fetch/$s_!A5BQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2be8cfac-8022-4cf4-aa10-3ea410407d0c_687x459.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!A5BQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2be8cfac-8022-4cf4-aa10-3ea410407d0c_687x459.png" width="687" height="459" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2be8cfac-8022-4cf4-aa10-3ea410407d0c_687x459.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:459,&quot;width&quot;:687,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:96368,&quot;alt&quot;:&quot;Resultado ejecuci&#243;n script interfaz red eth0&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.javivela.dev/i/167831092?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2be8cfac-8022-4cf4-aa10-3ea410407d0c_687x459.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Resultado ejecuci&#243;n script interfaz red eth0" title="Resultado ejecuci&#243;n script interfaz red eth0" srcset="https://substackcdn.com/image/fetch/$s_!A5BQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2be8cfac-8022-4cf4-aa10-3ea410407d0c_687x459.png 424w, https://substackcdn.com/image/fetch/$s_!A5BQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2be8cfac-8022-4cf4-aa10-3ea410407d0c_687x459.png 848w, https://substackcdn.com/image/fetch/$s_!A5BQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2be8cfac-8022-4cf4-aa10-3ea410407d0c_687x459.png 1272w, https://substackcdn.com/image/fetch/$s_!A5BQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2be8cfac-8022-4cf4-aa10-3ea410407d0c_687x459.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Resultado ejecuci&#243;n script interfaz red eth0</figcaption></figure></div><p>Los tres contenedores utilizan la misma IP, lo que permite la comunicaci&#243;n entre ellos a trav&#233;s de <code>localhost</code>.</p><p>Comprobamos que los tres contenedores usan el mismo hostname:</p><pre><code><code>SHIM_PID=14132
for pid in $(ps --ppid $SHIM_PID --no-headers -o pid); do
    hostname=$(nsenter -t $pid -u hostname)
    echo "PID $pid hostname: $hostname"
done</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Q-26!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42704c26-83d8-42fa-bcb9-04ee570f338d_703x245.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Q-26!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42704c26-83d8-42fa-bcb9-04ee570f338d_703x245.png 424w, https://substackcdn.com/image/fetch/$s_!Q-26!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42704c26-83d8-42fa-bcb9-04ee570f338d_703x245.png 848w, https://substackcdn.com/image/fetch/$s_!Q-26!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42704c26-83d8-42fa-bcb9-04ee570f338d_703x245.png 1272w, https://substackcdn.com/image/fetch/$s_!Q-26!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42704c26-83d8-42fa-bcb9-04ee570f338d_703x245.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Q-26!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42704c26-83d8-42fa-bcb9-04ee570f338d_703x245.png" width="703" height="245" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/42704c26-83d8-42fa-bcb9-04ee570f338d_703x245.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:245,&quot;width&quot;:703,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:54966,&quot;alt&quot;:&quot;Resultado ejecuci&#243;n script hostname&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.javivela.dev/i/167831092?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42704c26-83d8-42fa-bcb9-04ee570f338d_703x245.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Resultado ejecuci&#243;n script hostname" title="Resultado ejecuci&#243;n script hostname" srcset="https://substackcdn.com/image/fetch/$s_!Q-26!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42704c26-83d8-42fa-bcb9-04ee570f338d_703x245.png 424w, https://substackcdn.com/image/fetch/$s_!Q-26!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42704c26-83d8-42fa-bcb9-04ee570f338d_703x245.png 848w, https://substackcdn.com/image/fetch/$s_!Q-26!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42704c26-83d8-42fa-bcb9-04ee570f338d_703x245.png 1272w, https://substackcdn.com/image/fetch/$s_!Q-26!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42704c26-83d8-42fa-bcb9-04ee570f338d_703x245.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Resultado ejecuci&#243;n script hostname</figcaption></figure></div><h2>Conclusi&#243;n</h2><p><em>&#8220;Any sufficiently advanced technology is indistinguishable from magic&#8221;</em> - Arthur C. Clarke</p><p>Parece trivial ejecutar un contenedor o un Pod en Kubernetes, pero la realidad es mucho m&#225;s compleja.</p><p>El comando para ejecutar un contenedor lanza una coreograf&#237;a perfecta de acciones en un ecosistema de herramientas y abstracciones que hemos explorado en detalle:</p><ul><li><p><strong>Primitivas del kernel</strong>: namespaces y cgroups</p></li><li><p><strong>Runtimes de contenedores</strong>: runc y containerd</p></li><li><p><strong>Interfaces est&#225;ndar</strong>: CRI y OCI</p></li><li><p><strong>Orquestaci&#243;n de contenedores</strong>: Kubernetes</p></li></ul><p>Este sistema nos permite obtener portabilidad, escalabilidad y tolerancia a fallos, entre otras ventajas. Cada capa resuelve problemas reales y aporta valor a la soluci&#243;n final.</p><p>Sin embargo, cuando algo no funciona correctamente, esta misma complejidad puede convertir un problema simple en una pesadilla que requiere conocimiento profundo para poder resolverla.</p><p>Ahora sabes qu&#233; sucede realmente cuando Kubernetes hace su &#8220;magia&#8221;. Ese conocimiento es poder.</p><div><hr></div><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/kubernetes-desde-el-kernel-hasta-la-orquestacion?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">&#161;Te <strong>AGRADEZCO</strong> enormemente que hayas dedicado tu valioso tiempo a leer lo que escribo! Si te ha gustado y crees que puede ayudar a otras personas, <strong>puedes compartirlo</strong>.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/kubernetes-desde-el-kernel-hasta-la-orquestacion?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.javivela.dev/p/kubernetes-desde-el-kernel-hasta-la-orquestacion?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Compartir</span></a></p></div><div><hr></div><h2>Referencias</h2><ul><li><p><a href="https://github.com/containerd/containerd/blob/main/docs/cri/architecture.md">https://github.com/containerd/containerd/blob/main/docs/cri/architecture.md</a></p></li><li><p><a href="https://github.com/containerd/containerd/blob/main/docs/cri/config.md">https://github.com/containerd/containerd/blob/main/docs/cri/config.md</a></p></li><li><p><a href="https://github.com/kubernetes/cri-api/blob/master/pkg/apis/runtime/v1/api.proto">https://github.com/kubernetes/cri-api/blob/master/pkg/apis/runtime/v1/api.proto</a></p></li><li><p><a href="https://github.com/kubernetes/cri-api/blob/master/pkg/apis/services.go">https://github.com/kubernetes/cri-api/blob/master/pkg/apis/services.go</a></p></li><li><p><a href="https://github.com/kubernetes/kubernetes/blob/master/build/pause/linux/pause.c">https://github.com/kubernetes/kubernetes/blob/master/build/pause/linux/pause.c</a></p></li><li><p><a href="https://kubernetes.io/blog/2024/05/01/cri-streaming-explained/">https://kubernetes.io/blog/2024/05/01/cri-streaming-explained/</a></p></li><li><p><a href="https://kubernetes.io/docs/concepts/architecture/">https://kubernetes.io/docs/concepts/architecture/</a></p></li><li><p><a href="https://kubernetes.io/docs/concepts/overview/components/">https://kubernetes.io/docs/concepts/overview/components/</a></p></li><li><p><a href="https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/">https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/</a></p></li><li><p><a href="https://kubernetes.io/docs/tasks/debug/debug-cluster/crictl/">https://kubernetes.io/docs/tasks/debug/debug-cluster/crictl/</a></p></li></ul>]]></content:encoded></item><item><title><![CDATA[Contenedores: Desde el kernel hasta la orquestación - runc y containerd.]]></title><description><![CDATA[Continuamos con la segunda parte de &#8220;Desde el kernel hasta la orquestaci&#243;n&#8221;, en este art&#237;culo vamos a hablar sobre runc y containerd.]]></description><link>https://www.javivela.dev/p/runc-y-containerd-desde-el-kernel-hasta-la-orquestacion</link><guid isPermaLink="false">https://www.javivela.dev/p/runc-y-containerd-desde-el-kernel-hasta-la-orquestacion</guid><dc:creator><![CDATA[Javi Vela]]></dc:creator><pubDate>Tue, 08 Jul 2025 09:11:21 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!WRFo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495f76ac-7935-4239-9a77-22f242eef397_1329x1399.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introducci&#243;n</h2><p>Continuamos con la segunda parte de &#8220;Desde el kernel hasta la orquestaci&#243;n&#8221;, en este art&#237;culo vamos a hablar sobre <code>runc</code> y <code>containerd</code>.</p><p>En el post <a href="https://blog.javivela.dev/p/namespaces-y-control-groups-desde-el-kernel-hasta-la-orquestacion">Contenedores: Desde el kernel hasta la orquestaci&#243;n - namespaces y control groups (cgroups)</a> vimos los pilares fundamentales sobre los que se ejecutan los contenedores: <a href="https://blog.javivela.dev/p/namespaces-y-control-groups-desde-el-kernel-hasta-la-orquestacion#&#167;namespaces-linux">namespaces</a> y <a href="https://blog.javivela.dev/p/namespaces-y-control-groups-desde-el-kernel-hasta-la-orquestacion#&#167;cgroups-control-groups">cgroups</a> del kernel de Linux.</p><p>Estas funcionalidades del sistema operativo permiten el aislamiento de procesos y el control de los recursos utilizados; trabajar con estas tecnolog&#237;as requiere un conocimiento del kernel y de los comandos de bajo nivel.</p><p><code>runc</code> y <code>containerd</code> son dos herramientas que act&#250;an como interfaces entre las herramientas de alto nivel y los comandos de bajo nivel, simplificando enormemente el trabajo con contenedores.</p><p>Al comienzo, <code>Docker</code> integraba toda la funcionalidad en una aplicaci&#243;n monol&#237;tica: gesti&#243;n de im&#225;genes, networking, almacenamiento, ejecuci&#243;n de contenedores&#8230; Esta arquitectura presentaba grandes problemas de dependencia, evoluci&#243;n y control por una &#250;nica empresa.</p><p>En 2015 naci&#243; la <a href="https://opencontainers.org/">Open Container Initiative (OCI)</a>, su objetivo principal es crear un est&#225;ndar para el manejo y ejecuci&#243;n de contenedores que hasta el momento estaba dominado por Docker. De esta manera se garantizaba la interoperabilidad entre los diferentes proveedores y permiti&#243; crear est&#225;ndares abiertos para los runtimes de contenedores y el formato de las im&#225;genes, permitiendo as&#237; una arquitectura modular y flexible.</p><p>Las especificaciones m&#225;s importantes son las siguientes:</p><ul><li><p><a href="https://github.com/opencontainers/distribution-spec">Distribution Spec (c&#243;mo distribuir las im&#225;genes)</a>: Define la API REST est&#225;ndar para la distribuci&#243;n y almacenamiento de im&#225;genes de contenedor, incluyendo operaciones como el env&#237;o (push) y la descarga (pull) de im&#225;genes. Esto asegura la interoperabilidad entre diferentes herramientas y registros de im&#225;genes compatibles con OCI.</p></li><li><p><a href="https://github.com/opencontainers/image-spec">Image Spec (formato de las im&#225;genes)</a>: Define el formato de la estructura, almacenamiento y referencia de una imagen, garantizando que la imagen creada pueda ser ejecutada por cualquier runtime que cumpla est&#225;ndar OCI.</p></li><li><p><a href="https://github.com/opencontainers/runtime-spec">Runtime Spec (c&#243;mo ejecutar las im&#225;genes)</a>: Define la interfaz entre el runtime de bajo nivel y las herramientas de alto nivel, de esta manera podemos intercambiar el uso de herramientas como containerd o CRI-O sin realizar ninguna modificaci&#243;n.</p></li></ul><p><code>runc</code> y <code>containerd</code> hacen que trabajar con contenedores sea m&#225;s sencillo, tambi&#233;n son la clave para sistemas de orquestaci&#243;n de contenedores como Kubernetes, que pueden utilizar interfaces est&#225;ndar sin la necesidad de saber los detalles de la implementaci&#243;n del sistema operativo y de las herramientas utilizadas.</p><p>Ambas herramientas eran parte de Docker, fueron extra&#237;das y donadas a la <a href="https://www.cncf.io/">CNCF (Cloud Native Computing Foundation)</a>.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/subscribe?&quot;,&quot;text&quot;:&quot;Suscribirse&quot;,&quot;language&quot;:&quot;es&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">&#161;<strong>GRACIAS</strong> por dedicar unos minutos tan valiosos a leer los art&#237;culos que escribo! Suscr&#237;bete para no perderte ninguna novedad y tener toda la informaci&#243;n directamente en tu email.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Escribe tu correo electr&#243;nico..." tabindex="-1"><input type="submit" class="button primary" value="Suscribirse"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>runc</h2><p>Es una herramienta de l&#237;nea de comandos escrita en Go que solo puede ejecutarse en Linux. Permite ejecutar aplicaciones contenerizadas siguiendo el est&#225;ndar definido por la <a href="https://opencontainers.org/">Open Container Initiative (OCI)</a>.</p><p>Aunque proporciona un mayor nivel de abstracci&#243;n respecto a los comandos del kernel, sigue siendo una utilidad de bajo nivel y normalmente es utilizada por herramientas de m&#225;s alto nivel.</p><p>El est&#225;ndar definido para la ejecuci&#243;n de contenedores se basa en el concepto de <code>bundle</code>, que consiste en un directorio que contiene un archivo <code>config.json</code> y un directorio <code>rootfs (root filesystem)</code> con el sistema de archivos del contenedor.</p><p>El archivo <code>config.json</code> define c&#243;mo debe ejecutarse el contenedor. Algunos par&#225;metros que proporciona son los siguientes:</p><ul><li><p><strong>process</strong>: Define qu&#233; comando ejecutar, el usuario, las variables de entorno y las capacidades.</p></li><li><p><strong>root</strong>: Especifica la ruta al sistema de archivos ra&#237;z.</p></li><li><p><strong>mounts</strong>: Lista los puntos de montaje necesarios.</p></li><li><p><strong>linux.namespaces</strong>: Configura el aislamiento mediante namespaces.</p></li><li><p><strong>linux.resources</strong>: Establece l&#237;mites de recursos.</p></li></ul><p>Esta estructura JSON permite que herramientas de alto nivel generen configuraciones complejas.</p><pre><code><code>{
  "ociVersion": "1.2.1",
  "process": {
    "terminal": true,
    "user": {
      "uid": 0,
      "gid": 0
    },
    "args": ["sh"],
    "env": [
      "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
      "TERM=xterm"
    ],
    "cwd": "/",
    "capabilities": {
      "bounding": ["CAP_AUDIT_WRITE", "CAP_KILL", "CAP_NET_BIND_SERVICE"],
      "effective": ["CAP_AUDIT_WRITE", "CAP_KILL", "CAP_NET_BIND_SERVICE"],
      "permitted": ["CAP_AUDIT_WRITE", "CAP_KILL", "CAP_NET_BIND_SERVICE"]
    },
    "rlimits": [
      {
        "type": "RLIMIT_NOFILE",
        "hard": 1024,
        "soft": 1024
      }
    ],
    "noNewPrivileges": true
  },
  "root": {
    "path": "rootfs",
    "readonly": true
  },
  "hostname": "runc",
  "mounts": [
    {
      "destination": "/proc",
      "type": "proc",
      "source": "proc"
    },
    {
      "destination": "/dev",
      "type": "tmpfs",
      "source": "tmpfs",
      "options": ["nosuid", "strictatime", "mode=755", "size=65536k"]
    },
    {
      "destination": "/dev/pts",
      "type": "devpts",
      "source": "devpts",
      "options": [
        "nosuid",
        "noexec",
        "newinstance",
        "ptmxmode=0666",
        "mode=0620",
        "gid=5"
      ]
    },
    {
      "destination": "/dev/shm",
      "type": "tmpfs",
      "source": "shm",
      "options": ["nosuid", "noexec", "nodev", "mode=1777", "size=65536k"]
    },
    {
      "destination": "/dev/mqueue",
      "type": "mqueue",
      "source": "mqueue",
      "options": ["nosuid", "noexec", "nodev"]
    },
    {
      "destination": "/sys",
      "type": "sysfs",
      "source": "sysfs",
      "options": ["nosuid", "noexec", "nodev", "ro"]
    },
    {
      "destination": "/sys/fs/cgroup",
      "type": "cgroup",
      "source": "cgroup",
      "options": ["nosuid", "noexec", "nodev", "relatime", "ro"]
    }
  ],
  "linux": {
    "resources": {
      "devices": [
        {
          "allow": false,
          "access": "rwm"
        }
      ]
    },
    "namespaces": [
      {
        "type": "pid"
      },
      {
        "type": "network"
      },
      {
        "type": "ipc"
      },
      {
        "type": "uts"
      },
      {
        "type": "mount"
      },
      {
        "type": "cgroup"
      }
    ],
    "maskedPaths": [
      "/proc/acpi",
      "/proc/asound",
      "/proc/kcore",
      "/proc/keys",
      "/proc/latency_stats",
      "/proc/timer_list",
      "/proc/timer_stats",
      "/proc/sched_debug",
      "/sys/firmware",
      "/proc/scsi"
    ],
    "readonlyPaths": [
      "/proc/bus",
      "/proc/fs",
      "/proc/irq",
      "/proc/sys",
      "/proc/sysrq-trigger"
    ]
  }
}
</code></code></pre><p>Algunos de los comandos que define el est&#225;ndar <a href="https://opencontainers.org/">OCI</a> y que <code>runc</code> implementa son:</p><ul><li><p><code>events</code>: muestra eventos del contenedor como notificaciones OOM, estad&#237;sticas de uso de CPU, memoria e IO.</p></li><li><p><code>create</code>: ejecuta el proceso definido por el usuario en un contenedor creado.</p></li><li><p><code>delete</code>: elimina los recursos asociados al contenedor, utilizado frecuentemente con contenedores en modo desacoplado.</p></li><li><p><code>kill</code>: env&#237;a la se&#241;al especificada (por defecto: SIGTERM) al proceso principal del contenedor.</p></li><li><p><code>start</code>: inicia el proceso principal.</p></li><li><p><code>state</code>: obtiene el estado actual de un contenedor.</p></li></ul><p><code>rootfs (root filesystem)</code> es el sistema de archivos ra&#237;z del contenedor. Contiene todos los archivos, librer&#237;as y herramientas para que el contenedor pueda ejecutarse.</p><p>Una estructura t&#237;pica del sistema de archivos ser&#237;a:</p><pre><code><code>rootfs/
&#9500;&#9472;&#9472; bin/           &#9;# Binarios esenciales (sh, ls, cat, etc.)
&#9500;&#9472;&#9472; boot/          &#9;# Archivos de arranque (generalmente vac&#237;o)
&#9500;&#9472;&#9472; dev/           &#9;# Dispositivos (se monta din&#225;micamente)
&#9500;&#9472;&#9472; etc/           &#9;# Configuraciones del sistema
&#9474;   &#9500;&#9472;&#9472; passwd     &#9;# Usuarios del contenedor
&#9474;   &#9500;&#9472;&#9472; group      &#9;# Grupos del contenedor
&#9474;   &#9500;&#9472;&#9472; hosts      &#9;# Resoluci&#243;n local de nombres
&#9474;   &#9492;&#9472;&#9472; resolv.conf # Configuraci&#243;n DNS
&#9500;&#9472;&#9472; home/          &#9;# Directorios de usuarios
&#9500;&#9472;&#9472; lib/           &#9;# Bibliotecas compartidas esenciales
&#9500;&#9472;&#9472; lib64/         &#9;# Bibliotecas de 64 bits
&#9500;&#9472;&#9472; media/         &#9;# Puntos de montaje para medios removibles
&#9500;&#9472;&#9472; mnt/           &#9;# Puntos de montaje temporales
&#9500;&#9472;&#9472; opt/           &#9;# Paquetes de software opcionales
&#9500;&#9472;&#9472; proc/          &#9;# Sistema de archivos virtual (se monta din&#225;micamente)
&#9500;&#9472;&#9472; root/          &#9;# Directorio home del usuario root
&#9500;&#9472;&#9472; run/           &#9;# Datos de runtime
&#9500;&#9472;&#9472; sbin/          &#9;# Binarios del sistema
&#9500;&#9472;&#9472; srv/           &#9;# Datos de servicios
&#9500;&#9472;&#9472; sys/           &#9;# Sistema de archivos virtual (se monta din&#225;micamente)
&#9500;&#9472;&#9472; tmp/           &#9;# Archivos temporales
&#9500;&#9472;&#9472; usr/           &#9;# Programas y datos de usuario
&#9474;   &#9500;&#9472;&#9472; bin/       &#9;# Binarios de usuario
&#9474;   &#9500;&#9472;&#9472; lib/       &#9;# Bibliotecas
&#9474;   &#9500;&#9472;&#9472; local/     &#9;# Software local
&#9474;   &#9492;&#9472;&#9472; share/     &#9;# Datos compartidos
&#9492;&#9472;&#9472; var/           &#9;# Datos variables
    &#9500;&#9472;&#9472; log/      &#9;# Logs del sistema
    &#9500;&#9472;&#9472; cache/    &#9;# Cache de aplicaciones
    &#9492;&#9472;&#9472; tmp/      &#9;# Archivos temporales adicionales
</code></code></pre><p>Sistema de archivos de la imagen Alpine:</p><pre><code><code>rootfs/
&#9500;&#9472;&#9472; bin -&gt; /usr/bin
&#9500;&#9472;&#9472; etc/
&#9474;   &#9500;&#9472;&#9472; alpine-release
&#9474;   &#9500;&#9472;&#9472; passwd
&#9474;   &#9492;&#9472;&#9472; group
&#9500;&#9472;&#9472; lib -&gt; /usr/lib
&#9500;&#9472;&#9472; sbin -&gt; /usr/sbin
&#9500;&#9472;&#9472; usr/
&#9474;   &#9500;&#9472;&#9472; bin/
&#9474;   &#9474;   &#9500;&#9472;&#9472; sh -&gt; /bin/busybox
&#9474;   &#9474;   &#9500;&#9472;&#9472; ls -&gt; /bin/busybox
&#9474;   &#9474;   &#9492;&#9472;&#9472; cat -&gt; /bin/busybox
&#9474;   &#9492;&#9472;&#9472; lib/
&#9474;       &#9492;&#9472;&#9472; libc.musl-x86_64.so.1
&#9492;&#9472;&#9472; var/</code></code></pre><p>Sistema de archivos de la imagen Ubuntu:</p><pre><code><code>rootfs/
&#9500;&#9472;&#9472; bin/
&#9474;   &#9500;&#9472;&#9472; bash
&#9474;   &#9500;&#9472;&#9472; sh -&gt; dash
&#9474;   &#9492;&#9472;&#9472; ls
&#9500;&#9472;&#9472; usr/
&#9474;   &#9500;&#9472;&#9472; bin/
&#9474;   &#9474;   &#9500;&#9472;&#9472; python3
&#9474;   &#9474;   &#9492;&#9472;&#9472; apt
&#9474;   &#9492;&#9472;&#9472; lib/
&#9474;       &#9492;&#9472;&#9472; x86_64-linux-gnu/
&#9492;&#9472;&#9472; lib/
    &#9492;&#9472;&#9472; x86_64-linux-gnu/
        &#9500;&#9472;&#9472; libc.so.6
        &#9492;&#9472;&#9472; libdl.so.2</code></code></pre><h2>containerd</h2><p>Es un servicio que gestiona el ciclo de vida de los contenedores, implementando los est&#225;ndares definidos por la <a href="https://opencontainers.org/">OCI</a>.</p><p>Act&#250;a como la capa de abstracci&#243;n entre los orquestadores de contenedores, como Kubernetes, y los runtimes de bajo nivel, como <code>runc</code>.</p><p>Las funcionalidades principales de <code>containerd</code> son:</p><ul><li><p><strong>Image service</strong>: Gestiona la descarga, almacenamiento y distribuci&#243;n de im&#225;genes.</p><ul><li><p>Pull/Push: Descarga y subida de im&#225;genes desde/hacia registries</p></li><li><p>Gesti&#243;n de capas: Manejo eficiente de layers con deduplicaci&#243;n</p></li><li><p>Verificaci&#243;n de la integridad de las capas.</p></li><li><p>Recolecci&#243;n de basura (garbage collection).</p></li></ul></li><li><p><strong>Runtime service</strong>: Gestiona la ejecuci&#243;n de contenedores.</p></li><li><p><strong>Snapshot service</strong>: Gestiona los sistemas de archivos (filesystem) de los contenedores.</p></li></ul><p>Podemos interactuar con el servicio utilizando diferentes herramientas:</p><ul><li><p><code>ctr</code>: Cliente oficial de bajo nivel para containerd. Permite gestionar im&#225;genes, snapshots y contenedores, principalmente para tareas administrativas y de depuraci&#243;n.</p></li><li><p><code>nerdctl</code>: Interfaz de l&#237;nea de comandos compatible con Docker, dise&#241;ada para usuarios que buscan una experiencia similar a Docker pero utilizando containerd como backend.</p></li><li><p><code>crictl</code>: Herramienta de l&#237;nea de comandos para interactuar con runtimes compatibles con el est&#225;ndar CRI (Container Runtime Interface), utilizada principalmente en entornos Kubernetes para inspeccionar y gestionar contenedores.</p></li></ul><p>La configuraci&#243;n del servicio <code>containerd</code> se realiza a trav&#233;s del archivo <code>/etc/containerd/config.toml</code>. Este archivo permite ajustar par&#225;metros clave del servicio, como rutas de almacenamiento, plugins habilitados, configuraci&#243;n de red (CNI), integraci&#243;n con runtimes como <code>runc</code>, y opciones de seguridad.</p><p>Un ejemplo de configuraci&#243;n podr&#237;a ser:</p><pre><code><code>version = 3
root = '/var/lib/containerd'
state = '/run/containerd'
temp = ''
disabled_plugins = []
required_plugins = []
oom_score = 0
imports = []

[grpc]
  address = '/run/containerd/containerd.sock'
  tcp_address = ''
  tcp_tls_ca = ''
  tcp_tls_cert = ''
  tcp_tls_key = ''
  uid = 0
  gid = 0
  max_recv_message_size = 16777216
  max_send_message_size = 16777216

[ttrpc]
  address = ''
  uid = 0
  gid = 0

[debug]
  address = ''
  uid = 0
  gid = 0
  level = ''
  format = ''

[metrics]
  address = ''
  grpc_histogram = false

[plugins]
  [plugins.'io.containerd.cri.v1.images']
    snapshotter = 'overlayfs'
    disable_snapshot_annotations = true
    discard_unpacked_layers = false
    max_concurrent_downloads = 3
    concurrent_layer_fetch_buffer = 0
    image_pull_progress_timeout = '5m0s'
    image_pull_with_sync_fs = false
    stats_collect_period = 10
    use_local_image_pull = false

    [plugins.'io.containerd.cri.v1.images'.pinned_images]
      sandbox = 'registry.k8s.io/pause:3.10'

    [plugins.'io.containerd.cri.v1.images'.registry]
      config_path = ''

    [plugins.'io.containerd.cri.v1.images'.image_decryption]
      key_model = 'node'

  [plugins.'io.containerd.cri.v1.runtime']
    enable_selinux = false
    selinux_category_range = 1024
    max_container_log_line_size = 16384
    disable_apparmor = false
    restrict_oom_score_adj = false
    disable_proc_mount = false
    unset_seccomp_profile = ''
    tolerate_missing_hugetlb_controller = true
    disable_hugetlb_controller = true
    device_ownership_from_security_context = false
    ignore_image_defined_volumes = false
    netns_mounts_under_state_dir = false
    enable_unprivileged_ports = true
    enable_unprivileged_icmp = true
    enable_cdi = true
    cdi_spec_dirs = ['/etc/cdi', '/var/run/cdi']
    drain_exec_sync_io_timeout = '0s'
    ignore_deprecation_warnings = []

    [plugins.'io.containerd.cri.v1.runtime'.containerd]
      default_runtime_name = 'runc'
      ignore_blockio_not_enabled_errors = false
      ignore_rdt_not_enabled_errors = false

      [plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes]
        [plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc]
          runtime_type = 'io.containerd.runc.v2'
          runtime_path = ''
          pod_annotations = []
          container_annotations = []
          privileged_without_host_devices = false
          privileged_without_host_devices_all_devices_allowed = false
          cgroup_writable = false
          base_runtime_spec = ''
          cni_conf_dir = ''
          cni_max_conf_num = 0
          snapshotter = ''
          sandboxer = 'podsandbox'
          io_type = ''

          [plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc.options]
            BinaryName = ''
            CriuImagePath = ''
            CriuWorkPath = ''
            IoGid = 0
            IoUid = 0
            NoNewKeyring = false
            Root = ''
            ShimCgroup = ''

    [plugins.'io.containerd.cri.v1.runtime'.cni]
      bin_dir = ''
      bin_dirs = ['/opt/cni/bin']
      conf_dir = '/etc/cni/net.d'
      max_conf_num = 1
      setup_serially = false
      conf_template = ''
      ip_pref = ''
      use_internal_loopback = false

  [plugins.'io.containerd.differ.v1.erofs']
    mkfs_options = []

  [plugins.'io.containerd.gc.v1.scheduler']
    pause_threshold = 0.02
    deletion_threshold = 0
    mutation_threshold = 100
    schedule_delay = '0s'
    startup_delay = '100ms'

  [plugins.'io.containerd.grpc.v1.cri']
    disable_tcp_service = true
    stream_server_address = '127.0.0.1'
    stream_server_port = '0'
    stream_idle_timeout = '4h0m0s'
    enable_tls_streaming = false

    [plugins.'io.containerd.grpc.v1.cri'.x509_key_pair_streaming]
      tls_cert_file = ''
      tls_key_file = ''

  [plugins.'io.containerd.image-verifier.v1.bindir']
    bin_dir = '/opt/containerd/image-verifier/bin'
    max_verifiers = 10
    per_verifier_timeout = '10s'

  [plugins.'io.containerd.internal.v1.opt']
    path = '/opt/containerd'

  [plugins.'io.containerd.internal.v1.tracing']

  [plugins.'io.containerd.metadata.v1.bolt']
    content_sharing_policy = 'shared'
    no_sync = false

  [plugins.'io.containerd.monitor.container.v1.restart']
    interval = '10s'

  [plugins.'io.containerd.monitor.task.v1.cgroups']
    no_prometheus = false

  [plugins.'io.containerd.nri.v1.nri']
    disable = false
    socket_path = '/var/run/nri/nri.sock'
    plugin_path = '/opt/nri/plugins'
    plugin_config_path = '/etc/nri/conf.d'
    plugin_registration_timeout = '5s'
    plugin_request_timeout = '2s'
    disable_connections = false

  [plugins.'io.containerd.runtime.v2.task']
    platforms = ['linux/arm64/v8']

  [plugins.'io.containerd.service.v1.diff-service']
    default = ['walking']
    sync_fs = false

  [plugins.'io.containerd.service.v1.tasks-service']
    blockio_config_file = ''
    rdt_config_file = ''

  [plugins.'io.containerd.shim.v1.manager']
    env = []

  [plugins.'io.containerd.snapshotter.v1.blockfile']
    root_path = ''
    scratch_file = ''
    fs_type = ''
    mount_options = []
    recreate_scratch = false

  [plugins.'io.containerd.snapshotter.v1.devmapper']
    root_path = ''
    pool_name = ''
    base_image_size = ''
    async_remove = false
    discard_blocks = false
    fs_type = ''
    fs_options = ''

  [plugins.'io.containerd.snapshotter.v1.erofs']
    root_path = ''
    ovl_mount_options = []
    enable_fsverity = false

  [plugins.'io.containerd.snapshotter.v1.native']
    root_path = ''

  [plugins.'io.containerd.snapshotter.v1.overlayfs']
    root_path = ''
    upperdir_label = false
    sync_remove = false
    slow_chown = false
    mount_options = []

  [plugins.'io.containerd.snapshotter.v1.zfs']
    root_path = ''

  [plugins.'io.containerd.tracing.processor.v1.otlp']

  [plugins.'io.containerd.transfer.v1.local']
    max_concurrent_downloads = 3
    concurrent_layer_fetch_buffer = 0
    max_concurrent_uploaded_layers = 3
    check_platform_supported = false
    config_path = ''

[cgroup]
  path = ''

[timeouts]
  'io.containerd.timeout.bolt.open' = '0s'
  'io.containerd.timeout.cri.defercleanup' = '1m0s'
  'io.containerd.timeout.metrics.shimstats' = '2s'
  'io.containerd.timeout.shim.cleanup' = '5s'
  'io.containerd.timeout.shim.load' = '5s'
  'io.containerd.timeout.shim.shutdown' = '3s'
  'io.containerd.timeout.task.state' = '2s'

[stream_processors]
  [stream_processors.'io.containerd.ocicrypt.decoder.v1.tar']
    accepts = ['application/vnd.oci.image.layer.v1.tar+encrypted']
    returns = 'application/vnd.oci.image.layer.v1.tar'
    path = 'ctd-decoder'
    args = ['--decryption-keys-path', '/etc/containerd/ocicrypt/keys']
    env = ['OCICRYPT_KEYPROVIDER_CONFIG=/etc/containerd/ocicrypt/ocicrypt_keyprovider.conf']

  [stream_processors.'io.containerd.ocicrypt.decoder.v1.tar.gzip']
    accepts = ['application/vnd.oci.image.layer.v1.tar+gzip+encrypted']
    returns = 'application/vnd.oci.image.layer.v1.tar+gzip'
    path = 'ctd-decoder'
    args = ['--decryption-keys-path', '/etc/containerd/ocicrypt/keys']
    env = ['OCICRYPT_KEYPROVIDER_CONFIG=/etc/containerd/ocicrypt/ocicrypt_keyprovider.conf']</code></code></pre><p>En configuraciones avanzadas, se pueden definir m&#250;ltiples runtimes, ajustar el driver de almacenamiento (por ejemplo, <code>overlayfs</code>), configurar la comunicaci&#243;n por sockets, y personalizar la integraci&#243;n con Kubernetes mediante CRI.</p><p>Algunos puntos destacados de la configuraci&#243;n:</p><ul><li><p><strong>General</strong>: Define rutas de datos (<code>root</code>, <code>state</code>), plugins habilitados y par&#225;metros globales.</p></li><li><p><strong>Comunicaci&#243;n y APIs</strong>: Configura los sockets para gRPC y ttrpc, utilizados para la comunicaci&#243;n entre procesos y con los <a href="https://blog.javivela.dev/p/runc-y-containerd-desde-el-kernel-hasta-la-orquestacion#%C2%A7containerd-shim">shims</a>.</p></li><li><p><strong>CRI (Container Runtime Interface)</strong>: Permite la integraci&#243;n con Kubernetes, especificando im&#225;genes sandbox, runtimes por defecto y opciones de red.</p></li><li><p><strong>Gesti&#243;n de im&#225;genes</strong>: Selecci&#243;n del snapshotter (por ejemplo, <code>overlayfs</code>), deduplicaci&#243;n de capas y pol&#237;ticas de recolecci&#243;n de basura.</p></li><li><p><strong>Red (CNI)</strong>: Define rutas y par&#225;metros para la configuraci&#243;n de red de los contenedores.</p></li><li><p><strong>Runtimes</strong>: Permite definir y personalizar diferentes runtimes (como <code>runc</code>), as&#237; como sus opciones espec&#237;ficas.</p></li></ul><p>La flexibilidad de este archivo permite adaptar <code>containerd</code> a distintos entornos y necesidades, desde laboratorios hasta despliegues en producci&#243;n con Kubernetes.</p><p>Adem&#225;s de <code>containerd</code>, existen otras alternativas para la ejecuci&#243;n de contenedores:</p><ul><li><p><a href="https://cri-o.io/">CRI-O</a>: Un runtime ligero dise&#241;ado espec&#237;ficamente para Kubernetes. Implementa la especificaci&#243;n <a href="https://kubernetes.io/docs/concepts/architecture/cri/">Container Runtime Interface (CRI)</a> y utiliza <code>runc</code> como runtime de bajo nivel.</p></li><li><p><a href="https://docs.docker.com/engine/">Docker Engine</a>: Plataforma ampliamente utilizada para construir, enviar y ejecutar contenedores. Ofrece gesti&#243;n de im&#225;genes, redes y vol&#250;menes, y emplea internamente <code>containerd</code> y <code>runc</code>.</p></li><li><p><a href="https://www.mirantis.com/software/mirantis-container-runtime/">Mirantis Container Runtime</a>: Soluci&#243;n empresarial previamente conocida como Docker Engine - Enterprise, certificada para entornos de producci&#243;n y con caracter&#237;sticas avanzadas de seguridad y soporte extendido.</p></li></ul><h3>containerd-shim</h3><p>Para garantizar que los contenedores sigan funcionando incluso si el proceso principal de <code>containerd</code> se reinicia o actualiza, existe un componente intermedio llamado <strong>containerd-shim</strong>.</p><p>Este shim se sit&#250;a entre <code>containerd</code> y el runtime de bajo nivel (<code>runc</code>), y cumple varias funciones clave para ofrecer la gran resiliencia del sistema:</p><ul><li><p>Permite que los contenedores contin&#250;en ejecut&#225;ndose de forma independiente al proceso principal de <code>containerd</code>.</p></li><li><p>Gestiona la entrada y salida est&#225;ndar (stdin, stdout, stderr) de los procesos dentro del contenedor.</p></li><li><p>Se encarga de recolectar procesos hu&#233;rfanos (zombies) para evitar fugas de recursos.</p></li><li><p>Propaga se&#241;ales del sistema operativo (como SIGTERM o SIGKILL) al proceso principal del contenedor.</p></li></ul><p>De este modo, cada contenedor tiene su propio proceso shim, lo que mejora la resiliencia y el aislamiento de los contenedores gestionados por <code>containerd</code>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WRFo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495f76ac-7935-4239-9a77-22f242eef397_1329x1399.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WRFo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495f76ac-7935-4239-9a77-22f242eef397_1329x1399.png 424w, https://substackcdn.com/image/fetch/$s_!WRFo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495f76ac-7935-4239-9a77-22f242eef397_1329x1399.png 848w, https://substackcdn.com/image/fetch/$s_!WRFo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495f76ac-7935-4239-9a77-22f242eef397_1329x1399.png 1272w, https://substackcdn.com/image/fetch/$s_!WRFo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495f76ac-7935-4239-9a77-22f242eef397_1329x1399.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WRFo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495f76ac-7935-4239-9a77-22f242eef397_1329x1399.png" width="1329" height="1399" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/495f76ac-7935-4239-9a77-22f242eef397_1329x1399.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1399,&quot;width&quot;:1329,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Diagrama Kubernetes, containerd, containerd-shim, namespaces, cgroups.&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Diagrama Kubernetes, containerd, containerd-shim, namespaces, cgroups." title="Diagrama Kubernetes, containerd, containerd-shim, namespaces, cgroups." srcset="https://substackcdn.com/image/fetch/$s_!WRFo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495f76ac-7935-4239-9a77-22f242eef397_1329x1399.png 424w, https://substackcdn.com/image/fetch/$s_!WRFo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495f76ac-7935-4239-9a77-22f242eef397_1329x1399.png 848w, https://substackcdn.com/image/fetch/$s_!WRFo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495f76ac-7935-4239-9a77-22f242eef397_1329x1399.png 1272w, https://substackcdn.com/image/fetch/$s_!WRFo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495f76ac-7935-4239-9a77-22f242eef397_1329x1399.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Diagrama Kubernetes, containerd, containerd-shim, namespaces, cgroups.</figcaption></figure></div><h2>Ejemplo pr&#225;ctico</h2><p>Vamos a comprobar la evoluci&#243;n desde comandos del Kernel de Linux hasta las herramientas de alto nivel <code>runc</code> y <code>containerd</code>.</p><pre><code><code>sudo unshare --pid --mount --uts --fork /bin/bash
mount -t proc proc /proc
hostname manual-container
ps aux</code></code></pre><ol><li><p>El comando <code>unshare</code> permite crear nuevos namespaces en Linux, proporcionando una shell de <code>bash</code> que se ejecuta de forma aislada, puntos de montaje y hostname, aunque sigue teniendo acceso al sistema de archivos y procesos del host:</p><ul><li><p><code>--pid</code>: crea un nuevo namespace de PID, donde los procesos tienen su propio espacio de identificadores, comenzando desde 1.</p></li><li><p><code>--mount</code>: a&#237;sla las operaciones de montaje, de modo que los cambios no afectan al host.</p></li><li><p><code>--uts</code>: crea un namespace UTS, permitiendo modificar el hostname y domainname solo dentro del namespace.</p></li><li><p><code>--fork</code>: ejecuta el proceso <code>/bin/bash</code> como hijo, haciendo que este sea el proceso principal del nuevo namespace.</p></li></ul></li><li><p>El comando <code>mount -t proc proc /proc</code> monta un sistema de archivos virtual <code>proc</code> en el nuevo namespace, mostrando solo los procesos del namespace.</p></li><li><p>El comando <code>hostname manual-container</code> cambia el nombre del host dentro del namespace UTS reci&#233;n creado, sin afectar al sistema principal.</p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FUli!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd448b733-a947-433a-936d-88d2abe5cfd2_780x162.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FUli!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd448b733-a947-433a-936d-88d2abe5cfd2_780x162.png 424w, https://substackcdn.com/image/fetch/$s_!FUli!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd448b733-a947-433a-936d-88d2abe5cfd2_780x162.png 848w, https://substackcdn.com/image/fetch/$s_!FUli!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd448b733-a947-433a-936d-88d2abe5cfd2_780x162.png 1272w, https://substackcdn.com/image/fetch/$s_!FUli!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd448b733-a947-433a-936d-88d2abe5cfd2_780x162.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FUli!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd448b733-a947-433a-936d-88d2abe5cfd2_780x162.png" width="780" height="162" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d448b733-a947-433a-936d-88d2abe5cfd2_780x162.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:162,&quot;width&quot;:780,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Resultado ejecuci&#243;n comandos&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Resultado ejecuci&#243;n comandos" title="Resultado ejecuci&#243;n comandos" srcset="https://substackcdn.com/image/fetch/$s_!FUli!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd448b733-a947-433a-936d-88d2abe5cfd2_780x162.png 424w, https://substackcdn.com/image/fetch/$s_!FUli!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd448b733-a947-433a-936d-88d2abe5cfd2_780x162.png 848w, https://substackcdn.com/image/fetch/$s_!FUli!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd448b733-a947-433a-936d-88d2abe5cfd2_780x162.png 1272w, https://substackcdn.com/image/fetch/$s_!FUli!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd448b733-a947-433a-936d-88d2abe5cfd2_780x162.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Resultado ejecuci&#243;n comandos</figcaption></figure></div><p>Vamos a utilizar el comando <code>runc</code> para obtener el mismo resultado:</p><pre><code><code>CONTAINER_NAME=manual-container
mkdir $CONTAINER_NAME
cd $CONTAINER_NAME

sudo ctr image pull docker.io/library/alpine:3.22.0

mkdir rootfs

sudo ctr image mount docker.io/library/alpine:3.22.0 rootfs

runc spec

echo $(
  jq '.process.args = ["/bin/sh", "-c", "uname -a &amp;&amp; ps aux &amp;&amp; sleep 30"]' config.json
) &gt; config.json

sudo runc run $CONTAINER_NAME</code></code></pre><ol><li><p>Creamos un directorio para alojar el sistema de archivos <code>rootfs</code> y la configuraci&#243;n del contenedor (<code>config.json</code>).</p></li><li><p>Descargamos una imagen (por ejemplo, Alpine) para obtener el sistema de archivos base (<code>rootfs</code>).</p></li><li><p>Generamos el archivo de configuraci&#243;n <code>config.json</code> con el comando <code>runc spec</code>.</p></li><li><p>Modificamos el comando de inicio del contenedor para que ejecute <code>uname -a &amp;&amp; ps aux &amp;&amp; sleep 30</code>.</p></li><li><p>Iniciamos el contenedor con <code>sudo runc run $CONTAINER_NAME</code>.</p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WXCp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc23141d-3b5b-4ae6-83fa-ead2c346f4fe_1182x981.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WXCp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc23141d-3b5b-4ae6-83fa-ead2c346f4fe_1182x981.png 424w, https://substackcdn.com/image/fetch/$s_!WXCp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc23141d-3b5b-4ae6-83fa-ead2c346f4fe_1182x981.png 848w, https://substackcdn.com/image/fetch/$s_!WXCp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc23141d-3b5b-4ae6-83fa-ead2c346f4fe_1182x981.png 1272w, https://substackcdn.com/image/fetch/$s_!WXCp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc23141d-3b5b-4ae6-83fa-ead2c346f4fe_1182x981.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WXCp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc23141d-3b5b-4ae6-83fa-ead2c346f4fe_1182x981.png" width="1182" height="981" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bc23141d-3b5b-4ae6-83fa-ead2c346f4fe_1182x981.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:981,&quot;width&quot;:1182,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Resultado ejecuci&#243;n comandos runc&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Resultado ejecuci&#243;n comandos runc" title="Resultado ejecuci&#243;n comandos runc" srcset="https://substackcdn.com/image/fetch/$s_!WXCp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc23141d-3b5b-4ae6-83fa-ead2c346f4fe_1182x981.png 424w, https://substackcdn.com/image/fetch/$s_!WXCp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc23141d-3b5b-4ae6-83fa-ead2c346f4fe_1182x981.png 848w, https://substackcdn.com/image/fetch/$s_!WXCp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc23141d-3b5b-4ae6-83fa-ead2c346f4fe_1182x981.png 1272w, https://substackcdn.com/image/fetch/$s_!WXCp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc23141d-3b5b-4ae6-83fa-ead2c346f4fe_1182x981.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Resultado ejecuci&#243;n comandos</figcaption></figure></div><p>Ejecutamos el contenedor utilizando <code>containerd</code>:</p><pre><code><code>sudo ctr images pull docker.io/library/alpine:3.22.0
sudo ctr run --rm docker.io/library/alpine:3.22.0 manual-container /bin/sh -c "uname -a &amp;&amp; ps aux &amp;&amp; sleep 30"</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sTsb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd15b2dd5-fdce-4494-8597-1024c8cd7ac0_1486x953.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sTsb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd15b2dd5-fdce-4494-8597-1024c8cd7ac0_1486x953.png 424w, https://substackcdn.com/image/fetch/$s_!sTsb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd15b2dd5-fdce-4494-8597-1024c8cd7ac0_1486x953.png 848w, https://substackcdn.com/image/fetch/$s_!sTsb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd15b2dd5-fdce-4494-8597-1024c8cd7ac0_1486x953.png 1272w, https://substackcdn.com/image/fetch/$s_!sTsb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd15b2dd5-fdce-4494-8597-1024c8cd7ac0_1486x953.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sTsb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd15b2dd5-fdce-4494-8597-1024c8cd7ac0_1486x953.png" width="1456" height="934" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d15b2dd5-fdce-4494-8597-1024c8cd7ac0_1486x953.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:934,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Resultado ejecuci&#243;n comandos&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Resultado ejecuci&#243;n comandos" title="Resultado ejecuci&#243;n comandos" srcset="https://substackcdn.com/image/fetch/$s_!sTsb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd15b2dd5-fdce-4494-8597-1024c8cd7ac0_1486x953.png 424w, https://substackcdn.com/image/fetch/$s_!sTsb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd15b2dd5-fdce-4494-8597-1024c8cd7ac0_1486x953.png 848w, https://substackcdn.com/image/fetch/$s_!sTsb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd15b2dd5-fdce-4494-8597-1024c8cd7ac0_1486x953.png 1272w, https://substackcdn.com/image/fetch/$s_!sTsb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd15b2dd5-fdce-4494-8597-1024c8cd7ac0_1486x953.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Resultado ejecuci&#243;n comandos</figcaption></figure></div><h2>Conclusi&#243;n</h2><p>La orquestaci&#243;n y ejecuci&#243;n de contenedores no es una tarea trivial. Los <code>namespaces</code> y <code>cgroups</code> del kernel de Linux proporcionan el aislamiento y control de recursos a bajo nivel. Sobre estos cimientos, herramientas como <code>runc</code> y <code>containerd</code> a&#241;aden una capa de abstracci&#243;n que facilita la gesti&#243;n, mejora la experiencia de usuario y habilita funcionalidades avanzadas como la recolecci&#243;n de m&#233;tricas.</p><p>Gracias a la estandarizaci&#243;n impulsada por la comunidad y organizaciones como la OCI y la CNCF, hoy disponemos de un ecosistema diverso de herramientas (como gVisor, Kata Containers o CRI-O) que permiten adaptar la ejecuci&#243;n de contenedores a diferentes necesidades y escenarios, desde laboratorios hasta entornos de producci&#243;n y orquestaci&#243;n con Kubernetes.</p><p>Con estas bases s&#243;lidas, estamos preparados para el siguiente paso: <strong>Kubernetes</strong>.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/runc-y-containerd-desde-el-kernel-hasta-la-orquestacion?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">&#161;Te <strong>AGRADEZCO</strong> enormemente que hayas dedicado tu valioso tiempo a leer lo que escribo! Si te ha gustado y crees que puede ayudar a otras personas, <strong>puedes compartirlo</strong>.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/runc-y-containerd-desde-el-kernel-hasta-la-orquestacion?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.javivela.dev/p/runc-y-containerd-desde-el-kernel-hasta-la-orquestacion?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Compartir</span></a></p></div><h2>Referencias</h2><ul><li><p><a href="https://containerd.io/">https://containerd.io/</a></p></li><li><p><a href="https://github.com/containerd/containerd/blob/main/docs/PLUGINS.md">https://github.com/containerd/containerd/blob/main/docs/PLUGINS.md</a></p></li><li><p><a href="https://github.com/opencontainers/containerd">https://github.com/opencontainers/containerd</a></p></li><li><p><a href="https://github.com/opencontainers/runc">https://github.com/opencontainers/runc</a></p></li><li><p><a href="https://iximiuz.com/en/posts/you-dont-need-an-image-to-run-a-container/">https://iximiuz.com/en/posts/you-dont-need-an-image-to-run-a-container/</a></p></li><li><p><a href="https://kubernetes.io/docs/setup/production-environment/container-runtimes/">https://kubernetes.io/docs/setup/production-environment/container-runtimes/</a></p></li></ul>]]></content:encoded></item><item><title><![CDATA[Contenedores: Desde el kernel hasta la orquestación - namespaces y control groups (cgroups)]]></title><description><![CDATA[Este es el primer art&#237;culo de la serie &#8220;Desde el kernel hasta la orquestaci&#243;n&#8221;. El objetivo de los art&#237;culos es entender c&#243;mo funciona la orquestaci&#243;n de contenedores a m&#225;s bajo nivel.Uno de los beneficios de la ejecuci&#243;n y orquestaci&#243;n de contenedores es que no necesitamos preocuparnos por c&#243;mo se ejecutan a bajo nivel en la infraestructura.Es genial tener una abstracci&#243;n de c&#243;mo funciona la tecnolog&#237;a para poder centrarnos en a&#241;adir los servicios y la funcionalidad necesaria para nuestras aplicaciones, pero en ocasiones es importante tener el conocimiento de c&#243;mo funciona esta tecnolog&#237;a para entender lo que est&#225; pasando cuando tenemos una incidencia o necesitamos depurar un problema.]]></description><link>https://www.javivela.dev/p/namespaces-y-control-groups-desde-el-kernel-hasta-la-orquestacion</link><guid isPermaLink="false">https://www.javivela.dev/p/namespaces-y-control-groups-desde-el-kernel-hasta-la-orquestacion</guid><dc:creator><![CDATA[Javi Vela]]></dc:creator><pubDate>Mon, 23 Jun 2025 06:00:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!quAC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1689462a-7681-46b0-865b-850e8fbd3266_847x626.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introducci&#243;n</h2><p>Este es el primer art&#237;culo de la serie &#8220;Desde el kernel hasta la orquestaci&#243;n&#8221;. El objetivo de los art&#237;culos es entender c&#243;mo funciona la orquestaci&#243;n de contenedores a m&#225;s bajo nivel.</p><p>Uno de los beneficios de la ejecuci&#243;n y orquestaci&#243;n de contenedores es que no necesitamos preocuparnos por c&#243;mo se ejecutan a bajo nivel en la infraestructura.</p><p>Es genial tener una abstracci&#243;n de c&#243;mo funciona la tecnolog&#237;a para poder centrarnos en a&#241;adir los servicios y la funcionalidad necesaria para nuestras aplicaciones, pero en ocasiones es importante tener el conocimiento de c&#243;mo funciona esta tecnolog&#237;a para entender lo que est&#225; pasando cuando tenemos una incidencia o necesitamos depurar un problema.</p><p>En el siguiente diagrama podemos ver el stack de tecnolog&#237;as utilizado para la ejecuci&#243;n y orquestaci&#243;n de contenedores. En este post y en los siguientes los iremos desgranando para conocer c&#243;mo funcionan entre ellas:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!quAC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1689462a-7681-46b0-865b-850e8fbd3266_847x626.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!quAC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1689462a-7681-46b0-865b-850e8fbd3266_847x626.png 424w, https://substackcdn.com/image/fetch/$s_!quAC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1689462a-7681-46b0-865b-850e8fbd3266_847x626.png 848w, https://substackcdn.com/image/fetch/$s_!quAC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1689462a-7681-46b0-865b-850e8fbd3266_847x626.png 1272w, https://substackcdn.com/image/fetch/$s_!quAC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1689462a-7681-46b0-865b-850e8fbd3266_847x626.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!quAC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1689462a-7681-46b0-865b-850e8fbd3266_847x626.png" width="847" height="626" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1689462a-7681-46b0-865b-850e8fbd3266_847x626.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:626,&quot;width&quot;:847,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Diagrama kubernetes, containerd, runc, namespaces y control groups&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Diagrama kubernetes, containerd, runc, namespaces y control groups" title="Diagrama kubernetes, containerd, runc, namespaces y control groups" srcset="https://substackcdn.com/image/fetch/$s_!quAC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1689462a-7681-46b0-865b-850e8fbd3266_847x626.png 424w, https://substackcdn.com/image/fetch/$s_!quAC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1689462a-7681-46b0-865b-850e8fbd3266_847x626.png 848w, https://substackcdn.com/image/fetch/$s_!quAC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1689462a-7681-46b0-865b-850e8fbd3266_847x626.png 1272w, https://substackcdn.com/image/fetch/$s_!quAC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1689462a-7681-46b0-865b-850e8fbd3266_847x626.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Diagrama kubernetes, containerd, runc, namespaces y control groups</figcaption></figure></div><p>Para comenzar, vamos a hablar sobre namespaces y cgroups (control groups), los cuales son la base de la virtualizaci&#243;n de procesos en sistemas operativos que utilizan Linux como base.</p><p>Namespaces y cgroups est&#225;n disponibles desde 2002 y 2008, respectivamente. Utiliz&#225;ndolos de manera conjunta, podemos ejecutar de manera aislada procesos en Linux; adem&#225;s, son las tecnolog&#237;as utilizadas para la ejecuci&#243;n de contenedores en Linux.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/subscribe?&quot;,&quot;text&quot;:&quot;Suscribirse&quot;,&quot;language&quot;:&quot;es&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">&#161;<strong>GRACIAS</strong> por dedicar unos minutos tan valiosos a leer los art&#237;culos que escribo! <strong>Suscr&#237;bete</strong> para no perderte ninguna novedad y tener toda la informaci&#243;n directamente en tu email.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Escribe tu correo electr&#243;nico..." tabindex="-1"><input type="submit" class="button primary" value="Suscribirse"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Namespaces (Linux)</h2><blockquote><p>No confundir los namespaces en Linux con los namespaces de Kubernetes.</p></blockquote><p>El kernel de Linux incorpora una funcionalidad llamada <strong>namespaces</strong>, la cual permite aislar y limitar el acceso de un proceso a algunos recursos del sistema.</p><p>De esta manera, el proceso puede ejecutarse dentro de su propio entorno sin interferir ni acceder a otros recursos de otros procesos.</p><p>Esta funcionalidad se a&#241;adi&#243; al kernel de Linux en la versi&#243;n 2.6.24 (2008) y es la base para poder ejecutar contenedores a trav&#233;s de aplicaciones como Docker, LXC, containerd&#8230;</p><p>Algunos de los tipos de namespaces disponibles en el kernel son los siguientes:</p><ul><li><p><strong>cgroup namespace</strong> (kernel 4.6 - 2016): Permite aislar la vista y manipulaci&#243;n de los grupos de control (cgroups) para los procesos dentro del namespace. As&#237;, los procesos solo pueden gestionar y ver los cgroups a los que pertenecen, sin acceder a los del sistema anfitri&#243;n o de otros contenedores. Esto mejora la seguridad y el aislamiento de recursos.</p></li><li><p><strong>Inter-process communication (IPC) namespace</strong> (kernel 2.4.19 - 2006): A&#237;sla los mecanismos de comunicaci&#243;n entre procesos, como sem&#225;foros, colas de mensajes y memoria compartida. Los procesos dentro de un namespace IPC solo pueden comunicarse entre s&#237;, evitando interferencias o accesos no autorizados a recursos IPC de otros namespaces.</p></li><li><p><strong>Mount namespace</strong> (kernel 2.4.19 - 2002): Permite gestionar qu&#233; sistemas de archivos est&#225;n montados y disponibles para los procesos dentro del namespace. Cada mount namespace puede tener su propio conjunto de puntos de montaje, posibilitando que los contenedores tengan vistas independientes del sistema de archivos y aumentando el aislamiento y la flexibilidad en la gesti&#243;n de almacenamiento.</p></li><li><p><strong>Network namespace</strong> (kernel 2.6.29 - 2009): Virtualiza los elementos de red disponibles. Al crear el namespace, solo est&#225; disponible el dispositivo <code>loopback</code>. Cada dispositivo solo puede estar asociado a un namespace. Cada namespace tiene su propia IP, tabla de enrutamiento y firewall.</p></li><li><p><strong>PID namespace</strong> (kernel 2.6.24 - 2008): Permite aislar el espacio de identificadores de procesos (PID). Los procesos dentro de un PID namespace ven solo los procesos que existen en ese namespace, y el primer proceso creado tiene PID 1, similar al proceso init en un sistema Linux tradicional. Esto permite que los contenedores ejecuten sus propios &#225;rboles de procesos de manera independiente y facilita la gesti&#243;n de procesos hu&#233;rfanos.</p></li><li><p><strong>Time namespace</strong> (kernel 5.6 - 2020): Permite que los procesos de cada namespace utilicen diferentes offsets de tiempo.</p></li><li><p><strong>Unix time-sharing (UTS) namespace</strong> (kernel 2.6.19 - 2006): Permite que los procesos dentro de un namespace tengan su propio nombre de host (<code>hostname</code>) y nombre de dominio (<code>domainname</code>). Esto es &#250;til para que los contenedores tengan identificadores de red independientes, aislando la identidad del sistema dentro de cada contenedor.</p></li><li><p><strong>User namespace</strong> (kernel 3.8 - 2013): Proporciona aislamiento de usuarios y grupos. Los procesos pueden tener diferentes identificadores de usuario (UID) y grupo (GID) dentro del namespace respecto al sistema anfitri&#243;n. Esto permite, por ejemplo, que un proceso tenga privilegios de root dentro del contenedor pero sea un usuario sin privilegios fuera de &#233;l, mejorando la seguridad.</p></li></ul><h2>cgroups (control groups)</h2><p>cgroups es la abreviaci&#243;n de control groups. Esta funcionalidad del kernel de Linux permite establecer el control sobre la cantidad de recursos que un proceso puede utilizar. De esta manera, evitamos que un proceso que necesite hacer un uso intensivo de la CPU pueda interferir con otros procesos que estamos ejecutando en la misma m&#225;quina. Las principales caracter&#237;sticas son:</p><ul><li><p>Limitaci&#243;n de recursos: permite establecer l&#237;mites sobre el uso de CPU, memoria, I/O y n&#250;mero m&#225;ximo de archivos abiertos por grupo de procesos.</p></li><li><p>Priorizaci&#243;n: posibilita asignar diferentes prioridades de acceso a los recursos entre distintos grupos de procesos.</p></li><li><p>Accounting (facturaci&#243;n): proporciona m&#233;tricas detalladas sobre el consumo de recursos, &#250;tiles para monitorizaci&#243;n y facturaci&#243;n.</p></li><li><p>Control: permite pausar (congelar) o reanudar la ejecuci&#243;n de un grupo de procesos.</p></li><li><p>Jerarqu&#237;a: en cgroup v1, los grupos pueden organizarse jer&#225;rquicamente, permitiendo heredar l&#237;mites y configuraciones entre padres e hijos.</p></li></ul><p>Esta versi&#243;n presenta algunos problemas de uso:</p><ul><li><p>Es complejo administrar m&#250;ltiples jerarqu&#237;as.</p></li><li><p>Inconsistencia entre diferentes controladores.</p></li><li><p>Dificultad para delegar privilegios de manera segura.</p></li></ul><p>En 2016, con la versi&#243;n del kernel 4.5, llega la versi&#243;n 2 de cgroup. Las principales mejoras son:</p><ul><li><p>Jerarqu&#237;a unificada: todos los controladores que componen cgroup comparten una &#250;nica jerarqu&#237;a; la estructura es m&#225;s simple y coherente. Cada proceso pertenece solo a un cgroup.</p></li><li><p>Actualizaci&#243;n de los controladores que componen cgroup:</p><ul><li><p><strong>CPU:</strong> Control unificado de uso de CPU (bandwidth y cuotas).</p></li><li><p><strong>Memoria:</strong> Gesti&#243;n avanzada de memoria, con soporte para swapping y l&#237;mites m&#225;s precisos.</p></li><li><p><strong>IO:</strong> Sustituye a blkio, ofreciendo una contabilidad y control de entrada/salida m&#225;s eficiente.</p></li><li><p><strong>RDMA (Remote Direct Memory Access):</strong> Permite a los procesos acceder directamente a la memoria de otros sistemas a trav&#233;s de la red, sin intervenci&#243;n del procesador ni del sistema operativo remoto. Esto mejora el rendimiento en aplicaciones que requieren baja latencia y alto ancho de banda, como bases de datos distribuidas o sistemas de almacenamiento de alto rendimiento.</p></li><li><p><strong>PIDS:</strong> Permite establecer l&#237;mites en la cantidad de procesos que puede crear un grupo, evitando el agotamiento de recursos por exceso de procesos.</p></li></ul></li><li><p>Funcionalidades mejoradas en CPU y memoria: cgroup v2 ofrece un control m&#225;s granular y eficiente sobre el uso de CPU y memoria. Por ejemplo, permite definir cuotas y prioridades de CPU de forma m&#225;s precisa, as&#237; como establecer l&#237;mites de memoria m&#225;s estrictos y gestionar mejor situaciones de presi&#243;n de memoria. Adem&#225;s, la gesti&#243;n de memoria swap es m&#225;s flexible, lo que ayuda a evitar situaciones de OOM (Out Of Memory).</p></li><li><p>Delegaci&#243;n segura: cgroup v2 introduce mecanismos m&#225;s robustos para delegar la administraci&#243;n de subgrupos a procesos sin privilegios. Esto significa que los usuarios pueden gestionar sus propios recursos y crear jerarqu&#237;as de cgroups dentro de los l&#237;mites establecidos por el administrador del sistema, sin necesidad de privilegios elevados. Esta funcionalidad mejora la seguridad y facilita la multi-tenencia, permitiendo que diferentes usuarios o aplicaciones gestionen sus propios recursos de manera aislada y controlada, sin comprometer la integridad del sistema anfitri&#243;n.</p></li><li><p>Sem&#225;ntica mejorada: los l&#237;mites de recursos son m&#225;s predecibles y consistentes entre los distintos controladores, lo que facilita la configuraci&#243;n y reduce comportamientos inesperados. Adem&#225;s, se han mejorado las m&#233;tricas de consumo y la gesti&#243;n de situaciones de OOM (Out Of Memory), permitiendo una monitorizaci&#243;n y respuesta m&#225;s precisa ante el agotamiento de recursos.</p></li></ul><p>Gracias a esta versi&#243;n se ha mejorado el aislamiento de recursos entre contenedores y se permite limitar los recursos de una manera m&#225;s precisa.</p><p>Desde la versi&#243;n 1.25, en Kubernetes cgroups v2 est&#225; activado por defecto.</p><h2>Ejemplo pr&#225;ctico</h2><p>Vamos a comprobar c&#243;mo podemos ejecutar procesos limitando el uso de CPU y memoria.</p><p>Antes de continuar, verifica si tu m&#225;quina utiliza cgroups v2 ejecutando el comando <code>mount | grep cgroup</code>.</p><ul><li><p>Si ves m&#250;ltiples montajes, est&#225;s usando cgroups v1.</p></li><li><p>Si ves solo un montaje de tipo cgroup2, est&#225;s usando cgroups v2.</p></li></ul><p>Otra forma de comprobarlo es ejecutar <code>ls /sys/fs/cgroup/cgroup.controllers</code>. Si el comando falla, tienes cgroups v1; si muestra contenido, tienes cgroups v2.</p><p><strong>Estructura de directorios en cgroups v1:</strong></p><pre><code><code>/sys/fs/cgroup/
&#9500;&#9472;&#9472; blkio/           # Control de I/O de bloques
&#9500;&#9472;&#9472; cpu/             # Control de CPU
&#9500;&#9472;&#9472; cpuacct/         # Contabilidad de CPU  
&#9500;&#9472;&#9472; memory/          # Control de memoria
&#9500;&#9472;&#9472; devices/         # Control de dispositivos
&#9500;&#9472;&#9472; freezer/         # Congelar/descongelar procesos
&#9500;&#9472;&#9472; net_cls/         # Clasificaci&#243;n de red
&#9500;&#9472;&#9472; pids/            # Control de n&#250;mero de procesos
&#9492;&#9472;&#9472; systemd/         # Jerarqu&#237;a de systemd
</code></code></pre><p><strong>Estructura de directorios en cgroups v2:</strong></p><pre><code><code>/sys/fs/cgroup/
&#9500;&#9472;&#9472; cgroup.controllers      # Controladores disponibles
&#9500;&#9472;&#9472; cgroup.procs           # Procesos en este cgroup
&#9500;&#9472;&#9472; cgroup.subtree_control # Controladores habilitados
&#9500;&#9472;&#9472; cpu.max                # L&#237;mite m&#225;ximo de CPU
&#9500;&#9472;&#9472; memory.max             # L&#237;mite m&#225;ximo de memoria
&#9500;&#9472;&#9472; io.max                 # L&#237;mite m&#225;ximo de I/O
&#9500;&#9472;&#9472; pids.max               # L&#237;mite m&#225;ximo de procesos
&#9492;&#9472;&#9472; user.slice/            # Jerarqu&#237;a de systemd
    &#9500;&#9472;&#9472; system.slice/
    &#9492;&#9472;&#9472; docker.slice/
</code></code></pre><p>El directorio <code>/sys/fs/cgroup/</code> es el est&#225;ndar para las interfaces del kernel:</p><ul><li><p><code>sys</code>: Interfaces del kernel</p></li><li><p><code>fs</code>: Sistemas de archivos especiales</p></li><li><p><code>cgroup</code>: Subsistema cgroups</p></li></ul><p>Al crear un directorio en <code>/sys/fs/cgroup/</code>, se generan autom&#225;ticamente los archivos necesarios para configurar un nuevo cgroup:</p><pre><code><code>sudo mkdir /sys/fs/cgroup/my-group/
</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!B2nx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3177683a-7db4-43d1-8c62-1ff24ce3d364_1690x271.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!B2nx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3177683a-7db4-43d1-8c62-1ff24ce3d364_1690x271.png 424w, https://substackcdn.com/image/fetch/$s_!B2nx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3177683a-7db4-43d1-8c62-1ff24ce3d364_1690x271.png 848w, https://substackcdn.com/image/fetch/$s_!B2nx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3177683a-7db4-43d1-8c62-1ff24ce3d364_1690x271.png 1272w, https://substackcdn.com/image/fetch/$s_!B2nx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3177683a-7db4-43d1-8c62-1ff24ce3d364_1690x271.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!B2nx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3177683a-7db4-43d1-8c62-1ff24ce3d364_1690x271.png" width="1456" height="233" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3177683a-7db4-43d1-8c62-1ff24ce3d364_1690x271.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:233,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;cgroups ficheros configuraci&#243;n&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="cgroups ficheros configuraci&#243;n" title="cgroups ficheros configuraci&#243;n" srcset="https://substackcdn.com/image/fetch/$s_!B2nx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3177683a-7db4-43d1-8c62-1ff24ce3d364_1690x271.png 424w, https://substackcdn.com/image/fetch/$s_!B2nx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3177683a-7db4-43d1-8c62-1ff24ce3d364_1690x271.png 848w, https://substackcdn.com/image/fetch/$s_!B2nx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3177683a-7db4-43d1-8c62-1ff24ce3d364_1690x271.png 1272w, https://substackcdn.com/image/fetch/$s_!B2nx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3177683a-7db4-43d1-8c62-1ff24ce3d364_1690x271.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Resultado comando ls (cgroup)</figcaption></figure></div><p>El n&#250;mero de archivos puede variar seg&#250;n los controladores activos. Puedes consultar los controladores disponibles con <code>cat /sys/fs/cgroup/cgroup.controllers</code>.</p><p>Existen varios m&#233;todos para configurar un cgroup:</p><ol><li><p>Editar directamente los archivos.</p></li><li><p>Usar los binarios del paquete cgroup-tools (libcgroup).</p></li><li><p>Utilizar el comando <code>systemd-run</code>.</p></li></ol><p>Para limitar la memoria de un cgroup:</p><pre><code><code>echo "10M" | sudo tee /sys/fs/cgroup/my-group/memory.max
</code></code></pre><p>Para limitar el uso de CPU al 25%:</p><pre><code><code>echo "25000 100000" | sudo tee /sys/fs/cgroup/my-group/cpu.max
</code></code></pre><p>Puedes comprobar su funcionamiento utilizando la herramienta <code>stress-ng</code>:</p><pre><code><code>sudo bash -c "echo $$ &gt; /sys/fs/cgroup/my-group/cgroup.procs &amp;&amp; exec stress-ng --vm 1 --vm-bytes 200M"
</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Gsee!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3775e646-f684-4e6a-bd5e-7d2bea747179_1265x96.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Gsee!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3775e646-f684-4e6a-bd5e-7d2bea747179_1265x96.png 424w, https://substackcdn.com/image/fetch/$s_!Gsee!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3775e646-f684-4e6a-bd5e-7d2bea747179_1265x96.png 848w, https://substackcdn.com/image/fetch/$s_!Gsee!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3775e646-f684-4e6a-bd5e-7d2bea747179_1265x96.png 1272w, https://substackcdn.com/image/fetch/$s_!Gsee!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3775e646-f684-4e6a-bd5e-7d2bea747179_1265x96.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Gsee!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3775e646-f684-4e6a-bd5e-7d2bea747179_1265x96.png" width="1265" height="96" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3775e646-f684-4e6a-bd5e-7d2bea747179_1265x96.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:96,&quot;width&quot;:1265,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Resultado OOM&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Resultado OOM" title="Resultado OOM" srcset="https://substackcdn.com/image/fetch/$s_!Gsee!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3775e646-f684-4e6a-bd5e-7d2bea747179_1265x96.png 424w, https://substackcdn.com/image/fetch/$s_!Gsee!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3775e646-f684-4e6a-bd5e-7d2bea747179_1265x96.png 848w, https://substackcdn.com/image/fetch/$s_!Gsee!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3775e646-f684-4e6a-bd5e-7d2bea747179_1265x96.png 1272w, https://substackcdn.com/image/fetch/$s_!Gsee!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3775e646-f684-4e6a-bd5e-7d2bea747179_1265x96.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Resultado ejecuci&#243;n comando.</figcaption></figure></div><p>Tambi&#233;n puedes usar los comandos de cgroup-tools (libcgroup):</p><p><code>datawrapper.dwcdn.net/1rKVm/1/</code></p><pre><code><code>sudo cgcreate -g memory,cpu:/my-group

sudo cgset -r memory.max=10M my-group     
sudo cgset -r cpu.max="25000 100000" my-group

sudo cgexec -g memory,cpu:my-group stress-ng --vm 1 --vm-bytes 200M</code></code></pre><p><code>systemd-run</code> es la herramienta recomendada para gestionar procesos, ya que systemd es el principal gestor de cgroups (v2) en Linux y simplifica la ejecuci&#243;n de comandos bajo restricciones de recursos:</p><pre><code><code>systemd-run --scope -p MemoryMax=10M stress-ng --vm 1 --vm-bytes 200M --timeout 30s</code></code></pre><p>Otro ejemplo m&#225;s avanzado, limitando CPU, memoria e IO:</p><pre><code><code>systemd-run --unit=backup-job \
  -p CPUQuota=20% \
  -p IOWeight=50 \
  -p MemoryMax=1G \
  tar czf /backup/system-$(date +%Y%m%d).tar.gz /home</code></code></pre><p>Podemos utilizar de manera conjunta cgroups y namespaces. El siguiente ejemplo crea un nuevo cgroup, limitando la memoria a 256 megabytes, el uso de CPU al 25% y el n&#250;mero m&#225;ximo de procesos a 10:</p><pre><code><code>sudo mkdir /sys/fs/cgroup/my-container
echo "+memory +cpu +pids" | sudo tee /sys/fs/cgroup/cgroup.subtree_control
echo "256M" | sudo tee /sys/fs/cgroup/my-container/memory.max
echo "25000 100000" | sudo tee /sys/fs/cgroup/my-container/cpu.max
echo "10" | sudo tee /sys/fs/cgroup/my-container/pids.max

sudo unshare --pid --net --mount --uts --fork bash -c "
  echo \$\$ &gt; /sys/fs/cgroup/my-container/cgroup.procs
  hostname my-container
  mount -t proc proc /proc
  exec bash
"</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UKfS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a662760-6ae1-424c-aa00-b1eba9cdeb16_1906x1120.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UKfS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a662760-6ae1-424c-aa00-b1eba9cdeb16_1906x1120.png 424w, https://substackcdn.com/image/fetch/$s_!UKfS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a662760-6ae1-424c-aa00-b1eba9cdeb16_1906x1120.png 848w, https://substackcdn.com/image/fetch/$s_!UKfS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a662760-6ae1-424c-aa00-b1eba9cdeb16_1906x1120.png 1272w, https://substackcdn.com/image/fetch/$s_!UKfS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a662760-6ae1-424c-aa00-b1eba9cdeb16_1906x1120.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UKfS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a662760-6ae1-424c-aa00-b1eba9cdeb16_1906x1120.png" width="1456" height="856" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4a662760-6ae1-424c-aa00-b1eba9cdeb16_1906x1120.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:856,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Resultado ejecuci&#243;n cgroup y namespace&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Resultado ejecuci&#243;n cgroup y namespace" title="Resultado ejecuci&#243;n cgroup y namespace" srcset="https://substackcdn.com/image/fetch/$s_!UKfS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a662760-6ae1-424c-aa00-b1eba9cdeb16_1906x1120.png 424w, https://substackcdn.com/image/fetch/$s_!UKfS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a662760-6ae1-424c-aa00-b1eba9cdeb16_1906x1120.png 848w, https://substackcdn.com/image/fetch/$s_!UKfS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a662760-6ae1-424c-aa00-b1eba9cdeb16_1906x1120.png 1272w, https://substackcdn.com/image/fetch/$s_!UKfS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a662760-6ae1-424c-aa00-b1eba9cdeb16_1906x1120.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Resultado ejecuci&#243;n comandos.</figcaption></figure></div><p>Estos ejemplos permiten experimentar y comprender de forma pr&#225;ctica c&#243;mo los cgroups y namespaces trabajan juntos para aislar y limitar recursos en Linux.</p><h2>Resumen</h2><p>Aunque puedan parecer similares, namespaces y cgroups cumplen roles complementarios en la virtualizaci&#243;n de procesos en Linux:</p><ul><li><p><strong>Namespaces</strong> proporcionan aislamiento: cada contenedor tiene su propia vista del sistema operativo, incluyendo red, procesos, sistema de archivos, usuarios, etc. Esto significa que los procesos dentro de un contenedor no pueden ver ni interactuar directamente con los recursos de otros contenedores o del sistema anfitri&#243;n.</p></li><li><p><strong>cgroups</strong> proporcionan control de recursos: permiten limitar, priorizar y monitorizar el uso de recursos como CPU, memoria, almacenamiento y procesos para cada grupo de procesos. As&#237;, se evita que un contenedor consuma todos los recursos del sistema y afecte a los dem&#225;s.</p></li></ul><p>La combinaci&#243;n de ambas tecnolog&#237;as es lo que permite ejecutar m&#250;ltiples aplicaciones de forma segura, aislada y eficiente en el mismo kernel Linux. Cada contenedor se ejecuta en su propio espacio aislado (gracias a los namespaces) y con recursos controlados (gracias a los cgroups).</p><p>En resumen, los namespaces a&#237;slan <em>qu&#233;</em> puede ver y hacer un proceso, mientras que los cgroups controlan <em>cu&#225;nto</em> puede consumir. Juntos, hacen posible la ejecuci&#243;n de contenedores tal y como los conocemos hoy.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/namespaces-y-control-groups-desde-el-kernel-hasta-la-orquestacion?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">&#161;Te <strong>AGRADEZCO</strong> enormemente que hayas dedicado tu valioso tiempo a leer lo que escribo! Si te ha gustado y crees que puede ayudar a otras personas, <strong>puedes compartirlo</strong>.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/namespaces-y-control-groups-desde-el-kernel-hasta-la-orquestacion?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.javivela.dev/p/namespaces-y-control-groups-desde-el-kernel-hasta-la-orquestacion?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Compartir</span></a></p></div><h2>Referencias</h2><ul><li><p><a href="https://earthly.dev/blog/namespaces-and-cgroups-docker/">https://earthly.dev/blog/namespaces-and-cgroups-docker/</a></p></li><li><p><a href="https://en.wikipedia.org/wiki/Cgroups">https://en.wikipedia.org/wiki/Cgroups</a></p></li><li><p><a href="https://en.wikipedia.org/wiki/linux_namespaces">https://en.wikipedia.org/wiki/linux_namespaces</a></p></li><li><p><a href="https://kubernetes.io/docs/concepts/architecture/cgroups/">https://kubernetes.io/docs/concepts/architecture/cgroups/</a></p></li><li><p><a href="https://lwn.net/Articles/259217/">https://lwn.net/Articles/259217/</a></p></li><li><p><a href="https://man7.org/linux/man-pages/man7/cgroups.7.html">https://man7.org/linux/man-pages/man7/cgroups.7.html</a></p></li><li><p><a href="https://www.redhat.com/en/blog/cgroups-part-four">https://www.redhat.com/en/blog/cgroups-part-four</a></p></li></ul>]]></content:encoded></item><item><title><![CDATA[Sidecar Containers]]></title><description><![CDATA[Desde la versi&#243;n Kubernetes 1.28 Planternetes (alpha), se soporta la configuraci&#243;n de Sidecar containers de manera nativa, y desde la versi&#243;n 1.33 Octarine (stable) est&#225; disponible de forma estable.]]></description><link>https://www.javivela.dev/p/sidecar-containers</link><guid isPermaLink="false">https://www.javivela.dev/p/sidecar-containers</guid><dc:creator><![CDATA[Javi Vela]]></dc:creator><pubDate>Mon, 09 Jun 2025 06:00:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!MjnU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79b6c5ce-92d6-421e-8ded-6a60201d03f7_1024x608.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introducci&#243;n</h2><p>Cuando trabajamos con contenedores, podemos utilizar diferentes patrones para ejecutar nuestras aplicaciones.</p><p>Algunos de ellos son:</p><ul><li><p><strong>Sidecar</strong>: Contenedor que extiende funcionalidad (logging, monitoring).</p></li><li><p><strong>Ambassador</strong>: Proxy para comunicaciones externas.</p></li><li><p><strong>Adapter</strong>: Transforma datos para compatibilidad.</p></li><li><p><strong>Init Container</strong>: Crea y configura parte de la aplicaci&#243;n antes de que se ejecute el contenedor del Pod.</p></li></ul><p>En este post vamos a hablar del patr&#243;n <code>sidecar container</code>. El objetivo de este patr&#243;n es que uno o varios contenedores extiendan la funcionalidad principal de otro contenedor.</p><p>Imagina que necesitas extraer parte de la informaci&#243;n generada por tu aplicaci&#243;n. En vez de incluir esta funcionalidad dentro de tu aplicaci&#243;n, haci&#233;ndola m&#225;s pesada, delegamos este trabajo en otra aplicaci&#243;n que se despliega junto a la tuya, leyendo y extrayendo la informaci&#243;n generada.</p><p>Desde la versi&#243;n <a href="https://Kubernetes.io/blog/2023/08/15/Kubernetes-v1-28-release/#sidecar-init-containers">Kubernetes 1.28 Planternetes (alpha)</a>, se soporta la configuraci&#243;n de este patr&#243;n de manera nativa, y desde la versi&#243;n <a href="https://Kubernetes.io/blog/2025/04/23/Kubernetes-v1-33-release/#stable-sidecar-containers">1.33 Octarine (stable)</a> est&#225; disponible de forma estable.</p><p>A continuaci&#243;n, mostramos c&#243;mo podemos utilizarlo.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/subscribe?&quot;,&quot;text&quot;:&quot;Suscribirse&quot;,&quot;language&quot;:&quot;es&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">&#161;<strong>GRACIAS</strong> por dedicar unos minutos tan valiosos a leer los art&#237;culos que escribo! <strong>Suscr&#237;bete</strong> para no perderte ninguna novedad y tener toda la informaci&#243;n directamente en tu email.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Escribe tu correo electr&#243;nico..." tabindex="-1"><input type="submit" class="button primary" value="Suscribirse"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MjnU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79b6c5ce-92d6-421e-8ded-6a60201d03f7_1024x608.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MjnU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79b6c5ce-92d6-421e-8ded-6a60201d03f7_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!MjnU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79b6c5ce-92d6-421e-8ded-6a60201d03f7_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!MjnU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79b6c5ce-92d6-421e-8ded-6a60201d03f7_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!MjnU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79b6c5ce-92d6-421e-8ded-6a60201d03f7_1024x608.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MjnU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79b6c5ce-92d6-421e-8ded-6a60201d03f7_1024x608.png" width="728" height="432.25" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/79b6c5ce-92d6-421e-8ded-6a60201d03f7_1024x608.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:608,&quot;width&quot;:1024,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!MjnU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79b6c5ce-92d6-421e-8ded-6a60201d03f7_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!MjnU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79b6c5ce-92d6-421e-8ded-6a60201d03f7_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!MjnU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79b6c5ce-92d6-421e-8ded-6a60201d03f7_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!MjnU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79b6c5ce-92d6-421e-8ded-6a60201d03f7_1024x608.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Im&#225;gen generada por IA: Sidecar Containers</figcaption></figure></div><h2>&#191;C&#243;mo crear un sidecar container sin utilizar el soporte nativo de Kubernetes?</h2><p>Antes de que Kubernetes incluyera el soporte nativo de <code>sidecar containers</code>, pod&#237;amos aplicar el patr&#243;n de la siguiente manera:</p><pre><code><code>apiVersion: v1
kind: Pod
metadata:
  name: web-with-logger
spec:
  containers:
  - name: web-server
    image: nginx:alpine
    ports:
    - containerPort: 80
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/nginx

  - name: log-reader
    image: busybox
    command: ["sh", "-c"]
    args:
    - |
      while true; do
        if [ -f /logs/access.log ]; then
          tail -n 5 /logs/access.log
        fi
        sleep 10
      done
    volumeMounts:
    - name: shared-logs
      mountPath: /logs

  volumes:
  - name: shared-logs
    emptyDir: {}</code></code></pre><p>Esta manera de utilizar <code>sidecar containers</code> en Kubernetes presenta algunos problemas en ciertos casos:</p><ul><li><p><strong>Jobs</strong>: el Pod no termina hasta que todos los contenedores finalizan.</p></li><li><p>Los contenedores que procesan logs y m&#233;tricas necesitan un orden espec&#237;fico de ejecuci&#243;n para evitar la p&#233;rdida de datos.</p></li><li><p><strong>Service mesh</strong>: necesitan arrancar y estar en funcionamiento antes que el resto de los contenedores para ejecutar tareas relacionadas con el enrutamiento o la seguridad.</p></li></ul><h2>&#191;C&#243;mo crear un sidecar container de manera nativa en Kubernetes?</h2><p>La implementaci&#243;n nativa de <code>sidecar containers</code> se ha realizado utilizando la funcionalidad <code>initContainers</code>. Para ello, debemos especificar el valor <code>Always</code> en la propiedad <code>restartPolicy</code> del contenedor (si utilizamos otro valor, Kubernetes no ejecuta los contenedores como <code>sidecar containers</code>).</p><p>De esta manera, un <code>sidecar container</code> puede iniciarse, pararse o reiniciarse sin afectar al resto de contenedores que componen el Pod.</p><pre><code><code>apiVersion: v1
kind: Pod
metadata:
  name: web-with-logger
spec:
  initContainers:
  - name: log-reader
    image: busybox
    command: ["sh", "-c"]
    restartPolicy: Always
    args:
    - |
      while true; do
        if [ -f /logs/access.log ]; then
          tail -n 5 /logs/access.log
        fi
        sleep 10
      done
    volumeMounts:
    - name: shared-logs
      mountPath: /logs
  containers:
  - name: web-server
    image: nginx:alpine
    ports:
    - containerPort: 80
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/nginx

  volumes:
  - name: shared-logs
    emptyDir: {}</code></code></pre><p>Definiendo el valor <code>Always</code> en la propiedad <code>restartPolicy</code>, el contenedor se ejecutar&#225; durante todo el ciclo de vida del Pod y nos garantizar&#225; el orden correcto de ejecuci&#243;n de cada uno de los contenedores, siendo los definidos en <code>initContainers</code> los primeros en ejecutarse.</p><p>Cuando se inicia el proceso de finalizaci&#243;n del Pod, <code>kubelet</code> pospone la finalizaci&#243;n de los contenedores definidos en <code>initContainers</code> hasta que los contenedores definidos en la propiedad <code>containers</code> hayan finalizado, garantizando as&#237; hasta el final del ciclo de vida del Pod el funcionamiento de los <code>sidecar containers</code>.</p><h2>Conclusi&#243;n</h2><p>Aunque la implementaci&#243;n mediante <code>initContainers</code> y la propiedad <code>restartPolicy</code> puede resultar menos intuitiva para definir los <code>sidecar containers</code> de nuestro Pod, creo que contar con soporte nativo en Kubernetes simplifica significativamente la aplicaci&#243;n de este patr&#243;n, resolviendo los problemas de orquestaci&#243;n entre los contenedores y garantizando su correcto funcionamiento.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/sidecar-containers?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">&#161;Te <strong>AGRADEZCO</strong> enormemente que hayas dedicado tu valioso tiempo a leer lo que escribo! Si te ha gustado y crees que puede ayudar a otras personas, <strong>puedes compartirlo</strong>.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/sidecar-containers?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.javivela.dev/p/sidecar-containers?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Compartir</span></a></p></div><h2>Referencias</h2><ul><li><p><a href="https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/753-sidecar-containers/README.md">https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/753-sidecar-containers/README.md</a></p></li><li><p><a href="https://kubernetes.io/blog/2015/06/the-distributed-system-toolkit-patterns/">https://kubernetes.io/blog/2015/06/the-distributed-system-toolkit-patterns/</a></p></li><li><p><a href="https://kubernetes.io/blog/2023/08/15/kubernetes-v1-28-release/">https://kubernetes.io/blog/2023/08/15/kubernetes-v1-28-release/</a></p></li><li><p><a href="https://kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/">https://kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/</a></p></li></ul>]]></content:encoded></item><item><title><![CDATA[Kubernetes Image Volumes]]></title><description><![CDATA[Image Volumes permite montar una imagen como un volumen en un Pod.]]></description><link>https://www.javivela.dev/p/kubernetes-image-volumes</link><guid isPermaLink="false">https://www.javivela.dev/p/kubernetes-image-volumes</guid><dc:creator><![CDATA[Javi Vela]]></dc:creator><pubDate>Mon, 26 May 2025 06:00:00 GMT</pubDate><content:encoded><![CDATA[<h2>Introducci&#243;n</h2><p>La primera versi&#243;n de Image Volumes fue introducida en la versi&#243;n 1.31 (Elli) de Kubernetes (puedes consultar toda la informaci&#243;n relacionada en el siguiente enlace <a href="https://github.com/kubernetes/enhancements/issues/4639">https://github.com/kubernetes/enhancements/issues/4639</a> ).</p><p>En la release 1.33 (Octarine) lanzada en abril de 2025, pasa a un estado beta.</p><p>Por defecto esta funcionalidad no se encuentra activada ya que no todos los container runtime (CRI) soportan la funcionalidad.</p><p>En estos momentos:</p><ul><li><p><strong>CRI-O</strong>: soporta la funcionalidad completa.</p></li><li><p><strong>containerd</strong>: todav&#237;a no soporta las novedades incluidas en 1.33 (<a href="https://github.com/containerd/containerd/pull/11578">https://github.com/containerd/containerd/pull/11578</a> ).</p></li></ul><p>En este post resumimos c&#243;mo funciona y las mejoras introducidas.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/subscribe?&quot;,&quot;text&quot;:&quot;Suscribirse&quot;,&quot;language&quot;:&quot;es&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">&#161;<strong>GRACIAS</strong> por dedicar unos minutos tan valiosos a leer los art&#237;culos que escribo! <strong>Suscr&#237;bete</strong> para no perderte ninguna novedad y tener toda la informaci&#243;n directamente en tu email.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Escribe tu correo electr&#243;nico..." tabindex="-1"><input type="submit" class="button primary" value="Suscribirse"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>&#191;Qu&#233; es Image Volumes?</h2><p>Image Volumes permite montar una imagen como un volumen en un Pod. Podemos generar una imagen con el contenido est&#225;tico necesario para la aplicaci&#243;n (configuraci&#243;n, modelos de machine learning, &#8230;), almacenarlos en un container registry y montarlos como un volumen que ser&#225; utilizado por las aplicaciones.</p><p>La gran ventaja es que separamos la l&#243;gica de la aplicaci&#243;n y de los datos que necesita la aplicaci&#243;n pudiendo tener procesos de release totalmente diferentes.</p><h2>Novedades de Image Volumes en 1.33</h2><p>La mejora m&#225;s destacada en esta versi&#243;n es la capacidad de montar Image Volumes como subdirectorios dentro de un contenedor, lo que proporciona mayor flexibilidad y granularidad al configurar nuestras aplicaciones.</p><ul><li><p><code>subPath</code>: Permite especificar un subdirectorio est&#225;tico donde se montar&#225; el contenido del volumen.</p></li><li><p><code>subPathExpr</code>: Posibilita definir rutas din&#225;micas utilizando variables de entorno, ideal para configuraciones que requieren personalizaci&#243;n por instancia.</p></li></ul><p>Adicionalmente, introduce m&#233;tricas dedicadas para la supervisi&#243;n de Image Volumes:</p><ul><li><p><code>kubelet_image_volume_requested_total</code>: Muestra el total de peticiones image volumes solicitadas.</p></li><li><p><code>kubelet_image_volume_mounted_succeed_total</code>: Contabiliza el total de image volumes montadas correctamente.</p></li><li><p><code>kubelet_image_volume_mounted_errors_total</code>: Monitoriza el total de image volumes que no se han podido montar.</p></li></ul><h2>C&#243;mo podemos utilizar Image Volumes en un Pod</h2><p>Utilizaremos <a href="https://kind.sigs.k8s.io/docs/user/configuration/">Kind</a> para crear un cluster en nuestro y as&#237; poder probar Image volumes.</p><p>Creamos el siguiente fichero de configuraci&#243;n para habilitar la funcionalidad <code>ImageVolume</code> (<a href="https://kind.sigs.k8s.io/docs/user/configuration/#feature-gates%29">https://kind.sigs.k8s.io/docs/user/configuration/#feature-gates)</a>:</p><pre><code><code>kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
featureGates:
  "ImageVolume": true</code></code></pre><p>Creamos el cluster: <code>kind create cluster --config kind-config.yaml</code>.</p><p>Una vez creado el cluster creamos un Pod con un volumen como imagen:</p><pre><code><code>apiVersion: v1
kind: Pod
metadata:
  name: pod
spec:
  containers:
    - name: test
      command: ["sleep", "infinity"]
      image: debian
      volumeMounts:
        - name: volume
          mountPath: /volume
  volumes:
    - name: volume
      image:
        reference: quay.io/crio/artifact:v2
        pullPolicy: IfNotPresent</code></code></pre><p>Puedes comprobar el contenido de la imagen <code>quay.io/crio/artifact:v2</code> utilizando <a href="https://github.com/wagoodman/dive">dive</a>:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!t_IC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a83b21b-50a8-4cb6-afd9-76940c676e79_881x162.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!t_IC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a83b21b-50a8-4cb6-afd9-76940c676e79_881x162.png 424w, https://substackcdn.com/image/fetch/$s_!t_IC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a83b21b-50a8-4cb6-afd9-76940c676e79_881x162.png 848w, https://substackcdn.com/image/fetch/$s_!t_IC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a83b21b-50a8-4cb6-afd9-76940c676e79_881x162.png 1272w, https://substackcdn.com/image/fetch/$s_!t_IC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a83b21b-50a8-4cb6-afd9-76940c676e79_881x162.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!t_IC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a83b21b-50a8-4cb6-afd9-76940c676e79_881x162.png" width="881" height="162" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1a83b21b-50a8-4cb6-afd9-76940c676e79_881x162.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:162,&quot;width&quot;:881,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Dive contenido imagen&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Dive contenido imagen" title="Dive contenido imagen" srcset="https://substackcdn.com/image/fetch/$s_!t_IC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a83b21b-50a8-4cb6-afd9-76940c676e79_881x162.png 424w, https://substackcdn.com/image/fetch/$s_!t_IC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a83b21b-50a8-4cb6-afd9-76940c676e79_881x162.png 848w, https://substackcdn.com/image/fetch/$s_!t_IC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a83b21b-50a8-4cb6-afd9-76940c676e79_881x162.png 1272w, https://substackcdn.com/image/fetch/$s_!t_IC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a83b21b-50a8-4cb6-afd9-76940c676e79_881x162.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Resultado ejecuci&#243;n comando.</figcaption></figure></div><p>Ejecutamos una shell y comprobamos el contenido <code>kubectl exec pod -it -- sh</code>:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Seyu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9008253-a08a-41ac-ba03-485c8a85ccdf_460x295.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Seyu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9008253-a08a-41ac-ba03-485c8a85ccdf_460x295.png 424w, https://substackcdn.com/image/fetch/$s_!Seyu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9008253-a08a-41ac-ba03-485c8a85ccdf_460x295.png 848w, https://substackcdn.com/image/fetch/$s_!Seyu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9008253-a08a-41ac-ba03-485c8a85ccdf_460x295.png 1272w, https://substackcdn.com/image/fetch/$s_!Seyu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9008253-a08a-41ac-ba03-485c8a85ccdf_460x295.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Seyu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9008253-a08a-41ac-ba03-485c8a85ccdf_460x295.png" width="460" height="295" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f9008253-a08a-41ac-ba03-485c8a85ccdf_460x295.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:295,&quot;width&quot;:460,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Contenido carpeta /volume&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Contenido carpeta /volume" title="Contenido carpeta /volume" srcset="https://substackcdn.com/image/fetch/$s_!Seyu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9008253-a08a-41ac-ba03-485c8a85ccdf_460x295.png 424w, https://substackcdn.com/image/fetch/$s_!Seyu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9008253-a08a-41ac-ba03-485c8a85ccdf_460x295.png 848w, https://substackcdn.com/image/fetch/$s_!Seyu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9008253-a08a-41ac-ba03-485c8a85ccdf_460x295.png 1272w, https://substackcdn.com/image/fetch/$s_!Seyu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9008253-a08a-41ac-ba03-485c8a85ccdf_460x295.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Resultado ejecuci&#243;n comando.</figcaption></figure></div><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/kubernetes-image-volumes?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">&#161;Te <strong>AGRADEZCO</strong> enormemente que hayas dedicado tu valioso tiempo a leer lo que escribo! Si te ha gustado y crees que puede ayudar a otras personas, <strong>puedes compartirlo</strong>.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/kubernetes-image-volumes?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.javivela.dev/p/kubernetes-image-volumes?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Compartir</span></a></p></div><h2>Conclusion</h2><p>Image Volumes ha incorporado r&#225;pidamente nuevas funcionalidades como: <code>subPath</code>, <code>subPathExpr</code> y <code>m&#233;tricas</code> dedicadas en tan solo dos releases (de la 1.31 a la 1.33), encontr&#225;ndose esta funcionalidad en estado beta.</p><p>Esta progresi&#243;n refleja que hay una necesidad de gesti&#243;n de vol&#250;menes utilizando contenedores para poder separar y distribuir datos y aplicaciones en im&#225;genes diferentes.</p><h2>References</h2><ul><li><p><a href="https://kubernetes.io/blog/2025/04/29/kubernetes-v1-33-image-volume-beta/">https://kubernetes.io/blog/2025/04/29/kubernetes-v1-33-image-volume-beta/</a></p></li><li><p><a href="https://kubernetes.io/docs/tasks/configure-pod-container/image-volumes/">https://kubernetes.io/docs/tasks/configure-pod-container/image-volumes/</a></p></li><li><p><a href="https://github.com/kubernetes/enhancements/issues/4639">https://github.com/kubernetes/enhancements/issues/4639</a></p></li></ul>]]></content:encoded></item><item><title><![CDATA[Cosign, Trivy y Kyverno en acción]]></title><description><![CDATA[Vamos a describir c&#243;mo podemos verificar la autenticidad e integridad de una imagen firmada en el proceso de integraci&#243;n continua y c&#243;mo verificar la informaci&#243;n antes de su ejecuci&#243;n.]]></description><link>https://www.javivela.dev/p/cosign-trivy-y-kyverno-en-accion</link><guid isPermaLink="false">https://www.javivela.dev/p/cosign-trivy-y-kyverno-en-accion</guid><dc:creator><![CDATA[Javi Vela]]></dc:creator><pubDate>Wed, 29 Jan 2025 07:00:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!azGU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15d45848-6bf6-41b6-abe6-723ee91b5e1a_991x774.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Puedes encontrar el c&#243;digo fuente del post en el siguiente enlace: <a href="https://github.com/fjvela/cosign-trivy-kyverno-in-action">https://github.com/fjvela/cosign-trivy-kyverno-in-action</a></p></blockquote><h2>Introducci&#243;n</h2><p>Vamos a describir c&#243;mo podemos verificar la autenticidad e integridad de una imagen firmada en el proceso de integraci&#243;n continua y c&#243;mo verificar un <em>attestation</em> (informaci&#243;n verificable sobre la imagen: revisi&#243;n c&#243;digo fuente, escaneo de vulnerabilidades&#8230;) con la informaci&#243;n de las vulnerabilidades de la imagen antes de ejecutar la imagen en un cluster Kubernetes.</p><p>Para ello vamos a utilizar las siguientes herramientas:</p><ul><li><p><a href="https://blog.javivela.dev/p/cosign-trivy-y-kyverno-en-accion#&#167;cosign">Cosign</a></p></li><li><p><a href="https://blog.javivela.dev/p/cosign-trivy-y-kyverno-en-accion#&#167;kyverno">Kyverno</a></p></li><li><p><a href="https://blog.javivela.dev/p/cosign-trivy-y-kyverno-en-accion#&#167;trivy">Trivy</a></p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/subscribe?&quot;,&quot;text&quot;:&quot;Suscribirse&quot;,&quot;language&quot;:&quot;es&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">&#161;<strong>GRACIAS</strong> por dedicar unos minutos tan valiosos a leer los art&#237;culos que escribo! <strong>Suscr&#237;bete</strong> para no perderte ninguna novedad y tener toda la informaci&#243;n directamente en tu email.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Escribe tu correo electr&#243;nico..." tabindex="-1"><input type="submit" class="button primary" value="Suscribirse"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h3>Cosign</h3><p>Cosign es una herramienta creada por el proyecto <a href="https://www.sigstore.dev/">Sigstore</a> que nos permite firmar im&#225;genes Docker y otros artefactos software.</p><p>Su principal funci&#243;n es proporcionar una forma sencilla y segura de firmar digitalmente software, permitiendo verificar posteriormente su autenticidad e integridad.</p><p>Las firmas se pueden almacenar junto con las im&#225;genes en un registro de im&#225;genes compatible con <a href="https://opencontainers.org/">OCI (Open Container Initiative)</a>.</p><p>Por defecto, Cosign firma los artefactos software utilizando el modo <em>Keyless</em>, para ello utiliza Fulcio como entidad certificadora y Rekor como <em>transparency log</em>. En caso de que fuera necesario tambi&#233;n es posible realizar la firma utilizando nuestro certificado.</p><p>Una <em><a href="https://github.com/in-toto/attestation">attestation</a></em> es una &#8220;declaraci&#243;n&#8221; firmada que contiene metadatos sobre la imagen Docker. Pueden incluir informaci&#243;n sobre un escaneo de vulnerabilidades de la imagen o informaci&#243;n de c&#243;mo se ha generado. Estas se almacenan en el registro de im&#225;genes junto con la imagen y pueden ser verificadas por Cosign o por otras herramientas c&#243;mo Kyverno.</p><h3>Trivy</h3><p>Trivy es un esc&#225;ner de seguridad que nos permite escanear diferentes elementos como:</p><ul><li><p>Im&#225;genes</p></li><li><p>Ficheros</p></li><li><p>Repositorios Git</p></li><li><p>cluster de Kubernetes</p></li></ul><p>Dispone de distintos tipos de esc&#225;neres que podemos ejecutar en cualquier momento dentro de nuestros procesos de CI/CD:</p><ul><li><p>Escaneo de vulnerabilidades (CVEs)</p></li><li><p>Paquetes y dependencias (SBOM)</p></li><li><p>Configuraciones en el c&#243;digo de infraestructura (IaC)</p></li><li><p>Informaci&#243;n sensible (contrase&#241;as y secretos)</p></li></ul><h3>Kyverno</h3><p>Kyverno es gestor de pol&#237;ticas que nos va a permitir validar y/o modificar las peticiones de creaci&#243;n o modificaci&#243;n de los elementos de un cluster de Kubernetes. Para que esto sea posible, Kyverno se configura en el cluster como un <em><a href="https://kyverno.io/docs/introduction/admission-controllers/">Admission controller</a></em> para recibir todas las peticiones realizadas a la API de Kubernetes.</p><p>Las pol&#237;ticas se definen utilizando YAML, eliminando as&#237; la necesidad de aprender lenguajes espec&#237;ficos. Estas pol&#237;ticas permiten verificar si las im&#225;genes han sido firmadas o si los elementos creados en el cluster cumplen con nuestros est&#225;ndares de calidad y seguridad.</p><h2>Generaci&#243;n de la imagen y firma</h2><p>Para poder continuar instala las siguientes herramientas:</p><ul><li><p>Docker</p></li><li><p>Cosign</p></li><li><p>Trivy</p></li></ul><blockquote><p>Antes de comenzar con el proceso debes autenticarte en el almac&#233;n de im&#225;genes que vayas a utilizar (si usas GitHub: <a href="https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry">https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry</a>)</p></blockquote><ol><li><p>Generamos nuestra imagen: <code>docker build . -t ghcr.io/fjvela/blog-demo-image-sign-attestation:1.0.0</code></p></li><li><p>Almacenamos la imagen generada en nuestro contenedor de im&#225;genes: <code>docker push ghcr.io/fjvela/blog-demo-image-sign-attestation:1.0.0</code></p></li><li><p>Obtenemos el <em>digest</em> (el valor es &#250;nico por cada imagen generada y nos aseguramos que estamos firmando la imagen que queremos) de la imagen generada: <code>docker inspect --format='{{index .RepoDigests}}' ghcr.io/fjvela/blog-demo-image-sign-attestation:1.0.0</code></p></li><li><p>Firmamos la imagen con Cosign <code>cosign sign ghcr.io/fjvela/blog-demo-image-sign-attestation@sha256:76e0af3bda5badd9b8e9772903bfdc8d5e2810f647ea6942e73d913a467c2cff</code>.</p></li></ol><p>Cuando ejecutamos el comando <code>cosign sign</code> se ejecutan las siguientes acciones:</p><ul><li><p>Se verifica nuestra identidad a trav&#233;s de un <em>Identity provider</em>.</p></li><li><p>Una vez obtenido un <em>OIDC token</em>, Cosign solicita un certificado (v&#225;lido durante 10 minutos) a una entidad certificadora. En este caso a <strong>Fulcio</strong>, el cual emite certificados ef&#237;meros basados en identidades OIDC para firmar artefactos de software de forma segura.</p></li><li><p>Se firma la imagen con el certificado, se genera un timestamp. A trav&#233;s de la informaci&#243;n del timestamp podemos:</p><ul><li><p>Demostrar cu&#225;ndo se cre&#243; la firma</p></li><li><p>Ayuda a prevenir ataques de repetici&#243;n</p></li><li><p>Proporciona una l&#237;nea temporal auditable de la firma del contenedor</p></li><li><p>Permite decisiones de pol&#237;ticas basadas en tiempo en controladores de admisi&#243;n como Kyverno</p></li></ul></li><li><p>Toda la informaci&#243;n se almacena en nuestro <em>container registry</em>.</p></li><li><p>La informaci&#243;n sobre el certificado, la firma y el timestamp se env&#237;a a Rekor. Rekor es un registro inmutable y transparente (transparency log) que almacena y permite verificar firmas digitales y metadatos de artefactos de software.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!azGU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15d45848-6bf6-41b6-abe6-723ee91b5e1a_991x774.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!azGU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15d45848-6bf6-41b6-abe6-723ee91b5e1a_991x774.png 424w, https://substackcdn.com/image/fetch/$s_!azGU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15d45848-6bf6-41b6-abe6-723ee91b5e1a_991x774.png 848w, https://substackcdn.com/image/fetch/$s_!azGU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15d45848-6bf6-41b6-abe6-723ee91b5e1a_991x774.png 1272w, https://substackcdn.com/image/fetch/$s_!azGU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15d45848-6bf6-41b6-abe6-723ee91b5e1a_991x774.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!azGU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15d45848-6bf6-41b6-abe6-723ee91b5e1a_991x774.png" width="991" height="774" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/15d45848-6bf6-41b6-abe6-723ee91b5e1a_991x774.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:774,&quot;width&quot;:991,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Diagrama funcionamiento Cosign sign&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Diagrama funcionamiento Cosign sign" title="Diagrama funcionamiento Cosign sign" srcset="https://substackcdn.com/image/fetch/$s_!azGU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15d45848-6bf6-41b6-abe6-723ee91b5e1a_991x774.png 424w, https://substackcdn.com/image/fetch/$s_!azGU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15d45848-6bf6-41b6-abe6-723ee91b5e1a_991x774.png 848w, https://substackcdn.com/image/fetch/$s_!azGU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15d45848-6bf6-41b6-abe6-723ee91b5e1a_991x774.png 1272w, https://substackcdn.com/image/fetch/$s_!azGU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15d45848-6bf6-41b6-abe6-723ee91b5e1a_991x774.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Diagrama de secuencia generaci&#243;n imagen y firma</figcaption></figure></div><h2>Creaci&#243;n informe de vulnerabilidades y attestation</h2><p>Una vez firmada la imagen, generamos un informe con las vulnerabilidades de la imagen que hemos generado. El siguiente comando nos proporciona el formato necesario para poder crear un <em>attestation</em> utilizando cosign:</p><p><code>trivy image --ignore-unfixed --format cosign-vuln --output vuln.json ghcr.io/fjvela/blog-demo-image-sign-attestation@sha256:76e0af3bda5badd9b8e9772903bfdc8d5e2810f647ea6942e73d913a467c2cff</code></p><p>Creamos el <em>attestation</em> utilizando cosign:</p><p><code>cosign attest --type vuln --predicate vuln.json ghcr.io/fjvela/blog-demo-image-sign-attestation@sha256:76e0af3bda5badd9b8e9772903bfdc8d5e2810f647ea6942e73d913a467c2cff</code></p><p>Puedes consultar los tipos de <em>attestation</em> que puedes incluir en el siguiente enlace: <a href="https://docs.sigstore.dev/cosign/verifying/attestation/">https://docs.sigstore.dev/cosign/verifying/attestation/</a></p><p>Con los siguientes comandos, se puede verificar la firma e informaci&#243;n incluida en el <em>attestation</em>:</p><pre><code><code>cosign verify ghcr.io/fjvela/blog-demo-image-sign-attestation@sha256:76e0af3bda5badd9b8e9772903bfdc8d5e2810f647ea6942e73d913a467c2cff

cosign verify-attestation --type vuln ghcr.io/fjvela/blog-demo-image-sign-attestation@sha256:76e0af3bda5badd9b8e9772903bfdc8d5e2810f647ea6942e73d913a467c2cff</code></code></pre><h2>Verificaci&#243;n de firma y del escaneo de vulnerabilidades utilizando Kyverno</h2><p>En el siguiente enlace puedes consultar c&#243;mo instalar Kyverno en un cluster Kubernetes: <a href="https://kyverno.io/docs/installation/methods">https://kyverno.io/docs/installation/methods</a>. Kyverno se despliega en el cluster c&#243;mo un <em>Admission Controller</em>, si lo vas a utilizar en producci&#243;n es importante que revises la siguiente informaci&#243;n: <a href="https://kyverno.io/docs/introduction/admission-controllers/">https://kyverno.io/docs/introduction/admission-controllers/</a></p><p>Kyverno soporta diferentes tipos de pol&#237;ticas. El tipo <em>verifyImages</em> nos permite realizar comprobaciones sobre las im&#225;genes que se despliegan en nuestro cluster. Tambi&#233;n dispone de una amplia galer&#237;a de pol&#237;ticas ya creadas y que nos pueden servir como base para crear nuestras propias pol&#237;ticas.</p><p>Partiendo de la pol&#237;tica <em><a href="https://kyverno.io/policies/other/require-vulnerability-scan/require-vulnerability-scan/">Require Image Vulnerability Scans</a></em>:</p><pre><code><code>apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-vulnerability-scan
spec:
  validationFailureAction: Audit
  webhookTimeoutSeconds: 10
  failurePolicy: Fail
  rules:
    - name: scan-not-older-than-one-week
      match:
        any:
          - resources:
              kinds:
                - Pod
      verifyImages:
        - mutateDigest: false
          imageReferences:
            - "ghcr.io/fjvela/blog-demo-image-sign-attestation*"
          attestors:
            - entries:
                - keyless:
                    subject: "YOUR_EMAIL"
                    issuer: "https://github.com/login/oauth"
                    rekor:
                      url: https://rekor.sigstore.dev
          attestations:
            - type: https://cosign.sigstore.dev/attestation/vuln/v1
              attestors:
                - entries:
                    - keyless:
                        subject: "YOUR_EMAIL"
                        issuer: "https://github.com/login/oauth"
                        rekor:
                          url: https://rekor.sigstore.dev
              conditions:
                - all:
                    - key: "{{ time_since('','{{metadata.scanFinishedOn}}','') }}"
                      operator: LessThanOrEquals
                      value: "1h"</code></code></pre><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/cosign-trivy-y-kyverno-en-accion?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">&#161;Te <strong>AGRADEZCO</strong> enormemente que hayas dedicado tu valioso tiempo a leer lo que escribo! Si te ha gustado y crees que puede ayudar a otras personas, <strong>puedes compartirlo.</strong></p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/cosign-trivy-y-kyverno-en-accion?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.javivela.dev/p/cosign-trivy-y-kyverno-en-accion?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Compartir</span></a></p></div><h2>Conclusi&#243;n</h2><p>Como has podido comprobar, la combinaci&#243;n de Cosign para la firma digital, Trivy para el an&#225;lisis de vulnerabilidades y Kyverno para la gesti&#243;n de pol&#237;ticas de seguridad en Kubernetes, nos proporciona una manera sencilla de comprobar la integridad y autenticidad de las im&#225;genes que desplegamos en un cluster Kubernetes.</p><p>La combinaci&#243;n de estas herramientas nos permite:</p><ul><li><p>Asegurar la integridad y autenticidad de nuestras im&#225;genes mediante firmas digitales</p></li><li><p>Detectar vulnerabilidades de seguridad antes del despliegue</p></li><li><p>Automatizar la verificaci&#243;n de seguridad durante el despliegue en Kubernetes</p></li><li><p>Mantener un registro inmutable de todas las firmas y attestations</p></li></ul><h2>Referencias</h2><ul><li><p><a href="https://docs.sigstore.dev/cosign/signing/signing_with_containers/">https://docs.sigstore.dev/cosign/signing/signing_with_containers/</a></p></li><li><p><a href="https://docs.sigstore.dev/logging/overview/">https://docs.sigstore.dev/logging/overview/</a></p></li><li><p><a href="https://github.com/sigstore/fulcio">https://github.com/sigstore/fulcio</a></p></li><li><p><a href="https://github.com/sigstore/rekor">https://github.com/sigstore/rekor</a></p></li><li><p><a href="https://kyverno.io/">https://kyverno.io/</a></p></li><li><p><a href="https://trivy.dev/latest/">https://trivy.dev/latest/</a></p></li></ul>]]></content:encoded></item><item><title><![CDATA[Azure AD Workload Identity]]></title><description><![CDATA[El uso de Azure AD Workload Identity y Azure Managed Identities permite a las aplicaciones que se ejecutan en el cluster acceder a servicios desplegados en Azure sin necesidad de utilizar credenciales]]></description><link>https://www.javivela.dev/p/azure-ad-workload-identity</link><guid isPermaLink="false">https://www.javivela.dev/p/azure-ad-workload-identity</guid><dc:creator><![CDATA[Javi Vela]]></dc:creator><pubDate>Sun, 29 Dec 2024 07:00:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!y0eP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F389a208f-0a19-4cf8-849a-4642507a98cf_1227x483.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Puedes encontrar el c&#243;digo fuente del post en el siguiente enlace: <a href="https://github.com/fjvela/blog-demo-azure-ad-workload-identity">https://github.com/fjvela/blog-demo-azure-ad-workload-identity</a></p></blockquote><h2>Introducci&#243;n</h2><p>En el siguiente post voy a explicar c&#243;mo puedes utilizar <em>Azure Managed Identities</em> y <em>Azure Federated Identity Credentials</em> desde un cluster Kubernetes desplegado en Azure. Esto permitir&#225; a las aplicaciones que se ejecutan en el cluster acceder a servicios desplegados en Azure sin necesidad de utilizar credenciales.</p><p>Antes de continuar leyendo el post, te recomiendo que leas los posts sobre <a href="https://blog.javivela.dev/p/azure-managed-identities">Azure Managed Identities</a> y <a href="https://blog.javivela.dev/p/azure-federated-identity-credentials">Azure Federated Identity Credentials</a>.</p><p>En los posts mencionados, explico c&#243;mo acceder a los recursos desplegados en Azure sin necesidad de gestionar secretos y/o certificados:</p><ul><li><p><strong>Azure Managed Identities</strong>: Se usan en aplicaciones que se ejecutan en servicios de Azure (ej. m&#225;quinas virtuales).</p></li><li><p><strong>Azure Federated Identity Credentials</strong>: Se usan en aplicaciones y servicios que se ejecutan fuera de Azure (ej. GitHub Workflow).</p></li></ul><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/azure-ad-workload-identity?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">&#161;<strong>GRACIAS</strong> por dedicar unos minutos tan valiosos a leer los art&#237;culos que escribo! <strong>Suscr&#237;bete</strong> para no perderte ninguna novedad y tener toda la informaci&#243;n directamente en tu email.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/azure-ad-workload-identity?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.javivela.dev/p/azure-ad-workload-identity?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Compartir</span></a></p></div><h2>&#191;C&#243;mo funciona?</h2><p>Una <em>federated identity credential</em> permite establecer una relaci&#243;n de confianza entre una <em><strong>User managed identity</strong></em> y un proveedor de identidad externo (<em>external identity provider IdP</em>).</p><p>Esta relaci&#243;n permite a Microsoft Identity autenticar una aplicaci&#243;n externa a trav&#233;s del token recibido y el IdP configurado, generando a su vez otro token que permitir&#225; a la aplicaci&#243;n acceder a los recursos desplegados en Azure.</p><p>Tras crear la <em>user managed identity</em>, podemos configurar hasta un m&#225;ximo de 20 <em>federated identity credentials</em>.</p><p>Para aplicaciones desplegadas en un cluster de Kubernetes, se requiere la siguiente informaci&#243;n:</p><ul><li><p><strong>issuer</strong>: Direcci&#243;n URL del proveedor de identidades externo del cluster (IdP).</p></li><li><p><strong>namespace</strong>: Nombre del namespace donde se ejecutar&#225;n los pods.</p></li><li><p><strong>service account</strong>: Nombre del <em>service account</em> (SA) asociado a los pods de nuestro workload.</p></li><li><p><strong>audiences</strong>: Indica qu&#233; plataforma de identidad de Microsoft debe aceptar el token entrante (por defecto: api://AzureADTokenExchange - el valor depende del entorno cloud utilizado - Fairfax, Mooncake, USNat o USSec).</p></li></ul><p><strong>Nota</strong>: La combinaci&#243;n de namespace y service account debe ser &#250;nica en la <em>user managed identity</em>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!y0eP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F389a208f-0a19-4cf8-849a-4642507a98cf_1227x483.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!y0eP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F389a208f-0a19-4cf8-849a-4642507a98cf_1227x483.png 424w, https://substackcdn.com/image/fetch/$s_!y0eP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F389a208f-0a19-4cf8-849a-4642507a98cf_1227x483.png 848w, https://substackcdn.com/image/fetch/$s_!y0eP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F389a208f-0a19-4cf8-849a-4642507a98cf_1227x483.png 1272w, https://substackcdn.com/image/fetch/$s_!y0eP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F389a208f-0a19-4cf8-849a-4642507a98cf_1227x483.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!y0eP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F389a208f-0a19-4cf8-849a-4642507a98cf_1227x483.png" width="1227" height="483" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/389a208f-0a19-4cf8-849a-4642507a98cf_1227x483.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:483,&quot;width&quot;:1227,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Diagrama de funcionamiento federated identity credential&quot;,&quot;title&quot;:&quot;Diagrama de funcionamiento federated identity credential&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Diagrama de funcionamiento federated identity credential" title="Diagrama de funcionamiento federated identity credential" srcset="https://substackcdn.com/image/fetch/$s_!y0eP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F389a208f-0a19-4cf8-849a-4642507a98cf_1227x483.png 424w, https://substackcdn.com/image/fetch/$s_!y0eP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F389a208f-0a19-4cf8-849a-4642507a98cf_1227x483.png 848w, https://substackcdn.com/image/fetch/$s_!y0eP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F389a208f-0a19-4cf8-849a-4642507a98cf_1227x483.png 1272w, https://substackcdn.com/image/fetch/$s_!y0eP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F389a208f-0a19-4cf8-849a-4642507a98cf_1227x483.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Diagrama funcionamiento Azure AD Workload Identity y Azure Managed Identities.</figcaption></figure></div><ol><li><p>Cuando Kubernetes inicia un nuevo POD, <em>AD Workload Identity</em> crea un token en un path determinado.</p></li><li><p>La aplicaci&#243;n solicita un token a Microsoft identity platform, utilizando el token generado en el paso 1.</p></li><li><p>Microsoft identity platform valida el token incluido en la petici&#243;n contra el servicio de validaci&#243;n externo que se ha registrado previamente (OIDC del cluster). Si el token es v&#225;lido, se genera un token de autenticaci&#243;n para autenticarse contra otros servicios desplegados en Azure (hay que asignar los permisos necesarios en el servicio).</p></li><li><p>La aplicaci&#243;n utiliza el token generado para acceder a los recursos desplegados en Azure.</p></li></ol><h2>Configurar federated identity credentials (Kubernetes)</h2><p>Para comenzar, necesitamos un proveedor de identidad externo para crear la relaci&#243;n de confianza entre nuestro cluster y las managed identities utilizadas por las aplicaciones que se ejecutan en nuestro cluster.</p><p>Azure nos proporciona el servicio OpenID Connect (OIDC). Para activarlo podemos usar el siguiente comando:</p><pre><code><code>az aks update --resource-group myResourceGroup --name myAKScluster --enable-oidc-issuer</code></code></pre><blockquote><p><em>Si est&#225;s utilizando Amazon Elastic Kubernetes (EKS) o Google Kubernetes Engine (GKE) revisa la siguiente documentaci&#243;n:</em></p><ul><li><p><a href="https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html">https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html</a></p></li><li><p><a href="https://cloud.google.com/kubernetes-engine/enterprise/identity/setup/per-cluster">https://cloud.google.com/kubernetes-engine/enterprise/identity/setup/per-cluster</a></p></li></ul></blockquote><p>A continuaci&#243;n, vamos a configurar una <em>federated identity credential</em> para permitir que la aplicaci&#243;n pueda acceder a recursos desplegados en Azure.</p><p>Desde el men&#250; &#8220;Managed Identities&#8221; podemos crear una <em>User Managed Identity</em>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!H_N_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fde5412-8967-4965-b56c-7b40ea9a99a8_766x501.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!H_N_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fde5412-8967-4965-b56c-7b40ea9a99a8_766x501.png 424w, https://substackcdn.com/image/fetch/$s_!H_N_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fde5412-8967-4965-b56c-7b40ea9a99a8_766x501.png 848w, https://substackcdn.com/image/fetch/$s_!H_N_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fde5412-8967-4965-b56c-7b40ea9a99a8_766x501.png 1272w, https://substackcdn.com/image/fetch/$s_!H_N_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fde5412-8967-4965-b56c-7b40ea9a99a8_766x501.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!H_N_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fde5412-8967-4965-b56c-7b40ea9a99a8_766x501.png" width="766" height="501" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3fde5412-8967-4965-b56c-7b40ea9a99a8_766x501.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:501,&quot;width&quot;:766,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;C&#243;mo crear una User Managed Identity&quot;,&quot;title&quot;:&quot;C&#243;mo crear una User Managed Identity&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="C&#243;mo crear una User Managed Identity" title="C&#243;mo crear una User Managed Identity" srcset="https://substackcdn.com/image/fetch/$s_!H_N_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fde5412-8967-4965-b56c-7b40ea9a99a8_766x501.png 424w, https://substackcdn.com/image/fetch/$s_!H_N_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fde5412-8967-4965-b56c-7b40ea9a99a8_766x501.png 848w, https://substackcdn.com/image/fetch/$s_!H_N_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fde5412-8967-4965-b56c-7b40ea9a99a8_766x501.png 1272w, https://substackcdn.com/image/fetch/$s_!H_N_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fde5412-8967-4965-b56c-7b40ea9a99a8_766x501.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Creaci&#243;n de una User Managed Identity en el portal de Azure.</figcaption></figure></div><p>Una vez creada, a&#241;adimos una <em>federated identity credential</em>:</p><ol><li><p>Azure nos da la opci&#243;n de configuraci&#243;n para diferentes escenarios, en nuestro caso seleccionamos la opci&#243;n para configurar Kubernetes.</p></li><li><p>Completamos la informaci&#243;n que nos solicita:</p></li></ol><ul><li><p>Namespace donde se ejecuta la aplicaci&#243;n.</p></li><li><p>Service Account (SA) que utiliza la aplicaci&#243;n.</p></li><li><p>URL del emisor de OIDC de nuestro cluster, puedes consultarla en el portal o trav&#233;s del comando: <code>az aks show --name myAKScluster --resource-group myResourceGroup --query "oidcIssuerProfile.issuerUrl" -o tsv</code>.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!X6nC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c492c7f-18b9-4fe7-9a26-b165a56145f7_934x732.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!X6nC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c492c7f-18b9-4fe7-9a26-b165a56145f7_934x732.png 424w, https://substackcdn.com/image/fetch/$s_!X6nC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c492c7f-18b9-4fe7-9a26-b165a56145f7_934x732.png 848w, https://substackcdn.com/image/fetch/$s_!X6nC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c492c7f-18b9-4fe7-9a26-b165a56145f7_934x732.png 1272w, https://substackcdn.com/image/fetch/$s_!X6nC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c492c7f-18b9-4fe7-9a26-b165a56145f7_934x732.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!X6nC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c492c7f-18b9-4fe7-9a26-b165a56145f7_934x732.png" width="934" height="732" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8c492c7f-18b9-4fe7-9a26-b165a56145f7_934x732.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:732,&quot;width&quot;:934,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;C&#243;mo configurar GitHub federated identity credential&quot;,&quot;title&quot;:&quot;C&#243;mo configurar GitHub federated identity credential&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="C&#243;mo configurar GitHub federated identity credential" title="C&#243;mo configurar GitHub federated identity credential" srcset="https://substackcdn.com/image/fetch/$s_!X6nC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c492c7f-18b9-4fe7-9a26-b165a56145f7_934x732.png 424w, https://substackcdn.com/image/fetch/$s_!X6nC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c492c7f-18b9-4fe7-9a26-b165a56145f7_934x732.png 848w, https://substackcdn.com/image/fetch/$s_!X6nC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c492c7f-18b9-4fe7-9a26-b165a56145f7_934x732.png 1272w, https://substackcdn.com/image/fetch/$s_!X6nC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c492c7f-18b9-4fe7-9a26-b165a56145f7_934x732.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Configuraci&#243;n de una <em>federated identity credential en el portal de Azure.</em></figcaption></figure></div><blockquote><p>Despu&#233;s de crear la <em>user managed identity</em> y configurados los federated identity credentials, debemos asignar los permisos correspondientes de acceso.</p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!S3YS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e8f82f5-9fb3-40a0-9e50-f05e9fe86515_1151x757.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!S3YS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e8f82f5-9fb3-40a0-9e50-f05e9fe86515_1151x757.png 424w, https://substackcdn.com/image/fetch/$s_!S3YS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e8f82f5-9fb3-40a0-9e50-f05e9fe86515_1151x757.png 848w, https://substackcdn.com/image/fetch/$s_!S3YS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e8f82f5-9fb3-40a0-9e50-f05e9fe86515_1151x757.png 1272w, https://substackcdn.com/image/fetch/$s_!S3YS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e8f82f5-9fb3-40a0-9e50-f05e9fe86515_1151x757.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!S3YS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e8f82f5-9fb3-40a0-9e50-f05e9fe86515_1151x757.png" width="1151" height="757" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9e8f82f5-9fb3-40a0-9e50-f05e9fe86515_1151x757.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:757,&quot;width&quot;:1151,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Asignar un rol a la user Managed Identity&quot;,&quot;title&quot;:&quot;Asignar un rol a la user Managed Identity&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Asignar un rol a la user Managed Identity" title="Asignar un rol a la user Managed Identity" srcset="https://substackcdn.com/image/fetch/$s_!S3YS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e8f82f5-9fb3-40a0-9e50-f05e9fe86515_1151x757.png 424w, https://substackcdn.com/image/fetch/$s_!S3YS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e8f82f5-9fb3-40a0-9e50-f05e9fe86515_1151x757.png 848w, https://substackcdn.com/image/fetch/$s_!S3YS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e8f82f5-9fb3-40a0-9e50-f05e9fe86515_1151x757.png 1272w, https://substackcdn.com/image/fetch/$s_!S3YS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e8f82f5-9fb3-40a0-9e50-f05e9fe86515_1151x757.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Configuraci&#243;n de los roles en el portal de Azure.</figcaption></figure></div><h3>Como acceder a un recurso en Azure utilizando una <em>Managed Identity</em> utilizando .NET</h3><p>Podemos hacer uso de las <em>Managed Identities</em> creadas en Azure a trav&#233;s de los diferentes SDKs disponibles.</p><p>Vamos a describir c&#243;mo podemos acceder a un <em>Azure Key Vault</em> utilizando c&#243;digo .NET y la librer&#237;a <a href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity">Azure.Identity</a>:</p><ol><li><p>Crea un proyecto .NET, en este caso hemos creado un proyecto tipo Web.</p></li><li><p>A&#241;ade la referencia a la librer&#237;a Azure.Identity <code>dotnet add package Azure.Identity</code>.</p></li></ol><p>Azure.Identity proporciona varias clases que encapsulan la l&#243;gica necesaria para poder obtener un token de autenticaci&#243;n de Microsoft Entra ID haciendo uso de la <em>Managed Identity</em> configurada:</p><p><em><strong>DefaultAzureCredential:</strong></em> Intenta realizar la autenticaci&#243;n a trav&#233;s de diferentes mecanismos hasta que consigue conectarse con uno de ellos.</p><pre><code><code>var credential = new DefaultAzureCredential();
var client = new SecretClient(new Uri("https://mykv.vault.azure.net/"), credential);</code></code></pre><p><em><strong>ChainedTokenCredential:</strong></em> Intenta realizar la autenticaci&#243;n a trav&#233;s de la <em>Managed Identity</em>. Si no lo consigue, intenta conectarse a trav&#233;s de Azure CLI</p><pre><code><code>var credential = new ChainedTokenCredential();
var client = new SecretClient(new Uri("https://mykv.vault.azure.net/"), credential);</code></code></pre><p><em><strong>ManagedIdentityCredential:</strong></em> Utiliza la <em>Managed Identity</em> para solicitar el token de autenticaci&#243;n</p><pre><code><code>var credential = new ManagedIdentityCredential();
var client = new SecretClient(new Uri("https://mykv.vault.azure.net/"), credential);</code></code></pre><p>El c&#243;digo final de nuestro API controlador es el siguiente:</p><pre><code><code> [ApiController]
 [Route("[controller]")]
 public class SecretController : ControllerBase
 {
     private readonly ILogger&lt;SecretController&gt; _logger;
     private readonly IConfiguration _config;

     public SecretController(ILogger&lt;SecretController&gt; logger, IConfiguration config)
     {
         _logger = logger;
         _config = config;
     }

     [HttpGet(Name = "GetSecret")]
     public IActionResult Get(string name, string credentialType = "DefaultAzureCredential")
     {
         var kvName = _config["KV_NAME"];
         _logger.LogInformation($"C# HTTP trigger function processed a request. {name} {credentialType} {kvName}");

         var tokenCredential = GetTokenCredential(credentialType);
         var client = new SecretClient(new Uri($"https://{kvName}.vault.azure.net/"), tokenCredential);

         return new OkObjectResult(client.GetSecret(name));
     }

     private TokenCredential GetTokenCredential(string credentialType)
     {
         switch (credentialType)
         {
             case "DefaultAzureCredential":
                 return new DefaultAzureCredential();
             case "ChainedTokenCredential":
                 return new ChainedTokenCredential();
             case "ManagedIdentityCredential":
                 return new ManagedIdentityCredential();
         }

         throw new Exception($"The credential type {credentialType} is not valid");
     }
 }</code></code></pre><h3>Como configurar <em>Managed Identity</em> en el cluster</h3><p>Para configurar la <em>Managed Identity</em> en el cluster es necesario crear y asignar una <a href="https://kubernetes.io/docs/concepts/security/service-accounts/">Service Account (SA)</a> a nuestra aplicaci&#243;n.</p><p>Utilizando las anotaciones <code>azure.workload.identity/client-id</code> y <code>azure.workload.identity/tenant-id</code> podemos configurar la <em>Managed Identity</em> creada previamente y que utilizaremos con nuestra aplicaci&#243;n. A continuaci&#243;n puedes ver un ejemplo:</p><pre><code><code>apiVersion: v1
kind: ServiceAccount
metadata:
  name: sa-app-1
  namespace: develop
  annotations:
    azure.workload.identity/client-id: "3d49c3ea-369c-4af2-b770-3a5de4d0aca2"
    azure.workload.identity/tenant-id: "xxxxxx-xxx-x-x-x"</code></code></pre><p>Adem&#225;s es necesario a&#241;adir la etiqueta <code>azure.workload.identity/use</code> a los pods de nuestra aplicaci&#243;n para indicarle a <em>Azure AD Workload Identity</em> que debe crear un token de autenticaci&#243;n en el POD utilizando los datos de configuraci&#243;n proporcionados en la Service Account (SA).</p><p>A continuaci&#243;n puedes encontrar el c&#243;digo yaml necesario para desplegar la aplicaci&#243;n en el cluster kubernetes haciendo uso de una <em>Managed Identity</em> creada previamente:</p><pre><code><code>apiVersion: v1
kind: Namespace
metadata:
  name: develop
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: sa-app-1
  namespace: develop
  annotations:
    azure.workload.identity/client-id: "3d49c3ea-369c-4af2-b770-3a5de4d0aca2"
    azure.workload.identity/tenant-id: "xxxxxx-xxx-x-x-x"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: myapp
  name: myapp
  namespace: develop
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myapp
  strategy: {}
  template:
    metadata:
      labels:
        app: myapp
        azure.workload.identity/use: "true"
    spec:
      serviceAccountName: sa-app-1
      containers:
        - image: acrqi99.azurecr.io/app:1.0.0
          name: app
          ports:
            - containerPort: 8080
          env:
            - name: KV_NAME
              value: kv-qi99
          resources: {}</code></code></pre><p>Una vez desplegada la aplicaci&#243;n podemos comprobar como <em>Azure AD Workload Identity</em> ha modificado la configuraci&#243;n del POD para que la aplicaci&#243;n pueda acceder a los servicios desplegados en Azure haciendo uso de la <em>Managed Identity</em> configurada:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-Dp3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc794d760-9d62-441e-9bec-317a95dbc046_1278x633.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-Dp3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc794d760-9d62-441e-9bec-317a95dbc046_1278x633.png 424w, https://substackcdn.com/image/fetch/$s_!-Dp3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc794d760-9d62-441e-9bec-317a95dbc046_1278x633.png 848w, https://substackcdn.com/image/fetch/$s_!-Dp3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc794d760-9d62-441e-9bec-317a95dbc046_1278x633.png 1272w, https://substackcdn.com/image/fetch/$s_!-Dp3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc794d760-9d62-441e-9bec-317a95dbc046_1278x633.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-Dp3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc794d760-9d62-441e-9bec-317a95dbc046_1278x633.png" width="1278" height="633" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c794d760-9d62-441e-9bec-317a95dbc046_1278x633.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:633,&quot;width&quot;:1278,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;POD valores inyectados por <em>Azure AD Workload Identity</em>&quot;,&quot;title&quot;:&quot;Resultado contenido secreto&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="POD valores inyectados por <em>Azure AD Workload Identity</em>" title="Resultado contenido secreto" srcset="https://substackcdn.com/image/fetch/$s_!-Dp3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc794d760-9d62-441e-9bec-317a95dbc046_1278x633.png 424w, https://substackcdn.com/image/fetch/$s_!-Dp3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc794d760-9d62-441e-9bec-317a95dbc046_1278x633.png 848w, https://substackcdn.com/image/fetch/$s_!-Dp3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc794d760-9d62-441e-9bec-317a95dbc046_1278x633.png 1272w, https://substackcdn.com/image/fetch/$s_!-Dp3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc794d760-9d62-441e-9bec-317a95dbc046_1278x633.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Variables de entorno configuradas en el POD autom&#225;ticamente por Azure AD Workload Identity.</figcaption></figure></div><p>Realizando una llamada GET para consultar la informaci&#243;n del secreto <code>secret-sauce</code>, podemos comprobar que la <em>Managed Identity</em> ha sido configurada correctamente:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fyzm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c9bda9a-0de0-4947-b0ef-f0a8fc3a0221_1675x613.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fyzm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c9bda9a-0de0-4947-b0ef-f0a8fc3a0221_1675x613.png 424w, https://substackcdn.com/image/fetch/$s_!fyzm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c9bda9a-0de0-4947-b0ef-f0a8fc3a0221_1675x613.png 848w, https://substackcdn.com/image/fetch/$s_!fyzm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c9bda9a-0de0-4947-b0ef-f0a8fc3a0221_1675x613.png 1272w, https://substackcdn.com/image/fetch/$s_!fyzm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c9bda9a-0de0-4947-b0ef-f0a8fc3a0221_1675x613.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fyzm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c9bda9a-0de0-4947-b0ef-f0a8fc3a0221_1675x613.png" width="1456" height="533" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8c9bda9a-0de0-4947-b0ef-f0a8fc3a0221_1675x613.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:533,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Resultado contenido secreto&quot;,&quot;title&quot;:&quot;Resultado contenido secreto&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Resultado contenido secreto" title="Resultado contenido secreto" srcset="https://substackcdn.com/image/fetch/$s_!fyzm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c9bda9a-0de0-4947-b0ef-f0a8fc3a0221_1675x613.png 424w, https://substackcdn.com/image/fetch/$s_!fyzm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c9bda9a-0de0-4947-b0ef-f0a8fc3a0221_1675x613.png 848w, https://substackcdn.com/image/fetch/$s_!fyzm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c9bda9a-0de0-4947-b0ef-f0a8fc3a0221_1675x613.png 1272w, https://substackcdn.com/image/fetch/$s_!fyzm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c9bda9a-0de0-4947-b0ef-f0a8fc3a0221_1675x613.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Resultado ejecuci&#243;n test.</figcaption></figure></div><h2>Conclusi&#243;n</h2><p>La implementaci&#243;n de <em>Azure Managed Identities</em> junto con <em>Azure Federated Identity Credentials</em> y <em>Azure AD Workload Identity</em> proporciona una soluci&#243;n robusta y segura para gestionar el acceso a servicios de Azure a aplicaciones que se ejecutan en un cluster de Kubernetes.</p><p>Esta soluci&#243;n elimina la necesidad de gestionar credenciales manualmente, reduciendo significativamente los riesgos de seguridad asociados con el manejo de secretos y certificados.</p><p>Las ventajas principales de esta soluci&#243;n son:</p><ul><li><p>Eliminar la gesti&#243;n manual de credenciales.</p></li><li><p>Mayor seguridad al no almacenar secretos en el c&#243;digo o en el cluster.</p></li><li><p>Escalabilidad para m&#250;ltiples aplicaciones y servicios.</p></li><li><p>Compatibilidad con m&#250;ltiples entornos y proveedores de Kubernetes.</p></li></ul><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/azure-ad-workload-identity?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">&#161;Te <strong>AGRADEZCO</strong> enormemente que hayas dedicado tu valioso tiempo a leer lo que escribo! Si te ha gustado y crees que puede ayudar a otras personas, <strong>puedes compartirlo</strong>.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/azure-ad-workload-identity?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.javivela.dev/p/azure-ad-workload-identity?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Compartir</span></a></p></div><h2>Referencias</h2><ul><li><p><a href="https://azure.github.io/azure-workload-identity/docs/">https://azure.github.io/azure-workload-identity/docs/</a></p></li><li><p><a href="https://learn.microsoft.com/en-us/azure/aks/aks/use-oidc-issuer">https://learn.microsoft.com/en-us/azure/aks/aks/use-oidc-issuer</a></p></li><li><p><a href="https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html">https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html</a></p></li><li><p><a href="https://cloud.google.com/kubernetes-engine/enterprise/identity/setup/per-cluster">https://cloud.google.com/kubernetes-engine/enterprise/identity/setup/per-cluster</a></p></li></ul>]]></content:encoded></item><item><title><![CDATA[Azure Federated Identity Credentials]]></title><description><![CDATA[Las federated identity credentials nos van a permitir autenticar aplicaciones y servicios externos sin necesidad de gestionar secretos o certificados.]]></description><link>https://www.javivela.dev/p/azure-federated-identity-credentials</link><guid isPermaLink="false">https://www.javivela.dev/p/azure-federated-identity-credentials</guid><dc:creator><![CDATA[Javi Vela]]></dc:creator><pubDate>Sat, 12 Oct 2024 06:00:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!cW3I!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cd7583e-2ebd-48dd-8922-63669230acfa_1123x421.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Puedes encontrar el c&#243;digo fuente del post en el siguiente enlace: <a href="https://github.com/fjvela/blog-demo-federated-identity-credential">https://github.com/fjvela/blog-demo-federated-identity-credential</a></p></blockquote><h2>Introducci&#243;n</h2><p>En el post <a href="https://blog.javivela.dev/p/azure-managed-identities">Azure Managed Identities</a> revisamos c&#243;mo funcionan y c&#243;mo podemos utilizar <em>Managed Identities</em>. Estas nos permiten autenticarnos contra servicios de Azure u otras aplicaciones desplegadas en Azure sin necesidad de gestionar secretos y/o certificados.</p><p>Existen otros escenarios donde las aplicaciones o servicios desplegados fuera de Azure necesitan acceder a recursos desplegados en Azure.</p><p>Rotar y/o guardar secretos o certificados puede ser tedioso, adem&#225;s supone un riesgo para la seguridad ya que cualquiera que disponga de esta informaci&#243;n podr&#237;a acceder a estos servicios.</p><p>Las <em>federated identity credentials</em> nos van a permitir autenticar aplicaciones y servicios externos sin necesidad de gestionar secretos o certificados.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/subscribe?&quot;,&quot;text&quot;:&quot;Suscribirse&quot;,&quot;language&quot;:&quot;es&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">&#161;<strong>GRACIAS</strong> por dedicar unos minutos tan valiosos a leer los art&#237;culos que escribo! <strong>Suscr&#237;bete</strong> para no perderte ninguna novedad y tener toda la informaci&#243;n directamente en tu email.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Escribe tu correo electr&#243;nico..." tabindex="-1"><input type="submit" class="button primary" value="Suscribirse"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>&#191;C&#243;mo funciona?</h2><p>Una <em>federated identity credential</em> permite establecer una relaci&#243;n de confianza entre una <em><strong>User managed identity</strong></em> y un proveedor de identidad externo (<em>external identity provider IdP</em>).</p><p>Esta relaci&#243;n va a permitir a Microsoft Identity autenticar a una aplicaci&#243;n externa a trav&#233;s del token recibido y el IdP configurado, generando a su vez otro token que permitir&#225; a la aplicaci&#243;n acceder a los recursos desplegados en Azure.</p><p>Una vez creada la <em>user managed identity</em>, podemos configurar hasta un m&#225;ximo de 20 <em>federated identity credentials</em>.</p><p>La informaci&#243;n necesaria es la siguiente:</p><ul><li><p><strong>issuer</strong>: Direcci&#243;n URL del proveedor de identidades externo (IdP).</p></li><li><p><strong>subject</strong>: Es el identificador de la aplicaci&#243;n externa, el formato depende del proveedor de identidad externo (IdP).</p></li><li><p><strong>audiences</strong>: Indica qu&#233; plataforma de identidad de Microsoft debe aceptar el token entrante (por defecto: api://AzureADTokenExchange - el valor depende del entorno cloud utilizado - Fairfax, Mooncake, USNat o USSec).</p></li></ul><p>La combinaci&#243;n de issuer y subject debe ser &#250;nica en la <em>user managed identity</em>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cW3I!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cd7583e-2ebd-48dd-8922-63669230acfa_1123x421.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cW3I!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cd7583e-2ebd-48dd-8922-63669230acfa_1123x421.png 424w, https://substackcdn.com/image/fetch/$s_!cW3I!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cd7583e-2ebd-48dd-8922-63669230acfa_1123x421.png 848w, https://substackcdn.com/image/fetch/$s_!cW3I!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cd7583e-2ebd-48dd-8922-63669230acfa_1123x421.png 1272w, https://substackcdn.com/image/fetch/$s_!cW3I!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cd7583e-2ebd-48dd-8922-63669230acfa_1123x421.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cW3I!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cd7583e-2ebd-48dd-8922-63669230acfa_1123x421.png" width="1123" height="421" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5cd7583e-2ebd-48dd-8922-63669230acfa_1123x421.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:421,&quot;width&quot;:1123,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Diagrama de funcionamiento federated  identity credential&quot;,&quot;title&quot;:&quot;Diagrama de funcionamiento federated identity credential&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Diagrama de funcionamiento federated  identity credential" title="Diagrama de funcionamiento federated identity credential" srcset="https://substackcdn.com/image/fetch/$s_!cW3I!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cd7583e-2ebd-48dd-8922-63669230acfa_1123x421.png 424w, https://substackcdn.com/image/fetch/$s_!cW3I!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cd7583e-2ebd-48dd-8922-63669230acfa_1123x421.png 848w, https://substackcdn.com/image/fetch/$s_!cW3I!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cd7583e-2ebd-48dd-8922-63669230acfa_1123x421.png 1272w, https://substackcdn.com/image/fetch/$s_!cW3I!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cd7583e-2ebd-48dd-8922-63669230acfa_1123x421.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Diagrama funcionamiento <em>federated identity credential.</em></figcaption></figure></div><ol><li><p>La aplicaci&#243;n solicita un token a su proveedor de identidades.</p></li><li><p>La aplicaci&#243;n solicita un token a Microsoft identity platform, utilizando el token generado en el paso 1.</p></li><li><p>Microsoft identity platform valida el token incluido en la petici&#243;n contra el servicio de validaci&#243;n definido externo registrado. Si el token es v&#225;lido, se genera un token de autenticaci&#243;n para autenticarse contra otros servicios desplegados en Azure (hay que asignar los permisos necesarios en el servicio).</p></li><li><p>La aplicaci&#243;n utiliza el token generado para acceder a los recursos desplegados en Azure.</p></li></ol><h2>Configurar federated identity credentials (GitHub)</h2><p>A continuaci&#243;n, vamos a configurar una <em>federated identity credential</em> para permitir que un GitHub workflow pueda acceder a recursos desplegados en Azure.</p><p>Desde el men&#250; &#8220;Managed Identities&#8221; podemos crear una <em>User Managed Identity</em>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zez6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F639c473f-496b-469e-88ed-e9e4132d34e6_766x501.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zez6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F639c473f-496b-469e-88ed-e9e4132d34e6_766x501.png 424w, https://substackcdn.com/image/fetch/$s_!zez6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F639c473f-496b-469e-88ed-e9e4132d34e6_766x501.png 848w, https://substackcdn.com/image/fetch/$s_!zez6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F639c473f-496b-469e-88ed-e9e4132d34e6_766x501.png 1272w, https://substackcdn.com/image/fetch/$s_!zez6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F639c473f-496b-469e-88ed-e9e4132d34e6_766x501.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zez6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F639c473f-496b-469e-88ed-e9e4132d34e6_766x501.png" width="766" height="501" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/639c473f-496b-469e-88ed-e9e4132d34e6_766x501.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:501,&quot;width&quot;:766,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;C&#243;mo crear una User Managed Identity&quot;,&quot;title&quot;:&quot;C&#243;mo crear una User Managed Identity&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="C&#243;mo crear una User Managed Identity" title="C&#243;mo crear una User Managed Identity" srcset="https://substackcdn.com/image/fetch/$s_!zez6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F639c473f-496b-469e-88ed-e9e4132d34e6_766x501.png 424w, https://substackcdn.com/image/fetch/$s_!zez6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F639c473f-496b-469e-88ed-e9e4132d34e6_766x501.png 848w, https://substackcdn.com/image/fetch/$s_!zez6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F639c473f-496b-469e-88ed-e9e4132d34e6_766x501.png 1272w, https://substackcdn.com/image/fetch/$s_!zez6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F639c473f-496b-469e-88ed-e9e4132d34e6_766x501.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Creaci&#243;n de una user managed identity en el portal de Azure.</figcaption></figure></div><p>Una vez creada, a&#241;adimos una <em>federated identity credential</em>:</p><ol><li><p>Azure nos da la opci&#243;n de configuraci&#243;n para diferentes escenarios, en nuestro caso seleccionamos la opci&#243;n para configurar GitHub.</p></li><li><p>Completamos la informaci&#243;n de la organizaci&#243;n, repositorio y entidad (entity). En nuestro caso seleccionamos la entidad &#8220;branch&#8221; e introducimos el nombre del branch que estar&#225; autorizado a utilizar los recursos de Azure.</p><ul><li><p>No se pueden utilizar <em>wildcards (*)</em>.</p></li><li><p>Si necesitamos dar permisos a otros branches, debemos a&#241;adir cada uno de ellos.</p></li></ul></li></ol><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IXHc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90472354-6695-4bf3-9c79-fb8594d2c5dd_697x619.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IXHc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90472354-6695-4bf3-9c79-fb8594d2c5dd_697x619.png 424w, https://substackcdn.com/image/fetch/$s_!IXHc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90472354-6695-4bf3-9c79-fb8594d2c5dd_697x619.png 848w, https://substackcdn.com/image/fetch/$s_!IXHc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90472354-6695-4bf3-9c79-fb8594d2c5dd_697x619.png 1272w, https://substackcdn.com/image/fetch/$s_!IXHc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90472354-6695-4bf3-9c79-fb8594d2c5dd_697x619.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IXHc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90472354-6695-4bf3-9c79-fb8594d2c5dd_697x619.png" width="697" height="619" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/90472354-6695-4bf3-9c79-fb8594d2c5dd_697x619.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:619,&quot;width&quot;:697,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;C&#243;mo configurar GitHub federated identity credential&quot;,&quot;title&quot;:&quot;C&#243;mo configurar GitHub federated identity credential&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="C&#243;mo configurar GitHub federated identity credential" title="C&#243;mo configurar GitHub federated identity credential" srcset="https://substackcdn.com/image/fetch/$s_!IXHc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90472354-6695-4bf3-9c79-fb8594d2c5dd_697x619.png 424w, https://substackcdn.com/image/fetch/$s_!IXHc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90472354-6695-4bf3-9c79-fb8594d2c5dd_697x619.png 848w, https://substackcdn.com/image/fetch/$s_!IXHc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90472354-6695-4bf3-9c79-fb8594d2c5dd_697x619.png 1272w, https://substackcdn.com/image/fetch/$s_!IXHc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90472354-6695-4bf3-9c79-fb8594d2c5dd_697x619.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Configuraci&#243;n de una <em>federated identity credential con GitHub en el portal de Azure.</em></figcaption></figure></div><blockquote><p>Una vez creada la user managed identity y configurados los federated identity credentials, debemos asignar los permisos correspondientes de acceso.</p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nEjW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5d97fd7-1cdc-4c8a-97e2-2b4cecffca9c_817x987.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nEjW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5d97fd7-1cdc-4c8a-97e2-2b4cecffca9c_817x987.png 424w, https://substackcdn.com/image/fetch/$s_!nEjW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5d97fd7-1cdc-4c8a-97e2-2b4cecffca9c_817x987.png 848w, https://substackcdn.com/image/fetch/$s_!nEjW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5d97fd7-1cdc-4c8a-97e2-2b4cecffca9c_817x987.png 1272w, https://substackcdn.com/image/fetch/$s_!nEjW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5d97fd7-1cdc-4c8a-97e2-2b4cecffca9c_817x987.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nEjW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5d97fd7-1cdc-4c8a-97e2-2b4cecffca9c_817x987.png" width="817" height="987" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b5d97fd7-1cdc-4c8a-97e2-2b4cecffca9c_817x987.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:987,&quot;width&quot;:817,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Asignar un rol a la user managed identity&quot;,&quot;title&quot;:&quot;Asignar un rol a la user managed identity&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Asignar un rol a la user managed identity" title="Asignar un rol a la user managed identity" srcset="https://substackcdn.com/image/fetch/$s_!nEjW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5d97fd7-1cdc-4c8a-97e2-2b4cecffca9c_817x987.png 424w, https://substackcdn.com/image/fetch/$s_!nEjW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5d97fd7-1cdc-4c8a-97e2-2b4cecffca9c_817x987.png 848w, https://substackcdn.com/image/fetch/$s_!nEjW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5d97fd7-1cdc-4c8a-97e2-2b4cecffca9c_817x987.png 1272w, https://substackcdn.com/image/fetch/$s_!nEjW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5d97fd7-1cdc-4c8a-97e2-2b4cecffca9c_817x987.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Configuraci&#243;n roles de la user manager identity en el portal de Azure.</figcaption></figure></div><h3>Crear GitHub workflow</h3><p>Para comprobar el correcto funcionamiento de la <em>federated identity credential</em> vamos a crear un GitHub workflow que realiza un login y mostrar&#225; la informaci&#243;n de la suscripci&#243;n de Azure.</p><p>Para ello vamos a utilizar el GitHub action <a href="https://github.com/Azure/login">Azure login</a>:</p><pre><code><code>name: Run Azure Login with OIDC
on: [push]

permissions:
  id-token: write
  contents: read

jobs:
  azure-login:
    runs-on: ubuntu-latest
    steps:
      - name: Azure login
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

      - name: Azure CLI script
        uses: azure/cli@v2
        with:
          azcliversion: latest
          inlineScript: |
            az account show</code></code></pre><p>Una vez que el contenido est&#225; en el repositorio, la GitHub action se ejecuta cada vez que se a&#241;ade algo al branch main:</p><h2>Conclusi&#243;n</h2><p>El uso de <em>federated identity credentials</em> representa un avance significativo en la administraci&#243;n de seguridad y autenticaci&#243;n para aplicaciones y servicios que interact&#250;an con recursos de Azure desde entornos externos.</p><p>Algunas de las ventajas de su uso son:</p><ul><li><p>Seguridad mejorada: No se necesita administrar ni almacenar secretos y certificados, lo que reduce en gran medida el riesgo de que se comprometan las credenciales.</p></li><li><p>Administraci&#243;n simplificada: La configuraci&#243;n de <em>federated identity credentials</em> es un proceso simple que reduce la carga administrativa asociada con la rotaci&#243;n y el mantenimiento de secretos.</p></li><li><p>Flexibilidad: Permite una integraci&#243;n perfecta con una variedad de proveedores de identidad externos y se adapta a diferentes arquitecturas y requisitos de seguridad.</p></li></ul><p>Para los desarrolladores y administradores de sistemas que utilizan Azure, la adopci&#243;n de esta tecnolog&#237;a puede mejorar significativamente la seguridad de las aplicaciones y al mismo tiempo simplificar el proceso de autenticaci&#243;n y autorizaci&#243;n.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/azure-federated-identity-credentials?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">&#161;Te <strong>AGRADEZCO</strong> enormemente que hayas dedicado tu valioso tiempo a leer lo que escribo! Si te ha gustado y crees que puede ayudar a otras personas, <strong>puedes compartirlo</strong>.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/azure-federated-identity-credentials?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.javivela.dev/p/azure-federated-identity-credentials?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Compartir</span></a></p></div><h2>Referencias</h2><ul><li><p><a href="https://learn.microsoft.com/en-gb/entra/identity/managed-identities-azure-resources/">https://learn.microsoft.com/en-gb/entra/identity/managed-identities-azure-resources/</a></p></li><li><p><a href="https://learn.microsoft.com/en-us/entra/workload-id/">https://learn.microsoft.com/en-us/entra/workload-id/</a></p></li><li><p><a href="https://learn.microsoft.com/en-us/azure/developer/github/connect-from-azure?tabs=azure-portal%2Cwindows#use-the-azure-login-action-with-openid-connect">https://learn.microsoft.com/en-us/azure/developer/github/connect-from-azure?tabs=azure-portal%2Cwindows#use-the-azure-login-action-with-openid-connect</a></p></li><li><p><a href="https://learn.microsoft.com/en-us/azure/architecture/patterns/federated-identity">https://learn.microsoft.com/en-us/azure/architecture/patterns/federated-identity</a></p></li><li><p><a href="https://github.com/Azure/login">https://github.com/Azure/login</a></p></li></ul><p></p>]]></content:encoded></item><item><title><![CDATA[Azure Managed Identities]]></title><description><![CDATA[Azure proporciona Managed Identities para simplificar la autenticaci&#243;n necesaria para acceder a los recursos desplegados en Azure como Azure Key Vault.]]></description><link>https://www.javivela.dev/p/azure-managed-identities</link><guid isPermaLink="false">https://www.javivela.dev/p/azure-managed-identities</guid><dc:creator><![CDATA[Javi Vela]]></dc:creator><pubDate>Thu, 03 Oct 2024 06:00:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!LWXm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F654410bc-ed16-4da0-97b4-23fbfabe0f0e_1370x529.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Puedes encontrar el c&#243;digo fuente del post en el siguiente enlace: <a href="https://github.com/fjvela/blog-managed-identities">https://github.com/fjvela/blog-managed-identities</a></p></blockquote><h2>Introducci&#243;n</h2><p>Uno de los grandes retos que tenemos hoy en d&#237;a es gestionar la informaci&#243;n sensible (credenciales, certificados, &#8230;) que nuestras aplicaciones necesitan.</p><p>Azure proporciona <em>Managed Identities</em> para simplificar la autenticaci&#243;n necesaria para acceder a los recursos desplegados en Azure como <em><strong>Azure Key Vault</strong></em>. Puedes comprobar la lista de servicios que soportan la autenticaci&#243;n a trav&#233;s de <em>Managed Identities</em> en el siguiente enlace: <a href="https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/managed-identities-status">https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/managed-identities-status</a></p><p>La utilizaci&#243;n de <em>Managed Identities</em> tiene algunas ventajas:</p><ul><li><p>No es necesario utilizar y/o gestionar credenciales</p></li><li><p>Permite autenticarnos con cualquier otra aplicaci&#243;n (incluyendo nuestras propias aplicaciones)</p></li><li><p>No tiene un coste extra</p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/subscribe?&quot;,&quot;text&quot;:&quot;Suscribirse&quot;,&quot;language&quot;:&quot;es&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">&#161;<strong>GRACIAS</strong> por dedicar unos minutos tan valiosos a leer los art&#237;culos que escribo! <strong>Suscr&#237;bete</strong> para no perderte ninguna novedad y tener toda la informaci&#243;n directamente en tu email.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Escribe tu correo electr&#243;nico..." tabindex="-1"><input type="submit" class="button primary" value="Suscribirse"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Tipos de Managed Identities</h2><p>Existen dos tipos de <em>Managed Identities</em>:</p><ul><li><p><em><strong>System managed identities</strong></em>: Son creadas autom&#225;ticamente por Azure cuando se crean algunos servicios como m&#225;quinas virtuales:</p><ul><li><p>Solo se puede utilizar por el servicio que la ha creado</p></li><li><p>Su ciclo de vida est&#225; asociado al ciclo de vida del recurso que lo ha creado (si borras el recurso, se borra la <em>Managed Identity</em>)</p></li><li><p>Autom&#225;ticamente se crea un Service Principal en <em>Microsoft Entra ID</em> (directorio activo)</p></li><li><p>Debemos autorizar a qu&#233; servicios pueden acceder a la <em>Managed Identity</em></p></li></ul></li><li><p><em><strong>User managed identities</strong></em>: Podemos crear un <em>Managed Identity</em> y asign&#225;rsela a m&#225;s de una aplicaci&#243;n:</p><ul><li><p>Podemos utilizarla en una o varias aplicaciones</p></li><li><p>Debemos autorizar a qu&#233; servicios pueden acceder las aplicaciones que usen la <em>Managed Identity</em> creada</p></li><li><p>Autom&#225;ticamente se crea un Service Principal en <em>Microsoft Entra ID</em> (directorio activo), su ciclo de vida no est&#225; asociado al ciclo de vida de la aplicaci&#243;n que lo utiliza</p></li></ul></li></ul><h2>&#191;C&#243;mo funciona?</h2><p>Antes de explicar como funciona el proceso de creaci&#243;n y funcionamiento de una <em>managed identity</em>, debemos conocer qu&#233; es <em>Azure Instance Metadata Service identity (IMDS)</em>:</p><ul><li><p>Es un servicio REST interno disponible en la direcci&#243;n IP: 169.254.169.254</p></li><li><p>Proporciona informaci&#243;n sobre las instancias de VM en ejecuci&#243;n: Sistema operativo, mantenimientos programados, &#8230;</p></li><li><p>Tambi&#233;n proporciona tokens de autenticaci&#243;n que obtiene de <em>Microsoft Entra ID</em></p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LWXm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F654410bc-ed16-4da0-97b4-23fbfabe0f0e_1370x529.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LWXm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F654410bc-ed16-4da0-97b4-23fbfabe0f0e_1370x529.png 424w, https://substackcdn.com/image/fetch/$s_!LWXm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F654410bc-ed16-4da0-97b4-23fbfabe0f0e_1370x529.png 848w, https://substackcdn.com/image/fetch/$s_!LWXm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F654410bc-ed16-4da0-97b4-23fbfabe0f0e_1370x529.png 1272w, https://substackcdn.com/image/fetch/$s_!LWXm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F654410bc-ed16-4da0-97b4-23fbfabe0f0e_1370x529.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LWXm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F654410bc-ed16-4da0-97b4-23fbfabe0f0e_1370x529.png" width="1370" height="529" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/654410bc-ed16-4da0-97b4-23fbfabe0f0e_1370x529.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:529,&quot;width&quot;:1370,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Diagrama funcionamiento managed identities&quot;,&quot;title&quot;:&quot;Diagrama funcionamiento managed identities&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Diagrama funcionamiento managed identities" title="Diagrama funcionamiento managed identities" srcset="https://substackcdn.com/image/fetch/$s_!LWXm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F654410bc-ed16-4da0-97b4-23fbfabe0f0e_1370x529.png 424w, https://substackcdn.com/image/fetch/$s_!LWXm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F654410bc-ed16-4da0-97b4-23fbfabe0f0e_1370x529.png 848w, https://substackcdn.com/image/fetch/$s_!LWXm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F654410bc-ed16-4da0-97b4-23fbfabe0f0e_1370x529.png 1272w, https://substackcdn.com/image/fetch/$s_!LWXm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F654410bc-ed16-4da0-97b4-23fbfabe0f0e_1370x529.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Diagrama  funcionamiento Azure Managed Identity</figcaption></figure></div><ol><li><p><em>Azure Resource Manager</em> crea un <em>service principal</em> en <em>Microsoft Entra ID</em> asociado a la <em>Managed Identity</em> creada</p></li><li><p>A continuaci&#243;n <em>Azure Resource Manager</em>, actualiza <em>Azure Instance Metadata Service identity (IMDS)</em> proporcionando el ID el service principal y los certificados creados por <em>Microsoft Entra ID</em>. M&#225;s tarde ser&#225;n necesarios para poder autenticarse contra <em>Microsoft Entra ID</em></p></li><li><p>En este paso, <em>Azure Resource Manager</em> habilita los permisos necesarios para acceder a otros recursos de Azure (Azure RBAC). Por ejemplo, asignar el rol <em>Key Vault Secrets User</em> para poder leer secretos de un <em>Azure Key Vault</em></p></li><li><p>Cuando nuestra aplicaci&#243;n necesita acceder al recurso, se comunica con el <em>IMDS</em>, el cual solicita un token de autenticaci&#243;n a Microsoft Entra ID (utilizando el service principal y certificados creados en el paso 2) que ser&#225; utilizado por la aplicaci&#243;n para poder acceder a otros recursos desplegados en Azure.</p></li></ol><h2>Habilitar una Managed Identity en Azure</h2><p>Como hemos comentado, exiten dos tipos de <em>Managed Identites</em>: <em><strong>System managed identities</strong></em> y <em><strong>User managed identities</strong></em>. Vamos a ver como crear y habilitarlas en Azure.</p><blockquote><p>Una vez creada la managed identity, debemos asignar los permisos correspondientes de acceso.</p></blockquote><h3>System Managed Identity</h3><p>Para crear un System Managed Identity asociado a un recurso de Azure tan solo debemos seleccionarlo desde el portal y en el menu &#8220;Identity&#8221;, habilitarlo y guardar los cambios realizados.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yVMm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5cd5c11-3ab7-4e6c-9428-dc5d96e27048_1345x521.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yVMm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5cd5c11-3ab7-4e6c-9428-dc5d96e27048_1345x521.png 424w, https://substackcdn.com/image/fetch/$s_!yVMm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5cd5c11-3ab7-4e6c-9428-dc5d96e27048_1345x521.png 848w, https://substackcdn.com/image/fetch/$s_!yVMm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5cd5c11-3ab7-4e6c-9428-dc5d96e27048_1345x521.png 1272w, https://substackcdn.com/image/fetch/$s_!yVMm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5cd5c11-3ab7-4e6c-9428-dc5d96e27048_1345x521.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yVMm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5cd5c11-3ab7-4e6c-9428-dc5d96e27048_1345x521.png" width="1345" height="521" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c5cd5c11-3ab7-4e6c-9428-dc5d96e27048_1345x521.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:521,&quot;width&quot;:1345,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;System Managed Identity en Azure Functions creada&quot;,&quot;title&quot;:&quot;System Managed Identity en Azure Functions creada&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="System Managed Identity en Azure Functions creada" title="System Managed Identity en Azure Functions creada" srcset="https://substackcdn.com/image/fetch/$s_!yVMm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5cd5c11-3ab7-4e6c-9428-dc5d96e27048_1345x521.png 424w, https://substackcdn.com/image/fetch/$s_!yVMm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5cd5c11-3ab7-4e6c-9428-dc5d96e27048_1345x521.png 848w, https://substackcdn.com/image/fetch/$s_!yVMm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5cd5c11-3ab7-4e6c-9428-dc5d96e27048_1345x521.png 1272w, https://substackcdn.com/image/fetch/$s_!yVMm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5cd5c11-3ab7-4e6c-9428-dc5d96e27048_1345x521.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Captura de pantalla donde se muestra una Azure Managed Identity de tipo System asociada a una Azure Function.</figcaption></figure></div><h3>User Managed Identity</h3><p>Desde el apartado &#8220;Managed Identities&#8221; podemos crear <em>User Managed Identites</em>, una vez completados los datos requeridos debemos asignar la <em>managed identity</em> al recurso o recursos que har&#225;n uso de ella.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yIhN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4688676-2a7e-44bf-a0ce-da5b2534f350_1350x484.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yIhN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4688676-2a7e-44bf-a0ce-da5b2534f350_1350x484.png 424w, https://substackcdn.com/image/fetch/$s_!yIhN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4688676-2a7e-44bf-a0ce-da5b2534f350_1350x484.png 848w, https://substackcdn.com/image/fetch/$s_!yIhN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4688676-2a7e-44bf-a0ce-da5b2534f350_1350x484.png 1272w, https://substackcdn.com/image/fetch/$s_!yIhN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4688676-2a7e-44bf-a0ce-da5b2534f350_1350x484.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yIhN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4688676-2a7e-44bf-a0ce-da5b2534f350_1350x484.png" width="1350" height="484" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f4688676-2a7e-44bf-a0ce-da5b2534f350_1350x484.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:484,&quot;width&quot;:1350,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;User Managed Identity asignada a una Azure Functions&quot;,&quot;title&quot;:&quot;User Managed Identity asignada a una Azure Functions&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="User Managed Identity asignada a una Azure Functions" title="User Managed Identity asignada a una Azure Functions" srcset="https://substackcdn.com/image/fetch/$s_!yIhN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4688676-2a7e-44bf-a0ce-da5b2534f350_1350x484.png 424w, https://substackcdn.com/image/fetch/$s_!yIhN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4688676-2a7e-44bf-a0ce-da5b2534f350_1350x484.png 848w, https://substackcdn.com/image/fetch/$s_!yIhN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4688676-2a7e-44bf-a0ce-da5b2534f350_1350x484.png 1272w, https://substackcdn.com/image/fetch/$s_!yIhN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4688676-2a7e-44bf-a0ce-da5b2534f350_1350x484.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Captura de pantalla donde se muestra una Azure Manager Identity de tipo User asociada a una Azure Function.</figcaption></figure></div><h2>Como acceder a un recurso en Azure utilizando una Managed Identity utilizando .NET</h2><p>Podemos hacer uso de las <em>Managed Identities</em> creadas en Azure a trav&#233;s de los diferentes SDKs disponibles o implementando el c&#243;digo necesario para poder interactuar con el API REST proporcionado por la IMDS y as&#237; obtener los tokens de autenticaci&#243;n para acceder a otros recursos de Azure.</p><p>Vamos a describir c&#243;mo podemos acceder a un <em>Azure Key Vault</em> utilizando c&#243;digo .NET y la librer&#237;a <a href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity">Azure.Identity</a>:</p><ol><li><p>Crea una proyecto .NET, en este caso hemos creado un proyecto tipo Azure Functions para facilitar su despliegue en Azure</p></li><li><p>A&#241;ade la referencia a la librer&#237;a Azure.Identity <code>dotnet add package Azure.Identity</code></p></li></ol><p>Azure.Identity proporciona varias clases que encapsulan la l&#243;gica necesaria para poder obtener un token de autenticaci&#243;n de Microsoft Entra ID haciendo uso de la <em>Managed Identity</em> configurada a trav&#233;s de la IMDS:</p><p><em><strong>DefaultAzureCredential:</strong></em> Intenta realizar la autenticaci&#243;n a trav&#233;s de diferentes mecanismos hasta que consigue conectarse con uno de ellos.</p><pre><code><code>var credential = new DefaultAzureCredential();
var client = new SecretClient(new Uri("https://mykv.vault.azure.net/"), credential);</code></code></pre><p><em><strong>ChainedTokenCredential:</strong></em> Intenta realizar la autenticaci&#243;n a trav&#233;s de la <em>Managed Identity</em>. Si no lo consigue, intenta conectarse utilizando a trav&#233;s de Azure CLI</p><pre><code><code>var credential = new ChainedTokenCredential();
var client = new SecretClient(new Uri("https://mykv.vault.azure.net/"), credential);</code></code></pre><p><em><strong>ManagedIdentityCredential:</strong></em> Utiliza la <em>Managed Identity</em> para solicitar el token de autenticaci&#243;n</p><pre><code><code>var credential = new ManagedIdentityCredential();
var client = new SecretClient(new Uri("https://mykv.vault.azure.net/"), credential);</code></code></pre><p>El c&#243;digo final de nuestra Azure Function es el siguiente:</p><pre><code><code>  [Function("GetSecret")]
  public IActionResult GetSecret([HttpTrigger(AuthorizationLevel.Function, "get")] HttpRequest req, 
      [FromQuery] string name,
      [FromQuery] string credentialType)
  {
      _logger.LogInformation("C# HTTP trigger function processed a request.");
      var kvName = _config["KV_NAME"];

      var tokenCredential = GetTokenCredential(credentialType);
      var client = new SecretClient(new Uri($"https://{kvName}.vault.azure.net/"), tokenCredential);

      return new OkObjectResult(client.GetSecret(name));
  }

  private TokenCredential GetTokenCredential(string credentialType)
  {
      switch (credentialType) {
          case "DefaultAzureCredential":
              return new DefaultAzureCredential();
          case "ChainedTokenCredential":
              return new ChainedTokenCredential();
          case "ManagedIdentityCredential":
              return new ManagedIdentityCredential();
      }

      throw new Exception($"The credential type {credentialType} is not valid");
  }</code></code></pre><p>A continuaci&#243;n podemos ver el resultado de la ejecuci&#243;n de la Azure Function desde local y desde Azure:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4EdX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45775381-a42f-47e1-99c0-2adb979209f6_990x485.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4EdX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45775381-a42f-47e1-99c0-2adb979209f6_990x485.png 424w, https://substackcdn.com/image/fetch/$s_!4EdX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45775381-a42f-47e1-99c0-2adb979209f6_990x485.png 848w, https://substackcdn.com/image/fetch/$s_!4EdX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45775381-a42f-47e1-99c0-2adb979209f6_990x485.png 1272w, https://substackcdn.com/image/fetch/$s_!4EdX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45775381-a42f-47e1-99c0-2adb979209f6_990x485.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4EdX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45775381-a42f-47e1-99c0-2adb979209f6_990x485.png" width="990" height="485" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/45775381-a42f-47e1-99c0-2adb979209f6_990x485.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:485,&quot;width&quot;:990,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Resultado ejecuci&#243;n Azure Function desde Azure&quot;,&quot;title&quot;:&quot;Resultado ejecuci&#243;n Azure Function desde Azure&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Resultado ejecuci&#243;n Azure Function desde Azure" title="Resultado ejecuci&#243;n Azure Function desde Azure" srcset="https://substackcdn.com/image/fetch/$s_!4EdX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45775381-a42f-47e1-99c0-2adb979209f6_990x485.png 424w, https://substackcdn.com/image/fetch/$s_!4EdX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45775381-a42f-47e1-99c0-2adb979209f6_990x485.png 848w, https://substackcdn.com/image/fetch/$s_!4EdX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45775381-a42f-47e1-99c0-2adb979209f6_990x485.png 1272w, https://substackcdn.com/image/fetch/$s_!4EdX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45775381-a42f-47e1-99c0-2adb979209f6_990x485.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Resultado ejecuci&#243;n aplicaci&#243;n: muestra los datos almacenados de un secreto en un Azure Key Vault</figcaption></figure></div><h2>Conclusi&#243;n</h2><p>La utilizaci&#243;n de <em>Managed Identities</em> no solo simplifica la gesti&#243;n de credenciales, sino que tambi&#233;n mejora significativamente la seguridad de las aplicaciones, al eliminar la necesidad de configurar y guardar secretos en archivos de configuraci&#243;n.</p><p>Para los desarrolladores y arquitectos, utilizar <em>Managed Identities</em> deber&#237;a ser una pr&#225;ctica est&#225;ndar en la mayor&#237;a de los escenarios.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/azure-managed-identities?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">&#161;Te <strong>AGRADEZCO</strong> enormemente que hayas dedicado tu valioso tiempo a leer lo que escribo! Si te ha gustado y crees que puede ayudar a otras personas, <strong>puedes compartirlo</strong>.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/azure-managed-identities?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.javivela.dev/p/azure-managed-identities?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Compartir</span></a></p></div><h2>Referencias</h2><ul><li><p><a href="https://learn.microsoft.com/en-us/training/modules/implement-managed-identities/5-acquire-access-token">https://learn.microsoft.com/en-us/training/modules/implement-managed-identities/5-acquire-access-token</a></p></li><li><p><a href="https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview">https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview</a></p></li><li><p><a href="https://learn.microsoft.com/en-us/entra/identity-platform/how-applications-are-added">https://learn.microsoft.com/en-us/entra/identity-platform/how-applications-are-added</a></p></li><li><p><a href="https://learn.microsoft.com/en-us/azure/postgresql/single-server/how-to-connect-with-managed-identity">https://learn.microsoft.com/en-us/azure/postgresql/single-server/how-to-connect-with-managed-identity</a></p></li><li><p><a href="https://learn.microsoft.com/en-us/dotnet/api/overview/azure/identity-readme">https://learn.microsoft.com/en-us/dotnet/api/overview/azure/identity-readme</a></p></li><li><p><a href="https://learn.microsoft.com/es-es/azure/virtual-machines/instance-metadata-service">https://learn.microsoft.com/es-es/azure/virtual-machines/instance-metadata-service</a></p></li></ul>]]></content:encoded></item><item><title><![CDATA[Novedades en C# 13 (.NET 9 preview 6)]]></title><description><![CDATA[Conoce las alguna de las novedades incluidas en C# 13:&#160; params collectionsNew lock type and semantics, New escape sequence - \e, Implicit indexer access in object initializers y ref struct]]></description><link>https://www.javivela.dev/p/novedades-en-c-13-net-9-preview-6</link><guid isPermaLink="false">https://www.javivela.dev/p/novedades-en-c-13-net-9-preview-6</guid><dc:creator><![CDATA[Javi Vela]]></dc:creator><pubDate>Thu, 15 Aug 2024 06:00:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!nz0c!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83b3cfe0-db27-4ddc-9743-32fcbef0a122_583x307.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Ya va quedando menos para el lanzamiento de .NET 9 y tenemos disposibles algunas de las novedades que incluir&#225; C# 13 en su lanzamiento A continuaci&#243;n revisamos algunas de ellas.</p><p>Puedes encontrar el c&#243;digo fuente de los ejemplos en repositorio: <a href="https://github.com/fjvela/csharp-13">https://github.com/fjvela/csharp-13</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/subscribe?&quot;,&quot;text&quot;:&quot;Suscribirse&quot;,&quot;language&quot;:&quot;es&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">&#161;<strong>GRACIAS</strong> por dedicar unos minutos tan valiosos a leer los art&#237;culos que escribo! Suscr&#237;bete para no perderte ninguna novedad y tener toda la informaci&#243;n directamente en tu email.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Escribe tu correo electr&#243;nico..." tabindex="-1"><input type="submit" class="button primary" value="Suscribirse"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>params collections</h2><p>El modificador <code>params</code> nos permite pasar un n&#250;mero variable de argumentos a un m&#233;todo. Hasta el momento estaba limitado unicamente al uso con tipos de datos <em>Array</em>.</p><pre><code><code>var persons = new List&lt;Person&gt;
{
   new Person("Mads", "Torgersen"),
   new Person("Dustin", "Campbell"),
   new Person("Kathleen", "Dollard")
};

static void WriteNames(params string[] names)
 =&gt; Console.WriteLine(String.Join(", ", names));

WriteNames(persons.Select(person =&gt; person.FirstName).ToArray());

internal class Person( string Name, string FirstName)
{
    public string Name { get; set; }
    public string FirstName { get; set; }
}</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nz0c!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83b3cfe0-db27-4ddc-9743-32fcbef0a122_583x307.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nz0c!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83b3cfe0-db27-4ddc-9743-32fcbef0a122_583x307.png 424w, https://substackcdn.com/image/fetch/$s_!nz0c!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83b3cfe0-db27-4ddc-9743-32fcbef0a122_583x307.png 848w, https://substackcdn.com/image/fetch/$s_!nz0c!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83b3cfe0-db27-4ddc-9743-32fcbef0a122_583x307.png 1272w, https://substackcdn.com/image/fetch/$s_!nz0c!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83b3cfe0-db27-4ddc-9743-32fcbef0a122_583x307.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nz0c!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83b3cfe0-db27-4ddc-9743-32fcbef0a122_583x307.png" width="583" height="307" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/83b3cfe0-db27-4ddc-9743-32fcbef0a122_583x307.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:307,&quot;width&quot;:583,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Resultado binario decompilado, params collections&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Resultado binario decompilado, params collections" title="Resultado binario decompilado, params collections" srcset="https://substackcdn.com/image/fetch/$s_!nz0c!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83b3cfe0-db27-4ddc-9743-32fcbef0a122_583x307.png 424w, https://substackcdn.com/image/fetch/$s_!nz0c!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83b3cfe0-db27-4ddc-9743-32fcbef0a122_583x307.png 848w, https://substackcdn.com/image/fetch/$s_!nz0c!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83b3cfe0-db27-4ddc-9743-32fcbef0a122_583x307.png 1272w, https://substackcdn.com/image/fetch/$s_!nz0c!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83b3cfe0-db27-4ddc-9743-32fcbef0a122_583x307.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Resultado binario decompilado, params collections</figcaption></figure></div><p>C# 13 extiende el modificador permitiendonos trabajar con cualquier tipo de colecci&#243;n, tales como: <code>System.Span&lt;T&gt;_, _System.ReadOnlySpan&lt;T&gt;</code>, y tipos de datos que implementan la interfaz <code>System.Collections.Generic.IEnumerable&lt;T&gt;</code>.</p><pre><code><code>static void WriteNames(params IEnumerable&lt;string&gt; names)
  =&gt; Console.WriteLine(String.Join(", ", names));

WriteNames(persons.Select(person =&gt; person.FirstName));
WriteNames(from p in persons select p.FirstName);</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4KCq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b8b6475-5f0d-4a92-bfcb-c2888c081f17_557x363.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4KCq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b8b6475-5f0d-4a92-bfcb-c2888c081f17_557x363.png 424w, https://substackcdn.com/image/fetch/$s_!4KCq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b8b6475-5f0d-4a92-bfcb-c2888c081f17_557x363.png 848w, https://substackcdn.com/image/fetch/$s_!4KCq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b8b6475-5f0d-4a92-bfcb-c2888c081f17_557x363.png 1272w, https://substackcdn.com/image/fetch/$s_!4KCq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b8b6475-5f0d-4a92-bfcb-c2888c081f17_557x363.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4KCq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b8b6475-5f0d-4a92-bfcb-c2888c081f17_557x363.png" width="557" height="363" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5b8b6475-5f0d-4a92-bfcb-c2888c081f17_557x363.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:363,&quot;width&quot;:557,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Resultado binario decompilado, params collections&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Resultado binario decompilado, params collections" title="Resultado binario decompilado, params collections" srcset="https://substackcdn.com/image/fetch/$s_!4KCq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b8b6475-5f0d-4a92-bfcb-c2888c081f17_557x363.png 424w, https://substackcdn.com/image/fetch/$s_!4KCq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b8b6475-5f0d-4a92-bfcb-c2888c081f17_557x363.png 848w, https://substackcdn.com/image/fetch/$s_!4KCq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b8b6475-5f0d-4a92-bfcb-c2888c081f17_557x363.png 1272w, https://substackcdn.com/image/fetch/$s_!4KCq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b8b6475-5f0d-4a92-bfcb-c2888c081f17_557x363.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Resultado binario decompilado, params collections</figcaption></figure></div><h2>New lock type and semantics</h2><p>.NET 9 permitir&#225; bloquear el acceso a recursos compartidos se pueda realizar de una manera m&#225;s simple, eficiente y menos ambigua a trav&#233;s de la clase <code>System.Threading.Lock</code>.</p><p>Para poder usar esta nueva clase en nuestras aplicaciones existentes, solo tendremos que sustituir <code>private object myLock = new object();</code> por <code>private System.Threading.Lock myLock = new System.Threading.Lock();</code>. C# autom&#225;ticamente generar&#225; las llamadas necesarias a la API para usar la nueva clase.</p><pre><code><code>public class ClassLockTwo
{
    private System.Threading.Lock myLock = new System.Threading.Lock();

    public void MyMethod()
    {
        lock (myLock)
        {
            // Your code
        }
    }
}</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7CGY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbef56d3-bfba-4329-9ff3-8137bb26bd28_583x307.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7CGY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbef56d3-bfba-4329-9ff3-8137bb26bd28_583x307.png 424w, https://substackcdn.com/image/fetch/$s_!7CGY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbef56d3-bfba-4329-9ff3-8137bb26bd28_583x307.png 848w, https://substackcdn.com/image/fetch/$s_!7CGY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbef56d3-bfba-4329-9ff3-8137bb26bd28_583x307.png 1272w, https://substackcdn.com/image/fetch/$s_!7CGY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbef56d3-bfba-4329-9ff3-8137bb26bd28_583x307.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7CGY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbef56d3-bfba-4329-9ff3-8137bb26bd28_583x307.png" width="583" height="307" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cbef56d3-bfba-4329-9ff3-8137bb26bd28_583x307.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:307,&quot;width&quot;:583,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Resultado binario decompilado, lock&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Resultado binario decompilado, lock" title="Resultado binario decompilado, lock" srcset="https://substackcdn.com/image/fetch/$s_!7CGY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbef56d3-bfba-4329-9ff3-8137bb26bd28_583x307.png 424w, https://substackcdn.com/image/fetch/$s_!7CGY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbef56d3-bfba-4329-9ff3-8137bb26bd28_583x307.png 848w, https://substackcdn.com/image/fetch/$s_!7CGY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbef56d3-bfba-4329-9ff3-8137bb26bd28_583x307.png 1272w, https://substackcdn.com/image/fetch/$s_!7CGY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbef56d3-bfba-4329-9ff3-8137bb26bd28_583x307.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Resultado binario decompilado, lock</figcaption></figure></div><h2>New escape sequence - \e.</h2><p>C# 13 introduce la secuencia de espace <code>\e</code>. Esta secuencia equivale al c&#243;digo unicode <code>\u001b</code>.</p><pre><code><code>Console.WriteLine("\e[1mThis is a bold text\e[0m");

Console.ReadLine();</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!mba_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6db8ab85-a970-44ef-bd8c-a68fa81accfa_609x441.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!mba_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6db8ab85-a970-44ef-bd8c-a68fa81accfa_609x441.png 424w, https://substackcdn.com/image/fetch/$s_!mba_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6db8ab85-a970-44ef-bd8c-a68fa81accfa_609x441.png 848w, https://substackcdn.com/image/fetch/$s_!mba_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6db8ab85-a970-44ef-bd8c-a68fa81accfa_609x441.png 1272w, https://substackcdn.com/image/fetch/$s_!mba_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6db8ab85-a970-44ef-bd8c-a68fa81accfa_609x441.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!mba_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6db8ab85-a970-44ef-bd8c-a68fa81accfa_609x441.png" width="609" height="441" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6db8ab85-a970-44ef-bd8c-a68fa81accfa_609x441.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:441,&quot;width&quot;:609,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Resultado binario decompilado, New escape sequence&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Resultado binario decompilado, New escape sequence" title="Resultado binario decompilado, New escape sequence" srcset="https://substackcdn.com/image/fetch/$s_!mba_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6db8ab85-a970-44ef-bd8c-a68fa81accfa_609x441.png 424w, https://substackcdn.com/image/fetch/$s_!mba_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6db8ab85-a970-44ef-bd8c-a68fa81accfa_609x441.png 848w, https://substackcdn.com/image/fetch/$s_!mba_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6db8ab85-a970-44ef-bd8c-a68fa81accfa_609x441.png 1272w, https://substackcdn.com/image/fetch/$s_!mba_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6db8ab85-a970-44ef-bd8c-a68fa81accfa_609x441.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Resultado binario decompilado, New escape sequence</figcaption></figure></div><h2>Implicit indexer access in object initializers</h2><p>En C# podemos utilizar el operador <code>^</code> para acceder a un elemento de un <em>Array</em> desde el final del mismo. Con C# 13, podemos utilizarlo para inicializar elementos de un <em>Array</em> desde el final del mismo.</p><pre><code><code>var countdown = new TimerRemaining(10)
{
    Buffer =
    {
        [^1] = 0,
        [^10] = 9
    }
};

Console.WriteLine($"First: {countdown.Buffer.First()} Last: {countdown.Buffer.Last()}");
Console.ReadLine();

class TimerRemaining(int bufferSize)
{
    public int[] Buffer  { get; set; } = new int[bufferSize];
}</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!E_OF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b753367-47f0-41dd-b7ae-0807bd8fbe2b_712x322.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!E_OF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b753367-47f0-41dd-b7ae-0807bd8fbe2b_712x322.png 424w, https://substackcdn.com/image/fetch/$s_!E_OF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b753367-47f0-41dd-b7ae-0807bd8fbe2b_712x322.png 848w, https://substackcdn.com/image/fetch/$s_!E_OF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b753367-47f0-41dd-b7ae-0807bd8fbe2b_712x322.png 1272w, https://substackcdn.com/image/fetch/$s_!E_OF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b753367-47f0-41dd-b7ae-0807bd8fbe2b_712x322.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!E_OF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b753367-47f0-41dd-b7ae-0807bd8fbe2b_712x322.png" width="712" height="322" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3b753367-47f0-41dd-b7ae-0807bd8fbe2b_712x322.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:322,&quot;width&quot;:712,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Resultado binario decompilado, implicit index&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Resultado binario decompilado, implicit index" title="Resultado binario decompilado, implicit index" srcset="https://substackcdn.com/image/fetch/$s_!E_OF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b753367-47f0-41dd-b7ae-0807bd8fbe2b_712x322.png 424w, https://substackcdn.com/image/fetch/$s_!E_OF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b753367-47f0-41dd-b7ae-0807bd8fbe2b_712x322.png 848w, https://substackcdn.com/image/fetch/$s_!E_OF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b753367-47f0-41dd-b7ae-0807bd8fbe2b_712x322.png 1272w, https://substackcdn.com/image/fetch/$s_!E_OF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b753367-47f0-41dd-b7ae-0807bd8fbe2b_712x322.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Resultado binario decompilado, implicit index</figcaption></figure></div><h2>ref struct</h2><p>A continuaci&#243;n podemos comprobar algunas novedades relacionadas con el tipo <code>ref struct</code> y C# 13.</p><h3>Enable ref locals and unsafe contexts in iterators and async methods</h3><p>Para versiones anteriores a C# 13, no es posible utilizar los tipos <code>ref struct</code> en m&#233;todos iteradores (<code>yield return</code>). En los m&#233;todos asincronos (<code>async</code>) tampoco se pueden declarar variables de este tipo ni pueden ser usadas en contextos inseguros. C# 13 nos permitir&#225; hacer uso de este tipo en todos estos casos de uso.</p><pre><code><code>ref struct ClassOne
{
    public int Current =&gt; 0;
    public bool MoveNext() =&gt; false;
    public void Dispose() { }
}

class ClassTwo
{
    public ClassOne GetEnumerator() =&gt; new ClassOne();
    async void M()
    {
        await Task.Yield();
        using (new ClassOne()) { }
        lock (new System.Threading.Lock()) { }
        await Task.Yield();
    }
}</code></code></pre><h3>Allow ref struct types as arguments for type parameters in generics.</h3><p>Versiones anteriores a C# 13 no permiten hacer uso del tipo <code>ref struct</code>como par&#225;metro generico de un m&#233;todo. A partir de esta versi&#243;n ya es posible:</p><pre><code><code>T Identity&lt;T&gt;(T p)
    where T : allows ref struct
    =&gt; p;

var local = Identity(new User());

Console.ReadLine();

ref struct User
{

}
</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ACbx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faffecf3c-e938-437a-a9a2-fea4d68282b5_501x288.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ACbx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faffecf3c-e938-437a-a9a2-fea4d68282b5_501x288.png 424w, https://substackcdn.com/image/fetch/$s_!ACbx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faffecf3c-e938-437a-a9a2-fea4d68282b5_501x288.png 848w, https://substackcdn.com/image/fetch/$s_!ACbx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faffecf3c-e938-437a-a9a2-fea4d68282b5_501x288.png 1272w, https://substackcdn.com/image/fetch/$s_!ACbx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faffecf3c-e938-437a-a9a2-fea4d68282b5_501x288.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ACbx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faffecf3c-e938-437a-a9a2-fea4d68282b5_501x288.png" width="501" height="288" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/affecf3c-e938-437a-a9a2-fea4d68282b5_501x288.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:288,&quot;width&quot;:501,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Resultado binario decompilado, ref struct como tipo de dato en m&#233;todos gen&#233;ricos.&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Resultado binario decompilado, ref struct como tipo de dato en m&#233;todos gen&#233;ricos." title="Resultado binario decompilado, ref struct como tipo de dato en m&#233;todos gen&#233;ricos." srcset="https://substackcdn.com/image/fetch/$s_!ACbx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faffecf3c-e938-437a-a9a2-fea4d68282b5_501x288.png 424w, https://substackcdn.com/image/fetch/$s_!ACbx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faffecf3c-e938-437a-a9a2-fea4d68282b5_501x288.png 848w, https://substackcdn.com/image/fetch/$s_!ACbx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faffecf3c-e938-437a-a9a2-fea4d68282b5_501x288.png 1272w, https://substackcdn.com/image/fetch/$s_!ACbx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faffecf3c-e938-437a-a9a2-fea4d68282b5_501x288.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Resultado binario decompilado, ref struct como tipo de dato en m&#233;todos gen&#233;ricos</figcaption></figure></div><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/novedades-en-c-13-net-9-preview-6?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">&#161;Te <strong>AGRADEZCO</strong> enormemente que hayas dedicado tu valioso tiempo a leer lo que escribo! Si te ha gustado y crees que puede ayudar a otras personas, <strong>puedes compartirlo</strong>.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.javivela.dev/p/novedades-en-c-13-net-9-preview-6?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartir&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.javivela.dev/p/novedades-en-c-13-net-9-preview-6?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Compartir</span></a></p></div><h2>Referencias</h2><ul><li><p><a href="https://devblogs.microsoft.com/dotnet/csharp-13-explore-preview-features/">https://devblogs.microsoft.com/dotnet/csharp-13-explore-preview-features/</a></p></li><li><p><a href="https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-13">https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-13</a></p></li><li><p><a href="https://github.com/fjvela/csharp-13">https://github.com/fjvela/csharp-13</a></p></li></ul>]]></content:encoded></item></channel></rss>