Me arendasime DevOps nii hĂ€sti, kui suudame. Meid oli 8 inimest ja Vassil oli Windowsi alal kĂ”ige rohkem kogemusi. Ăkki lahkus Vassil ja mul tuli ĂŒlesanne kĂ€ivitada uus projekt, mis pakub Windowsi arendust. Kui ma laotasin lauale kogu Windowsi arenduse tehnoloogiapaki, siis sain aru, et olukord on valusâŠ
Nii algab lugu Aleksandr SinÄinov jĂ€rgnevaga . Kui ettevĂ”ttest lahkus peamine Windowsi spetsialist, kĂŒsis Aleksandr endalt, mida nĂŒĂŒd teha. Loomulikult tuli minna Linuxile! Aleksandr rÀÀgib, kuidas tal Ă”nnestus luua eelkĂ€ija ja viia osa Windowsi arendusest Linuxile, kasutades 100 000 lĂ”ppkasutajaga elluviidud projekti nĂ€idet.

Kuidas on lihtne ja muretu projekti RPM-i toimetamine, kasutades TFS-i, Puppetit, Linux .NET core'i? Kuidas hallata projekti andmebaasi versioonimist, kui arendajad kuulevad esmakordselt Postgresi ja Flyway sĂ”nu, ja tĂ€htaeg on ĂŒlehomme? Kuidas integreerida Dockeriga? Kuidas motiveerida .NET arendajaid loobuma Windowsist ja smuutidest Puppetile ja Linuxile ĂŒle minnes? Kuidas lahendada ideoloogilisi konfliktide, kui Windowsi teenindamine tootmises pole enam jĂ”ud, tahtmine ega ressursid? Sellest ja veel Web Deploy'ist, testimisest, CI-st, TFS-i kasutamise praktikatest olemasolevates projektides ning muidugi purunenud karkudest ja töötavatest lahendustest rÀÀkis Alexander oma ettekandes.

Nii et Vasja lahkus, ĂŒlesanne on minu, arendajad ootavad talgute ja kannatamatusega. Kui ma lĂ”puks mĂ”istsin, et Vasjat ei saa tagasi, asusin tööle. Esiteks hindasin Windows VM-i protsent meie pargis. Arvud ei olnud Windowsi kasuks.

Kuna me arendame aktiivselt DevOps-i, sain aru, et pean midagi muutma uue rakenduse vĂ€lja toomise lĂ€henemises. Lahendus oli ĂŒks - vĂ”imaluse korral viia kĂ”ik Linuxile ĂŒle. Google aitas mind - tol hetkel oli .Net juba Linuxile portitud ja mĂ”istsin, et see on lahendus!
Miks .NET core koos Linuxiga?
Sellel oli mitu pĂ”hjust. Enamiku jaoks, kes peab valima raha maksmise ja mitte maksmise vahel, valib enamus teise â nagu ka mina. MSDB litsents maksab umbes 1000 âŹ, Windowsi virtuaalmasinate hooldus ulatub sadadesse eurodesse. Suure ettevĂ”tte jaoks on need suured kulud. SeetĂ”ttu sÀÀst â esimene pĂ”hjus. See ei ole kĂ”ige olulisem, aga ĂŒks tĂ€htsatest.
Windowsi virtuaalmasinad tarbivad rohkem ressursse kui nende Linuxi vennad â need on rasked. Arvestades suure ettevĂ”tte mastaapi, valisime Linuxi.
SĂŒsteem integreerub lihtsalt olemasolevasse CI. Peame end progressiivseteks DevOps'iks, kasutame Bamboo, Jenkins ja GitLab CI, seetĂ”ttu on enamik meie töödest Linuxis.
Viimane pĂ”hjus on mugav jĂ€lgimine. Meil oli vaja vĂ€hendada âjĂ€lgijateâ sisenemisbarjÀÀri â poistele, kes mĂ”istavad tehnilist osa, tagavad töökindluse ja hooldavad teenuseid teise taseme kaudu. Nad olid juba tuttavad Linuxi tehnoloogiaga, seega on neil palju lihtsam uue toote mĂ”istmine, toetamine ja hooldamine kui investeerida tĂ€iendavaid ressursse Windowsi platvormi sarnase funktsionaalsuse mĂ”istmiseks.
NÔuded
Esiteks ja kĂ”ige tĂ€htsam â uue lahenduse mugavus arendajatele. Mitte kĂ”ik neist ei olnud muutusteks valmis, eriti pĂ€rast sĂ”na Linux esitamist. Arendajad soovivad oma lemmik Visual Studio't, TFS-i koos testide automaatika ja smuutidega. Kuidas toimub tootmise toimetamine â see ei huvita neid. SeetĂ”ttu otsustasime jĂ€tta harjumuspĂ€rase protsessi muutmata ja hoida Windowsi arenduses kĂ”ik endisena.
Uus projekt tuleb integreerida olemasolevasse CI. Raudteed olid juba olemas ja kogu töö pidi toimuma arvestusega sĂŒsteemihalduse parameetrite, vastuvĂ”etud kohaletoimetamise standardite ja jĂ€lgimissĂŒsteemide jĂ€rgi.
Lihtsus hoolduses ja kasutuses, nagu tingimus, et kÔik uued osalejad erinevate osakondade ja tugiosakonna poolt saaksid minimaalselt sisse elada.
TĂ€htaeg â eile.
Windowsi arendusmeeskond
Millega töötas Windowsi meeskond siis?

Praegu vĂ”in kindlalt öelda, et IdentityServer4 â see on suurepĂ€rane tasuta ADFS alternatiiv sarnaste vĂ”imalustega, vĂ”i et Entity Framework Core â arendaja paradiis, kus ei pea muretsema SQL skriptide kirjutamise pĂ€rast, vaid saab kirjeldada andmebaasi pĂ€ringuid OOP mĂ”istetega. Kuid siis, tegevuskava arutelus, vaatasin sellele stackile kui ĆĄumeeria kliendikirja, tunnustades vaid PostgreSQL ja Git.
Sel ajal kasutasime aktiivselt Puppet konfiguratsioonihalduse sĂŒsteemina. Enamikus meie projektides kasutasime GitLab CI, Elastic, koormatud teenuseid tasakaalustades HAProxy, jĂ€lgisime kĂ”ike Zabbix, komplekti Grafana ja Prometheus, Jaeger, ja kĂ”ik see töötas raua peal HP c ESXi jĂ€rgnevaga VMware. Ikka tuntud â ĆŸanri klassika.

Vaatame ja pĂŒĂŒame mĂ”ista, mis toimus enne, kui me kĂ”ik need sekkumised ette vĂ”tsime.
Mis oli
TFS on ĂŒsna vĂ”imas sĂŒsteem, mis mitte ainult ei edasta koodi arendajalt lĂ”ppkasutaja masinasse, vaid omab ka komplekti vĂ€ga paindlikuks integreerimiseks erinevate teenustega â CI tagamiseks ristplatvormi tasandil.

Varem olid need tĂ€ielikult avatud aknad. TFS kasutas mitmeid Build-agente, millel kogunes palju projekte. Igas agendis oli 3-4 töötegijat, et ĂŒlesandeid paralleelselt jagada ja protsessi optimeerida. Edasi, vastavalt vĂ€ljalaskekavadele, tarnis TFS vĂ€rskelt vĂ€lja kĂŒpsetatud Buildi Windows-rakenduste serverisse.
Kuhu me tahtsime jÔuda
Kasutame TFS-i tarnimiseks ja arendamiseks, siis kÀivitame rakenduse Linuxi rakendusserveris, ja nende vahel on mingi maagia. See Magic Box ongi eelseisva töö oluline punkt. Enne kui hakkan seda lammutama, teen sammu kÔrvale ja rÀÀgin paar sÔna rakendusest.
Projekt
Rakendus pakub funktsionaalsust ettekandepree-makstud kaartide haldamiseks.

Kliendi
Oli kaks tĂŒĂŒpi kasutajaid. Esimene oli ligipÀÀs SSL SHA-2 sertifikaadi kaudu. teine oli ligipÀÀs sisselogimise ja parooliga.
HAProxy
SeejĂ€rel jĂ”udis kliendi pĂ€ring HAProxy-sse, mis lahendas jĂ€rgmised ĂŒlesanded:
- esmane autoriseerimine;
- SSL-i lÔpetamine;
- HTTP pÀringute hÀÀlestamine;
- pÀringute tÔlkimine.
Kliendi sertifikaadi kontrollimine toimus ahelas. Me oleme authority ja saame endale sellise lubada, kuna anname ise vÀlja sertifikaate teenuse klientidele.
Pöörake tÀhelepanu kolmandale punktile, toome selle teemani tagasi veidi hiljem.
Backend
Tahtsime taustsĂŒsteemi teha Linuxil. TaustsĂŒsteem suhtleb andmebaasiga, laadib vajalikud Ă”iguste loendid ja seejĂ€rel, sĂ”ltuvalt sellest, milliste Ă”igustega autentitud kasutaja on, annab juurde pÀÀsuga finantsdokumentide allkirjastamiseks ja nende tĂ€itmiseks saatmiseks vĂ”i mingi aruande genereerimiseks.
SÀÀstmine c HAProxy
Lisaks kahele kontekstile, millega iga klient toimis, oli veel ĂŒks kontekst identity. IdentityServer4 see vĂ”imaldab sisse logida, see on tasuta ja vĂ”imas analoog ADFS â Active Directory Federation Services.
Identiteedi pĂ€ringut töödeldi mitmes etapis. Esimene etapp, kliendi sattus taustsĂŒsteemi, mis vahetas andmeid selle serveriga ja kontrollis kliendi tokeni olemasolu. Kui see ei leitud - pĂ€ring tagastati tagasi konteksti, kust see tuli, kuid juba suunamisega, ja koos suunamisega lĂ€ks see identiteedile.
Teine etapp - pÀring sattus autentimise lehele IdentityServeris, kus klient registreerus ja IdentityServeri andmebaasis ilmus see kauaoodatud token.
Kolmas etapp - klient suunati tagasi kontekstist, millest ta tuli.

IdentityServer4-l on ĂŒks omadus: vastus tagasiside pĂ€ringule tuleb lĂ€bi HTTP. Ăkski meie serveri seadistamise katsest vĂ”i dokumentatsioonist ei aidanud, me saime iga kord algse kliendi pĂ€ringu, mille URL tuli HTTPS kaudu, aga IdentityServer tagastas sama konteksti HTTP kaudu. Olime ĆĄokis! Ja suunasime selle kĂ”ik lĂ€bi identity konteksti HAProxy kaudu, kuid peame protokolli HTTP modifitseerima HTTPS-iks pĂ€istes.
Mis on parendused ja kus kokkuhoid?
Oleme raha kokku hoidnud, kasutades tasuta lahendust kasutajagruppide autoriseerimiseks, ressursse, kuna me ei tÔstnud IdentityServer4 eraldi sÔlmena eraldi segmenti, vaid kasutasime seda koos rakenduse tagarindega samal serveril, kus rakenduse tagariba töötab.
Kuidas see peaks töötama
Nii et, nagu ma lubasin - Magic Box. Me mĂ”istame nĂŒĂŒd, et suundume kindlasti Linuxi poole. Vaatame konkreetsed ĂŒlesanded, mis vajasid lahendamist.

Puppet manifestid. Teenuste ja rakenduste konfiguratsiooni edastamiseks ja haldamiseks tuli kirjutada suurepÀrased retseptid. Karp pliiatsiga nÀitab selgelt, kui kiiresti ja kvaliteetselt see tehtud sai.
Tarnimisviis. Standard on RPM. KĂ”ik mĂ”istavad, et Linuxis ei saa ilma selleta, kuid ise projekt pĂ€rast kompileerimist oli komplekt tĂ€idetud DLL-failidest. Neid oli umbes 150, projekt oli piisavalt mahukas. Ainus harmooniline lahendus oli pakkida see binaar RPM-i ja seejĂ€rel sealt rakendus ĂŒles tĂ”sta.
Versioonimine. Me pidime vabastama vĂ€ga sageli ja tuli otsustada, kuidas paketi nime kujundada. See on tasemekĂŒsimus TFS-iga integreerimisel. Meie Build-agendiks oli Linux. Kui TFS saadab ĂŒlesande töötlejale â worker â Build-agentile, edastab ta talle ka muutuja massiivi, mis tuleb töötleja protsessi keskkonda. Nendes keskkonnamuutujates edastatakse Buildi nimi, versiooni nimi ja teised muutujad. TĂ€iendavat teavet leiate allpool jaotises âRPM-paketi koostamineâ.
TFS-i seadistamine ÀÀrmus kulmineerub Pipeline'i seadistusse. Varem kogusime Windows-agentides kĂ”ik Windows-projektid, kuid nĂŒĂŒd lisandub Linux-agent â Build-agent, mille tuleb lisada kogumisse, rikastada mingite artefaktidega, mĂ€rkida, millise tĂŒĂŒbi projekte sellele Build-agentile kogutakse, ja muuta Pipeline'i.
IdentityServer. ADFS ei ole meie tee, toetame Open Source'i.
Vaadakem komponente.
Magic Box
Koosneb neljast osast.

Linux Build-agent. Linux, sest me kogume selle alla â loogiline. See osa viidi ellu kolme sammuga.
- Seadistada worker'id ja mitte ainult ĂŒks, kuna eeldati projekti jaotatud töötamist.
- Installeerida .NET Core 1.x. Miks just 1.x, kui 2.0 on juba tavarepositooriumis saadaval? Sest kui me arendamisega alustasime, oli stabiilne versioon 1.09 ja projekti otsustati teha selle alla.
- Git 2.x.
RPM-repositoorium. RPM-pakette tuli kuskil hoida. Eeldati, et kasutame sama ettevÔtte RPM-repositooriumi, mis on kÔigile Linuxi hostidele saadaval. Nii ka tegime. Serveris on repositoorium seadistatud webhook , mis laadis vajalikud RPM-paketid mÀÀratud kohast alla. Paketiversiooni teatas Build-agent webhook'ule.
GitLab. TĂ€htis! GitLab'i kasutatakse siin mitte arendajate, vaid halduskeskuse poolt rakenduse, paketiversioonide ning kĂ”ikide Linux-masinate oleku jĂ€lgimiseks, samuti hoitakse seal retsepte â kĂ”iki Puppet'i manifeste.
Puppet â lahendab kĂ”ik vaidlusalused kĂŒsimused ja toob meile just selle konfigureeringu, mida soovime, GitLab'ist.
Alustame sĂŒvenemist. Kuidas toimub DLL'i tarnimine RPM'i?
DDL'i tarnimine RPM'i
Oletame, et meil on .NET-i arenduse rokktĂ€ht. Ta kasutab Visual Studio't ja loob versiooniharu. PĂ€rast seda laadib ta selle Git'i, kus Git on TFS-ĂŒksus, see tĂ€hendab rakenduse hoidla, millega arendaja töötab.

PÀrast seda nÀeb TFS, et uus kinnitus on saabunud. Milline rakendus? TFS-i seadetes on mÀrge, milliste ressurssidega on erinevad Build-agendid varustatud. Antud juhul nÀeb ta, et ehitame .NET Core projekti ja valib Linuxi Build-agendi basseinist.
Build-agent saab lÀhtekoodid, tÔmbab vajalikud sÔltuvused .NET hoidlast, npm-ist jne, ja pÀrast rakenduse enda koostamist ja jÀrgmist pakkimist saadab RPM-paketi RPM-hoidlasse.
Teiselt poolt toimub jÀrgmist. KÀitamise osakonna insener tegeleb projekti kÀivitamisega: muudab pakettide versioone Hiera hoidlas, kus hoitakse rakenduse retseptuuri, pÀrast mida Puppet kÀivitab Yum, tÔmbab uue paketi hoidlast ja uus rakenduse versioon on kasutamiseks valmis.

KĂ€esolev osa on lihtne, kuid mis toimub tegelikult Build-agentis?
DLL RPM pakkimine
Projektin allikad on saadud ja koostamise ĂŒlesanne TFS-ilt. Build-agent kĂ€ivitab projekti koostamise allikatest.Koostatud projekt on saadaval hulgaliselt DLL faile, mis on pakitud zip-arhiivi, et vĂ€hendada koormust failisĂŒsteemile.
ZIP-arhiiv visatakse RPM pakendi koostamise katalooge. JÀrgmisena Bash-skript initsialiseerib keskkonnamuutujad, leiab Build versiooni, projekti versiooni, tee koostamise kataloogi ja kÀivitab RPM-buildi. PÀrast koostamise lÔpetamist avaldatakse paketid kohalikku hoidlasse, mis asub Build-agentis.
SeejÀrel saadetakse Build-agentist serverisse RPM-hoidlatesse JSON-pÀring versiooni ja build'i nime mÀÀramisega. Webhook, millest ma varem rÀÀkisin, tÔmbab selle paketi kohalikust hoidlast Build-ainel ja teeb uue ehituse installimiseks kergesti kÀttesaadavaks.

Miks just selline paketi kohaletoimetamise skeem RPM hoidlast? Miks ei saa kohe kokku pandud paketti hoidlast saata? Asi on selles, et see on turvalisuse tagamise tingimus. Selline stsenaarium piirab kĂ”rvaliste isikute vĂ”imalust mitteautoriseeritud RPM-pakettide ĂŒleslaadimiseks serverisse, mis on kĂ”igile Linuxi masinatele ligipÀÀsetav.
Andmebaasi versioonimine
Arenduskonsiiliumil selgus, et arendajatele meeldib rohkem MS SQL, kuid enamikus non-Windows projektides oleme juba aktiivselt kasutanud PostgreSQL-i. Kuna otsustasime loobuda kÔigest tasulisest, hakkasime ka siin PostgreSQL-i kasutama.

Selles osas tahan rÀÀkida, kuidas me andmebaasi versioonimist teostasime ja kuidas valisime Flyway ja Entity Framework Core vahel. Vaatame nende plusse ja miinuseid.
Miinused
Flyway töötab ainult ĂŒhes suunas, me ei saa tagasi tagasi minna â see oluline puudus. Entity Framework Core'i saab vĂ”rrelda teiste kriteeriumitega â arendaja mugavuse seisukohalt. Teate ju, et oleme sellele esmatĂ€htsuse andnud, ja peamine kriteerium oli, et mitte muuta midagi Windowsi arenduse jaoks.
Flyway jaoks meil oli vajalik mingi ĂŒmbris, et mehed ei kirjutaks SQL-pĂ€ringuteks. Neil on palju mugavam töötada OOP-tasandil. Kirjutasime juhised andmebaasi objektide kasutamiseks, SQL-i pĂ€ring moodustus ja tĂ€ideti. Uus andmebaasi versioon on valmis, testitud â kĂ”ik on hĂ€sti, kĂ”ik töötab.
Entity Framework Core'il on puudus â suurte koormustega teeb ta mitteoptimaalseid SQL-pĂ€ringuid, ja andmebaasi koormus vĂ”ib olla mĂ€rkimisvÀÀrne. Kuid kuna meil ei ole kĂ”rge koormuse teenust, me ei mÔÔda koormust sadade RPS-idega, siis vĂ”tsime need riskid endale ja delegasime probleemi tulevikus meile.
Plussid
Entity Framework Core töötab kohe ja on arendajatele mugav, kuid Flyway integreerub kergesti olemasolevasse CI. Aga me ju teeme arendajatele mugavamaks :)
KĂ€ivitamisprotseduur
Puppet nĂ€eb, et pakettide versioonide muutus toimub, sealhulgas see, mis vastutab migration'i eest. Esmalt installitakse pakett, kus sisaldub migration'i skriptid ja andmebaasi funktsionaalsus. PĂ€rast seda taaskĂ€ivitub rakendus, mis töötab andmebaasiga. JĂ€rgneb ĂŒlejÀÀnud komponentide installimine. Pakettide installimise jĂ€rjekord ja rakenduste kĂ€ivitamine on kirjeldatud Puppet'i manifestis.
Rakendused kasutavad tundlikke andmeid, nagu token'id ja andmebaasi paroolid; kÔik need tÔmmatakse konfiguraatorist Puppet master, kus nad on salastatud.
TFS probleemid
PĂ€rast seda, kui olime kindlad ja mĂ”istsime, et meil tĂ”epoolest kĂ”ik töötab, otsustasin vaadata, mis toimub TFS-i kogumite osas ĂŒldiselt Win-arendusosakonna muude projektide puhul â kas kokkupanekud/ĂŒlekanded on kiired vĂ”i mitte â ja tuvastasin mĂ€rkimisvÀÀrseid probleeme kiirusest.
Ăks olulisi projekte koostatakse 12-15 minuti jooksul â see on liiga pikk, nii ei saa elada. Kiire analĂŒĂŒs nĂ€itas kohutavat I/O langust ja see toimub massiivide peal.
PĂ€rast komponendi analĂŒĂŒsi eristasin kolm keskpunkti. Esimene â «Kaspersky antivirus», mis skannib lĂ€htekoodide kĂ”igil Windows Build-agentidel. Teine â Windows Indexer. See ei olnud vĂ€lja lĂŒlitatud ja Build-agentidel indekseeriti reaalses ajas kĂ”ik deploy'imise protsessi jooksul.
Kolmas â Npm install. Selgus, et enamikus Pipelines kasutasime just seda skripti. Mis on selle probleem? Npm install protseduur kĂ€ivitatakse sĂ”ltuvuste puu loomisel package-lock.json, kus fikseeritakse pakettide versioonid, mida projekti kokkupanekuks kasutatakse. Miinus seisneb selles, et Npm install toob iga kord uusimad paketiversioonid internetist, mis kulutab mĂ€rkimisvÀÀrselt aega suurte projektide korral.
Arendajad katsetavad mĂ”nikord kohalikul masinal, et kontrollida, kuidas töötavad ĂŒksikud osad vĂ”i terve projekt. MĂ”nikord selgus, et kohapeal kĂ”ik toimib hĂ€sti, aga kokkupanekul â mitte midagi ei töötanud. Alustame probleemi lahendamist â ah, erinevad paketiversioonid sĂ”ltuvustega.
Lahendus
- LÀhtekoodid AV vÀlja jÀtta.
- Indekseerimise keelamine.
- Ăleminekule npm ci.
Npm ci plussideks on see, et me koostame sĂ”ltuvuste puu ĂŒhe korra, ja saame vĂ”imaluse esitada arendajale aktuaalne paketilisti, millega saab katsetada lokaalselt nii palju kui soovib. See sÀÀstab aega arendajatele, kes kirjutavad koodi.
Konfiguratsioon
Natuke nĂŒĂŒd repositooriumi konfiguratsioonist. Ajalooliselt oleme kasutanud Nexus repositooriumide haldamiseks, sealhulgas Internaalse REPO. Selles sisemises repositooriumis on kĂ”ik komponendid, mida kasutame sisetöödeks, nĂ€iteks kohandatud monitooringud.

Kasutame ka NuGet, kuna see on paremini puhverdatud vÔrreldes teiste pakihalduritega.
Tulemus
PÀrast Build-agentide optimeerimist vÀhenes keskmine ehitusaeg 12 minutilt 7 minutile.
Kui arvestada kÔiki masiname, mida oleksime saanud Windowsile, aga muutsime Linuxiks selle projekti raames, siis sÀÀstsime umbes 10 000 dollarit. Ja see on ainult litsentside pealt, kui arvestada sisu - veel rohkem.
Tunniplaanid
JĂ€rgmisse kvartalisse oleme plaaninud koodi kohaletoimetamise optimeerimise.
Ăleminek eelkoostatud Docker-pildi. TFS on Ă€ge asi koos paljude pluginatega, mis vĂ”imaldavad integreerida Pipeline'i, sealhulgas ehituse kĂ€ivitamise nĂ€iteks Docker-pildi puhul. Soovime teha selle kĂ€ivitaja sellele. package-lock.json. Kui mingil viisil muutub projektis kasutatavate komponentide koosseis, kogume uue Docker-pildi. Edasi kasutatakse seda konteineri juurutamiseks koos kogutud rakendusega. Praegu seda ei ole, kuid plaanime ĂŒle minna mikroteenuste arhitektuurile Kuberneteses, mis meie ettevĂ”ttes aktiivselt areneb ja juba pikka aega toetab tootmislahendusi.
KokkuvÔte
Kutsub kÔiki Windowsist loobuma, kuid see pole seetÔttu, et ma ei oska seda seadistada. PÔhjus on selles, et suur osa avatud lÀhtekoodiga lahendustest on Linuxi stack. Te sÀÀstate hÀsti ressursse. Minu arvates on tulevik avatud lÀhtekoodiga lahendustes Linuxis, millel on tugev kogukond.
LĂ€biviija profiil Aleksandr SinÄinov .
 â see on konverents arendamise, testimise ja opereerimise protsesside integreerimiseks professionaalidelt professionaalidele. Just seetĂ”ttu on projekt, millest Aleksandr rÀÀkis, ellu viidud ja töötab, ning esinemispĂ€eva jooksul toimusid kaks edukat versiooni. 27. ja 28. mail on veel rohkem selliseid juhtumeid praktikutelt. Veel on vĂ”imalik viimasele rongile hĂŒpata ja vĂ”i rahulikult. pilet. Kohtume Skolkovo's!
Allikas: habr.com
