{"id":32526,"date":"2019-10-31T21:47:32","date_gmt":"2019-10-31T18:47:32","guid":{"rendered":"https:\/\/prohoster.info\/blog\/protsess-razrabotki-i-testirovaniya-s-docker-i-gitlab-ci\/"},"modified":"2019-10-31T21:47:32","modified_gmt":"2019-10-31T18:47:32","slug":"protsess-razrabotki-i-testirovaniya-s-docker-i-gitlab-ci","status":"publish","type":"post","link":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/protsess-razrabotki-i-testirovaniya-s-docker-i-gitlab-ci","title":{"rendered":"Il processo di sviluppo e testing con Docker e Gitlab CI","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><strong>\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440\u0430 \u0421\u0438\u0433\u0430\u0447\u0435\u0432\u0430 \u0438\u0437 Inventos &#171;\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441 Docker + Gitlab CI&#187;<\/strong><\/p>\n<p><\/p>\n<p>Chi inizia a implementare il processo di sviluppo e testing basato su Docker + Gitlab CI spesso si pone domande fondamentali. Da dove cominciare? Come organizzare? Come testare?<\/p>\n<p><\/p>\n<p>Questa presentazione \u00e8 utile perch\u00e9 spiega in modo strutturato il processo di sviluppo e testing utilizzando Docker e Gitlab CI. La presentazione risale al 2017. Penso che da questo documento si possano trarre le basi, la metodologia, l'idea e l\u2019esperienza d'uso. <\/p>\n<p>\n<center><div class=\"youtube-placeholder\" data-id=\"lJsqRwULRVA\" onclick=\"loadVideo(this)\">\r\n        <img decoding=\"async\" src=\"https:\/\/img.youtube.com\/vi\/lJsqRwULRVA\/hqdefault.jpg\" alt=\"Riproduci video\" loading=\"lazy\" width=\"480\" height=\"360\" style=\"width:100%;height:auto;\">\r\n        <div class=\"play-button\"><\/div>\r\n    <\/div><\/center><\/p>\n<p>Chi \u00e8 interessato, prosegua oltre. <noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p><\/p>\n<p>Mi chiamo Aleksandr Sigachev. Lavoro per la societ\u00e0 Inventos. Condivider\u00f2 la mia esperienza nell'utilizzo di Docker e come lo stiamo implementando gradualmente nei progetti dell'azienda.<\/p>\n<p><\/p>\n<p>Tema della presentazione: Il processo di sviluppo utilizzando Docker e Gitlab CI. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/e30c4757e4bda1bcc3e20b16e8e2709e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Questa \u00e8 la mia seconda presentazione su Docker. Al momento della mia prima presentazione, utilizzavamo Docker solo in fase di sviluppo sui computer degli sviluppatori. Il numero di dipendenti che utilizzavano Docker era di circa 2-3 persone. Gradualmente abbiamo accumulato esperienza e abbiamo fatto qualche passo avanti. Ecco il link al nostro <noindex><a rel=\"nofollow\" href=\"https:\/\/www.slideshare.net\/gled\/docker-development-70411088\">prima presentazione<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Cosa ci sar\u00e0 in questa presentazione? Condivideremo la nostra esperienza su quali ostacoli abbiamo incontrato e come abbiamo risolto diversi problemi. Non \u00e8 stato sempre facile, ma ci ha permesso di andare avanti.<\/p>\n<p><\/p>\n<p>Il nostro motto: containerizza tutto ci\u00f2 che ci passa per le mani.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/25ae4f97f1c502384abfe697bac502b1.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Quali problemi risolviamo?<\/p>\n<p><\/p>\n<p>Quando ci sono pi\u00f9 team in azienda, il programmatore diventa una risorsa condivisa. Ci sono momenti in cui il programmatore viene strappato da un progetto e assegnato per un certo tempo a un altro progetto.<\/p>\n<p><\/p>\n<p>Per permettere al programmatore di integrarsi rapidamente, \u00e8 necessario che scarichi il codice sorgente del progetto e avvii il prima possibile un ambiente che gli permetta di procedere affrontando le attivit\u00e0 di quel progetto.<\/p>\n<p><\/p>\n<p>Di solito, se si inizia da zero, la documentazione del progetto \u00e8 scarsa. Le informazioni su come configurare sono disponibili solo da chi \u00e8 gi\u00e0 presente da tempo. I collaboratori generalmente configurano il proprio ambiente di lavoro in uno o due giorni. Per accelerare questo processo, abbiamo utilizzato Docker.<\/p>\n<p><\/p>\n<p>Il motivo successivo \u00e8 la standardizzazione delle impostazioni in Development. Dalla mia esperienza, gli sviluppatori tendono sempre a prendere l'iniziativa. In un caso su cinque si introduce un dominio personalizzato, ad esempio vasya.dev. Vicino c'\u00e8 il vicino Petya, che ha il dominio petya.dev. Stanno sviluppando un sito o un componente del sistema utilizzando questo nome di dominio.<\/p>\n<p><\/p>\n<p>Quando il sistema si espande e questi nomi di dominio iniziano a comparire nelle configurazioni, si verifica un conflitto negli ambienti di Development e viene sovrascritto il percorso del sito.<\/p>\n<p><\/p>\n<p>Lo stesso accade con le impostazioni del database. Qualcuno non si preoccupa della sicurezza e lavora con la password vuota di root. Qualcun altro, durante l'installazione, ha trovato che MySQL richiedeva una password e la password era semplice, come 123. Spesso accade che la configurazione del database cambi in continuazione a seconda del commit dello sviluppatore. Qualcuno ha corretto, qualcun altro no. Ci sono stati stratagemmi in cui portavamo qualche configurazione di test in <code>.gitignore<\/code> ogni sviluppatore doveva installare un database. Questo complicava il processo di avvio. Oltre a tutto ci\u00f2, \u00e8 importante tenere a mente il database. Il database deve essere inizializzato, \u00e8 necessario specificare una password, un nome utente, creare una tabella e cos\u00ec via.<\/p>\n<p><\/p>\n<p>Un'altra problematica riguarda le diverse versioni delle librerie. Spesso gli sviluppatori lavorano su progetti diversi. C'\u00e8 un progetto legacy che \u00e8 stato avviato cinque anni fa (dal 2017 - nota del curatore). All'inizio si part\u00ec con MySQL 5.5. Ci sono anche progetti moderni, dove cerchiamo di implementare versioni pi\u00f9 recenti di MySQL, come 5.7 o superiore (nel 2017 - nota del curatore).<\/p>\n<p><\/p>\n<p>Chi lavora con MySQL sa che queste librerie portano con s\u00e9 delle dipendenze. \u00c8 piuttosto complicato avviare due database insieme. Almeno, \u00e8 problematico connettere i vecchi client a un nuovo database. Questo, a sua volta, crea diverse problematiche.<\/p>\n<p><\/p>\n<p>Il problema successivo si verifica quando uno sviluppatore lavora su una macchina locale, utilizzando risorse locali, file locali e RAM locale. Tutta l'interazione durante lo sviluppo delle soluzioni avviene all'interno di un unico sistema. Un esempio \u00e8 rappresentato dalla situazione in cui abbiamo 3 server backend in produzione, mentre lo sviluppatore salva i file nella directory radice, da cui nginx preleva i file per rispondere alle richieste. Quando questo codice viene trasferito in produzione, si scopre che il file \u00e8 presente su uno dei 3 server.<\/p>\n<p><\/p>\n<p>Attualmente si sta sviluppando la direzione dei microservizi. Quando suddividiamo le nostre grandi applicazioni in piccoli componenti che interagiscono tra loro. Questo consente di scegliere tecnologie specifiche per il particolare stack di compiti. Inoltre, permette di separare il lavoro e le aree di responsabilit\u00e0 tra gli sviluppatori.<\/p>\n<p><\/p>\n<p>Uno sviluppatore frontend, lavorando in JS, ha un'influenza minima sul backend. Lo sviluppatore backend, a sua volta, sta sviluppando, nel nostro caso, su Ruby on Rails e non interferisce con il frontend. L'interazione avviene tramite API.<\/p>\n<p><\/p>\n<p>Come bonus, grazie a Docker siamo riusciti a gestire le risorse su Staging. Ogni progetto, a causa della sua specificit\u00e0, richiedeva configurazioni particolari. Fisicamente, era necessario dedicare un server virtuale per ciascun progetto e configurarli separatamente, oppure condividere un ambiente variabile, potendo influenzare reciprocamente i progetti in base alle versioni delle librerie.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/fa5c99f90faef84a356d4791fd915830.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Strumenti. Cosa utilizziamo? <\/p>\n<p><\/p>\n<ul>\n<li>Il Docker stesso. Nel Dockerfile vengono descritte le dipendenze di un'applicazione. <\/li>\n<li>Docker-compose \u00e8 il collante che unisce alcune delle nostre applicazioni Docker.<\/li>\n<li>Utilizziamo GitLab per l'archiviazione del codice sorgente.<\/li>\n<li>Utilizziamo GitLab-CI per l'integrazione continua.<\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/b6041827a6ba928e0d33add6b79c581c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>La presentazione \u00e8 composta da due parti.<\/p>\n<p><\/p>\n<p>La prima parte parler\u00e0 di come abbiamo avviato Docker sulle macchine degli sviluppatori.<\/p>\n<p><\/p>\n<p>La seconda parte tratter\u00e0 di come interagiamo con GitLab, come eseguiamo i test e come distribuiamo su Staging.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/45746d3323d35e0d18f066c8bfcb2214.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Docker \u00e8 una tecnologia che consente di descrivere i componenti necessari utilizzando un approccio dichiarativo. Ecco un esempio di Dockerfile. Qui dichiariamo di ereditare dall'immagine Docker ufficiale Ruby:2.3.0, che contiene Ruby versione 2.3. Installiamo le librerie di compilazione necessarie e NodeJS. Descriviamo che creiamo una directory. <code>\/app<\/code>Assegniamo alla directory app la directory di lavoro. In questa directory posizioniamo il Gemfile e il Gemfile.lock minimi necessari. Poi eseguiamo la build dei progetti, che installano le dipendenze di questo'immagine. Indichiamo che il contenitore sar\u00e0 pronto ad ascoltare sulla porta esterna 3000. L'ultima riga \u00e8 il comando che avvia effettivamente la nostra applicazione. Se eseguiamo il comando di avvio del progetto, l'app tenter\u00e0 di eseguire e lancer\u00e0 il comando specificato.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/ba503c305ae90f49b39f4ae2cbda1668.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Questo \u00e8 un esempio minimo di file docker-compose. In questo caso mostriamo come si connettono due contenitori. Si tratta direttamente del servizio del database e del servizio web. Le nostre applicazioni web richiedono spesso come backend un database per memorizzare i dati. Poich\u00e9 utilizziamo MySQL, il nostro esempio \u00e8 con MySQL, ma non c'\u00e8 nulla che ci impedisca di utilizzare un altro database (PostgreSQL, Redis).<\/p>\n<p><\/p>\n<p>Prendiamo l'immagine MySQL 5.7.14 senza modifiche da una fonte ufficiale di Docker Hub. L'immagine che serve alla nostra applicazione web la creiamo dalla directory corrente. Durante il primo avvio, genera l'immagine per noi. Dopo di che, avvia il comando che eseguiamo qui. Se torniamo indietro, vediamo che \u00e8 stato definito un comando di avvio tramite Puma. Puma \u00e8 un servizio scritto in Ruby. Nel secondo caso, lo sovrascriviamo. Questo comando pu\u00f2 essere arbitrario in base alle nostre esigenze o compiti.<\/p>\n<p><\/p>\n<p>Definiamo anche il port forwarding dalla macchina host dello sviluppatore alla porta 3000 del contenitore. Questo avviene automaticamente tramite iptables e il meccanismo incorporato in Docker. <\/p>\n<p><\/p>\n<p>Lo sviluppatore pu\u00f2 continuare a utilizzare qualsiasi indirizzo IP disponibile, ad esempio, 127.0.0.1 come IP locale o l'indirizzo IP esterno della macchina.<\/p>\n<p><\/p>\n<p>L'ultima riga indica che il container web dipende dal container db. Quando avviamo il container web, prima docker-compose avvier\u00e0 il nostro database. Solo dopo l'avvio del database (in realt\u00e0, dopo l'avvio del container! La prontezza del DB non \u00e8 garantita) verr\u00e0 avviata la nostra applicazione, il backend.<\/p>\n<p><\/p>\n<p>Questo consente di evitare errori quando il database non \u00e8 attivo e permette di risparmiare risorse quando interrompiamo il container del database, liberando cos\u00ec risorse per altri progetti. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/4acbcf5de89b98db055e8abc419202de.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Cosa comporta l'uso della containerizzazione del database nel progetto. Fissiamo la versione di MySQL per tutti gli sviluppatori. Questo aiuta a evitare alcuni errori che possono sorgere quando ci sono discrepanze tra le versioni, quando cambia la sintassi, la configurazione, le impostazioni predefinite. Permette di indicare hostname comuni per il database, login e password. Ci allontaniamo cos\u00ec dal caos di nomi e conflitti nei file di configurazione che esistevano precedentemente. <\/p>\n<p><\/p>\n<p>Abbiamo la possibilit\u00e0 di utilizzare una configurazione pi\u00f9 ottimale per l'ambiente di sviluppo, che sar\u00e0 diversa da quella predefinita. MySQL \u00e8 impostato di default per macchine meno potenti e le sue prestazioni, cos\u00ec, sono molto basse fin dall'inizio.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/417d77a06b18e2df9b71440c0f2a1653.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Docker consente di utilizzare l'interprete Python, Ruby, NodeJS, PHP con la versione necessaria. Sgombriamo il campo dalla necessit\u00e0 di utilizzare un gestore di versioni. In passato, per Ruby, utilizzavamo un pacchetto rpm che permetteva di cambiare versione a seconda del progetto. Inoltre, grazie al container Docker, possiamo migrare il codice e versionarlo insieme alle sue dipendenze senza problemi di compatibilit\u00e0. Non ci saranno dubbi riguardo alla versione sia dell'interprete che del codice. Per aggiornare la versione, \u00e8 sufficiente abbattere il vecchio container e avviarne uno nuovo. Se qualcosa va storto, possiamo fermare il nuovo container e riavviare quello vecchio.<\/p>\n<p><\/p>\n<p>Dopo la costruzione dell'immagine, i container sia in sviluppo che in produzione saranno identici. Questo \u00e8 particolarmente rilevante per installazioni di grandi dimensioni.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/185a1bfe257f7e3e0eecdc6e0e0d330f.jpg\" style=\"display:block;margin: 0 auto;\" \/> Per il frontend utilizziamo JavaScript e NodeJS.<\/p>\n<p><\/p>\n<p>Attualmente, l'ultimo progetto \u00e8 su ReactJS. Gli sviluppatori hanno avviato tutti i container e lavorato utilizzando l'hot-reload.<\/p>\n<p><\/p>\n<p>Successivamente, viene avviato un task per la compilazione di JavaScript e il codice generato in statico viene servito tramite nginx, risparmiando risorse.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/4c2e28319d56d7fc81845b4133a1bfe6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Qui ho presentato lo schema del nostro ultimo progetto.<\/p>\n<p><\/p>\n<p>Quali problemi abbiamo risolto? Abbiamo avuto la necessit\u00e0 di costruire un sistema con cui interagirei dispositivi mobili. Ricevono dati. Una delle possibilit\u00e0 \u00e8 inviare notifiche push a questo dispositivo. <\/p>\n<p><\/p>\n<p>Cosa abbiamo fatto per questo?<\/p>\n<p><\/p>\n<p>Abbiamo suddiviso l'applicazione in componenti come: parte admin in JS, backend che opera tramite un'interfaccia REST con Ruby on Rails. Il backend interagisce con il database. I risultati generati vengono restituiti al cliente. L'admin interagisce con il backend e il database attraverso l'interfaccia REST.<\/p>\n<p><\/p>\n<p>Avevamo anche la necessit\u00e0 di inviare notifiche push. In precedenza, avevamo un progetto in cui era stato realizzato un meccanismo per la consegna di notifiche su piattaforme mobili. <\/p>\n<p><\/p>\n<p>Abbiamo sviluppato questo schema: l'operatore dal browser interagisce con l'admin, l'admin interagisce con il backend, e viene impostato un task per inviare notifiche push.<\/p>\n<p><\/p>\n<p>Le notifiche push interagiscono con un altro componente, implementato su NodeJS.<\/p>\n<p><\/p>\n<p>Le code delle notifiche viene costruito attraverso delle code, che poi vengono inviate secondo il loro meccanismo.<\/p>\n<p><\/p>\n<p>Qui sono illustrate due basi di dati. Attualmente, utilizzando Docker, abbiamo due basi di dati indipendenti, che non sono collegate tra loro. A parte il fatto che condividono una rete virtuale, i dati fisici sono memorizzati in diverse directory sulla macchina dello sviluppatore.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/dfde59db7e6886d2d851dcf884049318.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Lo stesso vale in numeri. Qui \u00e8 importante il riutilizzo del codice.<\/p>\n<p><\/p>\n<p>Se prima parlavamo del riutilizzo del codice sotto forma di librerie, in questo esempio il nostro servizio per le notifiche push viene riutilizzato come server completo. Fornisce un'API. E la nostra nuova applicazione interagisce con essa.<\/p>\n<p><\/p>\n<p>A quel tempo utilizzavamo la versione 4 di NodeJS. Attualmente (nel 2017 \u2014 nota della redazione) nei nuovi progetti utilizziamo la versione 7 di NodeJS. Non ci sono problemi ad incorporare nuove versioni delle librerie nei nuovi componenti. <\/p>\n<p><\/p>\n<p>Se necessario, si pu\u00f2 procedere a un refactoring e aggiornare la versione di NodeJS per il servizio delle notifiche push. <\/p>\n<p><\/p>\n<p>Se possiamo mantenere la compatibilit\u00e0 con l'API, potremo sostituirlo in altri progetti utilizzati in precedenza.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/5c58c65be078a5a1b9fc17ee2e7b4ad4.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Cosa serve per aggiungere Docker? Aggiungiamo nel nostro repository un Dockerfile che descrive le dipendenze necessarie. In questo esempio, i componenti sono suddivisi logicamente. Questa \u00e8 la configurazione minima per uno sviluppatore backend.<\/p>\n<p><\/p>\n<p>Quando creiamo un nuovo progetto, creiamo un Dockerfile e descriviamo l'ecosistema necessario (Python, Ruby, NodeJS). In docker-compose descriviamo le dipendenze necessarie, come il database. Specifichiamo di quale versione di database abbiamo bisogno e dove conservare i dati.<\/p>\n<p><\/p>\n<p>Utilizziamo un terzo contenitore separato con nginx per servire i file statici. \u00c8 prevista la possibilit\u00e0 di caricare immagini. Il backend le colloca in un volume preparato in anticipo, che \u00e8 anche montato nel contenitore con nginx, il quale serve i file statici.<\/p>\n<p><\/p>\n<p>Per archiviare la configurazione di nginx e mysql, abbiamo aggiunto una cartella Docker in cui conserviamo i file di configurazione necessari. Quando lo sviluppatore esegue il git clone del repository sulla propria macchina, ottiene gi\u00e0 un progetto pronto per lo sviluppo locale. Non ci si pone la domanda su quale porta o quali impostazioni applicare.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/e7a6b308a75cacf8ce60687a9e6081dd.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Successivamente, abbiamo diversi componenti: admin, inform-API, push-notifiche.<\/p>\n<p><\/p>\n<p>Per avviare tutto ci\u00f2, abbiamo creato un altro repository chiamato dockerized-app. Al momento utilizziamo diversi repository per ciascun componente. Questi si differenziano logicamente: in GitLab appare come una cartella, mentre sulla macchina dello sviluppatore si trova una cartella specifica per il progetto. A un livello inferiore ci sono i componenti che verranno uniti.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/f4e2c45c8ec20fca0bac74b3a3892543.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Questo \u00e8 un esempio del contenuto di dockerized-app. Qui includiamo anche la cartella Docker, in cui inseriamo le configurazioni necessarie per le interazioni tra i vari componenti. \u00c8 presente un README.md, che descrive brevemente come avviare il progetto.<\/p>\n<p><\/p>\n<p>Abbiamo applicato due file docker-compose. Questo \u00e8 stato fatto per avere la possibilit\u00e0 di avviare in modo graduale. Quando uno sviluppatore lavora sul core, non ha bisogno delle notifiche push, quindi avvia semplicemente il file docker-compose e di conseguenza si risparmiano le risorse.<\/p>\n<p><\/p>\n<p>Se \u00e8 necessario integrare le notifiche push, si avvia docker-compose.yaml e docker-compose-push.yaml.<\/p>\n<p><\/p>\n<p>Poich\u00e9 docker-compose.yaml e docker-compose-push.yaml si trovano nella stessa cartella, viene automaticamente creata una rete virtuale unica.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/535019c82c72c1602176fbaf4aa5640f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Descrizione dei componenti. Questo \u00e8 un file pi\u00f9 esteso che \u00e8 responsabile della raccolta dei componenti. Cosa c'\u00e8 di notevole qui? Qui introduciamo il componente bilanciatore.<\/p>\n<p><\/p>\n<p>Questo \u00e8 un'immagine Docker pronta, in cui viene eseguito nginx e un'applicazione che ascolta il socket Docker. Genera dinamicamente la configurazione di nginx man mano che i contenitori vengono attivati e disattivati. La gestione dei componenti viene distribuita su nomi di dominio di terzo livello.<\/p>\n<p><\/p>\n<p>Per l'ambiente di sviluppo utilizziamo il dominio .dev \u2014 api.informer.dev. Le applicazioni con dominio .dev sono accessibili sulla macchina locale dello sviluppatore.<\/p>\n<p><\/p>\n<p>In seguito, le configurazioni vengono trasferite a ciascun progetto e tutti i progetti vengono avviati simultaneamente.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/bc1e11e6f1fd1c837d2c8087d04145c4.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Se lo rappresentassimo graficamente, il client sarebbe il nostro browser o uno strumento tramite il quale inviamo richieste al bilanciatore.<\/p>\n<p><\/p>\n<p>Il bilanciatore determina, in base al nome di dominio, a quale contenitore rivolgersi.<\/p>\n<p><\/p>\n<p>Questo potrebbe essere nginx, che fornisce le JS della dashboard. Oppure nginx, che offre l'API o file statici, che vengono serviti da nginx come caricamento delle immagini.<\/p>\n<p><\/p>\n<p>Nello schema si vede che i contenitori sono connessi in una rete virtuale e nascosti dietro un proxy.<\/p>\n<p><\/p>\n<p>Su una macchina di sviluppo, \u00e8 possibile accedere al contenitore conoscendo l'IP, ma in generale non lo utilizziamo. Non sorge praticamente mai la necessit\u00e0 di un accesso diretto.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/2908c31fd9d3c79f6189bdbeeb6d028f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Quale esempio posso vedere per dockerizzare la mia applicazione? A mio parere, un buon esempio \u00e8 l'immagine ufficiale di Docker per MySQL.<\/p>\n<p><\/p>\n<p>\u00c8 piuttosto complesso. Ci sono molte versioni. Tuttavia, le sue funzionalit\u00e0 coprono molte esigenze che possono sorgere durante lo sviluppo. Se dedichi del tempo a capire come interagiscono tutte queste parti, penso che nell'implementazione autonoma non dovresti avere problemi.<\/p>\n<p><\/p>\n<p>Su hub.docker.com di solito ci sono collegamenti a github.com, dove sono forniti i dati grezzi da cui puoi creare autonomamente l'immagine.<\/p>\n<p><\/p>\n<p>All'interno di questo repository c'\u00e8 uno script docker-endpoint.sh, che si occupa dell'inizializzazione iniziale e della successiva gestione dell'avvio dell'applicazione.<\/p>\n<p><\/p>\n<p>In questo esempio \u00e8 anche presente la possibilit\u00e0 di configurare utilizzando variabili d'ambiente. Definendo un ambiente variabile al momento dell'avvio di un singolo container o tramite docker-compose, possiamo specificare che abbiamo bisogno di impostare una password vuota per docker per root su MySQL, oppure una password a nostra scelta.<\/p>\n<p><\/p>\n<p>C'\u00e8 la possibilit\u00e0 di creare una password casuale. Indichiamo che ci serve un utente, dobbiamo impostare una password per l'utente e dobbiamo creare un database.<\/p>\n<p><\/p>\n<p>Nei nostri progetti abbiamo unificato un po' il Dockerfile, che si occupa dell'inizializzazione. Abbiamo adattato le necessit\u00e0 per semplicemente estendere i diritti dell'utente utilizzato dall'applicazione. Questo ha permesso di creare facilmente un database dalla console dell'applicazione. Nelle applicazioni Ruby c'\u00e8 un comando per creare, modificare e eliminare database.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/4a9b56e21819d28dd39753134d23fee4.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Questo \u00e8 un esempio di come appare una versione specifica di MySQL su github.com. \u00c8 possibile aprire il Dockerfile e vedere come avviene l'installazione.<\/p>\n<p><\/p>\n<p>Lo script docker-endpoint.sh \u00e8 responsabile del punto d'ingresso. Durante la prima inizializzazione, sono necessarie alcune preparazioni e tutte queste azioni sono riportate nello script di inizializzazione.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/4153fa46526f3d802931dd1db48b08cd.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Passiamo alla seconda parte.<\/p>\n<p><\/p>\n<p>Per la memorizzazione del codice sorgente abbiamo scelto gitlab. \u00c8 un sistema piuttosto potente che offre un'interfaccia visiva.<\/p>\n<p><\/p>\n<p>Uno dei componenti di Gitlab \u00e8 Gitlab CI. Questo consente di descrivere una serie di comandi che saranno utilizzati successivamente per organizzare un sistema di distribuzione del codice o per avviare test automatici.<\/p>\n<p><\/p>\n<p>Relazione su Gitlab CI 2 <noindex><a rel=\"nofollow\" href=\"https:\/\/goo.gl\/uohKjI\">https:\/\/goo.gl\/uohKjI<\/a><\/noindex> \u2014 una presentazione del Ruby Russia club \u2014 piuttosto dettagliata e potrebbe interessarvi.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/5d26d20500f34eeb9768e6c3d91bbefa.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ora vediamo cosa \u00e8 necessario per attivare Gitlab CI. Per avviare Gitlab CI, \u00e8 sufficiente posizionare il file .gitlab-ci.yml nella radice del progetto.<\/p>\n<p><\/p>\n<p>Qui descriviamo le sequenze di stati che vogliamo eseguire, come i test o il deploy.<\/p>\n<p><\/p>\n<p>Eseguiamo script che richiamano direttamente la costruzione dell'applicazione usando docker-compose. Questo \u00e8 un esempio di backend.<\/p>\n<p><\/p>\n<p>Successivamente, ci assicuriamo di eseguire le migrazioni per le modifiche al database e di eseguire i test.<\/p>\n<p><\/p>\n<p>Se gli script vengono eseguiti correttamente e non restituiscono codice di errore, il sistema passa quindi alla seconda fase del deployment.<\/p>\n<p><\/p>\n<p>La fase di deployment \u00e8 attualmente implementata per lo staging. Non abbiamo organizzato un riavvio senza downtime.<\/p>\n<p><\/p>\n<p>Spegniamo forzatamente tutti i container e poi riavviamo tutti i container, assemblati nella prima fase durante il testing.<\/p>\n<p><\/p>\n<p>Eseguiamo le migrazioni del database gi\u00e0 per l'ambiente variabile corrente, scritte dai sviluppatori.<\/p>\n<p><\/p>\n<p>C'\u00e8 una nota che indica di applicare questo solo per il branch master.<\/p>\n<p><\/p>\n<p>Non viene eseguito quando si modificano altri branch.<\/p>\n<p><\/p>\n<p>C'\u00e8 la possibilit\u00e0 di organizzare i deployment per branch.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/8a5b880bd9a0d4bab0b276568e2ba413.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Per procedere con ci\u00f2, dobbiamo installare Gitlab Runner.<\/p>\n<p><\/p>\n<p>Questo strumento \u00e8 scritto in Golang. \u00c8 un file singolo, come \u00e8 consuetudine nel mondo Golang, senza dipendenze necessarie.<\/p>\n<p><\/p>\n<p>Durante l'esecuzione registriamo Gitlab Runner.<\/p>\n<p><\/p>\n<p>Otteniamo dalla web interfaccia di Gitlab una chiave.<\/p>\n<p><\/p>\n<p>Poi chiamiamo il comando di inizializzazione nel terminale.<\/p>\n<p><\/p>\n<p>Configuriamo Gitlab Runner in modalit\u00e0 dialogo (Shell, Docker, VirtualBox, SSH).<\/p>\n<p><\/p>\n<p>Il codice su Gitlab Runner verr\u00e0 eseguito a ogni commit in base alla configurazione di .gitlab-ci.yml.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/37c8ac7499f0cfba2eb07a84083e44e1.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ecco come appare visivamente in GitLab nell'interfaccia web. Dopo aver collegato GitLab CI, appare una bandiera che mostra in quale stato si trova attualmente il build.<\/p>\n<p><\/p>\n<p>Possiamo vedere che 4 minuti fa \u00e8 stato effettuato un commit che ha superato tutti i test senza alcun problema.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/33ac79c45f0651a5f8bde75092c4ac44.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Possiamo esaminare pi\u00f9 dettagliatamente i build. Qui vediamo che sono gi\u00e0 passati due stati: lo stato di test e lo stato di deploy su staging.<\/p>\n<p><\/p>\n<p>Se clicchiamo su un build specifico, ci sar\u00e0 l'output della console dei comandi eseguiti durante il processo secondo il file .gitlab-ci.yml.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/d26dd28708c7fc8a409af4be4d48f502.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ecco come appare la cronologia del nostro prodotto. Possiamo vedere i tentativi riusciti. Quando i test falliscono, non si passa al passo successivo e il codice su staging non viene aggiornato.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/ee7bd81dc283c7af0c194779d4230780.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Quali problemi abbiamo risolto su staging quando abbiamo implementato Docker? La nostra sistema \u00e8 composta da diversi componenti e abbiamo dovuto riavviare solo una parte dei componenti che erano stati aggiornati nel repository, piuttosto che l'intero sistema.<\/p>\n<p><\/p>\n<p>Per questo motivo, abbiamo dovuto separare tutto in cartelle distinte.<\/p>\n<p><\/p>\n<p>Dopo aver completato l'operazione, abbiamo riscontrato un problema con Docker-compose, che crea uno spazio di rete separato per ogni cartella e non riesce a vedere i componenti vicini.<\/p>\n<p><\/p>\n<p>Per aggirare questo, abbiamo creato manualmente una rete in Docker. In Docker-compose, abbiamo specificato di utilizzare questa rete per il progetto.<\/p>\n<p><\/p>\n<p>In questo modo, ogni componente che viene avviato con questa rete pu\u00f2 vedere i componenti in altre parti del sistema.<\/p>\n<p><\/p>\n<p>Il problema successivo riguarda la separazione degli ambienti di staging tra pi\u00f9 progetti.<\/p>\n<p><\/p>\n<p>Per far s\u00ec che tutto appaia attraente e il pi\u00f9 vicino possibile alla produzione, \u00e8 consigliabile utilizzare le porte 80 o 443, largamente utilizzate nel WEB.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/f863cf1833271bf132455a70ad7d2706.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Come abbiamo risolto questo problema? Abbiamo assegnato un unico Gitlab Runner a tutti i grandi progetti.<\/p>\n<p><\/p>\n<p>Gitlab consente di avviare pi\u00f9 Gitlab Runner distribuiti, i quali prenderanno gli incarichi in modo casuale e sequenziale.<\/p>\n<p><\/p>\n<p>Per evitare confusione, abbiamo limitato il gruppo dei nostri progetti a un solo Gitlab Runner, che gestisce senza problemi i nostri volumi di lavoro.<\/p>\n<p><\/p>\n<p>Abbiamo estratto nginx-proxy in uno script di avvio separato e in esso abbiamo specificato le reti di tutti i progetti. <\/p>\n<p><\/p>\n<p>Il nostro progetto ha una rete, mentre il bilanciatore ne ha diverse con i nomi dei progetti. Pu\u00f2 fare proxy in base ai nomi di dominio.<\/p>\n<p><\/p>\n<p>Riceviamo richieste sul dominio tramite la porta 80, che vengono gestite da un gruppo di container che serve quel dominio.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/25c769f029b272a17fd06bbe60cf0ea0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Quali altri problemi ci sono stati? Di default, tutti i container vengono eseguiti con l'utente root. Questo root non \u00e8 lo stesso del root del sistema host.<\/p>\n<p><\/p>\n<p>Tuttavia, se si accede al container, si avr\u00e0 root e il file che creiamo in quel container ottiene i diritti di root.<\/p>\n<p><\/p>\n<p>Se uno sviluppatore \u00e8 entrato nel container e ha eseguito alcuni comandi che generano file, poi esce dal container, nella propria directory di lavoro avr\u00e0 un file a cui non ha accesso.<\/p>\n<p><\/p>\n<p>Come possiamo risolvere questo problema? Possiamo aggiungere utenti che saranno nel container.<\/p>\n<p><\/p>\n<p>Quali problemi sono sorti quando abbiamo aggiunto un utente?<\/p>\n<p><\/p>\n<p>Creando un utente, spesso non coincidono l'ID del gruppo (UID) e l'ID dell'utente (GID).<\/p>\n<p><\/p>\n<p>Per risolvere questo problema, nel container utilizziamo utenti con ID 1000.<\/p>\n<p><\/p>\n<p>Nel nostro caso, questo coincide con il fatto che praticamente tutti gli sviluppatori utilizzano il sistema operativo Ubuntu. E in Ubuntu il primo utente ha ID 1000.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/d4911374e4953fdcd807c387efeafec3.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Quali sono i nostri piani?<\/p>\n<p><\/p>\n<p>Rileggere la documentazione su Docker. Il progetto \u00e8 in continua evoluzione e la documentazione cambia. I dati raccolti due o tre mesi fa stanno gi\u00e0 lentamente diventando obsoleti. <\/p>\n<p><\/p>\n<p>Alcuni dei problemi che abbiamo risolto sono probabilmente gi\u00e0 risolti con mezzi standard.<\/p>\n<p><\/p>\n<p>Vorrei tanto andare oltre e passare direttamente all'orchestrazione.<\/p>\n<p><\/p>\n<p>Uno degli esempi \u00e8 il meccanismo integrato in Docker chiamato Docker Swarm, che viene fornito di default. Voglio avviare qualcosa in produzione basato sulla tecnologia Docker Swarm.<\/p>\n<p><\/p>\n<p>La generazione di contenitori rende scomoda la gestione dei log. Attualmente i log sono isolati. Sono sparsi nei vari contenitori. Uno degli obiettivi \u00e8 creare un accesso comodo ai log tramite interfaccia web.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Il processo di sviluppo e testing con Docker e Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/cff8c72dd8af7de1fa0227601bd1d69c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>Fonte: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/449742\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440\u0430 \u0421\u0438\u0433\u0430\u0447\u0435\u0432\u0430 \u0438\u0437 Inventos &#171;\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441 Docker + Gitlab CI&#187; \u0422\u0435, \u043a\u0442\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0432\u043d\u0435\u0434\u0440\u044f\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430 \u0431\u0430\u0437\u0435 Docker + Gitlab CI \u0447\u0430\u0441\u0442\u043e \u0441\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u044e\u0442 \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b. \u0421 \u0447\u0435\u0433\u043e \u043d\u0430\u0447\u0430\u0442\u044c? \u041a\u0430\u043a \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u0442\u044c? \u041a\u0430\u043a \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c? \u042d\u0442\u043e\u0442 \u0434\u043e\u043a\u043b\u0430\u0434 \u0445\u043e\u0440\u043e\u0448 \u0442\u0435\u043c, \u0447\u0442\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043e \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":24326,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-32526","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 4.9.10 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440\u0430 \u0421\u0438\u0433\u0430\u0447\u0435\u0432\u0430 \u0438\u0437 Inventos &quot;\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441 Docker + Gitlab CI&quot; \u0422\u0435, \u043a\u0442\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0432\u043d\u0435\u0434\u0440\u044f\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430 \u0431\u0430\u0437\u0435 Docker + Gitlab CI \u0447\u0430\u0441\u0442\u043e \u0441\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u044e\u0442 \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b. \u0421 \u0447\u0435\u0433\u043e \u043d\u0430\u0447\u0430\u0442\u044c? \u041a\u0430\u043a \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u0442\u044c? \u041a\u0430\u043a \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c? \u042d\u0442\u043e\u0442 \u0434\u043e\u043a\u043b\u0430\u0434 \u0445\u043e\u0440\u043e\u0448 \u0442\u0435\u043c, \u0447\u0442\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043e \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/protsess-razrabotki-i-testirovaniya-s-docker-i-gitlab-ci\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 4.9.10\" \/>\n\t\t<meta property=\"og:locale\" content=\"it_IT\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441 Docker \u0438 Gitlab CI | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440\u0430 \u0421\u0438\u0433\u0430\u0447\u0435\u0432\u0430 \u0438\u0437 Inventos &quot;\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441 Docker + Gitlab CI&quot; \u0422\u0435, \u043a\u0442\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0432\u043d\u0435\u0434\u0440\u044f\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430 \u0431\u0430\u0437\u0435 Docker + Gitlab CI \u0447\u0430\u0441\u0442\u043e \u0441\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u044e\u0442 \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b. \u0421 \u0447\u0435\u0433\u043e \u043d\u0430\u0447\u0430\u0442\u044c? \u041a\u0430\u043a \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u0442\u044c? \u041a\u0430\u043a \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c? \u042d\u0442\u043e\u0442 \u0434\u043e\u043a\u043b\u0430\u0434 \u0445\u043e\u0440\u043e\u0448 \u0442\u0435\u043c, \u0447\u0442\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043e \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/protsess-razrabotki-i-testirovaniya-s-docker-i-gitlab-ci\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T18:47:32+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T18:47:32+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Il processo di sviluppo e testing con Docker e Gitlab CI | ProHoster","description":"Ti invitiamo a esplorare la trascrizione della presentazione di Aleksandr Sigachev di Inventos \"Il processo di sviluppo e testing con Docker + Gitlab CI\". Chi inizia a implementare processi di sviluppo e testing basati su Docker + Gitlab CI spesso pone domande fondamentali. Da dove cominciare? Come organizzare? Come testare? Questa presentazione \u00e8 utile perch\u00e9 illustra in modo strutturato il processo di sviluppo e","canonical_url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/protsess-razrabotki-i-testirovaniya-s-docker-i-gitlab-ci","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"it_IT","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441 Docker \u0438 Gitlab CI | ProHoster","og:description":"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440\u0430 \u0421\u0438\u0433\u0430\u0447\u0435\u0432\u0430 \u0438\u0437 Inventos &quot;\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441 Docker + Gitlab CI&quot; \u0422\u0435, \u043a\u0442\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0432\u043d\u0435\u0434\u0440\u044f\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430 \u0431\u0430\u0437\u0435 Docker + Gitlab CI \u0447\u0430\u0441\u0442\u043e \u0441\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u044e\u0442 \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b. \u0421 \u0447\u0435\u0433\u043e \u043d\u0430\u0447\u0430\u0442\u044c? \u041a\u0430\u043a \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u0442\u044c? \u041a\u0430\u043a \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c? \u042d\u0442\u043e\u0442 \u0434\u043e\u043a\u043b\u0430\u0434 \u0445\u043e\u0440\u043e\u0448 \u0442\u0435\u043c, \u0447\u0442\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043e \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438","og:url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/protsess-razrabotki-i-testirovaniya-s-docker-i-gitlab-ci","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T18:47:32+00:00","article:modified_time":"2019-10-31T18:47:32+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"32526","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-21 11:18:24","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 02:57:22","updated":"2026-01-21 11:18:24"},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/32526","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/comments?post=32526"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/32526\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media\/24326"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media?parent=32526"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/categories?post=32526"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/tags?post=32526"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}