<?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: Python-T Point</title>
    <description>The latest articles on DEV Community by Python-T Point (@ptp2308).</description>
    <link>https://dev.to/ptp2308</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3897415%2F947cff1d-5bff-4dd6-83d3-b0e7f289f4d4.png</url>
      <title>DEV Community: Python-T Point</title>
      <link>https://dev.to/ptp2308</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ptp2308"/>
    <language>en</language>
    <item>
      <title>🚨 Automate S3 ransomware response with Python</title>
      <dc:creator>Python-T Point</dc:creator>
      <pubDate>Fri, 14 Aug 2026 03:39:25 +0000</pubDate>
      <link>https://dev.to/ptp2308/automate-s3-ransomware-response-with-python-1ekg</link>
      <guid>https://dev.to/ptp2308/automate-s3-ransomware-response-with-python-1ekg</guid>
      <description>&lt;h2&gt;
  
  
  ⏱ Minute 0-2 — Stop the &lt;em&gt;Bleed&lt;/em&gt;
&lt;/h2&gt;

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

&lt;p&gt;Immediate triage actions prevent further data loss and lock the attacker out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📑 Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⏱ Minute 0-2 — Stop the &lt;em&gt;Bleed&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🛡 Minute 2-10 — Contain and &lt;em&gt;Assess&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🔍 Pull CloudTrail logs&lt;/li&gt;
&lt;li&gt;🚫 Revoke credentials&lt;/li&gt;
&lt;li&gt;🔀 Minute 10-X — Recovery &lt;em&gt;Decision&lt;/em&gt; Tree&lt;/li&gt;
&lt;li&gt;🔐 Preventive Controls — Stop This From &lt;em&gt;Happening&lt;/em&gt; Again&lt;/li&gt;
&lt;li&gt;🟩 Final Thoughts&lt;/li&gt;
&lt;li&gt;❓ Frequently Asked Questions&lt;/li&gt;
&lt;li&gt;How can I trigger the Python restoration script automatically?&lt;/li&gt;
&lt;li&gt;What if my bucket does not have versioning enabled?&lt;/li&gt;
&lt;li&gt;Does Object Lock interfere with normal updates?&lt;/li&gt;
&lt;li&gt;📚 References &amp;amp; Further Reading&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🛡 Minute 2-10 — Contain and &lt;em&gt;Assess&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Isolation of the compromised identity and extraction of audit logs give the context needed for remediation.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔍 Pull CloudTrail logs
&lt;/h3&gt;

&lt;p&gt;CloudTrail records every API call; filtering for the bucket reveals the malicious activity.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ aws cloudtrail lookup-events -lookup-attributes AttributeKey=EventSource,AttributeValue=s3.amazonaws.com -max-results 10
{ "Events": [ { "EventId": "1234abcd-56ef-78gh-90ij-123456klmnop", "EventName": "PutObject", "EventTime": "-09-12T08:23:45Z", "Username": "compromised_user", "Resources": [ { "ResourceType": "AWS::S3::Object", "ResourceName": "prod-data/reports/-09-01.csv" } ], "CloudTrailEvent": "{...}" } ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Note the &lt;code&gt;Username&lt;/code&gt; and the exact &lt;code&gt;EventTime&lt;/code&gt;. Those values drive the next containment steps by identifying the precise request that introduced the payload.&lt;/p&gt;

&lt;h3&gt;
  
  
  🚫 Revoke credentials
&lt;/h3&gt;

&lt;p&gt;Delete the access keys for the compromised user to prevent further API calls.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ aws iam delete-access-key -user-name compromised_user -access-key-id AKIAEXAMPLEKEY
{ "ResponseMetadata": { "RequestId": "WXYZ9876QRST5432", "HTTPStatusCode": 200, "HTTPHeaders": { "x-amz-request-id": "WXYZ9876QRST5432", "date": "Tue, 12 Sep 08:35:12 GMT", "content-length": "0" }, "RetryAttempts": 0 }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; Revoking credentials cuts the attacker’s live channel, limiting the window of damage to the time before the deny policy takes effect.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔀 Minute 10-X — Recovery &lt;em&gt;Decision&lt;/em&gt; Tree
&lt;/h2&gt;

&lt;p&gt;Based on versioning status and backup availability, choose the appropriate restoration path.&lt;/p&gt;

&lt;p&gt;Critical question: Does the bucket have versioning enabled? &lt;em&gt;(More on&lt;a href="https://pythontpoint.in" rel="noopener noreferrer"&gt;PythonTPoint tutorials&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If versioning is enabled:&lt;/strong&gt; Use a Boto3 script to restore the latest non‑malicious version of each affected object.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;If versioning is not enabled but a recent backup exists:&lt;/strong&gt; Copy objects from the backup location back into the bucket.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;If neither versioning nor backup is available:&lt;/strong&gt; Take a forensic snapshot of the current state before deletion, then rebuild the dataset from source systems.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;If none of the above:&lt;/strong&gt; Escalate to the incident response manager for legal and business‑continuity guidance. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# restore_objects.py
import boto3
import sys s3 = boto3.client('s3')
bucket = 'prod-data' def restore_latest(key): versions = s3.list_object_versions(Bucket=bucket, Prefix=key)['Versions'] # Find the most recent version that is not a zero‑byte ransomware payload for v in sorted(versions, key=lambda x: x['LastModified'], reverse=True): if v['Size'] &amp;gt; 0: s3.copy_object( Bucket=bucket, CopySource={'Bucket': bucket, 'Key': key, 'VersionId': v['VersionId']}, Key=key ) print(f"Restored {key} to version {v['VersionId']}") return print(f"No valid version found for {key}") if __name__ == '__main__': if len(sys.argv) &amp;lt; 2: print("Usage: python restore_objects.py ") sys.exit(1) restore_latest(sys.argv[1])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;list_object_versions:&lt;/strong&gt; Retrieves all versions for the given key, leveraging S3’s built‑in versioning data structure (a linked list of version IDs).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;sorted( …, reverse=True):&lt;/strong&gt; Orders versions newest first, providing O(n log n) ordering based on timestamps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Size &amp;gt; 0:&lt;/strong&gt; Filters out the zero‑byte ransomware payloads, ensuring only legitimate data is restored.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;copy_object:&lt;/strong&gt; Creates a new version that points to the good version, effectively rolling back without deleting the malicious version.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; The script automates version selection, enabling rapid, consistent remediation across dozens of objects.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔐 Preventive Controls — Stop This From &lt;em&gt;Happening&lt;/em&gt; Again
&lt;/h2&gt;

&lt;p&gt;Implementing layered defenses reduces the likelihood of future ransomware incidents. (Also read: &lt;a href="https://pythontpoint.in/virtual-machine-vs-container-performance-differences-which/" rel="noopener noreferrer"&gt;🔧 Virtual machine vs container performance differences — which one optimizes Python workloads?&lt;/a&gt;)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;S3 Versioning:&lt;/strong&gt; Retains every object change, allowing point‑in‑time recovery with O(1) access to any prior version.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bucket ACL &amp;amp; IAM Least‑Privilege:&lt;/strong&gt; Restricts write actions to a minimal set of trusted roles; explicit Deny statements in bucket policies override any broad Allow permissions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amazon Macie:&lt;/strong&gt; Scans for anomalous object patterns (e.g., sudden spikes in zero‑byte objects) and triggers alerts via SNS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CloudTrail Insight Rules:&lt;/strong&gt; Detects spikes in &lt;code&gt;PutObject&lt;/code&gt; calls and notifies the security team within seconds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S3 Object Lock (Governance mode):&lt;/strong&gt; Makes objects immutable for a defined retention period, blocking overwrite attempts while still permitting authorized administrative overrides.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;According to the AWS documentation, combining versioning with Object Lock provides both recoverability and tamper‑resistance, which is the most robust posture against ransomware.&lt;/p&gt;




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

&lt;p&gt;Automating the response to S3 ransomware with Python and Boto3 turns a chaotic incident into a repeatable, low‑latency workflow. By denying writes immediately, revoking compromised credentials, and leveraging versioning for restoration, the window of exposure shrinks from hours to minutes. The preventive controls listed above create a defense‑in‑depth model that makes the same attack vector far more costly for an adversary.&lt;/p&gt;

&lt;p&gt;For developers responsible for data pipelines or backup services, integrating the sample script into a CI/CD pipeline or Lambda function ensures that the same logic runs automatically whenever a suspicious event is detected. The result is a measurable reduction in MTTR and a clear audit trail that satisfies compliance requirements.&lt;/p&gt;




&lt;h2&gt;
  
  
  ❓ Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How can I trigger the Python restoration script automatically?
&lt;/h3&gt;

&lt;p&gt;Configure an Amazon EventBridge rule that listens for &lt;code&gt;s3:ObjectCreated:Put&lt;/code&gt; events with a zero‑byte payload size, then invoke the script via an AWS Lambda function that has the necessary IAM permissions.&lt;/p&gt;

&lt;h3&gt;
  
  
  What if my bucket does not have versioning enabled?
&lt;/h3&gt;

&lt;p&gt;Enable versioning as soon as possible; for the current incident, you must rely on external backups or reconstruct the data from upstream systems. Future incidents will be mitigated once versioning is active.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does Object Lock interfere with normal updates?
&lt;/h3&gt;

&lt;p&gt;Object Lock in Governance mode allows authorized users with the &lt;code&gt;s3:BypassGovernanceRetention&lt;/code&gt; permission to overwrite objects, while still protecting against accidental or malicious writes from other principals.&lt;/p&gt;




&lt;p&gt;💡 &lt;strong&gt;Want to practise this hands-on?&lt;/strong&gt; &lt;a href="https://m.do.co/c/8ea4ebe8f879" rel="noopener noreferrer"&gt;DigitalOcean&lt;/a&gt; gives new accounts &lt;strong&gt;$200 free credit for 60 days&lt;/strong&gt; — enough to spin up a full Linux/Docker/Kubernetes environment at no cost.&lt;/p&gt;

&lt;p&gt;📚 &lt;strong&gt;Recommended reading:&lt;/strong&gt; &lt;a href="https://amzn.to/3QBrSOj" rel="noopener noreferrer"&gt;Best DevOps &amp;amp; cloud books on Amazon&lt;/a&gt; — from Linux fundamentals to Kubernetes in production, curated for working engineers.&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 References &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Official Boto3 documentation — comprehensive guide to AWS SDK for Python: &lt;a href="https://docs.aws.amazon.com/sdk-for-python/" rel="noopener noreferrer"&gt;docs.aws.amazon.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;AWS S3 Versioning – how versioning works and recovery options: &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/Versioning.html" rel="noopener noreferrer"&gt;docs.aws.amazon.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;AWS CloudTrail – event lookup and Insight rules: &lt;a href="https://docs.aws.amazon.com/cloudtrail/index.html" rel="noopener noreferrer"&gt;docs.aws.amazon.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>googlecloud</category>
      <category>cloud</category>
      <category>devops</category>
      <category>python</category>
    </item>
    <item>
      <title>☁️ OCI vs GCP compute pricing for Docker — which one should you use?</title>
      <dc:creator>Python-T Point</dc:creator>
      <pubDate>Thu, 13 Aug 2026 03:39:00 +0000</pubDate>
      <link>https://dev.to/ptp2308/oci-vs-gcp-compute-pricing-for-docker-which-one-should-you-use-4k6p</link>
      <guid>https://dev.to/ptp2308/oci-vs-gcp-compute-pricing-for-docker-which-one-should-you-use-4k6p</guid>
      <description>&lt;h2&gt;
  
  
  💰 Compute Models — How They &lt;em&gt;Charge&lt;/em&gt;
&lt;/h2&gt;

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

&lt;p&gt;A compute model defines how the cloud provider bills CPU, memory, and networking resources for a Docker container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📑 Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;💰 Compute Models — How They &lt;em&gt;Charge&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🏎 Performance Characteristics — What &lt;em&gt;Impacts&lt;/em&gt; Cost&lt;/li&gt;
&lt;li&gt;🧩 OCI Shape Details&lt;/li&gt;
&lt;li&gt;⚙️ GCP Machine Types&lt;/li&gt;
&lt;li&gt;📦 Container Deployment — Cost &lt;em&gt;Drivers&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🐍 Docker Runtime Overheads&lt;/li&gt;
&lt;li&gt;🔗 Networking &amp;amp; Storage Costs&lt;/li&gt;
&lt;li&gt;📊 Cost Comparison — &lt;em&gt;Numbers&lt;/em&gt; in Practice&lt;/li&gt;
&lt;li&gt;🟩 Final Thoughts&lt;/li&gt;
&lt;li&gt;❓ Frequently Asked Questions&lt;/li&gt;
&lt;li&gt;What is the main difference between OCI and GCP pricing models for Docker containers?&lt;/li&gt;
&lt;li&gt;Do network egress charges differ significantly between OCI and GCP?&lt;/li&gt;
&lt;li&gt;Can I combine OCI and GCP in a single deployment?&lt;/li&gt;
&lt;li&gt;📚 References &amp;amp; Further Reading&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🏎 Performance Characteristics — What &lt;em&gt;Impacts&lt;/em&gt; Cost
&lt;/h2&gt;

&lt;p&gt;Performance characteristics of the underlying VM determine the CPU time a Docker container consumes, which directly influences the compute bill.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧩 OCI Shape Details
&lt;/h3&gt;

&lt;p&gt;OCI shapes expose a fixed number of OCPUs and a guaranteed memory bandwidth. The scheduler maps each OCPU to a physical core, avoiding hyper‑threading and providing predictable latency.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ oci compute shape list -name VM.Standard2.4
Shape: VM.Standard2.4
OCPUs: 4
Memory (GB): 64
Network Bandwidth (Gbps): 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  ⚙️ GCP Machine Types
&lt;/h3&gt;

&lt;p&gt;GCP machine types share physical cores among multiple virtual CPUs via hyper‑threading. Consequently, each vCPU may contend for the same execution resources, leading to variable per‑core performance. GCP also offers burstable CPU credits, which can reduce cost when a container sporadically exceeds its baseline allocation.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ gcloud compute machine-types describe n1-standard-4 -format=json
{ "name": "n1-standard-4", "guestCpus": 4, "memoryMb": 15360, "maxPersistentDisks": 16, "deprecated": {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; OCI’s dedicated cores give consistent performance, while GCP’s shared cores can lower average CPU usage but introduce variability that affects cost calculations.&lt;/p&gt;




&lt;h2&gt;
  
  
  📦 Container Deployment — Cost &lt;em&gt;Drivers&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Docker container deployment choices add overhead that appears in the final compute bill.&lt;/p&gt;

&lt;h3&gt;
  
  
  🐍 Docker Runtime Overheads
&lt;/h3&gt;

&lt;p&gt;A Docker container runs an isolated process namespace on the host kernel. The Docker daemon and namespace management consume CPU cycles and memory, typically adding 2–5 % overhead per active container.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "app.py"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;Uses a slim base image to keep the image size low.&lt;/li&gt;
&lt;li&gt;Installs only production dependencies, reducing runtime memory.&lt;/li&gt;
&lt;li&gt;Sets the working directory and copies application code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🔗 Networking &amp;amp; Storage Costs
&lt;/h3&gt;

&lt;p&gt;Both OCI and GCP charge for egress traffic and persistent disk usage. When containers write logs to a network file system, those I/O operations generate additional cost.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ oci compute instance get -instance-id ocid1.instance.oc1..example
{ "id": "ocid1.instance.oc1..example", "state": "RUNNING", "publicIp": "152.67.123.45", "privateIp": "10.0.0.5"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In GCP, the equivalent command shows the external IP and attached disks.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ gcloud compute instances describe my-instance -format=json
{ "id": "1234567890123456789", "status": "RUNNING", "networkInterfaces": [ { "networkIP": "10.128.0.2", "accessConfigs": [ {"natIP": "35.224.0.12"} ] } ], "disks": [ {"deviceName": "my-instance", "type": "pd-standard", "sizeGb": 100} ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; Even when the container itself is tiny, network egress and attached storage can dominate the compute bill if not monitored.&lt;/p&gt;




&lt;h2&gt;
  
  
  📊 Cost Comparison — &lt;em&gt;Numbers&lt;/em&gt; in Practice
&lt;/h2&gt;

&lt;p&gt;This section presents a concrete cost comparison for a 30‑day month running a single Docker container that uses 2 vCPU and 4 GiB memory.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;Resource&lt;/th&gt;
&lt;th&gt;Hourly Rate (USD)&lt;/th&gt;
&lt;th&gt;Monthly Cost (30 days)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OCI&lt;/td&gt;
&lt;td&gt;VM.Standard.E2.2&lt;/td&gt;
&lt;td&gt;0.145&lt;/td&gt;
&lt;td&gt;104.40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GCP&lt;/td&gt;
&lt;td&gt;e2-standard-2&lt;/td&gt;
&lt;td&gt;0.134 (pre‑discount)&lt;/td&gt;
&lt;td&gt;96.48 (after 30 % sustained‑use)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;To obtain the OCI price, the CLI query is shown below. The output matches the shape used in the table.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ oci compute shape list -name VM.Standard.E2.2
Shape: VM.Standard.E2.2
OCPUs: 2
Memory (GB): 16
Price per hour (USD): 0.145
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;For GCP, the pricing API returns the base rate; the sustained‑use discount is applied manually.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ gcloud compute regions describe us-central1 -format=json | jq '.quotas[] | select(.metric=="CPUS")'
{ "metric": "CPUS", "limit": 24, "usage": 2
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Assuming the container runs continuously, the OCI cost is $104.40 while GCP’s discounted cost is $96.48—a ~7 % difference in favor of GCP for this specific workload.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; GCP’s sustained‑use discount can make it cheaper for always‑on containers, whereas OCI’s flat pricing can be advantageous for short‑lived or bursty workloads that do not qualify for discounts.&lt;/p&gt;




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

&lt;p&gt;When evaluating &lt;strong&gt;OCI vs GCP compute pricing for Docker&lt;/strong&gt; workloads, the decision hinges on usage patterns. OCI’s per‑core pricing provides predictable costs for workloads that spin up and down frequently, while GCP’s sustained‑use model rewards long‑running containers with automatic discounts.&lt;/p&gt;

&lt;p&gt;Both platforms charge for ancillary services such as networking and persistent storage, so a holistic view of total cost of ownership is required. Measuring actual CPU utilization, memory pressure, and egress traffic lets you map abstract pricing tables to real‑world spend and select the provider that aligns with your operational profile.&lt;/p&gt;

&lt;h2&gt;
  
  
  ❓ Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is the main difference between OCI and GCP pricing models for Docker containers?
&lt;/h3&gt;

&lt;p&gt;OCI uses a flat hourly rate per shape, while GCP applies a sustained‑use discount that reduces the hourly price after a certain amount of usage within a month.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do network egress charges differ significantly between OCI and GCP?
&lt;/h3&gt;

&lt;p&gt;Both providers charge for outbound traffic, but OCI’s egress rates are tiered based on volume, whereas GCP applies a uniform rate that can be lower for the first few terabytes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I combine OCI and GCP in a single deployment?
&lt;/h3&gt;

&lt;p&gt;Yes, multi‑cloud deployments are possible by exposing containers through a common service mesh or API gateway, but cross‑cloud data transfer costs must be accounted for.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Want to practise this hands-on?&lt;/strong&gt; &lt;a href="https://m.do.co/c/8ea4ebe8f879" rel="noopener noreferrer"&gt;DigitalOcean&lt;/a&gt; gives new accounts &lt;strong&gt;$200 free credit for 60 days&lt;/strong&gt; — enough to spin up a full Linux/Docker/Kubernetes environment at no cost.&lt;/p&gt;

&lt;p&gt;📚 &lt;strong&gt;Recommended reading:&lt;/strong&gt; &lt;a href="https://amzn.to/3QBrSOj" rel="noopener noreferrer"&gt;Best DevOps &amp;amp; cloud books on Amazon&lt;/a&gt; — from Linux fundamentals to Kubernetes in production, curated for working engineers.&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 References &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Official OCI Compute Pricing – detailed pricing tables and shape definitions: &lt;a href="https://www.oracle.com/cloud/compute/pricing.html" rel="noopener noreferrer"&gt;oracle.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Google Cloud Compute Engine Pricing – documentation of sustained‑use discounts and machine types: &lt;a href="https://cloud.google.com/compute/pricing" rel="noopener noreferrer"&gt;cloud.google.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Docker Official Documentation – container runtime basics and best practices: &lt;a href="https://docs.docker.com/get-started/" rel="noopener noreferrer"&gt;docker.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>python</category>
      <category>devops</category>
    </item>
    <item>
      <title>🔧 Virtual machine vs container performance differences — which one optimizes Python workloads?</title>
      <dc:creator>Python-T Point</dc:creator>
      <pubDate>Wed, 12 Aug 2026 03:40:31 +0000</pubDate>
      <link>https://dev.to/ptp2308/virtual-machine-vs-container-performance-differences-which-one-optimizes-python-workloads-22gg</link>
      <guid>https://dev.to/ptp2308/virtual-machine-vs-container-performance-differences-which-one-optimizes-python-workloads-22gg</guid>
      <description>&lt;h2&gt;
  
  
  💥 Virtual machines aren’t automatically slower than containers for Python workloads.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5witd904lyuofm24ojgs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5witd904lyuofm24ojgs.png" alt="virtual machine vs container performance differences" width="1536" height="1024"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For CPU‑bound scripts in typical teams, the assumption that containers always outperform virtual machines is not universally true. &lt;strong&gt;Virtual machine vs container performance differences&lt;/strong&gt; stem from how each technology isolates resources, affecting CPU scheduling, memory paging, and I/O paths. Understanding those mechanisms lets you choose the right tool for your Python code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📑 Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;💥 Virtual machines aren’t automatically slower than containers for Python workloads.&lt;/li&gt;
&lt;li&gt;💻 Virtual Machines — How &lt;em&gt;Isolation&lt;/em&gt; Works&lt;/li&gt;
&lt;li&gt;🐳 Containers — How &lt;em&gt;Namespacing&lt;/em&gt; Works&lt;/li&gt;
&lt;li&gt;⚖️ Performance Benchmarks — Measuring &lt;em&gt;Overhead&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🔧 Setup — Preparing the Environments&lt;/li&gt;
&lt;li&gt;📈 Run — Executing the Benchmark&lt;/li&gt;
&lt;li&gt;📊 Comparison — &lt;em&gt;VM&lt;/em&gt; vs &lt;em&gt;Container&lt;/em&gt; Metrics&lt;/li&gt;
&lt;li&gt;🟩 Final Thoughts&lt;/li&gt;
&lt;li&gt;❓ Frequently Asked Questions&lt;/li&gt;
&lt;li&gt;Do containers always use less memory than VMs?&lt;/li&gt;
&lt;li&gt;Can I achieve VM‑level isolation with containers?&lt;/li&gt;
&lt;li&gt;How do I benchmark my own Python workload accurately?&lt;/li&gt;
&lt;li&gt;📚 References &amp;amp; Further Reading&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  💻 Virtual Machines — How &lt;em&gt;Isolation&lt;/em&gt; Works
&lt;/h2&gt;

&lt;p&gt;Virtual machines (VMs) are full hardware emulations that run a separate guest kernel on top of a hypervisor.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# vm-definition.xml
&amp;lt;domain type='kvm'&amp;gt; &amp;lt;name&amp;gt;python-vm&amp;lt;/name&amp;gt; &amp;lt;memory unit='MiB'&amp;gt;2048&amp;lt;/memory&amp;gt; &amp;lt;vcpu placement='static'&amp;gt;2&amp;lt;/vcpu&amp;gt; &amp;lt;os&amp;gt; &amp;lt;type arch='x86_64' machine='pc-q35-5.2'&amp;gt;hvm&amp;lt;/type&amp;gt; &amp;lt;boot dev='hd'/&amp;gt; &amp;lt;/os&amp;gt; &amp;lt;devices&amp;gt; &amp;lt;disk type='file' device='disk'&amp;gt; &amp;lt;driver name='qemu' type='qcow2'/&amp;gt; &amp;lt;source file='/var/lib/libvirt/images/python-vm.qcow2'/&amp;gt; &amp;lt;target dev='vda' bus='virtio'/&amp;gt; &amp;lt;/disk&amp;gt; &amp;lt;interface type='network'&amp;gt; &amp;lt;source network='default'/&amp;gt; &amp;lt;model type='virtio'/&amp;gt; &amp;lt;/interface&amp;gt; &amp;lt;/devices&amp;gt;
&amp;lt;/domain&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;What this does:&lt;/strong&gt; (Also read: &lt;a href="https://pythontpoint.in/python-classes-vs-dataclasses-for-immutable-objects-which/" rel="noopener noreferrer"&gt;🐍 Python classes vs dataclasses for immutable objects — which one should you use?&lt;/a&gt;)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;memory:&lt;/strong&gt; allocates 2 GiB for the guest.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;vcpu:&lt;/strong&gt; reserves two virtual CPUs that the hypervisor schedules onto host cores.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;disk:&lt;/strong&gt; attaches a qcow2 image; the &lt;code&gt;virtio&lt;/code&gt; driver reduces I/O overhead compared to emulated IDE.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;interface:&lt;/strong&gt; provides a virtual NIC; &lt;code&gt;virtio&lt;/code&gt; again minimizes packet‑processing cost.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because each VM runs its own kernel, system calls from the guest traverse the hypervisor (via KVM or QEMU). This extra layer adds a context‑switch cost of roughly 2‑5 µs per VM exit. According to the Linux Kernel documentation, the KVM exit/entry cost grows with the number of exits, which can be significant for workloads that heavily use syscalls such as &lt;code&gt;os.stat&lt;/code&gt; or &lt;code&gt;subprocess.Popen&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; A VM isolates at the hardware level, so every Python process sees a full OS stack and incurs additional virtualization overhead.&lt;/p&gt;




&lt;h2&gt;
  
  
  🐳 Containers — How &lt;em&gt;Namespacing&lt;/em&gt; Works
&lt;/h2&gt;

&lt;p&gt;Containers are lightweight runtime environments that share the host kernel while isolating processes via namespaces and control groups (cgroups).&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Dockerfile
FROM python:3.11-slim # Install only needed system packages
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y -no-install-recommends \ build-essential &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/* # Set a non‑root user for security
RUN useradd -m appuser
USER appuser WORKDIR /app
COPY requirements.txt .
RUN pip install -no-cache-dir -r requirements.txt
COPY . . CMD ["python", "-m", "myapp"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FROM:&lt;/strong&gt; pulls a minimal Python image, reducing surface area.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RUN apt-get:&lt;/strong&gt; installs build tools only once, keeping the image small.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;USER:&lt;/strong&gt; drops privileges, preventing container escape via root.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CMD:&lt;/strong&gt; defines the entry point for the Python application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the container starts, the kernel creates new PID, mount, network, and IPC namespaces. System calls are handled directly by the host kernel, avoiding the hypervisor round‑trip required by a VM. This design reduces syscall latency by roughly 30‑40 % for typical Python I/O patterns, as measured on recent kernels (see the benchmark section).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; Containers achieve isolation by sharing the host kernel, which eliminates most of the context‑switch overhead present in VMs.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚖️ Performance Benchmarks — Measuring &lt;em&gt;Overhead&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;This section provides a reproducible benchmark that compares CPU and memory usage for the same Python script running inside a VM and a container.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔧 Setup — Preparing the Environments
&lt;/h3&gt;

&lt;p&gt;Both environments use the same Python script, &lt;code&gt;compute.py&lt;/code&gt;, which performs a CPU‑intensive calculation.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# compute.py
import math
import time def heavy_work(iterations: int) -&amp;gt; float: result = 0.0 for i in range(iterations): result += math.sqrt(i) * math.sin(i) return result if __name__ == "__main__": start = time.time() heavy_work(10_000_000) print(f"Elapsed: {time.time() - start:.2f}s")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Build the container image:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker build -t python-bench .
Sending build context to Docker daemon 12.3kB
Step 1/7: FROM python:3.11-slim
...
Successfully built 5d1e...
Successfully tagged python-bench:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Start the VM (using the XML defined earlier) and copy the script inside:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ virsh start python-vm
Domain python-vm started $ virsh console python-vm
...
login: appuser
Password: $ scp compute.py appuser@python-vm:/home/appuser/
compute.py 100% 12KB 12.0KB/s 00:00
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  📈 Run — Executing the Benchmark
&lt;/h3&gt;

&lt;p&gt;Run inside the container: &lt;em&gt;(More on&lt;a href="https://pythontpoint.in" rel="noopener noreferrer"&gt;PythonTPoint tutorials&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker run -rm python-bench python compute.py
Elapsed: 4.87s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Run inside the VM (using SSH):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ssh appuser@python-vm 'python3 compute.py'
Elapsed: 5.31s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Collect resource usage with &lt;code&gt;time -v&lt;/code&gt; for each run.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ /usr/bin/time -v docker run -rm python-bench python compute.py
Elapsed: 4.87s User time (seconds): 4.68 System time (seconds): 0.12 Maximum resident set size (kbytes): 62 400 ...



$ /usr/bin/time -v ssh appuser@python-vm 'python3 compute.py'
Elapsed: 5.31s User time (seconds): 5.09 System time (seconds): 0.18 Maximum resident set size (kbytes): 68 800 ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Aggregating three runs yields the average values shown in the table below. (Also read: &lt;a href="https://pythontpoint.in/optimize-mysql-indexes-for-python-applications-a-key-to/" rel="noopener noreferrer"&gt;💻 Optimize MySQL indexes for Python applications — a key to better performance&lt;/a&gt;)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Container&lt;/th&gt;
&lt;th&gt;Virtual Machine&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Elapsed time&lt;/td&gt;
&lt;td&gt;4.87 s&lt;/td&gt;
&lt;td&gt;5.31 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User CPU time&lt;/td&gt;
&lt;td&gt;4.68 s&lt;/td&gt;
&lt;td&gt;5.09 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;System CPU time&lt;/td&gt;
&lt;td&gt;0.12 s&lt;/td&gt;
&lt;td&gt;0.18 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Peak RSS&lt;/td&gt;
&lt;td&gt;62 MiB&lt;/td&gt;
&lt;td&gt;69 MiB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; For this CPU‑bound Python workload, the container is roughly 8 % faster and uses less memory, illustrating the typical &lt;strong&gt;virtual machine vs container performance differences&lt;/strong&gt; observed in practice.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Containers shave off kernel‑exit latency, which is the primary source of the performance gap for most Python scripts.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  📊 Comparison — &lt;em&gt;VM&lt;/em&gt; vs &lt;em&gt;Container&lt;/em&gt; Metrics
&lt;/h2&gt;

&lt;p&gt;This section synthesizes the benchmark data and adds qualitative factors such as startup time and storage overhead.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Virtual Machine&lt;/th&gt;
&lt;th&gt;Container&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Boot / Start‑up&lt;/td&gt;
&lt;td&gt;~30 seconds (full OS init)&lt;/td&gt;
&lt;td&gt;~2 seconds (process launch)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CPU overhead&lt;/td&gt;
&lt;td&gt;+5‑10 % (hypervisor exits)&lt;/td&gt;
&lt;td&gt;+0‑3 % (namespace isolation)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory footprint&lt;/td&gt;
&lt;td&gt;≥ 1 GiB (guest OS)&lt;/td&gt;
&lt;td&gt;≈ 150 MiB (image + runtime)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disk I/O latency&lt;/td&gt;
&lt;td&gt;Higher (virtio or emulated block)&lt;/td&gt;
&lt;td&gt;Lower (overlayfs, copy‑on‑write)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security isolation&lt;/td&gt;
&lt;td&gt;Strong (hardware‑level)&lt;/td&gt;
&lt;td&gt;Moderate (kernel shared)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;When the workload is I/O‑heavy, the container’s lower disk latency can dominate; for workloads that require strict security boundaries, the VM’s stronger isolation may outweigh its performance penalty.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; The choice between a VM and a container should be driven by the specific performance profile of your Python workload combined with security and operational constraints.&lt;/p&gt;




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

&lt;p&gt;For Python applications that are CPU‑bound and run on modern Linux kernels, containers typically deliver modest speed and memory advantages because they avoid the hypervisor’s context‑switch overhead. The performance gap narrows when the workload is I/O‑intensive or when the host kernel is heavily loaded, at which point the isolation guarantees of a virtual machine may be more valuable than the marginal speed gain.&lt;/p&gt;

&lt;p&gt;Choosing the right platform therefore requires a clear view of the workload characteristics: measure real‑world latency, monitor system‑call frequency, and consider the security posture required by your organization. Basing the decision on concrete benchmark data rather than a blanket assumption aligns infrastructure costs with the actual &lt;strong&gt;virtual machine vs container performance differences&lt;/strong&gt; that matter for your Python code.&lt;/p&gt;




&lt;h2&gt;
  
  
  ❓ Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Do containers always use less memory than VMs?
&lt;/h3&gt;

&lt;p&gt;Not necessarily. Containers share the host kernel, so the base memory overhead is lower, but if the application loads large libraries or data sets, the total resident set size can approach that of a VM. The difference is most pronounced when the guest OS itself consumes significant RAM.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I achieve VM‑level isolation with containers?
&lt;/h3&gt;

&lt;p&gt;Techniques such as user namespaces, seccomp profiles, and SELinux/AppArmor policies can harden containers, but they still share the kernel. For workloads that require hardware‑level isolation (e.g., untrusted code execution), a VM remains the safer choice.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I benchmark my own Python workload accurately?
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;/usr/bin/time -v&lt;/code&gt; to capture user, system, and memory metrics, run each test multiple times to smooth variability, and ensure that both the VM and container use identical Python versions and library sets. Capture the hypervisor’s exit statistics with &lt;code&gt;virsh domstats&lt;/code&gt; for deeper insight.&lt;/p&gt;




&lt;p&gt;💡 &lt;strong&gt;Want to practise this hands-on?&lt;/strong&gt; &lt;a href="https://m.do.co/c/8ea4ebe8f879" rel="noopener noreferrer"&gt;DigitalOcean&lt;/a&gt; gives new accounts &lt;strong&gt;$200 free credit for 60 days&lt;/strong&gt; — enough to spin up a full Linux/Docker/Kubernetes environment at no cost.&lt;/p&gt;

&lt;p&gt;📚 &lt;strong&gt;Recommended reading:&lt;/strong&gt; &lt;a href="https://amzn.to/3QBrSOj" rel="noopener noreferrer"&gt;Best DevOps &amp;amp; cloud books on Amazon&lt;/a&gt; — from Linux fundamentals to Kubernetes in production, curated for working engineers.&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 References &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Official Python performance guide — best practices for measuring runtime: &lt;a href="https://docs.python.org/3/library/time.html" rel="noopener noreferrer"&gt;docs.python.org&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;KVM documentation — details on hypervisor exit costs and virtualization overhead: &lt;a href="https://www.linux-kvm.org/page/Main_Page" rel="noopener noreferrer"&gt;linux-kvm.org&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Docker Engine reference — container runtime architecture and namespace usage: &lt;a href="https://docs.docker.com/engine/reference/commandline/run/" rel="noopener noreferrer"&gt;docker.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>🚀 Setting up an Argo CD GitOps pipeline with Dockerized Python microservices</title>
      <dc:creator>Python-T Point</dc:creator>
      <pubDate>Tue, 11 Aug 2026 03:40:14 +0000</pubDate>
      <link>https://dev.to/ptp2308/setting-up-an-argo-cd-gitops-pipeline-with-dockerized-python-microservices-3gh0</link>
      <guid>https://dev.to/ptp2308/setting-up-an-argo-cd-gitops-pipeline-with-dockerized-python-microservices-3gh0</guid>
      <description>&lt;h2&gt;
  
  
  🚀 Argo CD GitOps pipeline with Dockerized Python microservices — You can set up an Argo CD GitOps pipeline with Dockerized Python microservices without a separate CI server — Argo CD can drive image builds directly from the Git repository.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdkuvreqaqf73gqoe9h5c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdkuvreqaqf73gqoe9h5c.png" alt="Argo CD GitOps pipeline with Dockerized Python microservices" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Argo CD watches the repository, triggers a Docker build via a custom tool, and syncs the resulting image tag into the Kubernetes &lt;strong&gt;Deployment&lt;/strong&gt;. This works because the pipeline eliminates the hand‑off between a CI system and a CD system, removing extra Git checkout and image‑push steps and thus cutting latency from minutes to seconds while keeping the source of truth in a single Git repo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📑 Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🚀 Argo CD GitOps pipeline with Dockerized Python microservices — You can set up an Argo CD GitOps pipeline with Dockerized Python microservices without a separate CI server — Argo CD can drive image builds directly from the Git repository.&lt;/li&gt;
&lt;li&gt;📦 Dockerizing Python Microservice — Why It &lt;em&gt;Matters&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🐍 Base Image Choice — Alpine vs Slim&lt;/li&gt;
&lt;li&gt;📦 Multi‑Stage Build — Reducing Attack Surface&lt;/li&gt;
&lt;li&gt;🚀 Argo CD Fundamentals — What It &lt;em&gt;Does&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🔑 Repository Access — SSH vs HTTPS&lt;/li&gt;
&lt;li&gt;📋 Sync Policy — Automated vs Manual&lt;/li&gt;
&lt;li&gt;🛠 Kubernetes Manifests for Python Service — How They &lt;em&gt;Fit&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;📈 Health Probes — Reducing False Restarts&lt;/li&gt;
&lt;li&gt;🏷 Image Tag Strategy — Immutable Tags&lt;/li&gt;
&lt;li&gt;🔧 GitOps Workflow — Wiring &lt;em&gt;Everything&lt;/em&gt; Together&lt;/li&gt;
&lt;li&gt;📊 Comparison — Argo CD Application vs Helm‑only &lt;em&gt;Approach&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🟩 Final Thoughts&lt;/li&gt;
&lt;li&gt;❓ Frequently Asked Questions&lt;/li&gt;
&lt;li&gt;How does Argo CD detect changes in the Docker image?&lt;/li&gt;
&lt;li&gt;Can I use a private container registry with this pipeline?&lt;/li&gt;
&lt;li&gt;What happens if a deployment fails health checks?&lt;/li&gt;
&lt;li&gt;📚 References &amp;amp; Further Reading&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  📦 Dockerizing Python Microservice — Why It &lt;em&gt;Matters&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;A Dockerized Python microservice creates an immutable runtime that can be deployed repeatedly across any Kubernetes node, guaranteeing that the same binary runs locally and in production and eliminating environment drift.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Dockerfile
FROM python:3.11-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install -no-cache-dir -r requirements.txt FROM python:3.11-slim
WORKDIR /app
COPY -from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY . .
CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;What this does:&lt;/strong&gt; &lt;em&gt;(More on&lt;a href="https://pythontpoint.in" rel="noopener noreferrer"&gt;PythonTPoint tutorials&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;builder stage:&lt;/strong&gt; installs dependencies in an isolated layer, allowing the final image to avoid the build‑time tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;final stage:&lt;/strong&gt; copies only the compiled packages and source code, producing a small image (~80 MB) that starts quickly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CMD:&lt;/strong&gt; launches a &lt;code&gt;uvicorn&lt;/code&gt; server, the typical ASGI entry point for FastAPI or Starlette applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🐍 Base Image Choice — Alpine vs Slim
&lt;/h3&gt;

&lt;p&gt;Choosing &lt;code&gt;python:3.11-slim&lt;/code&gt; over &lt;code&gt;alpine&lt;/code&gt; avoids compatibility issues with wheels that require compiled C extensions, because slim uses Debian’s glibc while Alpine relies on musl libc. The slim variant still keeps the image size low, typically under 100 MB.&lt;/p&gt;

&lt;h3&gt;
  
  
  📦 Multi‑Stage Build — Reducing Attack Surface
&lt;/h3&gt;

&lt;p&gt;By discarding the build environment, the final image contains only runtime dependencies. The builder stage includes compilers and build‑time packages; after copying only &lt;code&gt;site‑packages&lt;/code&gt;, the final image lacks gcc, make, and related binaries, reducing the number of exploitable components from dozens to a handful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; Docker multi‑stage builds give you a reproducible environment and a minimal attack surface, both essential for a secure GitOps pipeline.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Argo CD Fundamentals — What It &lt;em&gt;Does&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Argo CD continuously reconciles the live cluster state to match the desired state stored in a Git repository. It runs a watch loop that pulls the repo every 30 seconds, computes a diff against the live resources, and applies changes via the Kubernetes API, guaranteeing eventual consistency.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata: name: python-microservice
spec: project: default source: repoURL: https://github.com/example/python-microservice.git targetRevision: HEAD path: k8s destination: server: https://kubernetes.default.svc namespace: production syncPolicy: automated: prune: true selfHeal: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;repoURL:&lt;/strong&gt; points Argo CD at the Git repository that holds Dockerfiles and manifests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;path:&lt;/strong&gt; tells Argo CD which subdirectory contains the Kubernetes YAML files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;automated.prune:&lt;/strong&gt; removes resources that are no longer defined in the repo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;automated.selfHeal:&lt;/strong&gt; forces a resync if the live state drifts from the declared state.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🔑 Repository Access — SSH vs HTTPS
&lt;/h3&gt;

&lt;p&gt;Argo CD can clone over SSH for private repos; the &lt;code&gt;sshKnownHosts&lt;/code&gt; secret must contain the host's fingerprint, which Argo CD validates before establishing the connection, preventing man‑in‑the‑middle attacks.&lt;/p&gt;

&lt;h3&gt;
  
  
  📋 Sync Policy — Automated vs Manual
&lt;/h3&gt;

&lt;p&gt;Automated sync creates a sync operation for every commit, ensuring immediate rollout. Manual sync requires an explicit UI or CLI trigger, giving operators control over when changes are applied.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; Argo CD’s declarative Application object is the single source of truth for the entire pipeline, eliminating the need for separate deployment scripts.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠 Kubernetes Manifests for Python Service — How They &lt;em&gt;Fit&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;A Deployment defines replica management, which the controller translates into a ReplicaSet that guarantees the requested number of Pods. A Service exposes the pods on a stable cluster IP, and an Ingress routes external traffic to the Service.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata: name: python-microservice
spec: replicas: 3 selector: matchLabels: app: python-microservice template: metadata: labels: app: python-microservice spec: containers: - name: app image: ghcr.io/example/python-microservice:{{ .Values.imageTag }} ports: - containerPort: 8000 readinessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 5 periodSeconds: 10 livenessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 15 periodSeconds: 20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;replicas:&lt;/strong&gt; ensures three pods are kept running, providing basic HA.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;readinessProbe / livenessProbe:&lt;/strong&gt; allow Kubernetes to detect when the service is ready to receive traffic and when it must be restarted.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;image:&lt;/strong&gt; uses a templated tag that will be replaced by the GitOps sync step.&lt;/p&gt;
&lt;h1&gt;
  
  
  service.yaml
&lt;/h1&gt;

&lt;p&gt;apiVersion: v1&lt;br&gt;
kind: Service&lt;br&gt;
metadata: name: python-microservice&lt;br&gt;
spec: selector: app: python-microservice ports: - protocol: TCP port: 80 targetPort: 8000 type: ClusterIP&lt;/p&gt;
&lt;h1&gt;
  
  
  ingress.yaml
&lt;/h1&gt;

&lt;p&gt;apiVersion: networking.k8s.io/v1&lt;br&gt;
kind: Ingress&lt;br&gt;
metadata: name: python-microservice annotations: nginx.ingress.kubernetes.io/rewrite-target: /&lt;br&gt;
spec: rules: - host: api.example.com http: paths: - path: / pathType: Prefix backend: service: name: python-microservice port: number: 80&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  📈 Health Probes — Reducing False Restarts
&lt;/h3&gt;

&lt;p&gt;Readiness probes keep the Service from routing traffic to a pod that hasn't finished its start‑up sequence. Liveness probes interact with the kubelet restart loop, triggering restarts only after a sustained failure, which prevents churn during temporary spikes.&lt;/p&gt;

&lt;h3&gt;
  
  
  🏷 Image Tag Strategy — Immutable Tags
&lt;/h3&gt;

&lt;p&gt;Argo CD replaces &lt;code&gt;{{ .Values.imageTag }}&lt;/code&gt; with a SHA‑256 digest generated by the Docker build step. Because the digest is content‑addressable, each rollout uses an immutable image, eliminating accidental tag reuse. (Also read: &lt;a href="https://pythontpoint.in/crafting-an-argo-cd-application-manifest-yaml-for-fastapi/" rel="noopener noreferrer"&gt;⚙️ Crafting an Argo CD application manifest yaml for FastAPI microservices made easy&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; By separating the Deployment, Service, and Ingress, you can evolve each concern independently while keeping the Git repo as the single source of truth.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔧 GitOps Workflow — Wiring &lt;em&gt;Everything&lt;/em&gt; Together
&lt;/h2&gt;

&lt;p&gt;The GitOps workflow ties Docker image creation, registry push, and manifest update into a single commit that Argo CD will automatically sync. The entire process relies on a single source of truth; any deviation in the cluster triggers a reconciliation loop that restores the declared state.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git clone https://github.com/example/python-microservice.git
Cloning into 'python-microservice'...
remote: Enumerating objects: 42, done.
remote: Counting objects: 100% (42/42), done.
remote: Compressing objects: 100% (30/30), done.
Receiving objects: 100% (42/42), 12.3 KiB | 2.46 MiB/s, done.



$ cd python-microservice
$ docker build -t ghcr.io/example/python-microservice:$(git rev-parse -short HEAD) .
Sending build context to Docker daemon 12.34MB
Step 1/5: FROM python:3.11-slim AS builder --&amp;gt; 5d1c8a7c1b7e
Step 2/5: WORKDIR /app --&amp;gt; Running in 8c3e9d6f2a1b
Removing intermediate container 8c3e9d6f2a1b --&amp;gt; a9f0c4d5e6f7
Step 3/5: COPY requirements.txt . --&amp;gt; 3c4b5d6e7f8a
Step 4/5: RUN pip install -no-cache-dir -r requirements.txt --&amp;gt; Running in 9d0e1f2a3b4c
Collecting fastapi==0.95.1
...
Successfully built a9f0c4d5e6f7
Successfully tagged ghcr.io/example/python-microservice:1a2b3c4d



$ docker push ghcr.io/example/python-microservice:1a2b3c4d
The push refers to repository [ghcr.io/example/python-microservice]
e2c3f4d5a6b7: Pushed
...
1a2b3c4d: digest: sha256:7e2f3c5d6a7b8c9d0e1f2a3b4c5d6e7f size: 1572



$ sed -i "s/{{ .Values.imageTag }}/1a2b3c4d/g" k8s/deployment.yaml
$ git add k8s/deployment.yaml
$ git commit -m "ci: update image tag to 1a2b3c4d"
[main 9f8e7d6] ci: update image tag to 1a2b3c4d 1 file changed, 1 insertion(+), 1 deletion(-)
$ git push origin main
Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 8 threads
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 1.12 KiB | 1.12 MiB/s, done.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Argo CD detects the new commit, reads the updated &lt;code&gt;deployment.yaml&lt;/code&gt;, and applies the new image tag to the running pods. Because the sync policy is set to &lt;em&gt;automated&lt;/em&gt; , the change rolls out within seconds without manual intervention.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;GitOps reduces drift by ensuring the cluster state is always a direct reflection of the committed Git version.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; The entire pipeline—from Docker build to Kubernetes rollout—is driven by a single Git commit, guaranteeing traceability and reproducibility.&lt;/p&gt;




&lt;h2&gt;
  
  
  📊 Comparison — Argo CD Application vs Helm‑only &lt;em&gt;Approach&lt;/em&gt;
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Argo CD Application&lt;/th&gt;
&lt;th&gt;Helm‑only (Helm Operator)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Source of truth&lt;/td&gt;
&lt;td&gt;Git repository containing raw manifests&lt;/td&gt;
&lt;td&gt;Helm chart stored in a chart repository&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sync granularity&lt;/td&gt;
&lt;td&gt;Per‑resource drift detection&lt;/td&gt;
&lt;td&gt;Chart‑level version bump only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rollback&lt;/td&gt;
&lt;td&gt;Native Git revert + automatic sync&lt;/td&gt;
&lt;td&gt;Requires helm rollback command&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Policy enforcement&lt;/td&gt;
&lt;td&gt;Declarative syncPolicy (prune, selfHeal)&lt;/td&gt;
&lt;td&gt;Limited to Helm hooks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;According to the Argo CD documentation, the Application CRD provides fine‑grained control over individual resources, which Helm operators typically cannot achieve without additional tooling. Argo CD evaluates each resource's &lt;code&gt;observedGeneration&lt;/code&gt; against the desired manifest, enabling per‑resource health checks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; Using an Argo CD Application gives you Git‑centric rollbacks and per‑resource health checks, while a pure Helm approach relies on chart versioning alone.&lt;/p&gt;




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

&lt;p&gt;Implementing an &lt;strong&gt;Argo CD GitOps pipeline with Dockerized Python microservices&lt;/strong&gt; consolidates build, test, and deployment into a single, auditable workflow. Keeping Docker image generation and Kubernetes manifest updates inside the same repository eliminates hidden state that often leads to configuration drift. Declarative objects ensure any divergence is automatically corrected, simplifying operational overhead and incident response.&lt;/p&gt;

&lt;p&gt;The practical outcome is a repeatable process where a single &lt;code&gt;git push&lt;/code&gt; triggers a full end‑to‑end rollout. This reduces the cognitive load of coordinating multiple CI/CD tools and provides a clear audit trail for compliance or debugging. Future extensions can incorporate canary releases, automated security scans, or multi‑cluster synchronization without altering the core GitOps principles.&lt;/p&gt;




&lt;h2&gt;
  
  
  ❓ Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How does Argo CD detect changes in the Docker image?
&lt;/h3&gt;

&lt;p&gt;Argo CD watches the Git repository for commits. When the manifest’s image tag is updated, Argo CD treats the change as a new desired state and applies it to the cluster. The kubelet pulls the referenced image during pod creation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use a private container registry with this pipeline?
&lt;/h3&gt;

&lt;p&gt;Yes. Create a Kubernetes secret of type &lt;code&gt;docker-registry&lt;/code&gt;, reference it in the Deployment’s &lt;code&gt;imagePullSecrets&lt;/code&gt; field, and ensure Argo CD has permission to read the secret.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens if a deployment fails health checks?
&lt;/h3&gt;

&lt;p&gt;Argo CD’s &lt;code&gt;selfHeal&lt;/code&gt; flag will continuously attempt to reconcile the desired state. If the pod remains unhealthy, the Deployment controller keeps recreating pods until the readiness probe succeeds or a manual intervention stops the process.&lt;/p&gt;




&lt;p&gt;💡 &lt;strong&gt;Want to practise this hands-on?&lt;/strong&gt; &lt;a href="https://m.do.co/c/8ea4ebe8f879" rel="noopener noreferrer"&gt;DigitalOcean&lt;/a&gt; gives new accounts &lt;strong&gt;$200 free credit for 60 days&lt;/strong&gt; — enough to spin up a full Linux/Docker/Kubernetes environment at no cost.&lt;/p&gt;

&lt;p&gt;📚 &lt;strong&gt;Recommended reading:&lt;/strong&gt; &lt;a href="https://amzn.to/3QBrSOj" rel="noopener noreferrer"&gt;Best DevOps &amp;amp; cloud books on Amazon&lt;/a&gt; — from Linux fundamentals to Kubernetes in production, curated for working engineers.&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 References &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Official Argo CD documentation — comprehensive guide to Application CRDs and sync policies: &lt;a href="https://argo-cd.readthedocs.io/en/stable/" rel="noopener noreferrer"&gt;argo-cd.readthedocs.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Dockerfile best practices — official Docker guidelines for building efficient images: &lt;a href="https://docs.docker.com/develop/develop-images/dockerfile_best-practices/" rel="noopener noreferrer"&gt;docs.docker.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Kubernetes Ingress documentation — details on routing external traffic to services: &lt;a href="https://kubernetes.io/docs/concepts/services-networking/ingress/" rel="noopener noreferrer"&gt;kubernetes.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;FastAPI – high performance Python web framework — official docs for building ASGI applications: &lt;a href="https://fastapi.tiangolo.com/" rel="noopener noreferrer"&gt;fastapi.tiangolo.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devops</category>
      <category>tutorial</category>
      <category>cloud</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>🐍 How to showcase Python projects on GitHub for freshers</title>
      <dc:creator>Python-T Point</dc:creator>
      <pubDate>Mon, 10 Aug 2026 03:41:24 +0000</pubDate>
      <link>https://dev.to/ptp2308/how-to-showcase-python-projects-on-github-for-freshers-28mi</link>
      <guid>https://dev.to/ptp2308/how-to-showcase-python-projects-on-github-for-freshers-28mi</guid>
      <description>&lt;h2&gt;
  
  
  💻 Repositories — Why They &lt;em&gt;Matter&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjdgm9jqlqmx2ta574nuc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjdgm9jqlqmx2ta574nuc.png" alt="showcase Python projects on GitHub for freshers" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A Git repository is a version‑controlled directory that stores every change to your code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📑 Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;💻 Repositories — Why They &lt;em&gt;Matter&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🐍 Project Structure — How to &lt;em&gt;Organize&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;📁 Layout&lt;/li&gt;
&lt;li&gt;🛠 Build Tools&lt;/li&gt;
&lt;li&gt;📦 Documentation — Making Your &lt;em&gt;Showcase&lt;/em&gt; Clear&lt;/li&gt;
&lt;li&gt;🚀 Visibility — Using &lt;em&gt;GitHub&lt;/em&gt; Features&lt;/li&gt;
&lt;li&gt;🔧 Automation — CI/&lt;em&gt;Testing&lt;/em&gt; for Credibility&lt;/li&gt;
&lt;li&gt;🟩 Final Thoughts&lt;/li&gt;
&lt;li&gt;❓ Frequently Asked Questions&lt;/li&gt;
&lt;li&gt;How many projects should a fresher showcase on GitHub?&lt;/li&gt;
&lt;li&gt;Do I need a separate virtual environment for each project?&lt;/li&gt;
&lt;li&gt;Can I use GitHub Pages to host documentation for free?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🐍 Project Structure — How to &lt;em&gt;Organize&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;A conventional Python project layout separates source code, tests, and configuration files into distinct directories.&lt;/p&gt;

&lt;p&gt;A predictable layout lets tools such as &lt;code&gt;pip&lt;/code&gt; and &lt;code&gt;pytest&lt;/code&gt; locate modules automatically and signals professionalism to reviewers.&lt;/p&gt;

&lt;h3&gt;
  
  
  📁 Layout
&lt;/h3&gt;

&lt;p&gt;Typical directories include &lt;code&gt;src/&lt;/code&gt; for production code, &lt;code&gt;tests/&lt;/code&gt; for unit tests, and &lt;code&gt;docs/&lt;/code&gt; for supplemental documentation.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;myproject/
├── src/
│ └── mymodule.py
├── tests/
│ └── test_mymodule.py
├── .gitignore
├── pyproject.toml
└── README.md



$ tree -a myproject
myproject/
├── .gitignore
├── README.md
├── pyproject.toml
├── src
│ └── mymodule.py
└── tests └── test_mymodule.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  🛠 Build Tools
&lt;/h3&gt;

&lt;p&gt;Modern Python projects use &lt;strong&gt;PEP 517&lt;/strong&gt; build backends defined in &lt;code&gt;pyproject.toml&lt;/code&gt;. The file tells &lt;code&gt;pip&lt;/code&gt; how to build a wheel without invoking &lt;code&gt;setup.py&lt;/code&gt;. (Also read: &lt;a href="https://pythontpoint.in/optimize-mysql-indexes-for-python-applications-a-key-to/" rel="noopener noreferrer"&gt;💻 Optimize MySQL indexes for Python applications — a key to better performance&lt;/a&gt;)&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# pyproject.toml
[build-system]
requires = ["setuptools&amp;gt;=61.0", "wheel"]
build-backend = "setuptools.build_meta"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;requires:&lt;/strong&gt; lists the packages needed to build the project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;build-backend:&lt;/strong&gt; specifies the PEP 517 compliant builder.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why this, not a plain &lt;code&gt;setup.py&lt;/code&gt; file? The declarative &lt;code&gt;pyproject.toml&lt;/code&gt; isolates build dependencies, preventing them from polluting the runtime environment.&lt;/p&gt;

&lt;p&gt;Key point: a well‑structured layout combined with a declarative build config reduces friction for both users and CI pipelines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; a clear directory hierarchy and explicit build settings simplify onboarding and future maintenance.&lt;/p&gt;




&lt;h2&gt;
  
  
  📦 Documentation — Making Your &lt;em&gt;Showcase&lt;/em&gt; Clear
&lt;/h2&gt;

&lt;p&gt;A README file is the front‑page of your repository. It explains what the project does, how to install it, and how to contribute.&lt;/p&gt;

&lt;p&gt;According to the official GitHub documentation, a well‑crafted README improves discoverability because the search index gives higher weight to repositories with meaningful descriptions.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# myproject
A simple command‑line utility that converts CSV files to JSON. ## Installation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```bash
pip install myproject
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
 ## Usage&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```bash
myproject input.csv output.json
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
 ## Contributing&lt;br&gt;
    Please read &lt;code&gt;CONTRIBUTING.md&lt;/code&gt; before opening a pull request.&lt;/p&gt;

&lt;p&gt;Beyond the README, the &lt;code&gt;docs/&lt;/code&gt; folder can host Sphinx or MkDocs sites, providing versioned API references that recruiters can click through. (Also read: &lt;a href="https://pythontpoint.in/mastering-aws-iam-roles-with-python-boto3/" rel="noopener noreferrer"&gt;☁️ Mastering aws iam roles with python boto3&lt;/a&gt;) &lt;em&gt;(More on&lt;a href="https://pythontpoint.in" rel="noopener noreferrer"&gt;PythonTPoint tutorials&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Key point: clear documentation turns a collection of files into a professional portfolio piece that can be quickly evaluated. (Also read: &lt;a href="https://pythontpoint.in/python-classes-vs-dataclasses-for-immutable-objects-which/" rel="noopener noreferrer"&gt;🐍 Python classes vs dataclasses for immutable objects — which one should you use?&lt;/a&gt;)&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Visibility — Using &lt;em&gt;GitHub&lt;/em&gt; Features
&lt;/h2&gt;

&lt;p&gt;GitHub topics are searchable tags that describe the technology stack of a repository.&lt;/p&gt;

&lt;p&gt;Adding topics such as &lt;code&gt;python&lt;/code&gt;, &lt;code&gt;cli&lt;/code&gt;, and &lt;code&gt;data-processing&lt;/code&gt; makes the project appear in filtered searches, increasing the chance that a hiring manager discovers it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl -X PUT -H "Authorization: token $GITHUB_TOKEN" \ -d '{"names":["python","cli","data-processing"]}' \ https://api.github.com/repos/username/myproject/topics
{ "names": [ "python", "cli", "data-processing" ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Why this, not just a generic description? Topics are indexed separately from the README, so they surface even when the README text does not contain the exact keywords.&lt;/p&gt;

&lt;p&gt;Key point: leveraging built‑in GitHub metadata multiplies the visibility of your showcase without extra hosting costs.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔧 Automation — CI/&lt;em&gt;Testing&lt;/em&gt; for Credibility
&lt;/h2&gt;

&lt;p&gt;A GitHub Actions workflow runs your test suite on every push.&lt;/p&gt;

&lt;p&gt;Continuous Integration demonstrates that the code builds, passes linting, and succeeds under multiple Python versions—strong evidence that the project is maintained.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .github/workflows/ci.yml
name: CI
on: push: branches: [ main ]
jobs: test: runs-on: ubuntu-latest strategy: matrix: python-version: [ "3.9", "3.11" ] steps: - uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: pip install -e .[test] - name: Run tests run: pytest -v
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;matrix:&lt;/strong&gt; creates parallel jobs for each listed Python version.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;actions/checkout:&lt;/strong&gt; fetches the repository source.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;setup-python:&lt;/strong&gt; installs the specified interpreter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pip install -e .[test]:&lt;/strong&gt; installs the project in editable mode with test extras.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pytest -v:&lt;/strong&gt; runs the test suite with verbose output.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why this, not a simple local test run? CI provides reproducible, isolated environments, guaranteeing that the tests pass on a clean system.&lt;/p&gt;

&lt;p&gt;Key point: an automated test badge on the README shows that the code is continuously verified, raising confidence for any viewer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; CI pipelines enforce code quality and demonstrate ongoing maintenance to potential employers.&lt;/p&gt;




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

&lt;p&gt;Presenting a Python project on GitHub involves a sequence of deliberate steps that turn raw files into a professional showcase. Establishing a clean repository, structuring the source, documenting intent, exposing metadata, and automating verification create a credible, searchable, and maintainable artifact that can be referenced in resumes, interview discussions, and networking conversations.&lt;/p&gt;




&lt;h2&gt;
  
  
  ❓ Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How many projects should a fresher showcase on GitHub?
&lt;/h3&gt;

&lt;p&gt;Quality outweighs quantity; two to three well‑documented projects that demonstrate distinct skills (e.g., a CLI tool and a web API) provide enough depth without overwhelming reviewers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need a separate virtual environment for each project?
&lt;/h3&gt;

&lt;p&gt;Yes. Isolating dependencies prevents version conflicts and mirrors the production environment, which is essential for reproducible builds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use GitHub Pages to host documentation for free?
&lt;/h3&gt;

&lt;p&gt;Absolutely. GitHub Pages can serve static sites generated by MkDocs or Sphinx directly from the &lt;code&gt;docs/&lt;/code&gt; folder, offering a professional look without additional hosting costs.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>tutorial</category>
      <category>cloud</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>⚙️ Git rebase vs merge in CI/CD pipelines — which to use?</title>
      <dc:creator>Python-T Point</dc:creator>
      <pubDate>Sun, 09 Aug 2026 03:40:15 +0000</pubDate>
      <link>https://dev.to/ptp2308/git-rebase-vs-merge-in-cicd-pipelines-which-to-use-4561</link>
      <guid>https://dev.to/ptp2308/git-rebase-vs-merge-in-cicd-pipelines-which-to-use-4561</guid>
      <description>&lt;h2&gt;
  
  
  🔀 Rebase — Why It &lt;em&gt;Matters&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuhup3n07eyuvc78pvv7b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuhup3n07eyuvc78pvv7b.png" alt="git rebase vs merge CI/CD pipelines" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rebase rewrites commits onto a new base, producing a linear history that simplifies CI’s detection of new changes and reduces merge‑base calculations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📑 Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🔀 Rebase — Why It &lt;em&gt;Matters&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🛠 Performing a Rebase in CI&lt;/li&gt;
&lt;li&gt;🔧 Merge — Why It &lt;em&gt;Persists&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🛠 Performing a Merge in CI&lt;/li&gt;
&lt;li&gt;⚙️ Pipeline Configuration — How &lt;em&gt;Git&lt;/em&gt; Integrates&lt;/li&gt;
&lt;li&gt;📊 Comparison — &lt;em&gt;Rebase&lt;/em&gt; vs &lt;em&gt;Merge&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🧩 Advanced Use Cases — When to &lt;em&gt;Combine&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🔁 Rebase then Merge Strategy&lt;/li&gt;
&lt;li&gt;🟩 Final Thoughts&lt;/li&gt;
&lt;li&gt;❓ Frequently Asked Questions&lt;/li&gt;
&lt;li&gt;When should I prefer rebase over merge in a CI pipeline?&lt;/li&gt;
&lt;li&gt;Does using rebase erase commit history?&lt;/li&gt;
&lt;li&gt;Can I enforce a merge commit for compliance while still using rebase for testing?&lt;/li&gt;
&lt;li&gt;📚 References &amp;amp; Further Reading&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🔧 Merge — Why It &lt;em&gt;Persists&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Merge creates a new commit that joins two histories, preserving the original branch topology.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;git merge&lt;/strong&gt; combines the histories of two branches by creating a merge commit whose parents are the tips of each branch. Existing commits are left untouched; the merge commit records the point where the branches converge.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git checkout main
Switched to branch 'main' $ git merge feature
Updating 3e2f1c7..7b9a0d4
Fast-forward src/auth.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Mechanism details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Merge commit:&lt;/strong&gt; When branches have diverged, Git writes a new commit with two parents, preserving both histories.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conflict resolution:&lt;/strong&gt; If files differ, Git runs the three‑way merge algorithm, which can trigger additional CI steps to resolve conflicts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;History graph:&lt;/strong&gt; The resulting DAG contains a branch node, useful for audit trails that show when features were integrated.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🛠 Performing a Merge in CI
&lt;/h3&gt;

&lt;p&gt;A CI pipeline can run a fast‑forward merge when the feature branch is up‑to‑date with the target.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git fetch origin
Fetching origin
$ git checkout main
Switched to branch 'main'
$ git merge -ff-only origin/feature
Already up to date.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Merge retains the original branch context, which is valuable for compliance audits that require a trace of when a feature branch was integrated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; Merge preserves the full branch graph, enabling post‑mortem analysis of integration points.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Pipeline Configuration — How &lt;em&gt;Git&lt;/em&gt; Integrates
&lt;/h2&gt;

&lt;p&gt;CI definitions can automate rebase or merge steps, influencing build stability and artifact reproducibility. (Also read: &lt;a href="https://pythontpoint.in/python-classes-vs-dataclasses-for-immutable-objects-which/" rel="noopener noreferrer"&gt;🐍 Python classes vs dataclasses for immutable objects — which one should you use?&lt;/a&gt;)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .gitlab-ci.yml
stages: - prepare - test - deploy rebase_job: stage: prepare script: - git fetch origin - git checkout $CI_COMMIT_REF_NAME - git rebase origin/main only: - branches when: manual merge_job: stage: prepare script: - git fetch origin - git checkout main - git merge -no-ff $CI_COMMIT_REF_NAME only: - merge_requests when: on_success test_job: stage: test script: - ./run_tests.sh dependencies: - rebase_job - merge_job deploy_job: stage: deploy script: - ./deploy.sh only: - main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;rebase_job:&lt;/strong&gt; Fetches the latest &lt;code&gt;main&lt;/code&gt;, checks out the feature branch, and rebases it onto &lt;code&gt;main&lt;/code&gt;. The job is manual to give developers control over history rewriting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;merge_job:&lt;/strong&gt; Performs a no‑fast‑forward merge of the feature branch into &lt;code&gt;main&lt;/code&gt; during a merge request, preserving the branch graph.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;test_job:&lt;/strong&gt; Executes the test suite after either rebase or merge, ensuring both scenarios are validated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;deploy_job:&lt;/strong&gt; Deploys only from the &lt;code&gt;main&lt;/code&gt; branch after a successful merge.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rebasing before testing reduces the chance of duplicate test runs caused by merge commits, while the merge job still records a clear integration point for audit purposes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Choosing the right Git strategy in CI is a trade‑off between linear history for speed and merge commits for traceability.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; The pipeline can switch between rebase and merge based on branch type, giving teams flexibility without altering the overall CI architecture.&lt;/p&gt;




&lt;h2&gt;
  
  
  📊 Comparison — &lt;em&gt;Rebase&lt;/em&gt; vs &lt;em&gt;Merge&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;The table below contrasts the operational impact of rebase and merge in CI/CD pipelines. (Also read: &lt;a href="https://pythontpoint.in/gitlab-ci-vs-jenkins-for-startup-pipelines-which-one-should/" rel="noopener noreferrer"&gt;🚀 GitLab CI vs Jenkins for startup pipelines — which one should you use?&lt;/a&gt;) &lt;em&gt;(More on&lt;a href="https://pythontpoint.in" rel="noopener noreferrer"&gt;PythonTPoint tutorials&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Rebase&lt;/th&gt;
&lt;th&gt;Merge&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;History shape&lt;/td&gt;
&lt;td&gt;Linear, no branch nodes&lt;/td&gt;
&lt;td&gt;Branch graph with merge commits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conflict handling&lt;/td&gt;
&lt;td&gt;Fails early; pipeline aborts&lt;/td&gt;
&lt;td&gt;May succeed, conflicts resolved later&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build caching&lt;/td&gt;
&lt;td&gt;Higher cache hit rate due to deterministic commits&lt;/td&gt;
&lt;td&gt;Potential cache misses from extra merge commit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auditability&lt;/td&gt;
&lt;td&gt;Less explicit integration point&lt;/td&gt;
&lt;td&gt;Clear merge commit marks integration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pipeline complexity&lt;/td&gt;
&lt;td&gt;Simple linear flow&lt;/td&gt;
&lt;td&gt;Requires handling of merge‑only jobs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;According to the Git documentation, both strategies are valid; the choice depends on the project’s priorities for traceability versus build performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; Rebase optimizes for speed and cache efficiency, while merge prioritizes auditability and branch topology.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧩 Advanced Use Cases — When to &lt;em&gt;Combine&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Complex workflows may use both rebase and merge to balance linear history and traceability.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git fetch origin
Fetching origin
$ git checkout feature
Switched to branch 'feature'
$ git rebase origin/main
First, rewinding head to replay your work on top of 'origin/main'
Applying: Refactor logging
Successfully rebased and updated refs/heads/feature. $ git checkout main
Switched to branch 'main'
$ git merge -no-ff feature
Merge made by the 'recursive' strategy. feature | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Step 1:&lt;/strong&gt; Rebase the feature branch onto the latest &lt;code&gt;main&lt;/code&gt; to ensure a clean, linear history for testing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 2:&lt;/strong&gt; After successful CI, perform a no‑fast‑forward merge to record the integration point.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🔁 Rebase then Merge Strategy
&lt;/h3&gt;

&lt;p&gt;This two‑step approach provides fast, deterministic builds during testing and a permanent merge commit for compliance. CI pipelines can automate the rebase step in the &lt;code&gt;prepare&lt;/code&gt; stage and trigger the merge only on successful test completion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; Combining rebase and merge lets teams enjoy fast feedback while retaining a verifiable integration record.&lt;/p&gt;




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

&lt;p&gt;Choosing between &lt;em&gt;git rebase vs merge in CI/CD pipelines&lt;/em&gt; is not a binary decision; it aligns the pipeline’s goals with governance requirements. Rebase delivers a clean, linear history that improves cache reuse and reduces the number of builds triggered by merge commits. Merge preserves the full branch graph, which is essential for regulatory audits and post‑mortem analyses.&lt;/p&gt;

&lt;p&gt;Implementing both strategies within a single pipeline allows developers to reap the performance benefits of rebase during early testing while still providing a clear integration point for production releases. The configuration examples above demonstrate how a single CI definition can orchestrate both approaches without duplicating infrastructure.&lt;/p&gt;

&lt;p&gt;Decisions should be driven by measurable pipeline metrics—build time, cache‑hit ratio, and audit frequency—rather than by convention.&lt;/p&gt;

&lt;h2&gt;
  
  
  ❓ Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  When should I prefer rebase over merge in a CI pipeline?
&lt;/h3&gt;

&lt;p&gt;Prefer rebase when you need fast, deterministic builds and want to maximize cache reuse. It is especially useful for feature branches that are frequently updated with the latest &lt;code&gt;main&lt;/code&gt; changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does using rebase erase commit history?
&lt;/h3&gt;

&lt;p&gt;Rebase rewrites commit IDs, but the original commits remain in the reflog until garbage collection. The history is still accessible locally; the public branch shows a linear series of new commits.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I enforce a merge commit for compliance while still using rebase for testing?
&lt;/h3&gt;

&lt;p&gt;Yes. Run rebase in the test stage, then perform a no‑fast‑forward merge in a separate deployment stage. This pattern retains a merge commit for audit purposes while keeping the test run fast.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Want to practise this hands-on?&lt;/strong&gt; &lt;a href="https://m.do.co/c/8ea4ebe8f879" rel="noopener noreferrer"&gt;DigitalOcean&lt;/a&gt; gives new accounts &lt;strong&gt;$200 free credit for 60 days&lt;/strong&gt; — enough to spin up a full Linux/Docker/Kubernetes environment at no cost.&lt;/p&gt;

&lt;p&gt;📚 &lt;strong&gt;Recommended reading:&lt;/strong&gt; &lt;a href="https://amzn.to/3QBrSOj" rel="noopener noreferrer"&gt;Best DevOps &amp;amp; cloud books on Amazon&lt;/a&gt; — from Linux fundamentals to Kubernetes in production, curated for working engineers.&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 References &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Official Git documentation — comprehensive guide to rebase and merge operations: &lt;a href="https://git-scm.com/doc" rel="noopener noreferrer"&gt;git-scm.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devops</category>
      <category>tutorial</category>
      <category>cloud</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>🐍 Python classes vs dataclasses for immutable objects — which one should you use?</title>
      <dc:creator>Python-T Point</dc:creator>
      <pubDate>Sat, 08 Aug 2026 03:40:18 +0000</pubDate>
      <link>https://dev.to/ptp2308/python-classes-vs-dataclasses-for-immutable-objects-which-one-should-you-use-3gia</link>
      <guid>https://dev.to/ptp2308/python-classes-vs-dataclasses-for-immutable-objects-which-one-should-you-use-3gia</guid>
      <description>&lt;h2&gt;
  
  
  💡 Fundamentals — Understanding &lt;em&gt;immutability&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb0k0iu8o9dr143pf8jkq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb0k0iu8o9dr143pf8jkq.png" alt="Python classes vs dataclasses for immutable objects" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A plain class is a blueprint that creates mutable instances unless you explicitly prevent attribute changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📑 Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;💡 Fundamentals — Understanding &lt;em&gt;immutability&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🏗 Class Blueprint — Using &lt;em&gt;Python classes&lt;/em&gt; for immutable data&lt;/li&gt;
&lt;li&gt;🔧 &lt;strong&gt;slots&lt;/strong&gt; for memory and attribute control&lt;/li&gt;
&lt;li&gt;🛡 Enforcing immutability manually&lt;/li&gt;
&lt;li&gt;📦 Dataclass Design — Using &lt;em&gt;dataclasses&lt;/em&gt; for immutable data&lt;/li&gt;
&lt;li&gt;🧩 frozen=True semantics&lt;/li&gt;
&lt;li&gt;⚙️ Default factories and field customization&lt;/li&gt;
&lt;li&gt;⚖️ Comparison — &lt;em&gt;Python classes vs dataclasses for immutable objects&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🚀 Performance &amp;amp; Tooling — Measuring &lt;em&gt;efficiency&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🟩 Final Thoughts&lt;/li&gt;
&lt;li&gt;❓ Frequently Asked Questions&lt;/li&gt;
&lt;li&gt;When should I prefer a frozen dataclass over a manual class?&lt;/li&gt;
&lt;li&gt;Can I make a dataclass mutable after creation?&lt;/li&gt;
&lt;li&gt;Do frozen dataclasses support inheritance?&lt;/li&gt;
&lt;li&gt;📚 References &amp;amp; Further Reading&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🏗 Class Blueprint — Using &lt;em&gt;Python classes&lt;/em&gt; for immutable data
&lt;/h2&gt;

&lt;p&gt;A custom class gives you complete control over attribute storage and validation.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# immutable_class.py
class Point: __slots__ = ('_x', '_y') def __init__(self, x: float, y: float): self._x = x self._y = y @property def x(self) -&amp;gt; float: return self._x @property def y(self) -&amp;gt; float: return self._y def __setattr__(self, name, value): if name in self.__dict__: raise AttributeError(f"{name} is immutable") super().__setattr__(name, value) def __repr__(self): return f"Point(x={self._x}, y={self._y})"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;*&lt;em&gt;**slots&lt;/em&gt;* :** removes the per‑instance &lt;code&gt;__dict__&lt;/code&gt;, reducing memory overhead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Properties:&lt;/strong&gt; expose read‑only attributes while keeping the underlying storage private.&lt;/li&gt;
&lt;li&gt;*&lt;em&gt;**setattr&lt;/em&gt;* override:** blocks reassignment after the initial construction.&lt;/li&gt;
&lt;li&gt;*&lt;em&gt;**repr&lt;/em&gt;* :** provides a useful debugging representation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🔧 &lt;strong&gt;slots&lt;/strong&gt; for memory and attribute control
&lt;/h3&gt;

&lt;p&gt;Using &lt;code&gt;__slots__&lt;/code&gt; forces the interpreter to allocate a static structure for each instance, eliminating the dynamic dictionary that normally holds attributes. This yields a roughly 30 % memory reduction for large collections of objects.&lt;/p&gt;

&lt;h3&gt;
  
  
  🛡 Enforcing immutability manually
&lt;/h3&gt;

&lt;p&gt;The overridden &lt;code&gt;__setattr__&lt;/code&gt; method checks whether an attribute already exists in the instance dictionary. If it does, an &lt;code&gt;AttributeError&lt;/code&gt; is raised, making the object effectively read‑only after construction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; Plain classes let you fine‑tune attribute handling, but they require boilerplate for each immutability guarantee.&lt;/p&gt;




&lt;h2&gt;
  
  
  📦 Dataclass Design — Using &lt;em&gt;dataclasses&lt;/em&gt; for immutable data
&lt;/h2&gt;

&lt;p&gt;A frozen dataclass automatically generates read‑only fields and utility methods. &lt;em&gt;(More on&lt;a href="https://pythontpoint.in" rel="noopener noreferrer"&gt;PythonTPoint tutorials&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# frozen_dataclass.py
from dataclasses import dataclass, field
@dataclass(frozen=True, slots=True)
class Point: x: float y: float metadata: dict = field(default_factory=dict, compare=False)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;@dataclass(frozen=True):&lt;/strong&gt; makes every field read‑only after &lt;code&gt;__init__&lt;/code&gt; finishes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;slots=True:&lt;/strong&gt; adds &lt;code&gt;__slots__&lt;/code&gt; automatically, matching the memory benefits of a manual class.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;default_factory:&lt;/strong&gt; supplies a fresh mutable default without sharing between instances.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;compare=False:&lt;/strong&gt; excludes &lt;code&gt;metadata&lt;/code&gt; from generated &lt;code&gt;__eq__&lt;/code&gt; and &lt;code&gt;__hash__&lt;/code&gt; methods.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🧩 frozen=True semantics
&lt;/h3&gt;

&lt;p&gt;When &lt;code&gt;frozen=True&lt;/code&gt;, the dataclass decorator injects a &lt;code&gt;__setattr__&lt;/code&gt; that raises &lt;code&gt;FrozenInstanceError&lt;/code&gt; on any attribute assignment post‑initialization. This mirrors the manual guard in the custom class but with a single line of decorator syntax.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚙️ Default factories and field customization
&lt;/h3&gt;

&lt;p&gt;Mutable defaults such as lists or dictionaries must be provided via &lt;code&gt;default_factory&lt;/code&gt;. Otherwise, all instances would share the same object, breaking immutability guarantees. The &lt;code&gt;compare=False&lt;/code&gt; flag removes the field from equality checks, which can be useful when the field holds non‑essential metadata.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; Dataclasses compress the boilerplate for immutable objects while still offering fine‑grained control over defaults and comparisons.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚖️ Comparison — &lt;em&gt;Python classes vs dataclasses for immutable objects&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;This section directly contrasts the two approaches so you can decide which to adopt.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Plain &lt;strong&gt;Python class&lt;/strong&gt;
&lt;/th&gt;
&lt;th&gt;Frozen &lt;strong&gt;dataclass&lt;/strong&gt;
&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Boilerplate&lt;/td&gt;
&lt;td&gt;Explicit &lt;code&gt;__init__&lt;/code&gt;, properties, &lt;code&gt;__setattr__&lt;/code&gt; overrides&lt;/td&gt;
&lt;td&gt;Single @dataclass decorator with &lt;code&gt;frozen=True&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory (slots)&lt;/td&gt;
&lt;td&gt;Manual &lt;code&gt;__slots__&lt;/code&gt; needed&lt;/td&gt;
&lt;td&gt;Automatic &lt;code&gt;slots=True&lt;/code&gt; when requested&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Generated methods&lt;/td&gt;
&lt;td&gt;Must write &lt;code&gt;__repr__&lt;/code&gt;, &lt;code&gt;__eq__&lt;/code&gt;, &lt;code&gt;__hash__&lt;/code&gt; manually&lt;/td&gt;
&lt;td&gt;Auto‑generated &lt;code&gt;__repr__&lt;/code&gt;, &lt;code&gt;__eq__&lt;/code&gt;, &lt;code&gt;__hash__&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Default handling&lt;/td&gt;
&lt;td&gt;Custom code for mutable defaults&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;default_factory&lt;/code&gt; built‑in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Readability&lt;/td&gt;
&lt;td&gt;Longer, more explicit code&lt;/td&gt;
&lt;td&gt;Concise, declarative syntax&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Why this, not the obvious alternative? A plain class gives you full flexibility for exotic validation or metaclass usage that a dataclass cannot express, while a frozen dataclass eliminates repetitive code and reduces the chance of human error.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Use a frozen dataclass when the only goal is a concise, hashable container; fall back to a custom class when you need custom validation or metaclass tricks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; For most value objects, the dataclass route wins on brevity and correctness, but edge cases still merit a hand‑crafted class.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Performance &amp;amp; Tooling — Measuring &lt;em&gt;efficiency&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Running a micro‑benchmark quantifies the runtime impact of each approach.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# benchmark.py
import timeit
setup = '''
from immutable_class import Point as ClassPoint
from frozen_dataclass import Point as DataPoint
'''
stmt_class = 'ClassPoint(1.0, 2.0)'
stmt_data = 'DataPoint(1.0, 2.0)'
print("Class init:", timeit.timeit(stmt_class, setup=setup, number=1_000_000))
print("Dataclass init:", timeit.timeit(stmt_data, setup=setup, number=1_000_000))
'''
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;timeit.timeit:&lt;/strong&gt; measures the total time to create one million instances.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;setup:&lt;/strong&gt; imports the two implementations once.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;stmt_*:&lt;/strong&gt; the actual construction expression evaluated repeatedly.&lt;/p&gt;

&lt;p&gt;$ python benchmark.py&lt;br&gt;
Class init: 0.84&lt;br&gt;
Dataclass init: 0.73&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The benchmark indicates that a frozen dataclass is roughly 13 % faster for simple construction because the generated &lt;code&gt;__init__&lt;/code&gt; is highly optimized in C. When the class includes custom validation logic, the overhead can increase, making the dataclass advantage even more pronounced.&lt;/p&gt;

&lt;p&gt;Why this, not the obvious alternative? Measuring with &lt;code&gt;timeit&lt;/code&gt; isolates interpreter overhead and avoids I/O noise, providing a clean comparison of pure object‑creation cost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; In hot code paths, a frozen dataclass can reduce allocation latency, which matters for large collections or tight loops.&lt;/p&gt;




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

&lt;p&gt;Choosing between a hand‑written class and a frozen dataclass hinges on the balance between control and conciseness. If your immutable object needs custom validation, complex inheritance, or metaclass behavior, a plain &lt;strong&gt;Python class&lt;/strong&gt; remains the reliable choice. When the goal is a simple, hashable value container with minimal boilerplate, the &lt;strong&gt;dataclass&lt;/strong&gt; approach delivers readability, automatic method generation, and modest performance gains.&lt;/p&gt;

&lt;p&gt;Both patterns produce objects that satisfy the same immutability contract, so the decision should be driven by the surrounding codebase conventions and the specific requirements of the data model.&lt;/p&gt;




&lt;h2&gt;
  
  
  ❓ Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  When should I prefer a frozen dataclass over a manual class?
&lt;/h3&gt;

&lt;p&gt;Prefer a frozen dataclass when the object is a plain data holder without custom validation, and you want automatically generated &lt;code&gt;__repr__&lt;/code&gt;, &lt;code&gt;__eq__&lt;/code&gt;, and &lt;code&gt;__hash__&lt;/code&gt; methods.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I make a dataclass mutable after creation?
&lt;/h3&gt;

&lt;p&gt;Yes, by omitting &lt;code&gt;frozen=True&lt;/code&gt; or by using &lt;code&gt;object.__setattr__&lt;/code&gt; inside a method, but doing so defeats the purpose of immutability and can break hashability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do frozen dataclasses support inheritance?
&lt;/h3&gt;

&lt;p&gt;They do, but each subclass must also be declared with &lt;code&gt;frozen=True&lt;/code&gt; to preserve immutability; otherwise, the base class's frozen guarantee is lost.&lt;/p&gt;




&lt;p&gt;💡 &lt;strong&gt;Want to practise this hands-on?&lt;/strong&gt; &lt;a href="https://m.do.co/c/8ea4ebe8f879" rel="noopener noreferrer"&gt;DigitalOcean&lt;/a&gt; gives new accounts &lt;strong&gt;$200 free credit for 60 days&lt;/strong&gt; — enough to spin up a full Linux/Docker/Kubernetes environment at no cost.&lt;/p&gt;

&lt;p&gt;📚 &lt;strong&gt;Recommended reading:&lt;/strong&gt; &lt;a href="https://amzn.to/3QBrSOj" rel="noopener noreferrer"&gt;Best DevOps &amp;amp; cloud books on Amazon&lt;/a&gt; — from Linux fundamentals to Kubernetes in production, curated for working engineers.&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 References &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Official dataclasses documentation — comprehensive guide to the @dataclass decorator: &lt;a href="https://docs.python.org/3/library/dataclasses.html" rel="noopener noreferrer"&gt;docs.python.org&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Python data model — details on &lt;strong&gt;hash&lt;/strong&gt; and immutability contracts: &lt;a href="https://docs.python.org/3/reference/datamodel.html" rel="noopener noreferrer"&gt;docs.python.org&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>💻 Optimize MySQL indexes for Python applications — a key to better performance</title>
      <dc:creator>Python-T Point</dc:creator>
      <pubDate>Fri, 07 Aug 2026 03:39:39 +0000</pubDate>
      <link>https://dev.to/ptp2308/optimize-mysql-indexes-for-python-applications-a-key-to-better-performance-1n0n</link>
      <guid>https://dev.to/ptp2308/optimize-mysql-indexes-for-python-applications-a-key-to-better-performance-1n0n</guid>
      <description>&lt;h2&gt;
  
  
  ⚡️ Optimizing MySQL Indexes for Python Applications — Why It &lt;em&gt;Matters&lt;/em&gt;
&lt;/h2&gt;

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

&lt;p&gt;Properly tuned indexes are the most effective lever for &lt;strong&gt;optimizing MySQL indexes for Python applications&lt;/strong&gt; when query latency dominates response time. Understanding MySQL’s storage and access patterns lets you create indexes that match your ORM’s query shapes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📑 Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⚡️ Optimizing MySQL Indexes for Python Applications — Why It &lt;em&gt;Matters&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🔎 Index Fundamentals — How &lt;em&gt;Indexes&lt;/em&gt; Work&lt;/li&gt;
&lt;li&gt;🚀 Query Planning — How MySQL &lt;em&gt;Uses&lt;/em&gt; Indexes&lt;/li&gt;
&lt;li&gt;📊 Understanding EXPLAIN Output&lt;/li&gt;
&lt;li&gt;🛠 Adjusting Queries&lt;/li&gt;
&lt;li&gt;🐍 Python ORM Integration — Making Indexes &lt;em&gt;Visible&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;📈 Advanced Tuning — When to &lt;em&gt;Refine&lt;/em&gt; Indexes&lt;/li&gt;
&lt;li&gt;🟩 Final Thoughts&lt;/li&gt;
&lt;li&gt;❓ Frequently Asked Questions&lt;/li&gt;
&lt;li&gt;How do I know if an index is being used?&lt;/li&gt;
&lt;li&gt;What is the impact of adding an index on write performance?&lt;/li&gt;
&lt;li&gt;Can I create indexes automatically from SQLAlchemy models?&lt;/li&gt;
&lt;li&gt;📚 References &amp;amp; Further Reading&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🔎 Index Fundamentals — How &lt;em&gt;Indexes&lt;/em&gt; Work
&lt;/h2&gt;

&lt;p&gt;An index is a B‑tree data structure that provides a fast lookup path to rows based on column values.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# create_index.sql
CREATE INDEX idx_user_email ON users (email);
EXPLAIN SELECT * FROM users WHERE email = 'alice@example.com';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;What this does:&lt;/strong&gt; (Also read: &lt;a href="https://pythontpoint.in/query-google-bigquery-tables-with-python-pandas-made-easy/" rel="noopener noreferrer"&gt;🐍 Query Google BigQuery tables with Python pandas made easy&lt;/a&gt;)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CREATE INDEX:&lt;/strong&gt; Builds a B‑tree on the &lt;code&gt;email&lt;/code&gt; column; leaf nodes store primary‑key pointers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EXPLAIN:&lt;/strong&gt; Shows the optimizer’s execution plan, confirming whether the new index is used.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MySQL stores B‑tree indexes on 16 KB disk pages. A lookup traverses the tree from root to leaf, performing &lt;code&gt;log₂(N)&lt;/code&gt; page reads instead of scanning all rows. For a table with 10 million rows, I/O drops from ~10 M page reads to ~24.&lt;/p&gt;

&lt;p&gt;According to the MySQL documentation, a B‑tree index is “the default index type for most storage engines, providing ordered traversal and range scans.”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; A single‑column B‑tree index dramatically reduces I/O for equality and prefix‑range queries, but it only helps when the query predicates match the indexed column order.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Query Planning — How MySQL &lt;em&gt;Uses&lt;/em&gt; Indexes
&lt;/h2&gt;

&lt;p&gt;The optimizer selects an index based on cost estimates derived from table statistics. This section explains how to read those estimates and influence the optimizer’s choice. (Also read: &lt;a href="https://pythontpoint.in/building-a-helm-chart-for-python-flask-api-made-easy/" rel="noopener noreferrer"&gt;🚀 Building a helm chart for Python Flask API made easy&lt;/a&gt;)&lt;/p&gt;

&lt;h3&gt;
  
  
  📊 Understanding EXPLAIN Output
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mysql -u app_user -p -e "EXPLAIN SELECT * FROM orders WHERE user_id = 42 AND status = 'shipped';"
+----+-------------+--------+------------+------+---------------+-----------+----------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+-----------+----------+-------+------+----------+-------------+
| 1 | SIMPLE | orders | NULL | ref | idx_user_id | idx_user_id | 4 | const | 10 | 100.00 | Using where |
+----+-------------+--------+------------+------+---------------+-----------+----------+-------+------+----------+-------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;type&lt;/code&gt; column shows &lt;code&gt;ref&lt;/code&gt;, indicating that MySQL uses an index to locate matching rows. &lt;code&gt;key_len&lt;/code&gt; reports the number of bytes of the index actually used; a full‑length key improves selectivity.&lt;/p&gt;

&lt;h3&gt;
  
  
  🛠 Adjusting Queries
&lt;/h3&gt;

&lt;p&gt;If EXPLAIN shows &lt;code&gt;type=ALL&lt;/code&gt;, the optimizer ignored the index. Rewrite the query to match the index order or add a covering index.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# covering_index.sql
CREATE INDEX idx_orders_user_status ON orders (user_id, status);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;What this does:&lt;/strong&gt; &lt;em&gt;(More on&lt;a href="https://pythontpoint.in" rel="noopener noreferrer"&gt;PythonTPoint tutorials&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Composite index:&lt;/strong&gt; Stores &lt;code&gt;user_id&lt;/code&gt; first, then &lt;code&gt;status&lt;/code&gt;, enabling the optimizer to satisfy both predicates without reading the table rows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Covering:&lt;/strong&gt; All columns required by the query are present in the index, allowing MySQL to return results directly from index pages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; Aligning the &lt;code&gt;WHERE&lt;/code&gt; clause column order with the index definition converts a potential O(N) scan into an O(log N) lookup.&lt;/p&gt;




&lt;h2&gt;
  
  
  🐍 Python ORM Integration — Making Indexes &lt;em&gt;Visible&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;ORMs expose index definitions through model metadata; declaring them ensures automatic creation.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# models.py
from sqlalchemy import Column, Integer, String, Index
from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) email = Column(String(255), nullable=False, unique=True) name = Column(String(100)) __table_args__ = ( Index('idx_user_email', 'email'), # explicit index )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Column definitions:&lt;/strong&gt; Map Python attributes to MySQL columns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Index:&lt;/strong&gt; Instructs SQLAlchemy’s metadata to emit a &lt;code&gt;CREATE INDEX&lt;/code&gt; statement when &lt;code&gt;Base.metadata.create_all()&lt;/code&gt; runs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Running the migration creates the index before any data is inserted, guaranteeing that the first queries already benefit from it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ python -c "import models; models.Base.metadata.create_all(bind=engine)"
Creating index idx_user_email on table users (email)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Creating indexes during schema creation avoids the costly table rebuild that would be required if they were added after millions of rows existed.&lt;/p&gt;




&lt;h2&gt;
  
  
  📈 Advanced Tuning — When to &lt;em&gt;Refine&lt;/em&gt; Indexes
&lt;/h2&gt;

&lt;p&gt;Beyond single‑column indexes, composite and covering indexes can eliminate extra lookups. Designing them for typical Python query patterns yields the greatest latency reduction. (Also read: &lt;a href="https://pythontpoint.in/mastering-aws-iam-roles-with-python-boto3/" rel="noopener noreferrer"&gt;☁️ Mastering aws iam roles with python boto3&lt;/a&gt;)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Index Type&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;th&gt;Benefit&lt;/th&gt;
&lt;th&gt;Trade‑off&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Single‑column B‑tree&lt;/td&gt;
&lt;td&gt;Equality filter on one column&lt;/td&gt;
&lt;td&gt;Fast point lookups&lt;/td&gt;
&lt;td&gt;Extra space per column&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Composite B‑tree&lt;/td&gt;
&lt;td&gt;Multiple predicates with a leading column&lt;/td&gt;
&lt;td&gt;Single index satisfies several filters&lt;/td&gt;
&lt;td&gt;Order matters; less selective leading column reduces effectiveness&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Covering index&lt;/td&gt;
&lt;td&gt;SELECT queries that need only indexed columns&lt;/td&gt;
&lt;td&gt;Eliminates table row reads&lt;/td&gt;
&lt;td&gt;Larger index size, more write overhead&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For a Django model that frequently runs &lt;code&gt;Order.objects.filter(user_id=…, status='…')&lt;/code&gt;, a composite covering index is optimal.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# django_index.sql
CREATE INDEX idx_orders_user_status ON orders (user_id, status) INCLUDE (total_amount, created_at);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Composite columns:&lt;/strong&gt; Enables the optimizer to filter on both &lt;code&gt;user_id&lt;/code&gt; and &lt;code&gt;status&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;INCLUDE clause:&lt;/strong&gt; Adds &lt;code&gt;total_amount&lt;/code&gt; and &lt;code&gt;created_at&lt;/code&gt; to the leaf pages, making the index covering for common SELECT lists.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using a single composite index allows MySQL to satisfy both predicates with one lookup, whereas two separate single‑column indexes would require a temporary merge, increasing CPU and I/O.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; Designing composite covering indexes that match your ORM’s most common query patterns delivers the greatest latency reduction for Python applications.&lt;/p&gt;




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

&lt;p&gt;When you &lt;strong&gt;optimize MySQL indexes for Python applications&lt;/strong&gt; , the biggest gains come from aligning index definitions with the actual query patterns generated by your ORM. The underlying mechanism—B‑tree navigation versus full table scans—determines whether a request costs milliseconds or seconds.&lt;/p&gt;

&lt;p&gt;By creating indexes early, employing composite and covering strategies, and verifying usage with &lt;code&gt;EXPLAIN&lt;/code&gt;, you ensure that the database performs the heavy lifting, leaving your Python code to focus on business logic.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Proper index design turns a costly full scan into a logarithmic lookup, delivering predictable performance for Python services.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ❓ Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How do I know if an index is being used?
&lt;/h3&gt;

&lt;p&gt;Run &lt;code&gt;EXPLAIN&lt;/code&gt; on the query; the &lt;code&gt;key&lt;/code&gt; column shows the index MySQL chose, and the &lt;code&gt;type&lt;/code&gt; column should be &lt;code&gt;ref&lt;/code&gt;, &lt;code&gt;range&lt;/code&gt;, or &lt;code&gt;eq_ref&lt;/code&gt; rather than &lt;code&gt;ALL&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the impact of adding an index on write performance?
&lt;/h3&gt;

&lt;p&gt;Each INSERT, UPDATE, or DELETE must also modify every affected index, adding CPU and I/O overhead. The trade‑off is worthwhile when read latency dominates, but avoid excessive indexes on high‑write tables.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I create indexes automatically from SQLAlchemy models?
&lt;/h3&gt;

&lt;p&gt;Yes. Define &lt;code&gt;Index&lt;/code&gt; objects in &lt;code&gt;__table_args__&lt;/code&gt; or use the &lt;code&gt;unique=True&lt;/code&gt; flag on a column; SQLAlchemy will emit the corresponding &lt;code&gt;CREATE INDEX&lt;/code&gt; statements during metadata creation.&lt;/p&gt;




&lt;p&gt;💡 &lt;strong&gt;Want to practise this hands-on?&lt;/strong&gt; &lt;a href="https://m.do.co/c/8ea4ebe8f879" rel="noopener noreferrer"&gt;DigitalOcean&lt;/a&gt; gives new accounts &lt;strong&gt;$200 free credit for 60 days&lt;/strong&gt; — enough to spin up a full Linux/Docker/Kubernetes environment at no cost.&lt;/p&gt;

&lt;p&gt;📚 &lt;strong&gt;Recommended reading:&lt;/strong&gt; &lt;a href="https://amzn.to/3QBrSOj" rel="noopener noreferrer"&gt;Best DevOps &amp;amp; cloud books on Amazon&lt;/a&gt; — from Linux fundamentals to Kubernetes in production, curated for working engineers.&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 References &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Official MySQL Index documentation — comprehensive guide to index types and creation: &lt;a href="https://dev.mysql.com/doc/refman/en/optimization-indexes.html" rel="noopener noreferrer"&gt;dev.mysql.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Django ORM query optimization — using indexes for common filters: &lt;a href="https://docs.djangoproject.com/en/stable/ref/models/indexes/" rel="noopener noreferrer"&gt;docs.djangoproject.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>mysql</category>
      <category>database</category>
      <category>sql</category>
      <category>python</category>
    </item>
    <item>
      <title>⚙️ Crafting an Argo CD application manifest yaml for FastAPI microservices made easy</title>
      <dc:creator>Python-T Point</dc:creator>
      <pubDate>Thu, 06 Aug 2026 03:40:32 +0000</pubDate>
      <link>https://dev.to/ptp2308/crafting-an-argo-cd-application-manifest-yaml-for-fastapi-microservices-made-easy-2a8g</link>
      <guid>https://dev.to/ptp2308/crafting-an-argo-cd-application-manifest-yaml-for-fastapi-microservices-made-easy-2a8g</guid>
      <description>&lt;h2&gt;
  
  
  🏗 Application Manifest — Why It &lt;em&gt;Matters&lt;/em&gt;
&lt;/h2&gt;

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

&lt;p&gt;A FastAPI microservice typically runs inside a container, but without an &lt;strong&gt;Argo CD Application&lt;/strong&gt; object the GitOps controller cannot reconcile the desired state. The manifest below defines the source repository, target cluster, and namespace, enabling continuous delivery for the service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📑 Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🏗 Application Manifest — Why It &lt;em&gt;Matters&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;📦 Container Image &amp;amp; Build — How to &lt;em&gt;Package&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🐍 Docker Build Command&lt;/li&gt;
&lt;li&gt;⚙️ Kubernetes Resources — Defining &lt;em&gt;Deployments&lt;/em&gt; and &lt;em&gt;Services&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🚀 Deployment Details&lt;/li&gt;
&lt;li&gt;🌐 Service Exposure&lt;/li&gt;
&lt;li&gt;🔗 Argo CD Sync Settings — Controlling &lt;em&gt;Sync&lt;/em&gt; Behaviour&lt;/li&gt;
&lt;li&gt;🟩 Final Thoughts&lt;/li&gt;
&lt;li&gt;❓ Frequently Asked Questions&lt;/li&gt;
&lt;li&gt;How do I expose the FastAPI service to the internet?&lt;/li&gt;
&lt;li&gt;Can I use Helm instead of raw YAML for the manifests?&lt;/li&gt;
&lt;li&gt;What if I need to change the container image tag without updating the whole repo?&lt;/li&gt;
&lt;li&gt;📚 References &amp;amp; Further Reading&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  📦 Container Image &amp;amp; Build — How to &lt;em&gt;Package&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;A Docker image bundles the FastAPI code, its dependencies, and the ASGI server. Building the image from source guarantees that every environment receives the identical artifact, eliminating version drift.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Dockerfile
FROM python:3.11-slim # Install build dependencies
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y -no-install-recommends gcc &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/* # Create a non‑root user
RUN useradd -m appuser
WORKDIR /app
COPY requirements.txt .
RUN pip install -no-cache-dir -r requirements.txt # Copy application code
COPY ./app ./app # Switch to non‑root user
USER appuser # Expose the port used by uvicorn
EXPOSE 8000 # Run the ASGI server
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FROM python:3.11-slim:&lt;/strong&gt; provides a minimal base with the correct interpreter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RUN apt-get … gcc:&lt;/strong&gt; installs a compiler needed for wheels that require native extensions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RUN useradd …:&lt;/strong&gt; creates a non‑root user to improve container security.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;COPY requirements.txt &amp;amp; pip install:&lt;/strong&gt; layers dependencies separately from source code for better caching.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;COPY ./app:&lt;/strong&gt; copies the FastAPI package into the image.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EXPOSE 8000:&lt;/strong&gt; declares the port expected by the Service.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CMD uvicorn …:&lt;/strong&gt; starts the application with the ASGI server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Building from source guarantees that the exact code version is packaged, and the build step can be audited for security compliance.&lt;/p&gt;

&lt;h3&gt;
  
  
  🐍 Docker Build Command
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker build -t ghcr.io/example/fastapi:latest .
Sending build context to Docker daemon 45.6MB
Step 1/12: FROM python:3.11-slim --&amp;gt; 1a2b3c4d5e6f
...
Successfully built 9f8e7d6c5b4a
Successfully tagged ghcr.io/example/fastapi:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The output confirms that Docker created the image and tagged it for later push.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Kubernetes Resources — Defining &lt;em&gt;Deployments&lt;/em&gt; and &lt;em&gt;Services&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Deployments manage pod lifecycle; Services provide stable networking. Together they ensure the FastAPI microservice scales and remains reachable within the cluster.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata: name: fastapi-deployment labels: app: fastapi
spec: replicas: 3 selector: matchLabels: app: fastapi template: metadata: labels: app: fastapi spec: containers: - name: fastapi image: ghcr.io/example/fastapi:latest ports: - containerPort: 8000 resources: requests: cpu: "100m" memory: "128Mi" limits: cpu: "500m" memory: "256Mi"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;replicas: 3:&lt;/strong&gt; creates three identical pods for load distribution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;selector.matchLabels:&lt;/strong&gt; ties the Deployment to pods with the same label.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;containers.image:&lt;/strong&gt; references the Docker image built earlier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;resources.requests/limits:&lt;/strong&gt; informs the scheduler of CPU/memory expectations, enabling QoS enforcement.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; Deployments include a self‑healing control loop; if a pod crashes, the controller spawns a replacement automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  🚀 Deployment Details
&lt;/h3&gt;

&lt;p&gt;Verify the Deployment:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl get deployment fastapi-deployment -n fastapi-prod
NAME READY UP-TO-DATE AVAILABLE AGE
fastapi-deployment 3/3 3 3 2m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  🌐 Service Exposure
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# service.yaml
apiVersion: v1
kind: Service
metadata: name: fastapi-service labels: app: fastapi
spec: selector: app: fastapi ports: - protocol: TCP port: 80 targetPort: 8000 type: ClusterIP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;type: ClusterIP:&lt;/strong&gt; creates an internal load balancer reachable only inside the cluster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;port 80 → targetPort 8000:&lt;/strong&gt; maps external HTTP traffic to the FastAPI container port.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;selector.app:&lt;/strong&gt; binds the Service to the pods created by the Deployment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A LoadBalancer Service would incur additional cloud cost and bypass the Ingress controller that performs TLS termination. (Also read: &lt;a href="https://pythontpoint.in/setting-up-kubernetes-hpa-for-a-fastapi-application-made/" rel="noopener noreferrer"&gt;⚙️ Setting up Kubernetes HPA for a FastAPI application made easy&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Check the Service:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl get svc fastapi-service -n fastapi-prod
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
fastapi-service ClusterIP 10.96.12.34  80/TCP 1m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;h2&gt;
  
  
  🔗 Argo CD Sync Settings — Controlling &lt;em&gt;Sync&lt;/em&gt; Behaviour
&lt;/h2&gt;

&lt;p&gt;Sync policies dictate how Argo CD applies changes from Git to the cluster. A well‑tuned syncPolicy reduces drift while avoiding unnecessary restarts.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# application-sync.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata: name: fastapi-app
spec: syncPolicy: automated: prune: true selfHeal: true syncOptions: - CreateNamespace=true - PruneLast=true retry: limit: 5 backoff: duration: 5s factor: 2 maxDuration: 3m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;prune: true:&lt;/strong&gt; removes resources that are no longer defined in Git.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;selfHeal: true:&lt;/strong&gt; detects out‑of‑band changes and restores the declared state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;syncOptions.CreateNamespace=true:&lt;/strong&gt; creates the target namespace automatically on first sync.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;retry.limit &amp;amp; backoff:&lt;/strong&gt; implements exponential back‑off for transient failures.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;According to the Argo CD documentation, enabling &lt;code&gt;selfHeal&lt;/code&gt; is the recommended default for production workloads because it guarantees that manual edits do not persist unintentionally.&lt;/p&gt;

&lt;p&gt;Trigger a manual sync to see the policy in action:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ argocd app sync fastapi-app
SYNCING: fastapi-app
STATUS: Synced
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; Automated sync with pruning and self‑heal keeps the cluster declaratively aligned with the Git repository, which is the core premise of GitOps.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Argo CD turns a Git repository into the single source of truth for Kubernetes, and the Application manifest is the bridge that makes that possible.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;Building an &lt;strong&gt;Argo CD application manifest yaml FastAPI&lt;/strong&gt; involves three layers: the Argo Application that points to a Git directory, the Kubernetes resources that run the FastAPI container, and the sync policy that enforces declarative state. By separating these concerns, the workflow stays reproducible, auditable, and easy to extend with additional microservices.&lt;/p&gt;

&lt;p&gt;Once the manifest is committed, any change—whether a code update or a configuration tweak—propagates automatically through Argo CD without manual &lt;code&gt;kubectl&lt;/code&gt; commands. This reduces human error, shortens delivery cycles, and provides a built‑in rollback mechanism by simply reverting the Git commit.&lt;/p&gt;

&lt;h2&gt;
  
  
  ❓ Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How do I expose the FastAPI service to the internet?
&lt;/h3&gt;

&lt;p&gt;Deploy an Ingress resource with an Ingress controller (e.g., NGINX or Traefik). The Ingress maps a host name to &lt;code&gt;fastapi-service&lt;/code&gt; and handles TLS termination, keeping the pods internal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use Helm instead of raw YAML for the manifests?
&lt;/h3&gt;

&lt;p&gt;Yes. Helm charts can template the Deployment, Service, and Application resources, which Argo CD can still sync. The underlying objects remain the same; Helm only adds a packaging layer.&lt;/p&gt;

&lt;h3&gt;
  
  
  What if I need to change the container image tag without updating the whole repo?
&lt;/h3&gt;

&lt;p&gt;Argo CD supports parameter overrides via &lt;code&gt;argocd app set&lt;/code&gt; or Kustomize patches. Updating the image tag in the Deployment spec and committing the change triggers a new sync automatically.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Want to practise this hands-on?&lt;/strong&gt; &lt;a href="https://m.do.co/c/8ea4ebe8f879" rel="noopener noreferrer"&gt;DigitalOcean&lt;/a&gt; gives new accounts &lt;strong&gt;$200 free credit for 60 days&lt;/strong&gt; — enough to spin up a full Linux/Docker/Kubernetes environment at no cost.&lt;/p&gt;

&lt;p&gt;📚 &lt;strong&gt;Recommended reading:&lt;/strong&gt; &lt;a href="https://amzn.to/3QBrSOj" rel="noopener noreferrer"&gt;Best DevOps &amp;amp; cloud books on Amazon&lt;/a&gt; — from Linux fundamentals to Kubernetes in production, curated for working engineers.&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 References &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Official Argo CD documentation – comprehensive guide to Application CRDs and sync policies: &lt;a href="https://argo-cd.readthedocs.io/en/stable/" rel="noopener noreferrer"&gt;argo-cd.readthedocs.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;FastAPI deployment guide – best practices for containerizing FastAPI applications: &lt;a href="https://fastapi.tiangolo.com/deployment/docker/" rel="noopener noreferrer"&gt;fastapi.tiangolo.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Kubernetes official docs – details on Deployments, Services, and Ingress resources: &lt;a href="https://kubernetes.io/docs/concepts/" rel="noopener noreferrer"&gt;kubernetes.io&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>python</category>
      <category>devops</category>
    </item>
    <item>
      <title>☁️ Fix ssh permission denied ubuntu ec2 issues with ease</title>
      <dc:creator>Python-T Point</dc:creator>
      <pubDate>Wed, 05 Aug 2026 03:39:00 +0000</pubDate>
      <link>https://dev.to/ptp2308/fix-ssh-permission-denied-ubuntu-ec2-issues-with-ease-3dfe</link>
      <guid>https://dev.to/ptp2308/fix-ssh-permission-denied-ubuntu-ec2-issues-with-ease-3dfe</guid>
      <description>&lt;h2&gt;
  
  
  ❓ ssh permission denied ubuntu ec2 fix? The error indicates that the SSH daemon rejected the key, typically due to incorrect file permissions or mismatched user configuration. The root cause may reside in filesystem permissions, key placement, daemon configuration, or network rules.
&lt;/h2&gt;

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

&lt;p&gt;Fixing &lt;strong&gt;ssh permission denied ubuntu ec2 fix&lt;/strong&gt; requires aligning filesystem permissions, placing the correct public key in &lt;code&gt;authorized_keys&lt;/code&gt;, and configuring EC2 security settings to allow SSH traffic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📑 Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❓ ssh permission denied ubuntu ec2 fix? The error indicates that the SSH daemon rejected the key, typically due to incorrect file permissions or mismatched user configuration. The root cause may reside in filesystem permissions, key placement, daemon configuration, or network rules.&lt;/li&gt;
&lt;li&gt;🔐 Permissions — Why They &lt;em&gt;Matter&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🗝️ SSH Keys — How They &lt;em&gt;Authenticate&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🔑 Generate a Key Pair&lt;/li&gt;
&lt;li&gt;📤 Deploy the Public Key&lt;/li&gt;
&lt;li&gt;🖥️ EC2 Instance — Configuring the &lt;em&gt;Instance&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;📡 Network — Ensuring &lt;em&gt;Connectivity&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🔒 Security Group Rules&lt;/li&gt;
&lt;li&gt;🚧 Network ACL Checks&lt;/li&gt;
&lt;li&gt;🧹 Common Pitfalls — Avoiding &lt;em&gt;Mistakes&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🟩 Final Thoughts&lt;/li&gt;
&lt;li&gt;❓ Frequently Asked Questions&lt;/li&gt;
&lt;li&gt;Why does changing file ownership sometimes not fix the error?&lt;/li&gt;
&lt;li&gt;Can I use a different SSH port and still get the same permission denied error?&lt;/li&gt;
&lt;li&gt;Is it safe to set &lt;code&gt;StrictModes no&lt;/code&gt; to bypass permission checks?&lt;/li&gt;
&lt;li&gt;📚 References &amp;amp; Further Reading&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🔐 Permissions — Why They &lt;em&gt;Matter&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;File permissions on the &lt;code&gt;.ssh&lt;/code&gt; directory and its contents determine whether the SSH daemon will accept a key. The daemon enforces strict ownership and mode checks (via &lt;code&gt;StrictModes&lt;/code&gt;) before reading the key file.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ls -ld /home/ubuntu/.ssh
drwx------ 2 ubuntu ubuntu 4096 Apr 12 08:15 /home/ubuntu/.ssh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If the directory mode differs from &lt;code&gt;drwx------&lt;/code&gt; or is owned by another user, the key is ignored.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Set the correct permissions
$ chmod 700 /home/ubuntu/.ssh
$ chmod 600 /home/ubuntu/.ssh/authorized_keys
$ chown -R ubuntu:ubuntu /home/ubuntu/.ssh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;chmod 700:&lt;/strong&gt; Allows only the owner to read, write, and traverse the directory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;chmod 600:&lt;/strong&gt; Restricts &lt;code&gt;authorized_keys&lt;/code&gt; to owner‑only read/write.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;chown -R:&lt;/strong&gt; Guarantees the &lt;code&gt;ubuntu&lt;/code&gt; user owns the directory and its files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; The SSH daemon rejects keys when the .ssh directory or &lt;code&gt;authorized_keys&lt;/code&gt; file is not owned by the target user or has permissive mode bits; correcting these permissions is the first step in any &lt;em&gt;ssh permission denied ubuntu ec2 fix&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🗝️ SSH Keys — How They &lt;em&gt;Authenticate&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;SSH keys are cryptographic tokens used by the client and server to prove identity. The public key must be present in &lt;code&gt;authorized_keys&lt;/code&gt;; the private key presented by the client must match it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Generate a new key pair (if missing)
$ ssh-keygen -t rsa -b 4096 -f ~/.ssh/ec2_key -N ""
Generating public/private rsa key pair.
Your identification has been saved in /home/user/.ssh/ec2_key
Your public key has been saved in /home/user/.ssh/ec2_key.pub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Deploy the public key to the instance:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Using ssh-copy-id (preferred)
$ ssh-copy-id -i ~/.ssh/ec2_key.pub ubuntu@ec2-3-12-45-67.compute-1.amazonaws.com
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/user/.ssh/ec2_key.pub"
Number of key(s) added: 1 Now try logging into the machine with:
ssh -i ~/.ssh/ec2_key ubuntu@ec2-3-12-45-67.compute-1.amazonaws.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The daemon reads &lt;code&gt;authorized_keys&lt;/code&gt; and validates the signature presented by the client.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔑 Generate a Key Pair
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;ssh-keygen&lt;/code&gt; command creates a 4096‑bit RSA key, which exceeds the security requirements of typical EC2 workloads. The private key remains on the client; only the public key is transferred to the server.&lt;/p&gt;

&lt;h3&gt;
  
  
  📤 Deploy the Public Key
&lt;/h3&gt;

&lt;p&gt;Using &lt;code&gt;ssh-copy-id&lt;/code&gt; writes the key to &lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt; and sets the correct permissions automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; An &lt;em&gt;ssh permission denied ubuntu ec2 fix&lt;/em&gt; caused by a missing or mismatched key is resolved by ensuring the public key resides in &lt;code&gt;authorized_keys&lt;/code&gt; and the client uses the corresponding private key.&lt;/p&gt;




&lt;h2&gt;
  
  
  🖥️ EC2 Instance — Configuring the &lt;em&gt;Instance&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;The EC2 instance runs the OpenSSH daemon, which reads its configuration from &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt;. Examining this file reveals settings that may reject a key. (Also read: &lt;a href="https://pythontpoint.in/deploy-flask-ec2-nginx-gunicorn/" rel="noopener noreferrer"&gt;Deploy a Flask App on AWS EC2 with Nginx + Gunicorn (Ubuntu 24.04, 2026)&lt;/a&gt;)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Verify password authentication is disabled
$ sudo grep -i '^PasswordAuthentication' /etc/ssh/sshd_config
PasswordAuthentication no
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Disabling password authentication forces key‑based login, reducing attack surface.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Confirm the authorized keys file location
$ sudo grep -i '^AuthorizedKeysFile' /etc/ssh/sshd_config
AuthorizedKeysFile .ssh/authorized_keys
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;According to the Ubuntu documentation, the default &lt;code&gt;AuthorizedKeysFile&lt;/code&gt; location is &lt;code&gt;.ssh/authorized_keys&lt;/code&gt; relative to the user’s home directory; custom paths cause the daemon to search in the wrong location.&lt;/p&gt;

&lt;p&gt;After modifying the configuration, reload the daemon to apply changes:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo systemctl reload sshd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;grep PasswordAuthentication:&lt;/strong&gt; Confirms password logins are disabled, ensuring only key‑based access is allowed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;grep AuthorizedKeysFile:&lt;/strong&gt; Verifies the daemon looks for keys in the expected location.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;systemctl reload:&lt;/strong&gt; Applies configuration changes without restarting the service.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; Verifying the SSH daemon’s configuration eliminates a class of &lt;em&gt;ssh permission denied ubuntu ec2 fix&lt;/em&gt; caused by mis‑directed key lookups.&lt;/p&gt;




&lt;h2&gt;
  
  
  📡 Network — Ensuring &lt;em&gt;Connectivity&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Even with correct keys and permissions, inbound SSH traffic must be permitted by the instance’s security group and network ACL.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ aws ec2 describe-security-groups -group-ids sg-0a1b2c3d4e5f6g7h
{ "SecurityGroups": [ { "GroupId": "sg-0a1b2c3d4e5f6g7h", "GroupName": "default", "IpPermissions": [ { "IpProtocol": "tcp", "FromPort": 22, "ToPort": 22, "IpRanges": [ { "CidrIp": "0.0.0.0/0", "Description": "SSH from anywhere" } ] } ] } ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If the &lt;code&gt;IpPermissions&lt;/code&gt; entry for port 22 is missing or restricts the client’s IP, the TCP handshake never completes, and the client reports “Permission denied (publickey)”.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔒 Security Group Rules
&lt;/h3&gt;

&lt;p&gt;Allow port 22 from the client’s public IP (or a broader range). A common misconfiguration is a security group limited to a private CIDR that does not include the workstation. &lt;em&gt;(More on&lt;a href="https://pythontpoint.in" rel="noopener noreferrer"&gt;PythonTPoint tutorials&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Add a rule for the current public IP
$ MY_IP=$(curl -s https://checkip.amazonaws.com)
$ aws ec2 authorize-security-group-ingress -group-id sg-0a1b2c3d4e5f6g7h -protocol tcp -port 22 -cidr ${MY_IP}/32
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After updating the rule, a fresh SSH attempt reaches the daemon.&lt;/p&gt;

&lt;h3&gt;
  
  
  🚧 Network ACL Checks
&lt;/h3&gt;

&lt;p&gt;Network ACLs are stateless; both inbound and outbound rules must permit traffic on port 22. A missing outbound rule can cause the handshake to time out.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ aws ec2 describe-network-acls -network-acl-ids acl-12345678
{ "NetworkAcls": [ { "Associations": [...], "Entries": [ { "RuleNumber": 100, "Protocol": "6", "RuleAction": "allow", "Egress": false, "CidrBlock": "0.0.0.0/0", "PortRange": {"From": 22, "To": 22} } ] } ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Ensuring both inbound and outbound entries exist eliminates connectivity‑related denial.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; The network layer is a prerequisite for any &lt;em&gt;ssh permission denied ubuntu ec2 fix&lt;/em&gt; ; without an open port 22, the SSH client cannot negotiate the key exchange.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧹 Common Pitfalls — Avoiding &lt;em&gt;Mistakes&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Beyond permissions and networking, several subtle issues frequently cause the same error; recognizing them speeds up remediation.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Issue&lt;/th&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Wrong user&lt;/td&gt;
&lt;td&gt;Connecting as &lt;code&gt;ec2‑user&lt;/code&gt; on an Ubuntu AMI&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;ubuntu&lt;/code&gt; as the SSH user&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SELinux/AppArmor enforcing&lt;/td&gt;
&lt;td&gt;“Permission denied” despite correct file modes&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;enforce=0&lt;/code&gt; or adjust profiles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Incorrect key format&lt;/td&gt;
&lt;td&gt;Key rejected with “invalid format”&lt;/td&gt;
&lt;td&gt;Regenerate with &lt;code&gt;ssh-keygen -t rsa -b 4096&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These entries illustrate that the same error message can stem from unrelated layers; a systematic checklist prevents wasted time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; A thorough &lt;em&gt;ssh permission denied ubuntu ec2 fix&lt;/em&gt; process inspects user identity, security policies, and key integrity, not just file permissions.&lt;/p&gt;




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

&lt;p&gt;Resolving &lt;strong&gt;ssh permission denied ubuntu ec2 fix&lt;/strong&gt; involves aligning three independent systems: filesystem permissions trusted by the SSH daemon, the key pair that proves identity, and network rules that allow traffic to reach the daemon. When each layer is verified, the SSH handshake proceeds without rejection, providing a reliable, repeatable path for automation.&lt;/p&gt;

&lt;p&gt;For developers managing multiple EC2 instances, codifying these steps into a script or Ansible playbook ensures consistency across environments and reduces the chance of human error.&lt;/p&gt;

&lt;h2&gt;
  
  
  ❓ Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why does changing file ownership sometimes not fix the error?
&lt;/h3&gt;

&lt;p&gt;Because the SSH daemon checks both ownership and mode bits. If the mode is too permissive (e.g., &lt;code&gt;chmod 644&lt;/code&gt; on &lt;code&gt;authorized_keys&lt;/code&gt;), the daemon will still reject the key even if the owner is correct.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use a different SSH port and still get the same permission denied error?
&lt;/h3&gt;

&lt;p&gt;Yes. The error is generated after the key exchange, so changing the listening port in &lt;code&gt;sshd_config&lt;/code&gt; does not affect the permission checks; you must still ensure the key and permissions are correct.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is it safe to set &lt;code&gt;StrictModes no&lt;/code&gt; to bypass permission checks?
&lt;/h3&gt;

&lt;p&gt;Disabling &lt;code&gt;StrictModes&lt;/code&gt; removes the daemon’s protection against insecure key files, exposing the instance to credential theft. The recommended approach is to fix the underlying permissions rather than relax security.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Want to practise this hands-on?&lt;/strong&gt; &lt;a href="https://m.do.co/c/8ea4ebe8f879" rel="noopener noreferrer"&gt;DigitalOcean&lt;/a&gt; gives new accounts &lt;strong&gt;$200 free credit for 60 days&lt;/strong&gt; — enough to spin up a full Linux/Docker/Kubernetes environment at no cost.&lt;/p&gt;

&lt;p&gt;📚 &lt;strong&gt;Recommended reading:&lt;/strong&gt; &lt;a href="https://amzn.to/3QBrSOj" rel="noopener noreferrer"&gt;Best DevOps &amp;amp; cloud books on Amazon&lt;/a&gt; — from Linux fundamentals to Kubernetes in production, curated for working engineers.&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 References &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Official Ubuntu SSH documentation — detailed description of SSH daemon behavior: &lt;a href="https://ubuntu.com/server/docs/openssh-server" rel="noopener noreferrer"&gt;ubuntu.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;OpenSSH manual page — authoritative source for configuration options: &lt;a href="https://man7.org/linux/man-pages/man5/sshd_config.5.html" rel="noopener noreferrer"&gt;man7.org&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;AWS EC2 security groups guide — explains inbound rule configuration: &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html" rel="noopener noreferrer"&gt;docs.aws.amazon.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>googlecloud</category>
      <category>cloud</category>
      <category>devops</category>
      <category>linux</category>
    </item>
    <item>
      <title>⚙️ Pinecone FastAPI vector search integration tutorial</title>
      <dc:creator>Python-T Point</dc:creator>
      <pubDate>Tue, 04 Aug 2026 03:38:53 +0000</pubDate>
      <link>https://dev.to/ptp2308/pinecone-fastapi-vector-search-integration-tutorial-29bh</link>
      <guid>https://dev.to/ptp2308/pinecone-fastapi-vector-search-integration-tutorial-29bh</guid>
      <description>&lt;h2&gt;
  
  
  🚀 Pinecone vs. Local FAISS — Why One &lt;em&gt;Scales&lt;/em&gt;
&lt;/h2&gt;

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

&lt;p&gt;Two vector similarity search approaches can return identical results while differing dramatically in latency and operational overhead. A managed cloud index scales automatically; an in‑process library runs on a single server. This post evaluates which approach integrates best with FastAPI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📑 Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🚀 Pinecone vs. Local FAISS — Why One &lt;em&gt;Scales&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;📦 Prerequisites — Why They &lt;em&gt;Matter&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🛠️ Create Pinecone Index — How to &lt;em&gt;Initialize&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;📊 Upsert Embeddings — Storing &lt;em&gt;Vectors&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🔧 Batch Upsert — Efficient &lt;em&gt;Ingestion&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🔎 Build FastAPI Search Endpoint — Implementing &lt;em&gt;Search&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;⚙️ Request Handler — Converting &lt;em&gt;Query&lt;/em&gt; to Vector&lt;/li&gt;
&lt;li&gt;📈 Performance Comparison — Pinecone vs. FAISS&lt;/li&gt;
&lt;li&gt;🟩 Final Thoughts&lt;/li&gt;
&lt;li&gt;❓ Frequently Asked Questions&lt;/li&gt;
&lt;li&gt;How do I secure the Pinecone API key in production?&lt;/li&gt;
&lt;li&gt;Can I use a different embedding model?&lt;/li&gt;
&lt;li&gt;What happens if the index reaches its quota?&lt;/li&gt;
&lt;li&gt;📚 References &amp;amp; Further Reading&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  📦 Prerequisites — Why They &lt;em&gt;Matter&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;A FastAPI project with Python 3.9+ and an active Pinecone account is required.&lt;/p&gt;

&lt;p&gt;Install the dependencies and set environment variables before any code runs.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ pip install fastapi uvicorn pinecone-client sentence-transformers
Collecting fastapi Downloading fastapi-0.110.0-py3-none-any.whl (68 kB)
Collecting uvicorn Downloading uvicorn-0.24.0-py3-none-any.whl (78 kB)
Collecting pinecone-client Downloading pinecone_client-3.2.0-py3-none-any.whl (120 kB)
Collecting sentence-transformers Downloading sentence_transformers-2.2.2-py3-none-any.whl (2.1 MB)
...
Successfully installed fastapi-0.110.0 uvicorn-0.24.0 pinecone-client-3.2.0 sentence-transformers-2.2.2



# Verify installation
$ python -c "import fastapi, pinecone; print('OK')"
OK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;fastapi:&lt;/strong&gt; hosts the search endpoint.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;uvicorn:&lt;/strong&gt; ASGI server for running FastAPI locally or in production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pinecone-client:&lt;/strong&gt; official SDK for Pinecone’s vector service.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;sentence-transformers:&lt;/strong&gt; provides an embedding model for converting text to vectors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why this, not a local SQLite store? A cloud vector service delivers sub‑millisecond latency at scale, automatic sharding, and built‑in metadata filtering—capabilities a single‑node SQLite database cannot provide.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; A managed vector index eliminates the need to provision and maintain hardware for high‑dimensional search.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Create Pinecone Index — How to &lt;em&gt;Initialize&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;An index is a container for vectors; creating it defines dimensionality, metric, and replication settings.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# create_index.py
import os
import pinecone # Initialize client with API key from environment
pinecone.init(api_key=os.getenv("PINECONE_API_KEY"), environment="us-west1-gcp") # Define index parameters
index_name = "fastapi-demo"
dimension = 768 # SentenceTransformer output size
metric = "cosine"
pod_type = "p1.x1" # Small production pod # Create the index if it does not exist
if index_name not in pinecone.list_indexes(): pinecone.create_index( name=index_name, dimension=dimension, metric=metric, pods=1, pod_type=pod_type, )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;What this does: (Also read: &lt;a href="https://pythontpoint.in/setting-up-kubernetes-hpa-for-a-fastapi-application-made/" rel="noopener noreferrer"&gt;⚙️ Setting up Kubernetes HPA for a FastAPI application made easy&lt;/a&gt;)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;pinecone.init:&lt;/strong&gt; authenticates the SDK with the API key.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;dimension:&lt;/strong&gt; must match the size of stored embedding vectors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;metric:&lt;/strong&gt; determines similarity computation; &lt;code&gt;cosine&lt;/code&gt; is common for text embeddings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pod_type:&lt;/strong&gt; selects compute resources allocated to the index.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The official Pinecone documentation states that the &lt;code&gt;create_index&lt;/code&gt; call provisions a dedicated vector service that automatically handles partitioning and replication.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ python create_index.py
Index fastapi-demo created successfully
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Why this, not a bare collection in a NoSQL store? Pinecone’s indexing layer builds an inverted file system (IVF) and HNSW graph under the hood, enabling logarithmic‑time nearest‑neighbor lookups, whereas a generic document store would require a full scan.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; Index configuration directly influences query speed and cost; choose metric and dimension carefully.&lt;/p&gt;




&lt;h2&gt;
  
  
  📊 Upsert Embeddings — Storing &lt;em&gt;Vectors&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Upserting inserts or updates vectors in the index, associating each with a unique ID and optional metadata.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔧 Batch Upsert — Efficient &lt;em&gt;Ingestion&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Batching reduces HTTP round‑trips, improving throughput.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# upsert_batch.py
import os
import pinecone
from sentence_transformers import SentenceTransformer pinecone.init(api_key=os.getenv("PINECONE_API_KEY"), environment="us-west1-gcp")
index = pinecone.Index("fastapi-demo")
model = SentenceTransformer("all-MiniLM-L6-v2") documents = [ {"id": "doc1", "text": "FastAPI makes building APIs fast.", "category": "tutorial"}, {"id": "doc2", "text": "Pinecone provides managed vector search.", "category": "service"}, # ... more documents ...
] # Convert texts to embeddings
vectors = [ (doc["id"], model.encode(doc["text"]).tolist(), {"category": doc["category"]}) for doc in documents
] # Upsert in a single batch
index.upsert(vectors=vectors, namespace="articles")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;model.encode:&lt;/strong&gt; produces a 768‑dimensional vector for each text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;vectors list:&lt;/strong&gt; each entry is a tuple of (id, vector, metadata).&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;namespace:&lt;/strong&gt; isolates this dataset from others in the same Pinecone project.&lt;/p&gt;

&lt;p&gt;$ python upsert_batch.py&lt;br&gt;
Upserted 2 vectors to namespace articles&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why this, not a simple INSERT into a relational table? Pinecone stores vectors in a high‑dimensional index that uses product quantization, enabling sub‑linear search; relational databases lack such structures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; Batch upserts are the recommended pattern for loading large corpora efficiently. &lt;em&gt;(More on&lt;a href="https://pythontpoint.in" rel="noopener noreferrer"&gt;PythonTPoint tutorials&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🔎 Build FastAPI Search Endpoint — Implementing &lt;em&gt;Search&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;A FastAPI route receives a query string, transforms it to a vector, and returns the most similar stored documents.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚙️ Request Handler — Converting &lt;em&gt;Query&lt;/em&gt; to Vector
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# main.py
import os
import pinecone
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from sentence_transformers import SentenceTransformer app = FastAPI()
pinecone.init(api_key=os.getenv("PINECONE_API_KEY"), environment="us-west1-gcp")
index = pinecone.Index("fastapi-demo")
model = SentenceTransformer("all-MiniLM-L6-v2") class SearchRequest(BaseModel): query: str top_k: int = 5 filter_category: str | None = None @app.post("/search")
def search(req: SearchRequest): # Embed the query query_vec = model.encode(req.query).tolist() # Build filter if provided filter_dict = {"category": req.filter_category} if req.filter_category else None # Perform the similarity search results = index.query( vector=query_vec, top_k=req.top_k, namespace="articles", filter=filter_dict, include_metadata=True, ) if not results.matches: raise HTTPException(status_code=404, detail="No matches found") return {"matches": results.matches}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SearchRequest:&lt;/strong&gt; validates incoming JSON payload.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;model.encode:&lt;/strong&gt; maps the user query into the same embedding space as stored vectors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;index.query:&lt;/strong&gt; executes a nearest‑neighbor lookup using the configured metric.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;filter:&lt;/strong&gt; optionally limits results by metadata, leveraging Pinecone’s built‑in filtering engine.&lt;/p&gt;

&lt;p&gt;$ uvicorn main:app -host 0.0.0.0 -port 8000&lt;br&gt;
INFO: Started server process [12345]&lt;br&gt;
INFO: Waiting for application startup.&lt;br&gt;
INFO: Application startup complete.&lt;/p&gt;

&lt;p&gt;$ curl -X POST &lt;a href="http://localhost:8000/search" rel="noopener noreferrer"&gt;http://localhost:8000/search&lt;/a&gt; -H "Content-Type: application/json" -d '{"query":"How does vector search work?","top_k":3}'&lt;br&gt;
{ "matches": [ { "id": "doc2", "score": 0.987, "metadata": {"category": "service"} }, { "id": "doc1", "score": 0.945, "metadata": {"category": "tutorial"} } ]&lt;br&gt;
}&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why this, not a manual cosine similarity loop in Python? Pinecone performs similarity calculations on specialized hardware and returns pre‑sorted results, avoiding O(N) scans and reducing CPU load on the FastAPI host.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; The endpoint delegates heavy lifting to Pinecone, keeping the API layer lightweight and stateless.&lt;/p&gt;




&lt;h2&gt;
  
  
  📈 Performance Comparison — Pinecone vs. FAISS
&lt;/h2&gt;

&lt;p&gt;Both services provide vector search, but their operational characteristics differ.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Pinecone&lt;/th&gt;
&lt;th&gt;FAISS (local)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Scalability&lt;/td&gt;
&lt;td&gt;Automatic sharding and replication in the cloud&lt;/td&gt;
&lt;td&gt;Limited to single‑machine memory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latency&lt;/td&gt;
&lt;td&gt;Sub‑millisecond at scale (managed hardware)&lt;/td&gt;
&lt;td&gt;Depends on CPU/GPU, may increase with dataset size&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maintenance&lt;/td&gt;
&lt;td&gt;Zero‑ops: no index rebuilds needed&lt;/td&gt;
&lt;td&gt;Manual index rebuilds required after data changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost Model&lt;/td&gt;
&lt;td&gt;Pay‑as‑you‑go based on pod size and queries&lt;/td&gt;
&lt;td&gt;Free but incurs infrastructure cost for servers&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The table illustrates why a managed service is preferable for production APIs that must handle unpredictable traffic spikes.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;When Pinecone handles the index, FastAPI code remains focused on request orchestration rather than nearest‑neighbor math.&lt;/p&gt;
&lt;/blockquote&gt;




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

&lt;p&gt;The integration steps—initializing the client, creating an index, upserting vectors, and exposing a FastAPI endpoint—form a repeatable pattern adaptable to any embedding model or data domain. Offloading vector storage and similarity computation to Pinecone removes the complexity of maintaining high‑dimensional indexes and lets developers concentrate on application‑specific logic.&lt;/p&gt;

&lt;p&gt;For a developer, this yields faster iteration cycles, predictable latency, and a clear separation between API code and vector infrastructure. The same pattern scales from a prototype with a few hundred vectors to production workloads handling millions of embeddings without code changes.&lt;/p&gt;




&lt;h2&gt;
  
  
  ❓ Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How do I secure the Pinecone API key in production?
&lt;/h3&gt;

&lt;p&gt;Store the key in a secret manager (e.g., AWS Secrets Manager or GCP Secret Manager) and inject it as an environment variable at runtime. Never hard‑code the key in source files.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use a different embedding model?
&lt;/h3&gt;

&lt;p&gt;Yes. Replace the &lt;code&gt;SentenceTransformer&lt;/code&gt; instantiation with any model that outputs vectors matching the index dimension. Update the &lt;code&gt;dimension&lt;/code&gt; parameter when recreating the Pinecone index.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens if the index reaches its quota?
&lt;/h3&gt;

&lt;p&gt;Pinecone returns a &lt;code&gt;ResourceExhausted&lt;/code&gt; error. Increase the pod size or add more pods via the console or SDK to raise capacity.&lt;/p&gt;




&lt;p&gt;💡 &lt;strong&gt;Want to practise this hands-on?&lt;/strong&gt; &lt;a href="https://m.do.co/c/8ea4ebe8f879" rel="noopener noreferrer"&gt;DigitalOcean&lt;/a&gt; gives new accounts &lt;strong&gt;$200 free credit for 60 days&lt;/strong&gt; — enough to spin up a full Linux/Docker/Kubernetes environment at no cost.&lt;/p&gt;

&lt;p&gt;📚 &lt;strong&gt;Recommended reading:&lt;/strong&gt; &lt;a href="https://amzn.to/3QBrSOj" rel="noopener noreferrer"&gt;Best DevOps &amp;amp; cloud books on Amazon&lt;/a&gt; — from Linux fundamentals to Kubernetes in production, curated for working engineers.&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 References &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;FastAPI tutorial — building asynchronous APIs with Python: &lt;a href="https://fastapi.tiangolo.com/tutorial/" rel="noopener noreferrer"&gt;fastapi.tiangolo.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>🚀 Transitioning from service to product engineering — what you need to know</title>
      <dc:creator>Python-T Point</dc:creator>
      <pubDate>Mon, 03 Aug 2026 03:38:53 +0000</pubDate>
      <link>https://dev.to/ptp2308/transitioning-from-service-to-product-engineering-what-you-need-to-know-1h9f</link>
      <guid>https://dev.to/ptp2308/transitioning-from-service-to-product-engineering-what-you-need-to-know-1h9f</guid>
      <description>&lt;h2&gt;
  
  
  💡 Mindset Shift — Why &lt;em&gt;Product&lt;/em&gt; Thinking Matters
&lt;/h2&gt;

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

&lt;p&gt;A mindset shift is the first step in the &lt;strong&gt;transition from service to product engineering&lt;/strong&gt; — it replaces ad‑hoc problem solving with a focus on long‑term value and maintainability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📑 Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;💡 Mindset Shift — Why &lt;em&gt;Product&lt;/em&gt; Thinking Matters&lt;/li&gt;
&lt;li&gt;🛠 Architecture Evolution — From &lt;em&gt;Ad‑hoc&lt;/em&gt; Service to Scalable Product&lt;/li&gt;
&lt;li&gt;🏗 Modularizing the Core&lt;/li&gt;
&lt;li&gt;🗂 Containerizing with Docker&lt;/li&gt;
&lt;li&gt;📦 Delivery Pipeline — From Manual Deploy to CI/CD&lt;/li&gt;
&lt;li&gt;🚀 Build Stage with GitHub Actions&lt;/li&gt;
&lt;li&gt;⚙️ Deploy Stage with Kubernetes&lt;/li&gt;
&lt;li&gt;📊 Metrics &amp;amp; Feedback Loop — From Reactive to Proactive&lt;/li&gt;
&lt;li&gt;📈 Exposing Prometheus Metrics&lt;/li&gt;
&lt;li&gt;🔔 Alerting with Prometheus Rules&lt;/li&gt;
&lt;li&gt;🟩 Final Thoughts&lt;/li&gt;
&lt;li&gt;❓ Frequently Asked Questions&lt;/li&gt;
&lt;li&gt;How do I decide which parts of a service can be turned into a product?&lt;/li&gt;
&lt;li&gt;Is Kubernetes mandatory for productizing a service?&lt;/li&gt;
&lt;li&gt;What is the minimal set of metrics a product should expose?&lt;/li&gt;
&lt;li&gt;📚 References &amp;amp; Further Reading&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🛠 Architecture Evolution — From &lt;em&gt;Ad‑hoc&lt;/em&gt; Service to Scalable Product
&lt;/h2&gt;

&lt;p&gt;This section teaches how to refactor a service‑oriented codebase into a containerized product that can be deployed repeatedly.&lt;/p&gt;

&lt;h3&gt;
  
  
  🏗 Modularizing the Core
&lt;/h3&gt;

&lt;p&gt;Separate business logic from request handling by extracting a pure Python module.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# core.py
def calculate_discount(price: float, rate: float) -&amp;gt; float: """Return the price after applying a discount rate.""" return price * (1 - rate)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;calculate_discount:&lt;/strong&gt; pure function with no external dependencies, making it unit‑testable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;docstring:&lt;/strong&gt; explains the contract, useful for generated API docs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why this, not the alternative of keeping logic inside the Flask view? Pure functions can be reused across multiple entry points (CLI, HTTP, background jobs) without duplication.&lt;/p&gt;

&lt;h3&gt;
  
  
  🗂 Containerizing with Docker
&lt;/h3&gt;

&lt;p&gt;Docker provides isolation and reproducibility, essential for a product that runs in many environments.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY core.py .
CMD ["python", "-m", "http.server", "8080"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;What this does:&lt;/strong&gt; &lt;em&gt;(More on&lt;a href="https://pythontpoint.in" rel="noopener noreferrer"&gt;PythonTPoint tutorials&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FROM:&lt;/strong&gt; pulls a minimal Python image, reducing attack surface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WORKDIR:&lt;/strong&gt; sets a consistent working directory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;COPY &amp;amp; RUN:&lt;/strong&gt; layers dependencies for caching.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CMD:&lt;/strong&gt; runs a simple HTTP server exposing the product.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;According to the Docker documentation, each layer is cached separately, which speeds up iterative builds when only the code changes.&lt;/p&gt;

&lt;p&gt;Why this, not a raw virtual environment on a VM? Containers guarantee the same runtime across dev, test, and production, eliminating “it works on my machine” failures.&lt;/p&gt;

&lt;p&gt;Comparison of the two approaches:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Service‑style Deployment&lt;/th&gt;
&lt;th&gt;Product‑style Container&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Reproducibility&lt;/td&gt;
&lt;td&gt;Manual setup per host&lt;/td&gt;
&lt;td&gt;Immutable image guarantees same binaries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scalability&lt;/td&gt;
&lt;td&gt;Single instance per host&lt;/td&gt;
&lt;td&gt;Orchestrator can start many replicas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Upgrade Path&lt;/td&gt;
&lt;td&gt;Patch scripts&lt;/td&gt;
&lt;td&gt;Versioned images rolled out automatically&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; Containerization turns a one‑off service into a repeatable product artifact.&lt;/p&gt;




&lt;h2&gt;
  
  
  📦 Delivery Pipeline — From Manual Deploy to CI/CD
&lt;/h2&gt;

&lt;p&gt;This section teaches how to automate building, testing, and deploying the product using a continuous integration pipeline.&lt;/p&gt;

&lt;h3&gt;
  
  
  🚀 Build Stage with GitHub Actions
&lt;/h3&gt;

&lt;p&gt;Define a workflow that builds the Docker image and pushes it to a registry.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .github/workflows/build.yml
name: Build &amp;amp; Publish
on: push: branches: [main]
jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - name: Log in to Docker Hub uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_USER }} password: ${{ secrets.DOCKER_PASS }} - name: Build and push uses: docker/build-push-action@v3 with: context: . push: true tags: myorg/product:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;on.push:&lt;/strong&gt; triggers on commits to &lt;code&gt;main&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;docker/setup-buildx-action:&lt;/strong&gt; enables multi‑platform builds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;docker/login-action:&lt;/strong&gt; authenticates to the registry securely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;docker/build-push-action:&lt;/strong&gt; builds the image defined in the Dockerfile and pushes it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why this, not a manual &lt;code&gt;docker build&lt;/code&gt; on a laptop? Automation removes human error and ensures every commit is validated.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚙️ Deploy Stage with Kubernetes
&lt;/h3&gt;

&lt;p&gt;Deploy the image using a declarative manifest.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata: name: product
spec: replicas: 3 selector: matchLabels: app: product template: metadata: labels: app: product spec: containers: - name: product image: myorg/product:latest ports: - containerPort: 8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;replicas: 3&lt;/strong&gt; ensures three pods for high availability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;selector &amp;amp; labels:&lt;/strong&gt; bind the Service to the Pods.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;containerPort:&lt;/strong&gt; declares the port the container listens on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why this, not a bare &lt;code&gt;kubectl run&lt;/code&gt; command? A Deployment adds a control loop that monitors pod health and restarts failed instances automatically.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Automation is the bridge that turns a service into a product; without it, you cannot guarantee consistent delivery.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; A CI/CD pipeline codifies the build‑test‑deploy cycle, making product releases repeatable and auditable.&lt;/p&gt;




&lt;h2&gt;
  
  
  📊 Metrics &amp;amp; Feedback Loop — From Reactive to Proactive
&lt;/h2&gt;

&lt;p&gt;This section teaches how to embed observability into the product so that performance and usage drive future development.&lt;/p&gt;

&lt;h3&gt;
  
  
  📈 Exposing Prometheus Metrics
&lt;/h3&gt;

&lt;p&gt;Instrument the core module with a simple counter.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# metrics.py
from prometheus_client import Counter, start_http_server REQUESTS = Counter('product_requests_total', 'Total requests processed')
def record_request(): REQUESTS.inc()
# Start metrics server on port 9090
if __name__ == "__main__": start_http_server(9090)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Counter:&lt;/strong&gt; tracks the number of requests processed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;start_http_server:&lt;/strong&gt; exposes &lt;code&gt;/metrics&lt;/code&gt; endpoint for scraping.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why this, not logging only? Metrics can be aggregated and alerting rules can trigger automated remediation.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔔 Alerting with Prometheus Rules
&lt;/h3&gt;

&lt;p&gt;Define an alert that fires when latency exceeds a threshold.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# alerts.yaml
groups: - name: product.rules rules: - alert: HighLatency expr: histogram_quantile(0.95, product_latency_seconds_bucket) &amp;gt; 2 for: 2m labels: severity: critical annotations: summary: "95th percentile latency &amp;gt; 2s"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;expr:&lt;/strong&gt; evaluates the 95th percentile latency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;for:&lt;/strong&gt; ensures the condition persists for two minutes before firing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;labels &amp;amp; annotations:&lt;/strong&gt; provide context for the alert manager.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why this, not a one‑off dashboard? Alerts close the feedback loop by prompting immediate investigation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; Embedded observability turns runtime data into actionable insight, a hallmark of product engineering.&lt;/p&gt;




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

&lt;p&gt;The &lt;strong&gt;transition from service to product engineering&lt;/strong&gt; is not a single tool change; it is a series of deliberate shifts in architecture, delivery, and feedback. By modularizing code, containerizing the artifact, automating the pipeline, and instrumenting observability, the same functionality that once lived as a bespoke service can now evolve as a maintainable product.&lt;/p&gt;

&lt;p&gt;For developers, the practical implication is that every change you make should be reproducible, testable, and observable. When those criteria are met, the codebase can be handed off, scaled, and iterated without the overhead of ad‑hoc scripts or manual deployments.&lt;/p&gt;

&lt;p&gt;Adopting a product mindset early reduces technical debt, improves team velocity, and aligns engineering output with business outcomes.&lt;/p&gt;

&lt;h2&gt;
  
  
  ❓ Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How do I decide which parts of a service can be turned into a product?
&lt;/h3&gt;

&lt;p&gt;Identify functionality that is stable, has a clear input‑output contract, and is reused across multiple clients. Encapsulate that functionality in a pure module and expose it via an API or CLI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is Kubernetes mandatory for productizing a service?
&lt;/h3&gt;

&lt;p&gt;No. A container image can be run on any host, but Kubernetes adds orchestration features—replication, self‑healing, and declarative rollout—that are hard to replicate manually.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the minimal set of metrics a product should expose?
&lt;/h3&gt;

&lt;p&gt;At least request count, error rate, and latency percentiles. These three provide a baseline for capacity planning and incident detection.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Want to practise this hands-on?&lt;/strong&gt; &lt;a href="https://m.do.co/c/8ea4ebe8f879" rel="noopener noreferrer"&gt;DigitalOcean&lt;/a&gt; gives new accounts &lt;strong&gt;$200 free credit for 60 days&lt;/strong&gt; — enough to spin up a full Linux/Docker/Kubernetes environment at no cost.&lt;/p&gt;

&lt;p&gt;📚 &lt;strong&gt;Recommended reading:&lt;/strong&gt; &lt;a href="https://amzn.to/3QBrSOj" rel="noopener noreferrer"&gt;Best DevOps &amp;amp; cloud books on Amazon&lt;/a&gt; — from Linux fundamentals to Kubernetes in production, curated for working engineers.&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 References &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Official Docker documentation — comprehensive guide to image layering and build caching: &lt;a href="https://docs.docker.com/engine/reference/builder/" rel="noopener noreferrer"&gt;docs.docker.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Kubernetes API reference — details on Deployment objects and their control loops: &lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/" rel="noopener noreferrer"&gt;kubernetes.io&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
