Creazione di una pipeline CI/CD e automazione del lavoro con Docker

Ho creato i miei primi siti alla fine degli anni '90. Allora era molto semplice metterli in funzione. C'era un server Apache su qualche hosting condiviso, potevi accedere a questo server via FTP, inserendo nella barra del browser qualcosa come ftp://ftp.example.com. Poi bisognava inserire nome e password e caricare i file sul server. Altri tempi, era tutto più semplice allora rispetto a oggi.

Creazione di una pipeline CI/CD e automazione del lavoro con Docker

Negli ultimi due decenni, è cambiato molto. I siti sono diventati più complessi e, prima di essere messi in produzione, devono essere costruiti. Un singolo server è diventato un insieme di server che operano dietro bilanciatori di carico, l'uso dei sistemi di controllo versione è diventato normale.

Per il mio progetto personale avevo una configurazione speciale. E sapevo che avevo bisogno di poter implementare il sito in produzione con un'unica azione: pubblicare il codice in un ramo. master su GitHub. Inoltre, sapevo che per far funzionare la mia piccola applicazione web non volevo gestire un enorme cluster Kubernetes, né usare la tecnologia Docker Swarm, né mantenere un parco server con pod, agenti e tutte le altre complicazioni. Per raggiungere l'obiettivo di semplificare al massimo il lavoro, ho dovuto familiarizzare con CI/CD.

Se hai un piccolo progetto (nel nostro caso si tratta di un progetto Node.js) e desideri scoprire come automatizzare il deployment di questo progetto, assicurandoti che ciò che è archiviato nel repository corrisponda esattamente a ciò che funziona in produzione, penso che questo articolo possa interessarti.

Requisiti preliminari

Si prevede che il lettore di questo articolo abbia una conoscenza di base dell'uso della riga di comando e della scrittura di script Bash. Inoltre, saranno necessarie delle account. Travis CI e Docker Hub.

Obiettivi

Non dirò che questo articolo possa essere definito senza riserve come un 'manuale'. È piuttosto un documento in cui condivido ciò che ho imparato e descrivo il processo di test e deployment del codice in produzione che mi soddisfa, eseguito in un'unica passata automatizzata.

Ecco come è risultato il mio flusso di lavoro.

Per il codice inviato in qualsiasi ramo del repository, eccetto master, vengono effettuate le seguenti azioni:

  • Viene avviata la build del progetto su Travis CI.
  • Vengono eseguiti tutti i test unitari, di integrazione e end-to-end.

Solo per il codice che arriva in master, viene eseguito il seguente processo:

  • Tutto ciò che è stato detto sopra, più…
  • Creazione dell'immagine Docker basata sul codice attuale, sulle impostazioni e sull'ambiente.
  • Pubblicazione dell'immagine su Docker Hub.
  • Connessione al server di produzione.
  • Download dell'immagine da Docker Hub sul server.
  • Arresto del contenitore attuale e avvio di uno nuovo basato sulla nuova immagine.

Se non sai assolutamente nulla su Docker, immagini e contenitori, non preoccuparti. Ti spiegherò tutto.

Che cos'è il CI/CD?

L'abbreviazione CI/CD sta per «integrazione continua / distribuzione continua».

▍Integrazione continua

L'integrazione continua è un processo in cui gli sviluppatori effettuano commit nel repository principale del codice sorgente del progetto (di solito nel branch master). La qualità del codice è garantita attraverso test automatizzati.

▍Distribuzione continua

La distribuzione continua è un'implementazione automatizzata frequente del codice in produzione. La seconda parte dell'abbreviazione CI/CD viene talvolta interpretata come «consegna continua». Questo è, in generale, lo stesso della «distribuzione continua», ma la «consegna continua» implica la necessità di una conferma manuale delle modifiche prima di avviare il processo di distribuzione del progetto.

Inizio

L'applicazione su cui ho imparato tutto questo si chiama TakeNote. Questo è un progetto web su cui sto lavorando, destinato a prendere appunti. Inizialmente ho cercato di realizzare JAMStack- progetto, o solo un'applicazione front-end senza server, per sfruttare le funzionalità standard di hosting e deploy dei progetti offerte da Netlify. Man mano che la complessità dell'applicazione aumentava, ho dovuto creare anche la sua parte server, il che significava che dovevo sviluppare una mia strategia per l'integrazione automatizzata e il deploy automatizzato del progetto.

Nel mio caso, l'applicazione è un server Express che funziona in un ambiente Node.js, che serve un'applicazione React a pagina singola e supporta un'API server protetta. Questa architettura segue una strategia che si può trovare in questa guida all'autenticazione full-stack.

Ho consultato un amico, che è esperto in automazione, e gli ho chiesto cosa devo fare affinché tutto funzioni come desidero. Mi ha suggerito un'idea su come dovrebbe apparire il flusso di lavoro automatizzato, descritto nella sezione 'Obiettivi' di questo articolo. Il fatto di aver stabilito tali obiettivi significava che dovevo capire come utilizzare Docker.

Docker

Docker è uno strumento che, grazie alla tecnologia della containerizzazione, consente di distribuire facilmente le applicazioni e di eseguirle nello stesso ambiente, anche se la piattaforma Docker opera in ambienti diversi. Per iniziare, avevo bisogno di avere a disposizione gli strumenti da riga di comando (CLI) di Docker. Le istruzioni per l'installazione di Docker non sono molto chiare e comprensibili, ma si può apprendere che per fare il primo passo nell'installazione è necessario scaricare Docker Desktop (per Mac o Windows).

Docker Hub è più o meno equivalente a GitHub per i repository git, o il registro npm per i pacchetti JavaScript. È un repository online per le immagini Docker. È a questo a cui si collega Docker Desktop.

Per iniziare a lavorare con Docker, bisogna fare due cose:

Dopo di che, puoi verificare se Docker CLI funziona eseguendo il seguente comando per controllare la versione di Docker:

docker -v

Successivamente, accedi a Docker Hub inserendo il tuo nome utente e password quando richiesto:

docker login

Per utilizzare Docker, devi comprendere i concetti di immagini e contenitori.

▍Immagini

Un'immagine è come un piano che contiene istruzioni per costruire un contenitore. È un'istantanea immutabile del file system e delle impostazioni dell'applicazione. Gli sviluppatori possono facilmente condividere le immagini.

# Вывод сведений обо всех образах
docker images

Questo comando restituirà una tabella con il seguente titolo:

REPOSITORY     TAG     IMAGE ID     CREATED     SIZE
---

In seguito, esamineremo alcuni esempi di comandi in questo stesso formato — prima il comando con un commento, poi un esempio di ciò che potrebbe restituire.

▍Contenitori

Un container è un pacchetto eseguibile che contiene tutto il necessario per eseguire un'applicazione. Con questo approccio, l'applicazione funzionerà sempre allo stesso modo, indipendentemente dall'infrastruttura: in un ambiente isolato e nella stessa configurazione. Si tratta di eseguire istanze della stessa immagine in ambienti diversi.

# Перечисление всех контейнеров
docker ps -a
CONTAINER ID     IMAGE     COMMAND     CREATED     STATUS     PORTS     NAMES
---

▍Tag

Un tag è un'indicazione di una versione specifica dell'immagine.

▍Panoramica dei comandi Docker

Ecco una panoramica di alcuni dei comandi Docker più utilizzati.

Team

Contesto

Azione

docker build

Immagine

Costruzione di un'immagine da Dockerfile

docker tag

Immagine

Tagging dell'immagine

docker images

Immagine

Visualizzazione dell'elenco delle immagini

docker run

Container

Avvio di un container basato su un'immagine

docker push

Immagine

Invio dell'immagine nel registry

docker pull

Immagine

Download dell'immagine dal registry

docker ps

Container

Visualizzazione dell'elenco dei container

docker system prune

Immagine/Container

Rimozione di container e immagini non utilizzati

▍File Dockerfile

So come eseguire un'applicazione in locale per la produzione. Ho una configurazione Webpack progettata per costruire un'applicazione React pronta. Successivamente, ho un comando che avvia un server basato su Node.js sulla porta 5000. Ecco come si presenta:

npm i         # installazione delle dipendenze
npm run build # creazione dell'applicazione React
npm run start # avvio del server Node

Va notato che non ho un'applicazione di esempio per questo materiale. Ma qui, per esperimenti, andrà bene qualsiasi semplice applicazione Node.

Per utilizzare il contenitore, dovrai fornire istruzioni a Docker. Questo si fa tramite un file chiamato Dockerfile, che si trova nella directory principale del progetto. Questo file, all'inizio, può sembrare piuttosto complicato.

Ma ciò che contiene è solo una descrizione, con comandi speciali, di qualcosa di simile alla configurazione dell'ambiente di lavoro. Ecco alcuni di questi comandi:

  • DA — Questo comando avvia il file. Specifica l'immagine di base su cui viene costruito il contenitore.
  • COPY — Copiando file da una fonte locale al contenitore.
  • WORKDIR — Imposta la directory di lavoro per i comandi successivi.
  • RUN — Esecuzione dei comandi.
  • EXPOSE — Configurazione della porta.
  • ENTRYPOINT — Specifica il comando da eseguire.

Dockerfile può apparire circa così:

# Загрузить базовый образ
FROM node:12-alpine

# Скопировать файлы из текущей директории в директорию app/
COPY . app/

# Использовать app/ в роли рабочей директории
WORKDIR app/

# Установить зависимости (команда npm ci похожа npm i, но используется для автоматизированных сборок)
RUN npm ci --only-production

# Собрать клиентское React-приложение для продакшна
RUN npm run build

# Прослушивать указанный порт
EXPOSE 5000

# Запустить Node-сервер
ENTRYPOINT npm run start

A seconda dell'immagine di base scelta, potrebbe essere necessario installare dipendenze aggiuntive. Alcune immagini di base (come Node Alpine Linux) sono state create per essere il più compatte possibile. Di conseguenza, potrebbero mancare alcuni programmi su cui conti.

▍Costruzione, tagging e avvio del container

La costruzione e l'avvio locale del container sono, dopo che abbiamo Dockerfile, compiti piuttosto semplici. Prima di inviare l'immagine su Docker Hub, deve essere testata localmente.

▍Costruzione

Prima di tutto, devi costruire immagine, specificando un nome e, se necessario, un tag (se non viene specificato un tag, il sistema assegnerà automaticamente un tag all'immagine latest).

# Сборка образа
docker build -t <image>:<tag> .

Dopo aver eseguito questo comando, puoi vedere come Docker sta eseguendo la costruzione dell'immagine.

Invio del contesto di costruzione al demone Docker   2.88MB
Passo 1/9 : FROM node:12-alpine
 ---> ...esecuzione delle fasi di costruzione...
Costruzione riuscita 123456789123
Taggato con successo <image>:<tag>

La costruzione può richiedere un paio di minuti — tutto dipende da quante dipendenze hai. Dopo il completamento della costruzione, puoi eseguire il comando docker images e guardare la descrizione della tua nuova immagine.

REPOSITORY          TAG               IMAGE ID            CREATED              SIZE
             latest            123456789123        About a minute ago   x.xxGB

▍Avvio

L'immagine è stata creata. Questo significa che si può avviare un container basato su di essa. Poiché voglio avere la possibilità di accedere all'applicazione che gira nel container all'indirizzo localhost:5000, ho impostato nella parte sinistra della coppia 5000:5000 nel comando seguente. 5000. Nella parte destra si trova la porta del container.

# Запуск с использованием локального порта 5000 и порта контейнера 5000
docker run -p 5000:5000 <image>:<tag>

Ora che il container è stato creato e avviato, posso utilizzare il comando docker ps per dare un'occhiata alle informazioni su questo container (oppure posso utilizzare il comando docker ps -a, che restituisce informazioni su tutti i container, non solo su quelli in esecuzione).

CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS                    PORTS                    NAMES
987654321234                     "/bin/sh -c 'npm run…"   6 seconds ago        Up 6 seconds              0.0.0.0:5000->5000/tcp   stoic_darwin

Se ora accedi all'indirizzo localhost:5000 puoi vedere la pagina dell'applicazione in esecuzione, che appare esattamente come la pagina dell'applicazione in esecuzione nell'ambiente di produzione.

▍Assegnazione del tag e pubblicazione

Per utilizzare una delle immagini create su un server di produzione, è necessario avere la possibilità di caricare quest'immagine da Docker Hub. Questo significa che prima bisogna creare un repository su Docker Hub per il progetto. Dopo di che avremo a disposizione uno spazio in cui inviare l'immagine. L'immagine deve essere rinominata in modo che il suo nome inizi con il nostro nome utente su Docker Hub. Dopo di questo deve seguire il nome del repository. Alla fine del nome può esserci qualsiasi tag. Di seguito è mostrato un esempio di denominazione delle immagini secondo questo schema.

Ora possiamo costruire l'immagine assegnandole un nuovo nome e eseguire il comando docker push per inviarla nel repository Docker Hub.

docker build -t /: .
docker tag /: /:latest
docker push /:

# In pratica, questo può apparire, ad esempio, così:
docker build -t user/app:v1.0.0 .
docker tag user/app:v1.0.0 user/app:latest
docker push user/app:v1.0.0

Se tutto va come previsto, l'immagine sarà disponibile su Docker Hub e potrà essere facilmente caricata sul server o condivisa con altri sviluppatori.

Prossimi passi

Fino ad ora, abbiamo verificato che l'applicazione, in forma di contenitore Docker, funziona localmente. Abbiamo caricato il contenitore su Docker Hub. Questo significa che abbiamo già fatto significativi progressi verso l'obiettivo. Ora dobbiamo affrontare altre due questioni:

  • Configurazione dello strumento CI per testare e distribuire il codice.
  • Impostazione del server di produzione in modo che possa caricare e avviare il nostro codice.

Nel nostro caso, come soluzione CI/CD è utilizzato Travis CI. Come server — DigitalOcean.

Va notato che qui è possibile utilizzare anche un'altra combinazione di servizi. Ad esempio, invece di Travis CI, si possono utilizzare CircleCI o GitHub Actions. E invece di DigitalOcean — AWS o Linode.

Abbiamo deciso di lavorare con Travis CI, e in questo servizio ho già alcune impostazioni. Quindi ora descriverò brevemente come prepararlo per l'uso.

Travis CI

Travis CI è uno strumento per il testing e il deployment del codice. Non voglio entrare nei dettagli della configurazione di Travis CI, poiché ogni progetto è unico e ciò non sarebbe particolarmente utile. Tuttavia, posso spiegare le basi per aiutarvi a iniziare nel caso decidiate di utilizzare Travis CI. Qualunque cosa scegliate — Travis CI, CircleCI, Jenkins o altro — metodi di configurazione simili verranno applicati ovunque.

Per iniziare a lavorare con Travis CI, visitate il sito del progetto e create un account. Poi integrate Travis CI con il vostro account GitHub. Durante la configurazione dovrete specificare il repository con cui desiderate automatizzare il lavoro e fornire accesso a esso. (Utilizzo GitHub, ma sono certa che Travis CI possa integrarsi anche con BitBucket, GitLab e altri servizi simili).

Ogni volta che Travis CI inizia a lavorare, un server viene avviato ed esegue i comandi specificati nel file di configurazione, compreso il deployment delle relative branche del repository.

▍Ciclo di vita del compito

Il file di configurazione di Travis CI, chiamato .travis.yml e memorizzato nella directory principale del progetto, supporta il concetto di eventi del ciclo di vita di un’attività. Questi sono gli eventi, presentati nell'ordine in cui si verificano:

  • apt addons
  • cache components
  • before_install
  • install
  • before_script
  • script
  • before_cache
  • after_success o after_failure
  • before_deploy
  • deploy
  • after_deploy
  • after_script

▍Testing

Nel file di configurazione, andrò a impostare un server locale Travis CI. Come linguaggio ho scelto Node versione 12 e ho indicato al sistema di installare le dipendenze necessarie per utilizzare Docker.

Tutto ciò che è elencato in .travis.yml, verrà eseguito per tutte le pull request su tutti i rami del repository, a meno che non venga specificato diversamente. Questa è una funzionalità utile, poiché significa che possiamo testare tutto il codice che viene nel repository. Questo ci permette di sapere se il codice è pronto per essere scritto nel ramo master, e non romperà il processo di build del progetto. In questa configurazione globale, installo tutto localmente, avvio il server di sviluppo Webpack in background (questa è una caratteristica del mio flusso di lavoro) e faccio eseguire i test.

Se desideri che nel tuo repository vengano visualizzati badge con informazioni sulla copertura del codice nei test, qui puoi trovare una breve guida all'uso di Jest, Travis CI e Coveralls per raccogliere e visualizzare queste informazioni.

Quindi, ecco il contenuto del file .travis.yml:

# Установить язык
language: node_js

# Установить версию Node.js
node_js:
  - '12'

services:
  # Использовать командную строку Docker
  - docker

install:
  # Установить зависимости для тестов
  - npm ci

before_script:
  # Запустить сервер и клиент для тестов
  - npm run dev &

script:
  # Запустить тесты
  - npm run test

Qui terminano le azioni eseguite per tutti i rami del repository e per le pull request.

▍Distribuzione

Presumendo che tutti i test automatici siano stati eseguiti con successo, possiamo distribuire il codice sul server di produzione, il che non è obbligatorio. Poiché vogliamo farlo solo per il codice proveniente dal ramo master, diamo al sistema le istruzioni appropriate nelle impostazioni di distribuzione. Prima di provare a utilizzare nel tuo progetto il codice che esamineremo di seguito, vorrei avvisarti che è necessario avere uno script reale che venga chiamato per la distribuzione.

deploy:
  # Compila il contenitore Docker e invialo a Docker Hub
  provider: script
  script: bash deploy.sh
  on:
    branch: master

Lo script di distribuzione svolge due compiti:

  • Compilazione, tagging e invio dell'immagine a Docker Hub tramite lo strumento CI (in questo caso, Travis CI).
  • Caricamento dell'immagine sul server, arresto del vecchio contenitore e avvio di quello nuovo (in questo caso, il server è ospitato su DigitalOcean).

Per prima cosa, è necessario configurare un processo automatico per la creazione, il tagging e l'invio dell'immagine a Docker Hub. Tutto questo è molto simile a ciò che abbiamo già fatto manualmente, tranne per il fatto che abbiamo bisogno di una strategia per assegnare ai tag immagini unici e automatizzare l'accesso. Ho avuto alcune difficoltà con i dettagli dello script di distribuzione, come la strategia di tagging, l'accesso, la codifica delle chiavi SSH e l'instaurazione di una connessione SSH. Ma, per fortuna, il mio ragazzo è molto bravo con bash, così come con molte altre cose. Mi ha aiutato a scrivere questo script.

Quindi, la prima parte dello script è l'invio dell'immagine a Docker Hub. È abbastanza semplice. Lo schema di tagging che ho utilizzato prevede la combinazione dell'hash git e del tag git, se disponibile. Questo assicura la creazione di un tag unico e semplifica l'identificazione della build sulla quale si basa. DOCKER_USERNAME e DOCKER_PASSWORD — queste sono variabili d'ambiente personalizzate, che possono essere impostate tramite l'interfaccia di Travis CI. Travis CI gestirà automaticamente i dati sensibili in modo che non finiscano nelle mani sbagliate.

Ecco la prima parte dello script deploy.sh.

#!/bin/sh
set -e # Остановить скрипт при наличии ошибок

IMAGE="<username>/<repository>"                             # Образ Docker
GIT_VERSION=$(git describe --always --abbrev --tags --long) # Git-хэш и теги

# Сборка и тегирование образа
docker build -t ${IMAGE}:${GIT_VERSION} .
docker tag ${IMAGE}:${GIT_VERSION} ${IMAGE}:latest

# Вход в Docker Hub и выгрузка образа
echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USERNAME}" --password-stdin
docker push ${IMAGE}:${GIT_VERSION}

La configurazione della seconda parte dello script dipende completamente dal provider di hosting che utilizzi e da come è organizzata la connessione a esso. Nel mio caso, dato che utilizzo Digital Ocean, per connettermi al server utilizzo il comando doctl. Quando si lavora con AWS, si utilizzerà l'utility aws, e così via.

Impostare il funzionamento del server non è stato particolarmente difficile. Ho configurato un droplet basato su un'immagine di base. Va notato che il sistema da me scelto richiede un'installazione manuale singola di Docker e un avvio manuale singolo di Docker. Per installare Docker, ho utilizzato Ubuntu 18.04, quindi se utilizzate anche Ubuntu, potete semplicemente seguire questa semplice guida.

Non menziono qui i comandi specifici per il servizio, poiché questo aspetto può variare notevolmente in base ai casi. Fornirò solo un piano generale di azione da seguire dopo essersi connessi tramite SSH al server su cui verrà distribuito il progetto:

  • È necessario trovare il contenitore attualmente in esecuzione e fermarlo.
  • Successivamente, è necessario lanciare un nuovo contenitore in background.
  • Dovrai impostare la porta locale del server su 80 — questo ti permetterà di accedere al sito all'indirizzo del tipo example.com, senza specificare la porta, invece di usare un indirizzo come example.com:5000.
  • E infine, è necessario rimuovere tutti i vecchi container e immagini.

Ecco la continuazione dello script.

# Найти ID работающего контейнера
CONTAINER_ID=$(docker ps | grep takenote | cut -d" " -f1)

# Остановить старый контейнер, запустить новый, очистить систему
docker stop ${CONTAINER_ID}
docker run --restart unless-stopped -d -p 80:5000 ${IMAGE}:${GIT_VERSION}
docker system prune -a -f

Alcune cose a cui prestare attenzione

È possibile che, collegandoti al server via SSH da Travis CI, tu possa vedere un avviso che non permette di continuare l'installazione, poiché il sistema attenderà una risposta dall'utente.

L'autenticità dell'host '<hostname> (<IP address>)' non può essere stabilita.
La chiave RSA fingerprint è <key fingerprint>.
Vuoi davvero continuare a collegarti (sì/no)?

Ho scoperto che la chiave in formato stringa può essere codificata in base64 per essere conservata in una forma comoda e sicura. Durante l'installazione, puoi decodificare la chiave pubblica e scriverla in un file known_hosts per eliminare l'errore descritto sopra.

echo <public key> | base64 # restituisce <la chiave pubblica codificata in base64>

In pratica, questo comando può apparire così:

echo "123.45.67.89 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSU
GPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3
Pbv7kOdJ/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK/7XA
t3FaoJoAsncM1Q9x5+3V0Ww68/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw/Pb0rwert/En
mZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z/il8b+gw3r3+1nKatmIkjn2so1d01QraTlMqVSsbx
NrRFi9wrf+M7Q== you@example.com" | base64

Ecco come appare ciò che restituisce — una stringa in codifica base64:

MTIzLjQ1LjY3Ljg5IHNzaC1yc2EgQUFBQUIzTnphQzF5YzJFQUFBQUJJd0FBQVFFQWtsT1Vwa0RIcmZIWTE3U2JybVRJcE5MVEdLOVRqb20vQldEU1UKR1BsK25hZnpsSERUWVc3aGRJNHlaNWV3MThKSDRKVzlqYmhVRnJ2aVF6TTd4bEVMRVZmNGg5bEZYNVFWa2JQcHBTd2cwY2RhMwpQYnY3a09kSi9NVHlCbFdYRkNSK0hBbzNGWFJpdEJxeGlYMW5LaFhwSEFac01jaUxxOFY2UmpzTkFRd2RzZE1GdlNsVksvN1hBCnQzRmFvSm9Bc25jTTFROXg1KzNWMFd3NjgvZUlGbWIxenVVRmxqUUpLcHJyWDg4WHlwTkR2allOYnk2dncvUGIwcndlcnQvRW4KbVorQVc0T1pQblRQSTg5WlBtVk1MdWF5ckQyY0U4NlovaWw4YitndzNyMysxbkthdG1Ja2puMnNvMWQwMVFyYVRsTXFWU3NieApOclJGaTl3cmYrTTdRPT0geW91QGV4YW1wbGUuY29tCg==

Ecco il comando di cui si parlava sopra

install:
  - echo  | base64 -d >> $HOME/.ssh/known_hosts

Lo stesso approccio può essere utilizzato con la chiave privata durante la connessione, poiché potrebbe essere necessario avere una chiave privata per accedere al server. Quando si lavora con la chiave, è importante assicurarsi che venga conservata in modo sicuro nella variabile d'ambiente Travis CI e che non venga mai visualizzata.

Un'altra cosa da considerare è che potresti dover eseguire l'intero script di distribuzione come una sola riga, ad esempio utilizzando doctl. Questo potrebbe richiedere alcuni sforzi aggiuntivi.

doctl compute ssh  --ssh-command "tutte le comandi saranno qui && qui"

TLS/SSL e bilanciamento del carico

Dopo aver fatto tutto ciò di cui si è parlato sopra, l'ultimo problema che mi sono trovata di fronte è stato che il server non aveva SSL. Poiché utilizzo un server Node.js, per far funzionare il proxy inverso Nginx e Let’s Encrypt, è necessario impegnarsi bastante.

Non avevo davvero voglia di configurare tutto manualmente per SSL, così ho semplicemente creato un bilanciatore di carico e registrato i suoi dettagli nel DNS. Nel caso di DigitalOcean, ad esempio, creare un certificato autofirmato autoaggiornante sul bilanciatore di carico è una procedura semplice, gratuita e veloce. Questo approccio ha anche un vantaggio aggiuntivo: consente di configurare facilmente SSL su molti server che operano dietro al bilanciatore di carico. In questo modo, i server stessi non devono preoccuparsi di SSL, ma possono utilizzare normalmente la porta 80. Quindi, configurare SSL sul bilanciatore di carico è molto più semplice e comodo rispetto ad altri metodi di configurazione SSL.

Ora puoi chiudere sul server tutte le porte che accettano connessioni in ingresso, tranne la porta 80, utilizzata per la comunicazione con il bilanciatore di carico, e la porta 22 per SSH. Di conseguenza, ogni tentativo di accesso diretto al server su qualsiasi porta, tranne queste due, fallirà.

Risultati

Dopo aver fatto tutto ciò di cui ho parlato in questo materiale, non avevo più paura né della piattaforma Docker né dei concetti delle catene CI/CD automatizzate. Sono riuscita a configurare una catena di integrazione continua, durante la quale viene testato il codice prima che arrivi in produzione e viene effettuato il deploy automatico del codice sul server. Tutto ciò è ancora relativamente nuovo per me e sono sicura che ci siano modi per migliorare il mio flusso di lavoro automatizzato e renderlo più efficiente. Quindi, se avete idee al riguardo, fatemelo sapere. me saperlo. Spero che questo articolo vi sia stato utile. Spero che, leggendolo, abbiate appreso tanto quanto ho appreso io mentre mi occupavo di tutto ciò di cui ho parlato.

P.S. Nel nostro marketplace è disponibile un'immagine Docker, che può essere installata con un clic. Potete controllare il funzionamento dei container su VPS. A tutti i nuovi clienti sono offerti 3 giorni di prova gratuita.

Gentili lettori! Utilizzate tecnologie CI/CD nei vostri progetti?

Creazione di una pipeline CI/CD e automazione del lavoro con Docker

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster