از اونجایی که توی ایران استفاده از چنین پلتفرم هایی خیلی سخته و در صورت امکان ، هزینه های دلاری سنگینی هم ایجاد میکنه ، میتونیم کلاستر K8S رو خودمون به صورت Bare-Metal پیاده سازی کنیم. به این صورت که روی ماشین های مجازی یا سرور های مختلف کلاستر شخصی درست کرده و ازش استفاده می کنیم.

وقتی صحبت از کلاستر میشه ، مسلما شرایط همیشگی پابرجاست! یعنی چی ؟

هر کلاستر از یکسری Node تشکیل میشه که وظایف مربوط به خودشون رو انجام میدن. در این بین یک یا چند Node به عنوان مدیر کلاستر انتخاب میشن و وظیفه مدیریت کلاستر رو به عهده میگیرن. اینجا هم ما همین شرایط رو داریم و Node های ما شامل Master و Worker میشن.

kubernetes-cluster-components

پیش نیاز ها

برای تهییه این مطلب از چنین کانفیگی استفاده شده :

  • سرور G8 DL360
  • 3 ماشین مجازی ( 1 ماشین به عنوان Master و 2 ماشین به عنوان Worker )
  • ماشین Master با 32 گیگ رم و 4 هسته
  • ماشین های Worker با 16 گیگ رم و 2 هسته
  • سیستم عامل Ubuntu Server نسخه 18.04
  • ابزار Ansible برای Automation و استقرار کلاستر

توجه داشته باشید که اختصاص منابع برای زیرساخت و یا تعیین تعداد Node ها با توجه به نیاز خودتون انجام میشه

آماده سازی

قبل از اینکه شروع به پیاده سازی کلاستر کنیم ، لازمه تا یکسری کارها انجام بدیم :

  • برای هر ماشین hostname مناسب تنظیم کنید. در اینجا به این صورت ماشین ها رو ساختم
    K8s-manager
    K8s-node-1
    K8s-node-2
  • روی هر ماشین timezone ایران رو تنظیم کنید تا ساعت به درستی نشون داده بشه
  • از اونجایی که تمامی مخازن مورد نیاز برای دریافت Image های داکر و منابع مورد نیاز K8S تحریمه ، حتما Proxy مناسب روی ماشین ها تنظیم کنید
  • برای داشتن سرعت بهتر موقع نصب پکیج ها ، میتونید از Mirror های دیگه ای استفاده کنید. برای مثال این مخزن مربوط به ابر XaaS که سرعت خوبی هم داره : http://ubuntu.xaas.ir/ubuntu

تنظیم Ansible

برای ساده شدن روند پیاده سازی از Ansible استفاده می کنیم و نیازه تا فایل hosts رو به این صورت تنظیم کنیم :

[all:vars]
ansible_user=kube
ansible_password=changeme
ansible_sudo_pass=changeme
ansible_python_interpreter=/usr/bin/python3

[managers]
manager ansible_host=192.168.1.14

[nodes]
node1 ansible_host=192.168.1.16
node2 ansible_host=192.168.1.17

تو این قسمت آدرس آی پی ماشین ها ، نام کاربری و کلمه عبور مناسب باید قرار داده بشه. موقع نصب نام کاربری و کلمه عبور یکسانی برای ماشین ها استفاده کنید تا اینجا به مشکل نخورید. همچنین نسخه پیشفرض پایتون هم برای Ansible مشخص میکنیم. قبل از تنظیم این گزینه از آدرس صحیح پایتون مطمئن بشید ( میتونید از دستور which python یا which python3 استفاده کنید ).

در صورتی که تازه ماشین ها رو ساختید حتما یکبار از طریق SSH به اون ها متصل بشید تا fingerprint ها هم تنظیم بشه

برای اینکه مطمئن بشید همه چیز درست تنظیم شده و آماده است دستور زیر رو اجرا کنید :

ansible all -m ping

چنین خروجی باید داشته باشید :

ping

راه اندازی کلاستر

در اینجا چند فایل Playbook داریم که مرحله به مرحله اون ها رو اجرا می کنیم. اولین مرحله راه اندازی ، نصب Docker بوده که باید روی تمام ماشین ها انجام بشه.

نصب داکر

یک فایل playbook با نام docker_tasks.yml به اینصورت بسازید :

- name: Install docker packages
  apt:
    name: "{{ item }}"
    state: present
    update_cache: yes
  retries: 3
  delay: 10
  register: result
  until: result is succeeded
  with_items:
    - apt-transport-https
    - ca-certificates
    - curl
    - software-properties-common
  tags:
    - docker

- name: Add GPG key
  apt_key:
    url: https://download.docker.com/linux/ubuntu/gpg
    state: present
  retries: 3
  delay: 10
  register: result
  until: result is succeeded
  tags:
    - docker

- name: Verify that we have the key with the fingerprint
  apt_key:
    id: 0EBFCD88
    state: present
  retries: 3
  delay: 10
  register: result
  until: result is succeeded
  tags:
    - docker

- name: Set up the stable repository
  apt_repository:
    repo: deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable
    state: present
  retries: 3
  delay: 10
  register: result
  until: result is succeeded
  tags:
    - docker

- name: Update apt packages
  apt:
    update_cache: yes
  retries: 3
  delay: 10
  register: result
  until: result is succeeded
  tags:
    - docker

- name: Install docker
  apt:
    name: "{{ item }}"
    state: present
    update_cache: yes
  retries: 3
  delay: 10
  register: result
  until: result is succeeded
  with_items:
    - docker-ce
    - docker-ce-cli
    - containerd.io
  tags:
    - docker

- name: Add "kube" user to "docker" group
  user:
    name: "kube"
    group: "docker"
    append: yes
  retries: 3
  delay: 10
  register: result
  until: result is succeeded
  tags:
    - docker

وظایف قرار داده شده در این فایل به ترتیب شامل این موارد میشه :

  • نصب پکیج های مورد نیاز
  • اضافه کردن کلید GPG داکر
  • بررسی صحت کلید اضافه شده
  • اضافه کردن مخزن داکر ( توجه کنید که اینجا از مخزن مربوط به ابونتو 18.04 استفاده شده )
  • آپدیت کردن مخزن ها
  • نصب داکر
  • اضافه کردن کاربر پیشفرض ماشین ها به گروه داکر

توجه داشته باشید که لازم نیست این فایل جداگانه اجرا بشه. برای همین فقط شامل لیست Task های مورد نیازه و بعدا داخل فایل اصلی Include میشه.

نصب K8S

فایلی با نام dependencies.yml بسازید. این فایل شامل Task های مورد نیاز برای نصب کلیه پیش نیاز های کلاسترمون میشه و باید به این صورت باشه :

--- # Install Kubernetes

- hosts: all
  remote_user: kube
  become: yes
  become_method: sudo
  connection: ssh
  gather_facts: yes

  tasks:
    - include_tasks: docker_tasks.yml

    - name: Disabling Swap on all nodes
      shell: swapoff -a

    - name: Commenting Swap entries in /etc/fstab
      replace:
        path: /etc/fstab
        regexp: "(.*swap*)"
        replace: '#\1'

    - name: Add Kubernetes apt-key
      apt_key:
        url: https://packages.cloud.google.com/apt/doc/apt-key.gpg
        state: present
      retries: 3
      delay: 10
      register: result
      until: result is succeeded

    - name: Add Kubernetes APT repository
      apt_repository:
        repo: deb http://apt.kubernetes.io/ kubernetes-xenial main
        state: present
        filename: "kubernetes"
      retries: 3
      delay: 10
      register: result
      until: result is succeeded

    - name: Install kubelet
      apt:
        name: kubelet
        state: present
        update_cache: true
      retries: 3
      delay: 10
      register: result
      until: result is succeeded

    - name: Install kubeadm
      apt:
        name: kubeadm
        state: present
      retries: 3
      delay: 10
      register: result
      until: result is succeeded

- hosts: managers
  remote_user: kube
  become: yes
  become_method: sudo
  connection: ssh
  gather_facts: yes

  tasks:
    - name: Install kubectl
      apt:
        name: kubectl
        state: present
      retries: 3
      delay: 10
      register: result
      until: result is succeeded

وظایف قرار داده شده در این فایل به ترتیب شامل این موارد میشه :

  • وظایف مربوط به نصب داکر که در مرحله قبل نوشتیم Include میشه
  • برای کار با kubelet نیاز داریم تا swap روی کلیه ماشین ها غیرفعال بشه پس با این دستور این کار رو انجام میدیم
  • از اونجایی که دستور بالا به صورت موقت Swap رو غیرفعال میکنه ، با ویرایش فایل fstab برای اجراهای بعدی هم مطمئن میشیم Swap غیرفعال باقی بمونه
  • اضافه کردن کلید GPG مربوط به K8S
  • اضافه کردن مخزن K8S
  • نصب kubelet
  • نصب kubeadm

این موارد روی تمام Node ها نصب میشه و در انتها فقط روی نود Manager نصب kubectl رو انجام میدیم. این فایل رو با استفاده از دستور زیر اجرا می کنیم :

ansible-playbook dependencies.yml

ور در پایان چنین خروجی مد نظر ماست :

depend-done

تا اینجا همه چیز آماده شده و میتونیم کلاستر خودمون رو تشکیل بدیم. مدیر کلاستر یا همون Manager/Master خودش رو معرفی میکنه و با ارائه Token به Worker ها اجازه میده بهش بپیوندند. پس ابتدا نیازه تا Manager خودمون رو تنظیم کنیم.

پیکربندی Manager

برای این کار فایلی با نام manager.yml به این صورت تنظیم کنید :

--- # Setup master node

- hosts: managers
  remote_user: kube
  become: yes
  become_method: sudo
  connection: ssh
  gather_facts: yes

  tasks:
    - name: Remove debug file
      file:
        path: $HOME/cluster_init.txt
        state: absent

    - name: Initialize the cluster
      shell: kubeadm init --pod-network-cidr=10.244.0.0/16 >> cluster_init.txt
      args:
        chdir: $HOME
        creates: cluster_init.txt

    - name: Create .kube directory
      file:
        path: $HOME/.kube
        state: directory
        mode: 0755

    - name: Copy admin.conf to user's kube config
      copy:
        src: /etc/kubernetes/admin.conf
        dest: $HOME/.kube/config
        remote_src: yes
        owner: kube

    - name: Remove debug file
      file:
        path: $HOME/pod_network.txt
        state: absent

    - name: Install Pod network
      shell: kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml >> pod_network.txt
      args:
        chdir: $HOME
        creates: pod_network.txt
      retries: 3
      delay: 10
      register: result
      until: result is succeeded

برای این مرحله از فایل هایی جهت debug هم استفاده میشه تا درصورت بروز مشکل از علتش آگاه بشید. وظایف قرار داده شده در این فایل به ترتیب شامل این موارد میشه :

  • حذف فایل debug مربوط به تنظیم Manager ( در صورت وجود )
  • تنظیم نود Manager با استفاده از kubeadm و ذخیره نتایج در فایل debug. در اینجا بازه آی پی مورد نظر برای شبکه کلاستر رو هم تعریف می کنیم.
  • ساخت دایرکتوری برای قرار دادن فایل تنظیمات
  • کپی کردن فایل تنظیمات پیشفرض K8S به دایرکتوری که در مرحله قبل ساختیم
  • حذف فایل debug مربوط به تنظیم شبکه کلاستر ( در صورت وجود )
  • تنظیم شبکه کلاستر. برای این مورد از Flannel استفاده می کنیم. ابزاری بسیار ساده است که شبکه لایه 3 برامون درست میکنه. جهت اطلاعات بیشتر به ریپازیتوری پروژه در این آدرس مراجعه کنید. در این حین وضعیت و اطلاعات دستور ، در فایل debug مربوطه ذخیره میشه.

با اجرای این فایل نود مدیریتی کلاستر به تدریج آماده میشه. از اونجا که برای راحتی مشاهده وضعیت از فایل debug استفاده کردیم می تونید با مشاهده محتوای اون از وضعیت نصب آگاه بشید.

این فایل رو هم اجرا می کنیم :

ansible-playbook manager.yml
    
tail -f $HOME/cluster_init.txt

manager-init

این مرحله تقریبا باید بین 2 تا 5 دقیقه طول بکشه ( مسلما به سرعت اینترنت بستگی داره ).

پیکربندی Worker ها

این مرحله بسیار ساده است. همه چیز آمده است و مدیر کلاستر هم اطلاعات مورد نیاز رو محیا کرده تا همه Worker ها به مجموعه متصل بشن. برای تنظیم این نود ها فایلی با نام nodes.yml با محتوای زیر آماده کنید :

--- # Setup worker nodes

- hosts: managers
  remote_user: kube
  become: yes
  become_method: sudo
  connection: ssh
  gather_facts: yes

  tasks:
    - name: Get join command
      shell: kubeadm token create --print-join-command
      register: join_command_raw

    - name: Set join command
      set_fact:
        join_command: "{{ join_command_raw.stdout_lines[0] }}"

- hosts: nodes
  remote_user: kube
  become: yes
  become_method: sudo
  connection: ssh
  gather_facts: yes

  tasks:
    - name: Remove debug file
      file:
        path: $HOME/joined.txt
        state: absent

    - name: Join cluster
      shell: "{{ hostvars['manager'].join_command }} >> joined.txt"
      args:
        chdir: $HOME
        creates: joined.txt
      register: node

در ابتدا نیازه تا دو مورد در نود Manager اجرا بشه :

  • از اونجایی که Token مورد نظر برای اتصال ، در مرحله قبل ( موقع تنظیم کلاستر با kubeadm ) ساخته شده و بهمون نمایش داده میشه لازمه تا دوباره یکی بسازیم و اون رو در خروجی نمایش بدیم. در این Task از یک متغییر برای ذخیره کردن مقادیر خروجی استفاده می کنیم تا بعدا Token ساخته شده رو استفاده کنیم. با اجرای این دستور یک Command در اختیار ما قرار داده میشه که با اجرای اون هر Worker میتونه به مجموعه اضافه بشه.
  • در این قسمت Command ساخته شده رو به صورت fact ذخیره میکنیم چون باید در Task های بعدی که مربوط به Worker هاست ازش استفاده کنیم.

حالا نوبت به تنظیم Worker هاست و دستور ساده ای هم داره :

  • حذف فایل debug مربوط به اضافه شدن Worker به مجموعه ( در صورت وجود )
  • مقدار Command مورد نظر برای اتصال رو که در مرحله قبلی به صورت fact ذخیره کردیم باید از hostvars دریافت کنیم. این دستور مستقیم اجرا میشه و در نهایت Worker به مجموعه اضافه میشه

یه نکته خیلی مهم !!

برای دریافت fact از اجراهای قبلی باید از نام host استفاده کنیم و نه نام گروه اون !!!! اگه دوباره به فایل hosts مربوط به Ansible مراجعه کنید ، چنین کانفیگی داریم :

[managers]
manager ansible_host=192.168.1.14

در اینجا managers نام گروه و manager نام host ماست که باید از اون برای استخراج fact استفاده بشه به این صورت :

hostvars['manager'].join_command

حالا با اجرای این فایل آخرین مرحله از ساخت کلاستر هم انجام میشه و همه چیز تکمیل میشه :

ansible-playbook nodes.yml

برای مشاهده وضعیت کلاستر با SSH به نود مدیریتی متصل بشید و دستور زیر رو اجرا کنید

nodes

تقریبا چند دقیقه طول میکشه تا نود های Worker آماده بشن. حالا کلاستر آماده است و میتونید سرویس های خودتون رو روی اون مستقر کنید.


فایل های کامل این آموزش در آدرس زیر موجوده :

https://github.com/hatamiarash7/MyWebSite_Projects/tree/master/kubernetes-cluster

هر سوالی در مورد پیاده سازی و تنظیم کلاستر های K8S داشتید در کامنت ها بپرسید یا ایمیل بفرستید :))