УскоряванС Π½Π° Ansible с Mitogen

Ansible стана Π΅Π΄ΠΈΠ½ ΠΎΡ‚ Π½Π°ΠΉ-популярнитС Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Π½Π° систСмната конфигурация. Π‘Π»Π΅Π΄ Π΅ Π·Π°ΠΊΡƒΠΏΠ΅Π½ ΠΎΡ‚ Red Hat ΠΏΡ€Π΅Π· 2015 Π³. броят участници Π² ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° Π½Π°Π΄Ρ…Π²ΡŠΡ€Π»ΠΈ хиляди ΠΈ Ansible стана вСроятно Π½Π°ΠΉ-ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π°Ρ‚Π° систСма Π·Π° внСдряванС ΠΈ оркСстрация. Π¨ΠΈΡ€ΠΎΠΊΠ°Ρ‚Π° ΠΌΡƒ Π³Π°ΠΌΠ° ΠΎΡ‚ прилоТСния Π΅ ΠΌΠ½ΠΎΠ³ΠΎ впСчатляваща.

Ansible Ρ€Π°Π±ΠΎΡ‚ΠΈ ΠΏΡ€Π΅Π· SSH Π²Ρ€ΡŠΠ·ΠΊΠΈ към ΠΎΡ‚Π΄Π°Π»Π΅Ρ‡Π΅Π½ΠΈ хостовС. Π’ΠΎΠΉ отваря SSH сСсия, Π²Π»ΠΈΠ·Π° Π² систСмата, ΠΊΠΎΠΏΠΈΡ€Π° ΠΊΠΎΠ΄Π° Π½Π° Python ΠΏΠΎ ΠΌΡ€Π΅ΠΆΠ°Ρ‚Π° ΠΈ Π³ΠΎ записва Π² ΠΎΡ‚Π΄Π΅Π»Π΅Π½ Π²Ρ€Π΅ΠΌΠ΅Π½Π΅Π½ Ρ„Π°ΠΉΠ». Π‘Π»Π΅Π΄ Ρ‚ΠΎΠ²Π° Ρ‚ΠΎΠΉ изпълнява Ρ‚ΠΎΠ·ΠΈ Ρ„Π°ΠΉΠ» Π½Π° ΠΎΡ‚Π΄Π°Π»Π΅Ρ‡Π΅Π½Π°Ρ‚Π° машина. Цялата Ρ‚Π°Π·ΠΈ послСдоватСлност ΠΎΡ‚ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ Π΅ доста дълга ΠΈ досадна, Ρ‚Π°ΠΊΠ° Ρ‡Π΅ ΠΈΠΌΠ° Ρ€Π°Π·Π»ΠΈΡ‡Π½ΠΈ Π½Π°Ρ‡ΠΈΠ½ΠΈ Π·Π° Π½Π΅ΠΉΠ½ΠΎΡ‚ΠΎ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€Π°Π½Π΅.

Π•Π΄ΠΈΠ½ ΠΎΡ‚ Ρ‚Π΅Π·ΠΈ Π½Π°Ρ‡ΠΈΠ½ΠΈ Π΅ SSH Ρ‚Ρ€ΡŠΠ±ΠΎΠΏΡ€ΠΎΠ²ΠΎΠ΄ΠΈ ΠΊΠΎΠ΅Ρ‚ΠΎ Π²ΠΈ позволява Π΄Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ‚Π΅ Π΅Π΄Π½Π° SSH сСсия Π·Π° изпълнСниС Π½Π° инструкции, вмСсто Π΄Π° отварятС Π½ΠΎΠ²Π° сСсия всСки ΠΏΡŠΡ‚, ΠΊΠΎΠ΅Ρ‚ΠΎ ΠΌΠΎΠΆΠ΅ Π΄Π° Π½ΠΈ спСсти ΠΌΠ½ΠΎΠ³ΠΎ Π²Ρ€Π΅ΠΌΠ΅. (Π‘Π°ΠΌΠΎ Π½Π΅ забравяйтС Π΄Π° ΠΈΠ·ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅ requiretty настройка Π·Π° sudo във вашия /etc/sudoers Ρ„Π°ΠΉΠ» Π½Π° ΠΎΡ‚Π΄Π°Π»Π΅Ρ‡Π΅Π½Π°Ρ‚Π° машина)

Нов Π½Π°Ρ‡ΠΈΠ½ Π·Π° ΠΎΠ²ΡŠΡ€ΠΊΠ»ΠΎΠΊΠ²Π°Π½Π΅ Π½Π° Ansible Π΅ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° Π½Π° Python, Π½Π°Ρ€Π΅Ρ‡Π΅Π½Π° ΠΌΠΈΡ‚ΠΎΠ³Π΅Π½. Ако някой Π½Π΅ Π΅ Ρ‡ΡƒΠ²Π°Π» Π·Π° Π½Π΅Π³ΠΎ, Ρ‰Π΅ опиша Π½Π°ΠΊΡ€Π°Ρ‚ΠΊΠΎ функционалността ΠΌΡƒ. Π’ΠΎΠΉ позволява Π±ΡŠΡ€Π·ΠΎ изпълнСниС Π½Π° ΠΊΠΎΠ΄ Π½Π° Python Π½Π° ΠΎΡ‚Π΄Π°Π»Π΅Ρ‡Π΅Π½Π° машина, Π° Ansible Π΅ само Π΅Π΄ΠΈΠ½ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π·Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅. Mitogen ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π° UNIX ΠΊΠ°Π½Π°Π» Π½Π° ΠΎΡ‚Π΄Π°Π»Π΅Ρ‡Π΅Π½Π°Ρ‚Π° машина ΠΈ ΠΏΡ€Π΅Ρ…Π²ΡŠΡ€Π»Ρ Python ΠΊΠΎΠ΄, компрСсиран с zlib ΠΈ сСриализиран с pickle. Π’ΠΎΠ²Π° ΠΏΠΎΠΌΠ°Π³Π° Π΄Π° Π³ΠΎ Π·Π°Π²ΡŠΡ€ΡˆΠΈΡ‚Π΅ ΠΏΠΎ-Π±ΡŠΡ€Π·ΠΎ ΠΈ спСстява Ρ‚Ρ€Π°Ρ„ΠΈΠΊ. Ако сС интСрСсуватС ΠΎΡ‚ ΠΏΠΎ-ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎ обяснСниС, Π½Π°ΠΉ-Π΄ΠΎΠ±Ρ€Π΅ ΠΏΡ€ΠΎΡ‡Π΅Ρ‚Π΅Ρ‚Π΅ Π·Π° Ρ‚ΠΎΠ²Π° Π½Π° страницата "Как Ρ€Π°Π±ΠΎΡ‚ΠΈ". Но днСс Ρ‰Π΅ сС ΡΡŠΡΡ€Π΅Π΄ΠΎΡ‚ΠΎΡ‡ΠΈΠΌ само Π²ΡŠΡ€Ρ…Ρƒ Ρ‚ΠΎΠ²Π° ΠΊΠ°ΠΊ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°Ρ‚Π° Ρ€Π°Π±ΠΎΡ‚ΠΈ с Ansible.

Mitogen ΠΏΡ€ΠΈ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈ обстоятСлства ΠΌΠΎΠΆΠ΅ Π΄Π° ускори вашия Ansible ΠΊΠΎΠ΄ няколко ΠΏΡŠΡ‚ΠΈ ΠΈ Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»Π½ΠΎ Π΄Π° Π½Π°ΠΌΠ°Π»ΠΈ ΠΏΠΎΡ‚Ρ€Π΅Π±Π»Π΅Π½ΠΈΠ΅Ρ‚ΠΎ Π½Π° Ρ‚Ρ€Π°Ρ„ΠΈΠΊ. НСка Π΄Π° Ρ€Π°Π·Π³Π»Π΅Π΄Π°ΠΌΠ΅ Π½Π°ΠΉ-популярнитС случаи Π½Π° ΡƒΠΏΠΎΡ‚Ρ€Π΅Π±Π° ΠΈ Π΄Π° Π²ΠΈΠ΄ΠΈΠΌ ΠΊΠΎΠ»ΠΊΠΎ Π½ΠΈ ΠΏΠΎΠΌΠ°Π³Π°Ρ‚.

Използвам Ansible Π½Π°ΠΉ-Π²Π΅Ρ‡Π΅ Π·Π°: създаванС Π½Π° ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΎΠ½Π½ΠΈ Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅ Π½Π° ΠΎΡ‚Π΄Π°Π»Π΅Ρ‡Π΅Π½Π° машина, инсталиранС Π½Π° ΠΏΠ°ΠΊΠ΅Ρ‚ΠΈ, ΠΊΠΎΠΏΠΈΡ€Π°Π½Π΅ Π½Π° Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅ към ΠΈ ΠΎΡ‚ ΠΎΡ‚Π΄Π°Π»Π΅Ρ‡Π΅Π½Π°Ρ‚Π° машина. МоТС Π±ΠΈ ΠΈΠΌΠ°Ρ‚Π΅ Π΄Ρ€ΡƒΠ³ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΈ - Π½Π°ΠΏΠΈΡˆΠ΅Ρ‚Π΅ Π² ΠΊΠΎΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΡ‚Π΅.

Π”Π° Π²ΡŠΡ€Π²ΠΈΠΌ!

ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡΡ‚Π° Π½Π° Mitogen Π·Π° Ansible Π΅ ΠΌΠ½ΠΎΠ³ΠΎ проста:
Π˜Π½ΡΡ‚Π°Π»ΠΈΡ€Π°ΠΉΡ‚Π΅ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°Ρ‚Π° Mitogen:

pip install mitogen

Π‘Π΅Π³Π° ΠΈΠΌΠ° Π΄Π²Π° Π΅ΠΊΠ²ΠΈΠ²Π°Π»Π΅Π½Ρ‚Π½ΠΈ Π½Π°Ρ‡ΠΈΠ½Π° - ΠΈΠ»ΠΈ Π΄Π° ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€ΠΈΡ€Π°Ρ‚Π΅ ΠΎΠΏΡ†ΠΈΠΈΡ‚Π΅ Π² конфигурационния Ρ„Π°ΠΉΠ» ansible.cfg, ΠΈΠ»ΠΈ Π΄Π° Π·Π°Π΄Π°Π΄Π΅Ρ‚Π΅ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΈΡ‚Π΅ ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ Π½Π° срСдата.

Π”Π° ΠΏΡ€ΠΈΠ΅ΠΌΠ΅ΠΌ, Ρ‡Π΅ ΠΏΡŠΡ‚ΡΡ‚ Π΄ΠΎ инсталирания Mitogen Ρ‰Π΅ бъдС /usr/lib/python2.7/site-packages/ansible_mitogen/plugins/strategy. Π’ΠΎΠ³Π°Π²Π°:

export ANSIBLE_STRATEGY_PLUGINS=/usr/lib/python2.7/site-packages/ansible_mitogen/plugins/strategy
export ANSIBLE_STRATEGY=mitogen_linear

ΠΈΠ»ΠΈ

[defaults]
strategy = mitogen_linear
strategy_plugins = /usr/lib/python2.7/site-packages/ansible_mitogen/plugins/strategy

НСка инсталирамС Ansible във virtualenv, със ΠΈ Π±Π΅Π· Mitogen:

virtualenv mitogen_ansible
./mitogen_ansible/bin/pip install ansible==2.7.10 mitogen
virtualenv pure_ansible
./pure_ansible/bin/pip install ansible==2.7.10

Моля, ΠΎΠ±ΡŠΡ€Π½Π΅Ρ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, Ρ‡Π΅ Mitogen 0.2.7 Π½Π΅ Ρ€Π°Π±ΠΎΡ‚ΠΈ с Ansible 2.8 (ΠΎΡ‚ ΠΌΠ°ΠΉ 2019 Π³.)

БъздаванС на псСвдоними:

alias pure-ansible-playbook='$(pwd)/pure_ansible/bin/ansible-playbook'
alias mitogen-ansible-playbook='ANSIBLE_STRATEGY_PLUGINS=$(pwd)/mitogen_ansible/lib/python3.7/site-packages/ansible_mitogen/plugins/strategy ANSIBLE_STRATEGY=mitogen_linear $(pwd)/mitogen_ansible/bin/ansible-playbook'

Π‘Π΅Π³Π° Π½Π΅ΠΊΠ° сС ΠΎΠΏΠΈΡ‚Π°ΠΌΠ΅ Π΄Π° стартирамС ΠΊΠ½ΠΈΠ³Π° Π·Π° ΠΈΠ³Ρ€Π°, която създава Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅ Π½Π° ΠΎΡ‚Π΄Π°Π»Π΅Ρ‡Π΅Π½Π° машина:

---
- hosts: all
  gather_facts: false
  tasks:
    - name: Create files with copy content module
      copy:
        content: |
          test file {{ item }}
        dest: ~/file_{{ item }}
      with_sequence: start=1 end={{ n }}

И Π½Π΅ΠΊΠ° Π³ΠΎ стартирамС с ΠΈ Π±Π΅Π· Mitogen, Π·Π° Π΄Π° създадСм 10 Ρ„Π°ΠΉΠ»Π°:

time mitogen-ansible-playbook file_creation.yml -i hosts -e n=10 &>/dev/null

real    0m2.603s
user    0m1.152s
sys     0m0.096s

time pure-ansible-playbook file_creation.yml -i hosts -e n=10 &>/dev/null

real    0m5.908s
user    0m1.745s
sys     0m0.643s

Π’ΠΈΠΆΠ΄Π°ΠΌΠ΅ Π΄Π²ΡƒΠΊΡ€Π°Ρ‚Π½ΠΎ ΠΏΠΎΠ΄ΠΎΠ±Ρ€Π΅Π½ΠΈΠ΅. НСка ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΠΌ Π·Π° 2, 20, ..., 30 Ρ„Π°ΠΉΠ»Π°:

time pure-ansible-playbook file_creation.yml -i hosts -e n=100 &>/dev/null

real    0m51.775s
user    0m8.039s
sys     0m6.305s

time mitogen-ansible-playbook file_creation.yml -i hosts -e n=100 &>/dev/null

real    0m4.331s
user    0m1.903s
sys     0m0.197s

Π’ Ρ€Π΅Π·ΡƒΠ»Ρ‚Π°Ρ‚ Π½Π° Ρ‚ΠΎΠ²Π° ускорихмС ΠΈΠ·ΠΏΡŠΠ»Π½Π΅Π½ΠΈΠ΅Ρ‚ΠΎ ΠΏΠΎΠ²Π΅Ρ‡Π΅ ΠΎΡ‚ 10 ΠΏΡŠΡ‚ΠΈ!
Π‘Π΅Π³Π° Π½Π΅ΠΊΠ° ΠΎΠΏΠΈΡ‚Π°ΠΌΠ΅ Ρ€Π°Π·Π»ΠΈΡ‡Π½ΠΈ сцСнарии ΠΈ Π΄Π° Π²ΠΈΠ΄ΠΈΠΌ ΠΊΠΎΠ»ΠΊΠΎ ΠΏΠΎ-Π±ΡŠΡ€Π·ΠΎ Ρ€Π°Π±ΠΎΡ‚ΠΈ всичко Π·Π° нас:

  • Π‘ΠΊΡ€ΠΈΠΏΡ‚ Π·Π° ΠΊΠΎΠΏΠΈΡ€Π°Π½Π΅ Π½Π° Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅ Π½Π° ΠΎΡ‚Π΄Π°Π»Π΅Ρ‡Π΅Π½ хост ΠΎΡ‚ Π»ΠΎΠΊΠ°Π»Π΅Π½ (с ΠΌΠΎΠ΄ΡƒΠ»Π° copy):
    УскоряванС Π½Π° Ansible с Mitogen

  • Π‘ΠΊΡ€ΠΈΠΏΡ‚ Π·Π° създаванС Π½Π° Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅ Π½Π° ΠΎΡ‚Π΄Π°Π»Π΅Ρ‡Π΅Π½ хост с copy ΠΌΠΎΠ΄ΡƒΠ»:
    УскоряванС Π½Π° Ansible с Mitogen

  • Π‘Ρ†Π΅Π½Π°Ρ€ΠΈΠΉ с изтСглянС Π½Π° Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅ ΠΎΡ‚ ΠΎΡ‚Π΄Π°Π»Π΅Ρ‡Π΅Π½ хост към Π»ΠΎΠΊΠ°Π»Π΅Π½:
    УскоряванС Π½Π° Ansible с Mitogen

НСка ΠΎΠΏΠΈΡ‚Π°ΠΌΠ΅ сцСнарий с няколко (3) ΠΎΡ‚Π΄Π°Π»Π΅Ρ‡Π΅Π½ΠΈ машини, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ сцСнарий с ΠΊΠΎΠΏΠΈΡ€Π°Π½Π΅ Π½Π° Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅ Π½Π° ΠΎΡ‚Π΄Π°Π»Π΅Ρ‡Π΅Π½ хост:
УскоряванС Π½Π° Ansible с Mitogen

ΠšΠ°ΠΊΡ‚ΠΎ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° Π²ΠΈΠ΄ΠΈΡ‚Π΅, Mitogen Π½ΠΈ спСстява Π²Ρ€Π΅ΠΌΠ΅ ΠΈ Ρ‚Ρ€Π°Ρ„ΠΈΠΊ Π² Ρ‚Π΅Π·ΠΈ сцСнарии. Но Π°ΠΊΠΎ тясното място Π½Π΅ Π΅ Π² Ansible, Π° Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ във I/O Π½Π° диск ΠΈΠ»ΠΈ ΠΌΡ€Π΅ΠΆΠ°, ΠΈΠ»ΠΈ някъдС Π΄Ρ€ΡƒΠ³Π°Π΄Π΅, Ρ‚ΠΎΠ³Π°Π²Π° Π΅ Ρ‚Ρ€ΡƒΠ΄Π½ΠΎ Π΄Π° ΠΎΡ‡Π°ΠΊΠ²Π°ΠΌΠ΅ Mitogen Π΄Π° Π½ΠΈ ΠΏΠΎΠΌΠΎΠ³Π½Π΅.

НСка ΠΎΠΏΠΈΡ‚Π°ΠΌΠ΅ скрипт с инсталиранС Π½Π° ΠΏΠ°ΠΊΠ΅Ρ‚ΠΈ с ΠΌΠΎΠ΄ΡƒΠ»ΠΈ yum/dnf ΠΈ python с ΠΏΠΎΠΌΠΎΡ‰Ρ‚Π° Π½Π° pip. ΠŸΠ°ΠΊΠ΅Ρ‚ΠΈΡ‚Π΅ бяха ΠΊΠ΅ΡˆΠΈΡ€Π°Π½ΠΈ, Π·Π° Π΄Π° Π½Π΅ зависят ΠΎΡ‚ ΠΌΡ€Π΅ΠΆΠΎΠ²ΠΈ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠΈ:

---
- hosts: all
  gather_facts: false
  tasks:
    - name: Install packages
      become: true
      package:
        name:
          - samba
          - httpd
          - nano
          - ruby
        state: present

    - name: Install pip modules
      become: true
      pip:
        name:
          - pytest-split-tests
          - bottle
          - pep8
          - flask
        state: present

Π‘ Mitogen ΠΎΡ‚Π½Π΅ 12 сСкунди, ΠΊΠΎΠ»ΠΊΠΎΡ‚ΠΎ ΠΈ Π±Π΅Π· Π½Π΅Π³ΠΎ.
На страницата Mitogen Π·Π° страница Ansible ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° Ρ€Π°Π·Π³Π»Π΅Π΄Π°Ρ‚Π΅ Π΄Ρ€ΡƒΠ³ΠΈ Π±Π΅Π½Ρ‡ΠΌΠ°Ρ€ΠΊΠΎΠ²Π΅ ΠΈ тСстовС. ΠšΠ°ΠΊΡ‚ΠΎ сС посочва Π½Π° страницата:

Mitogen Π½Π΅ ΠΌΠΎΠΆΠ΅ Π΄Π° ускори ΠΌΠΎΠ΄ΡƒΠ»Π°, ΠΊΠΎΠ³Π°Ρ‚ΠΎ Ρ‚ΠΎΠΉ Ρ€Π°Π±ΠΎΡ‚ΠΈ. МоТС само Π΄Π° Π½Π°ΠΏΡ€Π°Π²ΠΈ ΠΈΠ·ΠΏΡŠΠ»Π½Π΅Π½ΠΈΠ΅Ρ‚ΠΎ Π½Π° Ρ‚ΠΎΠ·ΠΈ ΠΌΠΎΠ΄ΡƒΠ» възмоТно Π½Π°ΠΉ-Π±ΡŠΡ€Π·ΠΎ.

Π•Ρ‚ΠΎ Π·Π°Ρ‰ΠΎ Π΅ Π²Π°ΠΆΠ½ΠΎ Π΄Π° Π½Π°ΠΌΠ΅Ρ€ΠΈΡ‚Π΅ своитС тСсни мСста във Π²Π°ΡˆΠ΅Ρ‚ΠΎ внСдряванС ΠΈ Π°ΠΊΠΎ Ρ‚Π΅ сС Π΄ΡŠΠ»ΠΆΠ°Ρ‚ Π½Π° Ansible, Ρ‚ΠΎΠ³Π°Π²Π° Mitogen Ρ‰Π΅ Π²ΠΈ ΠΏΠΎΠΌΠΎΠ³Π½Π΅ Π΄Π° Π³ΠΈ Ρ€Π°Π·Ρ€Π΅ΡˆΠΈΡ‚Π΅ ΠΈ Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»Π½ΠΎ Π΄Π° ускори ΠΈΠ·ΠΏΡŠΠ»Π½Π΅Π½ΠΈΠ΅Ρ‚ΠΎ Π½Π° Π²Π°ΡˆΠΈΡ‚Π΅ ΠΊΠ½ΠΈΠ³ΠΈ Π·Π° ΠΈΠ³Ρ€Π°.

Π˜Π·Ρ‚ΠΎΡ‡Π½ΠΈΠΊ: www.habr.com

ДобавянС Π½Π° Π½ΠΎΠ² ΠΊΠΎΠΌΠ΅Π½Ρ‚Π°Ρ€