cogini.elixir-release

elixir-release

このAnsibleロールは、Elixir/Phoenixリリースをデプロイします。

Erlangの「リリース」を使用し、プロセス監視にsystemdを用います。詳細については、"AnsibleでElixirアプリをデプロイする"や"Elixirアプリをデプロイするためのベストプラクティス"を参照してください。

ディレクトリ構造

Capistranoのような構造を使ってリリースファイルを管理します。基本ディレクトリはアプリ名、例えば/srv/fooという名前になり、その下にreleasesディレクトリがあります。ロールがリリースをデプロイすると、タイムスタンプで命名されたディレクトリ、例えば/srv/foo/releases/20190603T072116が作成されます。その下にファイルが展開され、/srv/foo/currentから新しいディレクトリへのシンボリックリンクが作成されます。

再起動

リリースをデプロイした後、アプリを再起動して運用を開始します。

デフォルトでは、elixir_release_restart_method: systemctlが設定されている場合、以下のコマンドを実行して再起動します:

sudo /bin/systemctl restart foo

デプロイユーザーアカウントには、アプリを再起動するために十分な権限が必要です。デプロイアカウントに全てのsudo権限を与える代わりに、ユーザー固有のsudo設定ファイルを用意して、実行できるコマンドを指定します。例えば、/etc/sudoers.d/deploy-fooには以下のように記述します:

deploy ALL=(ALL) NOPASSWD: /bin/systemctl start foo, /bin/systemctl stop foo, /bin/systemctl restart foo

sudo権限を全く必要としない方が良いでしょう。一つの選択肢はsystemdを利用してアプリを再起動することです。

elixir_release_restart_method: systemd_flagを設定すると、デプロイ後にディスク上の/srv/foo/flags/restart.flagファイルに触れることで、systemdが新しいコードで再起動します。

完全な例については、mix-deploy-exampleを参照してください。

使用例

アプリ名がfooの最小限のプレイブック:

- hosts: '*'
  become: true
  vars:
    elixir_release_app_name: foo
  roles:
    - cogini.elixir-release

これをansible/playbooks/deploy-app.ymlに保存します。

まず、ターゲットマシンのセットアップを行います。例えば、パッケージのインストールやディレクトリの作成を行います。次のコマンドを開発マシンから実行し、sudo権限を持つユーザーを指定します:

ansible-playbook -u $USER -v -l web_servers playbooks/deploy-app.yml --skip-tags deploy -D

次に、コードをデプロイします。ビルドサーバーから、ターゲットマシンのデプロイアカウントへのSSHアクセスを持つユーザーアカウントで以下を実行します:

ansible-playbook -u deploy -v -l web_servers playbooks/deploy-app.yml --tags deploy --extra-vars ansible_become=false -D

よりカスタマイズされたプレイブックの例:

- hosts: '*'
  become: true
  vars:
    elixir_release_app_name: foo
    elixir_release_app_user: bar
    elixir_release_deploy_user: deploy
    elixir_release_mix_env: frontend
    elixir_release_systemd_source: mix_systemd
    elixir_release_base_dir: /opt/bar
    elixir_release_app_dirs:
      - configuration
      - runtime
      - logs
      - tmp
      - state
      - cache
    elixir_release_tmp_directory_base: /var/tmp/bar
    elixir_release_state_directory_base: /var/bar
    elixir_release_http_listen_port: 8080
    elixir_release_cache_directory_mode: 0700
    elixir_release_configuration_directory_mode: 0755
    elixir_release_logs_directory_mode: 0755
    elixir_release_state_directory_mode: 0755
    elixir_release_tmp_directory_mode: 0755
    elixir_release_sudoers_file: "{{ elixir_release_app_user }}-{{ elixir_release_service_name }}"
    elixir_release_src_dir: "{{ playbook_dir }}/../../../foo"
  roles:
    - cogini.elixir-release

ロール変数

リリースを構築するために使用するシステム、"mix"または"distillery"のいずれかを指定します。

elixir_release_release_system: "mix"

リリースファイルを取得するアプリの場所。デフォルトでは、アプリソースにansibleディレクトリがあると仮定します。

elixir_release_app_dir: "{{ role_path }}/../../.."

Distilleryがディレクトリやスクリプトの名前を付けるために使用するアプリケーションのErlang名。

elixir_release_app_name: my_app

リリース名。デフォルトはapp_nameですが、通常はMIX_ENVが使われます。

elixir_release_release_name: "{{ elixir_release_app_name }}"

アプリの外部名であり、systemdサービスやディレクトリの名前に使用されます。デフォルトでは、アンダースコアをハイフンに変換します。

elixir_release_service_name: "{{ elixir_release_app_name | replace('_', '-') }}"

Elixirアプリケーション名。デフォルトではアプリ名のCamelCaseバージョンになります。

elixir_release_app_module: "{{ elixir_release_service_name.title().replace('_', '') }}"

リリースするアプリのバージョン。指定がない場合、リリースディレクトリ内のstart_erl.dataファイルから読み込みます。

elixir_release_version: "0.1.0"

セキュリティのため、アプリをデプロイするアカウントと実行するアカウントは別にします。デプロイアカウントはコードと設定ファイルを所有し、アプリを再起動する権利があります。通常はdeployという別のアカウントを使用します。アプリは最小限の権限で別のアカウントで実行されます。通常はアプリにちなんだ名前を作成します。例:fooapp

リリースファイルの所有権はdeploy:appで、モードは0644でアプリが読むことができます。

リリースファイルをデプロイし所有するOSアカウント:

elixir_release_deploy_user: deploy

リリースファイルをデプロイし所有するOSグループ:

elixir_release_deploy_group: "{{ elixir_release_deploy_user }}"

アプリが実行されるOSアカウント:

elixir_release_app_user: "{{ elixir_release_service_name }}"

アプリが実行されるOSグループ:

elixir_release_app_group: "{{ elixir_release_app_user }}"

アプリリリース環境。つまり、MIX_ENVの設定で、_buildディレクトリ内のリリースファイルを見つけるために使用されます。

elixir_release_mix_env: prod

リリースファイルのディレクトリプレフィックス:

elixir_release_base_dir: /srv

デプロイファイルの基本ディレクトリ:

elixir_release_deploy_dir: "{{ elixir_release_base_dir }}/{{ elixir_release_service_name }}"

デプロイディレクトリ内のサブディレクトリ。

リリースtarballが展開される場所:

elixir_release_releases_dir: "{{ elixir_release_deploy_dir }}/releases"

現在実行中のリリース(シンボリックリンク):

elixir_release_current_dir: "{{ elixir_release_deploy_dir }}/current"

デプロイスクリプトの場所:

elixir_release_scripts_dir: "{{ elixir_release_deploy_dir }}/bin"

再起動のシグナルとして使用されるフラグファイルディレクトリ:

elixir_release_flags_dir: "{{ elixir_release_deploy_dir }}/flags"

アプリがファイルを保管するためのディレクトリ、systemdに従ったもの。

elixir_release_app_dirs:
  - configuration
  - runtime

conformを使用するかどうか:

elixir_release_conform: false
elixir_release_conform_conf_path: "{{ elixir_release_configuration_dir }}/config.conform"

アプリをどのように再起動するか:

elixir_release_restart_method: systemctl
# elixir_release_restart_method: systemd_flag
# elixir_release_restart_method: touch

オプションは:

  • systemctl、これはsystemctl restart fooを実行します。
  • systemd_flag、これは{{ elixir_release_shutdown_flags_dir }}/restart.flagファイルを触ります。
  • touch、これは{{ elixir_release_shutdown_flags_dir }}/restart.flagファイルを触ります。ディレクトリの権限は0770で、管理されたプロセスが自動的に再起動できるようにします。

どのユーザーがsudo /bin/systemctl restartを使ってアプリを再起動できるか(method == systemctlのとき)。

elixir_release_restart_users:
    - "{{ elixir_release_deploy_user }}"

これを[]に設定すると誰も再起動できなくなります。他の名前を追加することも可能です。例:- "{{ elixir_release_app_user }}"

systemdとスクリプト

デフォルトでは、このロールは mix_systemdを使用してsystemdユニットファイルを生成し、mix_deployを使用してライフサイクルスクリプトを生成していると仮定します。

elixir_release_systemd_sourceはsystemdユニットファイルのソースを制御します。

elixir_release_systemd_source: mix_systemd

デフォルト値がmix_systemdの場合、このロールは_build/{{ elixir_release_mix_env }}/systemdディレクトリからsystemdユニットファイルをコピーします。selfに設定すると、このロールはテンプレートからsystemdユニットファイルを生成します。

elixir_release_scripts_sourceはスクリプトのソースを制御します。

elixir_release_scripts_source: bin

デフォルト値がbinの場合、このロールはプロジェクトのbinディレクトリからスクリプトをターゲットシステムの/srv/foo/binにコピーします。output_dir_per_env: truemix_deploy設定で設定している場合、生成されたスクリプトは_buildに保存されています。

systemdユニットファイル生成時に使用される変数は次の通りです:

アプリがHTTP接続を待ち受けるポート:

elixir_release_http_listen_port: 4000

アプリがHTTPS接続を待ち受けるポート:

elixir_release_https_listen_port: 4001

オープンファイル制限:

elixir_release_limit_nofile: 65536

再起動の間隔(秒):

elixir_release_systemd_restart_sec: 5

LANG環境変数:

elixir_release_lang: "en_US.UTF-8"

umask:

elixir_release_umask: "0027"

ターゲットsystemdバージョン。より高度な機能を有効にするために使用されます。

elixir_release_systemd_version: 219

systemdサービスのタイプ:simple | exec | notify | forking。詳しくはsystemdのTypeを参照してください。

elixir_release_service_type: simple

アプリを起動するために実行するリリースコマンド。mixはsimpleのためにstart、forkingのためにdaemonを使用します。 distileryはsimpleのためにforeground、forkingのためにstartを使用します。

elixir_release_start_command: start

forkingサービスタイプを使用する場合のPIDファイル:

elixir_release_pid_file: "{{ elixir_release_runtime_dir }}/{{ elixir_release_app_name}}.pid"

systemdユニットファイル内のExecStartPreスクリプトのリスト:

elixir_release_exec_start_pre: []

systemdユニットファイル内に設定する環境変数のリスト:

elixir_release_env_vars: []

依存関係

なし

要件

なし

ライセンス

MIT

著者情報

Jake Morrison jake@cogini.com

プロジェクトについて

Deploy an Elixir app

インストール
ansible-galaxy install cogini.elixir-release
ライセンス
mit
ダウンロード
108
所有者
Product development services for ambitious innovators