如何与CI/CD并行运行dbt测试

427 阅读6分钟

软件开发周期中的一个困难挑战是提高开发速度,同时确保代码的质量保持不变。近年来,数据世界采用了软件开发实践,在部署前测试数据变化。测试过程可能很耗时,而且容易出现意外的错误。

例如,在CircleCI,我们的数据团队大规模地使用dbt。直到最近,我们一直在经历由dbt云中的长时间测试运行引起的部署瓶颈。为了解决这个问题,我们设置了CircleCI来自动测试和部署我们的数据变化,这样我们就能以最快的速度向我们的数据消费者提供高质量的数据模型版本。在这篇文章中,我们将指导你如何使用CircleCI和dbt来自动测试你的数据变化,以确保数据的完整性并提高你的开发速度。

本教程假定你是一个活跃的CircleCI用户。如果您是该平台的新手,您可以注册一个免费账户

什么是dbt?

dbt是一个数据转换工具,它允许数据人员将模块化SQL与软件工程的最佳实践相结合,使数据转换可靠、迭代和快速。你可以通过dbt CLI(命令行界面)或dbt Cloud与dbt互动。在CLI版本中,你可以完全控制你的数据项目配置,并能够根据需要发布文档,而dbt Cloud提供了一个用户界面,为你设置了一些配置,并自动生成dbt文档。

为什么dbt在数据工程和分析中很有用?

dbt是一个强大的数据工具,它允许你在不手动修改UPSERT语句的情况下迭代修改你的表。你可以用模块化的方式编写你的SQL,并使用参数化查询或dbt提供的本地测试功能配置数据测试。它有助于跟踪你的数据依赖性,集中你的数据转换和文档,确保重要的业务指标有一个单一的真实来源。此外,它允许你测试你对数据的假设,以确保数据在生产中发布前的完整性。

dbt云中的并发性问题

你可以通过使用dbt云的slim CI功能,为你的数据测试建立一个持续集成和持续交付(CI/CD)管道。你可以让它连接到你的GitLab或GitHub仓库,并配置测试工作在每个新的拉动请求上被触发。测试工作的状态将直接出现在拉动请求中,以帮助使你的审查过程更有效率。

然而,目前的dbt Cloud CI/CD流程有几个问题。首先,dbt云CI/CD流程目前一次只允许一个作业,如果有多个拉动请求合并到生产中,这可能会减慢部署速度。这对于只有一两个活跃的dbt贡献者的小型数据团队来说是可行的,但当我们的分析部门开始扩大规模,分析师开始更频繁地在dbt中贡献和部署时,它就显示出其局限性。对于一个大尺寸的数据部署,它可以使所有其他的部署慢上一整天。

此外,当拉动请求中有多个提交时,dbt云测试不能自动取消多余的工作流程,这会影响分析开发的测试速度。

如何使用CircleCI来并行运行dbt测试并启用自动取消功能

通过使用CircleCI、dbt和Snowflake,针对生产数据运行并行的dbt测试和自动取消冗余的工作流程是可行的。在一个较高的水平上,步骤是

  1. 为 dbt CI 工作创建一个 dbt 配置文件,以验证你的数据模型和测试。
  2. 配置 dbt 来设置自定义模式,以允许拉动请求在各自的容器中运行数据模型和数据测试。
  3. 在CircleCI中设置一个Python环境,为dbt测试做准备。
  4. 在CircleCI中设置dbt运行和测试,以测试修改后的数据文件。

创建一个dbt配置文件

首先,在profiles.yml ,配置一个dbt-ci配置文件。

circleci:
    # use user and password auth
    type: snowflake
    account: "nxa13674.us-east-1"
    user: "{{ env_var('DBT_DATA_MODELING_SNOWFLAKE_USER', 'not_set') }}"
    password: "{{ env_var('DBT_DATA_MODELING_SNOWFLAKE_PASSWORD', 'not_set') }}"
    role: "{{ env_var('DBT_DATA_MODELING_SNOWFLAKE_ROLE', 'not_set') }}"
    database: "{{ env_var('DBT_DATA_MODELING_SNOWFLAKE_DATABASE', 'not_set') }}"
    warehouse: "XSMALL_WAREHOUSE"
    schema: "public"
    query_tag: "circleci_dbt"

之后,进入CircleCI组织设置页面,设置一个CircleCI上下文,以安全地共享项目中的环境变量。该上下文被命名为dbt-ci-cd ,因此你可以在CircleCI YAML文件中引用它。

Setting up a context

在dbt中设置自定义模式

接下来,设置一个dbt自定义模式宏,以允许拉动请求在容器化环境中运行数据模型和数据测试。

  1. 在你的dbt项目的根目录下创建macros/get_custom_schema.sql ,以定制模式配置。
  2. get_custom_schema.sql 文件中复制并粘贴下面的代码。
{% macro generate_schema_name(custom_schema_name, node) -%}

   {%- set default_schema = target.schema -%}
   {%- if target.name == "circleci" -%}
       {# replace everything except letter and number in branch name to be underscore#}
       {% set re = modules.re %}
       {% set git_branch = modules.re.sub('[^a-zA-Z0-9]', '_', env_var('CIRCLE_BRANCH')).lower() %}
       {%- if custom_schema_name is none -%}
           z_pr_{{ git_branch }}_{{ default_schema }}
       {%- else -%}
           z_pr_{{ git_branch }}_{{default_schema}}_{{ custom_schema_name | trim }}
       {%- endif -%}
   {%- else -%}
       {%- if custom_schema_name is none -%}
           {{ default_schema }}
       {%- else -%}
           {{ custom_schema_name | trim }}
       {%- endif -%}
{%- endmacro -%}       

它将在CircleCI CI过程中建立dbt数据模型,其标准模式格式为z_pr_<the branch name>_<default schema> ,以容器化CI过程中产生的数据模型。

配置你的CircleCI管道来测试dbt数据

最后,为dbt配置CircleCI。

CircleCI的工作流程被定义在dbt项目根目录下的YAML文件 .circleci/config.yml 。默认情况下,CircleCI会在每次提交被推送到你的版本库时自动触发测试过程,或者可以手动触发。以下是设置该过程的步骤。

  1. 在你的dbt项目的根目录下创建.circleci/config.yml
  2. 复制并粘贴下面的YAML来设置你的dbt CI流程。我们在CircleCI使用Poetry来管理我们的Python依赖性,但你可以使用你喜欢的任何Python依赖性管理工具。dbt CI流程使用dbt的state:modified运行方法,只使用生产环境运行和测试修改过的dbt数据模型。
commands:
 setup-python-dependencies:
   description: Setup the python environment for testing and linting
   steps:
     - checkout:
         path: ~/project
     - restore_cache:
         keys:
           - v1-poetry-cache-{{ arch }}-{{ .Branch }}-{{ checksum "poetry.lock" }}
           - v1-poetry-cache-{{ arch }}-{{ .Branch }}
           - v1-poetry-cache
     - run: echo "export PATH=$HOME/.poetry/bin:$PATH" >> $BASH_ENV
     - run: curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python -
     - run: poetry install
     - save_cache:
         key: v1-poetry-cache-{{ arch }}-{{ .Branch }}-{{ checksum "poetry.lock" }}
         paths: /virtualenvs

jobs:
  dbt-build-ci:
	executor: python
	steps:
  	- setup-python-dependencies
  	- run: poetry run dbt deps --project-dir resources
  	- run:
      	name: compile dbt manifest in master branch
      	# use --target prod so the --defer will work correctly
      	command: |
        	git checkout master
        	poetry run dbt debug --project-dir resources --target prod
        	poetry run dbt compile --project-dir resources --target prod
        	mv resources/target/manifest.json .
  	- run: git checkout ${CIRCLE_BRANCH}
  	# separate run and test because "dbt build" will fail all downstream if upstream tests fail. We still want to see all tests results if the test failure is from production
  	# currently there is a version bug with state:modified.body, we will add state:modified.body back once we update dbt to be 1.0.4;
  	- run: poetry run dbt run --models state:modified --defer --state ~/project --exclude tag:skip-ci --project-dir resources -x
  	- run: poetry run dbt test --models state:modified --defer --state ~/project --exclude tag:skip-ci --project-dir resources

workflows:
  commit:
  	- dbt-build-ci:
      	context: dbt-ci-cd
      	filters:
        	branches:
          	ignore:
            	- master

在你的CI/CD管道中运行平行的dbt测试

一旦你推送你的变化到你的版本控制工具,CircleCI将自动为你启动测试过程。单个任务可以并行运行。

Tasks running in parallel

现在,你有一个成功的构建!

Build success

总结

您已经成功地在持续集成管道中设置了一个数据测试工作流程当你的数据团队开始扩大规模时,在发布到生产之前测试你的数据变化是一个重要的步骤。它可以帮助数据团队更快地进行迭代,并确保利益相关者对数据的信任。在持续集成管道中运行数据模型测试可以帮助你的数据团队扩展其工程和分析过程。