Support for post deployment migrations
These are regular Rails migrations that are executed by default. A user can opt-out of these migrations by setting an environment variable during the deployment process. Fixes gitlab-org/gitlab-ce#22133
This commit is contained in:
parent
696f09c7bf
commit
83c8241160
7 changed files with 124 additions and 0 deletions
|
@ -24,6 +24,7 @@ Please view this file on the master branch, on stable branches it's out of date.
|
||||||
- Refactor less readable existance checking code from CoffeeScript !6289 (jlogandavison)
|
- Refactor less readable existance checking code from CoffeeScript !6289 (jlogandavison)
|
||||||
- Update mail_room and enable sentinel support to Reply By Email (!7101)
|
- Update mail_room and enable sentinel support to Reply By Email (!7101)
|
||||||
- Add task completion status in Issues and Merge Requests tabs: "X of Y tasks completed" (!6527, @gmesalazar)
|
- Add task completion status in Issues and Merge Requests tabs: "X of Y tasks completed" (!6527, @gmesalazar)
|
||||||
|
- Added support for executing post deployment migrations
|
||||||
- Simpler arguments passed to named_route on toggle_award_url helper method
|
- Simpler arguments passed to named_route on toggle_award_url helper method
|
||||||
- Fix typo in framework css class. !7086 (Daniel Voogsgerd)
|
- Fix typo in framework css class. !7086 (Daniel Voogsgerd)
|
||||||
- New issue board list dropdown stays open after adding a new list
|
- New issue board list dropdown stays open after adding a new list
|
||||||
|
|
12
config/initializers/0_post_deployment_migrations.rb
Normal file
12
config/initializers/0_post_deployment_migrations.rb
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# Post deployment migrations are included by default. This file must be loaded
|
||||||
|
# before other initializers as Rails may otherwise memoize a list of migrations
|
||||||
|
# excluding the post deployment migrations.
|
||||||
|
unless ENV['SKIP_POST_DEPLOYMENT_MIGRATIONS']
|
||||||
|
path = Rails.root.join('db', 'post_migrate').to_s
|
||||||
|
|
||||||
|
Rails.application.config.paths['db/migrate'] << path
|
||||||
|
|
||||||
|
# Rails memoizes migrations at certain points where it won't read the above
|
||||||
|
# path just yet. As such we must also update the following list of paths.
|
||||||
|
ActiveRecord::Migrator.migrations_paths << path
|
||||||
|
end
|
0
db/post_migrate/.gitkeep
Normal file
0
db/post_migrate/.gitkeep
Normal file
|
@ -41,6 +41,7 @@
|
||||||
|
|
||||||
- [What requires downtime?](what_requires_downtime.md)
|
- [What requires downtime?](what_requires_downtime.md)
|
||||||
- [Adding database indexes](adding_database_indexes.md)
|
- [Adding database indexes](adding_database_indexes.md)
|
||||||
|
- [Post Deployment Migrations](post_deployment_migrations.md)
|
||||||
|
|
||||||
## Compliance
|
## Compliance
|
||||||
|
|
||||||
|
|
75
doc/development/post_deployment_migrations.md
Normal file
75
doc/development/post_deployment_migrations.md
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
# Post Deployment Migrations
|
||||||
|
|
||||||
|
Post deployment migrations are regular Rails migrations that can optionally be
|
||||||
|
executed after a deployment. By default these migrations are executed alongside
|
||||||
|
the other migrations. To skip these migrations you will have to set the
|
||||||
|
environment variable `SKIP_POST_DEPLOYMENT_MIGRATIONS` to a non-empty value
|
||||||
|
when running `rake db:migrate`.
|
||||||
|
|
||||||
|
For example, this would run all migrations including any post deployment
|
||||||
|
migrations:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bundle exec rake db:migrate
|
||||||
|
```
|
||||||
|
|
||||||
|
This however will skip post deployment migrations:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
SKIP_POST_DEPLOYMENT_MIGRATIONS=true bundle exec rake db:migrate
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deployment Integration
|
||||||
|
|
||||||
|
Say you're using Chef for deploying new versions of GitLab and you'd like to run
|
||||||
|
post deployment migrations after deploying a new version. Let's assume you
|
||||||
|
normally use the command `chef-client` to do so. To make use of this feature
|
||||||
|
you'd have to run this command as follows:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
SKIP_POST_DEPLOYMENT_MIGRATIONS=true sudo chef-client
|
||||||
|
```
|
||||||
|
|
||||||
|
Once all servers have been updated you can run `chef-client` again on a single
|
||||||
|
server _without_ the environment variable.
|
||||||
|
|
||||||
|
The process is similar for other deployment techniques: first you would deploy
|
||||||
|
with the environment variable set, then you'll essentially re-deploy a single
|
||||||
|
server but with the variable _unset_.
|
||||||
|
|
||||||
|
## Creating Migrations
|
||||||
|
|
||||||
|
To create a post deployment migration you can use the following Rails generator:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bundle exec rails g post_deployment_migration migration_name_here
|
||||||
|
```
|
||||||
|
|
||||||
|
This will generate the migration file in `db/post_migrate`. These migrations
|
||||||
|
behave exactly like regular Rails migrations.
|
||||||
|
|
||||||
|
## Use Cases
|
||||||
|
|
||||||
|
Post deployment migrations can be used to perform migrations that mutate state
|
||||||
|
that an existing version of GitLab depends on. For example, say you want to
|
||||||
|
remove a column from a table. This requires downtime as a GitLab instance
|
||||||
|
depends on this column being present while it's running. Normally you'd follow
|
||||||
|
these steps in such a case:
|
||||||
|
|
||||||
|
1. Stop the GitLab instance
|
||||||
|
2. Run the migration removing the column
|
||||||
|
3. Start the GitLab instance again
|
||||||
|
|
||||||
|
Using post deployment migrations we can instead follow these steps:
|
||||||
|
|
||||||
|
1. Deploy a new version of GitLab while ignoring post deployment migrations
|
||||||
|
2. Re-run `rake db:migrate` but without the environment variable set
|
||||||
|
|
||||||
|
Here we don't need any downtime as the migration takes place _after_ a new
|
||||||
|
version (which doesn't depend on the column anymore) has been deployed.
|
||||||
|
|
||||||
|
Some other examples where these migrations are useful:
|
||||||
|
|
||||||
|
* Cleaning up data generated due to a bug in GitLab
|
||||||
|
* Removing tables
|
||||||
|
* Migrating jobs from one Sidekiq queue to another
|
|
@ -0,0 +1,22 @@
|
||||||
|
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
|
||||||
|
# for more information on how to write migrations for GitLab.
|
||||||
|
|
||||||
|
class <%= migration_class_name %> < ActiveRecord::Migration
|
||||||
|
include Gitlab::Database::MigrationHelpers
|
||||||
|
|
||||||
|
DOWNTIME = false
|
||||||
|
|
||||||
|
# When using the methods "add_concurrent_index" or "add_column_with_default"
|
||||||
|
# you must disable the use of transactions as these methods can not run in an
|
||||||
|
# existing transaction. When using "add_concurrent_index" make sure that this
|
||||||
|
# method is the _only_ method called in the migration, any other changes
|
||||||
|
# should go in a separate migration. This ensures that upon failure _only_ the
|
||||||
|
# index creation fails and can be retried or reverted easily.
|
||||||
|
#
|
||||||
|
# To disable transactions uncomment the following line and remove these
|
||||||
|
# comments:
|
||||||
|
# disable_ddl_transaction!
|
||||||
|
|
||||||
|
def change
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,13 @@
|
||||||
|
module Rails
|
||||||
|
class PostDeploymentMigrationGenerator < Rails::Generators::NamedBase
|
||||||
|
def create_migration_file
|
||||||
|
timestamp = Time.now.strftime('%Y%m%d%H%I%S')
|
||||||
|
|
||||||
|
template "migration.rb", "db/post_migrate/#{timestamp}_#{file_name}.rb"
|
||||||
|
end
|
||||||
|
|
||||||
|
def migration_class_name
|
||||||
|
file_name.camelize
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue