首页 > 解决方案 > 使用 ansible 应用数据库迁移

问题描述

我确实想在使用 ansible 获取构建工件时应用迁移。

一些事实:

可能的问题:

我对如何解决这个问题的想法:

使用 fs 层:

这种方式看起来很奇怪 - 我认为 fs 不可靠,主要主机可以更改(被销毁等)

使用数据库:

这种方式看起来更好 - 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}}"

标签: linuxpostgresqlbashansible

解决方案


如何跟踪已经应用的脚本,避免双重应用?

在数据库世界中,有两种主要的自动数据库迁移方式。

  1. 基于状态的迁移
  • 源代码控制所有数据库对象处于一致状态
  • 部署工具将存储库状态与实时数据库进行比较并生成差异脚本
  • 脚本是对象定义,例如:CREATE TABLE ...
  • 示例:SQL Server 数据工具
  1. 基于迁移的方法
  • 源代码控制:不断发展的对象和变化
  • 部署脚本
  • 脚本大多类似于: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 脚本,我们可以完全控制部署的内容。

相关:版本控制工具


推荐阅读