Ruby: Utilizzi avanzati

Approfondire i tuoi deployment Ruby

👋 Benvenuti nella documentazione di Stackhero!

Stackhero offre una soluzione Ruby cloud pronta all'uso che fornisce numerosi vantaggi, tra cui:

  • Distribuisci la tua applicazione in pochi secondi con un semplice git push.
  • Usa il tuo nome di dominio e beneficia della configurazione automatica dei certificati HTTPS per una sicurezza potenziata.
  • Goditi la tranquillità con backup automatici, aggiornamenti con un clic, e una tariffazione semplice, trasparente e prevedibile.
  • Ottieni prestazioni ottimali e una sicurezza robusta grazie a una VM privata e dedicata.

Risparmia tempo e semplificati la vita: bastano solo 5 minuti per provare la soluzione Ruby cloud hosting di Stackhero!

Fino ad ora, abbiamo distribuito la nostra applicazione Ruby inviando il branch main utilizzando:

git push stackhero main

Se desideri distribuire un altro branch, puoi usare questo comando. Sostituisci <BRANCH> con il nome del branch che vuoi distribuire:

git push stackhero <BRANCH>:main

Ad esempio, per distribuire un branch chiamato production, esegui:

git push stackhero production:main

In alcuni casi potresti voler distribuire un tag piuttosto che un branch. Per farlo, esegui il seguente comando. Sostituisci <TAG> con il tag che vuoi distribuire:

git push stackhero '<TAG>^{}:main'

Ad esempio, per distribuire il tag v1.0.0, esegui:

git push stackhero 'v1.0.0^{}:main'

La sintassi ^{} è usata per riferirsi al commit a cui il tag punta.

Oltre ai branch o ai tag, puoi distribuire un commit specifico. Sostituisci <COMMIT_HASH> nel comando sottostante con l'hash del commit desiderato:

git push -f stackhero <COMMIT_HASH>:main

Ad esempio, per distribuire un commit con l'hash abcde, esegui:

git push -f stackhero abcde:main

Se il tuo deployment in produzione non funziona come previsto, puoi tornare indietro distribuendo un commit precedente. Usa prima il comando sottostante per visualizzare la cronologia dei commit:

git log

Questo comando mostra la data, l'hash del commit e la descrizione per ogni commit nel tuo repository. Ad esempio, potresti vedere un output come:

commit cccc8b3ebdccb9abc1926ef49ee589dae5c5fe06 (HEAD -> main, stackhero/main)
Author: Developer
Date:   Fri Apr 28 09:36:18 +0000

    Break the code

commit bbbb622301772072c3d82f3cc0d91e29e6e84901
Author: Developer
Date:   Wed Apr 26 12:49:28 +0000

    Update the code

commit aaaa1d8b06535b413e0df8298ccf52339dfef3ff
Author: Developer
Date:   Wed Apr 26 12:44:50 +0000

    Improve the code

Se il commit con il messaggio "Break the code" (hash cccc...) è in esecuzione in produzione, e decidi di tornare al commit precedente "Update the code" (hash bbbb...), esegui:

git push -f stackhero bbbb622301772072c3d82f3cc0d91e29e6e84901:main

Per evitare di distribuire codice difettoso e aumentare la stabilità della tua produzione, è altamente raccomandato avere un ambiente "staging".

Situato tra gli ambienti "development" e "production", l'ambiente "staging" fornisce una replica quasi esatta dell'ambiente di produzione. Questo ti permette di testare il tuo codice e assicurarne la qualità prima di distribuirlo in produzione.

Utilizzando un ambiente di staging, puoi essere più sicuro della funzionalità e delle prestazioni del tuo codice, garantendo un deployment in produzione più affidabile e robusto.

Questo tipo di ambiente sarà discusso più avanti nella documentazione.

Un ambiente staging è una buona pratica da utilizzare insieme ai tuoi ambienti development e production. Replica il tuo ambiente di produzione in modo da poter testare aggiornamenti e modifiche prima che vadano online.

Un ambiente di staging deve rispecchiare da vicino l'ambiente di produzione.

Tuttavia, assicurati che l'ambiente di staging utilizzi un clone del database di produzione piuttosto che il database di produzione stesso.

Se il tuo servizio Ruby è collegato a un database o ad altri servizi, ricreali nel nuovo stack <Project> - Staging.

Per configurare un ambiente di staging su Stackhero, segui questi passaggi:

  1. Sul dashboard di Stackhero, rinomina il tuo stack esistente da <Project> a <Project> - Production. Ad esempio, se il tuo progetto si chiama Chat Bot, rinomina lo stack in Chat Bot - Production.
  2. Crea un nuovo stack chiamato <Project> - Staging. Usando l'esempio precedente, questo sarebbe Chat Bot - Staging.
  3. Avvia un servizio Ruby all'interno dello stack di staging.
  4. Recupera il valore del comando git remote e segui le istruzioni nella sezione Distribuire nell'ambiente di staging.

Seguendo questi passaggi, otterrai un ambiente di staging correttamente configurato per testare e verificare gli aggiornamenti prima che raggiungano la produzione.

Gestire ambienti separati come staging e production è altamente raccomandato. Come spiegato in Configurare un ambiente di staging, puoi distribuire in ogni ambiente con diversi remoti Git.

Inizia rinominando il repository remoto attuale. Ad esempio, rinomina il remoto "stackhero" in "stackhero-production" con questo comando:

git remote rename stackhero stackhero-production

Successivamente, crea un nuovo servizio Ruby per l'ambiente di staging. Usa il comando "git remote add" fornito e modificalo come segue (sostituisci <XXXXXX> con il dominio del tuo servizio):

  • Comando originale:

    git remote add stackhero ssh://stackhero@<XXXXXX>.stackhero-network.com:222/project.git
    
  • Comando modificato:

    git remote add stackhero-staging ssh://stackhero@<XXXXXX>.stackhero-network.com:222/project.git
    

Ora puoi distribuire su staging usando:

git push stackhero-staging main

Oppure distribuire in produzione con:

git push stackhero-production main

Per semplificare ulteriormente il processo di deployment, considera l'uso della versione migliorata del Makefile.

Con questo Makefile migliorato, il deployment in produzione o in staging può essere effettuato facilmente usando make deploy-production o make deploy-staging.

Di seguito è riportato un Makefile migliorato che supporta più regole per attività comuni:

  • make dev (o semplicemente make): Avvia l'applicazione in modalità sviluppo.
  • make deploy: Distribuisce l'applicazione sul remoto chiamato stackhero (ideale quando hai una sola istanza Stackhero).
  • make deploy-production: Distribuisce l'applicazione sul remoto chiamato stackhero-production.
  • make deploy-staging: Distribuisce l'applicazione sul remoto chiamato stackhero-staging.

Questo Makefile è progettato per gestire i casi in cui il codice è già stato distribuito, evitando l'errore "Everything up-to-date".

Copia e incolla il seguente contenuto nel tuo nuovo Makefile:

# Regola da eseguire di default quando si invoca "make" senza argomento
.DEFAULT_GOAL := dev


# Stackhero per Ruby eseguirà la regola "run" sulla tua istanza.
# Questo è il comando da eseguire sulle piattaforme di produzione e staging.
run:
  rake assets:precompile
  rake db:migrate RAILS_ENV=production
  RAILS_ENV=production bundle exec puma -C config/puma.rb


# Comando da eseguire nell'ambiente di sviluppo
dev:
  RAILS_ENV=development rails server -b 0.0.0.0


# La regola "deploy" distribuisce sull'istanza "stackhero".
# Adatto quando hai solo un'istanza.
deploy:
  @$(MAKE) -s deploy-script DEPLOY_REMOTE=stackhero DEPLOY_BRANCH=main


# La regola "deploy-*" distribuisce sull'istanza "stackhero-*".
# Ad esempio, esegui "make deploy-production" per distribuire su "stackhero-production",
# o "make deploy-staging" per distribuire su "stackhero-staging".
deploy-%:
  @$(MAKE) -s deploy-script DEPLOY_REMOTE=stackhero-$* DEPLOY_BRANCH=main


# Regola di deployment interna. Non modificare.
deploy-script:
  @echo "Distribuzione del branch \"${DEPLOY_BRANCH}\" su \"${DEPLOY_REMOTE}\"..."
  @echo

  @if [ -n "$$(git status --porcelain)" ]; then \
    echo "Impossibile distribuire perché ci sono modifiche non commesse:"; \
    echo "\e[0m"; \
    git status -s; \
    echo ""; \
    echo "\e[0;31m"; \
    echo "Puoi usare questo comando per commettere le modifiche:"; \
    echo "git add -A . && git commit -m \"Il tuo messaggio\""; \
    echo "\e[0m"; \
    exit 1; \
  fi

  @git push --dry-run ${DEPLOY_REMOTE} ${DEPLOY_BRANCH} 2>&1 | grep -q -F "Everything up-to-date"; \
  EXIT_CODE=$$?; \
  if [ $$EXIT_CODE -eq 0 ]; then \
    echo -n "Niente di nuovo da distribuire... Forzare la distribuzione (questo creerà un nuovo commit)? (y/N) "; \
    read answer && \
    case $$answer in \
      y|Y|yes|YES) \
      git commit --allow-empty -m "Force update for deploy purpose to \"${DEPLOY_REMOTE}\"" ; \
      ;; \
      *) \
      echo "Niente da distribuire!"; \
      exit 1; \
      ;; \
    esac \
  fi

  git push ${DEPLOY_REMOTE} ${DEPLOY_BRANCH}

A un certo punto, dovrai gestire segreti come token o password per database e servizi di terze parti. È essenziale memorizzare questi segreti in modo sicuro. Evita di incorporare direttamente i segreti nel tuo repository o codice perché questo rappresenta un serio rischio per la sicurezza.

Le variabili d'ambiente offrono due vantaggi significativi:

  1. I tuoi segreti non saranno memorizzati nel tuo repository Git, riducendo il rischio se qualcuno accede al tuo codice sorgente.
  2. Puoi usare credenziali diverse per ambienti diversi. Ad esempio, connettersi al tuo database di produzione in produzione mentre usi un database di sviluppo durante lo sviluppo.

Per lo sviluppo, crea un file .env nella radice del tuo progetto. Questo file sarà escluso da Git in modo che non venga mai commesso. Usa la gem dotenv per caricare automaticamente il file .env.

Per prima cosa, aggiungi la gem dotenv-rails al tuo Gemfile:

# Gemfile
gem 'dotenv-rails', groups: [:development, :test]

Poi installa la gem:

bundle install

Successivamente, crea un file .env alla radice del tuo progetto e aggiungi le tue variabili:

RAILS_ENV="development"
DATABASE_PASSWORD="secretPassword"
THIRD_API_PRIVATE_KEY="secretKey"
# ...

Infine, assicurati che il file .env sia ignorato da Git:

echo '.env*' >> .gitignore

Per staging e produzione, il file .env non è sicuro né pratico perché non può essere memorizzato in un repository Git. Invece, Stackhero fornisce una soluzione sicura per gestire le variabili d'ambiente direttamente nella configurazione del tuo servizio Ruby.

Puoi impostare queste variabili tramite il dashboard di Stackhero selezionando il tuo servizio Ruby e cliccando sul pulsante "Configura".

In Ruby, puoi facilmente accedere alle variabili d'ambiente usando ENV. Ad esempio, per recuperare DATABASE_PASSWORD, usa:

ENV['DATABASE_PASSWORD'] # => 'secretPassword'

Ecco un esempio di come connettersi a un server RabbitMQ usando variabili d'ambiente:

require 'bunny'

class RabbitMQClient
  def initialize
    @connection = Bunny.new(hostname: ENV['RABBITMQ_HOST'],
                            username: ENV['RABBITMQ_USERNAME'],
                            password: ENV['RABBITMQ_PASSWORD'])
    @connection.start
  end

  def publish(queue_name, message)
    channel = @connection.create_channel
    queue = channel.queue(queue_name)
    channel.default_exchange.publish(message, routing_key: queue.name)
  end

  def close
    @connection.close
  end
end

Sulla piattaforma di sviluppo, il tuo file .env potrebbe includere:

RABBITMQ_HOST='127.0.0.1'
RABBITMQ_USERNAME='developmentUser'
RABBITMQ_PASSWORD='developmentPassword'

Per produzione e staging, definisci le tue variabili d'ambiente nel dashboard di Stackhero sotto la configurazione del servizio Ruby come mostrato di seguito:

RABBITMQ_HOST='<XXXXXX>.stackhero-network.com'
RABBITMQ_USERNAME='production'
RABBITMQ_PASSWORD='secretProductionPassword'

Le applicazioni Ruby utilizzano spesso il protocollo HTTP sulle porte 80 (HTTP) e 443 (HTTPS). Se la tua applicazione necessita di porte aggiuntive o protocolli diversi (TCP o UDP), configura le impostazioni "Ports Redirections" nel tuo servizio Ruby tramite il dashboard di Stackhero.

Dovrai specificare la porta di ingresso (aperta pubblicamente), la porta di destinazione (aperta all'interno del tuo servizio Ruby) e il protocollo (TCP o UDP).

Per archiviare file come foto degli utenti o documenti, è altamente raccomandato utilizzare una soluzione di object storage. L'object storage ti permette di condividere file tra più servizi e istanze e disaccoppia il livello di archiviazione dal tuo codice. Questo è considerato una buona pratica.

Raccomandiamo MinIO come soluzione semplice, veloce e potente compatibile con il protocollo Amazon S3.

Se scegli l'archiviazione file locale, puoi utilizzare l'archiviazione persistente fornita con la tua istanza Ruby. Questa archiviazione locale è disponibile sotto la directory /persistent/storage/.

Tuttavia, l'archiviazione file locale non è generalmente raccomandata poiché potrebbe non essere la migliore pratica per la scalabilità e l'affidabilità a lungo termine.

ATTENZIONE: Non memorizzare mai dati al di fuori della cartella /persistent/storage/!

Memorizzare dati in qualsiasi posizione diversa dalla cartella di archiviazione persistente può comportare la perdita di dati quando la tua istanza viene riavviata, aggiornata o quando invii nuovo codice.

Se stai usando macOS, potresti trovare scomodo digitare la password della tua chiave privata SSH ogni volta che invii il tuo codice. Sebbene la sicurezza sia essenziale, puoi migliorare la comodità memorizzando in modo sicuro la tua password nel Portachiavi di Apple.

Può essere allettante rimuovere la password dalla tua chiave privata SSH, ma questo non è consigliabile.

Invece, memorizza la password della tua chiave nel Portachiavi usando il seguente comando per una chiave chiamata id_ed25519:

ssh-add --apple-use-keychain ~/.ssh/id_ed25519

Dopo aver eseguito questo comando, non dovresti più essere invitato a inserire la password della tua chiave. Se usi una chiave RSA, sostituisci id_ed25519 con id_rsa come mostrato di seguito:

ssh-add --apple-use-keychain ~/.ssh/id_rsa