it

CircleCI Orbs Cost Optimization ลดค่าใช้จ่าย

CircleCI Orbs Cost Optimization ลดค่าใช้จ่าย

CircleCI Orbs Cost Optimization ลดค่าใช้จ่าย

CircleCI Orbs Cost Optimization ลดค่าใช้จ่าย

CircleCI เป็น CI/CD platform ยอดนิยมที่ใช้ credits-based pricing model Orbs คือ reusable packages ของ CircleCI configuration ที่ช่วยลด boilerplate และเพิ่ม consistency ข้าม projects Cost Optimization คือการลดค่าใช้จ่ายของ CI/CD pipeline โดยไม่กระทบ quality และ speed บทความนี้อธิบายวิธีใช้ Orbs อย่างมีประสิทธิภาพ ลด build time ลด credit usage และ optimize resource allocation เพื่อประหยัดค่าใช้จ่ายสำหรับทีม development

CircleCI Pricing & Credits

# pricing.py — CircleCI pricing model

import json



class CircleCIPricing:

    PLANS = {

        "free": {

            "name": "Free Plan",

            "credits": "30,000 credits/month",

            "users": "1 user",

            "parallelism": "1x",

            "cost": "$0",

        },

        "performance": {

            "name": "Performance Plan",

            "credits": "Custom (pay-as-you-go)",

            "users": "Unlimited",

            "parallelism": "Up to 80x",

            "cost": "From $15/month + credits",

        },

        "scale": {

            "name": "Scale Plan",

            "credits": "Custom + self-hosted runners",

            "users": "Unlimited",

            "parallelism": "Unlimited",

            "cost": "Custom pricing",

        },

    }



    CREDIT_RATES = {

        "docker_medium": {"name": "Docker Medium (2 vCPU, 4GB)", "credits": "10 credits/min", "use": "Default, general builds"},

        "docker_large": {"name": "Docker Large (4 vCPU, 8GB)", "credits": "20 credits/min", "use": "Heavy builds, compilation"},

        "docker_xlarge": {"name": "Docker XLarge (8 vCPU, 16GB)", "credits": "40 credits/min", "use": "Parallel tests, large projects"},

        "machine_medium": {"name": "Machine Medium (2 vCPU, 8GB)", "credits": "40 credits/min", "use": "Docker-in-Docker, privileged"},

        "machine_large": {"name": "Machine Large (4 vCPU, 16GB)", "credits": "80 credits/min", "use": "Heavy Docker builds"},

        "macos_medium": {"name": "macOS Medium", "credits": "50 credits/min", "use": "iOS/macOS builds"},

        "arm_medium": {"name": "ARM Medium", "credits": "13 credits/min", "use": "ARM builds (cheaper!)"},

    }



    def show_plans(self):

        print("=== CircleCI Plans ===\n")

        for key, plan in self.PLANS.items():

            print(f"[{plan['name']}] {plan['credits']} | {plan['cost']}")



    def show_rates(self):

        print(f"\n=== Credit Rates ===")

        for key, rate in self.CREDIT_RATES.items():

            print(f"  [{rate['name']}] {rate['credits']} — {rate['use']}")



    def cost_calculator(self):

        print(f"\n=== Monthly Cost Example ===")

        builds = [

            {"name": "Unit Tests", "resource": "docker_medium", "mins": 5, "runs": 200, "credits_per_min": 10},

            {"name": "Integration Tests", "resource": "docker_large", "mins": 10, "runs": 100, "credits_per_min": 20},

            {"name": "Docker Build", "resource": "machine_medium", "mins": 8, "runs": 100, "credits_per_min": 40},

            {"name": "Deploy", "resource": "docker_medium", "mins": 3, "runs": 50, "credits_per_min": 10},

        ]

        total = 0

        for b in builds:

            credits = b["mins"] * b["runs"] * b["credits_per_min"]

            total += credits

            print(f"  {b['name']}: {b['mins']}min × {b['runs']} runs × {b['credits_per_min']} = {credits:,} credits")

        cost = total * 0.0006

        print(f"\n  Total: {total:,} credits (~/month)")



pricing = CircleCIPricing()

pricing.show_plans()

pricing.show_rates()

pricing.cost_calculator()

Orbs สำหรับ Cost Optimization

# orbs_optimization.py — Orbs for cost optimization

import json



class OrbsOptimization:

    USEFUL_ORBS = {

        "node": {

            "name": "circleci/node",

            "optimization": "Built-in caching สำหรับ node_modules — ลด install time 50-80%",

            "config": "node/install: with_cache: true",

        },

        "docker": {

            "name": "circleci/docker",

            "optimization": "Docker Layer Caching (DLC) — ลด Docker build time 60%+",

            "config": "docker/build: docker-layer-caching: true",

        },

        "aws_cli": {

            "name": "circleci/aws-cli",

            "optimization": "Pre-installed AWS CLI — ไม่ต้อง install ทุก build (ลด 1-2 min)",

            "config": "aws-cli/setup",

        },

        "slack": {

            "name": "circleci/slack",

            "optimization": "Notify เฉพาะ failure — ลด noise, ไม่เปลือง build time",

            "config": "slack/notify: event: fail",

        },

    }



    OPTIMIZATION_CONFIG = """

# .circleci/config.yml — Optimized configuration

version: 2.1



orbs:

  node: circleci/node@5.2

  docker: circleci/docker@2.6

  slack: circleci/slack@4.13



# 1. Use smallest resource class possible

executors:

  small:

    docker:

      - image: cimg/node:20.11

    resource_class: small    # 1 vCPU, 2GB — 5 credits/min (ถูกที่สุด!)

  medium:

    docker:

      - image: cimg/node:20.11

    resource_class: medium   # 2 vCPU, 4GB — 10 credits/min



jobs:

  # 2. Cache aggressively

  test:

    executor: small          # ใช้ small สำหรับ tests!

    steps:

      - checkout

      - node/install-packages:

          cache-path: node_modules

          override-ci-command: npm ci --prefer-offline

      - run:

          name: Run Tests

          command: npm test

      - store_test_results:

          path: test-results



  # 3. Build only when needed

  build:

    executor: medium

    steps:

      - checkout

      - node/install-packages:

          cache-path: node_modules

      - run: npm run build

      - persist_to_workspace:

          root: .

          paths: [dist]



workflows:

  # 4. Filter branches — don't build everything

  main:

    jobs:

      - test:

          filters:

            branches:

              ignore: [docs/*, dependabot/*]  # Skip non-code branches

      - build:

          requires: [test]

          filters:

            branches:

              only: [main, develop]  # Build only main branches

"""



    def show_orbs(self):

        print("=== Useful Orbs for Optimization ===\n")

        for key, orb in self.USEFUL_ORBS.items():

            print(f"[{orb['name']}]")

            print(f"  Optimization: {orb['optimization']}")

            print()



    def show_config(self):

        print("=== Optimized Config ===")

        print(self.OPTIMIZATION_CONFIG[:600])



orbs = OrbsOptimization()

orbs.show_orbs()

orbs.show_config()

Cost Reduction Strategies

CircleCI Orbs Cost Optimization ลดค่าใช้จ่าย
# strategies.py — Cost reduction strategies

import json



class CostStrategies:

    STRATEGIES = {

        "resource_class": {

            "name": "1. ใช้ Resource Class เล็กที่สุด",

            "saving": "50-75%",

            "detail": "small (5 cr/min) แทน medium (10 cr/min) สำหรับ lint, unit tests",

            "example": "resource_class: small → ลดจาก 10 เป็น 5 credits/min",

        },

        "caching": {

            "name": "2. Cache ทุกอย่างที่ cache ได้",

            "saving": "30-60%",

            "detail": "node_modules, pip packages, Docker layers, build artifacts",

            "example": "npm ci: 120s → 15s (with cache) = ลด 87%",

        },

        "parallelism": {

            "name": "3. Parallelism อย่างชาญฉลาด",

            "saving": "20-40%",

            "detail": "แบ่ง tests เป็นกลุ่ม รัน parallel — ลด wall time แต่ใช้ credits เท่าเดิม",

            "example": "parallelism: 4 → tests 20min → 5min (same total credits, faster feedback)",

        },

        "conditional": {

            "name": "4. Conditional Execution",

            "saving": "30-50%",

            "detail": "รัน jobs เฉพาะเมื่อ files ที่เกี่ยวข้องเปลี่ยน",

            "example": "path-filtering orb: skip backend tests ถ้าเปลี่ยนแค่ frontend",

        },

        "branch_filter": {

            "name": "5. Branch Filtering",

            "saving": "20-40%",

            "detail": "ไม่ build ทุก branch — skip docs, dependabot, feature branches",

            "example": "filters: branches: ignore: [docs/*, dependabot/*]",

        },

        "docker_layer": {

            "name": "6. Docker Layer Caching (DLC)",

            "saving": "40-70% Docker build time",

            "detail": "Cache Docker layers ระหว่าง builds — จ่าย 200 credits/job แต่คุ้มถ้า build > 5min",

            "example": "Docker build 15min → 4min with DLC",

        },

        "arm": {

            "name": "7. ใช้ ARM Resource Class",

            "saving": "20-30%",

            "detail": "ARM medium = 13 credits/min vs x86 medium = 10 credits/min (comparable performance)",

            "example": "resource_class: arm.medium → ถูกกว่าสำหรับ compatible workloads",

        },

        "self_hosted": {

            "name": "8. Self-Hosted Runners",

            "saving": "50-80%",

            "detail": "รัน builds บน infrastructure ของตัวเอง — ไม่เสีย credits",

            "example": "Scale plan + self-hosted runners สำหรับ heavy builds",

        },

    }



    def show_strategies(self):

        print("=== Cost Reduction Strategies ===\n")

        for key, strat in self.STRATEGIES.items():

            print(f"[{strat['name']}] Saving: {strat['saving']}")

            print(f"  {strat['detail']}")

            print()



    def before_after(self):

        print("=== Before vs After Optimization ===")

        print(f"\n  Before (Unoptimized):")

        print(f"    Resource: medium (10 cr/min) for everything")

        print(f"    No caching, no filtering")

        print(f"    Monthly: 500,000 credits (~$300/month)")

        print(f"\n  After (Optimized):")

        print(f"    Resource: small for lint/test, medium for build")

        print(f"    Full caching, branch filtering, conditional jobs")

        print(f"    Monthly: 150,000 credits (~$90/month)")

        print(f"\n  Saving: 70% ($210/month)")



strat = CostStrategies()

strat.show_strategies()

strat.before_after()

Monitoring & Analytics

# monitoring.py — CI/CD cost monitoring

import json

import random



class CICDMonitoring:

    INSIGHTS_API = """

# circleci_insights.py — CircleCI Insights API

import requests



class CircleCIInsights:

    def __init__(self, token, org_slug):

        self.token = token

        self.org_slug = org_slug

        self.base_url = "https://circleci.com/api/v2"

        self.headers = {"Circle-Token": token}

    

    def get_project_workflows(self, project_slug):

        resp = requests.get(

            f"{self.base_url}/insights/{project_slug}/workflows",

            headers=self.headers,

        )

        return resp.json().get("items", [])

    

    def get_workflow_metrics(self, project_slug, workflow_name):

        resp = requests.get(

            f"{self.base_url}/insights/{project_slug}/workflows/{workflow_name}",

            headers=self.headers,

        )

        return resp.json()

    

    def get_job_metrics(self, project_slug, workflow_name):

        resp = requests.get(

            f"{self.base_url}/insights/{project_slug}/workflows/{workflow_name}/jobs",

            headers=self.headers,

        )

        return resp.json().get("items", [])

    

    def find_expensive_jobs(self, project_slug, workflow_name):

        jobs = self.get_job_metrics(project_slug, workflow_name)

        sorted_jobs = sorted(jobs, key=lambda j: j.get("metrics", {}).get("duration_metrics", {}).get("median", 0), reverse=True)

        return sorted_jobs[:5]



# Usage

# insights = CircleCIInsights("your-token", "gh/org")

# expensive = insights.find_expensive_jobs("gh/org/repo", "build-and-test")

"""



    def show_api(self):

        print("=== CircleCI Insights API ===")

        print(self.INSIGHTS_API[:500])



    def cost_dashboard(self):

        print(f"\n=== CI/CD Cost Dashboard ===")

        jobs = [

            {"name": "unit-tests", "avg_min": random.uniform(2, 8), "runs": random.randint(100, 300), "resource": "small"},

            {"name": "integration-tests", "avg_min": random.uniform(5, 15), "runs": random.randint(50, 150), "resource": "medium"},

            {"name": "docker-build", "avg_min": random.uniform(3, 12), "runs": random.randint(50, 100), "resource": "medium"},

            {"name": "deploy", "avg_min": random.uniform(1, 5), "runs": random.randint(20, 60), "resource": "small"},

        ]

        rates = {"small": 5, "medium": 10, "large": 20}

        total_credits = 0

        for j in jobs:

            credits = j["avg_min"] * j["runs"] * rates[j["resource"]]

            total_credits += credits

            print(f"  {j['name']:<20} {j['avg_min']:>5.1f}min × {j['runs']:>3} runs = {credits:>8,.0f} credits")

        cost = total_credits * 0.0006

        print(f"\n  Total: {total_credits:,.0f} credits (~/month)")



    def optimization_tips(self):

        print(f"\n=== Quick Wins ===")

        tips = [

            "ลด resource_class ของ lint job จาก medium เป็น small → ลด 50%",

            "เพิ่ม cache สำหรับ npm/pip → ลด install time 60-80%",

            "Skip CI สำหรับ docs-only changes → ลด 20-30% runs",

            "ใช้ path-filtering → รัน tests เฉพาะ changed modules",

        ]

        for tip in tips:

            print(f"  • {tip}")



mon = CICDMonitoring()

mon.show_api()

mon.cost_dashboard()

mon.optimization_tips()

Custom Orb สำหรับองค์กร

# custom_orb.py — Custom Orb for organization

import json



class CustomOrb:

    ORB_TEMPLATE = """

# orb.yml — Custom cost-optimized orb

version: 2.1

description: "Organization CI/CD orb with cost optimization built-in"



executors:

  # Pre-defined optimized executors

  light:

    docker:

      - image: cimg/base:current

    resource_class: small

  standard:

    docker:

      - image: cimg/node:20.11

    resource_class: medium

  heavy:

    docker:

      - image: cimg/node:20.11

    resource_class: large



commands:

  # Cached install with fallback

  smart-install:

    parameters:

      package-manager:

        type: enum

        enum: [npm, yarn, pnpm]

        default: npm

    steps:

      - restore_cache:

          keys:

            - deps-v2-{{ checksum "package-lock.json" }}

            - deps-v2-

      - run:

          name: Install Dependencies

          command: |

            if [ -d node_modules ]; then

              echo "Cache hit - skipping install"

            else

              npm ci --prefer-offline

            fi

      - save_cache:

          key: deps-v2-{{ checksum "package-lock.json" }}

          paths: [node_modules]



  # Conditional step based on changed files

  run-if-changed:

    parameters:

      paths:

        type: string

      command:

        type: string

    steps:

      - run:

          name: Check changed files

          command: |

            CHANGED=$(git diff --name-only HEAD~1 | grep -E "<< parameters.paths >>" || true)

            if [ -z "$CHANGED" ]; then

              echo "No relevant changes — skipping"

              circleci-agent step halt

            fi

      - run:

          name: Execute

          command: << parameters.command >>



jobs:

  test:

    executor: light

    steps:

      - checkout

      - smart-install

      - run: npm test

"""



    def show_template(self):

        print("=== Custom Orb Template ===")

        print(self.ORB_TEMPLATE[:600])



    def publish_steps(self):

        print(f"\n=== Publish Custom Orb ===")

        steps = [

            "circleci namespace create my-org github",

            "circleci orb create my-org/cost-optimized",

            "circleci orb pack src/ > orb.yml",

            "circleci orb validate orb.yml",

            "circleci orb publish orb.yml my-org/cost-optimized@0.1.0",

        ]

        for i, step in enumerate(steps, 1):

            print(f"  {i}. {step}")



orb = CustomOrb()

orb.show_template()

orb.publish_steps()

FAQ - คำถามที่พบบ่อย

Q: CircleCI แพงไหม?

A: Free plan: 30,000 credits/month (พอสำหรับ side projects) Performance plan: เริ่ม $15/month + credits ($0.0006/credit) ทีมเล็ก (5 devs): ~$50-150/month (optimized) ทีมกลาง (20 devs): ~$200-800/month ลดค่าใช้จ่าย: optimize resource class, caching, branch filtering

เนื้อหาเกี่ยวข้อง — แนะนำให้อ่าน DALL-E API Security Hardening ป้องกันแฮก

Q: Orbs ช่วยลดค่าใช้จ่ายอย่างไร?

แนะนำเพิ่มเติม — ระบบเทรดของ iCafeForex

A: 1. Built-in caching (node, python orbs) — ลด install time 50-80% 2. Pre-configured executors — ใช้ resource class ที่เหมาะสม 3. Reusable config — ลด config errors ที่ทำให้ build ช้า 4. Docker Layer Caching orb — ลด Docker build time 60%+ 5. Path-filtering orb — skip jobs ที่ไม่เกี่ยวข้อง

เนื้อหาเกี่ยวข้อง — อ่านต่อ: Falco Runtime Security Internal Developer

Q: Resource class ไหนคุ้มที่สุด?

A: small (5 cr/min): lint, unit tests, simple scripts → ถูกที่สุด medium (10 cr/min): general builds, integration tests → default ดี large (20 cr/min): parallel tests, heavy compilation → ใช้เมื่อจำเป็น machine (40 cr/min): Docker-in-Docker → แพง ใช้เฉพาะ Docker builds กฎ: เริ่มจาก small แล้ว upgrade เมื่อ job ช้าเกินไป

แนะนำเพิ่มเติม — บทวิเคราะห์จาก XM Signal

เนื้อหาเกี่ยวข้อง — ดูเพิ่มเติมเรื่อง Server-Sent Events Incident Management

Q: Self-hosted runners คุ้มไหม?

A: คุ้มเมื่อ: ใช้ credits > 500,000/month, มี idle servers, ต้องการ custom hardware (GPU) ไม่คุ้มเมื่อ: ทีมเล็ก, ไม่มี DevOps ดูแล infrastructure, ใช้ credits น้อย ข้อดี: ไม่เสีย credits, custom environment, faster (local network) ข้อเสีย: ต้องดูแล infrastructure, security, scaling เอง

เนื้อหาเกี่ยวข้อง — บทความที่เกี่ยวข้อง: OAuth 2.1 Security Hardening ป้องกันแฮก

XM Legend · เทรดเดอร์ & ผู้สอน Forex 13 ปี

ผู้ก่อตั้ง SiamCafe ตั้งแต่ปี 1997 · เทรดเดอร์สาย Forex มากกว่า 13 ปี ได้รับการยกย่องเป็น XM Legend · แบ่งปันความรู้ Forex, ไอที, AI และการเทรด จากประสบการณ์จริงในตลาดจริง