使用DMS向Redshift Serverless复制数据所需要的IAM Role

更新了Redshift加载IAM Role的说明

一、背景

在使用DMS向Redshift Serverless复制数据的过程中,添加Redshift Serverless为Target Endpoint,然后按下测试按钮,此时后收到报错:

Role 'dms-access-for-endpoint' is not configured properly.

根据有关文档,配置完成这个IAM Role后,开始Redshift复制任务,又会遇到错误,在DMS生成的CloudWatch日志中,出现如下错误:

2023-10-31T15:12:44 [TARGET_LOAD     ]E:  RetCode: SQL_ERROR  SqlState: XX000 NativeError: 30 Message: [Amazon][Amazon Redshift] (30) Error occurred while trying to execute a query: [SQLState XX000] ERROR:  exception name : UnauthorizedException, error type : 135, message: The requested role arn:aws:iam::1xxxxxxx:role/dms-access-for-endpoint is not associated to cluster, should retry : 0 DETAIL:     -----------------------------------------------   error:  exception name : UnauthorizedException, error type : 135, message: The requested role arn:aws:iam::133129065110:role/dms-access-for-endpoint is not associated to cluster, should retry : 0   code:      30000   context:      query:     409714[child_sequence:1]   location:  xen_aws_credentials_mgr.cpp:422   process:   padbmaster [pid=1073955240]   -----------------------------------------------  [1022500]  (ar_odbc_stmt.c:5007)

如何让DMS能够正确的连接到Redshift Serverless?

二、网络环境、IAM和Redshift集群准备

1、DMS加载到Redshift原理

这里涉及一个相当炸裂的事情,DMS写入Redshift并非是靠JDBC方式通过SQL写入数据,而是通过将原始数据导出为CSV格式文件,保存在一个临时S3存储桶上。然后,DMS通过ODBC连接到Redshift,再使用IAM Role的方式从S3加载数据,完成向DMS的复制。复制完成后,临时存储桶清空。这个过程,在官网文档中有描述,在DMS执行Redshift任务的日志(通过CloudWatch Loggroup)也可以看到。

因此,整个配置和排错过程,也就是围绕这个数据加载流程进行。

2、DMS和Redshift的网络设计

VPC设计:

  • 本VPC包括Public Subnet和Private Subnet
  • 本VPC的Private Subnet的路由表包含0.0.0.0/0去往NAT Gateway的路由,可以正常访问外部网络
  • 本VPC创建了S3 Gateway Endpoint,位于Private Subnet
  • 创建一个名叫dms-redshift的安全组,入站规则允许myself的所有流量 All traffic入站,允许去往0.0.0.0/0出站

Redshift的网络设计:

  • Redshift Serverless关闭了Public Access
  • Redshift Serverless打开了Enhanced VPC Access
  • Redshift Serverless创建时候选择了本VPC的私有子网,没有选择公有子网
  • 绑定dms-redshift的安全组

Redshift Serverless的网络配置部分,在Workgroup设置中可以看到。如下截图。

DMS复制实例的网络设计:

  • DMS的Subnet Group创建在Private Subnet私有子网,且与Redshift位于同一个Private Subnet
  • DMS关闭了Public Access
  • 绑定dms-redshift的安全组

在满足以上情况下,继续IAM配置。

3、DMS所需要的IAM Role和IAM Policy

请进入IAM,新建一个Role,取名为dms-access-for-endpoint。请注意这里必须用这个名字,这个是DMS向Redshift复制时候的限制。可参考本文末尾的文档即可看到这个限制。

为本IAM Role加入如下策略,可使用Inline策略,也可以预先编辑一个策略:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "ec2:CreateNetworkInterface",
                "ec2:DescribeAvailabilityZones",
                "ec2:DescribeInternetGateways",
                "ec2:DescribeSecurityGroups",
                "ec2:DescribeSubnets",
                "ec2:DescribeVpcs",
                "ec2:DeleteNetworkInterface",
                "ec2:ModifyNetworkInterfaceAttribute"
            ],
            "Effect": "Allow",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:CreateBucket",
                "s3:ListBucket",
                "s3:DeleteBucket",
                "s3:GetBucketLocation",
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject",
                "s3:GetObjectVersion",
                "s3:GetBucketPolicy",
                "s3:PutBucketPolicy",
                "s3:GetBucketAcl",
                "s3:PutBucketVersioning",
                "s3:GetBucketVersioning",
                "s3:PutLifecycleConfiguration",
                "s3:GetLifecycleConfiguration",
                "s3:DeleteBucketPolicy"
            ],
            "Resource": "arn:aws:s3:::dms-*"
        }
    ]
}

创建名为dms-access-for-endpoint的IAM Role之后,为本角色设置Trust relationships。如下截图。

策略如下。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "dms",
            "Effect": "Allow",
            "Principal": {
                "Service": "dms.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        },
        {
            "Sid": "redshift",
            "Effect": "Allow",
            "Principal": {
                "Service": "redshift.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        },
        {
            "Sid": "redshiftserverless",
            "Effect": "Allow",
            "Principal": {
                "Service": "redshift-serverless.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

保存完成。

需要注意的是,创建DMS的Target Endpoint和DMS Task时候,都不会提示选择IAM Role。因此这个IAM Role是个前置条件。

4、为Redshift Serverless添加IAM Role

进入Redshift Serverless的Namespaces配置界面,找到其中的安全和加密Security and encryption标签栏,点击进入。如下截图。

点击编辑按钮,确认上一步创建的IAM Role被绑定上。一个Redshift Serverless集群可以同时绑定多个IAM Role。绑定后,需要3-5分钟生效。生效后界面上显示为绿色的In-sync字样。如下截图。

至此准备完成。

三、配置DMS任务

1、将Redshift Serverless填写到DMS Target Endpoint

如果希望将数据写入DMS的Dev库(Schema),那么在Endpoint配置位置按照如下截图填写。

2、测试DMS Target Endpoint连接

这样即可将数据写入DEV Schema中。

在按照以上方式配置了Redshift和DMS后,测试连接即可成功。

3、在Redshift Serverless上创建Schema和表结构

为了确保数据一致,在目标库上手工创建表结构,这样避免DMS自动识别表结构转换不准确,发生数据类型不一致的问题。

由于Redshift的结构是 数据库 -> Schema -> 表 的三级关系,因此前文步骤在DMS Target Endpoint的配置中,输入的数据库是Redshift默认的dev

如果源站是MySQL,例如数据库是demo1,因为MySQL没有Schema概念,因此对等到Redshift上,还需要在dev库下新建Schema demo1。使用如下语句创建。

create schema demo1;

然后就是在Redshift使用建表语句,正常创建table即可。

4、创建任务

启动一个新的DMS任务,DMS Task配置与普通非Serverless的数据库配置方式是一样的。

在处理目标库的表时候,当重启任务的时候,为了保持数据一致,一般可选择Truncate清空现有表,但是保持表结构。如下截图。

这里展开讲解:如果选择第一个选项Do nothing,那么重启任务后,目标库上的数据可能会出现重复条目。如果选择Drop tables on target,那么目标库的表在重启任务时候会被删除,同时其数据库用户权限也会丢失。然后重启任务,由DMS自动创建表。此时,DMS会根据源表的Schema自行转换格式建表 —— 由此有相当概率转换不准确,造成字段类型不匹配。因此对于手工创建了目标表确保字段一致性的场景,目标库被Drop是很不利的。因此这就是为什么这里推荐选择Truncate

由于目标库是Redshift,属于OLAP数据库,因此批量加载性能更好。在创建DMS任务时候,要选中batch批处理的选项,这样可优化加载性能。如下截图。

在选择要复制的源库上的表这一步,不要使用默认的通配符%,因为这样会把源库的系统库例如mysql等都复制过来,造成大量错误。这里需要精确的输入源库上要复制的库和表的名字。例如输入demo1数据库下cdcdata表。如下截图。

创建任务完毕。

5、启动任务

如果之前配置有错误,那么可以选择Restart重启,主要不要选择恢复Resume,要选择Restart重启。

当任务启动成功后,即可在Redshift Serverless的名为Dev的Schema下看到MySQL上的demo1的数据库,其中的表正常被同步过来。

6、查看DMS日志

DMS的日志分成:

  • Task:任务管理:
  • Source Unload:从源库读取
  • Target Load:目标库写入

等几个步骤。分步骤查看,即可看到错误是来自哪里。从DMS的任务控制台界面,即可跳转到CloudWatch的Loggroups界面。如下截图。

至此DMS复制到Redshift Serverless运行正常。

四、参考文档

Using AWS DMS with Amazon Redshift Serverless as a Target

https://docs.aws.amazon.com/dms/latest/userguide/CHAPTarget.Redshift.html#CHAPTarget.Redshift.RSServerless

How can I troubleshoot connectivity failures and errors for an AWS DMS task that uses Amazon Redshift as the target endpoint?

https://repost.aws/knowledge-center/dms-redshift-connectivity-failures

The migration task failed with the error role/dms-access-for-endpoint is not associated to cluster

https://stackoverflow.com/questions/77116459/dms-task-to-migrate-from-aurora-postgresql-to-redshift