<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Ali Mehraji</title>
    <description>The latest articles on Forem by Ali Mehraji (@cod3mason).</description>
    <link>https://forem.com/cod3mason</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F887044%2F2ee1d97b-12e5-49b2-8640-87045cd7ef6d.jpg</url>
      <title>Forem: Ali Mehraji</title>
      <link>https://forem.com/cod3mason</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/cod3mason"/>
    <language>en</language>
    <item>
      <title>Mattermost Receiver For Alertmanager in Prometheus-Stack in K8S</title>
      <dc:creator>Ali Mehraji</dc:creator>
      <pubDate>Thu, 26 Feb 2026 20:18:46 +0000</pubDate>
      <link>https://forem.com/cod3mason/mattermost-receiver-for-alertmanager-in-prometheus-stack-in-k8s-4i50</link>
      <guid>https://forem.com/cod3mason/mattermost-receiver-for-alertmanager-in-prometheus-stack-in-k8s-4i50</guid>
      <description>&lt;h3&gt;
  
  
  Overview
&lt;/h3&gt;

&lt;p&gt;Since &lt;code&gt;Prometheus-Stack&lt;/code&gt; &lt;code&gt;Alertmanager&lt;/code&gt; doesn’t include &lt;code&gt;Mattermost&lt;/code&gt; as a built-in receiver, we will integrate it using a &lt;code&gt;webhook&lt;/code&gt; via creating a Python relay application that accepts &lt;code&gt;Alertmanager&lt;/code&gt; webhook notifications, formats them into a Mattermost-compatible payload, and sends them to a Mattermost incoming webhook URL.&lt;/p&gt;

&lt;p&gt;Then we will deploy this relay inside Kubernetes using a Deployment and expose it with a Service so Alertmanager can reliably reach it.&lt;/p&gt;

&lt;p&gt;Finally, we will configure Alertmanager using an AlertmanagerConfig resource to define a new receiver and route, so alerts matching our rules (severity/namespace/etc.) get delivered to Mattermost through the relay.&lt;/p&gt;

&lt;h3&gt;
  
  
  How
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Prometheus Alert Rules trigger alerts.&lt;/li&gt;
&lt;li&gt;Alertmanager processes and routes the alerts.&lt;/li&gt;
&lt;li&gt;Alertmanager sends webhook notifications to the Python Relay Service.&lt;/li&gt;
&lt;li&gt;The relay formats the alert payload.&lt;/li&gt;
&lt;li&gt;The relay forwards the formatted message to Mattermost Incoming Webhook.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Steps
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Create an &lt;a href="https://docs.mattermost.com/integrations-guide/incoming-webhooks.html" rel="noopener noreferrer"&gt;Incoming Webhook in Mattermost&lt;/a&gt;. This webhook URL will be used by the Python relay to deliver alert messages to the desired channel.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ensure you securely store the generated webhook URL, as it will be injected into the relay application via environment variables or Kubernetes secrets.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://github.com/cod3mas0n/k8s-alertmanager-mattermost/blob/main/src/app.py" rel="noopener noreferrer"&gt;Python Relay&lt;/a&gt; Application&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A lightweight webhook server that receives Alertmanager alerts and forwards them to Mattermost.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Build the Docker Image &lt;a href="https://github.com/cod3mas0n/k8s-alertmanager-mattermost/blob/main/src/Dockerfile" rel="noopener noreferrer"&gt;Dockerfile&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the relay application is complete, build the image and push it to a container registry accessible by your Kubernetes cluster.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deploy in Kubernetes: &lt;a href="https://github.com/cod3mas0n/k8s-alertmanager-mattermost/tree/main/kubernetes" rel="noopener noreferrer"&gt;K8S Manifests&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure Alertmanager with &lt;a href="https://github.com/cod3mas0n/k8s-alertmanager-mattermost/blob/main/kubernetes/alertmanagerConfig.yaml" rel="noopener noreferrer"&gt;AlertmanagerConfig&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ensure having a &lt;a href="https://github.com/cod3mas0n/k8s-alertmanager-mattermost/blob/main/kubernetes/alertmanagerConfig.yaml#L6-L7" rel="noopener noreferrer"&gt;label&lt;/a&gt; in AlertmanagerConfig to select via prometheus operator&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the Alertmanagerconfig to prometheus &lt;code&gt;values.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;⋮&lt;/span&gt;
&lt;span class="na"&gt;alertmanager&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;alertmanagerSpec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;alertmanagerConfigSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;alertmanagerConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alertmanager-mattermost&lt;/span&gt;
    &lt;span class="na"&gt;alertmanagerConfigMatcherStrategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;None&lt;/span&gt;
&lt;span class="s"&gt;⋮&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;And then do &lt;code&gt;helm upgrade&lt;/code&gt; to prometheus operator selects the alertmanagerConfig and route alerts.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm upgrade &lt;span class="nt"&gt;--install&lt;/span&gt; prometheus prometheus-community/kube-prometheus-stack &lt;span class="nt"&gt;-f&lt;/span&gt; values.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>alertmanager</category>
      <category>prometheus</category>
      <category>monitoring</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Docker Remote Context via SSH over Proxy</title>
      <dc:creator>Ali Mehraji</dc:creator>
      <pubDate>Tue, 23 Dec 2025 22:26:32 +0000</pubDate>
      <link>https://forem.com/cod3mason/docker-remote-context-via-ssh-over-proxy-268l</link>
      <guid>https://forem.com/cod3mason/docker-remote-context-via-ssh-over-proxy-268l</guid>
      <description>&lt;p&gt;Securely manage a remote Docker daemon over SSH using Docker contexts, with SSH traffic routed through a SOCKS5 proxy.&lt;/p&gt;

&lt;p&gt;If you want to connect to and manage a remote Docker daemon without exposing the Docker API over the network, you can use Docker contexts over SSH. In environments where direct access to the remote server is restricted or must pass through a controlled network path, the SSH connection can be routed through a SOCKS5 proxy.&lt;/p&gt;

&lt;p&gt;By configuring SSH to use a proxy and defining a Docker context that targets the remote host via SSH, Docker commands executed locally are transparently forwarded to the remote Docker daemon. This allows you to use standard Docker workflows (&lt;code&gt;docker ps&lt;/code&gt;, &lt;code&gt;docker compose&lt;/code&gt;, &lt;code&gt;docker build&lt;/code&gt;) as if the daemon were local, while still benefiting from SSH key authentication, proxy enforcement, and connection &lt;code&gt;keepalive&lt;/code&gt; mechanisms.&lt;/p&gt;

&lt;h2&gt;
  
  
  SSH Configuration
&lt;/h2&gt;

&lt;p&gt;To connect to a remote server via SSH through a proxy, &lt;code&gt;ProxyCommand&lt;/code&gt; is used together with &lt;code&gt;nc&lt;/code&gt; (&lt;code&gt;netcat&lt;/code&gt;). All SSH connections to the remote host are routed through the specified SOCKS5 (it could be HTTP) proxy.&lt;/p&gt;

&lt;p&gt;The wildcard host configuration (&lt;code&gt;vps-*&lt;/code&gt;) ensures that any matching host uses the proxy and &lt;code&gt;keepalive&lt;/code&gt; settings automatically.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;~/.ssh/config&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;HOST&lt;/span&gt; &lt;span class="n"&gt;vps&lt;/span&gt;-*
  &lt;span class="n"&gt;ServerAliveInterval&lt;/span&gt;   &lt;span class="m"&gt;10&lt;/span&gt;
  &lt;span class="n"&gt;ProxyCommand&lt;/span&gt; &lt;span class="n"&gt;nc&lt;/span&gt; --&lt;span class="n"&gt;proxy&lt;/span&gt;-&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;socks5&lt;/span&gt; --&lt;span class="n"&gt;proxy&lt;/span&gt; &lt;span class="m"&gt;127&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;1&lt;/span&gt;:&lt;span class="m"&gt;10808&lt;/span&gt; %&lt;span class="n"&gt;h&lt;/span&gt; %&lt;span class="n"&gt;p&lt;/span&gt;

&lt;span class="n"&gt;Host&lt;/span&gt; &lt;span class="n"&gt;vps&lt;/span&gt;-&lt;span class="n"&gt;docker&lt;/span&gt;
  &lt;span class="n"&gt;HostName&lt;/span&gt; &amp;lt;&lt;span class="n"&gt;HOST_IP&lt;/span&gt;&amp;gt;
  &lt;span class="n"&gt;User&lt;/span&gt; &amp;lt;&lt;span class="n"&gt;USER_NAME&lt;/span&gt;&amp;gt;
  &lt;span class="n"&gt;Port&lt;/span&gt; &amp;lt;&lt;span class="n"&gt;HOST_SSH_PORT&lt;/span&gt;&amp;gt;
  &lt;span class="n"&gt;PreferredAuthentications&lt;/span&gt; &lt;span class="n"&gt;publickey&lt;/span&gt;

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ServerAliveInterval&lt;/code&gt;: keeps the SSH connection alive by sending periodic packets, preventing timeouts during long-running operations.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ProxyCommand&lt;/code&gt;: forces SSH traffic to pass through a local SOCKS5 proxy (e.g. a VPN tunnel).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PreferredAuthentications publickey&lt;/code&gt;: Specifies that SSH should prefer (and effectively enforce) public key–based authentication instead of password-based authentication when connecting to the host.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Docker Context
&lt;/h2&gt;

&lt;p&gt;Docker can connect to the remote Docker daemon over SSH.&lt;br&gt;
The SSH connection itself is routed through the configured SOCKS5 proxy , ensuring all Docker traffic to the remote host passes through the proxy.&lt;/p&gt;

&lt;p&gt;To define a Docker context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker context create vps-docker-host &lt;span class="nt"&gt;--docker&lt;/span&gt; &lt;span class="nv"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ssh://&amp;lt;vps-docker&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To switch and use created context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker context use vps-docker-host
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once this context is created and activated, all Docker CLI commands (including docker ps, docker compose, and docker build) will operate against the remote Docker daemon instead of the local one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/engine/manage-resources/contexts" rel="noopener noreferrer"&gt;Docker Context&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://man7.org/linux/man-pages/man5/ssh_config.5.html" rel="noopener noreferrer"&gt;SSH Config &lt;code&gt;~/.ssh/config&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>ssh</category>
      <category>linux</category>
    </item>
    <item>
      <title>runcmd and package order in Cloud-Init</title>
      <dc:creator>Ali Mehraji</dc:creator>
      <pubDate>Mon, 08 Dec 2025 00:45:58 +0000</pubDate>
      <link>https://forem.com/cod3mason/runcmd-and-package-in-cloud-init-g62</link>
      <guid>https://forem.com/cod3mason/runcmd-and-package-in-cloud-init-g62</guid>
      <description>&lt;p&gt;During boot, cloud-init identifies the cloud it is running on and initializes the system accordingly. Cloud instances will automatically be provisioned during first boot with networking, storage, SSH keys, packages and various other system aspects already configured.&lt;/p&gt;

&lt;p&gt;running Cloud-Init is the job of the &lt;code&gt;cloud-init-local&lt;/code&gt;, &lt;code&gt;cloud-init&lt;/code&gt;, &lt;code&gt;cloud-config&lt;/code&gt; and &lt;code&gt;cloud-final&lt;/code&gt; init scripts in &lt;code&gt;/etc/init.d&lt;/code&gt;. Cloud-Init can be configured to carry out a wide range of tasks such as adding &lt;code&gt;yum&lt;/code&gt; or &lt;code&gt;apt&lt;/code&gt; repositories, writing files, creating users and groups, and bootstrapping configuration management.&lt;/p&gt;

&lt;p&gt;How is it possible to run a command via &lt;code&gt;runcmd&lt;/code&gt; before installing its related package via &lt;code&gt;packages&lt;/code&gt; in Cloud-Init? Which one runs first ?&lt;/p&gt;

&lt;p&gt;In a Cloud-Init configuration, it may look strange that a command referencing a service can run before the package providing that service is installed. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;#cloud-config&lt;/span&gt;
&lt;span class="s"&gt;︙&lt;/span&gt;
&lt;span class="na"&gt;package_update&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;package_upgrade&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;runcmd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;systemctl enable --now qemu-guest-agent.service&lt;/span&gt;

&lt;span class="na"&gt;packages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;qemu-guest-agent&lt;/span&gt;
&lt;span class="s"&gt;︙&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this setup, commonly used when provisioning VMs with Terraform’s &lt;a href="https://registry.terraform.io/providers/dmacvicar/libvirt/latest/docs" rel="noopener noreferrer"&gt;libvirt provider&lt;/a&gt; on QEMU/KVM, &lt;code&gt;runcmd&lt;/code&gt; attempts to enable and start &lt;code&gt;qemu-guest-agent.service&lt;/code&gt; even though the package providing it (&lt;code&gt;qemu-guest-agent&lt;/code&gt;) hasn’t been installed yet. The guest agent is often required early so tools like Ansible’s &lt;a href="https://github.com/cod3mas0n/qemu-kvm-terraform/blob/main/dynamic-inventory.py" rel="noopener noreferrer"&gt;dynamic inventory&lt;/a&gt; can query host information.&lt;/p&gt;

&lt;p&gt;So how can Cloud-Init run &lt;code&gt;systemctl enable --now qemu-guest-agent.service&lt;/code&gt; before the package exists?&lt;/p&gt;

&lt;p&gt;The sentence “The &lt;a href="https://cloudinit.readthedocs.io/en/latest/reference/modules.html#runcmd" rel="noopener noreferrer"&gt;runcmd&lt;/a&gt; module runs very late in the boot process” can be confusing at first glance, because in Cloud-Init’s documented module stages, &lt;code&gt;runcmd&lt;/code&gt; appears in the &lt;a href="https://cloudinit.readthedocs.io/en/latest/explanation/boot.html" rel="noopener noreferrer"&gt;Config stage&lt;/a&gt; while package installation via &lt;code&gt;packages&lt;/code&gt; happens in the Final stage.&lt;/p&gt;

&lt;p&gt;It looks like &lt;code&gt;runcmd&lt;/code&gt; runs before packages are installed and it wont work.&lt;/p&gt;

&lt;p&gt;However, The &lt;code&gt;runcmd&lt;/code&gt; module does not execute commands directly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The runcmd module only writes the script to be run later. The module that actually runs the script is &lt;a href="https://cloudinit.readthedocs.io/en/latest/reference/modules.html#scripts-user" rel="noopener noreferrer"&gt;scripts_user&lt;/a&gt; in the Final boot stage.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So even though &lt;code&gt;runcmd&lt;/code&gt; appears in the Config stage, the commands you place under &lt;code&gt;runcmd&lt;/code&gt; are not executed immediately. They are scheduled to run later, after packages have been installed and other finalization tasks are complete.&lt;/p&gt;

&lt;p&gt;By the time the &lt;code&gt;scripts_user&lt;/code&gt; module runs (in the Final stage), the &lt;code&gt;qemu-guest-agent&lt;/code&gt; is installed, &lt;code&gt;qemu-guest-agent.service&lt;/code&gt; exists and &lt;code&gt;systemctl enable --now&lt;/code&gt; will be succeed.&lt;/p&gt;

&lt;p&gt;The runcmd scripts will be written in &lt;code&gt;/var/lib/cloud/instance/scripts/runcmd&lt;/code&gt; in the instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /var/lib/cloud/instance/scripts/runcmd

&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;
systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; qemu-guest-agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;&lt;code&gt;cloud-config&lt;/code&gt; Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;#cloud-config&lt;/span&gt;
&lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;USERNAME&lt;/span&gt;
    &lt;span class="na"&gt;groups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;users, admin&lt;/span&gt;
    &lt;span class="na"&gt;sudo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ALL=(ALL)&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;NOPASSWD:ALL"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;gecos&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DevOps&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Engineer"&lt;/span&gt;
    &lt;span class="na"&gt;passwd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SHA-512&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;hashed&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;password"&lt;/span&gt; &lt;span class="c1"&gt;# mkpasswd --method=SHA-512&lt;/span&gt;
    &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/bin/bash&lt;/span&gt;
    &lt;span class="na"&gt;ssh_authorized_keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ssh-ed25519&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;..."&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ssh-rsa&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;..."&lt;/span&gt;

&lt;span class="na"&gt;ssh_pwauth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

&lt;span class="na"&gt;package_update&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;package_upgrade&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;apt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# file /etc/apt/apt.conf.d/cloud-init-aptproxy will be written&lt;/span&gt;
  &lt;span class="na"&gt;http_proxy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://&amp;lt;proxy-server&amp;gt;:port&lt;/span&gt;
  &lt;span class="na"&gt;https_proxy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://&amp;lt;proxy-server&amp;gt;:port&lt;/span&gt;

&lt;span class="na"&gt;write_files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/etc/ssh/sshd_config.d/ssh-hardening.conf&lt;/span&gt;
    &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;Port 2200&lt;/span&gt;
      &lt;span class="s"&gt;KbdInteractiveAuthentication no&lt;/span&gt;
      &lt;span class="s"&gt;ChallengeResponseAuthentication no&lt;/span&gt;
      &lt;span class="s"&gt;MaxAuthTries 2&lt;/span&gt;
      &lt;span class="s"&gt;AllowTcpForwarding no&lt;/span&gt;
      &lt;span class="s"&gt;X11Forwarding no&lt;/span&gt;
      &lt;span class="s"&gt;AllowAgentForwarding no&lt;/span&gt;
      &lt;span class="s"&gt;AuthorizedKeysFile .ssh/authorized_keys&lt;/span&gt;

&lt;span class="na"&gt;runcmd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;systemctl enable --now qemu-guest-agent&lt;/span&gt;

&lt;span class="na"&gt;packages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;qemu-guest-agent&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;htop&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;tree&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://youtu.be/1joQfUZQcPg" rel="noopener noreferrer"&gt;Cloud-Init: Building clouds&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloudinit.readthedocs.io/en/latest/index.html" rel="noopener noreferrer"&gt;Cloud-Init&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://registry.terraform.io/providers/dmacvicar/libvirt/latest/docs" rel="noopener noreferrer"&gt;terraform libvirt provider&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jen20.dev/post/cloudinit-configuration-merging/" rel="noopener noreferrer"&gt;Cloud-Init configuration merging&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloudinit.readthedocs.io/en/latest/explanation/first_boot.html#first-boot-determination" rel="noopener noreferrer"&gt;First Boot Determination&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>qemu</category>
      <category>virtualization</category>
      <category>cloudinit</category>
      <category>devops</category>
    </item>
    <item>
      <title>OOMKill in Kubernetes and Linux (Exit Code 137)</title>
      <dc:creator>Ali Mehraji</dc:creator>
      <pubDate>Mon, 22 Sep 2025 13:23:25 +0000</pubDate>
      <link>https://forem.com/cod3mason/oomkill-in-kubernetes-and-linux-exit-code-137-20ba</link>
      <guid>https://forem.com/cod3mason/oomkill-in-kubernetes-and-linux-exit-code-137-20ba</guid>
      <description>&lt;p&gt;When a container(process) is terminated due to an &lt;a href="https://www.kernel.org/doc/gorman/html/understand/understand016.html" rel="noopener noreferrer"&gt;Out Of Memory (OOM) manager&lt;/a&gt; condition, Kubernetes marks it as &lt;strong&gt;OOMKilled&lt;/strong&gt;. In this case , the Linux kernel’s OOM Killer terminates the process and the container exits with exit code &lt;a href="https://tldp.org/LDP/abs/html/exitcodes.html" rel="noopener noreferrer"&gt;&lt;strong&gt;137&lt;/strong&gt;&lt;/a&gt;. This exit code is an important troubleshooting signal in Kubernetes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why OOMKill Happens
&lt;/h3&gt;

&lt;p&gt;Linux uses an over-commitment policy for memory management. Applications can request more memory than is physically available. When the actual demand exceeds system capacity, the kernel must decide which process to kill in order to reclaim memory. &lt;a href="https://www.kernel.org/doc/gorman/html/understand/understand016.html" rel="noopener noreferrer"&gt;How OOM Kill works ?&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The OOM Killer selects and terminates processes based on their OOM score.&lt;/li&gt;
&lt;li&gt;In Kubernetes, this usually happens when a container exceeds its memory limit.&lt;/li&gt;
&lt;li&gt;Kubernetes then records the container’s state as OOMKilled, and logs exit code 137. &lt;a href="https://github.com/torvalds/linux/blob/master/mm/oom_kill.c#L948" rel="noopener noreferrer"&gt;OOM Killer Sends What Signal to the Process ?&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://tldp.org/LDP/abs/html/exitcodes.html" rel="noopener noreferrer"&gt;Exit codes&lt;/a&gt; &lt;code&gt;1 - 2&lt;/code&gt;, &lt;code&gt;126 - 165&lt;/code&gt;, and &lt;code&gt;255&lt;/code&gt; have special meanings, and should therefore be avoided for user-specified exit parameters. Ending a script with exit 127 would certainly cause confusion when troubleshooting (is the error code a "command not found" or a user-defined one?).&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html" rel="noopener noreferrer"&gt;Exit Status&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tldp.org/LDP/abs/html/exitcodes.html" rel="noopener noreferrer"&gt;Exit Codes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.kernel.org/doc/gorman/html/understand/understand016.html" rel="noopener noreferrer"&gt;Out Of Memory Management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/linux/memory-overcommitment-oom-killer" rel="noopener noreferrer"&gt;Linux Memory Overcommitment and the OOM Killer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/torvalds/linux/blob/master/mm/oom_kill.c#L948" rel="noopener noreferrer"&gt;Kill signal linux kernel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://grafana.com/grafana/dashboards/16718-oom-and-restarts/" rel="noopener noreferrer"&gt;OOM Dashboard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lumigo.io/kubernetes-troubleshooting/kubernetes-oomkilled-error-how-to-fix-and-tips-for-preventing-it/" rel="noopener noreferrer"&gt;Kubernetes OOMKilled Error&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=2bjuqRLFaHc" rel="noopener noreferrer"&gt;Virtual Memory in Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://povilasv.me/go-memory-management/" rel="noopener noreferrer"&gt;Go Memory Management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cs.uic.edu/~jbell/CourseNotes/OperatingSystems/9_VirtualMemory.html" rel="noopener noreferrer"&gt;Virtual Memory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/urU7UhF7D3Q" rel="noopener noreferrer"&gt;Memory Segments in C&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Tasks

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://labs.iximiuz.com/challenges/kill-process-group-on-oom-event" rel="noopener noreferrer"&gt;Kill Process Group on OOM Event&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://labs.iximiuz.com/challenges/kill-container-on-child-process-oom-event-docker" rel="noopener noreferrer"&gt;Make the Container Exit When One of Its Processes Runs Out of Memory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://labs.iximiuz.com/challenges/make-kubernetes-pod-outlive-oom-event" rel="noopener noreferrer"&gt;Make a Kubernetes Pod Survive an OOM Event Without Restarting&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>bash</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Kubernetes Ephemeral Containers and kubectl debug Command</title>
      <dc:creator>Ali Mehraji</dc:creator>
      <pubDate>Sat, 23 Aug 2025 22:29:01 +0000</pubDate>
      <link>https://forem.com/cod3mason/kubectl-debug-3ad8</link>
      <guid>https://forem.com/cod3mason/kubectl-debug-3ad8</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This post is only a brief overview, with references collected at the end. If you’d like to dive deeper, I recommend starting with &lt;a href="https://iximiuz.com/en/posts/kubernetes-ephemeral-containers/" rel="noopener noreferrer"&gt;Deep Diving Kubernetes Ephemeral Containers and kubectl debug Command&lt;/a&gt; and then following the related &lt;a href="https://labs.iximiuz.com/challenges/copy-files-to-from-distroless-kubernetes-pod" rel="noopener noreferrer"&gt;Task: Copy Files To/From a Distroless Kubernetes Pod&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Ephemeral containers
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://kubernetes.io/docs/concepts/workloads/pods/ephemeral-containers/" rel="noopener noreferrer"&gt;Ephemeral containers&lt;/a&gt; provide a powerful way to debug applications running in Kubernetes. Unlike regular containers, they are not part of the pod’s original specification but can be injected into a running pod when needed. This makes them especially valuable for interactive troubleshooting, particularly when &lt;code&gt;kubectl exec&lt;/code&gt; is insufficient—for example, when a container has already crashed or when the original image lacks essential debugging tools.&lt;/p&gt;

&lt;p&gt;Modern container practices often favor minimal or &lt;code&gt;distroless&lt;/code&gt; images to improve security and performance. In many cases, base images are stripped down to the essential. sometimes even using &lt;code&gt;scratch&lt;/code&gt; with nothing but the application binary. While this approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;have a smaller attack vector area.&lt;/li&gt;
&lt;li&gt;have faster-scanning performance.&lt;/li&gt;
&lt;li&gt;Reduced image size.&lt;/li&gt;
&lt;li&gt;have a faster build and CD/CI cycle.&lt;/li&gt;
&lt;li&gt;have fewer dependencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also means that traditional debugging utilities (like a shell or package manager) are unavailable.&lt;/p&gt;

&lt;p&gt;Ephemeral containers allow engineers to inject a temporary container image that includes the required debugging tools, without altering the original pod definition. This is particularly useful for inspecting the live state of an application, reproducing elusive issues, and running arbitrary commands inside a pod—giving teams the best of both worlds: lean production images with flexible on-demand debugging capabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Share Process
&lt;/h3&gt;

&lt;p&gt;While troubleshooting a Pod, I'd typically want to see the processes of all pods containers, as well as I'd be interested in exploring their filesystems. Can an ephemeral container be a little more unraveling?&lt;/p&gt;

&lt;p&gt;However, if you explore the filesystem with &lt;code&gt;ls&lt;/code&gt;, you'll notice that it's a filesystem of the ephemeral container itself (busybox in our case), and not of any other container in the Pod. Well, it makes sense - &lt;a href="https://raw.githubusercontent.com/cod3mas0n/Documents/refs/heads/main/posts/assets/k8s-debug-ctr-in-pod-shared-ns.webP" rel="noopener noreferrer"&gt;containers in a Pod (typically) &lt;strong&gt;share&lt;/strong&gt; &lt;code&gt;net&lt;/code&gt;, &lt;code&gt;ipc&lt;/code&gt;, and &lt;code&gt;uts&lt;/code&gt; namespaces&lt;/a&gt;, they can &lt;strong&gt;share&lt;/strong&gt; the &lt;code&gt;pid&lt;/code&gt; namespace, but they &lt;strong&gt;&lt;em&gt;never&lt;/em&gt;&lt;/strong&gt; share the &lt;code&gt;mnt&lt;/code&gt; namespace. Also, filesystems of different containers always stay independent. Otherwise, all sorts of collisions would start happening.&lt;/p&gt;

&lt;p&gt;Understanding process namespace sharing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The container process no longer has PID 1&lt;/strong&gt;. Some containers refuse to start without PID 1 (for example, containers using systemd) or run commands like &lt;code&gt;kill -HUP 1&lt;/code&gt; to signal the container process. In pods with a shared process namespace, &lt;code&gt;kill -HUP 1&lt;/code&gt; will signal the pod sandbox (&lt;code&gt;/pause&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Processes are visible to other containers in the pod&lt;/strong&gt;. This includes all information visible in &lt;code&gt;/proc&lt;/code&gt;, such as passwords that were passed as arguments or environment variables. These are protected only by regular Unix permissions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Container filesystems are visible to other containers&lt;/strong&gt;. This makes debugging easier, but it also means that filesystem secrets are protected only by filesystem permissions.Thus, if you know a PID of a process from the container you want to explore, you can find its filesystem at &lt;code&gt;/proc/&amp;lt;PID&amp;gt;/root&lt;/code&gt; from inside the debugging container.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Lets get hands dirty
&lt;/h3&gt;

&lt;p&gt;Create pod with a distroless image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;distroless-nginx&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;distroless-nginx&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;distroless-nginx&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;distroless-nginx&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;distroless-nginx-ctr&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cgr.dev/chainguard/nginx&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the pod is created, try to get shell via &lt;code&gt;kubectl exec&lt;/code&gt; (try with &lt;code&gt;sh&lt;/code&gt;, &lt;code&gt;ash&lt;/code&gt; , ...):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;k &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; default distroless-nginx-cbbdbd698-49fjr &lt;span class="nt"&gt;--&lt;/span&gt; bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It wont be able to give you typical TTY shell.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;error: Internal error occurred: Internal error occurred: error executing &lt;span class="nb"&gt;command &lt;/span&gt;&lt;span class="k"&gt;in &lt;/span&gt;container: failed to &lt;span class="nb"&gt;exec &lt;/span&gt;&lt;span class="k"&gt;in &lt;/span&gt;container: failed to start &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"c336401c1da1996fc382a2c8aefd82552a60b6de52da1d12aec0d3b5f9b3b65a"&lt;/span&gt; : OCI runtime &lt;span class="nb"&gt;exec &lt;/span&gt;failed: &lt;span class="nb"&gt;exec &lt;/span&gt;failed: unable to start container process: &lt;span class="nb"&gt;exec&lt;/span&gt;: &lt;span class="s2"&gt;"bash"&lt;/span&gt;: executable file not found &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;$PATH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;kubectl debug&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcod3mas0n%2FDocuments%2Frefs%2Fheads%2Fmain%2Fposts%2Fassets%2Fkubectl-debug%2Fcdebug-slide-4.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcod3mas0n%2FDocuments%2Frefs%2Fheads%2Fmain%2Fposts%2Fassets%2Fkubectl-debug%2Fcdebug-slide-4.webp" title="Kubectl debug" alt="kubectl debug" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcod3mas0n%2FDocuments%2Frefs%2Fheads%2Fmain%2Fposts%2Fassets%2Fkubectl-debug%2Fcdebug-slide-5.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcod3mas0n%2FDocuments%2Frefs%2Fheads%2Fmain%2Fposts%2Fassets%2Fkubectl-debug%2Fcdebug-slide-5.webp" title="debugger endpoint" alt="debugger endpoint" width="800" height="467"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;POD_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get pods &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;distroless-nginx &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.items[0].metadata.name}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
kubectl debug &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; debugger &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;busybox &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;POD_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you inject an &lt;code&gt;ephemeralContainer&lt;/code&gt; into a pod, it behaves like any other container, unless you explicitly grant it additional privileges or enable process and filesystem sharing with the target container.&lt;/p&gt;

&lt;p&gt;So, unless your workloads run with &lt;code&gt;shareProcessNamespace&lt;/code&gt; enabled by default (which is unlikely a good idea since it reduces the isolation between containers), we still need a better solution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;POD_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get pods &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;distroless-nginx &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.items[0].metadata.name}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
kubectl debug &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; debugger &lt;span class="nt"&gt;--target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;distroless-nginx-ctr &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;busybox &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;POD_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Targeting container &lt;span class="s2"&gt;"distroless-nginx-ctr"&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; If you don&lt;span class="s1"&gt;'t see processes from this container it may be because the container runtime doesn'&lt;/span&gt;t support this feature.
&lt;span class="nt"&gt;--profile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;legacy is deprecated and will be removed &lt;span class="k"&gt;in &lt;/span&gt;the future. It is recommended to explicitly specify a profile, &lt;span class="k"&gt;for &lt;/span&gt;example &lt;span class="s2"&gt;"--profile=general"&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
If you don&lt;span class="s1"&gt;'t see a command prompt, try pressing enter.

/ # ps aux
PID   USER     TIME  COMMAND
    1 65532     0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf -e /dev/stderr -g daemon off;
    7 65532     0:00 nginx: worker process
    8 65532     0:00 nginx: worker process
    9 65532     0:00 nginx: worker process
   10 65532     0:00 nginx: worker process
   17 root      0:00 sh
   22 root      0:00 ps aux
/ #
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case the &lt;a href="https://raw.githubusercontent.com/cod3mas0n/Documents/refs/heads/main/posts/assets/ctr-in-pod-shared-pid-ns.WebP" rel="noopener noreferrer"&gt;debugger container can access to other processes&lt;/a&gt;. what does the &lt;code&gt;--target&lt;/code&gt; do ?&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="nt"&gt;--target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;:
  When using an ephemeral container, target processes &lt;span class="k"&gt;in &lt;/span&gt;this container name.

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note&lt;/em&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;--target&lt;/code&gt; parameter must be supported by the Container Runtime. When not supported, the Ephemeral Container may not be started, or it may be started with an isolated process namespace so that ps does not reveal processes in other containers.&lt;/p&gt;

&lt;p&gt;Now, let’s say we want to modify the distroless-nginx-ctr container’s /etc/nginx/nginx.conf. Immediately we run into a problem: we don’t even have permission to change directories with cd, nor can we list the root directory of the target container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ &lt;span class="c"&gt;# ls /proc/1/root&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt;: /proc/1/root: Permission denied
~ &lt;span class="c"&gt;# cd /proc/1/root&lt;/span&gt;
sh: &lt;span class="nb"&gt;cd&lt;/span&gt;: can&lt;span class="s1"&gt;'t cd to /proc/1/root: Permission denied
~ #
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This highlights a key limitation—process sharing alone isn’t enough. To properly inspect and interact with the target container’s filesystem, we also need elevated privileges. That’s where the &lt;a href="https://kubernetes.io/docs/tasks/debug/debug-application/debug-running-pod/#debugging-profiles" rel="noopener noreferrer"&gt;&lt;code&gt;--profile&lt;/code&gt;&lt;/a&gt; flag comes in, as it can grant the necessary access for debugging and modification.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;POD_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get pods &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;distroless-nginx &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.items[0].metadata.name}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
kubectl debug &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; debugger &lt;span class="nt"&gt;--target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;distroless-nginx-ctr &lt;span class="nt"&gt;--profile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sysadmin &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;busybox &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;POD_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note&lt;/em&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;kubectl debug automatically generates a container name if you don't choose one using the &lt;code&gt;--container&lt;/code&gt; flag.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;-i&lt;/code&gt; flag causes kubectl debug to attach to the new container by default. You can prevent this by specifying -&lt;code&gt;-attach=false&lt;/code&gt;. If your session becomes disconnected you can reattach using &lt;code&gt;kubectl attach&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--share-processes&lt;/code&gt; allows the containers in this Pod to see processes from the other containers in the Pod. For more information about how this works, see &lt;a href="https://kubernetes.io/docs/tasks/configure-pod-container/share-process-namespace/" rel="noopener noreferrer"&gt;Share Process Namespace between Containers in a Pod&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't forget&lt;/strong&gt; to clean up the debugging Pod when you're finished with it.&lt;/li&gt;
&lt;li&gt;Install a Kubernetes policy engine (OPA/Gatekeeper) to prevent &lt;a href="https://medium.com/@rudra910203/the-kubectl-debug-command-that-exposed-our-entire-kubernetes-cluster-3a125ed6e539" rel="noopener noreferrer"&gt;exposing your cluster&lt;/a&gt;:

&lt;ul&gt;
&lt;li&gt;Block privileged debug containers&lt;/li&gt;
&lt;li&gt;Require &lt;code&gt;automountServiceAccountToken&lt;/code&gt;: false&lt;/li&gt;
&lt;li&gt;Implement just-in-time access for debugging&lt;/li&gt;
&lt;li&gt;Use managed debug tools like Teleport instead of raw kubectl debug&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Debug Session Monitoring Now we alert on:

&lt;ul&gt;
&lt;li&gt;Added Debug Session Monitoring&lt;/li&gt;
&lt;li&gt;Any ephemeral container creation&lt;/li&gt;
&lt;li&gt;Service account token access from unexpected pods&lt;/li&gt;
&lt;li&gt;Debug sessions lasting &amp;gt;5 minutes&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;kubectl debug node&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;k debug node/debian-11 &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--image-pull-policy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'IfNotPresent'&lt;/span&gt; &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ubuntu &lt;span class="nt"&gt;--profile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sysadmin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://kubernetes.io/docs/tasks/debug/debug-application/debug-running-pod/#node-shell-session" rel="noopener noreferrer"&gt;When creating a debugging session on a node, keep in mind that&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;kubectl debug&lt;/code&gt; automatically generates the name of the new Pod based on the name of the Node.&lt;/li&gt;
&lt;li&gt;The root filesystem of the Node will be mounted at &lt;code&gt;/host&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The container runs in the host IPC, Network, and PID namespaces, although the pod isn't privileged, so reading some process information may fail, and &lt;code&gt;chroot /host&lt;/code&gt; may fail.&lt;/li&gt;
&lt;li&gt;If you need a privileged pod, create it manually or use the &lt;code&gt;--profile=sysadmin&lt;/code&gt; flag.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To debug node like an SSH session, just invoke &lt;code&gt;chroot /host&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Creating debugging pod node-debugger-debian-11-wrjhs with container debugger on node debian-11.
If you don&lt;span class="s1"&gt;'t see a command prompt, try pressing enter.
/ # chroot /host
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't forget to clean up the debugging Pod when you're finished with it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete pod node-debugger-debian-11-wrjhs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Sidecar container via Docker
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcod3mas0n%2FDocuments%2Frefs%2Fheads%2Fmain%2Fposts%2Fassets%2Fkubectl-debug%2Fcdebug-slide-3.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcod3mas0n%2FDocuments%2Frefs%2Fheads%2Fmain%2Fposts%2Fassets%2Fkubectl-debug%2Fcdebug-slide-3.webp" title="docker exec ,sidecar" alt="docker exec" width="800" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How &lt;code&gt;docker exec&lt;/code&gt; and &lt;a href="https://github.com/iximiuz/cdebug" rel="noopener noreferrer"&gt;&lt;code&gt;cdebug&lt;/code&gt;&lt;/a&gt; works ?&lt;/p&gt;

&lt;p&gt;How to reproduce the docker exec-like functionality with the docker run command by starting a new container in the target container's namespaces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-itd&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; sidecar &lt;span class="nt"&gt;--pid&lt;/span&gt; container:target &lt;span class="nt"&gt;--ipc&lt;/span&gt; container:target &lt;span class="nt"&gt;--network&lt;/span&gt; container:target alpine sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://docs.docker.com/reference/cli/docker/debug/" rel="noopener noreferrer"&gt;Docker Debug&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://labs.iximiuz.com/tutorials/containers-vs-pods" rel="noopener noreferrer"&gt;Docker Containers vs. Kubernetes Pods - Taking a Deeper Look&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.mirantis.com/blog/kubernetes-pod-vs-container-multi-container-pods-and-container-communication/" rel="noopener noreferrer"&gt;Multi-container pods and container communication&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://github.com/kubernetes/enhancements/issues/277" rel="noopener noreferrer"&gt;Ephemeral Containers&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://iximiuz.com/en/posts/kubernetes-ephemeral-containers/" rel="noopener noreferrer"&gt;Kubernetes Ephemeral Containers and kubectl debug Command&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kubernetes/kubernetes/issues/45922" rel="noopener noreferrer"&gt;FR: New kubectl command kubectl debug&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.vcluster.com/blog/using-kubernetes-ephemeral-containers-for-troubleshooting" rel="noopener noreferrer"&gt;Using Kubernetes Ephemeral Containers for Troubleshooting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/concepts/workloads/pods/ephemeral-containers/" rel="noopener noreferrer"&gt;Ephemeral Containers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opensource.googleblog.com/2022/01/Introducing%20Ephemeral%20Containers.html" rel="noopener noreferrer"&gt;Introducing Ephemeral Containers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/01001101/ephemeral-containers-the-future-of-kubernetes-workload-debugging-c5b7ded3019f" rel="noopener noreferrer"&gt;The future of Kubernetes workload debugging&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://kubernetes.io/docs/tasks/configure-pod-container/share-process-namespace/" rel="noopener noreferrer"&gt;Share Process Namespace between Containers in a Pod&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://medium.com/@rudra910203/the-kubectl-debug-command-that-exposed-our-entire-kubernetes-cluster-3a125ed6e539" rel="noopener noreferrer"&gt;kubectl Debug Exposed Kubernetes Cluster&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://kubernetes.io/docs/tasks/debug/debug-cluster/kubectl-node-debug/" rel="noopener noreferrer"&gt;Debug node&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://kubernetes.io/docs/tasks/debug/debug-application/debug-running-pod/#node-shell-session" rel="noopener noreferrer"&gt;Debugging via a shell on the node&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Tasks&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/tasks/debug/debug-application/debug-running-pod/#ephemeral-container" rel="noopener noreferrer"&gt;Debugging with an ephemeral debug container&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://labs.iximiuz.com/challenges/copy-files-to-from-distroless-kubernetes-pod" rel="noopener noreferrer"&gt;Copy Files To/From a Running Kubernetes Pod: a Distroless Image Case&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://labs.iximiuz.com/challenges/docker-container-share-namespaces" rel="noopener noreferrer"&gt;Run a Sidecar Container in the Namespace of Another Container&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://labs.iximiuz.com/challenges/edit-file-in-running-kubernetes-pod" rel="noopener noreferrer"&gt;Edit a File in a Running Kubernetes Pod: a Tricky Case&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Python Env Variables in Dockerfile</title>
      <dc:creator>Ali Mehraji</dc:creator>
      <pubDate>Fri, 25 Jul 2025 17:45:36 +0000</pubDate>
      <link>https://forem.com/cod3mason/python-env-variables-in-dockerfile-5920</link>
      <guid>https://forem.com/cod3mason/python-env-variables-in-dockerfile-5920</guid>
      <description>&lt;p&gt;It is necessary to set Python-specific environment variables in Dockerfile. Some of these variables are optional, while others are essential.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PYTHONUNBUFFERED=1 \&lt;/span&gt;
    PYTHONDONTWRITEBYTECODE=1 \
    PIP_DISABLE_PIP_VERSION_CHECK=on \
    PIP_TIMEOUT=60 \
    PIP_INDEX_URL=https://${JFROG}/artifactory/api/pypi/python/simple/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;a href="https://docs.python.org/3/using/cmdline.html#envvar-PYTHONUNBUFFERED" rel="noopener noreferrer"&gt;PYTHONUNBUFFERED&lt;/a&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Force the &lt;code&gt;stdout&lt;/code&gt; and stderr streams to be unbuffered. This option has no effect on the stdin stream.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Ensure &lt;strong&gt;logs appear immediately&lt;/strong&gt; in the container logs, Disables output buffering for &lt;code&gt;stdout&lt;/code&gt; and &lt;code&gt;stderr&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Crucial for:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Debugging&lt;/strong&gt; or &lt;strong&gt;monitoring logs&lt;/strong&gt; (e.g., in &lt;code&gt;docker logs&lt;/code&gt; or CI pipelines).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streaming logs&lt;/strong&gt; to systems like &lt;code&gt;ELK&lt;/code&gt;, &lt;code&gt;Loki&lt;/code&gt;, etc.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://docs.python.org/3/using/cmdline.html#envvar-PYTHONDONTWRITEBYTECODE" rel="noopener noreferrer"&gt;PYTHONDONTWRITEBYTECODE&lt;/a&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;If this is set to a non-empty string, Python won’t try to write .pyc files on the import of source modules. This is equivalent to specifying the &lt;code&gt;-B&lt;/code&gt; option.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Disables writing &lt;code&gt;.pyc&lt;/code&gt; files (compiled bytecode) to disk.&lt;/li&gt;
&lt;li&gt;Prevents Python from creating:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;__pycache__/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.pyc&lt;/code&gt; files&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Keeps the container &lt;strong&gt;clean and lightweight&lt;/strong&gt;.&lt;/li&gt;

&lt;li&gt;Avoids unnecessary file writes (especially important on container read-only filesystems or volume mounts).&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://pip.pypa.io/en/stable/topics/configuration/#environment-variables" rel="noopener noreferrer"&gt;PIP_INDEX_URL&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;This environment variable is used for on-premises/private PYPI artifactory.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;pip’s command line options can be set with environment variables using the format &lt;code&gt;PIP_&amp;lt;UPPER_LONG_NAME&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Dashes (&lt;code&gt;-&lt;/code&gt;) have to be replaced with underscores (&lt;code&gt;_&lt;/code&gt;).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--disable-pip-version-check&lt;/code&gt; --&amp;gt; &lt;code&gt;PIP_DISABLE_PIP_VERSION_CHECK&lt;/code&gt; &lt;br&gt;
&lt;code&gt;--timeout&lt;/code&gt; --&amp;gt; &lt;code&gt;PIP_TIMEOUT&lt;/code&gt; &lt;br&gt;
&lt;code&gt;--no-color&lt;/code&gt; --&amp;gt; &lt;code&gt;PIP_NO_COLOR&lt;/code&gt; &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;invoke &lt;code&gt;pip --help&lt;/code&gt; to get the cli options (flags)&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  General Options:
    &lt;span class="nt"&gt;--proxy&lt;/span&gt; &amp;lt;proxy&amp;gt;             Specify a proxy &lt;span class="k"&gt;in &lt;/span&gt;the form scheme://[user:passwd@]proxy.server:port.
    &lt;span class="nt"&gt;--retries&lt;/span&gt; &amp;lt;retries&amp;gt;         Maximum attempts to establish a new HTTP connection. &lt;span class="o"&gt;(&lt;/span&gt;default: 5&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nt"&gt;--timeout&lt;/span&gt; &amp;lt;sec&amp;gt;             Set the socket &lt;span class="nb"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;default 15 seconds&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
    &lt;span class="nt"&gt;--exists-action&lt;/span&gt; &amp;lt;action&amp;gt;    Default action when a path already exists: &lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt;witch, &lt;span class="o"&gt;(&lt;/span&gt;i&lt;span class="o"&gt;)&lt;/span&gt;gnore, &lt;span class="o"&gt;(&lt;/span&gt;w&lt;span class="o"&gt;)&lt;/span&gt;ipe, &lt;span class="o"&gt;(&lt;/span&gt;b&lt;span class="o"&gt;)&lt;/span&gt;ackup, &lt;span class="o"&gt;(&lt;/span&gt;a&lt;span class="o"&gt;)&lt;/span&gt;bort.
    &lt;span class="nt"&gt;--trusted-host&lt;/span&gt; &amp;lt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;   Mark this host or host:port pair as trusted, even though it does not have valid or any HTTPS.
    &lt;span class="nt"&gt;--cert&lt;/span&gt; &amp;lt;path&amp;gt;               Path to PEM-encoded CA certificate bundle. If provided, overrides the default. See &lt;span class="s1"&gt;'SSL Certificate
                                Verification'&lt;/span&gt; &lt;span class="k"&gt;in &lt;/span&gt;pip documentation &lt;span class="k"&gt;for &lt;/span&gt;more information.
    &lt;span class="nt"&gt;--client-cert&lt;/span&gt; &amp;lt;path&amp;gt;        Path to SSL client certificate, a single file containing the private key and the certificate &lt;span class="k"&gt;in &lt;/span&gt;PEM
                                format.
    &lt;span class="nt"&gt;--cache-dir&lt;/span&gt; &amp;lt;&lt;span class="nb"&gt;dir&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;           Store the cache data &lt;span class="k"&gt;in&lt;/span&gt; &amp;lt;&lt;span class="nb"&gt;dir&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
    &lt;span class="nt"&gt;--no-cache-dir&lt;/span&gt;              Disable the cache.
    &lt;span class="nt"&gt;--disable-pip-version-check&lt;/span&gt; Dont periodically check PyPI to determine whether a new version of pip is available &lt;span class="k"&gt;for &lt;/span&gt;download. Implied with &lt;span class="nt"&gt;--no-index&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
    &lt;span class="nt"&gt;--no-color&lt;/span&gt;                  Suppress colored output.
    &lt;span class="nt"&gt;--use-feature&lt;/span&gt; &amp;lt;feature&amp;gt;     Enable new functionality, that may be backward incompatible.
    &lt;span class="nt"&gt;--use-deprecated&lt;/span&gt; &amp;lt;feature&amp;gt;  Enable deprecated functionality, that will be removed &lt;span class="k"&gt;in &lt;/span&gt;the future.
    &lt;span class="nt"&gt;--resume-retries&lt;/span&gt; &amp;lt;resume_retries&amp;gt;
                                Maximum attempts to resume or restart an incomplete download. &lt;span class="o"&gt;(&lt;/span&gt;default: 0&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Notice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Security best practices in K8S&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Running processes as a non-root user using &lt;code&gt;USER nonroot:nonroot&lt;/code&gt; in the Dockerfile allows Kubernetes &lt;code&gt;SecurityContext&lt;/code&gt; settings such as &lt;code&gt;fsGroup&lt;/code&gt;, &lt;code&gt;runAsGroup&lt;/code&gt;, and &lt;code&gt;runAsUser&lt;/code&gt; to take effect in the pod template. Additionally, because the filesystem is set to &lt;code&gt;read-only&lt;/code&gt;, &lt;code&gt;PYTHONDONTWRITEBYTECODE=1&lt;/code&gt; must be set to prevent Python from writing &lt;code&gt;.pyc&lt;/code&gt; files.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/using/cmdline.html#command-line-and-environment" rel="noopener noreferrer"&gt;Python CommandLine and Environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/using/cmdline.html#envvar-PYTHONUNBUFFERED" rel="noopener noreferrer"&gt;PYTHONUNBUFFERED&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/using/cmdline.html#envvar-PYTHONDONTWRITEBYTECODE" rel="noopener noreferrer"&gt;PYTHONDONTWRITEBYTECODE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pip.pypa.io/en/stable/topics/configuration/#environment-variables" rel="noopener noreferrer"&gt;PIP Environment Variables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/" rel="noopener noreferrer"&gt;Install packages using pip&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>python</category>
      <category>devops</category>
    </item>
    <item>
      <title>TIL Kubectl CSA/SSA (Client/Server Side Apply)</title>
      <dc:creator>Ali Mehraji</dc:creator>
      <pubDate>Thu, 05 Jun 2025 14:39:43 +0000</pubDate>
      <link>https://forem.com/cod3mason/til-kubectl-csaclient-side-apply-and-ssaserver-side-apply-20k4</link>
      <guid>https://forem.com/cod3mason/til-kubectl-csaclient-side-apply-and-ssaserver-side-apply-20k4</guid>
      <description>&lt;p&gt;Kubectl CSA(Client Side Apply) and SSA(Server Side Apply).&lt;/p&gt;

&lt;p&gt;The need to read and dig into the SSA and CSA came from &lt;a href="https://github.com/longhorn/longhorn/discussions/11008" rel="noopener noreferrer"&gt;command Annotation in Installation Requirements manifests ?&lt;/a&gt; and which was validating with &lt;a href="https://youtu.be/1DWWlcDUxtA?t=704" rel="noopener noreferrer"&gt;&lt;code&gt;dry-run&lt;/code&gt;&lt;/a&gt; that Question Came from a &lt;a href="https://dev.to/alimehr75/til-may-28-2025-5547"&gt;TIL about &lt;code&gt;nsenter&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://kubernetes.io/docs/reference/using-api/server-side-apply/#field-management" rel="noopener noreferrer"&gt;Field management&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The Kubernetes API server tracks managed fields for all newly created objects. When trying to apply an object, &lt;strong&gt;&lt;em&gt;fields that have a different value&lt;/em&gt;&lt;/strong&gt; &lt;strong&gt;AND&lt;/strong&gt; &lt;strong&gt;&lt;em&gt;are owned by another manager&lt;/em&gt;&lt;/strong&gt; will result in a &lt;strong&gt;conflict&lt;/strong&gt;. This is done in order to signal that the operation might undo another collaborator's changes. Writes to objects with managed fields can be forced, in which case the value of any conflicted field will be overridden, and the ownership will be transferred.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcod3mas0n%2FDocuments%2Frefs%2Fheads%2Fmain%2Fposts%2Fassets%2Fkubectl-ssa-csa%2Fconflict.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcod3mas0n%2FDocuments%2Frefs%2Fheads%2Fmain%2Fposts%2Fassets%2Fkubectl-ssa-csa%2Fconflict.webp" alt="conflict-image" width="800" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Whenever a field's value does change, ownership moves from its current manager to the manager making the change.&lt;/p&gt;

&lt;p&gt;Compared to the (legacy) kubectl.kubernetes.io/last-applied-configuration annotation managed by kubectl, Server-Side Apply uses a more declarative approach, that tracks a user's (or client's) field management, rather than a user's last applied state. As a side effect of using Server-Side Apply, information about which field manager manages each field in an object also becomes available.&lt;/p&gt;

&lt;p&gt;Field management details are stored in a managedFields field that is part of an object's metadata.&lt;br&gt;
The field management record consists of basic information about the managing entity itself, plus details about the fields being managed and the relevant operation (Apply or Update). If the request that last changed that field was a &lt;strong&gt;Server-Side Apply patch&lt;/strong&gt; then the value of operation is &lt;strong&gt;Apply&lt;/strong&gt;; otherwise, it is &lt;strong&gt;Update&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;kubectl get omits managed fields by default. Add &lt;code&gt;--show-managed-fields&lt;/code&gt; to show &lt;code&gt;managedFields&lt;/code&gt; when the output format is either &lt;code&gt;json&lt;/code&gt; or &lt;code&gt;yaml&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Apply
&lt;/h3&gt;

&lt;p&gt;Lets apply(create) a pod then check those fields.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;netshoot.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pod&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;netshoot&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;netshoot&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nicolaka/netshoot:latest&lt;/span&gt;
      &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sleep"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;infinity"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NET_ADMIN"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SYS_MODULE"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;restartPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OnFailure&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;--server-side&lt;/span&gt; &lt;span class="nt"&gt;--dry-run&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;server &lt;span class="nt"&gt;-f&lt;/span&gt; netshoot.yaml &lt;span class="nt"&gt;-o&lt;/span&gt; yaml &lt;span class="nt"&gt;-n&lt;/span&gt; test-tool &lt;span class="nt"&gt;--show-managed-fields&lt;/span&gt; | yq .metadata.managedFields
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;managedFields&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;managedFields&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
    &lt;span class="na"&gt;fieldsType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;FieldsV1&lt;/span&gt;
    &lt;span class="na"&gt;fieldsV1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;f:spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;f:containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="s"&gt;k:{"name":"netshoot"}:&lt;/span&gt;
            &lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
            &lt;span class="na"&gt;f:command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
            &lt;span class="na"&gt;f:image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
            &lt;span class="na"&gt;f:name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
            &lt;span class="na"&gt;f:securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;f:capabilities&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;f:add&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
        &lt;span class="na"&gt;f:restartPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
    &lt;span class="na"&gt;manager&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kubectl&lt;/span&gt;
    &lt;span class="na"&gt;operation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Apply&lt;/span&gt;
    &lt;span class="na"&gt;time&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2025-06-04T20:43:41Z"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
    &lt;span class="na"&gt;fieldsType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;FieldsV1&lt;/span&gt;
    &lt;span class="na"&gt;fieldsV1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;f:metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;f:annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;.&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
          &lt;span class="na"&gt;f:cni.projectcalico.org/containerID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
          &lt;span class="na"&gt;f:cni.projectcalico.org/podIP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
          &lt;span class="na"&gt;f:cni.projectcalico.org/podIPs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
    &lt;span class="na"&gt;manager&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;calico&lt;/span&gt;
    &lt;span class="na"&gt;operation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Update&lt;/span&gt;
    &lt;span class="na"&gt;subresource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;status&lt;/span&gt;
    &lt;span class="na"&gt;time&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2025-06-04T20:43:42Z"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
    &lt;span class="na"&gt;fieldsType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;FieldsV1&lt;/span&gt;
    &lt;span class="na"&gt;fieldsV1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;f:metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;f:annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;f:ambient.istio.io/redirection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
    &lt;span class="na"&gt;manager&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;install-cni&lt;/span&gt;
    &lt;span class="na"&gt;operation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Update&lt;/span&gt;
    &lt;span class="na"&gt;subresource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;status&lt;/span&gt;
    &lt;span class="na"&gt;time&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2025-06-04T20:43:42Z"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
    &lt;span class="na"&gt;fieldsType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;FieldsV1&lt;/span&gt;
    &lt;span class="na"&gt;fieldsV1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;f:status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;f:conditions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="s"&gt;k:{"type":"ContainersReady"}:&lt;/span&gt;
            &lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
            &lt;span class="na"&gt;f:lastProbeTime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
            &lt;span class="na"&gt;f:lastTransitionTime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
            &lt;span class="na"&gt;f:status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
            &lt;span class="na"&gt;f:type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
        &lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="s"&gt;k:{"type":"Initialized"}:&lt;/span&gt;
            &lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
            &lt;span class="na"&gt;f:lastProbeTime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
            &lt;span class="na"&gt;f:lastTransitionTime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
            &lt;span class="na"&gt;f:status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
            &lt;span class="na"&gt;f:type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
        &lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="s"&gt;k:{"type":"Ready"}:&lt;/span&gt;
            &lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
            &lt;span class="na"&gt;f:lastProbeTime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
            &lt;span class="na"&gt;f:lastTransitionTime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
            &lt;span class="na"&gt;f:status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
            &lt;span class="na"&gt;f:type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
        &lt;span class="na"&gt;f:containerStatuses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
        &lt;span class="na"&gt;f:hostIP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
        &lt;span class="na"&gt;f:phase&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
        &lt;span class="na"&gt;f:podIP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
        &lt;span class="na"&gt;f:podIPs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;.&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
          &lt;span class="s"&gt;k:{"ip":"10.237.81.196"}:&lt;/span&gt;
            &lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
            &lt;span class="na"&gt;f:ip&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
        &lt;span class="na"&gt;f:startTime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
    &lt;span class="na"&gt;manager&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kubelet&lt;/span&gt;
    &lt;span class="na"&gt;operation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Update&lt;/span&gt;
    &lt;span class="na"&gt;subresource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;status&lt;/span&gt;
    &lt;span class="na"&gt;time&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2025-06-04T20:43:43Z"&lt;/span&gt;

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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Change some fields in &lt;code&gt;magaedFields&lt;/code&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;A Server-Side Apply patch request requires the client to provide its identity as a field manager. When using Server-Side Apply, trying to change a field that is controlled by a different manager results in a rejected request unless the client forces an override. For details of overrides, see &lt;a href="https://kubernetes.io/docs/reference/using-api/server-side-apply/#conflicts" rel="noopener noreferrer"&gt;Conflicts&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Invoke below command to save the current(live) state of the pod in a file, &lt;code&gt;netshoot-current.yaml&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;k get &lt;span class="nt"&gt;-n&lt;/span&gt; test-tool pod netshoot &lt;span class="nt"&gt;--show-managed-fields&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; yaml | &lt;span class="nb"&gt;tee &lt;/span&gt;netshoot-current.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change the &lt;code&gt;podIP&lt;/code&gt; and &lt;code&gt;podIPs&lt;/code&gt;, and apply it via:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pod&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;cni.projectcalico.org/podIP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CHANGE_LAST_OCTET&lt;/span&gt;
    &lt;span class="na"&gt;cni.projectcalico.org/podIPs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CHANGE_LAST_OCTET&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;--server-side&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; netshoot-current.yaml &lt;span class="nt"&gt;-n&lt;/span&gt; test-tool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we expected the &lt;a href="https://kubernetes.io/docs/reference/using-api/server-side-apply/#conflicts" rel="noopener noreferrer"&gt;Conflict&lt;/a&gt; happened, because&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The owner of those ips fields is the CNI, in this case is &lt;code&gt;calico&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AND&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;The Value of those IP Fields are different.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Error from server &lt;span class="o"&gt;(&lt;/span&gt;BadRequest&lt;span class="o"&gt;)&lt;/span&gt;: metadata.managedFields must be nil
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
    &lt;span class="s"&gt;fieldsType&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;FieldsV1&lt;/span&gt;
    &lt;span class="s"&gt;fieldsV1&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;f:metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;f:annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;.&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
          &lt;span class="na"&gt;f:cni.projectcalico.org/containerID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
          &lt;span class="na"&gt;f:cni.projectcalico.org/podIP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
          &lt;span class="na"&gt;f:cni.projectcalico.org/podIPs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
  &lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="na"&gt;manager&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;calico&lt;/span&gt;
    &lt;span class="na"&gt;operation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Update&lt;/span&gt;
    &lt;span class="na"&gt;subresource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;status&lt;/span&gt;
    &lt;span class="na"&gt;time&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2025-06-04T20:43:42Z"&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Lets do the apply command verbose with &lt;code&gt;-v=6&lt;/code&gt; to see what exactly happening with &lt;a href="https://youtu.be/1DWWlcDUxtA?t=638" rel="noopener noreferrer"&gt;imperative endpoints&lt;/a&gt; under the hood.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;--server-side&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; netshoot-current.yaml-n test-tool &lt;span class="nt"&gt;-v&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="s2"&gt;"Response"&lt;/span&gt; &lt;span class="nv"&gt;verb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"PATCH"&lt;/span&gt; &lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://rancher.example.com/k8s/clusters/&amp;lt;CLUSTER_ID&amp;gt;/api/v1/namespaces/test-tool/pods/netshoot?fieldManager=kubectl&amp;amp;fieldValidation=Strict&amp;amp;force=false"&lt;/span&gt; &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"400 Bad Request"&lt;/span&gt; &lt;span class="nv"&gt;milliseconds&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;kubectl apply --server-side&lt;/code&gt; (rejected with Bad Request)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Respects field ownership strictly

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;fieldValidation=Strict&lt;/code&gt; in query params in &lt;code&gt;PATCH&lt;/code&gt; request.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Calico owns the &lt;code&gt;PodIP&lt;/code&gt;/&lt;code&gt;PodIPs&lt;/code&gt; fields

&lt;ul&gt;
&lt;li&gt;apply is going to change the &lt;code&gt;calico&lt;/code&gt; field manager to &lt;code&gt;fieldManager=kubectl&lt;/code&gt; query param in &lt;code&gt;PATCH&lt;/code&gt; request.&lt;/li&gt;
&lt;li&gt;For other updates, the API server infers a &lt;a href="https://kubernetes.io/docs/reference/using-api/server-side-apply/#managers" rel="noopener noreferrer"&gt;Field manager&lt;/a&gt; identity from the "User-Agent:" HTTP header (if present).&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;force&lt;/code&gt; is &lt;code&gt;false&lt;/code&gt; in the &lt;code&gt;server-side&lt;/code&gt; apply to respect the ownership.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Kubernetes server rejects the conflict because you don't own those fields&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;status="400 Bad Request&lt;/code&gt; in response, This is the correct &lt;strong&gt;protective&lt;/strong&gt; behavior.
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;Bad Request&lt;span class="s2"&gt;" milliseconds=80
I0605 00:40:45.502024   24714 helpers.go:246] server response object: %s[{
  "&lt;/span&gt;kind&lt;span class="s2"&gt;": "&lt;/span&gt;Status&lt;span class="s2"&gt;",
  "&lt;/span&gt;apiVersion&lt;span class="s2"&gt;": "&lt;/span&gt;v1&lt;span class="s2"&gt;",
  "&lt;/span&gt;metadata&lt;span class="s2"&gt;": {},
  "&lt;/span&gt;status&lt;span class="s2"&gt;": "&lt;/span&gt;Failure&lt;span class="s2"&gt;",
  "&lt;/span&gt;message&lt;span class="s2"&gt;": "&lt;/span&gt;metadata.managedFields must be nil&lt;span class="s2"&gt;",
  "&lt;/span&gt;reason&lt;span class="s2"&gt;": "&lt;/span&gt;BadRequest&lt;span class="s2"&gt;",
  "&lt;/span&gt;code&lt;span class="s2"&gt;": 400
}]
Error from server (BadRequest): metadata.managedFields must be nil
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;kubectl apply&lt;/code&gt; or &lt;code&gt;kubectl edit&lt;/code&gt; (succeeded)
&lt;/h3&gt;

&lt;p&gt;If we don't use the &lt;code&gt;--server-side&lt;/code&gt; which is going to be the default apply (CSA), in that case the apply wil use the default &lt;code&gt;force=true&lt;/code&gt; in CSA.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It is however possible to change &lt;code&gt;.metadata.managedFields&lt;/code&gt; through an &lt;code&gt;update&lt;/code&gt;, or through a &lt;code&gt;patch&lt;/code&gt; operation that does not use Server-Side Apply. Doing so is &lt;strong&gt;&lt;em&gt;highly discouraged&lt;/em&gt;&lt;/strong&gt;, but might be a reasonable option to try if, for example, the &lt;code&gt;.metadata.managedFields&lt;/code&gt; get into an inconsistent state (which should not happen in normal operations).&lt;/p&gt;

&lt;p&gt;The format of managedFields is described in the Kubernetes API reference.&lt;/p&gt;

&lt;p&gt;Caution:&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;.metadata.managedFields&lt;/code&gt; field is managed by the API server. You should avoid updating it manually.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="s2"&gt;"Response"&lt;/span&gt; &lt;span class="nv"&gt;verb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"PATCH"&lt;/span&gt; &lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://rancher.example.com/k8s/clusters/&amp;lt;CLUSTER_ID&amp;gt;/api/v1/namespaces/test-tool/pods/netshoot?fieldManager=kubectl-client-side-apply&amp;amp;fieldValidation=Strict"&lt;/span&gt; &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"200 OK"&lt;/span&gt; &lt;span class="nv"&gt;milliseconds&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;97
pod/netshoot configured
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Uses Client-Side Apply (strategic merge patch)

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;fieldManager=kubectl-client-side-apply&lt;/code&gt; in query params in &lt;code&gt;PATCH&lt;/code&gt; request.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Calculates the patch on the client side&lt;/li&gt;

&lt;li&gt;Sends a PATCH request that can override existing fields&lt;/li&gt;

&lt;li&gt;Less strict about field ownership conflicts

&lt;ul&gt;
&lt;li&gt;It does validate with &lt;code&gt;fieldValidation=Strict&lt;/code&gt; in query param in &lt;code&gt;PATCH&lt;/code&gt; request, but the force is force.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Essentially "forces" the change through&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;As you can see, the manager(owner) of the &lt;code&gt;podIP&lt;/code&gt; and &lt;code&gt;podIPs&lt;/code&gt; fields changed to &lt;code&gt;kubectl-client-side-apply&lt;/code&gt; and the operation is &lt;code&gt;Update&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
  &lt;span class="na"&gt;fieldsType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;FieldsV1&lt;/span&gt;
  &lt;span class="na"&gt;fieldsV1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;f:metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;f:annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;f:cni.projectcalico.org/podIP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
        &lt;span class="na"&gt;f:cni.projectcalico.org/podIPs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
        &lt;span class="na"&gt;f:kubectl.kubernetes.io/last-applied-configuration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
  &lt;span class="na"&gt;manager&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kubectl-client-side-apply&lt;/span&gt;
  &lt;span class="na"&gt;operation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Update&lt;/span&gt;
  &lt;span class="na"&gt;time&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2025-06-04T21:26:09Z"&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conflict Example
&lt;/h2&gt;

&lt;p&gt;Scenario:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Apply &lt;a href="https://raw.githubusercontent.com/cod3mas0n/Documents/refs/heads/main/posts/assets/kubectl-ssa-csa/manifests/netshoot-deployment.yaml" rel="noopener noreferrer"&gt;&lt;code&gt;netshoot-deployment.yaml&lt;/code&gt;&lt;/a&gt; deployment with 1 replicas, no server-side, just as normal (CSA)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sets the Owner(manager) and operation of the &lt;code&gt;replicas&lt;/code&gt; field to
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;manager&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kubectl-client-side-apply&lt;/span&gt;
&lt;span class="na"&gt;operation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Update&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;kubectl.kubernetes.io/last-applied-configuration&lt;/code&gt; annotation exists.&lt;/li&gt;
&lt;li&gt;For the first time &lt;code&gt;apply&lt;/code&gt; the manager for the whole fields is &lt;code&gt;kubectl-client-side-apply&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Scale the pods with&lt;br&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  kubectl scale deployment netshoot &lt;span class="nt"&gt;-n&lt;/span&gt; test-tool &lt;span class="nt"&gt;--replicas&lt;/span&gt; 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;ad-hoc scale does not update the &lt;code&gt;last-applied-configuration&lt;/code&gt; , just sets a new owner(manager) to the &lt;code&gt;replicas&lt;/code&gt; field.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;fieldsType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;FieldsV1&lt;/span&gt;
&lt;span class="na"&gt;fieldsV1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;f:spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;f:replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;span class="na"&gt;manager&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kubectl&lt;/span&gt;
&lt;span class="na"&gt;operation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Update&lt;/span&gt;
&lt;span class="na"&gt;subresource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;scale&lt;/span&gt;

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


&lt;ul&gt;
&lt;li&gt;Another scale with changing the &lt;code&gt;replicas&lt;/code&gt; in manifest and apply with &lt;code&gt;--server-side&lt;/code&gt;, for example &lt;code&gt;replicas: 5&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  kubectl apply &lt;span class="nt"&gt;--server-side&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; netshoot-deployment.yaml &lt;span class="nt"&gt;-n&lt;/span&gt; test-tool &lt;span class="nt"&gt;-v&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Conflict &lt;code&gt;status="409 Conflict"&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="s2"&gt;"Response"&lt;/span&gt; &lt;span class="nv"&gt;verb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"PATCH"&lt;/span&gt; &lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://rancher.example.com/k8s/clusters/&amp;lt;CLUSTER_ID&amp;gt;/apis/apps/v1/namespaces/test-tool/deployments/netshoot?fieldManager=kubectl&amp;amp;fieldValidation=Strict&amp;amp;force=false"&lt;/span&gt; &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"409 Conflict"&lt;/span&gt; &lt;span class="nv"&gt;milliseconds&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;75
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```bash
error: Apply failed with 1 conflict: conflict with "kubectl" with subresource "scale" using apps/v1: .spec.replicas
Please review the fields above--they currently have other managers. Here
are the ways you can resolve this warning:
* If you intend to manage all of these fields, please re-run the apply
  command with the `--force-conflicts` flag.
* If you do not intend to manage all of the fields, please edit your
  manifest to remove references to the fields that should keep their
  current managers.
* You may co-own fields by updating your manifest to match the existing
  value; in this case, you'll become the manager if the other manager(s)
  stop managing the field (remove it from their configuration).
See https://kubernetes.io/docs/reference/using-api/server-side-apply/#conflicts
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Why we expect a conflict?
&amp;gt; A conflict is a special status error that occurs when an Apply operation tries to change a field that another manager also claims to manage. This prevents an applier from unintentionally overwriting the value set by another user.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ArgoCD
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;This option enables Kubernetes &lt;a href="https://kubernetes.io/docs/reference/using-api/server-side-apply/" rel="noopener noreferrer"&gt;Server-Side Apply&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;By default, Argo CD executes kubectl apply operation to apply the configuration stored in Git. This is a client side operation that relies on kubectl.kubernetes.io/last-applied-configuration annotation to store the previous resource state.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;However, there are some cases where you want to use kubectl apply &lt;code&gt;--server-side&lt;/code&gt; over kubectl apply:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resource is too big to fit in &lt;code&gt;262144&lt;/code&gt; bytes allowed annotation size.&lt;/li&gt;
&lt;li&gt;Patching of existing resources on the cluster that are not fully managed by Argo CD.&lt;/li&gt;
&lt;li&gt;Use a more declarative approach, which tracks a user's field management, rather than a user's last applied state.

&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;ServerSideApply=true&lt;/code&gt; sync option is set, Argo CD will use &lt;code&gt;kubectl apply --server-side&lt;/code&gt; command to apply changes.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Read More
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://argo-cd.readthedocs.io/en/stable/user-guide/sync-options/#respect-ignore-difference-configs" rel="noopener noreferrer"&gt;Argocd and HPA&lt;/a&gt;, The Question is how to control ArgoCD from interfering a Deployment Replicas when the HPA is Enabled for ?&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Kubernetes cluster deployed with Kubespray and added to a rancher cluster manually.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://youtu.be/1DWWlcDUxtA" rel="noopener noreferrer"&gt;Kubectl Apply&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/reference/using-api/server-side-apply/" rel="noopener noreferrer"&gt;Server-Side Apply&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/swlh/break-down-kubernetes-server-side-apply-5d59f6a14e26" rel="noopener noreferrer"&gt;Break Down K8S Server-Side Apply&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/reference/using-api/server-side-apply/#comparison-with-client-side-apply" rel="noopener noreferrer"&gt;Comparison with Client-Side Apply&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://argo-cd.readthedocs.io/en/stable/user-guide/sync-options/#server-side-apply" rel="noopener noreferrer"&gt;Argo-CD Server-Side Apply&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/reference/using-api/server-side-apply/#using-server-side-apply-in-a-controller" rel="noopener noreferrer"&gt;Using Server-Side Apply in a controller&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>k8s</category>
    </item>
    <item>
      <title>TIL `nsenter`</title>
      <dc:creator>Ali Mehraji</dc:creator>
      <pubDate>Wed, 28 May 2025 13:05:36 +0000</pubDate>
      <link>https://forem.com/cod3mason/til-may-28-2025-5547</link>
      <guid>https://forem.com/cod3mason/til-may-28-2025-5547</guid>
      <description>&lt;p&gt;Host Level operations on a K8S node with privileged container.&lt;/p&gt;

&lt;h2&gt;
  
  
  Annotations
&lt;/h2&gt;

&lt;p&gt;Set an annotation named &lt;code&gt;command&lt;/code&gt; and use &lt;a href="https://yaml.org/refcard.html" rel="noopener noreferrer"&gt;yaml anchor&lt;/a&gt; &lt;code&gt;&amp;amp;cmd&lt;/code&gt; to use it later.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In YAML, &amp;amp;cmd creates an anchor named cmd. You can later reference it using *cmd.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/" rel="noopener noreferrer"&gt;Kubernetes Annotations Document&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can use Kubernetes annotations to attach arbitrary non-identifying metadata to objects. Clients such as tools and libraries can retrieve this metadata.&lt;br&gt;
You can use either labels or annotations to attach metadata to Kubernetes objects. Labels can be used to select objects and to find collections of objects that satisfy certain conditions. In contrast, annotations are not used to identify and select objects. The metadata in an annotation can be small or large, structured or unstructured, and can include characters not permitted by labels. It is possible to use labels as well as annotations in the metadata of the same object.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;But&lt;/strong&gt; wait, the &lt;code&gt;&amp;amp;cmd&lt;/code&gt; yaml anchor does nothing to do with the annotation, so im waiting for the discussion.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/longhorn/longhorn/discussions/11008" rel="noopener noreferrer"&gt;[QUESTION] command Annotation in Installation Requirements manifests ?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[Update]&lt;/strong&gt;: &lt;a href="https://github.com/longhorn/longhorn/discussions/11008#discussioncomment-13321110" rel="noopener noreferrer"&gt;Discussion Answer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://raw.githubusercontent.com/longhorn/longhorn/v1.9.0/deploy/prerequisite/longhorn-nfs-installation.yaml" rel="noopener noreferrer"&gt;Longhorn NFS Installation&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DaemonSet&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;longhorn-nfs-installation&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;longhorn-system&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;longhorn-nfs-installation&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;cmd&lt;/span&gt; &lt;span class="s"&gt;OS=$(grep -E "^ID_LIKE=" /etc/os-release | cut -d '=' -f 2); if [[ -z "${OS}" ]]; then OS=$(grep -E "^ID=" /etc/os-release | cut -d '=' -f 2); fi; if [[ "${OS}" == *"debian"* ]]; then sudo apt-get update -q -y &amp;amp;&amp;amp; sudo apt-get install -q -y nfs-common &amp;amp;&amp;amp; sudo modprobe nfs; elif [[ "${OS}" == *"suse"* ]]; then sudo zypper --gpg-auto-import-keys -q refresh &amp;amp;&amp;amp; sudo zypper --gpg-auto-import-keys -q install -y nfs-client &amp;amp;&amp;amp; sudo modprobe nfs; else sudo yum makecache -q -y &amp;amp;&amp;amp; sudo yum --setopt=tsflags=noscripts install -q -y nfs-utils &amp;amp;&amp;amp; sudo modprobe nfs; fi &amp;amp;&amp;amp; if [ $? -eq 0 ]; then echo "nfs install successfully"; else echo "nfs install failed error code $?"; fi&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;longhorn-nfs-installation&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;longhorn-nfs-installation&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;hostNetwork&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;hostPID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;initContainers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nfs-installation&lt;/span&gt;
        &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;nsenter&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--mount=/proc/1/ns/mnt&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;bash&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;-c&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;*cmd&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alpine:3.12&lt;/span&gt;
        &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;privileged&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sleep&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;registry.k8s.io/pause:3.1&lt;/span&gt;
  &lt;span class="na"&gt;updateStrategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RollingUpdate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Host Level Operation on K8S Node within a container
&lt;/h2&gt;

&lt;p&gt;Was wondering how a container can install a package or do host level commands!?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;hostNetwork&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;hostPID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;initContainers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nfs-installation&lt;/span&gt;
        &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;nsenter&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--mount=/proc/1/ns/mnt&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;bash&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;-c&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;*cmd&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alpine:3.12&lt;/span&gt;
        &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;privileged&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;command&lt;/code&gt; breakdown
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://man7.org/linux/man-pages/man1/nsenter.1.html" rel="noopener noreferrer"&gt;&lt;code&gt;nsenter&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;nsenter&lt;/code&gt; is a Linux utility used to enter different namespaces of other processes — like the network, mount, PID, UTS, etc. This is useful when you want to operate inside another process's context (like the host) from within a container.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--mount=/proc/1/ns/mnt&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;enter the mount namespace of process 1 (usually the host system’s init process inside the node).&lt;br&gt;
&lt;code&gt;/proc/1/ns/mnt&lt;/code&gt; special file that represents the mount namespace of PID 1 (host).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-- bash -c *cmd&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Separator; everything after the &lt;code&gt;--&lt;/code&gt; is passed to the new shell.&lt;br&gt;
new shell runs the cmd, which is defined in the annotation of Daemonset, and as described in the &lt;a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/" rel="noopener noreferrer"&gt;K8S Annotaion&lt;/a&gt; document, the container can access to &lt;code&gt;command&lt;/code&gt; annotation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For the host(node) level operations, the &lt;code&gt;nsenter&lt;/code&gt; needs privileges&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;hostNetwork: true&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;What it does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Makes the Pod (and all containers in it) use the host’s network namespace.&lt;/li&gt;
&lt;li&gt;That means it shares the host’s network stack — same IP address, routing table, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why it’s needed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the command inside the init container needs to:&lt;/li&gt;
&lt;li&gt;Access network services that are only available on the host network (e.g., certain NFS servers or internal routes),&lt;/li&gt;
&lt;li&gt;Or resolve hostnames as the host does, this gives it direct access. 
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  kubectl explain ds.spec.template.spec.hostNetwork
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  hostNetwork   &amp;lt;boolean&amp;gt;
    Host networking requested for this pod. Use the host's network namespace. If
    this option is set, the ports that will be used must be specified. Default
    to false.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;hostPID: true&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;What it does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Makes the Pod share the host’s PID namespace.&lt;/li&gt;
&lt;li&gt;So the container can see and interact with host processes, including PID 1.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why it’s needed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using &lt;code&gt;--mount=/proc/1/ns/mnt&lt;/code&gt;, path points to PID 1’s mount namespace — which is usually the host’s root process (init/systemd).&lt;/li&gt;
&lt;li&gt;Without hostPID: true, PID 1 inside the container is not the host’s PID 1 — and nsenter would fail because /proc/1/ns/mnt would refer to the container’s own namespace, not the host’s. 
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  kubectl explain ds.spec.template.spec.hostPID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    hostPID &amp;lt;boolean&amp;gt;
    Use the host's pid namespace. Optional: Default to false.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;initContainers.securityContext.privileged: true&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  kubectl explain ds.spec.template.spec.initContainers.securityContext.privileged
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  Run container in privileged mode. Processes in privileged containers are essentially equivalent to root on the host.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Additional notes from ChatGPT
&lt;/h2&gt;

&lt;p&gt;🧠 What Happens When You Use It?&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;nsenter --mount=/proc/1/ns/mnt&lt;/code&gt;,You are telling your container&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Hey, stop using your own isolated mount namespace. Enter the host's mount namespace." &lt;br&gt;
This lets your process (inside a container) perform filesystem operations as if it were on the host.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nsenter &lt;span class="nt"&gt;--mount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/proc/1/ns/mnt &lt;span class="nt"&gt;--&lt;/span&gt; bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'mount -t nfs ...'&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;🔒 Permissions Required&lt;/p&gt;

&lt;p&gt;To access &lt;code&gt;/proc/1/ns/mnt&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You must have &lt;code&gt;CAP_SYS_ADMIN&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;In Kubernetes, that typically means the container must be run as &lt;code&gt;privileged: true&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;You also need &lt;code&gt;hostPID: true&lt;/code&gt; to ensure &lt;code&gt;PID 1&lt;/code&gt; is the host &lt;code&gt;PID 1&lt;/code&gt;, not the container's own init.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/" rel="noopener noreferrer"&gt;Kubernetes Annotations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://raw.githubusercontent.com/longhorn/longhorn/v1.9.0/deploy/prerequisite/longhorn-nfs-installation.yaml" rel="noopener noreferrer"&gt;longhorn-nfs-installation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://labs.iximiuz.com/tutorials/containers-vs-pods/" rel="noopener noreferrer"&gt;container vs pods&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://man7.org/linux/man-pages/man7/namespaces.7.html" rel="noopener noreferrer"&gt;Namespaces&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://man7.org/linux/man-pages/man8/lsns.8.html" rel="noopener noreferrer"&gt;lsns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://man7.org/linux/man-pages/man5/proc.5.html#" rel="noopener noreferrer"&gt;proc&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>career</category>
      <category>k8s</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Offline, Multistage Python Dockerfile</title>
      <dc:creator>Ali Mehraji</dc:creator>
      <pubDate>Mon, 26 May 2025 21:00:16 +0000</pubDate>
      <link>https://forem.com/cod3mason/offline-multistage-python-dockerfile-n2j</link>
      <guid>https://forem.com/cod3mason/offline-multistage-python-dockerfile-n2j</guid>
      <description>&lt;p&gt;There Was a need to reduce a python application docker image size, also had to have offline installation either in the PYPI packages installation or in APT update and installing packages.&lt;/p&gt;

&lt;p&gt;Lets get to the Optimization Line by Line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker build &lt;code&gt;buildx&lt;/code&gt; &lt;code&gt;syntax&lt;/code&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;First of all make sure docker uses the &lt;code&gt;docker buildx&lt;/code&gt; as its default &lt;code&gt;docker build&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://docs.docker.com/build/buildkit/#getting-started" rel="noopener noreferrer"&gt;BuildKit&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you have installed Docker Desktop, you don't need to enable BuildKit. If you are running a version of Docker Engine version earlier than 23.0, you can enable BuildKit either by setting an environment variable, or by making BuildKit the default setting in the daemon configuration.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;DOCKER_BUILDKIT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 docker build &lt;span class="nt"&gt;--file&lt;/span&gt; /path/to/dockerfile &lt;span class="nt"&gt;-t&lt;/span&gt; docker_image_name:tag
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;# syntax=docker/dockerfile:1.4&lt;/code&gt; for the &lt;a href="https://www.docker.com/blog/introduction-to-heredocs-in-dockerfiles/" rel="noopener noreferrer"&gt;heredoc in Dockerfile&lt;/a&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# syntax=docker/dockerfile:1.4 # Required for heredocs [3, 4]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Project Directory Tree
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── main.py
├── requirements.txt
└── src
    ├── log.py
    └── prometheus.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Multistage Dockerfile
&lt;/h2&gt;

&lt;p&gt;as mentioned before, at first provisioning the &lt;code&gt;base&lt;/code&gt; stage to be used in the next &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;runtime&lt;/code&gt; stages.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;base&lt;/code&gt; stage
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;base image
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; JFROG=jfrog.example.com&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;${JFROG}/docker/python:3.13-slim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;base&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Change the default SHELL

&lt;ul&gt;
&lt;li&gt;A safe way with custom shell with &lt;code&gt;pipefail&lt;/code&gt; and &lt;code&gt;errexit&lt;/code&gt; options, its very useful in the Heredoc in the Debian Private repo setup section.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;SHELL&lt;/span&gt;&lt;span class="s"&gt; ["/bin/bash", "-c", "-o", "pipefail", "-o", "errexit"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Environments, see &lt;a href="https://dev.to/alimehr75/python-env-variables-in-dockerfile-5920"&gt;Python Env Variables in Dockerfile&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; JFROG=jfrog.example.com&lt;/span&gt;

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PYTHONUNBUFFERED=1 \&lt;/span&gt;
    PYTHONDONTWRITEBYTECODE=1 \
    PIP_DISABLE_PIP_VERSION_CHECK=on \
    PIP_TIMEOUT=60 \
    PIP_INDEX_URL=https://${JFROG}/artifactory/api/pypi/python/simple/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Private Debian Repository (Offline Installation)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Used &lt;a href="https://www.docker.com/blog/introduction-to-heredocs-in-dockerfiles/" rel="noopener noreferrer"&gt;&lt;code&gt;heredoc&lt;/code&gt;&lt;/a&gt; in Docker to change the base image apt sources to update and install packages from private Debian repository. heredoc needs the &lt;a href="https://docs.docker.com/build/buildkit/frontend/" rel="noopener noreferrer"&gt;dockerfile syntax&lt;/a&gt; mentioned before.&lt;br&gt;
   If the structure of the Debian repo is different in a private repo , please change the &lt;code&gt;URIs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://repolib.readthedocs.io/en/latest/deb822-format.html#deb822-style-format" rel="noopener noreferrer"&gt;DEB822 format (apt .sources files)&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Using DEB822 format (.sources files) - for newer systems&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;

CODENAME=$(grep VERSION_CODENAME /etc/os-release | cut -d'=' -f2)
DISTRO=$(grep '^ID=' /etc/os-release | cut -d'=' -f2)

cat &amp;gt; /etc/apt/sources.list.d/debian.sources &amp;lt;&amp;lt;SOURCE_FILE_CONTENT
Types: deb
URIs: https://${JFROG}/artifactory/debian/debian/
Suites: ${CODENAME} ${CODENAME}-updates
Components: main
Trusted: true

Types: deb
URIs: https://${JFROG}/artifactory/debian/debian-security/
Suites: ${CODENAME}-security
Components: main
Trusted: true
SOURCE_FILE_CONTENT
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Install Shared and common packages in all stages.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the package installation there is no need to install recommended packages to reduces the image size.&lt;/li&gt;
&lt;li&gt;After installation, for the sake of size image there is need to remove packages downloads. 
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;--no-install-recommends&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    ca-certificates &lt;span class="se"&gt;\
&lt;/span&gt;    curl &lt;span class="se"&gt;\
&lt;/span&gt;    gnupg &lt;span class="se"&gt;\
&lt;/span&gt;    lsb-release &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;build&lt;/code&gt; stage
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use the prepared &lt;code&gt;base&lt;/code&gt; image as &lt;code&gt;build&lt;/code&gt; image
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;There was no need for build specific packages in all stages, so just install them in &lt;code&gt;build&lt;/code&gt; stage.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;--no-install-recommends&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    build-essential &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Install requirements&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Change directory to &lt;code&gt;app&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create virtualenv, in the &lt;code&gt;runtime&lt;/code&gt; stage, &lt;a href="https://pythonspeed.com/articles/multi-stage-docker-python/" rel="noopener noreferrer"&gt;the &lt;code&gt;virtualenv&lt;/code&gt; will be copied&lt;/a&gt; in image.&lt;/li&gt;
&lt;li&gt;use the &lt;a href="https://docs.docker.com/build/cache/optimize/#use-cache-mounts" rel="noopener noreferrer"&gt;cache mount&lt;/a&gt; for faster build.&lt;/li&gt;
&lt;li&gt;For the sake of image size install requirements with &lt;a href="https://pip.pypa.io/en/latest/topics/caching/#disabling-caching" rel="noopener noreferrer"&gt;disabling pip cache&lt;/a&gt; with &lt;code&gt;--no-cache-dir&lt;/code&gt; flag. 
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PATH="/app/.venv/bin:$PATH"&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; requirements.txt .&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nt"&gt;--mount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cache,target&lt;span class="o"&gt;=&lt;/span&gt;/root/.cache/pip &lt;span class="se"&gt;\
&lt;/span&gt;pip &lt;span class="nt"&gt;--timeout&lt;/span&gt; 100 &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-cache-dir&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;runtime&lt;/code&gt; stage
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use the prepared &lt;code&gt;base&lt;/code&gt; image as &lt;code&gt;build&lt;/code&gt; image
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Security best practices&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create &lt;code&gt;group&lt;/code&gt; and &lt;code&gt;user&lt;/code&gt; to leverage the kubernetes &lt;code&gt;runAsUser&lt;/code&gt;, &lt;code&gt;runAsGroup&lt;/code&gt; and &lt;code&gt;fsGroup&lt;/code&gt; &lt;a href="https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#supplementalgroupspolicy" rel="noopener noreferrer"&gt;&lt;code&gt;securityContext&lt;/code&gt;&lt;/a&gt; 
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;RUN &lt;/span&gt;addgroup &lt;span class="nt"&gt;--gid&lt;/span&gt; 1001 &lt;span class="nt"&gt;--system&lt;/span&gt; nonroot &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    adduser &lt;span class="nt"&gt;--no-create-home&lt;/span&gt; &lt;span class="nt"&gt;--shell&lt;/span&gt; /bin/false &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;--disabled-password&lt;/span&gt; &lt;span class="nt"&gt;--uid&lt;/span&gt; 1001 &lt;span class="nt"&gt;--system&lt;/span&gt; &lt;span class="nt"&gt;--group&lt;/span&gt; nonroot

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; nonroot:nonroot&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;VirtualEnv&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add the &lt;code&gt;/app/.venv/bin&lt;/code&gt; into &lt;code&gt;PATH&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pythonspeed.com/articles/multi-stage-docker-python/" rel="noopener noreferrer"&gt;Copy the &lt;code&gt;virtualenv&lt;/code&gt;&lt;/a&gt; from build stage. 
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; VIRTUAL_ENV=/app/.venv \&lt;/span&gt;
    PATH="/app/.venv/bin:$PATH"

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build --chown=nonroot:nonroot /app/.venv /app/.venv&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Copy &lt;code&gt;src&lt;/code&gt; directory.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --chown=nonroot:nonroot src /app/src&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --chown=nonroot:nonroot main.py .&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CMD&lt;/code&gt; to run container from image.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["python", "/app/main.py"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Before And After The optimization
&lt;/h2&gt;



&lt;h3&gt;
  
  
  Before The Optimization
&lt;/h3&gt;



&lt;p&gt;The Dockerfile was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; jfrog.example.com/docker/python:latest&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="s"&gt; src/ .&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;pip config &lt;span class="nb"&gt;set &lt;/span&gt;global.index-url https://jfrog.example.com/artifactory/api/pypi/python/simple/ &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;  &lt;span class="se"&gt;\
&lt;/span&gt;    pip &lt;span class="nt"&gt;--timeout&lt;/span&gt; 100 &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["python","-u","main.py"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After build its size was &lt;code&gt;1.02GB&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Dockerfile After Optimization
&lt;/h3&gt;



&lt;p&gt;After all Optimization and multistage Dockerfile its size reduced to &lt;code&gt;242MB&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# syntax=docker/dockerfile:1.4 # Required for heredocs [3, 4]&lt;/span&gt;

&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; PYTHON_VERSION=3.12.3&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; JFROG=jfrog.example.com&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;${JFROG}/docker/python:${PYTHON_VERSION}-slim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;base&lt;/span&gt;
&lt;span class="k"&gt;SHELL&lt;/span&gt;&lt;span class="s"&gt; ["/bin/bash", "-c", "-o", "pipefail", "-o", "errexit"]&lt;/span&gt;

&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; JFROG=jfrog.example.com&lt;/span&gt;

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PYTHONUNBUFFERED=1 \&lt;/span&gt;
    PYTHONDONTWRITEBYTECODE=1 \
    PIP_DISABLE_PIP_VERSION_CHECK=on \
    PIP_TIMEOUT=60 \
    PIP_INDEX_URL=https://${JFROG}/artifactory/api/pypi/python/simple/

# Using DEB822 format (.sources files) - for newer systems
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;

CODENAME=$(grep VERSION_CODENAME /etc/os-release | cut -d'=' -f2)
# DISTRO=$(grep '^ID=' /etc/os-release | cut -d'=' -f2)

cat &amp;gt; /etc/apt/sources.list.d/debian.sources &amp;lt;&amp;lt;SOURCE_FILE_CONTENT
Types: deb
URIs: https://${JFROG}/artifactory/debian/debian/
Suites: ${CODENAME} ${CODENAME}-updates
Components: main
Trusted: true

Types: deb
URIs: https://${JFROG}/artifactory/debian/debian-security/
Suites: ${CODENAME}-security
Components: main
Trusted: true
SOURCE_FILE_CONTENT
EOF

&lt;span class="c"&gt;# securely copy .netrc using BuildKit secrets&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nt"&gt;--mount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;secret,id&lt;span class="o"&gt;=&lt;/span&gt;netrc,target&lt;span class="o"&gt;=&lt;/span&gt;/root/.netrc &lt;span class="se"&gt;\
&lt;/span&gt;    apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-install-recommends&lt;/span&gt; &lt;span class="nt"&gt;--no-install-suggests&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;      ca-certificates &lt;span class="se"&gt;\
&lt;/span&gt;      gnupg &lt;span class="se"&gt;\
&lt;/span&gt;      curl &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get clean &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get remove &lt;span class="nt"&gt;--purge&lt;/span&gt; &lt;span class="nt"&gt;--auto-remove&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;

&lt;span class="c"&gt;# securely copy .netrc using BuildKit secrets&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nt"&gt;--mount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;secret,id&lt;span class="o"&gt;=&lt;/span&gt;netrc,target&lt;span class="o"&gt;=&lt;/span&gt;/root/.netrc &lt;span class="se"&gt;\
&lt;/span&gt;    apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-install-recommends&lt;/span&gt; &lt;span class="nt"&gt;--no-install-suggests&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;      build-essential &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get clean &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get remove &lt;span class="nt"&gt;--purge&lt;/span&gt; &lt;span class="nt"&gt;--auto-remove&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PATH="/app/.venv/bin:$PATH"&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; requirements.txt .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nt"&gt;--mount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cache,target&lt;span class="o"&gt;=&lt;/span&gt;/root/.cache/pip &lt;span class="se"&gt;\
&lt;/span&gt;    pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--timeout&lt;/span&gt; 100 &lt;span class="nt"&gt;--no-cache-dir&lt;/span&gt; &lt;span class="nt"&gt;--upgrade&lt;/span&gt; pip &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--timeout&lt;/span&gt; 100 &lt;span class="nt"&gt;--no-cache-dir&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;runtime&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;addgroup &lt;span class="nt"&gt;--gid&lt;/span&gt; 1001 &lt;span class="nt"&gt;--system&lt;/span&gt; nonroot &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    adduser &lt;span class="nt"&gt;--no-create-home&lt;/span&gt; &lt;span class="nt"&gt;--shell&lt;/span&gt; /bin/false &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;--disabled-password&lt;/span&gt; &lt;span class="nt"&gt;--uid&lt;/span&gt; 1001 &lt;span class="nt"&gt;--system&lt;/span&gt; &lt;span class="nt"&gt;--group&lt;/span&gt; nonroot

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; nonroot:nonroot&lt;/span&gt;

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; VIRTUAL_ENV=/app/.venv \&lt;/span&gt;
    PATH="/app/.venv/bin:$PATH"

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build --chown=nonroot:nonroot /app/.venv /app/.venv&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --chown=nonroot:nonroot src /app/src&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --chown=nonroot:nonroot main.py .&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["python", "/app/main.py"]&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Notice
&lt;/h2&gt;

&lt;p&gt;After a second thought, realized there is no need for dockerfile syntax version 1.4 to manipulate the &lt;code&gt;apt&lt;/code&gt; sources, it could be done with &lt;code&gt;sed&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The new dockerfile syntax was fun to learn, so i keep this guide as it is.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/cod3mas0n/Dockerfiles/blob/main/Offline-Dockerfiles/Dockerfile" rel="noopener noreferrer"&gt;Dockerfile&lt;/a&gt; with no new syntax and manipulating the &lt;code&gt;apt&lt;/code&gt; sources via &lt;code&gt;sed&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Updates
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Mon Jul 14 2025&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add Credentials for Artifactories with authentication&lt;/li&gt;
&lt;li&gt;handled via &lt;code&gt;.netrc&lt;/code&gt; and mount it in build time via &lt;a href="https://docs.docker.com/build/buildkit/#getting-started" rel="noopener noreferrer"&gt;Buildkit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;no credential exposed in image history or saved in image with &lt;a href="https://docs.docker.com/build/building/secrets/#secret-mounts" rel="noopener noreferrer"&gt;Secret Mount&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Added Line
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nt"&gt;--mount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;secret,id&lt;span class="o"&gt;=&lt;/span&gt;netrc,target&lt;span class="o"&gt;=&lt;/span&gt;/root/.netrc
&lt;/code&gt;&lt;/pre&gt;



&lt;ul&gt;
&lt;li&gt;After update, updating and installing packages steps
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# securely copy .netrc using BuildKit secrets&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nt"&gt;--mount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;secret,id&lt;span class="o"&gt;=&lt;/span&gt;netrc,target&lt;span class="o"&gt;=&lt;/span&gt;/root/.netrc &lt;span class="se"&gt;\
&lt;/span&gt;    apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;--no-install-recommends&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    build-essential &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get clean &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://labs.iximiuz.com/challenges/dockerize-python-application" rel="noopener noreferrer"&gt;Dockerize Python Application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/reference/dockerfile/" rel="noopener noreferrer"&gt;Dockerfile Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.docker.com/blog/introduction-to-heredocs-in-dockerfiles/" rel="noopener noreferrer"&gt;Heredoc in Dockerfile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/build/buildkit/frontend/" rel="noopener noreferrer"&gt;Custom Dockerfile Syntax&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://repolib.readthedocs.io/en/latest/deb822-format.html#deb822-style-format" rel="noopener noreferrer"&gt;Deb822-style Format&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/build/concepts/overview/" rel="noopener noreferrer"&gt;Docker build Concepts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/using/cmdline.html#command-line-and-environment" rel="noopener noreferrer"&gt;Python cmdline &amp;amp; environments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pip.pypa.io/en/stable/topics/configuration/" rel="noopener noreferrer"&gt;PIP Configuration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>python</category>
      <category>devops</category>
      <category>debian</category>
    </item>
    <item>
      <title>Alertmanager with Telegram for Prometheus-Stack in K8S</title>
      <dc:creator>Ali Mehraji</dc:creator>
      <pubDate>Sun, 09 Mar 2025 12:06:12 +0000</pubDate>
      <link>https://forem.com/cod3mason/alertmanager-with-telegram-for-prometheus-stack-in-k8s-2n5p</link>
      <guid>https://forem.com/cod3mason/alertmanager-with-telegram-for-prometheus-stack-in-k8s-2n5p</guid>
      <description>&lt;h3&gt;
  
  
  &lt;a href="https://www.directual.com/lesson-library/how-to-create-a-telegram-bot" rel="noopener noreferrer"&gt;How to create a Telegram bot&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;To create a Telegram bot, you'll need to have the Telegram app installed on your computer. If you don't have it already, you can download it from the Telegram website.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect to BotFather and hit the &lt;code&gt;/newbot&lt;/code&gt; and follow the instruction&lt;/p&gt;

&lt;p&gt;BotFather is a bot created by Telegram that allows you to create and manage your own bots. To connect to BotFather, search for "&lt;a class="mentioned-user" href="https://dev.to/botfather"&gt;@botfather&lt;/a&gt;" in the Telegram app and click on the result to start a conversation.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In case you’d like a more detailed walkthrough, we suggest you take a look at this amazing &lt;a href="https://core.telegram.org/bots/tutorial" rel="noopener noreferrer"&gt;tutorial&lt;/a&gt; prepared by Telegram.&lt;/p&gt;

&lt;p&gt;Save the bot access token, it will be used in seting up telegram receiver in alertmanager.Also, join the bot to a channel/group to get the messages.&lt;br&gt;
&lt;br&gt;
To get a info about the bot&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;bot&lt;/code&gt; prefix has to be in the URL before the &lt;br&gt;
bot.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;BOT_ACCESS_TOKEN&lt;/code&gt;: it is provided by the &lt;code&gt;"@BotFather"&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://api.telegram.org/bot&amp;lt;BOT_ACCESS_TOKEN&amp;gt;/getMe | jq &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"result"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;some_id&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"is_bot"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"first_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="s2"&gt;"bot_name"&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="s2"&gt;"bot_username"&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"can_join_groups"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"can_read_all_group_messages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"supports_inline_queries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"can_connect_to_business"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"has_main_web_app"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CHAT_ID&lt;/code&gt;: After joining the bot to a channel/group , get the &lt;code&gt;chat_id&lt;/code&gt; which you want to send message on behalf of the bot to that channel/group .
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://api.telegram.org/bot&amp;lt;BOT_ACCESS_TOKEN&amp;gt;/getUpdates | jq &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;To Send a test message&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"https://api.telegram.org/bot&amp;lt;BOT_ACCESS_TOKEN&amp;gt;/sendMessage"&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"chat_id=&amp;lt;CHAT_ID&amp;gt;"&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"text=Hello, World!"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;Let's say the &lt;code&gt;prometheus-stack&lt;/code&gt; is installed via &lt;code&gt;helm&lt;/code&gt; or its &lt;code&gt;operator&lt;/code&gt; in K8S cluster.&lt;br&gt;
The release name will be used in many objects like &lt;code&gt;AlertmanagerConfig&lt;/code&gt;, &lt;code&gt;ServiceMonitor&lt;/code&gt;, &lt;code&gt;PodMonitor&lt;/code&gt;, etc ... which the prometheus operator be able to select objects and add configs to the prometheus or alertmanager .&lt;/p&gt;

&lt;p&gt;get release list in the &lt;code&gt;prometheus&lt;/code&gt; namespace&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm list &lt;span class="nt"&gt;-n&lt;/span&gt; prometheus
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME                NAMESPACE   REVISION    UPDATED                                     STATUS      CHART                           APP VERSION
prometheus-stack    prometheus  1       2025-03-08 23:34:47.082601345 +0330 +0330   deployed    kube-prometheus-stack-68.4.4    v0.79.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h2&gt;
  
  
  &lt;code&gt;AlertmanagerConfig&lt;/code&gt; to define the &lt;code&gt;Telegram&lt;/code&gt; receiver
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GROUP:      monitoring.coreos.com
KIND:       AlertmanagerConfig
VERSION:    v1alpha1

DESCRIPTION:
    AlertmanagerConfig configures the Prometheus Alertmanager,
    specifying how alerts should be grouped, inhibited and notified to external
    systems.

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;telegramConfigs&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl explain AlertmanagerConfig.spec.receivers.telegramConfigs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GROUP:      monitoring.coreos.com
KIND:       AlertmanagerConfig
VERSION:    v1alpha1

FIELD: telegramConfigs &amp;lt;[]Object&amp;gt;


DESCRIPTION:
    List of Telegram configurations.
    TelegramConfig configures notifications via Telegram.
    See
    https://prometheus.io/docs/alerting/latest/configuration/#telegram_config

  botToken  &amp;lt;Object&amp;gt;
    Telegram bot token. It is mutually exclusive with `botTokenFile`.
    The secret needs to be in the same namespace as the AlertmanagerConfig
    object and accessible by the Prometheus Operator.

    Either `botToken` or `botTokenFile` is required.

  chatID    &amp;lt;integer&amp;gt; -required-
    The Telegram chat ID.

  parseMode &amp;lt;string&amp;gt;
  enum: MarkdownV2, Markdown, HTML
    Parse mode for telegram message

  sendResolved  &amp;lt;boolean&amp;gt;
    Whether to notify about resolved alerts.

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;botToken&lt;/code&gt; has to be a &lt;code&gt;Secret&lt;/code&gt; in the same &lt;code&gt;namespace&lt;/code&gt; as the &lt;code&gt;AlertmanagerConfig&lt;/code&gt;. lets say we name the secret file name &lt;code&gt;telegram-bot-token-secret.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Secret&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;telegram-bot-token-secret&lt;/span&gt; &lt;span class="c1"&gt;# secret name will be referred in botToken in AlertmanagerConfig&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prometheus&lt;/span&gt; &lt;span class="c1"&gt;# same `namespace` as the `AlertmanagerConfig`.&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Opaque&lt;/span&gt;
&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# bot-token will be used as key for botToken in AlermanagerConfig.&lt;/span&gt;
  &lt;span class="na"&gt;bot-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;Base64-encoded-BOT-TOKEN&amp;gt;&lt;/span&gt;
  &lt;span class="c1"&gt;# example&lt;/span&gt;
  &lt;span class="c1"&gt;# echo -n "&amp;lt;BOT_ACCESS_TOKEN&amp;gt;" | base64 (Token without bot prefix, exactly the token get from bot_father)&lt;/span&gt;

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create the &lt;code&gt;Secret&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; telegram-bot-token-secret.yaml &lt;span class="nt"&gt;-n&lt;/span&gt; prometheus
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h3&gt;
  
  
  &lt;code&gt;AlertmanagerConfig&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Create a new file named &lt;code&gt;alertmanagerconfig-telegram.yaml&lt;/code&gt; with contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;monitoring.coreos.com/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AlertmanagerConfig&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alert-config-telegram&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prometheus&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prometheus-stack&lt;/span&gt; &lt;span class="c1"&gt;# the release label should be the exact label of the prometheus helm release label&lt;/span&gt;
    &lt;span class="na"&gt;alertmanagerConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alertmanager-telegram&lt;/span&gt; &lt;span class="c1"&gt;# custom label and also set this label to alertmanager in the prometheus-stack values.yaml&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;route&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;groupBy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;alertname"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;job"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;namespace"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# it could be other labels to be grouped by&lt;/span&gt;
    &lt;span class="na"&gt;groupWait&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;
    &lt;span class="na"&gt;groupInterval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5m&lt;/span&gt;
    &lt;span class="na"&gt;repeatInterval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1h&lt;/span&gt;
    &lt;span class="na"&gt;receiver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;telegram"&lt;/span&gt;
    &lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;receiver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;telegram"&lt;/span&gt;
      &lt;span class="na"&gt;matchers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;severity&lt;/span&gt;
          &lt;span class="na"&gt;matchType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;=~"&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;warning|critical"&lt;/span&gt;
  &lt;span class="na"&gt;receivers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;telegram&lt;/span&gt;
      &lt;span class="na"&gt;telegramConfigs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;botToken&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;telegram-bot-token-secret&lt;/span&gt; &lt;span class="c1"&gt;# refer to the secret name has been created before&lt;/span&gt;
            &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bot-token&lt;/span&gt; &lt;span class="c1"&gt;# bot-token data in the secret&lt;/span&gt;
          &lt;span class="na"&gt;chatID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;CHAT_ID&amp;gt;&lt;/span&gt;
          &lt;span class="na"&gt;parseMode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;MarkdownV2'&lt;/span&gt; &lt;span class="c1"&gt;# The template I provide is in Markdown Mode&lt;/span&gt;
          &lt;span class="na"&gt;disableNotifications&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
          &lt;span class="na"&gt;sendResolved&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create the &lt;code&gt;AlertmanagerConfig&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;/div&gt;





&lt;h3&gt;
  
  
  The &lt;code&gt;alertmanager&lt;/code&gt; changes in the&lt;code&gt;prometheus-stack&lt;/code&gt; &lt;code&gt;values.yaml&lt;/code&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Templates in &lt;code&gt;alertmanager.templateFiles&lt;/code&gt; will be mounted in &lt;code&gt;/etc/alertmanager/config/*.tmpl&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;telegram.tmpl&lt;/code&gt; will be mounted as &lt;code&gt;/etc/alertmanager/config/telegram.tmpl&lt;/code&gt;, with defining the &lt;code&gt;{{ define "telegram.default.message" }}&lt;/code&gt; there is no need to define &lt;code&gt;message&lt;/code&gt; in the &lt;code&gt;AlertmanagerConfig.spec.receivers.telegramConfigs&lt;/code&gt;. with that the default template for the telegram will be overwritten.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;alertmanager&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;templateFiles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;telegram.tmpl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|-&lt;/span&gt;
        &lt;span class="s"&gt;{{ define "telegram.default.message" }}&lt;/span&gt;
        &lt;span class="s"&gt;{{- if eq .Status "firing" -}}&lt;/span&gt;
            &lt;span class="s"&gt;{{- if eq .CommonLabels.severity "critical" -}}&lt;/span&gt;
                &lt;span class="s"&gt;🔴 Alert: {{ .CommonLabels.alertname }}&lt;/span&gt;
            &lt;span class="s"&gt;{{- else if eq .CommonLabels.severity "warning" -}}&lt;/span&gt;
                &lt;span class="s"&gt;🟠 Alert: {{ .CommonLabels.alertname }}&lt;/span&gt;
            &lt;span class="s"&gt;{{- else -}}&lt;/span&gt;
                &lt;span class="s"&gt;⚪️ Alert: {{ .CommonLabels.alertname }}&lt;/span&gt;
            &lt;span class="s"&gt;{{- end }}&lt;/span&gt;
        &lt;span class="s"&gt;Status: 🔥 FIRING&lt;/span&gt;
        &lt;span class="s"&gt;Severity: {{ if eq .CommonLabels.severity "critical" }}🔴 {{ .CommonLabels.severity | title }}{{ else if eq .CommonLabels.severity "warning" }}🟠 {{ .CommonLabels.severity | title }}{{ else }}⚪️ {{ .CommonLabels.severity | title }}{{ end }}&lt;/span&gt;
        &lt;span class="s"&gt;{{- else if eq .Status "resolved" -}}&lt;/span&gt;
            &lt;span class="s"&gt;⚪️ Alert: {{ .CommonLabels.alertname }}&lt;/span&gt;
        &lt;span class="s"&gt;Status: ✅ RESOLVED&lt;/span&gt;
        &lt;span class="s"&gt;Severity: {{ if eq .CommonLabels.severity "critical" }}🟢 {{ .CommonLabels.severity | title }}{{ else if eq .CommonLabels.severity "warning" }}🟢 {{ .CommonLabels.severity | title }}{{ else }}⚪️ {{ .CommonLabels.severity | title }}{{ end }}&lt;/span&gt;
        &lt;span class="s"&gt;{{- end }}&lt;/span&gt;

        &lt;span class="s"&gt;{{- range .Alerts -}}&lt;/span&gt;

        &lt;span class="s"&gt;{{- if .Labels.job }}&lt;/span&gt;
        &lt;span class="s"&gt;Job: `{{ .Labels.job }}`&lt;/span&gt;
        &lt;span class="s"&gt;{{- end }}&lt;/span&gt;

        &lt;span class="s"&gt;{{- if .Labels.namespace }}&lt;/span&gt;
        &lt;span class="s"&gt;Namespace: `{{ .Labels.namespace }}`&lt;/span&gt;
        &lt;span class="s"&gt;{{- end }}&lt;/span&gt;

        &lt;span class="s"&gt;{{- if .Labels.instance }}&lt;/span&gt;
        &lt;span class="s"&gt;Instance: `{{ .Labels.instance }}`&lt;/span&gt;
        &lt;span class="s"&gt;{{- end }}&lt;/span&gt;

        &lt;span class="s"&gt;{{- if .Annotations.runbook_url }}&lt;/span&gt;
        &lt;span class="s"&gt;[RunbookURL]({{ .Annotations.runbook_url }})&lt;/span&gt;

        &lt;span class="s"&gt;{{- end }}&lt;/span&gt;
        &lt;span class="s"&gt;{{- end }}&lt;/span&gt;
        &lt;span class="s"&gt;{{ end }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Example Message&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🟠 Alert: TargetDown
Status: 🔥 FIRING
Severity: 🟠 Warning
Job: kube-proxy
Namespace: kube-system
RunbookURL
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;alertmanagerConfigSelector&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;alertmanager&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;alertmanagerSpec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;## AlertmanagerConfigs to be selected to merge and configure Alertmanager with.&lt;/span&gt;
      &lt;span class="c1"&gt;##&lt;/span&gt;
      &lt;span class="na"&gt;alertmanagerConfigSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;alertmanagerConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alertmanager-telegram&lt;/span&gt; &lt;span class="c1"&gt;# it is the same label in the AlertmanagerConfig.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;alertmanagerConfigMatcherStrategy&lt;/code&gt; with the &lt;code&gt;None&lt;/code&gt; Type the &lt;code&gt;AlertmanagerConfig&lt;/code&gt; will match the all alerts.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  kubectl explain Alertmanager.spec.alertmanagerConfigMatcherStrategy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  GROUP:      monitoring.coreos.com
  KIND:       Alertmanager
  VERSION:    v1

  FIELD: alertmanagerConfigMatcherStrategy &amp;lt;Object&amp;gt;


  DESCRIPTION:
      AlertmanagerConfigMatcherStrategy defines how AlertmanagerConfig objects
      process incoming alerts.

  FIELDS:
  type  &amp;lt;string&amp;gt;
  enum: OnNamespace, None
    AlertmanagerConfigMatcherStrategyType defines the strategy used by
    AlertmanagerConfig objects to match alerts in the routes and inhibition
    rules.

    The default value is `OnNamespace`.

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

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;alertmanager&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;alertmanagerSpec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;## Defines the strategy used by AlertmanagerConfig objects to match alerts. eg:&lt;/span&gt;
      &lt;span class="c1"&gt;##&lt;/span&gt;
      &lt;span class="na"&gt;alertmanagerConfigMatcherStrategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;None&lt;/span&gt;
      &lt;span class="c1"&gt;## Example with use OnNamespace strategy&lt;/span&gt;
      &lt;span class="c1"&gt;# alertmanagerConfigMatcherStrategy:&lt;/span&gt;
      &lt;span class="c1"&gt;#   type: OnNamespace&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;After all changes are made in the &lt;code&gt;values.yaml&lt;/code&gt;, apply changes , in the case you installed the &lt;code&gt;prometheus-stack&lt;/code&gt; with &lt;code&gt;helm&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm upgrade prometheus-stack &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; prometheus &lt;span class="nt"&gt;--values&lt;/span&gt; values.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Example alerts via &lt;code&gt;prometheus-rule&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Create a file named &lt;code&gt;targets-prometheus-rules.yaml&lt;/code&gt; with contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;monitoring.coreos.com/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PrometheusRule&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prometheus&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;targets&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prometheus-stack&lt;/span&gt; &lt;span class="c1"&gt;# this label has to be the release name prometheus-stack&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;groups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;targets&lt;/span&gt;
      &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;alert&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PrometheusTargetMissing&lt;/span&gt;
          &lt;span class="na"&gt;expr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;up == &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
          &lt;span class="na"&gt;for&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2m&lt;/span&gt;
          &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;warning&lt;/span&gt;
          &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Prometheus&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;target&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;missing&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;(instance&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$labels.instance&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;)"&lt;/span&gt;
            &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Prometheus&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;target&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;has&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;disappeared.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;An&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;exporter&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;might&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;be&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;crashed.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="nv"&gt;  &lt;/span&gt;&lt;span class="s"&gt;VALUE&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$value&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="nv"&gt;  &lt;/span&gt;&lt;span class="s"&gt;LABELS&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$labels&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;

        &lt;span class="c1"&gt;# node_exporter related metrics for alert&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;alert&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HostOutOfMemory&lt;/span&gt;
          &lt;span class="na"&gt;expr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;(node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes &amp;lt; .10)&lt;/span&gt;
          &lt;span class="na"&gt;for&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2m&lt;/span&gt;
          &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;warning&lt;/span&gt;
          &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Host out of memory (instance {{ $labels.instance }})&lt;/span&gt;
            &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Node&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;memory&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;is&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;filling&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;up&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;10%&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;left)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="nv"&gt;  &lt;/span&gt;&lt;span class="s"&gt;VALUE&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$value&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="nv"&gt;  &lt;/span&gt;&lt;span class="s"&gt;LABELS&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$labels&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Example Message in Telegram
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⚪️ Alert: PrometheusTargetMissing
Status: ✅ RESOLVED
Severity: 🟢 Warning
Job: kube-proxy
Namespace: kube-system
Instance: 192.168.173.192:10249
Job: kube-proxy
Namespace: kube-system
Instance: 192.168.173.27:10249
Job: kube-proxy
Namespace: kube-system
Instance: 192.168.173.31:10249
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🔴 Alert: KubeControllerManagerDown
Status: 🔥 FIRING
Severity: 🔴 Critical
RunbookURL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🔴 Alert: KubeSchedulerDown
Status: 🔥 FIRING
Severity: 🔴 Critical
RunbookURL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Read about the &lt;a href="https://runbooks.prometheus-operator.dev/" rel="noopener noreferrer"&gt;RunbookURL&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>alertmanager</category>
      <category>prometheus</category>
      <category>monitoring</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Script Template in vim</title>
      <dc:creator>Ali Mehraji</dc:creator>
      <pubDate>Sat, 08 Mar 2025 23:05:25 +0000</pubDate>
      <link>https://forem.com/cod3mason/script-template-in-vim-2cjl</link>
      <guid>https://forem.com/cod3mason/script-template-in-vim-2cjl</guid>
      <description>&lt;h2&gt;
  
  
  Script templates in Vim
&lt;/h2&gt;

&lt;p&gt;Every time I wrote Bash or Python scripts in Vim, I had to add the Shebang &lt;code&gt;#! /bin/bash&lt;/code&gt; or &lt;code&gt;#! /usr/bin/python&lt;/code&gt; in the scripts manually.&lt;/p&gt;

&lt;p&gt;So how can we automate this process with Vim to catch &lt;code&gt;*.sh&lt;/code&gt; or &lt;code&gt;*.py&lt;/code&gt; extensions and create a new file with our desired template, Let’s go for it :&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First, you need to create a template file at &lt;code&gt;$HOME/.vim/sh_template.temp&lt;/code&gt; with the contents you want:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="c"&gt;# =================================================================&lt;/span&gt;

&lt;span class="c"&gt;# Author: &amp;lt; Your Name &amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;# Email: &amp;lt;Your Email&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;# Script Name:&lt;/span&gt;
&lt;span class="c"&gt;# Date Created:&lt;/span&gt;
&lt;span class="c"&gt;# Last Modified:&lt;/span&gt;

&lt;span class="c"&gt;# Description:&lt;/span&gt;
&lt;span class="c"&gt;# &amp;lt; Description of what is this script for &amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;# Usage:&lt;/span&gt;
&lt;span class="c"&gt;# &amp;lt; How to use this script , flag usage or ... &amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;# =================================================================&lt;/span&gt;

&lt;span class="c"&gt;# ======================== Start Of Code ==========================&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-xe&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Next, you need to configure &lt;code&gt;autocmd&lt;/code&gt; in Vim by editing &lt;code&gt;$HOME/.vimrc&lt;/code&gt; and adding this line:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="c"&gt;" ========= Shell Script Template ========================&lt;/span&gt;
&lt;span class="k"&gt;au&lt;/span&gt; bufnewfile *&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;sh&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="k"&gt;r&lt;/span&gt; $HOME&lt;span class="sr"&gt;/.vim/&lt;/span&gt;sh_template&lt;span class="p"&gt;.&lt;/span&gt;temp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Comment lines in vim scripting that are applied in &lt;code&gt;.vimrc&lt;/code&gt; too, begin with &lt;code&gt;"&lt;/code&gt; character .&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;au&lt;/code&gt; represents &lt;code&gt;autocmd&lt;/code&gt;. &lt;a href="https://vimdoc.sourceforge.net/htmldoc/autocmd.html" rel="noopener noreferrer"&gt;&lt;em&gt;autocmd docs&lt;/em&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bufnewfile&lt;/code&gt; event for opening a file that doesn’t exist for editing.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;*.sh&lt;/code&gt; cath all files with &lt;code&gt;.sh&lt;/code&gt; extension. For Python scripts, you can replace it with &lt;code&gt;*.py&lt;/code&gt; .&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Now its time to create a shell script with the desired template:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vi Shell_Script.sh&lt;/code&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can follow the same steps for every script or language you need.&lt;/li&gt;
&lt;li&gt;Start using &lt;a href="https://www.redhat.com/sysadmin/beginners-guide-vim" rel="noopener noreferrer"&gt;vim&lt;/a&gt;, you’ll love it ;).&lt;/li&gt;
&lt;li&gt;There’s even a game to learn, give a try &lt;a href="https://vim-adventures.com/" rel="noopener noreferrer"&gt;Vim Adventures&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>vim</category>
      <category>template</category>
      <category>script</category>
    </item>
    <item>
      <title>Special $@ and $* Parameters in bash</title>
      <dc:creator>Ali Mehraji</dc:creator>
      <pubDate>Sat, 08 Mar 2025 22:48:26 +0000</pubDate>
      <link>https://forem.com/cod3mason/special-and-parameters-in-bash-4kn3</link>
      <guid>https://forem.com/cod3mason/special-and-parameters-in-bash-4kn3</guid>
      <description>&lt;p&gt;There is a say no difference between &lt;code&gt;$@&lt;/code&gt; and &lt;code&gt;$*&lt;/code&gt; in Shell! What ?!!&lt;/p&gt;

&lt;p&gt;Have you ever thought if there is no difference, why there are two of them? it could be one &lt;code&gt;$@&lt;/code&gt; or &lt;code&gt;$*&lt;/code&gt; , Do You Agree?&lt;/p&gt;

&lt;p&gt;So Let’s see What the difference is . Create a script and try it one by one&lt;/p&gt;

&lt;p&gt;First One &lt;code&gt;$@&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

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

MAIN&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"First Parameter is &lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

MAIN &lt;span class="nv"&gt;$@&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Execute it like below and give the script some arguments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./Diff.sh &lt;span class="s2"&gt;"Jhon Smith"&lt;/span&gt; &lt;span class="s2"&gt;"Marry Ann"&lt;/span&gt;
First Parameter is Jhon

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

&lt;/div&gt;



&lt;p&gt;Second One &lt;code&gt;$*&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

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

MAIN&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"First Parameter is &lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

MAIN &lt;span class="nv"&gt;$*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result will be :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./Diff.sh &lt;span class="s2"&gt;"Jhon Smith"&lt;/span&gt; &lt;span class="s2"&gt;"Marry Ann"&lt;/span&gt;
First Parameter is Jhon
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Far Now There is no difference, maybe those people were right!&lt;/p&gt;

&lt;p&gt;Let us go further and try them with double quotes &lt;code&gt;"$@"&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

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

MAIN&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"First Parameter is &lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

MAIN &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./Diff.sh &lt;span class="s2"&gt;"Jhon Smith"&lt;/span&gt; &lt;span class="s2"&gt;"Marry Ann"&lt;/span&gt;
First Parameter is Jhon Smith
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second one in double quotes &lt;code&gt;"$*"&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

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

MAIN&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"First Parameter is &lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

MAIN &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$*&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./Diff.sh &lt;span class="s2"&gt;"Jhon Smith"&lt;/span&gt; &lt;span class="s2"&gt;"Marry Ann"&lt;/span&gt;
First Parameter is Jhon Smith Marry Ann
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So be careful when you use double quotes and tell those people there is a difference, explain to them shell is sensitive to double quotes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.gnu.org/software/bash/" rel="noopener noreferrer"&gt;Gnu.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.gnu.org/software/bash/manual/" rel="noopener noreferrer"&gt;Bash Documents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.ca/Learning-bash-Shell-Unix-Programming/dp/0596009658" rel="noopener noreferrer"&gt;Book&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.gnu.org/software/bash/manual/html_node/Special-Parameters.html" rel="noopener noreferrer"&gt;Special Parameters&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>bash</category>
      <category>gnulinux</category>
      <category>linux</category>
    </item>
  </channel>
</rss>
