Ceph ื‘ืืžืฆืขื•ืช iSCSI - ืื• ืกืงื™ ื‘ืขืžื™ื“ื” ื‘ืขืจืกืœ

ื”ืื ื™ืฉ ื‘ื™ื ื™ื ื• (ื˜ืกืคื•ื‘ื•ื“ื•ื‘) ืฉืœื ืื•ื”ื‘ื™ื "ืืงืกื˜ืจื™ื ืžืงืฆื•ืขื™ื™ื"?

ื–ื” ืœื ืกื‘ื™ืจ - ืื—ืจืช ืœื ื”ื™ื™ื ื• ืžืกืชื•ื‘ื‘ื™ื ืขื ื”ืžื•ืฆืจ ื”ืžืขื ื™ื™ืŸ ื•ื”ืžืฆื—ื™ืง ื”ื–ื”.

ืจื‘ื™ื ืžืืœื” ืฉื”ื™ื• ืžืขื•ืจื‘ื™ื ื‘ืชืคืขื•ืœ ืฉืœ Ceph ื ืชืงืœื• ื‘ืžืงืจื” ืœื ืžืื•ื“ ืชื“ื™ืจ (ืื• ืœื™ืชืจ ื“ื™ื•ืง ืืคื™ืœื• ื ื“ื™ืจ ืžืื•ื“) ืื‘ืœ ืœืคืขืžื™ื ืžื‘ื•ืงืฉ - ื—ื™ื‘ื•ืจ ืฉืœ Ceph ื‘ืืžืฆืขื•ืช iSCSI ืื• FC. ื‘ืฉื‘ื™ืœ ืžื”? ื•ื‘ื›ืŸ, ืœืžืฉืœ, ืฉืœื— ืชืžื•ื ื” ืž-Ceph ืœืฉืจืช Windows ืื• Solaris ืฉืขื“ื™ื™ืŸ ืœื ืขื‘ืจ ื•ื™ืจื˜ื•ืืœื™ื–ืฆื™ื” ืžืกื™ื‘ื” ื›ืœืฉื”ื™. ืื• ื•ื™ืจื˜ื•ืืœื™ื–ืฆื™ื”, ืื‘ืœ ื‘ืืžืฆืขื•ืช hypervisor ืฉืœื ื™ื›ื•ืœ ืœืขืฉื•ืช Ceph - ื•ื›ื™ื“ื•ืข, ื™ืฉ ื”ืจื‘ื” ื›ืืœื”. ืœื“ื•ื’ืžื”? ื•ื‘ื›ืŸ, ืœืžืฉืœ, HyperV ืื• ESXi, ืฉื‘ื”ื ื ืขืฉื” ืฉื™ืžื•ืฉ ืคืขื™ืœ. ื•ืื ืขื•ืœื” ื”ืžืฉื™ืžื” ืฉืœ ื”ื’ืฉืช ืชืžื•ื ื” ืž-Ceph ืœืžื›ื•ื ืช ืื•ืจื—, ื–ื” ื”ื•ืคืš ืœืžืฉื™ืžื” ืžืื•ื“ ืžืจื’ืฉืช.

ืื– ื ืชื•ืŸ:

  1. ืืฉื›ื•ืœ Ceph ืฉื›ื‘ืจ ืคื•ืขืœ
  2. ืชืžื•ื ื” ืงื™ื™ืžืช ืฉื›ื‘ืจ ื™ืฉ ืœื”ื’ื™ืฉ ื‘ืืžืฆืขื•ืช iSCSI
  3. ืฉื ื”ื‘ืจื™ื›ื” mypool, ืฉื ืชืžื•ื ื” ืชืžื•ื ื” ืฉืœื™

ื”ืชื—ืœ?

ืงื•ื“ื ื›ืœ, ื›ืฉืื ื—ื ื• ืžื“ื‘ืจื™ื ืขืœ FC ืื• iSCSI, ื™ืฉ ืœื ื• ื™ืฉื•ื™ื•ืช ื›ืžื• ื™ื•ื–ื ื•ืžื˜ืจื”. ื”ื™ืขื“ ื”ื•ื ืœืžืขืฉื” ืฉืจืช, ื”ื™ื•ื–ื ื”ื•ื ืœืงื•ื—. ื”ืžืฉื™ืžื” ืฉืœื ื• ื”ื™ื ืœื”ื’ื™ืฉ ืืช ืชืžื•ื ืช ื”-Ceph ืœื™ื•ื–ื ื‘ืžื™ื ื™ืžื•ื ืžืืžืฅ. ื–ื” ืื•ืžืจ ืฉืขืœื™ื ื• ืœื”ืจื—ื™ื‘ ืืช ื”ื™ืขื“. ืื‘ืœ ืื™ืคื”, ื‘ืื™ื–ื” ืžื—ืฉื‘?

ืœืžืจื‘ื” ื”ืžื–ืœ, ื‘ืืฉื›ื•ืœ Ceph ื™ืฉ ืœื ื• ืœืคื—ื•ืช ืจื›ื™ื‘ ืื—ื“ ืฉื›ืชื•ื‘ืช ื”-IP ืฉืœื• ืงื‘ื•ืขื” ื•ืขืœื™ื• ืžื•ื’ื“ืจ ืื—ื“ ื”ืจื›ื™ื‘ื™ื ื”ื—ืฉื•ื‘ื™ื ื‘ื™ื•ืชืจ ืฉืœ Ceph, ื•ื”ืจื›ื™ื‘ ื”ื–ื” ื”ื•ื ื”ืžื•ื ื™ื˜ื•ืจ. ื‘ื”ืชืื ืœื›ืš, ืื ื• ืžืชืงื™ื ื™ื ืžื˜ืจืช iSCSI ืขืœ ื”ืžืกืš (ื•ื’ื ื™ื•ื–ื ื‘ื• ื–ืžื ื™ืช, ืœืคื—ื•ืช ืœื‘ื“ื™ืงื•ืช). ืขืฉื™ืชื™ ื–ืืช ื‘-CentOS, ืื‘ืœ ื”ืคืชืจื•ืŸ ืžืชืื™ื ื’ื ืœื›ืœ ื”ืคืฆื” ืื—ืจืช - ืืชื” ืจืง ืฆืจื™ืš ืœื”ืชืงื™ืŸ ืืช ื”ื—ื‘ื™ืœื•ืช ื‘ืฆื•ืจื” ื”ืžืงื•ื‘ืœืช ื‘ื”ืคืฆื” ืฉืœืš.

# yum -y install iscsi-initiator-utils targetcli

ืžื” ื”ืžื˜ืจื” ืฉืœ ื”ื—ื‘ื™ืœื•ืช ื”ืžื•ืชืงื ื•ืช?

  • targetcli - ื›ืœื™ ืขื–ืจ ืœื ื™ื”ื•ืœ ื™ืขื“ SCSI ื”ืžื•ื‘ื ื” ื‘ืœื™ื‘ืช ืœื™ื ื•ืงืก
  • iscsi-initiator-utils - ื—ื‘ื™ืœื” ืขื ื›ืœื™ ืขื–ืจ ื”ืžืฉืžืฉื™ื ืœื ื™ื”ื•ืœ ื™ื•ื–ื iSCSI ื”ืžื•ื‘ื ื” ื‘ืœื™ื‘ืช ืœื™ื ื•ืงืก

ืขืœ ืžื ืช ืœืฉืœื•ื— ืชืžื•ื ื” ื“ืจืš iSCSI ืœื™ื•ื–ื, ืงื™ื™ืžื•ืช ืฉืชื™ ืืคืฉืจื•ื™ื•ืช ืœืคื™ืชื•ื— ืื™ืจื•ืขื™ื - ื”ืฉืชืžืฉ ื‘-userspace backend ืฉืœ ื”ื™ืขื“ ืื• ื—ื‘ืจ ืืช ื”ืชืžื•ื ื” ื›ื”ืชืงืŸ ื‘ืœื•ืง ื’ืœื•ื™ ืœืžืขืจื›ืช ื”ื”ืคืขืœื” ื•ื™ื™ืฆื ืื•ืชื” ื‘ืืžืฆืขื•ืช iSCSI. ื ืœืš ื‘ื“ืจืš ื”ืฉื ื™ื™ื” - ื”-Userspace backend ืขื“ื™ื™ืŸ ื‘ืžืฆื‘ "ื ื™ืกื™ื•ื ื™" ื•ืงืฆืช ืœื ืžื•ื›ืŸ ืœืฉื™ืžื•ืฉ ืคืจื•ื“ื•ืงื˜ื™ื‘ื™. ื‘ื ื•ืกืฃ, ื™ืฉ ื‘ื• ืžืœื›ื•ื“ื•ืช, ืฉืขืœื™ื”ืŸ ืืคืฉืจ ืœื“ื‘ืจ ื”ืจื‘ื” ื•(ืื•ื™ ื–ื•ื•ืขื”!) ืœื”ืชื•ื•ื›ื—.

ืื ืื ื—ื ื• ืžืฉืชืžืฉื™ื ืืคื™ืœื• ื‘ื”ืคืฆื” ืงืฆืช ื™ืฆื™ื‘ื” ืขื ืžื—ื–ื•ืจ ืชืžื™ื›ื” ืืจื•ืš, ืื– ื”ืงืจื ืœ ืฉื™ืฉ ืœื ื• ื”ื•ื ื’ืจืกื” ืขืชื™ืงื” ื•ืขืชื™ืงื” ื›ืœืฉื”ื™. ืœื“ื•ื’ืžื”, ื‘-CentOS7 ื–ื” 3.10.*, ื‘-CentOS8 ื–ื” 4.19. ื•ืื ื—ื ื• ืžืขื•ื ื™ื™ื ื™ื ื‘ืงืจื ืœ ืฉืœ ืœืคื—ื•ืช 5.3 (ืื• ื™ื•ืชืจ ื ื›ื•ืŸ 5.4) ื•ืžืขืœื”. ืœืžื”? ื›ื™ ื›ื‘ืจื™ืจืช ืžื—ื“ืœ ืœืชืžื•ื ื•ืช Ceph ื™ืฉ ืกื˜ ืฉืœ ืืคืฉืจื•ื™ื•ืช ืžื•ืคืขืœื•ืช ืฉืื™ื ืŸ ืชื•ืืžื•ืช ืœื™ื‘ื•ืช ื™ืฉื ื•ืช ื™ื•ืชืจ. ื–ื” ืื•ืžืจ ืฉืื ื—ื ื• ืžื—ื‘ืจื™ื ืžืื’ืจ ืขื ืœื™ื‘ื” ื—ื“ืฉื” ืœื”ืคืฆื” ืฉืœื ื• (ืœื“ื•ื’ืžื”, ืขื‘ื•ืจ CentOS ื–ื” elrepo), ืžืชืงื™ืŸ ืืช ื”ื’ืจืขื™ืŸ ื”ื—ื“ืฉ ื•ืžืคืขื™ืœื™ื ืžื—ื“ืฉ ืืช ื”ืžืขืจื›ืช ื›ื“ื™ ืœืขื‘ื•ื“ ืขื ื”ืงืจื ืœ ื”ื—ื“ืฉ:

  • ื”ืชื—ื‘ืจ ืœืžื•ื ื™ื˜ื•ืจ ืฉื ื‘ื—ืจ ืœื ื™ืกื•ื™
  • ืื ื• ืžื—ื‘ืจื™ื ืžืื’ืจื™ elrepo ืœืคื™ ื”ื”ื•ืจืื•ืช - elrepo.org/tiki/tiki-index.php
  • ื”ืชืงืŸ ืืช ื”ืงืจื ืœ: yum -y โ€”enablerepo=elrepo-kernel ื”ืชืงืŸ kernel-ml
  • ื”ืคืขืœ ืžื—ื“ืฉ ืืช ื”ืฉืจืช ืขื ื”ืฆื’ (ื™ืฉ ืœื ื• ืฉืœื•ืฉื” ืžืกื›ื™ื, ื ื›ื•ืŸ?)

ื—ื™ื‘ื•ืจ ื”ืชืžื•ื ื” ื›ื”ืชืงืŸ ื‘ืœื•ืง

# rbd map mypool/myimage
/dev/rbd0

ื›ืœ ืžื” ืฉื ื•ืชืจ ื”ื•ื ืœื”ื’ื“ื™ืจ ืืช ื”ื™ืขื“. ื‘ื“ื•ื’ืžื” ื–ื•, ืื ื™ ืื’ื“ื™ืจ ืืช ื”ื™ืขื“ ื‘ืžื” ืฉื ืงืจื. ืžืฆื‘ ื”ื“ื’ืžื” - ืœืœื ืื™ืžื•ืช, ื’ืœื•ื™ ื•ื ื’ื™ืฉ ืœื›ื•ืœื. ื‘ืกื‘ื™ื‘ืช ื™ื™ืฆื•ืจ, ืกื‘ื™ืจ ืœื”ื ื™ื— ืฉืชืจืฆื” ืœื”ื’ื“ื™ืจ ืื™ืžื•ืช - ืื‘ืœ ื–ื” ืงืฆืช ืžื—ื•ืฅ ืœื˜ื•ื•ื— ื”ืชืจื’ื™ืœ ืฉืœ ื”ื™ื•ื ืจืง ื‘ืฉื‘ื™ืœ ื”ื›ื™ืฃ.

ืฆื•ืจ ืงืฆื” ืื—ื•ืจื™ ื‘ืฉื disk1 ื”ืžืฉื•ื™ืš ืœืงื•ื‘ืฅ /dev/rbd/mypool/myimage. ื”ืงื•ื‘ืฅ ืฉืฆื•ื™ืŸ ื”ื•ื ืงื™ืฉื•ืจ ืกืžืœื™ ืฉื ื•ืฆืจ ืื•ื˜ื•ืžื˜ื™ืช ืขืœ ื™ื“ื™ ื”ื“ืžื•ืŸ udev ืืœ /dev/rbd0. ืื ื• ืžืฉืชืžืฉื™ื ื‘ืงื™ืฉื•ืจ ืกืžืœื™ ืžื›ื™ื•ื•ืŸ ืฉืฉื ืžื›ืฉื™ืจ ื”-rbd ื™ื›ื•ืœ ืœื”ืฉืชื ื•ืช ื‘ื”ืชืื ืœืกื“ืจ ืฉื‘ื• ืชืžื•ื ื•ืช Ceph ืžื—ื•ื‘ืจื•ืช ืœืžืืจื—.

ืฆื•ืจ ืงืฆื” ืื—ื•ืจื™:

# targetcli /backstores/block create disk1 /dev/rbd/mypool/myimage

ืฆื•ืจ ื™ืขื“ iSCSI:

# targetcli /iscsi create iqn.2020-01.demo.ceph:mypool

ืื ื• ืžื—ื‘ืจื™ื ืืช ื”ืงืฆื” ื”ืื—ื•ืจื™ ื›-LUN ืœืžื˜ืจื”:

# targetcli /iscsi/iqn.2020-01.demo.ceph:mypool/tpg1/luns create /backstores/block/disk1

ื‘ื•ืื• ื ื’ื“ื™ืจ ืืช ื”ื™ืขื“ ืœืžืฆื‘ ื”ื“ื’ืžื”:

# targetcli /iscsi/iqn.2020-01.demo.ceph:mypool/tpg1/ set
> attribute demo_mode_write_protect=0
# targetcli /iscsi/iqn.2020-01.demo.ceph:mypool/tpg1/ set
> attribute generate_node_acls=1
# targetcli /iscsi/iqn.2020-01.demo.ceph:mypool/tpg1/ set
> attribute cache_dynamic_acls=1

ืฉืžื•ืจ ืืช ื”ืชืฆื•ืจื”:

# targetcli saveconfig

ื‘ื“ื™ืงืช ื–ืžื™ื ื•ืช ื”ื™ืขื“:

# iscsiadm -m discovery -t st -p 127.0.0.1:3260
127.0.0.1:3260,1 iqn.2020-01.demo.ceph:mypool

ืื ื• ืžื—ื‘ืจื™ื ืืช ื”ืžื˜ืจื”:

# iscsiadm -m node --login
Logging in to [iface: default, target: iqn.2020-01.demo.ceph:mypool, portal: 127.0.0.1,3260] (multiple)
Login to [iface: default, target: iqn.2020-01.demo.ceph:mypool, portal: 127.0.0.1,3260] successful.

ืื ืขืฉื™ืช ื”ื›ืœ ื ื›ื•ืŸ, ื™ื•ืคื™ืข ื‘ืฉืจืช ื“ื™ืกืง ื—ื“ืฉ, ืฉื ืจืื” ื›ืžื• ื”ืชืงืŸ SCSI, ืื‘ืœ ื”ื•ื ืœืžืขืฉื” ืชืžื•ื ื” ืž-Ceph, ืืœื™ื” ื ื™ืชืŸ ืœื’ืฉืช ื“ืจืš ื™ืขื“ iSCSI. ื›ื“ื™ ืœืžื ื•ืข ื‘ืขื™ื•ืช ืืชื—ื•ืœ, ืขื“ื™ืฃ ืœื”ืกื™ืจ ืืช ื”ื“ื™ืกืง ื”ืžื—ื•ื‘ืจ ื•ืืช ื”ื™ืขื“ ืฉื–ื•ื”ื” ืžื”ื™ื–ื ื”ืžืงื•ืžื™:

# iscsiadm -m node --logout
# iscsiadm -m discoverydb -o delete -t st -p 127.0.0.1:3260

ื›ืœ ืžื” ืฉื ื•ืชืจ ื”ื•ื ืœื”ืชืžื™ื“ ื‘ืชืฆื•ืจื” ื›ืš ืฉื”ืชืžื•ื ื” ืชืชื—ื‘ืจ ืื•ื˜ื•ืžื˜ื™ืช ื•ืœืื—ืจ ื”ื—ื™ื‘ื•ืจ, ื”ืžื˜ืจื” ืชื”ื™ื” ืžืจื•ื‘ื“ืช. ืฉื™ื’ื•ืจ ืžื˜ืจื” ืžื•ืจื›ื‘ ืžืฉื ื™ ืฉืœื‘ื™ื - ื—ื™ื‘ื•ืจ ื”-RBD ื•ื‘ืขืฆื ืฉื™ื’ื•ืจ ื”ืžื˜ืจื”.

ืจืืฉื™ืช, ื‘ื•ืื• ื ื’ื“ื™ืจ ืืช ื”ื—ื™ื‘ื•ืจ ื”ืื•ื˜ื•ืžื˜ื™ ืฉืœ ืชืžื•ื ื•ืช RBD ืœืžืืจื—. ื–ื” ื ืขืฉื” ืขืœ ื™ื“ื™ ื”ื•ืกืคืช ื”ืฉื•ืจื•ืช ื”ื‘ืื•ืช ืœืงื•ื‘ืฅ /etc/ceph/rbdmap:

# cat /etc/ceph/rbdmap
# RbdDevice Parameters
mypool/myimage id=admin
# systemctl enable rbdmap

ืฉื—ื–ื•ืจ ืชืฆื•ืจืช ื”ื™ืขื“ ื”ื•ื ืงืฆืช ื™ื•ืชืจ ืžืกื•ื‘ืš - ืื ื—ื ื• ืฆืจื™ื›ื™ื ืœื›ืชื•ื‘ ื™ื—ื™ื“ื” ืขื‘ื•ืจ systemd ืฉืชืฉื—ื–ืจ ืืช ื”ืชืฆื•ืจื”:

# cat /usr/lib/systemd/system/scsi-target.service
[Unit] Description=Start iSCSI target

After=network-online.target rbdmap.service
Before=remote-fs-pre.target
Wants=network-online.target remote-fs-pre.target

[Service] Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/targetcli restoreconfig

[Install] WantedBy=multi-user.target

# systemctl daemon-reload
# systemctl enable scsi-target

ื”ืžื‘ื—ืŸ ื”ืื—ืจื•ืŸ ื”ื•ื ืœืืชื—ืœ ืืช ื”ืฆื’ ืฉืœื ื• ืฉื•ื‘ (ืขื›ืฉื™ื• ื–ื” ื™ืขื“ iSCSI). ื™ืฉ ืœืฆื™ื™ืŸ ืฉืื ืœื ื”ื™ื™ื ื• ืžื ืงื™ื ืืช ืžืกื“ ื”ื ืชื•ื ื™ื ืฉืœ ื”ื™ื•ื–ื ืขื ื”ืคืงื•ื“ื” iscsiadm -n discoverydb -o ืžื—ืง ... ืืชื” ื™ื›ื•ืœ ื‘ืกื•ืคื• ืฉืœ ื“ื‘ืจ ืœืงื‘ืœ ืฉืจืช ืฉืœื ื ื˜ืขืŸ ืื• ืœื•ืงื— ื”ืจื‘ื” ื–ืžืŸ ืœื˜ืขื•ืŸ.

ืžื” ืฉื ืฉืืจ?

ื”ื’ื“ืจ ืืช ื”ื™ื•ื–ื ื‘ืฉืจืช ืืœื™ื• ื ืจืฆื” ืœืฉืœื•ื— ืืช ื”ื™ืขื“.

ื›ื™ืฆื“ ืœื”ื‘ื˜ื™ื— ืกื•ื‘ืœื ื•ืช ืชืงืœื•ืช ืฉืœ ื”ืžื˜ืจื” ืฉืœื ื•?

ื ื™ืชืŸ ืœื”ื’ื“ื™ืจ ื‘ืื•ืคืŸ ื“ื•ืžื” ื™ืขื“ื™ื ื‘ืžืกื›ื™ื ืื—ืจื™ื ื•ืœื”ื’ื“ื™ืจ multipath (vmware ืชื‘ื™ืŸ ืืช ื–ื” ื•ืืคื™ืœื• ืชืขื‘ื•ื“, Hyper-V ืœื ื™ื‘ื™ืŸ - ื–ื” ื“ื•ืจืฉ ื ืขื™ืœื•ืช SCSI). ืžื›ื™ื•ื•ืŸ ืฉืœืงื•ื— Ceph ืžื”ืงืจื ืœ ืื™ื ื• ืžืฉืชืžืฉ ื‘ืžื˜ืžื•ืŸ, ื–ื” ื“ื™ ื‘ืจ ื‘ื™ืฆื•ืข. ืื• ืืคืฉืจื•ืช ืื—ืจืช ื”ื™ื ืœื™ืฆื•ืจ ืžืฉืื‘ ืืฉื›ื•ืœื•ืช ืฉืœ ืฉืœื•ืฉื” ืžืจื›ื™ื‘ื™ื - ื›ืชื•ื‘ืช IP ื™ื™ืขื•ื“ื™ืช ืœื™ืขื“ ื•ืฉื™ืจื•ืชื™ rbdmap ื•-scsi-target, ื•ืœื ื”ืœ ืืช ื”ืžืฉืื‘ ื”ื–ื” ื‘ืืžืฆืขื•ืช ื›ืœื™ ืืฉื›ื•ืœื•ืช (ืžื™ ืืžืจ ืงื•ืฆื‘ ืœื‘?)

ื‘ืžืงื•ื ืืคื™ืœื•ื’

ื›ืคื™ ืฉื‘ืจื•ืจ, ื”ืžืืžืจ ื”ื–ื” ื”ื•ื ืงืฆืช ื‘ื“ื™ื—ื” - ืื‘ืœ ื‘ื• ื ื™ืกื™ืชื™ "ืžื”ืจ ื•ืขื ื“ื•ื’ืžืื•ืช" ืœืฉืงื•ืœ ื›ืžื” ื ื•ืฉืื™ื ืคื•ืคื•ืœืจื™ื™ื ืœืžื“ื™ ื‘ื•-ื–ืžื ื™ืช - iSCSI target, ืฉืื•ืœื™ ืœื ื‘ื”ื›ืจื— ื™ื™ืฆื ืชืžื•ื ื•ืช Ceph - ืื‘ืœ ืœืžืฉืœ, ื™ื™ืฆื•ื ื ืคื—ื™ LVM, ื”ื™ืกื•ื“ื•ืช ืฉืœ ืขื‘ื•ื“ื” ืขื ื™ื•ื–ื iSCSI (ืื™ืš ืœืกืจื•ืง ื™ืขื“, ืื™ืš ืœื”ืชื—ื‘ืจ ืœื™ืขื“, ืœื ืชืง, ืœืžื—ื•ืง ืขืจืš ื™ืขื“ ืžืžืกื“ ื”ื ืชื•ื ื™ื), ื›ืชื™ื‘ืช ื™ื—ื™ื“ื” ืžืฉืœืš ืขื‘ื•ืจ systemd ื•ืขื•ื“ ื›ืžื” ืื—ืจื™ื

ืื ื™ ืžืงื•ื•ื” ืฉื’ื ืื ืœื ืชื—ื–ื•ืจ ืขืœ ื›ืœ ื”ื ื™ืกื•ื™ ื”ื–ื” ื‘ืžืœื•ืื•, ืœืคื—ื•ืช ืžืฉื”ื• ืžื”ืžืืžืจ ื”ื–ื” ื™ื•ืขื™ืœ ืœืš.

ืžืงื•ืจ: www.habr.com

ื”ื•ืกืคืช ืชื’ื•ื‘ื”