Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Hiji pendekatan IaC (Infrastruktur salaku Code) diwangun teu ngan kode nu disimpen dina gudang, tapi ogé jalma jeung prosés nu ngurilingan kode ieu. Naha mungkin pikeun ngagunakeun deui pendekatan tina pamekaran parangkat lunak ka manajemén infrastruktur sareng pedaran? Ieu bakal mangrupakeun ide nu sae pikeun tetep gagasan ieu dina pikiran bari maca artikel.

vérsi basa Inggris

Ieu transkrip abdi pagelaran dina DevopsConf 2019-05-28.

Slide jeung video

Infrastruktur salaku sajarah bash

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Anggap anjeun datang ka proyék anyar, sarta aranjeunna ngabejaan Anjeun: "urang geus Infrastruktur salaku Code". Dina kanyataanana tétéla Infrastruktur salaku sajarah bash atawa contona Dokuméntasi salaku sajarah bash. Ieu mangrupikeun kaayaan anu nyata, contona, kasus anu sami dijelaskeun ku Denis Lysenko dina pidato Kumaha ngaganti sakabéh infrastruktur tur mimitian saré soundly, Anjeunna ngawartoskeun kumaha aranjeunna ngagaduhan infrastruktur koheren pikeun proyék ti sajarah bash.

Kalawan sababaraha kahayang, urang bisa disebutkeun yen Infrastruktur salaku sajarah bash ieu sapertos kode:

  1. reproducibility: Anjeun tiasa nyandak sajarah bash, ngajalankeun paréntah ti dinya, jeung anjeun bisa, ku jalan, meunang konfigurasi gawé salaku kaluaran.
  2. versioning: anjeun terang saha sumping di na naon maranehna ngalakukeun, deui, éta lain kanyataan yén ieu bakal ngakibatkeun anjeun konfigurasi gawé di kaluar.
  3. dongeng: carita anu ngalakukeun naon. ngan anjeun moal bisa make eta lamun leungit server.

Naon anu kudu dipigawé?

Infrastruktur salaku Code

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Malah kasus aneh saperti Infrastruktur salaku sajarah bash anjeun tiasa narik éta ku ceuli Infrastruktur salaku Code, Tapi lamun urang rék ngalakukeun hal nu leuwih pajeulit batan server LAMP heubeul alus, urang bakal datang ka kacindekan yén kode ieu kudu kumaha bae dirobah, robah, ningkat. Salajengna urang hoyong mertimbangkeun parallels antara Infrastruktur salaku Code jeung ngembangkeun software.

GARING

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Dina proyék pangembangan sistem panyimpenan, aya subtugas périodik ngonpigurasikeun SDS: urang ngarilis release anyar - eta perlu digulung kaluar pikeun nguji salajengna. Tugasna saderhana pisan:

  • lebet di dieu via ssh sareng laksanakeun paréntahna.
  • salin file nu aya.
  • ngabenerkeun config di dieu.
  • ngamimitian jasa di dinya
  • ...
  • Kauntungan!

Pikeun logika anu dijelaskeun, bash langkung ti cukup, khususna dina tahap awal proyék, nalika nembé ngamimitian. Ieu teu goréng nu ngagunakeun bash, Tapi kana waktu aya requests nyebarkeun hal sarupa, tapi rada béda. Hal kahiji anu datang ka pikiran nyaéta copy-paste. Sareng ayeuna urang parantos gaduh dua naskah anu sami anu ngalakukeun hal anu sami. Kana waktu, jumlah Aksara tumuwuh, sarta kami Nyanghareupan kanyataan yén aya hiji logika bisnis tangtu pikeun deploying hiji instalasi nu kudu nyingkronkeun antara Aksara béda, ieu téh rada pajeulit.

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Tétéla aya prakték sapertos GARING (Ulah Ulang Diri). Ide pikeun ngagunakeun deui kode anu aya. Ieu disada basajan, tapi urang teu datang ka ieu langsung. Dina hal urang, éta ide banal: misahkeun configs tina Aksara. Jelema. logika bisnis kumaha instalasi deployed misah, configs misah.

SOLID pikeun CFM

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Leuwih waktos proyék tumuwuh sarta tutugan alam nya éta mecenghulna Ansible. Alesan utama pikeun penampilanna nyaéta yén aya kaahlian dina tim sareng yén bash henteu dirancang pikeun logika kompleks. Ansible ogé mimiti ngandung logika kompléks. Pikeun nyegah logika kompléks jadi rusuh, aya prinsip organisasi kode dina ngembangkeun software PADAT Salaku conto, Grigory Petrov dina laporan "Naha spesialis IT peryogi merek pribadi" ngangkat patarosan yén hiji jalma dirancang ku cara anu langkung gampang pikeun anjeunna beroperasi sareng sababaraha éntitas sosial, dina pamekaran software ieu. mangrupa objék. Lamun urang ngagabungkeun dua gagasan ieu terus ngamekarkeun aranjeunna, urang bakal aya bewara yen urang ogé bisa ngagunakeun PADAT pikeun ngagampangkeun pikeun ngajaga sareng ngaropea logika ieu ka hareup.

Prinsip Tanggung Jawab Tunggal

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Unggal kelas ngalaksanakeun ngan hiji tugas.

Teu perlu campur kode jeung nyieun monolithic monster spaghetti ketuhanan. Infrastruktur kedah diwangun ku bata basajan. Tétéla yén lamun dibeulah playbook Ansible kana lembar leutik, baca peran Ansible, lajeng aranjeunna gampang pikeun ngajaga.

Prinsip Buka Tutup

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Prinsip kabuka/tutup.

  • Open to extension: hartina paripolah hiji éntitas bisa diperpanjang ku cara nyieun tipe éntitas anyar.
  • Ditutup pikeun robah: Salaku hasil tina ngalegaan paripolah hiji éntitas, euweuh parobahan kudu dilakukeun kana kode anu ngagunakeun éntitas maranéhanana.

Mimitina, urang deployed infrastruktur test dina mesin virtual, tapi alatan kanyataan yén logika bisnis deployment misah ti palaksanaan, urang ditambahkeun rolling kaluar mun baremetall tanpa masalah.

Prinsip Substitusi Liskov

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Prinsip substitusi Barbara Liskov. Obyék dina program kedah tiasa diganti ku conto subtipe na tanpa ngarobih palaksanaan program anu leres.

Upami anjeun ningal langkung lega, éta sanés fitur tina proyék khusus anu tiasa diterapkeun di dinya PADAT, éta umumna ngeunaan CFM, Contona, dina proyék séjén perlu nyebarkeun hiji aplikasi Java boxed on luhureun rupa Java, server aplikasi, database, OS, jsb. Ngagunakeun conto ieu, kuring bakal mertimbangkeun prinsip salajengna PADAT

Dina kasus urang, aya kasapukan dina tim infrastruktur yén lamun urang geus dipasang imbjava atanapi peran oraclejava, lajeng urang boga java binér executable. Ieu diperlukeun sabab Peran hulu gumantung kana kabiasaan ieu; Dina waktos anu sami, ieu ngamungkinkeun urang pikeun ngagentos hiji palaksanaan / versi java sareng anu sanés tanpa ngarobih logika panyebaran aplikasi.

Masalahna di dieu nyaéta kanyataan yén teu mungkin pikeun nerapkeun ieu di Ansible, salaku hasil tina sababaraha perjanjian muncul dina tim.

Prinsip Segregation Antarmuka

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Prinsip pamisahan antarmuka: "Seueur antarmuka khusus klien anu langkung saé tibatan hiji antarmuka tujuan umum.

Mimitina, urang nyobian nempatkeun sagala variability tina deployment aplikasi kana hiji playbook Ansible, tapi éta hésé ngarojong, sarta pendekatan lamun urang boga hiji panganteur éksternal dieusian (klien ekspektasi port 443), lajeng hiji infrastruktur bisa dirakit ti individu. bata pikeun palaksanaan husus.

Prinsip Inversi Dependency

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Prinsip inversi kagumantungan. Modul dina tingkat anu langkung luhur henteu kedah gumantung kana modul dina tingkat anu langkung handap. Duanana jinis modul kedah gumantung kana abstraksi. Abstraksi henteu kedah gumantung kana detil. Rincian kedah gumantung kana abstraksi.

Di dieu conto bakal dumasar kana antipattern.

  1. Salah sahiji palanggan ngagaduhan awan pribadi.
  2. Urang maréntahkeun mesin virtual di jero awan.
  3. Tapi kusabab sifat awan, panyebaran aplikasi dihijikeun sareng hypervisor VM na.

Jelema. Logika panyebaran aplikasi tingkat luhur ngalir sareng katergantungan ka tingkat handap hypervisor, sareng ieu hartosna masalah nalika nganggo deui logika ieu. Ulah ngalakukeun cara kieu.

saling mere pangaruh

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Infrastruktur salaku kode lain ngan ngeunaan kode, tapi ogé ngeunaan hubungan antara kode jeung jalma, ngeunaan interaksi antara pamekar infrastruktur.

Faktor beus

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Hayu urang nganggap yén anjeun gaduh Vasya dina proyék anjeun. Vasya terang sadayana ngeunaan infrastruktur anjeun, naon anu bakal kajadian upami Vasya ujug-ujug ngaleungit? Ieu kaayaan anu nyata pisan, sabab anjeunna tiasa ditabrak ku beus. Kadang-kadang kajadian. Upami ieu kajantenan sareng pangaweruh ngeunaan kodeu, strukturna, kumaha jalanna, penampilan sareng kecap akses henteu disebarkeun diantara tim, maka anjeun tiasa mendakan sababaraha kaayaan anu teu pikaresepeun. Pikeun ngaleutikan résiko ieu sareng nyebarkeun pangaweruh dina tim, anjeun tiasa nganggo sababaraha pendekatan

Pasangan Devopsing

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Teu siga salaku lulucon, yén admins nginum bir, robah kecap akses, sarta analog program pasangan. Jelema. dua insinyur calik dina hiji komputer, hiji keyboard sareng mimitian nyetél infrastruktur anjeun babarengan: nyetél server, nyerat peran Ansible, jsb. Ieu disada nice, tapi teu dianggo keur urang. Tapi kasus husus tina prakték ieu digawé. A pagawe anyar geus anjog, mentor na nyandak hiji tugas nyata babarengan jeung manehna, dianggo tur mindahkeun pangaweruh.

Kasus khusus anu sanés nyaéta panggero kajadian. Nalika aya masalah, sakelompok jalma anu tugas sareng anu kalibet ngumpul, hiji pamimpin diangkat, anu ngabagi layar sareng nyoarakeun karéta pamikiran. pamilon séjén nuturkeun pikiran pamimpin urang, nénjo dina trik tina konsol nu, pariksa yen aranjeunna geus teu lasut garis dina log, sarta diajar hal anyar ngeunaan sistem. Pendekatan ieu dianggo langkung sering tibatan henteu.

Tinjauan Kode

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Sacara subyektif, langkung efektif nyebarkeun pangaweruh ngeunaan infrastruktur sareng cara jalanna ngagunakeun ulasan kode:

  • Infrastruktur dijelaskeun ku kode dina gudang.
  • Parobahan lumangsung dina cabang misah.
  • Salila pamundut ngahiji, anjeun tiasa ningali délta parobahan dina infrastruktur.

Sorotan di dieu nya éta reviewers dipilih hiji-hiji, nurutkeun jadwal a, i.e. kalawan sababaraha gelar kamungkinan anjeun bakal nanjak kana sapotong anyar infrastruktur.

Gaya Kode

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Kana waktu, squabbles mimiti muncul salila ulasan, sabab ... reviewers miboga gaya sorangan jeung rotasi reviewers tumpuk aranjeunna kalayan gaya béda: 2 spasi atawa 4, camelCase atanapi snake_case. Teu mungkin pikeun nerapkeun ieu langsung.

  • Gagasan anu munggaran nyaéta nyarankeun ngagunakeun linter, saatos sadayana, sadayana insinyur, sadayana pinter. Tapi éditor béda, OS, teu merenah
  • Ieu robah jadi bot nu nulis slack pikeun tiap komitmen masalah na napel kaluaran linter. Tapi dina kalolobaan kasus aya hal anu langkung penting pikeun dilakukeun sareng kodena tetep teu dibenerkeun.

Héjo Ngawangun Master

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Waktos pas, sarta kami geus datang ka kacindekan yen commits nu teu lulus tés tangtu teu bisa diwenangkeun kana master. Voila! Kami nimukeun Green Build Master, anu parantos lami dipraktékkeun dina pamekaran parangkat lunak:

  • Pangwangunan dijalankeun dina cabang anu misah.
  • Tés ngajalankeun on thread ieu.
  • Upami tés gagal, kodeu moal tiasa janten master.

Nyieun kaputusan ieu nyeri pisan, sabab ... ngabalukarkeun loba kontrovérsi, tapi éta patut eta, sabab. Harita mimiti narima requests pikeun mergers tanpa béda dina gaya, sarta kana waktu jumlah wewengkon masalah mimiti ngurangan.

Tés IaC

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Salian mariksa gaya, anjeun tiasa nganggo hal-hal sanés, contona, pikeun mariksa yén infrastruktur anjeun leres-leres tiasa nyebarkeun. Atawa pariksa yen parobahan dina infrastruktur moal ngakibatkeun leungitna duit. Naha ieu tiasa diperyogikeun? Patarosan ieu rumit sarta filosofis, éta hadé pikeun ngajawab kalawan carita nu kumaha bae aya hiji auto-scaler on Powershell nu teu pariksa kaayaan wates => leuwih VMs dijieun ti diperlukeun => klien spent leuwih duit ti rencanana. Ieu teu pisan pikaresepeun, tapi bakal rada mungkin nyekel kasalahan ieu dina tahap saméméhna.

Hiji meureun nanya, naha nyieun infrastruktur kompléks malah leuwih kompleks? Tés pikeun infrastruktur, sapertos kodeu, sanés ngeunaan nyederhanakeun, tapi ngeunaan terang kumaha infrastruktur anjeun kedah jalan.

IaC Testing Piramida

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Uji IaC: Analisis statik

Upami anjeun nyebarkeun sadayana infrastruktur sakaligus sareng pariksa yén éta tiasa dianggo, anjeun tiasa mendakan yén éta peryogi seueur waktos sareng peryogi seueur waktos. Ku alatan éta, dasarna kudu hal anu gancang, aya loba eta, sarta eta nyertakeun loba tempat primitif.

Bash téh tricky

Hayu urang nempo conto trivial. pilih sadaya file dina diréktori ayeuna sareng salin ka lokasi anu sanés. Hal kahiji anu datang ka pikiran:

for i in * ; do 
    cp $i /some/path/$i.bak
done

Kumaha upami aya rohangan dina nami file? Nya, ok, urang pinter, urang terang kumaha ngagunakeun tanda petik:

for i in * ; do cp "$i" "/some/path/$i.bak" ; done

Saé? Henteu! Kumaha lamun aya nanaon dina diréktori, i.e. globbing moal jalan.

find . -type f -exec mv -v {} dst/{}.bak ;

Alus ayeuna? Heueuh... Hilap naon anu tiasa aya dina nami file n.

touch x
mv x  "$(printf "foonbar")"
find . -type f -print0 | xargs -0 mv -t /path/to/target-dir

Alat analisis statik

Masalah tina léngkah anu saacanna tiasa kapendak nalika urang hilap kutipan, pikeun ieu aya seueur pangobatan di alam. Shellcheck, Sacara umum aya loba di antarana, jeung paling dipikaresep anjeun bisa manggihan linter pikeun tumpukan anjeun handapeun IDE Anjeun.

basa
alat

bash
Shellcheck

inten beureum
RuboCop

python
pylint

ansible
Ansible Lint

Tés IaC: Tés Unit

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Salaku urang nempo tina conto saméméhna, linters teu omnipotent sarta teu bisa nunjuk kaluar sakabeh wewengkon masalah. Salajengna, ku analogi sareng uji dina pamekaran parangkat lunak, urang tiasa ngémutan tés unit. Anu langsung aya dina pikiran téh sunit, junit, rspec, pytest. Tapi naon anu kudu dipigawé kalayan ansible, koki, saltstack jeung nu lianna kawas aranjeunna?

Dina pisan mimiti urang ngobrol ngeunaan PADAT sarta yén infrastruktur urang kudu diwangun ku bata leutik. Waktosna parantos sumping.

  1. Infrastruktur dibagi kana bata leutik, contona, peran Ansible.
  2. Sababaraha jenis lingkungan anu disebarkeun, janten docker atanapi VM.
  3. Kami nerapkeun peran Ansible kami ka lingkungan tés ieu.
  4. Urang pariksa yen sagalana digawé sakumaha urang ekspektasi (urang ngajalankeun tés).
  5. Urang mutuskeun ok atanapi henteu ok.

Uji IaC: Alat Uji Unit

Patarosan, naon tés pikeun CFM? Anjeun ngan saukur tiasa ngajalankeun naskah, atanapi anjeun tiasa nganggo solusi anu siap-siap pikeun ieu:

CFM
alat

Ansible
Testinfra

sirah
Inspeksi

sirah
Spésifikasi server

tumpukan uyah
Gosip

Conto pikeun testinfra, mariksa yén pamaké test1, test2 aya jeung aya dina hiji grup sshusers:

def test_default_users(host):
    users = ['test1', 'test2' ]
    for login in users:
        assert host.user(login).exists
        assert 'sshusers' in host.user(login).groups

Naon anu kudu dipilih? Patarosanna rumit sareng ambigu, ieu mangrupikeun conto parobihan dina proyék github pikeun 2018-2019:

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

kerangka Tés IaC

Patarosan timbul: kumaha carana nempatkeun eta sadayana babarengan jeung ngajalankeun eta? Tiasa nyandak eta jeung ngalakukeun eta sorangan lamun aya jumlah cukup insinyur. Atanapi anjeun tiasa nyandak solusi anu siap-siap, sanaos henteu seueur pisan:

CFM
alat

Ansible
Molekul

sirah
Tés Dapur

Terraform
Terratest

Conto parobahan dina proyék dina github pikeun 2018-2019:

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Molekul vs. Dapur tés

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Mimitina urang diusahakeun make testkitchen:

  1. Jieun VM dina paralel.
  2. Larapkeun kalungguhan Ansible.
  3. Jalankeun pamariksaan.

Pikeun 25-35 kalungguhan éta digawé 40-70 menit, nu panjang.

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Lengkah saterusna nyaéta transisi ka jenkins / docker / ansible / molekul. Idiologically sagalana sarua

  1. Lint playbooks.
  2. Ngajajarkeun kalungguhan.
  3. wadahna peluncuran
  4. Larapkeun kalungguhan Ansible.
  5. Ngajalankeun testinfra.
  6. Pariksa idémpotensi.

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Linting pikeun 40 peran jeung tés pikeun belasan mimiti nyandak ngeunaan 15 menit.

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Naon anu kudu dipilih gumantung kana sababaraha faktor, sapertos tumpukan anu dianggo, kaahlian dina tim, jsb. di dieu dulur mutuskeun sorangan kumaha nutup sual nguji Unit

Tés IaC: Tés Integrasi

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Léngkah salajengna dina piramida uji infrastruktur bakal janten tés integrasi. Éta sami sareng tés Unit:

  1. Infrastruktur dibagi kana bata leutik, contona peran Ansible.
  2. Sababaraha jenis lingkungan anu disebarkeun, janten docker atanapi VM.
  3. Pikeun lingkungan tés ieu dilarapkeun sakumpulan Kalungguhan ansible.
  4. Urang pariksa yen sagalana digawé sakumaha urang ekspektasi (urang ngajalankeun tés).
  5. Urang mutuskeun ok atanapi henteu ok.

Sacara kasar, urang henteu pariksa kinerja unsur individu tina sistem sapertos dina tés unit, urang pariksa kumaha server dikonpigurasi sacara gembleng.

Uji IaC: Tes Tungtung ka Tungtung

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Di luhureun piramida urang disambut ku tungtung ka tungtung tés. Jelema. Kami henteu pariksa kinerja server anu misah, naskah anu misah, atanapi bata anu misah tina infrastruktur kami. Urang pariksa yen loba server disambungkeun babarengan, infrastruktur urang jalan sakumaha urang ngaharepkeun eta. Hanjakalna, kuring henteu kantos ningali solusi kotak siap-siap, sigana kusabab ... Infrastrukturna sering unik sareng sesah template sareng nyiptakeun kerangka pikeun nguji. Hasilna, unggal jalma nyiptakeun solusi sorangan. Aya paménta, tapi euweuh jawaban. Kukituna, kuring bakal nyarioskeun ka anjeun naon anu aya pikeun nyorong batur pikeun nyarioskeun pikiran atanapi ngagosok irung kuring dina kanyataan yén sadayana diciptakeun lami sateuacan urang.

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Hiji proyék kalawan sajarah euyeub. Hal ieu dianggo dina organisasi ageung sareng sigana masing-masing anjeun henteu langsung nyebrang jalan sareng éta. Aplikasi ngadukung seueur pangkalan data, integrasi, jsb. Nyaho naon prasarana sigana sapertos seueur file docker-compose, sareng terang mana tés anu kedah dijalankeun di lingkungan mana Jenkins.

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Skéma ieu digawé pikeun lila, nepi ka dina kerangka panalungtikan kami geus teu diusahakeun mindahkeun ieu Openshift. Wadahna tetep sami, tapi lingkungan peluncuran parantos robih (halo DRY deui).

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Gagasan panilitian langkung jauh, sareng dina openshift aranjeunna mendakan hal sapertos APB (Ansible Playbook Bundle), anu ngamungkinkeun anjeun ngepak pangaweruh ngeunaan cara nyebarkeun infrastruktur kana wadahna. Jelema. aya hiji titik ulang, testable pangaweruh ngeunaan cara nyebarkeun infrastruktur.

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Sadaya ieu disada saé dugi ka urang ngagaduhan infrastruktur hétérogén: urang peryogi Windows pikeun tés. Hasilna, pangaweruh ngeunaan naon, dimana, kumaha nyebarkeun, sarta uji aya dina jenkins.

kacindekan

Anu Kuring Diajar tina Nguji 200 Garis Kode Infrastruktur

Infrastruktur sakumaha Code nyaeta

  • Kodeu dina gudang.
  • Interaksi manusa.
  • Uji Infrastruktur.

Tumbu

sumber: www.habr.com

Tambahkeun komentar