この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
どーもsutoです。
今回は以前に記事で予告していたとおり、LinkedIn製のOSSデータカタログ「DataHub」をフロントエンド部分はAWS EKSに、それ以外のコンポーネントをAWSマネージドサービスに変更した構成で構築してみたいと思います。
今回のゴール
以前の記事では、全てのコンポーネントをAWS EKSクラスター上に構成した手順で紹介しました。
今回は以下の下側の図のように、Datahubのストレージにあたる部分を各AWSサービスに変更した構成で構築します。
つまり、Frontend部分(WebUIとMetadata Ingection)→EKSに残し、Metadata Store→RDS、Metadata Crawler→Glue schema registry、Elasticsearch→Amazon Opensearch、MAE/MCE機能→Amazon Managed Kafka(MSK)、CLB→ALBに変えます。
前提条件と作業環境の設定について
※作業環境はMacです。
事前に以下のツールをインストールしておく必要があります。Python3については省略させていただきますが、その他はリンク先を参考に実施できると思います。
- Pthon3.6以降の環境をセットアップしておく
- AWS CLIインストールとCredentials,Config設定
- kubectlインストール
brew install kubectl
kubectl version --client
brew tap weaveworks/tap
brew install weaveworks/tap/eksctl
eksctl version
brew install helm
EKSクラスター作成
eksctlコマンドを使用してクラスターを作成します。今回は以下のパラメータで作成します。
- VPC:CIDRを指定して新規作成(10.1.0.0/16)
- クラスター名:datahub-test
- リージョン:ap-northeast-1
- インスタンスタイプ:t3.medium
- ノード数:3
eksctl create cluster \
--vpc-cidr 10.1.0.0/16 \
--name datahub-test \
--region ap-northeast-1 \
--with-oidc \
--node-type t3.medium \
--node-private-networking \
--nodes 3
実行するとCloudformationスタックが実行され、完了後にkubectl get nodes
を実行することで以下のように3ノードが表示されます
% kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-10-1-107-176.ap-northeast-1.compute.internal Ready <none> 3m6s v1.21.5-eks-bc4871b
ip-10-1-152-244.ap-northeast-1.compute.internal Ready <none> 3m10s v1.21.5-eks-bc4871b
ip-10-1-184-243.ap-northeast-1.compute.internal Ready <none> 3m7s v1.21.5-eks-bc4871b
ストレージ部分のリソースを構築
次に以下のCloudformationテンプレートを使って、RDS、OpenSearchクラスター、Glue schema registry、MSKクラスター、関連するSGやIAMロールを作成します。
Parameters:
ProjectName:
Description: ProjectName
Type: String
Default: 'datahub-test'
DBInstanceClass:
Type: String
Default: 'db.t3.small'
DbPassword:
Type: String
Description: Password string for master user of DB Instance
Default: ''
NoEcho: true
KafkaInstanceType:
Type: String
Default: 'kafka.t3.small'
OSSInstanceType:
Type: String
Default: 't3.medium.search'
VPCId:
Type: String
Description: id for VPC.
Default: 'vpc-xxxxxx'
PrimarySubnetId:
Type: String
Description: Private Subnet id 1.
Default: 'subnet-xxxxxx'
SecondarySubnetId:
Type: String
Description: Private Subnet id 2.
Default: 'subnet-xxxxxx'
ThirdSubnetId:
Type: String
Description: Private Subnet id 3.
Default: 'subnet-xxxxxx'
EKSNodeRole:
Type: String
Description: Name of EKS nodegroup IAM Role.
Default: 'eksctl-datahub-nodegroup-ng-NodeInstanceRole-xxxxxxxx'
NodeInstanceSG:
Type: String
Description: EKS nodegroup instances SG id.
Default: 'sg-xxxxxx'
Resources:
DatahubSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub ${ProjectName}-strage-sg
GroupDescription: Enable datahub service instances access
VpcId: !Ref VPCId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '443'
ToPort: '443'
SourceSecurityGroupId: !Ref NodeInstanceSG
- IpProtocol: tcp
FromPort: '3306'
ToPort: '3306'
SourceSecurityGroupId: !Ref NodeInstanceSG
- IpProtocol: tcp
FromPort: '9092'
ToPort: '9092'
SourceSecurityGroupId: !Ref NodeInstanceSG
- IpProtocol: tcp
FromPort: '2181'
ToPort: '2181'
SourceSecurityGroupId: !Ref NodeInstanceSG
- IpProtocol: tcp
FromPort: '9091'
ToPort: '9091'
SourceSecurityGroupId: !Ref NodeInstanceSG
Tags:
- Key: Name
Value: !Sub ${ProjectName}-strage-sg
MyDB:
Type: AWS::RDS::DBInstance
Properties:
AllocatedStorage: '10'
DBInstanceClass: !Ref DBInstanceClass
DBInstanceIdentifier: !Sub ${ProjectName}-mysql
DBSubnetGroupName: !Ref DBSubnetGroup
Engine: MySQL
MasterUsername: 'root'
MasterUserPassword: !Ref DbPassword
StorageType: gp2
VPCSecurityGroups:
- !GetAtt 'DatahubSecurityGroup.GroupId'
#DeletionPolicy: Snapshot
DBSubnetGroup:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupDescription: custom subnet group
SubnetIds:
- !Ref PrimarySubnetId
- !Ref SecondarySubnetId
- !Ref ThirdSubnetId
MSKCluster:
Type: 'AWS::MSK::Cluster'
Properties:
ClusterName: !Sub ${ProjectName}-kafka
KafkaVersion: 2.6.2
NumberOfBrokerNodes: 3
EncryptionInfo:
EncryptionInTransit:
ClientBroker: TLS_PLAINTEXT
BrokerNodeGroupInfo:
BrokerAZDistribution: DEFAULT
InstanceType: !Ref KafkaInstanceType
SecurityGroups:
- Ref: DatahubSecurityGroup
StorageInfo:
EBSStorageInfo:
VolumeSize: 100
ClientSubnets:
- !Ref PrimarySubnetId
- !Ref SecondarySubnetId
- !Ref ThirdSubnetId
GlueSchemaRegistry:
Type: AWS::Glue::Registry
Properties:
Description: 'Datahub schema registry'
Name: !Sub ${ProjectName}-schema-registry
GlueIAMPolicy:
Type: 'AWS::IAM::Policy'
Properties:
PolicyName: !Sub ${ProjectName}-schema-registry-policy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- 'glue:GetRegistry'
- 'glue:ListRegistries'
- 'glue:CreateSchema'
- 'glue:UpdateSchema'
- 'glue:GetSchema'
- 'glue:ListSchemas'
- 'glue:RegisterSchemaVersion'
- 'glue:GetSchemaByDefinition'
- 'glue:GetSchemaVersion'
- 'glue:GetSchemaVersionsDiff'
- 'glue:ListSchemaVersions'
- 'glue:CheckSchemaVersionValidity'
- 'glue:PutSchemaVersionMetadata'
- 'glue:QuerySchemaVersionMetadata'
Resource:
- !Sub arn:aws:glue:*:${AWS::AccountId}:schema/*
- !GetAtt GlueSchemaRegistry.Arn
- Effect: Allow
Action: 'glue:GetSchemaVersion'
Resource: '*'
Roles:
- !Ref EKSNodeRole
OpenSearchServiceDomain:
Type: AWS::OpenSearchService::Domain
Properties:
DomainName: !Sub ${ProjectName}-oss
EngineVersion: 'OpenSearch_1.1'
ClusterConfig:
DedicatedMasterEnabled: true
InstanceCount: '2'
ZoneAwarenessEnabled: true
InstanceType: !Ref OSSInstanceType
DedicatedMasterType: !Ref OSSInstanceType
DedicatedMasterCount: '3'
DomainEndpointOptions:
EnforceHTTPS: true
EBSOptions:
EBSEnabled: true
Iops: '0'
VolumeSize: '30'
VolumeType: 'gp2'
AccessPolicies:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
AWS: '*'
Action: 'es:*'
Resource: '*'
VPCOptions:
SubnetIds:
- !Ref PrimarySubnetId
- !Ref SecondarySubnetId
SecurityGroupIds:
- Ref: DatahubSecurityGroup
※スタック内でOpensearch作成時にBefore you can proceed, you must enable a service-linked role~
のエラーが出たら以下コマンドでサービルリンクロールを事前に作成しましょう。
aws iam create-service-linked-role --aws-service-name es.amazonaws.com
作成したリソースの情報を控えておきます。
- RDSのマスターユーザー名とパスワード
- RDSのエンドポイント(以下を参照)
- MSKクラスターのブートストラップサーバのエンドポイント(テキストプレーン)
- MSKクラスターのzookeeperサーバのエンドポイント(テキストプレーン)
- ※どちらも3エンドポイントをまるごとコピーしてください
- OpensearchのVPCエンドポイント
- ※以下の赤枠の”https://”を除いた部分をコピー
EKSクラスターにALBコントローラーをセットアップ
- コントローラがAWSAPIを呼び出すことができるようにするためのIAMポリシードキュメントをダウンロードします。
curl -o iam_policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.2.0/docs/install/iam_policy.json
- 次のコマンドを実行して、ポリシードキュメントに基づいてIAMポリシーを作成します。
aws iam create-policy \
--policy-name AWSLoadBalancerControllerIAMPolicy \
--policy-document file://iam_policy.json
- eksctlを使用して、上記のポリシーをkubernetesポッドにアタッチできるサービスアカウントを作成します。
eksctl create iamserviceaccount \
--cluster=<<cluster-name>> \
--namespace=kube-system \
--name=aws-load-balancer-controller \
--attach-policy-arn=arn:aws:iam::<<account-id>>:policy/AWSLoadBalancerControllerIAMPolicy \
--override-existing-serviceaccounts \
--approve
- 次のコマンドを実行して、TargetGroupBindingカスタムリソース定義をインストールします。
kubectl apply -k "github.com/aws/eks-charts/stable/aws-load-balancer-controller//crds?ref=master"
- 最新バージョンのALBコントローラーを含むヘルムチャートリポジトリを追加します。
helm repo add eks https://aws.github.io/eks-charts
helm repo update
- 次のコマンドを実行して、コントローラーをkubernetesクラスターにインストールします。
helm upgrade -i aws-load-balancer-controller eks/aws-load-balancer-controller \
--set clusterName=<<cluster-name>> \
--set serviceAccount.create=false \
--set serviceAccount.name=aws-load-balancer-controller \
-n kube-system
- インストールが完了すれば、以下のコマンドで次のような結果が返されるはずです。
% kubectl get deployment -n kube-system aws-load-balancer-controller
NAME READY UP-TO-DATE AVAILABLE AGE
aws-load-balancer-controller 2/2 2 2 142m
Helmを使用してEKSクラスターにDataHubをセットアップ
- DatahubのリポジトリをHelmに追加します。
helm repo add datahub https://helm.datahubproject.io/
- 作成したRDSのパスワードを格納したkubernetesシークレットを作成します。
kubectl create secret generic mysql-secrets --from-literal=mysql-root-password=<RDSのパスワード>
- Helmチャートのvalues.yamlを作成します。各パラメータを以下のようにAWSリソースの情報に書き換えて保存してください。
- 【参考】デフォルト構成はこちら
datahub-gms:
enabled: true
image:
repository: linkedin/datahub-gms
tag: "v0.8.23"
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: instance
alb.ingress.kubernetes.io/inbound-cidrs: 0.0.0.0/0
hosts:
- paths:
- /*
datahub-frontend:
enabled: true
image:
repository: linkedin/datahub-frontend-react
tag: "v0.8.23"
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: instance
alb.ingress.kubernetes.io/inbound-cidrs: 0.0.0.0/0
hosts:
- paths:
- /*
datahub-mae-consumer:
image:
repository: linkedin/datahub-mae-consumer
tag: "v0.8.23"
datahub-mce-consumer:
image:
repository: linkedin/datahub-mce-consumer
tag: "v0.8.23"
datahub-ingestion-cron:
enabled: false
image:
repository: linkedin/datahub-ingestion
tag: "v0.8.23.0"
elasticsearchSetupJob:
enabled: true
image:
repository: linkedin/datahub-elasticsearch-setup
tag: "v0.8.23"
extraEnvs:
- name: USE_AWS_ELASTICSEARCH
value: "true"
kafkaSetupJob:
enabled: true
image:
repository: linkedin/datahub-kafka-setup
tag: "v0.8.23"
mysqlSetupJob:
enabled: true
image:
repository: acryldata/datahub-mysql-setup
tag: "v0.8.23.0"
datahubUpgrade:
enabled: true
image:
repository: acryldata/datahub-upgrade
tag: "v0.8.23.0"
noCodeDataMigration:
sqlDbType: "MYSQL"
global:
graph_service_impl: elasticsearch
datahub_analytics_enabled: true
datahub_standalone_consumers_enabled: false
elasticsearch:
host: "<OpensearchクラスターのVPCエンドポイント>"
port: "443"
useSSL: "true"
kafka:
bootstrap:
server: "<MSKクラスターのbootstrap-server endpoint>"
zookeeper:
server: "<MSKクラスターのzookeeper endpoint>"
## For AWS MSK set this to a number larger than 1
partitions: 3 # MSKクラスタ数と同じにする
replicationFactor: 3 # MSKクラスタ数と同じにする
schemaregistry:
type: AWS_GLUE
glue:
region: ap-northeast-1 # <<region>>
registry: <Glue schema registry name>
sql:
datasource:
host: "<RDSのエンドポイント>:3306"
hostForMysqlClient: "<RDSのエンドポイント>"
port: "3306"
url: "jdbc:mysql://<RDSのエンドポイント>:3306/datahub?verifyServerCertificate=false&useSSL=true&useUnicode=yes&characterEncoding=UTF-8"
driver: "com.mysql.jdbc.Driver"
username: "<RDSのマスターユーザー>"
password:
secretRef: mysql-secrets
secretKey: mysql-root-password
datahub:
gms:
port: "8080"
mae_consumer:
port: "9091"
appVersion: "1.0"
- 以下のコマンドを実行してDatahubをデプロイします。
helm upgrade --install datahub datahub/datahub --values <yamlファイルを保存したフォルダパス>/values.yaml
- デプロイ完了後、podの一覧が以下のようになるはずです。
% kubectl get pods
NAME READY STATUS RESTARTS AGE
datahub-datahub-frontend-6c47c77468-v2hsn 1/1 Running 0 4m23s
datahub-datahub-gms-59dfd97556-9vrsr 1/1 Running 0 4m23s
datahub-datahub-upgrade-job-8xbhc 0/1 Error 0 4m23s
datahub-datahub-upgrade-job-g4qpn 0/1 Completed 0 3m14s
datahub-elasticsearch-setup-job-kj95r 0/1 Completed 0 6m9s
datahub-kafka-setup-job-kwkqs 0/1 Completed 0 6m
datahub-mysql-setup-job-64grv 0/1 Completed 0 4m29s
- デプロイ完了後、Frontendアクセス用とメタデータ取り込み(GMS)用2つのALBが作成されています。
- ※Helmによるデプロイの影響で、同時にCLBも2つ作成されていますが、ALBがあるため不要なので削除して大丈夫です。
-
以下コマンドで確認して「ADDESS」列のFrontend用ALBのエンドポイントを控える
% kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
datahub-datahub-frontend <none> * k8s-default-datahubd-xxxxxxxx.ap-northeast-1.elb.amazonaws.com 80 32h
datahub-datahub-gms <none> * k8s-default-datahubd-xxxxxxxx.ap-northeast-1.elb.amazonaws.com 80 32h
- Frontend用ALBにブラウザでアクセスしてみると以下のようにログイン画面が表示されます。
- デフォルトユーザとパスワード(datahub:datahub)でログインできるはずです。
【おまけ】ALBのアクセスポイントをhttpsにする場合
ALBのアクセスをhttpsで構成したい場合は、Route53やACMなどを利用してパブリックDNSと証明書を用意した上でvalues.yamlのingress部分を以下のように構成してください。
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: instance
alb.ingress.kubernetes.io/certificate-arn: <<certificate-arn>> # ACMで作成した証明書のArnを入力
alb.ingress.kubernetes.io/inbound-cidrs: 0.0.0.0/0
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'
alb.ingress.kubernetes.io/actions.ssl-redirect: '{"Type": "redirect", "RedirectConfig": { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}'
hosts:
- host: <<host-name>> # パブリックDNS名を入力
redirectPaths:
- path: /*
name: ssl-redirect
port: use-annotation
paths:
- /*
まとめ
今回のようにストレージ部分をAWSサービスに外出しする構成にできれば、データベース部分のバックアップがやりやすくなる他、アップデート作業にも対応しやすくなります。最新バージョンを保てればセキュリティ面でも安心できますね。
また、AWS Opensearchに移行できたことで、クラスター内のElasticsearchの日本語プラグインの対応をしなくて済むのも大きなメリットです。
しかしながら、日本語の検索機能をより向上させるには別途インデックスのカスタマイズは必要になるかと思います。