.NET Core en Linukso, DevOps ĉevaldorse

Ni disvolvis DevOps kiel eble plej bone. Ni estis 8, kaj Vasja estis la plej mojosa en Vindozo. Subite Vasja foriris, kaj mi havis la taskon lanĉi novan projekton, kiun liveris Vindoza evoluo. Kiam mi forĵetis la tutan Vindozan disvolvan stakon sur la tablon, mi rimarkis, ke la situacio estis doloro...

Tiel komenciĝas la rakonto Aleksandra Sinĉinova sur DevOpsConf. Kiam la ĉefa Windows-specialisto forlasis la firmaon, Aleksandro demandis sin kion fari nun. Ŝanĝu al Linukso, kompreneble! Aleksandro rakontos al vi kiel li sukcesis krei precedencon kaj translokigi parton de Vindoza evoluo al Linukso uzante la ekzemplon de finita projekto por 100 finaj uzantoj.

.NET Core en Linukso, DevOps ĉevaldorse

Kiel facile kaj senpene liveri projekton al RPM uzante TFS, Puppet, Linukso .NET-kernon? Kiel subteni version de projekto-datumbazo se la evolua teamo aŭdas la vortojn Postgres kaj Flyway unuafoje, kaj la limdato estas postmorgaŭ? Kiel integri kun Docker? Kiel instigi .NET-programistojn forlasi Vindozon kaj smoothies favore al Puppet kaj Linukso? Kiel solvi ideologiajn konfliktojn se ekzistas nek la forto, nek la deziro, nek la rimedoj por konservi Vindozon en produktado? Pri tio, same kiel pri Web Deploy, testado, CI, pri la praktikoj uzi TFS en ekzistantaj projektoj, kaj, kompreneble, pri rompitaj lambastonoj kaj laborsolvoj, en la transskribo de la raporto de Aleksandro.


Do, Vasja foriris, la tasko estas sur mi, la programistoj atendas senpacience kun forkoj. Kiam mi finfine komprenis, ke Vasja ne povas esti resendita, mi eklaboris. Komence, mi taksis la procenton de Win VMs en nia floto. La poentaro ne estis favora al Vindozo.

.NET Core en Linukso, DevOps ĉevaldorse

Ĉar ni aktive disvolvas DevOps, mi rimarkis, ke io devas esti ŝanĝita en la aliro al livero de nova aplikaĵo. Estis nur unu solvo - se eble, transigu ĉion al Linukso. Guglo helpis min - tiutempe .Net jam estis portita al Linukso, kaj mi konstatis, ke tio estas la solvo!

Kial .NET-kerno kune kun Linukso?

Estis pluraj kialoj por ĉi tio. Inter "pagi monon" kaj "ne pagi", la plimulto elektos la duan - kiel mi. Licenco por MSDB kostas ĉirkaŭ $1; konservi aron de Vindozaj virtualaj maŝinoj kostas centojn da dolaroj. Por granda kompanio ĉi tio estas granda elspezo. Tial ŝparante - unua kialo. Ne la plej grava, sed unu el la signifaj.

Vindozaj virtualaj maŝinoj okupas pli da rimedoj ol iliaj Linuksaj fratoj - ili estas pezaj. Konsiderante la skalon de la granda kompanio, ni elektis Linukson.

La sistemo estas simple integrita en ekzistanta CI. Ni konsideras nin progresemaj DevOps, ni uzas Bambuon, Jenkins kaj GitLab CI, do plejparto de nia laboro funkcias per Linukso.

La lasta kialo estas oportuna akompano. Ni bezonis malaltigi la baron al eniro por "eskortoj" - la uloj kiuj komprenas la teknikan parton, certigas seninterrompan servon kaj konservas servojn de la dua linio. Ili jam konis la Linuksan stakon, do estas multe pli facile por ili kompreni, subteni kaj konservi novan produkton ol elspezi pliajn rimedojn por kompreni la saman funkcion de programaro por la Vindoza platformo.

postuloj

Unue kaj ĉefe - oportuno de la nova solvo por programistoj. Ne ĉiuj estis pretaj por ŝanĝo, precipe post kiam la vorto Linukso estis parolita. Programistoj volas sian plej ŝatatan Visual Studion, TFS kun aŭtotestoj por asembleoj kaj smoothies. Kiel okazas livero al produktado ne gravas por ili. Tial ni decidis ne ŝanĝi la kutiman procezon kaj lasi ĉion senŝanĝa por Vindoza disvolviĝo.

Nova projekto bezonata integriĝu en ekzistanta CI. La reloj jam estis tie kaj la tuta laboro devis esti farita konsiderante la parametrojn de la agorda administra sistemo, akceptitaj livernormoj kaj monitoraj sistemoj.

Facileco de subteno kaj operacio, kiel kondiĉo por la minimuma enirsojlo por ĉiuj novaj partoprenantoj de malsamaj sekcioj kaj la subtena fako.

Limdato - hieraŭ.

Win Development Group

Kun kio laboris tiam la Vindoza teamo?

.NET Core en Linukso, DevOps ĉevaldorse

Nun mi povas memfide diri tion Identeca Servilo4 estas bonega senpaga alternativo al ADFS kun similaj kapabloj, aŭ kio Enta Kadro Kerno - paradizo por programisto, kie vi ne devas ĝeni skribi SQL-skriptojn, sed priskribi demandojn en la datumbazo en OOP-esprimoj. Sed tiam, dum la diskuto pri la agadplano, mi rigardis ĉi tiun stakon kvazaŭ ĝi estus sumera kojnoforma, rekonante nur PostgreSQL kaj Git.

Tiutempe ni aktive uzis Marioneto kiel agorda administradsistemo. En la plej multaj el niaj projektoj ni uzis GitLab CI, elasta, ekvilibraj altŝarĝaj servoj uzante HAProxy monitoris ĉion per Zabbikh, ligamentoj grafana и Prometeo, Jaeger, kaj ĉio ĉi ŝpinis sur ferpecoj HPESXi sur VMware. Ĉiuj scias ĝin - klasikaĵo de la ĝenro.

.NET Core en Linukso, DevOps ĉevaldorse

Ni rigardu kaj provu kompreni kio okazis antaŭ ol ni komencis ĉiujn ĉi intervenojn.

Kio okazis

TFS estas sufiĉe potenca sistemo, kiu ne nur liveras kodon de la programisto al la fina produktmaŝino, sed ankaŭ havas aron por tre fleksebla integriĝo kun diversaj servoj - por provizi CI sur transplatforma nivelo.

.NET Core en Linukso, DevOps ĉevaldorse
Antaŭe, ĉi tiuj estis solidaj fenestroj. TFS uzis plurajn Build-agentojn, kiuj kutimis kunveni multajn projektojn. Ĉiu agento havas 3-4 laboristojn por paraleligi taskojn kaj optimumigi la procezon. Tiam, laŭ eldonplanoj, TFS liveris la ĵus bakitan Konstruaĵon al la Vindoza aplikaĵoservilo.

Kion ni volis atingi?

Ni uzas TFS por livero kaj evoluo, kaj rulas la aplikaĵon sur Linuksa Aplika servilo, kaj estas ia magio inter ili. Ĉi tio Magia Skatolo kaj tie estas la salo de la laboro antauxe. Antaŭ ol mi disigos ĝin, mi faros paŝon flanken kaj diros kelkajn vortojn pri la aplikaĵo.

La projekto

La aplikaĵo provizas funkciojn por manipuli antaŭpagitajn kartojn.

.NET Core en Linukso, DevOps ĉevaldorse

Kliento

Estis du specoj de uzantoj. La unua akiris aliron per ensaluto per SSL SHA-2-atestilo. U la dua estis aliro uzante ensaluton kaj pasvorton.

HAProxy

Tiam la klienta peto iris al HAProxy, kiu solvis la sekvajn problemojn:

  • primara rajtigo;
  • SSL-fino;
  • agordi HTTP-petojn;
  • elsendaj petoj.

La klientatestilo estis kontrolita laŭ la ĉeno. Ni - aŭtoritato kaj ni povas pagi ĉi tion, ĉar ni mem eldonas atestilojn al servaj klientoj.

Atentu la trian punkton, ni revenos al ĝi iom poste.

backend

Ili planis fari la backend sur Linukso. La backend interagas kun la datumbazo, ŝarĝas la necesan liston de privilegioj kaj tiam, depende de kiaj privilegioj havas la rajtigita uzanto, disponigas aliron por subskribi financajn dokumentojn kaj sendi ilin por ekzekuto, aŭ generi ian raporton.

Ŝparaĵoj kun HAProxy

Krom la du kuntekstoj, kiujn ĉiu kliento navigis, ekzistis ankaŭ identeca kunteksto. Identeca Servilo4 nur permesas vin ensaluti, ĉi tio estas senpaga kaj potenca analogo por ADFS - Aktivaj Adresaraj Federaciaj Servoj.

La identecpeto estis procesita en pluraj paŝoj. Unua paŝo - kliento eniris la malantaŭon, kiu komunikis kun ĉi tiu servilo kaj kontrolis la ĉeeston de ĵetono por la kliento. Se ĝi ne estis trovita, la peto estis resendita al la kunteksto de kiu ĝi venis, sed kun alidirektilo, kaj kun la alidirektilo ĝi iris al identeco.

Dua paŝo - la peto estis ricevita al la rajtiga paĝo en IdentityServer, kie la kliento registriĝis, kaj tiu longe atendita ĵetono aperis en la datumbazo IdentityServer.

Tria paŝo - la kliento estis redirektita al la kunteksto de kiu ĝi venis.

.NET Core en Linukso, DevOps ĉevaldorse

IdentityServer4 havas funkcion: ĝi resendas la respondon al la revenpeto per HTTP. Kiom ajn ni luktis por agordi la servilon, kiom ajn ni lumigis nin per la dokumentado, ĉiufoje ni ricevis komencan klientpeton kun URL, kiu venis per HTTPS, kaj IdentityServer resendis la saman kuntekston, sed kun HTTP. Ni estis ŝokitaj! Kaj ni transdonis ĉion ĉi tra la identeckunteksto al HAProxy, kaj en la kaplinioj ni devis modifi la HTTP-protokolon al HTTPS.

Kio estas la plibonigo kaj kie vi ŝparis?

Ni ŝparis monon uzante senpagan solvon por rajtigi grupon de uzantoj, rimedojn, ĉar ni ne metis IdentityServer4 kiel apartan nodon en apartan segmenton, sed uzis ĝin kune kun la backend sur la sama servilo kie funkcias la backend de la aplikaĵo. .

Kiel ĝi devus funkcii

Do, kiel mi promesis - Magia Skatolo. Ni jam komprenas, ke ni garantias moviĝi al Linukso. Ni formulu specifajn taskojn, kiuj postulis solvojn.

.NET Core en Linukso, DevOps ĉevaldorse

Marioneto manifestiĝas. Por liveri kaj administri servon kaj aplikan agordon, bonegaj receptoj devis esti skribitaj. Rulo da krajono elokvente montras kiom rapide kaj efike ĝi estis farita.

Livera metodo. La normo estas RPM. Ĉiuj komprenas, ke en Linukso oni ne povas malhavi ĝin, sed la projekto mem, post kunigo, estis aro de ruleblaj DLL-dosieroj. Estis ĉirkaŭ 150 el ili, la projekto estis sufiĉe malfacila. La sola harmonia solvo estas paki ĉi tiun binaron en RPM kaj deploji la aplikaĵon de ĝi.

Versiado. Ni devis liberigi tre ofte, kaj ni devis decidi kiel formi la paknomon. Ĉi tio estas demando pri la nivelo de integriĝo kun TFS. Ni havis konstruagenton en Linukso. Kiam TFS sendas taskon al prizorganto - laboristo - al la Build-agento, ĝi ankaŭ pasas al ĝi aron da variabloj, kiuj finiĝas en la medio de la pritraktila procezo. Ĉi tiuj mediaj variabloj enhavas la Konstruan nomon, version-nomon kaj aliajn variablojn. Legu pli pri tio en la sekcio "Konstruado de RPM-pakaĵo".

Agordi TFS venis al starigo de Pipeline. Antaŭe, ni kolektis ĉiujn Vindozajn projektojn pri Vindozaj agentoj, sed nun aperas Linukso-agento - Build-agento, kiu devas esti inkluzivita en la konstrugrupo, riĉigita per kelkaj artefaktoj, kaj rakontita kiaj projektoj estos konstruitaj sur ĉi tiu Build-agento. , kaj iel modifi la Dukto.

Identeca Servilo. ADFS ne estas nia maniero, ni iras por Malferma Fonto.

Ni trairu la komponantojn.

Magia Skatolo

Konsistas el kvar partoj.

.NET Core en Linukso, DevOps ĉevaldorse

Agento de Linuksa Konstruo. Linukso, ĉar ni konstruas por ĝi - ĝi estas logika. Ĉi tiu parto estis farita en tri paŝoj.

  • Agordi laboristojn kaj ne sole, ĉar estis atendita disdonata laboro pri la projekto.
  • Instalu .NET Core 1.x. Kial 1.x kiam 2.0 jam disponeblas en la norma deponejo? Ĉar kiam ni komencis disvolviĝon, la stabila versio estis 1.09, kaj oni decidis fari la projekton bazitan sur ĝi.
  • Git 2.x.

RPM-deponejo. RPM-pakaĵoj devis esti stokitaj ie. Oni supozis, ke ni uzus la saman kompanian RPM-deponejon, kiu estas disponebla por ĉiuj Linuksaj gastigantoj. Tion ili faris. La deponeja servilo estas agordita rethoko kiu elŝutis la bezonatan RPM-pakaĵon de la specifita loko. La pakaĵversio estis raportita al la rethoko fare de la Build-agento.

GitLab. Atentu! GitLab ĉi tie estas uzata ne de programistoj, sed de la operacia fako por kontroli aplikaĵversiojn, pakaĵversiojn, monitori la staton de ĉiuj Linuksaj maŝinoj, kaj ĝi konservas la recepton - ĉiuj Puppet-manifestoj.

Marioneto — solvas ĉiujn polemikajn problemojn kaj liveras ĝuste la agordon, kiun ni volas de Gitlab.

Ni komencas plonĝi. Kiel funkcias DLL-livero al RPM?

Livero DDL al RPM

Ni diru, ke ni havas .NET-disvolvan rokstelulon. Ĝi uzas Visual Studio kaj kreas eldonbranĉon. Post tio, ĝi alŝutas ĝin al Git, kaj Git ĉi tie estas TFS-unuo, tio estas, ĝi estas la aplikaĵa deponejo kun kiu la programisto laboras.

.NET Core en Linukso, DevOps ĉevaldorse

Post tio TFS vidas, ke nova transdono alvenis. Kiu aplikaĵo? En la agordoj de TFS estas etikedo indikanta kiajn rimedojn havas aparta Build-agento. En ĉi tiu kazo, li vidas, ke ni konstruas .NET Core-projekton kaj elektas Linuksan Konstruan agenton el la naĝejo.

La Build-agento ricevas la fontojn kaj elŝutas la necesajn dependecoj el la deponejo .NET, npm, ktp. kaj post konstruado de la aplikaĵo mem kaj posta pakado, sendas la RPM-pakaĵon al la RPM-deponejo.

Aliflanke, la sekvanta okazas. La operacia fako-inĝeniero estas rekte implikita en la lanĉo de la projekto: li ŝanĝas la versiojn de pakaĵoj enen Hiera en la deponejo kie la aplika recepto estas stokita, post kiu Puppet ekfunkciigas yum, prenas la novan pakaĵon el la deponejo, kaj la nova versio de la aplikaĵo estas preta por uzi.

.NET Core en Linukso, DevOps ĉevaldorse

Ĉio estas simpla en vortoj, sed kio okazas ene de la Build-agento mem?

Pakado de DLL RPM

Ricevis projektfontojn kaj konstrutaskon de TFS. Konstrua agento komencas konstrui la projekton mem el fontoj. La kunvenita projekto haveblas kiel aro DLL-dosieroj, kiuj estas enpakitaj en zip-arkivo por redukti la ŝarĝon sur la dosiersistemo.

La ZIP-arkivo estas forĵetita al la RPM-paka konstrua dosierujo. Poste, la Bash-skripto pravalorigas la mediovariablojn, trovas la Build-version, la projektan version, la vojon al la konstrua dosierujo kaj rulas RPM-build. Post kiam la konstruo estas kompleta, la pakaĵo estas publikigita al loka deponejo, kiu situas sur la Build-agento.

Poste, de la Konstrua agento al la servilo en la RPM-deponejo JSON-peto estas sendita indikante la nomon de la versio kaj konstruo. Webhook, pri kiu mi parolis pli frue, elŝutas ĉi tiun pakaĵon el la loka deponejo sur la Build-agento kaj disponigas la novan asembleon por instalo.

.NET Core en Linukso, DevOps ĉevaldorse

Kial ĉi tiu speciala paka liveroskemo al la RPM-deponejo? Kial mi ne povas tuj sendi la kunmetitan pakaĵon al la deponejo? Fakte, ĉi tio estas kondiĉo por certigi sekurecon. Ĉi tiu scenaro limigas la eblecon de neaŭtorizitaj homoj alŝuti RPM-pakaĵojn al servilo kiu estas alirebla por ĉiuj Linuksaj maŝinoj.

datumbaza versio

Ĉe interkonsiliĝo kun la disvolva teamo, montriĝis, ke la uloj estis pli proksimaj al MS SQL, sed en la plej multaj ne-Vindozaj projektoj ni jam uzis PostgreSQL kun ĉiuj fortoj. Ĉar ni jam decidis forlasi ĉion pagita, ni komencis uzi PostgreSQL ankaŭ ĉi tie.

.NET Core en Linukso, DevOps ĉevaldorse

En ĉi tiu parto mi volas rakonti al vi kiel ni versionis la datumbazon kaj kiel ni elektis inter Flyway kaj Entity Framework Core. Ni rigardu iliajn avantaĝojn kaj malavantaĝojn.

Miksoj

Flugvojo iras nur unudirekte, ni ni ne povas retroiri - tio estas grava malavantaĝo. Vi povas kompari ĝin kun Entity Framework Core alimaniere - laŭ komforto de programisto. Vi memoras, ke ni metis ĉi tion ĉe la avangardo, kaj la ĉefa kriterio estis ne ŝanĝi ion ajn por Vindoza disvolviĝo.

Por Flyway ni ia envolvaĵo estis bezonatapor ke la uloj ne skribu SQL-demandoj. Ili estas multe pli proksimaj al funkciado en OOP terminoj. Ni skribis instrukciojn por labori kun datumbazaj objektoj, generis SQL-demandon kaj efektivigis ĝin. La nova versio de la datumbazo estas preta, provita - ĉio estas en ordo, ĉio funkcias.

Entity Framework Core havas minuson - sub pezaj ŝarĝoj ĝi konstruas suboptimumajn SQL-demandojn, kaj la malaltiĝo en la datumbazo povas esti signifa. Sed ĉar ni ne havas altan ŝarĝan servon, ni ne kalkulas la ŝarĝon en centoj da RPS, ni akceptis ĉi tiujn riskojn kaj delegis la problemon al ni estontaj.

Puloj

Enta Kadro Kerno funkcias ekster la skatolo kaj estas facile disvolvigebla, kaj Flyway Facile integriĝas en ekzistanta CI. Sed ni faras ĝin oportuna por programistoj :)

Roll-up proceduro

Puppet vidas, ke venas ŝanĝo en pakaĵversio, inkluzive de tiu, kiu respondecas pri migrado. Unue, ĝi instalas pakaĵon kiu enhavas migrajn skriptojn kaj datumbaz-rilatajn funkciojn. Post tio, la aplikaĵo, kiu funkcias kun la datumbazo, estas rekomencita. Poste venas la instalado de la ceteraj komponantoj. La ordo en kiu pakaĵoj estas instalitaj kaj aplikaĵoj estas lanĉitaj estas priskribita en la Puppet-manifesto.

Aplikoj uzas sentemajn datumojn, kiel ĵetonojn, datumbazajn pasvortojn, ĉio ĉi estas enmetita en la agordon de Puppet-majstro, kie ili estas konservitaj en ĉifrita formo.

TFS-problemoj

Post kiam ni decidis kaj komprenis, ke ĉio vere funkcias por ni, mi decidis rigardi kio okazas kun la asembleoj en TFS kiel tuto por la Win-disvolva fako pri aliaj projektoj - ĉu ni konstruas/publikigas rapide aŭ ne, kaj malkovris gravajn problemojn kun rapideco.

Unu el la ĉefaj projektoj bezonas 12-15 minutojn por kunveni - tio estas longa tempo, vi ne povas vivi tiel. Rapida analizo montris teruran malaltiĝon en I/O, kaj ĉi tio estis sur tabeloj.

Analizinte ĝin komponanto post komponanto, mi identigis tri fokusojn. Unue - "Kaspersky-antiviruso", kiu skanas fontojn sur ĉiuj Windows Build-agentoj. Due - fenestroj Indeksilo. Ĝi ne estis malŝaltita, kaj ĉio estis indeksita en reala tempo ĉe la Build-agentoj dum la deplojprocezo.

Tria - Npm instali. Montriĝis, ke en la plej multaj Pipelines ni uzis ĉi tiun precizan scenaron. Kial li estas malbona? La instalprocedo de Npm ruliĝas kiam la dependeca arbo estas formita package-lock.json, kie la versioj de pakaĵoj kiuj estos uzataj por konstrui la projekton estas registritaj. La malavantaĝo estas, ke Npm-instalo eltiras la plej novajn versiojn de pakaĵoj de la Interreto ĉiufoje, kaj ĉi tio prenas multan tempon en la kazo de granda projekto.

Programistoj foje eksperimentas sur loka maŝino por testi kiel aparta parto aŭ tuta projekto funkcias. Kelkfoje montriĝis, ke ĉio estis malvarmeta surloke, sed ili kunmetis ĝin, ruliĝis, kaj nenio funkciis. Ni komencas eltrovi, kio estas la problemo - jes, malsamaj versioj de pakaĵoj kun dependecoj.

decido

  • Fontoj en AV-esceptoj.
  • Malebligu indeksadon.
  • Iru al npm ci.

La avantaĝoj de npm ci estas ke ni Ni kolektas la dependecan arbon unufoje, kaj ni ricevas la ŝancon provizi la programiston aktuala listo de pakoj, kun kiu li povas eksperimenti surloke kiom li ŝatas. Ĉi tio ŝparas tempon programistoj kiuj skribas kodon.

Agordo

Nun iomete pri la deponeja agordo. Historie ni uzas ligilo por administri deponejojn, inkluzive Interna REPO. Ĉi tiu interna deponejo enhavas ĉiujn komponantojn, kiujn ni uzas por internaj celoj, ekzemple, memskriba monitorado.

.NET Core en Linukso, DevOps ĉevaldorse

Ni ankaŭ uzas NuGet, ĉar ĝi havas pli bonan kaŝmemoron kompare kun aliaj pakaĵadministrantoj.

rezulto

Post kiam ni optimumigis la Konstruajn Agentojn, la meza konstrua tempo reduktiĝis de 12 minutoj al 7.

Se ni kalkulas ĉiujn maŝinojn, kiujn ni povus uzi por Vindozo, sed ŝanĝis al Linukso en ĉi tiu projekto, ni ŝparis ĉirkaŭ $ 10 000. Kaj tio estas nur pri permesiloj, kaj pli se ni konsideras la enhavon.

Planoj

Por la venonta trimonato, ni planis labori pri optimumigo de koda livero.

Ŝanĝi al antaŭkonstruita Docker-bildo. TFS estas bonega afero kun multaj kromprogramoj, kiuj permesas vin integriĝi en Pipeline, inkluzive de ellasil-bazita kunigo de, ekzemple, bildo de Docker. Ni volas fari ĉi tiun ellasilon por la sama package-lock.json. Se la komponado de la komponantoj uzataj por konstrui la projekton iel ŝanĝiĝas, ni konstruas novan Docker-bildon. Ĝi poste estas uzata por deploji la ujon kun la kunmetita aplikaĵo. Ĉi tio ne estas la kazo nun, sed ni planas ŝanĝi al mikroserva arkitekturo en Kubernetes, kiu aktive disvolviĝas en nia kompanio kaj delonge servas produktadsolvojn.

Resumo

Mi instigas ĉiujn forĵeti Vindozon, sed ne estas ĉar mi ne scias kiel kuiri ĝin. La kialo estas, ke la plej multaj Opensource-solvoj estas Linuksa stako. Ĉu vi estas bone ŝpari sur rimedoj. Laŭ mi, la estonteco apartenas al Malfermfontaj solvoj en Linukso kun potenca komunumo.

Profilo de parolanto de Aleksandro Sinĉinov sur GitHub.

DevOps Conf estas konferenco pri la integriĝo de evoluado, testado kaj operacioprocezoj por profesiuloj de profesiuloj. Tial la projekto pri kiu parolis Aleksandro? efektivigita kaj funkcianta, kaj en la tago de la prezento estis du sukcesaj eldonoj. On DevOps Conf ĉe RIT++ La 27-an kaj 28-an de majo estos eĉ pli similaj kazoj de praktikistoj. Vi ankoraŭ povas salti en la lastan kaleŝon kaj sendi raporton aŭ prenu vian tempon rezervi bileto. Renkontu nin en Skolkovo!

fonto: www.habr.com

Aldoni komenton