
こんにちは、最近気になっている哺乳類はオリンギートな、開発部の塩崎です。
私の所属しているMarketingAutomationチームではRealtimeMarketingシステムの開発運用を行っております。
このシステムはZOZOTOWNのユーザーに対してメールやLINEなどのコミュニケーションチャンネルを使い情報の配信を行うものです。
メルマガの配信数や開封数などの数値は自動的に集計され、BIツールであるRedashによってモニタリングされています。
このRedashは社内PCによってホスティングされていましたが、運用面で辛い部分が多々あったためパブリッククラウドに移行しました。
移行先のクラウドはawsを選択し、RedashをホスティングするためのサービスはECS on Fargateを選択しました。
この記事ではawsに構築した環境や、移行作業などを紹介します。
移行前のRedashがどのような環境でホスティングされていたのかを説明します。

Windows10の物理マシンがあり、そのなかにコンテナ管理ツールのPortainerが入っています。
RedashのwebサーバーやRedashを動作させるためのミドルウェアなどはすべてDockerコンテナの中で動いており、その管理をPortainerに任せています。
Redashのデータソースは主に2種類あり、それはBigQueryとPuredataです。
BigQueryはGoogle製の完全にマネージドなDWHです。
BigQueryとの接続にはRedashがデフォルトで用意しているインテグレーション機能を使用しています。
一方、PuredataはIBM製のDWHアプライアンスです。
こちらはRedashとのインテグレーションが用意されていません。
そのため、我々のチームでPuredataと接続するためのゲートウェイを作成し、Redashとの接続に使用しています。
Puredataに接続するためのインタフェースとしてIBMからJDBCドライバーが提供されています。
しかし、RedashはPythonで実装されており、JDBCドライバーを直接読み込むことができません。
何らかの仕組みでPythonとJavaの変換が必要です。
ですので、Py4Jを使いPythonからJavaのメソッドを呼ぶことでRedashからPuredataに接続しています。
参考:
RedashとBigQueryのインテグレーション機能
上記で説明したような構成のRedashにはいくつかの問題がありました。
主には物理マシンの管理が面倒という内容です。
物理マシンが落ちた時の復旧が手動
何らかの原因で物理マシンが落ちたときには、物理マシンが置いてある場所まで行き、手動で起動をするという運用が必要になってしまっていました。
ビルの法定停電の時にマシンの電源を落とす必要がある
ビルの法定停電の時には停電前に電源を落とし、停電から復旧した後に正常に動作するかどうかを確認する運用が必要になっていました。
次にawsに構築したRedashの紹介をします。

Redashの動作に必要なミドルウェアはPostgerSQLとRedisです。
これらはawsのフルマネージドサービスであるRelational Database Service(RDS)とElastiCacheでホスティングすることによって、管理コストを下げました。
RedashとPuredataGatewayのDockerイメージはElastic Container Registry(ECR)で管理されており、ECSはここからdocker pullを行います。
DockerhubでホスティングされているRedash公式のDockerイメージを使わない理由は、Puredataに対応させるために独自のパッチを当てているためです。
次にコンテナ間通信について説明します。
RedashとPuredataGatewayの間はPy4JによるTCP通信をさせる必要があります。
しかしPuredataGatewayコンテナのIPアドレスは起動するごとに変化するので、Redashのコンテナの中にIPアドレスをハードコーディングすることはできません。
Redash workerコンテナがPuredataGatewayコンテナのIPアドレスを取得する仕組みが必要です。
NLBを使うことはその1つの解決策ですが、今回は最近東京リージョンでも使えるようになったRoute53 Auto Namingで実現しました。
これはコンテナの起動・終了のタイミングでDNSのAレコードの値が自動的に増減する仕組みです。
Redash側からPuredataGatewayに接続するときにはこのAレコードを参照すれば、現在アクティブなPuredataGatewayのIPアドレスを得ることができます。
NLBではなくAutoNamingを利用した主な理由はロードバランサーを入れないほうが全体の構成がシンプルになるためです。
これらのインフラ構成はすべてCloudFormationで管理されています。
これ以降でインフラ構成を説明するときにはCloudFormationのテンプレートファイルを使って説明します。
また、これらのサービスの監視はDatadogで行っています。
RDSとElastiCacheはaws integrationでメトリクスの収集を行っています。
そして、コンテナのメトリクスの収集はDatadog Agentのサイドカーコンテナを配置することで行っています。
FargateとDatadogの連携に関する設定はこの下で詳しく説明します。
今回のRedashホスティングにFargateを選定した理由を説明します。
まず、Redashを動作させるためのDockerイメージが公式から提供されているので、それを使うことを考えました。
その場合、何かしらの仕組みでコンテナのオーケストレーションを行う必要があります。
マーケティングオートメーションチームは既にawsでのサービスの開発・運用実績がありましたので、パブリッククラウドとしてawsを選択しました。
awsでDockerのオーケストレーションをしてくれるマネージドサービスはECSとEKSがあります。
EKSはDocker界隈で最近ますます存在感を増しているkubernatesのマネージドサービスです。
ですが、コントロールプレーンのみがマネージドであり、ワーカーノードの管理は自分たちで行う必要があります。
今回は可能な限りインフラの管理をawsに任せたいという思いがあったため、ECS on Fargateを選択しました。
ここからは今回構築したRedash環境の詳細をCloudFormationのテンプレートファイルを交えながら説明していきます。
RDS(PostgreSQL) + ElastiCache(Redis)
まずは、Redashが必要としているミドルウェアであるPostgreSQLとRedisを構築します。
どちらともawsによるマネージドサービスが提供されているので、RDSとElastiCacheを使うことにしました。
今回は高いSLOが求められないので、値段を優先して一番安いインスタンスを使ったシングルAZ構成で構築しました。
たとえシングルAZ構成でも、 OSのセキュリティパッチやデータベースのバックアップはaws側がやってくれます。
そのため、Redash公式のdocker-composeを使った構成よりも管理コストが低いです。
また、可用性を高めるためこれをマルチAZ構成にすることも比較的容易です。
Resources:
RDSDBParameterGroupForRedash:
Type: 'AWS::RDS::DBParameterGroup'
Properties:
Description: 'rds parameter group for redash'
Family: 'postgres9.6'
RDSDBSubnetGroupNameForRedash:
Type: "AWS::RDS::DBSubnetGroup"
Properties:
DBSubnetGroupDescription: 'rds subnet group for redash'
DBSubnetGroupName: redash-rds-subnet-group
SubnetIds:
- !Ref EC2SubnetApplicationPrivateAZ1
- !Ref EC2SubnetApplicationPrivateAZ2
EC2SecurityGroupRDSRedash:
Type: 'AWS::EC2::SecurityGroup'
Properties:
GroupName: redash-rds-security-group
GroupDescription: 'rds security group for redash'
VpcId: !Ref EC2VPC
SecurityGroupIngress:
- SourceSecurityGroupId: !Ref EC2SecurityGroupECSRedash
FromPort: 5432
ToPort: 5432
IpProtocol: 'tcp'
RDSForRedash:
Type: 'AWS::RDS::DBInstance'
Properties:
Engine: 'postgres'
EngineVersion: '9.6'
AutoMinorVersionUpgrade: true
DBInstanceClass: 'db.t2.micro'
DBParameterGroupName: !Ref RDSDBParameterGroupForRedash
BackupRetentionPeriod: 7
StorageType: 'gp2'
AllocatedStorage: 20
MultiAZ: false
AvailabilityZone: !Ref AZ1
PubliclyAccessible: false
DBSubnetGroupName: !Ref RDSDBSubnetGroupNameForRedash
VPCSecurityGroups:
- !Ref EC2SecurityGroupRDSRedash
MasterUsername: !Ref RDSForRedashMasterUsername
MasterUserPassword: !Ref RDSForRedashMasterUserPassword
PreferredBackupWindow: '15:00-17:00'
PreferredMaintenanceWindow: 'Sat:17:00-Sat:19:00'
ElastiCacheSubnetGroupForRedash:
Type: 'AWS::ElastiCache::SubnetGroup'
Properties:
CacheSubnetGroupName: redash-redis-subnet-group
Description: 'redis subnet group for redash'
SubnetIds:
- !Ref EC2SubnetApplicationPrivateAZ1
- !Ref EC2SubnetApplicationPrivateAZ2
EC2SecurityGroupRedashRedis:
Type: 'AWS::EC2::SecurityGroup'
Properties:
GroupName: redash-redis-security-group
GroupDescription: 'redis security group for redash'
VpcId: !Ref EC2VPC
SecurityGroupIngress:
- SourceSecurityGroupId: !Ref EC2SecurityGroupECSRedash
FromPort: 6379
ToPort: 6379
IpProtocol: 'tcp'
ElastiCacheParameterGroupForRedash:
Type: 'AWS::ElastiCache::ParameterGroup'
Properties:
CacheParameterGroupFamily: 'redis4.0'
Description: 'Redash Redis'
ElasticacheClusterForRedash:
Type: 'AWS::ElastiCache::CacheCluster'
Properties:
ClusterName: 'redash-redis'
Engine: 'redis'
EngineVersion: '4.0.10'
AutoMinorVersionUpgrade: true
CacheNodeType: 'cache.t2.micro'
NumCacheNodes: 1
CacheParameterGroupName: !Ref ElastiCacheParameterGroupForRedash
PreferredAvailabilityZone: !Ref AZ1
CacheSubnetGroupName: !Ref ElastiCacheSubnetGroupForRedash
VpcSecurityGroupIds:
- !GetAtt EC2SecurityGroupRedashRedis.GroupId
Port: 6379
次にECS on FargateでRedashをホスティングする部分を説明します。
今回は以下のようにサービスを分割しました。
PuredataGatewayはPy4JでPythonとJavaの間を取り持つコンテナなので、分離されているのは自然です。
一方でRedash系の2つが分離されているのは違和感ある人がいるかもしてないので、理由を説明します。
Redash ServerはRedashのweb UIをホスティングしているwebサーバーで、このサービスが直接クエリの実行することはありません。
クエリの実行を担うのはRedash Workerの方です。
これらの間は非同期ジョブライブラリのCeleryによってクエリのやり取りが行われています。
なお、Celeryによって作られるジョブキューの実体はRedisのリストです。
そしてクエリの実行結果はPostgreSQLに書き込まれ、それがRedash Serverによって読み出されグラフィカルに表示されます。
クエリの個数が多くなった時にRedash Workerのスケーリングが必要です。
ですので、Redash ServerとRedash Workerの分離を行いました。
今回はECSサービスを3つ作りましたが、まずはRedash ServerとRedash Workerのサービス定義を説明します。
特に注意が必要なポイントは以下の2点で、それぞれ後で説明します。
Resources:
ECSClusterForRedash:
Type: 'AWS::ECS::Cluster'
Properties:
ClusterName: redash
IAMRoleForRedashTaskExecution:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: 'Allow'
Principal:
Service: 'ecs-tasks.amazonaws.com'
Action: 'sts:AssumeRole'
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy'
IAMServiceLinkedRoleForECSRedashService:
Type: 'AWS::IAM::ServiceLinkedRole'
Properties:
AWSServiceName: 'ecs.amazonaws.com'
Description: 'Role to enable Amazon ECS to manage your cluster.'
ECSTaskDefinitionApplication:
Type: 'AWS::ECS::TaskDefinition'
Properties:
Family: redash-server
RequiresCompatibilities:
- 'FARGATE'
Cpu: 1024
Memory: 2048
NetworkMode: 'awsvpc'
ExecutionRoleArn: !GetAtt IAMRoleForRedashTaskExecution.Arn
ContainerDefinitions:
- Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${ECRRepositoryForRedash}:last
Name: 'redash-server'
Command:
- 'server'
Environment:
- Name: 'PYTHONUNBUFFERED'
Value: '0'
- Name: 'REDASH_LOG_LEVEL'
Value: 'INFO'
- Name: 'REDASH_REDIS_URL'
Value: !Sub redis://${ElasticacheClusterForRedash.RedisEndpoint.Address}:${ElasticacheClusterForRedash.RedisEndpoint.Port}/0
- Name: 'REDASH_DATABASE_URL'
Value: !Sub postgresql://redash:${RDSRedashUserPassword}@${RDSForRedash.Endpoint.Address}/redash
- Name: 'REDASH_HOST'
Value: ''
- Name: 'REDASH_WEB_PORT'
Value: '5100'
- Name: 'REDASH_ALLOW_SCRIPTS_IN_USER_INPUT'
Value: 'true'
- Name: 'REDASH_DATE_FORMAT'
Value: 'YY/MM/DD'
- Name: 'REDASH_ADDITIONAL_QUERY_RUNNERS'
Value: 'redash.query_runner.puredata'
- Name: 'REDASH_JAVA_GATEWAY_HOST'
Value: puredata-gateway.redash.internal
Cpu: 1024
Memory: 2048
PortMappings:
- ContainerPort: 5100
HostPort: 5100
Protocol: 'tcp'
LogConfiguration:
LogDriver: 'awslogs'
Options:
awslogs-group: !Ref LogsLogGroupForRedash
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: 'server'
ECSTaskDefinitionWorker:
Type: 'AWS::ECS::TaskDefinition'
Properties:
Family: redash-worker
RequiresCompatibilities:
- 'FARGATE'
Cpu: 1024
Memory: 2048
NetworkMode: 'awsvpc'
ExecutionRoleArn: !GetAtt IAMRoleForRedashTaskExecution.Arn
ContainerDefinitions:
- Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${ECRRepositoryForRedash}:${RedashGithubSHA1}
Name: 'redash-worker'
Command:
- 'scheduler'
Environment:
- Name: 'PYTHONUNBUFFERED'
Value: '0'
- Name: 'REDASH_LOG_LEVEL'
Value: 'DEBUG'
- Name: 'REDASH_REDIS_URL'
Value: !Sub redis://${ElasticacheClusterForRedash.RedisEndpoint.Address}:${ElasticacheClusterForRedash.RedisEndpoint.Port}/0
- Name: 'REDASH_DATABASE_URL'
Value: !Sub postgresql://redash:${RDSRedashUserPassword}@${RDSForRedash.Endpoint.Address}/redash
- Name: 'QUEUES'
Value: 'queries,scheduled_queries,celery'
- Name: 'WORKERS_COUNT'
Value: '10'
- Name: 'REDASH_ADDITIONAL_QUERY_RUNNERS'
Value: 'redash.query_runner.puredata'
- Name: 'REDASH_JAVA_GATEWAY_HOST'
Value: !Sub puredata-gateway.redash.internal
Cpu: 1024
Memory: 2048
LogConfiguration:
LogDriver: 'awslogs'
Options:
awslogs-group: !Ref LogsLogGroupForRedash
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: 'worker'
EC2SecurityGroupECSRedash:
Type: 'AWS::EC2::SecurityGroup'
Properties:
GroupName: redash-ecs-security-group
GroupDescription: 'ecs security group for redash'
VpcId: !Ref EC2VPC
SecurityGroupIngress:
- SourceSecurityGroupId: !Ref EC2SecurityGroupALBExternalRedash
FromPort: 5100
ToPort: 5100
IpProtocol: 'tcp'
ECSServiceRedash:
Type: 'AWS::ECS::Service'
DependsOn:
- IAMServiceLinkedRoleForECSRedashService
- ECSServicePuredataGateway
Properties:
Cluster: !Ref ECSClusterForRedash
DesiredCount: 1
LaunchType: 'FARGATE'
LoadBalancers:
- ContainerName: 'redash-server'
ContainerPort: 5100
TargetGroupArn: !Ref ElasticLoadBalancingV2TargetGroupExternalRedash
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: 'DISABLED'
SecurityGroups:
- !Ref EC2SecurityGroupECSRedash
Subnets:
- !Ref EC2SubnetApplicationPrivateAZ1
- !Ref EC2SubnetApplicationPrivateAZ2
PlatformVersion: '1.2.0'
TaskDefinition: !Ref ECSTaskDefinitionApplication
ECSServiceRedashWorker:
Type: 'AWS::ECS::Service'
DependsOn:
- IAMServiceLinkedRoleForECSRedashService
- ECSServicePuredataGateway
Properties:
Cluster: !Ref ECSClusterForRedash
DesiredCount: 3
LaunchType: 'FARGATE'
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: 'DISABLED'
SecurityGroups:
- !Ref EC2SecurityGroupECSRedash
Subnets:
- !Ref EC2SubnetApplicationPrivateAZ1
- !Ref EC2SubnetApplicationPrivateAZ2
PlatformVersion: '1.2.0'
TaskDefinition: !Ref ECSTaskDefinitionWorker
次にPuredata Gatewayのサービス定義を示します。
基本的にはRedashのサービス定義と変わりませんが、ServiceDiscoveryに関する設定が追加されているのが特徴です。
前述したRedashサービスから接続をしていたpuredata-gatewat.redash.internalのサービスディスカバリはここで行われます。
まず AWS::ServiceDiscovery::PrivateDnsNamespace
リソースによって、 puredata-gateway.redash.internal
というHostedZoneがRoute53に作られます。
そして AWS::ServiceDiscovery::Service
リソースによって、そのHostedZoneの中にマルチバリューAレコードが作られます。
最後に AWS::ECS::Service
リソースのServiceRegistriesプロパティを指定します。
これによって、タスクの起動終了のタイミングでAレコードの値が自動的に書き換わります。
https://docs.aws.amazon.com/Route53/latest/APIReference/overview-service-discovery.html
Resources:
ServiceDiscoveryPrivateDnsNamespaceForPuredataGateway:
Type: "AWS::ServiceDiscovery::PrivateDnsNamespace"
Properties:
Vpc: !Ref EC2VPC
Name: puredata-gateway.redash.internal
ServiceDiscoveryServiceForPuredataGateway:
Type: "AWS::ServiceDiscovery::Service"
Properties:
Name: puredata-gateway
DnsConfig:
NamespaceId: !Ref ServiceDiscoveryPrivateDnsNamespaceForPuredataGateway
DnsRecords:
- Type: 'A'
TTL: 60
HealthCheckCustomConfig:
FailureThreshold: 2
ECSTaskDefinitionPuredataGateway:
Type: 'AWS::ECS::TaskDefinition'
Properties:
Family: puredata-gateway
RequiresCompatibilities:
- 'FARGATE'
Cpu: 1024
Memory: 2048
NetworkMode: 'awsvpc'
ExecutionRoleArn: !GetAtt IAMRoleForRedashTaskExecution.Arn
ContainerDefinitions:
- Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${ECRRepositoryForPuredataGateway}
Name: 'puredata-gateway'
Command: ['command', 'to', 'start', 'puregata gateway']
Cpu: 1024
Memory: 2048
PortMappings:
- ContainerPort: 25333
HostPort: 25333
Protocol: 'tcp'
LogConfiguration:
LogDriver: 'awslogs'
Options:
awslogs-group: !Ref LogsLogGroupForRedash
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: 'puredata-gateway'
EC2SecurityGroupECSPuredataGateway:
Type: 'AWS::EC2::SecurityGroup'
Properties:
GroupName: puredata-gateway-ecs-security-group
GroupDescription: 'ecs security group for puredata gateway'
VpcId: !Ref EC2VPC
SecurityGroupIngress:
- CidrIp: !Ref ApplicationPrivateCidrBlockAZ1
FromPort: 25333
ToPort: 25333
IpProtocol: 'tcp'
- CidrIp: !Ref ApplicationPrivateCidrBlockAZ2
FromPort: 25333
ToPort: 25333
IpProtocol: 'tcp'
ECSServicePuredataGateway:
Type: 'AWS::ECS::Service'
DependsOn: IAMServiceLinkedRoleForECSRedashService
Properties:
Cluster: !Ref ECSClusterForRedash
DesiredCount: 1
LaunchType: 'FARGATE'
ServiceRegistries:
- RegistryArn: !GetAtt ServiceDiscoveryServiceForPuredataGateway.Arn
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: 'DISABLED'
SecurityGroups:
- !Ref EC2SecurityGroupECSPuredataGateway
Subnets:
- !Ref EC2SubnetApplicationPrivateAZ1
- !Ref EC2SubnetApplicationPrivateAZ2
PlatformVersion: '1.2.0'
TaskDefinition: !Ref ECSTaskDefinitionPuredataGateway
Redashをawsに構築するにあたって、これ以外にもALB、ACM、Route53なども使用しましたが、記事が長くなってしまうのでここでは割愛します。
これらのコンテナのメトリクスの監視にはDatadogを使用しています。
Datadogでメトリクスを収集するためには、Datadogのコンテナをサイドカーコンテナとして配置します。
例えば、Redash Serverのコンテナのメトリクスを収集したい場合は、以下のようにコンテナを配置します。
環境変数ECS_FARGATEを true
に指定するだけで、そのタスクに含まれるすべてのコンテナのメトリクスを収集してくれます。
Resources:
ECSTaskDefinitionApplication:
Type: 'AWS::ECS::TaskDefinition'
Properties:
ContainerDefinitions:
- Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${ECRRepositoryForRedash}:last
Name: 'redash-server'
- Image: datadog/agent:latest
Name: 'datadog'
Cpu: 256
Memory: 512
Environment:
- Name: 'DD_API_KEY'
Value: !Ref DatadogAPIKey
- Name: 'ECS_FARGATE'
Value: 'true'
LogConfiguration:
LogDriver: 'awslogs'
Options:
awslogs-group: !Ref LogsLogGroupForRedash
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: 'redash-datadog'
https://www.datadoghq.com/blog/monitor-aws-fargate/
FargateでRedashを構築する最中に感じた、Fargateの利点欠点などをまとめます。
まず真っ先に思い浮かぶFargateの利点はEC2を管理する必要がないということです。
ECS on EC2の構築をするためにはEC2インスタンスを立ち上げ、そこにECSエージェントをインストールする必要があります。
Fargateを使うことによって、そのような一手間をかけること無く、いきなりコンテナをデプロイできるので便利です。
前述したことと少し関連しますが、EC2の管理から解放されたことでスケーリングの時に考慮する必要のある要素が減りました。
スケーリングをするときにはサービスのタスク数だけを変化させればよく、従来のECS on EC2で考える必要のあったEC2インスタンスのスケーリングは不要です。
システムをマイクロサービス化するときにサービスディスカバリの仕組みはほぼ必須です。
Route53のAutoNamingを使うとDNSレベルでのサービスディスカバリができます。
なお、これはFargateの利点というよりもECSの利点です。
Fargateを使った時にはコンテナのデプロイには数分かかってしまいます。
そのため、高速なスケールアウトを期待してFargateを使うとがっかりすることがあるかと思います。
Fargateでは同一タスクに属するコンテナ間の通信をさせるためにはlocalhostを使います。
そのため、同一タスクに属する複数のプロセスが同じポート番号で待受しようとすると、後から待受した方が失敗します。
実際にRedashとDatadog Agentの両方が5000番ポートでlistenをしていたため、Redashのサーバーが立ち上がらないという現象が発生しました。
そのためRedashにパッチを当て、5100番ポートで待ち受けるように修正しました。
CloudFormationのテンプレートで5100番ポートを使ってRedashの待受をしている理由はこれです(伏線回収)
ECS on EC2の場合はjournaldやfluentdにログを流すことができますが、ECS on Fargateではawslogsドライバーのみがサポートされます。
awslogsドライバーが収集したログはCloudWatchLogsに送られます。
そのため、すでに別のログ収集基盤がある場合には、CloudWatchLogsからそちらにログを流す必要があります。
https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_LogConfiguration.html
これは些細な欠点ですが、privilegeモードでDockerを動かすことができないので、例えばDocker in Dockerのような構成にすることはできません。
社内PCでホスティングされていたRedashをawsに移すことによって、Redashの動作に必要なコンポーネントをすべてフルマネージドにできました。
さらにこの設定はすべてCloudFormationで管理されています。
そのため、他のチームがawsにRedashを構築したくなったときにはテンプレートファイルを渡すことで同等の構成を簡単に作ることが出来るようになりました。
弊社ではZOZOTOWNの売上を支えているMarketingAutomationに興味がある方、クラウドを活用して既存の運用を改善することに興味がある方を募集しています。
興味のある方はぜひ以下のリンクからご応募ください。
www.wantedly.com