استفاده از StatefulSet در پلتفرم ابری آروان
پلتفرم ابری در واقع یک مدل از مبحث رایانش ابری است که سرویس دهنده با ایجاد امکانات سختافزاری و برخی ابزارها، سرعت توسعه نرمافزار را بالا برده و دغدغه توسعهدهنده را، در ارتباط با زیرساختهای مورد نیاز محصول، مرتفع میسازد.
در این مقاله به بررسی مفهوم StatefulSet و نحوهی استفاده از آن و همچنین اجزای سازنده یک StatefulSet و تعریف آن میپردازیم. مفهوم StatefulSet در پلتفرم ابری آروان با مفهوم StatefulSet در Kubernetes کاملا سازگار است.
پیشنیازها
تنها پیشنیاز این سیستم، داشتن اکانت ابر آروان و دسترسی به پلتفرم ابری آروان است.
ابتدا یه سایت آروان به نشانی www.arvancloud.com بروید و یک اکانت بسازید. سپس به بخش پروفایل رفته و در سربرگ API KEYS برای خود یک API KEY جدید بسازید و آن را در جایی ذخیره کنید.
برای انجام مراحل این مقاله نیاز است که از کامندلاین ابر آروان استفاده کنید. با استفاده از این لینک کامندلاین را دانلود کرده (در صورت نیاز آن را در PATH خود قرار داده) و از طریق خط فرمان لاگین کنید:
arvan login
سپس API KEY که از سایت دریافت کردهاید را در ادامه پیست کنید.
StatefulSet چیست؟
در پلتفرم ابری آروان هنگام استفاده از persistentVolumeClaim، هر دیسک را میتوان همزمان به یک Pod متصل کرد و در نتیجه، نمیتوان چند replica از یک Pod دارای دیسک در یک deployment داشت.
برای استفاده از سرویسهای stateful و یا سیستمهای توزیعشده، میتوان از statefulSet استفاده کرد. دو ویژگی مهم statefulSet که آن را مناسب جهت استفاده در این سیستمها میکند، توان اتصال دیسکهای مجزا به replicaهای مربوط به Pod و همچنین نامگذاری Podها بر اساس شمارههای افزایشی است. یعنی در statefulSet، هر Pod شامل نام statefulSet به همراه یک شماره افزایشی است. برای مثال: Pod-1، Pod-2 و... .
ساخت StatefulSet
برای ساخت StatefulSet، میبایست اطلاعات مورد نیاز را در قالب yaml در یک فایل وارد کرده و سپس از طریق کامندلاین آن را به پلتفرم ابری آروان ارایه کرد. در ادامه مثالی ساده از یک StatefulSet برای یک سرویس nginx آورده شده و هر یک از بخشهای آن توضیح داده شده است. در این مثال فرض شده، دادههای مربوط به log سیستم نیاز به ذخیره سازی در دیسک دائم دارند.
apiVersion: apps/v1 kind: StatefulSet metadata: annotations: labels: app: nginx name: nginx spec: selector: matchLabels: app: nginx serviceName: "nginx" replicas: 3 template: metadata: labels: app: nginx spec: terminationGracePeriodSeconds: 10 containers: - name: nginx image: nginx ports: - containerPort: 80 name: http resources: limits: cpu: '2' ephemeral-storage: 4G memory: 1G requests: cpu: '2' ephemeral-storage: 4G memory: 1G volumeMounts: - name: nginx-log mountPath: /var/log/nginx volumeClaimTemplates: - metadata: name: nginx-log spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "standard" resources: requests: storage: 4Gi
نکته: توجه کنید که دندانهگذاری (indentation) در فایلهای yaml مهم است و کوچکترین جابهجایی میتواند باعث برگرداندن خطا و یا تنظیمات ناخواسته شود.
در ادامه فیلدهای مربوطه توضیح داده میشود.
- kind: مشخص کننده نوع ماهیت میباشد. این فیلد میتواند مقادیری مانند: Pod، Service، StatefulSet، Deploymentو… داشته باشد. در واقع مانند ماهیتهایی که در kubernetes وجود دارد. در این مثال، هدف تعریف StatefulSet میباشد لذا این مقدار مشخص شده است.
- metadata.name: مشخص کننده نام StatefulSet میباشد.
- spec.replica: مشخص کننده تعداد pod هایی است که StatefulSet اجرا و مدیریت میکند. pod در قسمت spec.template.spec تعریف میشود و فیلد spec.replica تعیین میکند چه تعداد pod (کاملا مشابه) مطابق تعریف در حال اجرا باشد.
- spec.selector.matchLabels: از طریق این فیلد، StatefulSet متوجه میشود که کدام pod ها را میبایست کنترل کند. مقداری که برای این فیلد تعیین میشود باید به صورت key:value معادل فیلد spec.template.metadata.labels باشد. در این مثال این مقدار معادل app: nginx قرار گرفته شده است.
- spec.serviceName: این فیلد مشخصکنندهی نام سرویسی است که امکان دسترسی به nodeهای nginx را فراهم میکند. نام این فیلد باید معادل metadata.name آن service ای باشد که برای دسترسی به Pod های nginx استفاده میشود.
- spec.template.metadata.labels: این فیلد label هایی را به شکل key: value به pod های ساخته شده اختصاص میدهد.
به طور کلی ارتباطات بین ماهیتهای پلتفرم ابری آروان از طریق label ها و selectorها انجام میپذیرد. لذا در انتخاب و تعیین این مقادیر میبایست دقت کافی به خرج داد.
- spec.template.spec: این بخش مشخصات pod ای که StatefulSet میبایست کنترل کند را مشخص میکند. در این بخش زیرمجموعه spec.template.spec.containers مشخص کننده container هایی است که قرار درون هر pod اجرا شود.
- spec.template.spec.containers.image: مشخص کننده آدرس docker image است که قرار است pod آن را اجرا کند.
- spec.template.spec.containers.name: مشخص کننده نام container ای است که قرار است درون pod اجرا شود.
- spec.template.spec.containers.imagePullPolicy: تعیین میکند در چه صورت docker image مجددا pull شود.
در این مثال برابر IfNotPresent قرار گرفته، که مقدار پیشفرض این فیلد است، تا در هر بار اجرا در صورتی که image روی نود اجرا شده یافت نشد، این image دریافت شود. سایر مقادیر ممکن برای این فیلد برابر با Always و Never است. در صورتی که Always انتخاب شود، همواره هنگام اجرای مجدد برنامه (Pod) پلتفرم ابری image را مجددا دریافت میکند.
توصیه میشود به هیچ وجه حالت Never را انتخاب نکنید، چرا که در این حالت، پلتفرم ابری فرض میکند همواره image بر روی نودها موجود میباشد و تلاشی برای pull کردن image نمیکند.
- spec.template.spec.containers.ports: لیست portهایی که از خارج از container قابل دیدن میباشند را مشخص میکند.
- spec.template.spec.containers.resources: این بخش مشخص کننده میزان منابعی است که container برای اجرا نیاز خواهد داشت.
مشخص کردن این منابع در پلتفرم ابری آروان اجباری است. هنگام تعیین این منابع میبایست دقت کافی را به خرج داد تا هنگام اجرا، container با کمبود منابع مواجه نشده و اجرای آن دچار اختلال نشود.
این بخش از دو زیر بخش limits و requests تشکیل شده که هر زیر بخش شامل cpu، memory و ephemeral-storage میباشد. مقادیر هر کدام را برای limits و requests میبایست مساوی قرار داد.
همچنین ephemeral-storage مشخص کننده میزان دیسک مورد استفاده container است. و دادههای ذخیره شده در آن پایدار نیست؛ بدین معنی که، در صورت restart شدن pod، دادههای موجود در آن به مقادیر پیشفرض container باز میگردد و تغییرات از بین میروند. درصورتی که نیاز به دیسک پایدار باشد، میتوان از persistentVolumeClaim استفاده کرد.
- spec.template.spec.containers.volumeMounts: در این بخش، مسیری که نیاز است دیسک mount شود مشخص میشود.
- spec.template.spec.containers.volumeMounts.name: از آنجا که میشود بیش از چند دیسک به یک کانتینر متصل کرد، جهت تفکیک مسیرها، آنها را نامگذاری باید کرد.
- spec.template.spec.containers.volumeMounts.mountPath: مشخص کننده آدرس مسیری درون کانتینر است که میخواهیم دیتای آن بر روی دیسک دایمی نوشته و از آن خوانده شود.
- spec.volumeClaimTemplate: این بخش مشخصات دیسکهایی است که باید به Pod ها متصل شوند.
- spec.volumeClaimTemplate.metadata.name: نام دیسکهایی که باید متصل شوند میبایست مشابه spec.template.spec.containers.volumeMounts.name باشد.
- spec.volumeClaimTemplate.spec.accessMode: در پلتفرم ابری آروان این مقدار میبایست معادل ReadWriteOnce باشد.
- spec.volumeClaimTemplate.spec.resources.requests.storage: حجم هر دیسک را مشخص میکند.
خطوط بالا را در یک فایل به نام nginx-StatefulSet.yaml وارد کرده و ذخیره کنید. سپس از طریق کامند لاین با دستور زیر، StatefulSet خود را به پلتفرم ابری آروان ارایه کنید.
arvan paas apply -f nginx-StatefulSet.yaml
سپس با دستور زیر میتوانید از وضعیت StatefulSet خود و اجرای آن بر روی پلتفرم ابری آروان آگاه شوید.
arvan paas get sts
خروجی مشابه زیر خواهد بود:
$ arvan paas get sts NAME DESIRED CURRENT AGE nginx-StatefulSet 3 3 2h
در خروجی بالا، NAME مشخص کننده نام StatefulSet است. DESIRED تعیین کننده تعداد podهایی است که میبایست توسط این StatefulSet اجرا شود و توسط فیلد spec.replica درون StatefulSet تعیین میشود. مقدار CURRENT بیان میکند در این لحظه چه تعداد POD در حال اجرا میباشد. همچنین AGE مشخص کننده مدت زمانی است که StatefulSet اجرا شده.
همچنین با دستور زیر میتوانید podهای در حال اجرا را مشاهده کنید.
$ arvan paas get pods NAME READY STATUS RESTARTS AGE nginx-0 1/1 Running 0 14m nginx-1 1/1 Running 0 5m nginx-2 1/1 Running 0 1m
روش دیگر تغییر تعداد podها تغییر فیلد spec.replica در فایل کانفیگ StatefulSet است. کافیست این مقدار را در فایل خود تغییر دهید و مجددا آن را به پلتفرم ابری آروان ارایه کنید.
همچنین میتوانید با دستور زیر تنظیمات StatefulSet را مستقیم بر روی پلتفرم ابری آروان تغییر دهید.
arvan paas edit statefulset nginx-StatefulSet
دستور بالا از طریق editor پیشفرض پلتفرم ابری آروان تنظیمات StatefulSet را در قالب yaml به شما نمایش میدهد و میتوانید تغییرات خود را اعمال کرده و سپس ذخیره کنید. پس از بستن editor تنظیمات به طور خودکار اعمال خواهد شد و نیاز به انجام عمل دیگری نیست.
Headless service
جهت دسترسی به Pod های statefulSet از درون پلتفرم ابری آروان میتوان از headless service استفاده کرد. Headless service این امکان را فراهم میکند تا به شکل مستقیم به Pod ها بدون load balancing ترافیک ورودی، دسترسی داشت. جهت تعریف headless service کافیست spec.clusterIP را در تنظیمات service برابر با none قرار دهید. در این حالت میتوان به Pod ها با نام دامنه به شکل Pod-1.svc دست یافت. خطوط زیر نحوه تعریف یک headless service را نمایش میدهد.
apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: http clusterIP: None selector: app: nginx
نکته: توجه کنید که دندانه گذاری (indentation) در فایلهای yaml مهم است و کوچکترین جابجایی میتواند باعث برگرداندن خطا و یا تنظیمات ناخواسته شود.
در ادامه فیلدهای مربوطه توضیح داده میشود.
- metadata.name: نام service میباشد که در این مثال باید معادل مقدار spec.serviceName مشخص شده در توصیف statefulSet باشد.
- spec.clusterIP: این مقدار باید معادل none قرار گیرد تا مشخص شود قصد تعریف یک headless service داریم.
- spec.selector: در این بخش مشخص میشود که ترافیک ورودی به کدام Pod ها میبایست ارسال شود. در این مثال Pod های مربوط به statefulSet مشخص شدهاند.
با توجه به تعاریف بالا جهت دسترسی به هر یک از Pod های statefulSet تعریف شده میتوان از نام دامنههای زیر استفاده کرد.
nginx-0.nginx nginx-1.nginx nginx-2.nginx
با توجه به اینکه از پورت ۸۰ استفاده شده نیازی به مشخص کردن پورت به صورت مستقیم نیست. در صورتی که پورت دیگری انتخاب شده بود، میبایست آن را مشخصن به کار برد برای مثال nginx-0.nginx:80
همچنین میتوانید با مراجعه به این مقاله میتوانید نمونه کاربردی استفاده از statefulSet را در پلتفرم ابری آروان مشاهده کنید.
جهت اطلاعات بیشتر میتوانید به مستندات kubernetes و okd مراجعه کنید.
این مقاله از مراجع زیر اقتباس شده است.
https://kubernetes.io/docs/tutorials/stateful-application/basic-stateful-set