Emi Matchu
9ebc498888
I move `ruby_version` into an Ansible variable, to make it easier to update in the future!
132 lines
5.5 KiB
YAML
132 lines
5.5 KiB
YAML
---
|
|
- name: Deploy impress from the current local version
|
|
hosts: webserver
|
|
become: yes
|
|
become_user: impress
|
|
vars:
|
|
local_app_root: "{{ playbook_dir }}/.."
|
|
remote_project_root: "/srv/impress"
|
|
ruby_version: "3.3.5"
|
|
|
|
# deploy:setup should have added us to the "impress-deployers" group, so we
|
|
# should be able to become the "impress" user without a password.
|
|
ansible_become_password: ""
|
|
|
|
# Set this to `yes` to skip setting this version as `current`. (We also
|
|
# skip our usual cleanup, to avoid disrupting the `current` version!)
|
|
#
|
|
# This can be useful for upgrading our Ruby version without downtime:
|
|
# 1. Install the new Ruby version, but don't uninstall the old one.
|
|
# 2. Update the app to reference the new Ruby version in the `Gemfile`.
|
|
# 3. Deploy the app with `skip_set_as_current`.
|
|
# 4. Update the service file manually to use the new Ruby to run the new
|
|
# version of the app, referenced directly by path.
|
|
# 5. Link the new version as `current` manually.
|
|
# 6. Reset the service file to use the new Ruby to run `current`.
|
|
skip_set_as_current: no
|
|
tasks:
|
|
- name: Generate a version name from the current timestamp
|
|
command: date '+%Y-%m-%d-%s'
|
|
register: new_app_version
|
|
|
|
- name: Print out the new version name
|
|
debug:
|
|
msg: "Deploying new version: {{ new_app_version.stdout }}"
|
|
|
|
- name: Save new remote folder path to a variable
|
|
set_fact:
|
|
remote_app_root: "{{ remote_project_root }}/versions/{{ new_app_version.stdout }}"
|
|
|
|
- name: Create new remote folder for the new version
|
|
file:
|
|
path: "{{ remote_app_root }}"
|
|
state: directory
|
|
|
|
# NOTE: We skip most gitignored files, except for public/assets/*, which
|
|
# contains the assets we precompiled for production.
|
|
- name: Copy local app's source files to new remote folder
|
|
ansible.posix.synchronize:
|
|
src: "{{ local_app_root }}/"
|
|
dest: "{{ remote_app_root }}"
|
|
rsync_opts:
|
|
- "--include=/public/assets/*"
|
|
- "--exclude=.git"
|
|
- "--filter=':- .gitignore'"
|
|
|
|
- name: Link the public-data folder to the shared public-data folder
|
|
file:
|
|
src: "{{ remote_project_root }}/shared/public-data"
|
|
dest: "{{ remote_app_root }}/public/public-data"
|
|
state: link
|
|
|
|
- name: Configure Bundler to run in deployment mode
|
|
command:
|
|
chdir: "{{ remote_app_root }}"
|
|
cmd: /opt/ruby-{{ ruby_version }}/bin/bundle config set --local deployment true
|
|
|
|
# This ensures that, while attempting our current deploy, we don't
|
|
# accidentally delete gems out from under the currently-running version.
|
|
# NOTE: From reading the docs, I thiink this is the default behavior, but
|
|
# I can't be sure? Rather than deep-dive to find out, I'd rather just set
|
|
# it, to be clear about the default(?) behavior we're depending on.
|
|
- name: Configure Bundler to *not* clean up old gems when installing
|
|
command:
|
|
chdir: "{{ remote_app_root }}"
|
|
cmd: /opt/ruby-{{ ruby_version }}/bin/bundle config set --local clean false
|
|
|
|
# NOTE: Bundler recommends this, and they're pretty smart about it: if the
|
|
# Gemfile changes, this shouldn't disrupt the currently-running version,
|
|
# because we won't clean up its now-unused gems yet, and if we upgrade a
|
|
# gem it'll install *both* versions of the gem until we clean up.
|
|
- name: Configure Bundler to use the bundle folder shared by all app versions
|
|
command:
|
|
chdir: "{{ remote_app_root }}"
|
|
cmd: "/opt/ruby-{{ ruby_version }}/bin/bundle config set --local path {{ remote_project_root}}/shared/bundle"
|
|
|
|
- name: Run `bundle install` to install dependencies in remote folder
|
|
command:
|
|
chdir: "{{ remote_app_root }}"
|
|
# The `--local` flag instructs Bundler to use the cached dependencies
|
|
# in `vendor/cache`, instead of reading from the web, which is much
|
|
# faster and more reliable!
|
|
cmd: /opt/ruby-{{ ruby_version }}/bin/bundle install --local
|
|
|
|
- name: Update the `current` folder to point to the new version
|
|
file:
|
|
src: "{{ remote_app_root }}"
|
|
dest: /srv/impress/current
|
|
state: link
|
|
when: not skip_set_as_current
|
|
|
|
# NOTE: This uses the passwordless sudo rule we set up in deploy:setup.
|
|
# We write it as a command rather than using the built-in `systemd` Ansible
|
|
# module, to make sure we're invoking it exactly as we wrote in that rule.
|
|
#
|
|
# NOTE: We use `sudo` instead of `become_user: root`, because we don't have
|
|
# permission to *become* the root user; we only have permission to run this
|
|
# one command as them.
|
|
- name: Restart the app
|
|
become: no
|
|
command: sudo systemctl restart impress
|
|
when: not skip_set_as_current
|
|
|
|
- name: Clean up gems no longer used in the current app version
|
|
command:
|
|
chdir: "{{ remote_app_root }}"
|
|
cmd: /opt/ruby-{{ ruby_version }}/bin/bundle clean
|
|
when: not skip_set_as_current
|
|
|
|
- name: Find older app versions to clean up
|
|
# Print out all but the 5 last-recently-updated versions.
|
|
command:
|
|
chdir: "{{ remote_project_root }}/versions"
|
|
cmd: bash -c 'ls -t | tail -n +6'
|
|
register: versions_to_clean_up
|
|
when: not skip_set_as_current
|
|
|
|
- name: Clean up older versions
|
|
file:
|
|
path: "{{ remote_project_root }}/versions/{{ item }}"
|
|
state: absent
|
|
with_items: "{{ versions_to_clean_up.stdout_lines }}"
|
|
when: not skip_set_as_current
|