Do you want to pick up from where you left of?
Take me there

Distillery (Βασικά)

Η Distillery είναι ένας διαχειριστής εκδόσεων γραμμένος σε καθαρή Elixir. Μας επιτρέπει να δημιουργούμε εκδόσεις που μπορούν να γίνουν deploy κάπου αλλού με λίγη ή καθόλου παραμετροποίηση.

Τι είναι μια έκδοση

Μια έκδοση είναι ένα πακέτο που περιλαμβάνει τον μεταγλωττισμένο κώδικα Erlang/Elixir (για παράδειγμα BEAM bytecode). Επίσης παρέχει όσα script χρειάζονται για να εκκινήσει η εφαρμογή μας.

Όταν θα έχετε γράψει μια ή παραπάνω εφαρμογές, μπορεί να θέλετε να δημιουργήσετε ένα πλήρες σύστημα με αυτές τις εφαρμογές και ένα υποσύνολο από τις εφαρμογές Erlang/OTP. Αυτό ονομάζεται μια έκδοση. - Τεκμηρίωση Erlang

Οι εκδόσεις καθιστούν δυνατή την απλοποιημένη deployment: είναι αυτόνομες και παρέχουν τα πάντα που απαιτούνται για να εκκινήσει η έκδοση - είναι εύκολα διαχειριζόμενες από το παρεχόμενο script τερματικού για να ανοίξουμε μια απομακρυσμένη κονσόλα, να εκκινήσουμε / σταματήσουμε / επανεκιννήσουμε την έκδοση, να την εκκινήσουμε στο παρασκήνιο, να στείλουμε απομακρυσμένες εντολές και περισσότερα. Επιπρόσθετα, είναι αρχειοθετημένα αντικείμενα, που σημαίνει ότι μπορείτε να επαναφέρετε μια παλαιότερη έκδοση από το tarball της σε οποιοδήποτε σημείο στο μέλλον (εκτός από περιπτώσεις ασυμβατότητας με το υποκείμενο λειτουργικό σύστημα ή βιβλιοθήκες συστήματος). Η χρήση των εκδόσεων είναι επίσης προαπαιτούμενο της λειτουργίας των γρήγορων αναβαθμίσεων και υποβαθμίσεων, ένα από τα πιο ισχυρά χαρακτηριστικά του Erlang VM. - Τεκμηρίωση Distillery

Μια έκδοση θα περιλαμβάνει τα ακόλουθα:

Ξεκινώντας / Εγκατάσταση

Για να προσθέσετε τη Distillery στο project σας, προσθέστε το σαν εξάρτηση στο αρχείο mix.exs σας. Σημείωση - αν δουλεύετε σε μια εφαρμογή ομπρέλας αυτό θα πρέπει να είναι στο mix.exs αρχείο στο γονικό φάκελο του project σας.

defp deps do
  [{:distillery, "~> 2.0"}]
end

Τότε στο τερματικό σας τρέξτε:

mix deps.get
mix compile

Χτίζοντας την έκδοσή σας

Στο τερματικό σας, τρέξτε:

mix release.init

Αυτή η εντολή παράγει ένα φάκελο rel με μερικά αρχεία παραμετροποίησης μέσα του.

Για να παράξετε μια έκδοση στο τερματικό σας τρέξτε την mix release.

Μόλις η έκδοση χτιστεί θα πρέπει να δείτε μερικές οδηγίες στο τερματικό σας:

==> Assembling release..
==> Building release book_app:0.1.0 using environment dev
==> You have set dev_mode to true, skipping archival phase
Release successfully built!
To start the release you have built, you can use one of the following tasks:

    # start a shell, like 'iex -S mix'
    > _build/dev/rel/book_app/bin/book_app console

    # start in the foreground, like 'mix run --no-halt'
    > _build/dev/rel/book_app/bin/book_app foreground

    # start in the background, must be stopped with the 'stop' command
    > _build/dev/rel/book_app/bin/book_app start

If you started a release elsewhere, and wish to connect to it:

    # connects a local shell to the running node
    > _build/dev/rel/book_app/bin/book_app remote_console

    # connects directly to the running node's console
    > _build/dev/rel/book_app/bin/book_app attach

For a complete listing of commands and their use:

    > _build/dev/rel/book_app/bin/book_app help

Για να τρέξετε την εφαρμογή γράψτε το παρακάτω στο τερματικό σας:

_build/dev/rel/MYAPP/bin/MYAPP foreground

Στη δική σας περίπτωση αντικαταστήστε τη λέξη MYAPP με το όνομα του project σας. Τώρα τρέχουμε τη μεταγλωττισμένη έκδοση της εφαρμογής μας!

Χρησιμοποιώντας τη Distillery με το Phoenix

Αν χρησιμοποιείτε τη distillery με το Phoenix υπάρχουν μερικά έξτρα βήματα που πρέπει να ακολουθήσετε ώστε να λειτουργήσει.

Αρχικά, πρέπει να επεξεργαστούμε το αρχείο config/prod.exs.

Αλλάξτε την παρακάτω γραμμή από αυτό:

config :book_app, BookAppWeb.Endpoint,
  load_from_system_env: true,
  url: [host: "example.com", port: 80],
  cache_static_manifest: "priv/static/cache_manifest.json"

σε αυτό:

config :book_app, BookAppWeb.Endpoint,
  http: [port: {:system, "PORT"}],
  url: [host: "localhost", port: {:system, "PORT"}],
  cache_static_manifest: "priv/static/cache_manifest.json",
  server: true,
  root: ".",
  version: Application.spec(:book_app, :vsn)

Κάναμε μερικά πράγματα εδώ:

Αν εκτελέσετε την παραπάνω εντολή, θα πρέπει να παρατηρήσετε ότι η εφαρμογή σας κράσαρε επειδή είναι αδύνατο να συνδεθεί στη βάση δεδομένων, από τη στιγμή που δεν υπάρχει βάση δεδομένων ακόμα. Αυτό μπορεί να λυθεί τρέχοντας μια εντολή mix του Ecto. Στο τερματικό σας γράψτε τα παρακάτω:

MIX_ENV=prod mix ecto.create

Αυτή η εντολή θα δημιουργήσει τη βάση δεδομένων για εσάς. Προσπαθήστε να ξανά τρέξετε την εφαρμογή σας και θα πρέπει να εκκινήσει επιτυχημένα. Εν τούτοις, θα παρατηρήσετε ότι οι μετατροπές στη βάση δεδομένων σας δεν έχουν τρέξει. Συνήθως, στο περιβάλλον ανάπτυξης τις τρέχουμε με τη χρήση της mix ecto.migrate. Για την έκδοση, θα πρέπει να τη ρυθμίσουμε ώστε να τρέχει τις μετατροπές μόνη της.

Τρέχοντας Μετατροπές στην Παραγωγή

Η Distillery μας παρέχει τη δυνατότητα να εκτελέσουμε κώδικα σε διαφορετικά σημεία του κύκλου λειτουργίας μιας έκδοσης. Αυτά τα σημεία είναι γνωστά σαν boot-hooks. Τα hooks που παρέχονται από την Distillery περιλαμβάνουν

Για τους δικούς μας σκοπούς, θα χρησιμοποιήσουμε την post_start hook για να τρέξουμε τις μετατροπές της εφαρμογής μας στην παραγωγή. Ας πάμε πρώτα να δημιουργήσουμε μια νέα εργασία που θα ονομάσουμε migrate. Μια εργασία έκδοσης είναι μια συνάρτηση ενότητας που θα καλέσουμε από το τερματικό μας η οποια περιαλμβάνει κώδικα ο οποίος είναι ξεχωριστός από τα εσωτερικά της ίδιας μας της εφαρμογής. Είναι χρήσιμο για τις εργασίες ότι η εφαρμογή η ίδια δεν θα χρειάζεται να τρέχει.

defmodule BookAppWeb.ReleaseTasks do
  def migrate do
    {:ok, _} = Application.ensure_all_started(:book_app)

    path = Application.app_dir(:book_app, "priv/repo/migrations")

    Ecto.Migrator.run(BookApp.Repo, path, :up, all: true)
  end
end

Σημείωση Είναι καλή πρακτική να βεβαιώνεστε ότι η εφαρμογή σας έχει εκκινήσει σωστά πριν να τρέξουν αυτές οι μετατροπές. Η Ecto.Migrator μας επιτρέπει να τρέξουμε τις μετατροπές μας με τη συνδεδεμένη βάση δεδομένων.

Στη συνέχεια, δημιουργήστε ένα νέο αρχείο - rel/hooks/post_start/migrate.sh και προσθέστε τον παρακάτω κώδικα:

echo "Running migrations"

bin/book_app rpc "Elixir.BookApp.ReleaseTasks.migrate"

Για να τρέξει σωστά αυτός ο κώδικας, χρησιμοποιούμε την ενότητα rpc της Erlang που μας δίνει πρόσβαση στην υπηρεσία Remote Procedure Call. Βασικά, αυτό μας επιτρέπει να καλέσουμε μια συνάρτηση στον απομακρυσμένο κόμβο και να πάρουμε μια απάντηση. Όταν τρέχει στην παραγωγή είναι πιθανό ότι η εφαρμογή μας θα τρέχει σε πολλούς διαφορετικούς κόμβους.

Τελικά, στο αρχείο μας rel/config.exs θα προσθέσουμε το hook στη ρύθμιση της παραγωγής μας.

Ας αντικαταστήσουμε

environment :prod do
  set include_erts: true
  set include_src: false
  set cookie: :"TkJuF,3nc4)OWPBpPxPDb6mz$>)>a>/v/,l2}W*sUFaz<)bG,v*3pPESE,`XOk{,"
  set vm_args: "rel/vm.args"
end

με

environment :prod do
  set include_erts: true
  set include_src: false
  set cookie: :"TkJuF,3nc4)OWPBpPxPDb6mz$>)>a>/v/,l2}W*sUFaz<)bG,v*3pPESE,`XOk{,"
  set vm_args: "rel/vm.args"
  set post_start_hooks: "rel/hooks/post_start"
end

Σημείωση - Αυτό το hook υπάρχει μόνο στην έκδοση παραγωγής αυτής της εφαρμογής. Αν χρησιμοποιούσαμε την προκαθορισμένη έκδοση ανάπτυξης δεν θα έτρεχε.

Χειροποίητες Εντολές

Όταν εργάζεστε με μια έκδοση, είναι πολύ πιθανό να μην έχετε πρόσβαση στις εντολές mix καθώς το mix μπορεί να μην έχει εγκατασταθεί στο μηχάνημα στο οποίο η έκδοση έχει γίνει deploy. Μπορούμε να το λύσουμε αυτό με τις χειροποίητες εντολές.

Οι χειροποίητες εντολές είναι προεκτάσεις στο script εκκίνησης, και χρησιμοποιούνται με τον ίδιο τρόπο που χρησιμοποιείτε τις εντολές foreground ή remote_console, με άλλα λόγια, εμφανίζονται σαν να είναι μέρος του script εκκίνησης. Σαν τα hooks, έχουν πρόσβαση στις βοηθητικές εργασίες του script εκκίνησης και το περιβάλλον - Τεκμηρίωση Distillery

Οι εντολές είναι παρόμοιες με τις εργασίες έκδοσης στο ότι είναι συναρτήσεις αλλά διαφορετικές από αυτές στο ότι τρέχουν από το τερματικό αντί να τρέχουν από το script έκδοσης.

Τώρα που μπορούμε να τρέξουμε την εφαρμογή μας, μπορεί να θέλουμε να φορτώσουμε τη βάση δεδομένων μας με πληροφορίες μέσω μιας εντολής. Αρχικά, προσθέστε μια μέθοδο στις εργασίες έκδοσής μας. Στην ενότητα BookAppWeb.ReleaseTasks, προσθέστε τα ακόλουθα:

def seed do
  seed_path = Application.app_dir(:book_app_web, "priv/repo/seeds.exs")
  Code.eval_file(seed_path)
end

Στη συνέχεια, δημιουργήστε ένα νέο αρχείο rel/commands/seed.sh και προσθέστε τον παρακάτω κώδικα:

#!/bin/sh

release_ctl eval "BookAppWeb.ReleaseTasks.seed/0"

Σημείωση - Το releace_ctl είναι ένα script τερματικού που παρέχεται από την Distillery για να μας επιτρέψει να εκτελούμε εντολές τοπικά ή σε ένα καθαρό κόμβο. Αν χρειάζεστε να την τρέξετε σε έναν υπάρχον κόμβο μπορείτε να τρέξετε την release_remote_ctl()

Δείτε περισσότερα για τα shell_scripts από την Distillery εδώ

Τελικά, προσθέστε το παρακάτω στο αρχείο σας rel/config.exs

release :book_app do
  ...
  set commands: [
    seed: "rel/commands/seed.sh"
  ]
end

Επαναδημιουργήστε την έκδοση τρέχοντας την MIX_ENV=prod mix release. Όταν ολοκληρωθεί, θα μπορείτε να τρέξετε στο τερματικό σας την PORT=4001 _build/prod/rel/book_app/bin/book_app seed.

Έπιασες λάθος ή θέλεις να συνεισφέρεις στο μάθημα; Επεξεργαστείτε αυτό το μάθημα στο GitHub!