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 }}/../../.."
Erlang 应用名称,用于 Distillery 命名目录和脚本。
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 应用名称。默认是应用名称的驼峰版本:
elixir_release_app_module: "{{ elixir_release_service_name.title().replace('_', '') }}"
要发布的应用版本。如果不指定,将从发布目录中的 start_erl.data
文件读取。
elixir_release_version: "0.1.0"
出于安全原因,我们使用不同的账户来部署和运行应用。部署账户拥有代码和配置文件,并有权限重启应用。我们通常使用名为 deploy
的账户。应用在一个具有最低权限的单独账户下运行。我们通常创建一个与应用匹配的名称,如 foo
,或使用像 app
这样的通用名称。
发布文件的所有者为 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
重启应用,当方法 == 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
。如果在 mix_deploy
配置中设置了 output_dir_per_env: true
,将 elixir_release_scripts_source
设置为 mix_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
启动应用的发布命令。mix 使用 start(simple)和 daemon(forking)。distillery 使用 foreground(simple)和 start(forking)。
elixir_release_start_command: start
使用 fork 服务类型时的 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