<?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-06-16 07:12:52</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 - قسمت هشتم (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>
                    <item>
                <title>در C# چطور کنترلر WebAPI پس از برگرداندن جواب به کلاینت، به پردازش ادامه دهد</title>
                <link>https://virgool.io/@farhad.sadeghi/%D8%AF%D8%B1-c-%DA%86%D8%B7%D9%88%D8%B1-%DA%A9%D9%86%D8%AA%D8%B1%D9%84%D8%B1-webapi-%D9%BE%D8%B3-%D8%A7%D8%B2-%D8%A8%D8%B1%DA%AF%D8%B1%D8%AF%D8%A7%D9%86%D8%AF%D9%86-%D8%AC%D9%88%D8%A7%D8%A8-%D8%A8%D9%87-%DA%A9%D9%84%D8%A7%DB%8C%D9%86%D8%AA%D8%AA-%D8%A8%D9%87-%D9%BE%D8%B1%D8%AF%D8%A7%D8%B2%D8%B4-%D8%A7%D8%AF%D8%A7%D9%85%D9%87-%D8%AF%D9%87%D8%AF-hrbijoh1vvx3</link>
                <description>آیا در C# تا به حال به یک راه حل &quot;fire and forget&quot; نیاز داشته اید که در آن مشتری یک کنترلر  WebAPI را فراخوانی کند که کاری طولانی مدت انجام می دهد، اما واقعاً نتیجه فراخوانی اهمیتی برای مشتری ندارد؟به عنوان مثال، فرض کنید یک job زمانبندی شده دارید که یک سری وظایف را اجرا می کند و یکی از آنها فراخوانی یک WebAPI برای ایجاد چیزی شبیه انتقال داده از جدول SQL Server به یک فایل است.مشکلجدول بزرگ است و انتقال آن، job زمانبندی شده را از اجرای بقیه وظایف در فرآیند باز می‌دارد، یا فرآیند زمان‌بندی  را متوقف می‌کند یا با خطای Timeout مواجه می شود. در حالی که نتیجه وب سرویس هیچ اهمیتی در نتیجه نهایی فرآیند ندارد، زیرا WebAPI، خطاها را به روش دیگری مانند ایمیل گزارش می دهد.راه حلباید WebAPI یک کد HttpStatus مانند 200 OK در جواب ارسال کند و بگوید که درخواست مشتری به دست من رسید و فرآیند درخواست کامل شده است، در حالی که همچنان به کار روی درخواست در پس‌زمینه ادامه می‌دهد.برای افزودن قابلیت fire and forget، در کنترلر WebAPI خود، این کار را انجام دهید:public async Task&lt;IActionResult&gt; Post(string id)
{
    try
    {
        return Ok(&#039;Request submitted successfully&#039;);
    }
    finally
    {
        Response.OnCompleted(async () =&gt;
        {
            await DoProcessing(id);
        });
    }
} بخش کلیدی کد قسمت Response.OnCompleted است که به برنامه شما اجازه می دهد حتی پس از گزارش OK به مشتری، به اجرای خود ادامه دهد.</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Sat, 11 Jan 2025 15:05:10 +0330</pubDate>
            </item>
                    <item>
                <title>مدیریت جریان ارزش و DevOps 2.0</title>
                <link>https://virgool.io/@farhad.sadeghi/%D9%85%D8%AF%DB%8C%D8%B1%DB%8C%D8%AA-%D8%AC%D8%B1%DB%8C%D8%A7%D9%86-%D8%A7%D8%B1%D8%B2%D8%B4-%D9%88-devops-20-lhfwksobapuo</link>
                <description>فلسفه مدیریت جریان ارزش (Value Stream Management) چندان جدید نیست، اما با تشکیل کنسرسیوم VSM، که VSM را به عنوان &quot;نسل بعدی DevOps&quot; معرفی می کند، اعتبار عمومی یافت. تشکیل دهندگان این کنسرسیوم می گویند که اگرچه اصول DevOps باعث ایجاد سازمانهایی با عملکرد بالاتر می شود، اما دشوار است  وقتی سازمانهای شما از انباره های اطلاعات ساخته می شوند و داده ها دفن می شوند، چیزی بهبود یابد. تفکر و کار به عنوان جریان های ارزشی به معنای وسواس تیمها در مورد ارزشی است کار آنها برای مشتری ایجاد می کند.موسسه پژوهشی گارتنر همچنین در مورد VSM حرف های زیادی برای گفتن دارد. گارتنر پیش بینی می کند که طی دو سال آینده، 70٪ سازمان ها از مدیریت جریان ارزش برای بهبود جریان در روند DevOps استفاده می کنند و این امر آینده DevOps را تعریف می کند.بنابراین، آیا می توان تیم های چابک و DevOps را تشویق و ترغیب کرد تا گامی رو به جلو بردارند و درباره ارزشی که کار آنها برای مشتری ایجاد می کند وسواس داشته باشند؟ شکی نیست که مدیران و متخصصان فناوری اطلاعات، به صورت جداگانه، واقعاً می خواهند بهترین نرم افزارهای ممکن را ارائه دهند. اما وقتی پویایی سازمانی مانع این هدف شود، نرم افزارها از این هدف دور می شوند.اما VSM دقیقاً چیست؟ فلینت برنتون از چند سال قبل در یک پست فوربس شرح مفصلی در این مورد ارائه داده است. مدیریت جریان ارزش VSM یک عمل تجاری ناب است که به تعیین ارزش توسعه نرم افزار و تلاشها برای تحویل آن کمک می کند.این مفهوم همچنین به بهبود جریان ارزش سازمان کمک می کند، در حالی که چرخه عمر تحویل نرم افزار را کنترل می کند. با شناسایی و بررسی جریان ارزشها، به جای &quot;ویژگی ها و عملکردها&quot; و اندازه گیری موفقیت در تحویل نرم افزار، تیم ها می توانند انرژی و زمان بیشتری روی موضوعات مثمر ثمر و کارا به جای ناکارایی ها بگذارند.ممکن است سوال شود، آیا این همان هدفی نیست که توسعه نرم افزار چابک و DevOps قرار بود محقق کند؟ برنتون اظهار می دارد Agile ،DevOps و مدیریت جریان ارزش نیروهای مکمل یکدیگر هستند. نقش VSM با جمع آوری اندازه گیری ها و معیارهای مهم برای نتایج کسب و کار  یا&quot;نگاشت جریان ارزش&quot;، فراهم کردن قابلیت دید در کل چرخه عمر نرم افزار است.به گفته تحلیلگران گارتنر، برای تیم های Agile و DevOps تشخیص و از بین بردن محدودیت های تحویل محصول چالش برانگیز است. تیمهای Agile و DevOps که فقط معیارهای عملکرد فنی را در نظر می گیرند (به استثنای معیارهای مشتری مداری) نمی توانند اولویت های خود را با سازمان هماهنگ کنند. تأثیر روی شیوه هایی مانند VSM در ابتکارات تحول دیجیتال به طور بالقوه می تواند عمیق باشد.رهبران شرکت ها می خواهند درک بهتری از چگونگی کمک نرم افزار به پیشبرد اهداف سازمانی خود داشته باشند. یک نظرسنجی از 600 مدیر فناوری اطلاعات که به تازگی توسط Digital. ai، ارائه کننده راهکارهای VSM و عضو موسس کنسرسیوم VSM منتشر شده، نشان می دهد که چه میزان تغییر شکل دیجیتال به یک نگرانی سطح بالای تجاری و سازمانی تبدیل شده است.94٪ از پاسخ دهندگان موافقت کردند که باید توسعه و تحویل نرم افزار خود را به اهداف تجاری نزدیک کنند، اما تنها 54٪ گفتند که تیم های تجاری، IT و امنیتی آنها از نظر استراتژیک همسو هستند و در راستای اهداف مشابه کار می کنند.نود و پنج درصد مدیران معتقدند که سازمان های آنها در حال حاضر به نوعی VSM را اجرا می کنند ولی تنها 50٪ سازمانهای خود را &quot;مشتری محور&quot; می دانند. گفتنی است، طراحان این نظرسنجی همچنین اشاره کردند، هیچ اتفاق نظر روشنی در مورد معنای VSM در شرکت های آنها وجود ندارد.تیم Gartner خاطرنشان می کند: نگاشت جریان ارزش تیم های DevOps را قادر می سازد از اتلاف و اصراف ممانعت به عمل آورند، اعتماد متقابل ایجاد کنند، شفافیت را افزایش دهند و اهداف خود را با اهداف سازمانی هماهنگ کنند. این رویکرد&quot;تفکر سیستمی&quot; به تیم های DevOps کمک می کند تا تمرکز خود را فراتر از معیارهای عملیاتی اعلام شده گسترش دهند. در عوض شاخص های عملکرد مشتری مدار و در سطح تیم را ارائه دهند.</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Sat, 07 Dec 2024 19:25:32 +0330</pubDate>
            </item>
                    <item>
                <title>پیاده سازی تولید ناب و رسم جریان ارزش (VSM)</title>
                <link>https://virgool.io/@farhad.sadeghi/%D9%BE%DB%8C%D8%A7%D8%AF%D9%87-%D8%B3%D8%A7%D8%B2%DB%8C-%D8%AA%D9%88%D9%84%DB%8C%D8%AF-%D9%86%D8%A7%D8%A8-%D9%88-%D9%86%D9%82%D8%B4%D9%87-%D8%A8%D8%B1%D8%AF%D8%A7%D8%B1%DB%8C-%D8%AC%D8%B1%DB%8C%D8%A7%D9%86-%D8%A7%D8%B1%D8%B2%D8%B4-vsm-in3id8bx0btj</link>
                <description>تولید ناب اولین بار در سال های پایانی جنگ جهانی دوم و هم زمان با نیاز شدید ژاپن به وسایل نقلیه ی موتوری توسط تای چی اونو در شرکت تویوتا عنوان و سپس در سال 1990 به همت جیمز ووماک و همکاران وی از دانشگاه ام آی تی در قالب یک طرح تحقیقاتی مطرح و در کتابی به نام ماشینی که جهان را تغییر داد منتشر گشت. تولید ناب در واقع از مزایای تولید دستی و انبوه استفاده و از معایبی چون قیمت بالا و عدم تنوع محصول نهایی اجتناب می کند. زیرا به طور خلاصه در تولید دستی نیروی کار ماهر ، حجم پایین تولید و قیمت نهایی بالا مطرح است که حتی با افزایش میزان محصول هم کاهش محسوسی نخواهد داشت. در تولید انبوه نیز عمدتاً از ماشین آلات گران قیمت و کارگران غیر ماهر استفاده می شود که همین امر هرگونه نوآوری در خط تولید را به دلیل گران تر تمام شدن قطعه ی جدید عملاً غیر ممکن می سازد در نتیجه محصول نهایی به بهای از دست رفتن تنوع فقط ارزان تر به دست مشتری خواهد رسید. تای چی اونو مهندس شرکت تویوتا در دهه 1930 به آمریکا سفر و از شرکت اتوموبیل سازی فورد بازدید نمود ولی به این نتیجه رسید که سیستم تولید انبوه آن ها پر از انواع اتلاف است. هفت اتلاف مد نظر وی به شرح زیر می باشند:تولید بیش از تقاضاموجودی بالا در انبارزمان های تاخیرحمل و نقل های غیر ضروریپردازش زیاد محصولات به دلیل طراحی اولیه ضعیفحرکات زائد کارگران که ارزش افزوده ای به بار نمی آوردتولیدات معیوب که باعث دوباره کاری یا از دست دادن سهم بازار می شونداصول اصلی تفکر تولید ناب نیز از قرار زیر است:جلوگیری از تولید محصولات معیوبتوجه به نیازهای واقعی مشتریانپیاده کردن اصول کایزن در کارخانهگسترش ارتباطات درون مجموعهنقشه برداری جریان ارزش اولین گام در جهت پیاده سازی تولید ناب (lean Production)رسم جریان ارزش (VSM) که در ابتدا، نقشه جریان مواد و اطلاعات نامیده می شد، یک دیاگرام تک صفحه اي است که در آن فرآیند استفاده شده براي تولید یک محصول اعم از جریان حرکت مواد از مرحله تأمین مواد اولیه تا در اختیار گرفتن محصول نهایی توسط مشتري، نمایش داده می شود. این دیاگرام براي اولین بار توسط بخش مشاوره مدیریت عملیات شرکت خودروسازي تویوتا در اواخر دهه 1980 ابداع شد.همانطور که برای ساختن یک بنا احتیاج به نقشه ساخت داریم جهت پیاده سازی سیستم تولید ناب نیز احتیاج به یک نقشه راهنما داریم. نقشه ای که در سیستم تولید ناب بعنوان راهنما از آن استفاده می گردد نقشه جریان ارزش Value-stream mapping نام دارد. بر خلاف تصور، این نقشه همانند یک نقشه layout کارخانه نمیباشد و تمرکز ما در این نقشه بروی مشخص کردن اعمالی است که از دید مشتری ارزش آفرین و یا فاقد ارزش میباشد. در این نقشه گرافیکی که با علایم ساده و قابل فهم ترسیم میشود میتوان حرکت مواد و اطلاعات از در ورود تا در خروج کارخانه را نشان داد. جهت رسم این نقشه باید کاغذ و مدادی تدارک ببینید و شخصا در کارگاه حضور یابید تا با پیمایش مراحل تولید بتوانید به درک درستی از حرکت و توالی فرآیندها دست یابید. توصیه میشود جهت رسم نقشه جریان ارزش معکوس عمل نمایید و از قسمت ارسال محصول نهایی شروع کنید و از قسمت های مختلف عبور کنید تا به بخش دریافت مواد اولیه برسید. در طی این پیمایش مسیر می بایست اطلاعاتی را از ایستگاه های کاری جمع آوری نمایید. بهتر است این اطلاعات شامل :زمان چرخه محصول ( cycle time ) که نشان دهنده زمانی است که یک قطعه از فرآیندی خارج میشودزمان تبدیل ( change overtime) که بیانگر زمان جابجایی تولید یک نوع محصول به تولید نوع دیگر می باشدزمان قابل استفاده بودن ماشین آلاتاندازه دسته های تولیدتعداد اپراتورزمان مفید کاریمیزان نرخ ضایعات و غیرهبیاد داشته باشید تمامی اطلاعات مورد نیاز را شخصا محاسبه نمایید و از داده های قبلی کارگاه استفاده نکنید، همچنین در زمان پیمایش فرآیندها از یک کرنومتر استفاده کرده و تمامی زمان ها را برحسب ثانیه محاسبه نمایید. بطور کل هدف از نقشه برداری جریان ارزش شناسایی منابع و ریشه های اتلاف و حذف آن ها از طریق پیاده سازی وضع آینده میباشد. پس از ترسیم نقشه جریان ارزش حال نوبت رسم نقشه وضع آینده است. برای اینکه بتوانید نقشه وضع آینده را تهیه کنید خیلی خوب است که در جستجوی یافتن پاسخ پرسش های ذیل باشید:بر اساس زمان کار فرآیند پایین جریانی که از همه به مشتری نزدیک تر است، زمان تکت شما چیست؟آیا باید محصول را نخست به سوپرمارکت محصول نهایی بفرستید که تحت کشش مشتری کار میکند یا مستقیما محصول را برای مشتری ارسال کنید؟در کدام نقطه از جریان ارزش میتوانید محصول را در یک حرکت پیوسته پردازش کنید؟برای کنترل تولید فرآیندهای بالای جریان باید در چه نقاطی از سیستم کشش سوپرمارکتی استفاده کنید؟در کدام نقطه از زنجیره تولید میتوانید تولید را زمان بندی کنید؟چگونه میتوانید در فرآیند سرعت ساز ، ترکیب تولید را هموار کنید؟در فرآیند سرعت ساز باید بطور ثابت، چه حجمی از کار را وارد و خارج کنید؟کدام بهبود های فرآیندی لازم هستند تا بتوانید در جریان ارزش حرکتی را ایجاد کنید که در طراحی وضع آینده تعیین نموده اید؟براساس پاسخ هایی که به این پرسش ها میدهید، ایده های مربوط به وضع آینده را بروی نقشه وضع موجود مشخص کنید. مهمترین نکته در خصوص برنامه تحقق وضع آینده این است که فکر نکنید دارید مجموعه ای از تکنیک ها را پیاده میکنید، بلکه این برنامه را چونان فرآیند ایجاد مجموعه ای از حرکت های مرتبط با هم تصور کنید که برای یک خانواده محصول صورت میگیرد.نقشه جریان ارزش نشان می دهد که به کجا میخواهید بروید. با استفاده از نقشه وضع آینده ای که ترسیم میکنید می توانید برنامه سالانه جریان ارزش را تدوین نمایید، این برنامه شامل:برنامه دقیق و مرحله به مرحله انجام کارهایی معین در زمانی معیناهداف قابل برنامه ریزیمقاطع دقیق کنترل با ضرب الاجل های واقعی و نام مسئولین بازبینیبا استفاده از نکات فوق می توانید بروی نقشه وضع آینده حلقه هایی رسم نمایید جهت جداسازی قسمت های مختلف نقشه و مطابق با اولویت بندی این حلقه ها را شماره گذاری نمایید. یک استراتژی کارآمد و موثر آن است که کار پیاده سازی را با حلقه سرعت ساز پایین جریان شروع کنید و سپس به وقت ضرورت بطرف بالای جریان پیش بروید. حلقه سرعت ساز که نزدیک ترین حلقه به مشتری نهایی است برای شما به عنوان یک مشتری داخلی عمل خواهد کرد و تمامی تقاضاها را در حلقه های بالای جریان تحت کنترل خود در خواهد آورد. هنگامی که در حلقه سرعت ساز حرکت محصول ناب شد و ثبات یافت آنگاه مشکلات بالای جریان که نیاز به توجه دارند آشکار خواهد شد. بطور مشخص بهتر است برای انجام بهبودها در یک حلقه از الگو ذیل پیروی نمایید:ایجاد حرکت پیوسته مبتنی بر زمان تکتاستقرار یک سیستم کششی برای کنترل تولیدهموارسازیانجام کایزن برای حذف پیوسته اتلاف ها، کاهش اندازه دسته ها، کوچک کردن سوپرمارکت ها و وسعت بخشیدن به گستره حرکت پیوستهدر پایان باید خاطر نشان کرد که پیاده سازی تولید ناب انجام یک کار گروهی است که تمامی افراد از مدیران ارشد تا کارگران ساده درگیر این سیستم میشوند و تنها در سایه همکاری، همدلی و پشتکار فراوان است که قادر خواهید بود تولید ناب را پیاده سازی کنید. جهت دستیابی به اهداف نقشه وضع آینده باید مدیر جریان ارزش تعیین شود که وظیفه اش رهبری افرادی است که فرآیند را اجرا میکنند، مدیر جریان ارزش مسئولیت هزینه و کیفیت محصول را در وضع حاضر و ترسیم نقشه وضع آینده و تحقق آن را به رهبری خود بر عهده خواهد داشت. آنچه در این نوشته آمده است مقدمه ای مختصر جهت آشنایی با نقشه جریان ارزش می باشد، علاقمندان میتوانند جهت آموزش و بررسی کامل نقشه جریان ارزش به کتاب مفید آموزش دیدن نوشته مایک رادر و جان شوک مراجعه نمایند.کاربردهای نقشه جریان ارزشالبته VSM منافع زیادي به دنبال دارد که از آن جمله می توان به موارد زیر اشاره کرد :نه تنها بهترین ابزار براي شناسایی تلفات است، بلکه از آن براي شناسایی ریشه هاي بروز تلفات نیز استفاده می شود.به افراد کمک می کند که به جاي ارتقاء و بهبود جزیرهاي فرایندها، سیستم را بهبود بخشند.یک زبان قابل فهم براي صحبت و تحلیل جمعی چگونگی عملکرد فرایند تولید است.این ابزار بر تحلیل وضعیت واقعی جریان مواد و اطلاعات استوار است.در این ابزار مفاهیم عمیق تولید ناب با ابزار تولید ناب به خوبی ادغام شده است.علاوه بر نمایش جریان کار و اطلاعات، حسن دیگري دارد و آن آشکارسازي تلفات زمانی با نمایش زمان صرف شده در هر فرآیند خط تولید در مقایسه با کل زمان تلف شده از مرحله سفارش تا تحویل کالا به مشتري است. چرا که اغلب تلفات منابعی نظیر مواد، تجهیزات و فضا به راحتی قابل تشخیص است، ولی تلفات زمانی در پشت فعالیتها و رفت و آمدهاي غیرضروري پوشیده و مخفی است.از دیدگاه تولید ناب هشت قلم ضایعات (از نگاه سیستم تولید تویوتا) را میتوان مطرح کرد که در ادامه خواهیم خواند:حمل و نقل هایی که باوجود غیرضروری بودن انجام می شوندموجودی هایی که اضافی می باشندجابه‎جا کردن افراد و ماشین آلات یا تجهیزات درصورتی که ضروری نمی باشد.زمانی که برای انتظارافراد یا تجهیزات بیکار صرف می شوداینکه بیش از حد یک محصول را تولید کنیمپرداختن به محصول بصورتی که بیش از جد باشد و پرداختن به محصول بیشتر از آنچه که مشتری نیاز دارد بطور مثال پرداختن به طرحهایی که برای تولید آنها نیاز به تکنولوژی با لا و حتی غیر ضروری داریمنقص‎هایی که برای اصلاح انها هزینه و تلاش زیادی لازم استتلف شدن استعدادها و نوابغی که مورد استفاده قرار نمی گیرند.مورد هشتم ابتدا در سیستم تولید تویوتا قرار نداشت با اینحال بعضا این مورد را هم مطرح می کنند.</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Wed, 04 Dec 2024 19:50:21 +0330</pubDate>
            </item>
                    <item>
                <title>اصول SOLID</title>
                <link>https://virgool.io/@farhad.sadeghi/%D8%A7%D8%B5%D9%88%D9%84-solid-naztdpgggcse</link>
                <description>اصول SOLID یک اصول قانون مند در برنامه نویسی شی گرا هستند که  در تمام زبان های برنامه نویسی شی گرا  موجود و قابل پیاده سازی است .کلمه SOLID مخفف پنج اصل بسیار مهم در مدیریت وابستگی (Dependency Management) در توسعه ی برنامه های شی گرا می باشد. در واقع هر کدام از حروف کلمه ی SOLID به یکی از این اصول بر می گردد.یکی از مشکلاتی که طراحی نامناسب برنامه های شی گرا برای برنامه نویسان ایجاد می کند موضوع مدیریت وابستگی در اجزای برنامه می باشد. اگر این وابستگی به درستی مدیریت نشود مشکلاتی شبیه موارد زیر در برنامه ایجاد می شوند:برنامه ی نوشته شده را نمی توان تغییر داد و یا قابلیت جدید اضافه کرد. دلیل آن هم این است که با ایجاد تغییر در قسمتی از برنامه، این تغییر به صورت آبشاری در بقیه ی قسمت ها منتشر می شود و مجبور خواهیم بود که قسمت های زیادی از برنامه را تغییر دهیم. یعنی برنامه به یک برنامه ی ثابت و غیر قابل پیشرفت تبدیل می شود. (این مشکل را Rigidity می نامیم.)تغییر دادن برنامه مشکل است و آن هم به این دلیل که با ایجاد تغییر در یک قسمت از برنامه، قسمت های دیگر برنامه از کار می افتند و دچار مشکل می شوند. (این مشکل را Fragility می نامیم.)قابلیت استفاده مجدد از اجزای برنامه وجود ندارد. در واقع، قسمت های مجدد برنامه ی شی گرای شما آنچنان به هم وابستگی تو در تو دارند که به هیچ وجه نمی توانید یک قسمت را جدا کرده و در برنامه ی دیگری استفاده کنید. (این مشکل را Immobility می نامیم.)اصول SOLID که قصد رفع کردن این مشکلات و بسیاری مسائل گوناگون را دارد عبارت اند از:Single Responsibility PrincipleOpen-Closed PrincipleLiskov Substitution PrincipleInterface Segregation PrincipleDependency Inversion Principleبا کنار هم گذاشتن حرف اول هر کدام از این اصول کلمه ی SOLID ایجاد می شود. با در نظر گرفتن این پنج اصل و پیاده سازی آنها در برنامه های خود می توانید به یک طراحی شی گرای پاک و درست دست پیدا کنید.S - Single-responsibility Principle (اصلی تک مسئولیتی)Single-responsibility Principle (SRP) states:A class should have one and only one reason to change, meaning that a class should have only one job.نقل قول زیر توضیح رسمی هست که برای SRP ارائه شده:یک کلاس فقط باید به یک دلیل تغییر کنه.یعنی چی؟ 🤔این اصل به ما میگه که هر کلاسی که توی برنامه‌ی ما وجود داره، باید یک مسئولیت خاص و مشخص داشته باشه. در واقع این کلاس باید فقط و فقط مسئول یک عملکرد توی برنامه باشه.این جمله رو همه شنیدیم: یک کار انجام بده ولی درست انجام بده!O - Open-Closed Principle (اصل باز/بسته)Open-closed Principle (OCP) states:Objects or entities should be open for extension but closed for modification.تعریف رسمی این اصل به این صورت هست:موجودیت‌های یک نرم‌افزار (کلاس‌ها، ماژول‌ها، توابع و ...) باید برای توسعه داده شدن، باز و برای تغییر دادن، بسته باشند.توی این اصل از کلمه‌های باز و بسته استفاده شده. این کلمات با چیزی که توی ذهنمون داریم یکم متفاوت هست. اول بذارید معنی کلاس باز و بسته رو با هم بررسی کنیم و بعد به توضیح این اصل بپردازیم.چه زمانی به یک کلاس میگیم باز؟به کلاسی که بشه اون رو توسعه داد، بشه از اون extend کرد، متدها و پراپرتی‌های جدید اضافه کرد و ویژگی‌ها و رفتار اون رو تغییر داد، میگن باز.چه زمانی به یک کلاس میگیم بسته؟کلاسی که کامل باشه. یعنی 100% تست شده باشه که بتونه توسط بقیه کلاس‌ها استفاده بشه، پایدار باشه و در آینده تغییر نکنه، میگن بسته. توی بعضی از زبان‌های برنامه‌نویسی یکی از راه‌های بسته نگه داشتن یک کلاس، استفاده از کلمه کلیدی final هست.خب حالا بپردازیم به توضیح اصل OCP:اصل OCP میگه که ما باید کد رو جوری بنویسیم که وقتی می‌خوایم اون رو توسعه بدیم و ویژگی‌های جدید اضافه کنیم، مجبور نشیم اون رو تغییر بدیم و دستکاری کنیم. ویژگی‌های جدید باید براحتی و بدون دستکاری کردن قسمت‌های دیگه اضافه بشن.طبق این اصل کلاس باید همزمان هم بسته باشه و هم باز! یعنی همزمان که توسعه داده میشه (باز بودن)، تغییر نکنه و دستکاری نشه (بسته بودن).L - Liskov Substitution Principle (اصل جایگزینی لیسکوف)Liskov Substitution Principle states:Let q(x) be a property provable about objects of x of type T. Then q(y) should be provable for objects y of type S where S is a subtype of T.تعریف آکادمیک این اصل بصورت زیر هست:اگر S یک زیر کلاس از  T باشه، آبجکت‌های نوع T باید بتونن بدون تغییر دادن کد برنامه با آبجکت‌های نوع S جایگزین بشنپس باید در نظر داشته باشیم وقتی که میخواهیم یک کلاس رو با مشتق کردن توسعه بدیم، جاهایی از برنامه که از کلاس والد استفاده شده، باید بتونه بدون مشکل با کلاس‌های فرزند هم کار کنه. یعنی کلاس فرزند نباید ویژگی‌ها و رفتار کلاس والد رو تغییر بده. مثلا اگه کلاس والد یک متد داره که خروجی اون عددی هست، کلاس فرزند نباید این متد رو جوری رونوشت کنه که خروجی آرایه باشه.I - Interface Segregation Principle (اصل جداسازی اینترفیس‌ها)The interface segregation principle states:A client should never be forced to implement an interface that it doesn’t use, or clients shouldn’t be forced to depend on methods they do not use.توضیح رسمی و آکادمیک این اصل بصورت زیر هست:کلاس‌ها نباید مجبور باشن متدهایی که به اونها احتیاجی ندارن رو پیاده‌سازی کنناین اصل میگه که ما باید اینترفیس (Interface) ها رو جوری بنویسیم که وقتی یک کلاس از اون استفاده میکنه، مجبور نباشه متدهایی که لازم نداره رو پیاده‌سازی کنه. یعنی متدهای بی‌ربط نباید توی یک اینترفیس کنار هم باشن. در این مواقع باید اون اینترفیس، به دو یا چند اینترفیس دیگه شکسته بشه. این اصل شباهت زیادی به اصل اول SOLID داره که میگه کلاس‌ها باید فقط مسئول انجام یک کار باشن.رعایت کردن این اصل به ما کمک میکنه کدهای خواناتر و تمیزتری داشته باشیم. توی شی‌گرایی باید یک نکته رو درنظر داشته باشیم که هر چی از کلی‌نویسی (عمومی‌نویسی) دوری کنیم و کدهایی داشته باشیم که مجزا و تفکیک شده باشن، برنامه‌ای منسجم‌تر و ساختاریافته‌تر خواهیم داشت. بنابراین کدها قابل استفاده مجدد میشن، تست و Refactor هم راحت‌تر انجام میشه 👌D - Dependency Inversion Principle (اصل وارونگی وابستگی)Dependency inversion principle states:Entities must depend on abstractions, not on concretions. It states that the high-level module must not depend on the low-level module, but they should depend on abstractions.توضیح رسمی و آکادمیک این اصل به صورت زیر هست. این توضیح رو بخونید تا با هم ریز به ریز جزییاتش رو بررسی کنیم:کلاس‌های سطح بالا نباید به کلاس‌های سطح پایین وابسته باشن؛ هر دو باید وابسته به انتزاع (Abstractions) باشن. موارد انتزاعی نباید وابسته به جزییات باشن. جزییات باید وابسته به انتزاع باشنخب دوستان این توضیحی بود که خیلی آکادمیک و یکم گنگ هست. مواردی مثل کلاس سطح بالا و سطح پایین، انتزاع و جزییات مواردی هستن که باید روشن بشن تا بتونیم این اصل رو خوب درک کنیم.کلاس سطح پایین چیه؟ 🤔به کلاس‌هایی گفته میشه که مسئول عملیات اساسی و پایه‌ای توی نرم‌افزار هستن. مثل کلاسی که با دیتابیس یا هارددیسک ارتباط برقرار می‌کنه، کلاسی که برای ارسال ایمیل استفاده میشه و ...کلاس سطح بالا چیه؟ 🤔کلاس‌هایی که عملیات پیچیده‌تر و خاص‌تری انجام میدن و برای انجام این کار از کلاس‌های سطح پایین استفاده میکنن. برای مثال کلاس گزارش‌گیری برای ثبت و خوندن گزارش، به کلاس دیتابیس یا هارددیسک نیاز داره. کلاس Users، برای اطلاع‌رسانی به کاربرها به کلاس ایمیل نیاز داره.مفهوم انتزاع (Abstraction)کلاس‌های انتزاعی کلاس‌های هستن که قابل پیاده‌سازی نیستن اما به عنوان یک طرح و الگو برای کلاس‌های دیگه در نظر گرفته میشن. مثلا یک کلاس انتزاعی برای گربه، زرافه، پلنگ و پنگوئن، میشه کلاس Animal. خود Animal به خودی خود قابل پیاده‌سازی نیست. بلکه یک طرح کلی برای حیوونایی هستن که مثال زدیم. پس تک تک این حیوون‌ها یک ورژن کلی‌تر دارن که می‌تونیم اون رو Animal بنامیم.مفهوم جزییاتمنظور از جزییات توی تعریف این اصل، جزییات یک کلاس مثل نام و ویژگی پراپرتی‌ها و متدهاست.خب بپردازیم به بررسی این اصل. ابتدا کد زیر رو در نظر بگیرید:class MySql {
    public insert() {}
    public update() {}
    public delete() {}
}

class Log {
    private database: MySql;

    constructor() {
        this.database = new MySql;
    }
}فرض کنیم یک کلاس سطح پایین داریم مثلا دیتابیس MySql. و یک سری کلاس سطح بالا مثلاً گزارش‌گیری (Log) از این کلاس استفاده می‌کنه. اگه بخوایم یک تغییر توی کلاس دیتابیس انجام بدیم، ممکنه بطور مستقیم تاثیر بذاره روی کلاس‌هایی که ازش استفاده میکنن. مثلا اگه توی کلاس MySql اسم متد رو تغییر بدیم و یا پارامترها رو کم و زیاد کنیم، نهایتا توی کلاس Log این تغییرات رو باید اعمال کنیم.همچنین کلاس‌های سطح بالا قابل استفاده مجدد نیستن. مثلاً اگه بخوایم برای کلاس Log از دیتابیس‌های دیگه مثلا MongoDB یا هارددیسک استفاده کنیم باید کلاس Log رو تغییر بدیم یا یک کلاس جدا براساس هر نوع دیتابیس بسازیم.خب همونطور که می‌بینید اگه یک کلاس سطح بالا وابسته به یک کلاس سطح پایین باشه این مشکلات به وجود میاد.راه حلبرای حل این مشکل باید با اینترفیس، یک لایه انتزاعی درست کنیم. با این کار کلاس Log دیگه وابسته به یک کلاس خاص برای ذخیره‌سازی و خوندن اطلاعات نیست و می‌تونیم هر نوع دیتابیسی رو استفاده کنیم و برای کلاس Log اهمیتی نداره که با چه نوع دیتابیسی داره کار میکنه. چون وابسته به انتزاع هست.ابتدا یک اینترفیس میسازیم برای اینکه کلاس‌های سطح بالا و سطح پایین رو وابسته به این اینترفیس کنیم:interface Database {
    insert();
    update();
    delete();
}حالا کلاس‌های سطح پایین باید این اینترفیس رو پیاده‌سازی کنن تا وابسته به انتزاع بشن:class MySql implements Database {
    public insert() {}
    public update() {}
    public delete() {}
}

class FileSystem implements Database {
    public insert() {}
    public update() {}
    public delete() {}
}

class MongoDB implements Database {
    public insert() {}
    public update() {}
    public delete() {}
}و نهایتاً توی کلاس‌های سطح بالا، وابستگی به یک کلاس خاص رو به اینترفیس واگذار می‌کنیم. کلاس‌های سطح بالا زمانی وابسته به انتزاع میشن که بجای استفاده مستقیم از کلاس‌های سطح پایین، از یک اینترفیس (رابط) استفاده کنن:class Log {
    private db: Database;

    public setDatabase(db: Database) {
        this.db = db;
    }

    public update() {
        this.db.update();
    }
}همونطور که می‌بینیم وابستگی به یک کلاس خاص از بین رفت و میتونیم هر نوع دیتابیسی رو برای کلاس Log استفاده کنیم:logger = new Log;

logger.setDatabase(new MongoDB);
// ...
logger.setDatabase(new FileSystem);
// ...
logger.setDatabase(new MySql);

logger.update();</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Wed, 27 Nov 2024 16:41:03 +0330</pubDate>
            </item>
                    <item>
                <title>کانفلوئنس (Confluence) چیست؟</title>
                <link>https://virgool.io/@farhad.sadeghi/%DA%A9%D8%A7%D9%86%D9%81%D9%84%D9%88%D8%A6%D9%86%D8%B3-confluence-%DA%86%DB%8C%D8%B3%D8%AA-lidctbwknzjk</link>
                <description>کانفلوئنس یک ابزار مدیریت مستندات و دانش است که کاملا تحت وب و به شکل ویکی (Wiki) است. این نرمافزار توسعه داده شده توسط شرکت اتلسین (Atlassian) است. ویژگیهایی مانند امکان نصب پلاگینهای متنوع، مدیریت دسترسی کامل، مدیریت نسخه، امکان ویرایش همزمان یک مستند، یکپارچه شدن با جیرا، کامنت گذاری روی مستند از جمله مهم ترین مزیتهای استفاده از این ابزار است.مشکلات مدیریت مستندات به شکل سنتیمدیریت مستندات در سازمانها از مهمترین دغدغه هایی است که سازمان از بدو شروع کار، با آن دست و پنجه نرم میکند. سازمانها همیشه به دنبال سامانه و سیستمهایی هستند که به کمک آن بتوانند مستندات جاری سازمان را به خوبی مدیریت کنند. یک سامانه مدیریت مستندات لازم است شامل ویژگی های زیر باشد: 1.  سهولت در نگهداری سامانه 2.  امکان دسته بندی مستندات به شکلهای مختلف 3.  مدیریت دسترسی افراد به مستندات 4.  سهولت دسترسیپذیری افرادنرم افزارهای مختلفی برای بحث مدیریت مستندات در سازمانهای مختلف مورد استفاده قرار میگیرند. یکی از معروفترین ابزارهای مورد استفاده در این زمینه Microsoft SharePoint است که یک Document Management System &#40;DMS&#41; است. سیستمهای DMS اساس کار خود را بر اساس فایلهای Word , Excel , PowerPoint و … قرار داده اند و هدف آنها ایجاد بستری برای دستهبندی، نگهداری و مدیریت دسترسی بر این فایلهاست.</description>
                <category>فرهاد صادقی</category>
                <author>فرهاد صادقی</author>
                <pubDate>Tue, 12 Nov 2024 20:30:23 +0330</pubDate>
            </item>
            </channel>
</rss>