<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: kamlesh merugu</title>
    <description>The latest articles on DEV Community by kamlesh merugu (@kamlesh_merugu).</description>
    <link>https://dev.to/kamlesh_merugu</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%2F3179646%2F3faeb929-1dc9-48bb-af7a-fd8fe863b2f8.jpg</url>
      <title>DEV Community: kamlesh merugu</title>
      <link>https://dev.to/kamlesh_merugu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kamlesh_merugu"/>
    <language>en</language>
    <item>
      <title>Part 4: Automated Backups &amp; Restore Procedures</title>
      <dc:creator>kamlesh merugu</dc:creator>
      <pubDate>Wed, 14 Jan 2026 23:06:38 +0000</pubDate>
      <link>https://dev.to/kamlesh_merugu/part-4-automated-backups-restore-procedures-4dp6</link>
      <guid>https://dev.to/kamlesh_merugu/part-4-automated-backups-restore-procedures-4dp6</guid>
      <description>&lt;p&gt;We will implement a &lt;strong&gt;robust, atomic backup strategy&lt;/strong&gt; that protects your n8n workflows, credentials, Redis queues, and custom nodes.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Target:&lt;/strong&gt; PostgreSQL (n8n data), Redis (Queue state), N8N (Custom nodes &amp;amp; config)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage:&lt;/strong&gt; Central Backup PVC (PG/Redis) + Direct Upload (N8N)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud:&lt;/strong&gt; Mega.nz (Off-site with 15-day retention)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encryption:&lt;/strong&gt; Optional GPG encryption&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📋 Overview
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Architecture:&lt;/strong&gt; Central Jobs (DB) + Direct Job (N8N).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Atomic Staging:&lt;/strong&gt; Jobs write to a &lt;code&gt;staging&lt;/code&gt; folder first, then move to &lt;code&gt;ready&lt;/code&gt; only when complete.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Destination:&lt;/strong&gt; All backups go to &lt;code&gt;k8s-backups&lt;/code&gt; on Mega (N8N goes into &lt;code&gt;k8s-backups/n8n&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Encryption:&lt;/strong&gt; Backups are encrypted before syncing to the cloud.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🧩 Step 1: Prepare Secrets
&lt;/h2&gt;

&lt;p&gt;We need secrets in &lt;strong&gt;BOTH&lt;/strong&gt; &lt;code&gt;backup&lt;/code&gt; and &lt;code&gt;prod&lt;/code&gt; namespaces.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Configure Rclone
&lt;/h3&gt;

&lt;p&gt;On your local machine (or server), generate the config.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rclone config
&lt;span class="c"&gt;# Name: mega&lt;/span&gt;
&lt;span class="c"&gt;# Type: mega&lt;/span&gt;
&lt;span class="c"&gt;# Account: Enter your Mega email/pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Create Rclone Secrets
&lt;/h3&gt;

&lt;p&gt;Create the secret in both namespaces.&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;# In Prod (for N8N Backup)&lt;/span&gt;
kubectl create secret generic rclone-secret &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;rclone.conf&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/.config/rclone/rclone.conf &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; prod

&lt;span class="c"&gt;# In Backup (for Sync Job)&lt;/span&gt;
kubectl create secret generic rclone-secret &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;rclone.conf&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/.config/rclone/rclone.conf &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; backup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Create Encryption Secret (Backup NS)
&lt;/h3&gt;

&lt;p&gt;Generates a key to encrypt database dumps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openssl rand &lt;span class="nt"&gt;-base64&lt;/span&gt; 32 &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; backup-passphrase.txt
kubectl create secret generic backup-encryption-secret &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;passphrase&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;backup-passphrase.txt &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; backup
&lt;span class="c"&gt;# **Save this passphrase in a password manager!**&lt;/span&gt;
&lt;span class="nb"&gt;rm &lt;/span&gt;backup-passphrase.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Copy Database Password
&lt;/h3&gt;

&lt;p&gt;The database secret is in &lt;code&gt;prod&lt;/code&gt;, but the backup job runs in &lt;code&gt;backup&lt;/code&gt;. We copy it while stripping internal IDs to prevent conflicts.&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 postgres-secret &lt;span class="nt"&gt;-n&lt;/span&gt; prod &lt;span class="nt"&gt;-o&lt;/span&gt; yaml | &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/namespace: prod/namespace: backup/'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'/uid:/d'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'/resourceVersion:/d'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'/creationTimestamp:/d'&lt;/span&gt; | &lt;span class="se"&gt;\&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧩 Step 2: Infrastructure
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;backups/01-infrastructure.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Namespace&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backup&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PersistentVolumeClaim&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;backup-pvc&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;backup&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;accessModes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ReadWriteOnce&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;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30Gi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Apply:&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="nt"&gt;-f&lt;/span&gt; backups/01-infrastructure.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧩 Step 3: Job 1 — PostgreSQL Backup
&lt;/h2&gt;

&lt;p&gt;Dumps to &lt;code&gt;staging&lt;/code&gt;, encrypts, moves to &lt;code&gt;ready&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;backups/02-postgres-backup.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;batch/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;CronJob&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;postgres-backup&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;backup&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;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt; 
  &lt;span class="na"&gt;successfulJobsHistoryLimit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;jobTemplate&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;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;backup-client&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;postgres:17-alpine&lt;/span&gt;
            &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/bin/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;set -e&lt;/span&gt;
              &lt;span class="s"&gt;TIMESTAMP=$(date +%Y%m%d_%H%M%S)&lt;/span&gt;
              &lt;span class="s"&gt;STAGING_DIR="/backup/staging/postgres"&lt;/span&gt;
              &lt;span class="s"&gt;READY_DIR="/backup/ready/postgres"&lt;/span&gt;
              &lt;span class="s"&gt;mkdir -p $STAGING_DIR $READY_DIR&lt;/span&gt;
              &lt;span class="s"&gt;FILENAME="n8n_db_${TIMESTAMP}.dump"&lt;/span&gt;
              &lt;span class="s"&gt;STAGING_FILE="${STAGING_DIR}/${FILENAME}"&lt;/span&gt;

              &lt;span class="s"&gt;PGPASSWORD=$POSTGRES_PASSWORD pg_dump \&lt;/span&gt;
                &lt;span class="s"&gt;-h postgres.prod.svc.cluster.local -U n8n -d n8n \&lt;/span&gt;
                &lt;span class="s"&gt;-F c -b -f $STAGING_FILE&lt;/span&gt;

              &lt;span class="s"&gt;if [ ! -s $STAGING_FILE ]; then exit 1; fi&lt;/span&gt;

              &lt;span class="s"&gt;# Encrypt if key exists&lt;/span&gt;
              &lt;span class="s"&gt;if [ -f /etc/backup/passphrase ]; then&lt;/span&gt;
                &lt;span class="s"&gt;apk add --no-cache gnupg &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;/span&gt;
                &lt;span class="s"&gt;cat $STAGING_FILE | gpg --batch --yes \&lt;/span&gt;
                  &lt;span class="s"&gt;--passphrase-file /etc/backup/passphrase \&lt;/span&gt;
                  &lt;span class="s"&gt;--symmetric --cipher-algo AES256 \&lt;/span&gt;
                  &lt;span class="s"&gt;--output ${STAGING_FILE}.gpg&lt;/span&gt;
                &lt;span class="s"&gt;mv ${STAGING_FILE}.gpg ${READY_DIR}.gpg&lt;/span&gt;
                &lt;span class="s"&gt;rm $STAGING_FILE&lt;/span&gt;
              &lt;span class="s"&gt;else&lt;/span&gt;
                &lt;span class="s"&gt;mv $STAGING_FILE $READY_DIR&lt;/span&gt;
              &lt;span class="s"&gt;fi&lt;/span&gt;

              &lt;span class="s"&gt;find $READY_DIR -name "*.dump*" -mtime +7 -delete&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;POSTGRES_PASSWORD&lt;/span&gt;
              &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;secretKeyRef&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;postgres-secret&lt;/span&gt;
                  &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;password&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;backup-storage&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;/backup&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;encryption-key&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;/etc/backup&lt;/span&gt;
              &lt;span class="na"&gt;readOnly&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;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;backup-storage&lt;/span&gt;
            &lt;span class="na"&gt;persistentVolumeClaim&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;claimName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backup-pvc&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;encryption-key&lt;/span&gt;
            &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backup-encryption-secret&lt;/span&gt;
              &lt;span class="na"&gt;optional&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;restartPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OnFailure&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Apply:&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="nt"&gt;-f&lt;/span&gt; backups/02-postgres-backup.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧩 Step 4: Job 2 — Redis Backup
&lt;/h2&gt;

&lt;p&gt;Non-blocking backup (&lt;code&gt;BGSAVE&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;backups/03-redis-backup.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;batch/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;CronJob&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;redis-backup&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;backup&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;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt; 
  &lt;span class="na"&gt;successfulJobsHistoryLimit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;jobTemplate&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;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;redis-client&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;redis:8.0-alpine&lt;/span&gt;
            &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/bin/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;set -e&lt;/span&gt;
              &lt;span class="s"&gt;TIMESTAMP=$(date +%Y%m%d_%H%M%S)&lt;/span&gt;
              &lt;span class="s"&gt;STAGING_DIR="/backup/staging/redis"&lt;/span&gt;
              &lt;span class="s"&gt;READY_DIR="/backup/ready/redis"&lt;/span&gt;
              &lt;span class="s"&gt;mkdir -p $STAGING_DIR $READY_DIR&lt;/span&gt;

              &lt;span class="s"&gt;redis-cli -h redis.prod.svc.cluster.local BGSAVE&lt;/span&gt;
              &lt;span class="s"&gt;LAST_SAVE=$(redis-cli -h redis.prod.svc.cluster.local LASTSAVE)&lt;/span&gt;
              &lt;span class="s"&gt;while [ "$(redis-cli -h redis.prod.svc.cluster.local LASTSAVE)" -le "$LAST_SAVE" ]; do sleep 2; done&lt;/span&gt;

              &lt;span class="s"&gt;redis-cli -h redis.prod.svc.cluster.local --rdb - &amp;gt; ${STAGING_DIR}/redis_${TIMESTAMP}.rdb&lt;/span&gt;
              &lt;span class="s"&gt;if [ -s ${STAGING_DIR}/redis_${TIMESTAMP}.rdb ]; then&lt;/span&gt;
                 &lt;span class="s"&gt;mv ${STAGING_DIR}/redis_${TIMESTAMP}.rdb ${READY_DIR}/&lt;/span&gt;
                 &lt;span class="s"&gt;find $READY_DIR -name "*.rdb" -mtime +7 -delete&lt;/span&gt;
              &lt;span class="s"&gt;fi&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;backup-storage&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;/backup&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;backup-storage&lt;/span&gt;
            &lt;span class="na"&gt;persistentVolumeClaim&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;claimName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backup-pvc&lt;/span&gt;
          &lt;span class="na"&gt;restartPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OnFailure&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Apply:&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="nt"&gt;-f&lt;/span&gt; backups/03-redis-backup.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧩 Step 5: Job 3 — N8N Backup (Direct Upload)
&lt;/h2&gt;

&lt;p&gt;Runs in &lt;code&gt;prod&lt;/code&gt;, uploads to &lt;code&gt;mega:k8s-backups/n8n&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;backups/04-n8n-backup.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;batch/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;CronJob&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;n8n-backup&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;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;15&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt; 
  &lt;span class="na"&gt;successfulJobsHistoryLimit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;jobTemplate&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;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;n8n-client&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;rclone/rclone:latest&lt;/span&gt;
            &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/bin/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;set -e&lt;/span&gt;
              &lt;span class="s"&gt;TIMESTAMP=$(date +%Y%m%d_%H%M%S)&lt;/span&gt;
              &lt;span class="s"&gt;# Copy config to temp to prevent read-only errors&lt;/span&gt;
              &lt;span class="s"&gt;cat /config/rclone.conf &amp;gt; /tmp/rclone.conf&lt;/span&gt;

              &lt;span class="s"&gt;STAGING_DIR="/tmp/staging/n8n"&lt;/span&gt;
              &lt;span class="s"&gt;READY_DIR="/tmp/ready/n8n"&lt;/span&gt;
              &lt;span class="s"&gt;mkdir -p $STAGING_DIR $READY_DIR&lt;/span&gt;
              &lt;span class="s"&gt;FILENAME="n8n_data_${TIMESTAMP}.tar.gz"&lt;/span&gt;

              &lt;span class="s"&gt;tar -czf ${STAGING_DIR}/${FILENAME} -C /n8n_data .&lt;/span&gt;

              &lt;span class="s"&gt;if [ -s ${STAGING_DIR}/${FILENAME} ]; then&lt;/span&gt;
                &lt;span class="s"&gt;mv ${STAGING_DIR}/${FILENAME} $READY_DIR&lt;/span&gt;
                &lt;span class="s"&gt;rclone copy $READY_DIR mega:k8s-backups/n8n \&lt;/span&gt;
                  &lt;span class="s"&gt;--config=/tmp/rclone.conf&lt;/span&gt;
                &lt;span class="s"&gt;rclone delete mega:k8s-backups/n8n --min-age 15d \&lt;/span&gt;
                  &lt;span class="s"&gt;--config=/tmp/rclone.conf&lt;/span&gt;
              &lt;span class="s"&gt;fi&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;n8n-pvc&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;/n8n_data&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;rclone-config&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;/config&lt;/span&gt;
              &lt;span class="na"&gt;readOnly&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;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;n8n-pvc&lt;/span&gt;
            &lt;span class="na"&gt;persistentVolumeClaim&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;claimName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;n8n-pvc&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;rclone-config&lt;/span&gt;
            &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rclone-secret&lt;/span&gt;
          &lt;span class="na"&gt;restartPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OnFailure&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Apply:&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="nt"&gt;-f&lt;/span&gt; backups/04-n8n-backup.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧩 Step 6: Job 4 — Mega.nz Sync (Central)
&lt;/h2&gt;

&lt;p&gt;Uploads &lt;code&gt;postgres&lt;/code&gt; and &lt;code&gt;redis&lt;/code&gt; from local PVC to &lt;code&gt;mega:k8s-backups&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;backups/05-mega-sync.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;batch/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;CronJob&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;mega-sync&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;backup&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;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;30&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt; 
  &lt;span class="na"&gt;successfulJobsHistoryLimit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;jobTemplate&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;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;rclone-sync&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;rclone/rclone:latest&lt;/span&gt;
            &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/bin/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;# Copy config to temp to prevent read-only errors&lt;/span&gt;
              &lt;span class="s"&gt;cat /secret/rclone.conf &amp;gt; /tmp/rclone.conf&lt;/span&gt;

              &lt;span class="s"&gt;rclone sync /backup/ready mega:k8s-backups \&lt;/span&gt;
                &lt;span class="s"&gt;--config=/tmp/rclone.conf \&lt;/span&gt;
                &lt;span class="s"&gt;--transfers 4&lt;/span&gt;

              &lt;span class="s"&gt;rclone delete mega:k8s-backups --min-age 15d \&lt;/span&gt;
                &lt;span class="s"&gt;--config=/tmp/rclone.conf&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;backup-storage&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;/backup&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;rclone-secret&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;/secret&lt;/span&gt;
              &lt;span class="na"&gt;readOnly&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;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;backup-storage&lt;/span&gt;
            &lt;span class="na"&gt;persistentVolumeClaim&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;claimName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backup-pvc&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;rclone-secret&lt;/span&gt;
            &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rclone-secret&lt;/span&gt;
          &lt;span class="na"&gt;restartPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OnFailure&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Apply:&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="nt"&gt;-f&lt;/span&gt; backups/05-mega-sync.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧩 Step 7: Kubernetes Dashboard
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Enable &amp;amp; Expose Service
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;microk8s &lt;span class="nb"&gt;enable &lt;/span&gt;dashboard
microk8s kubectl expose deployment kubernetes-dashboard &lt;span class="nt"&gt;-n&lt;/span&gt; kube-system &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;kubernetes-dashboard &lt;span class="nt"&gt;--port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;443 &lt;span class="nt"&gt;--target-port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;8443
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Ingress (Valid SSL)
&lt;/h3&gt;

&lt;p&gt;Access at &lt;code&gt;https://kube.kamleshmerugu.me&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;k8s-stack/ingress/dashboard-ingress.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Ingress&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;dashboard-ingress&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;kube-system&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;cert-manager.io/cluster-issuer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;letsencrypt-prod"&lt;/span&gt;
    &lt;span class="na"&gt;nginx.ingress.kubernetes.io/backend-protocol&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"&lt;/span&gt;
    &lt;span class="na"&gt;nginx.ingress.kubernetes.io/proxy-ssl-verify&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;false"&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;ingressClassName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;public&lt;/span&gt;
  &lt;span class="na"&gt;tls&lt;/span&gt;&lt;span class="pi"&gt;:&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="nv"&gt;kube.kamleshmerugu.me&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dashboard-tls-secret&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;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kube.kamleshmerugu.me&lt;/span&gt;
      &lt;span class="na"&gt;http&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="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
            &lt;span class="na"&gt;pathType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prefix&lt;/span&gt;
            &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;service&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;kubernetes-dashboard&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;443&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Apply:&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="nt"&gt;-f&lt;/span&gt; k8s-stack/ingress/dashboard-ingress.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Get Token
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;microk8s kubectl describe secret &lt;span class="nt"&gt;-n&lt;/span&gt; kube-system microk8s-dashboard-token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧩 Step 8: Verification
&lt;/h2&gt;

&lt;p&gt;Test the jobs immediately.&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;# 1. Run backups&lt;/span&gt;
kubectl create job &lt;span class="nt"&gt;--from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cronjob/postgres-backup manual-pg &lt;span class="nt"&gt;-n&lt;/span&gt; backup
kubectl create job &lt;span class="nt"&gt;--from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cronjob/redis-backup manual-redis &lt;span class="nt"&gt;-n&lt;/span&gt; backup
kubectl create job &lt;span class="nt"&gt;--from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cronjob/n8n-backup manual-n8n &lt;span class="nt"&gt;-n&lt;/span&gt; prod
kubectl create job &lt;span class="nt"&gt;--from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cronjob/mega-sync manual-sync &lt;span class="nt"&gt;-n&lt;/span&gt; backup

&lt;span class="c"&gt;# 2. Check Mega.nz&lt;/span&gt;
&lt;span class="c"&gt;# You should see folder: k8s-backups&lt;/span&gt;
&lt;span class="c"&gt;# Inside: postgres/, redis/, n8n/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧩 Step 9: Restore Procedures
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Restore PostgreSQL
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Download&lt;/span&gt;
kubectl run pg-download &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;rclone/rclone:latest &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; backup &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Never &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--overrides&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{"spec":{"containers":[{"name":"d","image":"rclone/rclone:latest","command":["sh","-c","sleep 3600"],"volumeMounts":[{"name":"v","mountPath":"/b"},{"name":"c","mountPath":"/s","readOnly":true}]}],"volumes":[{"name":"v","persistentVolumeClaim":{"claimName":"backup-pvc"}},{"name":"c","secret":{"secretName":"rclone-secret"}}]}}'&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; sh

&lt;span class="c"&gt;# Inside shell:&lt;/span&gt;
rclone copy mega:k8s-backups /b/ready &lt;span class="nt"&gt;--config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/s/rclone.conf
&lt;span class="nb"&gt;exit&lt;/span&gt;

&lt;span class="c"&gt;# 2. Restore&lt;/span&gt;
kubectl run pg-restore &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgres:17-alpine &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; backup &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Never &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--overrides&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{"spec":{"containers":[{"name":"r","image":"postgres:17-alpine","command":["sh"],"env":[{"name":"PGPASSWORD","valueFrom":{"secretKeyRef":{"name":"postgres-secret","namespace":"backup","key":"password"}}}],"volumeMounts":[{"name":"v","mountPath":"/d"}]}],"volumes":[{"name":"v","persistentVolumeClaim":{"claimName":"backup-pvc"}}]}}'&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; sh

&lt;span class="c"&gt;# Inside shell:&lt;/span&gt;
gpg &lt;span class="nt"&gt;--batch&lt;/span&gt; &lt;span class="nt"&gt;--passphrase&lt;/span&gt; &lt;span class="s2"&gt;"YOUR_PASS"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--decrypt&lt;/span&gt; /d/ready/postgres/n8n_db_DATE.dump.gpg &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; /d/ready/restore.dump
psql &lt;span class="nt"&gt;-h&lt;/span&gt; postgres.prod.svc.cluster.local &lt;span class="nt"&gt;-U&lt;/span&gt; n8n &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"DROP DATABASE n8n;"&lt;/span&gt;
psql &lt;span class="nt"&gt;-h&lt;/span&gt; postgres.prod.svc.cluster.local &lt;span class="nt"&gt;-U&lt;/span&gt; n8n &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"CREATE DATABASE n8n;"&lt;/span&gt;
pg_restore &lt;span class="nt"&gt;-h&lt;/span&gt; postgres.prod.svc.cluster.local &lt;span class="nt"&gt;-U&lt;/span&gt; n8n &lt;span class="nt"&gt;-d&lt;/span&gt; n8n /d/ready/restore.dump
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Restore Redis
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Pull to local from backup PVC&lt;/span&gt;
kubectl run redis-helper &lt;span class="nt"&gt;-n&lt;/span&gt; backup &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;busybox &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &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;cat&lt;/span&gt; /backup/ready/redis/redis_DATE.rdb &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/redis.rdb

&lt;span class="c"&gt;# 2. Push to Redis Pod&lt;/span&gt;
&lt;span class="nv"&gt;REDIS_POD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get pod &lt;span class="nt"&gt;-n&lt;/span&gt; prod &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;redis &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.items[0].metadata.name}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
kubectl &lt;span class="nb"&gt;cp&lt;/span&gt; /tmp/redis.rdb &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;REDIS_POD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;:/data/dump.rdb &lt;span class="nt"&gt;-n&lt;/span&gt; prod

&lt;span class="c"&gt;# 3. Restart&lt;/span&gt;
kubectl delete pod &lt;span class="nt"&gt;-n&lt;/span&gt; prod &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Restore N8N
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl run n8n-restore &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;rclone/rclone:latest &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; prod &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Never &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--overrides&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{"spec":{"containers":[{"name":"r","image":"rclone/rclone:latest","command":["sh","-c","sleep 3600"],"volumeMounts":[{"name":"n","mountPath":"/n8n_data"},{"name":"c","mountPath":"/s","readOnly":true}]}],"volumes":[{"name":"n","persistentVolumeClaim":{"claimName":"n8n-pvc"}},{"name":"c","secret":{"secretName":"rclone-secret"}}]}}'&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; sh

&lt;span class="c"&gt;# Inside shell:&lt;/span&gt;
rclone copy mega:k8s-backups/n8n /tmp/r &lt;span class="nt"&gt;--config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/s/rclone.conf
&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xzf&lt;/span&gt; /tmp/r/n8n_data_DATE.tar.gz &lt;span class="nt"&gt;-C&lt;/span&gt; /tmp/r
&lt;span class="nb"&gt;mv&lt;/span&gt; /n8n_data/.n8n /n8n_data/.n8n_old
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; /tmp/r/.n8n /n8n_data/
&lt;span class="nb"&gt;exit

&lt;/span&gt;kubectl delete pod &lt;span class="nt"&gt;-n&lt;/span&gt; prod &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;n8n
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🎉 Checklist
&lt;/h2&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;Strategy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Postgres&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Staging -&amp;gt; Encrypt -&amp;gt; Ready -&amp;gt; Sync&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Redis&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;BGSAVE -&amp;gt; Ready -&amp;gt; Sync&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;N8N&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Direct Upload to &lt;code&gt;k8s-backups/n8n&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Retention&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;7 Days Local, 15 Days Cloud&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dashboard&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Accessible at &lt;code&gt;https://kube.kamleshmerugu.me&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;You now have a bulletproof, production-ready backup system that is Simple, Modular, and RBAC-Free!&lt;/strong&gt; 🛡️&lt;/p&gt;

</description>
      <category>backup</category>
      <category>kubernetes</category>
      <category>container</category>
    </item>
    <item>
      <title>🚀 Part 3 — Deploy Production Stack on MicroK8s</title>
      <dc:creator>kamlesh merugu</dc:creator>
      <pubDate>Tue, 13 Jan 2026 14:23:58 +0000</pubDate>
      <link>https://dev.to/kamlesh_merugu/part-3-production-namespace-app-deployment-backups-restore-step-by-step-guide-2ff5</link>
      <guid>https://dev.to/kamlesh_merugu/part-3-production-namespace-app-deployment-backups-restore-step-by-step-guide-2ff5</guid>
      <description>&lt;p&gt;In this part, we move from a basic MicroK8s cluster to a &lt;strong&gt;real production stack&lt;/strong&gt; with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PostgreSQL database&lt;/li&gt;
&lt;li&gt;Redis cache&lt;/li&gt;
&lt;li&gt;n8n workflow automation&lt;/li&gt;
&lt;li&gt;HTTPS using Let’s Encrypt&lt;/li&gt;
&lt;li&gt;Kubernetes Dashboard on its own domain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All deployed using &lt;strong&gt;proper namespaces and ingress rules&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ Prerequisites
&lt;/h2&gt;

&lt;p&gt;From previous parts, you must already have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ MicroK8s installed and running&lt;/li&gt;
&lt;li&gt;✅ &lt;code&gt;kubectl&lt;/code&gt; alias working&lt;/li&gt;
&lt;li&gt;✅ DNS records created:&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;Domain&lt;/th&gt;
&lt;th&gt;Points To&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;n8n.domain.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Your server public IP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;kube.domain.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Your server public IP&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🔌 Step 1 — Enable Required MicroK8s Add-ons
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;microk8s &lt;span class="nb"&gt;enable &lt;/span&gt;dns storage ingress cert-manager dashboard metrics-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait for everything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-A&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All pods should be &lt;strong&gt;Running&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧱 Step 2 — Project Structure
&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;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; k8s-project/&lt;span class="o"&gt;{&lt;/span&gt;03-postgres,04-redis,05-n8n,07-ingress&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;k8s-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧩 Step 3 — Create Production Namespace
&lt;/h2&gt;



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

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔐 Step 4 — Create Secrets
&lt;/h2&gt;

&lt;h3&gt;
  
  
  PostgreSQL Password
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create secret generic postgres-secret &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="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;openssl rand &lt;span class="nt"&gt;-base64&lt;/span&gt; 24&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  n8n Encryption Key
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create secret generic n8n-secret &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;encryption-key&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;openssl rand &lt;span class="nt"&gt;-base64&lt;/span&gt; 32&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🐘 Step 5 — Deploy PostgreSQL
&lt;/h2&gt;

&lt;p&gt;📁 &lt;code&gt;03-postgres/postgres.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PersistentVolumeClaim&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;postgres-pvc&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;accessModes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ReadWriteOnce&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10Gi&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&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;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;postgres&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;postgres&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;postgres&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;postgres:16&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;POSTGRES_DB&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;n8n&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;POSTGRES_USER&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;n8n&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;POSTGRES_PASSWORD&lt;/span&gt;
              &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;secretKeyRef&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;postgres-secret&lt;/span&gt;
                  &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;password&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5432&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;data&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;/var/lib/postgresql/data&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;data&lt;/span&gt;
          &lt;span class="na"&gt;persistentVolumeClaim&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;claimName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres-pvc&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&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;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5432&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply:&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; 03-postgres/postgres.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔴 Step 6 — Deploy Redis
&lt;/h2&gt;

&lt;p&gt;📁 &lt;code&gt;04-redis/redis.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;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;redis&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;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;redis&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;redis&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;redis&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;redis:7-alpine&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6379&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis&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;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6379&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply:&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; 04-redis/redis.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔁 Step 7 — Deploy n8n
&lt;/h2&gt;

&lt;p&gt;📁 &lt;code&gt;05-n8n/n8n.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PersistentVolumeClaim&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;n8n-pvc&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;accessModes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ReadWriteOnce&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5Gi&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;n8n&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;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;n8n&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;n8n&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;n8n&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;n8nio/n8n:latest&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;DB_TYPE&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgresdb&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;DB_POSTGRESDB_HOST&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&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;DB_POSTGRESDB_DATABASE&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;n8n&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;DB_POSTGRESDB_USER&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;n8n&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;DB_POSTGRESDB_PASSWORD&lt;/span&gt;
              &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;secretKeyRef&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;postgres-secret&lt;/span&gt;
                  &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;password&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;N8N_ENCRYPTION_KEY&lt;/span&gt;
              &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;secretKeyRef&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;n8n-secret&lt;/span&gt;
                  &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;encryption-key&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;N8N_HOST&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;n8n.domain.com&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;N8N_PROTOCOL&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https&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;WEBHOOK_URL&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://n8n.domain.com/&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5678&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;data&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;/home/node/.n8n&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;data&lt;/span&gt;
          &lt;span class="na"&gt;persistentVolumeClaim&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;claimName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;n8n-pvc&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;n8n&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;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;n8n&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5678&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5678&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply:&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; 05-n8n/n8n.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔐 Step 8 — Create Let’s Encrypt Issuer
&lt;/h2&gt;

&lt;p&gt;📁 &lt;code&gt;07-ingress/issuer.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cert-manager.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClusterIssuer&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;letsencrypt-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;acme&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;your-email@domain.com&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://acme-v02.api.letsencrypt.org/directory&lt;/span&gt;
    &lt;span class="na"&gt;privateKeySecretRef&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;letsencrypt-prod&lt;/span&gt;
    &lt;span class="na"&gt;solvers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http01&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;ingress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;public&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply:&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; 07-ingress/issuer.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🌍 Step 9 — Ingress for n8n
&lt;/h2&gt;

&lt;p&gt;📁 &lt;code&gt;07-ingress/n8n-ingress.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Ingress&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;n8n-ingress&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;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;cert-manager.io/cluster-issuer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;letsencrypt-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;ingressClassName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;public&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;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;n8n.domain.com&lt;/span&gt;
      &lt;span class="na"&gt;http&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="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
            &lt;span class="na"&gt;pathType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prefix&lt;/span&gt;
            &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;service&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;n8n&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;5678&lt;/span&gt;
  &lt;span class="na"&gt;tls&lt;/span&gt;&lt;span class="pi"&gt;:&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="s"&gt;n8n.domain.com&lt;/span&gt;
      &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;n8n-tls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply:&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; 07-ingress/n8n-ingress.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📊 Step 10 — Ingress for Kubernetes Dashboard
&lt;/h2&gt;

&lt;p&gt;📁 &lt;code&gt;07-ingress/dashboard-ingress.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Ingress&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;dashboard-ingress&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;kube-system&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;cert-manager.io/cluster-issuer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;letsencrypt-prod&lt;/span&gt;
    &lt;span class="na"&gt;nginx.ingress.kubernetes.io/backend-protocol&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"&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;ingressClassName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;public&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;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kube.domain.com&lt;/span&gt;
      &lt;span class="na"&gt;http&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="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
            &lt;span class="na"&gt;pathType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prefix&lt;/span&gt;
            &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;service&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;kubernetes-dashboard&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;443&lt;/span&gt;
  &lt;span class="na"&gt;tls&lt;/span&gt;&lt;span class="pi"&gt;:&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="s"&gt;kube.domain.com&lt;/span&gt;
      &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kube-dashboard-tls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply:&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; 07-ingress/dashboard-ingress.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ✅ Step 11 — Verify Everything
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pods
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-A&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Certificates
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get certificate &lt;span class="nt"&gt;-A&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Services
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get svc &lt;span class="nt"&gt;-n&lt;/span&gt; prod
kubectl get svc &lt;span class="nt"&gt;-n&lt;/span&gt; kube-system | &lt;span class="nb"&gt;grep &lt;/span&gt;dashboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🎉 Result
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;URL&lt;/th&gt;
&lt;th&gt;What You Get&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://n8n.domain.com" rel="noopener noreferrer"&gt;https://n8n.domain.com&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;n8n UI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://kube.domain.com" rel="noopener noreferrer"&gt;https://kube.domain.com&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Kubernetes Dashboard&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🔜 Coming Next
&lt;/h2&gt;

&lt;h4&gt;
  
  
  👉 Part 4 — Centralized Secrets with Doppler + External Secrets Operator
&lt;/h4&gt;

&lt;h4&gt;
  
  
  👉 Part 5 — Observability (Prometheus, Grafana, Loki)
&lt;/h4&gt;

&lt;h4&gt;
  
  
  👉 Part 6 — Automated Backups &amp;amp; Disaster Recovery (Velero + DB dumps)
&lt;/h4&gt;

</description>
      <category>containers</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>🧱 Part 1 — Production-Ready MicroK8s Installation on Debian 12 (with snapd)</title>
      <dc:creator>kamlesh merugu</dc:creator>
      <pubDate>Tue, 13 Jan 2026 12:39:52 +0000</pubDate>
      <link>https://dev.to/kamlesh_merugu/installing-microk8s-on-ubuntu-2404-a-lightweight-kubernetes-setup-guide-d1n</link>
      <guid>https://dev.to/kamlesh_merugu/installing-microk8s-on-ubuntu-2404-a-lightweight-kubernetes-setup-guide-d1n</guid>
      <description>&lt;p&gt;This guide sets up a &lt;strong&gt;secure, production-grade MicroK8s Kubernetes cluster&lt;/strong&gt; on Debian 12, ready for deploying:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;n8n workflows&lt;/li&gt;
&lt;li&gt;Postgres &amp;amp; Redis&lt;/li&gt;
&lt;li&gt;Observabilit y stack (Prometheus, Grafana, Loki)&lt;/li&gt;
&lt;li&gt;Centralized secrets (Doppler, in Part 2)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Follow every step carefully—skipping steps can break the cluster.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ✅ Supported Systems
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Debian 12 (Bookworm) LTS&lt;/li&gt;
&lt;li&gt;VPS, VM, or bare-metal&lt;/li&gt;
&lt;li&gt;Minimum: 2 vCPU, 4 GB RAM&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔧 Step 1 — Update &amp;amp; Prepare the Server
&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;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt full-upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reconnect after reboot. Install essential tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  curl wget git vim htop neofetch &lt;span class="se"&gt;\&lt;/span&gt;
  apt-transport-https ca-certificates gnupg lsb-release
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;✅ System updated and ready for Kubernetes.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  👤 Step 2 — Create a Deployment User (Optional but Recommended)
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Kubernetes should &lt;strong&gt;never run as root&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;adduser deploy
&lt;span class="nb"&gt;sudo &lt;/span&gt;usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;deploy
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"deploy ALL=(ALL) NOPASSWD: ALL"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/sudoers.d/deploy
&lt;span class="nb"&gt;sudo chmod &lt;/span&gt;440 /etc/sudoers.d/deploy
su - deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔁 Step 3 — Disable Swap
&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;sudo &lt;/span&gt;swapoff &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;span class="nb"&gt;sudo sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'/\sswap\s/s/^/#/'&lt;/span&gt; /etc/fstab
free &lt;span class="nt"&gt;-h&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Swap should show &lt;code&gt;0B&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🌐 Step 4 — Kernel Modules &amp;amp; Networking
&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;sudo tee&lt;/span&gt; /etc/modules-load.d/k8s.conf &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
br_netfilter
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;modprobe br_netfilter

&lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/sysctl.d/99-k8s.conf &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;sysctl &lt;span class="nt"&gt;--system&lt;/span&gt;
sysctl net.ipv4.ip_forward
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📦 Step 5 — Install snapd
&lt;/h2&gt;

&lt;p&gt;MicroK8s is distributed as a Snap package.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; snapd
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; snapd
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; snapd.socket
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify snap:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  🚀 Step 6 — Install Latest MicroK8s
&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;sudo &lt;/span&gt;snap &lt;span class="nb"&gt;install &lt;/span&gt;microk8s &lt;span class="nt"&gt;--classic&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Adjust the channel to the desired stable version.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🧠 Step 7 — Add Deploy User to MicroK8s Group
&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;sudo &lt;/span&gt;usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; microk8s &lt;span class="nv"&gt;$USER&lt;/span&gt;
&lt;span class="nb"&gt;sudo chown&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="nv"&gt;$USER&lt;/span&gt; ~/.kube
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Log out and back in, or use:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;newgrp microk8s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔹 Step 8 — Enable Core Addons
&lt;/h2&gt;

&lt;p&gt;MicroK8s includes essential production addons:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;microk8s status &lt;span class="nt"&gt;--wait-ready&lt;/span&gt;
microk8s &lt;span class="nb"&gt;enable &lt;/span&gt;dns storage ingress metrics-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;dns&lt;/code&gt; — service discovery&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;storage&lt;/code&gt; — dynamic persistent volumes&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ingress&lt;/code&gt; — NGINX ingress controller&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;metrics-server&lt;/code&gt; — node &amp;amp; pod metrics&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🧰 Step 9 — Setup kubectl for Deploy User
&lt;/h2&gt;

&lt;p&gt;MicroK8s ships its own kubectl. To avoid typing &lt;code&gt;microk8s.kubectl&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="nb"&gt;sudo &lt;/span&gt;snap &lt;span class="nb"&gt;alias &lt;/span&gt;microk8s.kubectl kubectl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Optional: export kubeconfig for scripts/CI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.kube
microk8s config &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.kube/config
&lt;span class="nb"&gt;chmod &lt;/span&gt;600 &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.kube/config
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;KUBECONFIG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/.kube/config
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'export KUBECONFIG=$HOME/.kube/config'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🌍 Step 10 — Optional: Remote kubectl Access
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;microk8s config &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; kubeconfig.yaml
scp kubeconfig.yaml user@localmachine:~/.kube/config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Adjust &lt;code&gt;server:&lt;/code&gt; IP if needed for external access.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ➕ Step 11 — Add Worker Nodes (Optional)
&lt;/h2&gt;



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

&lt;/div&gt;



&lt;p&gt;Follow instructions on worker nodes. Verify:&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 nodes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔎 Step 12 — Verify Cluster Health
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;microk8s status &lt;span class="nt"&gt;--wait-ready&lt;/span&gt;
kubectl get nodes
kubectl get pods &lt;span class="nt"&gt;-A&lt;/span&gt;
kubectl cluster-info
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All &lt;code&gt;kube-system&lt;/code&gt; pods should be &lt;strong&gt;Running&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ What You’ve Achieved
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;MicroK8s installed via Snap on Debian 12&lt;/li&gt;
&lt;li&gt;Deploy user configured with group membership&lt;/li&gt;
&lt;li&gt;Kernel &amp;amp; networking configured for Kubernetes&lt;/li&gt;
&lt;li&gt;Swap disabled, core addons enabled&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl&lt;/code&gt; working for non-root deploy user&lt;/li&gt;
&lt;li&gt;Ready for &lt;strong&gt;n8n, Postgres, Redis, observability, and secrets&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🚀 Next Steps (Part 2)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Setup &lt;strong&gt;centralized secrets with Doppler&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Install &lt;strong&gt;External Secrets Operator&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Prepare namespaces &amp;amp; secret sync for workloads&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>container</category>
      <category>programming</category>
      <category>ai</category>
    </item>
    <item>
      <title>Part 2: Installing MicroK8s on Ubuntu 24.04+</title>
      <dc:creator>kamlesh merugu</dc:creator>
      <pubDate>Tue, 13 Jan 2026 11:54:57 +0000</pubDate>
      <link>https://dev.to/kamlesh_merugu/prerequisites-basic-ubuntu-setup-creating-a-user-adding-sudo-access-setting-up-ssh-keys-38f8</link>
      <guid>https://dev.to/kamlesh_merugu/prerequisites-basic-ubuntu-setup-creating-a-user-adding-sudo-access-setting-up-ssh-keys-38f8</guid>
      <description>&lt;p&gt;MicroK8s is a powerful yet lightweight Kubernetes distribution perfect for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🚀 Developers testing Kubernetes locally&lt;/li&gt;
&lt;li&gt;🧪 CI/CD environments&lt;/li&gt;
&lt;li&gt;🏠 Homelabs&lt;/li&gt;
&lt;li&gt;🛠️ Edge and IoT systems&lt;/li&gt;
&lt;li&gt;🧩 Single-node or small clusters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This configuration is ideal for running MicroK8s with multiple workloads, monitoring tools, and CI/CD pipelines.&lt;/p&gt;




&lt;h2&gt;
  
  
  📋 What You'll Learn
&lt;/h2&gt;

&lt;p&gt;In this guide, you will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✨ Install MicroK8s&lt;/li&gt;
&lt;li&gt;🔒 Configure user permissions&lt;/li&gt;
&lt;li&gt;🧰 Enable essential add-ons&lt;/li&gt;
&lt;li&gt;🧪 Verify the cluster is running&lt;/li&gt;
&lt;li&gt;🎉 Deploy a test application&lt;/li&gt;
&lt;li&gt;🔄 Ensure services autostart on boot&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ❓ Why MicroK8s?
&lt;/h2&gt;

&lt;p&gt;MicroK8s is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lightweight&lt;/strong&gt; 🪶 — Minimal resource footprint&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy to install&lt;/strong&gt; ⚡ — One command setup&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero external dependencies&lt;/strong&gt; 🎯 — Everything bundled&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Production-ready&lt;/strong&gt; 🔥 — Enterprise-grade&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Beginner-friendly and pro-friendly&lt;/strong&gt; 👨‍💻 — Great for learning and production&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It includes core Kubernetes components and plug-and-play add-ons like DNS, Ingress, Helm, and the Dashboard.&lt;/p&gt;




&lt;h2&gt;
  
  
  📦 Install MicroK8s
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Update your system
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install MicroK8s via Snap
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;snap &lt;span class="nb"&gt;install &lt;/span&gt;microk8s &lt;span class="nt"&gt;--classic&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will take a few minutes. MicroK8s installs the latest stable Kubernetes release.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verify installation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;microk8s status &lt;span class="nt"&gt;--wait-ready&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;microk8s is running
high-availability: no
  datastore master nodes: 127.0.0.1:19001
  datastore standby nodes: none
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🎉 Kubernetes is up and running!&lt;/p&gt;




&lt;h2&gt;
  
  
  👥 Add Your User to the MicroK8s Group
&lt;/h2&gt;

&lt;p&gt;MicroK8s creates its own Unix group to manage access. Add your user to avoid using &lt;code&gt;sudo&lt;/code&gt; every time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;usermod &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nt"&gt;-G&lt;/span&gt; microk8s &lt;span class="nv"&gt;$USER&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply group changes immediately without logging out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;newgrp microk8s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can run &lt;code&gt;microk8s&lt;/code&gt; commands without &lt;code&gt;sudo&lt;/code&gt;!&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 Pro Tip: Create a Kubectl Alias
&lt;/h2&gt;

&lt;p&gt;Typing &lt;code&gt;microk8s kubectl&lt;/code&gt; every time is tedious. Let's create an alias so you can just type &lt;code&gt;kubectl&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Add the alias to your bash configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'alias kubectl="microk8s kubectl"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply the changes to your current session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Test it:&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 version &lt;span class="nt"&gt;--client&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;From this point forward, all commands in this guide will use &lt;code&gt;kubectl&lt;/code&gt; for brevity, but remember it is running the MicroK8s version.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🔧 Enable Essential Kubernetes Add-ons
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Recommended add-ons
&lt;/h3&gt;

&lt;p&gt;Enable DNS for internal service discovery:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;microk8s &lt;span class="nb"&gt;enable &lt;/span&gt;dns
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enable storage for persistent volumes (databases, file storage):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;microk8s &lt;span class="nb"&gt;enable &lt;/span&gt;storage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enable Ingress for external access (domain routing, SSL):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;microk8s &lt;span class="nb"&gt;enable &lt;/span&gt;ingress
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Optional but useful add-ons
&lt;/h3&gt;

&lt;p&gt;Enable Helm 3 package manager:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;microk8s &lt;span class="nb"&gt;enable &lt;/span&gt;helm3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enable Kubernetes Dashboard (UI):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;microk8s &lt;span class="nb"&gt;enable &lt;/span&gt;dashboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enable Metrics Server (for monitoring CPU/RAM usage):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;microk8s &lt;span class="nb"&gt;enable &lt;/span&gt;metrics-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check status
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;microk8s status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see all enabled add-ons listed as active.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧪 Test Your Kubernetes Cluster
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Check node status
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;Expected output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME       STATUS   ROLES   AGE   VERSION
hostname   Ready    &amp;lt;none&amp;gt;  5m    v1.31.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;STATUS&lt;/strong&gt; should be &lt;strong&gt;Ready&lt;/strong&gt; ✅&lt;/p&gt;

&lt;h3&gt;
  
  
  Check system pods
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;All components should show &lt;strong&gt;Running&lt;/strong&gt; or &lt;strong&gt;Completed&lt;/strong&gt; status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAMESPACE     NAME                                     READY   STATUS    RESTARTS   AGE
kube-system   calico-node-xxxxx                        1/1     Running   0          5m
kube-system   coredns-xxxxx                            1/1     Running   0          4m
ingress       nginx-ingress-microk8s-controller-xxxxx  1/1     Running   0          3m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything shows &lt;strong&gt;Running&lt;/strong&gt;, your cluster is healthy! 🎉&lt;/p&gt;




&lt;h2&gt;
  
  
  🐳 Deploy a Test NGINX App
&lt;/h2&gt;

&lt;p&gt;Let's deploy a simple NGINX workload to verify everything works end-to-end:&lt;/p&gt;

&lt;h3&gt;
  
  
  Create deployment
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create deployment nginx &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Expose the deployment
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl expose deployment nginx &lt;span class="nt"&gt;--port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;80 &lt;span class="nt"&gt;--type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;NodePort
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Get service details
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;You'll see output like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME    TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
nginx   NodePort   10.152.183.45   &amp;lt;none&amp;gt;        80:31234/TCP   10s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the &lt;strong&gt;NodePort&lt;/strong&gt; (e.g., &lt;code&gt;31234&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Access the application
&lt;/h3&gt;

&lt;p&gt;Open your browser and visit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://your-server-ip:31234
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see the &lt;strong&gt;NGINX welcome page&lt;/strong&gt; → 🎉 Your Kubernetes cluster is working perfectly!&lt;/p&gt;




&lt;h2&gt;
  
  
  🔄 Ensuring MicroK8s Auto-Starts on Boot
&lt;/h2&gt;

&lt;p&gt;Since MicroK8s is installed via Snap, &lt;strong&gt;systemctl cannot be used directly&lt;/strong&gt;. Snap manages startup behavior automatically, but let's verify and ensure it's active.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✔️ Step 1: Check Service Status
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;snap services microk8s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service                              Startup
microk8s.daemon-apiserver            enabled
microk8s.daemon-containerd           enabled
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If all services show &lt;strong&gt;Startup: enabled&lt;/strong&gt;, MicroK8s is set to autostart ✅&lt;/p&gt;

&lt;h3&gt;
  
  
  ✔️ Step 2: Enable Autostart (If Needed)
&lt;/h3&gt;

&lt;p&gt;If services show &lt;code&gt;disabled&lt;/code&gt;, simply run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;snap start &lt;span class="nt"&gt;--enable&lt;/span&gt; microk8s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This enables the entire application service and its internal daemons.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✔️ Step 3: Reboot &amp;amp; Validate
&lt;/h3&gt;

&lt;p&gt;Reboot the server to test autostart:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After logging back in, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;microk8s status &lt;span class="nt"&gt;--wait-ready&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see &lt;code&gt;microk8s is running&lt;/code&gt;, then autostart is confirmed! 🎉&lt;/p&gt;

&lt;h3&gt;
  
  
  Verify your NGINX app survived the reboot
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;Your nginx pod should be running.&lt;/p&gt;




&lt;h2&gt;
  
  
  💾 Resource Usage Check
&lt;/h2&gt;

&lt;p&gt;Check how much of your 8GB RAM MicroK8s is using:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Check disk usage (out of 120GB):&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;MicroK8s typically uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;~500MB-1GB RAM&lt;/strong&gt; at idle&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;~2-3GB storage&lt;/strong&gt; for base installation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This leaves plenty of resources for your workloads! 🚀&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Troubleshooting Tools
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Check cluster health (Generates a report)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;microk8s inspect
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Restart MicroK8s
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;microk8s stop
&lt;span class="nb"&gt;sudo &lt;/span&gt;microk8s start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check specific logs
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check kubelet logs&lt;/span&gt;
journalctl &lt;span class="nt"&gt;-u&lt;/span&gt; snap.microk8s.daemon-kubelet &lt;span class="nt"&gt;-f&lt;/span&gt;

&lt;span class="c"&gt;# Check API server logs&lt;/span&gt;
journalctl &lt;span class="nt"&gt;-u&lt;/span&gt; snap.microk8s.daemon-apiserver &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📋 Summary Checklist
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;✅ Install MicroK8s&lt;/td&gt;
&lt;td&gt;Kubernetes runtime&lt;/td&gt;
&lt;td&gt;Done&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✅ Add user to group&lt;/td&gt;
&lt;td&gt;Non-root access&lt;/td&gt;
&lt;td&gt;Done&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✅ Set up kubectl alias&lt;/td&gt;
&lt;td&gt;Simplify commands&lt;/td&gt;
&lt;td&gt;Done&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✅ Enable add-ons&lt;/td&gt;
&lt;td&gt;DNS, storage, ingress&lt;/td&gt;
&lt;td&gt;Done&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✅ Test with kubectl&lt;/td&gt;
&lt;td&gt;Validate cluster&lt;/td&gt;
&lt;td&gt;Done&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✅ Deploy NGINX&lt;/td&gt;
&lt;td&gt;Confirm workload scheduling&lt;/td&gt;
&lt;td&gt;Done&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✅ Enable autostart&lt;/td&gt;
&lt;td&gt;Ensure services start on boot&lt;/td&gt;
&lt;td&gt;Done&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🧹 Clean Up Test Deployment (Optional)
&lt;/h2&gt;

&lt;p&gt;Once you've verified everything works, you can remove the test NGINX deployment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete deployment nginx
kubectl delete service nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🎯 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Congratulations! 🎉 Your &lt;strong&gt;4-core, 8GB RAM, 120GB Ubuntu server&lt;/strong&gt; is now running a fully functional MicroK8s cluster!&lt;/p&gt;

&lt;p&gt;You have a robust foundation ready for production workloads.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔙 Previous Guide
&lt;/h2&gt;

&lt;p&gt;👈 &lt;strong&gt;&lt;a href="https://dev.to/kamlesh_merugu/installing-microk8s-on-ubuntu-2404-a-lightweight-kubernetes-setup-guide-d1n"&gt;Back to Part 1: Prerequisites &amp;amp; Basic Ubuntu Setup&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🔜 What's Next?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Ready to deploy production applications?&lt;/strong&gt; 🚀&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://dev.to/kamlesh_merugu/part-3-production-namespace-app-deployment-backups-restore-step-by-step-guide-2ff5"&gt;Continue to Part 3: Production Namespace, App Deployment &amp;amp; Configuration&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In Part 3, you'll learn how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🏗️ Create production namespaces for workload isolation&lt;/li&gt;
&lt;li&gt;🚀 Deploy PostgreSQL and n8n with proper configurations&lt;/li&gt;
&lt;li&gt;📦 Set up Persistent Volume Claims for databases&lt;/li&gt;
&lt;li&gt;🔐 Secure sensitive data using Kubernetes Secrets&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>beginners</category>
      <category>kubernetes</category>
      <category>tutorial</category>
      <category>ubuntu</category>
    </item>
    <item>
      <title>🏗️ Kubernetes Automation Stack (n8n + Postgres + Redis + Observability + Centralized Secrets)</title>
      <dc:creator>kamlesh merugu</dc:creator>
      <pubDate>Tue, 13 Jan 2026 11:21:01 +0000</pubDate>
      <link>https://dev.to/kamlesh_merugu/install-k3s-on-debian-1112-3ppo</link>
      <guid>https://dev.to/kamlesh_merugu/install-k3s-on-debian-1112-3ppo</guid>
      <description>&lt;h2&gt;
  
  
  📌 Project Overview
&lt;/h2&gt;

&lt;p&gt;This project sets up a &lt;strong&gt;production-ready MicroK8s Kubernetes environment&lt;/strong&gt; for hosting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;n8n&lt;/strong&gt; — workflow automation platform&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Postgres&lt;/strong&gt; — relational database for n8n&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redis&lt;/strong&gt; — cache &amp;amp; queue backend for n8n&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observability Stack&lt;/strong&gt; — Prometheus + Grafana + Loki&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Centralized Secrets&lt;/strong&gt; — Bitwarden (SaaS) as single source of truth&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Backup &amp;amp; restore is included for all critical services to ensure disaster recovery.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🔑 Project Goals
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Centralized Secrets Management&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Secrets live in &lt;strong&gt;Bitwarden&lt;/strong&gt; only.&lt;/li&gt;
&lt;li&gt;Auto-sync into Kubernetes via &lt;strong&gt;External Secrets Operator (ESO)&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Clean, Modular Deployment&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Each service has its &lt;strong&gt;own namespace &amp;amp; manifest/Helm structure&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Independent lifecycle per service.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Observability &amp;amp; Health Checks&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Metrics for cluster nodes, Postgres, Redis, n8n workflows.&lt;/li&gt;
&lt;li&gt;Alerts &amp;amp; dashboards via Grafana.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Production-Ready Infrastructure&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Persistent storage (PV/PVC) for Postgres + Redis.&lt;/li&gt;
&lt;li&gt;Ingress with HTTPS (cert-manager / Let’s Encrypt).&lt;/li&gt;
&lt;li&gt;Scalable and maintainable architecture.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Backup &amp;amp; Restore Strategy&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Backup Postgres, Redis, and n8n workflows.&lt;/li&gt;
&lt;li&gt;Cluster-level snapshot for disaster recovery.&lt;/li&gt;
&lt;li&gt;Easy restore procedure for production incidents.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🏛️ Architecture Diagram
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 ┌─────────────────────────┐
                 │ MicroK8s Cluster        │
                 │  (Namespaces &amp;amp; PVs)     │
                 └─────────┬──────────────-┘
                           │
   ┌───────────────────────┼────────────────────────┐
   │                       │                        │
   ▼                       ▼                        ▼
┌─────────┐           ┌─────────┐             ┌──────────┐
│ n8n     │           │ Postgres│             │ Redis    │
└─────────┘           └─────────┘             └──────────┘
     │                     │                        │
     └─────────────┬───────┴───────────────┬────────┘
                   ▼                       ▼
             ┌────────────┐           ┌────────────┐
             │ Prometheus │           │ Grafana    │
             └────────────┘           └────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🛠️ Tech Stack
&lt;/h2&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;Version / Tool&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Kubernetes&lt;/td&gt;
&lt;td&gt;MicroK8s v1.28+&lt;/td&gt;
&lt;td&gt;Lightweight production-grade K8s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secrets&lt;/td&gt;
&lt;td&gt;Bitwarden SaaS&lt;/td&gt;
&lt;td&gt;Centralized secrets vault&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secrets Sync&lt;/td&gt;
&lt;td&gt;External Secrets Operator&lt;/td&gt;
&lt;td&gt;Sync secrets from Bitwarden → K8s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;PostgreSQL&lt;/td&gt;
&lt;td&gt;Primary n8n DB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache&lt;/td&gt;
&lt;td&gt;Redis&lt;/td&gt;
&lt;td&gt;Queue &amp;amp; cache for n8n&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workflow&lt;/td&gt;
&lt;td&gt;n8n&lt;/td&gt;
&lt;td&gt;Automation engine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Observability&lt;/td&gt;
&lt;td&gt;Prometheus + Grafana + Loki&lt;/td&gt;
&lt;td&gt;Monitoring &amp;amp; dashboards&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ingress&lt;/td&gt;
&lt;td&gt;NGINX + cert-manager&lt;/td&gt;
&lt;td&gt;HTTPS routing &amp;amp; certificates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backup&lt;/td&gt;
&lt;td&gt;Velero / Custom CronJobs&lt;/td&gt;
&lt;td&gt;Backup &amp;amp; restore critical components&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🗂️ Project Structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;k8s-project/
├── 01-cluster-setup/           # MicroK8s setup scripts &amp;amp; configs
├── 02-secrets/                 # Bitwarden + ExternalSecrets configs
├── 03-postgres/                # Postgres manifests / Helm / PVs
├── 04-redis/                   # Redis manifests / Helm / PVs
├── 05-n8n/                     # n8n manifests / Helm
├── 06-observability/           # Prometheus, Grafana, Loki
├── 07-ingress/                 # Ingress &amp;amp; cert-manager setup
├── 08-backup-restore/          # Backup &amp;amp; restore scripts / Velero configs
└── README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🚀 Setup Plan
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1 — Prepare Cluster
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Update Debian nodes, disable swap, configure networking.&lt;/li&gt;
&lt;li&gt;Install &lt;strong&gt;MicroK8s&lt;/strong&gt; (single or multi-node).&lt;/li&gt;
&lt;li&gt;Enable addons: &lt;code&gt;dns&lt;/code&gt;, &lt;code&gt;storage&lt;/code&gt;, &lt;code&gt;ingress&lt;/code&gt;, &lt;code&gt;metrics-server&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 2 — Configure Centralized Secrets
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Setup &lt;strong&gt;Bitwarden Vault&lt;/strong&gt; for all sensitive keys.&lt;/li&gt;
&lt;li&gt;Install &lt;strong&gt;External Secrets Operator&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Create &lt;code&gt;ExternalSecret&lt;/code&gt; manifests to sync secrets into K8s namespaces.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 3 — Deploy Databases
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Deploy &lt;strong&gt;Postgres&lt;/strong&gt; with PVCs and secrets from Bitwarden.&lt;/li&gt;
&lt;li&gt;Deploy &lt;strong&gt;Redis&lt;/strong&gt; with PVCs and secrets from Bitwarden.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 4 — Deploy n8n
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Deploy &lt;strong&gt;n8n&lt;/strong&gt; using manifests or Helm.&lt;/li&gt;
&lt;li&gt;Configure secrets via ESO.&lt;/li&gt;
&lt;li&gt;Expose via &lt;strong&gt;Ingress with HTTPS&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 5 — Deploy Observability Stack
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Prometheus, Grafana, Loki.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Collect metrics from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MicroK8s nodes&lt;/li&gt;
&lt;li&gt;n8n, Postgres, Redis&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Setup dashboards &amp;amp; alerts.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 6 — Validate &amp;amp; Harden
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Test app workflows, DB connectivity, and secret sync.&lt;/li&gt;
&lt;li&gt;Apply network policies, resource limits, and backup schedules.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 7 — Backup &amp;amp; Restore Strategy
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Postgres:&lt;/strong&gt; Scheduled &lt;code&gt;pg_dump&lt;/code&gt; + store in PVC or external S3 bucket.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redis:&lt;/strong&gt; Scheduled RDB/AOF snapshots.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;n8n workflows:&lt;/strong&gt; Export via n8n API cronjobs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cluster state:&lt;/strong&gt; Use &lt;strong&gt;Velero&lt;/strong&gt; for cluster snapshots (PV + resources).&lt;/li&gt;
&lt;li&gt;Provide &lt;strong&gt;restore scripts&lt;/strong&gt; to recover from disaster with minimal downtime.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔑 End Goal
&lt;/h2&gt;

&lt;p&gt;By the end of this project:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Fully functional MicroK8s cluster&lt;/strong&gt; running n8n + Redis + Postgres + Observability stack.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;All secrets centralized&lt;/strong&gt; in Bitwarden.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safe, repeatable deployments&lt;/strong&gt; with Helm/manifests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalable, production-ready architecture&lt;/strong&gt; with monitoring, backups, and HTTPS ingress.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disaster recovery plan&lt;/strong&gt; via backup &amp;amp; restore strategy.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Link to part 1 &lt;/p&gt;

</description>
      <category>debian</category>
      <category>k3s</category>
      <category>containers</category>
    </item>
    <item>
      <title>🐋 Complete Podman Desktop + WSL2 Setup Guide - Replace Docker Desktop for FREE!</title>
      <dc:creator>kamlesh merugu</dc:creator>
      <pubDate>Sat, 14 Jun 2025 01:15:15 +0000</pubDate>
      <link>https://dev.to/kamlesh_merugu/complete-podman-desktop-wsl2-setup-guide-replace-docker-desktop-for-free-3j1p</link>
      <guid>https://dev.to/kamlesh_merugu/complete-podman-desktop-wsl2-setup-guide-replace-docker-desktop-for-free-3j1p</guid>
      <description>&lt;p&gt;🚀 Complete Tutorial: Accessing Podman Desktop Containers from Ubuntu WSL&lt;/p&gt;

&lt;p&gt;Ever wished you could seamlessly manage your Podman containers from your Ubuntu WSL terminal while still enjoying the slick UI of Podman Desktop on Windows? 🤔 You're in luck! This tutorial will guide you through setting up this powerful integration, giving you the best of both worlds. 💻✨&lt;/p&gt;

&lt;p&gt;This is super useful for developers who want to leverage the Linux environment of WSL for their container workflows, while keeping Podman Desktop as their central hub for visual management. Let's dive in! 🐳&lt;/p&gt;

&lt;h3&gt;
  
  
  📋 Prerequisites
&lt;/h3&gt;

&lt;p&gt;Before we get started, make sure you have these essentials in place:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Podman Desktop&lt;/strong&gt; installed and happily running on your Windows machine.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;Ubuntu WSL distribution&lt;/strong&gt; already installed and configured.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Podman Machine&lt;/strong&gt; created in Podman Desktop. (This usually happens automatically during the initial setup. 👍)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  💡 Overview
&lt;/h3&gt;

&lt;p&gt;Podman Desktop is smart! It sets up a special WSL virtual machine called "Podman Machine" and configures the Windows Podman client to chat with it. However, it doesn't automatically extend this courtesy to your other WSL distributions (like our beloved Ubuntu). Our mission: to bridge this communication gap! 🌉&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 1: Access Your Ubuntu WSL Distribution 🚪
&lt;/h3&gt;

&lt;p&gt;First things first, let's jump into your Ubuntu WSL session. Open your favorite Windows terminal (Command Prompt, PowerShell, or Windows Terminal) and type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wsl &lt;span class="nt"&gt;--distribution&lt;/span&gt; Ubuntu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If Ubuntu is your go-to default distribution, a simple &lt;code&gt;wsl&lt;/code&gt; will do the trick! 😉&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Install Podman Remote Client 📥
&lt;/h3&gt;

&lt;p&gt;Instead of a full-blown Podman installation from Ubuntu's repositories, we're going for the leaner, meaner &lt;code&gt;podman-remote&lt;/code&gt; binary. This ensures you're always on the cutting edge with the latest features and best compatibility! ✂️&lt;/p&gt;

&lt;h4&gt;
  
  
  Download the Latest Podman Remote Binary
&lt;/h4&gt;

&lt;p&gt;Always check the &lt;a href="https://github.com/containers/podman/releases" rel="noopener noreferrer"&gt;Podman releases page&lt;/a&gt; for the absolute latest version.&lt;/p&gt;

&lt;p&gt;Then, download and install the binary (remember to replace &lt;code&gt;v5.5.1&lt;/code&gt; with the &lt;em&gt;actual&lt;/em&gt; latest version you found!):&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/containers/podman/releases/download/v5.5.1/podman-remote-static-linux_amd64.tar.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Configure the Binary 🛠️
&lt;/h4&gt;

&lt;p&gt;Let's make sure your system knows where to find &lt;code&gt;podman-remote&lt;/code&gt; and give it a friendly alias. Edit your &lt;code&gt;.zshrc&lt;/code&gt; (or &lt;code&gt;.bashrc&lt;/code&gt; if you're using Bash):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'export PATH="$PATH:/usr/local/bin"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.zshrc
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'alias podman="podman-remote-static-linux_amd64"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.zshrc
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Identify Your Podman Machine Configuration 🕵️‍♀️
&lt;/h3&gt;

&lt;p&gt;Before we connect, we need to know which socket your Podman Desktop is currently using.&lt;/p&gt;

&lt;h4&gt;
  
  
  Find Available Sockets 🔗
&lt;/h4&gt;

&lt;p&gt;List the available Podman sockets in your WSL distribution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find /mnt/wsl/podman-sockets/ &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'*.sock'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/mnt/wsl/podman-sockets/podman-machine-default/podman-root.sock
/mnt/wsl/podman-sockets/podman-machine-default/podman-user.sock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Identify the Active Socket 👀
&lt;/h4&gt;

&lt;p&gt;Now, open a &lt;em&gt;new&lt;/em&gt; Command Prompt or PowerShell window on Windows (don't close your WSL terminal yet!). Check which connection Podman Desktop is using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;podman&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;system&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for the connection marked &lt;code&gt;true&lt;/code&gt; in the &lt;code&gt;Default&lt;/code&gt; column. The &lt;code&gt;URI&lt;/code&gt; will tell you if it's &lt;code&gt;rootful&lt;/code&gt; or &lt;code&gt;rootless&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rootful:&lt;/strong&gt; &lt;code&gt;ssh://root@127.0.0.1:PORT/run/podman/podman.sock&lt;/code&gt; (most common, default)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rootless:&lt;/strong&gt; &lt;code&gt;ssh://user@127.0.0.1:PORT/run/user/1000/podman/podman.sock&lt;/code&gt;
### Step 4: Configure the Podman Connection 🤝&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Based on whether your Podman Desktop is using rootful or rootless mode, let's set up the connection!&lt;/p&gt;

&lt;h4&gt;
  
  
  For Rootful Podman (Default) 👑
&lt;/h4&gt;

&lt;p&gt;If your Podman Desktop is in rootful mode (which is typically the default):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;podman system connection add &lt;span class="nt"&gt;--default&lt;/span&gt; podman-machine-default-root unix:///mnt/wsl/podman-sockets/podman-machine-default/podman-root.sock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  For Rootless Podman 🌱
&lt;/h4&gt;

&lt;p&gt;If your Podman Desktop is using rootless mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;podman system connection add &lt;span class="nt"&gt;--default&lt;/span&gt; podman-machine-default-user unix:///mnt/wsl/podman-sockets/podman-machine-default/podman-user.sock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5: Configure User Permissions 🔒
&lt;/h3&gt;

&lt;p&gt;Your WSL user needs the right permissions to talk to the Podman Machine socket. Add your user to the appropriate group and &lt;em&gt;then exit your WSL session&lt;/em&gt; to apply the changes. This step is crucial! 🔑&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;usermod &lt;span class="nt"&gt;--append&lt;/span&gt; &lt;span class="nt"&gt;--groups&lt;/span&gt; 10 &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;whoami&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;exit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 6: Test the Connection! ✅
&lt;/h3&gt;

&lt;p&gt;It's showtime! Restart your WSL session and let's verify everything is working smoothly.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  Verify Group Membership 👥
&lt;/h4&gt;

&lt;p&gt;Double-check that your user is now in the correct group:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;groups&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see &lt;code&gt;uucp&lt;/code&gt; in the list (this corresponds to group ID &lt;code&gt;10&lt;/code&gt; for rootful access).&lt;/p&gt;

&lt;h4&gt;
  
  
  Verify Podman Connection 🌐
&lt;/h4&gt;

&lt;p&gt;Confirm that the connection is properly configured:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  Test Podman Version 🧪
&lt;/h4&gt;

&lt;p&gt;Now, the moment of truth! Verify that Podman in your WSL can communicate with the remote machine:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;You should see both &lt;code&gt;Client&lt;/code&gt; and &lt;code&gt;Server&lt;/code&gt; versions, indicating a glorious, successful connection! 🎉&lt;/p&gt;

&lt;h4&gt;
  
  
  Test Container Operations 📦
&lt;/h4&gt;

&lt;p&gt;Let's run a quick test by launching a simple container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;podman run quay.io/podman/hello
podman ps &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nt"&gt;--last&lt;/span&gt; 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Voilà! The container should magically appear in both your WSL terminal output &lt;em&gt;and&lt;/em&gt; in Podman Desktop's container list. Synchronization at its finest! 👯‍♀️
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 7: Switching Between Rootful and Rootless (Optional) 🔄
&lt;/h3&gt;

&lt;p&gt;Sometimes you might need to flip between rootful and rootless modes. Here's how:&lt;/p&gt;

&lt;h4&gt;
  
  
  To Switch to Rootless Mode:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;In Windows terminal:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;podman&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;machine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--rootful&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;In WSL:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;podman system connection add &lt;span class="nt"&gt;--default&lt;/span&gt; podman-machine-default-user unix:///mnt/wsl/podman-sockets/podman-machine-default/podman-user.sock
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  To Switch to Rootful Mode:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;In Windows terminal:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;podman&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;machine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--rootful&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;In WSL:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;podman system connection add &lt;span class="nt"&gt;--default&lt;/span&gt; podman-machine-default-root unix:///mnt/wsl/podman-sockets/podman-machine-default/podman-root.sock
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  🐛 Troubleshooting Corner
&lt;/h3&gt;

&lt;p&gt;Ran into a snag? Don't worry, we've got you covered with some common fixes!&lt;/p&gt;

&lt;h4&gt;
  
  
  Permission Denied Errors 🚫
&lt;/h4&gt;

&lt;p&gt;If you're seeing &lt;code&gt;Permission denied&lt;/code&gt; errors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ensure you're in the correct group:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;groups&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;uucp
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;If not, add yourself to the group again and exit/restart:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;usermod &lt;span class="nt"&gt;--append&lt;/span&gt; &lt;span class="nt"&gt;--groups&lt;/span&gt; 10 &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;whoami&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;exit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Restart WSL completely:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wsl &lt;span class="nt"&gt;--shutdown&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

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

&lt;h4&gt;
  
  
  Socket Not Found 🔌
&lt;/h4&gt;

&lt;p&gt;If the socket files seem to be playing hide-and-seek:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ensure Podman Desktop is running.&lt;/strong&gt; 🏃‍♀️&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ensure the Podman Machine is started in Podman Desktop.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Check if the machine name is different (it might not be &lt;code&gt;podman-machine-default&lt;/code&gt;):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; /mnt/wsl/podman-sockets/
&lt;/code&gt;&lt;/pre&gt;

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

&lt;h4&gt;
  
  
  Connection Refused 🛑
&lt;/h4&gt;

&lt;p&gt;If you're getting &lt;code&gt;Connection refused&lt;/code&gt; errors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Verify Podman Desktop is running.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Check that the Podman Machine is started.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Try restarting the Podman Machine from Podman Desktop.&lt;/strong&gt; 🔄&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  ⚙️ Custom Configurations
&lt;/h3&gt;

&lt;p&gt;A couple of notes for more unique setups:&lt;/p&gt;

&lt;h4&gt;
  
  
  Custom WSL Distribution 🐧
&lt;/h4&gt;

&lt;p&gt;If you're using a WSL distribution other than Ubuntu, the group names for group ID &lt;code&gt;10&lt;/code&gt; might be different. You can find the correct group name using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;getent group 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Custom Podman Machine Name 🏷️
&lt;/h4&gt;

&lt;h2&gt;
  
  
  If you've been adventurous and created a custom Podman Machine with a different name, simply replace &lt;code&gt;podman-machine-default&lt;/code&gt; in the socket paths with your machine's actual name.
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ➡️ Next Steps
&lt;/h3&gt;

&lt;p&gt;Congratulations! 🎉 You've successfully configured your Ubuntu WSL distribution to communicate with Podman Desktop's container engine. Now, the world of containerized development is your oyster within WSL!&lt;/p&gt;

&lt;p&gt;You can now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;all Podman commands&lt;/strong&gt; directly from your WSL terminal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manage containers&lt;/strong&gt; that appear seamlessly in both your WSL and Podman Desktop.&lt;/li&gt;
&lt;li&gt;Start experimenting with container orchestration tools like &lt;strong&gt;Podman Compose&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Deeply &lt;strong&gt;integrate container workflows&lt;/strong&gt; into your WSL development environment.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🌟 Summary
&lt;/h3&gt;

&lt;p&gt;You've done it! You've successfully linked your Ubuntu WSL with Podman Desktop, allowing you to enjoy the power of the Podman CLI from within WSL while benefiting from Podman Desktop's excellent graphical interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key takeaways to remember:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Always use &lt;code&gt;podman-remote&lt;/code&gt; for the latest features and best compatibility.&lt;/li&gt;
&lt;li&gt;Configure the correct socket path based on your Podman Desktop's rootful/rootless setting.&lt;/li&gt;
&lt;li&gt;Proper group permissions are essential for socket access.&lt;/li&gt;
&lt;li&gt;The magic part: &lt;strong&gt;Both WSL and Podman Desktop will now show the same containers and images!&lt;/strong&gt; ✨&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy containerizing! 🚀&lt;/p&gt;

</description>
      <category>podman</category>
      <category>docker</category>
      <category>wsl2</category>
      <category>containers</category>
    </item>
  </channel>
</rss>
