Ruby: Geavanceerde toepassingen

Verder gaan met uw Ruby-deployments

👋 Welkom bij de Stackhero-documentatie!

Stackhero biedt een kant-en-klare Ruby cloud oplossing die tal van voordelen biedt, waaronder:

  • Implementeer uw applicatie in seconden met een eenvoudige git push.
  • Gebruik uw eigen domeinnaam en profiteer van de automatische configuratie van HTTPS-certificaten voor verbeterde beveiliging.
  • Geniet van gemoedsrust met automatische back-ups, updates met één klik, en eenvoudige, transparante en voorspelbare prijzen.
  • Krijg optimale prestaties en robuuste beveiliging dankzij een privé en dedicated VM.

Bespaar tijd en vereenvoudig uw leven: het kost slechts 5 minuten om de Ruby cloud hosting oplossing van Stackhero te proberen!

Tot nu toe hebben we onze Ruby-applicatie gedeployed door de main branch te pushen met:

git push stackhero main

Als u een andere branch wilt deployen, kunt u deze opdracht gebruiken. Vervang <BRANCH> door de naam van de branch die u wilt deployen:

git push stackhero <BRANCH>:main

Bijvoorbeeld, om een branch genaamd production te deployen, voert u uit:

git push stackhero production:main

In sommige gevallen wilt u misschien een tag in plaats van een branch deployen. Voer hiervoor de volgende opdracht uit. Vervang <TAG> door de tag die u wilt deployen:

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

Bijvoorbeeld, om de tag v1.0.0 te deployen, voert u uit:

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

De ^{} syntax wordt gebruikt om te verwijzen naar de commit waar de tag naar wijst.

Naast branches of tags kunt u een specifieke commit deployen. Vervang <COMMIT_HASH> in de onderstaande opdracht door de hash van de gewenste commit:

git push -f stackhero <COMMIT_HASH>:main

Bijvoorbeeld, om een commit met de hash abcde te deployen, voert u uit:

git push -f stackhero abcde:main

Als uw productie-deployment niet werkt zoals verwacht, kunt u teruggaan door een oudere commit te deployen. Gebruik eerst de onderstaande opdracht om uw commitgeschiedenis te bekijken:

git log

Deze opdracht toont de datum, commit-hash en beschrijving voor elke commit in uw repository. Bijvoorbeeld, u zou een uitvoer kunnen zien zoals:

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

Als de commit met de boodschap "Break the code" (hash cccc...) in productie draait, en u besluit terug te gaan naar de vorige commit "Update the code" (hash bbbb...), voert u uit:

git push -f stackhero bbbb622301772072c3d82f3cc0d91e29e6e84901:main

Om te voorkomen dat u defecte code deployt en de stabiliteit van uw productie te verhogen, wordt sterk aanbevolen om een "staging" omgeving te hebben.

Gelegen tussen "development" en "production" omgevingen, biedt de "staging" omgeving een bijna exacte replica van de productieomgeving. Dit stelt u in staat om uw code te testen en de kwaliteit ervan te waarborgen voordat u deze naar productie deployt.

Door een staging-omgeving te gebruiken, kunt u meer vertrouwen hebben in de functionaliteit en prestaties van uw code, wat zorgt voor een betrouwbaardere en robuustere productie-deployment.

Dit type omgeving zal later in de documentatie worden besproken.

Een staging omgeving is een best practice om te gebruiken naast uw development en production omgevingen. Het repliceert uw productieomgeving zodat u updates en wijzigingen kunt testen voordat ze live gaan.

Een staging-omgeving moet de productieomgeving nauwkeurig weerspiegelen.

Zorg er echter voor dat de staging-omgeving een kloon van de productiedatabase gebruikt in plaats van de daadwerkelijke productiedatabase.

Als uw Ruby-service is gekoppeld aan een database of andere services, recreëer deze dan in de nieuwe <Project> - Staging stack.

Om een staging-omgeving op Stackhero op te zetten, volgt u deze stappen:

  1. Hernoem op het Stackhero-dashboard uw bestaande stack van <Project> naar <Project> - Production. Bijvoorbeeld, als uw project Chat Bot heet, hernoemt u de stack naar Chat Bot - Production.
  2. Maak een nieuwe stack genaamd <Project> - Staging. Met het vorige voorbeeld zou dit Chat Bot - Staging zijn.
  3. Start een Ruby-service binnen de staging-stack.
  4. Haal de waarde van de git remote opdracht op en volg de instructies in de sectie Deployen naar staging-omgeving.

Door deze stappen te volgen, krijgt u een correct geconfigureerde staging-omgeving om updates te testen en te verifiëren voordat ze de productie bereiken.

Het beheren van gescheiden omgevingen zoals staging en production wordt sterk aanbevolen. Zoals uitgelegd in Een staging-omgeving opzetten, kunt u naar elke omgeving deployen met verschillende Git-remotes.

Begin met het hernoemen van de huidige remote repository. Bijvoorbeeld, hernoem de remote "stackhero" naar "stackhero-production" met deze opdracht:

git remote rename stackhero stackhero-production

Maak vervolgens een nieuwe Ruby-service voor de staging-omgeving. Gebruik de verstrekte "git remote add" opdracht en wijzig deze als volgt (vervang <XXXXXX> door het domein van uw service):

  • Originele opdracht:

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

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

U kunt nu naar staging deployen met:

git push stackhero-staging main

Of naar productie deployen met:

git push stackhero-production main

Om het deploymentproces verder te stroomlijnen, overweeg het gebruik van de verbeterde Makefile-versie.

Met deze verbeterde Makefile kan het deployen naar productie of staging eenvoudig worden gedaan met make deploy-production of make deploy-staging.

Hieronder staat een verbeterde Makefile die meerdere regels voor veelvoorkomende taken ondersteunt:

  • make dev (of gewoon make): Start de applicatie in ontwikkelingsmodus.
  • make deploy: Deploy de applicatie naar de remote genaamd stackhero (ideaal wanneer u een enkele Stackhero-instantie heeft).
  • make deploy-production: Deploy de applicatie naar de remote genaamd stackhero-production.
  • make deploy-staging: Deploy de applicatie naar de remote genaamd stackhero-staging.

Deze Makefile is ontworpen om gevallen te behandelen waarin code al is gedeployed, waardoor de "Everything up-to-date" fout wordt vermeden.

Kopieer en plak de volgende inhoud in uw nieuwe Makefile:

# Standaardregel om uit te voeren bij het aanroepen van "make" zonder argument
.DEFAULT_GOAL := dev


# Stackhero voor Ruby zal de "run" regel op uw instantie uitvoeren.
# Dit is de opdracht om uit te voeren op zowel productie- als staging-platforms.
run:
  rake assets:precompile
  rake db:migrate RAILS_ENV=production
  RAILS_ENV=production bundle exec puma -C config/puma.rb


# Opdracht om uit te voeren in de ontwikkelomgeving
dev:
  RAILS_ENV=development rails server -b 0.0.0.0


# Regel "deploy" deployt naar de instantie "stackhero".
# Geschikt wanneer u slechts één instantie heeft.
deploy:
  @$(MAKE) -s deploy-script DEPLOY_REMOTE=stackhero DEPLOY_BRANCH=main


# Regel "deploy-*" deployt naar de instantie "stackhero-*".
# Bijvoorbeeld, voer "make deploy-production" uit om naar "stackhero-production" te deployen,
# of "make deploy-staging" om naar "stackhero-staging" te deployen.
deploy-%:
  @$(MAKE) -s deploy-script DEPLOY_REMOTE=stackhero-$* DEPLOY_BRANCH=main


# Interne deploymentregel. Niet wijzigen.
deploy-script:
  @echo "Deployen van branch \"${DEPLOY_BRANCH}\" naar \"${DEPLOY_REMOTE}\"..."
  @echo

  @if [ -n "$$(git status --porcelain)" ]; then \
    echo "Kan niet deployen omdat er niet-gecommitte wijzigingen zijn:"; \
    echo "\e[0m"; \
    git status -s; \
    echo ""; \
    echo "\e[0;31m"; \
    echo "U kunt deze opdracht gebruiken om de wijzigingen te committen:"; \
    echo "git add -A . && git commit -m \"Uw bericht\""; \
    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 "Niets nieuws om te deployen... Forceer deploy (dit zal een nieuwe commit maken)? (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 "Niets om te deployen!"; \
      exit 1; \
      ;; \
    esac \
  fi

  git push ${DEPLOY_REMOTE} ${DEPLOY_BRANCH}

Op een gegeven moment moet u geheimen beheren zoals tokens of wachtwoorden voor databases en externe services. Het is essentieel om deze geheimen veilig op te slaan. Vermijd het direct in uw repository of code opnemen van geheimen, omdat dit een ernstig beveiligingsrisico vormt.

Omgevingsvariabelen bieden twee belangrijke voordelen:

  1. Uw geheimen worden niet in uw Git-repository opgeslagen, waardoor het risico wordt verminderd als iemand toegang krijgt tot uw broncode.
  2. U kunt verschillende referenties gebruiken voor verschillende omgevingen. Bijvoorbeeld, verbinding maken met uw productiedatabase in productie terwijl u een ontwikkelingsdatabase gebruikt tijdens ontwikkeling.

Voor ontwikkeling maakt u een .env bestand in de root van uw project. Dit bestand wordt uitgesloten van Git zodat het nooit wordt gecommit. Gebruik de dotenv gem om het .env bestand automatisch te laden.

Voeg eerst de dotenv-rails gem toe aan uw Gemfile:

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

Installeer vervolgens de gem:

bundle install

Maak vervolgens een .env bestand in de root van uw project en voeg uw variabelen toe:

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

Zorg er ten slotte voor dat het .env bestand door Git wordt genegeerd:

echo '.env*' >> .gitignore

Voor staging en productie is het .env bestand niet veilig of praktisch omdat het niet in een Git-repository kan worden opgeslagen. In plaats daarvan biedt Stackhero een veilige oplossing voor het beheren van omgevingsvariabelen direct in uw Ruby-serviceconfiguratie.

U kunt deze variabelen instellen via het Stackhero-dashboard door uw Ruby-service te selecteren en op de knop "Configure" te klikken.

In Ruby kunt u eenvoudig toegang krijgen tot omgevingsvariabelen met ENV. Bijvoorbeeld, om DATABASE_PASSWORD op te halen, gebruikt u:

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

Hier is een voorbeeld van hoe u verbinding maakt met een RabbitMQ-server met behulp van omgevingsvariabelen:

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

Op het ontwikkelingsplatform kan uw .env bestand bevatten:

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

Voor productie en staging definieert u uw omgevingsvariabelen in het Stackhero-dashboard onder de Ruby-serviceconfiguratie zoals hieronder weergegeven:

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

Ruby-applicaties gebruiken vaak het HTTP-protocol op poorten 80 (HTTP) en 443 (HTTPS). Als uw applicatie extra poorten of andere protocollen (TCP of UDP) nodig heeft, configureert u de "Ports Redirections" instellingen in uw Ruby-service via het Stackhero-dashboard.

U moet de invoerpoort (openbaar toegankelijk), de bestemmingspoort (open binnen uw Ruby-service) en het protocol (TCP of UDP) specificeren.

Voor het opslaan van bestanden zoals gebruikersfoto's of documenten wordt sterk aanbevolen om een objectopslagoplossing te gebruiken. Objectopslag stelt u in staat om bestanden te delen tussen meerdere services en instanties en ontkoppelt de opslaglaag van uw code. Dit wordt beschouwd als een best practice.

We raden MinIO aan als een eenvoudige, snelle en krachtige oplossing die compatibel is met het Amazon S3-protocol.

Als u kiest voor lokale bestandsopslag, kunt u de persistente opslag gebruiken die bij uw Ruby-instantie wordt geleverd. Deze lokale opslag is beschikbaar onder de directory /persistent/storage/.

Lokale bestandsopslag wordt echter over het algemeen niet aanbevolen, omdat het mogelijk niet de beste praktijk is voor langdurige schaalbaarheid en betrouwbaarheid.

WAARSCHUWING: Sla nooit gegevens op buiten de map /persistent/storage/!

Gegevens opslaan op een andere locatie dan de persistente opslagmap kan leiden tot gegevensverlies wanneer uw instantie opnieuw wordt opgestart, bijgewerkt of wanneer u nieuwe code pusht.

Als u macOS gebruikt, vindt u het misschien ongemakkelijk om elke keer dat u uw code pusht uw SSH privé-sleutelwachtwoord in te typen. Hoewel beveiliging essentieel is, kunt u het gemak verbeteren door uw wachtwoord veilig op te slaan in de Apple Keychain.

Het kan verleidelijk zijn om het wachtwoord van uw SSH privé-sleutel te verwijderen, maar dit is niet aan te raden.

In plaats daarvan slaat u uw sleutelwaachtwoord op in de Keychain met de volgende opdracht voor een sleutel genaamd id_ed25519:

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

Na het uitvoeren van deze opdracht zou u niet meer om uw sleutelwaachtwoord gevraagd moeten worden. Als u een RSA-sleutel gebruikt, vervangt u id_ed25519 door id_rsa zoals hieronder weergegeven:

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