AnketのAurora MySQLのVPCを引っ越しました

Anket はSlack でアンケートをとるためのサービスです。

hatappi.slack.com

今回やったこと

Aurora MySQLVPC を移行しました。

というのもAnket は EKS を使って k8s 上にアプリケーションを構築しているのですが、Redis と DB を AWS のサービスを利用しています。
ただもともと Anket 以外もサービスを作っていた時の名残で DB が別 VPC にある状態でした。

※ イメージ図 f:id:hatappi1225:20190211152112p:plain

このままでもサービスは稼働していたのですが、EKS や Redis がある VPC は Terraform でコード管理されていたのですが、 Aurora MySQL がある VPC は手で作ったやつなので、この機会に整理しようと思いました。

今回の流れ

  1. Terraform で 移行先の VPC に新しい Aurora MySQL をたてる
  2. データを移行元から移行する

処理としてはざっくりこんな感じです。
Aurora のクローン機能を使えば移行元の VPCクラスターのクローンを移行先に作って実現もできそうすが、今回はAWSの提供する Database Migration Service を使ってみたかったというのがあります。
AWS サービス多すぎて使う少しでも使う機会がある時に使わないとずっと使わずに終わりそうw

Terraform で移行先に 新しい Aurora MySQL を作成

Terraform で module をこんな感じで作成しました。

locals {
  prefix = "anket-${var.env}"
}

resource "aws_rds_cluster" "aurora_cluster" {
  cluster_identifier              = "${local.prefix}-cluster"
  engine                          = "aurora-mysql"
  database_name                   = "${var.db_name}"
  master_username                 = "${var.db_username}"
  master_password                 = "${var.db_password}"
  skip_final_snapshot             = true
  port                            = "3306"
  vpc_security_group_ids          = ["${var.sg_ids}"]
  db_subnet_group_name            = "${aws_db_subnet_group.aurora_subnet_group.name}"
  db_cluster_parameter_group_name = "${aws_rds_cluster_parameter_group.default.name}"

  tags {
    Product = "Anket"
    Env     = "${var.env}"
  }
}

resource "aws_rds_cluster_instance" "aurora_cluster_instance" {
  count                   = "${var.instance_count}"
  identifier              = "${local.prefix}-${count.index}"
  cluster_identifier      = "${aws_rds_cluster.aurora_cluster.id}"
  engine                  = "aurora-mysql"
  instance_class          = "${var.instance_type}"
  db_subnet_group_name    = "${aws_db_subnet_group.aurora_subnet_group.name}"
  db_parameter_group_name = "${aws_db_parameter_group.default.name}"
  monitoring_role_arn     = "${aws_iam_role.rds_monitoring_role.arn}"
  monitoring_interval     = 60

  tags {
    Product = "Anket"
    Env     = "${var.env}"
  }
}

resource "aws_db_subnet_group" "aurora_subnet_group" {
  name        = "${local.prefix}-${var.vpc_id}"
  description = "Created from terraform"
  subnet_ids  = ["${var.subnet_ids}"]

  tags {
    Product = "Anket"
    Env     = "${var.env}"
  }
}

resource "aws_db_parameter_group" "default" {
  name   = "${local.prefix}-instance"
  family = "aurora-mysql5.7"

  tags {
    Product = "Anket"
    Env     = "${var.env}"
  }
}

resource "aws_rds_cluster_parameter_group" "default" {
  name   = "${local.prefix}-cluster"
  family = "aurora-mysql5.7"

  tags {
    Product = "Anket"
    Env     = "${var.env}"
  }

  parameter {
    name         = "time_zone"
    value        = "Asia/Tokyo"
    apply_method = "immediate"
  }
}

resource "aws_iam_role" "rds_monitoring_role" {
  name = "${local.prefix}-rds-monitoring"
  path = "/"

  assume_role_policy = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "monitoring.rds.amazonaws.com"
      },
      "Effect": "Allow"
    }
  ]
}
POLICY
}

resource "aws_iam_role_policy_attachment" "rds_monitoring_policy_attachment" {
  role       = "${aws_iam_role.rds_monitoring_role.name}"
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole"
}

データの移行

データの移行には今回は Database Migration Service (DMS) を使ってみました。
DMS 自体は2016年頃に正式リリースされたサービスでオンプレやEC2上にたてたデータベースをRDSでたてたデータベースへ移行できるサービスです。
面白いのはMySQL から MySQL のような同種のエンジンだけでなく Schema Conversion Tool を使えば Orace から MySQL のような異種のエンジンへの移行も出来るみたいです。

今回は Aurora MySQL から Aurora MySQL への移行です。

DMS 自体の全体像です。

https://docs.aws.amazon.com/ja_jp/dms/latest/userguide/images/datarep-Welcome.png 引用: https://docs.aws.amazon.com/ja_jp/dms/latest/userguide/Welcome.html

真ん中にあるレプリケーションインスタンスが 移行元からデータをもってきてフォーマットしたのちに 移行先にロードしてくれます。

DMS をはじめるにはまずこのレプリケーションインスタンスを作成して、その後に 移行元と移行先の指定を行います。

f:id:hatappi1225:20190211160112p:plain

上の画像にのせたものがその移行元と移行先を指定する画面ですが、 RDS DB インスタンスの選択というチェックボックスがありますが、これをチェックすると selectbox で RDS で管理している一覧がでてくるので、それを選択すればパスワード以外は補完してくれます!

あとはタスクと呼ばれるログの記録要件やエラー処理やスキーマの指定などを行います。
基本デフォルトですむのですが、移行元からどうやってデータを移行するかの選択だけは行いました。

f:id:hatappi1225:20190211162209p:plain

一番上が一度移行元のデータをレプリケーションするものです。
これを選択した場合ロードが完了した後にデータに変更があっても移行先にはレプリケートされません。
そのため今回は「既存のデータを移行して、継続的な変更をレプリケートする」を選択しました。

ただ継続的な変更をレプリケートする場合、今回 Aurora MySQL を使用しているのでバイナリロギングを有効にする必要がありました。

docs.aws.amazon.com

ドキュメントを参考にパラメータグループから binlog_formatbinlog_checksum を設定しました。
binlog_checksum は dynamic ですが binglog_format は static なのでリブートする必要がありました。。。
ここでダウンタイムが3, 4分おきてしまいました。

無事 DMS の設定ができると次の画像のようになります。

f:id:hatappi1225:20190211163120p:plain

試しにデータを移行元に INSERT すると移行先にも INSERT されます!
パラメータグループの設定で少し時間をくってしまいましたが、 DMS の設定自体は数分で設定できました。

後はタイミングをみて Rails が参照する先を切り替えてあげれば完了です。

最後に

今回は Aurora MySQLVPC を機会に DMS を使ってみました。 binlog_format を有効にするためのリブート以外はダウンタイムはほぼなしで移行できました。

DMS を使ったコストですが料金表 を見るとレプリケーションインスタンス、ストレージ、データ転送ですが、レプリケーションインスタンス自体は多分無料??

f:id:hatappi1225:20190211163644p:plain

データベースを Amazon AuroraAmazon Redshift、または Amazon DynamoDB に移行する場合は、DMS を無料で 6 か月間利用できます。

ってドキュメントに書いてあった。