linux - 使用 ansible 应用数据库迁移
问题描述
我确实想在使用 ansible 获取构建工件时应用迁移。
一些事实:
- 迁移是纯 sql
- Postresql 处于集群模式(无分片)
- 有 2 个主机(api1 和 api2)
- 不需要“向下机制”
可能的问题:
- 如何选择应该运行迁移的主机(首先准备好还是始终为主)?
- 如何跟踪已经应用的脚本,避免双重应用?
我对如何解决这个问题的想法:
使用 fs 层:
- 每个构建工件都将包含 sql-migrations
- 部署后,主主机应将现有迁移文件与新迁移文件进行比较并应用新迁移文件,通过用新文件替换旧文件来保存状态
- 迁移执行
community.postgresql.postgresql_query
这种方式看起来很奇怪 - 我认为 fs 不可靠,主要主机可以更改(被销毁等)
使用数据库:
- 每个构建工件都将包含 sql-migrations
- 部署后,准备就绪的主机应查询某些表以获取已应用的迁移并应用新的迁移,通过
community.postgresql.postgresql_query
插入新的迁移名称来保存状态
这种方式看起来更好 - db 仍然可靠,但是可以使用 ansible 吗?
我对 python 不熟悉,所以我不能接受像“编写你自己的插件”这样的解决方案——我以后将无法支持它。并且不首选任何 NPM 包,我仅限于编译的解决方案和内置的 linux 工具,如python
,bash
等。
顺便说一句,剧本看起来像:
---
- hosts: api
vars:
api_apps:
- name: "Api"
description: "API service"
exec: "/usr/local/bin/handler"
identifier: "handler"
env:
- name: PORT
value: "3000"
- name: DB_TYPE
value: 'postgres'
- name: DB_PATH
value: "postgres://{{hostvars['db01'].postgresql_users[0].name}}:{{hostvars['db01'].postgresql_users[0].pass}}@{{hostvars['db01'].private_ip}}:{{hostvars['db01'].postgresql_port}}/{{hostvars['db01'].postgresql_databases[0].name}}"
- name: ACCESS_CONTROL_ALLOW_ORIGIN
value: "\"*""
- name: ACCESS_CONTROL_MAX_AGE
value: 9600
tasks:
- block: # Pull and extract artifacts
- name: "[ api ] Pull release info"
uri:
url: "https://api.github.com/repos/<my_profile>/{{ item }}/releases/latest"
headers:
Authorization: "Bearer {{ github_token }}"
return_content: true
register: release_response
no_log: True
with_items:
- "<my_private_repo>"
- name: "[ api ] Pull latest artifact"
get_url:
url: "{{ item.json.assets[0].url }}"
headers:
Accept: "application\/octet-stream"
Authorization: "Bearer {{ github_token }}"
force: true
dest: "/tmp/{{ item.item }}.zip"
no_log: True
register: pulled_items
with_items: "{{ release_response.results }}"
- name: Extract archives
unarchive:
src: "/tmp/{{ item.item.item }}.zip"
dest: "/usr/local/bin"
remote_src: yes
no_log: True
with_items: "{{ pulled_items.results }}"
- name: create service templates
template:
src: "files/api/service.j2"
dest: "/etc/systemd/system/{{item.identifier}}.service"
with_items: "{{ api_apps }}"
no_log: False
- name: Start services
systemd:
state: restarted
daemon_reload: yes
name: "{{item.identifier}}"
with_items: "{{api_apps}}"
解决方案
如何跟踪已经应用的脚本,避免双重应用?
在数据库世界中,有两种主要的自动数据库迁移方式。
- 基于状态的迁移
- 源代码控制所有数据库对象处于一致状态
- 部署工具将存储库状态与实时数据库进行比较并生成差异脚本
- 脚本是对象定义,例如:CREATE TABLE ...
- 示例:SQL Server 数据工具
- 基于迁移的方法
- 源代码控制:不断发展的对象和变化
- 部署脚本
- 脚本大多类似于:ALTER/CREATE OR REPLACE
- 示例:Redgate Flyway
每种方法都有其优点和缺点。我不知道有任何支持 PosrgreSQL 状态迁移的现有工具。
至于避免双重设备相同的脚本:
理想情况下,每个 SQL 脚本都应该是幂等且正交的。
例如,如果您需要添加一个新列:
ALTER TABLE tab ADD COLUMN new_col INT;
这个脚本不是幂等的,因为第二次运行会失败。因此,我们可以将其保护为:
ALTER TABLE tab ADD COLUMN IF NOT EXISTS new_col INT;
另一个常见的例子是添加字典数据:
-- instead of
INSERT INTO tab(col, ...) VALUES (...);
-- use upsert to handle existing data
INSERT INTO tab(col, ...)
VALUES(....)
ON CONFLICT (...)
DO
另一个问题是正确的脚本顺序。例如,在创建使用新列的视图时,必须首先使用 ALTER 表。
正如我们所看到的,原本微不足道的事情变得越来越棘手。
幸运的是,我们有工具。主要思想是一个迁移跟踪表,其中包含已运行脚本的完整历史记录。通过订购 SQL 脚本,我们可以完全控制部署的内容。
相关:版本控制工具
推荐阅读
- postgresql - 如何将 postgres 表从一个数据库复制到另一个使用序列的服务器上的另一个数据库
- mongodb - Loopback4 与 Mongodb 身份验证状态代码 500 错误
- html - 直接下载字体包而不是使用
- bash - 循环遍历目录路径列表
- android - 如何启动另一个具有权限的应用程序的活动别名?
- python - 根据条件从 numpy 数组的子数组中删除行
- file-upload - Laminas\InputFilter\FileInput 究竟做了什么?
- go - 针对 DynamoDB-Local 测试容器
- python - 使用 Python 的 Google 索引 API
- cocoapods - 无法将“MidiParser”pod 添加到 Podfile