Muhtasari mfupi wa Taarifa za PostgreSQL za Kubernetes, Chaguo Zetu na Uzoefu

Muhtasari mfupi wa Taarifa za PostgreSQL za Kubernetes, Chaguo Zetu na Uzoefu

Kwa kuongezeka, wateja wanapokea maombi yafuatayo: "Tunaitaka kama Amazon RDS, lakini kwa bei nafuu"; "Tunaitaka kama RDS, lakini kila mahali, katika miundombinu yoyote." Ili kutekeleza suluhisho kama hilo linalosimamiwa kwenye Kubernetes, tuliangalia hali ya sasa ya waendeshaji maarufu zaidi wa PostgreSQL (Stolon, waendeshaji kutoka Crunchy Data na Zalando) na tukafanya chaguo letu.

Nakala hii ni uzoefu ambao tumepata kutoka kwa mtazamo wa kinadharia (mapitio ya suluhisho) na kutoka kwa upande wa vitendo (kilichochaguliwa na kilichokuja). Lakini kwanza, wacha tuamue mahitaji ya jumla ni nini kwa uingizwaji unaowezekana wa RDS...

RDS ni nini

Wakati watu wanazungumza juu ya RDS, katika uzoefu wetu, wanamaanisha huduma inayosimamiwa ya DBMS ambayo:

  1. rahisi kusanidi;
  2. ina uwezo wa kufanya kazi na snapshots na kupona kutoka kwao (ikiwezekana kwa usaidizi PITR);
  3. inakuwezesha kuunda topolojia ya bwana-mtumwa;
  4. ina orodha tajiri ya upanuzi;
  5. hutoa ukaguzi na usimamizi wa ufikiaji wa mtumiaji.

Kwa ujumla, mbinu za kutekeleza kazi iliyopo zinaweza kuwa tofauti sana, lakini njia iliyo na masharti ya Ansible haiko karibu nasi. (Wenzake kutoka 2GIS walifikia hitimisho sawa kama matokeo jaribio lake unda "chombo cha kupeleka haraka nguzo ya kushindwa kwa msingi wa Postgres.")

Waendeshaji ni mbinu ya kawaida ya kutatua matatizo sawa katika mfumo ikolojia wa Kubernetes. Mkurugenzi wa kiufundi wa "Flanta" tayari amezungumza kwa undani zaidi kuwahusu kuhusiana na hifadhidata iliyozinduliwa ndani ya Kubernetes. distolindani moja ya ripoti zake.

NB: Ili kuunda waendeshaji rahisi kwa haraka, tunapendekeza kuzingatia matumizi yetu ya Open Source shell-operator. Kwa kuitumia, unaweza kufanya hivyo bila ujuzi wa Go, lakini kwa njia zinazojulikana zaidi kwa wasimamizi wa mfumo: katika Bash, Python, nk.

Kuna waendeshaji kadhaa maarufu wa K8s kwa PostgreSQL:

  • Stolon;
  • Data Crunchy PostgreSQL Operator;
  • Opereta wa Zalando Postgres.

Hebu tuwaangalie kwa karibu zaidi.

Uchaguzi wa waendeshaji

Mbali na vipengele muhimu vilivyotajwa hapo juu, sisi - kama wahandisi wa shughuli za miundombinu ya Kubernetes - pia tulitarajia yafuatayo kutoka kwa waendeshaji:

  • kupelekwa kutoka Git na kwa Rasilimali Maalum;
  • msaada wa kupambana na mshikamano wa pod;
  • kufunga mshikamano wa nodi au kichaguzi cha nodi;
  • ufungaji wa uvumilivu;
  • upatikanaji wa uwezo wa kurekebisha;
  • teknolojia zinazoeleweka na hata amri.

Bila kuingia katika maelezo juu ya kila moja ya vidokezo (uliza kwenye maoni ikiwa bado una maswali juu yao baada ya kusoma kifungu kizima), nitagundua kwa ujumla kuwa vigezo hivi vinahitajika kuelezea kwa usahihi zaidi utaalam wa nodi za nguzo ili waagize kwa maombi maalum. Kwa njia hii tunaweza kufikia usawa bora katika suala la utendaji na gharama.

Sasa wacha tuendelee kwa waendeshaji wa PostgreSQL wenyewe.

1. Stolon

Stolon kutoka kwa kampuni ya Italia Sorint.lab in ripoti iliyotajwa tayari ilizingatiwa kama aina ya kiwango kati ya waendeshaji kwa DBMS. Huu ni mradi wa zamani kabisa: toleo lake la kwanza la umma lilifanyika mnamo Novemba 2015(!), na hazina ya GitHub inajivunia karibu nyota 3000 na wachangiaji 40+.

Hakika, Stolon ni mfano bora wa usanifu wa kufikiria:

Muhtasari mfupi wa Taarifa za PostgreSQL za Kubernetes, Chaguo Zetu na Uzoefu
Kifaa cha operator hii kinaweza kupatikana kwa undani katika ripoti au nyaraka za mradi. Kwa ujumla, inatosha kusema kwamba inaweza kufanya kila kitu kilichoelezewa: kushindwa, proksi za ufikiaji wa uwazi wa mteja, chelezo ... Zaidi ya hayo, washirika hutoa ufikiaji kupitia huduma moja ya mwisho - tofauti na suluhisho zingine mbili zilizojadiliwa hapa chini (kila moja ina huduma mbili kwa msingi wa ufikiaji).

Hata hivyo, Stolon hakuna Rasilimali Maalum, ndiyo sababu haiwezi kutumwa kwa njia ambayo ni rahisi na ya haraka - "kama mikate ya moto" - kuunda matukio ya DBMS katika Kubernetes. Usimamizi unafanywa kupitia shirika stolonctl, uwekaji unafanywa kupitia chati ya Helm, na maalum hufafanuliwa na kubainishwa katika ConfigMap.

Kwa upande mmoja, zinageuka kuwa operator si kweli operator (baada ya yote, haitumii CRD). Lakini kwa upande mwingine, ni mfumo unaonyumbulika unaokuruhusu kusanidi rasilimali katika K8s unavyoona inafaa.

Kwa muhtasari, kwetu sisi binafsi haikuonekana kuwa bora kuunda chati tofauti kwa kila hifadhidata. Kwa hiyo, tulianza kutafuta njia mbadala.

2. Data Crunchy PostgreSQL Operator

Opereta kutoka Data Crunchy, mwanzilishi mchanga wa Marekani, alionekana kuwa mbadala wa kimantiki. Historia yake ya umma inaanza na toleo la kwanza mnamo Machi 2017, tangu wakati huo hazina ya GitHub imepokea chini ya nyota 1300 na wachangiaji 50+. Toleo jipya zaidi la Septemba lilijaribiwa kufanya kazi na Kubernetes 1.15-1.18, OpenShift 3.11+ na 4.4+, GKE na VMware Enterprise PKS 1.3+.

Usanifu wa Crunchy Data PostgreSQL Operator pia inakidhi mahitaji yaliyotajwa:

Muhtasari mfupi wa Taarifa za PostgreSQL za Kubernetes, Chaguo Zetu na Uzoefu

Usimamizi hutokea kupitia matumizi pgo, hata hivyo, inazalisha Rasilimali Maalum kwa Kubernetes. Kwa hivyo, opereta alitufurahisha kama watumiaji wanaowezekana:

  • kuna udhibiti kupitia CRD;
  • usimamizi rahisi wa mtumiaji (pia kupitia CRD);
  • ushirikiano na vipengele vingine Crunchy Data Container Suite - mkusanyiko maalum wa picha za kontena za PostgreSQL na huduma za kufanya kazi nayo (pamoja na pgBackRest, pgAudit, viendelezi kutoka kwa mchango, n.k.).

Walakini, majaribio ya kuanza kutumia opereta kutoka kwa Crunchy Data yalifunua shida kadhaa:

  • Hakukuwa na uwezekano wa kuvumiliana - nodeSelector pekee hutolewa.
  • Maganda yaliyoundwa yalikuwa sehemu ya Usambazaji, licha ya ukweli kwamba tulituma maombi ya hali ya juu. Tofauti na StatefulSets, Utumiaji hauwezi kuunda diski.

Upungufu wa mwisho husababisha wakati wa kuchekesha: kwenye mazingira ya mtihani tuliweza kuendesha nakala 3 na diski moja uhifadhi wa ndani, na kusababisha opereta kuripoti kuwa nakala 3 zilikuwa zikifanya kazi (ingawa hazikuwa zikifanya kazi).

Kipengele kingine cha operator huyu ni ushirikiano wake tayari na mifumo mbalimbali ya wasaidizi. Kwa mfano, ni rahisi kusakinisha pgAdmin na pgBounce, na in nyaraka Grafana na Prometheus zilizosanidiwa hapo awali zinazingatiwa. Hivi karibuni kutolewa 4.5.0-beta1 Ushirikiano ulioboreshwa na mradi umebainishwa kando pgMonitor, shukrani ambayo operator hutoa taswira wazi ya metriki za PgSQL nje ya boksi.

Hata hivyo, uchaguzi wa ajabu wa rasilimali zinazozalishwa na Kubernetes ulituongoza kwenye haja ya kupata suluhisho tofauti.

3. Opereta wa Zalando Postgres

Tumejua bidhaa za Zalando kwa muda mrefu: tuna uzoefu wa kutumia Zalenium na, bila shaka, tulijaribu Mchungaji ndio suluhisho lao maarufu la HA kwa PostgreSQL. Kuhusu mbinu ya kampuni ya kuunda Mwendeshaji wa Postgres mmoja wa waandishi wake, Alexey Klyukin, alisema hewani Postgres-Jumanne #5, na tuliipenda.

Hili ndilo suluhisho la mwisho lililojadiliwa katika makala: toleo la kwanza lilifanyika mnamo Agosti 2018. Hata hivyo, hata licha ya idadi ndogo ya matoleo rasmi, mradi umekuja kwa muda mrefu, tayari unazidi kwa umaarufu suluhisho kutoka kwa Data ya Crunchy na nyota 1300+ kwenye GitHub na idadi kubwa ya wachangiaji (70+).

"Chini ya kofia" mwendeshaji huyu hutumia suluhisho zilizojaribiwa kwa wakati:

  • Patroni na Spilo Kwa kuendesha gari,
  • WAL-E - kwa chelezo,
  • PgBouncer - kama bwawa la unganisho.

Hivi ndivyo usanifu wa opereta kutoka Zalando unavyowasilishwa:

Muhtasari mfupi wa Taarifa za PostgreSQL za Kubernetes, Chaguo Zetu na Uzoefu

Opereta anadhibitiwa kikamilifu kupitia Rasilimali Maalum, huunda StatefulSet kiotomatiki kutoka kwa vyombo, ambavyo vinaweza kubinafsishwa kwa kuongeza kando mbalimbali kwenye ganda. Yote hii ni faida kubwa kwa kulinganisha na operator kutoka Data Crunchy.

Kwa kuwa tulichagua suluhisho kutoka kwa Zalando kati ya chaguo 3 zinazozingatiwa, maelezo zaidi ya uwezo wake yatawasilishwa hapa chini, mara moja pamoja na mazoezi ya maombi.

Fanya mazoezi na Opereta wa Postgres kutoka Zalando

Uwekaji wa opereta ni rahisi sana: pakua tu toleo la sasa kutoka kwa GitHub na utumie faili za YAML kutoka kwenye saraka. hudhihirisha. Vinginevyo, unaweza pia kutumia kituo cha uendeshaji.

Baada ya ufungaji, unapaswa kuwa na wasiwasi kuhusu kuanzisha kuhifadhi kwa kumbukumbu na chelezo. Hii inafanywa kupitia ConfigMap postgres-operator katika nafasi ya majina ambapo umesakinisha opereta. Mara tu hazina zitakaposanidiwa, unaweza kupeleka nguzo yako ya kwanza ya PostgreSQL.

Kwa mfano, uwekaji wetu wa kawaida unaonekana kama hii:

apiVersion: acid.zalan.do/v1
kind: postgresql
metadata:
 name: staging-db
spec:
 numberOfInstances: 3
 patroni:
   synchronous_mode: true
 postgresql:
   version: "12"
 resources:
   limits:
     cpu: 100m
     memory: 1Gi
   requests:
     cpu: 100m
     memory: 1Gi
 sidecars:
 - env:
   - name: DATA_SOURCE_URI
     value: 127.0.0.1:5432
   - name: DATA_SOURCE_PASS
     valueFrom:
       secretKeyRef:
         key: password
         name: postgres.staging-db.credentials
   - name: DATA_SOURCE_USER
     value: postgres
   image: wrouesnel/postgres_exporter
   name: prometheus-exporter
   resources:
     limits:
       cpu: 500m
       memory: 100Mi
     requests:
       cpu: 100m
       memory: 100Mi
 teamId: staging
 volume:
   size: 2Gi

Faili hii ya maelezo hutumia kundi la matukio 3 yenye kando katika fomu postgres_nje, ambapo tunachukua vipimo vya maombi. Kama unaweza kuona, kila kitu ni rahisi sana, na ikiwa unataka, unaweza kuunda idadi isiyo na kikomo ya nguzo.

Inafaa kulipa kipaumbele paneli ya utawala wa wavuti - postgres-operator-ui. Inakuja na operator na inakuwezesha kuunda na kufuta makundi, pamoja na kufanya kazi na salama zilizofanywa na operator.

Muhtasari mfupi wa Taarifa za PostgreSQL za Kubernetes, Chaguo Zetu na Uzoefu
Orodha ya vikundi vya PostgreSQL

Muhtasari mfupi wa Taarifa za PostgreSQL za Kubernetes, Chaguo Zetu na Uzoefu
Usimamizi wa chelezo

Kipengele kingine cha kuvutia ni msaada API ya Timu. Utaratibu huu huunda kiotomatiki majukumu katika PostgreSQL, kulingana na orodha inayotokana ya majina ya watumiaji. API basi hukuruhusu kurudisha orodha ya watumiaji ambao majukumu yao yameundwa kiotomatiki.

Matatizo na ufumbuzi

Walakini, utumiaji wa opereta hivi karibuni ulifunua mapungufu kadhaa muhimu:

  1. ukosefu wa nodeSelector msaada;
  2. kutokuwa na uwezo wa kuzima chelezo;
  3. wakati wa kutumia kazi ya uundaji wa hifadhidata, marupurupu ya chaguo-msingi hayaonekani;
  4. Mara kwa mara, hati hukosekana au zimepitwa na wakati.

Kwa bahati nzuri, wengi wao wanaweza kutatuliwa. Wacha tuanze kutoka mwisho - shida na nyaraka.

Uwezekano mkubwa zaidi, utakutana na ukweli kwamba sio wazi kila wakati jinsi ya kusajili nakala rudufu na jinsi ya kuunganisha ndoo ya chelezo kwenye UI ya Opereta. Nyaraka zinazungumza juu ya hili kwa kupita, lakini maelezo halisi yako ndani PR:

  1. haja ya kufanya siri;
  2. kuipitisha kwa opereta kama parameta pod_environment_secret_name katika CRD iliyo na mipangilio ya opereta au katika ConfigMap (kulingana na jinsi unavyoamua kusakinisha opereta).

Walakini, kama inavyogeuka, hii kwa sasa haiwezekani. Ndio maana tulikusanya toleo lako la opereta na baadhi ya maendeleo ya ziada ya wahusika wengine. Kwa habari zaidi juu yake, tazama hapa chini.

Ikiwa utapitisha vigezo vya chelezo kwa mwendeshaji, yaani - wal_s3_bucket na funguo za ufikiaji katika AWS S3, basi itahifadhi kila kitu: si tu besi katika uzalishaji, lakini pia staging. Hii haikutufaa.

Katika maelezo ya vigezo vya Spilo, ambayo ni karatasi ya msingi ya Docker ya PgSQL wakati wa kutumia opereta, iliibuka: unaweza kupitisha parameta. WAL_S3_BUCKET tupu, na hivyo kuzima chelezo. Zaidi ya hayo, kwa furaha kubwa, nilipata tayari PR, ambayo tuliikubali mara moja kwenye uma wetu. Sasa unahitaji tu kuongeza enableWALArchiving: false kwa rasilimali ya nguzo ya PostgreSQL.

Ndiyo, kulikuwa na fursa ya kufanya hivyo tofauti kwa kuendesha waendeshaji 2: moja kwa ajili ya staging (bila backups), na pili kwa ajili ya uzalishaji. Lakini tuliweza kufanya na moja.

Sawa, tulijifunza jinsi ya kuhamisha ufikiaji wa hifadhidata za S3 na chelezo zilianza kuingia kwenye hifadhi. Jinsi ya kufanya kurasa za chelezo kufanya kazi katika UI ya Opereta?

Muhtasari mfupi wa Taarifa za PostgreSQL za Kubernetes, Chaguo Zetu na Uzoefu

Utahitaji kuongeza anuwai 3 kwenye Kiolesura cha Opereta:

  • SPILO_S3_BACKUP_BUCKET
  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY

Baada ya hayo, usimamizi wa chelezo utapatikana, ambao kwa upande wetu utarahisisha kazi kwa kuweka hatua, na kuturuhusu kutoa vipande kutoka kwa uzalishaji huko bila hati za ziada.

Faida nyingine ilikuwa kazi na API ya Timu na fursa nyingi za kuunda hifadhidata na majukumu kwa kutumia zana za waendeshaji. Walakini, iliyoundwa majukumu hayakuwa na haki kwa default. Ipasavyo, mtumiaji aliye na haki za kusoma hakuweza kusoma jedwali mpya.

Kwanini hivyo? Pamoja na ukweli kwamba katika kanuni kuna lazima GRANT, hazitumiwi kila wakati. Kuna mbinu 2: syncPreparedDatabases ΠΈ syncDatabases. Katika syncPreparedDatabases - licha ya ukweli kwamba katika sehemu hiyo preparedDatabases kuna kuna sharti defaultRoles ΠΈ defaultUsers kuunda majukumu, haki chaguo-msingi hazitumiki. Tuko katika mchakato wa kuandaa kiraka ili haki hizi zitumike kiotomatiki.

Na hatua ya mwisho katika maboresho ambayo ni muhimu kwetu - kiraka, ambayo inaongeza Uhusiano wa Node kwa StatefulSet iliyoundwa. Wateja wetu mara nyingi wanapendelea kupunguza gharama kwa kutumia matukio ya mara kwa mara, na ni wazi hawafai kuhudumia huduma za hifadhidata. Suala hili linaweza kutatuliwa kwa uvumilivu, lakini uwepo wa Node Affinity unatoa ujasiri mkubwa.

Nini kimetokea?

Kulingana na matokeo ya kutatua shida zilizo hapo juu, tuligawa Opereta wa Postgres kutoka Zalando hadi hazina yako, ambapo hukusanywa na viraka vile muhimu. Na kwa urahisi zaidi, sisi pia tulikusanya Picha ya Docker.

Orodha ya PRs zilizokubaliwa kwenye uma:

Itakuwa vyema ikiwa jumuiya itatumia PRs hizi ili ziweze kufika juu na toleo linalofuata la opereta (1.6).

Ziada! Hadithi ya mafanikio ya uhamiaji wa uzalishaji

Ikiwa unatumia Patroni, utayarishaji wa moja kwa moja unaweza kuhamishwa hadi kwa opereta kwa muda mdogo wa kupungua.

Spilo hukuruhusu kuunda vikundi vya kusubiri kupitia hifadhi ya S3 na Wal-E, wakati logi ya binary ya PgSQL inahifadhiwa kwanza katika S3 na kisha kutolewa na nakala. Lakini nini cha kufanya ikiwa unayo hakuna inatumiwa na Wal-E kwenye miundombinu ya zamani? Suluhisho la tatizo hili tayari ilipendekezwa kwenye kitovu.

Urudiaji wa kimantiki wa PostgreSQL huja kuwaokoa. Hata hivyo, hatutaingia kwa undani kuhusu jinsi ya kuunda machapisho na usajili, kwa sababu ... mpango wetu ulikuwa fiasco.

Ukweli ni kwamba hifadhidata ilikuwa na meza kadhaa zilizopakiwa na mamilioni ya safu, ambazo, zaidi ya hayo, zilijazwa tena na kufutwa. Usajili rahisi с copy_data, wakati nakala mpya inakili yaliyomo yote kutoka kwa bwana, haiwezi kwenda sambamba na bwana. Kunakili maudhui kulifanya kazi kwa wiki moja, lakini hakukutana na bwana. Mwishowe, ilinisaidia kutatua shida makala wenzake kutoka Avito: unaweza kuhamisha data kwa kutumia pg_dump. Nitaelezea toleo letu (lililorekebishwa kidogo) la algorithm hii.

Wazo ni kwamba unaweza kufanya usajili uliozimwa kuunganishwa na nafasi maalum ya urudufishaji, na kisha kurekebisha nambari ya muamala. Kulikuwa na nakala zinazopatikana kwa kazi ya uzalishaji. Hii ni muhimu kwa sababu replica itasaidia kuunda dampo thabiti na kuendelea kupokea mabadiliko kutoka kwa bwana.

Amri zinazofuata zinazoelezea mchakato wa uhamiaji zitatumia vidokezo vifuatavyo vya mwenyeji:

  1. bwana - seva ya chanzo;
  2. nakala1 - replica ya utiririshaji kwenye uzalishaji wa zamani;
  3. nakala2 - replica mpya ya kimantiki.

Mpango wa uhamiaji

1. Unda usajili kwa bwana kwa meza zote kwenye schema public msingi dbname:

psql -h master -d dbname -c "CREATE PUBLICATION dbname FOR ALL TABLES;"

2. Unda nafasi ya kuiga kwenye bwana:

psql -h master -c "select pg_create_logical_replication_slot('repl', 'pgoutput');"

3. Acha urudufishaji kwenye nakala ya zamani:

psql -h replica1 -c "select pg_wal_replay_pause();"

4. Pata nambari ya muamala kutoka kwa bwana:

psql -h master -c "select replay_lsn from pg_stat_replication where client_addr = 'replica1';"

5. Ondoa dampo kutoka kwa nakala ya zamani. Tutafanya hivyo katika nyuzi kadhaa, ambayo itasaidia kuharakisha mchakato:

pg_dump -h replica1 --no-publications --no-subscriptions -O -C -F d -j 8 -f dump/ dbname

6. Pakia utupaji kwenye seva mpya:

pg_restore -h replica2 -F d -j 8 -d dbname dump/

7. Baada ya kupakua dampo, unaweza kuanza urudufishaji kwenye nakala ya utiririshaji:

psql -h replica1 -c "select pg_wal_replay_resume();"

7. Hebu tuunde usajili kwenye nakala mpya ya kimantiki:

psql -h replica2 -c "create subscription oldprod connection 'host=replica1 port=5432 user=postgres password=secret dbname=dbname' publication dbname with (enabled = false, create_slot = false, copy_data = false, slot_name='repl');"

8. Hebu tupate oid usajili:

psql -h replica2 -d dbname -c "select oid, * from pg_subscription;"

9. Tuseme ilipokelewa oid=1000. Wacha tutumie nambari ya muamala kwa usajili:

psql -h replica2 -d dbname -c "select pg_replication_origin_advance('pg_1000', 'AA/AAAAAAAA');"

10. Wacha tuanze kuiga:

psql -h replica2 -d dbname -c "alter subscription oldprod enable;"

11. Angalia hali ya usajili, urudufu unapaswa kufanya kazi:

psql -h replica2 -d dbname -c "select * from pg_replication_origin_status;"
psql -h master -d dbname -c "select slot_name, restart_lsn, confirmed_flush_lsn from pg_replication_slots;"

12. Baada ya urudufishaji kuanza na hifadhidata kusawazishwa, unaweza kubadili.

13. Baada ya kulemaza urudiaji, unahitaji kusahihisha mlolongo. Hili limeelezewa vyema katika makala kwenye wiki.postgresql.org.

Shukrani kwa mpango huu, ubadilishaji ulifanyika kwa ucheleweshaji mdogo.

Hitimisho

Waendeshaji wa Kubernetes hukuruhusu kurahisisha vitendo mbalimbali kwa kuzipunguza hadi kuunda rasilimali za K8s. Walakini, baada ya kupata otomatiki ya kushangaza kwa msaada wao, inafaa kukumbuka kuwa inaweza pia kuleta idadi ya nuances zisizotarajiwa, kwa hivyo chagua waendeshaji wako kwa busara.

Baada ya kuzingatia waendeshaji watatu maarufu wa Kubernetes kwa PostgreSQL, tulichagua mradi kutoka Zalando. Na ilitubidi kushinda ugumu fulani nayo, lakini matokeo yalikuwa ya kufurahisha sana, kwa hivyo tunapanga kupanua uzoefu huu kwa usakinishaji mwingine wa PgSQL. Ikiwa una uzoefu wa kutumia suluhisho zinazofanana, tutafurahi kuona maelezo katika maoni!

PS

Soma pia kwenye blogi yetu:

Chanzo: mapenzi.com

Kuongeza maoni