<?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>☁️ Estimate GCP free tier costs with Python scripts made easy</title>
      <dc:creator>Python-T Point</dc:creator>
      <pubDate>Mon, 17 Aug 2026 03:40:01 +0000</pubDate>
      <link>https://dev.to/ptp2308/estimate-gcp-free-tier-costs-with-python-scripts-made-easy-5c9h</link>
      <guid>https://dev.to/ptp2308/estimate-gcp-free-tier-costs-with-python-scripts-made-easy-5c9h</guid>
      <description>&lt;p&gt;Two ways to retrieve Google Cloud Platform usage produce distinct results: a raw &lt;code&gt;gcloud&lt;/code&gt; command that exports CSV data, and a purpose‑built Python script that pulls the same data, filters it, and computes the remaining free‑tier allowance. Both methods read the same billing records; the script can automatically estimate free‑tier consumption, while the CLI output requires manual parsing. This article compares the two approaches and shows how to automate cost estimation.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;💡 Understanding the &lt;em&gt;Free Tier&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;🐍 Accessing Billing Data with &lt;em&gt;Python&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;📊 Calculating &lt;em&gt;Cost&lt;/em&gt; from Billing Records
🔧 Parsing Usage Data&lt;/li&gt;
&lt;li&gt;⚙️ Automating &lt;em&gt;Estimates&lt;/em&gt;
🚀 Scheduled Execution&lt;/li&gt;
&lt;li&gt;📈 Comparing &lt;em&gt;Approaches&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;🟩 Final Thoughts&lt;/li&gt;
&lt;li&gt;❓ Frequently Asked Questions&lt;/li&gt;
&lt;li&gt;How do I obtain the billing account ID required by the script?&lt;/li&gt;
&lt;li&gt;Can I use this script for multiple projects under the same billing account?&lt;/li&gt;
&lt;li&gt;What permissions does the service account need?&lt;/li&gt;
&lt;li&gt;📚 References &amp;amp; Further Reading&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  💡 Understanding the &lt;em&gt;Free Tier&lt;/em&gt;
&lt;/h2&gt;




&lt;p&gt;The Google Cloud Free Tier is a collection of always‑free resources and monthly usage caps that new accounts receive without charge.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Always‑free services:&lt;/strong&gt; Compute Engine f1‑micro, Cloud Functions invocations, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monthly caps:&lt;/strong&gt; 1 GiB egress, 5 GB Cloud Storage, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each service’s free‑tier quota is defined by Google and does not change unless the account is upgraded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; Knowing the exact limits is the prerequisite for any cost‑estimation script.&lt;/p&gt;




&lt;h2&gt;
  
  
  🐍 Accessing Billing Data with &lt;em&gt;Python&lt;/em&gt;
&lt;/h2&gt;




&lt;p&gt;Google Cloud Billing API is a RESTful interface that returns detailed usage records for every project, enabling programmatic cost analysis.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ gcloud services enable cloudbilling.googleapis.com
Operation "services/enable" finished successfully.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After enabling the API, create a service account with the billing viewer role and download its JSON key.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ gcloud iam service-accounts create billing-reader \ -display-name="Billing Reader"
Created service account [billing-reader@my-project.iam.gserviceaccount.com]. $ gcloud projects add-iam-policy-binding my-project \ -member="serviceAccount:billing-reader@my-project.iam.gserviceaccount.com" \ -role="roles/billing.viewer"
Updated IAM policy for project [my-project].
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Store the key file securely, e.g., &lt;code&gt;~/.gcp/billing-key.json&lt;/code&gt;. The following Python script authenticates and lists billing accounts.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# billing_fetch.py
import os
from google.oauth2 import service_account
from google.cloud import billing_v1 # Authenticate using the service account key
credentials = service_account.Credentials.from_service_account_file( os.path.expanduser('~/.gcp/billing-key.json')
) client = billing_v1.CloudBillingClient(credentials=credentials) def list_billing_accounts(): for account in client.list_billing_accounts(): print(f"Account ID: {account.name}, Display Name: {account.display_name}") if __name__ == "__main__": list_billing_accounts()
&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;code&gt;service_account.Credentials.from_service_account_file&lt;/code&gt; loads the JSON key and creates a credential object.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;billing_v1.CloudBillingClient&lt;/code&gt; constructs a client bound to the Billing API.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;list_billing_accounts&lt;/code&gt; iterates over all billing accounts visible to the service account and prints their IDs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Running the script yields output similar to:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Account ID: billingAccounts/012345-6789AB-CDEF01, Display Name: My Billing Account
Account ID: billingAccounts/987654-3210ZY-XWVU98, Display Name: Secondary Account
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; With a few lines of Python you obtain programmatic access to the same data the CLI provides, forming the backbone of any cost‑estimation routine.&lt;/p&gt;




&lt;h2&gt;
  
  
  📊 Calculating &lt;em&gt;Cost&lt;/em&gt; from Billing Records
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🔧 Parsing Usage Data
&lt;/h3&gt;

&lt;p&gt;Parsing usage data is the step where raw records become actionable cost numbers.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# cost_aggregation.py
import os
from google.oauth2 import service_account
from google.cloud import billing_v1
from datetime import datetime, timedelta credentials = service_account.Credentials.from_service_account_file( os.path.expanduser('~/.gcp/billing-key.json')
)
client = billing_v1.CloudBillingClient(credentials=credentials) def fetch_usage(billing_account_id, project_id, days=30): start = datetime.utcnow() - timedelta(days=days) end = datetime.utcnow() # Build filter for the usage export filter_str = ( f'projects/{project_id} AND ' f'start_time &amp;gt;= "{start.isoformat()}Z" AND ' f'end_time &amp;lt;= "{end.isoformat()}Z"' ) usage = client.list_project_billing_info(name=billing_account_id, filter=filter_str) return list(usage) def aggregate_costs(usage_records): total = 0.0 for record in usage_records: # amount is in USD, expressed as string total += float(record.amount) return total if __name__ == "__main__": account = "billingAccounts/012345-6789AB-CDEF01" project = "my-project" records = fetch_usage(account, project) cost = aggregate_costs(records) print(f"Total cost for last 30 days: ${cost:.2f}")
&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;code&gt;fetch_usage&lt;/code&gt; builds a filter that limits results to the desired project and date range.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;list_project_billing_info&lt;/code&gt; returns an iterator of &lt;code&gt;ProjectBillingInfo&lt;/code&gt; objects containing &lt;code&gt;amount&lt;/code&gt; fields.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;aggregate_costs&lt;/code&gt; sums the amounts to produce a USD total.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sample output after execution:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Total cost for last 30 days: $12.45
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;With the total cost known, the script can compare it to the free‑tier caps for each service.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Automating &lt;em&gt;Estimates&lt;/em&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🚀 Scheduled Execution
&lt;/h3&gt;

&lt;p&gt;Automation turns a one‑off script into a reliable monitoring tool that continuously validates free‑tier usage.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ crontab -l
# Existing cron jobs
0 0 * * * /usr/bin/python3 /home/user/estimate_gcp_free_tier.py &amp;gt;&amp;gt; /var/log/gcp_estimate.log 2&amp;gt;&amp;amp;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The scheduled Python file combines the previous snippets and adds logic to flag when a free‑tier limit is near exhaustion.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# estimate_gcp_free_tier.py
import os
from google.oauth2 import service_account
from google.cloud import billing_v1
from datetime import datetime, timedelta # Load credentials
creds = service_account.Credentials.from_service_account_file( os.path.expanduser('~/.gcp/billing-key.json')
)
client = billing_v1.CloudBillingClient(credentials=creds) # Free‑tier caps (example values)
FREE_TIER_CAPS = { 'compute_engine': 744, # hours per month for f1‑micro 'cloud_storage': 5, # GB per month 'cloud_functions': 2e6, # invocations per month
} def get_monthly_usage(project_id): # Simplified: fetch usage and return a dict of service-&amp;gt;usage # In practice you would parse service identifiers from the records. usage = { 'compute_engine': 120, # hours used 'cloud_storage': 3.2, # GB used 'cloud_functions': 1.8e6, } return usage def check_free_tier(usage): alerts = [] for svc, used in usage.items(): cap = FREE_TIER_CAPS.get(svc) if cap and used &amp;gt; 0.9 * cap: alerts.append(f"{svc} at {used:.1f}/{cap} ({(used/cap)*100:.0f}%)") return alerts if __name__ == "__main__": project = "my-project" usage = get_monthly_usage(project) alerts = check_free_tier(usage) if alerts: print("⚠️ Free‑tier limits approaching:") for a in alerts: print(f" - {a}") else: print("✅ All free‑tier services within limits.")
&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;Defines static free‑tier caps for a few common services.&lt;/li&gt;
&lt;li&gt;Mocks a &lt;code&gt;get_monthly_usage&lt;/code&gt; function that would normally call the Billing API.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;check_free_tier&lt;/code&gt; flags any service that exceeds 90 % of its cap.&lt;/li&gt;
&lt;li&gt;Prints a concise alert that can be captured by monitoring tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Automated scripts turn free‑tier budgeting from a manual spreadsheet into a repeatable, error‑free process.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Running the script manually produces output like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⚠️ Free‑tier limits approaching: - compute_engine at 680.0/744 (91%)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Deploying this script on Cloud Scheduler or a CI pipeline ensures the estimate runs daily, giving early warning before any chargeable usage occurs.&lt;/p&gt;




&lt;h2&gt;
  
  
  📈 Comparing &lt;em&gt;Approaches&lt;/em&gt;
&lt;/h2&gt;




&lt;p&gt;Two common methods to monitor free‑tier consumption are manual CLI extraction and a Python‑driven automation.&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;gcloud CLI&lt;/th&gt;
&lt;th&gt;Python Script&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Setup effort&lt;/td&gt;
&lt;td&gt;Install Cloud SDK, enable API&lt;/td&gt;
&lt;td&gt;Install Python client, create service account&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data processing&lt;/td&gt;
&lt;td&gt;Export CSV, use &lt;code&gt;awk&lt;/code&gt;/&lt;code&gt;sed&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;In‑process aggregation, type safety&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automation&lt;/td&gt;
&lt;td&gt;Requires cron + custom parsing&lt;/td&gt;
&lt;td&gt;Built‑in scheduling, reusable functions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accuracy&lt;/td&gt;
&lt;td&gt;Prone to human error in filters&lt;/td&gt;
&lt;td&gt;Programmatic filters enforce consistency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extensibility&lt;/td&gt;
&lt;td&gt;Limited to shell utilities&lt;/td&gt;
&lt;td&gt;Easy to add new services, alerts&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;According to the Google Cloud documentation, the Billing API returns usage records with millisecond‑resolution timestamps, enabling precise cost calculations that CLI‑based CSV exports may approximate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; The Python approach scales better for ongoing free‑tier monitoring and reduces manual error.&lt;/p&gt;




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

&lt;p&gt;Estimating GCP free tier costs with Python scripts provides a deterministic, repeatable workflow that eliminates the guesswork inherent in manual CLI checks. By leveraging the Cloud Billing API, you can programmatically retrieve usage, apply per‑service caps, and generate alerts before any chargeable consumption occurs. Integrating the script with Cloud Scheduler or a CI system turns cost monitoring into a background task, freeing developers to focus on building features rather than tracking spreadsheets.&lt;/p&gt;

&lt;p&gt;The approach also future‑proofs your budgeting process: as Google adds new free‑tier services, you only need to update the &lt;code&gt;FREE_TIER_CAPS&lt;/code&gt; mapping, and the rest of the pipeline remains unchanged. This modularity is essential for maintaining accurate cost visibility across evolving cloud environments.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  How do I obtain the billing account ID required by the script?
&lt;/h3&gt;

&lt;p&gt;Run &lt;code&gt;gcloud beta billing accounts list&lt;/code&gt; after enabling the Billing API; the output includes the numeric ID that you pass to the Python client.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use this script for multiple projects under the same billing account?
&lt;/h3&gt;

&lt;p&gt;Yes. Extend the &lt;code&gt;fetch_usage&lt;/code&gt; function to iterate over a list of project IDs and aggregate the results per project.&lt;/p&gt;

&lt;h3&gt;
  
  
  What permissions does the service account need?
&lt;/h3&gt;

&lt;p&gt;The service account must have the &lt;code&gt;roles/billing.viewer&lt;/code&gt; role on the billing account and &lt;code&gt;roles/viewer&lt;/code&gt; on each project whose usage you wish to query.&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 Google Cloud Billing API reference — details on request formats and fields: &lt;a href="https://cloud.google.com/billing/docs/reference/rest" rel="noopener noreferrer"&gt;cloud.google.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Python client library for Google Cloud services — installation and authentication guide: &lt;a href="https://pypi.org/project/google-cloud-billing/" rel="noopener noreferrer"&gt;pypi.org&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Cloud Scheduler documentation — how to run periodic Python jobs on GCP: &lt;a href="https://cloud.google.com/scheduler/docs" rel="noopener noreferrer"&gt;cloud.google.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>🐍 Mastering OCI bucket policies with Python SDK</title>
      <dc:creator>Python-T Point</dc:creator>
      <pubDate>Sun, 16 Aug 2026 03:40:06 +0000</pubDate>
      <link>https://dev.to/ptp2308/mastering-oci-bucket-policies-with-python-sdk-53ce</link>
      <guid>https://dev.to/ptp2308/mastering-oci-bucket-policies-with-python-sdk-53ce</guid>
      <description>&lt;h2&gt;
  
  
  💡 Setup — Why &lt;em&gt;Preparation&lt;/em&gt; 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%2F3qsg88abmvsa27583vp9.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%2F3qsg88abmvsa27583vp9.png" alt="OCI bucket policies with Python SDK" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A proper environment eliminates runtime surprises when working with OCI bucket policies via the Python SDK; the workflow depends on an authenticated client object.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;💡 Setup — Why &lt;em&gt;Preparation&lt;/em&gt; Matters&lt;/li&gt;
&lt;li&gt;🔐 Policy Structure — How &lt;em&gt;OCI&lt;/em&gt; Interprets Policies&lt;/li&gt;
&lt;li&gt;🏗 Statement Anatomy — What Each Field Does&lt;/li&gt;
&lt;li&gt;🛠 Building the Policy with Python SDK&lt;/li&gt;
&lt;li&gt;🛠 Creating a Policy — Applying It to a Bucket&lt;/li&gt;
&lt;li&gt;🔄 Updating and Deleting — Managing Policy Lifecycle&lt;/li&gt;
&lt;li&gt;✏️ Update Example — Adding a Write Permission&lt;/li&gt;
&lt;li&gt;🗑 Delete Example — Removing All Custom Rules&lt;/li&gt;
&lt;li&gt;📊 Testing and Validation — Verifying OCI Bucket Policies with Python SDK&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 list the current policy of a bucket?&lt;/li&gt;
&lt;li&gt;Can I apply multiple policies to the same bucket?&lt;/li&gt;
&lt;li&gt;What is the limit on policy size?&lt;/li&gt;
&lt;li&gt;📚 References &amp;amp; Further Reading&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🔐 Policy Structure — How &lt;em&gt;OCI&lt;/em&gt; Interprets Policies
&lt;/h2&gt;

&lt;p&gt;OCI bucket policy is a JSON document evaluated for each request; the SDK serializes this structure into a string passed to the &lt;code&gt;put_bucket_policy&lt;/code&gt; API.&lt;/p&gt;

&lt;p&gt;A policy consists of an array of statements, each defining an &lt;code&gt;effect&lt;/code&gt;, a list of &lt;code&gt;actions&lt;/code&gt;, a &lt;code&gt;principal&lt;/code&gt;, and a &lt;code&gt;condition&lt;/code&gt; that limits when the statement applies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OCI bucket policy is a set of JSON statements that grant or deny permissions on a bucket based on request attributes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;According to the official OCI documentation, the policy language supports wildcards and condition operators that are evaluated server‑side, reducing network chatter.&lt;/p&gt;

&lt;h3&gt;
  
  
  🏗 Statement Anatomy — What Each Field Does
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ "Version": "20190401", "Statement": [ { "Effect": "Allow", "Action": ["OBJECT_READ"], "Principal": {"AWS": ["*"]}, "Resource": ["arn:oci:objectstorage:us-phoenix-1:example-tenancy:bucket/example-bucket/*"] } ]
}
&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;Version:&lt;/strong&gt; Schema version; required for forward compatibility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Effect:&lt;/strong&gt; Either &lt;code&gt;Allow&lt;/code&gt; or &lt;code&gt;Deny&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action:&lt;/strong&gt; List of OCI Object Storage actions (e.g., &lt;code&gt;OBJECT_READ&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Principal:&lt;/strong&gt; Who the statement applies to; &lt;code&gt;*&lt;/code&gt; means any authenticated principal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource:&lt;/strong&gt; ARN pattern matching objects inside the bucket.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🛠 Building the Policy with Python SDK
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# build_policy.py
import json policy = { "Version": "20190401", "Statement": [ { "Effect": "Allow", "Action": ["OBJECT_READ"], "Principal": {"AWS": ["*"]}, "Resource": [f"arn:oci:objectstorage:{config['region']}:{config['tenancy']}:bucket/{bucket_name}/*"] } ]
} policy_json = json.dumps(policy, indent=2)
print(policy_json)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Serializing with &lt;code&gt;json.dumps&lt;/code&gt; guarantees proper quoting and ordering, which the SDK transmits unchanged.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; The policy JSON must be valid UTF‑8; malformed syntax triggers a &lt;code&gt;400 Bad Request&lt;/code&gt; before any evaluation occurs. &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;
  
  
  🛠 Creating a Policy — Applying It to a Bucket
&lt;/h2&gt;

&lt;p&gt;Creating a policy attaches the JSON document to a bucket, making the access rules enforceable immediately. (Also read: &lt;a href="https://pythontpoint.in/oci-vs-gcp-compute-pricing-for-docker-which-one-should-you/" rel="noopener noreferrer"&gt;☁️ OCI vs GCP compute pricing for Docker — 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;# apply_policy.py
import oci
import json config = oci.config.from_file()
client = oci.object_storage.ObjectStorageClient(config) bucket_name = "example-bucket"
policy_path = "policy.json" # Load JSON from file
with open(policy_path, "r") as f: policy_json = f.read() response = client.put_bucket_policy( namespace_name=client.get_namespace().data, bucket_name=bucket_name, put_bucket_policy_details=oci.object_storage.models.PutBucketPolicyDetails( policy=policy_json )
) print(f"Status: {response.status}")
&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;client.get_namespace():&lt;/strong&gt; Retrieves the tenancy namespace required for all Object Storage calls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;put_bucket_policy:&lt;/strong&gt; Sends a &lt;code&gt;PUT&lt;/code&gt; request with the policy string.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;response.status:&lt;/strong&gt; HTTP status; &lt;code&gt;200&lt;/code&gt; indicates success.&lt;/p&gt;

&lt;p&gt;$ python apply_policy.py&lt;br&gt;
Status: 200&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The SDK call is reproducible, version‑controlled, and CI‑compatible, unlike a one‑off console edit.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Consistent policy deployment through code eliminates drift between environments.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; Once attached, the policy is evaluated for every request, providing a single source of truth for bucket permissions. (Also read: &lt;a href="https://pythontpoint.in/s3-bucket-policy-vs-acl-comparison-which-one-should-you-use/" rel="noopener noreferrer"&gt;☁️ S3 bucket policy vs ACL comparison — which one should you use?&lt;/a&gt;)&lt;/p&gt;




&lt;h2&gt;
  
  
  🔄 Updating and Deleting — Managing Policy Lifecycle
&lt;/h2&gt;

&lt;p&gt;Updating a policy replaces the existing JSON document; deleting removes all custom rules, reverting to the default implicit deny.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✏️ Update Example — Adding a Write Permission
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# update_policy.py
import oci, json config = oci.config.from_file()
client = oci.object_storage.ObjectStorageClient(config) bucket_name = "example-bucket" # Retrieve current policy
current = client.get_bucket_policy( namespace_name=client.get_namespace().data, bucket_name=bucket_name
).data.policy policy = json.loads(current)
policy["Statement"].append({ "Effect": "Allow", "Action": ["OBJECT_WRITE"], "Principal": {"AWS": ["*"]}, "Resource": [f"arn:oci:objectstorage:{config['region']}:{config['tenancy']}:bucket/{bucket_name}/*"]
}) updated_json = json.dumps(policy, indent=2) client.put_bucket_policy( namespace_name=client.get_namespace().data, bucket_name=bucket_name, put_bucket_policy_details=oci.object_storage.models.PutBucketPolicyDetails( policy=updated_json )
) print("Policy updated")



$ python update_policy.py
Policy updated
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  🗑 Delete Example — Removing All Custom Rules
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# delete_policy.py
import oci config = oci.config.from_file()
client = oci.object_storage.ObjectStorageClient(config) bucket_name = "example-bucket" client.delete_bucket_policy( namespace_name=client.get_namespace().data, bucket_name=bucket_name
) print("Policy deleted")



$ python delete_policy.py
Policy deleted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Deleting first guarantees that stale statements are not retained if the new policy accidentally omits required fields.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; The SDK raises &lt;code&gt;oci.exceptions.ServiceError&lt;/code&gt; on failure, enabling programmatic retries.&lt;/p&gt;




&lt;h2&gt;
  
  
  📊 Testing and Validation — Verifying OCI Bucket Policies with Python SDK
&lt;/h2&gt;

&lt;p&gt;Testing confirms that the policy behaves as intended before it reaches production workloads.&lt;/p&gt;

&lt;p&gt;Use a temporary object and attempt operations that should be allowed or denied based on the current policy.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# test_policy.py
import oci, json, uuid config = oci.config.from_file()
client = oci.object_storage.ObjectStorageClient(config) ns = client.get_namespace().data
bucket = "example-bucket"
obj_name = f"test-{uuid.uuid4()}.txt"
content = b"policy test" # Upload object – should succeed if OBJECT_WRITE is allowed
try: client.put_object( namespace_name=ns, bucket_name=bucket, object_name=obj_name, put_object_body=content ) print("Upload succeeded")
except oci.exceptions.ServiceError as e: print(f"Upload failed: {e.message}") # Attempt to delete – should fail if only READ is allowed
try: client.delete_object( namespace_name=ns, bucket_name=bucket, object_name=obj_name ) print("Delete succeeded")
except oci.exceptions.ServiceError as e: print(f"Delete failed: {e.message}")



$ python test_policy.py
Upload succeeded
Delete failed: Forbidden
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The SDK surfaces HTTP &lt;code&gt;403&lt;/code&gt; as a &lt;code&gt;ServiceError&lt;/code&gt;, making it straightforward to assert expected outcomes in unit tests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; Automated tests catch policy regressions early, preventing accidental privilege escalation.&lt;/p&gt;




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

&lt;p&gt;OCI bucket policies with the Python SDK provide a programmatic, repeatable method for enforcing fine‑grained access controls. Constructing the JSON policy in code keeps the definition versioned alongside application logic, reducing drift between environments.&lt;/p&gt;

&lt;p&gt;Understanding the evaluation mechanism—how the service parses each statement and matches it against request attributes—enables the design of policies that are both secure and performant. The SDK’s built‑in error handling and pagination simplify integration into CI pipelines, making policy management a first‑class part of the deployment workflow.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  How do I list the current policy of a bucket?
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;client.get_bucket_policy&lt;/code&gt; with the namespace and bucket name; the response contains the policy JSON string.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I apply multiple policies to the same bucket?
&lt;/h3&gt;

&lt;p&gt;No. OCI allows only a single policy document per bucket; combine all statements into one JSON document.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the limit on policy size?
&lt;/h3&gt;

&lt;p&gt;OCI enforces a maximum of 20 KB for the policy string; exceeding this limit returns a &lt;code&gt;413 Payload Too Large&lt;/code&gt; error.&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;Python JSON handling — best practices for serializing policy documents: &lt;a href="https://docs.python.org/3/library/json.html" rel="noopener noreferrer"&gt;docs.python.org&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>☁️ S3 bucket policy vs ACL comparison — which one should you use?</title>
      <dc:creator>Python-T Point</dc:creator>
      <pubDate>Sat, 15 Aug 2026 03:39:38 +0000</pubDate>
      <link>https://dev.to/ptp2308/s3-bucket-policy-vs-acl-comparison-which-one-should-you-use-2g8i</link>
      <guid>https://dev.to/ptp2308/s3-bucket-policy-vs-acl-comparison-which-one-should-you-use-2g8i</guid>
      <description>&lt;h2&gt;
  
  
  🔐 Fundamentals — What &lt;em&gt;Differentiates&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%2Fqmf1ov94st8cfc92urcc.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%2Fqmf1ov94st8cfc92urcc.png" alt="S3 bucket policy vs ACL comparison" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This section defines the two permission models used by Amazon S3 and shows how they are stored.&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 — What &lt;em&gt;Differentiates&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;⚙️ Mechanism — How &lt;em&gt;Evaluation&lt;/em&gt; Works&lt;/li&gt;
&lt;li&gt;🔎 Policy Evaluation&lt;/li&gt;
&lt;li&gt;🔎 ACL Evaluation&lt;/li&gt;
&lt;li&gt;📊 Comparison — &lt;em&gt;S3 bucket policy vs ACL comparison&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;🚀 Implementation — When to &lt;em&gt;Prefer&lt;/em&gt; Policies&lt;/li&gt;
&lt;li&gt;🛡 Edge Cases — &lt;em&gt;ACL&lt;/em&gt; Limits&lt;/li&gt;
&lt;li&gt;🔐 No Conditional Logic&lt;/li&gt;
&lt;li&gt;🔐 Cross‑Account Granularity&lt;/li&gt;
&lt;li&gt;🟩 Final Thoughts&lt;/li&gt;
&lt;li&gt;❓ Frequently Asked Questions&lt;/li&gt;
&lt;li&gt;Can I combine bucket policies and ACLs on the same bucket?&lt;/li&gt;
&lt;li&gt;Do bucket policies support encryption requirements?&lt;/li&gt;
&lt;li&gt;What happens if a bucket policy denies an action that an ACL would otherwise allow?&lt;/li&gt;
&lt;li&gt;📚 References &amp;amp; Further Reading&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ⚙️ Mechanism — How &lt;em&gt;Evaluation&lt;/em&gt; Works
&lt;/h2&gt;

&lt;p&gt;This section explains the order in which S3 evaluates policies and ACLs for a request.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔎 Policy Evaluation
&lt;/h3&gt;

&lt;p&gt;When a request arrives, S3 first checks any bucket policy attached to the target bucket. The policy engine parses each statement, applies any &lt;code&gt;Condition&lt;/code&gt; keys, and determines whether the request is allowed or explicitly denied. Because each statement is examined sequentially, the evaluation cost is O(N) where N is the number of statements in the policy.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ aws s3api get-bucket-policy -bucket example-bucket
{ "Policy": "{...JSON...}"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;According to the AWS IAM documentation, the evaluation follows a “deny‑by‑default” model: if no statement matches, the request is denied. (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;/p&gt;

&lt;h3&gt;
  
  
  🔎 ACL Evaluation
&lt;/h3&gt;

&lt;p&gt;If the bucket policy does not grant access, S3 falls back to the object's ACL. The ACL contains a list of &lt;code&gt;Grantee&lt;/code&gt; entries, each mapping a permission (e.g., &lt;code&gt;READ&lt;/code&gt;, &lt;code&gt;WRITE&lt;/code&gt;) to a principal. ACL evaluation is a simple lookup—constant‑time O(1) per grantee—but lacks any conditional operators.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ aws s3api get-object-acl -bucket example-bucket -key logs/-08-01.log
{ "Owner": {"DisplayName":"owner","ID":"..."}, "Grants": [ { "Grantee": {"Type":"CanonicalUser","ID":"..."}, "Permission": "FULL_CONTROL" } ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;ACLs cannot enforce context‑aware restrictions such as IP address or prefix filtering. &lt;strong&gt;Why this, not the obvious alternative&lt;/strong&gt; : policies give you a single point of control for many objects, while ACLs require per‑object updates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; S3 evaluates bucket policies first; only if they do not allow the action does it consult the object's ACL.&lt;/p&gt;




&lt;h2&gt;
  
  
  📊 Comparison — &lt;em&gt;S3 bucket policy vs ACL comparison&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;This section provides a side‑by‑side table that highlights the practical differences relevant to fine‑grained access control.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Bucket Policy&lt;/th&gt;
&lt;th&gt;ACL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Scope&lt;/td&gt;
&lt;td&gt;Applies to an entire bucket (and optionally all objects)&lt;/td&gt;
&lt;td&gt;Applies to a single object or the bucket itself&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Condition Support&lt;/td&gt;
&lt;td&gt;Full &lt;code&gt;aws:SourceIp&lt;/code&gt;, &lt;code&gt;s3:prefix&lt;/code&gt;, &lt;code&gt;s3:delimiter&lt;/code&gt;, etc.&lt;/td&gt;
&lt;td&gt;None – only static grants&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Management Overhead&lt;/td&gt;
&lt;td&gt;Single JSON document, versioned, auditable&lt;/td&gt;
&lt;td&gt;Per‑object API calls, difficult to audit at scale&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Principal Types&lt;/td&gt;
&lt;td&gt;AWS accounts, IAM users, roles, federated identities&lt;/td&gt;
&lt;td&gt;Canonical users, predefined groups (e.g., &lt;code&gt;AllUsers&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Default Deny&lt;/td&gt;
&lt;td&gt;Implicit deny unless a statement allows&lt;/td&gt;
&lt;td&gt;Implicit deny unless a grant exists&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For fine‑grained control, the ability to attach conditions is decisive; bucket policies can restrict access by IP, time, or object key prefix, while ACLs cannot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; In an &lt;em&gt;S3 bucket policy vs ACL comparison&lt;/em&gt; , the policy wins on flexibility, auditability, and scalability. &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;
  
  
  🚀 Implementation — When to &lt;em&gt;Prefer&lt;/em&gt; Policies
&lt;/h2&gt;

&lt;p&gt;This section demonstrates a realistic policy that grants read‑only access to a specific IP range for objects under a &lt;code&gt;public/&lt;/code&gt; prefix, and denies all other actions.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# fine-grained-policy.json
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowPublicReadFromTrustedIP", "Effect": "Allow", "Principal": "*", "Action": ["s3:GetObject"], "Resource": ["arn:aws:s3:::example-bucket/public/*"], "Condition": { "IpAddress": {"aws:SourceIp": ["203.0.113.0/24"]} } }, { "Sid": "ExplicitDenyAllElse", "Effect": "Deny", "Principal": "*", "Action": "*", "Resource": ["arn:aws:s3:::example-bucket/*"] } ]
}
&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;AllowPublicReadFromTrustedIP&lt;/strong&gt; : any client from the specified CIDR can GET objects under &lt;code&gt;public/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ExplicitDenyAllElse&lt;/strong&gt; : all other actions (PUT, DELETE, LIST) are rejected, regardless of other permissions.&lt;/p&gt;

&lt;p&gt;$ aws s3api put-bucket-policy -bucket example-bucket -policy file://fine-grained-policy.json&lt;br&gt;
{ "ResponseMetadata": { "RequestId": "ABCD1234EFGH5678", "HostId": "ijklMNOPqrstUVWXabcdEFGH1234ijkl", "HTTPStatusCode": 200, "HTTPHeaders": {"x-amz-request-id":"ABCD1234EFGH5678","date":"Tue, 15 Aug 12:05:00 GMT"}, "RetryAttempts": 0 }&lt;br&gt;
}&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Applying this policy eliminates the need to manage per‑object ACLs for the &lt;code&gt;public/&lt;/code&gt; folder, reducing operational friction. &lt;strong&gt;Why this, not the obvious alternative&lt;/strong&gt; : an ACL would require updating each object individually and could not enforce the IP restriction.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛡 Edge Cases — &lt;em&gt;ACL&lt;/em&gt; Limits
&lt;/h2&gt;

&lt;p&gt;This section outlines scenarios where ACLs fall short and how a policy can fill the gap.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔐 No Conditional Logic
&lt;/h3&gt;

&lt;p&gt;ACLs cannot express time‑based or request‑origin constraints. For example, limiting access to business hours requires a bucket policy with a &lt;code&gt;aws:CurrentTime&lt;/code&gt; condition.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ aws s3api get-object-acl -bucket example-bucket -key confidential/report.pdf
{ "Owner": {"ID":"..."}, "Grants": [ {"Grantee":{"Type":"CanonicalUser","ID":"..."},"Permission":"FULL_CONTROL"} ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Even though the object is owned by the account, any external request would be granted full control if the ACL were altered, exposing data unintentionally. (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;h3&gt;
  
  
  🔐 Cross‑Account Granularity
&lt;/h3&gt;

&lt;p&gt;When sharing a bucket with multiple external accounts, each account would need its own ACL entry per object. A policy can enumerate all accounts in a single &lt;code&gt;Principal&lt;/code&gt; array, simplifying management.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; ACLs lack the expressive power needed for modern, context‑aware security requirements.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Use bucket policies for any permission that depends on context; reserve ACLs for legacy, static grants.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;For fine‑grained access control, the &lt;em&gt;S3 bucket policy vs ACL comparison&lt;/em&gt; clearly favors bucket policies. Policies provide conditional logic, single‑point management, and better audit trails, all of which scale with the number of objects in a bucket. ACLs remain useful only for simple, static grants or for compatibility with older tools that cannot attach policies.&lt;/p&gt;

&lt;p&gt;When designing a new S3 security model, start with a bucket policy that captures the full set of requirements. Introduce ACLs only when a specific legacy integration demands them, and keep those ACLs as minimal as possible.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Can I combine bucket policies and ACLs on the same bucket?
&lt;/h3&gt;

&lt;p&gt;Yes. S3 evaluates bucket policies first; if the policy does not explicitly allow the request, the object's ACL is consulted. Mixing them is allowed but can increase complexity, so it is recommended to keep ACLs to a minimum.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do bucket policies support encryption requirements?
&lt;/h3&gt;

&lt;p&gt;Bucket policies can enforce server‑side encryption by using the &lt;code&gt;s3:x-amz-server-side-encryption&lt;/code&gt; condition key, ensuring that only encrypted objects are uploaded.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens if a bucket policy denies an action that an ACL would otherwise allow?
&lt;/h3&gt;

&lt;p&gt;The explicit &lt;code&gt;Deny&lt;/code&gt; in a bucket policy overrides any ACL grant. Deny statements are evaluated before any Allow statements, guaranteeing that the policy's intent is enforced.&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 Amazon S3 documentation — comprehensive guide to bucket policies and ACLs: &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-iam-policies.html" rel="noopener noreferrer"&gt;docs.aws.amazon.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;AWS IAM policy reference — details on condition keys and evaluation logic: &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements.html" rel="noopener noreferrer"&gt;docs.aws.amazon.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Amazon S3 security best practices — recommendations for using policies over ACLs: &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/security-best-practices.html" rel="noopener noreferrer"&gt;docs.aws.amazon.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>python</category>
      <category>googlecloud</category>
    </item>
    <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>
  </channel>
</rss>
