<?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: Quoc-Hung Hoang</title>
    <description>The latest articles on DEV Community by Quoc-Hung Hoang (@hoangquochung1110).</description>
    <link>https://dev.to/hoangquochung1110</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F764813%2F7591ed1e-819d-467e-be8d-b5f68bd0456d.jpeg</url>
      <title>DEV Community: Quoc-Hung Hoang</title>
      <link>https://dev.to/hoangquochung1110</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hoangquochung1110"/>
    <language>en</language>
    <item>
      <title>AWS Lambda Deployment Made Easy with GitHub Actions</title>
      <dc:creator>Quoc-Hung Hoang</dc:creator>
      <pubDate>Sat, 09 Aug 2025 16:13:21 +0000</pubDate>
      <link>https://dev.to/hoangquochung1110/aws-lambda-deployment-made-easy-with-github-actions-57e</link>
      <guid>https://dev.to/hoangquochung1110/aws-lambda-deployment-made-easy-with-github-actions-57e</guid>
      <description>&lt;h2&gt;
  
  
  Great News for the Serverless Community! 🚀
&lt;/h2&gt;

&lt;p&gt;On August 7th, AWS released the &lt;code&gt;aws-actions/aws-lambda-deploy&lt;/code&gt; action for GitHub Actions, designed to streamline the deployment and configuration updates for Lambda functions on AWS.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Did Lambda Deployment Work Before?
&lt;/h3&gt;

&lt;p&gt;Previously, developers had to manually define AWS SDK commands (or use IaC tools like Terraform or SAM) to build, package code artifacts, and upload them as zip files or through S3 buckets for Lambda function deployment:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Build code&lt;/strong&gt; from source&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Package&lt;/strong&gt; into ZIP files or container images&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Upload&lt;/strong&gt; to S3 buckets, ECR, or as zip files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Update&lt;/strong&gt; Lambda function configuration&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The New Solution: Just One Action!
&lt;/h3&gt;

&lt;p&gt;Now you simply need to declare &lt;code&gt;aws-actions/aws-lambda-deploy&lt;/code&gt; in your GitHub Actions workflow with parameters like: &lt;code&gt;function-name&lt;/code&gt;, &lt;code&gt;code-artifacts-dir&lt;/code&gt; (directory containing Lambda function source code), &lt;code&gt;handler&lt;/code&gt;, and &lt;code&gt;runtime&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Under the hood, this action leverages the &lt;a href="https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/" rel="noopener noreferrer"&gt;AWS SDK for JavaScript&lt;/a&gt; and packages everything into a unified, user-friendly experience.&lt;/p&gt;

&lt;p&gt;Check out the detailed release announcement &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/deploying-github-actions.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real-World Implementation
&lt;/h3&gt;

&lt;p&gt;Here's a GitHub Actions workflow from the &lt;a href="https://github.com/hoangquochung1110/insta-post-extractor" rel="noopener noreferrer"&gt;Instagram Post Extractor&lt;/a&gt; project—a Lambda function that extracts metadata from Instagram posts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Lambda CD Pipeline&lt;/span&gt;
&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt; &lt;span class="c1"&gt;# Required for OIDC authentication&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;development&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;AWS_REGION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ap-southeast-1&lt;/span&gt;
  &lt;span class="na"&gt;S3_BUCKET&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ig-post-extractor-artifact&lt;/span&gt;
  &lt;span class="na"&gt;LAMBDA_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;IgPostExtractor&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Configure AWS credentials with OIDC&lt;/span&gt;
      &lt;span class="c1"&gt;# Use OpenID Connect (OIDC) to authenticate with AWS to avoid&lt;/span&gt;
      &lt;span class="c1"&gt;# storing AWS credentials as long-lived GitHub secrets&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/configure-aws-credentials@v4&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;role-to-assume&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_ROLE_TO_ASSUME }}&lt;/span&gt;
        &lt;span class="na"&gt;aws-region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.AWS_REGION }}&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy Lambda Function&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/aws-lambda-deploy@v1&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;function-name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.LAMBDA_NAME }}&lt;/span&gt;
        &lt;span class="na"&gt;code-artifacts-dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;src/functions/&lt;/span&gt;
        &lt;span class="na"&gt;s3-bucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.S3_BUCKET }}&lt;/span&gt;
        &lt;span class="c1"&gt;# Generate unique S3 key with timestamp and git commit hash&lt;/span&gt;
        &lt;span class="na"&gt;s3-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;functions/"$(date +%Y%m%d%H%M%S)-${{ github.sha }}"&lt;/span&gt;
        &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ig_post_extractor.lambda_handler&lt;/span&gt;
        &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python3.12&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Triển khai AWS Lambda functions nay đã dễ dàng hơn với Github Actions</title>
      <dc:creator>Quoc-Hung Hoang</dc:creator>
      <pubDate>Sat, 09 Aug 2025 16:09:08 +0000</pubDate>
      <link>https://dev.to/hoangquochung1110/trien-khai-aws-lambda-functions-nay-da-de-dang-hon-voi-github-actions-b19</link>
      <guid>https://dev.to/hoangquochung1110/trien-khai-aws-lambda-functions-nay-da-de-dang-hon-voi-github-actions-b19</guid>
      <description>&lt;h2&gt;
  
  
  Tin vui cho cộng đồng Serverless! 🚀
&lt;/h2&gt;

&lt;p&gt;Ngày 07 tháng 8 vừa rồi, AWS vừa release action &lt;code&gt;aws-actions/aws-lambda-deploy&lt;/code&gt; tích hợp trong Github Actions nhằm cập nhật cấu hình và mã nguồn của Lambda functions trên môi trường AWS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Việc deploy Lambda trước kia như thế nào?
&lt;/h3&gt;

&lt;p&gt;Developers cần định nghĩa thủ công các dòng lệnh AWS SDK (hoặc IaC như Terraform hay SAM) để thực hiện build, đóng gói code artifact rồi upload ở dạng zip hoặc thông qua S3 bucket để triển khai Lambda function:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. **Build code** từ source
2. **Đóng gói** thành file ZIP hoặc container image
3. **Upload** lên S3 bucket hoặc ECR hoặc zip file
4. **Update** Lambda function configuration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Giải pháp mới: Chỉ cần 1 action duy nhất!
&lt;/h3&gt;

&lt;p&gt;Giờ đây bạn chỉ cần khai báo &lt;code&gt;aws-actions/aws-lambda-deploy&lt;/code&gt; trong Github Actions workflow kèm các tham số như: &lt;code&gt;function-name&lt;/code&gt;, &lt;code&gt;code-artifacts-dir&lt;/code&gt; (thư mục chứa mã nguồn Lambda function), &lt;code&gt;handler&lt;/code&gt;, &lt;code&gt;runtime&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Về cách thức hoạt động, action này sẽ dựa vào &lt;a href="https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/" rel="noopener noreferrer"&gt;AWS SDK for JavaScript&lt;/a&gt; và đóng gói thành khối thống nhất để thuận tiện cho người dùng.&lt;/p&gt;

&lt;p&gt;Xem chi tiết thông báo release &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/deploying-github-actions.html" rel="noopener noreferrer"&gt;tại đây&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Thực hành với dự án thực tế
&lt;/h3&gt;

&lt;p&gt;Dưới đây là một Github Actions workflow lấy từ dự án &lt;a href="https://github.com/hoangquochung1110/insta-post-extractor" rel="noopener noreferrer"&gt;Instagram Post Extractor&lt;/a&gt;, một Lambda function để extract metadata từ Instagram posts.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Lambda CD Pipeline&lt;/span&gt;
&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt; &lt;span class="c1"&gt;# Cần thiết cho OIDC authentication&lt;/span&gt;


&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;development&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;AWS_REGION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ap-southeast-1&lt;/span&gt;
  &lt;span class="na"&gt;S3_BUCKET&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ig-post-extractor-artifact&lt;/span&gt;
  &lt;span class="na"&gt;LAMBDA_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;IgPostExtractor&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Configure AWS credentials with OIDC&lt;/span&gt;
      &lt;span class="c1"&gt;# use OpenID Connect (OIDC) to authenticate with AWS to avoid&lt;/span&gt;
      &lt;span class="c1"&gt;# storing AWS credentials as long-lived GitHub secrets.&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/configure-aws-credentials@v4&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;role-to-assume&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_ROLE_TO_ASSUME }}&lt;/span&gt;
        &lt;span class="na"&gt;aws-region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.AWS_REGION }}&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy Lambda Function&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/aws-lambda-deploy@v1&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;function-name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.LAMBDA_NAME }}&lt;/span&gt;
        &lt;span class="na"&gt;code-artifacts-dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;src/functions/&lt;/span&gt;
        &lt;span class="na"&gt;s3-bucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.S3_BUCKET }}&lt;/span&gt;
        &lt;span class="c1"&gt;# Tạo unique S3 key với timestamp và git commit hash&lt;/span&gt;
        &lt;span class="na"&gt;s3-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;functions/"$(date +%Y%m%d%H%M%S)-${{ github.sha }}"&lt;/span&gt;
        &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ig_post_extractor.lambda_handler&lt;/span&gt;
        &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python3.12&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>lambda</category>
      <category>aws</category>
      <category>githubactions</category>
    </item>
    <item>
      <title>Bổ sung ngữ cảnh cho LLM: Nâng cao độ chính xác và tin cậy cho ứng dụng GenAI</title>
      <dc:creator>Quoc-Hung Hoang</dc:creator>
      <pubDate>Wed, 25 Jun 2025 15:13:22 +0000</pubDate>
      <link>https://dev.to/hoangquochung1110/bo-sung-ngu-canh-cho-llm-nang-cao-do-chinh-xac-va-tin-cay-cho-ung-dung-genai-47ef</link>
      <guid>https://dev.to/hoangquochung1110/bo-sung-ngu-canh-cho-llm-nang-cao-do-chinh-xac-va-tin-cay-cho-ung-dung-genai-47ef</guid>
      <description>&lt;p&gt;Các Mô hình Ngôn ngữ Lớn (LLM) là những công cụ đa năng mạnh mẽ, nhưng giá trị thực sự của chúng trong môi trường kinh doanh chỉ được khai phá khi chúng có thể hoạt động với thông tin cụ thể và phù hợp. Mặc định, một LLM không có kiến thức về dữ liệu nội bộ, các sự kiện thời gian thực, hay hoàn cảnh riêng của người dùng. Để thu hẹp khoảng cách này, chúng ta phải cung cấp cho nó ngữ cảnh.&lt;/p&gt;

&lt;p&gt;Có nhiều kỹ thuật để làm điều này, mỗi kỹ thuật đại diện cho một mức độ phức tạp, chi phí và năng lực khác nhau. Hiểu rõ các phương pháp này cho phép bạn lựa chọn chiến lược phù hợp với nhu cầu cụ thể của mình. Dưới đây là bốn kỹ thuật thiết yếu, được sắp xếp theo thứ tự từ đơn giản đến phức tạp nhất.&lt;/p&gt;

&lt;h1&gt;
  
  
  Các phương thức bổ sung ngữ cảnh cho LLMs
&lt;/h1&gt;

&lt;p&gt;Các Mô hình Ngôn ngữ Lớn (LLM) là những công cụ đa năng mạnh mẽ, nhưng giá trị thực sự của chúng trong môi trường kinh doanh chỉ được khai phá khi chúng có thể hoạt động với thông tin cụ thể và phù hợp. Mặc định, một LLM không có kiến thức về dữ liệu nội bộ, các sự kiện thời gian thực, hay hoàn cảnh riêng của người dùng. Để thu hẹp khoảng cách này, chúng ta phải cung cấp cho nó ngữ cảnh.&lt;/p&gt;

&lt;p&gt;Có nhiều kỹ thuật để làm điều này, mỗi kỹ thuật đại diện cho một mức độ phức tạp, chi phí và năng lực khác nhau. Hiểu rõ các phương pháp này cho phép bạn lựa chọn chiến lược phù hợp với nhu cầu cụ thể của mình. Dưới đây là bốn kỹ thuật thiết yếu, được sắp xếp theo thứ tự từ đơn giản đến phức tạp nhất.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.ssan.me%2Fllm_context_chart.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%2Fstatic.ssan.me%2Fllm_context_chart.png" alt="Add context to LLMs" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1: Kỹ thuật Prompt theo Ngữ cảnh (Contextual Prompt Engineering)
&lt;/h2&gt;

&lt;p&gt;Đây là phương pháp trực tiếp và đơn giản nhất. Nó bao gồm việc chèn thông tin mà LLM cần trực tiếp vào câu lệnh (prompt), cùng với truy vấn của người dùng.&lt;br&gt;
Cách thức hoạt động: Bạn xây dựng một câu lệnh bao gồm cả ngữ cảnh thực tế cần thiết và câu hỏi bạn muốn LLM trả lời. Mô hình sử dụng thông tin được cung cấp này để hình thành phản hồi cho duy nhất lượt tương tác đó.&lt;/p&gt;

&lt;p&gt;❌&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write about climate change
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are an environmental science educator writing for high school students.

Write a 300-word explanation of climate change that:
- Defines climate change in simple terms
- Explains 2-3 main causes
- Describes 2-3 observable effects
- Suggests 2 actionable steps students can take

Use clear, accessible language and include one concrete example or analogy to make the concept relatable. Structure your response with clear paragraphs and avoid technical jargon.

Format: Start with a hook sentence, then provide the explanation, and end with an encouraging call to action.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡 Cách tiếp cận này là con đường nhanh nhất để bắt đầu. Nó không đòi hỏi hạ tầng đặc biệt và hoàn hảo cho việc tạo mẫu thử nghiệm và các ứng dụng đơn giản nơi ngữ cảnh nhỏ và thay đổi theo từng truy vấn. Nó xem LLM như một bộ máy suy luận thuần túy, cung cấp tất cả các dữ kiện cần thiết một cách tạm thời.&lt;/p&gt;

&lt;p&gt;✅ Ưu điểm: Rào cản gia nhập cực kỳ thấp; không yêu cầu huấn luyện hay quản lý dữ liệu.&lt;br&gt;
⚠️ Nhược điểm: Bị giới hạn nghiêm trọng bởi cửa sổ ngữ cảnh (lượng văn bản tối đa mà mô hình có thể xử lý cùng lúc). Nó không hiệu quả khi triển khai ở quy mô lớn, vì bạn liên tục gửi và trả phí cho cùng một ngữ cảnh. Kiến thức này chỉ là tạm thời và sẽ bị "lãng quên" ngay sau khi phản hồi được tạo ra.&lt;/p&gt;

&lt;h2&gt;
  
  
  2: Sinh Nội dung Tăng cường bằng Truy xuất (RAG)
&lt;/h2&gt;

&lt;p&gt;RAG là phương pháp tiếp cận phổ biến và thực tế nhất để xây dựng các ứng dụng mạnh mẽ, giàu kiến thức hiện nay. Nó tự động hóa quá trình tìm kiếm và cung cấp ngữ cảnh phù hợp cho LLM.&lt;/p&gt;

&lt;p&gt;Cách thức hoạt động: Đây là một quy trình hai bước:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Truy xuất (Retrieve): Khi người dùng đặt câu hỏi, hệ thống trước tiên sẽ tìm kiếm trong một kho kiến thức riêng (ví dụ: tài liệu công ty, bài viết hỗ trợ, cơ sở dữ liệu) để tìm thông tin phù hợp nhất. Điều này thường được thực hiện bằng cơ sở dữ liệu vector, nơi tìm kiếm tài liệu dựa trên sự tương đồng về ngữ nghĩa.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tăng cường &amp;amp; Sinh nội dung (Augment &amp;amp; Generate): Thông tin được truy xuất sau đó được tự động chèn vào câu lệnh cùng với câu hỏi ban đầu của người dùng. LLM sử dụng ngữ cảnh đã được chọn lọc này để tạo ra một câu trả lời có căn cứ và xác thực.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;🔩 RAG khắc phục những hạn chế chính của việc tạo prompt thủ công. Nó cho phép LLM truy cập vào kho kiến thức có tính chất thay đổi thuờng xuyên. RAG nhằm lọc và đưa những phần thông tin phù hợp nhất vào cửa sổ ngữ cảnh có giới hạn của LLMs, mang lại sự cân bằng tuyệt vời giữa chi phí và lợi ích bởi cho phép truy cập dữ liệu độc quyền mà không tốn kém chi phí khổng lồ để huấn luyện lại mô hình. Nó cũng giảm đáng kể nguy cơ "ảo giác" (hallucination) bằng cách neo mô hình vào các tài liệu nguồn cụ thể.&lt;/p&gt;

&lt;p&gt;✅ Ưu điểm: Khả năng mở rộng cao, cho phép truy cập thông tin thời gian thực và tương đối tiết kiệm chi phí.&lt;br&gt;
⚠️ Nhược điểm: Mang lại sự phức tạp về mặt kỹ thuật, &lt;strong&gt;đòi hỏi quản lý một chuỗi xử lý dữ liệu&lt;/strong&gt;, quy trình nhúng (embedding) và một cơ sở dữ liệu vector. &lt;strong&gt;Chất lượng của câu trả lời cuối cùng phụ thuộc rất nhiều vào chất lượng của bước truy xuất&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  3: Tinh chỉnh Mô hình (Fine-Tuning)
&lt;/h2&gt;

&lt;p&gt;Tinh chỉnh là việc lấy một mô hình nền tảng đã được huấn luyện trước và tiếp tục quá trình huấn luyện nó trên một tập dữ liệu nhỏ hơn, đã được tuyển chọn của riêng bạn.&lt;/p&gt;

&lt;p&gt;💡 Cách thức hoạt động: Bạn chuẩn bị một tập dữ liệu chất lượng cao gồm các cặp câu lệnh-phản hồi mẫu để thể hiện một hành vi cụ thể mà bạn muốn mô hình học theo. Ví dụ, học cách trả lời theo giọng văn thương hiệu của công ty, áp dụng một tính cách cụ thể, hoặc luôn xuất ra một định dạng có cấu trúc như JSON.&lt;/p&gt;

&lt;p&gt;🔔 Tinh chỉnh không phải là để dạy cho mô hình những dữ kiện mới; nó là để dạy cho mô hình một kỹ năng, phong cách, hoặc cấu trúc mới. Trong khi RAG cung cấp kiến thức, tinh chỉnh định hình hành vi của mô hình. Đây là lựa chọn đúng đắn khi bạn cần mô hình tuân thủ một phong cách nhất quán hoặc xuất sắc trong một nhiệm vụ chuyên biệt khác với việc huấn luyện chung của nó.&lt;/p&gt;

&lt;p&gt;✅ Ưu điểm: Có thể mang lại hiệu suất vượt trội cho các nhiệm vụ chuyên biệt và cải thiện độ tin cậy về văn phong và định dạng.&lt;br&gt;
⚠️ Nhược điểm: Đây là một cách không hiệu quả để thêm kiến thức thực tế, vì dữ liệu có thể trở nên lỗi thời. Nó đòi hỏi sự chuẩn bị dữ liệu cẩn thận và có chi phí tính toán cao hơn RAG.&lt;/p&gt;

&lt;p&gt;🧷 Phân biệt quan trọng: &lt;strong&gt;Kiến thức&lt;/strong&gt; vs. &lt;strong&gt;Hành vi&lt;/strong&gt; (RAG vs. Fine-Tuning)&lt;br&gt;
Sử dụng &lt;strong&gt;RAG&lt;/strong&gt; để cung cấp cho mô hình quyền truy cập vào &lt;strong&gt;kiến thức&lt;/strong&gt;.&lt;br&gt;
Sử dụng &lt;strong&gt;Fine-Tuning&lt;/strong&gt; để dạy cho mô hình &lt;strong&gt;cách hành xử&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Các hệ thống mạnh mẽ nhất thường kết hợp cả hai: một mô hình được tinh chỉnh để có hành vi chuyên gia, sử dụng RAG để lấy ngữ cảnh thực tế năng động.&lt;/p&gt;

&lt;h2&gt;
  
  
  4: Huấn luyện Mô hình từ đầu
&lt;/h2&gt;

&lt;p&gt;Đây là phương pháp mạnh mẽ và đòi hỏi khắt khe nhất, chỉ dành cho các trường hợp sử dụng cực kỳ chuyên biệt.&lt;/p&gt;

&lt;p&gt;Cách thức hoạt động: Bao gồm việc thu thập một tập dữ liệu khổng lồ, chuyên sâu về một lĩnh vực (hàng terabyte văn bản) và huấn luyện một mô hình nền tảng mới từ con số không.&lt;br&gt;
Lý do và Lập luận: Lựa chọn này chỉ được theo đuổi khi các mô hình hiện có về cơ bản không phù hợp với lĩnh vực của bạn, chẳng hạn như trong các ngành khoa học chuyên sâu (ví dụ: di truyền học) hoặc để tạo ra một mô hình có kiến trúc hoàn toàn mới. Mục tiêu là xây dựng một "bộ não" đã học được các nguyên tắc cốt lõi của một lĩnh vực từ những nguyên lý đầu tiên.&lt;/p&gt;

&lt;p&gt;✅ Ưu điểm: Cung cấp quyền kiểm soát tối đa, hiệu suất đỉnh cao cho lĩnh vực mục tiêu và tạo ra lợi thế cạnh tranh đáng kể.&lt;br&gt;
⚠️ Nhược điểm: Chi phí cực kỳ đắt đỏ, đòi hỏi hàng triệu đô la chi phí tính toán và một đội ngũ các nhà khoa học nghiên cứu hàng đầu. Đây là một nỗ lực kéo dài nhiều năm chỉ dành cho một số ít các tổ chức lớn.&lt;/p&gt;

&lt;h1&gt;
  
  
  Kết luận: Lựa chọn Chiến lược Phù hợp
&lt;/h1&gt;

&lt;p&gt;Xây dựng AI có nhận thức về ngữ cảnh là một bài toán về việc đưa ra các quyết định đánh đổi mang tính chiến lược. Con đường tối ưu thường bao gồm:&lt;/p&gt;

&lt;p&gt;Bắt đầu với Kỹ thuật Prompt để nhanh chóng xác thực một ý tưởng.&lt;br&gt;
Triển khai RAG như một giải pháp mặc định cho hầu hết các ứng dụng cần truy cập thông tin độc quyền hoặc năng động.&lt;/p&gt;

&lt;p&gt;Bổ sung thêm Fine-Tuning nếu bạn cần cải thiện hiệu suất hành vi, phong cách hoặc định dạng của mô hình.&lt;br&gt;
Cân nhắc huấn luyện từ đầu chỉ khi bạn có đủ nguồn lực và nhu cầu chiến lược mà không một mô hình hiện có nào có thể đáp ứng.&lt;/p&gt;

&lt;p&gt;Bằng cách hiểu rõ các kỹ thuật này, bạn có thể lựa chọn phương pháp phù hợp nhất cho dự án, ngân sách và mục tiêu của mình, từ đó biến đổi một LLM tổng quát thành một công cụ chuyên biệt có giá trị cao.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>genai</category>
      <category>llm</category>
      <category>rag</category>
    </item>
    <item>
      <title>TERRAFORM - ANSIBLE: SỰ PHÂN ĐỊNH TRONG MÔ HÌNH CẤU HÌNH DEVOPS</title>
      <dc:creator>Quoc-Hung Hoang</dc:creator>
      <pubDate>Wed, 07 May 2025 07:41:46 +0000</pubDate>
      <link>https://dev.to/hoangquochung1110/terraform-ansible-su-phan-dinh-trong-mo-hinh-cau-hinh-devops-3mgf</link>
      <guid>https://dev.to/hoangquochung1110/terraform-ansible-su-phan-dinh-trong-mo-hinh-cau-hinh-devops-3mgf</guid>
      <description>&lt;h2&gt;
  
  
  1. Tổng quan 🛠️
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Terraform
&lt;/h3&gt;

&lt;p&gt;Terraform là một công cụ Infrastructure as Code (IaC) mã nguồn mở được phát triển bởi HashiCorp, &lt;strong&gt;tập trung vào việc cung cấp và quản lý cơ sở hạ tầng cloud và on-premises&lt;/strong&gt;. Terraform sử dụng phương pháp &lt;strong&gt;declarative&lt;/strong&gt; thuần túy. 🌟&lt;/p&gt;

&lt;h3&gt;
  
  
  Ansible
&lt;/h3&gt;

&lt;p&gt;Ansible là một công cụ tự động hóa, mã nguồn mở được phát triển bởi Red Hat, &lt;strong&gt;tập trung vào triển khai các tác vụ song song trên nhiều máy chủ cùng một lúc&lt;/strong&gt;. Ansible sử dụng phương pháp &lt;strong&gt;procedural declarative&lt;/strong&gt;. 🤖&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Mô hình Declarative vs Imperative 🔄
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Declarative Configuration (Cấu hình khai báo) ✍️
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Mô tả &lt;strong&gt;trạng thái mong muốn&lt;/strong&gt; của hệ thống&lt;/li&gt;
&lt;li&gt;Công cụ tự quyết định cách đạt được trạng thái đó&lt;/li&gt;
&lt;li&gt;Tập trung vào "CÁI GÌ" (what), không phải "LÀM THẾ NÀO" (how)&lt;/li&gt;
&lt;li&gt;Duy trì trạng thái (state) để biết những gì đã tồn tại&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Imperative Configuration (Cấu hình mệnh lệnh) 🧩
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Xác định &lt;strong&gt;chuỗi các lệnh cụ thể&lt;/strong&gt; để thực hiện&lt;/li&gt;
&lt;li&gt;Người dùng đặc tả chính xác cách thực hiện từng bước&lt;/li&gt;
&lt;li&gt;Tập trung vào "LÀM THẾ NÀO" (how) để đạt được kết quả&lt;/li&gt;
&lt;li&gt;Thường không theo dõi trạng thái hiện tại của hệ thống&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Phân tích sâu về Terraform: Declarative thuần túy 🌱
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Ưu điểm của cách tiếp cận Declarative
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Idempotency&lt;/strong&gt;: Có thể chạy nhiều lần mà không gây ra tác dụng phụ 🔄&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency&lt;/strong&gt;: Đảm bảo trạng thái cuối cùng luôn nhất quán ✅&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dễ đọc&lt;/strong&gt;: Code mô tả chính xác cái gì sẽ được tạo ra 📖&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quản lý thay đổi&lt;/strong&gt;: Dễ dàng thêm, sửa, xóa tài nguyên qua mã dựa trên đồ thị phụ thuộc giữa các tài nguyên ✏️&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Phân tích sâu về Ansible: "Procedural Declarative" ⚙️
&lt;/h2&gt;

&lt;p&gt;Ở góc nhìn "frontend", Ansible khéo léo khoác lên mình chiếc áo choàng declarative nhưng thực chất vẫn tuân thủ triết lý imperative, tức là nó cho phép người dùng định nghĩa trạng thái mong muốn (what) nhưng đồng thời cũng yêu cầu chỉ rõ cách thức đạt được trạng thái đó (how). Điều này tạo nên một mô hình lai độc đáo được gọi là "procedural declarative".&lt;/p&gt;

&lt;h3&gt;
  
  
  Tính chất "Procedural Declarative"
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Declarative&lt;/strong&gt;: Mô tả trạng thái mong muốn trong modules (state: present, absent, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Task-based&lt;/strong&gt;: Thực thi các task theo thứ tự từ trên xuống 📋&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Procedural&lt;/strong&gt;: Các task được thực thi tuần tự, không tự động giải quyết phụ thuộc&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agentless&lt;/strong&gt;: Không yêu cầu agent trên máy đích, sử dụng SSH/WinRM 🔒&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limited State Management&lt;/strong&gt;: Không duy trì trạng thái tổng thể của hệ thống&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idempotency&lt;/strong&gt;: Cố gắng đạt được idempotency nhưng đòi hỏi lập trình viên phải đảm bảo&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. So sánh qua ví dụ cụ thể 🔍
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Ví dụ 1: Triển khai máy chủ web 🌐
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Cách tiếp cận Declarative (Terraform)
&lt;/h4&gt;

&lt;p&gt;Với Terraform, bạn khai báo: "Tôi muốn có 3 máy chủ web, mỗi máy có 2GB RAM, sử dụng hệ điều hành Ubuntu 22.04, và tất cả đều nằm trong nhóm bảo mật web_servers."&lt;/p&gt;

&lt;p&gt;Terraform sẽ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tự động xác định có cần tạo mới, cập nhật hay xóa máy chủ nào không&lt;/li&gt;
&lt;li&gt;Tự quản lý trình tự tạo tài nguyên (ví dụ: tạo network trước, sau đó mới tạo máy chủ)&lt;/li&gt;
&lt;li&gt;Đảm bảo trạng thái cuối cùng luôn khớp với mô tả, bất kể trạng thái ban đầu&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Cách tiếp cận Procedural Declarative (Ansible)
&lt;/h4&gt;

&lt;p&gt;Với Ansible, bạn sẽ viết:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;"Tạo 3 máy chủ web với 2GB RAM và Ubuntu 22.04"&lt;/li&gt;
&lt;li&gt;"Cấu hình mỗi máy chủ để chạy dịch vụ web"&lt;/li&gt;
&lt;li&gt;"Thêm các máy chủ vào nhóm bảo mật web_servers"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ansible sẽ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Thực hiện tuần tự từng bước theo thứ tự đã định&lt;/li&gt;
&lt;li&gt;Sử dụng các module để đạt được trạng thái mong muốn cho từng bước&lt;/li&gt;
&lt;li&gt;Không tự động theo dõi trạng thái tổng thể của hệ thống&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Ví dụ 2: Triển khai ứng dụng 📦
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Cách tiếp cận Declarative (Terraform)
&lt;/h4&gt;

&lt;p&gt;Với Terraform: "Ứng dụng của tôi cần 1 cơ sở dữ liệu, 2 máy chủ ứng dụng, và 1 cân bằng tải ở phía trước. Cơ sở dữ liệu cần kết nối với các máy chủ ứng dụng, và cân bằng tải cần phân phối lưu lượng đến các máy chủ ứng dụng."&lt;/p&gt;

&lt;p&gt;Terraform sẽ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tạo một đồ thị phụ thuộc giữa các tài nguyên&lt;/li&gt;
&lt;li&gt;Xác định thứ tự tạo tài nguyên (cơ sở dữ liệu → máy chủ ứng dụng → cân bằng tải)&lt;/li&gt;
&lt;li&gt;Đảm bảo tất cả các kết nối và quan hệ phụ thuộc được đáp ứng&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Cách tiếp cận Procedural Declarative (Ansible)
&lt;/h4&gt;

&lt;p&gt;Với Ansible:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;"Tạo cơ sở dữ liệu với cấu hình X"&lt;/li&gt;
&lt;li&gt;"Tạo 2 máy chủ ứng dụng với cấu hình Y"&lt;/li&gt;
&lt;li&gt;"Cấu hình kết nối giữa cơ sở dữ liệu và máy chủ ứng dụng"&lt;/li&gt;
&lt;li&gt;"Tạo cân bằng tải với cấu hình Z"&lt;/li&gt;
&lt;li&gt;"Cấu hình cân bằng tải để phân phối lưu lượng đến các máy chủ ứng dụng"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ansible sẽ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Thực hiện từng bước theo thứ tự đã định&lt;/li&gt;
&lt;li&gt;Nhà phát triển phải xác định rõ thứ tự thực hiện&lt;/li&gt;
&lt;li&gt;Sử dụng các biến và đăng ký kết quả để truyền thông tin giữa các bước&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. Triết lý Immutable vs Mutable Infrastructure 🏗️
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Immutable Infrastructure: "Không sửa, chỉ thay" 🔄
&lt;/h3&gt;

&lt;p&gt;Immutable Infrastructure là phương pháp trong đó các thành phần cơ sở hạ tầng &lt;strong&gt;không bao giờ được sửa đổi&lt;/strong&gt; sau khi triển khai. Thay vì cập nhật cấu hình trên máy chủ đang chạy, toàn bộ máy chủ được thay thế bằng phiên bản mới đã được cấu hình sẵn.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Đặc điểm chính:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Máy chủ được xem như "gia súc" (cattle), không phải "thú cưng" (pet) 🐄&lt;/li&gt;
&lt;li&gt;Cập nhật = Hủy cũ + Tạo mới&lt;/li&gt;
&lt;li&gt;Dựa vào các template, image, snapshot 📸&lt;/li&gt;
&lt;li&gt;Loại bỏ "configuration drift" và "snowflake servers" ❄️&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Mutable Infrastructure: "Sửa chữa tại chỗ" 🔧
&lt;/h3&gt;

&lt;p&gt;Mutable Infrastructure là phương pháp truyền thống, trong đó các thành phần cơ sở hạ tầng được &lt;strong&gt;cập nhật và sửa đổi tại chỗ&lt;/strong&gt; khi cần thiết.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Đặc điểm chính:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Máy chủ được xem như "thú cưng" cần chăm sóc 🐕&lt;/li&gt;
&lt;li&gt;Thực hiện các thay đổi trực tiếp trên hệ thống đang chạy&lt;/li&gt;
&lt;li&gt;Dễ dẫn đến "configuration drift"&lt;/li&gt;
&lt;li&gt;Lịch sử thay đổi có thể không được ghi lại đầy đủ&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Terraform: Người ủng hộ trung thành của Immutable Infrastructure 🌟
&lt;/h3&gt;

&lt;p&gt;Terraform, với triết lý declarative thuần túy, là công cụ lý tưởng cho Immutable Infrastructure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quản lý toàn diện&lt;/strong&gt;: Tạo và quản lý toàn bộ vòng đời của tài nguyên&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tất cả hoặc không có gì&lt;/strong&gt;: Thay đổi tài nguyên thường đồng nghĩa với việc tạo mới và hủy cái cũ&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nhất quán&lt;/strong&gt;: Đảm bảo môi trường luôn ở trạng thái đã định nghĩa&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dễ dàng roll back&lt;/strong&gt;: Quay lại version cũ chỉ đơn giản là apply lại cấu hình cũ&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Terraform giống như một kiến trúc sư khó tính: "Nếu cần thay đổi, tôi sẽ xây lại từ đầu!" 🏗️&lt;/p&gt;

&lt;h3&gt;
  
  
  Ansible: "Kẻ đa năng" trong thế giới infrastructure 🔧
&lt;/h3&gt;

&lt;p&gt;Ansible, với bản chất procedural declarative, thích nghi tốt với Mutable Infrastructure nhưng cũng có thể hỗ trợ Immutable:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trong thế giới Mutable:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Chuyên gia "chỉnh sửa"&lt;/strong&gt;: Thay đổi cấu hình trên các máy chủ đang chạy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linh hoạt&lt;/strong&gt;: Thực hiện các thay đổi nhỏ mà không cần rebuild toàn bộ&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nhanh chóng&lt;/strong&gt;: Không cần chu kỳ tạo-hủy cho mỗi thay đổi nhỏ&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Hỗ trợ Immutable khi cần:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Xây dựng các image (AMI, Docker)&lt;/li&gt;
&lt;li&gt;Cấu hình ban đầu cho các instance mới&lt;/li&gt;
&lt;li&gt;Phần của pipeline CI/CD cho immutable deployments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ansible giống như một thợ sửa chữa đa năng: có thể xây mới, nhưng cũng rất giỏi trong việc sửa chữa tại chỗ! 🛠️&lt;/p&gt;

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

&lt;h2&gt;
  
  
  7. Trường hợp sử dụng phù hợp 🎯
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Khi nào nên sử dụng Terraform
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Provisioning hạ tầng&lt;/strong&gt;: Tạo mới toàn bộ cơ sở hạ tầng 🏗️&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quản lý tài nguyên cloud&lt;/strong&gt;: AWS, Azure, GCP, etc. ☁️&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kiến trúc bất biến (Immutable Infrastructure)&lt;/strong&gt;: Tạo mới thay vì cập nhật 🔄&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quản lý trạng thái phức tạp&lt;/strong&gt;: Nhiều tài nguyên phụ thuộc lẫn nhau 🔗&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Khi nào nên sử dụng Ansible
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cấu hình máy chủ&lt;/strong&gt;: Cài đặt phần mềm, cập nhật cấu hình 🖥️&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Triển khai ứng dụng&lt;/strong&gt;: Deployment pipelines 🚀&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tự động hóa tác vụ lặp đi lặp lại&lt;/strong&gt;: Patches, updates 🔄&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Điều phối nhiều máy chủ&lt;/strong&gt;: Các tác vụ cần thực hiện đồng thời trên nhiều máy ⚡&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Kết hợp cả hai công cụ 🤝
&lt;/h3&gt;

&lt;p&gt;Mô hình phổ biến:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Sử dụng &lt;strong&gt;Terraform&lt;/strong&gt; để provision infrastructure&lt;/li&gt;
&lt;li&gt;Sử dụng &lt;strong&gt;Ansible&lt;/strong&gt; để cấu hình và triển khai ứng dụng&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  8. Kết luận 🏁
&lt;/h2&gt;

&lt;p&gt;Terraform và Ansible đại diện cho hai triết lý khác nhau trong quản lý hạ tầng và tự động hóa:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Terraform&lt;/strong&gt;: Declarative thuần túy, tập trung vào việc quản lý trạng thái và mối quan hệ phụ thuộc giữa các tài nguyên.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ansible&lt;/strong&gt;: Procedural declarative, kết hợp giữa mô tả trạng thái mong muốn và thực thi tuần tự.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cả hai công cụ đều có giá trị riêng và thường được sử dụng bổ sung cho nhau trong các pipeline DevOps hiện đại. Hiểu rõ sự khác biệt giữa cách tiếp cận declarative và imperative giúp đội ngũ DevOps lựa chọn công cụ phù hợp cho từng loại tác vụ. 🚀&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>ansible</category>
    </item>
    <item>
      <title>Tái Cấu Trúc Terraform: Chuyển Đổi Từ State Monolithic Sang Kiến Trúc Mô-đun Theo Môi Trường</title>
      <dc:creator>Quoc-Hung Hoang</dc:creator>
      <pubDate>Sun, 20 Apr 2025 09:47:08 +0000</pubDate>
      <link>https://dev.to/hoangquochung1110/tai-cau-truc-terraform-chuyen-doi-tu-state-monolithic-sang-kien-truc-mo-dun-theo-moi-truong-4354</link>
      <guid>https://dev.to/hoangquochung1110/tai-cau-truc-terraform-chuyen-doi-tu-state-monolithic-sang-kien-truc-mo-dun-theo-moi-truong-4354</guid>
      <description>&lt;p&gt;Trong quá trình phát triển công cụ tự đông hoá truy vấn Google Maps theo địa chỉ dưới dạng văn bản trên nền tảng Instagram (chi tiết tại &lt;a href="https://www.facebook.com/groups/j2team.community/posts/2642859852712785/" rel="noopener noreferrer"&gt;đây&lt;/a&gt;), nhận thấy sự cần thiết trong việc chuyển đổi cấu trúc quản lí trạng thái của Terraform từ dạng phẳng, phi cấu trúc, monolith sang dạng mô-đun, phân tách môi trường theo file directory&lt;/p&gt;

&lt;p&gt;Dưới đây là hướng dẫn sơ khai các bước để tổ chức lại codebase Terraform của bạn để có sự tách biệt, tái sử dụng và triển khai an toàn hơn.&lt;/p&gt;




&lt;h2&gt;
  
  
  Nội dung chính
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Tổ chức State Ban Đầu&lt;/li&gt;
&lt;li&gt;Giới Thiệu Về Terraform Module&lt;/li&gt;
&lt;li&gt;Cấu Trúc Mới: Mô-đun Hóa, Hướng Theo Môi Trường&lt;/li&gt;
&lt;li&gt;Thực hiện Migrate &amp;amp; Quản Lý State&lt;/li&gt;
&lt;li&gt;Xác Minh Quá Trình Chuyển Đổi&lt;/li&gt;
&lt;li&gt;Kết quả và lời kết&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Tổ Chức State Ban Đầu
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform-serverless-project/
├── main.tf                 &lt;span class="c"&gt;# All infrastructure defined here&lt;/span&gt;
├── variables.tf            &lt;span class="c"&gt;# All variables defined here&lt;/span&gt;
├── outputs.tf              &lt;span class="c"&gt;# All outputs defined here&lt;/span&gt;
├── providers.tf            &lt;span class="c"&gt;# AWS provider configuration&lt;/span&gt;
├── terraform.tfstate       &lt;span class="c"&gt;# Single state file managing everything&lt;/span&gt;
├── terraform.tfstate.backup
├── .terraform.lock.hcl
├── src                     &lt;span class="c"&gt;# Application code goes here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cấu Trúc &amp;amp; Quy Trình&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Một thư mục gốc &lt;code&gt;terraform/&lt;/code&gt; với &lt;code&gt;main.tf&lt;/code&gt;, &lt;code&gt;variables.tf&lt;/code&gt;, v.v.&lt;/li&gt;
&lt;li&gt;Một file state duy nhất (&lt;code&gt;terraform.tfstate&lt;/code&gt;), thường được lưu trữ trong S3 hoặc cục bộ.&lt;/li&gt;
&lt;li&gt;Sử dụng &lt;code&gt;.tfvars&lt;/code&gt; (&lt;code&gt;dev.tfvars&lt;/code&gt;, &lt;code&gt;prod.tfvars&lt;/code&gt;) ghi đè biến để phân tách môi trường.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Lợi ích&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cấu trúc đơn giản, trực quan đối với người mới và dự án nhỏ.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Hạn Chế &amp;amp; Nhược Điểm&lt;/strong&gt;&lt;br&gt;
Sẽ bộc lộ khi số lượng tài nguyên tăng lên:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;State phình to: tất cả tài nguyên (dev/staging/prod) đều nằm trong một file.&lt;/li&gt;
&lt;li&gt;Triển khai rủi ro: vô tình thay đổi tài nguyên production.&lt;/li&gt;
&lt;li&gt;Mô-đun hóa kém: mọi thay đổi đối với API, IAM, Lambda đều nằm trong cùng một file.&lt;/li&gt;
&lt;li&gt;Không có ranh giới rõ ràng: khó để đào tạo thành viên mới hoặc phân chia trách nhiệm.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Giới Thiệu Về Terraform Module
&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.amazonaws.com%2Fuploads%2Farticles%2F1r48kk27fgyi3dpjane2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1r48kk27fgyi3dpjane2.png" alt="Modularize Terraform management" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Module Là Gì?&lt;/strong&gt;&lt;br&gt;
Một thư mục chứa mã Terraform (resources, inputs, outputs) mà bạn có thể gọi từ một cấu hình khác.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Root module&lt;/strong&gt;: &lt;code&gt;main.tf&lt;/code&gt; cấp cao nhất và các file liên quan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Child modules&lt;/strong&gt;: các khối xây dựng có thể tái sử dụng (ví dụ: &lt;code&gt;modules/lambda/&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Kiến Trúc và Giao Tiếp Của Module&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Một module Terraform không chỉ là một thư mục mã—nó là một đối tượng đóng gói độc lập với một hợp đồng (ràng buộc) rõ ràng về cách tương tác với thế giới bên ngoài thông qua biến (&lt;code&gt;var&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;modules/lambda/
├── main.tf         # Định nghĩa tài nguyên chính
├── variables.tf    # Tham số đầu vào (API của module)
├── outputs.tf      # Giá trị được hiển thị cho module cha
├── locals.tf       # Tính toán và biến đổi nội bộ
├── data.tf         # Data sources và lookups
└── README.md       # Tài liệu về mục đích, inputs, và outputs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mỗi file có một mục đích cụ thể:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;main.tf&lt;/strong&gt; - Chứa và tập hợp các định nghĩa tài nguyên cốt lõi (thường đi kèm với nhau) để thực hiện một hành động/tính năng hoàn chỉnh mà module tạo và quản lý. Đối với module Lambda, nó sẽ bao gồm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resource "aws_lambda_function" "functions" {
  for_each = var.functions

  function_name = "${var.name_prefix}-${each.key}"
  handler       = each.value.handler
  runtime       = each.value.runtime
  role          = var.execution_role_arn

  filename         = each.value.source_file
  source_code_hash = filebase64sha256(each.value.source_file)

  memory_size = each.value.memory_size
  timeout     = each.value.timeout

  environment {
    variables = merge(var.common_environment_variables, each.value.environment_variables)
  }

  tags = merge(var.common_tags, each.value.tags)
}

# Các tài nguyên bổ sung như permissions, CloudWatch log groups, v.v.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;variables.tf&lt;/strong&gt; - Định nghĩa các tham số đầu vào của module, với mô tả và ràng buộc kiểu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;variable "name_prefix" {
  description = "Tiền tố được thêm vào trước tất cả tên tài nguyên"
  type        = string
}

variable "functions" {
  description = "Bản đồ các hàm Lambda cần tạo"
  type = map(object({
    handler               = string
    runtime               = string
    source_file           = string
    memory_size           = number
    timeout               = number
    environment_variables = map(string)
    tags                  = map(string)
  }))
}

variable "execution_role_arn" {
  description = "ARN của IAM role được sử dụng bởi các hàm Lambda"
  type        = string
}

variable "common_environment_variables" {
  description = "Biến môi trường áp dụng cho tất cả các hàm"
  type        = map(string)
  default     = {}
}

variable "common_tags" {
  description = "Tags áp dụng cho tất cả tài nguyên"
  type        = map(string)
  default     = {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;outputs.tf&lt;/strong&gt; - Định nghĩa các giá trị mà module hiển thị cho các module cha:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;output "function_arns" {
  description = "ARNs của các hàm Lambda đã tạo"
  value = {
    for name, function in aws_lambda_function.functions : name =&amp;gt; function.arn
  }
}

output "function_names" {
  description = "Tên của các hàm Lambda đã tạo"
  value = {
    for name, function in aws_lambda_function.functions : name =&amp;gt; function.function_name
  }
}

output "invoke_urls" {
  description = "URLs cơ sở để gọi các hàm Lambda (nếu tích hợp API Gateway được bật)"
  value = {
    for name, _ in var.functions :
    name =&amp;gt; aws_apigatewayv2_stage.api[name].invoke_url
    if contains(keys(aws_apigatewayv2_stage.api), name)
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;&lt;strong&gt;Sự Kết Hợp và Tái Sử Dụng Module&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Các module có thể gọi các module khác, tạo thành một mẫu kết hợp. Điều này cho phép bạn xây dựng các trừu tượng cấp cao hơn:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Bên trong một module "serverless_api" kết hợp các module khác
module "lambda" {
  source = "../lambda"

  name_prefix        = var.name_prefix
  functions          = var.functions
  execution_role_arn = module.iam.lambda_execution_role_arn
}

module "api_gateway" {
  source = "../api_gateway"

  name_prefix     = var.name_prefix
  api_name        = "${var.name_prefix}-api"
  lambda_function = module.lambda.function_arns["api_handler"]
  stage_name      = var.environment
}

module "iam" {
  source = "../iam"

  name_prefix = var.name_prefix
  services    = ["lambda.amazonaws.com"]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Phiên Bản Module&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Để đảm bảo tính ổn định, bạn nên đánh phiên bản cho các module của mình bằng một trong những cách tiếp cận sau:&lt;/p&gt;

&lt;p&gt;1️⃣ &lt;strong&gt;Tham chiếu Git&lt;/strong&gt; - Gắn với một commit hoặc tag cụ thể:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   module "lambda" {
     source = "git::https://github.com/company/terraform-modules.git//modules/lambda?ref=v1.2.3"
     # Cấu hình module...
   }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2️⃣ &lt;strong&gt;Terraform Registry&lt;/strong&gt; - Cho các module trong registry công khai hoặc riêng tư:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   module "lambda" {
     source  = "terraform-aws-modules/lambda/aws"
     version = "2.7.0"
     # Cấu hình module...
   }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3️⃣ &lt;strong&gt;Đường dẫn cục bộ với phiên bản&lt;/strong&gt; - Cho phát triển nội bộ:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   module "lambda" {
     source = "../../modules/lambda"  # Với quy trình kiểm soát phiên bản nội bộ
     # Cấu hình module...
   }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Lợi Ích&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Đóng gói: nhóm các tài nguyên liên quan (Lambda + aliases + permissions).&lt;/li&gt;
&lt;li&gt;Tái sử dụng: chia sẻ các mẫu tiêu chuẩn giữa các dự án.&lt;/li&gt;
&lt;li&gt;Tùy biến: hiển thị inputs (&lt;code&gt;var.memory_size&lt;/code&gt;, &lt;code&gt;var.aliases&lt;/code&gt;) và outputs.&lt;/li&gt;
&lt;li&gt;Đánh phiên bản: gắn nguồn module với một Git tag hoặc phiên bản registry.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cách Sử Dụng&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module "lambda" {
  source             = "../../modules/lambda"
  functions          = local.lambda_functions
  execution_role_arn = module.iam.execution_role_arn
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Định nghĩa inputs (maps, lists, primitives).&lt;/li&gt;
&lt;li&gt;Sử dụng outputs (&lt;code&gt;module.lambda.alias_arns["myfunc_dev"]&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Tận dụng &lt;code&gt;for_each&lt;/code&gt; / &lt;code&gt;count&lt;/code&gt; cho tính năng động.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Cấu Trúc Mới: Mô-đun Hóa, Hướng Theo Môi Trường
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform/
├── environments/
│   ├── dev/
│   │   └── main.tf
│   ├── staging/
│   │   └── main.tf
│   └── prod/
│       └── main.tf
└── modules/
    ├── lambda/
    ├── iam/
    ├── api_gateway/
    └── cloudwatch/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Thư mục theo môi trường&lt;/strong&gt;: cô lập state, vars, backends.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modules&lt;/strong&gt;: triển khai các vấn đề cốt lõi (compute, IAM, logging, API).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Locals &amp;amp; tagging&lt;/strong&gt;: định nghĩa &lt;code&gt;local.project&lt;/code&gt;, &lt;code&gt;local.environment&lt;/code&gt;, &lt;code&gt;local.common_tags&lt;/code&gt; trong mỗi môi trường.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Thực hiện Migrate &amp;amp; Quản Lý State
&lt;/h2&gt;

&lt;p&gt;Ở phần phần này, mính sẽ giới thiệu qua các lệnh phổ biển của Terraform CLI để dịch chuyển state và các tài nguyên liên quan.&lt;/p&gt;

&lt;p&gt;Có it nhất 2 cách để thực hiện:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;terraform state rm&lt;/code&gt; và &lt;code&gt;terraform import&lt;/code&gt; để import tài nguyên vào module mới.&lt;/li&gt;
&lt;li&gt;Sử dụng &lt;code&gt;terraform state mv&lt;/code&gt; để di chuyển tài nguyên vào module mới.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;📌 Đi kèm là 2 công cụ đắc lực để theo dõi hiện trạng state: &lt;code&gt;terraform state list&lt;/code&gt; và &lt;code&gt;terraform state show&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Sử dụng &lt;code&gt;terraform state rm&lt;/code&gt; và &lt;code&gt;terraform import&lt;/code&gt; để import tài nguyên vào module mới&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Flow cơ bản:&lt;/p&gt;

&lt;p&gt;1️⃣ Khởi tạo state cho từng môi trường, ở đây là &lt;code&gt;dev&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;terraform/environments/dev
terraform init &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-backend-config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"key=dev/terraform.tfstate"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2️⃣ Định nghĩa module ở môi trường mới&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# my_project/terraform/modules/lambda/main.tf&lt;/span&gt;
resource &lt;span class="s2"&gt;"aws_lambda_function"&lt;/span&gt; &lt;span class="s2"&gt;"my_lambda_function"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  function_name &lt;span class="o"&gt;=&lt;/span&gt; var.function_name

  &lt;span class="c"&gt;# Function-specific configuration&lt;/span&gt;
  handler          &lt;span class="o"&gt;=&lt;/span&gt; var.handler
  runtime          &lt;span class="o"&gt;=&lt;/span&gt; var.runtime
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3️⃣ Định nghĩa các biến đầu vào cho module trên&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# my_project/terraform/modules/lambda/variables.tf&lt;/span&gt;
variable &lt;span class="s2"&gt;"function_name"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; string
&lt;span class="o"&gt;}&lt;/span&gt;

variable &lt;span class="s2"&gt;"handler"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; string
&lt;span class="o"&gt;}&lt;/span&gt;

variable &lt;span class="s2"&gt;"runtime"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; string
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4️⃣ Gọi module lambda trong file &lt;code&gt;main.tf&lt;/code&gt; của môi trường mới&lt;/p&gt;

&lt;p&gt;Để đơn giản, chúng ta hardcode các tham số đầu vào, tuy nhiên thực tế chúng ta nên định nghĩa các biến đầu vào trong &lt;code&gt;variables.tf&lt;/code&gt; kết hợp &lt;code&gt;terraform.tfvars&lt;/code&gt; của module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# my_project/terraform/environments/dev/main.tf&lt;/span&gt;
module &lt;span class="s2"&gt;"lambda"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"../../modules/lambda"&lt;/span&gt;

  function_name &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"my_lambda_function"&lt;/span&gt;
  handler       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"index.handler"&lt;/span&gt;
  runtime       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"python3.8"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;5️⃣ Xác định tài nguyên cần di chuyển ở môi trường cũ&lt;br&gt;
Tại môi trường cũ, hãy xem các tài nguyên hiện có rồi xoá tài nguyên khỏi file trạng thái:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# my_project/&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; terraform state list
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; terraform state show aws_lambda_function.my_lambda_function
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; terraform state &lt;span class="nb"&gt;rm &lt;/span&gt;aws_lambda_function.my_lambda_function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rồi xoá thủ công tài nguyên trên khỏi code ở môi trường cũ.&lt;/p&gt;

&lt;p&gt;6️⃣ Import tài nguyên vào module mới&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# my_project/terraform/environments/dev&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; terraform import module.lambda.aws_lambda_function.my_lambda_function &amp;lt;resource_id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bạn có thể phải cần truyền các tham số đầu vào thông qua flag &lt;code&gt;--var&lt;/code&gt; hoặc &lt;code&gt;--var-file&lt;/code&gt;.&lt;br&gt;
Ví dụ:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; terraform import module.lambda.aws_lambda_function.my_lambda_function &amp;lt;resource_id&amp;gt; &lt;span class="nt"&gt;--var&lt;/span&gt; &lt;span class="s2"&gt;"function_name = 'my_lambda_function'"&lt;/span&gt; &lt;span class="nt"&gt;--var&lt;/span&gt; &lt;span class="s2"&gt;"handler = 'index.handler'"&lt;/span&gt; &lt;span class="nt"&gt;--var&lt;/span&gt; &lt;span class="s2"&gt;"runtime = 'python3.8'"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Xác Minh Quá Trình Chuyển Đổi
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Xác Thực Bằng Plan&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Xác nhận không có thay đổi (các tài nguyên trỏ đến cùng một cơ sở hạ tầng vật lý).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Liệt kê state&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  terraform state list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hiển thị chi tiết tài nguyên&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  terraform state show module.lambda.aws_lambda_function.functions[&lt;span class="s2"&gt;"ig_post_extractor"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Kết quả plan&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Không có thay đổi đồng nghĩa với thành công.&lt;/li&gt;
&lt;li&gt;Bất kỳ sự khác biệt nào cho thấy một sự ánh xạ sai cần phải sửa bằng &lt;code&gt;state mv&lt;/code&gt; hoặc cập nhật biến.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Triển Khai Qua Các Môi Trường&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Lặp lại init/import/plan trong &lt;code&gt;staging&lt;/code&gt; và &lt;code&gt;prod&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Mỗi môi trường sử dụng khóa backend state riêng (&lt;code&gt;staging/terraform.tfstate&lt;/code&gt;, v.v.).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cấu Trúc Cuối Cùng Thành Công&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sau khi di chuyển, cấu trúc của chúng ta trông như thế này:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform/
├── environments/
│   ├── dev/
│   │   ├── main.tf
│   │   └── terraform.tfstate &lt;span class="o"&gt;(&lt;/span&gt;trong S3&lt;span class="o"&gt;)&lt;/span&gt;
│   ├── staging/
│   │   ├── main.tf
│   │   └── terraform.tfstate &lt;span class="o"&gt;(&lt;/span&gt;trong S3&lt;span class="o"&gt;)&lt;/span&gt;
│   └── prod/
│       ├── main.tf
│       └── terraform.tfstate &lt;span class="o"&gt;(&lt;/span&gt;trong S3&lt;span class="o"&gt;)&lt;/span&gt;
└── modules/
    ├── lambda/
    ├── api_gateway/
    ├── iam/
    └── cloudwatch/
├── src                 &lt;span class="c"&gt;# Application code goes here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Kết Quả và lời kết
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tách biệt&lt;/strong&gt;: mỗi môi trường có state riêng, không có sự nhiễm chéo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mô-đun hóa&lt;/strong&gt;: các module đóng gói các phương pháp hay nhất và dễ dàng đánh phiên bản.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lặp lại&lt;/strong&gt;: tạo môi trường mới bằng cách sao chép một thư mục và điều chỉnh các biến.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An toàn&lt;/strong&gt;: các lệnh &lt;code&gt;plan&lt;/code&gt; + &lt;code&gt;state&lt;/code&gt; đảm bảo di chuyển có kiểm soát, không bị gián đoạn.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dễ bảo trì&lt;/strong&gt;: thành viên mới trong nhóm có thể nhanh chóng hiểu cấu trúc codebase.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quản trị&lt;/strong&gt;: dễ dàng triển khai quy trình phê duyệt cho từng môi trường.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sau khi di chuyển, các nhóm có thể làm việc độc lập trên các môi trường hoặc module khác nhau, với ranh giới rõ ràng và giảm nguy cơ thay đổi vô tình các tài nguyên sản xuất.&lt;/p&gt;

</description>
      <category>terraform</category>
    </item>
    <item>
      <title>Zero-Code Authentication: Unleashing AWS Application Load Balancer's Built-in capabilities for simplifying user login</title>
      <dc:creator>Quoc-Hung Hoang</dc:creator>
      <pubDate>Mon, 07 Apr 2025 04:58:25 +0000</pubDate>
      <link>https://dev.to/hoangquochung1110/deploy-oidc-authentication-on-aws-with-no-coding-using-aws-cognito-and-application-load-balancer-1g8o</link>
      <guid>https://dev.to/hoangquochung1110/deploy-oidc-authentication-on-aws-with-no-coding-using-aws-cognito-and-application-load-balancer-1g8o</guid>
      <description>&lt;p&gt;In this guide, I'll walk you through setting up ALB authentication at a high level, demonstrating how you can leverage this serverless approach to handle user login flows. This solution can significantly streamline your authentication implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unlock the Hidden Power of Application Load Balancer Authentication
&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.amazonaws.com%2Fuploads%2Farticles%2F76relrcke41qex2i3831.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F76relrcke41qex2i3831.png" alt="Zero-code Authentication thanks to Application Load Balanncer" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
While many developers overlook a game-changing security feature, AWS Application Load Balancers (ALBs) harbor a secret weapon: native OpenID Connect (OIDC) authentication. This lesser-known capability transforms authentication from a complex, resource-draining challenge into a streamlined, efficient solution that operates directly at the infrastructure level.&lt;/p&gt;

&lt;p&gt;By enabling OIDC authentication at the load balancer, you can offload critical authentication work from your application servers, reducing complexity, minimizing potential security vulnerabilities, and delivering a more robust authentication strategy with minimal additional configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits
&lt;/h2&gt;

&lt;p&gt;✅ Application Load Balancer acts as an OIDC Relying Party (RP) that provides authentication backend with seamless integration with AWS Cognito, public IdP (such as Facebook, Google) and corporate identities using SAML, LDAP, Microsoft AD, or OIDC&lt;br&gt;
✅ Offloading the responsibility of authentication to the Application Load Balancer, while benefiting from its scale, availability, and reliability.&lt;br&gt;
✅ Cost-Effectiveness: Managed authentication reduces the need for custom solutions, saving time and resources on development and maintenance.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;📌 OIDC client is implemented in ALB via configured listener rules that simplifies authorization in the backends&lt;br&gt;
📌 Cognito User Pool Domain serves as the OIDC Provider (OP), hosting the authorization server endpoints&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;⚠️ Cookie Size Restrictions:&lt;br&gt;
The session cookies used by ALB have size limitations (maximum 4KB). if token payloads exceed this limit (e.g., larger than 11KB), the load balancer may return errors like HTTP 500.&lt;br&gt;
⚠️ Dependency on Publicly Resolvable DNS:&lt;br&gt;
For OIDC-compliant IdPs, the OIDC Provider's endpoints must be publicly resolvable even if they resolve to private IPs, which may not be feasible in certain private network setups.&lt;br&gt;
⚠️ No Custom Login Pages:&lt;br&gt;
Applications relying on ALB for authentication must use the login page hosted by the IdP (e.g., Amazon Cognito). Customization of the login UI may be limited.&lt;br&gt;
⚠️ Complex Configuration for Multiple Applications:&lt;br&gt;
When supporting multiple applications via a single ALB, developers must configure unique session cookies and listener rules to avoid conflicts between client authentications&lt;/p&gt;

&lt;h2&gt;
  
  
  Design Overview
&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.amazonaws.com%2Fuploads%2Farticles%2F5ff6mi4cnmjv7qgixj8s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ff6mi4cnmjv7qgixj8s.png" alt="Design overview of authenticating user at Load Balancer" width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration Components
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. DNS and SSL Configuration
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create CNAME record in your domain registrar:

&lt;ul&gt;
&lt;li&gt;Record: app.[your-domain].com&lt;/li&gt;
&lt;li&gt;Target: [your-load-balancer-dns-name].region.elb.amazonaws.com&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Request SSL certificate in AWS Certificate Manager (ACM):

&lt;ul&gt;
&lt;li&gt;Domain name: app.[your-domain].com&lt;/li&gt;
&lt;li&gt;Validation: DNS validation recommended&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Amazon Cognito Configuration
&lt;/h3&gt;

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

&lt;h4&gt;
  
  
  User Pool Setup
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;User Pool Name: [Your Application Name]-user-pool&lt;/li&gt;
&lt;li&gt;Domain: [your-domain].auth.[region].amazoncognito.com&lt;/li&gt;
&lt;li&gt;App client:

&lt;ul&gt;
&lt;li&gt;Name: of your choice&lt;/li&gt;
&lt;li&gt;Generate client secret: &lt;code&gt;Yes&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Allowed OAuth Flows: &lt;code&gt;Authorization code grant&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Allowed OAuth Scopes: &lt;code&gt;openid, email, profile&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Callback URLs: https://[your-load-balancer-domain]/oauth2/idpresponse and https://[your-domain]/oauth2/idpresponse &lt;strong&gt;(this is an ALB-specific endpoint required for the OIDC authentication flow)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Application Load Balancer Configuration
&lt;/h3&gt;

&lt;p&gt;Our Application Load Balancer is configured with two listeners:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx0omxnmdd8vpmltqrfgf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx0omxnmdd8vpmltqrfgf.png" alt="Image description" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  HTTP Listener (Port 80)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rule Configuration&lt;/strong&gt;: Redirects all HTTP traffic to HTTPS (port 443)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Status Code&lt;/strong&gt;: HTTP 301 (Permanent Redirect)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security Purpose&lt;/strong&gt;: Ensures all authentication traffic is encrypted&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  HTTPS Listener (Port 443)
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Configuration&lt;/strong&gt;: Serve HTTPS traffic as path routing, handles authentication through AWS Cognito before routing to downstream applications depending on different listener rules&lt;br&gt;
This listener has two distinct rules that handle different access patterns:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Public Resource Rule&lt;/strong&gt; (Priority: 1)

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Path Pattern&lt;/strong&gt;: Exact match for root path "/"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Actions&lt;/strong&gt;: Direct forward to target group without authentication&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Purpose&lt;/strong&gt;: Allows public access to the homepage without requiring authentication&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protected Resources Rule&lt;/strong&gt; (Default Rule)

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Path Pattern&lt;/strong&gt;: All other paths not explicitly matched by other rules&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Actions&lt;/strong&gt;: Configured in the following order:

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;authenticate-cognito&lt;/strong&gt; (Order: 1): Authenticates users via Cognito before allowing access. We need to specify Cognito User Pool, User Pool Domain, App Client and include TLS/SSL Certificate here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;forward&lt;/strong&gt; (Order: 2): Forwards authenticated requests to the target group&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Purpose&lt;/strong&gt;: Protects all application resources by requiring authentication&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>aws</category>
      <category>cloudnative</category>
      <category>cognito</category>
      <category>authentication</category>
    </item>
    <item>
      <title>Django 5.2's Smart Shell: Goodbye Manual Model Imports!</title>
      <dc:creator>Quoc-Hung Hoang</dc:creator>
      <pubDate>Tue, 11 Mar 2025 06:58:12 +0000</pubDate>
      <link>https://dev.to/hoangquochung1110/django-52s-smart-shell-goodbye-manual-model-imports-1aae</link>
      <guid>https://dev.to/hoangquochung1110/django-52s-smart-shell-goodbye-manual-model-imports-1aae</guid>
      <description>&lt;p&gt;One of the most convenient features from &lt;code&gt;django-extensions&lt;/code&gt; has finally made its way into Django's core. Starting with Django 5.2, the shell comes with automatic model imports, streamlining your development workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Old Way
&lt;/h3&gt;

&lt;p&gt;Remember how we used to start our Django shell sessions? It typically looked something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from myapp.models import User, Product, Order
# More imports...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The New Way
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.ssan.me%2FDjango%2B5.2%2BShell%2BAuto%2BImport%2BTip.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.ssan.me%2FDjango%2B5.2%2BShell%2BAuto%2BImport%2BTip.webp" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Behind the Scene
&lt;/h3&gt;

&lt;p&gt;This feature was previously available through the excellent &lt;code&gt;shell_plus&lt;/code&gt; command in &lt;code&gt;django-extensions&lt;/code&gt; package. The Django core team recognized its value and integrated it into the main framework, making development just a bit more pleasant for everyone.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why This Matters
&lt;/h3&gt;

&lt;p&gt;This small but meaningful improvement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduces boilerplate code&lt;/li&gt;
&lt;li&gt;Speeds up debugging sessions&lt;/li&gt;
&lt;li&gt;Makes interactive development more fluid&lt;/li&gt;
&lt;li&gt;Eliminates a common source of frustration&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>django</category>
    </item>
    <item>
      <title>Quick AWS Console Navigation: A Chrome Search Engine Hack The Problem</title>
      <dc:creator>Quoc-Hung Hoang</dc:creator>
      <pubDate>Sat, 22 Feb 2025 08:08:07 +0000</pubDate>
      <link>https://dev.to/hoangquochung1110/quick-aws-console-navigation-a-chrome-search-engine-hack-the-problem-4cnc</link>
      <guid>https://dev.to/hoangquochung1110/quick-aws-console-navigation-a-chrome-search-engine-hack-the-problem-4cnc</guid>
      <description>&lt;p&gt;We've all been there - navigating the AWS Console can be a pain.&lt;/p&gt;


  
  Your browser does not support the video tag.


&lt;p&gt;Whether you're:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clicking through multiple levels of the navigation bar&lt;/li&gt;
&lt;li&gt;Trying to remember which category contains the service you need&lt;/li&gt;
&lt;li&gt;Googling "how to find X service in AWS console"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's time-consuming and breaks your workflow momentum.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;What if you could jump directly to any AWS service by typing aws ec2 or aws s3 in your Chrome address bar? No more searching, no more clicking through menus.&lt;br&gt;
[Image: Screenshot showing Chrome address bar with "aws ec2" typed in]&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;All you need to type is&lt;/strong&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;aws [tab] ec2 [enter]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And you're there! It's that simple.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup Guide
&lt;/h2&gt;

&lt;p&gt;Here's how to set this up in Chrome:&lt;/p&gt;

&lt;p&gt;Open Chrome Settings for Search Engines&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;code&gt;chrome://settings/searchEngines&lt;/code&gt; in Chrome&lt;/li&gt;
&lt;li&gt;Scroll down to &lt;code&gt;Site Search&lt;/code&gt; and click Add&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fill in the following details:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Name: AWS Console&lt;br&gt;
Shortcut: aws&lt;br&gt;
URL: &lt;a href="https://console.aws.amazon.com/%s" rel="noopener noreferrer"&gt;https://console.aws.amazon.com/%s&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click "Add" to save&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;Once configured, here's how to use it:&lt;/p&gt;


  
  Your browser does not support the video tag.


&lt;h2&gt;
  
  
  Pro Tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The service name should match its URL path in the AWS Console&lt;/li&gt;
&lt;li&gt;You can use this technique for other services too - not just AWS!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Conclusion&lt;br&gt;
This simple Chrome setup can save you countless clicks and searches throughout your day. It's especially helpful if you frequently switch between different AWS services.&lt;br&gt;
No more menu diving or Google searches - just aws [tab] and go!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>googlesearch</category>
      <category>utilitytips</category>
    </item>
    <item>
      <title>API Gateway Authorization Methods: My quick evaluation</title>
      <dc:creator>Quoc-Hung Hoang</dc:creator>
      <pubDate>Sat, 25 Jan 2025 08:37:41 +0000</pubDate>
      <link>https://dev.to/hoangquochung1110/api-gateway-authorization-methods-my-quick-evaluation-4of2</link>
      <guid>https://dev.to/hoangquochung1110/api-gateway-authorization-methods-my-quick-evaluation-4of2</guid>
      <description>&lt;h2&gt;
  
  
  API Gateway Authorization Methods: My quick evaluation
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;I'm developing a utility tool for my internal team using API Gateway + Lambda. One aspect I'd like to apply when it comes to securing APIs is limiting API access. AWS provides us three primary authorization methods exist: IAM, Amazon Cognito, and Lambda Authorizers. Here is my quick evaluation of each method's implementation effort, and ideal use cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authorization Method Comparisons
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. IAM Authorization
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Complexity&lt;/strong&gt;: Low&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best For&lt;/strong&gt;: Internal AWS environments&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implementation Effort&lt;/strong&gt;: 1/5&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key Advantages&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Native AWS ecosystem integration&lt;/li&gt;
&lt;li&gt;Minimal custom code requirements&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Limitations&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Restricted to AWS infrastructure&lt;/li&gt;
&lt;li&gt;Limited external user support&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Amazon Cognito
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Complexity&lt;/strong&gt;: Medium&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best For&lt;/strong&gt;: User-centric applications&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implementation Effort&lt;/strong&gt;: 3/5&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key Advantages&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Managed user authentication&lt;/li&gt;
&lt;li&gt;Built-in social login capabilities&lt;/li&gt;
&lt;li&gt;Multi-factor authentication support&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Challenges&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Requires initial configuration&lt;/li&gt;
&lt;li&gt;Steeper learning curve for advanced features&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Lambda Authorizers
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Complexity&lt;/strong&gt;: High&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best For&lt;/strong&gt;: Enterprise-level, custom authentication scenarios&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implementation Effort&lt;/strong&gt;: 5/5&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key Advantages&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Maximum authentication customization&lt;/li&gt;
&lt;li&gt;Supports intricate authentication logic&lt;/li&gt;
&lt;li&gt;Integrates with external identity providers&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Challenges&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Requires custom Lambda function development&lt;/li&gt;
&lt;li&gt;Higher maintenance overhead&lt;/li&gt;
&lt;li&gt;Potential performance implications
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fihxk93s8b74wyaxg5knu.png" alt="Lambda Authorizer Authorization Workflow" width="800" height="450"&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Recommendation Matrix
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Recommended Method&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Small/Internal Projects&lt;/td&gt;
&lt;td&gt;IAM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User-Focused Applications&lt;/td&gt;
&lt;td&gt;Cognito&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complex Enterprise Requirements&lt;/td&gt;
&lt;td&gt;Lambda Authorizers&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  My closing thoughts
&lt;/h2&gt;

&lt;p&gt;I'm developing some web-bases utility tools for my internal team. IAM Authorization seems a no-brainer to me. Minimal coding and configuration required helps me to ship fast to collect users' feedback as we also use AWS as our cloud provider.&lt;/p&gt;

&lt;p&gt;In case, security concerns and authorization grow more complex, I'll look into Lambda Authorizers thanks to its flexibility while I'd like to avoid AWS Cognito as it requires steep learning curve when requirements are more complex.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>apigateway</category>
    </item>
    <item>
      <title>What I Learned from the 'Amazon DynamoDB for Serverless Architectures' Course on AWS Skill Builder</title>
      <dc:creator>Quoc-Hung Hoang</dc:creator>
      <pubDate>Thu, 09 Jan 2025 04:00:33 +0000</pubDate>
      <link>https://dev.to/hoangquochung1110/what-i-learned-from-the-amazon-dynamodb-for-serverless-architectures-course-on-aws-skill-builder-58og</link>
      <guid>https://dev.to/hoangquochung1110/what-i-learned-from-the-amazon-dynamodb-for-serverless-architectures-course-on-aws-skill-builder-58og</guid>
      <description>&lt;h3&gt;
  
  
  TL;DR
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;DynamoDB is well designed for at &lt;strong&gt;Online Transaction Processing (OLTP)&lt;/strong&gt; workloads where you need consistent single-digit millisecond response times at any scale&lt;/li&gt;
&lt;li&gt;Unlike traditional databases, the key to unlocking DynamoDB's power lies in &lt;strong&gt;knowing your request patterns&lt;/strong&gt; upfront - not as an afterthought, but as a fundamental part of your design process. You can't just throw any query at it; instead, you design your data model around specific questions you need to answer. This approach makes it ideal for applications with well-defined workflows, like e-commerce carts, user sessions, or game states, but less suitable for exploratory analytics or ad-hoc queries.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How it works
&lt;/h3&gt;

&lt;p&gt;Data is stored in tables. A table contains items with attributes.&lt;br&gt;
You can think of items as rows or tuples in a relational database and attributes as columns.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.ssan.me%2Ftables-and-partitions-dynamo-db.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%2Fstatic.ssan.me%2Ftables-and-partitions-dynamo-db.png" title="Tables and Partitions" alt="Tables and Partitions" width="800" height="609"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Primary keys
&lt;/h4&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%2Fstatic.ssan.me%2Fdynamo-db-primary-keys.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%2Fstatic.ssan.me%2Fdynamo-db-primary-keys.png" title="Primary keys" alt="Primary keys" width="800" height="688"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Basic item requests:
&lt;/h4&gt;

&lt;p&gt;Write&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PutItem: Write item to specified primary key.&lt;/li&gt;
&lt;li&gt;UpdateItem: Change attributes for item with specified primary key.&lt;/li&gt;
&lt;li&gt;BatchWriteItem: Write bunch of items to the specified primary keys.&lt;/li&gt;
&lt;li&gt;DeleteItem: Remove item associated with specified primary key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Read&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GetItem:  Retrieve item associated with specified primary key.&lt;/li&gt;
&lt;li&gt;BatchGetItem: Retrieve items with this bunch of specified primary keys.&lt;/li&gt;
&lt;li&gt;Query: For specified partition key, retrieve items matching sort key expression (forward/reverse order).&lt;/li&gt;
&lt;li&gt;Scan: Give me every item in my table.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Details: &lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithItems.html?t" rel="noopener noreferrer"&gt;Working with items and attributes in DynamoDB&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Secondary indexes: allow to query data based on other attributes than your table's primary key.
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Local secondary indexes

&lt;ul&gt;
&lt;li&gt;index is local to partition key&lt;/li&gt;
&lt;li&gt;allow you to query items with the same partition key&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Global secondary indexes:

&lt;ul&gt;
&lt;li&gt;allow you to query over the entire table&lt;/li&gt;
&lt;li&gt;index is across all partitions&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Improved query performance&lt;/li&gt;
&lt;li&gt;Support complex queries&lt;/li&gt;
&lt;li&gt;Non-Unique Indexing: They allow for indexing on non-unique attributes, which broadens the range of query possibilities, such as searching for products by category or timestamps in logs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write Performance Overhead: Each time an item in the base table is updated, corresponding entries in the secondary index must also be updated. This can slow down insert and update operations, especially if there are multiple secondary indexes on a table&lt;/li&gt;
&lt;li&gt;Storage Costs: While secondary indexes reduce data retrieval time, they also consume additional storage space, which can be a consideration in environments with limited resources&lt;/li&gt;
&lt;li&gt;Limited Use Cases: Secondary indexes should not be applied to attributes with low or very high cardinality; low cardinality can lead to inefficient queries, while high cardinality can result in excessive scanning across nodes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Important notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The secondary index should not apply to the values with too low (e.g. gender -&amp;gt; male/female) or too high cardinality (e.g. user's unique id)

&lt;ul&gt;
&lt;li&gt;former case: querying won't be efficient as leads to wide index partitions and automatically we've a lot of data to scan&lt;/li&gt;
&lt;li&gt;latter case: queries can be executed at best on 1 node and at worst in all nodes&lt;/li&gt;
&lt;li&gt;Learn more: &lt;a href="https://www.waitingforcode.com/general-big-data/secondary-index-nosql-data-stores/read?t#sample_implementation" rel="noopener noreferrer"&gt;https://www.waitingforcode.com/general-big-data/secondary-index-nosql-data-stores/read?t#sample_implementation&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Design considerations
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Partition keys
&lt;/h4&gt;

&lt;p&gt;When selecting an attribute as a partition key in a NoSQL database, it is crucial to consider several key factors to ensure that read and write operations are evenly distributed across partitions. Here are the primary considerations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;High Cardinality (that means there are lots of unique values):&lt;br&gt;
• Definition: Choose attributes that have a large number of distinct values (high cardinality). For instance, using &lt;code&gt;user_id&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, or &lt;code&gt;order_id&lt;/code&gt; can help ensure that data is spread across many partitions.&lt;br&gt;
• Impact: High cardinality minimizes the risk of “hot partitions,” where one partition receives significantly more traffic than others, leading to performance bottlenecks .&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoid Monotonically Increasing Values:&lt;br&gt;
• Examples: Attributes like timestamps or sequential IDs can lead to uneven distribution because new entries will always be directed to the same partition until it reaches its capacity.&lt;br&gt;
• Recommendation: Instead, consider using composite keys or appending random suffixes to create variability in the partition key .&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Hot and Cold Data
&lt;/h4&gt;

&lt;p&gt;Separate data that is frequently accessed (hot) from data that is not accessed frequently (cold)&lt;/p&gt;

&lt;h4&gt;
  
  
  Large attributes
&lt;/h4&gt;

&lt;p&gt;Ideally should keep item size small&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compress large data before storing it&lt;/li&gt;
&lt;li&gt;Store large data in external storage like S3&lt;/li&gt;
&lt;li&gt;Break it up into smaller items&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Closing Thoughts
&lt;/h3&gt;

&lt;p&gt;DynamoDB represents a fundamental shift in how we approach database design. While traditional databases let us figure out our queries after the fact, DynamoDB asks us to think differently – to start with our application's access patterns and build our data model around them. This isn't just a technical constraint; it's a design philosophy that rewards careful planning with exceptional performance and scalability.&lt;/p&gt;

&lt;p&gt;Throughout this course, I've come to appreciate that success with DynamoDB isn't about fighting its constraints but embracing them. Whether it's choosing the right partition keys, managing hot and cold data, or designing secondary indexes, each decision flows from understanding your application's specific needs upfront.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>dynamodb</category>
      <category>nosql</category>
    </item>
    <item>
      <title>Run additional script when starting a Postgres container</title>
      <dc:creator>Quoc-Hung Hoang</dc:creator>
      <pubDate>Tue, 23 May 2023 13:17:20 +0000</pubDate>
      <link>https://dev.to/hoangquochung1110/run-additional-script-when-starting-a-postgres-container-e64</link>
      <guid>https://dev.to/hoangquochung1110/run-additional-script-when-starting-a-postgres-container-e64</guid>
      <description>&lt;p&gt;Today, I've just explored a feature when you start a postgres instance on Docker which allows you to set up initial data like CREATE ROLE or GRANT .&lt;/p&gt;

&lt;p&gt;You may learn more details &lt;a href="https://github.com/docker-library/docs/tree/master/postgres#initialization-scripts"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We create *.sql or *.sh script to run SQL statement or bash script to prepare initial data. Postgres container will run any *.sql and *.sh found in the directory (which containing docker-compose.yml) to do further initialization before starting the service.&lt;/p&gt;

&lt;p&gt;NOTE: scripts in /docker-entrypoint-initdb.d are only run if you start the container with a data directory that is empty; any pre-existing database will be left untouched on container startup.&lt;/p&gt;

&lt;p&gt;And visit my example code at &lt;a href="https://gist.github.com/hoangquochung1110/5486440c7e2b43f98135ff7803750b5f"&gt;my gist&lt;/a&gt;&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>docker</category>
      <category>dx</category>
      <category>devops</category>
    </item>
    <item>
      <title>Commit message with title and body with one-liner git command</title>
      <dc:creator>Quoc-Hung Hoang</dc:creator>
      <pubDate>Thu, 11 Aug 2022 09:51:52 +0000</pubDate>
      <link>https://dev.to/hoangquochung1110/commit-message-with-title-and-body-with-one-liner-git-command-2k90</link>
      <guid>https://dev.to/hoangquochung1110/commit-message-with-title-and-body-with-one-liner-git-command-2k90</guid>
      <description>&lt;p&gt;When you use git, one of the most frequent used command is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"my commit message"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But most of the time, you would give a more meaningful commit message. Meaningful I mean here is that the message should consist of subject line (a short description of your changes in code) and body (to give more detailed description of what you did)&lt;/p&gt;

&lt;p&gt;Today I learn that &lt;code&gt;git commit&lt;/code&gt; accept multiple message flag 😉&lt;br&gt;
If you run this command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"subject line"&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"commit description"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will result in this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Author: hunghoang-saritasa &amp;lt;hung.hoang@saritasa.com&amp;gt;
Date:   Thu Aug 11 16:29:07 2022 +0700

    Subject line

    Commit message
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This new finding helps me save time a lot. No need to open a vim editor when committing message with subject and body. And actually &lt;a href="https://git-scm.com/docs/git-commit#Documentation/git-commit.txt--mltmsggt" rel="noopener noreferrer"&gt;the git documentation&lt;/a&gt; do mention it.&lt;/p&gt;

&lt;p&gt;Bonus: Another way to achieve this commit message structure is opening quotes then press enter and closing the commit with quotes again&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc4gijdfwk9wg7l8kmue2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc4gijdfwk9wg7l8kmue2.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>bash</category>
    </item>
  </channel>
</rss>
