<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های فرهاد صادقی</title>
        <link>https://virgool.io/feed/@farhad.sadeghi</link>
        <description>مهندس نرم افزار، طراحی و راه اندازی سیستم های نرم افزاری بر پایه معماری میکروسرویس</description>
        <language>fa</language>
        <pubDate>2026-07-06 10:10:50</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/121988/avatar/67MbOq.jpg?height=120&amp;width=120</url>
            <title>فرهاد صادقی</title>
            <link>https://virgool.io/@farhad.sadeghi</link>
        </image>

                    <item>
                <title>آموزش Kubernetes - قسمت سیزدهم (Backup-Gateway API)</title>
                <link>https://virgool.io/@farhad.sadeghi/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-kubernetes-%D9%82%D8%B3%D9%85%D8%AA-%D8%B3%DB%8C%D8%B2%D8%AF%D9%87%D9%85-backup-gateway-api-qew5zpi0grsk</link>
                <description>1.Backupفرض کنید ما دو تا دیتاسنتر با نام های DC-1 و DC-2 داشته باشیم و بخواهیم یک نسخه کامل از همه اپلیکیشن ها و دیتاهای دیتاسنتر1 را به عنوان Disaster روی دیتاسنتر2 هم داشته باشیم.راه اول این است که ما یک کلاستر کوبر توزیع شده بین این دو دیتاسنتر داشته باشیم. یعنی یکی از نودهای مستر کلاستر در دیتاسنتر1 و نود مستر دیگر، در دیتاسنتر2 قرار بگیرند. و هر پاد را هم در نودهای worker دیتاسنتر1 و هم در نودهای worker دیتاسنتر2 اجرا کنیم.برای انجام این کار می توان از مفهوم Affinity و Anti Affinity کمک گرفت.راه دوم این است که ما با ابزاری مانند Velero در بازه های زمانی مختلف یک بکاپ از دیتاسنتر1 را در دیتاسنتر2 قرار دهیم.برای انجام این کار باید ابزار Velero را روی کلاستر1 بالا بیاوریم (Velero بصورت پاد در کلاستر اجرا می شود) این Velero در بازه های زمانی مشخص شده، یک نسخه از همه پادها و اطلاعات موجود در کلاستر1 را ذخیره می کند.برای ذخیره سازی این اطلاعات نیاز به یک storage داریم که S3 را پشتیبانی کند. توجه داشته باشید که این storage نباید داخل کلاستر1 یا 2 باشد زیرا در مواقعی که برای این کلاسترها مشکلی پیش بیاید و در دسترس نباشند، امکان دسترسی به storage باید وجود داشته باشد.یک نسخه دیگر از Velero را هم در کلاستر2 بالا می آوریم. این نسخه بر خلاف نسخه اول، اطلاعات را در بازه های زمانی مشخص شده از storage خوانده و به کلاستر2 منتقل می کند.راهنمای نصب Velero:https://velero.io/docs/v1.6/basic-installبعد از اینکه خود Velero را نصب کردیم، باید آن را کانفیگ و محل ذخیره سازی را برای آن تنظیم کنیم. این کار با دستور velero install انجام می شود.velero install --provider velero.io/aws --bucket mybucket --backup-location-config region=ir-thr-at1,s3ForcePathStyle=&quot;true&quot;,s3Url=https://s3.ir-thr-at1.arvanstorage.ir --plugins velero/velero-plugin-for-aws:v1.0.0,digitalocean/velero-plugin:v1.0.0  --secret-file ./credentialsقبل از کانفیگ Velero ما باید محل ذخیره سازی بکاپ ها را مشخص کنیم. محل ذخیره سازی در پارامتر backup-location-config وارد می شود. به عنوان مثال فرض کنید ما یک باکت در آروان کلاد ایجاد کرده ایم و از آن به عنوان محل ذخیره سازی استفاده خواهیم کرد.https://mybucket.s3.ir-thr-at1.arvanstorage.irتوجه: قسمت اول آدرس در باکت آروان کلاد، نام bucket و قسمت میانی نام region می باشد.برای اتصال به باکت همچنین نیاز است که access_key و secret_key داشته باشیم. این کلیدها به فرمت زیر و داخل فایل credentials تعریف می شوند.credentials[default]
aws_access_key_id=ee00744a-8d81-4989-8804-8868e3c51ff7
aws_secret_access_key=3e366632a7bda34cee72d3efa192c0c250fcb7b8ایجاد بکاپ:velero backup create nginx-backup --selector app=v1شرح بکاپ:velero backup describe nginx-backupمشاهده لاگ:velero backup logs nginx-backup2.Gateway APIGateway API نسل جدید مدیریت ترافیک در Kubernetes است که توسط جامعه Kubernetes توسعه داده شده تا محدودیت‌های Ingress را برطرف کند.اگر بخواهم خیلی ساده بگویم:Ingress = راه‌حل قدیمی و ساده برای ورود ترافیک HTTP/HTTPSGateway API = راه‌حل جدید، انعطاف‌پذیر و استاندارد برای مدیریت انواع ترافیک (HTTP، HTTPS، TCP، UDP، TLS و ...)مشکل Ingress چه بود؟فرض کنید یک برنامه دارید.Internet
     │
     ▼
Ingress
     │
     ▼
Service
     │
     ▼
Podsیک Ingress معمولی:apiVersion: networking.k8s.io/v1
kind: Ingress

spec:
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /
        backend:
          service:
            name: api-service
            port:
              number: 80برای کاربردهای ساده مناسب است.اما مشکلاتی داشت:فقط HTTP/HTTPS را به خوبی پشتیبانی می‌کرد.هر Ingress Controller قابلیت‌های اختصاصی خودش را داشت.برای ویژگی‌هایی مانند Rate Limiting، Canary، Header Rewrite یا JWT باید از Annotationهای مخصوص هر کنترلر استفاده می‌کردید.اگر از کنترلری مانند NGINX به HAProxy مهاجرت می‌کردید، احتمالاً باید Annotationها را بازنویسی می‌کردید.مثلاً:metadata:
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /اگر از کنترلر دیگری استفاده کنید، این Annotation دیگر کار نمی‌کند.Gateway API چه چیزی اضافه می‌کند؟Gateway API منابع Kubernetes را به چند بخش تقسیم کرده است تا هر بخش مسئولیت مشخصی داشته باشد.مهم‌ترین منابع عبارت‌اند از:GatewayClassGatewayHTTPRouteTCPRouteTLSRouteUDPRouteGRPCRouteدر نتیجه، پیکربندی ساده‌تر و قابل توسعه‌تر می‌شود.معماری Gateway API               GatewayClass
                     │
                     ▼
                 Gateway
                     │
        ┌────────────┴────────────┐
        ▼                         ▼
   HTTPRoute                 TCPRoute
        │                         │
        ▼                         ▼
    Service A                 Service B
        │                         │
      Pods                      PodsGatewayClass:مشخص می‌کند از چه پیاده‌سازی استفاده می‌کنید.مثلاً:NGINX GatewayEnvoy GatewayKong GatewayIstioCiliumنمونه:apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass

metadata:
  name: envoy

spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controllerاین شبیه StorageClass در Storage یا IngressClass برای Ingress است.Gateway:Gateway همان Load Balancer یا Entry Point است.مثلاً:apiVersion: gateway.networking.k8s.io/v1
kind: Gateway

metadata:
  name: web-gateway

spec:
  gatewayClassName: envoy
  listeners:
  - protocol: HTTP
    port: 80
    name: httpدر اینجا فقط تعریف می‌کنید که Gateway روی پورت ۸۰ به درخواست‌ها گوش دهد.HTTPRoute:اینجاست که قوانین مسیریابی تعریف می‌شوند.apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute

metadata:
  name: api-route

spec:
  parentRefs:
  - name: web-gateway

  hostnames:
   - example.com

  rules:
    - matches:
      - path:
          type: PathPrefix
          value: /api
    backendRefs:
      - name: api-service
        port: 80
        weight: 90در این مثال:/api
    │
    ▼
api-serviceمثال کاملفرض کنید دو سرویس دارید:frontend-service
backend-serviceمی‌خواهید:/
↓
frontend

/api
↓
backendGateway:Internet
↓
GatewayHTTPRoute:/
↓
frontend-service

/api
↓
backend-serviceبه این ترتیب، مسئولیت Listener و مسئولیت Route از هم جدا شده‌اند.یکی از بزرگ‌ترین مزیت‌ها: تفکیک مسئولیت‌هادر Ingress معمولاً یک فایل همه چیز را مشخص می‌کرد:پورتدامنهمسیرهاTLSدر Gateway API این مسئولیت‌ها جدا شده‌اند.مثلاً:تیم زیرساخت:Gatewayرا مدیریت می‌کند.اما تیم توسعه فقط:HTTPRouteخودش را ایجاد می‌کند.بدون اینکه به تنظیمات Load Balancer دست بزند.این موضوع برای سازمان‌های بزرگ بسیار مهم است.قابلیت‌های پیشرفتهGateway API به صورت استاندارد از قابلیت‌هایی مانند:Header MatchingHeader RewriteURL RewriteTraffic SplittingCanary DeploymentWeight-based RoutinggRPCTCPUDPTLS Passthroughپشتیبانی می‌کند.بدون اینکه وابسته به Annotationهای مخصوص یک Vendor باشید.آیا Gateway API جایگزین Ingress شده است؟در عمل، بله، اما به تدریج.Ingress هنوز به‌طور گسترده استفاده می‌شود و توسط Kubernetes حذف نشده است، اما Gateway API مسیر آینده اکوسیستم Kubernetes محسوب می‌شود و بسیاری از پروژه‌ها و کنترلرها (مانند Envoy Gateway، Istio، Kong، Cilium و نسخه‌های جدید NGINX Gateway Fabric) روی آن سرمایه‌گذاری کرده‌اند.آیا برای Gateway API باز هم به یک Controller نیاز داریم؟بله. این نکته یکی از رایج‌ترین ابهام‌هاست.Gateway API فقط تعریف استاندارد Resourceها (CRDها) را ارائه می‌دهد. برای اینکه این Resourceها واقعاً ترافیک را مدیریت کنند، باید یک Gateway Controller آن‌ها را پیاده‌سازی کند.نمونه‌هایی از Gateway Controllerها عبارت‌اند از:NGINX Gateway FabricEnvoy GatewayKong Gateway OperatorIstio (با پشتیبانی از Gateway API)Cilium Gateway APIبه عبارت دیگر:Ingress + Ingress Controller → مدیریت ترافیکGateway API + Gateway Controller → مدیریت ترافیک با قابلیت‌های بیشتربنابراین Gateway API جایگزین Ingress Resource است، نه جایگزین خود Controller. همچنان برای اعمال تنظیمات و هدایت ترافیک به یک پیاده‌سازی (Controller) نیاز دارید.How to install envoy gateway:https://gateway.envoyproxy.io/v1.5/install/install-helm/</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Sun, 05 Jul 2026 00:08:44 +0330</pubDate>
            </item>
                    <item>
                <title>آموزش Kubernetes - قسمت دوازدهم (Job-CronJob-Helm/Chart)</title>
                <link>https://virgool.io/@farhad.sadeghi/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-kubernetes-%D9%82%D8%B3%D9%85%D8%AA-%D8%AF%D9%88%D8%A7%D8%B2%D8%AF%D9%87%D9%85-job-cronjob-helmchart-dksb6cfs71ie</link>
                <description>1.JobJob در Kubernetes یک منبع (Resource) است که برای اجرای کارهای یک‌باره (Batch یا Run-to-Completion) استفاده می‌شود. برخلاف Deployment که همیشه سعی می‌کند Podها در حال اجرا باشند، Job پس از اینکه کار موردنظر با موفقیت انجام شد، به پایان می‌رسد.Job چه زمانی استفاده می‌شود؟موارد رایج استفاده از Job:اجرای اسکریپت‌های Backupپردازش فایل‌هاImport یا Export داده‌هااجرای Migration پایگاه دادهارسال گزارش‌های دوره‌ای (اگر زمان‌بندی لازم باشد، معمولاً با CronJob)اجرای تست‌های Batchنحوه کار Jobفرض کنید یک Job ایجاد می‌کنید.Kubernetes یک یا چند Pod ایجاد می‌کند.Pod برنامه را اجرا می‌کند.اگر برنامه با Exit Code = 0 تمام شود، Job موفق (Succeeded) می‌شود.اگر برنامه با خطا خارج شود، Job بسته به تنظیمات، Pod جدیدی ایجاد کرده و دوباره تلاش می‌کند.به عبارت دیگر:Job
 │
 └── Pod
      │
      ├── اجرای برنامه
      ├── موفق → Job Complete
      └── ناموفق → Retry
یک مثال سادهapiVersion: batch/v1
kind: Job
metadata:
  name: hello-job
spec:
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: hello
        image: busybox
        command:
        - echo
        - &quot;Hello Kubernetes Job&quot;
ایجاد Job:kubectl apply -f job.yaml
مشاهده Job:kubectl get jobs
مشاهده Pod:kubectl get pods
لاگ:kubectl logs &lt;pod-name&gt;جزئیات:kubectl describe job hello-jobحذف:kubectl delete job hello-jobrestartPolicyدر Job فقط دو مقدار مجاز هستند:restartPolicy: Never
یا
restartPolicy: OnFailureNeverاگر برنامه شکست بخورد:Pod 1 → Failed
        ↓
Job یک Pod جدید ایجاد می‌کند.
OnFailureاگر Container داخل همان Pod کرش کند:Container
    ↓
همان Pod دوباره اجرا می‌شود.
backoffLimitتعداد دفعات Retry را مشخص می‌کند.مثال:spec:
  backoffLimit: 4
یعنی اگر Job چهار بار شکست بخورد:Attempt 1 ❌

Attempt 2 ❌

Attempt 3 ❌

Attempt 4 ❌

Job Failed
completionsتعداد دفعاتی که Job باید با موفقیت اجرا شود.مثال:spec:
  completions: 5
یعنی:Success 1 ✔

Success 2 ✔

Success 3 ✔

Success 4 ✔

Success 5 ✔

Job Complete
parallelismچند Pod همزمان اجرا شوند.مثال:spec:
  completions: 10
  parallelism: 3
خروجی:Pod1
Pod2
Pod3     ← همزمان

وقتی یکی تمام شد

Pod4

بعد Pod5

...
در نهایت باید ۱۰ اجرای موفق داشته باشید، اما حداکثر ۳ Pod همزمان اجرا می‌شوند.activeDeadlineSecondsحداکثر زمان اجرای Job.spec:
  activeDeadlineSeconds: 300
بعد از ۵ دقیقه:Job → Failed
حتی اگر هنوز کامل نشده باشد.ttlSecondsAfterFinishedحذف خودکار Job بعد از اتمام.spec:
  ttlSecondsAfterFinished: 600
یعنی:Job Complete

↓

۱۰ دقیقه بعد

↓

حذف Job و Pod
نمونه کاملapiVersion: batch/v1
kind: Job
metadata:
  name: batch-job
spec:
  completions: 5
  parallelism: 2
  backoffLimit: 3
  ttlSecondsAfterFinished: 300

  template:
    spec:
      restartPolicy: Never
      containers:
      - name: worker
        image: busybox
        command:
        - sh
        - -c
        - |
          echo Start
          sleep 10
          echo Done
2.CronJobJob: یک بار اجرا می‌شود.CronJob: بر اساس زمان‌بندی، به‌صورت خودکار Jobهای جدید ایجاد می‌کند (مشابه cron در لینوکس).به طور خلاصه، CronJob یک زمان‌بند است که در هر نوبت، یک Job جدید می‌سازد؛ بنابراین هر قابلیتی که برای Job وجود دارد (مانند backoffLimit، parallelism و completions) را می‌توانید داخل بخش jobTemplate نیز پیکربندی کنیدبرای مثال، اگر بخواهید هر شب ساعت ۲ بامداد از پایگاه داده نسخه پشتیبان تهیه کنید، از CronJob استفاده می‌کنید که در هر نوبت، یک Job جدید برای انجام عملیات Backup ایجاد می‌کند.مثال: اجرای Job هر دقیقهapiVersion: batch/v1
kind: CronJob
metadata:
  name: hello-cronjob
spec:
  schedule: &quot;* * * * *&quot;

  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: Never
          containers:
          - name: hello
            image: busybox
            command:
            - sh
            - -c
            - |
              echo &quot;Current time: $(date)&quot;اعمال آن:kubectl apply -f cronjob.yamlمشاهده CronJobkubectl get cronjobsنمونه خروجی:NAME            SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE
hello-cronjob   * * * * *     False     0        30sمشاهده Jobهای ایجادشدهkubectl get jobsنمونه خروجی:NAME                         COMPLETIONS   DURATION
hello-cronjob-28692340       1/1           5s
hello-cronjob-28692341       1/1           4s
hello-cronjob-28692342       1/1           5sهر بار که زمان‌بندی فرا برسد، یک Job جدید ساخته می‌شود.مشاهده لاگاگر نام Pod را ندانید:kubectl logs job/hello-cronjob-28692342یا:kubectl logs &lt;pod-name&gt;فرمت زمان‌بندی (Cron Expression)CronJob از ۵ فیلد برای زمان‌بندی استفاده می‌کند:* * * * *
│ │ │ │ │
│ │ │ │ └── روز هفته (0-6)
│ │ │ └──── ماه (1-12)
│ │ └────── روز ماه (1-31)
│ └──────── ساعت (0-23)
└────────── دقیقه (0-59)مثال واقعی: Backup دیتابیس هر شبapiVersion: batch/v1
kind: CronJob
metadata:
  name: mysql-backup
spec:
  schedule: &quot;0 2 * * *&quot;

  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: Never
          containers:
          - name: backup
            image: mysql:8
            command:
            - sh
            - -c
            - |
              mysqldump -h mysql-service \
                        -u root \
                        -p$MYSQL_PASSWORD \
                        mydb &gt; /backup/mydb.sqlدر این مثال، هر شب ساعت ۲ یک Job جدید ایجاد می‌شود که از پایگاه داده نسخه پشتیبان تهیه می‌کند.تنظیمات مهم CronJobجلوگیری از اجرای هم‌زماناگر اجرای قبلی هنوز تمام نشده باشد:concurrencyPolicy: Forbidگزینه‌های ممکن:Allow (پیش‌فرض): اجرای هم‌زمان مجاز است.Forbid: اگر Job قبلی هنوز در حال اجرا باشد، Job جدید ایجاد نمی‌شود.Replace: Job قبلی متوقف شده و Job جدید جایگزین آن می‌شود.نگهداری تاریخچه JobهاsuccessfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1یعنی فقط ۳ Job موفق و ۱ Job ناموفق نگه داشته شوند و بقیه حذف شوند.متوقف کردن CronJobبرای جلوگیری موقت از اجرای زمان‌بندی:spec:
  suspend: trueبرای فعال‌سازی مجدد:spec:
  suspend: false3.Helm/Chartاگر Kubernetes را با apt مقایسه کنیم، Helm همان چیزی است که apt برای لینوکس یا npm برای Node.js است.به عبارت ساده:Kubernetes = سیستم‌عامل اجرای کانتینرهاHelm = Package Manager برای KubernetesChart = بسته (Package) که شامل تمام فایل‌های موردنیاز برای نصب یک برنامه روی Kubernetes است.چرا Helm به وجود آمد؟فرض کنید می‌خواهید یک برنامه مانند Jenkins را روی Kubernetes نصب کنید.بدون Helm باید فایل‌های زیر را خودتان بنویسید:DeploymentServiceConfigMapSecretPersistentVolumeClaimIngressServiceAccountRoleRoleBindingNetworkPolicyممکن است بیش از ۲۰ فایل YAML داشته باشید.ساختار:jenkins/
 ├── deployment.yaml
 ├── service.yaml
 ├── pvc.yaml
 ├── ingress.yaml
 ├── secret.yaml
 ├── configmap.yaml
 ├── role.yaml
 ├── rolebinding.yaml
 └── ...مدیریت این فایل‌ها سخت می‌شود. Helm این مشکل را حل می‌کند.Helm Chart چیست؟یک Chart مجموعه‌ای از Templateهای Kubernetes است که به همراه مقادیر قابل تنظیم (Values) بسته‌بندی شده‌اند.ساختار یک Chart:mychart/
│
├── Chart.yaml
├── values.yaml
├── charts/
├── templates/
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── ingress.yaml
│   └── pvc.yaml
└── .helmignoreChart.yamlاطلاعات خود Chart را نگهداری می‌کند.مثال:apiVersion: v2
name: nginx
description: My nginx chart
type: application
version: 1.0.0
appVersion: &quot;1.27&quot;values.yamlتمام تنظیمات قابل تغییر اینجاست.مثلاً:replicaCount: 2

image:
  repository: nginx
  tag: latest

service:
  type: ClusterIP
  port: 80اگر بخواهید تعداد Replica را تغییر دهید، لازم نیست Deployment را ویرایش کنید؛ فقط این فایل را تغییر می‌دهید.templates/داخل این پوشه Templateهای Kubernetes قرار دارند.مثلاً Deployment:apiVersion: apps/v1
kind: Deployment

metadata:
  name: {{ .Release.Name }}

spec:
  replicas: {{ .Values.replicaCount }}

  template:

    spec:

      containers:

      - name: nginx

        image: &quot;{{ .Values.image.repository }}:{{ .Values.image.tag }}&quot;دقت کنید:{{ .Values.replicaCount }}از فایل values.yaml خوانده می‌شود.نحوه کار Helmفرض کنید:values.yamlreplicaCount: 3Template:replicas: {{ .Values.replicaCount }}بعد از نصب Helm:replicas: 3تولید می‌شود.یعنی Helm قبل از ارسال فایل به Kubernetes، Templateها را Render می‌کند.نصب یک Chartمثلاً نصب Nginx:helm install my-nginx bitnami/nginxاتفاقی که می‌افتد:Helm
↓
Template Rendering
↓
Deployment
Service
ConfigMap
PVC
...
↓
Kubernetes APIنصب با مقادیر سفارشیفرض کنید می‌خواهید سه Replica داشته باشید:helm install my-nginx bitnami/nginx --set replicaCount=3یاhelm install my-nginx bitnami/nginx -f values-production.yamlUpgradeیکی از بزرگ‌ترین مزیت‌های Helm:helm upgrade my-nginx bitnami/nginxبدون حذف برنامه، تنظیمات را به‌روزرسانی می‌کند.Rollbackاگر نسخه جدید مشکل داشت:ابتدا تاریخچه نسخه‌ها را ببینید:helm history my-nginxسپس به نسخه قبل برگردید:helm rollback my-nginx 1این یکی از ویژگی‌هایی است که مدیریت نسخه و بازگشت سریع را بسیار ساده می‌کند.حذف برنامهhelm uninstall my-nginxتمام Resourceهایی که Helm ایجاد کرده بود حذف می‌شوند.ساخت یک Chart جدیدhelm create myappساختار زیر ایجاد می‌شود:myapp/
Chart.yaml
values.yaml
templates/
charts/دستورات مهم Helmhelm repo add bitnami https://charts.bitnami.com/bitnami

helm repo update

helm search repo nginx

helm install my-nginx bitnami/nginx

helm list

helm status my-nginx

helm upgrade my-nginx bitnami/nginx

helm rollback my-nginx 1

helm uninstall my-nginxمثال عملیفرض کنید می‌خواهید یک برنامه را در سه محیط مختلف اجرا کنید.DevelopmentreplicaCount: 1

image:
  tag: devStagingreplicaCount: 2

image:
  tag: stagingProductionreplicaCount: 5

image:
  tag: stableبرای هر محیط فقط فایل مقادیر (Values) تغییر می‌کند:helm install app-dev ./mychart -f values-dev.yaml

helm install app-stage ./mychart -f values-stage.yaml

helm install app-prod ./mychart -f values-prod.yamlبدون اینکه Templateها را تغییر دهید، Helm تنظیمات مناسب هر محیط را اعمال می‌کند.جمع‌بندیHelm سه مفهوم کلیدی دارد:Chart: بسته‌ای شامل Templateها و تنظیمات یک برنامه.Values: مقادیر قابل تنظیم که بدون تغییر Templateها، رفتار برنامه را تغییر می‌دهند.Release: هر بار که یک Chart را نصب می‌کنید، Helm یک Release ایجاد می‌کند و نسخه‌های آن را مدیریت می‌کند.به همین دلیل، Helm به استاندارد رایج برای استقرار و مدیریت برنامه‌های پیچیده روی Kubernetes تبدیل شده است؛ زیرا نصب، به‌روزرسانی، بازگشت به نسخه قبل و سفارشی‌سازی برنامه‌ها را به‌صورت یکپارچه فراهم می‌کند.برای نصب Helm، به راهنمای موجود در سایت رسمی آن رجوع کنید:https://helm.shhttps://helm.sh/docs/intro/installهمچنین در سایت زیر می توانید مجموعه کاملی از پکیج ها و نرم افزارهای Cloud Native را جستجو کرده و آنها را از طریق Helm/Chart نصب کنید:https://artifacthub.io</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Sat, 04 Jul 2026 21:00:57 +0330</pubDate>
            </item>
                    <item>
                <title>آموزش Kubernetes - قسمت یازدهم (HPA-RBAC-Network Policy)</title>
                <link>https://virgool.io/@farhad.sadeghi/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-kubernetes-%D9%82%D8%B3%D9%85%D8%AA-%DB%8C%D8%A7%D8%B2%D8%AF%D9%87%D9%85-hpa-rbac-network-policy-t30de9uov6pb</link>
                <description>1.Horizontal Pod Autoscaling (HPA)https://kubernetes.io/docs/concepts/workloads/autoscaling/horizontal-pod-autoscale/https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/Metrics Serverبرای اینکه metricهای سرور مانند میزان مصرف CPU و RAM را داشته باشیم باید metric server نصب کنیم.https://github.com/kubernetes-sigs/metrics-serverkubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yamlاگر Metric server نصب باشد، با دستور زیر می توانیم پادهایی که بیشترین منابع را مصرف می کنند را مشاهده کنیم:HPA:apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: phpapp
spec:
  maxReplicas: 5
  metrics:
  - resource:
      name: cpu
      target:
        averageUtilization: 70
        type: Utilization
    type: Resource
  minReplicas: 1
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: phpappYou can check the current status of the newly-made HorizontalPodAutoscaler, by running:# You can use &quot;hpa&quot; or &quot;horizontalpodautoscaler&quot;; either name works OK.
kubectl get hpaThe output is similar to:NAME         REFERENCE                  TARGET    MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache/scale  0%/50%    1       10       1          18s2.Role Based Access Control (RBAC)https://kubernetes.io/docs/concepts/security/rbac-good-practices/https://kubernetes.io/docs/reference/access-authn-authz/rbac/Role exampleHere&#039;s an example Role in the &quot;default&quot; namespace that can be used to grant read access to pods:access/simple-role.yamlapiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [&quot;&quot;] # &quot;&quot; indicates the core API group
  resources: [&quot;pods&quot;]
  verbs: [&quot;get&quot;, &quot;watch&quot;, &quot;list&quot;]RoleBinding examplesHere is an example of a RoleBinding that grants the &quot;pod-reader&quot; Role to the user &quot;jane&quot; within the &quot;default&quot; namespace. This allows &quot;jane&quot; to read pods in the &quot;default&quot; namespace.access/simple-rolebinding-with-role.yamlapiVersion: rbac.authorization.k8s.io/v1
# This role binding allows &quot;jane&quot; to read pods in the &quot;default&quot; namespace.
# You need to already have a Role named &quot;pod-reader&quot; in that namespace.
kind: RoleBinding
metadata:
  name: read-pods
  namespace: default
subjects:
# You can specify more than one &quot;subject&quot;
- kind: User
  name: jane # &quot;name&quot; is case sensitive
  apiGroup: rbac.authorization.k8s.io
roleRef:
  # &quot;roleRef&quot; specifies the binding to a Role / ClusterRole
  kind: Role #this must be Role or ClusterRole
  name: pod-reader # this must match the name of the Role you wish to bind to
  apiGroup: rbac.authorization.k8s.ioنحوه مشاهده همه کلیدهای خصوصی و certificateهای موجود در کلاستر کوبرنتیز:اگر ما برای یک کاربر جدید در کلاستر کوبر خود کلید خصوصی و عمومی تعریف کنیم، خود این کلیدها باید توسط کلیدهای کلاستر کوبر مجددا رمز می شوند. این کار باعث می شود که هر کسی نتواند با تولید یک جفت کلید عمومی و خصوصی برای خود، بتواند در کلاستر کوبرنتیز کاربر اضافه کند.برای اینکه یک کاربر از روی لپ‌تاپ یا یک سرور خارج از نودهای Kubernetes بتواند با kubectl به کلاستر متصل شود و کلاستر کوبرنتیز را مدیریت کند یا یک سری از کامندهای محدود را اجرا کند، روند کلی به این صورت است:ایجاد هویت برای کاربر (Certificate یا Token)اعطای مجوز با RBACساخت kubeconfig برای کاربردر دسترس قرار دادن Kubernetes API Server از بیرونروش استاندارد: استفاده از Certificate + RBAC1. ساخت Private Keyopenssl genrsa -out user.key 20482. ساخت CSRopenssl req -new -key user.key -out user.csr -subj &quot;/CN=ali/O=developers&quot;CN = نام کاربرO = گروه کاربر3. امضای Certificateاگر CA کلاستر را دارید (مثلاً در kubeadm):openssl x509 -req \
  -in user.csr \
  -CA /etc/kubernetes/pki/ca.crt \
  -CAkey /etc/kubernetes/pki/ca.key \
  -CAcreateserial \
  -out user.crt \
  -days 3654. ساخت Role یا ClusterRoleمثلاً اجازه مشاهده Podها:apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: pod-reader
rules:
- apiGroups: [&quot;&quot;]
  resources: [&quot;pods&quot;]
  verbs: [&quot;get&quot;,&quot;list&quot;,&quot;watch&quot;]اعمال:kubectl apply -f role.yaml5. Bind کردن Role به کاربرapiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: ali-pod-reader
subjects:
- kind: User
  name: ali
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io6. ساخت kubeconfigkubectl config set-cluster mycluster \
  --server=https://&lt;API_SERVER&gt;:6443 \
  --certificate-authority=ca.crt

kubectl config set-credentials ali \
  --client-certificate=user.crt \
  --client-key=user.key

kubectl config set-context ali-context \
  --cluster=mycluster \
  --user=ali

kubectl config use-context ali-contextاین فایل را به کاربر می دهیم.در دسترس بودن API Serverاگر کاربر خارج از نودها است، باید بتواند به آدرس API Server دسترسی داشته باشد، مثلاً:https://k8s.example.com:6443یاhttps://10.10.10.5:6443بنابراین باید:پورت 6443 روی فایروال باز باشد.آدرس API Server از شبکه کاربر قابل دسترس باشد.در صورت استفاده از Load Balancer، آدرس آن را در kubeconfig قرار دهید.اگر کاربر ادمین باشدمی‌توانید kubeconfig ادمین را نیز در اختیار او قرار دهید (برای محیط‌های Production توصیه نمی‌شود):/etc/kubernetes/admin.confیا نسخه‌ای از آن با آدرس API مناسب برای دسترسی خارجی ایجاد کنید.3.Network Policyhttps://kubernetes.io/docs/concepts/services-networking/network-policies/There are two sorts of isolation for a pod: isolation for egress, and isolation for ingress.An example NetworkPolicy might look like this:service/networking/networkpolicy.yamlapiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978Default policiesBy default, if no policies exist in a namespace, then all ingress and egress traffic is allowed to and from pods in that namespace. The following examples let you change the default behavior in that namespace.Default deny all ingress trafficYou can create a &quot;default&quot; ingress isolation policy for a namespace by creating a NetworkPolicy that selects all pods but does not allow any ingress traffic to those pods.service/networking/network-policy-default-deny-ingress.yaml---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
spec:
  podSelector: {}
  policyTypes:
  - IngressThis ensures that even pods that aren&#039;t selected by any other NetworkPolicy will still be isolated for ingress. This policy does not affect isolation for egress from any pod.Allow all ingress trafficIf you want to allow all incoming connections to all pods in a namespace, you can create a policy that explicitly allows that.service/networking/network-policy-allow-all-ingress.yaml---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-ingress
spec:
  podSelector: {}
  ingress:
  - {}
  policyTypes:
  - IngressWith this policy in place, no additional policy or policies can cause any incoming connection to those pods to be denied. This policy has no effect on isolation for egress from any pod.Default deny all egress trafficYou can create a &quot;default&quot; egress isolation policy for a namespace by creating a NetworkPolicy that selects all pods but does not allow any egress traffic from those pods.service/networking/network-policy-default-deny-egress.yaml---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-egress
spec:
  podSelector: {}
  policyTypes:
  - EgressThis ensures that even pods that aren&#039;t selected by any other NetworkPolicy will not be allowed egress traffic. This policy does not change the ingress isolation behavior of any pod.Caution:A default deny-all egress policy also blocks DNS traffic. If your workloads need DNS resolution, you must add a separate NetworkPolicy that allows egress to your cluster&#039;s DNS service.Allow all egress trafficIf you want to allow all connections from all pods in a namespace, you can create a policy that explicitly allows all outgoing connections from pods in that namespace.service/networking/network-policy-allow-all-egress.yaml---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-egress
spec:
  podSelector: {}
  egress:
  - {}
  policyTypes:
  - EgressWith this policy in place, no additional policy or policies can cause any outgoing connection from those pods to be denied. This policy has no effect on isolation for ingress to any pod.Default deny all ingress and all egress trafficYou can create a &quot;default&quot; policy for a namespace which prevents all ingress AND egress traffic by creating the following NetworkPolicy in that namespace.service/networking/network-policy-default-deny-all.yaml---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - EgressThis ensures that even pods that aren&#039;t selected by any other NetworkPolicy will not be allowed ingress or egress traffic.</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Sat, 04 Jul 2026 20:50:05 +0330</pubDate>
            </item>
                    <item>
                <title>آموزش Kubernetes - قسمت دهم (Storage)</title>
                <link>https://virgool.io/@farhad.sadeghi/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-kubernetes-%D9%82%D8%B3%D9%85%D8%AA-%D8%AF%D9%87%D9%85-storage-y08dgg6m3ywg</link>
                <description>فرض کنید ما یک فضای ذخیره سازی مانند NFS داریم. حالا ما یک پاد بالا می آوریم و می خواهیم مسیر data/ آن را به NFS وصل کنیم.NFS (Network File System): پروتکل دسترسی به فایل تحت شبکهاین کار مزایایی برای ما خواهد داشت، از جمله:اطلاعات پاد persistent می شود و با از بین رفتن پاد، اطلاعات آن همچنان پا برجاست.از طرف دیگر ما به راحتی می توانیم پاد خود را scale کنیم و تعداد بیشتری از آن را بالا بیاوریم که همگی از یک منبع ذخیره سازی استفاده می کنند و دیتاهای مشترکی دارند.نصب NFS~ yum -y install nfs-utils
~ systemctl enable --now nfs-servermkdir /var/nfs
vim /etc/exportsدر فایل etc/exports باید مشخص کنیم که چه رنج IPهایی به چه فولدرهایی دسترسی دارند. هر درخواست که از هر پاد صادر می شود به آی پی Node آن پاد مپ می شود، بنابراین در این قسمت IP نودها مدنظر است./var/nfs     192.168.65.0/24(rw,sync,no_root_squash,no_all_squash)systemctl restart nfs-serverبرخی از storage solution ها را کوبرنتیز می شناسد مانند NFS و فقط کافی است آنها را نصب کنید اما برخی دیگر را باید به کوبرنتیز بشناسانیم، برای این کار باید CSI driver آنها را نصب کنیم.storage های سخت افزاری مانند SAN Storage بسیار گران قیمت هستند و خیلی از شرکت های هاستینگ و نرم افزاری سراغ Software Defined Storageها می روند. مانند CEPH که یک ذخیره ساز Distributed می باشد. یعنی می توانیم Replica های مختلف در چند دیتاسنتر داشته باشیم.Software Defined Storages:.........................................................................................CEPH (Object Storage, Block Storage, File Storage)GlusterFS (File Storage)Minio (Object Storage)Open EBS (Block Storage)LongHorn (Block Storage)VSAN (Block Storage)Access Modes.........................................................................................ReadwriteOnceReadOnlyMany (RX)ReadWriteMany (RWX)ReadWriteOncePodSoftware Defined Storage ها به سه روش دیسک در اختیار ما قرار می دهند:Block Storage:storage را به بلاک های خام تقسیم بندی می کنیم. روی هر یک از بلاک ها باید file system نصب شود و پارتیشن بندی انجام شود تا بتوان از آن استفاده کرد.از جمله کاربردهای Block storage برای راه اندازی ماشین های مجازی می باشد، یعنی فضای ذخیره سازی را به بلاک هایی تقسیم بندی می کنند، هر فضا را به یک VM تخصیص می دهند و آن VM خودش روی فضای تخصیص داده شده file system نصب کرده و آن را پارتیشن بندی می کند.File Storage:نیازی به پارتیشن بندی و نصب فایل سیستم وجود ندارد و بلافاصله بعد از راه اندازی قابل استفاده هستند. NFS نمونه ای از file storage ها است. file storage ها عموما over network هستند.از جمله کاربردهای File storage ایجاد فضای اشتراک فایل می باشد (فولدرها یا پارتیشن های Share). یعنی دیتا یک جای دیگر و روی سروری مشخص ذخیره می شود و شما با پروتکل های شبکه به آن متصل می شوید.Object Storage:در object storage فایل یا محتوایی که می خواهیم ذخیره سازی کنیم بصورت object در باکت ذخیره سازی می شود. در این حالت object همانطور که over http منتقل می شود، همانطور هم ذخیره می شود و موقع بازیابی هم، به همان صورت از باکت خوانده شده و over http منتقل می شود.در Object storage یک باکت ساخته می شود، access key و secret key و url تحویل برنامه داده می شود. برنامه با استفاده از این کلیدها می تواند در باکت فایل ذخیره کند. در Object storage ما کاری با فرمت و نحوه ذخیره سازی اطلاعات در سرور نداریم. فایل خود را over http به آن می دهیم و over http هم از آن می گیریم.Assign storage to PODPV (Persistence Volume):ابتدا باید یک PV تعریف کنیم. PV یک مفهوم logical است. در هر PV باید مشخص شود که چقدر فضا دارد؟ روی چه سخت افزاری قرار دارد؟ و سطح دسترسی به آن به چه شکلی است؟PV:Size: 5 GiStorage Solution: NFSaccessMode: read/write/manykubectl api-resources | grep pvpv.yamlapiVersion: v1
kind: PersistentVolume
metadata:
 name: db-pv
spec:
 capacity:
  storage: 5Gi
 accessMode:
  - ReadWriteMany
 storageClassName: nfs
 nfs:
  server: 192.168.65.43
  path: /var/nfsدقت داشته باشید که نیاز نیست ما NFS را روی همه نودها نصب کنیم بلکه آن را روی یک نود نصب می کنیم و بقیه از آن استفاده می کنند، مانند دیتابیس.kubectl apply -f pv.yaml
kubectl get pvPVC (Persistence Volume Claim):حالا فرض کنید یک پاد درخواست 10 Gi فضا داشته باشد، به این درخواست claim می گویند.PVC:Size: 10 GiaccessMode: read/write/manyهر درخواست (PVC) باید به یک storage (PV) اصطلاحا Bound شود.اگر فضای درخواست شده بیشتر از فضای PV باشد، آن درخواست pending می ماند.kubectl api-resources | grep pvcpvc.yamlapiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: vote-app-pvc
spec:
 accessModes:
  - ReadWriteMany
 storageClassName: nfs
 resources:
  requests:
   storage: 5Gikubectl apply -f pvc.yaml
kubectl get pv,pvcpostgres.yamltemplate:
 metadata:
  labels:
   app: postgres
 spec:
  containers:
   - image: apk-reg.aradarpanet.ir/class/postgres:15
     name: postgres
     imagePullPolicy: IfNotPresent
     volumeMounts:
      - mountPath: /var/lib/postgresql/data/
        name: vote-nfs
     env:
      - name: POSTGRES_USER
        value: postgres
      - name: POSTGRES_PASSWORD
        value: postgres
  volumes:
   - name: vote-nfs
     persistentVolumeClaim:
      claimName: vote-app-pvcبعد از apply کردن postgres.yaml، احتمالا اجرای پاد با خطا مواجه می شود چون پروتکل nfs روی نودی که پاد روی آن اجرا می شود نصب نشده است و ما باید nfs-client را روی آن نود نصب کنیم تا بتواند با nfs-server ارتباط بگیرد.yum -y install nfs-client
yum -y install nfs-utilsReclaim Policy:فرض کنید ما یک PV و PVC تعریف کردیم و این دو به هم bound شدند و PVC به یک پاد تخصیص داده شد. حال اگر آن پاد حذف شود وضعیت PV چه خواهد بود؟! آیا با حذف شدن PVC آن، PV هم آزاد می شود و می توان آن را در اختیار پاد دیگر قرار داد؟! اینها سوالاتی است که توسط Reclaim Policy پاسخ داده می شوند.Retain:در Retain وقتی PV ایجاد می شود، وضعیت آن ابتدا Available است. اولین درخواست PVC که وارد شود و منابع خواسته شده، با PV موجود سازگار باشد آن PV به PVC متصل می شود و وضعیت PV به Bound تغییر می کند. حالا اگر PVC از بین برود، وضعیت PV به Available تغییر نمی کند بلکه وضعیت آن Released می شود. یعنی درست است که در حال حاضر PV ما به هیچ PVC ای باند نشده است ولی دیتای PVC قبلی روی آن قرار دارد و نمی توان آن PV را در اختیار PVC جدید قرار داد. در این حالت برای اینکه ما منابع را آزاد کنیم باید ابتدا PV را حذف کنیم. سپس دیتای موجود در storage مربوطه را هم پاک کنیم و در آخر یک PV جدید بسازیم تا PVC های درخواست شده بتوانند به آن bound شوند.Retain Policy زمانی کاربرد دارد که ما نمی خواهیم اطلاعات کاربر قبلی توسط کاربر بعدی قابل دسترس باشد. معمولا cloud providerهای معروف از این policy استفاده می کنند. فرض کنید شما از خدمات ابری آمازون (AWS) یک سرویس دریافت کرده اید و برای سرویس شما PVC و PV ایجاد شده است حال اگر شما سرویس خود را لغو کنید یا آن را تمدید نکنید، PVC شما حذف می شود اگر آمازون PV شما را هم آزاد کند و آن را به کاربر بعدی تخصیص دهد، آن کاربر ممکن است فایلها و اطلاعت شخصی شما را مشاهده کند. بنابراین آمازون از Retain Policy در این مورد استفاده می کند.Delete:در Delete Policy اگر PVC حذف شود، PV و اطلاعات داخل آن هم بصورت خودکار حذف می شوند. انتخاب پالیسی Delete نیازمند این است که storage ما از این قابلیت پشتیبانی کند.Container Storage Interface (CSI)برای نصب CSI driver مربوط به NFS می توانیم از راهنمای موجود در github کمک بگیریم:https://github.com/kubernetes-csi/csi-driver-nfsدر قسمت Installation آدرس بالا دو روش برای نصب بیان شده است؛ اولی نصب با Helm chart و دومی نصب با kubectlبرای نصب با روش kubectl طبق مستندات این صفحه، می توانیم دستور زیر را اجرا کنیم، با اجرای این دستور یک shell فایل دانلود شده و روی سیستم ما اجرا می شود. داخل این فایل shell فایلهای yaml مربوطه دانلود و apply می شود.curl -skSL https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/v4.13.2/deploy/install-driver.sh | bash -s v4.13.2 --همانگونه که در خروجی اجرا هم مشاهده می شود، پس از نصب NFS driver، یک سری resource type و deployment و پاد به کوبرنتیز اضافه می شود.بعد از نصب CSI driver، باید storage class تعریف کرد:nfs-storageclass.yamlapiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
 name: nfs-csi
provisioner: nfs.csi.k8s.io
parameters:
 server: 192.168.65.43
 share: /var/team9
reclaimPolicy: Deleteکوبرنتیز بصورت پیش فرض storage class مربوط به NFS را در خود دارد. همانطور که مشاهده کردید ما بدون نصب CSI driver و تعریف storage class جدید هم توانستیم PV و PVC تعریف کنیم.نصب NFS CSI driver و نیز تعریف storage class جدید فقط جنبه آموزش داشت. همین فرآیند را می توانیم برای سایر Storage ها طی کرده و در کوبر خود از آنها استفاده کنیم.حالا بیایید یک PVC جدید با استفاده از storage class جدیدی که خودمان برای NFS ایجاد کردیم بسازیم:nfs-csi-pvc.yamlapiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: nfs-pvc
spec:
 accessModes:
  - ReadWriteMany
 storageClassName: nfs-csi
 resources:
  requests:
   storage: 5Giایجاد NFS storage class جدید درست است که جنبه آموزشی داشت اما یک تفاوت با NFS storage class پیش فرض کوبرنتیز دارد و آن قابلیت Dynamic Provisioning است یعنی نیاز نیست ما ابتدا PV و بعد PVC تعریف کنیم. با تعریف PVC و اعمال آن، PV بصورت خودکار ساخته می شود.Host Pathحالت بعدی در Storage کوبرنتیز Host Path می باشد. یعنی ما اطلاعات پاد را در مسیری از نود آن ذخیره کنیم. در این حالت اگر از یک پاد چند نسخه در نودهای مختلف اجرا شده باشد، دیتاها بصورت پراکنده در نودها ذخیره می شود و آنها را بصورت متمرکز نداریم مگر اینکه با ابزارهایی مانند FileBeat آنها را متمرکزسازی کنیم.از این روش در برخی موارد مانند ذخیره لاگ برنامه ها استفاده می شود.Secrets &amp; ConfigMapsفایلهای کانفیگ و پسوردها را اگر در سورس کد یا سرور git قرار دهیم، امکان دسترسی برنامه نویسان و سایرین به آنها وجود دارد. کوبرنتیز پیشنهاد می کند که کانفیگ ها در قالب یک آبجکت به کوبر معرفی شود، کوبر هنگام اجرای پاد همان آبجکت را در برنامه override می کند. یعنی هر چه اطلاعات و کانفیگ های حساس است را از دل برنامه خارج کنیم و آنها را در قالب Secret و ConfigMap نگه داریم.مثال: nginx یک فایل با پسوند conf دارد که کانفیگ سرویس nginx در آن قرار می گیرد. بیایید با هم این فایل را به ConfigMap در کوبرنتیز تبدیل کنیم.nginx.yamlapiVersion: apps/v1
kind: Deployment
metadata:
 name: nginx
 labels:
  app: nginx
spec:
 replicas: 1
 selector:
  matchLabels:
   app: nginx
 template:
  metadata:
   labels:
    app: nginx
  spec:
   containers:
   - name: nginx
     image: docker.arvancloud.ir/nginx:1.17.1
     imagePullPolicy: IfNotPresentاگر ما فایل nginx.yaml را apply کنیم، کانفیگ nginx هم در آن وجود دارد و ما باید بعد از بالا آمدن پاد، کانفیگ آن را تنظیم کنیم. اگر پاد دیگری هم بالا بیاید باید همین کار را برای آن انجام دهیم.راه حل این است که ما یک فایل کانفیگ مانند default.conf بسازیم و آن را داخل nginx اعمال کنیم.default.confserver {
 listen 80;
 server_name _;
 return 403;
 location / {
  root /usr/share/nginx/html;
  index index.html index.htm;
}
}kubectl create configmap nginxconfig --from-file=default.conf --dry-run=client -o yaml &gt; nginxconfigmap.yamlnginxconfigmap.yamlapiVersion: v1
data:
 default.conf: &quot;server { \n listen 80;\n server_name _;\n location / {\n\n root/usr/share/nginx/html;\n index.html index.htm;\n}\n}\n\n&quot;
kind: ConfigMap
metadata:
 name: nginxconfig
 حالا کانفیگ مپ تولید شده را در کوبرنتیز اعمال می کنیم:# kubectl apply -f nginxconfigmap.yaml 
configmap/nginxconfig created

#kubectl get cm
NAME                        DATA      AGE
kube-root-ca.crt            1         97d
nginxconfig                 1         2s
سپس فایل manifest سرویس nginx را به روز رسانی می کنیم تا کانفیگ خود را از کانفیگ مپ nginxconfigmap بگیرد:nginx.yamlapiVersion: apps/v1
kind: Deployment
metadata:
 name: nginx
 labels:
  app: nginx
spec:
 replicas: 1
 selector:
  matchLabels:
   app: nginx
 template:
  metadata:
   labels:
    app: nginx
  spec:
   volumes:
    - name: nginx-config
      configMap:
       name: nginxconfig
   containers:
   - name: nginx
     image: docker.arvancloud.ir/nginx:1.17.1
     imagePullPolicy: IfNotPresent
     volumeMounts:
     - name: nginx-config
      mountPath: /etc/nginx/conf.d/# kubectl apply -f nginx.yaml
deployment.apps/nginx createdبیایید نگاهی به داخل پاد nginx بیندازیمهمانطور که مشاهده می کنید فایل کانفیگ داخل پاد همان کانفیگی است که ما در nginxconfigmap.yaml داشتیم.حالا برای اعمال کانفیگ جدید در nginx فقط کافی است ما فایل جدید nginxconfigmap.yaml را در کوبرنتیز apply کنیم تا کانفیگ nginx بصورت خودکار تغییر کند.1.
update default.conf file

2.
kubectl create configmap nginxconfig --from-file=default.conf --dry-run=client -o yaml &gt; nginxconfigmap.yaml

3.
kubectl apply -f nginxconfigmap.yaml

4. Now nginx config updated automaticallySubPathدر مثالی که بیان شد، کل پوشه conf.d مپ شده است. یعنی همه فایلهای داخل این پوشه بروز رسانی می شود. حال اگر بخواهیم فقط فایل default.conf مپ و بروزرسانی شود، باید از SubPath استفاده کنیم. این روش فقط یک بدی دارد و آن این است که برای اعمال تغییرات configmap، پاد باید متوقف شده و مجددا بالا بیاید.nginx.yamlapiVersion: apps/v1
kind: Deployment
metadata:
 name: nginx
 labels:
  app: nginx
spec:
 replicas: 1
 selector:
  matchLabels:
   app: nginx
 template:
  metadata:
   labels:
    app: nginx
  spec:
   volumes:
    - name: nginx-config
      configMap:
       name: nginxconfig
   containers:
   - name: nginx
     image: docker.arvancloud.ir/nginx:1.17.1
     imagePullPolicy: IfNotPresent
     volumeMounts:
     - name: nginx-config
      mountPath: /etc/nginx/conf.d/default.conf
      subPath: default.conf
      readOnly: trueتعریف ConfigMap از روی Variable هاnginxvars.yamlclass=devops
httpurl=https://cando.ackubectl create configmap nginxenv --from-env-file=nginxvars.yaml --dry-run=clinet -o yaml &gt; nginxvarconfigmap.yamlnginxvarconfigmap.yamlapiVersion: v1
data:
 class: devops
 httpurl: https://cando.ac
kind: ConfigMap
metadata:
 name: nginxenvnginx.yamlapiVersion: apps/v1
kind: Deployment
metadata:
 name: nginx
 labels:
  app: nginx
spec:
 replicas: 1
 selector:
  matchLabels:
   app: nginx
 template:
  metadata:
   labels:
    app: nginx
  spec:
   volumes:
    - name: nginx-config
      configMap:
       name: nginxconfig
   containers:
   - name: nginx
     image: docker.arvancloud.ir/nginx:1.17.1
     imagePullPolicy: IfNotPresent
     env:
      - name: class
        valueFrom:
         configMapKeyRef:
          name: nginxenv
          key: class
      - name: httpurl
        valueFrom:
         configMapKeyRef:
          name: nginxenv
          key: httpurl
     volumeMounts:
     - name: nginx-config
      mountPath: /etc/nginx/conf.d/default.conf
      subPath: default.conf
      readOnly: true</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Sat, 20 Jun 2026 15:22:10 +0330</pubDate>
            </item>
                    <item>
                <title>آموزش Kubernetes - قسمت نهم (Service و Update Strategy)</title>
                <link>https://virgool.io/@farhad.sadeghi/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-kubernetes-%D9%82%D8%B3%D9%85%D8%AA-%D9%86%D9%87%D9%85-service-%D9%88-update-strategy-aedkwuucthul</link>
                <description>Serviceفرض کنید ما یک سری پاد از برنامه Payment داریم که روی نودهای مختلف کلاستر بالا آمده اند.همچنین یک سری پاد هم از برنامه Store روی چند نود دیگر کلاستر بالا آمده اند.چطور ما داخل کلاستر کوبرنتیز بتوانیم از برنامه Payment به Store وصل شویم؟ چطور از خارج کلاستر کوبرنتیز به برنامه Store وصل شویم؟ باید توجه داشت که ما نمی توانیم به یک پاد مشخص وصل شویم چون یک پاد ممکن است از بین برود، متوقف شود، نمونه های دیگری از آن در نودهای دیگر ایجاد شود. بنابراین چه باید کرد؟!راهکار تعریف &quot;سرویس&quot; می باشد.انواع سرویس:1.ClusterIP: مخصوص ارتباطات داخل کلاستر یا ارتباطات شرقی-غربی (East-West) است.2.NodePort: برای ارتباطات از خارج کلاستر به داخل آن یعنی ارتباطات شمالی-جنوبی (North-South) می باشد.3.LoadBalancer: برای ارتباطات از خارج کلاستر به داخل آن یعنی ارتباطات شمالی-جنوبی (North-South) می باشد.[root@MASTER-01 ~]# kubectl api-resources | grep services
services            svc          v1                true         Service1. ClusterIPاز آنجایی که همه پادهای store در یک deployment قرار دارند بنابراین همه آنها label مشخصی دارند. ما یک آی پی مجازی (VIP) تعریف می کنیم و همه پادهایی که دارای label مشخص هستند را پشت آن VIP قرار می دهیم. هر پادی که خواست به برنامه store وصل شود با آن VIP ارتباط می گیرد.حتی CoreDNS می تواند به VIP یک نام assign کند و پادهای دیگر بجای VIP به آن نام وصل شوند.توجه داشته باشید که ما فقط برای برنامه ای که قرار است دیگران به آن وصل شوند &quot;سرویس&quot; تعریف می کنیم و برای سایر برنامه ها نیاز به تعریف سرویس نیست.برنامه نویس Payment برای وصل شدن به برنامه Store باید نام سرویس Store یا VIP آن را بداند. در واقع باید رکورد DNS سرویس Store را بداند. به این نام رکورد، ClusterIP گفته می شود.برای ارتباطات Async که ما یک Message Broker بین برنامه A و B قرار می دهیم و می خواهیم A به B وصل شود، نیاز نیست برای B سرویس تعریف کنیم بلکه برای Message Broker سرویس تعریف می کنیم. A به سرویس Message Broker وصل می شود و پیغام خود را می گذارد. همه پادهای B هم به سرویس Message Broker وصل هستند و به محض قرار گرفتن پیام توسط A روی Message Broker، یکی از برنامه های B پیام را برمی دارد.deployment.yamlapiVersion: apps/v1
kind: Deployment
metadata:
 name: webapp
 labels:
  nginx: 1.16.1
spec:
 replicas: 1
 selector:
  matchLabels:
   security: S1
 template:
  metadata:
   labels:
    security: S1
  spec:
   - name: nginx
     image: docker.arvancloud.ir/nginx:1.16.1
     imagePullPolicy: IfNotPresentداخل یک فایل yaml می توان چند manifest نوشت؛ فقط باید آنها را با سه خط تیره (---) از هم جدا کرد.deployment.yamlapiVersion: apps/v1
kind: Deployment
metadata:
 name: webapp
 labels:
  nginx: 1.16.1
spec:
 replicas: 1
 selector:
  matchLabels:
   security: S1
 template:
  metadata:
   labels:
    security: S1
  spec:
   - name: nginx
     image: docker.arvancloud.ir/nginx:1.16.1
     imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Service
metadata:
 name: nginx-web
 labels:
  app: nginx
spec:
 selector:
  security: S1
 type: ClusterIP
 ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 80Port: پورت سرویسTargetPort: پورتی که پاد مقصد روی آن listen می کند[root@MASTER-01 ~]# kubectl apply -f deployment.yaml
deployment.apps/webapp unchanged
service/nginx-web created

[root@MASTER-01 ~]# kubectl get deploy
NAME     READY   UP-TO-DATE   AVAILABLE   AGE
webapp   1/1     1            1           88s

[root@MASTER-01 ~]# kubectl get rs
NAME                DESIRED   CURRENT   READY   AGE
webapp-68cb45785d   1         1         1       94s

[root@MASTER-01 ~]# kubectl get po
NAME                      READY   STATUS    RESTARTS   AGE
webapp-68cb45785d-mggjl   1/1     Running   0          102s

[root@MASTER-01 ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
nginx-web    ClusterIP   10.98.247.120   &lt;none&gt;        80/TCP    37sحالا می توانیم برنامه مورد نظر را از پشت سرویس فراخوانی کنیم:[root@WORKER-01 ~]# curl http://10.98.247.120
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Welcome to nginx!&lt;/title&gt;
&lt;style&gt;
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1&gt;Welcome to nginx!&lt;/h1&gt;
&lt;p&gt;If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.&lt;/p&gt;

&lt;p&gt;For online documentation and support please refer to
&lt;a href=&quot;http://nginx.org/&quot;&gt;nginx.org&lt;/a&gt;.&lt;br/&gt;
Commercial support is available at
&lt;a href=&quot;http://nginx.com/&quot;&gt;nginx.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thank you for using nginx.&lt;/em&gt;&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;برای اینکه بفهمیم پشت یک سرویس چه IPهایی هست:[root@MASTER-01 ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1       &lt;none&gt;        443/TCP   62d
nginx-web    ClusterIP   10.98.247.120   &lt;none&gt;        80/TCP    7m9s

[root@MASTER-01 ~]# kubectl get ep nginx-web
Warning: v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice
NAME        ENDPOINTS          AGE
nginx-web   10.100.171.40:80   7m32sروش رفتن داخل یک پاد و اجرای دستور داخل آن:$ kubectl exec -it podname --bash
Or
$ kubectl exec -it podname --sh

$ kubectl exec -it nginx-master-01 --bashاگر پاد A و پاد B در namespace های جداگانه ای باشند آنگاه نام namespace در نحوه resolve کردن تاثیر دارد.2. NodePortبرای ارتباط با یک پاد (سرویس) از خارج کلاستر کوبرنتیز ما نیاز به تعریف NodePort روی نودها داریم. در این حالت کاربر می تواند به nodeport هر یک از نودها متصل شود. درخواست کاربر از nodeport به ClusterIP سرویس NAT می شود. فرقی نمی کند کاربر به کدام یک از نودها متصل شود.اگر ما پورت برای NodePort مشخص نکنیم خود کوبرنتیز یک پورت رندوم بین 30000 تا 32767 به آن تخصیص می دهد.deployment2.yamlapiVersion: apps/v1
kind: Deployment
metadata:
 name: webapp
 labels:
  nginx: 1.16.1
spec:
 replicas: 1
 selector:
  matchLabels:
   security: S1
 template:
  metadata:
   labels:
    security: S1
  spec:
   - name: nginx
     image: docker.arvancloud.ir/nginx:1.16.1
     imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Service
metadata:
 name: nginx-web
 labels:
  app: nginx
spec:
 selector:
  security: S1
 type: NodePort
 ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 80
    nodePort: 30000[root@MASTER-01 ~]# kubectl apply -f deployment2.yaml
deployment.apps/webapp unchanged
service/nginx-web configured

[root@MASTER-01 ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1       &lt;none&gt;        443/TCP        62d
nginx-web    NodePort    10.98.247.120   &lt;none&gt;        80:30000/TCP   46mحالا اگر در مرورگر خود آی پی هر یک از نودها را به همراه پورت 30000 وارد کنیم صفحه nginx را مشاهده می کنیم.http://192.168.65.45:30000http://192.168.65.46:30000http://192.168.65.47:30000[root@WORKER-02 ~]# curl http://192.168.65.46:30000
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Welcome to nginx!&lt;/title&gt;
&lt;style&gt;
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1&gt;Welcome to nginx!&lt;/h1&gt;
&lt;p&gt;If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.&lt;/p&gt;

&lt;p&gt;For online documentation and support please refer to
&lt;a href=&quot;http://nginx.org/&quot;&gt;nginx.org&lt;/a&gt;.&lt;br/&gt;
Commercial support is available at
&lt;a href=&quot;http://nginx.com/&quot;&gt;nginx.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thank you for using nginx.&lt;/em&gt;&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;از آنجایی که در NodePort ترافیک NAT می شود، بنابراین ما در برنامه خود IP کلاینت را نداریم و همه درخواستها با یک IP به دست برنامه می رسد. برای اینکه آی پی کاربر را داشته باشیم، باید در تجهیزات و سرویسهای بین مسیر X-Forwarded-For تنظیم شود. اینکار باعث می شود که زنجیره آی پی ها در هدر x-forwarded-for درخواست http قرار بگیرد.فرض کنید ما بخواهیم این محدودیت را روی سرویس بگذاریم که اگر ترافیک به دست یک نود رسید در صورتی که پاد مقصد روی آن نود باشد ادامه مسیر بدهد و اگر پاد روی آن نود نباشد مانع شود. (در شکل بالا اگر ترافیک به نود سمت راست برسد نباید امکان فراخوانی داده شود)apiVersion: v1
kind: Service
metadata:
 name: nginx-web
 labels:
  app: nginx
spec:
 selector:
  security: S1
 type: NodePort
 ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 80
    nodePort: 30000
 externalTrafficPolicy: Local3. LoadBalancerدر Cloud Provider ها ممکن است یک Load Balancer بیرون از کلاستر کوبرنتیز در اختیار ما گذاشته شود.F5 BigIPF5 BigIP سخت افزاری است که بیرون از کلاستر کوبرنتیز می باشد و با کوبرنتیز integrate می شود. درخواستها ابتدا به F5 می رسد و F5 درخواست را به سرویس مربوطه در کلاستر کوبرنتیز ارجاع می دهد. توجه داشته باشید که این تجهیز سخت افزاری مشابه یک پاد داخل کلاستر عمل می کند.metallbکوبرنتیز از iptable و kubeproxy برای انجام عمل پروکسی استفاده می کند. اما این ابزارها در لود بالا احتمالا کند عمل خواهند کرد. بنابراین تصمیم گرفتند که پروتکلی را درست کنند که با استفاده از خود کرنل لینوکس عملیات پروکسی کردن را انجام دهد و به این ترتیب پروتکل eBPF ایجاد شد.CNI (Network Driver) --&gt; Calico , Cilium , ...Cilium پروتکل eBPF را در دل خود پیاده سازی کرده است و اگر ما از Cilium بجای Calico استفاده کنیم، می تواند مستقلا عمل لود بالانس را انجام دهد و نیاز به ابزار دیگری مانند metallb نداشتیم.نصب metallbimageهای controller و speaker را در containerd همه نودهای کلاستر ایمپورت می کنیم.apply کردن فایلهای metallb.yaml[root@MASTER-01 ~]# kubectl apply -f metallb.yaml

[root@MASTER-01 ~]# kubectl get po -n metallb-system -o wide
NAME                          READY   STATUS    RESTARTS        AGE     IP              NODE        NOMINATED NODE   READINESS GATES
controller-66bdd896c6-92vt9   1/1     Running   1 (6d11h ago)   6d11h   10.103.204.68   worker-02   &lt;none&gt;           &lt;none&gt;
speaker-92vrg                 1/1     Running   0               6d11h   192.168.65.14   worker-01   &lt;none&gt;           &lt;none&gt;
speaker-bzhcs                 1/1     Running   0               6d11h   192.168.65.15   worker-02   &lt;none&gt;           &lt;none&gt;
speaker-gkmcb                 1/1     Running   0               6d11h   192.168.65.13   master-01   &lt;none&gt;           &lt;none&gt;
بعد از apply کردن metallb.yaml یک پاد controller و به تعداد نودها پاد speaker بالا می آید.قاعدتا ما یک یا چند IP ثابت در اختیار داریم که از خارج از کلاستر کوبرنتیز در دسترس باشند. در فایل metallb-l2.yaml ما لیست اینIPها را به عنوان IP Pool وارد کرده و آن را apply می کنیم. هر کس که از metallb درخواست سرویس لودبالانسر کند، metallb یکی از IPها را برداشته و به عنوان IP ورودی خود استفاده می کند.[root@MASTER-01 ~]# kubectl apply -f metallb-l2.yamlدر انتها نیاز است تا فایل metallb-advertise.yaml را apply کنیم. این کار به سیستم اعلام می کند که IPهای موجود در IP Pool در اختیار metallb می باشد و ارسال ترافیک از این IPها به metallb بلامانع است.[root@MASTER-01 ~]# kubectl apply -f metallb-advertise.yamlتا اینجای کار metallb نصب شد. حالا باید یک سرویس از نوع LoadBalancer بنویسیم که ترافیک را روی یکی از IPهای موجود در IP pool دریافت کند و آن را به pod مپ کند.تعریف manifest و ایجاد سرویس به دو صورت می تواند انجام شود:Declarative یا توصیفی؛ یعنی همان روشی که تا کنون انجام می دادیم و مشخصات سرویس را در قالب فایل yaml تعریف می کردیم.Imperative یا قدم به قدم؛ یعنی با اجرای یک یا چند دستور اقدام به ایجاد سرویس نماییم.دستور زیر ایجاد سرویس بصورت Imperative را نشان می دهد. خروجی آن در فایل nginx-web.yaml ذخیره می شود.[root@MASTER-01 ~]# kubectl create deployment nginx-web --image=docker.arvancloud.ir/nginx:1.17.1 --replicas=2 --dry-run=client -o yaml &gt; nginx-web.yamldry-run=client یعنی اینکه این کامند را واقعا اجرا نکن فقط خروجی اجرا را نشان بده.[root@MASTER-01 session-09]# vim nginx-web.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-web
  name: nginx-web
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-web
  strategy: {}
  template:
    metadata:
      labels:
        app: nginx-web
    spec:
      containers:
      - image: docker.arvancloud.ir/nginx:1.17.1
        name: nginx
        imagePullPolicy: IfNotPresentاضافات فایل nginx-web.yaml را پاک کرده و آن را apply می کنیم.[root@MASTER-01 ~]# kubectl apply -f nginx-web.yaml
deployment.apps/nginx-web created

[root@MASTER-01 ~]# kubectl get po
NAME                         READY   STATUS    RESTARTS   AGE
nginx-web-8558c77df5-8s2s2   1/1     Running   0          29s
nginx-web-8558c77df5-8tnln   1/1     Running   0          29sخروجی دستور زیر که برای ایجاد سرویس از نوع LoadBalancer می باشد، به انتهای فایل nginx-web.yaml اضافه می شود.[root@MASTER-01 ~]# kubectl expose deployment nginx-web --name nginx-svc --type=LoadBalancer --port=80 --dry-run=client -o yaml &gt;&gt; nginx-web.yaml[root@MASTER-01 ~]# vim nginx-web.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-web
  name: nginx-web
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-web
  strategy: {}
  template:
    metadata:
      labels:
        app: nginx-web
    spec:
      containers:
      - image: docker.arvancloud.ir/nginx:1.17.1
        name: nginx
        imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx-web
  name: nginx-svc
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx-web
  type: LoadBalancer[root@MASTER-01 session-09]# kubectl apply -f nginx-web.yaml
deployment.apps/nginx-web unchanged
service/nginx-svc created

[root@MASTER-01 session-09]# kubectl get svc
NAME         TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP      10.96.0.1      &lt;none&gt;        443/TCP        63d
nginx-svc    LoadBalancer   10.111.82.92   &lt;pending&gt;     80:30179/TCP   3m23sبه این ترتیب LoadBalancer روی External-IP بالا می آید و حالا می توانیم از خارج از کلاستر کوبرنتیز به این IP درخواست بزنیم و LoadBalancer درخواست ما را به یکی از پادها ارسال می کند.تفاوت NodePort و LoadBalancer در این است که در LoadBalancer کلاینت با یک IP مشخص طرف است و این IP ثابت است. این IP یک IP شناور (Floating IP) می باشد و حتی اگر LoadBalancer متوقف شود و روی یک نود دیگر مجددا بالا بیاید، آن IP به نود جدید اختصاص می یابد. اما در NodePort سرویس از طریق IP هر یک از نودها قابل دسترس هست.Update Strategiesدر کوبرنتیز برای بروزرسانی نرم افزارها از یک نسخه به نسخه دیگر، استراتژی های مختلفی وجود دارد. پرکاربردترین آنها Rolling Update و ReCreate می باشند. سایر استراتژی ها مانند Blue-Green و Canary کاربرد خاص منظوره و کمتری دارند.Rolling Update:در این روش، تعدادی از پادهای نسخه فعلی حذف می شوند و تعدادی پاد نسخه جدید ایجاد می گردند. اگر پادهای جدید با موفقیت اجرا شوند، مجددا تعداد دیگری از پادهای نسخه فعلی حذف و تعدادی پاد نسخه جدید اجرا می شود. این روند تا زمانی که همه پادهای نسخه فعلی حذف و همه پادهای نسخه جدید ایجاد شوند، ادامه می یابد.در این روش، تقریبا Downtime صفر داریم و در طول مدت زمان آپدیت، سرویس بالاست.ReCreate:در این روش همه پادهای نسخه فعلی حذف می شوند و سپس به همان تعداد پاد نسخه جدید ایجاد می گردد.اگر تغییرات انجام شده در نسخه جدید برنامه، ساختار جداول دیتابیس را تغییر دهد و امکان اجرا و ثبت اطلاعات توسط نسخه قبلی برنامه وجود نداشته باشد، ما مجبور هستیم از استراتژی Recreate استفاده کنیم. چون نسخه های قدیمی امکان کار با دیتابیس جدید را نخواهند داشت و دچار مشکل می شوند.apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-web
  name: nginx-web
spec:
  replicas: 6
  selector:
    matchLabels:
      app: nginx-web
  strategy:
   rollingUpdate:
    maxSurge: 1
    maxUnavailable: 1
  template:
    metadata:
      labels:
        app: nginx-web
    spec:
      containers:
      - image: docker.arvancloud.ir/nginx:1.17.1
        name: nginx
        imagePullPolicy: IfNotPresentبرای بروزرسانی نسخه ایمیج از دستور زیر هم می توانیم استفاده کنیم:[root@MASTER-01 ~]# kubectl set image nginx-web nginx=docker.arvancloud.ir/nginx:1.17.1مشاهده تاریخچه آپدیت های Deployment با نام redis-dep:[root@MASTER-01 ~]# kubectl rollout history deployment redis-dep
deployment.apps/redis-dep
REVISION  CHANGE-CAUSE
1         &lt;none&gt;
2         &lt;none&gt;
3         &lt;none&gt;مشاهده جزئیات revision اول:[root@MASTER-01 ~]# kubectl rollout history deployment redis-dep --revision=1
deployment.apps/redis-dep with revision #1
Pod Template:
  Labels:       app=redis-app
        pod-template-hash=67dc46768b
  Containers:
   redis:
    Image:      apk-reg.aradarpanet.ir/class/redis:latest
    Port:       &lt;none&gt;
    Host Port:  &lt;none&gt;
    Environment:        &lt;none&gt;
    Mounts:     &lt;none&gt;
  Volumes:      &lt;none&gt;
  Node-Selectors:       &lt;none&gt;
  Tolerations:  &lt;none&gt;سایر دستورات و کاربردهای rollout را در زیر مشاهده می کنید:[root@MASTER-01 ~]# kubectl rollout --help
Manage the rollout of one or many resources.

 Valid resource types include:

  *  deployments
  *  daemonsets
  *  statefulsets

Examples:
  # Rollback to the previous deployment
  kubectl rollout undo deployment/abc

  # Check the rollout status of a daemonset
  kubectl rollout status daemonset/foo

  # Restart a deployment
  kubectl rollout restart deployment/abc

  # Restart deployments with the &#039;app=nginx&#039; label
  kubectl rollout restart deployment --selector=app=nginx

Available Commands:
  history       View rollout history
  pause         Mark the provided resource as paused
  restart       Restart a resource
  resume        Resume a paused resource
  status        Show the status of the rollout
  undo          Undo a previous rollout

Usage:
  kubectl rollout SUBCOMMAND [options]

Use &quot;kubectl rollout &lt;command&gt; --help&quot; for more information about a given command.
Use &quot;kubectl options&quot; for a list of global command-line options (applies to all commands).کوبرنتیز برای هر update و rollback یک Replicaset جدید می سازد و با تغییر عدد DESIRED در Replicasetها، عملیات آپدیت و rollback را انجام می دهد. به همین خاطر اگر لیست Replicasetها را مشاهده کنیم، خواهیم دید که تعدادی Replicaset با عدد DESIRED صفر وجود دارد.</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Wed, 17 Jun 2026 23:05:21 +0330</pubDate>
            </item>
                    <item>
                <title>آموزش Kubernetes - قسمت هشتم (Deployment and Node Assignment)</title>
                <link>https://virgool.io/@farhad.sadeghi/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-kubernetes-%D9%82%D8%B3%D9%85%D8%AA-%D9%87%D8%B4%D8%AA%D9%85-deployment-and-node-assignment-jeu8ucefbyj9</link>
                <description>LabelsLabel ها Key/Value pair هستند. در کوبرنتیز به هر آبجکتی می توان لیبل چسباند.با لیبل می توانیم آبجکت ها را دسته بندی کنیم. مثلا اگر ما یک برنامه داریم که از دو قسمت Backend و Frontend تشکیل شده است. می توانیم برای همه پادهای Backend آن برنامه لیبل Backend و برای همه پادهای Fronend آن لیبل Frontend بزنیم.برای مشاهده لیبل ها، کافی است به انتهای دستور عبارت show-labels را اضافه کنیم.[root@MASTER-01 ~]# kubectl get po --show-labels
NAME                     READY   STATUS    RESTARTS        AGE     LABELS
mywebapp-9qsx8           1/1     Running   0               4m3s    app=nginx
mywebapp-hhpkh           1/1     Running   0               2d10h   app=nginx
nginx-1                  1/1     Running   0               145m    app=web
nginx-2                  1/1     Running   0               142m    app=web
webapp-56nnr             1/1     Running   1 (2d10h ago)   44d     app=nginx,controller-revision-hash=5597cb68cb,pod-template-generation=1
webapp-5bcxx             1/1     Running   0               2d8h    app=nginx,controller-revision-hash=5597cb68cb,pod-template-generation=1
webapp-fbd9ddfc7-5xdqn   1/1     Running   0               2d10h   app=nginx,pod-template-hash=fbd9ddfc7
webapp-fbd9ddfc7-f88gt   1/1     Running   0               2d10h   app=nginx,pod-template-hash=fbd9ddfc7
webapp-fbd9ddfc7-wbzlf   1/1     Running   0               2d10h   app=nginx,pod-template-hash=fbd9ddfc7انتخاب پادهایی که دارای لیبل app=web هستند:[root@MASTER-01 ~]# kubectl get po --selector=app=web
NAME      READY   STATUS    RESTARTS   AGE
nginx-1   1/1     Running   0          146m
nginx-2   1/1     Running   0          143mانتخاب پادهایی که دارای لیبل app=web یا app=web2 هستند:[root@MASTER-01 ~]# kubectl get po --selector=&quot;app in (web, web2)&quot;
NAME      READY   STATUS    RESTARTS   AGE
nginx-1   1/1     Running   0          146m
nginx-2   1/1     Running   0          143m
nginx-3   1/1     Running   0          143mثبت لیبل با دستور kubectl label [resourcetype] [resourcename] [key=value] انجام می شود. به عنوان مثال دستور زیر لیبل hdd=ssd را برای نود worker-02 ثبت می کند.[root@MASTER-01 ~]# kubectl label node worker-02 hdd=ssd
node/worker-02 labeledReplicaSetوقتی ما یک پاد بالا می آوریم هیچ کنترل کننده ای برای آن پاد وجود ندارد که سلامت پاد را بررسی کند یا وقتی آن پاد حذف شد مجددا یک نسخه از آن بالا بیاورد.ReplicaSet همان مفهوم بالادستی برای پاد است.یعنی بجای اینکه ما یک منیفست پاد تهیه کنیم و آن را در کوبرنتیز بالا بیاوریم، یک کنترل کننده پاد تعریف می کنیم و آن کنترل کننده به تعداد نسخه هایی که برایش مشخص کرده ایم پاد بالا می آورد.Replicaset یکی از منابع تعریف شده در کوبرنتیز می باشد.[root@MASTER-01 ~]# kubectl api-resources | grep replicaset
replicasets          rs           apps/v1        true         ReplicaSetبیایید یک mainifest برای اولین replicaset خود بنویسیم:replicaset.yamlapiVersion: apps/v1
kind: ReplicaSet
metadata:
 name: mywebapp
 labels:
  app: v10.1.1
spec:
 replicas: 2
 selector:
  matchLabels:
   app: nginx
 template:
  metadata:
   labels:
    app: nginx
  spec:
   containers:
   - name: nginx
     image: docker.arvancloud.ir/nginx:latest
     imagePullPolicy: IfNotPresentreplicas : تعداد نسخه هایی از پاد می باشد که میخواهیم همزمان داشته باشیمselector : نحوه انتخاب پادهای زیر replicaset را مشخص می کند. یعنی چه پادهایی در کنترل replicase هستند.template : یک قالب برای پادهای زیرمجموعه replicaset مشخص می کند. نحوه تعریف آن دقیقا شبیه تعریف پاد می باشد با این تفاوت که نباید برای آن نام تعریف شود. همچنین هر آنچه در selector مشخص شده است باید در این قسمت برای پاد در نظرگرفته شود تا هر یک از پادهایی که ایجاد می شوند در زمره زیرمجموعه های replicaset قرار بگیرند.[root@MASTER-01 ~]# kubectl apply -f replicaset.yaml
replicaset.apps/mywebapp created

[root@MASTER-01 ~]# kubectl get rs
NAME                DESIRED   CURRENT   READY   AGE
mywebapp            2         2         2       36sهمانطور که مشاهده می کنید مانند سایر منابع، ما می توانیم لیست replicaset های موجود را مشاهده نماییم.DESIRED و CURRENT و READY به ترتیب تعداد پادهای تعیین شده در replicaset، تعداد پادهای فعلی اجرا شده و تعداد پادهای اجرا شده بدون مشکل را نمایش می دهد.[root@MASTER-01 ~]# kubectl get po
NAME                     READY   STATUS    RESTARTS        AGE
mywebapp-5nb6h           1/1     Running   0               5m27s
mywebapp-ksb8l           1/1     Running   0               5m26sبعد از apply کردن replicaset، دو پاد مطابق با template اجرا می شود. همانطور که مشاهده می کند نام پادها برابر با نام replicaset و یک رشته رندوم می باشد.Pod_Name = Replicaset_name + Random_Stringحالا اگر ما یکی از پادها را حذف کنیم، replicaset بلافاصله یک پاد دیگر را بعنوان جایگزین آن بالا می آورد تا همواره 2 پاد (به تعداد replicas) بالا باشد.[root@MASTER-01 ~]# kubectl delete po mywebapp-5nb6h
pod &quot;mywebapp-5nb6h&quot; deleted from default namespace

[root@MASTER-01 ~]# kubectl get po
NAME                     READY   STATUS    RESTARTS        AGE
mywebapp-jms8t           1/1     Running   0               15s
mywebapp-ksb8l           1/1     Running   0               14mاگر برنامه ما از چند قسمت تشکیل شده باشد؛ مثلا از front و back تشکیل شده باشد، باید به ازای هر کدام از آن بخش ها یک ReplicaSet بالا بیاوریم.هر چند که برای کاهش یا افزایش تعداد پادها بهتر است فایل manifest را تغییر داده و مجددا apply کنیم، ولی می توانیم با دستور scale هم این کار را انجام دهیم.[root@MASTER-01 ~]# kubectl scale replicaset mywebapp --replicas=3
replicaset.apps/mywebapp scaled

[root@MASTER-01 ~]# kubectl get po
NAME                     READY   STATUS    RESTARTS        AGE
mywebapp-jms8t           1/1     Running   0               8h
mywebapp-ksb8l           1/1     Running   0               8h
mywebapp-q78fm           1/1     Running   0               6sبرخی مواقع نیاز است تا تعداد پادها صفر شود تا هیچ پادی از برنامه بالا نباشد. به عنوان مثال ما اگر بخواهیم یک نرم افزار را بروزرسانی کنیم و در طول مدت بروزرسانی هیچ درخواستی سمت دیتابیس ثبت نشود، باید ابتدا تعداد پادهای دیتابیس را به صفر scale کنیم و بعد از انجام کار، مجددا تعداد پادها را به تعداد قبلی برگردانیم.توجه داشته باشید که حتی زمانی که عدد replicas صفر می شود، درست است که هیچ پادی بالا نیست اما همچنان ReplicaSet فعال است.[root@MASTER-01 ~]# kubectl scale replicaset mywebapp --replicas=0
replicaset.apps/mywebapp scaled

[root@MASTER-01 ~]# kubectl get po
NAME                     READY   STATUS        RESTARTS        AGE
mywebapp-jms8t           1/1     Terminating   0               8h
mywebapp-ksb8l           1/1     Terminating   0               8h
mywebapp-q78fm           1/1     Terminating   0               74s

[root@MASTER-01 ~]# kubectl get po
NAME                     READY   STATUS        RESTARTS        AGEوقتی ما با دستور scale تعداد replicas را تغییر می دهیم، فایل منیفست تغییر نمی کند. برای دریافت فایل منیفست از ReplicaSet موجود، از دستور زیر می توان استفاده کرد:[root@MASTER-01 ~]# kubectl get rs mywebapp -o yaml &gt; replicaset.yamlحذف ReplicaSet:[root@MASTER-01 ~]# kubectl get po
NAME                     READY   STATUS    RESTARTS       AGE
mywebapp-2689w           1/1     Running   0              33m
mywebapp-b4gbj           1/1     Running   0              33m
mywebapp-lzk4d           1/1     Running   0              33m

[root@MASTER-01 ~]# kubectl delete rs mywebapp
replicaset.apps &quot;mywebapp&quot; deleted from default namespace

[root@MASTER-01 ~]# kubectl get po
NAME                     READY   STATUS    RESTARTS       AGEهمانطور که ملاحظه می کنید، با حذف یک ReplicaSet همه پادهای زیر مجموعه آن هم حذف می شوند.Deployment[root@MASTER-01 ~]# kubectl api-resources | grep deployment
deployments        deploy       apps/v1           true         Deploymentما معمولا از Replicaset بصورت مستقیم استفاده نمی کنیم و بجای آن از Deployment استفاده می کنیم.اگر برنامه ما همواره بروزرسانی می شود و نسخه جدید آن باید منتشر شود، می بایست از Deployment استفاده شود.فرض کنید ما یک ReplicaSet از نسخه 1.0.0 برنامه backend داشته باشیم و بخواهیم نسخه برنامه را در Replicaset به 2.0.0 تغییر دهیم.برای این کار ما نیاز به یک کنترل کننده بالادستی ReplicaSet داریم تا عمل آپدیت را انجام دهد.Deployment این کار را انجام می دهد. Deployment در دل خود یک ReplicaSet از برنامه بالا می آورد. وقتی ما نسخه برنامه را از 1.0.0 به 2.0.0 تغییر می دهیم، Deployment به آرامی تعداد replicas در ReplicaSet فعلی را کم می کند و تعداد replicas در ReplicaSet جدید را افزایش می دهد. این فرآیند تا زمانی که تعداد replicas در ReplicaSet قدیمی صفر شود و همه آنها به ReplicaSet جدید منتقل شوند ادامه پیدا می کند.حالا سوال اینجاست که چرا ما آپدیت نسخه برنامه را در ReplicaSet انجام نمی دهیم؟ جواب این است که در این صورت خیلی از قابلیت هایی که Deployment ارائه می دهد را از دست می دهیم. به عنوان مثال:فرآیند بروز رسانی به مرور و بدون DownTime انجام نخواهد شد.قابلیت برگشت به نسخه قبلی ReplicaSet را نخواهیم داشت. (Deployment تا 10 نسخه قبلی ReplicaSet خود را نگه می دارد و هر زمان نیاز باشد می توان به هر یک از آنها برگردیم.)بیایید یک manifest برای اولین deployment خود بنویسیم:deployment.yamlapiVersion: apps/v1
kind: Deployment
metadata:
 name: webapp
 labels:
  app: v10.1.1
spec:
 replicas: 3
 selector:
  matchLabels:
   app: nginx
 template:
  metadata:
   labels:
    app: nginx
  spec:
   containers:
   - name: nginx
     image: docker.arvancloud.ir/nginx:1.14.1
     imagePullPolicy: IfNotPresent[root@MASTER-01 ~]# kubectl get po
NAME           READY   STATUS    RESTARTS       AGE

[root@MASTER-01 ~]# kubectl apply -f deployment.yaml
deployment.apps/webapp created

[root@MASTER-01 ~]# kubectl get deployment
NAME     READY   UP-TO-DATE   AVAILABLE   AGE
webapp   3/3     3            3           37m

[root@MASTER-01 ~]# kubectl get rs
NAME               DESIRED   CURRENT   READY   AGE
webapp-fbd9ddfc7   3         3         1       19s

[root@MASTER-01 ~]# kubectl get po
NAME                     READY   STATUS    RESTARTS       AGE
webapp-fbd9ddfc7-fkbf4   1/1     Running   0              38s
webapp-fbd9ddfc7-hdjwj   1/1     Running   0              38s
webapp-fbd9ddfc7-n98gv   1/1     Running   0              38sوقتی ما فایل مانیفست deployment را apply می کنیم، کوبرنتیز یک Deployment می سازد و در دل آن یک ReplicaSet ساخته و پادها را داخل آن ReplicaSet بالا می آورد.اگر به نحوه نام گذاری این منابع دقت کنید متوجه می شوید نام گذاری آنها با قوانین زیر انجام می شود:Replicaset_Name = Deployment_Name + Random_StringPod_Name = Replicaset_Name + Random_Stringنحوه scale کردن در Deployment همانند ReplicaSet می باشد و همان قوانین در اینجا هم حاکم است:[root@MASTER-01 ~]# kubectl scale deployment webapp --replicas=2
deployment.apps/webapp scaled

[root@MASTER-01 ~]# kubectl get po
NAME                     READY   STATUS    RESTARTS       AGE
webapp-fbd9ddfc7-fkbf4   1/1     Running   0              47m
webapp-fbd9ddfc7-hdjwj   1/1     Running   0              47mWorkload/ Workload Management: لغتی است که به هر یک از ReplicaSetها، Deploymentها، StatefullSetها و ... اطلاق می شود.[root@MASTER-01 ~]# kubectl get po --show-labels
NAME                     READY   STATUS    RESTARTS       AGE     LABELS
webapp-fbd9ddfc7-fkbf4   1/1     Running   0              4h40m   app=nginx,pod-template-hash=fbd9ddfc7
webapp-fbd9ddfc7-fs257   0/1     Pending   0              1s      app=nginx,pod-template-hash=fbd9ddfc7
webapp-fbd9ddfc7-hdjwj   1/1     Running   0              4h40m   app=nginx,pod-template-hash=fbd9ddfc7
webapp-fbd9ddfc7-x4qpz   0/1     Pending   0              1s      app=nginx,pod-template-hash=fbd9ddfc7همانطور که مشاهده می کنید لیبل های زیر به همه پادهای Deployment اختصاص داده شده است:app=nginxpod-template-hash=fbd9ddfc7همانطور که گفته شد هر بار که ما فایل مانیفست deployment را تغییر داده و apply میکنیم، کوبرنتیز یک ReplicaSet جدید می سازد و فرآیند حذف یکی یکی پادها از ReplicaSet قدیمی و بالا آوردن پاد جدید در ReplicaSet جدید را انجام میدهد. کوبر همیشه تعداد ده ReplicaSet آخر را نگه می دارد.[root@MASTER-01 ~]# kubectl apply -f deployment.yaml
deployment.apps/webapp configured

[root@MASTER-01 ~]# kubectl get rs
NAME               DESIRED   CURRENT   READY   AGE
webapp-dffd67d4c   1         1         0       5s
webapp-fbd9ddfc7   3         3         3       4h58mما علاوه بر تغییر فایل مانیفست و اعمال آن در کوبرنتیز، می توانیم تغییرات خود در deployment را به صورت اجرای دستور کوبرنتیز نیز اعمال نماییم:[root@MASTER-01]# kubectl set image deployments webapp nginx=docker.arvancloud.ir/nginx:1.18.1
deployment.apps/webapp image updatedهمچنین با دستور زیر می توانیم manifest ذخیره شده deployment در پایگاه داده را باز کرده و ویرایش کنیم. بعد از ذخیره و بستن آن، deployment بروزرسانی خواهد شد.[root@MASTER-01]# kubectl edit deployment webapp
deployment.apps/webapp editedبنابراین سه روش زیر برای تغییر و بروزرسانی deployment وجود دارد:تغییر فایل مانیفست خودمان و apply کردن مجدد آنانجام تغییر در deployment با دستور مستقیمباز کردن مانیفست ذخیره شده deployment در پایگاه داده، تغییر و ذخیره آنDaemonSetدر Deployment ما تعداد Replica را خودمان مشخص می کنیم ولی در DaemonSet تعداد Replica برابر با تعداد نودهای Worker می باشد. یعنی به ازای هر نود Worker یک پاد بالا می آید.[root@MASTER-01 ~]# kubectl api-resources | grep daemonset
daemonsets              ds           apps/v1               true         DaemonSetبیایید یک manifest برای اولین DaemonSet خود بنویسیم و آن را در کلاستر کوبرنتیز اعمال کنیم:daemonset.yamlapiVersion: apps/v1
kind: DaemonSet
metadata:
 name: webapp
 labels:
   nginx: 1.17.1
spec:
 selector:
  matchLabels:
   app: nginx
 template:
  metadata:
   labels:
    app: nginx
  spec:
   containers:
   - name: nginx
     image: docker.arvancloud.ir/nginx:1.17.1
     imagePullPolicy: IfNotPresent[root@MASTER-01 ~]# kubectl apply -f daemonset.yaml
daemonset.apps/webapp created

[root@MASTER-01 ~]# kubectl get ds
NAME     DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
webapp   2         2         2       2            2           &lt;none&gt;          42s[root@MASTER-01]# kubectl get no
NAME        STATUS   ROLES           AGE   VERSION
master-01   Ready    control-plane   61d   v1.35.1
worker-01   Ready    worker          60d   v1.35.1
worker-02   Ready    worker          59d   v1.35.1

[root@MASTER-01]# kubectl get po
NAME           READY   STATUS    RESTARTS   AGE
webapp-45kgs   1/1     Running   0          2m26s
webapp-7jhpb   1/1     Running   0          2m26s

[root@MASTER-01]# kubectl get po -o wide
NAME           READY   STATUS    RESTARTS   AGE     IP              NODE        NOMINATED NODE   READINESS GATES
webapp-45kgs   1/1     Running   0          2m37s   10.100.171.38   worker-01   &lt;none&gt;           &lt;none&gt;
webapp-7jhpb   1/1     Running   0          2m37s   10.103.204.83   worker-02   &lt;none&gt;           &lt;none&gt;همانطور که ملاحظه می کنید، روی هر نود worker یک پاد بالا آمده است.کاربرد daemonset در مواقعی است که ما میخواهیم یک سرویس را روی همه نودهای سرور اجرا کنیم. به عنوان مثال فرض کنید ما می خواهیم روی هر نود worker یک سرویس مانند Filebeat بالا بیاوریم که فایلهای لاگ را خوانده و آنها را به Elk ارسال کند، اینجاست که daemonset به کارمان می آید.برخی از ابزارهای مدیریت کلاستر کوبرنتیز هم از DaemonSet استفاده می کنند. مانند calico-node و kube-proxy[root@MASTER-01]# kubectl get po -n kube-system
NAME                                     READY   STATUS    RESTARTS        AGE
calico-kube-controllers-9dff488b-6kbvv   1/1     Running   7 (4d12h ago)   60d
calico-node-dff24                        1/1     Running   3 (4d12h ago)   60d
calico-node-mbtlb                        1/1     Running   1 (47d ago)     59d
calico-node-pbjmj                        1/1     Running   1 (4d14h ago)   60d
coredns-7d764666f9-pwjgn                 1/1     Running   2 (4d12h ago)   61d
coredns-7d764666f9-qrqvv                 1/1     Running   2 (4d12h ago)   61d
etcd-master-01                           1/1     Running   2 (4d12h ago)   61d
kube-apiserver-master-01                 1/1     Running   4 (4d12h ago)   61d
kube-controller-manager-master-01        1/1     Running   18 (2d7h ago)   61d
kube-proxy-46f4b                         1/1     Running   1 (47d ago)     59d
kube-proxy-v6zgz                         1/1     Running   1 (4d14h ago)   60d
kube-proxy-xp7vx                         1/1     Running   2 (4d12h ago)   61d
kube-scheduler-master-01                 1/1     Running   17 (2d7h ago)   61d
metrics-server-d6484c959-rk64z           1/1     Running   0               48d
metrics-server-d6484c959-x84k6           1/1     Running   0               4d14h

[root@MASTER-01]# kubectl get ds -n kube-system
NAME          DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
calico-node   3         3         3       3            3           kubernetes.io/os=linux   60d
kube-proxy    3         3         3       3            3           kubernetes.io/os=linux   61dتوجه داشته باشید که می توان تنظیمات پیش فرض daemonset را طوری تغییر داد که پادها علاوه بر نودهای worker، روی نودهای master نیز بالا بیایند.How to schedule daemonset on all nodes (master and worker nodes):apiVersion: apps/v1
kind: DaemonSet
metadata:
 name: webapp
 labels:
   nginx: 1.17.1
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      tolerations:
      - key: node-role.kubernetes.io/control-plane
        operator: Exists
        effect: NoSchedule
      - key: node-role.kubernetes.io/master
        operator: Exists
        effect: NoSchedule
      containers:
      - image: docker.arvancloud.ir/nginx:1.17.1
        imagePullPolicy: IfNotPresent
        name: nginxStatefullSetاگر ما بخواهیم یک پاد روی یک یا چند نود با پارامترهای مشخص بالا بیاید از StatefullSet استفاده می کنیم. به عنوان مثال فرض کنید ما میخواهیم دیتابیس Postgre خود را در کلاستر کوبرنتیز بالا بیاوریم. در این صورت از StatefullSet استفاده می کنیم؛ چرا که میخواهیم یک یا چند پاد از دیتابیس روی نودهای مشخص بالا بیایند و همیشه همانجا اجرا شوند بدون اینکه Scale شوند، جابجا شوند یا مشخصات آنها مانند نام پاد، شبکه و ... تغییر کند.NodeSelectorگاهی اوقات نیاز است تا پاد ما روی نود یا نودهای خاصی بالا بیاید. مثلا فرض کنید برنامه ما دائما نیاز به خواندن و نوشتن در هارددیسک داشته باشد بنابراین باید عملیات I/O هارددیسک به سرعت انجام شود و فقط یکی از نودهای ما دارای هارد پرسرعت SSDمی باشد. بنابراین ما دوست داریم که پاد آن برنامه حتما روی آن نود مشخص که دارای هارد SSD است اجرا شود.یا فرض کنید ما از یک نسخه از AI استفاده می کنیم و نیاز به GPU بالا داریم. بنابراین ما دوست داریم پاد آن برنامه روی نودهایی با GPU بالا اجرا شود.در همه این مثالها ما می توانیم از مفهوم node selector استفاده کنیم. در node selector ما روی هر یک از نودهای کلاستر یک سری label می زنیم و با استفاده از آن لیبل ها می توانیم نود/نودهای موردنظر خود را فیلتر نماییم.[root@MASTER-01]# kubectl uncordon Worker-02
Worker-02 uncordonedapiVersion: apps/v1
kind: Deployment
metadata:
 name: webapp
 labels:
  app: v11.1.1
spec:
 replicas: 3
 selector:
  matchLabels:
   app: nginx
 template:
  metadata:
   labels:
    app: nginx
  spec:
   containers:
   - name: nginx
     image: docker.arvancloud.ir/nginx:1.16.1
     imagePullPolicy: IfNotPresent
   nodeSelector:
    hdd: ssd[root@MASTER-01]# kubectl apply -f deployment.yaml
deployment.apps/webapp created[root@MASTER-01]# kubectl get deploy
NAME     READY   UP-TO-DATE   AVAILABLE   AGE
webapp   3/3     3            3           4m30s

[root@MASTER-01]# kubectl get rs
NAME                DESIRED   CURRENT   READY   AGE
webapp-566fd96dbb   3         3         3       5m12s

[root@MASTER-01]# kubectl get po -o wide
NAME                      READY   STATUS    RESTARTS   AGE     IP              NODE        NOMINATED NODE   READINESS GATES
webapp-566fd96dbb-2s6gj   1/1     Running   0          5m25s   10.103.204.85   worker-02   &lt;none&gt;           &lt;none&gt;
webapp-566fd96dbb-xdwwr   1/1     Running   0          5m24s   10.103.204.86   worker-02   &lt;none&gt;           &lt;none&gt;
webapp-566fd96dbb-z2h8x   1/1     Running   0          5m24s   10.103.204.84   worker-02   &lt;none&gt;           &lt;none&gt;همانطور که مشاهده می شود، هر 3 پاد روی نود worker-02 بالا آمده اند چون فقط این نود دارای لیبل hdd = ssd می باشد.توجه داشته باشید که اگر ما در بخش nodeSelector، لیبلی را مشخص کنیم که روی هیچ نودی وجود نداشته باشد، اجرای پاد در وضعیت Pending می ماند.Node affinity &amp; node anti affinityدر Node Affinity ما مشخص می کنیم که پاد روی چه نودهایی می تواند بالا بیاید.NodeSelector در واقع یک Node Affinity ساده است که نودها را تنها براساس لیبل مشخص می کند.Node Affinity را می توان در دو نوع مشخص کرد:requiredDuringSchedulingIgnoredDuringExecution:در این حالت حتما باید نود دارای شرایط مشخص شده باشد تا پاد روی آن بالا بیاید. اگر نودی با شرایط خواسته شده پیدا نشود، وضعیت پاد Pending می ماند.preferredDuringSchedulingIgnoredDuringExecution:در این حالت اگر نودی با شرایط مشخص شده پیدا شود، پاد روی آن بالا می آید. در غیر این صورت، پاد روی نزدیکترین نود به شرایط تعیین شده (نودی با بالاترین امتیاز)، بالا می آید.فرض کنید ما یک کلاستر کوبرنتیز داریم که نودهای آن در سه دیتاسنتر تهران، تبریز و مازندران قرار دارند و مکان دیتاسنتر با یک لیبل در نود مشخص شده است.[root@MASTER-01 ~]# kubectl label node worker-02 topology.kubernetes.io/zone=Tehran
node/worker-02 labeledحالا با node affinity می توانیم تعیین کنیم که پادهای برنامه فقط روی نودهای واقع در تهران یا تبریز بالا بیایند.apiVersion: apps/v1
kind: Deployment
metadata:
 name: webapp
 labels:
  app: v11.1.1
spec:
 replicas: 3
 selector:
  matchLabels:
   app: nginx
 template:
  metadata:
   labels:
    app: nginx
  spec:
   containers:
   - name: nginx
     image: docker.arvancloud.ir/nginx:1.16.1
     imagePullPolicy: IfNotPresent
   affinity:
     nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
       nodeSelectorTerms:
       - matchExpressions:
         - key: topology.kubernetes.io/zone
           operator: In
           values:
           - Tehran
           - Tabriz
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
         matchExpressions:
         - key: another-node-label-key
           operator: In
           values:
             - another-node-label-vlaues[root@MASTER-01]# kubectl apply -f deployment.yaml
deployment.apps/webapp created

[root@MASTER-01]# kubectl get po -o wide
NAME                      READY   STATUS    RESTARTS   AGE     IP              NODE        NOMINATED NODE   READINESS GATES
webapp-6b6984c47d-2fhm7   1/1     Running   0          16s     10.103.204.88   worker-02   &lt;none&gt;           &lt;none&gt;
webapp-6b6984c47d-dsjnj   1/1     Running   0          16s     10.103.204.87   worker-02   &lt;none&gt;           &lt;none&gt;
webapp-6b6984c47d-qxp82   1/1     Running   0          16s     10.103.204.89   worker-02   &lt;none&gt;           &lt;none&gt;سایر operatorهای affinity عبارتد از :InNotInExistsDoesNotExistGt (Greater than)Lt (Less than)Weight:در preferredDuringSchedulingIgnoredDuringExecution می توانیم چند preference تعریف کنیم و برای هر یک از آنها عددی بین 1 تا 100 را به عنوان وزن تعیین کنیم.ممکن است از بین نودهای کلاستر چند نود حائز شرایط معین شده باشند. در این صورت آن نودی انتخاب می شود که مجموع weight برای آن بیشتر از بقیه نودها باشد.Pod affinity &amp; pod anti affinityاین مورد خیلی شبیه به node affinity/node anti affinity است. با این تفاوت که انتخاب نود بر اساس پادهای داخل آن صورت می گیرد.فرض کنید که سیستم ما دارای دو برنامه جدا از هم می باشد یکی backend و دیگری frontend. این دو برنامه داده های زیادی را بین هم رد و بدل می کنند و ما برای افزایش سرعت برنامه و کاهش زمان پاسخ میخواهیم پادهای این دو برنامه کنار هم و روی یک نود اجرا شوند. برای این منظور از Pod Affinity استفاده می کنیم؛ به عنوان مثال در فایل مانیفست frontend و در بخش Pod Affinity تعیین می کنیم که این پاد روی نودی بالا بیاید که پاد backend اجرا می شود.حالا فرض کنید ما دو برنامه داریم که هر دو نیاز به CPU بالا هستند و پردازشهای سنگینی را انجام می دهند. قاعدتا ما می خواهیم که پادهای این دو برنامه روی یک نود اجرا نشوند و روی نودهای جداگانه بالا بیایند. برای این منظور از Pod Anti Affinity استفاده می کنیم.معمولا ما ترجیح می دهیم که هر یک از replicaهای پاد روی نودهای جداگانه قرار بگیرند و دو پاد از یک برنامه روی یک نود نباشند. مثلا اگر ما سه نسخه از Redis بالا می آوریم بهتر است هر یک روی نودهای جداگانه باشد تا در مواقعی که یک نود دچار مشکل شد نودهای دیگر جوابگوی درخواستها باشند. این مورد هم یکی از کاربردهای عمده Pod Anti Affinity می باشد.منابع:https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/https://kubernetes.io/docs/concepts/workloads/controllers/deployment/https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Thu, 21 May 2026 13:01:29 +0330</pubDate>
            </item>
                    <item>
                <title>آموزش Kubernetes - قسمت هفتم (Pod Healthcheck &amp; Resouce Management)</title>
                <link>https://virgool.io/@farhad.sadeghi/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-kubernetes-%D9%82%D8%B3%D9%85%D8%AA-%D9%87%D9%81%D8%AA%D9%85-pod-healthcheck-resouce-management-mcvkazlu5nxb</link>
                <description>در این پست با دو مفهوم در رابطه با پادها یعنی Pod Healthcheck و Pod Resource Management صحبت خواهم کرد.اما قبل از اینکه به آنها بپردازم توجه شما را به چند نکته و دستور در کوبرنتیز جلب می کنم:اگر به هر دلیل یکی از نودهای شما دچار مشکل شد و در حالت Not Ready بود در بسیاری از موارد، اجرای دستور زیر روی آن نود مشکل را برطرف می کند.iptables -F ; systemctl restart containerd ; systemctl restart kubeletمشاهده لیست namespace ها:$ kubectl get ns
NAME              STATUS   AGE
cilium-secrets    Active   73d
default           Active   73d
kube-node-lease   Active   73d
kube-public       Active   73d
kube-system       Active   73dایجاد namespace جدید:$ kubectl create ns newnamespace

$ kubectl create ns test-ns
namespace/test-ns createdShow Labels:kubectl get po --show-labels
kubectl get po --selector=app=webHow to export/import images from/into containerd:ctr -n k8s.io images import k8s-v1.35-all.tar
ctr -n k8s.io images export scheduler.tar registry.k8s.io/kube-scheduler:v1.35.0نمونه ای از فایل pod manifest و نحوه apply کردن آن:time-exporter.yamlapiVersion: v1
kind: Pod
metadata:
 name: time-exporter
 labels:
   app: time
 namespace: time-app
spec:
 volumes:
  - name: time
    emptyDir: {}
 containers:
  - name: nginx
    image: nginx:latest
    imagePullPolicy: IfNotPresent
    volumeMounts:
     - name: time
       mountPath: /usr/share/nginx/html

  - name: time-app
    image: mytime-exporter:v3.0.0
    imagePullPolicy: IfNotPresent
    volumeMounts:
      - name: time
        mountPath: /exportapply کردن فایل manifest:kubectl create ns time-app
kubectl apply -f time-exporter.yaml
kubectl expose pod -n time-app time-exporter --type=NodePort --port=80
kubectl get svc -n time-appPod Healthcheck1. Liveness Probeاگر fail شود، کوبر پاد را ریستارت می کند. یعنی برنامه نویس باید Endpoint ی را دراختیار ما قرار دهد که با fail شدن آن، کوبر برنامه را ریستارت کند و با ریستارت شدن برنامه، مشکل برطرف شود.2. Readiness Probeاگر fail شود کوبر درخواستی را به پاد نمی فرستد. یعنی برنامه نویس باید Endpoint ی را در اختیار ما قرار دهد که با fail شدن آن، کوبر ترافیکی را به سمت برنامه نفرستد و وقتی که true شد مجددا کوبر، ترافیک را سمت برنامه بفرستد و مشکل برطرف شده باشد.3. Startup Probeاگر fail شود یعنی هنوز برنامه به طور کامل بالا نیامده است.برای چک کردن liveness سه روش وجود دارد:1.1 Liveness Command:یعنی ما داخل پاد، یک اسکریپتی را مثلا هر 5 ثانیه یکبار اجرا کنیم و اگر با موفقیت اجرا نشد (خروجی اجرا صفر نشد) یعنی برنامه مشکل دارد و باید ریستارت شود.apiVersion: v1
kind: Pod
metadata:
 name: livenessprobe
 labels:
  app: sample
spec:
 containers:
  - name: liveness
    image: busybox:latest
    args:
     - /bin/sh
     - -c
     - touch /tmp/healthy ; sleep 30 ; rm -f /tmp/healthy ; sleep 600
    livenessProbe:
     exec:
      command:
       - cat
       - /tmp/healthy
     initialDelaySeconds: 5
     periodSeconds: 5args یا command بعد از بالا آمدن کانتینر اجرا می شوند. اگر در داکرفایل، CMD وجود نداشته باشد یا اینکه بخواهیم آن را override کنیم از args یا command استفاده می کنیم.دستور touch در لینوکس فایل می سازد.در مثال بالا، بعد از بالا آمدن کانتینر، یک فایل در مسیر tmp/healthy ایجاد می شود و 30 ثانیه بعد آن فایل حذف می شود.liveness command بعد از یک تاخیر 5 ثانیه ای در ابتدای کار، هر 5 ثانیه فایل tmp/healthy را می خواند، اگر نتواند فایل را بخواند خروجی ناموفق (غیر صفر) برمی گرداند. یعنی ما توقع داریم ابتدا liveness probe موفقیت آمیز باشد اما بعد از گذشت 30 ثانیه که فایل مذکور حذف شد، liveness probe ناموفق بوده و کوبرنتیز، پاد را ریستارت کند.1.2 HttpGetResponse Code: 200~399 =&gt; okResponse Code &gt;= 400 =&gt; not okیعنی برنامه نویس آدرس یک endpoint را در اختیار کوبرنتیز قرار می دهد؛ اگر کوبر آن آدرس را فراخوانی کند و کد وضعیت 200 یا 300 برگردد همه چیز خوب است. ولی اگر کد وضعیت 400 یا 500 برگردد مشکلی در اجرا بوجود آمده است و پاد باید ریستارت شود.apiVersion: v1
kind: Pod
metadata:
 name: liveness
 labels:
  app: v1
spec:
 containers:
  - name: myapp
    image: registry.k8s.io/e2e-test-images/agnhost:2.40
    args:
     - liveness
    livenessProbe:
     httpGet:
       path: /healthz
       port: 8080
       httpHeaders:
         - name: Custom-Header
           value: Awesome
     initialDelaySeconds: 3
     periodSeconds: 3registry.k8s.io/e2e-test-images/agnhost یک ایمیج آموزشی است که سایت کوبرنتیز منتشر کرده است.در فراخوانی httpGet می توانیم هدر مشخصی را هم ارسال کنیم و httpGet فقط به درخواستهایی پاسخ می دهد که این هدر را داشته باشند. این کار برای این منظور است که httpGet فقط توسط liveness probe فراخوانی شود.1.3 Check portدرست مانند httpGet است منتها در این روش بجای چک کردن یک endpoint، یک پورت چک می شود. اگر listen می کرد یعنی همه چیز خوب است ولی اگر listen نمی کرد یعنی مشکلی در اجرای برنامه رخ داده است و پاد باید ریستارت شود.apiVersion: v1
kind: Pod
metadata:
 name: liveness
 labels:
  app: v1
spec:
 containers:
  - name: myapp
    image: registry.k8s.io/goproxy:0.1
    ports:
     - containerPort: 8080
    livenessProbe:
     tcpSocket:
       port: 8080
     initialDelaySeconds: 15
     periodSeconds: 10نحوه تنظیم readiness دقیقا همانند liveness می باشد فقط بجای livenessProbe از عبارت readinessProbe استفاده می کنیم. یک کانتینر می تواند یکی از این دو را و یا هر دو را همزمان داشته باشد.Pod Resouce Managementrequests.memoryrequests.cpulimits.memorylimits.cpuمقدار request مقداری است که حتما باید در اختیار کانتینر قرار داده شود و کوبر آن را گارانتی می کند. حتی اگر مصرف کانتینر کمتر از مقدار request هم باشد باز هم مقدار request برای کانتینر رزرو شده است.کوبر موقعی که کانتنر را بالا می آورد به دنبال نودی می گردد که منابع درخواست شده به میزان Request را داشته باشد و پاد را روی آن بالا می آورد. اگر منابع به میزان request روی هیچ نودی وجود نداشته باشد، کوبر نمی تواند پاد را بالا بیاورد و منتظر آزاد شدن منابع می ماند.مقدار limit مقداری است که بیشتر از آن در اختیار کانتینر قرار داده نمی شود. یعنی حداکثر مقدار منابعی است که کوبر در اختیار کانتینر قرار می دهد.توجه داشته باشید که اگر یک برنامه تمام memory خود را استفاده کرده باشد به احتمال زیاد crash خواهد کرد چون قادر نیست پارامتر جدیدی را ایجاد کند و حافظه به آن تخصیص دهد. موقعی که یک کانتینر تمام memory تخصیص داده شده به خود را مصرف کند کوبر خطای OOM(Out Of Memory) می دهد.apiVersion: v1
kind: Pod
metadata:
 name: nginx
 labels:
  app: web
spec:
 containers:
  - name: webapp
    image: docker.arvancloud.ir/nginx:latest
    imagePullPolicy: IfNotPresent
    resources:
     requests:
       memory: &quot;512Mi&quot;
       cpu: &quot;500m&quot;
     limits:
       memory: &quot;1Gi&quot;
       cpu: &quot;1000m&quot;

//m: milli core* واحدها دو نوع‌اند:دودویی (Binary)Ki = 1024 bytes (Kibibyte)Mi = 1024² bytes (Mebibyte)Gi = 1024³ bytes (Gibibyte)ده‌دهی (Decimal)KB = 1000 bytesMB = 1000² bytesGB = 1000³ bytesدر تعیین منابع پادها ما باید به SLI و SLO و SLA توجه داشته باشیم.این سه اصطلاح مربوط به Site Reliability Engineering (SRE) و مدیریت کیفیت سرویس هستند.1. SLISLI = Service Level Indicatorیک شاخص قابل اندازه‌گیری برای سنجش عملکرد یا کیفیت سرویس است.یعنی من خودم در نرم افزارم یکسری شاخص داشته باشم که مثلا اگر گفتند سیستم کند است من با مراجعه به آن شاخص ها بفهم کجا و چرا کند است.مثال‌ها:درصد موفقیت درخواست‌هازمان پاسخ (latency)نرخ خطا (error rate)availabilityمثال:99.95% of requests succeed2. SLOSLO = Service Level Objectiveیک هدف مشخص برای SLI است؛ یعنی می‌گوییم مقدار شاخص باید در چه سطحی باشد.یعنی خودمان بین تیم ها یک سری مواردی مشخص کنیم مثلا  Response time همه وب سرویسها باید حداکثر 200 میلی ثانیه باشد.مثال:99.9% availability per month3. SLASLA = Service Level AgreementSLA یعنی توافق‌نامه سطح خدمات؛ یک قرارداد رسمی و قانونی بین ارائه‌دهنده سرویس و مشتری که مشخص می‌کند:سرویس چه کیفیتی باید داشته باشداگر کیفیت رعایت نشد، چه جریمه‌ها یا خسارت‌هایی پرداخت می‌شودبه زبان ساده: SLA یک قرارداد رسمی است، در حالی که SLO یک هدف داخلی برای تیم مهندسی است.SLA شامل موارد زیر است:حداقل آپ‌تایم (Availability) تضمین‌شدهحداکثر Latency قابل قبولمیزان نرخ خطا (Error rate) مجاززمان پاسخگویی پشتیبانی (Support response time)سیاست‌های جبران خسارت (Refunds / Credits)مثال:SLA: سرویس باید 99.9٪ در دسترس باشد،وگرنه به ازای هر 1٪ کاهش آپ‌تایم، 10٪ اعتبار به مشتری بازگردانده می‌شود.</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Sat, 25 Apr 2026 14:03:34 +0330</pubDate>
            </item>
                    <item>
                <title>آموزش Kubernetes - قسمت ششم (Kube API و Pod)</title>
                <link>https://virgool.io/@farhad.sadeghi/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-kubernetes-%D9%82%D8%B3%D9%85%D8%AA-%D8%B4%D8%B4%D9%85-kube-api-%D9%88-pod-ghzqrgvector</link>
                <description>Kubernetes API و Pod1. Kubernetes APIوقتی ما دستور kubectl را اجرا می کنیم، در واقع آن دستور تبدیل به فراخوانی REST API می شود و به kube API Server ارسال می شود.پارامترهای ورودی تبدیل به json شده و به kube API Server ارسال می شوند و نتیجه نیز بصورت json برگردانده می شود.Resource: هر چیزی که کوبرنتیز مدیریت می کند، یک Resource است مانند Node و Pod و ServiceAPI Group: دسته ای از API ها که یک حیطه کاری را انجام می دهند جزو یک API Group هستند.API Versioning:1.Alpha (Example: V1Alpha1)نسخه ای است که هنوز به طور کامل تست نشده است و ممکن است دارای Bug باشد. ممکن است این نسخه در آینده کلا حذف شود. در محیط product به هیچ وجه نباید از نسخه های alpha استفاده شود.2.Beta (Example: V1Beta1)نسخه ای است که تست اولیه شده است. در آینده حذف نخواهد شد. مانند نسخه آلفا از نسخه بتا نیز نباید در محیط product استفاده شود.3.Stable (Example: V1)نسخه پایدار است که بصورت کامل تست شده و Bug های آن برطرف شده است.1.1 فراخوانی Kube APIفرمت فراخوانی:GET /api/GROUP/VERSION/RESOURCETYPE*توجه: اگر GROUP وارد نشود، مقدار پیش فرض آن یعنی core در نظر گرفته می شود.برای فراخوانی مستقیم API های kubernetes، ابتدا باید یک پروکسی بالا بیاوریم. با دستور زیر یک پروکسی کوبرنتیز ایجاد می شود:kubectl proxy --port=8080حالا می توانیم از طریق پروکسی ایجاد شده، APIهای کوبر را فراخوانی کنیم:# گرفتن لیست پادها
curl http://127.0.0.1:8080/api/v1/pods

# گرفتن لیست پادها و ذخیره خروجی در فایل
curl http://127.0.0.1:8080/api/v1/pods &gt; pods.json# get pods in kube-system namespace by kubectl command 
kubectl get po -n kube-system

# get pods in kube-system namespace by kube API
curl http://127.0.0.1:8080/api/v1/namespaces/kube-system/pods1.2 گرفتن لیست همه Resource های کوبرنتیز به همراه Namespace آنهاkubectl api-resources | more[root@MASTER-01 ~]# kubectl api-resources | more
NAME                                SHORTNAMES   APIVERSION                          NAMESPACED   KIND
bindings                                         v1                                  true         Binding
componentstatuses                   cs           v1                                  false        ComponentStatus
configmaps                          cm           v1                                  true         ConfigMap
endpoints                           ep           v1                                  true         Endpoints
events                              ev           v1                                  true         Event
limitranges                         limits       v1                                  true         LimitRange
namespaces                          ns           v1                                  false        Namespace
nodes                               no           v1                                  false        Node
persistentvolumeclaims              pvc          v1                                  true         PersistentVolumeClaim
persistentvolumes                   pv           v1                                  false        PersistentVolume
pods                                po           v1                                  true         Pod
podtemplates                                     v1                                  true         PodTemplate
...1.3 نصب bash-completionبرای اینکه نیاز نباشد ما دستورات kubernetes را حفظ بکنیم و به راحتی از دستورات استفاده کنیم، باید bash-completion را نصب کنیم.yum -y install bash-completion

kubectl completion bash | sudo tee /etc/bash_completion.d/kubectl &gt; /dev/null
sudo chmod a+r /etc/bash_completion.d/kubectlحالا هنگام نوشتن دستورات kubectl، هر کجا که نیاز داشته باشیم می توانیم با زدن tab پیشنهادات موجود در ادامه دستور را مشاهده کنیم.* ابزارهایی مانند Rancher ، Lenz و غیره از Kube API برای ارتباط با کوبر استفاده می کنند.*2. Podکوچکترین واحد قابل Deploy روی کلاستر kubernetes پاد می باشد.پاد مجموعه ای از یک یا چند Container هست که storage و network مشترکی دارند و Namespace آنها یکی است.یعنی هر پاد و همه کانتینرهای داخل آن یک IP دارند. همچنین اگر ما پوشه ای را داخل پاد یا داخل یکی از کانتینرهای آن بسازیم، همه کانتینرهای داخل پاد به آن پوشه دسترسی خواهند داشت.2.1 Pod ManifestManifest هر پاد در فایل yaml نوشته می شود و چهار بخش دارد:apiVersion:kind:metadata:spec:apiVersion و kind مربوط به پاد را با دستور زیر می توانیم بدست آوریم:kubectl api-resources | grep pods[root@MASTER-01 ~]# kubectl api-resources | grep pods
pods                  po           v1         true         Podاطلاعاتی که در هر بخش نوشته می شوند به شرح زیر هستند:apiVersion: [نسخه پاد]
kind: Pod

metadata:
 name: [نام پاد]
 namespace: [نام namespace]

spec:
 containers: //مشخصات کانتینرهای پاد
  - name: [نام کانتینر]
    image: [image کانتینر]
    imagePullPolicy: [ifNotPresent/Always/Never]مثال:apiVersion: v1
kind: Pod
metadata:
 name: webserver
 namespace: default
spec:
 containers:
  - name: nginx
    image: nginx:latest
    imagePullPolicy: ifNotPresentبعد از تهیه فایل manifest پاد، آن را در کلاستر کوبرنتیز apply می کنیم.kubectl apply -f pod.yaml2.2 POD Phases (Lifecycle)CrashLoopBackup:وقتی یک پاد در وضعیت Pending است، کوبر دائما تلاش می کند که آن را به وضعیت Running ببرد. اگر بعد از تعدادی تلاش، کوبر نتواند پاد را اجرایی کند مثلا اگر نتواند image آن را دانلود کند، وضعیت پاد را به CrashLoopBackup تغییر می دهد. در وضعیت CrashLoopBackup کوبر همچنان از تلاش برای اجرای پاد دست نمی کشد ولی بازه های زمانی تلاش مجدد خود را طولانی تر می کند.Container Phases (Lifecycle):1.Running2.Waiting3.Terminatedوضعیت پاد تابعی است از وضعیت کانتینر.Pod Canditions:PodReadyToStartContainers (True/False)Initialized (True/False)Ready (True/False)ContainersReady (True/False)PodScheduled (True/False)2.3 مدیریت PODوقتی دستور kubectl apply را اجرا می کنیم، کانتینر و پاد روی نود worker بالا می آید. یعنی فایلهای image و کانتینر روی Pod دانلود می شود و نیازی به دانلود آنها روی نودهای master نیست.حذف پاد:Kubectl delete -f pod.yaml --force
Kubectl delete po webserver --force اجرای دستور bash داخل پادی با نام webserver:Kubectl exec -it webserver -- bash
حالا داخل پاد هستیم
ls -l* قاعدتا ما نباید نیازی به این کار داشته باشیم؛ مگر در حالتهای خاص برای troubleshooting.اگر روی یک پاد چند کانتینر وجود داشته باشد موقع اجرای کامند exec باید مشخص کنیم که منظورمان کدام کانتینر است. در غیر این صورت کوبرنتیز خودش یکی از کانتینرها را به عنوان پیش فرض انتخاب کرده و داخل آن می شود.Kubectl exec -it -n time-namespace time-pod -c nginx-container -- bash مشاهده 200 خط آخر لاگی که برنامه نویس روی کنسول write کرده است:Kubectl logs --tail 200 -f webserverابزارهایی وجود دارند که کنسول برنامه را خوانده و در ابزارهای ذخیره لاگ، ذخیره می کند. بنابراین فقط کافی است که برنامه نویس لاگهای خود را با یک فرمت استاندارد مثلا json در کنسول write کند.دریافت اطلاعات پاد:Kubectl get po redisExport فایل yaml از پاد:Kubectl get po redis -o yaml &gt; redis.yamlفایل yaml خروجی، شامل برخی اطلاعات اضافی هست که مختص همین پادی است که در حال اجراست. برای ایجاد یک پاد دیگر از روی این فایل yaml، باید اطلاعات اضافی حذف شوند.2.4 InitContainerکانتینری است که قبل از کانتینر اصلی بالا می آید و بعد از اینکه terminate شد، کانتینر اصلی بالا می آید. در حالتهایی که بخواهیم قبل از اجرای کانتینر اصلی یک کانتینر اجرا شود و دیتاهای اولیه را برای کانتینر اصلی فراهم کند، از initContainer استفاده می کنیم.یک پاد می تواند چند initContainer و چند کانتینر اصلی داشته باشد.نحوه تعریف initContainer در فایل manifestمانند کانتینر اصلی است.apiVersion: v1
kind: Pod
metadata:
 name: webserver
spec:
 containers:
  - name: nginx
    image: nginx:1.14.2
    imagePullPolicy: IfNotPresent
 initContainers:
  - name: init-service1
    image: busybox:1.28
    command: [ “sleep”, “10”] 
  - name: init-service2
    image: busybox:1.28
    command: [ “sleep”, “10”] اگر خطایی در اجرای initContainer رخ دهد، کانتینر اصلی اجرا نمی شود.2.5 Multicontainerفرق initContainer و multiContainer در این است که initContainer ها ابتدا اجرا می شوند و بعد از اتمام کار آنها، کانتینرهای اصلی اجرا می شوند ولی در یک پاد multiContainer همه کانتنرها باهم اجرا می شوند.کاربرد multiContainer در دو حالت زیر می باشد:1. Sidecarدر sidecar، کانتینرها موازی با هم اجرا می شوند. از این حالت عمدتا برای لاگ گیری و مانیتورینگ استفاده می شود.مثال: ما یک اپلیکیشن داشته باشیم که کار خود را انجام دهد و لاگ ها را در کنسول بنویسد. همزمان یک اپلیکیشن دیگر هم نیاز داشته باشیم که لاگ ها را بخواند و به یک لاگ سرور مانند Fluend ارسال کند. یعنی ما نمیخواهیم اپلیکیشن اصلی درگیر نحوه ارسال و ذخیره لاگ شود.2. Ambassadorاز این حالت عمدتا برای proxy و کنترل ترافیک استفاده می کنند.مثال: ما یک اپلیکیشن داریم که میخواهیم قبل از اینکه درخواستها به آن برسند، درخواستها از یک پروکسی مانند envoy رد شوند و از این طریق قوانین و محدودیتهایی را برای مسیریابی و دسترسی اعمال نماییم. منابع:https://kubernetes.io/docs/concepts/workloads/pods/init-containers/</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Wed, 22 Apr 2026 12:36:48 +0330</pubDate>
            </item>
                    <item>
                <title>آموزش Kubernetes - قسمت پنجم (مدیریت کلاستر)</title>
                <link>https://virgool.io/@farhad.sadeghi/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-kubernetes-%D9%82%D8%B3%D9%85%D8%AA-%D9%BE%D9%86%D8%AC%D9%85-%D9%85%D8%AF%DB%8C%D8%B1%DB%8C%D8%AA-%DA%A9%D9%84%D8%A7%D8%B3%D8%AA%D8%B1-rfk6ef5yil18</link>
                <description>مدیریت کلاستر Kubernetesمشاهده لیست Nodeها:kubectl get nokubectl get nodes[root@MASTER-01 ~]# kubectl get no
NAME        STATUS   ROLES           AGE   VERSION
master-01   Ready    control-plane   36h   v1.35.1
worker-01   Ready    &lt;none&gt;          33h   v1.35.1
worker-02   Ready    &lt;none&gt;          23h   v1.35.1مشاهده لیست Podها:kubectl get po -A[root@MASTER-01 sources]# kubectl get po -A
NAMESPACE     NAME                                     READY   STATUS  
kube-system   calico-kube-controllers-9dff488b-6kbvv   1/1     Running 
kube-system   calico-node-dff24                        1/1     Running
kube-system   calico-node-pbjmj                        1/1     Running
kube-system   coredns-7d764666f9-pwjgn                 1/1     Running 
kube-system   coredns-7d764666f9-qrqvv                 1/1     Running 
kube-system   etcd-master-01                           1/1     Running 
kube-system   kube-apiserver-master-01                 1/1     Running 
kube-system   kube-controller-manager-master-01        1/1     Running 
kube-system   kube-proxy-v6zgz                         1/1     Running 
kube-system   kube-proxy-xp7vx                         1/1     Running 
kube-system   kube-scheduler-master-01                 1/1     Runningمشاهده اینکه هر Pod روی چه Node اجرا شده است:kubectl get po -A -o wide[root@MASTER-01 ~]# kubectl get po -A -o wide
NAMESPACE     NAME                                     READY   STATUS             RESTARTS          AGE   IP              NODE        NOMINATED NODE   READINESS GATES
kube-system   calico-kube-controllers-9dff488b-6kbvv   1/1     Running            0                 31h   10.98.184.65    master-01   &lt;none&gt;           &lt;none&gt;
kube-system   calico-node-dff24                        1/1     Running            1 (31h ago)       31h   192.168.65.13   master-01   &lt;none&gt;           &lt;none&gt;
kube-system   calico-node-j4qrn                        1/1     Running            0                 23h   192.168.65.15   worker-02   &lt;none&gt;           &lt;none&gt;
kube-system   calico-node-pbjmj                        1/1     Running            0                 31h   192.168.65.14   worker-01   &lt;none&gt;           &lt;none&gt;
kube-system   coredns-7d764666f9-pwjgn                 1/1     Running            0                 36h   10.98.184.66    master-01   &lt;none&gt;           &lt;none&gt;
kube-system   coredns-7d764666f9-qrqvv                 1/1     Running            0                 36h   10.98.184.67    master-01   &lt;none&gt;           &lt;none&gt;
kube-system   etcd-master-01                           1/1     Running            0                 36h   192.168.65.13   master-01   &lt;none&gt;           &lt;none&gt;
kube-system   kube-apiserver-master-01                 1/1     Running            2 (31h ago)       36h   192.168.65.13   master-01   &lt;none&gt;           &lt;none&gt;
kube-system   kube-controller-manager-master-01        1/1     Running            5 (26h ago)       36h   192.168.65.13   master-01   &lt;none&gt;           &lt;none&gt;
kube-system   kube-proxy-q9k4t                         1/1     Running            0                 23h   192.168.65.15   worker-02   &lt;none&gt;           &lt;none&gt;
kube-system   kube-proxy-v6zgz                         1/1     Running            0                 33h   192.168.65.14   worker-01   &lt;none&gt;           &lt;none&gt;
kube-system   kube-proxy-xp7vx                         1/1     Running            0                 36h   192.168.65.13   master-01   &lt;none&gt;           &lt;none&gt;
kube-system   kube-scheduler-master-01                 1/1     Running            4 (26h ago)       36h   192.168.65.13   master-01   &lt;none&gt;           &lt;none&gt;
kube-system   metrics-server-d6484c959-9rjfx           1/1     Running            0                 22h   10.100.171.6    worker-01   &lt;none&gt;           &lt;none&gt;
kube-system   metrics-server-d6484c959-vwxx2           1/1     Running            0                 22h   10.103.204.65   worker-02   &lt;none&gt;           &lt;none&gt;
time-app      time-exporter                            2/2     Running            0                 26h   10.100.171.1    worker-01   &lt;none&gt;           &lt;none&gt;مشاهده همه جزئیات یک Pod:kubectl describe po -n [namespace] [PodName][root@MASTER-01 ~]# kubectl describe po -n kube-system calico-node-dff24
Name:                 calico-node-dff24
Namespace:            kube-system
Priority:             2000001000
Priority Class Name:  system-node-critical
Service Account:      calico-node
Node:                 master-01/192.168.65.13
Start Time:           Wed, 25 Feb 2026 20:02:04 -0500
Labels:               controller-revision-hash=b69b5fdf4
                      k8s-app=calico-node
                      pod-template-generation=1
Annotations:          &lt;none&gt;
Status:               Running
SeccompProfile:       RuntimeDefault
IP:                   192.168.65.13
IPs:
  IP:           192.168.65.13
Controlled By:  DaemonSet/calico-node
Init Containers:
  upgrade-ipam:
    Container ID:  containerd://255fac1cfc55a2c0cf5c9a2ee0e58bbe6451473e226cea866cabaef75deeacd2
    Image:         quay.io/calico/cni:v3.31.4
    Image ID:      quay.io/calico/cni@sha256:210055d9682571ee5d6f724d774b54ef524ba7da51379abb6adc73b93eccd07f
    Port:          &lt;none&gt;
    Host Port:     &lt;none&gt;
    Command:
      /opt/cni/bin/calico-ipam
      -upgrade
    State:          Terminated
      Reason:       Completed
      Exit Code:    0
      Started:      Wed, 25 Feb 2026 20:04:46 -0500
...Apply کردن فایل Manifest (Yaml):kubectl apply -f mymanifest.yamlتخلیه Node:kubectl drain [NodeName] --ignore-daemonsets[root@MASTER-01 ~]# kubectl drain worker-02 --ignore-daemonsets
...
[root@MASTER-01 ~]# kubectl get no
NAME        STATUS                     ROLES           AGE   VERSION
master-01   Ready                      control-plane   44h   v1.35.1
worker-01   Ready                      &lt;none&gt;          41h   v1.35.1
worker-02   Ready,SchedulingDisabled   &lt;none&gt;          31h   v1.35.1drain: تخلیه، تخلیه کردناین دستور سبب می شود که نود مربوطه unschedulable شود یعنی پاد جدید روی آن اجرا نمی شود.پادهایی که روی نود اجرا می شوند را می توان به دو دسته تقسیم بندی کرد؛ دسته اول پادهای سیستمی کوبرنتیز هستند که مختص همان نود می باشند و دسته دوم سایر پادها هستند که مربوط به برنامه های اجرایی هستند.با اجرای دستور drain، پادهای دسته دوم روی نود حذف شده و روی نود دیگری مجددا ایجاد می شوند. پارامتر ignore-daemonsets هم می گوید که دسته اول حذف شود و به آنها نیاز نیست. اگر این پارامتر وارد نشود، اجرای دستور drain با خطا (هشدار) مواجه می شود.*توجه داشته باشید که اجرای دستور drain، نود را حذف نمی کند فقط آن را تخلیه می کند. از این دستور زمانی استفاده می کنیم که بخواهیم آن نود را از لحاظ سخت افزاری یا نرم افزاری ارتقا بدهیم یا تعمیر کنیم.حذف Node از کلاستر:برای حذف یک نود از کلاستر، مراحل زیر را به ترتیب باید انجام دهیم.1.ابتدا با اجرای دستور زیر در control-plane، آن نود را تخلیه می کنیم:kubectl drain [NodeName] --ignore-daemonsets2.با اجرای دستور زیر در نود مورد نظر، عضویت آن را در کلاستر لغو می کنیم:kubeadm reset[root@WORKER-02 ~]# kubeadm reset
W0227 12:35:48.438671  697028 preflight.go:55] [reset] WARNING: Changes made to this host by &#039;kubeadm init&#039; or &#039;kubeadm join&#039; will be reverted.
[reset] Are you sure you want to proceed? [y/N]: y
[preflight] Running pre-flight checks
W0227 12:36:02.923635  697028 removeetcdmember.go:105] [reset] No kubeadm config, using etcd pod spec to get data directory
[reset] Deleted contents of the etcd data directory: /var/lib/etcd
[reset] Stopping the kubelet service
[reset] Unmounting mounted directories in &quot;/var/lib/kubelet&quot;
[reset] Deleting contents of directories: [/etc/kubernetes/manifests /var/lib/kubelet /etc/kubernetes/pki]
[reset] Deleting files: [/etc/kubernetes/admin.conf /etc/kubernetes/super-admin.conf /etc/kubernetes/kubelet.conf /etc/kubernetes/bootstrap-kubelet.conf /etc/kubernetes/controller-manager.conf /etc/kubernetes/scheduler.conf]

The reset process does not perform cleanup of CNI plugin configuration,
network filtering rules and kubeconfig files.

For information on how to perform this cleanup manually, please see:
    https://k8s.io/docs/reference/setup-tools/kubeadm/kubeadm-reset/[root@MASTER-01 ~]# kubectl get no
NAME        STATUS                        ROLES           AGE   VERSION
master-01   Ready                         control-plane   45h   v1.35.1
worker-01   Ready                         &lt;none&gt;          41h   v1.35.1
worker-02   NotReady,SchedulingDisabled   &lt;none&gt;          31h   v1.35.13.با اجرای دستور زیر در control-plane، آن نود را از کلاستر حذف می کنیم:kubectl delete no [NodeName][root@MASTER-01 ~]# kubectl delete no worker-02
node &quot;worker-02&quot; deleted
[root@MASTER-01 ~]# kubectl get no
NAME        STATUS   ROLES           AGE   VERSION
master-01   Ready    control-plane   45h   v1.35.1
worker-01   Ready    &lt;none&gt;          42h   v1.35.1حذف توکن کلاستر:kubeadm token delete [TokenName][root@MASTER-01 ~]# kubeadm token list
TOKEN                     TTL         EXPIRES                USAGES                   DESCRIPTION                                                EXTRA GROUPS
bfuf4z.h3n9ec80ukmxqo4s   23h         2026-02-28T17:58:55Z   authentication,signing   &lt;none&gt;                                                     system:bootstrappers:kubeadm:default-node-token
[root@MASTER-01 ~]# kubeadm token delete bfuf4z.h3n9ec80ukmxqo4s
bootstrap token &quot;bfuf4z&quot; deletedایجاد توکن و join command:kubeadm token create --print-join-commandNode Roles/Labels:مشاهده لیست نودها به همراه label های هر کدام:kubectl get no --show-labelsافزودن Role به یک نود:kubectl label no [NodeName] node-role.kubernetes.io/[RoleName]=حذف Role از یک نود:kubectl label no [NodeName] node-role.kubernetes.io/[RoleName]-[root@MASTER-01 ~]# kubectl get no --show-labels
NAME        STATUS   ROLES           AGE   VERSION   LABELS
master-01   Ready    control-plane   2d    v1.35.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=master-01,kubernetes.io/os=linux,node-role.kubernet                           es.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=
worker-01   Ready    &lt;none&gt;          45h   v1.35.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker-01,kubernetes.io/os=linux
worker-02   Ready    &lt;none&gt;          16m   v1.35.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker-02,kubernetes.io/os=linux[root@MASTER-01 ~]# kubectl label no worker-01 node-role.kubernetes.io/worker=
node/worker-01 labeled[root@MASTER-01 ~]# kubectl get no --show-labels
NAME        STATUS   ROLES           AGE   VERSION   LABELS
master-01   Ready    control-plane   2d    v1.35.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=master-01,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=
worker-01   Ready    worker          45h   v1.35.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker-01,kubernetes.io/os=linux,node-role.kubernetes.io/worker=
worker-02   Ready    &lt;none&gt;          17m   v1.35.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker-02,kubernetes.io/os=linuxرفع مشکل READY نبودن یک نود در کلاستر:روی نودی که مشکل دارد دستور زیر را اجرا می کنیم:iptables -F; systemctl restart containerd; systemctl restart kubelet;</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Tue, 21 Apr 2026 14:59:37 +0330</pubDate>
            </item>
                    <item>
                <title>دستورات Docker و Dockerfile و Docker Compose</title>
                <link>https://virgool.io/@farhad.sadeghi/%D8%AF%D8%B3%D8%AA%D9%88%D8%B1%D8%A7%D8%AA-docker-%D9%88-dockerfile-%D9%88-docker-compose-wpdzaq0eefbz</link>
                <description>1. Docker Commandsget pulled images$ docker imagespull image$ docker pull busybox
$ docker pull docker.elastic.co/elasticsearch/elasticsearch:6.3.2remove all images$ docker rmirun container from an image// name: container name
// it: join to the container
// rm: remove container after termination
// d: run container in dettached process
// P: show container’s all ports
// p: set container port
// p 8888:80 use port 8888 instead of 80
// net: bridge network name that container run on it
​
$ docker run busybox
$ docker run busybox echo &quot;hello from busybox&quot;
$ docker run -it busybox sh
$ docker run --rm prakhar1989/static-site
$ docker run -d -P --name static-site prakhar1989/static-site
$ docker run -p 8888:80 prakhar1989/static-sit
$ docker run -d --name es -p 9200:9200 -p 9300:9300 -e &quot;discovery.type=single-node&quot; docker.elastic.co/elasticsearch/elasticsearch:6.3.2
$ docker run -it --rm --net foodtrucks-net prakhar1989/foodtrucks-web bash
$ docker container run -d --name myapp mytime-exporter:v1.0.0get containers list// none: get only running containers
// a: get all containers
// q: return only containers ID
// f: set condition
​
$ docker ps
$ docker ps -a
$ docker ps -a -q -f status=exited
$ docker ps -a | grep myapp
​
$ docker container lsview container logs$ docker container logs mycontainername
​
//view last 200 line of myapp container log
$ docker container logs –tail 200 -f myappstop container$ docker container stop containername
$ docker stop containernameremove containers$ docker rm 305297d7a235 ff0a5c3750b9
$ docker container rm containername
$ docker container rm --force myapp
​
//remove all containers
$ docker container pruneview a container’s all ports$ docker port containername​get docker networks$ docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
5ae2ac433ebf   bridge    bridge    local
65e87bdbf368   host      host      local
ae51ba479b34   none      null      local* شبکه bridge، شبکه‌ای است که در آن کانتینرها به صورت پیش‌فرض اجرا می‌شوند.inspect a docker network$ docker network inspect netowrknamecreate bridge network$ docker network create foodtrucks-netremove network$ docker network rm foodtrucks-net2. Build and Run Automationدستورات در یک اسکریپت Bash به صورت زیر گرد‌آوری می شوند:# ساخت کانتینر فلسک
docker build -t prakhar1989/foodtrucks-web .
​
# ایجاد شبکه
docker network create foodtrucks-net
​
# راه•اندازی کانتینر ES
docker run -d --name es --net foodtrucks-net -p 9200:9200 -p 9300:9300 -e &quot;discovery.type=single-node&quot; docker.elastic.co/elasticsearch/elasticsearch:6.3.2
​
# راه•اندازی کانتینر اپلیکیشن فلسک
docker run -d --net foodtrucks-net -p 5000:5000 --name foodtrucks-web prakhar1989/foodtrucks-webاکنون باید تصور کرد که قرار است اپلیکیشن مربوطه برای اشخاص دیگری توزیع یا این اپلیکیشن روی سروری اجرا شود که داکر در آن نصب شده است:$ git clone https://github.com/prakhar1989/FoodTrucks
$ cd FoodTrucks
$ ./setup-docker.shو به این ترتیب کار به اتمام رسیده است. این یک روش بسیار عالی و قدرتمند برای به اشتراک گذاری و اجرای اپلیکیشن‌ها به حساب می‌آید.3. Dockerfile# شروع کار با ایمیج پایه
FROM ubuntu:18.04
​
# نصب متعلقات سراسری در سیستم برای پایتون و گره
RUN apt-get -yqq update
RUN apt-get -yqq install python3-pip python3-dev curl gnupg
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash
RUN apt-get install -yq nodejs
​
# کپی کردن کدهای اپلیکیشن مربوطه
ADD flask-app /opt/flask-app
​
# تنظیم یک شاخه برای اپلیکیشن
WORKDIR /opt/flask-app
​
# دریافت متعلقات مختص اپلیکیشن
RUN npm install
RUN npm run build
RUN pip3 install -r requirements.txt
​
# در معرض استفاده قرار دادن پورت
EXPOSE 5000
​
# راه•اندازی و استارت زدن اپلیکیشن
CMD [ &quot;python3&quot;, &quot;./app.py&quot; ]پرچم «yqq» برای حذف خروجی استفاده می‌شود و همه اعلان‌ها (Prompt) را «Yes» در نظر می‌گیرد.create image from dockerfile$ docker build . -t yourusername/imagename
$ docker image build . -t mytime-exporter:v1.0.0publish created image$ docker push yourusername/imagenamesave created imagedocker image save mytime-exporter:v1.0.0 &gt; mytime.tarimport saved image to containerdctr -n k8s.io images import mytime.tar4. Docker ComposeCompose ابزاری است که برای تعریف و اجرای اپلیکیشن‌های چند کانتینری به شکلی ساده مورد استفاده قرار می‌گیرد. این ابزار یک فایل پیکربندی به نام «docker-compose.yml» فراهم می‌کند که می‌توان از آن تنها با یک دستور برای استقرار یک اپلیکیشن و مجموعه سرویس‌هایش استفاده کرد که به آن‌ها وابسته است. Compose در تمام محیط‌ها کار می‌کند. هر یک از این محیط‌ها در ادامه فهرست شده‌اند:تولید (Production)صحنه پردازی (Staging)توسعه (Development)آزمایش (Testing)به همراه جریان‌های کاری CIاگرچه، باید گفته شود که Compose بیش‌تر برای محیط‌های توسعه و تست ایده‌آل است.محتویات فایل Docker Compose به صورت زیر است:version: &quot;3&quot;
services:
  es:
    image: docker.elastic.co/elasticsearch/elasticsearch:6.3.2
    container_name: es
    environment:
      - discovery.type=single-node
    ports:
      - 9200:9200
    volumes:
      - esdata1:/usr/share/elasticsearch/data
  web:
    image: prakhar1989/foodtrucks-web
    build: . # replaced image with build
    command: python3 app.py
    depends_on:
      - es
    ports:
      - 5000:5000
    environment:
      - DEBUG=True # set an env var for flask
    volumes:
      - ./flask-app:/opt/flask-app
volumes:
  esdata1:
    driver: local*Volumeها دایرکتوری‌های به اشتراک گذاشته شده بین کانتینرها هستند.check docker version$ docker-compose –versioncreate and run docker container from docker compose$ docker-compose up
​
//run docker-compose container detached
$ docker-compose up -dget containers list$ docker-compose psdelete compose and its data$ docker-compose down -vوقتی دستور up اجرا می شود؛ Compose خودش یک شبکه جدید به نام «composename_default» ایجاد و سرویس های جدید را در آن شبکه به گونه‌ای ضمیمه می کند که هر یک از آن‌ها برای دیگری قابل شناسایی باشند. هر کانتینر برای یک سرویس به شبکه پیش‌فرض می‌پیوندد و هر یک به وسیله سایر کانتینرها در آن شبکه قابل دسترسی و توسط آن‌ها با نام میزبانی مطابق نام کانتینر قابل شناسایی هستند.​</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Mon, 20 Apr 2026 16:23:45 +0330</pubDate>
            </item>
                    <item>
                <title>Anti-Corruption Layer (ACL) / Adapter</title>
                <link>https://virgool.io/@farhad.sadeghi/anti-corruption-layer-acl-adapter-wrkinyp6cxwr</link>
                <description>فرض کنید ما در کسب و کار خودمان یا در سازمانی که کار می کنیم از معماری میکروسرویس و REST API استفاده می کنیم. ما یک سری سرویس را به صورت soap از شرکت ها یا واحدهای دیگر دریافت می کنیم.حال سوال اینجاست که بهترین و اصولی ترین جایی که این تبدیل پروتکل باید انجام بشه کجاست؟ آیا داخل هر سرویسی که نیاز به فراخوانی سرویس soap دارد باید این کار انجام شود، داخل Api Gateway باید این تبدیل انجام شود یا جایی دیگر؟توی این مطلب میخوام این موضوع را به صورت خیلی ساده و خودمونی و برای همیشه روشن کنم. قبل از اینکه SOAP با REST قاطی بشه و سیستم ها تبدیل به آش شله قلمکار بشن.جواب کوتاه و محکمبهترین و اصولی‌ترین جا برای تبدیل SOAP → REST یک لایهٔ Anti-Corruption / Adapter / Integration Layer مستقل بیرون از سرویس‌های میکروسرویسی است.جواب کامل و مهندسیدر معماری میکروسرویس، هیچ‌وقت سرویس‌هات رو وادار نکن با دنیای عجیب SOAP صحبت کنن.سرویس‌های تو باید فقط REST بلد باشن و فاز «من هم SOAP بلدم، هم REST، هم GraphQL، هم چایی دم می‌کنم» نگیرن.پس باید چی کار کنیم؟بهترین محل تبدیل پروتکل کجاست؟1. لایه‌ی Anti-Corruption Layer (ACL) / Adapterاین همون لایه‌ایه که مثل مترجم همزمان سازمان ملل بین سرویس‌های مدرن RESTای تو و سرویس‌های باستانی SOAP طرف مقابل می‌ایسته.این لایه:درخواست REST داخلی رو می‌گیرهتبدیلش می‌کنه به SOAPبا سرویس بیرونی حرف می‌زنهجواب SOAP رو تبدیل می‌کنه به JSON/RESTو در نهایت «تمیز و اتو کشیده» تحویل میکروسرویس‌ها می‌دهچرا اینجا بهترین گزینه‌ست؟جداسازی کامل پروتکل خارجی از معماری داخلیسرویس‌های داخلی پاک و ساده می‌مونند (Single Responsibility)اگر فردا SOAP منقرض شد یا REST بیرونی به gRPC تغییر کرد… فقط همین لایه رو آپدیت می‌کنیامکان کشینگ، لاگینگ، ریت‌لیمیتینگ، امنیت و حتی Retry logic اینجا خیلی راحت‌ترهدیباگ و مانیتورینگ centralized می‌شه2. گزینه‌های غلط که گاهی وسوسه‌انگیز می‌شنانجام تبدیل داخل خود میکروسرویس‌هاسرویس‌هات چاق و شلخته می‌شن، وابسته به SOAP می‌شن و SRP میره رو هوا.گیت‌وی، APIگیت‌وی باید Routing و Security و throttling بکنه… تبدیل SOAP به REST؟عزیزم نه! اون طفل معصوم تحمل این مصیبت رو نداره.ساختار توصیه‌شدهInternal microservices (REST)⬇️⬆️Integration Layer / SOAP Adapter / ACL⬇️⬆️External SOAP Servicesارتباط ACL با گیت وی چطور باید باشه؟اول از همه: چه کسی با چه کسی حرف می‌زند؟در معماری درست، جریان ارتباط این‌جوریه:Client⬇️API Gateway⬇️Microservice (REST)⬇️Anti-Corruption Layer (ACL)⬇️External SOAP serviceیعنی ACL زیرمجموعهٔ Backend است نه زیرمجموعهٔ Gateway.چرا این ترتیب درسته؟1. API Gateway وظیفه‌اش این‌هاست:احراز هویت/مجوزRate LimitingRoutingامنیتلاگ و مانیتورینگ سطح بالاaggregation خیلی سادهگیت‌وی نباید تبدیل پروتکل انجام بده.چون اگه گیت‌وی SOAP-دان بشه، دیگه بهش نمی‌گن Gateway… می‌گن «فرودگاه خدمات متفرقه!» 😅2. ACL یک سرویس backend است، نه یک سرویس لبه (edge)وظیفه‌اش:ترجمه REST → SOAPترجمه SOAP → RESTهندل کردن Retry، Error mapping، Fault mappingکشینگ خاص سرویس خارجیلاگ‌های سطح پروتکل خارجیاین کارها اساساً کار سرویس‌های داخلی است، نه Gateway.معماری درست و تمیز (که از دور هم داد می‌زند: من حرفه‌ای‌ام)Flow سطح کاربردیکلاینت به گیت‌وی ضربه می‌زندگیت‌وی درخواست را به میکروسرویس تو پاس می‌دهدسرویس تو اگر نیاز داشت با سرویس خارجی حرف بزند، به ACL می‌گویدACL می‌رود SOAP را صدا می‌زندپاسخ را تمیز می‌کند و REST برمی‌گرداندسرویس تو جواب نهایی را می‌دهدگیت‌وی آن را تحویل کلاینت می‌دهدیک سؤال مهم:«حالا گیت‌وی باید ACL را ببیند یا نه؟»جواب:نه. به هیچ‌وجه!ACL یک سرویس داخلی است.گیت‌وی فقط باید سرویس‌های Domain را ببیند، نه Adapterهای پشت صحنه را.اگر گیت‌وی ACL را ببیند:لایهٔ دامنه دور زده می‌شودcoupling بالا می‌رودACL مجبور می‌شود رفتار API کاربر را تامین کند!! که فاجعه است.معماری layered رسماً می‌کشد میرودپس معماری درست چیه؟Gateway فقط به میکروسرویس‌ها روت می‌کندمیکروسرویس‌ها با ACL حرف می‌زنندACL با SOAP حرف می‌زندیک تشبیه بامزه:گیت‌وی مثل گارد ورودی یک شرکت است.کارمندها (میکروسرویس‌ها) داخل ساختمان هستند.ACL مثل مترجم شرکت است.آیا گارد ورودی باید با مترجم وارد بحث شود؟نه!فقط با کارمندها حرف می‌زند.کارمندها اگر نیاز داشتند، می‌روند سراغ مترجم. 😄میمونه بحث احراز هویت و امنیت:احتمالا سرویس soap نیاز به احراز هویت دارد، نام کاربری و رمز عبور اون توی چه لایه ای باید قرار بگیره؟این سؤال دقیقاً همون نقطه‌ایه که خیلی از تیم‌ها اشتباه می‌کنن و آخرش پسورد SOAP رو میذارن تو گیت‌وی، بعد گیت‌وی دپرس میشه و شب‌ها کابوس WSDL می‌بینه 😄روش شسته‌رفته و معماری‌شده:نام کاربری و رمز سرویس SOAP باید در خودِ لایهٔ ACL ذخیره و استفاده شود.نه در گیت‌وی،نه در میکروسرویس‌های داخلی،نه در کلاینت.فقط و فقط ACL.چرا باید credentialهای SOAP در ACL باشند؟1. ACL تنها لایه‌ای است که مستقیماً با SOAP سرویس خارجی حرف می‌زندپس طبیعیه که احراز هویت مخصوص SOAP هم همین‌جا انجام بشه.میکروسرویس‌های داخلی نباید حتی بوی SOAP بهشون بخوره.2. جداسازی مسئولیت‌ها (SRP)گیت‌وی = احراز هویت کاربران سیستم شمامیکروسرویس = منطق دامنهACL = ترجمه پروتکل + امنیت سرویس‌های خارجیاگر پسورد SOAP رو جای دیگه بذاری، این مرزهای طلایی قاطی میشه.3. امنیتاگر credentialهای SOAP وارد گیت‌وی شوند:گیت‌وی عملاً تبدیل می‌شود به سرویس خارجی شماattack surface بیشتر می‌شودمدیریت Rotation سخت می‌شودلاگ‌ها خطرناک می‌شونداما اگر فقط ACL آنها را بداند،امنیت و مدیریت ساده و متمرکز می‌ماند.بهترین مکان ذخیره credentials دقیقا کجاست؟داخل ACL، ولی در این ساختار:ذخیره در Secret Manager (مثل Vault, AWS Secrets Manager, Kubernetes Secrets)Inject شدن در ACL هنگام startupاستفاده فقط در کد adapterعدم ذخیره سازی مستقیم در config معمولی یا imageچه چیزی هرگز نباید اتفاق بیفتد؟گیت‌وی credential SOAP را پاس بدهدکلاینت credential SOAP را بدانددرخواست REST داخلی شامل یوزر/پسورد SOAP باشدسرویس داخلی خودش credential را ذخیره کندپیشنهاد بهتر: Token Relay + Rotationاگر سرویس SOAP امکان استفاده از token داشته باشد (بعضی WSDLها دارند)،بهترین کار:ACL در startup یا دوره‌ای token بگیردtoken را در حافظه یا cache امن نگه داردبرای هر درخواست از همان token استفاده کنداین کار امنیت را چند برابر بالا می‌برد.</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Sun, 12 Apr 2026 17:07:26 +0330</pubDate>
            </item>
                    <item>
                <title>آموزش Kubernetes - قسمت چهارم</title>
                <link>https://virgool.io/@farhad.sadeghi/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-kubernetes-%D9%82%D8%B3%D9%85%D8%AA-%DA%86%D9%87%D8%A7%D8%B1%D9%85-qavxanba1hpc</link>
                <description>راه اندازی کلاستر Kubernetesدر قسمت قبل آموزش کوبرنتیز، مراحل نصب kubectl، kubelet و kubeadm بصورت کامل شرح داده شد و روی همه نودهای کلاستر مراحل نصب انجام شد.برای راه اندازی کلاستر کوبرنتیز تنها نصب نرم افزارها روی نودها کفایت نمی کند. در این مرحله باید master node راه اندازی (init) شود و worker node ها یکی یکی به آن متصل شوند.به مجموعه کارهایی که در این قسمت انجام خواهیم داد، اصطلاحا بوت استرپ کردن کلاستر کوبرنتیز (Kubernetes cluster bootstrapping) می گویند.1. Pre-operation checkssystemctl status containerd
systemctl status kubeletقبل از bootstrap کردن کلاستر کوبرنتیز با اجرای دستورات بالا به ترتیب وضعیت containerd و kubelet را بررسی می کنیم.containerd باید enabled و active(running) باشد.kubelet باید enabled باشد ولی active نخواهد بود. kubelet بعد از kubeadm init اجرا خواهد شد.On most modern Linux systems that use systemd (like Ubuntu, CentOS, Debian, RHEL), there are several possible service states.When you run:systemctl status &lt;service-name&gt;You’ll mainly see two types of states:1️⃣ Active State (Primary Service State)These are the most common:active (running) → Service is running properlyactive (exited) → Ran successfully and exited (normal for one-shot services)inactive (dead) → Not runningfailed → Service crashed or failed to startactivating → In the process of startingdeactivating → In the process of stoppingSo there are 6 common active states.2️⃣ Enablement State (Boot Status)Check with:systemctl is-enabled &lt;service-name&gt;Possible results:enabled → Starts at bootdisabled → Does not start at bootstatic → Cannot be enabled manually (dependency only)masked → Completely blocked from startingindirect → Enabled via another servicegenerated → Created dynamicallytransient → Temporary unitSo around 7 enablement states.✅ Enable a servicesudo systemctl enable &lt;service-name&gt;

#Example (kubelet):
sudo systemctl enable kubelet▶️ Start it immediately (optional)Enabling does not start it right away.To start it now:sudo systemctl start &lt;service-name&gt;Or both at once:sudo systemctl enable --now &lt;service-name&gt;Example:sudo systemctl enable --now kubeletسایر مواردی که باید چک شوند وضعیت SELinux و firewalld می باشند. SELinux باید Permissive باشد و firewalld باید inactive باشد.getenforce
systemctl status firewalld2. Kubeadm initبرای راه اندازی و bootstrap کردن کلاستر کوبر از دستور kubeadm init استفاده می کنیم.kubeadm init --apiserver-advertise-address=192.168.65.43 --pod-network-cidr=10.96.0.0/12 –-kubernetes-version=1.34.4ممکن است Master Node ما دارای چند کارت شبکه باشد (این امر در بحث کلاستر کوبرنیتز و نودهای مستر مرسوم است)، در این صورت باید یکی از آنها را با وارد کردن IP در پارامتر apiserver-advertise-address مشخص کنیم. با این کار، Kubeapi روی همان IP هاست می شود.ممکن است نودهای ما در ساب شبکه های مختلف قرار داشته باشند. در پارامتر pod-network-cidr باید رنج IP نودها را مشخص کنیم.اگر نسخه Kubernetes را مشخص نکنیم، آخرین نسخه نصب می شود.توجه: در محیط محصول همه imageها روی یک nexuse قرار می گیرند و کوبرنتیز از روی آن، image ها را لود می کند و imageها بصورت دستی نباید کپی شوند.وقتی کامند kubeadm init اجرا می شود کارها/فازهای زیر انجام می شود:preflight                     Run pre-flight checks
certs                         Certificate generation
  /ca                           Generate the self-signed Kubernetes CA to provision identities for other Kubernetes components
  /apiserver                    Generate the certificate for serving the Kubernetes API
  /apiserver-kubelet-client     Generate the certificate for the API server to connect to kubelet
  /front-proxy-ca               Generate the self-signed CA to provision identities for front proxy
  /front-proxy-client           Generate the certificate for the front proxy client
  /etcd-ca                      Generate the self-signed CA to provision identities for etcd
  /etcd-server                  Generate the certificate for serving etcd
  /etcd-peer                    Generate the certificate for etcd nodes to communicate with each other
  /etcd-healthcheck-client      Generate the certificate for liveness probes to healthcheck etcd
  /apiserver-etcd-client        Generate the certificate the apiserver uses to access etcd
  /sa                           Generate a private key for signing service account tokens along with its public key
kubeconfig                    Generate all kubeconfig files necessary to establish the control plane and the admin kubeconfig file
  /admin                        Generate a kubeconfig file for the admin to use and for kubeadm itself
  /super-admin                  Generate a kubeconfig file for the super-admin
  /kubelet                      Generate a kubeconfig file for the kubelet to use *only* for cluster bootstrapping purposes
  /controller-manager           Generate a kubeconfig file for the controller manager to use
  /scheduler                    Generate a kubeconfig file for the scheduler to use
etcd                          Generate static Pod manifest file for local etcd
  /local                        Generate the static Pod manifest file for a local, single-node local etcd instance
control-plane                 Generate all static Pod manifest files necessary to establish the control plane
  /apiserver                    Generates the kube-apiserver static Pod manifest
  /controller-manager           Generates the kube-controller-manager static Pod manifest
  /scheduler                    Generates the kube-scheduler static Pod manifest
kubelet-start                 Write kubelet settings and (re)start the kubelet
wait-control-plane            Wait for the control plane to start
upload-config                 Upload the kubeadm and kubelet configuration to a ConfigMap
  /kubeadm                      Upload the kubeadm ClusterConfiguration to a ConfigMap
  /kubelet                      Upload the kubelet component config to a ConfigMap
upload-certs                  Upload certificates to kubeadm-certs
mark-control-plane            Mark a node as a control-plane
bootstrap-token               Generates bootstrap tokens used to join a node to a cluster
kubelet-finalize              Updates settings relevant to the kubelet after TLS bootstrap
  /enable-client-cert-rotation  Enable kubelet client certificate rotation
addon                         Install required addons for passing conformance tests
  /coredns                      Install the CoreDNS addon to a Kubernetes cluster
  /kube-proxy                   Install the kube-proxy addon to a Kubernetes cluster
show-join-command             Show the join command for control-plane and worker nodePreflight: همه پیش نیازها چک می شود.Certs: کار Certificate generation انجام می شود. در این مرحله کوبرنتیز برای خودش یک CA بالا می آورد و هرچقدر که certificate نیاز داشته باشد از CA دریافت می کند. در کلاستر کوبرنتیز همه ارتباطات بین اجزای کلاستر از جمله ارتباط بین kubectl و kubeapi و سایر ارتباطات داخل کلاستر بر پایه certificate انجام می شود یعنی علاوه بر اینکه ارتباط بین اجزا encrypt می شود، Authentication هم با certificate انجام می شود.kubeconfig: فایلهای کانفیگ ایجاد می شود.به عنوان مثال تا ایجای کار kubelet در حالت اجرا نبود و قابلیت اجرا شدن نداشت چون فایل کانفیگی برای آن وجود نداشت. در این مرحله kubelet کانفیگ می شود و آماده اجراست.etcd: در این مرحله static Pod مربوط به etcd کانفیگ می شود.static pod ها، همه پادهایی هستند که برای بوت استرپ کردن و اجرای کلاستر کوبرنتیز نیاز می باشند مانند kubeapi, kubelet, etcd و ... . همانطور که قبلا هم گفته شد، کلاستر کوبرنتیز خود یک میکروسرویس می باشد که همه قسمت های آن در قالب Pod اجرا می شود.control-plane: در این مرحله static Pod های kube-apiserver, kube-controller-manager و kube-scheduler کانفیگ می شوند.kubelet-start: تنظیمات kubelet اعمال شده و start/restart می شود.wait-control-plane: منتظر می ماند تا control plane اجرا شده و stable شود.upload-config: در این مرحله کانفیگ kubeadm و kubelet روی ConfigMap بارگذاری می شود.در کلاستر کوبرنتیز، Pod ها readonly هستند و در طول اجرا ویرایش نمی شوند. بعنوان مثال اگر یک پاد از connection string برای اتصال به پایگاه داده استفاده می کند ما نمی توانیم پاد را ویرایش کنیم و connection string آن را تغییر دهیم و به پایگاه داده جدید متصل کنیم. برای این منظور همه کانفیگ های مورد نیاز Pod ها در فایل ConfigMap نوشته می شوند. و در صورت نیاز، این فایل ConfigMap می باشد که تغییر می کند.upload-certs: همه certificate های kubeadm بارگذاری می شوند.mark-control-plane: نود فعلی بعنوان نود مستر (Control-Plane) تگ گذاری می شود.bootstrap-token: توکن کلاستر کوبرنتیز ایجاد می شود. این توکن برای اتصال سایر نودها به کلاستر کوبرنتیز استفاده می شود.kubelet-finalize: در این مرحله kubelet نهایی می شود.addon: در این مرحله addon های دیگر مانند coredns و kube-proxy نصب می شوند.show-join-command: در مرحله آخر، join-command نمایش داده می شود. cluster token هم داخل این کامند وجود دارد. سایر نودها برای اتصال به کلاستر، تنها کافی است که join-command را اجرا کنند.#How to export/import images into containerd
--------------------------------------
crictl images ls
ctr -n k8s.io images import k8s-v1.35-all.tar
ctr -n k8s.io images export scheduler.tar registry.k8s.io/kube-scheduler:v1.35.0بعد از اجرای موفق دستور kubeadm init پوشه etc/kubernetes ساخته می شود. محتویات این پوشه را در زیر مشاهده می کنید:-rw-------. 1 root root 5637 Feb 25 15:26 admin.conf
-rw-------. 1 root root 5665 Feb 25 15:26 controller-manager.conf
-rw-r--r--. 1 root root   91 Feb 19 04:11 kubelet-systemd.conf
-rw-------. 1 root root 1965 Feb 25 15:28 kubelet.conf
drwxr-xr-x. 2 root root  113 Feb 25 15:26 manifests
drwxr-xr-x. 3 root root 4096 Feb 25 15:26 pki
-rw-------. 1 root root 5609 Feb 25 15:26 scheduler.conf
-rw-------. 1 root root 5661 Feb 25 15:26 super-admin.confدر فایلهای با پسوند conf، همه کانفیگ های مورد نیاز اجزای کلاستر کوبرنتیز از جمله کانفیگ scheduler و kublet و نحوه اتصال آنها به kube api نوشته شده است. توجه داشته باشید همانطور که گفته شد همه ارتباطات کلاستر از طریق kube api صورت می گیرد و ارتباطات با استفاده از certificate هایی که CA تولید می کند، رمز میشوند.حین اجرای دستور kubeadm init فرآیند اجرا بصورت کامل در ترمینال نمایش داده می شود. در صورت اجرای موفقیت آمیز دستور kubeadm init بخش پایانی زیر در ترمینال نمایش داده می شود. این بخش حاوی پیام های مهمی است که با هم آن را بررسی می کنیم.Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run &quot;kubectl apply -f [podnetwork].yaml&quot; with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.65.13:6443 --token 7m53p1.68r7728rdnu9fidg \
        --discovery-token-ca-cert-hash sha256:2d341a0bcbe14f4f366b297ac8bd3f12be21c17883ef5d179f841c15009a57b7
خط 1: Kubernetes control-plane یا همان Master Node با موفقیت راه اندازی شد.خط 3 تا 11: همه اطلاعات مربوط به کاربر ادمین کوبرنتیز در فایل admin.conf قرار گرفته است. این فایل یک فایل مهم است و هر شخصی که این فایل را داشته باشد می تواند بعنوان ادمین کوبرتیز باشد.خط 5 تا 7 می گوید که اگر شما بعنوان ادمین کوبرنتیز هستید، یک پوشه مخفی با نام kube برای خودتان بسازید و فایل admin.conf را به آن کپی کنید و بعدا از این طریق آن را مورد استفاده قرار دهید.در روش جایگزین، خط 11 می گوید که می توانید یک variable با نام KUBECONFIG تعریف کنید و مقدار آن را برابر با مسیر فایل admin.conf قرار دهید. هر کسی که این variable را داشته باشد می تواند به فایل admin.conf دسترسی داشته و بعنوان ادمین کوبرنتیز باشد.با انتخاب و اجرای یکی از دو روش ذکر شده، حالا ما ادمین کلاستر هستیم و می توانیم با اجرای دستورات kubectl، کلاستر کوبرنتیز را مدیریت نماییم.خط 13 تا 15: در بخش بعد توضیح داده خواهد شد.خط 17 تا 20: حالا که کلاستر ما راه اندازی شد با اجرای دستور موجود در خط 19و20 روی یک نود worker می توانیم آن نود را به کلاستر متصل کنیم. به هر تعدادی که بخواهیم می توانیم نود worker به کلاستر کوبرنتیز خود اضافه کنیم.kubeadm join 192.168.65.13:6443 --token 7m53p1.68r7728rdnu9fidg \
        --discovery-token-ca-cert-hash sha256:2d341a0bcbe14f4f366b297ac8bd3f12be21c17883ef5d179f841c15009a57b7توجه داشته باشید که اتصال اولیه worker nodeها به کلاستر توسط توکن انجام می شود. اما بعد از اتصال اولیه، certificate بین آنها و master node ردوبدل می شود و از این پس ارتباط بین آنها با certificate انجام می گیرد.برای مشاهده لیست توکن ها می توانید از دستور زیر استفاده کنید:kubeadm token listاین توکن ها مدت انقضایی در حدود 24 ساعت دارند و بعد از منقضی شدن نمی توان از آنها استفاده کرد.برای تولید توکن جدید می توانید از دستور زیر استفاده کنید:kubeadm token create --print-join-commandپارامتر print-join-command باعث می شود علاوه بر تولید توکن جدید، join-command مربوط به آن هم نمایش داده شود.3. Setup CNICNI: Container Network Interfaceدستور زیر لیست همه Podها را نشان می دهد:kubectl get po -Aبعد از اجرای kubeadm init و راه اندازی کلاستر کوبرنتیز، لیست پادها بصورت زیر می باشند:[root@MASTER-01 kubernetes]# kubectl get po -A
NAMESPACE     NAME                                READY   STATUS    RESTARTS   AGE
kube-system   coredns-7d764666f9-pwjgn            0/1     Pending   0          136m
kube-system   coredns-7d764666f9-qrqvv            0/1     Pending   0          135m
kube-system   etcd-master-01                      1/1     Running   0          137m
kube-system   kube-apiserver-master-01            1/1     Running   0          137m
kube-system   kube-controller-manager-master-01   1/1     Running   0          137m
kube-system   kube-proxy-xp7vx                    1/1     Running   0          136m
kube-system   kube-scheduler-master-01            1/1     Running   0          137metcd, kube-apiserver, kube-controller-manager, kube-proxy و kube-scheduler پادهای سیستمی هستند که روی نود مستر (Control-plane) اجرا می شوند و همانگونه که در ستون READY مشاهده می شود، همه آنها در حال اجرا می باشند. اما پاد coredns که دو نسخه از آن هم موجود می باشد می تواند روی master node یا روی worker node اجرا شود.مانند container runtime، در زمینه Networking هم خود kubernetes، ابزاری را توسعه نداده است. در عوض یک اینترفیس (cni) ایجاد کرده است و هر ابزاری که این اینترفیس را پیاده سازی کند می تواند بعنوان مدیریت کننده شبکه کلاستر استفاده شود. لیستی از این ابزارها در سایت kubernetes در بخش Networking and Network Policy آورده شده است.یکی از ابزارهای معرفی شده در این زمینه Calico می باشد. (برای محیط production بهتر است از Cilium بجای Calico استفاده شود.)راهنمای کامل نصب کالیکو در سایت آن به آدرس زیر وجود دارد:https://docs.tigera.io/calico/latest/getting-started/kubernetes/self-managed-onprem/onpremisesInstall Calico with Kubernetes API datastore, 50 nodes or lessDownload the Calico networking manifest for the Kubernetes API datastore.curl https://raw.githubusercontent.com/projectcalico/calico/v3.31.4/manifests/calico.yaml -OIf you are using pod CIDR 192.168.0.0/16, skip to the next step. If you are using a different pod CIDR with kubeadm, no changes are required — Calico will automatically detect the CIDR based on the running configuration. For other platforms, make sure you uncomment the CALICO_IPV4POOL_CIDR variable in the manifest and set it to the same value as your chosen pod CIDR.Customize the manifest as necessary.Apply the manifest using the following command.kubectl apply -f calico.yamlطبق مستندات نصب کالیکو، ما فایل calico.yaml را دانلود می کنیم و مقدار CALICO_IPV4POOL_CIDR را برابر با مقداری که موقع kubeadm init وارد کرده بودیم قرار می دهیم.# - name: CALICO_IPV4POOL_CIDR
#   value: &quot;192.168.0.0/16&quot;تبدیل می شود به:- name: CALICO_IPV4POOL_CIDR
  value: &quot;10.96.0.0/12&quot;در گام بعدی می توانیم تغییرات دلخواه خود را در فایل calico.yaml بدهیم. به عنوان مثال می توانیم آدرس همه imageها را از مقدار اصلی به آدرس repository خود تغییر دهیم.و در آخر با اجرای دستور زیر این فایل manifest را در کلاستر اعمال می کنیم:kubectl apply -f calico.yamlوقتی این دستور اجرا می شود، kubectl مقدار فایل manifest را تبدیل به json کرده و آن را با فراخوانی REST API به kubeapi می فرستد. kubeapi بعد از دریافت مقدار json آن را در دیتابیس ثبت می کند. سپس اگر نیاز هست پادی بالا بیاید، kubeapi به scheduler دستور بالا آمدن پاد را می دهد. scheduler مجددا از طریق kubeapi دستور میدهد به kubelet.kubelet از طریق containerd اقدام به ساخت image می کند، سپس آن را تبدیل به Pod کرده و تحویل می دهد.حالا مجددا با اجرای دستور kubectl get po -A لیست پادهای موجود در کلاستر را مشاهده می کنیم:[root@MASTER-01 sources]# kubectl get po -A
NAMESPACE     NAME                                     READY   STATUS  
kube-system   calico-kube-controllers-9dff488b-6kbvv   1/1     Running 
kube-system   calico-node-dff24                        1/1     Running
kube-system   calico-node-pbjmj                        1/1     Running
kube-system   coredns-7d764666f9-pwjgn                 1/1     Running 
kube-system   coredns-7d764666f9-qrqvv                 1/1     Running 
kube-system   etcd-master-01                           1/1     Running 
kube-system   kube-apiserver-master-01                 1/1     Running 
kube-system   kube-controller-manager-master-01        1/1     Running 
kube-system   kube-proxy-v6zgz                         1/1     Running 
kube-system   kube-proxy-xp7vx                         1/1     Running 
kube-system   kube-scheduler-master-01                 1/1     Running 
برای مشاهده وضعیت یک پاد می توانیم از دستور زیر استفاده کنیم:kubectl describe po -n kube-system calico-node-dff24پارامتر اول بعد از n- نام namespace و پارامتر بعدی نام پاد می باشد.برای مشاهده وضعیت همه نودهای کلاستر از دستور زیر استفاده می کنیم:kubectl get noبرای مشاهده اینکه هر پادی روی چه نودی اجرا شده، از دستور زیر استفاده می کنیم:kubectl get po -A -o wideمنابع:https://kubernetes.io/docs/concepts/cluster-administration/addons/https://www.tigera.io/tigera-products/calico/https://docs.tigera.io/calico/latest/getting-started/kubernetes/self-managed-onprem/onpremises</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Fri, 27 Feb 2026 12:05:25 +0330</pubDate>
            </item>
                    <item>
                <title>آموزش Kubernetes - قسمت سوم</title>
                <link>https://virgool.io/@farhad.sadeghi/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-kubernetes-%D9%82%D8%B3%D9%85%D8%AA-%D8%B3%D9%88%D9%85-nksz9y3y2bzj</link>
                <description>مراحل نصب Kubernetes1. Install Container RuntimeYou need to install a container runtime into each node in the cluster so that Pods can run there.Kubernetes 1.35 requires that you use a runtime that conforms with the Container Runtime Interface (CRI).Container runtime های عمومی مختلفی قابلیت استفاده در Kubernetes دارند:containerdCRI-ODocker EngineMirantis Container Runtimeتوجه:نسخه‌های Kubernetes قبل از v1.24 شامل یک یکپارچگی مستقیم با Docker Engine بودند، این کار با استفاده از کامپوننتی به نام dockershim انجام می شد. این یکپارچگی مستقیمِ ویژه دیگر بخشی از Kubernetes نیست (حذف آن به‌عنوان بخشی از انتشار نسخه v1.20 اعلام شد).Docker Engine در دل خود از containerd استفاده می کند. به همین خاطر، کوبرنتیز در نسخه های جدید تصمیم گرفت خودش به صورت مستقیم از containerd به عنوان container runtime استفاده کند.1.1 Install and configure prerequisitesBy default, the Linux kernel does not allow IPv4 packets to be routed between interfaces. Most Kubernetes cluster networking implementations will change this setting (if needed), but some might expect the administrator to do it for them.Enable IPv4 packet forwardingTo manually enable IPv4 packet forwarding:# sysctl params required by setup, params persist across reboots
cat &lt;&lt;EOF | sudo tee /etc/sysctl.d/k8s.conf
net.ipv4.ip_forward = 1
EOF

# Apply sysctl params without reboot
sudo sysctl --system
Verify that net.ipv4.ip_forward is set to 1 with:sysctl net.ipv4.ip_forward1.2 Install containerdبرای نصب containerd سه روش وجود دارد:download and install binary filesusing yumcompile from source codeما روش اول یعنی دانلود و نصب فایل binary را در پیش خواهیم گرفت که خود شامل مراحل زیر است:1- download and install containerd and write linux servicetar Cxzvf /usr/local/ containerd-2.2.1-linux-amd64.tar.gz
cp containerd.service /usr/lib/systemd/system/
systemctl daemon-reload
systemctl enable --now containerdخط اول فایل containerd-2.2.1-linux-arm64.tar.gz را extract کرده و محتویات آن را در پوشه usr/local قرار می دهد. چرا که مسیر پوشه usr/local در PATH$ (مسیر فایلهای اجرایی) وجود دارد و با قرار دادن فایلها داخل آن، در واقع فایلهای باینری containerd نصب می شوند.خط دوم فایل containerd.service را در مسیر usr/lib/systemd/system کپی می کند. داخل فایل containerd.service فایل اجرایی containerd بصورت یک سرویس لینوکسی توصیف شده است. وقتی این فایل در پوشه systemd/system کپی می شود، سرویس توصیف شده نصب شده و در لیست سرویس های لینوکس قرار می گیرد.در لینوکس ما وقتی یک برنامه را تبدیل به سرویس می کنیم مانند windows service ها در ویندوز امکان شروع، پایان و یا راه اندازی خودکار آن سرویس وجود دارد و ما می توانیم با کامند systemctl آن را کنترل کنیم.خط سوم لیست سرویس ها را reload می کند تا سرویس containerd که جدیدا نصب شده است، در لیست سرویس ها قرار گیرد.خط چهارم سرویس containerd را auto start می کند.2- download and install runcinstall -m 755 runc.amd64 /usr/local/sbin/runcاین خط فایل run.amd64 را در مسیر usr/local/sbin/runc کپی می کند و دسترسی سطح 755 را هم برای آن تنظیم می کند تا برای کاربر root قابل اجرا باشد.کامند install فایل را کپی می کند و permission های آن را نیز تنظیم می کند. هر جا ما نیاز داشته باشیم این دو کار را باهم انجام دهیم می توانیم از کامند install استفاده کنیم.3- download and install cni-plugin(cni: container network interface)mkdir -p /opt/cni/bin
tar Cxzvf /opt/cni/bin/ cni-plugins-linux-amd64-v1.9.0.tgzخط اول مسیر opt/cni/bin را ایجاد می کند. پارامتر p امکان ایجاد هر پوشه و پوشه های داخل آن را در صورتی که وجود نداشته باشند فراهم می کند. با اجرای این خط پوشه cni داخل پوشه opt ایجاد می شود و پوشه bin نیز داخل پوشه cni ایجاد می شود.خط دوم فایل cni-plugins-linux-amd64-v1.9.0.tgz را در مسیر opt/cni/bin که در خط اول ایجاد شد extract می کند.2. Install Kubeadm, Kubectl, Kubeletkubeadm: the command to bootstrap the cluster.kubectl: the command line util to talk to your cluster.kubelet: the component that runs on all of the machines in your cluster and does things like starting pods and containers.برای راه اندازی کلاستر کوبرنتیز باید kubeadm را نصب کنیم. یعنی اگر ما بخواهیم یک کلاستر کوبرنتیز بالا بیاوریم باید با کامند لاین kubeadm این کار را انجام دهیم.Kubectl (The Kubernetes command-line tool) کامند لاین کوبرنتیز است. یعنی ما command را به آن می دهیم و این پکیج آن را به Kubernetes Api منتقل می کند. این ابزار امکان ارتباط با کلاستر کوبرنتیز و اجرای دستورات روی آن را فراهم می کند. با استفاده از kubectl شما می توانید برنامه ها را deploy کنید، منابع کلاستر کوبرنتیز را بازرسی و مدیریت کنید و لاگ ها را مشاهده نمایید.kubectl روی سیستم عامل های ویندوز، لینوکس و مک قابلیت نصب شدن دارد. من در اینجا نحوه نصب آن روی نود لینوکس را شرح می دهم.2.1 Swap configurationفضای swap بخشی از هارد دیسک است که در صورت نیاز بخشی از RAM می تواند در آن قرار گیرد. مثلا وقتی فضای RAM پر شود سیستم عامل بخشی از آن را روی فضای swap در هارددیسک کپی می کند تا فضای خالی روی RAM برای ادامه کار داشته باشد.نسخه های قدیمی کوبرنتیز برای اینکه performance بهتری داشته باشند از swap پشتیبانی نمی کردند. نسخه های جدید کوبرنتیز هم به شرط تعریف swapBehavior از آن پشتیبانی می کنند. اما همچنان توصیه این است که این قابلیت غیرفعال شود.swapoff -a
topخط اول swap را غیرفعال می کند.با اجرای خط دوم می توانیم وضعیت حافظه swap را مشاهده کنیم.بعد از ریستارت کردن سیستم وضعیت swap دوباره برمی گردد. برای اینکه تغییرات همیشگی باشد باید در فایل fstab خط مربوط به swap کامنت شود.vim /etc/fstab2.2 Set SELinux to permissive modeSELinux (Security-Enhanced Linux) اجازه نمی دهد که هر پورتی به هر پروسسی bind شود. kubernetes با SELinux یکپارچگی ندارد. به همین منظور توصیه می کند آن را غیرفعال کنیم و فقط در صورتی آن را فعال نگه داریم که به نحوه کانفیگ کردن آن تسلط کافی داشته باشیم.These instructions are for Kubernetes 1.35.# Set SELinux in permissive mode (effectively disabling it)
sudo setenforce 0
sudo sed -i &#039;s/^SELINUX=enforcing$/SELINUX=permissive/&#039; /etc/selinux/configsetenforce 1 وضعیت را به Enforcing تغییر می دهد و setenforce 0 وضعیت را به Premissive تغییر می دهد. SELinux در حالت premissive فقط پروسس ها و پورت ها را مانیتور می کند ولی مانع اجرای آنها نمی شود.برای نمایش وضعیت فعلی می توانیم از دستور getenforce استفاده کنیم.2.3 Add the Kubernetes yum repositoryآدرس repository کوبرنتیز https://pkgs.k8s.io/core:/stable:/v1.35/rpm می باشد یعنی همه rpm های کوبرنتیز در این آدرس است. با دستور زیر، این آدرس به لیست ریپوزیتوری ها اضافه می شود. (توجه داشته باشید که این آدرس بخاطر تحریم ها از ایران قابل دسترس نیست)# This overwrites any existing configuration in /etc/yum.repos.d/kubernetes.repo
cat &lt;&lt;EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.35/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.35/rpm/repodata/repomd.xml.key
exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni
EOFبعد از اجرای دستور بالا باید kubernetes.repo به آدرس etc/yum.repos.d اضافه شده باشد.خط شماره دو:cat &lt;&lt;EOF | sudo tee /etc/yum.repos.d/kubernetes.repo🔹 cat &lt;&lt;EOFاین ساختار به آن Here Document می‌گویند.یعنی هر متنی که تا رسیدن به EOF نوشته شود، به عنوان ورودی به دستور cat داده می‌شود.🔹 |خروجی cat را به دستور بعدی می‌فرستد (pipe).🔹 sudo tee /etc/yum.repos.d/kubernetes.repoدستور tee متن دریافتی را داخل فایل مشخص‌شده می‌نویسد.چون مسیر /etc/yum.repos.d/ نیاز به دسترسی روت دارد، از sudo استفاده شده است.📌 نتیجه: یک فایل به نام/etc/yum.repos.d/kubernetes.repoساخته یا بازنویسی می‌شود.بخش دوم: محتوای فایل ریپو[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.35/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.35/rpm/repodata/repomd.xml.key
exclude=kubelet kubeadm kubectl cri-tools kubernetes-cniاین تنظیمات مربوط به مخزن رسمی Kubernetes برای سیستم‌های مبتنی بر yum/dnf (مثل CentOS، Red Hat Enterprise Linux و Fedora) است.2.4 Install Kubeadm, Kubectl, Kubeletبا اجرای دستور زیر kubeadm, kubectl و kubelet از ریپوزیتوری کوبرنیتز دریافت و نصب می شوند.sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetesتوجه داشته باشید که ریپوزیتوری های kubernetes برای کشور ما بسته است. شما می توانید با ویرایش فایل resolve.conf و تنظیم DNS Server شکن این تحریم را دور بزنید.vi /etc/resolv.conf

#change resolv.conf file
nameserver 178.22.122.100
nameserver 185.51.200.2اگر نیاز داشته باشید که پکیج های rpm نصب را دانلود کنید و بعدا بصورت آفلاین روی سرورهای دیگر خود نصب کنید، می توانید با دستور زیر آنها را در مسیر دلخواه خود دانلود کنید:sudo yum install --downloadonly --downloaddir=/mysources/ -y kubelet kubeadm kubectl --disableexcludes=kubernetesپکیج های rpm دانلود شده را با دستور زیر می توان نصب کرد:sudo yum install -y kubeadm-1.35.0-0x86-64.rpm kubectl-1.35.0-0x86-64.rpm3. Configuring cgroup driverدر زمینه مدیریت منابع (Resource management) کانتینرها، دو مفهوم وجود دارد:namespace: اجازه نمی دهد IPها، MountPoint ها، Porccess Id های یکسان داشته باشیم.Cgroup: منابع را از لحاظ CPU، رم و ... مدیریت و محدود می کند.وقتی می گوییم Pod شماره یک باید 2 گیگ رم داشته باشد، این مطلب را هم باید containerd متوجه باشد و هم kubelet. بنابراین هر دوی آنها باید با یک زبان مشترک صحبت بکنند. cgroup driver این کار را انجام می دهد. در واقع هر دوی آنها از یک درایور برای مدیریت منابع استفاده می کنند و آن cgroup driver است.در Kubernetes برای cgroup driver دو گزینه وجود دارد:cgroupfssystemdدر لینوکس systemd اولین سرویسی است که بالا می آید و فرآیند بوت کرنل (init system) و بالا آمدن سرویس های دیگر را systemd انجام می دهد. طبق پیشنهاد Kubernetes، در سیستم هایی که systemd بعنوان init system بکار می رود، توصیه نمی شود از cgroupfs بعنوان cgroup driver استفاده شود و بهتر است بجای آن از systemd cgroup driver استفاده شود.3.1 Configuring containerd&#039;s cgroup driverدر گام اول ما می خواهیم systemd را بعنوان cgroup driver سرویس containerd تنظیم کنیم:#How to change containerd cgroup driver:
--------------------------------------------
mkdir /etc/containerd
containerd config default | tee /etc/containerd/config.toml
vi /etc/containerd/config.toml
#change SystemdCgroup = true
systemctl restart containerdدر خط چهارم یک پوشه برای تنظیمات containerd ساخته می شود.در خط پنجم کانفیگ فعلی (پیش فرض) containerd گرفته شده و در فایل etc/containerd/config.toml نوشته می شود.خط ششم فایل config.toml را باز می کند.در این فایل با مقدار پارامتر SystemCgroup را از false به true تغییر داده و فایل را ذخیره می کنیم.برای اینکه تغییرات در containerd اعمال شود، در خط 8 سرویس containerd را یک بار ریستارت می کنیم.تا اینجای کار systemd بعنوان cgroup برای containerd تنظیم شد.3.2 Configuring kubelet&#039;s cgroup driverدر گام بعد ما می خواهیم systemd را بعنوان cgroup driver سرویس kubelet تنظیم کنیم:#How to change kubelet cgroup driver:
--------------------------------------------
vim /etc/kubernetes/kubelet-systemd.confابتدا فایل kubelet-systemd.conf را در مسیر etc/kubernetes ایجاد می کنیم و سپس محتوای زیر را در آن می نویسیم و ذخیره می کنیم:apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemdحالا باید فایل سرویس kubelet را باز می کنیم و به آن بفهمانیم که از این به بعد فایل کانفیگی که ساختیم را هم لود کن.vim /usr/lib/systemd/system/kubelet.serviceتوجه: برای اینکه بدانیم فایل kubelete.service در چه مسیری قرار دارد می توانیم از دستور زیر استفاده کنیم.systemctl status kubeletدر فایل kubelet.service به انتهای خط ExecStart عبارت زیر را اضافه می کنیم و به این ترتیب سرویس kubelet موقع اجرا شدن، فایل کانفیگی که ما ایجاد کردیم را اعمال می کند.--config /etc/kubernetes/kubelet-systemd.confبه این ترتیب سکشن Service در فایل kubelet.service به شکل زیر خواهد بود:[Service]
ExecStart=/usr/bin/kubelet --config /etc/kubernetes/kubelet-systemd.conf
Restart=always
StartLimitInterval=0
RestartSec=10 در انتها یکبار سرویس kubelet را ریستارت می کنیم.systemctl restart kubeletمنابع:https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/http://kernel.org/https://kubernetes.io/docs/reference/node/kernel-version-requirements/https://kubernetes.io/docs/setup/production-environment/container-runtimeshttps://github.com/containerd/containerd/blob/main/docs/getting-started.md</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Thu, 19 Feb 2026 15:01:23 +0330</pubDate>
            </item>
                    <item>
                <title>آموزش Kubernetes - قسمت دوم</title>
                <link>https://virgool.io/@farhad.sadeghi/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-kubernetes-%D9%82%D8%B3%D9%85%D8%AA-%D8%AF%D9%88%D9%85-cfibq3plqm63</link>
                <description>کلاستر Kubernetes چیست؟برای راه اندازی کلاستر کوبرنتیز در محیط تست به حداقل 3 نود نیاز است؛ یک نود Master و دو نود Worker. ولی در محیط محصول (production environment) بهتر است حداقل 6 نود داشته باشیم که 3 تای آنها بعنوان Master Node و 3 تای آنها بعنوان Worker Node در نظر گرفته می شوند.حداقل منابع مورد نیاز برای هر نود به شرح زیر می باشد:CPU: 2 CoreRAM: 2 GiBHDD: 40 GiBنودهای Master وظیفه مدیریت کلاستر کوبرنتیز را برعهده دارند. نودهای Worker همانطور که از اسمشان پیداست، وظیفه اجرای برنامه های کاربردی را برعهده دارند. برنامه های کاربردی در قالب Pod روی نودهای Worker اجرا می شوند.کوبرنتیز به خودی خود یک میکروسرویس است یعنی خودش از یک سری کامپوننت و سرویس تشکیل شده است که با هم در ارتباط می باشند و با همکاری هم سرویس کوبرنتیز ارائه می شود.کامپوننت های مورد استفاده در هر یک از نودهای master و worker به شرح زیر می باشند:Control Plane Manager (Master Node):• Kube-apiServer• Etcd• Kube-Scheduler• Kube-ControllerWorker Node:• Kube-Proxy• Kubelet• Container Runtimeبرخی از این ابزارها و کامپوننت ها توسط خود Kubernetes پیاده سازی و ایجاد شده اند مانند Kube-Scheduler، Kube-Controller ، Kube-Proxy و Kube-apiServer.اما برخی دیگر از این ها ابزارهای open source می باشند که Kubernetes از آنها استفاده می کند مانند Etcd که یک دیتابیس Key/Value Store می باشد و یا Containerd که یک Container Runtime می باشد و Kubernetes از آن استفاده می کند.ساختار کلاستر کوبرنتیزControl Plane ComponentsManage the overall state of the cluster:kube-apiserverThe core component server that exposes the Kubernetes HTTP API. (port 6443)etcdConsistent and highly-available key value store for all API server data.kube-schedulerLooks for Pods not yet bound to a node, and assigns each Pod to a suitable node.kube-controller-managerRuns controllers to implement Kubernetes API behavior.cloud-controller-manager (optional)Integrates with underlying cloud provider(s).Node ComponentsRun on every node, maintaining running pods and providing the Kubernetes runtime environment:kubeletEnsures that Pods are running, including their containers.kube-proxy (optional)Maintains network rules on nodes to implement Services.Container runtimeSoftware responsible for running containers.🛇 This item links to a third party project or product that is not part of Kubernetes itself.قبلا Kubernetes از Docker بعنوان Container runtime استفاده می کرد، از آنجایی که داکر در دل خود از Containerd استفاده می کند، Kubernetes تصمیم گرفت از Containerd بجای Docker استفاده کند و در نسخه های جدید کوبرنتیز از Containerd بعنوان Container runtime استفاده می شود.Your cluster may require additional software on each node; for example, you might also run systemd on a Linux node to supervise local components.AddonsAddons extend the functionality of Kubernetes. A few important examples include:DNSFor cluster-wide DNS resolution.Web UI (Dashboard)For cluster management via a web interface.Container Resource MonitoringFor collecting and storing container metrics.Cluster-level LoggingFor saving container logs to a central log store.در پست بعدی، نحوه نصب و راه اندازی کلاستر کوبرنتیز را آموزش خواهیم داد.</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Fri, 06 Feb 2026 16:26:37 +0330</pubDate>
            </item>
                    <item>
                <title>آموزش Kubernetes - قسمت اول</title>
                <link>https://virgool.io/@farhad.sadeghi/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-kubernetes-%D9%82%D8%B3%D9%85%D8%AA-%D8%A7%D9%88%D9%84-uskkwfhoxm8o</link>
                <description>راه اندازی kubernetes در محیط تست لوکالSetting up local Kubernetes environmentsRunning Kubernetes locally gives you a safe environment to learn and experiment. You can set up and tear down clusters without worrying about costs or affecting production systems.kindkind (Kubernetes IN Docker) runs Kubernetes clusters using Docker containers as nodes. It is lightweight and designed specifically for testing Kubernetes itself, but works great for learning too.minikubeminikube runs a single-node Kubernetes cluster on your local machine. It supports multiple container runtimes and works on Linux, macOS, and Windows.Other local options🛇 This item links to a third party project or product that is not part of Kubernetes itself.There are several third-party tools that can also run Kubernetes locally. Kubernetes does not provide support for these tools, but they may work well for your learning needs:Docker Desktop can run a local Kubernetes clusterPodman Desktop can run a local Kubernetes clusterRancher Desktop provides Kubernetes on your desktopMicroK8s runs a lightweight Kubernetes clusterRed Hat CodeReady Containers (CRC) runs a minimal OpenShift cluster locally (OpenShift is Kubernetes-conformant)Refer to each tool&#039;s documentation for setup instructions and support.Using online playgrounds🛇 This item links to a third party project or product that is not part of Kubernetes itself.Online Kubernetes playgrounds let you try Kubernetes without installing anything on your computer. These environments run in your web browser:Killercoda provides interactive Kubernetes scenarios and a playground environmentPlay with Kubernetes gives you a temporary Kubernetes cluster in your browserThese platforms are useful for quick experiments and following tutorials without local setup.</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Fri, 06 Feb 2026 16:00:54 +0330</pubDate>
            </item>
                    <item>
                <title>Clean Architecture</title>
                <link>https://virgool.io/@farhad.sadeghi/clean-architecture-m7fd0ucxgwnk</link>
                <description>Core (Domain Model) ProjectIn Clean Architecture, the central focus should be on Entities and business rules.In Domain-Driven Design, this is the Domain Model.This project should contain all of your Entities, Value Objects, and business logic.Entities that are related and should change together should be grouped into an Aggregate.Entities should leverage encapsulation and should minimize public setters.Entities can leverage Domain Events to communicate changes to other parts of the system.Entities can define Specifications that can be used to query for them.For mutable access, Entities should be accessed through a Repository interface.Read-only ad hoc queries can use separate Query Services that don&#039;t use the Domain Model.Use Cases (Application Services) ProjectIn Clean Architecture, the Use Cases (or Application Services) project is a relatively thin layer that wraps the domain model.Use Cases are typically organized by feature. These may be simple CRUD operations or much more complex activities.Use Cases should not depend directly on infrastructure concerns, making them simple to unit test in most cases.Use Cases are often grouped into Commands and Queries, following CQRS.Having Use Cases as a separate project can reduce the amount of logic in UI and Infrastructure projects.For simpler projects, the Use Cases project can be omitted, and its behavior moved into the UI project, either as separate services or MediatR handlers, or by simply putting the logic into the API endpoints.Infrastructure ProjectIn Clean Architecture, Infrastructure concerns are kept separate from the core business rules (or domain model in DDD).The only project that should have code concerned with EF, Files, Email, Web Services, Azure/AWS/GCP, etc is Infrastructure.Infrastructure should depend on Core (and, optionally, Use Cases) where abstractions (interfaces) exist.Infrastructure classes implement interfaces found in the Core (Use Cases) project(s).These implementations are wired up at startup using DI. In this case using Microsoft.Extensions.DependencyInjection and extension methods defined in each project.Resources and Samples:https://github.com/mimohammadi/CleanArchitectureTempByMinaMohammadihttps://github.com/ardalis/CleanArchitecturehttps://github.com/jasontaylordev/CleanArchitecturehttps://vrgl.ir/woLc2https://vrgl.ir/g2AKj</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Wed, 04 Feb 2026 13:49:56 +0330</pubDate>
            </item>
                    <item>
                <title>پیام‌های ناموفق و Retry در RabbitMQ</title>
                <link>https://virgool.io/@farhad.sadeghi/%D9%BE%DB%8C%D8%A7%D9%85-%D9%87%D8%A7%DB%8C-%D9%86%D8%A7%D9%85%D9%88%D9%81%D9%82-%D9%88-retry-%D8%AF%D8%B1-rabbitmq-lyftskoj7ucy</link>
                <description>✅ مشاهده پیام‌های ناموفق در RabbitMQ❌ واقعیت مهمRabbitMQ به‌صورت پیش‌فرض جایی برای دیدن پیام‌های ناموفق نداره.اگر پیام fail بشه و درست هندل نشه، ممکنه برای همیشه حذف بشه.✔ راه‌حل استاندارد: Dead Letter Queue (DLQ)پیام چه زمانی می‌ره DLQ؟reject یا nack با requeue=falseاتمام TTLپر شدن صف (max-length)🔧 تنظیم DLQ روی صف اصلیx-dead-letter-exchange: my.dlx
x-dead-letter-routing-key: dead🔍 چطور پیام‌های ناموفق رو ببینیم؟فعال بودن RabbitMQ Management Pluginرفتن به UI → Queuesباز کردن DLQدکمه Get Messages📌 مناسب دیباگ و بررسی، نه مصرف دائمی📎 اطلاعات مهم داخل پیام DLQدر headerها:x-death.reason (علت fail)x-death.count (چند بار fail شده)x-death.exchangex-death.queueاگر DLQ درست مدیریت نشه، می‌تونه حافظه یا دیسک سرور RabbitMQ رو پر کنه و باعث down شدن سرور بشه.ولی خبر خوب اینه که با چند تا تنظیم ساده، این ریسک تقریباً صفر می‌شه 👇چرا DLQ خطرناک می‌شه؟DLQ دقیقاً مثل هر صف دیگه‌ایه. اگر:پیام‌ها دائماً fail بشنمصرف‌کننده‌ای برای DLQ نداشته باشییا limit نذاریاون صف بی‌نهایت رشد می‌کنه.نتیجه:اگر پیام‌ها transient باشن → RAM پر می‌شهاگر persistent باشن → Disk پر می‌شهRabbitMQ وقتی به limit برسه:شروع به block کردن publisher می‌کنهیا بدتر: کل node از دسترس خارج می‌شه ❌چطور DLQ رو امن کنیم؟ (Best Practices)1️⃣ حتماً برای DLQ محدودیت بذار (خیلی مهم)x-max-length: 10000
x-overflow: drop-headیا بر اساس حجم:x-max-length-bytes: 100MB📌 این باعث می‌شه پیام‌های خیلی قدیمی حذف بشن.2️⃣ روی DLQ هم TTL بذارx-message-ttl: 604800000مثلاً بعد از ۷ روز خودکار پاک بشن.3️⃣ پیام‌های DLQ رو persistent نکن (در صورت امکان)اگر فقط برای debug هست:delivery_mode = 1  // transient4️⃣ حتماً alarm های RabbitMQ رو مانیتور کنRabbitMQ وقتی منابع کم می‌شن alarm می‌زنه:memory_alarmdisk_alarmو publisher رو block می‌کنه.حتماً این‌ها رو مانیتور کن:rabbitmqctl statusیا در UI:Overview → Node details🔁 Retry در RabbitMQ (به روش درست)DLQ برای retry نیست ❌اشتباه رایج:«بیایم پیام‌های DLQ رو دوباره publish کنیم»❌ روش اشتباهnack + requeue=trueاین کار باعث loop و انفجار پیام می‌شه 💣برای retry درست از:Retry QueueDelayed Exchangeیا backoff strategyاستفاده کن.الگوی امن پیشنهادیMain Queue
   ↓ fail
Retry Queue (TTL + DLX)
   ↓ expire
Main Queue
   ↓ fail after N tries
DLQ (TTL + max-length)🔧 Retry Queuex-message-ttl: 30000
x-dead-letter-exchange: main.exchange📌 پیام بعد از ۳۰ ثانیه دوباره به صف اصلی برمی‌گرده🔢 محدود کردن retryبا header مثل x-retry-countیا x-death.countمنطق:retry &lt; N → retry
retry ≥ N → DLQ⏳ Backoff (خیلی مهم)چند retry queue با TTL مختلف:retry 5sretry 30sretry 2m🧠 چه پیام‌هایی retry بشن؟✅ retrytimeoutnetwork errorservice unavailable❌ چه پیام هایی مستقیم به DLQ می روند؟validation errorbusiness rule failmessage خراب🔐 نکته حیاتی: IdempotencyRetry = احتمال پیام تکراریconsumer باید:idempotent باشهیا deduplication داشته باشه</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Mon, 05 Jan 2026 19:45:06 +0330</pubDate>
            </item>
                    <item>
                <title>طراحی UI و UX (رابط کاربری و تجربه کاربری)</title>
                <link>https://virgool.io/@farhad.sadeghi/%D8%AA%D9%81%D8%A7%D9%88%D8%AA-ui-%D9%88-ux-%D8%B1%D8%A7%D8%A8%D8%B7-%DA%A9%D8%A7%D8%B1%D8%A8%D8%B1%DB%8C-%D9%88-%D8%AA%D8%AC%D8%B1%D8%A8%D9%87-%DA%A9%D8%A7%D8%B1%D8%A8%D8%B1%DB%8C-rsftegurce1o</link>
                <description>طراحی UI/UX به معنای طراحی رابط کاربری و تجربه کاربری است و هدف آن ایجاد محصولاتی است که هم از نظر بصری جذاب و هم از نظر تعامل کاربر دلپذیر باشند.تفاوت بین طراحی UI و UXتفاوت UI و UXاگر توی وب UI vs UX رو جستجو کنین یکی از مثال‌های اصلی که زیاد باهاش روبرو می‌شوید همین مثال سس HEINZ هست که می‌گه سمت چپیه ظاهر زیبایی داره و به UI اشاره داره اما سمت راستیه علاوه بر ظاهر زیبا، چون برعکس طراحی شده همیشه مایه سس در پایین ظرف و نزدیک درب خروجیه و در نتیجه راحت‌تر سس میاد بیرون و خوب کاربردی‌تره و تجربه بهتری منتقل می‌کنه.رابط کاربری (UI) و تجربه کاربری (UX) دو رشته جداگانه هستند که بر جنبه‌های مختلف تعامل کاربر تمرکز دارند.این دو رشته در بسیاری از جنبه‌ها همپوشانی دارند و به یکدیگر کمک می‌کنند.از آنجایی که صحبت ما در رابطه با طراحی UI/UX هست، بررسی آماری در این زمینه از کشور هند خالی از لطف نیست.رشد کسب‌وکارهای آنلاین در هند (2021-2022)هند در رتبه 20 از 100 کشور برتر در شاخص اکوسیستم استارتاپ جهانی قرار دارد.بیش از 1 میلیون شغل در طراحی UX در سراسر این کشور وجود دارد.81 شرکت هندی در سال 2021 به لیست استارتاپ‌های یونیکورن پیوستند.فهرستی از استارتاپ‌های سرمایه‌گذاری‌کننده در UI/UXUNIQLOYUJ DesignsCLARITIZ INNOVATIONSpread Design and Innovation Pvt Ltd17Sevenبرندهای هندی با رابط کاربری جالب و آسانNYKAAHUNGERBOXCAREER ANNACULT.FITTopprچه کسی می‌تواند طراح تجربه کاربری شود؟هر کسی که حساسیت به رفتار مصرف‌کننده داشته باشد و از ساده‌سازی طراحی لذت ببرد.طراحان و کارآفرینانی که می‌خواهند هویت آنلاین خود را بسازند.مهارت‌های مورد نیاز برای طراح UI و UXتفکر خلاق و حس طراحیدانش زبان طراحی بصریتوانایی رهبری و هماهنگی در توسعه محصولاگر بخواهیم از مدل بهتری استفاده کنیم باید بگیم که UI بخشی از UX محسوب می‌شه و در حقیقت تصمیم، انتخاب و دانشی در UI نیست که رد اون رو نشه در UX پیدا کرد.حتی موضوعاتی مثل انتخاب فونت، رنگ، انتخاب تصاویر و ابعاد و سایه‌ها هم که هر چند در نگاه اول مربوط به UI می‌شن اما می‌تونند بنا به دلایل UXی مجبور به تغییر بشند.خوبه که بدونید UX خودش زیر مجموعه Customer experience و Brand experience محسوب می‌شه.اگر دوست دارید بیشتر در رابطه با تفاوت این مفاهیم بدانید، مقاله زیر را مطالعه کنید:تفاوت UI و UX و CX در چیست؟مراحل طراحی از ایده تا طرح نهاییتحلیل نیازها و جریان کاریابتدا طی جلسه‌ای با حضور افراد تیم و مدیر پروژه، نیازها و جریان کاری کاربر برای استفاده از برنامه تعیین شده و در یک واسط که در شکل زیر به ابتدایی ترین شکل کشیده شده است سعی می شود که مفاهیم و خواسته‌ها را شرح دهیم.شرح نیاز واسط کاربری و جریان تعامل کاربر با برنامهقبل از طراحی: User Flow ترسیم کنیددر ابتدا باید تصویر درستی از صفحات مختلف نرم افزار و نحوه ی تعامل کاربر با آن ها داشته باشید. اگر این اصل را رعایت کنید، طراحی وایرفریم بسیار آسان تر خواهد بود.بطور خلاصه، User Flow مجموعه مراحلی است که کاربر برای رسیدن به یک هدف خاص، طی می‌کند. در حقیقت، &quot;هدف خاص کاربر&quot; در اینجا نقش اساسی دارد؛ چرا که هر کاربر برای رسیدن به یک هدف ممکن است راه های مختلفی را امتحان کند و همین امر باعث می شود تا User Flow همواره یک مسیر خطی تلقی نشود. User Flow، به شما کمک می‌کند تا بدانید چه تعداد وایرفریم باید طراحی کنید و آن ها چگونه باید به یکدیگر متصل شوند؟برای ترسیم User Flow می توانید از شکل های ابتدایی مانند جعبه های مستطیل شکل و فلش استفاده کنید. قلم و کاغذ یا ابزار دیجیتالی فرقی نمی‌کند. در ادامه نوعی از User Flow طراحی شده در نرم افزار بالزامیک را می بینیم:User Flow فرآیند تحویل غذااسکچ زدن رابط کاربریحال با درنظر داشتن اصول گفته شده، یک رابط کاربری برای تعامل با سیستم به عنوان یک مطالعه موردی انجام می دهیم. ممکن است در ابتدا طرح اولیه روی کاغذ زده شده (Sketch) و با گرفتن بازخورد از هم تیم ها و مدیر پروژه اشکالاتی که دارد برطرف شود.اسکچ رابط کاربری برنامه با کاغذ و مدادطراحی وایرفریمدر مرحله طراحی واسط کاربری ابتدا بازخوردها و ایده‌های قبلی که روی کاغذ آورده بودیم را می کشیم تا نقشه راه مان در مراحل بعد باشد. در شکل زیر به ردیف اول (اشکال هندسی توخالی) وایرفریم low-fidelity یا سطح پایین نیز گفته می‌شود.ایجاد پروتوتایپ در ردیف دوم با استفاده از راهنمای طراحی متریال گوگل اقدام به کامل‌تر نمودن پروتوتایپ ها می کنیم که با استفاده از پلت رنگی بنفش که بالای آرت برد ها آورده شده است. با تکیه بر سادگی، زیبایی و در عین حال کاربردپذیری واسط کاربری طراحی ها انجام شده اند.نمایی از برنامه AdobeXD حین طراحی پروتوتایپ های برنامهبرای مطالعه دقیقتر مراحل طراحی نرم افزار و وایرفریم می توانید به مقاله زیر مراجعه کنید:طراحی وایرفریم برای اپ موبایلسیستم های طراحی نرم افزار (Design Systems)سیستم‌های طراحی در نرم‌افزار (Design Systems) به مجموعه‌ای از اصول، الگوها و ابزارها اشاره دارند که به توسعه‌دهندگان و طراحان کمک می‌کنند تا رابط‌های کاربری و تجربه کاربری (UX) بهتری ایجاد کنند. این سیستم‌ها معمولاً شامل اجزای زیر هستند:کتابخانه‌های کامپوننت: مجموعه‌ای از عناصر طراحی مانند دکمه‌ها، فرم‌ها، نوار جستجو و غیره که می‌توانند به راحتی در پروژه‌های مختلف استفاده شوند.راهنماهای طراحی: مستنداتی که اصول طراحی، رنگ‌ها، فونت‌ها و نحوه استفاده از کامپوننت‌ها را توضیح می‌دهند. این راهنماها به حفظ یکپارچگی طراحی در تمام پروژه‌ها کمک می‌کنند.الگوهای طراحی: راه‌حل‌های از پیش تعریف‌شده برای مشکلات رایج در طراحی و توسعه نرم‌افزار. این الگوها می‌توانند شامل الگوهای ناوبری، الگوهای فرم و غیره باشند.ابزارهای طراحی: نرم‌افزارهایی که به طراحان کمک می‌کنند تا طراحی‌های خود را ایجاد و ویرایش کنند. این ابزارها می‌توانند شامل نرم‌افزارهای گرافیکی، پروتوتایپ‌سازی و همکاری باشند.سیستم‌های طراحی ریسپانسیو: طراحی‌هایی که به طور خودکار به اندازه‌های مختلف صفحه نمایش و دستگاه‌ها پاسخ می‌دهند و تجربه کاربری بهتری را فراهم می‌کنند.استفاده از سیستم‌های طراحی می‌تواند به افزایش کارایی، کاهش زمان توسعه و بهبود تجربه کاربری کمک کند. از جمله سیستم‌های طراحی معروف می‌توان به موارد زیر اشاره کرد:Material Design: طراحی شده توسط گوگل، این سیستم بر اساس اصول طراحی متریال و تجربه کاربری مدرن است.Bootstrap: یک فریم‌ورک طراحی وب که شامل مجموعه‌ای از کامپوننت‌ها و الگوهای طراحی برای ایجاد وب‌سایت‌های ریسپانسیو است.Ant Design: یک سیستم طراحی برای برنامه‌های وب و موبایل که توسط علی‌بابا توسعه یافته و بر روی طراحی کاربرپسند تمرکز دارد.Foundation: یک فریم‌ورک طراحی وب که به توسعه‌دهندگان کمک می‌کند تا وب‌سایت‌های ریسپانسیو و قابل دسترس بسازند.Carbon Design System: سیستم طراحی IBM که برای ایجاد تجربه‌های کاربری یکپارچه و مدرن در محصولات و خدمات این شرکت طراحی شده است.Fluent Design System: طراحی شده توسط مایکروسافت، این سیستم بر روی ایجاد تجربه‌های کاربری زیبا و کاربرپسند در محصولات مایکروسافت تمرکز دارد.Salesforce Lightning Design System: یک سیستم طراحی برای ایجاد رابط‌های کاربری در پلتفرم Salesforce که شامل کامپوننت‌ها و الگوهای طراحی است.Atlassian Design Guidelines: سیستم طراحی Atlassian که برای محصولات این شرکت مانند Jira و Confluence طراحی شده است.Grommet: یک فریم‌ورک طراحی برای React که بر روی ایجاد رابط‌های کاربری ریسپانسیو و قابل دسترس تمرکز دارد.Shopify Polaris: سیستم طراحی Shopify که برای ایجاد تجربه‌های کاربری یکپارچه در پلتفرم تجارت الکترونیک این شرکت طراحی شده است.چی یاد بگیریم؟داستان سرایی برای یوزر استوری و استوری برداصول تئوری طراحی کاربر محور(User Centered Design)اصول تئوری طراحی تجربه کاربری(User Experience Design)طراحی(Wireframe)استفاده از ابزارهای طراحی مثل:FigmaSketch Adobe XDBalsamiqInVision StudioAdob Creative Suiteاصول کاربردپذیری(usability)prototypingGoogle analytics</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Sat, 01 Mar 2025 14:49:20 +0330</pubDate>
            </item>
                    <item>
                <title>آموزش سریع Regex یا Regular Expression</title>
                <link>https://virgool.io/@farhad.sadeghi/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-%D8%B3%D8%B1%DB%8C%D8%B9-regex-%DB%8C%D8%A7-regular-expression-ckjlfzhucle6</link>
                <description>در دنیای برنامه نویسی و نرم افزار، Regex از جمله ابزارهایی است که هر برنامه نویسی دیر یا زود با آن روبرو میشود و باید استفاده از آن را یاد بگیرد. عبارات باقاعده یا Regular Expression ها یا بصورت خلاصه شده Regexها ابزارهایی قدرتمند برای تطابق الگو و جستجو در رشته ها هستند.عبارات باقاعده می توانند برای کارهایی مانند اعتبار سنجی ورودی ها (input validating)، جستجو به دنبال الگوهای مشخص و یا دستکاری کردن رشته های متنی استفاده شوند.در زیر آموزش و راهنمای پایه ای از regex بیان شده است تا به شما کمک کند آن را فرا بگیرید.1. Basic SyntaxLiterals: Characters that match themselves. For example, a matches the character &quot;a&quot;.Metacharacters: Special characters that have specific meanings:.: Matches any single character except newline.^: Asserts the start of a string.$: Asserts the end of a string.*: Matches 0 or more occurrences of the preceding element.+: Matches 1 or more occurrences of the preceding element.?: Matches 0 or 1 occurrence of the preceding element (makes it optional).\: Escapes a metacharacter to treat it as a literal.2. Character ClassesBasic Classes:\d: Matches any digit (equivalent to [0-9]).\D: Matches any non-digit character.\w: Matches any word character (alphanumeric + underscore, equivalent to [a-zA-Z0-9_]).\W: Matches any non-word character.\s: Matches any whitespace character (spaces, tabs, line breaks).\S: Matches any non-whitespace character.Custom Classes: You can define your own character classes using square brackets:[abc]: Matches either &quot;a&quot;, &quot;b&quot;, or &quot;c&quot;.[a-z]: Matches any lowercase letter.[0-9]: Matches any digit.3. QuantifiersQuantifiers specify how many times an element can occur:{n}: Exactly n occurrences.{n,}: At least n occurrences.{n,m}: Between n and m occurrences.4. Groups and RangesGrouping: Use parentheses () to group parts of a regex. This allows you to apply quantifiers to the entire group. Example: (abc)+ matches &quot;abc&quot;, &quot;abcabc&quot;, etc.Alternation: Use the pipe | to specify alternatives. Example: cat|dog matches either &quot;cat&quot; or &quot;dog&quot;.5. AnchorsStart and End: Use ^ to assert the start of a string and $ to assert the end. Example: ^Hello matches &quot;Hello&quot; at the start of a string.مثال:در اینجا چند نمونه عملی از الگوهای regex آورده شده است:Email Validation:^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$Phone Number (US):^\(\d{3}\) \d{3}-\d{4}$Date (YYYY-MM-DD):^\d{4}-\d{2}-\d{2}$Lookaroundبررسی اطراف (Lookaround) در عبارات باقاعده (Regex) ابزاری است برای بررسی وجود یا عدم وجود یک الگو قبل یا بعد از موقعیت فعلی، بدون اینکه آن بخش از متن در نتیجه نهایی گنجانده شود. این ابزارها به دو دسته اصلی تقسیم میشوند:Lookahead (بررسی جلو)Lookbehind (بررسی عقب)هر کدام از این دسته ها به دو نوع مثبت (Positive) و منفی (Negative) تقسیم میشوند.1. Positive Lookahead (?=...)هدف: بررسی میکند که بعد از موقعیت فعلی، الگوی مشخصی وجود داشته باشد.مثال:فرض کنید میخواهیم کلمه cat را فقط زمانی پیدا کنیم که بعد از آن کلمه fish بیاید:cat(?= fish)تست:I have a cat fish → cat is foundI have a cat dog → cat can not be found2. Negative Lookahead (?!...)هدف: بررسی میکند که بعد از موقعیت فعلی، الگوی مشخصی وجود نداشته باشد.مثال:کلمه cat را پیدا کنید که بعد از آن کلمه dog نیاید:cat(?! dog)تست:I have a cat fish → cat is foundI have a cat dog → cat can not be found3. Positive Lookbehind (?&lt;=...)هدف: بررسی میکند که قبل از موقعیت فعلی، الگوی مشخصی وجود داشته باشد.مثال:اعدادی را پیدا کنید که قبل از آن علامت $ باشد:(?&lt;=\$)\d+تست:Price: $100 → 100 is foundPrice: €100 → 100 can not be found4. Negative Lookbehind (?&lt;!...)هدف: بررسی میکند که قبل از موقعیت فعلی، الگوی مشخصی وجود نداشته باشد.مثال:اعدادی را پیدا کنید که قبل از آن علامت $ نباشد:(?&lt;!\$)\d+تست:Price: €100 → 100 is foundPrice: $100 → 100 is not be foundمثال کاربردی ترکیبی (رمز عبور):فرض کنید میخواهیم رمز عبوری را اعتبارسنجی کنیم که:حداقل یک حرف بزرگ ([A-Z]) داشته باشد.حداقل یک عدد (\d) داشته باشد.حداقل ۸ کاراکتر طول داشته باشد.^(?=.*[A-Z])(?=.*\d).{8,}$توضیح:(?=.*[A-Z]) وجود حرف بزرگ در هر جای رشته.(?=.*\d) وجود عدد در هر جای رشته.. هر کاراکتری.{8,} حداقل ۸ کاراکتر.نکات مهم:بررسی اطراف (Lookaround) کاراکترها را مصرف نمیکند (Zero-width assertions).در Lookbehindها، الگو باید طول ثابتی داشته باشد (در برخی موتورهای Regex).برای ترکیب چند شرط، از چند Lookaround پشت سر هم استفاده کنید.Modifiersدر عبارات منظم &quot;modifier&quot; ها (یا &quot;flag&quot;ها) به شما این امکان را می‌دهند که رفتار جستجو را تغییر دهید. این modifier ها می‌توانند به شما کمک کنند تا جستجوهای خود را دقیق‌تر و کارآمدتر انجام دهید. در زیر به برخی از مهم‌ترین modifiers در regex اشاره می‌کنم:i (case insensitive) این modifier باعث می‌شود که جستجو به صورت غیر حساس به حروف بزرگ و کوچک انجام شود. به عنوان مثال می‌تواند abc، Abc، aBc و غیره را پیدا کند.m (multiline) با استفاده از این modifier، علامت ^ و $ به ابتدای هر خط و انتهای هر خط در یک متن چند خطی اشاره می‌کنند. به طور پیش‌فرض، این علامت‌ها فقط به ابتدا و انتهای کل متن اشاره دارند.s (dotall) این modifier باعث می‌شود که علامت . بتواند شامل کاراکترهای جدید (newline) نیز باشد. به طور پیش‌فرض، . فقط کاراکترهای غیر از newline را شامل می‌شود.x (extended) این modifier به شما این امکان را می‌دهد که از فضاهای خالی و کامنت‌ها در عبارات منظم استفاده کنید. با استفاده از این modifier، می‌توانید عبارات خود را خواناتر کنید.u (unicode) این modifier به شما این امکان را می‌دهد که از کاراکترهای یونیکد در عبارات منظم استفاده کنید.g (global)این modifier در برخی زبان‌ها (مانند JavaScript) به شما این امکان را می‌دهد که تمام تطابق‌ها را در یک متن پیدا کنید، نه فقط اولین تطابق را. (do not return after first match)مثال‌ها:برای جستجوی کلمه hello به صورت غیر حساس به حروف بزرگ و کوچک:(?i)helloبرای جستجوی یک الگو در یک متن چند خطی:(?m)^start.*end$برای جستجوی یک الگو که شامل newline باشد:(?s)hello.worldبا استفاده modifierها، می‌توانید عبارات منظم خود را به گونه‌ای تنظیم کنید که به نیازهای خاص شما پاسخ دهند.ابزارهای تمرین و تست Regexبرای انجام تمرین و تست از ابزارهای آنلاین زیر می توانید استفاده کنید:Regex101RegExrاین ابزارها الگوهای regex شما را توضیح می دهند و به شما امکان تست کردن الگوهای خود در مقابل ورودی ها (رشته های) ساده را فراهم می کنند.بهترین راه برای یادگیری regex تمرین کردن است. سعی کنید برای سناریوهای مختلف از جمله اعتبارسنجی نام کاربری، رمز عبور یا فرمت های خاص ورودی regex ایجاد نمایید.عبارات منظم می توانند پیچیده باشند اما با تمرین شما می توانید در استفاده از آنها خبره و مسلط باشید. از الگوهای ساده شروع کنید و به تدریج به سمت الگوهای پیچیده بروید.</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Mon, 24 Feb 2025 14:54:38 +0330</pubDate>
            </item>
                    <item>
                <title>نقش‌های کلیدی در یک تیم توسعه نرم‌افزار کدامند؟</title>
                <link>https://virgool.io/@farhad.sadeghi/%D9%86%D9%82%D8%B4-%D9%87%D8%A7%DB%8C-%DA%A9%D9%84%DB%8C%D8%AF%DB%8C-%D8%AF%D8%B1-%DB%8C%DA%A9-%D8%AA%DB%8C%D9%85-%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D9%86%D8%B1%D9%85-%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-%DA%A9%D8%AF%D8%A7%D9%85%D9%86%D8%AF-k3aiizq0dahh</link>
                <description>مالک محصول (PO)Product Ownerمدیر پروژه (PM)Project managerتحلیل‌گر کسب و کار (BA)Business Analystتحلیل‌گر سیستم (SA)System Analystطراح UI/UX یا طراح نرم‌افزار (SD)کشف ایده (اثبات مفهوم برنامه با ایجاد صفحه نمایش برنامه)نمونه‌سازی یا پروتوتایپینگتست ایده هویت برند (طراحی لوگو و سایر عناصر بصری)رابط کاربری و تجربه کاربریمهندس نرم‌افزار (SE)مهندسان فرانت‌اندمهندسان بک‌اندمهندسان موبایلمهندسان پایگاه دادهمعمار نرم‌افزار (SA) (Software Architect)معمار نرم‌افزار ماهرترین مهندس تیم است. بر خلاف سایر متخصصان نرم‌افزار، معمار نرم‌افزار نه تنها کدنویسی کرده و روی توسعه اپلیکیشن کار می‌کند، بلکه به مدیریت پروژه و تجزیه و تحلیل سیستم کمک می‌کند و ارتباط اساسی بین جنبه‌های کسب و کار و فنی تیم را فراهم می‌سازد.مهندس تست یا مهندس تضمین کیفیت (TE یا QA)Software Test EngineerSoftware Quality Assurance</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Thu, 06 Feb 2025 16:43:06 +0330</pubDate>
            </item>
            </channel>
</rss>