使用Docker实现PostgreSQL与ElasticSearch数据同步的源码演示


如果您尝试对正在同步的数据库表中的某些数据进行 CRUD,只需使用docker-compose up -d. 这些更改几乎会立即镜像到 Elastic。
Github存储库中找到完整的示例
本文旨在向您展示如何轻松地在 PostgreSQL 和 ElasticSearch 之间同步数据。通过同步,我的意思是每次在数据库中 CRUD 数据时,这些更改都会立即反映在 Elastic 中。
 
创建 Elastic 和 Kibana 服务
Kibana 是一个用于 Elastic 数据可视化的开源插件。它提供了各种数据操作工具。它还为我们提供了对 Elastic 实例进行直接查询的控制台。它类似于 GraphQL Playground(如果您曾经使用过)。
因此,我们的 docker-compose 可能如下所示:

version: '3.8'
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.13.4
    container_name: elasticsearch
    environment:
      - xpack.security.enabled=false
      - discovery.type=single-node
      - bootstrap.memory_lock=true
      - 'ES_JAVA_OPTS=-Xms512m -Xmx512m'
    ulimits:
      memlock:
        soft: -1
        hard: -1
    ports:
      - '9200:9200'

  kibana:
    image: docker.elastic.co/kibana/kibana:7.13.4
    depends_on:
      - elasticsearch
    ports:
      - '5601:5601'
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200

当然,您可以只创建 Elastic。但是在 Kibana 的帮助下,您可以轻松地向 Elastic 发出请求并通过 UI 查看(也创建)数据。
 

PostgreSQL 服务
稍后我们需要对其进行自定义,因此无需直接在 docker-compose 文件中使用基本Image镜像。创建PostgresDockerfile并粘贴这个:
FROM postgres:13
然后将其添加到服务下的 docker-compose 文件中:

database:
    build:
      context: .
      dockerfile: PostgresDockerfile
    container_name: database
    ports:
      - '5432:5432'
    environment:
      - POSTGRES_PASSWORD=postgres

 
同步
PGSync是一个可以帮助我们实现目标的工具!您可以在此处阅读更多相关信息。我们只需要Redis(因为它使用发布-订阅机制)和模式。因此,将此行添加到 docker-compose 文件中:

redis:
    image: 'redis:alpine'
    container_name: redis
    ports:
      - '6379:6379'

这个工具是用 Python 编写的,所以我们需要创建一个 Python 容器。正如我们从文档中看到的,我们还应该更改postgresql.conf.
因此,创建目录pgsync,并PgsyncDockerfile在项目的根。

FROM python:3.7-slim

WORKDIR /usr/src/app

COPY ./pgsync ./

RUN chmod +x ./entrypoint.sh

RUN pip install pgsync==2.1.1

RUN apt update \
    && apt install -y moreutils \
    && apt install -y jq \
    && apt install -y wait-for-it

ENTRYPOINT ["bash", "./entrypoint.sh"]

要将额外的配置应用到 postgres 容器,我们只需创建任意数量的 sql 文件,然后将它们复制到/docker-entrypoint-initdb.d我们容器的目录中。好的!它们将在容器初始化时执行。
因此,让我们创建conf.sql以下内容:

ALTER SYSTEM SET wal_level = logical;
ALTER SYSTEM SET max_replication_slots = 1;
-- set this value to the number of tables you want to load into elastic

并更改PostgresDockerfile为:
FROM postgres:13

COPY ./pgsync/conf.sql /docker-entrypoint-initdb.d/
COPY ./pgsync/populate.sql /docker-entrypoint-initdb.d/

RUN chmod a+r /docker-entrypoint-initdb.d/conf.sql
RUN chmod a+r /docker-entrypoint-initdb.d/populate.sql

好的,正如你所看到的,我们也应该有entrypoint.shin outpgsync目录。这是主文件,如果我们运行 pgsync 容器,它将被执行。

#!/usr/bin/env bash

wait-for-it $PG_HOST:5432 -t 60
wait-for-it $REDIS_HOST:6379 -t 60
wait-for-it $ELASTICSEARCH_HOST:9200 -t 60

jq '.[].database = env.PG_DATABASE' schema.json | sponge schema.json

bootstrap --config ./schema.json
pgsync --config ./schema.json -d

我们jq在这里使用实用程序schema根据PG_DATABASE构建阶段的 env 变量在我们的文件中动态设置数据库名称。
我们还使用wait-for-it脚本来等待我们的服务。仅depends_on在 docker-compose 文件中写入并不总是有效,相​​信我!
 
Schema文件
在pgsync目录内创建schema.json:

[
  {
    "database": "db_name",
    "index": "elastic-index-name",
    "nodes": {
      "table": "table-name",
      "schema": "public",
      "columns": []
    }
  }
]

此处提供了有关架构定义的更多信息。
 
服务
将这些添加到 docker-compose 中:

pgsync:
    build:
      context: .
      dockerfile: PgsyncDockerfile
    container_name: pgsync
    environment:
      - PG_USER=postgres
      - PG_PASSWORD=postgres
      - PG_DATABASE=postgres
      - PG_HOST=database
      - ELASTICSEARCH_HOST=elasticsearch
      - REDIS_HOST=redis

 
运行!
而已。只需使用docker-compose up -d. 现在,如果您尝试对正在同步的数据库表中的某些数据进行 CRUD,这些更改几乎会立即镜像到 Elastic。