برای استفاده‌ی تخصصی از کانتینر ابری آروان نیاز است با مفاهیم پایه Kubernetes آشنایی پیدا کنید. در این بخش به‌شکل کلی به بررسی مفاهیم عمومی خواهیم پرداخت. پس از مطالعه‌ی این راهنما با مراجعه به مقالات تخصصی می‌توانید اطلاعات دقیق‌تری در مورد هر کدام از مفاهیم پایه کانتینر ابری بدست آورید.

مقدمه

اگر با فرآیند استقرار نرم‌افزار درگیر بوده‌اید با مراحل مختلف، پیچیدگی و دشواری‌های آن آشنایی دارید. مثلن برای استقرار Backend Application‌ای که با Laravel PHP نوشته‌اید، نیاز دارید یک سرور خریداری کنید. بعد از نصب سیستم‌عامل پیش‌نیازهای نرم‌افزار خود مانند php-fpm را نصب کنید. با نصب nginx یا apache ترافیک را به نرم‌افزار خود برسانید. fpm و nginx را برای Serve درخواست‌های کاربران پیکربندی کنید. در پایان با خرید دامنه و تنظیم کردن آن بر روی IP سرور، ترافیک کاربران را به سرور هدایت کنید.

مهم‌ترین بخشی که کانتینر ابری ابر آروان به شما کمک می‌کند و به کار شما سرعت می‌بخشد، بخش استقرار نرم‌افزار است.

از آنجا که کانتینر ابری آروان بر مبنای Kubernetes (یا به‌طور دقیق‌تر OpenShift) طراحی شده، در این مقاله به بررسی مفاهیم کلی آن و همین‌طور ارتباط این مفاهیم با روال سنتی استقرار نرم‌افزار می‌پردازیم.

Kubernetes چیست و چگونه از آن استفاده می‌کنیم؟

برای درک بهتر از Kubernetes مروری بر روال سنتی استقرار نرم‌افزار خواهیم داشت.

۱- اجرای نرم‌افزار

در این پروسه شما نیاز دارید نرم‌افزار خود را روی سرور اجرا کنید. معمولن این کار با انتقال فایل‌های نرم‌افزار روی سرور انجام می‌شود. مثلن اگر یک پروژه‌ی Laravel PHP داشته باشید فایل‌ها را به سرور منتقل می‌کنید؛ یا اگر پروژه‌ی شما به golang نوشته شده باشد، فایل کامپایل شده‌ی پروژه را به سرور می‌فرستید.

در Kubernetes دقیقا همین پروسه انجام می‌شود. با این تفاوت که نرم‌افزار شما باید داخل کانتینر (Container) قرار گیرد. کانتینر در واقع همان فایل یا فایل‌های اجرای نرم‌افزار شما است که داخل یک فایل آرشیوی (فایل tar) قرار گرفته و بعد از انتقال بر روی سرور اجرا می‌شود.

کانتینرها یک تفاوت دیگر هم با اجرای مستقیم روی سرور دارند؛ این‌که نرم‌افزار شما وقتی به‌صورت کانتینر (مثلن با استفاده از Docker) روی سرور اجرا می‌شود، دسترسی‌های بسیار محدودتری دارد و حتی می‌توان میزان استفاده از منابع آن را از کل منابع سیستم محدودتر کرد. مثلن می‌توان از هشت هسته پردازشگر، یک هسته و حتا ۰.۵ هسته را به آن اختصاص داد. هم‌چنین، به‌دلیل محدودیت‌های زیاد اجرای نرم‌افزار داخل کانتینر، نرم‌افزار شما حتا به کتابخانه‌های  سیستم‌عامل هم دسترسی ندارد. به همین دلیل شما برای ساخت کانتینر نرم‌افزار خود، باید تمامی کتابخانه‌های مورد نیاز را درون کانتینر قرار دهید.

یک تفاوت دیگر در اجرای نرم‌افزار درون کانتینر با روش سنتی، موقتی و میرا بودن (Ephemeral) حافظه‌ی آن است. یعنی هر میزان اطلاعاتی که بعد از اجرای نرم‌افزار داخل کانتینر، روی دیسک نوشته شود، تمامی فایل‌های این اطلاعات نوشته شده بعد از اجرای مجدد نرم‌افزار بر اثر Restart کردن Container یا توقف آن به هر صورت دیگری، از بین خواهد رفت. به همین دلیل برای اجرای نرم‌افزارهایی مانند پایگاه‌های داده، نیاز است دیسک دایمی به کانتینر خود متصل کنید.

توجه داشته باشید که در Kubernetes نرم‌افزارها به‌جای این‌که در داخل کانتینر اجرا شوند، داخل یک Pod اجرا می‌شوند، هرچند از دید کاربری در اکثر موارد می‌توانید این دو را معادل فرض کنید.

۲- مدیریت اجرای نرم‌افزار

اگر تاکنون نرم‌افزاری را روی سرور مستقر کرده باشید احتمالا به این موضوع برخورده‌اید که همیشه به سرویسی احتیاج است که در صورت به خطا خوردن نرم‌افزار شما یا این‌که ریست شدن سرور، نرم‌افزار شما را دوبار اجرا کند. مثلن شاید از systemd و یا upstart برای این کار استفاده کرده باشید. (البته در مورد زمانی که از سرویس مانند php-fpm برای اجرای نرم‌افزار استفاده می‌کنید، در واقع systemd اجرای php-fpm را مدیریت می‌کند و نرم‌افزار شما توسط php-fpm اجرا می‌شود.)
در این حالت مثلن سرویسی که برای systemd تعریف کرده‌اید تضمین می‌کند که نرم‌افزار شما همیشه روی سرور در حال اجرا باشد.
به عنوان مثال نرم‌افزار sshd که مسوول پذیرش درخواست‌ها SSH به سرور در لینوکس است، سرویسی به‌صورت زیر در محل /etc/systemd/system/sshd.service دارد:

[Unit]
Description=OpenBSD Secure Shell server
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run

[Service]
EnvironmentFile=-/etc/default/ssh
ExecStartPre=/usr/sbin/sshd -t
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify

[Install]
WantedBy=multi-user.target
Alias=sshd.service

فایل بالا و استارت کردن سرویس sshd با استفاده از دستور systemctl start sshd.service این تضمین را می‌دهد که همیشه سرویس بالا بوده و حتی در صورت مختل شدن و توقف نرم‌افزار، دوباره آن را اجرا کند.

مشابه همین موضوع، در Kubernetes مفهوم Deployment وجود دارد با یک تفاوت بسیار مهم. سرویس‌های systemd و یا سرویس‌های مشابه، این قابلیت و تضمین را به شما می‌دهند که نرم‌افزار شما روی یک سرور همیشه در حال اجرا باشد، در حالی که Deployment این تضمین را می‌دهد که نرم‌افزار شما روی یکی از سرورهای کلاستر Kubernetes در حال اجرا باشد و شما به‌طور معمول کنترلی برای این‌که نرم‌افزار روی چه سروری اجرا شود اعمال نمی‌کنید و حتا از آن مطلع نیستید.

این یک قابلیت بسیار مهم Kubernetes است که شما مستقل از این‌که اطلاعی از وضعیت سرور خود داشته باشید، مطمین هستید که حتی اگر سروری که نرم‌افزار شما بر روی آن قرار دارد به هر دلیلی از دسترس خارج شود، نرم‌افزار شما روی سروری دیگری از کلاستر اجرا خواهد شد.

هم‌چنین با توجه به همین قابلیت مهم، شما می‌توانید به‌راحتی تعریف کنید که چند نسخه از نرم‌افزار شما روی کلاستر اجرا شود (با تعریف تعداد Replica)، و بدون این‌که مطلع باشید کانتینر نرم‌افزار شما روی هر تعداد سروری که موجود باشید اجرا خواهد شد.

برای تعریف هر نوع ماهیتی در Kubernetes از جمله Deployment معمولن از فایل‌های yaml استفاده می‌شود. این فایل‌ها که توسط شما باید ساخته شود، تعیین می‌کند که مثلن Deployment شما، کانتینر نرم‌افزار را از کجا دریافت نماید، چه تعداد نسخه از نرم‌افزار شما را اجرا کند، و یا این‌که چه حجم از منابع پردازشی و حافظه را به نرم‌افزار شما اختصاص دهد. به‌عنوان مثال فایل yaml مربوط به Deployment یک نرم‌افزار nginx را می‌توانید اینجا مشاهده کنید:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        imagePullPolicy: IfNotPresent
        name: nginx
        ports:
        - containerPort: 2368
          protocol: TCP
        resources:
          limits:
            cpu: '1'
            ephemeral-storage: 2G
            memory: 1G
          requests:
            cpu: '1'
            ephemeral-storage: 2G
            memory: 1G

به دلیل وجود این ماهیت‌های مختلف، در پنل ابر آروان تمامی این‌ها به‌عنوان یک اپلیکیشن در صفحه اول لیست می‌شوند و مدل این ماهیت به‌عنوان زیرتیتر هر کدام از نرم‌افزارها شما نوشته می‌شود. برای مطالعه‌ی بیشتر در مورد Deployment به مقاله‌ی اختصاصی آن مراجعه کنید.

۳- شبکه و توزیع بار

زمانی که نرم‌افزاری را روی سرور نصب می‌کنیم، معمولن از سرویس‌هایی مانند nginx و یا haproxy برای فرستادن ترافیک ورودی به سمت نرم‌افزار استفاده می‌شود. این روش این قابلیت را به ما می‌دهد که مثلن ترافیک ورودی را بین چند سرور تقسیم کنیم و یا این‌که با قرار دادن Health-check روی haproxy مطمین باشیم که در صورت داون شدن یک سرور ترافیک کاربران ما به سمت سروری که سالم است هدایت خواهد شد.

با توجه به ماهیت Deployment توضیح دادیم که در هر زمان ممکن است نرم‌افزار ما روی یک سرور متفاوت اجرا شود. هم‌چنین بر اساس تنظیماتی که ما برای Deployment تعیین کرده‌ایم، می‌تواند چندین نسخه از نرم‌افزار روی سرورهای کلاستر اجرا شود. این توزیع بار در داخل کلاستر Kubernetes با استفاده از مفهوم سرویس صورت می‌گیرد. شما برای هر کدام از نرم‌افزارهای Backend خود و هم‌چنین نرم‌افزارهای پشتیبان آنها مانند cacheها و پایگاه‌های داده، و در واقع برای هر Deployment باید یک سرویس تعریف کنید. به‌عنوان مثال برای یک سرویس مانند Redis بعد از تعریف Deployment باید Service را به‌صورت زیر تعریف کنیم:

apiVersion: v1
kind: Service
metadata:
  name: redis-service
spec:
  selector:
    app: redis
  ports:
    - name: input
      protocol: TCP
      port: 6379
      targetPort: 6379

استفاده از Service یک مزیت بسیار مهم دارد. این‌که برای ارتباط بین نرم‌افزارهای شما دیگر نیازی به استفاده از IP نیست و به راحتی می‌توانید با استفاده از نام Service به سایر نرم‌افزارهای خود داخل کلاستر دسترسی داشته باشید. به‌عنوان مثال شما در نرم‌افزار PHP خود برای اتصال به Redisی که در بالا تعریف شده می‌توانید به آدرس redis-service:6379 درخواست دهید.
برای مطالعه بیشتر در مورد Service و نحوه استفاده آن در کانتینر ابری آروان به مقاله اختصاصی Service مراجعه کنید.

همانطور که توضیح داده شد، سرویس‌ها صرفن برای ارتباط داخل ‌کلاستری مورد استفاده قرار می‌گیرند، اما زمانی که نیاز است ترافیک کاربران را از خارج دیتاسنتر به نرم‌افزار خود منتقل کنیم چطور؟

برای این کار در روش سنتی نیاز است که یک دامنه تعریف کرده سپس با قرار دادن یک سرویس مانند Apache و یا nginx ترافیک‌های HTTP و HTTPS را Serve کنیم. در Kubernetes این کار به‌وسیله‌ی Ingress و در OpenShift توسط Route صورت می‌گیرد. Route صرفن تعیین می‌کند که ترافیک ورودی به کلاستر برای یک دامنه مشخص به چه Serviceی منتقل شود. شما پس از تعریف Service برای Deployment نرم‌افزار خود، به راحتی می‌توانید ترافیک را از خارج از کلاستر به داخل هدایت کنید. به‌عنوان مثال در زیر تعریف یک Route را می‌توانید مشاهده کنید:

apiVersion: v1
kind: Route
metadata:
  name: my-app-route 
spec:
  host: my-app-example-project.apps.ir-thr-at1.arvan.run
  to:
    kind: Service
    name: nginx-service
  tls:
    termination: edge
    insecureEdgeTerminationPolicy: Allow
  port:
    targetPort: http

برای مطالعه بیش‌تر در مورد Route و شیوه‌ی پیکربندی آن برای دریافت ترافیک از خارج کلاستر به مقاله‌ی اختصاصی Route مراجعه نمایید.

۴- پیکربندی نرم‌افزار

احتمالن برای تولید هر نرم‌افزار نیاز است یک یا چند فایل config داشته باشیم تا نرم‌افزار اطلاعاتی مانند آدرس و رمز دسترسی به پایگاه داده را از روی این فایل‌ها بخواند. این اطلاعات ممکن است مثل اطلاعات دسترسی به پایگاه داده دارای محرمانگی بالایی باشند و یا این‌که اطلاعات غیرمحرمانه‌ای باشند مانند این‌که نرم‌افزار روی چه دامنه‌ای سرو می‌شود.

در مدل استقرار سنتی تنظیم اطلاعات config یا پیکربندی معمولن با یک یا چند فایل بر روی سرور انجام می‌شوند که Sysadmin یا مسوول سرور با اعمال تغییر در این فایل تنظیمات نرم‌افزار را تغییر می‌دهد.

در Kubernetes گرچه می‌توان فایل پیکربندی را داخل کانتینر قرار داد، اما این کار ضمن این‌که از لحاظ امنیت توصیه نمی‌شود، امکان تغییر در آن را سخت می‌کند. برای این منظور مفاهیم Secret و ConfigMap وجود دارند که می‌توانند با attach شدن به کانتینر نرم‌افزار شما به‌عنوان یک فایل خوانده شوند و هم‌چنین امنیتی بالاتری برای تنظیمات حساس شما ایجاد می‌کنند. (به‌شکل کلی تفاوت زیادی بین Secret و ConfigMap وجود ندارد و صرفن توصیه می‌شود اطلاعات محرمانه را با استفاده از Secret برای نرم‌افزار تعریف کنید.)
برای مطالعه اطلاعات دقیقتر در مورد این مفاهیم به مقاله اختصاصی Secret مراجعه نمایید.

جمع‌بندی

به‌طور کلی می‌توانید Kubernetes را به‌عنوان یک فرد مسوول (Agent) در نظر بگیرید که همواره در تلاش است با مانیتور کردن مستمر وضعیت فعلی کلاستر (Current State) آن را به وضعیت مطلوبی (Desired State) که شما تعریف می‌کنید برساند. وجود تفاوتی بین این دو وضعیت مثلن تعریف Deployment جدید و یا سوختن یک سرور و کم شدن تعداد نسخه‌های فعال نرم‌افزار شما منجر به انجام یک عمل در برای تغییر وضعیت فعلی به سمت وضعیت مطلوب شما خواهد شد.

کانتینر ابری و Kubernetes، زیرساخت‌هایی هستند در جهت ساده‌سازی پروسه استقرار نرم‌افزار و سهولت مدیریت منابع سخت‌افزاری،‌ پیاده‌سازی نرم‌افزار بر این بسترها این امکان را به شما می‌دهد که در کمترین زمان ممکن، نرم‌افزار خود را به مرحله اجرای کامل رسانده و هم‌چنین بدون داشتن دغدغه زیرساخت، نرم‌افزار خود را مدیریت کنید. برای دریافت راهنماهای اجرای مفاهیم ذکر شده می‌توانید به بخش راهنمای کانتینر ابری مراجعه کنید.