<?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: Omar Ahmed</title>
    <description>The latest articles on Forem by Omar Ahmed (@omar_ahmed).</description>
    <link>https://forem.com/omar_ahmed</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%2F3153093%2F3b5ed7bc-cbee-4107-9902-b2b81e07bd38.jpeg</url>
      <title>Forem: Omar Ahmed</title>
      <link>https://forem.com/omar_ahmed</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/omar_ahmed"/>
    <language>en</language>
    <item>
      <title>Docker Production Best Practices - Complete Guide</title>
      <dc:creator>Omar Ahmed</dc:creator>
      <pubDate>Fri, 06 Feb 2026 21:00:05 +0000</pubDate>
      <link>https://forem.com/omar_ahmed/docker-production-best-practices-complete-guide-i6l</link>
      <guid>https://forem.com/omar_ahmed/docker-production-best-practices-complete-guide-i6l</guid>
      <description>&lt;h2&gt;
  
  
  Part 1 : Image Selection &amp;amp; Architecture
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Minimal Base Images
&lt;/h3&gt;

&lt;p&gt;Containers are not Virtual Machines. They share the host kernel.&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;# ❌ BAD - Large attack surface (800MB+)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; ubuntu:22.04&lt;/span&gt;

&lt;span class="c"&gt;# ✅ GOOD - Minimal attack surface (5-50MB) Alpine / Distroless&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; alpine:3.19&lt;/span&gt;
&lt;span class="c"&gt;# OR&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; gcr.io/distroless/static-debian12&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;Every package you don't include is a package that cannot have vulnerabilities.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Compiled ( Go , Rust )&lt;/code&gt; Use Distroless or Scratch. Compile to a static binary, &lt;code&gt;no runtime dependencies needed, only need the binary file&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Interpreted (Node, Python)&lt;/code&gt;  Use Alpine or Slim variants. You &lt;code&gt;only need the language runtime, not the OS tools&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Separate the Builder from the Runner - Multi-Stage Builds
&lt;/h3&gt;

&lt;p&gt;We don't need the source code, compilers, dependencies, or test files in production, so we &lt;code&gt;need to separate the build stage from the runtime stage&lt;/code&gt;. The final image discards all build tools.&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="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:alpine&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;builder&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;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run build

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; nginx:alpine&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /app/dist /usr/share/nginx/html&lt;/span&gt;
&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;┌─────────────────┐                      ┌─────────────────┐
│                 │                      │                 │
│  ┌──────────┐   │                      │  ┌──────────┐   │
│  │  Source  │   │   COPY --from=       │  │   App    │   │
│  └──────────┘   │     builder          │  │  Binary  │   │
│                 │  ─────────────────&amp;gt;  │  └──────────┘   │
│  ┌──────────┐   │                      │                 │
│  │ Compiler │   │                      │                 │
│  └──────────┘   │                      │                 │
│                 │                      │                 │
└─────────────────┘                      └─────────────────┘
Stage 1: Builder                        Stage 2: Runner
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Derive Versions, Don't Guess
&lt;/h3&gt;

&lt;p&gt;Always match Dockerfile base image versions to your project configuration files - Use specific version tags, not &lt;code&gt;latest&lt;/code&gt; .&lt;/p&gt;

&lt;p&gt;Your project config is the Source of Truth. The Dockerfile must mirror it. Mismatched versions lead to "It works on my machine" but fails in production.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ┌─────────────┐
  │ package.json│
  │             │
  │  engines:   │
  │  node &amp;gt;= 20 │──────────────────────&amp;gt; FROM node:20-alpine
  │             │
  └─────────────┘


  ┌─────────────┐
  │   go.mod    │
  │             │
  │  go 1.21    │──────────────────────&amp;gt; FROM golang:1.21
  │             │
  └─────────────┘


  ┌─────────────┐
  │   Pipfile   │
  │             │
  │ python_     │
  │ version =   │──────────────────────&amp;gt; FROM python:3.11-slim
  │   3.11      │
  └─────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 2 : Optimization - Build Speed &amp;amp; Layer Caching
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Combine Install and Clean Steps
&lt;/h3&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;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm cache clean &lt;span class="nt"&gt;--force&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates TWO separate layers in the Docker image:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first RUN command installs packages and creates cache files in Layer 1&lt;/li&gt;
&lt;li&gt;The second RUN command cleans the cache in Layer 2&lt;/li&gt;
&lt;li&gt;However, the cache files from Layer 1 are only hidden, not deleted&lt;/li&gt;
&lt;li&gt;They still exist in the image and contribute to the total image size&lt;/li&gt;
&lt;li&gt;This wastes disk space and increases image size unnecessarily&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Solution (Production Way)&lt;/strong&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="k"&gt;RUN &lt;/span&gt;npm ci &lt;span class="nt"&gt;--omit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm cache clean &lt;span class="nt"&gt;--force&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Both commands execute in a single layer&lt;/li&gt;
&lt;li&gt;The cache files are created and then immediately cleaned within the same layer&lt;/li&gt;
&lt;li&gt;The temporary cache files never commit to the final image history&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key Concept&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Docker layers are additive. &lt;code&gt;You cannot delete data from a previous layer, only mask it&lt;/code&gt;. When you delete files in a subsequent layer, they're hidden but still consume space in the image. To truly remove temporary files, you must clean them up in the same RUN command where they were created using &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; to chain commands together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Other Example&lt;/strong&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;# ❌ BAD - Two layers&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; package &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="c"&gt;# ✅ GOOD - Single layer&lt;/span&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; &lt;span class="se"&gt;\
&lt;/span&gt;    apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; package &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;h3&gt;
  
  
  2. Be Explicit with Files and Dependencies
&lt;/h3&gt;

&lt;p&gt;No Lazy Copying - Avoid &lt;code&gt;COPY . .&lt;/code&gt; in the final stage. &lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;COPY . .&lt;/code&gt; copies everything from your project directory into the container, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.env&lt;/code&gt; files (sensitive credentials)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.git&lt;/code&gt; directory (version control history)&lt;/li&gt;
&lt;li&gt;Test files&lt;/li&gt;
&lt;li&gt;Documentation&lt;/li&gt;
&lt;li&gt;Development configs&lt;/li&gt;
&lt;li&gt;Build artifacts you don't need&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Solution:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Copy ONLY what is needed:&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;# ❌ BAD - Copies everything&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="c"&gt;# ✅ GOOD - Explicit and selective&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./dist ./dist&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Best Practice:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Be explicit about which files and directories you copy&lt;/li&gt;
&lt;li&gt;Only include runtime-necessary files&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;.dockerignore&lt;/code&gt; to exclude unwanted files&lt;/li&gt;
&lt;li&gt;Copy built artifacts from builder stage, not source files&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Production Dependencies Only
&lt;/h3&gt;

&lt;p&gt;Dev tools do not belong in production.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;npm ci --omit=dev&lt;/code&gt; (or equivalent for your package manager)&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;# ❌ BAD - Installs all dependencies including dev&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# ✅ GOOD - Production dependencies only&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm ci &lt;span class="nt"&gt;--omit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 3 : Security Hardening
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Never Run as Root
&lt;/h3&gt;

&lt;p&gt;By default, Docker containers run as the root user (UID 0), which poses significant security risks. Always create and switch to a non-root user in production containers.&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;RUN &lt;/span&gt;addgroup &lt;span class="nt"&gt;-S&lt;/span&gt; appgroup &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;-S&lt;/span&gt; appuser &lt;span class="nt"&gt;-G&lt;/span&gt; appgroup
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; appuser&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Security Risk&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If an attacker compromises a container running as root, they potentially gain root privileges over the host.&lt;/p&gt;

&lt;p&gt;This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full control over the container&lt;/li&gt;
&lt;li&gt;Possible escape to the host system&lt;/li&gt;
&lt;li&gt;Access to sensitive host resources&lt;/li&gt;
&lt;li&gt;Ability to compromise other containers&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. The Latest Tag is a Lie
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;No version control&lt;/li&gt;
&lt;li&gt;No reproducibility&lt;/li&gt;
&lt;li&gt;Debugging nightmares&lt;/li&gt;
&lt;li&gt;Unexpected breaking changes&lt;/li&gt;
&lt;li&gt;Security vulnerabilities from unknown versions
&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;# ❌ BAD - Today you get Node 20, tomorrow you might get Node 21&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:latest&lt;/span&gt;

&lt;span class="c"&gt;# ✅ GOOD - Always Node 20.11.0 on Alpine 3.19&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:20.11.0-alpine3.19&lt;/span&gt;

&lt;span class="c"&gt;# ✅ ACCEPTABLE - Gets patch updates but stays on 20.x&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:20-alpine&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Random images from Docker Hub
&lt;/h3&gt;

&lt;p&gt;Unknown Source can contain malware, crypto-miners, or backdoors.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Remove the Attacker's Toolkit
&lt;/h3&gt;

&lt;p&gt;If an attacker gets in, don't hand them the tools to explore.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;curl, wget, vim , netcat&lt;/code&gt; - These tools allow attackers to explore the network, download malware. If the tool isn't there, their job becomes significantly harder.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question:&lt;/strong&gt; If I strip all tools from my production container, how do I debug a DNS issue?&lt;/p&gt;

&lt;p&gt;Instead of bloating your production container with debugging tools, use an &lt;code&gt;Ephemeral Sidecars - temporary sidecar container&lt;/code&gt; that attaches to your production container's network namespace only when needed.&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;# Find your container ID or name&lt;/span&gt;
docker ps

&lt;span class="c"&gt;# Run netshoot (debugging toolbox) in the same network namespace&lt;/span&gt;
docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--network&lt;/span&gt; container:my-app-container &lt;span class="se"&gt;\&lt;/span&gt;
  nicolaka/netshoot

&lt;span class="c"&gt;# Now you have access to debugging tools:&lt;/span&gt;
&lt;span class="c"&gt;# - curl http://api.example.com&lt;/span&gt;
&lt;span class="c"&gt;# - dig google.com&lt;/span&gt;
&lt;span class="c"&gt;# - nslookup database-service&lt;/span&gt;
&lt;span class="c"&gt;# - ping redis&lt;/span&gt;
&lt;span class="c"&gt;# - tcpdump&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Simply exit the sidecar container - it's removed automatically (due to --rm flag), leaving your production container pristine.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Other Example&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;# network debugging&lt;/span&gt;
docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--network&lt;/span&gt; container:my-app nicolaka/netshoot

&lt;span class="c"&gt;# basic Unix tools&lt;/span&gt;
docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--network&lt;/span&gt; container:my-app busybox

&lt;span class="c"&gt;# alpine with tools&lt;/span&gt;
docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--network&lt;/span&gt; container:my-app &lt;span class="se"&gt;\&lt;/span&gt;
  alpine sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"apk add --no-cache curl bind-tools &amp;amp;&amp;amp; sh"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Root Owns, User Executes
&lt;/h3&gt;

&lt;p&gt;This security pattern ensures that even if an attacker compromises your application, they cannot establish a permanent foothold by modifying the application binary itself.&lt;/p&gt;

&lt;p&gt;If the application is compromised:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Attacker gains access to the running container as appuser&lt;/li&gt;
&lt;li&gt;Attacker tries to inject backdoor into the application binary&lt;/li&gt;
&lt;li&gt;Attack fails because appuser has no write permissions&lt;/li&gt;
&lt;li&gt;Result: Attacker cannot establish persistence through binary modification&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Entity&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Permission&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Impact&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Owner (Root)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Read / Write&lt;/td&gt;
&lt;td&gt;Can update app ✅ (during build)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;User (AppUser)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Read / Execute&lt;/td&gt;
&lt;td&gt;Can RUN app, cannot MODIFY app ❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&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="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:20-alpine&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;builder&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;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm ci
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:20-alpine&lt;/span&gt;
&lt;span class="c"&gt;# Create non-root user&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;addgroup &lt;span class="nt"&gt;-S&lt;/span&gt; appgroup &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; adduser &lt;span class="nt"&gt;-S&lt;/span&gt; appuser &lt;span class="nt"&gt;-G&lt;/span&gt; appgroup
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="c"&gt;# Copy files as root, set ownership to root&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder --chown=root:root /app/dist ./dist&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder --chown=root:root /app/node_modules ./node_modules&lt;/span&gt;

&lt;span class="c"&gt;# Make binaries executable but not writable&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;755 dist/

&lt;span class="c"&gt;# Switch to non-root user for execution&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; appuser&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "dist/index.js"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Attacker → Backdoor.sh → [×] App Binary (Read Only) → ✓ Protected&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 4: Maintainability - Dev Experience &amp;amp; Documentation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Sort Arguments
&lt;/h3&gt;

&lt;p&gt;Alphabetize multi-line installs for cleaner git diffs.&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;# ❌ BAD - Unsorted, harder to track changes&lt;/span&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="se"&gt;\
&lt;/span&gt;    curl &lt;span class="se"&gt;\
&lt;/span&gt;    git &lt;span class="se"&gt;\
&lt;/span&gt;    jq &lt;span class="se"&gt;\
&lt;/span&gt;    python3 &lt;span class="se"&gt;\
&lt;/span&gt;    zip

&lt;span class="c"&gt;# ✅ GOOD - Alphabetically sorted (A→Z)&lt;/span&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="se"&gt;\
&lt;/span&gt;    curl &lt;span class="se"&gt;\
&lt;/span&gt;    git &lt;span class="se"&gt;\
&lt;/span&gt;    jq &lt;span class="se"&gt;\
&lt;/span&gt;    python3 &lt;span class="se"&gt;\
&lt;/span&gt;    zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cleaner git diffs - Easy to see what was added/removed&lt;/li&gt;
&lt;li&gt;Prevents duplicates - Sorted list makes duplicates obvious&lt;/li&gt;
&lt;li&gt;Easier reviews - Reviewers can quickly scan alphabetically&lt;/li&gt;
&lt;li&gt;Merge conflicts - Reduces conflicts when multiple people edit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example git diff with sorted packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;RUN apt-get update &amp;amp;&amp;amp; apt-get install -y \
&lt;/span&gt;    curl \
    git \
&lt;span class="gi"&gt;+   htop \
&lt;/span&gt;    jq \
    python3 \
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Use WORKDIR
&lt;/h3&gt;

&lt;p&gt;Don't use &lt;code&gt;cd&lt;/code&gt;. It resets every layer ( Context Reset: Layer boundary). &lt;code&gt;WORKDIR&lt;/code&gt; sets persistent context (Set once, applies to all following).&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; node:20-alpine&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /app
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; The &lt;code&gt;cd /app&lt;/code&gt; command only affects that single RUN layer. The next layer (COPY) resets back to the &lt;code&gt;root directory&lt;/code&gt;, so files go to the wrong location.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. OCI Labels
&lt;/h3&gt;

&lt;p&gt;Tag images with metadata (source, version, description) for easier registry identification.&lt;/p&gt;

&lt;p&gt;OCI labels are key-value pairs that provide metadata about your Docker image.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&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="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:20-alpine&lt;/span&gt;

&lt;span class="c"&gt;# Add OCI labels for metadata&lt;/span&gt;
&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; org.opencontainers.image.title="My Application"&lt;/span&gt;
&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; org.opencontainers.image.description="A production-ready Node.js application"&lt;/span&gt;
&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; org.opencontainers.image.version="1.2.3"&lt;/span&gt;
&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; org.opencontainers.image.authors="team@example.com"&lt;/span&gt;
&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; org.opencontainers.image.source="https://github.com/myorg/myapp"&lt;/span&gt;
&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; org.opencontainers.image.created="2026-02-06T12:00:00Z"&lt;/span&gt;
&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; org.opencontainers.image.revision="abc123def"&lt;/span&gt;
&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; org.opencontainers.image.licenses="MIT"&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;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm ci &lt;span class="nt"&gt;--omit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; node&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "index.js"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Automated Label Injection (CI/CD)&lt;/strong&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;# Use ARG to accept build-time variables, ARG vars Exist only during build, Can be overridden with --build-arg, Have default values (so local builds don't fail)&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; VERSION=dev&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; GIT_COMMIT=unknown&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; BUILD_DATE=unknown&lt;/span&gt;

&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; org.opencontainers.image.version="${VERSION}"&lt;/span&gt;
&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; org.opencontainers.image.revision="${GIT_COMMIT}"&lt;/span&gt;
&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; org.opencontainers.image.created="${BUILD_DATE}"&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="c"&gt;# Build with metadata from CI/CD&lt;/span&gt;
docker build &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--build-arg&lt;/span&gt; &lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git describe &lt;span class="nt"&gt;--tags&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--build-arg&lt;/span&gt; &lt;span class="nv"&gt;GIT_COMMIT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git rev-parse HEAD&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--build-arg&lt;/span&gt; &lt;span class="nv"&gt;BUILD_DATE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; +&lt;span class="s1"&gt;'%Y-%m-%dT%H:%M:%SZ'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-t&lt;/span&gt; myapp:latest &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Handle Signals Gracefully
&lt;/h3&gt;

&lt;p&gt;Always use JSON array syntax (exec form) for &lt;code&gt;CMD&lt;/code&gt; and &lt;code&gt;ENTRYPOINT&lt;/code&gt; in Dockerfiles or similar container configurations. This ensures your application receives system signals and can shut down gracefully, which is crucial for production reliability.&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;CMD&lt;/span&gt;&lt;span class="s"&gt; npm start  # ❌ BAD &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Problem:&lt;/strong&gt; When you use shell form syntax like &lt;code&gt;CMD npm start&lt;/code&gt;, Node.js spawns your command through a shell (like &lt;code&gt;/bin/sh&lt;/code&gt;). This creates a process hierarchy where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The shell becomes PID 1 (the main process)&lt;/li&gt;
&lt;li&gt;Your actual Node app runs as a child process (PID 2)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a SIGTERM signal is sent (typically during shutdown, like docker stop), it goes to PID 1 (the shell). However, shells don't forward signals to their children by default, so:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the shell ( main process ) will kill, so a children process will forced kill ( not graceful shutdown )&lt;/li&gt;
&lt;li&gt;The Node app never receives the signal&lt;/li&gt;
&lt;li&gt;The app can't perform graceful shutdown (close connections, finish requests, cleanup)&lt;/li&gt;
&lt;li&gt;The system eventually force-kills the app after a timeout&lt;/li&gt;
&lt;li&gt;This can lead to data loss or corrupted state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Solution&lt;/strong&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="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["npm", "start"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you use exec form syntax like CMD ["npm", "start"], Node.js runs your command directly without a shell wrapper. This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your Node app becomes PID 1 directly&lt;/li&gt;
&lt;li&gt;SIGTERM is sent directly to your application&lt;/li&gt;
&lt;li&gt;Your app can handle the signal properly (using event listeners like process.on('SIGTERM'))&lt;/li&gt;
&lt;li&gt;The app can perform graceful shutdown operations&lt;/li&gt;
&lt;li&gt;Clean, controlled shutdown is achieved&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Secrets Do Not Belong in Dockerfiles
&lt;/h3&gt;

&lt;p&gt;If a secret goes into a Docker image, it's already leaked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅ DO:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inject secrets at runtime via environment variables
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Runtime injection&lt;/span&gt;
docker run &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;DATABASE_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$DB_PASS&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$API_KEY&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  myapp:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Use secret management tools (AWS Secrets Manager, Vault, K8s Secrets)&lt;/li&gt;
&lt;li&gt;Mount secrets as volumes from secure storage&lt;/li&gt;
&lt;li&gt;Use Docker secrets in Swarm mode&lt;/li&gt;
&lt;li&gt;Keep secrets in .gitignore and .dockerignore&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;❌ DON'T:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hardcode secrets in Dockerfile&lt;/li&gt;
&lt;li&gt;COPY secret files into the image&lt;/li&gt;
&lt;li&gt;Use ENV for sensitive data&lt;/li&gt;
&lt;li&gt;Commit .env files with real secrets to git&lt;/li&gt;
&lt;li&gt;Assume deleting in a later layer removes the secret&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Thanks for reading! If you found this helpful, please share it with your team.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>docker</category>
    </item>
    <item>
      <title>Vim</title>
      <dc:creator>Omar Ahmed</dc:creator>
      <pubDate>Sat, 27 Dec 2025 12:57:40 +0000</pubDate>
      <link>https://forem.com/omar_ahmed/vim-39p4</link>
      <guid>https://forem.com/omar_ahmed/vim-39p4</guid>
      <description>&lt;ul&gt;
&lt;li&gt;1. Match all occurrences of the word under the cursor
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;2. Replace a word with another word
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;%s&lt;span class="sr"&gt;/word/&lt;/span&gt;newword/gc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;g: global , c: confirm&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;3. Visually select a word &lt;code&gt;i / a (inside / outside)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;viw ( Selects only the word itself )
vaw ( Selects the word plus surrounding whitespace )
vi( ( Visual texts inside () )
ci" ( change around double "" )
va( ( Visual () )
va" ( Visual "" )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;4. Show all registers
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;reg&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;5. Paste from a specific register
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"&amp;lt;reg number&amp;gt;p
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;6. Yank (copy) the current line to the system clipboard ( + : clipboard system register)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"+yy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;7. Yank the current file name to the system clipboard
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; @&lt;span class="p"&gt;+=&lt;/span&gt;@% &lt;span class="p"&gt;,&lt;/span&gt; then &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; any &lt;span class="k"&gt;file&lt;/span&gt; &lt;span class="nb"&gt;and&lt;/span&gt; ctrl&lt;span class="p"&gt;+&lt;/span&gt;&lt;span class="k"&gt;v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;assigns the contents of the % register (current file name) to the + register (system clipboard).&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;8. Copy the absolute path of the current file
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; @&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'%:p'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;9. Record and play a macro
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;q&amp;lt;any character&amp;gt;&amp;lt;action&amp;gt;q
@h
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;ul&gt;
&lt;li&gt;10. :normal Mode
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;When you select lines in Visual mode and press :
:'&amp;lt;,'&amp;gt;

:'&amp;lt;,'&amp;gt;normal &amp;lt;keys&amp;gt;&amp;lt;text&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Keys:&lt;/strong&gt;&lt;br&gt;
I : go to start of lines and enter Insert mode&lt;br&gt;
A : go to end of lines and append a new text&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%2F8ciee1cpo0pymw1uaw6u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ciee1cpo0pymw1uaw6u.png" alt=" " width="419" height="408"&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3eodzab7lcprt1f27roi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3eodzab7lcprt1f27roi.png" alt=" " width="265" height="500"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hello
world
goodbye

:'&amp;lt;,'&amp;gt;normal Ivar + space

var hello
var world
var goodbye
&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;hello
world
goodbye

:'&amp;lt;,'&amp;gt;normal A ;

hello ;
world ;
goodbye ;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;11. Number
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ctrl-a : increment number
Ctrl-x : decrement number
value = 2
&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;list.get(0);
list.get(0);
list.get(0);
list.get(0);
list.get(0);
list.get(0);

select all lines + g + Ctrl-a

list.get(1);
list.get(2);
list.get(3);
list.get(4);
list.get(5);
list.get(6);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;12. Switching Selection
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;select lines + o
select lines + O
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;13. w / W &lt;code&gt;letters, digits, or underscores / whitespace characters&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Lis:st.get(0) hello world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






</description>
      <category>vim</category>
      <category>neovim</category>
      <category>linux</category>
    </item>
    <item>
      <title>GitLab-CI</title>
      <dc:creator>Omar Ahmed</dc:creator>
      <pubDate>Wed, 01 Oct 2025 18:16:35 +0000</pubDate>
      <link>https://forem.com/omar_ahmed/gitlab-ci-p9g</link>
      <guid>https://forem.com/omar_ahmed/gitlab-ci-p9g</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;GitLab Docs: &lt;a href="https://docs.gitlab.com/ci/yaml/" rel="noopener noreferrer"&gt;CI/CD YAML syntax reference&lt;/a&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  gitlab cicd file name
&lt;/h3&gt;

&lt;p&gt;In GitLab, the CI/CD pipeline configuration file is always named:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.gitlab-ci.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;It must be placed in the root directory of your repository.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  template .gitlab-ci.yml
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;pipeline&lt;/span&gt;
&lt;span class="s"&gt;stages&lt;/span&gt;
&lt;span class="na"&gt;job1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;before_script&lt;/span&gt;
        &lt;span class="s"&gt;step&lt;/span&gt;
    &lt;span class="s"&gt;script&lt;/span&gt;
        &lt;span class="s"&gt;step&lt;/span&gt;
    &lt;span class="s"&gt;after_script&lt;/span&gt;
        &lt;span class="s"&gt;step&lt;/span&gt;
&lt;span class="na"&gt;job2&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;script&lt;/span&gt;
        &lt;span class="s"&gt;step&lt;/span&gt;
&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;workflow&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;Test&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;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CI_COMMIT_BRANCH == 'main'&lt;/span&gt;

&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;

&lt;span class="na"&gt;test_job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;saas-linux-samll-amd64&lt;/span&gt;
  &lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;chmod +x test.sh&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./test.sh&lt;/span&gt;
  &lt;span class="na"&gt;after_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ls&lt;/span&gt;

&lt;span class="na"&gt;deploy_job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;touch test.txt&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Multi Lines in the step
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;workflow&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;Test&lt;/span&gt;

&lt;span class="na"&gt;test_job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;chmod +x test.sh&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./test.txt&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="s"&gt;this is a test pipeline&lt;/span&gt;
      &lt;span class="s"&gt;so do not take it seriously &amp;gt; test.txt&lt;/span&gt;
  &lt;span class="na"&gt;after_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo "done"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  stages
&lt;/h3&gt;

&lt;p&gt;Use stages to define stages that contain groups of jobs. Use stage in a job to configure the job to run in a specific stage.&lt;br&gt;
If stages is not defined in the .gitlab-ci.yml file, the default pipeline stages are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;.pre&lt;/li&gt;
&lt;li&gt;build&lt;/li&gt;
&lt;li&gt;test&lt;/li&gt;
&lt;li&gt;deploy&lt;/li&gt;
&lt;li&gt;.post&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The order of the items in stages defines the execution order for jobs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Jobs in the same stage run in parallel.&lt;/li&gt;
&lt;li&gt;Jobs in the next stage run after the jobs from the previous stage complete successfully.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a pipeline contains only jobs in the .pre or .post stages, it does not run. There must be at least one other job in a different stage.&lt;/p&gt;

&lt;p&gt;Keyword type: Global keyword.&lt;/p&gt;

&lt;p&gt;Example of stages:&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;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All jobs in build execute in parallel.&lt;/li&gt;
&lt;li&gt;If all jobs in build succeed, the test jobs execute in parallel.&lt;/li&gt;
&lt;li&gt;If all jobs in test succeed, the deploy jobs execute in parallel.&lt;/li&gt;
&lt;li&gt;If all jobs in deploy succeed, the pipeline is marked as passed.
If any job fails, the pipeline is marked as failed and jobs in later stages do not start. Jobs in the current stage are not stopped and continue to run.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Artifacts - Storing Job Data
&lt;/h3&gt;

&lt;p&gt;Use artifacts to specify which files to save as job artifacts. Job artifacts are a list of files and directories that are attached to the job when it succeeds, fails, or always.&lt;/p&gt;

&lt;p&gt;The artifacts are sent to GitLab after the job finishes. They are available for download in the GitLab UI&lt;/p&gt;

&lt;p&gt;By default, jobs in later stages automatically download all the artifacts created by jobs in earlier stages. You can control artifact download behavior in jobs with dependencies.&lt;/p&gt;

&lt;p&gt;When using the needs keyword, jobs can only download artifacts from the jobs defined in the needs configuration.&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;job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;job1-artifacts-file"&lt;/span&gt;
    &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;on_success&lt;/span&gt;
    &lt;span class="na"&gt;expire_in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1 week&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;binaries/&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.config&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example stores all files in binaries/, but not *.o files located in subdirectories of binaries/.&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;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;binaries/&lt;/span&gt;
  &lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;binaries/**/*.o&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using needs Keyword
&lt;/h3&gt;

&lt;p&gt;You can use the needs keyword to create dependencies between jobs in a pipeline. Jobs run as soon as their dependencies are met, regardless of the pipeline’s stages configuration. You can even configure a pipeline with no stages defined (effectively one large stage) and jobs still run in the proper order.&lt;/p&gt;

&lt;h3&gt;
  
  
  Working with Variables
&lt;/h3&gt;

&lt;p&gt;Variables can be defined in a CI/CD job, or as a top-level (global) keyword to define default CI/CD variables for all jobs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1- job variables:&lt;/strong&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;review_job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;DEPLOY_SITE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://dev.example.com/"&lt;/span&gt;
    &lt;span class="na"&gt;REVIEW_PATH&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/review"&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deploy-review-script --url $DEPLOY_SITE --path $REVIEW_PATH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2- Default variables:&lt;/strong&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;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;DEPLOY_SITE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://example.com/"&lt;/span&gt;

&lt;span class="na"&gt;deploy_job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deploy-script --url $DEPLOY_SITE --path "/"&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;

&lt;span class="na"&gt;deploy_review_job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
  &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;DEPLOY_SITE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://dev.example.com/"&lt;/span&gt;
    &lt;span class="na"&gt;REVIEW_PATH&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/review"&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deploy-review-script --url $DEPLOY_SITE --path $REVIEW_PATH&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;deploy_job has no variables defined. The default DEPLOY_SITE variable is copied to the job and can be used in the script section.&lt;/li&gt;
&lt;li&gt;deploy_review_job already has a DEPLOY_SITE variable defined, so the default DEPLOY_SITE is not copied to the job. The job also has a REVIEW_PATH job variable defined. Both job variables can be used in the script section.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Masking Variables using CICD Settings
&lt;/h4&gt;

&lt;p&gt;masking a variable means hiding its value in the job logs so it doesn’t get exposed when printed (for example, passwords, API tokens, or other secrets).&lt;br&gt;
1- Go to your project in GitLab &amp;gt; Settings → CI/CD → Variables &amp;gt; Add variable &amp;gt; Key: MY_SECRET_TOKEN &amp;gt; Value: the secret value&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enable: 

&lt;ul&gt;
&lt;li&gt;Masked → hides it in logs&lt;/li&gt;
&lt;li&gt;Protected (optional) → makes it available only on protected branches/tags&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2- Use the variable in your .gitlab-ci.yml:&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;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;

&lt;span class="na"&gt;print-secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo "Using secret token..."&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo "$MY_SECRET_TOKEN"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the logs will show something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Using secret token...
[MASKED]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Predefined CI/CD Variables
&lt;/h4&gt;

&lt;p&gt;Predefined variables become available at three different phases of pipeline execution:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pre-pipeline: Pre-pipeline variables are available before the pipeline is created. These variables are the only variables that can be used with include:rules to control which configuration files to use when creating the pipeline.&lt;/li&gt;
&lt;li&gt;Pipeline: Pipeline variables become available when GitLab is creating the pipeline. Along with pre-pipeline variables, pipeline variables can be used to configure rules defined in jobs, to determine which jobs to add to the pipeline.&lt;/li&gt;
&lt;li&gt;Job-only: These variables are only made available to each job when a runner picks up the job and runs it.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.gitlab.com/ci/variables/predefined_variables/#predefined-variables" rel="noopener noreferrer"&gt;Predefined variables&lt;/a&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;print-predefined&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo "Running on branch&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CI_COMMIT_BRANCH"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo "Commit SHA&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CI_COMMIT_SHA"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo "Pipeline ID&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CI_PIPELINE_ID"&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  GitLab Merge Requests
&lt;/h3&gt;

&lt;p&gt;A Merge Request proposes changes from one branch into another (e.g., feature/foo → main). &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Merge Request &amp;amp; rules at Job level:&lt;/strong&gt; Use rules to include or exclude jobs in pipelines.&lt;/li&gt;
&lt;li&gt;the keyword rules at the job level controls when a job should run (or not run) based on conditions like branch, pipeline source, variables, etc&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rules are evaluated when the pipeline is created, and evaluated in order. When a match is found, no more rules are checked and the job is either included or excluded from the pipeline depending on the configuration. If no rules match, the job is not added to the pipeline.&lt;/p&gt;

&lt;p&gt;rules accepts an array of rules. Each rules must have at least one of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if&lt;/li&gt;
&lt;li&gt;changes&lt;/li&gt;
&lt;li&gt;exists&lt;/li&gt;
&lt;li&gt;when
&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;merge_request_predefined_variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# CI_PIPELINE_SOURCE tells you why a pipeline was created.It’s a predefined variable that GitLab automatically sets for every job.&lt;/span&gt;
  &lt;span class="c1"&gt;# https://docs.gitlab.com/ci/jobs/job_rules/#ci_pipeline_source-predefined-variable&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_PIPELINE_SOURCE&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;"merge_request_event"'&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;echo "CI_MERGE_REQUEST_LABELS - $CI_MERGE_REQUEST_LABELS"&lt;/span&gt;
    &lt;span class="s"&gt;echo "CI_MERGE_REQUEST_TARGET_BRANCH_NAME - $CI_MERGE_REQUEST_TARGET_BRANCH_NAME"&lt;/span&gt;
    &lt;span class="s"&gt;echo "CI_MERGE_REQUEST_ASSIGNEES - $CI_MERGE_REQUEST_ASSIGNEES"&lt;/span&gt;
    &lt;span class="s"&gt;echo "CI_MERGE_REQUEST_SOURCE_BRANCH_NAME - $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME"&lt;/span&gt;
    &lt;span class="s"&gt;echo "CI_MERGE_REQUEST_TITLE - $CI_MERGE_REQUEST_TITLE"&lt;/span&gt;
&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;job_main_branch&lt;/span&gt;&lt;span class="pi"&gt;:&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;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_COMMIT_BRANCH&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;"main"'&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo "I run only on main"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Use rules at Workflow Level
&lt;/h4&gt;

&lt;p&gt;The rules keyword in workflow is similar to rules defined in jobs, but controls whether or not a whole pipeline is created. When no rules evaluate to true, the pipeline does not run.&lt;/p&gt;

&lt;p&gt;Supported values: You can use some of the same keywords as job-level rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rules: if.&lt;/li&gt;
&lt;li&gt;rules: changes.&lt;/li&gt;
&lt;li&gt;rules: exists.&lt;/li&gt;
&lt;li&gt;when, can only be always or never when used with workflow.&lt;/li&gt;
&lt;li&gt;variables.
&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;workflow&lt;/span&gt;&lt;span class="pi"&gt;:&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;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CI_COMMIT_TITLE =~ /-draft$/&lt;/span&gt; &lt;span class="c1"&gt;# =~: match, $: end&lt;/span&gt;
      &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;never&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CI_PIPELINE_SOURCE == "merge_request_event"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CI_COMMIT_BRANCH == 'main'&lt;/span&gt;
       &lt;span class="s"&gt;variables&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
           &lt;span class="na"&gt;DEPLOY_VARIABLE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PRODUCTION&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, pipelines run if the commit title (first line of the commit message) does not end with -draft and the pipeline is for either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A merge request&lt;/li&gt;
&lt;li&gt;The main branch, Then set a job-level variable DEPLOY_VARIABLE with the value "PRODUCTION"
&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;workflow&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;Exploring GitLab CI Concepts&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;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_COMMIT_BRANCH&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;"main"'&lt;/span&gt;
      &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;DEPLOY_VARIABLE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PRODUCTION"&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME&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;/^feature/&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$CI_PIPELINE_SOURCE&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;"merge_request_event"'&lt;/span&gt; &lt;span class="c1"&gt;# ^: start with feature word&lt;/span&gt;
      &lt;span class="na"&gt;changes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;README.md&lt;/span&gt;
      &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;DEPLOY_VARIABLE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TESTING"&lt;/span&gt;

&lt;span class="na"&gt;deploy-job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo "Deploying application..."&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo "Application successfully deployed to $DEPLOY_VARIABLE environment"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;First rule → if branch is main, it sets DEPLOY_VARIABLE=PRODUCTION.&lt;/li&gt;
&lt;li&gt;Second rule → if source branch starts with feature and pipeline comes from a merge request and README.md changed, then DEPLOY_VARIABLE=TESTING.
Job output → prints the deployment target environment (PRODUCTION or TESTING).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Resource Groups
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use resource_group to create a resource group that ensures a job is mutually exclusive across different pipelines for the same project.&lt;/li&gt;
&lt;li&gt;For example, if multiple jobs that belong to the same resource group are queued simultaneously, only one of the jobs starts. The other jobs wait until the resource_group is free.&lt;/li&gt;
&lt;li&gt;If two jobs have the same resource group, GitLab runs them one after the other (queue).&lt;/li&gt;
&lt;li&gt;If they have different resource groups, they can run at the same time.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.gitlab.com/ci/resource_groups/#process-modes" rel="noopener noreferrer"&gt;Process modes&lt;/a&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;migrate_db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
  &lt;span class="na"&gt;resource_group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./migrate.sh&lt;/span&gt;

&lt;span class="na"&gt;deploy_app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
  &lt;span class="na"&gt;resource_group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./deploy.sh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Both jobs affect the same production database/app.&lt;/li&gt;
&lt;li&gt;If two pipelines run migrations + deploy at the same time → chaos.&lt;/li&gt;
&lt;li&gt;By sharing resource_group: production, GitLab ensures these always run one after another, never overlapping.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Resource groups control concurrency across pipelines:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pipelines run in parallel when multiple developers push or open merge requests.&lt;/li&gt;
&lt;li&gt;Two pipelines can both reach the deploy stage at the same time.&lt;/li&gt;
&lt;li&gt;Stages don’t prevent different pipelines from overlapping.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Alice pushes → Pipeline A runs → reaches deploy.&lt;/li&gt;
&lt;li&gt;Bob pushes → Pipeline B runs at the same time → also reaches deploy.&lt;/li&gt;
&lt;li&gt;Both deploy jobs run together → race condition (two versions deploying to the same server).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Resource groups solve this:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If Pipeline A is deploying, Pipeline B’s deploy job is queued until A finishes.&lt;/li&gt;
&lt;li&gt;Prevents overlapping deployments to the same environment.&lt;/li&gt;
&lt;li&gt;Works across all pipelines, not just within one.
### Job Timeout
&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;sleep-job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo "Starting long process..."&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sleep &lt;/span&gt;&lt;span class="m"&gt;120&lt;/span&gt;   &lt;span class="c1"&gt;# pretend this takes 2 minutes&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo "Process finished!"&lt;/span&gt;
  &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1 minute&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The job runs sleep 120 (2 minutes).&lt;/li&gt;
&lt;li&gt;But the job has timeout: 1 minute.&lt;/li&gt;
&lt;li&gt;After 1 minute, GitLab kills the job with a timeout error.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Parallel Matrix
&lt;/h3&gt;

&lt;p&gt;parallel matrix in GitLab CI/CD lets you run the same job multiple times in parallel with different variable values&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This runs 3 jobs in parallel, one for each Python version:&lt;/strong&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;test_python&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&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;python:$PYTHON_VERSION&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;python --version&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pytest&lt;/span&gt;
  &lt;span class="na"&gt;parallel&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;PYTHON_VERSION&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;3.8"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.9"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.10"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;This expands to 4 jobs:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node 16 + Ubuntu&lt;/li&gt;
&lt;li&gt;Node 16 + Alpine&lt;/li&gt;
&lt;li&gt;Node 18 + Ubuntu&lt;/li&gt;
&lt;li&gt;Node 18 + Alpine
&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;test_node&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node --version&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm test&lt;/span&gt;
  &lt;span class="na"&gt;parallel&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;NODE_VERSION&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;16"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;18"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="na"&gt;OS&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;ubuntu"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;alpine"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3 parallel jobs → each runs tests against a different database:&lt;/strong&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;integration_tests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./run_tests.sh --db=$DB&lt;/span&gt;
  &lt;span class="na"&gt;parallel&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;DB&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;mysql"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;postgres"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sqlite"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Skip Pipeline
&lt;/h3&gt;

&lt;p&gt;If your commit message contains [ci skip] or [skip ci], GitLab won’t create a pipeline.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Update README [ci skip]"&lt;/span&gt;
git push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;skip jobs if the only change is in README.md:&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;job_build:
  stage: build
  script:
    - &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Building app..."&lt;/span&gt;
  rules:
    - changes:
        - &lt;span class="s2"&gt;"README.md"&lt;/span&gt;
      when: never   &lt;span class="c"&gt;# don't run if only README changed&lt;/span&gt;
    - when: on_success   &lt;span class="c"&gt;# run for everything else&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






</description>
      <category>gitlab</category>
      <category>cicd</category>
      <category>devops</category>
    </item>
    <item>
      <title>GitOps with ArgoCD</title>
      <dc:creator>Omar Ahmed</dc:creator>
      <pubDate>Sat, 13 Sep 2025 13:28:27 +0000</pubDate>
      <link>https://forem.com/omar_ahmed/gitops-argocd-495g</link>
      <guid>https://forem.com/omar_ahmed/gitops-argocd-495g</guid>
      <description>&lt;p&gt;&lt;a href="https://notes.kodekloud.com/docs/GitOps-with-ArgoCD/Introduction/Course-Introduction" rel="noopener noreferrer"&gt;gitopsWithArgoCD-Docs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/sidd-harth/gitops-argocd" rel="noopener noreferrer"&gt;gitops-argocd-Repo&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  1. What is GitOps?
&lt;/h2&gt;

&lt;p&gt;GitOps is a modern approach to managing and deploying infrastructure and applications using Git as the single source of truth.&lt;br&gt;
Instead of manually applying changes to servers or clusters, you declare the desired system state in Git, and an automated tool keeps your running systems in sync with that state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Core Principles :&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Declarative configuration:
All infrastructure and application configs are stored as code in Git repositories (e.g., Kubernetes manifests, Helm charts, Terraform modules).&lt;/li&gt;
&lt;li&gt;Version-controlled:
Every change is done through Git commits, pull requests, and code reviews—giving you full history, auditability, and rollback capability.&lt;/li&gt;
&lt;li&gt;Automated reconciliation:
Specialized GitOps controllers (like Argo CD or Flux) continuously watch the Git repo and the live environment.
If something drifts, they automatically sync it back to match the Git state.
The GitOps operator &lt;code&gt;ArgoCD&lt;/code&gt; also makes sure that the entire system is self-healing to reduce the risk of human errors. The operator continuously loops through three steps, observe, diff, and act. In &lt;code&gt;the observe step&lt;/code&gt;, it checks the Git repository for any changes in the desired state. In &lt;code&gt;the diff step&lt;/code&gt;, it compares the resources received from the previous step &lt;code&gt;the observe step&lt;/code&gt; to the actual state of the cluster ( It performs a diff (comparison) between the desired state (Git) and the actual state (cluster), Any mismatch is called “drift” ). And in &lt;code&gt;the Act step&lt;/code&gt;, it uses a reconciliation function and tries to match the actual state to the desired state ( If a drift is found, the operator runs its reconciliation logic, It applies the necessary changes to bring the cluster back to match Git, This ensures the system self-heals from manual or accidental changes ).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;Desired State: Git , Actual State: Kubernetes Cluster&lt;/code&gt;&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Continuous deployment:
Merging to the main branch becomes the trigger for deployments, replacing manual &lt;code&gt;kubectl apply&lt;/code&gt; or ad-hoc scripts.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Full audit trail of all infrastructure and app changes.&lt;/li&gt;
&lt;li&gt;Rollback is as simple as reverting a Git commit.&lt;/li&gt;
&lt;li&gt;Strong security (no direct access to production clusters needed - pull the desired state from Git and apply it in one or more environments or clusters)&lt;/li&gt;
&lt;li&gt;Enables collaboration and consistent workflows across teams.&lt;/li&gt;
&lt;/ul&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%2F6c7h1okjndrgebrudtak.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6c7h1okjndrgebrudtak.png" alt=" " width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Push vs Pull based Deployments :
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Push-based Deployment :&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;How it works :&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The CI/CD system (like Jenkins) builds the code, creates container images, pushes them to a registry, and then directly applies manifests to the Kubernetes cluster using kubectl apply.&lt;/li&gt;
&lt;li&gt;The CI/CD system has Read-Write (RW) access to the cluster.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key points from the image :&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Easy to deploy Helm charts.&lt;/li&gt;
&lt;li&gt;✅ Easy to inject container version updates via the build pipeline.&lt;/li&gt;
&lt;li&gt;✅ Simpler secret management from inside the pipeline.&lt;/li&gt;
&lt;li&gt;❌ Cluster config is embedded in the CI system (tightly coupled).&lt;/li&gt;
&lt;li&gt;❌ CI system holds RW access to the cluster (security risk).&lt;/li&gt;
&lt;li&gt;❌ Deployment approach is tied to the CD system (less flexible).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Pull-based Deployment (GitOps) :&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;How it works :&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The CI system builds and pushes images to a registry.&lt;/li&gt;
&lt;li&gt;The desired manifests are committed to a Git repository.&lt;/li&gt;
&lt;li&gt;A GitOps operator (like Argo CD) inside the cluster pulls the manifests from Git and syncs them to the cluster, reconciling continuously.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key points from the image :&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ No external user/client can modify the cluster (only GitOps operator can).&lt;/li&gt;
&lt;li&gt;✅ Can scan container registries for new versions.&lt;/li&gt;
&lt;li&gt;✅ Secrets can be managed via Git repo + Vault.&lt;/li&gt;
&lt;li&gt;✅ Not coupled to the CD pipeline — independent.&lt;/li&gt;
&lt;li&gt;✅ Supports multi-tenant setups.&lt;/li&gt;
&lt;li&gt;❌ Managing secrets for Helm deployments is harder.&lt;/li&gt;
&lt;li&gt;❌ Generic secret management is more complex.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  2. ArgoCD Basics
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is Argo CD?&lt;/strong&gt;&lt;br&gt;
Argo CD (Argo Continuous Delivery) is a GitOps tool for Kubernetes that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Runs inside your cluster as a controller.&lt;/li&gt;
&lt;li&gt;Continuously monitors a Git repository that stores your Kubernetes manifests (YAML, Helm, Kustomize, etc.).&lt;/li&gt;
&lt;li&gt;Automatically applies and syncs those manifests to the cluster.&lt;/li&gt;
&lt;li&gt;Provides a web UI, CLI, and API to visualize and manage application deployments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Installation :&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;helm repo add argo https://argoproj.github.io/argo-helm
helm repo update
kubectl create namespace argocd
helm &lt;span class="nb"&gt;install &lt;/span&gt;argocd argo/argo-cd &lt;span class="nt"&gt;-n&lt;/span&gt; argocd

&lt;span class="c"&gt;# Optional: Specify custom values&lt;/span&gt;
helm show values argo/argo-cd &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; values.yaml
helm &lt;span class="nb"&gt;install &lt;/span&gt;argocd argo/argo-cd &lt;span class="nt"&gt;-n&lt;/span&gt; argocd &lt;span class="nt"&gt;-f&lt;/span&gt; values.yaml

kubectl port-forward svc/argocd-server &lt;span class="nt"&gt;--address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.0.0.0 &lt;span class="nt"&gt;-n&lt;/span&gt; argocd 8080:443
&lt;span class="c"&gt;# Get the Initial Admin Password&lt;/span&gt;
kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; argocd get secret argocd-initial-admin-secret &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{.data.password}"&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why use Argo CD?&lt;/strong&gt;&lt;br&gt;
Argo CD solves common deployment and operations problems by embracing GitOps principles:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;How Argo CD Helps&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Manual &lt;code&gt;kubectl apply&lt;/code&gt; steps&lt;/td&gt;
&lt;td&gt;Automates syncing from Git&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configuration drift (manual changes)&lt;/td&gt;
&lt;td&gt;Detects drift and &lt;strong&gt;self-heals&lt;/strong&gt; by reverting to Git&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hard to audit who changed what&lt;/td&gt;
&lt;td&gt;Uses Git history as the &lt;strong&gt;single source of truth&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CI pipelines need cluster credentials&lt;/td&gt;
&lt;td&gt;Removes this risk — &lt;strong&gt;cluster pulls from Git&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Slow feedback on deployment status&lt;/td&gt;
&lt;td&gt;Real-time UI with &lt;strong&gt;health, sync status, and diffs&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;ArgoCD Concepts &amp;amp; Terminology :&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Term&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Application&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A group of Kubernetes resources as defined by a manifest.&lt;br&gt;An application is a Custom Resource Definition, which represents a deployed application instance in a cluster.&lt;br&gt;An application in ArgoCD is defined by two key pieces of information, the source &lt;code&gt;Git repo where is the desired state of a kubernetes manifest&lt;/code&gt; and the destination for your Kubernetes resources &lt;code&gt;where the resources should be deployed in a kubernetes&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Application source type&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The tool used to build the application. E.g., Helm, Kustomize, or Ksonnet.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Project&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Provides a logical grouping of applications, useful when Argo CD is used by multiple teams.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Target state&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The desired state of an application, as represented by files in a Git repository.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Live state&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The live state of that application. What pods, configmaps, secrets, etc. are created/deployed in a Kubernetes cluster.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sync status&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Whether or not the live state matches the target state. Is the deployed application the same as Git says it should be?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sync&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The process of making an application move to its target state (e.g., by applying changes to a Kubernetes cluster).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sync operation status&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Whether or not a sync succeeded.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Refresh&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Compare the latest code in Git with the live state to figure out what is different.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Health&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The health of the application — is it running correctly? Can it serve requests?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;What is an Argo CD Application?&lt;/strong&gt;&lt;br&gt;
An Application is the core deployment unit in Argo CD.&lt;br&gt;
It represents a set of Kubernetes resources defined in a Git repository and tells Argo CD:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where to get the manifests (Git repo + path + branch)&lt;/li&gt;
&lt;li&gt;Where to deploy them (cluster + namespace)&lt;/li&gt;
&lt;li&gt;How to manage them (sync policies like auto-sync, self-heal)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Creating an Application :&lt;/strong&gt;&lt;br&gt;
1.Using CLI&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;argocd app create color-app &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repo&lt;/span&gt; https://github.com/sid/app-1.git &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--path&lt;/span&gt; team-a/color-app &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dest-namespace&lt;/span&gt; color &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dest-server&lt;/span&gt; https://kubernetes.default.svc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explanation:&lt;br&gt;
--repo: Git repository URL containing the manifests.&lt;br&gt;
--path: Path inside the repo where the manifests are stored.&lt;br&gt;
--dest-namespace: Target namespace in the cluster.&lt;br&gt;
--dest-server: Target Kubernetes API server (usually the same cluster).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;argocd login localhost:8080 &lt;span class="nt"&gt;--username&lt;/span&gt; admin &lt;span class="nt"&gt;--password&lt;/span&gt; &amp;lt;password&amp;gt;
argocd app create solar-system-app &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repo&lt;/span&gt; https://github.com/sidd-harth/gitops-argocd &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--path&lt;/span&gt; ./solar-system &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dest-namespace&lt;/span&gt; solar-system &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dest-server&lt;/span&gt; https://kubernetes.default.svc

argocd app list
argocd app &lt;span class="nb"&gt;sync &lt;/span&gt;solar-system-app
argocd app get solar-system-app
&lt;span class="c"&gt;# check using kubectl with the namespace that argocd deployed in it&lt;/span&gt;
kubectl get app &lt;span class="nt"&gt;-n&lt;/span&gt; gitops
kubectl describe app &lt;span class="nt"&gt;-n&lt;/span&gt; gitops
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2.Using a YAML manifest (color-app.yaml)&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;argoproj.io/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;Application&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;color-app&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;argocd&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;project&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
  &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;repoURL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/sid/app-1.git&lt;/span&gt;
    &lt;span class="na"&gt;targetRevision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HEAD&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;team-a/color&lt;/span&gt;
  &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://kubernetes.default.svc&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;color&lt;/span&gt;
  &lt;span class="na"&gt;syncPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;automated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;selfHeal&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;syncOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CreateNamespace=true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;metadata.name: Application name shown in Argo CD UI.&lt;/li&gt;
&lt;li&gt;spec.source: Where manifests come from (repo, branch, path).&lt;/li&gt;
&lt;li&gt;spec.destination: Which cluster and namespace to deploy to.&lt;/li&gt;
&lt;li&gt;syncPolicy.automated: Enables auto-sync and self-healing.&lt;/li&gt;
&lt;li&gt;syncOptions.CreateNamespace=true: Automatically create the namespace if it doesn’t exist.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;3.using UI&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click “+ NEW APP”&lt;/li&gt;
&lt;li&gt;Application Name: A unique name (e.g. color-app)&lt;/li&gt;
&lt;li&gt;Project: Select default (unless you created custom projects)&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sync Policy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose Manual or Automatic&lt;/li&gt;
&lt;li&gt;Enable Self Heal and Prune if you want Argo CD to auto-fix drift and delete removed resources&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Specify the Source (Git Repo)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repository URL or Added it using &lt;code&gt;settings =&amp;gt; Repositories =&amp;gt; Connect Repo =&amp;gt; Via HTTP/HTTPS =&amp;gt; Type: git =&amp;gt; Name: Any Name =&amp;gt; Project: default =&amp;gt; Repository URL&lt;/code&gt; then check the Connection Status&lt;/li&gt;
&lt;li&gt;Revision: HEAD (or branch/tag name like main)&lt;/li&gt;
&lt;li&gt;Path: The path in the repo (./solar-system)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Specify the Destination (Cluster + Namespace)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cluster URL:

&lt;ul&gt;
&lt;li&gt;Use &lt;a href="https://kubernetes.default.svc" rel="noopener noreferrer"&gt;https://kubernetes.default.svc&lt;/a&gt; for the same cluster Argo CD is running in&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Namespace: solar-system

&lt;ul&gt;
&lt;li&gt;Check “Create Namespace” if it does not exist&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Review and Create&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click “Create”&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Sync the Application&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After creation, go to the app page&lt;/li&gt;
&lt;li&gt;Click “Sync” (if using manual sync)&lt;/li&gt;
&lt;li&gt;Argo CD will pull the manifests and deploy them to your cluster&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;ArgoCD Architecture :&lt;/strong&gt;&lt;br&gt;
Argo CD is deployed as a set of Kubernetes controllers and services inside your cluster.&lt;br&gt;
It continuously pulls manifests from Git and applies them to the cluster, keeping everything in sync.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;API Server&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Provides the UI, CLI (&lt;code&gt;argocd&lt;/code&gt;), and REST API. Handles RBAC and authentication.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Repository Server (Repo Server)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Clones Git repositories and renders manifests (Helm, Kustomize, etc.).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Application Controller&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Core GitOps reconciliation engine: compares desired vs live state and performs sync actions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dex (Optional)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Identity provider for SSO authentication (OIDC, GitHub, LDAP, etc.).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Redis (Optional)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Used as a cache to speed up repository and application state operations.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Create ArgoCD Project :&lt;/strong&gt;&lt;br&gt;
When you install Argo CD, it automatically creates a built-in project called default :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Has no restrictions by default&lt;/li&gt;
&lt;li&gt;Allows any Git repository as a source&lt;/li&gt;
&lt;li&gt;Allows deployments to any cluster and any namespace&lt;/li&gt;
&lt;li&gt;Allows all resource kinds (cluster-scoped and namespace-scoped)
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❯❯❯ argocd proj list
NAME     DESCRIPTION  DESTINATIONS  SOURCES  CLUSTER-RESOURCE-WHITELIST  NAMESPACE-RESOURCE-BLACKLIST  SIGNATURE-KEYS  ORPHANED-RESOURCES
default               *,*           *        */*                         &amp;lt;none&amp;gt;                        &amp;lt;none&amp;gt;          disabled
&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 get appproj &lt;span class="nt"&gt;-n&lt;/span&gt; gitops &lt;span class="c"&gt;# check project&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;we'll try to create a custom project which has some restrictions :&lt;/strong&gt;&lt;br&gt;
Creating your own AppProject lets you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Restrict which repos can be used&lt;/li&gt;
&lt;li&gt;Restrict which clusters/namespaces can be deployed to&lt;/li&gt;
&lt;li&gt;Apply RBAC per project&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Using UI :&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to Settings → Projects&lt;/li&gt;
&lt;li&gt;Click “+ NEW PROJECT”&lt;/li&gt;
&lt;li&gt;Project Name and Description&lt;/li&gt;
&lt;li&gt;Create&lt;/li&gt;
&lt;li&gt;Source Repositories: only repos will be allowed.&lt;/li&gt;
&lt;li&gt;Destinations (CLUSTER + NAMESPACE)&lt;/li&gt;
&lt;/ul&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%2Fnxtym8ljoukefoxjoqg7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnxtym8ljoukefoxjoqg7.png" alt=" " width="800" height="273"&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdc179lpkuv85oqkb8p43.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdc179lpkuv85oqkb8p43.png" alt=" " width="800" height="410"&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzv0304e6eampjze2rdri.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzv0304e6eampjze2rdri.png" alt=" " width="800" height="173"&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3tbfv8u1r5i7f8m51iik.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3tbfv8u1r5i7f8m51iik.png" alt=" " width="800" height="275"&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqljc1swj0aqjd9l4fbvx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqljc1swj0aqjd9l4fbvx.png" alt=" " width="800" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ClusterRole (in the rbac.authorization.k8s.io API group) is restricted.&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Any Application assigned to this Project that tries to create, update, or delete a ClusterRole will be blocked by Argo CD.&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;The sync will fail with a permission/validation error, and the ClusterRole resource will not be applied.&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Section&lt;/th&gt;
&lt;th&gt;What it means&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cluster Resource Allow List&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A whitelist of cluster-scoped resources (apply to the whole cluster, not tied to a namespace) that applications are allowed to create/update/delete. If empty → all are allowed by default.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cluster Resource Deny List&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A blacklist of cluster-scoped resources that applications are forbidden from managing. In your case, &lt;code&gt;ClusterRole&lt;/code&gt; is listed here — meaning apps in this project cannot create or modify ClusterRoles.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Namespace Resource Allow List&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A whitelist of namespace-scoped resources (like Deployments, ConfigMaps, Services, etc.) that applications are allowed to manage.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Namespace Resource Deny List&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A blacklist of namespace-scoped resources that are forbidden.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❯❯❯ argocd proj get test-project
Name:                        test-project
Description:                 for testing
Destinations:                https://kubernetes.default.svc,*
Repositories:                https://github.com/sidd-harth/gitops-argocd
Scoped Repositories:         &amp;lt;none&amp;gt;
Allowed Cluster Resources:   &amp;lt;none&amp;gt;
Scoped Clusters:             &amp;lt;none&amp;gt;
Denied Namespaced Resources: &amp;lt;none&amp;gt;
Signature keys:              &amp;lt;none&amp;gt;
Orphaned Resources:          disabled
&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;argocd proj get test-project &lt;span class="nt"&gt;-o&lt;/span&gt; yaml
&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;metadata:
  creationTimestamp: &lt;span class="s2"&gt;"2025-09-13T18:25:20Z"&lt;/span&gt;
  generation: 5
  managedFields:
  - apiVersion: argoproj.io/v1alpha1
    fieldsType: FieldsV1
    fieldsV1:
      f:spec:
        .: &lt;span class="o"&gt;{}&lt;/span&gt;
        f:clusterResourceBlacklist: &lt;span class="o"&gt;{}&lt;/span&gt;
        f:description: &lt;span class="o"&gt;{}&lt;/span&gt;
        f:destinations: &lt;span class="o"&gt;{}&lt;/span&gt;
        f:sourceRepos: &lt;span class="o"&gt;{}&lt;/span&gt;
      f:status: &lt;span class="o"&gt;{}&lt;/span&gt;
    manager: argocd-server
    operation: Update
    &lt;span class="nb"&gt;time&lt;/span&gt;: &lt;span class="s2"&gt;"2025-09-13T18:43:52Z"&lt;/span&gt;
  name: test-project
  namespace: gitops
  resourceVersion: &lt;span class="s2"&gt;"30359"&lt;/span&gt;
  uid: 829347ce-cb3d-46bb-8b1b-8bef6f5a9a56
spec:
  clusterResourceBlacklist:
  - group: &lt;span class="s1"&gt;'""'&lt;/span&gt;
    kind: ClusterRole
  description: &lt;span class="k"&gt;for &lt;/span&gt;testing
  destinations:
  - name: &lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="nt"&gt;-cluster&lt;/span&gt;
    namespace: &lt;span class="s1"&gt;'*'&lt;/span&gt;
    server: https://kubernetes.default.svc
  sourceRepos:
  - https://github.com/sidd-harth/gitops-argocd
status: &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;Applications in test-project can deploy anything from the specified Git repo to any namespace in the in-cluster cluster — except creating ClusterRole objects.&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  3. ArgoCD Intermediate
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Reconciliation loop
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. timeout.reconciliation (TIMEOUT option) :&lt;/strong&gt;&lt;br&gt;
What it is:&lt;br&gt;
A ConfigMap setting that defines the maximum duration of a single reconciliation loop.&lt;br&gt;
A reconciliation loop is how often your ArgoCD application will synchronize from the Git repository : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In a generic ArgoCD configuration, the default timeout period is set to 3 minutes.&lt;/li&gt;
&lt;li&gt;This value is configurable and is used within the ArgoCD repo server.&lt;/li&gt;
&lt;li&gt;The ArgoCD repo server is responsible to retrieve the desired state from the Git repo server and it has a timeout option called as the application reconciliation timeout.&lt;/li&gt;
&lt;li&gt;If we check the environment variable of ArgoCD repo server pod, it says that the key timeout reconciliation can be configured on an ArgoCD config map.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; gitops describe pod argocd-repo-server-cd79f5cc4-lvvgp | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"ARGOCD_RECONCILIATION_TIMEOUT:"&lt;/span&gt; &lt;span class="nt"&gt;-B1&lt;/span&gt;
kubectl get cm argocd-cm &lt;span class="nt"&gt;-n&lt;/span&gt; gitops &lt;span class="nt"&gt;-o&lt;/span&gt; yaml | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="nb"&gt;timeout&lt;/span&gt;
&lt;span class="c"&gt;# kubectl patch command to update the timeout.reconciliation value in the argocd-cm&lt;/span&gt;
kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; gitops patch configmap argocd-cm &lt;span class="nt"&gt;--patch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{"data":{"timeout.reconciliation":"300s"}}'&lt;/span&gt;
kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; gitops rollout restart deploy/argocd-repo-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;argocd-repo-server&lt;/code&gt; takes the config value from &lt;code&gt;argocd-cm&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❯❯❯ kubectl -n gitops describe pod argocd-repo-server-cd79f5cc4-lvvgp | grep -i "ARGOCD_RECONCILIATION_TIMEOUT:" -B1                                                                      
      ARGOCD_REPO_SERVER_NAME:                                      argocd-repo-server
      ARGOCD_RECONCILIATION_TIMEOUT:                                &amp;lt;set to the key 'timeout.reconciliation' of config map 'argocd-cm'&amp;gt;                                          Optional: true
&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;❯❯❯ k get cm argocd-cm -n gitops -o yaml | grep -i timeout.reconciliation                                                                                                                 
  timeout.reconciliation: 180s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Webhook (GIT WEBHOOK option) :&lt;/strong&gt;&lt;br&gt;
What it is:&lt;br&gt;
An event trigger that tells Argo CD to immediately start a reconciliation loop when new commits are pushed.&lt;br&gt;
Where configured:&lt;br&gt;
In your Git hosting platform (GitHub/GitLab/Bitbucket etc.)&lt;br&gt;
You add a webhook pointing to Argo CD’s API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://&amp;lt;argocd-server&amp;gt;/api/webhook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;kubectl -n gitops rollout restart deploy/argocd-repo-server&lt;br&gt;
Effect:&lt;br&gt;
Instead of waiting for the default polling interval (3 min), Argo CD instantly sees new commits and starts reconciliation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;By default, the argocd-server component only serves HTTPS (TLS) on port 443/8080.&lt;/strong&gt;&lt;br&gt;
When your Gitea webhook points to http://.../api/webhook instead of https://..., Argo CD will reject it (because it expects TLS), won’t accept it without valid HTTPS.&lt;br&gt;
The &lt;code&gt;--insecure&lt;/code&gt; flag tells argocd-server: “Serve plain HTTP instead of HTTPS.”&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl edit &lt;span class="nt"&gt;-n&lt;/span&gt; gitops deployments.apps argocd-server
&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;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;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/usr/local/bin/argocd-server&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--insecure&lt;/span&gt; &lt;span class="c1"&gt;# add this line&lt;/span&gt;
&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;❯❯❯ k get po -n gitops argocd-server-554fb76c44-ck57g                                                                                        ⎈ (kind-kind/solar-system)
NAME                             READY   STATUS    RESTARTS   AGE
argocd-server-554fb76c44-ck57g   1/1     Running   0          8m35s
&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 port-forward svc/argocd-server &lt;span class="nt"&gt;--address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.0.0.0 &lt;span class="nt"&gt;-n&lt;/span&gt; gitops 8080:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;Create a New App in ArgoCD&lt;/li&gt;
&lt;li&gt;Now, when you push a new commit, Argo will show an &lt;code&gt;Out of Sync&lt;/code&gt; status for this App.&lt;/li&gt;
&lt;/ul&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%2Fzuqo462obx32autrypyz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzuqo462obx32autrypyz.png" alt=" " width="800" height="236"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Application health
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🟢 &lt;strong&gt;Healthy&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;All resources are 100% healthy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔵 &lt;strong&gt;Progressing&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Resource is unhealthy, but could still be healthy given time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;💗 &lt;strong&gt;Degraded&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Resource status indicates a failure or an inability to reach a healthy state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🟡 &lt;strong&gt;Missing&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Resource is not present in the cluster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🟣 &lt;strong&gt;Suspended&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Resource is suspended or paused. Typical example is a paused Deployment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⚪ &lt;strong&gt;Unknown&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Health assessment failed and actual health status is unknown&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Sync Strategies
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Manual or automatic sync&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;If set to automatic, Argo CD will apply the changes then update or create new resources in the target Kubernetes cluster.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Auto-pruning of resources&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Auto-pruning feature describes what happens when files are deleted or removed from Git.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Self-Heal of cluster&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Self-heal defines what Argo CD does when you make &lt;code&gt;kubectl edit&lt;/code&gt; changes directly to the cluster.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Declarative Setup - Mono Application
&lt;/h3&gt;

&lt;p&gt;Mono-application = one Application object tracks exactly one app path.&lt;br&gt;
Keep app config declarative in Git; Argo CD watches it and reconciles automatically (if automated enabled).&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%2Fevbu60vo6v99f32ykxwa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fevbu60vo6v99f32ykxwa.png" alt=" " width="800" height="422"&gt;&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;argoproj.io/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;Application&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;geocentric-model-app&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;argocd&lt;/span&gt;
  &lt;span class="na"&gt;finalizers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;resources-finalizer.argocd.argoproj.io&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;project&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;

  &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;repoURL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://165.22.209.118:3000/siddharth/gitops-argocd.git&lt;/span&gt;
    &lt;span class="na"&gt;targetRevision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HEAD&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;./declarative/manifests/geocentric-model&lt;/span&gt;  &lt;span class="c1"&gt;# this path contains deployment and svc&lt;/span&gt;

  &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://kubernetes.default.svc&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;geocentric-model&lt;/span&gt;

  &lt;span class="na"&gt;syncPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;syncOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CreateNamespace=true&lt;/span&gt;  
    &lt;span class="na"&gt;automated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;prune&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;selfHeal&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;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; filename.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  App of Apps
&lt;/h3&gt;

&lt;p&gt;What is App of Apps?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mono-app = one Application → one set of manifests.&lt;/li&gt;
&lt;li&gt;App of Apps = one parent/root Application points to a folder containing multiple Application YAMLs.&lt;/li&gt;
&lt;li&gt;Argo CD applies the root app → which creates all the child apps.&lt;/li&gt;
&lt;li&gt;You only need to manually create the root application — all other apps are bootstrapped from Git.&lt;/li&gt;
&lt;/ul&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%2F19q4so2dhi43egrsoido.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F19q4so2dhi43egrsoido.png" alt=" " width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example repo structure :&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;gitops-repo/
└─ root/
   ├─ app-of-apps.yaml            &lt;span class="c"&gt;# the parent Argo CD Application&lt;/span&gt;
   ├─ apps/
   │   ├─ frontend.yaml           &lt;span class="c"&gt;# child app definition&lt;/span&gt;
   │   ├─ backend.yaml            &lt;span class="c"&gt;# child app definition&lt;/span&gt;
   │   └─ database.yaml            &lt;span class="c"&gt;# child app definition&lt;/span&gt;
   ├─ frontend/                   &lt;span class="c"&gt;# actual manifests (Helm/Kustomize/YAML)&lt;/span&gt;
   │   ├─ deployment.yaml
   │   └─ service.yaml
   ├─ backend/
   └─ database/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Parent Application (app-of-apps.yaml) :&lt;/strong&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;argoproj.io/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;Application&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;root-app&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;argocd&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;project&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
  &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;repoURL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/your-org/gitops-repo.git&lt;/span&gt;
    &lt;span class="na"&gt;targetRevision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main&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;root/apps&lt;/span&gt;                 &lt;span class="c1"&gt;# folder that holds child App YAMLs&lt;/span&gt;
    &lt;span class="na"&gt;directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;recurse&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;                 &lt;span class="c1"&gt;# include all files recursively&lt;/span&gt;
  &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://kubernetes.default.svc&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;argocd&lt;/span&gt;
  &lt;span class="na"&gt;syncPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;automated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;selfHeal&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;prune&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;syncOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CreateNamespace=true&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;One of the child applications (frontend.yaml) :&lt;/strong&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;argoproj.io/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;Application&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;frontend&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;argocd&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;project&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
  &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;repoURL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/your-org/gitops-repo.git&lt;/span&gt;
    &lt;span class="na"&gt;targetRevision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main&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;root/frontend&lt;/span&gt;
  &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://kubernetes.default.svc&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;frontend&lt;/span&gt;
  &lt;span class="na"&gt;syncPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;automated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;selfHeal&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;prune&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;syncOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CreateNamespace=true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How it works:&lt;br&gt;
1.Apply the root app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; root/app-of-apps.yaml &lt;span class="nt"&gt;-n&lt;/span&gt; argocd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2.Argo CD syncs the root app.&lt;br&gt;
3.Root app creates the child Application objects from Git.&lt;br&gt;
4.Each child app manages its own manifests as if it were a standalone app.&lt;/p&gt;
&lt;h3&gt;
  
  
  Deploy apps using HELM Chart
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Deploy Using My Helm Chart :&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❯❯❯ cd gitops-argocd/                                                                                                     ⎈ (kind-kind/solar-system)
[I] [~/gitops-argocd] (22:34:45) main

❯❯❯ ls | grep config                                                                                                      ⎈ (kind-kind/solar-system)
📂 declarative  📂 health-check  📂 helm-chart  📂 jenkins-demo  📄 LICENSE  📂 nginx-app  📂 sealed-secret  📂 solar-system  📂 vault-secrets
[I] [~/gitops-argocd] (22:34:46) main

❯❯❯ cd helm-chart/                                                                                                        ⎈ (kind-kind/solar-system)
[I] [~/g/helm-chart] (22:34:52) main

❯❯❯ cd templates/                                                                                                         ⎈ (kind-kind/solar-system)
[I] [~/g/h/templates] (22:34:56) main

❯❯❯ pwd                                                                                                                   ⎈ (kind-kind/solar-system)
/home/poseidon/gitops-argocd/helm-chart/templates
[I] [~/g/h/templates] (22:34:58) main

❯❯❯ ls                                                                                                                    ⎈ (kind-kind/solar-system)
📄 _helpers.tpl  📄 configmap.yaml  📄 deployment.yaml  📄 NOTES.txt  📄 service.yaml
[I] [~/g/h/templates] (22:35:00) main

❯❯❯ cat deployment.yaml                                                                                                   ⎈ (kind-kind/solar-system)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-deploy
  labels:
    {{- include "random-shapes.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      {{- include "random-shapes.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      {{- with .Values.podAnnotations }}
      annotations:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      labels:
        {{- include "random-shapes.selectorLabels" . | nindent 8 }}
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          envFrom:
          - configMapRef:
              name: {{ .Release.Name }}-configmap
[I] [~/g/h/templates] (22:35:04) main

❯❯❯ cat service.yaml                                                                                                      ⎈ (kind-kind/solar-system)
apiVersion: v1
kind: Service
metadata:
  name: {{ .Release.Name }}-service
  labels:
    {{- include "random-shapes.labels" . | nindent 4 }}
spec:
  type: {{ .Values.service.type }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: {{ .Values.service.targetPort }}
      protocol: TCP
      name: http
  selector:
    {{- include "random-shapes.selectorLabels" . | nindent 4 }}
[I] [~/g/h/templates] (22:35:07) main

❯❯❯ cd ..                                                                                                                 ⎈ (kind-kind/solar-system)
[I] [~/g/helm-chart] (22:35:12) main

❯❯❯ ls                                                                                                                    ⎈ (kind-kind/solar-system)
📄 Chart.yaml  📂 templates  📄 values.yaml
[I] [~/g/helm-chart] (22:35:13) main

❯❯❯ cat values.yaml                                                                                                       ⎈ (kind-kind/solar-system)
replicaCount: 1
image:
  repository: siddharth67/php-random-shapes:v1
  pullPolicy: IfNotPresent
  # Overrides the image tag whose default is the chart appVersion.
  tag: ""

imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""

service:
  type: ClusterIP
  port: 80
  targetPort: 80

color:
   circle: black
   oval: black
   triangle: black
   rectangle: black
   square: black    
[I] [~/g/helm-chart] (22:35:17) main

❯❯❯ cat Chart.yaml                                                                                                        ⎈ (kind-kind/solar-system)
apiVersion: v2
name: random-shapes-chart
description: A Helm chart for Random Shape App
version: 1.0.0
&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;argocd app create helm-random-shapes &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repo&lt;/span&gt; https://github.com/sidd-harth/gitops-argocd &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--path&lt;/span&gt; helm-chart &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--helm-set&lt;/span&gt; &lt;span class="nv"&gt;replicaCount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--helm-set&lt;/span&gt; color.circle&lt;span class="o"&gt;=&lt;/span&gt;pink &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--helm-set&lt;/span&gt; color.square&lt;span class="o"&gt;=&lt;/span&gt;green &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--helm-set&lt;/span&gt; service.type&lt;span class="o"&gt;=&lt;/span&gt;ClusterIP &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dest-namespace&lt;/span&gt; default &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dest-server&lt;/span&gt; https://kubernetes.default.svc
&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;❯❯❯ argocd app create helm-random-shapes \                                                                                ⎈ (kind-kind/solar-system)
          --repo https://github.com/sidd-harth/gitops-argocd \
          --path helm-chart \
          --helm-set replicaCount=2 \
          --helm-set color.circle=pink \
          --helm-set color.square=green \
          --helm-set service.type=ClusterIP \
          --dest-namespace default \
          --dest-server https://kubernetes.default.svc

application 'helm-random-shapes' created
[I] [~/gitops] (22:32:01) 
❯❯❯ h ls                                                                                                                  ⎈ (kind-kind/solar-system)
NAME    NAMESPACE   REVISION    UPDATED STATUS  CHART   APP VERSION
[I] [~/gitops] (22:32:09) 
❯❯❯ argocd app get helm-random-shapes                                                                                     ⎈ (kind-kind/solar-system)
Name:               gitops/helm-random-shapes
Project:            default
Server:             https://kubernetes.default.svc
Namespace:          default
URL:                https://argocd.example.com/applications/helm-random-shapes
Source:
- Repo:             https://github.com/sidd-harth/gitops-argocd
  Target:           
  Path:             helm-chart
SyncWindow:         Sync Allowed
Sync Policy:        Manual
Sync Status:        OutOfSync from  (05e2501)
Health Status:      Missing

GROUP  KIND        NAMESPACE  NAME                          STATUS     HEALTH   HOOK  MESSAGE
       ConfigMap   default    helm-random-shapes-configmap  OutOfSync  Missing        
       Service     default    helm-random-shapes-service    OutOfSync  Missing        
apps   Deployment  default    helm-random-shapes-deploy     OutOfSync  Missing        
[I] [~/gitops] (22:32:20) 
❯❯❯ argocd app get helm-random-shapes                                                                                     ⎈ (kind-kind/solar-system)
Name:               gitops/helm-random-shapes
Project:            default
Server:             https://kubernetes.default.svc
Namespace:          default
URL:                https://argocd.example.com/applications/helm-random-shapes
Source:
- Repo:             https://github.com/sidd-harth/gitops-argocd
  Target:           
  Path:             helm-chart
SyncWindow:         Sync Allowed
Sync Policy:        Manual
Sync Status:        Synced to  (05e2501)
Health Status:      Healthy

GROUP  KIND        NAMESPACE  NAME                          STATUS  HEALTH   HOOK  MESSAGE
       ConfigMap   default    helm-random-shapes-configmap  Synced                 configmap/helm-random-shapes-configmap created
       Service     default    helm-random-shapes-service    Synced  Healthy        service/helm-random-shapes-service created
apps   Deployment  default    helm-random-shapes-deploy     Synced  Healthy        deployment.apps/helm-random-shapes-deploy created
[I] [~/gitops] (22:32:51) 
❯❯❯ 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Deploy Using Bitnami Helm Charts :&lt;/strong&gt;&lt;br&gt;
Add Bitnami Helm Charts Repo :&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%2Fpend58uupx9qvnxclqoi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpend58uupx9qvnxclqoi.png" alt=" " width="800" height="400"&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbpnpbc3rdv5spme2su2i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbpnpbc3rdv5spme2su2i.png" alt=" " width="800" height="221"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create App : &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%2Fx42l4m1rfeso5a7ggx21.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx42l4m1rfeso5a7ggx21.png" alt=" " width="800" height="410"&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw2p8hh57tws15s7oicn6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw2p8hh57tws15s7oicn6.png" alt=" " width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You can also modify all the parameters : Change &lt;code&gt;service.type&lt;/code&gt; from &lt;code&gt;LoadBalancer&lt;/code&gt; to &lt;code&gt;ClusterIP&lt;/code&gt; :&lt;/strong&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%2F70amrsj3l108kv9mlwd6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F70amrsj3l108kv9mlwd6.png" alt=" " width="800" height="411"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❯❯❯ k get all -n bitnami                                                                                                  ⎈ (kind-kind/solar-system)
NAME                                          READY   STATUS     RESTARTS   AGE
pod/bitnami-helm-nginx-app-7bc9fc68c9-np9t7   0/1     Init:0/1   0          46s

NAME                             TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)          AGE
service/bitnami-helm-nginx-app   ClusterIP   10.96.61.98   &amp;lt;none&amp;gt;        80/TCP,443/TCP   47s

NAME                                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/bitnami-helm-nginx-app   0/1     1            0           46s

NAME                                                DESIRED   CURRENT   READY   AGE
replicaset.apps/bitnami-helm-nginx-app-7bc9fc68c9   1         1         0       46s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. ArgoCD Advanced
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How ArgoCD manages role-based access control.
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;RBAC Architecture in Argo CD :&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Users or Groups&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authenticated identities are then mapped to RBAC roles.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Roles&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logical sets of permissions.&lt;/li&gt;
&lt;li&gt;Defined in the argocd-rbac-cm ConfigMap (in the argocd namespace).&lt;/li&gt;
&lt;li&gt;Each role can contain multiple policy rules.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Policies (Rules)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define what actions a role can perform on what resources.&lt;/li&gt;
&lt;li&gt;Written in the format:
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;p, &amp;lt;role&amp;gt;, &amp;lt;resource&amp;gt;, &amp;lt;action&amp;gt;, &amp;lt;object&amp;gt;, &amp;lt;effect&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;resource → what kind of object (applications, projects, repositories, clusters…)&lt;br&gt;
action → get, create, update, delete, sync, override, etc.&lt;br&gt;
object → * (all) or specific names&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Role Bindings

&lt;ul&gt;
&lt;li&gt;Map users or groups to roles:
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;g, &amp;lt;username_or_group&amp;gt;, &amp;lt;role&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Give user jai permission to create clusters :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; argocd patch configmap argocd-rbac-cm &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--patch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{"data":{"policy.csv":"p, role:create-cluster, clusters, create, *, allow\ng, jai, role:create-cluster"}}'&lt;/span&gt;

&lt;span class="c"&gt;# Test it:&lt;/span&gt;
argocd account can-i create clusters &lt;span class="s1"&gt;'*'&lt;/span&gt;
&lt;span class="c"&gt;# should print: yes   # (when logged in as jai)&lt;/span&gt;

argocd account can-i delete clusters &lt;span class="s1"&gt;'*'&lt;/span&gt;
&lt;span class="c"&gt;# should print: no    # (when logged in as jai)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Give user ali permission to manage applications in kia-project :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; argocd patch configmap argocd-rbac-cm &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--patch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{"data":{"policy.csv":"p, role:kia-admins, applications, *, kia-project/*, allow\ng, ali, role:kia-admins"}}'&lt;/span&gt;

&lt;span class="c"&gt;# Test it:&lt;/span&gt;
argocd account can-i &lt;span class="nb"&gt;sync &lt;/span&gt;applications kia-project/&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="c"&gt;# should print: yes   # (when logged in as ali)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;p = policy (what a role can do)&lt;/li&gt;
&lt;li&gt;g = group binding (who gets the role)&lt;/li&gt;
&lt;li&gt;argocd account can-i ... tests permissions for the currently logged in user&lt;/li&gt;
&lt;li&gt;After patching, Argo CD automatically reloads the RBAC config (no restart needed)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  User Management
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The default ArgoCD installation has one built-in admin user that has full access to the system and is a super user.&lt;/li&gt;
&lt;li&gt;It is advised to only utilize the admin user for initial settings and then disable it after adding all required users.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❯❯❯ argocd account list                                                                                                   ⎈ (kind-kind/solar-system)

NAME   ENABLED  CAPABILITIES
admin  true     login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;New users can be created and used for various roles. &lt;/li&gt;
&lt;li&gt;New users can be defined using ArgoCD ConfigMap.&lt;/li&gt;
&lt;li&gt;We edit the ArgoCD ConfigMap and add &lt;code&gt;accounts.username&lt;/code&gt; record.&lt;/li&gt;
&lt;li&gt;Each user can be associated with two capabilities, API key and login.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Creates two local accounts: jai and ali&lt;/span&gt;
kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; argocd patch configmap argocd-cm &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--patch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{"data":{"accounts.jai": "apiKey,login"}}'&lt;/span&gt;

kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; argocd patch configmap argocd-cm &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--patch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{"data":{"accounts.ali": "apiKey,login"}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Grants them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;login → allows logging in via UI/CLI&lt;/li&gt;
&lt;li&gt;apiKey → API key allows generating JSON Web Token authentication for APl access.&lt;/li&gt;
&lt;li&gt;After this, you can bind them to RBAC roles using g, jai, role:... in the argocd-rbac-cm.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❯❯❯ kubectl -n gitops patch configmap argocd-cm \
        --patch='{"data":{"accounts.jai": "apiKey,login"}}'

configmap/argocd-cm patched

❯❯❯ kubectl -n gitops patch configmap argocd-cm \
        --patch='{"data":{"accounts.ali": "apiKey,login"}}'

configmap/argocd-cm patched

❯❯❯ argocd account list
NAME   ENABLED  CAPABILITIES
admin  true     login
ali    true     apiKey, login
jai    true     apiKey, login
&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;❯❯❯ argocd account update-password --account jai
*** Enter password of currently logged in user (admin): 
*** Enter new password for user jai: 
*** Confirm new password for user jai: 
Password updated
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;ArgoCD has two predefined default roles, &lt;code&gt;read-only&lt;/code&gt; and &lt;code&gt;admin&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;The read-only role&lt;/code&gt; provides read-only access to all the resources, whereas &lt;code&gt;the admin role&lt;/code&gt; provides unrestricted access to all resources.&lt;/li&gt;
&lt;li&gt;And by default, the admin user is assigned to the admin role.&lt;/li&gt;
&lt;li&gt;We can modify this and can also assign custom roles to users by editing the ArgoCD RBAC Config Map.
&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;&lt;span class="c"&gt;# set the default role in Argo CD RBAC to readonly&lt;/span&gt;
kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; argocd patch configmap argocd-rbac-cm &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--patch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{"data":{"policy.default": "role:readonly"}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we are patching the ArgoCD RBAC ConfigMap by assigning a default read-only role to any user who is not mapped to a specific role.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bitnami Sealed Secrets
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Summary of Flow :&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create normal Secret&lt;/li&gt;
&lt;li&gt;Encrypt with kubeseal → SealedSecret&lt;/li&gt;
&lt;li&gt;Commit to Git&lt;/li&gt;
&lt;li&gt;Argo CD syncs it&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sealed-secrets-controller&lt;/code&gt; decrypts to a real Secret&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Step 1 — Create a normal Kubernetes Secret manifest&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create secret generic mysql-password &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-literal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'s1Ddh@rt#'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dry-run&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;client &lt;span class="nt"&gt;-o&lt;/span&gt; yaml &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; mysql-password_k8s-secret.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This produces a file like:&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;mysql-password&lt;/span&gt;
&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;czF1RGRoQHJ0Iw==&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 2 — Install the Sealed Secrets controller (via Argo CD)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;argocd app create sealed-secrets &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repo&lt;/span&gt; https://bitnami-labs.github.io/sealed-secrets &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--helm-chart&lt;/span&gt; sealed-secrets &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--revision&lt;/span&gt; 2.2.0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dest-server&lt;/span&gt; https://kubernetes.default.svc &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dest-namespace&lt;/span&gt; kube-system

&lt;span class="c"&gt;# then sync &lt;/span&gt;
argocd app &lt;span class="nb"&gt;sync &lt;/span&gt;sealed

&lt;span class="c"&gt;# or &lt;/span&gt;
argocd app create sealed &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repo&lt;/span&gt; https://bitnami-labs.github.io/sealed-secrets &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--helm-chart&lt;/span&gt; sealed-secrets &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--revision&lt;/span&gt; 2.2.0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dest-server&lt;/span&gt; https://kubernetes.default.svc &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dest-namespace&lt;/span&gt; sealed &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--sync-option&lt;/span&gt; &lt;span class="nv"&gt;CreateNamespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--sync-policy&lt;/span&gt; automated

kubectl get all &lt;span class="nt"&gt;-n&lt;/span&gt; sealed
kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; sealed get deploy,sealedsecret,po,svc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 3 — Get the public certificate from the controller&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;# Export the cluster’s sealing public key:&lt;/span&gt;
kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; sealed get secret &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-l&lt;/span&gt; sealedsecrets.bitnami.com/sealed-secrets-key&lt;span class="o"&gt;=&lt;/span&gt;active &lt;span class="se"&gt;\&lt;/span&gt;
  &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].data.tls\.crt}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; sealedSecret.crt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 4 — Install the kubeseal CLI locally&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.18.0/kubeseal-0.18.0-linux-amd64.tar.gz &lt;span class="nt"&gt;-O&lt;/span&gt; kubeseal.tar.gz
&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xzf&lt;/span&gt; kubeseal.tar.gz
&lt;span class="nb"&gt;sudo install&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; 755 kubeseal /usr/local/bin/kubeseal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 5 — Seal your secret&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;# Use kubeseal to convert your Secret into a SealedSecret:&lt;/span&gt;
kubeseal &lt;span class="nt"&gt;-o&lt;/span&gt; yaml &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--scope&lt;/span&gt; cluster-wide &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cert&lt;/span&gt; sealedSecret.crt &lt;span class="se"&gt;\&lt;/span&gt;
  &amp;lt; mysql-password_k8s-secret.yaml &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; mysql-password_sealed-secret.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you have an encrypted SealedSecret manifest.&lt;/p&gt;

&lt;p&gt;Step 6 — Commit the SealedSecret to Git (Argo CD watches it)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Push &lt;code&gt;mysql-password_sealed-secret.yaml&lt;/code&gt; to your Git repo along with your &lt;code&gt;deployment.yaml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Argo CD will sync and apply it.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;sealed-secrets-controller&lt;/code&gt; pod will decrypt it and create the real &lt;code&gt;Secret&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Step 7 — Verify the decrypted Secret&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get secret mysql-password &lt;span class="nt"&gt;-o&lt;/span&gt; yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see the real base64-encoded password.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hashicorp Vault
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. ArgoCD Vault Plugin CLI :&lt;/strong&gt;&lt;br&gt;
Step 1 -- Create Vault App in ArgoCD&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%2Fotgvi2v7jaxtbrjnxv58.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fotgvi2v7jaxtbrjnxv58.png" alt=" " width="800" height="444"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❯❯❯ k get all -n vault-demo-gitops
NAME                                           READY   STATUS    RESTARTS   AGE
pod/vault-app-0                                0/1     Running   0          2m2s
pod/vault-app-agent-injector-67ff69f54-8dxqc   1/1     Running   0          2m3s

NAME                                   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
service/vault-app                      ClusterIP   10.96.132.44    &amp;lt;none&amp;gt;        8200/TCP,8201/TCP   2m3s
service/vault-app-agent-injector-svc   ClusterIP   10.96.201.162   &amp;lt;none&amp;gt;        443/TCP             2m3s
service/vault-app-internal             ClusterIP   None            &amp;lt;none&amp;gt;        8200/TCP,8201/TCP   2m3s

NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/vault-app-agent-injector   1/1     1            1           2m3s

NAME                                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/vault-app-agent-injector-67ff69f54   1         1         1       2m3s

NAME                         READY   AGE
statefulset.apps/vault-app   0/1     2m2s

❯❯❯ k get po -n vault-demo-gitops
NAME                                       READY   STATUS    RESTARTS   AGE
vault-app-0                                0/1     Running   0          2m10s
vault-app-agent-injector-67ff69f54-8dxqc   1/1     Running   0          2m11s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 2 --- Unsealed Process&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;# Access Vault UI&lt;/span&gt;
kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; vault-demo-gitops port-forward svc/vault-app 8200:8200 &lt;span class="nt"&gt;--address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.0.0.0
&lt;span class="c"&gt;# From UI: &lt;/span&gt;
&lt;span class="c"&gt;# Key shares: 3&lt;/span&gt;
&lt;span class="c"&gt;# Key threshold: 2&lt;/span&gt;
&lt;span class="c"&gt;# Then Download Keys (root key and 3 sealed keys) , then UI will ask you about Unseal Keys and root key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now: vault-app-0 will be 1/1  Ready state&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❯❯❯ k get po -n vault-demo-gitops
NAME                                       READY   STATUS    RESTARTS   AGE
vault-app-0                                1/1     Running   0          10m
vault-app-agent-injector-67ff69f54-8dxqc   1/1     Running   0          10m
&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;From UI: 
Enable new engine =&amp;gt; KV =&amp;gt; Next =&amp;gt; Path: Credentials =&amp;gt; Enable Engine =&amp;gt; Create Secret =&amp;gt; Path for this secret: app =&amp;gt; Secret Data =&amp;gt; Enter Random Vaules(username , password , apikey) =&amp;gt; Save 
Now From Secrets, we can see credentials and from three dots =&amp;gt; details , we can see path /credentials
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 3 -- Create Secret with Template Syntax: vault.yaml&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;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;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app-crds&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;avp.kubernetes.io/path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;credentials/data/app"&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;stringData&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;apikey&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;apikey&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;username&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;password&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 4 -- Install ArgoCD Vault Plugin&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;-L&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; argocd-vault-plugin https://github.com/argoproj-labs/argocd-vault-plugin/releases/download/v1.17.0/argocd-vault-plugin_1.17.0_linux_amd64
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x argocd-vault-plugin
&lt;span class="nb"&gt;sudo mv &lt;/span&gt;argocd-vault-plugin /usr/local/bin/

&lt;span class="c"&gt;# Verify installation&lt;/span&gt;
argocd-vault-plugin version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 5 -- Create vault.env&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VAULT_ADDR=http://localhost:8200
VAULT_TOKEN=&amp;lt;root token&amp;gt;
AVP_TYPE=vault
AVP_AUTH_TYPE=token
&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;argocd-vault-plugin generate &lt;span class="nt"&gt;-c&lt;/span&gt; vault.env - &amp;lt; vault.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will see as shown below :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: Secret
metadata:
  annotations:
    avp.kubernetes.io/path: credentials/data/app
  name: app-crds
stringData:
  apikey: sdfshifsdifj596211af
  password: root9289
  username: omar
type: Opaque
&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;❯❯❯ cat vault.yaml
kind: Secret
apiVersion: v1
metadata:
  name: app-crds
  annotations:
    avp.kubernetes.io/path: "credentials/data/app"
type: Opaque
stringData:
  apikey: &amp;lt;apikey&amp;gt;
  username: &amp;lt;username&amp;gt;
  password: &amp;lt;password&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. ArgoCD with ArgoCD Vault Plugin :&lt;/strong&gt;&lt;br&gt;
we need to patch &lt;code&gt;argocd-repo-server&lt;/code&gt; deployment and &lt;code&gt;argocd-cm&lt;/code&gt; config map :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;k edit &lt;span class="nt"&gt;-n&lt;/span&gt; gitops deployments.apps argocd-repo-server
&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;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;argocd-repo-server&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;template&lt;/span&gt;&lt;span class="pi"&gt;:&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;argocd-repo-server&lt;/span&gt;
        &lt;span class="na"&gt;volumeMounts&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;custom-tools&lt;/span&gt;
          &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/usr/local/bin/argocd-vault-plugin&lt;/span&gt;
          &lt;span class="na"&gt;subPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argocd-vault-plugin&lt;/span&gt;

        &lt;span class="c1"&gt;# Note: AVP config (for the secret manager, etc) can be passed in several ways. This is just one example&lt;/span&gt;
        &lt;span class="c1"&gt;# https://argocd-vault-plugin.readthedocs.io/en/stable/config/&lt;/span&gt;
        &lt;span class="na"&gt;envFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;secretRef&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;argocd-vault-plugin-credentials&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;custom-tools&lt;/span&gt;
        &lt;span class="na"&gt;emptyDir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&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;download-tools&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.8&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="nv"&gt;sh&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;-c&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

        &lt;span class="c1"&gt;# Don't forget to update this to whatever the stable release version is&lt;/span&gt;
        &lt;span class="c1"&gt;# Note the lack of the `v` prefix unlike the git tag&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AVP_VERSION&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;1.7.0"&lt;/span&gt;
        &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;-&lt;/span&gt;
            &lt;span class="s"&gt;wget -O argocd-vault-plugin&lt;/span&gt;
            &lt;span class="s"&gt;https://github.com/argoproj-labs/argocd-vault-plugin/releases/download/v${AVP_VERSION}/argocd-vault-plugin_${AVP_VERSION}_linux_amd64 &amp;amp;&amp;amp;&lt;/span&gt;
            &lt;span class="s"&gt;chmod +x argocd-vault-plugin &amp;amp;&amp;amp;&lt;/span&gt;
            &lt;span class="s"&gt;mv argocd-vault-plugin /custom-tools/&lt;/span&gt;
        &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/custom-tools&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;custom-tools&lt;/span&gt;

      &lt;span class="c1"&gt;# Not strictly necessary, but required for passing AVP configuration from a secret and for using Kubernetes auth to Hashicorp Vault&lt;/span&gt;
      &lt;span class="na"&gt;automountServiceAccountToken&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;k edit &lt;span class="nt"&gt;-n&lt;/span&gt; gitops cm argocd-cm
&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;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;configManagementPlugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|-&lt;/span&gt;
    &lt;span class="s"&gt;- name: argocd-vault-plugin&lt;/span&gt;
      &lt;span class="s"&gt;generate:&lt;/span&gt;
        &lt;span class="s"&gt;command: ["argocd-vault-plugin"]&lt;/span&gt;
        &lt;span class="s"&gt;args: ["generate", "./"]&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;k rollout restart deploy  argocd-repo-server
&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;From UI: 
Create App =&amp;gt; URL: https://github.com/sidd-harth/gitops-argocd
path: ./vault-secrets
under the namespace option , we will find Directory Icon, switch from Directory to  Plugin =&amp;gt; Name: argocd-vault-plugin =&amp;gt; Env: 
VAULT_ADDR=http://vault-app.vault-demo.svc.cluster.local:8200
VAULT_TOKEN=&amp;lt;root token&amp;gt;
AVP_TYPE=vault
AVP_AUTH_TYPE=token

=&amp;gt; Create
&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="c"&gt;# to test&lt;/span&gt;
k &lt;span class="nt"&gt;-n&lt;/span&gt; vault-secret get secrets &lt;span class="nt"&gt;-o&lt;/span&gt; yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






</description>
      <category>gitops</category>
      <category>argocd</category>
      <category>devops</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Falco With Kubernetes</title>
      <dc:creator>Omar Ahmed</dc:creator>
      <pubDate>Sat, 06 Sep 2025 20:40:33 +0000</pubDate>
      <link>https://forem.com/omar_ahmed/falco-2f7n</link>
      <guid>https://forem.com/omar_ahmed/falco-2f7n</guid>
      <description>&lt;h2&gt;
  
  
  Falco Basics
&lt;/h2&gt;

&lt;p&gt;Falco is an open-source, cloud-native runtime security project designed to detect unexpected application behavior and alert on threats in real time.&lt;br&gt;
By default, Falco has 5 outputs for its events: stdout, file, gRPC, shell and http. &lt;br&gt;
These can be integrated with other components using falcosidekick, a daemon that extends that number of possible outputs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Points about Falco:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Runtime Security:&lt;/strong&gt; It continuously monitors your applications, containers, and hosts at runtime to detect abnormal activities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Container Visibility:&lt;/strong&gt; It provides complete visibility into containerized environments using a single lightweight sensor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rules-Based Detection:&lt;/strong&gt; Falco uses a rich set of rules to define what is considered abnormal. When these rules are violated, alerts are triggered.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Examples of what Falco can detect by default:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A shell being run inside a container (which could indicate a breach).&lt;/li&gt;
&lt;li&gt;A server process spawning an unexpected type of child process.&lt;/li&gt;
&lt;li&gt;An attempt to read sensitive files, like /etc/shadow.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Falco Installation
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create namespace falco

helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update

helm &lt;span class="nb"&gt;install &lt;/span&gt;falco falcosecurity/falco &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--set&lt;/span&gt; falcosidekick.enabled&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--set&lt;/span&gt; falcosidekick.webui.enabled&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-n&lt;/span&gt; falco

&lt;span class="c"&gt;# falco → release name&lt;/span&gt;
&lt;span class="c"&gt;# falcosecurity/falco → chart&lt;/span&gt;
&lt;span class="c"&gt;# -n falco --create-namespace → installs Falco in a separate falco namespace&lt;/span&gt;

&lt;span class="c"&gt;# check that the Falco pods are running:&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; falco
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Test Using Falco UI
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl run nginx &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx &lt;span class="nt"&gt;-n&lt;/span&gt; falco &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Never &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;sleep &lt;/span&gt;infinity
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; nginx &lt;span class="nt"&gt;-n&lt;/span&gt; falco &lt;span class="nt"&gt;--&lt;/span&gt; bash 
&lt;span class="c"&gt;# user: admin , password: admin&lt;/span&gt;
kubectl port-forward &lt;span class="nt"&gt;--address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.0.0.0 svc/falco-falcosidekick-ui 3000:2802
&lt;span class="c"&gt;# go to events tab&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


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


&lt;h2&gt;
  
  
  Falco Slack Notifications
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Follow these steps to create and test a Slack Incoming Webhook for Falco alerts:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Channels =&amp;gt; Create =&amp;gt; Create Channel =&amp;gt; Channel Name =&amp;gt; Falco
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create an App&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click Create New App&lt;/li&gt;
&lt;li&gt;Go to &lt;a href="https://api.slack.com/apps" rel="noopener noreferrer"&gt;Slack API Apps&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Choose From Scratch&lt;/li&gt;
&lt;li&gt;Enter App Name: Falco Slack App&lt;/li&gt;
&lt;li&gt;Pick a workspace to develop your app: Test&lt;/li&gt;
&lt;li&gt;Click Create App&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enable Incoming Webhooks&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From the left sidebar → click Incoming Webhooks&lt;/li&gt;
&lt;li&gt;Switch Activate Incoming Webhooks → ON&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a Webhook to Workspace&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scroll down and click Add New Webhook to Workspace&lt;/li&gt;
&lt;li&gt;Select a channel: #falco&lt;/li&gt;
&lt;li&gt;Click Allow&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Copy and Test the Sample Curl URL Request&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Run the sample Curl URL request in your terminal:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{"text":"Hello, World!"}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX 
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open your Slack #falco channel,You should see: Hello, World! &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy &lt;strong&gt;the Webhook URL Provided&lt;/strong&gt; and use it below:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm upgrade falco falcosecurity/falco &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--set&lt;/span&gt; falcosidekick.enabled&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--set&lt;/span&gt; falcosidekick.webui.enabled&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--set&lt;/span&gt; falcosidekick.config.slack.webhookurl&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://hooks.slack.com/services/XXXX"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--set&lt;/span&gt; falcosidekick.config.customfields&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"environment:production&lt;/span&gt;&lt;span class="se"&gt;\,&lt;/span&gt;&lt;span class="s2"&gt;datacenter:egypt"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-n&lt;/span&gt; falco 

&lt;span class="c"&gt;# check the revision number&lt;/span&gt;
helm &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; falco

&lt;span class="c"&gt;# attach a terminal in a container &lt;/span&gt;
kubectl run nginx &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx &lt;span class="nt"&gt;-n&lt;/span&gt; falco &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Never &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;sleep &lt;/span&gt;infinity
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; nginx &lt;span class="nt"&gt;-n&lt;/span&gt; falco &lt;span class="nt"&gt;--&lt;/span&gt; bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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




</description>
      <category>kubernetes</category>
      <category>falco</category>
      <category>devops</category>
      <category>devsecops</category>
    </item>
    <item>
      <title>Istio - Service Mesh</title>
      <dc:creator>Omar Ahmed</dc:creator>
      <pubDate>Fri, 05 Sep 2025 15:41:45 +0000</pubDate>
      <link>https://forem.com/omar_ahmed/istio-service-mesh-4ncl</link>
      <guid>https://forem.com/omar_ahmed/istio-service-mesh-4ncl</guid>
      <description>&lt;h3&gt;
  
  
  Istio Basics
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Download Istio CLI&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;curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://istio.io/downloadIstio | sh -
&lt;span class="nb"&gt;cd &lt;/span&gt;istio-&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$PWD&lt;/span&gt;/bin:&lt;span class="nv"&gt;$PATH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Install Istio control plane&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;istioctl &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--set&lt;/span&gt; &lt;span class="nv"&gt;profile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;demo &lt;span class="nt"&gt;-y&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; istio-system
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Enable auto sidecar injection on prod&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;kubectl create namespace prod
kubectl label namespace prod istio-injection&lt;span class="o"&gt;=&lt;/span&gt;enabled
&lt;span class="c"&gt;# Confirm:&lt;/span&gt;
kubectl get ns &lt;span class="nt"&gt;--show-labels&lt;/span&gt;
kubectl get namespace &lt;span class="nt"&gt;-L&lt;/span&gt; istio-injection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Open Kiali UI&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;# Kiali's UI&lt;/span&gt;
kubectl port-forward &lt;span class="nt"&gt;--address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.0.0.0 svc/kiali 3000:20001 
&lt;span class="c"&gt;# Then open: http://localhost:3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5. Verify sidecar injection (pods should be 2/2 Ready)&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;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; prod create deploy node-app &lt;span class="nt"&gt;--image&lt;/span&gt; siddharth67/node-service:v1
kubectl describe pod node-app-786cb44f85-wkq99 &lt;span class="nt"&gt;-n&lt;/span&gt; prod | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-A2&lt;/span&gt; &lt;span class="s2"&gt;"Containers:"&lt;/span&gt;
&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;❯❯❯ kubectl describe pod node-app-786cb44f85-wkq99 -n prod | grep -A2 "Containers:"                                                        ⎈ (kind-kind/prod)
Init Containers:
  istio-init:
    Container ID:  containerd://2b5ae904579ca1739120831e123b29d23ee3649c6e615f9b4fd1b24f07bbfea7
--
Containers:
  node-service:
    Container ID:   containerd://97484d714ff2c66bf40408aa674b75c049f32f0f9bfbd8d76b7a17f784bbb53b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Istio Ingress Gateway
&lt;/h3&gt;

&lt;p&gt;The Istio Ingress Gateway is a specialized Envoy proxy that handles inbound traffic from outside the service mesh into your cluster.&lt;br&gt;
&lt;strong&gt;What it does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Acts as the entry point for external traffic&lt;/li&gt;
&lt;li&gt;Provides load balancing, TLS termination, and protocol handling&lt;/li&gt;
&lt;li&gt;Replaces traditional ingress controllers in Istio environments&lt;/li&gt;
&lt;li&gt;Runs as a deployment (not a sidecar)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Virtual Service
&lt;/h3&gt;

&lt;p&gt;Virtual Service defines routing rules - it tells the gateway WHERE to send the traffic once it enters the mesh.&lt;br&gt;
&lt;strong&gt;What it does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Defines traffic routing logic&lt;/li&gt;
&lt;li&gt;Handles path-based routing, header matching, traffic splitting&lt;/li&gt;
&lt;li&gt;Works with both ingress traffic (via Gateway) and internal traffic&lt;/li&gt;
&lt;li&gt;Provides advanced routing features like retries, timeouts, fault injection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;6. Bring traffic through Istio ingress (so Kiali can see it)&lt;/strong&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;networking.istio.io/v1alpha3&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Gateway&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;devsecops-gateway&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;prod&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;istio&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ingressgateway&lt;/span&gt;
  &lt;span class="na"&gt;servers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HTTP&lt;/span&gt;
    &lt;span class="na"&gt;hosts&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;*"&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.istio.io/v1alpha3&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;VirtualService&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;devsecops-vs&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;prod&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;hosts&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;*"&lt;/span&gt;
  &lt;span class="na"&gt;gateways&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;devsecops-gateway&lt;/span&gt;
  &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;match&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/plusone&lt;/span&gt;
    &lt;span class="na"&gt;route&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;devsecops-svc&lt;/span&gt;
        &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;End-to-end path:&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;&lt;code&gt;Client → Istio ingressgateway (port 80) → VirtualService match /plusone → ClusterIP Service devsecops-svc:5000 → Pod.&lt;/code&gt;&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;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; prod apply &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: devsecops
  name: devsecops
spec:
  replicas: 3
  selector:
    matchLabels:
      app: devsecops
  template:
    metadata:
      labels:
        app: devsecops
    spec:
      serviceAccountName: default
      volumes:
      - name: vol
        emptyDir: {}
      containers:
      - name: devsecops-container
        image: siddharth67/node-service:v1   
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
        volumeMounts:
        - mountPath: /tmp
          name: vol
        securityContext:
          capabilities:
            drop: [ "NET_RAW" ]
          runAsUser: 100
          runAsNonRoot: true
          readOnlyRootFilesystem: true
          allowPrivilegeEscalation: false
        resources:
          requests:
            memory: "256Mi"
            cpu: "200m"
          limits:
            memory: "512Mi"
            cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: devsecops
  name: devsecops-svc
spec:
  selector:
    app: devsecops
  ports:
  - port: 8080
    targetPort: 8080
    protocol: TCP
  type: ClusterIP
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;7. Send traffic through the mesh&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;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; istio-system port-forward svc/istio-ingressgateway 8080:80
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://localhost:8080/plusone/99&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;sleep&lt;/span&gt; .2&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Kiali will not see the traffic if you're not routing through the Istio gateway,&lt;/strong&gt; so if we want to see the workload through the Kiali UI, we should create IngressGateway and VirtualService objects.&lt;br&gt;
Here's why: Kiali visualizes service mesh traffic by reading telemetry data that Istio's sidecars (Envoy proxies) collect. For this to work, your traffic needs to flow through Istio's data plane components.&lt;/p&gt;


&lt;h3&gt;
  
  
  Istio mTLS - Auto mutual TLS
&lt;/h3&gt;

&lt;p&gt;mTLS (mutual TLS) with Istio provides automatic encryption and authentication between services in your mesh. Here's how it works:&lt;br&gt;
&lt;strong&gt;Default Behavior:&lt;/strong&gt;&lt;br&gt;
Istio enables mTLS automatically when sidecars are injected:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Traffic between services with sidecars is automatically encrypted&lt;/li&gt;
&lt;li&gt;Uses permissive mode by default (accepts both mTLS and plain text)&lt;/li&gt;
&lt;li&gt;No configuration needed for basic mTLS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;App A ──(plaintext)──► Sidecar A ──(mTLS)──► Sidecar B ──(plaintext)──► App B&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  PeerAuthentication modes
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;1. PERMISSIVE (Default)&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
Traffic accepted:&lt;br&gt;
✅ mTLS from other sidecars&lt;br&gt;
✅ Plain text from non-mesh services&lt;br&gt;
✅ Plain text from services without sidecars&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;security.istio.io/v1beta1&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;PeerAuthentication&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;default&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;prod&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;mtls&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PERMISSIVE&lt;/span&gt;  &lt;span class="c1"&gt;# Accepts both mTLS and plaintext&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;2. STRICT&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
Traffic accepted:&lt;br&gt;
✅ mTLS from other sidecars&lt;br&gt;
❌ Plain text traffic (rejected with connection errors)&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;security.istio.io/v1beta1&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;PeerAuthentication&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;enforce-mtls&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;prod&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;mtls&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;STRICT&lt;/span&gt;  &lt;span class="c1"&gt;# Only accepts mTLS traffic&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;3. DISABLE&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
Traffic accepted:&lt;br&gt;
❌ mTLS traffic (rejected)&lt;br&gt;
✅ Plain text traffic only&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;security.istio.io/v1beta1&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;PeerAuthentication&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;disable-mtls&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;prod&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;mtls&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DISABLE&lt;/span&gt;
&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;❯❯❯ k get crd
NAME                                       CREATED AT
authorizationpolicies.security.istio.io    2025-09-05T13:29:53Z
destinationrules.networking.istio.io       2025-09-05T13:29:52Z
envoyfilters.networking.istio.io           2025-09-05T13:29:52Z
gateways.networking.istio.io               2025-09-05T13:29:52Z
peerauthentications.security.istio.io      2025-09-05T13:29:54Z #&amp;lt;&amp;lt;##########
proxyconfigs.networking.istio.io           2025-09-05T13:29:52Z
requestauthentications.security.istio.io   2025-09-05T13:29:54Z
serviceentries.networking.istio.io         2025-09-05T13:29:52Z
sidecars.networking.istio.io               2025-09-05T13:29:53Z
telemetries.telemetry.istio.io             2025-09-05T13:29:54Z
virtualservices.networking.istio.io        2025-09-05T13:29:53Z
wasmplugins.extensions.istio.io            2025-09-05T13:29:51Z
workloadentries.networking.istio.io        2025-09-05T13:29:53Z
workloadgroups.networking.istio.io         2025-09-05T13:29:53Z

❯❯❯ k get peerauthentications
No resources found in prod namespace.

❯❯❯ k get pa  # peerauthentications
No resources found in prod namespace.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;8. MTLS Modes:&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;kubectl apply &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: mtls
  namespace: prod
spec:
  mtls:
    mode: PERMISSIVE
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Apply the Deployment below for testing:&lt;/strong&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;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;devsecops-client&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;prod&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;devsecops-client&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;devsecops-client&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;devsecops-client&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;curl&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;curlimages/curl:latest&lt;/span&gt;
        &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sh&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="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;while true; do&lt;/span&gt;
              &lt;span class="s"&gt;echo "$(date) -&amp;gt; $(curl -sS -o /dev/null -w '%{http_code}' http://devsecops-svc.prod.svc.cluster.local:5000/health || echo 'curl-failed')";&lt;/span&gt;
              &lt;span class="s"&gt;sleep 5;&lt;/span&gt;
            &lt;span class="s"&gt;done&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;runAsNonRoot&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;runAsUser&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;
          &lt;span class="na"&gt;allowPrivilegeEscalation&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;readOnlyRootFilesystem&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;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;50m&lt;/span&gt;
            &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;64Mi&lt;/span&gt;
          &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;200m&lt;/span&gt;
            &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;128Mi&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; deploy.yaml
&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;❯❯❯ k get pa                                                                                                                                                    
NAME   MODE         AGE
mtls   PERMISSIVE   103s

❯❯❯ k describe pa mtls                                                                                                                                  
Name:         mtls
Namespace:    prod
Labels:       &amp;lt;none&amp;gt;
Annotations:  &amp;lt;none&amp;gt;
API Version:  security.istio.io/v1
Kind:         PeerAuthentication
Metadata:
  Creation Timestamp:  2025-09-06T13:04:22Z
  Generation:          1
  Resource Version:    48804
  UID:                 1c9f7fbd-a1a3-4135-9a8a-94e7efb65e9e
Spec:
  Mtls:
    Mode: PERMISSIVE
Events:    &amp;lt;none&amp;gt;     
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❯❯❯ cat pa.yaml                                                                                                                                                 
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: mtls
  namespace: prod
spec:
  mtls:
    mode: DISABLE

❯❯❯ k apply -f pa.yaml                                                                                                                                          
peerauthentication.security.istio.io/mtls configured

❯❯❯ k get pa                                                                                                                                                    
NAME   MODE      AGE
mtls   DISABLE   10m

❯❯❯ k describe pa mtls                                                                                                                                          
Name:         mtls
Namespace:    prod
Labels:       &amp;lt;none&amp;gt;
Annotations:  &amp;lt;none&amp;gt;
API Version:  security.istio.io/v1
Kind:         PeerAuthentication
Metadata:
  Creation Timestamp:  2025-09-06T13:14:56Z
  Generation:          2
  Resource Version:    51468
  UID:                 17008123-2ca7-414c-9b37-136fdc9a67ad
Spec:
  Mtls:
    Mode:  DISABLE
Events:    &amp;lt;none&amp;gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

</description>
      <category>devops</category>
      <category>devsecops</category>
      <category>kubernetes</category>
      <category>istio</category>
    </item>
    <item>
      <title>Vault With Kubernetes 🔐</title>
      <dc:creator>Omar Ahmed</dc:creator>
      <pubDate>Wed, 03 Sep 2025 22:24:46 +0000</pubDate>
      <link>https://forem.com/omar_ahmed/vault-with-kubernetes-452k</link>
      <guid>https://forem.com/omar_ahmed/vault-with-kubernetes-452k</guid>
      <description>&lt;h2&gt;
  
  
  What is HashiCorp Vault?
&lt;/h2&gt;

&lt;p&gt;HashiCorp Vault is a secrets &amp;amp; encryption platform for securely storing, generating, and controlling access to sensitive data (API keys, DB creds, TLS certs, tokens, etc.). Teams use it to centralize secrets, issue short-lived credentials on demand, and enforce least-privilege access across apps, CI/CD, and infrastructure&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Vault Without a DataStorage (Dev Mode)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm repo add hashicorp https://helm.releases.hashicorp.com
helm repo update
helm repo list
helm &lt;span class="nb"&gt;install &lt;/span&gt;vault hashicorp/vault &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--namespace&lt;/span&gt; vault &lt;span class="nt"&gt;--create-namespace&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; &lt;span class="s1"&gt;'server.dev.enabled=true'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; &lt;span class="s1"&gt;'server.dataStorage.enabled=false'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; &lt;span class="s1"&gt;'ui.enabled=true'&lt;/span&gt;
kubectl config set-context &lt;span class="nt"&gt;--current&lt;/span&gt; &lt;span class="nt"&gt;--namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vault
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Install Vault With a DataStorage (Raft storage)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; values.yaml &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;YAML&lt;/span&gt;&lt;span class="sh"&gt;'
server:
  dev:
    enabled: false
  standalone:
    enabled: true
    config: |
      ui = true
      listener "tcp" {
        address         = "[::]:8200"
        cluster_address = "[::]:8201"
        tls_disable     = 1
      }
      storage "raft" {
        path = "/vault/data"
      }
  dataStorage:
    enabled: true
    size: 1Gi

ui:
  enabled: true
  serviceType: ClusterIP   # use port-forward; change to NodePort/Ingress if you prefer
&lt;/span&gt;&lt;span class="no"&gt;YAML
&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;helm repo add hashicorp https://helm.releases.hashicorp.com
helm repo update
helm &lt;span class="nt"&gt;-n&lt;/span&gt; vault &lt;span class="nb"&gt;install &lt;/span&gt;vault hashicorp/vault &lt;span class="nt"&gt;-f&lt;/span&gt; values.yaml &lt;span class="nt"&gt;--create-namespace&lt;/span&gt; &lt;span class="nt"&gt;--version&lt;/span&gt; 0.16.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Seal/Unseal
&lt;/h2&gt;

&lt;p&gt;When you start a Vault server, it starts in a sealed state. In this state, Vault can access the physical storage, but it cannot decrypt any of the data on it.&lt;br&gt;
Vault encrypts the data using an encryption key (in the keyring) and stores them in its storage backend. To protect this encryption key, Vault encrypts it using another encryption key known as the root key and stores it with the data.&lt;br&gt;
To decrypt the data, Vault needs the root key so that it can decrypt the encryption key. Unsealing is the process of getting access to this root key. Vault encrypts the root key using the unseal key, and stores it alongside all other Vault data.&lt;br&gt;
&lt;strong&gt;To summarize,&lt;/strong&gt; Vault encrypts most data using the encryption key in the keyring. To get the keyring, Vault uses the root key to decrypt it. The root key itself requires the unseal key to decrypt it. &lt;/p&gt;
&lt;h2&gt;
  
  
  Shamir seals
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Key Shares / Unseal Keys                Root Key               Encryption Key
                                                              (protected by root key)
┌─────────────────────┐
│ Jon      🔑         │
├─────────────────────┤
│ Jane     🔑         │--------------&amp;gt;&amp;gt;&amp;gt;🔑 ----------------------&amp;gt;&amp;gt;🔑
├─────────────────────┤                Root Key                  Encryption Key
│ James    🔑         │
├─────────────────────┤
│ Alison   🔑         │
├─────────────────────┤
│ Pam      🔑         │
└─────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Instead of distributing the unseal key to an operator as a single key, the default Vault configuration uses an algorithm known as Shamir's Secret Sharing to split the key into shares.&lt;br&gt;
Vault requires a certain threshold of shares to reconstruct the unseal key. Vault operators add shares one at a time in any order until Vault has enough shares to reconstruct the key. Then, Vault uses the unseal key to decrypt the root key. This is the Vault unseal process.&lt;br&gt;
&lt;strong&gt;To Summarize:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vault never writes the master key to disk.&lt;/li&gt;
&lt;li&gt;Only encrypted data is stored (plus an encrypted data-encryption key). &lt;/li&gt;
&lt;li&gt;On startup Vault can’t decrypt anything by itself, so it starts sealed. &lt;/li&gt;
&lt;li&gt;Unseal = provide a quorum of unseal key shares (Shamir) to reconstruct the master key in memory → that master key decrypts the data-encryption key → Vault becomes unsealed and can serve requests.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯❯❯ k get po                                                                                ⎈ &lt;span class="o"&gt;(&lt;/span&gt;kind-my-cluster/vault&lt;span class="o"&gt;)&lt;/span&gt;
NAME                                    READY   STATUS    RESTARTS   AGE
vault-0                                 0/1     Running   0          55s
vault-agent-injector-6d97459765-4mc6b   1/1     Running   0          55s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;vault-0     0/1  Ready (not 1/1) &amp;gt;&amp;gt;  because vault is sealed&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;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; vault &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; vault-0 &lt;span class="nt"&gt;--&lt;/span&gt; vault status &lt;span class="c"&gt;# sealed=true as shown below&lt;/span&gt;
Key                Value
&lt;span class="nt"&gt;---&lt;/span&gt;                &lt;span class="nt"&gt;-----&lt;/span&gt;
Seal Type          shamir
Initialized        &lt;span class="nb"&gt;true
&lt;/span&gt;Sealed             &lt;span class="nb"&gt;true
&lt;/span&gt;Total Shares       5
Threshold          3
Unseal Progress    0/3
Unseal Nonce       n/a
Version            1.8.3
Storage Type       raft
HA Enabled         &lt;span class="nb"&gt;true&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;❯❯❯ k &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; vault-0 &lt;span class="nt"&gt;--&lt;/span&gt; /bin/sh                                    ⎈ &lt;span class="o"&gt;(&lt;/span&gt;kind-my-cluster/vault&lt;span class="o"&gt;)&lt;/span&gt;
/ &lt;span class="nv"&gt;$ &lt;/span&gt;vault operator init 
Unseal Key 1: Q3Awl3Qw+ItIWFyLFVGFiE3OOJ1qHrHC+kQnFD2kwLbE
Unseal Key 2: OON236vYc+bf3K45J75lVHy3FmwIRdUT+mGPU3Iq4SX9
Unseal Key 3: N53iBqGPiL9RRkNNVg5DmrlD5dn6R3Vt703y6NhVUB+0
Unseal Key 4: mWPyNPitk8JTlxZByNkyYJefDo+MTpfIEcDn/lkaKuP3
Unseal Key 5: kRHm81+cYIbjO12eFJp0iJP8y3u7CR4NkOAb/4nHS5Kl

Initial Root Token: s.bQN8VBeKBga76dAUVmaGyTjJ

Vault initialized with 5 key shares and a key threshold of 3. Please securely
distribute the key shares printed above. When the Vault is re-sealed,
restarted, or stopped, you must supply at least 3 of these keys to unseal it
before it can start servicing requests.

Vault does not store the generated master key. Without at least 3 keys to
reconstruct the master key, Vault will remain permanently sealed!

It is possible to generate new unseal keys, provided you have a quorum of
existing unseal keys shares. See &lt;span class="s2"&gt;"vault operator rekey"&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;more information.
/ &lt;span class="nv"&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;vault operator unseal Q3Awl3Qw+ItIWFyLFVGFiE3OOJ1qHrHC+kQnFD2kwLbE
Key                Value
&lt;span class="nt"&gt;---&lt;/span&gt;                &lt;span class="nt"&gt;-----&lt;/span&gt;
Seal Type          shamir
Initialized        &lt;span class="nb"&gt;true
&lt;/span&gt;Sealed             &lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="c"&gt;###### it is still sealed&lt;/span&gt;
Total Shares       5
Threshold          3
Unseal Progress    1/3
Unseal Nonce       8932e24e-a03d-59e7-a694-9c9d9d6005f3
Version            1.8.3
Storage Type       raft
HA Enabled         &lt;span class="nb"&gt;true&lt;/span&gt;
/ &lt;span class="nv"&gt;$ &lt;/span&gt;vault operator unseal OON236vYc+bf3K45J75lVHy3FmwIRdUT+mGPU3Iq4SX9
Key                Value
&lt;span class="nt"&gt;---&lt;/span&gt;                &lt;span class="nt"&gt;-----&lt;/span&gt;
Seal Type          shamir
Initialized        &lt;span class="nb"&gt;true
&lt;/span&gt;Sealed             &lt;span class="nb"&gt;true
&lt;/span&gt;Total Shares       5
Threshold          3
Unseal Progress    2/3
Unseal Nonce       8932e24e-a03d-59e7-a694-9c9d9d6005f3
Version            1.8.3
Storage Type       raft
HA Enabled         &lt;span class="nb"&gt;true&lt;/span&gt;
/ &lt;span class="nv"&gt;$ &lt;/span&gt;vault operator unseal N53iBqGPiL9RRkNNVg5DmrlD5dn6R3Vt703y6NhVUB+0
Key                     Value
&lt;span class="nt"&gt;---&lt;/span&gt;                     &lt;span class="nt"&gt;-----&lt;/span&gt;
Seal Type               shamir
Initialized             &lt;span class="nb"&gt;true
&lt;/span&gt;Sealed                  &lt;span class="nb"&gt;false&lt;/span&gt; &lt;span class="c"&gt;######## it is unsealed&lt;/span&gt;
Total Shares            5
Threshold               3
Version                 1.8.3
Storage Type            raft
Cluster Name            vault-cluster-62a5fa0a
Cluster ID              97d206e3-d4a2-2c1f-f898-6a95c034b87e
HA Enabled              &lt;span class="nb"&gt;true
&lt;/span&gt;HA Cluster              n/a
HA Mode                 standby
Active Node Address     &amp;lt;none&amp;gt;
Raft Committed Index    24
Raft Applied Index      24
/ &lt;span class="nv"&gt;$ &lt;/span&gt;vault status
Key                     Value
&lt;span class="nt"&gt;---&lt;/span&gt;                     &lt;span class="nt"&gt;-----&lt;/span&gt;
Seal Type               shamir
Initialized             &lt;span class="nb"&gt;true
&lt;/span&gt;Sealed                  &lt;span class="nb"&gt;false&lt;/span&gt; &lt;span class="c"&gt;#&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;#########&lt;/span&gt;
Total Shares            5
Threshold               3
Version                 1.8.3
Storage Type            raft
Cluster Name            vault-cluster-62a5fa0a
Cluster ID              97d206e3-d4a2-2c1f-f898-6a95c034b87e
HA Enabled              &lt;span class="nb"&gt;true
&lt;/span&gt;HA Cluster              https://vault-0.vault-internal:8201
HA Mode                 active
Active Since            2025-09-03T20:26:58.922335892Z
Raft Committed Index    29
Raft Applied Index      29
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Vault-0 becomes 1/1 Ready state (now vault is unsealed):&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;❯❯❯ k get po                                                        ⎈ &lt;span class="o"&gt;(&lt;/span&gt;kind-my-cluster/vault&lt;span class="o"&gt;)&lt;/span&gt;
NAME                                    READY   STATUS    RESTARTS   AGE
vault-0                                 1/1     Running   0          27m
vault-agent-injector-6d97459765-4mc6b   1/1     Running   0          27m
&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;vault operator init 
Unseal Key 1: Q3Awl3Qw+ItIWFyLFVGFiE3OOJ1qHrHC+kQnFD2kwLbE
Unseal Key 2: OON236vYc+bf3K45J75lVHy3FmwIRdUT+mGPU3Iq4SX9
Unseal Key 3: N53iBqGPiL9RRkNNVg5DmrlD5dn6R3Vt703y6NhVUB+0
Unseal Key 4: mWPyNPitk8JTlxZByNkyYJefDo+MTpfIEcDn/lkaKuP3
Unseal Key 5: kRHm81+cYIbjO12eFJp0iJP8y3u7CR4NkOAb/4nHS5Kl

Initial Root Token: s.bQN8VBeKBga76dAUVmaGyTjJ

/ &lt;span class="nv"&gt;$ &lt;/span&gt;vault login s.bQN8VBeKBga76dAUVmaGyTjJ
Success! You are now authenticated. The token information displayed below
is already stored &lt;span class="k"&gt;in &lt;/span&gt;the token helper. You &lt;span class="k"&gt;do &lt;/span&gt;NOT need to run &lt;span class="s2"&gt;"vault login"&lt;/span&gt;
again. Future Vault requests will automatically use this token.

Key                  Value
&lt;span class="nt"&gt;---&lt;/span&gt;                  &lt;span class="nt"&gt;-----&lt;/span&gt;
token                s.bQN8VBeKBga76dAUVmaGyTjJ
token_accessor       mkdn3cQnsFcO4hmklMrV8Chq
token_duration       ∞
token_renewable      &lt;span class="nb"&gt;false
&lt;/span&gt;token_policies       &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"root"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
identity_policies    &lt;span class="o"&gt;[]&lt;/span&gt;
policies             &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"root"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
/ &lt;span class="nv"&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="c"&gt;# Enable Kubernetes Authentication&lt;/span&gt;
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; vault &lt;span class="nt"&gt;-it&lt;/span&gt; vault-0 &lt;span class="nt"&gt;--&lt;/span&gt; vault auth &lt;span class="nb"&gt;enable &lt;/span&gt;kubernetes
&lt;span class="c"&gt;# Create Service Account for App Pods&lt;/span&gt;
kubectl create namespace webapps
kubectl create serviceaccount vault-auth &lt;span class="nt"&gt;-n&lt;/span&gt; webapps

&lt;span class="c"&gt;# Configure Kubernetes Auth in Vault&lt;/span&gt;
&lt;span class="c"&gt;# Extract required info:&lt;/span&gt;
&lt;span class="nv"&gt;SERVICE_ACCOUNT_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vault-auth
&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;webapps

&lt;span class="c"&gt;# JWT Token&lt;/span&gt;
&lt;span class="nv"&gt;TOKEN_REVIEW_JWT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get secret &lt;span class="si"&gt;$(&lt;/span&gt;kubectl get serviceaccount &lt;span class="nv"&gt;$SERVICE_ACCOUNT_NAME&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$NAMESPACE&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{.secrets[0].name}"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$NAMESPACE&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{.data.token}"&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;--decode&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Kubernetes API Host&lt;/span&gt;
&lt;span class="nv"&gt;KUBE_HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl config view &lt;span class="nt"&gt;--raw&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.clusters[0].cluster.server}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Kubernetes CA Cert&lt;/span&gt;
&lt;span class="nv"&gt;KUBE_CA_CERT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get secret &lt;span class="si"&gt;$(&lt;/span&gt;kubectl get serviceaccount &lt;span class="nv"&gt;$SERVICE_ACCOUNT_NAME&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$NAMESPACE&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{.secrets[0].name}"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$NAMESPACE&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{.data['ca.crt']}"&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;--decode&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Configure in Vault:&lt;/span&gt;
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; vault &lt;span class="nt"&gt;-it&lt;/span&gt; vault-0 &lt;span class="nt"&gt;--&lt;/span&gt; vault write auth/kubernetes/config &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;token_reviewer_jwt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TOKEN_REVIEW_JWT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;kubernetes_host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$KUBE_HOST&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;kubernetes_ca_cert&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$KUBE_CA_CERT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Purpose of Kubernetes Auth Configuration:&lt;/strong&gt;&lt;br&gt;
This command configures Vault to trust and communicate with the Kubernetes API server so that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vault can validate that service account tokens are legitimate&lt;/li&gt;
&lt;li&gt;Pods can authenticate to Vault using their Kubernetes service account tokens&lt;/li&gt;
&lt;li&gt;Vault can verify which namespace and service account a request is coming from
&lt;strong&gt;Breaking Down Each Parameter:&lt;/strong&gt;
&lt;code&gt;token_reviewer_jwt&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;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get secret vault-token-reviewer &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;'{.data.token}'&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;What it is: A service account token that Vault uses to authenticate with the Kubernetes API&lt;/li&gt;
&lt;li&gt;Why needed: Vault needs to call the Kubernetes TokenReview API to validate incoming service account tokens&lt;/li&gt;
&lt;li&gt;What it does: Acts as Vault's "identity" when talking to Kubernetes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;kubernetes_host&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"https://kubernetes.default.svc:443"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;What it is: The URL of the Kubernetes API server from inside the cluster&lt;/li&gt;
&lt;li&gt;Why needed: Vault needs to know where to send TokenReview requests&lt;/li&gt;
&lt;li&gt;kubernetes.default.svc: This is the internal DNS name for the Kubernetes API server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;kubernetes_ca_cert&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="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get secret vault-token-reviewer &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;'{.data.ca\.crt}'&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;What it is: The Certificate Authority certificate for the Kubernetes cluster&lt;/li&gt;
&lt;li&gt;Why needed: Vault uses this to verify the SSL certificate when connecting to the Kubernetes API&lt;/li&gt;
&lt;li&gt;Security: Prevents man-in-the-middle attacks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Authentication Flow:&lt;/strong&gt;&lt;br&gt;
Here's what happens when a pod tries to authenticate to Vault:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Pod → Vault: "Here's my service account token"
2. Vault → Kubernetes API: "Is this token valid?" (using token_reviewer_jwt)
3. Kubernetes API → Vault: "Yes, it belongs to service account X in namespace Y"
4. Vault → Pod: "Authentication successful, here's your Vault token"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without this configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vault can't verify that service account tokens are real&lt;/li&gt;
&lt;li&gt;Any pod could potentially forge authentication requests&lt;/li&gt;
&lt;li&gt;You lose the security boundary that Kubernetes provides&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vault cryptographically verifies each authentication request&lt;/li&gt;
&lt;li&gt;Only legitimate pods with valid service account tokens can authenticate&lt;/li&gt;
&lt;li&gt;You get fine-grained access control based on Kubernetes RBAC&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This step essentially creates a trust relationship between Vault and your Kubernetes cluster, enabling secure, automated authentication for your workloads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create Vault Policy:&lt;/strong&gt; Create a file myapp-policy.hcl:&lt;br&gt;
A policy in Vault is a set of rules (paths + capabilities) that defines what a token/identity is allowed to do.&lt;br&gt;
Vault is deny-by-default—nothing is allowed unless a policy explicitly grants it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Access to read/write secret data&lt;/span&gt;
&lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="s2"&gt;"secret/data/mysql"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
  &lt;span class="nx"&gt;capabilities&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"create"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"update"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"read"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"delete"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"list"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="s2"&gt;"secret/data/frontend"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;capabilities&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"create"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"update"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"read"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"delete"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"list"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Access to list secrets under the path&lt;/span&gt;
&lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="s2"&gt;"secret/metadata/mysql"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;capabilities&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"list"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="s2"&gt;"secret/metadata/frontend"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;capabilities&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"list"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Apply Vault Policy:&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;kubectl &lt;span class="nb"&gt;cp &lt;/span&gt;myapp-policy.hcl vault/vault-0:/tmp/myapp-policy.hcl
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; vault &lt;span class="nt"&gt;-it&lt;/span&gt; vault-0 &lt;span class="nt"&gt;--&lt;/span&gt; vault policy write myapp-policy /tmp/myapp-policy.hcl
vault policy &lt;span class="nb"&gt;read&lt;/span&gt; &amp;lt;policy name&amp;gt;                   &lt;span class="c"&gt;# show a policy&lt;/span&gt;
vault policy list
&lt;span class="c"&gt;# to use the app policy token &lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;VAULT_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;vault token create &lt;span class="nt"&gt;-field&lt;/span&gt; token &lt;span class="nt"&gt;-policy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;app&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Create Role in Vault to Map Pod to Policy:&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;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; vault &lt;span class="nt"&gt;-it&lt;/span&gt; vault-0 &lt;span class="nt"&gt;--&lt;/span&gt; vault write auth/kubernetes/role/vault-role &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;bound_service_account_names&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vault-auth &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;bound_service_account_namespaces&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"webapps"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;policies&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;myapp-policy &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;24h

kubectl describe clusterrolebindings vault-server-binding
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Store Secrets in Vault:&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;# Enable KV V2 Engine at the specific path (secret)&lt;/span&gt;
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; vault &lt;span class="nt"&gt;-it&lt;/span&gt; vault-0 &lt;span class="nt"&gt;--&lt;/span&gt; vault secrets &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;secret &lt;span class="nt"&gt;-version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2 kv
&lt;span class="c"&gt;# Store Secrets in Vault&lt;/span&gt;
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; vault &lt;span class="nt"&gt;-it&lt;/span&gt; vault-0 &lt;span class="nt"&gt;--&lt;/span&gt; vault kv put secret/mysql &lt;span class="nv"&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bankappdb &lt;span class="nv"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Test@123
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; vault &lt;span class="nt"&gt;-it&lt;/span&gt; vault-0 &lt;span class="nt"&gt;--&lt;/span&gt; vault kv put secret/frontend &lt;span class="nv"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Test@123
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; vault &lt;span class="nt"&gt;-it&lt;/span&gt; vault-0 &lt;span class="nt"&gt;--&lt;/span&gt; vault kv get secret/frontend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What makes KV v2 different from v1:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Versioning: every write creates a new version of the secret.&lt;/li&gt;
&lt;li&gt;Soft delete &amp;amp; undelete: you can delete specific versions and later restore them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example:&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="nv"&gt;$ &lt;/span&gt;vault secrets &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;crds kv-v2
Success! Enabled the kv-v2 secrets engine at: crds/
/ &lt;span class="nv"&gt;$ &lt;/span&gt;vault kv put crds/mysql &lt;span class="nv"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;root
Key              Value
&lt;span class="nt"&gt;---&lt;/span&gt;              &lt;span class="nt"&gt;-----&lt;/span&gt;
created_time     2025-09-04T12:00:14.567764837Z
deletion_time    n/a
destroyed        &lt;span class="nb"&gt;false
&lt;/span&gt;version          1
/ &lt;span class="nv"&gt;$ &lt;/span&gt;vault kv put crds/mysql &lt;span class="nv"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;root &lt;span class="nv"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;12345
Key              Value
&lt;span class="nt"&gt;---&lt;/span&gt;              &lt;span class="nt"&gt;-----&lt;/span&gt;
created_time     2025-09-04T12:00:22.119818763Z
deletion_time    n/a
destroyed        &lt;span class="nb"&gt;false
&lt;/span&gt;version          2
/ &lt;span class="nv"&gt;$ &lt;/span&gt;vault kv get crds/mysql
&lt;span class="o"&gt;======&lt;/span&gt; Metadata &lt;span class="o"&gt;======&lt;/span&gt;
Key              Value
&lt;span class="nt"&gt;---&lt;/span&gt;              &lt;span class="nt"&gt;-----&lt;/span&gt;
created_time     2025-09-04T12:00:22.119818763Z
deletion_time    n/a
destroyed        &lt;span class="nb"&gt;false
&lt;/span&gt;version          2

&lt;span class="o"&gt;======&lt;/span&gt; Data &lt;span class="o"&gt;======&lt;/span&gt;
Key         Value
&lt;span class="nt"&gt;---&lt;/span&gt;         &lt;span class="nt"&gt;-----&lt;/span&gt;
password    12345
username    root
/ &lt;span class="nv"&gt;$ &lt;/span&gt;vault kv get crds/mysql
&lt;span class="o"&gt;======&lt;/span&gt; Metadata &lt;span class="o"&gt;======&lt;/span&gt;
Key              Value
&lt;span class="nt"&gt;---&lt;/span&gt;              &lt;span class="nt"&gt;-----&lt;/span&gt;
created_time     2025-09-04T12:00:22.119818763Z
deletion_time    n/a
destroyed        &lt;span class="nb"&gt;false
&lt;/span&gt;version          2

&lt;span class="o"&gt;======&lt;/span&gt; Data &lt;span class="o"&gt;======&lt;/span&gt;
Key         Value
&lt;span class="nt"&gt;---&lt;/span&gt;         &lt;span class="nt"&gt;-----&lt;/span&gt;
password    12345
username    root
/ &lt;span class="nv"&gt;$ &lt;/span&gt;vault kv metadata get crds/mysql
&lt;span class="o"&gt;==========&lt;/span&gt; Metadata &lt;span class="o"&gt;==========&lt;/span&gt;
Key                     Value
&lt;span class="nt"&gt;---&lt;/span&gt;                     &lt;span class="nt"&gt;-----&lt;/span&gt;
cas_required            &lt;span class="nb"&gt;false
&lt;/span&gt;created_time            2025-09-04T12:00:14.567764837Z
current_version         2
delete_version_after    0s
max_versions            0
oldest_version          0
updated_time            2025-09-04T12:00:22.119818763Z

&lt;span class="o"&gt;======&lt;/span&gt; Version 1 &lt;span class="o"&gt;======&lt;/span&gt;
Key              Value
&lt;span class="nt"&gt;---&lt;/span&gt;              &lt;span class="nt"&gt;-----&lt;/span&gt;
created_time     2025-09-04T12:00:14.567764837Z
deletion_time    n/a
destroyed        &lt;span class="nb"&gt;false&lt;/span&gt;

&lt;span class="o"&gt;======&lt;/span&gt; Version 2 &lt;span class="o"&gt;======&lt;/span&gt;
Key              Value
&lt;span class="nt"&gt;---&lt;/span&gt;              &lt;span class="nt"&gt;-----&lt;/span&gt;
created_time     2025-09-04T12:00:22.119818763Z
deletion_time    n/a
destroyed        &lt;span class="nb"&gt;false&lt;/span&gt;
/ &lt;span class="nv"&gt;$ &lt;/span&gt;vault kv delete crds/mysql
Success! Data deleted &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;it existed&lt;span class="o"&gt;)&lt;/span&gt; at: crds/mysql
/ &lt;span class="nv"&gt;$ &lt;/span&gt;vault kv get crds/mysql
&lt;span class="o"&gt;======&lt;/span&gt; Metadata &lt;span class="o"&gt;======&lt;/span&gt;
Key              Value
&lt;span class="nt"&gt;---&lt;/span&gt;              &lt;span class="nt"&gt;-----&lt;/span&gt;
created_time     2025-09-04T12:00:22.119818763Z
deletion_time    2025-09-04T12:02:04.56772668Z
destroyed        &lt;span class="nb"&gt;false
&lt;/span&gt;version          2

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Create YAML Manifest File (With Below Configurations):&lt;/strong&gt;&lt;br&gt;
Example annotation block for a pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;vault.hashicorp.com/agent-inject&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt; &lt;span class="c1"&gt;# this should be set to a true or false, default to false&lt;/span&gt;
  &lt;span class="na"&gt;vault.hashicorp.com/role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vault-role"&lt;/span&gt; &lt;span class="c1"&gt;# role name&lt;/span&gt;
  &lt;span class="na"&gt;vault.hashicorp.com/agent-inject-secret-MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;secret/mysql"&lt;/span&gt; &lt;span class="c1"&gt;# agent-inject-secret-&amp;lt;the name of the secret&amp;gt; , this will retrieve the secret from Vault&lt;/span&gt;
  &lt;span class="c1"&gt;# agent-inject-template-&amp;lt;the name of the secret&amp;gt;: used for rendering a secret&lt;/span&gt;
  &lt;span class="na"&gt;vault.hashicorp.com/agent-inject-template-MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;{{- with secret "secret/mysql" -}}&lt;/span&gt;
    &lt;span class="s"&gt;export MYSQL_ROOT_PASSWORD="{{ .Data.data.MYSQL_ROOT_PASSWORD }}"&lt;/span&gt;
    &lt;span class="s"&gt;{{- end }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;what to read and how to write.&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;vault.hashicorp.com/agent-inject-secret-MYSQL_ROOT_PASSWORD: "&amp;lt;vault path&amp;gt;"&lt;/code&gt;&lt;br&gt;
Tells the injector which secret to fetch from Vault and that it should write a file named MYSQL_ROOT_PASSWORD under /vault/secrets/ (unless you override the filename/path).&lt;br&gt;
&lt;code&gt;vault.hashicorp.com/agent-inject-template-MYSQL_ROOT_PASSWORD:&lt;/code&gt;&lt;br&gt;
Provides a custom template for what to write into that file. Without this, the injector writes a default rendering (key=value lines). With it, you control the exact content.&lt;br&gt;
&lt;strong&gt;Template:&lt;/strong&gt; It renders a shell line into the injected file, like: &lt;code&gt;export MYSQL_ROOT_PASSWORD="supersecret123"&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="nv"&gt;- with secret "secret/mysql" -&lt;/span&gt;&lt;span class="pi"&gt;}}&lt;/span&gt;
    &lt;span class="s"&gt;export MYSQL_ROOT_PASSWORD="{{ .Data.data.MYSQL_ROOT_PASSWORD }}"&lt;/span&gt;
    &lt;span class="s"&gt;{{- end }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The sidecar Vault Agent will:&lt;br&gt;
    • Auth using the service account token&lt;br&gt;
    • Fetch secrets from Vault&lt;br&gt;
    • Write them to /vault/secrets/... &amp;gt;&amp;gt;&amp;gt; /vault/secrets/MYSQL_ROOT_PASSWORD inside the pod&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UI access&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;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; vault get svc vault
kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; vault port-forward &lt;span class="nt"&gt;--address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.0.0.0 svc/vault 8200:8200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Clean-up steps&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;helm uninstall vault
kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; vault delete pod &lt;span class="nt"&gt;-l&lt;/span&gt; app.kubernetes.io/name&lt;span class="o"&gt;=&lt;/span&gt;vault &lt;span class="nt"&gt;--force&lt;/span&gt; &lt;span class="nt"&gt;--grace-period&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
&lt;/span&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; vault delete pvc &lt;span class="nt"&gt;-l&lt;/span&gt; app.kubernetes.io/name&lt;span class="o"&gt;=&lt;/span&gt;vault &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>devops</category>
      <category>devsecops</category>
      <category>vault</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Socket management and Kernel Data structures</title>
      <dc:creator>Omar Ahmed</dc:creator>
      <pubDate>Mon, 12 May 2025 09:16:52 +0000</pubDate>
      <link>https://forem.com/omar_ahmed/socket-management-and-kernel-data-structures-nog</link>
      <guid>https://forem.com/omar_ahmed/socket-management-and-kernel-data-structures-nog</guid>
      <description>&lt;h3&gt;
  
  
  🧠 Concept of Socket and Listening Mechanism
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;In Linux, a socket is a special type of file &lt;code&gt;file descriptor&lt;/code&gt; used for inter-process communication (IPC) or network communication. It acts as an endpoint for sending or receiving data between processes, either on the same system or across different systems over a network. Sockets provide a standardized way for programs to exchange data, making them a fundamental concept in networking and system programming.&lt;/li&gt;
&lt;li&gt;When a Process listens on an IP/Port it produces a socket.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🧵 Connection Lifecycle and Queues
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A socket transitions to a connection through the TCP three-way handshake: &lt;code&gt;SYN, SYN-ACK, and ACK&lt;/code&gt;. Two key kernel-level queues are introduced:

&lt;ol&gt;
&lt;li&gt;Socket SYN Queue: 

&lt;ul&gt;
&lt;li&gt;What it is: 

&lt;ul&gt;
&lt;li&gt;Also called the &lt;code&gt;incomplete connection queue&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Holds incoming TCP connection requests that are in the initial stage of the TCP three-way handshake.&lt;/li&gt;
&lt;li&gt;Holds half-open connections awaiting handshake completion.&lt;/li&gt;
&lt;li&gt;It stores connections that have received a &lt;code&gt;SYN&lt;/code&gt; packet from a client but haven’t completed the handshake yet.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;How it works &lt;code&gt;Three Way Handshake&lt;/code&gt;:

&lt;ol&gt;
&lt;li&gt;A client sends a &lt;code&gt;SYN&lt;/code&gt; packet to the server to initiate a connection.&lt;/li&gt;
&lt;li&gt;The server responds with a &lt;code&gt;SYN-ACK&lt;/code&gt; packet and places the connection in the SYN Queue. &lt;/li&gt;
&lt;li&gt;The connection remains in this queue until the client sends an &lt;code&gt;ACK&lt;/code&gt; packet to complete the handshake.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;Socket Accept Queue: Stores fully established connections ready for backend processes to accept using the &lt;code&gt;accept()&lt;/code&gt; system call.

&lt;ul&gt;
&lt;li&gt;What it is: 

&lt;ul&gt;
&lt;li&gt;Also called the &lt;code&gt;completed connection queue&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Holds fully established TCP connections that have completed the three-way handshake &lt;code&gt;SYN, SYN-ACK, ACK&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;It stores complete connections and are waiting for the application to accept them via the &lt;code&gt;accept()&lt;/code&gt; system call.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;How it works:

&lt;ol&gt;
&lt;li&gt;Once the client sends the final &lt;code&gt;ACK&lt;/code&gt;, the connection moves from the SYN Queue to the Accept Queue.&lt;/li&gt;
&lt;li&gt;The server’s application (e.g., a web server) calls &lt;code&gt;accept()&lt;/code&gt; to dequeue a connection and begin processing it.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ol&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  ⛵ Connection Queue
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Once the connection is established, it's represented in the kernel by a file descriptor.&lt;/li&gt;
&lt;li&gt;This file descriptor holds the state and metadata of the connection and lives in the accepting process’s memory space (PCB).

&lt;ol&gt;
&lt;li&gt;Receive Queue:

&lt;ul&gt;
&lt;li&gt;The receive queue is part of the kernel memory space associated with an individual connection.&lt;/li&gt;
&lt;li&gt;It temporarily stores incoming data from the client before it's passed to the application (e.g., your server).&lt;/li&gt;
&lt;li&gt;If the backend does not read fast enough, the receive queue fills up, leading the kernel to trigger flow control that tells the client to slow down.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Send Queue: 

&lt;ul&gt;
&lt;li&gt;The send queue stores outgoing data from the server that will be transmitted to the client.&lt;/li&gt;
&lt;li&gt;When the application writes data (e.g., API response), it's placed here first—not sent immediately.&lt;/li&gt;
&lt;li&gt;The kernel may delay actual transmission to optimize performance, bundling small writes into larger packets before flushing them to the network.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>linux</category>
    </item>
    <item>
      <title>Hi</title>
      <dc:creator>Omar Ahmed</dc:creator>
      <pubDate>Mon, 12 May 2025 09:11:01 +0000</pubDate>
      <link>https://forem.com/omar_ahmed/hi-1p4j</link>
      <guid>https://forem.com/omar_ahmed/hi-1p4j</guid>
      <description>&lt;p&gt;First Hello from &lt;strong&gt;dev.to&lt;/strong&gt;, I'm a DevOps Engineer!&lt;/p&gt;

</description>
      <category>devops</category>
      <category>career</category>
      <category>welcome</category>
    </item>
  </channel>
</rss>
