Amazon Web Services ブログ
Amazon EFS を利用して AWS Fargate 上の Amazon EKS でステートフルなワークロードを実行する
この記事は、Running stateful workloads with Amazon EKS on AWS Fargate using Amazon EFS を翻訳したものです。
本投稿は、Container Specialist Solutions Architect の Re Alvarez-Parmar と Sr Technical Account Manager の Vikram Venkataraman により寄稿されました。
Amazon Elastic Kubernetes Service (EKS) では、EC2インスタンスまたは AWS Fargate で Kubernetes ポッドを実行することができます。コンテナ用のサーバーレスコンピューティングエンジンである AWS Fargate を使用すると、サーバーの作成と管理、データプレーンのスケーリング、EC2 インスタンスの適切なサイズ設定、ワーカーノードのアップグレードの処理を行うことなく、Kubernetes ワークロードを実行できます。今のところ Fargate は、ステートレスなコンテナ化されたワークロードを安全で費用対効果の高い方法で実行するのに理想的です。Fargate は VM で分離された環境で各ポッドを実行し、ノードに自動的にパッチを適用するため安全です。Fargate では、ポッド用に構成したコンピューティングリソースに対してのみ課金されるため、費用対効果が高まります。最近リリースされた Amazon Elastic File System (EFS) とのネイティブ統合により、ステートフルな Kubernetes ワークロードを Fargate 上で実行するのに必要な、パズルの欠けている部分が提供されました。
WordPress をサンプルのワークロードとして、この記事では Amazon EFS を使用して Fargate でステートフルな Kubernetes ワークロードを実行する方法を示します。WordPress は、Web サイトやブログを構築するためのオープンソースのコンテンツ管理システム (CMS) です。Fargate の EFS サポートにより、WordPress のようにコンテナファイルシステムの外部にデータを永続化する必要があるアプリケーションを、Undifferentiated Heavy Lifting (サーバーまたはミドルウェアの運用といった、他との差別化につながらない重労働) を行うことなく実行できます。Fargate がサーバーレスコンテナを実行できるのと同様に、EFS はサーバーなしで高可用性、耐久性、およびペタバイト規模のストレージを提供します。
Amazon EFS は、ファイルが追加および削除されると自動的に拡大および縮小する大規模な並列共有アクセスを提供します。複数のコンテナと EC2 インスタンスは、共有 EFS ファイルシステムで読み取り操作と書き込み操作を同時に実行できます。ポッド用の永続ストレージレイヤーを有することで、Fargate はデータ分析、メディア処理、コンテンツ管理、Web サービスなど、低レイテンシー、高スループットかつ書き込み後の読み取り整合性などの機能を必要とする Kubernetes ワークロードに最適化することができます。
Kubernetes におけるステートフルワークロード
コンテナ自体は一時的なものですが、Kubernetes は永続ボリュームをポッドにアタッチすることで、ステートフルワークロードの実行をサポートします。永続ボリュームがアタッチされたポッドは、ポッド自体の生存期間よりも長期保存されるデータを格納することができます。ポッドがクラッシュまたは終了した場合、別のポッドがボリュームに接続し、データを失うことなく作業を再開します。
Kubernetes Container Storage Interface(CSI) は、ステートフルコンテナ化されたアプリケーションを実行するのに役立ちます。CSI ドライバーは、Kubernetes クラスターが永続ボリュームのライフサイクルを管理できるようにする CSI インターフェイスを提供します。Amazon EKS では、次の 3 つの AWS ストレージサービスに CSI ドライバーを提供することで、ステートフルなワークロードの実行を容易にします。
- Amazon EFS (Fargate および EC2 をサポート): ビッグデータ分析、Web サービスとコンテンツ管理、アプリケーションの開発とテスト、メディアとエンターテインメントのワークフロー、データベースのバックアップ、コンテナーストレージに最適な完全マネージド型スケーラブルで伸縮自在なファイルシステムです。EFS は、複数のアベイラビリティーゾーン (AZ) に跨ってデータを冗長的に格納し、Kubernetes ポッドが実行されているAZに関係なく、Kubernetes ポッドからの低遅延アクセスを提供します。
- Amazon EBS (EC2 のみサポート): EC2 インスタンスとコンテナからアクセスできる、あらゆる規模のスループットとトランザクション集約型ワークロードの両方に対応するように設計された、専用ストレージボリュームへの直接アクセスを提供するブロックストレージサービスです。
- FSx for Lustre (EC2 のみサポート): 機械学習、ハイパフォーマンスコンピューティング、ビデオ処理、財務モデリング、電子設計自動化、分析などのワークロード向けに最適化された、完全に管理されたハイパフォーマンスファイルシステムです。FSx for Lustre を使用すると、S3 データリポジトリにリンクされた高性能ファイルシステムをすばやく作成し、S3 オブジェクトにファイルとして透過的にアクセスできます。
現在、Fargate で実行されているポッドは、Amazon EFS を使用してデータを保存できます。Fargate は Amazon EFS CSI ドライバーを自動的にインストールしますが、クラスターに EC2 ノードもある場合は、EFS CSI ドライバーを自分でインストールする必要があります。
Amazon EFS を使用した StatefulSet
Kubernetes では、永続ボリュームと永続ボリューム要求を使用して、永続ストレージをリクエストし、ポッドに関連付けることができます。StatefulSet は、volumeClaimTemplate
を使用してその場でボリュームを作成します。これは動的プロビジョニングと呼ばれ、StatefulSet がポッドを作成するときにオンデマンドでストレージボリュームを作成できるようにします。動的プロビジョニングを使用しない場合は、StatefulSet がポッドを作成する前に、永続ボリュームを手動で作成する必要があります。
EFS による動的プロビジョニングのサポートは開発中であり、ここで機能を確認できます。この機能により、EFS アクセスポイントを介した動的プロビジョニングのサポートが追加されます。EFS CSI ドライバーは、既存の EFS ファイルシステムにアクセスポイントを作成することにより、新しい永続ボリュームをプロビジョニングします。EFS CSI ドライバーは動的プロビジョニングをサポートしていませんが、EFS を使用して StatefulSet のストレージを提供できます。なお、StatefulSet を作成する前に、ボリュームを手動で作成する必要があります。
ソリューション
Amazon EKS クラスターを作成し、Kubernetes が AWS Fargate でポッドを実行できるようにする Fargate プロファイルを作成します。クラスターの準備ができたら、Helm を使用して WordPress をインストールします。これは Application Load Balancer を使用して公開されます。
WordPress ポッドは、AWS リージョン内の 3 つの AZ のいずれかで実行できます。各 AZ のポッドは、その AZ のローカル EFS マウントターゲットを使用して EFS ファイルシステムをマウントします。また、WordPress データベース用の MySQL データベースインスタンスを作成するために、Amazon RDS for MySQL を使用します。
このアーキテクチャでは、(ElastiCache for Memcachedのような) キャッシングレイヤーが無い点に留意してください。必要な場合はこのガイドに従って、Amazon ElastiCache for Memcached で WordPress を高速化する方法を学ぶことができます。
このチュートリアルを完了するには、以下が必要です。
まず、いくつかの環境変数を設定することから始めましょう。
WOF_AWS_REGION=us-west-2 <-- 利用するリージョンに合わせて変更してください
WOF_ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
WOF_EKS_CLUSTER=eks-fargate-stateful
EKS クラスターの作成
EC2 ベースのワーカーノードなしで新しい EKS クラスターを作成します。eksctl
を使用すると、デフォルトの名前空間と kube-system 名前空間のポッドが Fargate で実行される EKS クラスターを簡単に作成することができます。
eksctl create cluster \
--name $WOF_EKS_CLUSTER \
--version 1.18 \
--region $WOF_AWS_REGION \
--fargate
--fargate
オプションを使用すると、eksctl
はポッド実行ロールと Fargate プロファイルを作成して、Fargate で実行できるように coredns
デプロイメントにパッチ適用をします。
VPCID とその CIDR ブロックを環境変数に保存します。
WOF_VPC_ID=$(aws eks describe-cluster --name $WOF_EKS_CLUSTER --query "cluster.resourcesVpcConfig.vpcId" --region $WOF_AWS_REGION --output text)
WOF_CIDR_BLOCK=$(aws ec2 describe-vpcs --vpc-ids $WOF_VPC_ID --query "Vpcs[].CidrBlock" --region $WOF_AWS_REGION --output text)
EFS ファイルシステムの作成
永続ボリュームを作成する前に、EFS ファイルシステムを作成する必要があります。
EFS ファイルシステムを作成します。
WOF_EFS_FS_ID=$(aws efs create-file-system \
--creation-token WordPress-on-Fargate \
--encrypted \
--performance-mode generalPurpose \
--throughput-mode bursting \
--tags Key=Name,Value=WordpressVolume \
--region $WOF_AWS_REGION \
--output text \
--query "FileSystemId")
EFS アクセスポイントを作成します。
WOF_EFS_AP=$(aws efs create-access-point \
--file-system-id $WOF_EFS_FS_ID \
--posix-user Uid=1000,Gid=1000 \
--root-directory "Path=/bitnami,CreationInfo={OwnerUid=1000,OwnerGid=1000,Permissions=777}" \
--region $WOF_AWS_REGION \
--query 'AccessPointId' \
--output text)
EFS アクセスポイントは、共有データセットへのアプリケーションアクセスの管理を容易にする、EFS ファイルシステムへのアプリケーション固有のエントリポイントです。アクセスポイントは、アクセスポイントを介して行われるすべてのファイルシステム要求に対して、ユーザーの POSIX グループを含むユーザー ID を適用できます。また、ファイルシステムに別のルートディレクトリを適用して、クライアントが指定されたディレクトリまたはそのサブディレクトリ内のデータにのみアクセスできるようにすることもできます。EFS セキュリティモデルとコンテナとの連携についてさらに理解するには、Massimo Re Ferre が記した「Developers guide to using Amazon EFS with Amazon ECS and AWS Fargate – Part 2 (Amazon ECS および AWS Fargate で Amazon EFS を使用するための開発者向けガイド – パート 2)」をご覧ください。
次に、インバウンド NFS トラフィック (ポート 2049) を許可するファイルシステムのセキュリティグループが必要です。
WOF_EFS_SG_ID=$(aws ec2 create-security-group \
--description WordPress-on-Fargate \
--group-name WordPress-on-Fargate \
--vpc-id $WOF_VPC_ID \
--region $WOF_AWS_REGION \
--query 'GroupId' --output text)
aws ec2 authorize-security-group-ingress \
--group-id $WOF_EFS_SG_ID \
--protocol tcp \
--port 2049 \
--cidr $WOF_CIDR_BLOCK
eksctl
が作成した Fargate プロファイルで使用されるすべてのサブネットで、ボリュームの EFS マウントターゲットを作成します。
for subnet in $(aws eks describe-fargate-profile \
--output text --cluster-name $WOF_EKS_CLUSTER\
--fargate-profile-name fp-default \
--region $WOF_AWS_REGION \
--query "fargateProfile.subnets"); \
do (aws efs create-mount-target \
--file-system-id $WOF_EFS_FS_ID \
--subnet-id $subnet \
--security-group $WOF_EFS_SG_ID \
--region $WOF_AWS_REGION); \
done
上記のコマンドで作成される EKS クラスターでは、EKS は複数の AZ にわたって Fargate 上のポッドをスケジュールします。各 AZ の Fargate ポッドは、その AZ の EFS マウントターゲットを使用して EFS ファイルシステムをマウントします。
永続ボリュームの作成
EFS ファイルシステムを使用して、永続ボリュームと永続ボリューム要求を作成します。
echo "
apiVersion: storage.k8s.io/v1beta1
kind: CSIDriver
metadata:
name: efs.csi.aws.com
spec:
attachRequired: false
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: efs-sc
provisioner: efs.csi.aws.com
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: wordpress-efs-pv
spec:
capacity:
storage: 100Gi
volumeMode: Filesystem
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
storageClassName: efs-sc
csi:
driver: efs.csi.aws.com
volumeHandle: $WOF_EFS_FS_ID::$WOF_EFS_AP
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: wordpress-efs-uploads-pvc
spec:
accessModes:
- ReadWriteMany
storageClassName: efs-sc
resources:
requests:
storage: 25Gi
" | kubectl apply -f -
AWS Load Balancer Controller のデプロイ
Application Load Balancer を使用して、WordPress を実行するポッドにトラフィックを分散します。Kubernetes ワークロードの Ingress (外部からのアクセスを管理する API オブジェクト) として ALB を使用するには、AWS Load Balancer Controller をインストールする必要があります。また、コントローラーの IAM ロールを作成する必要があるため、コントローラーにはユーザーに代わって ALB を管理するアクセス許可が与えられます
OIDC プロバイダーを EKS クラスターに関連付けて、コントローラーの IAM ロールを作成しましょう。
## Associate OIDC provider
eksctl utils associate-iam-oidc-provider \
--region $WOF_AWS_REGION \
--cluster $WOF_EKS_CLUSTER\
--approve
## Download the IAM policy document
curl -S https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v2_ga/docs/install/iam_policy.json -o iam-policy.json
## Create an IAM policy
aws iam create-policy \
--policy-name AWSLoadBalancerControllerIAMPolicy \
--policy-document file://iam-policy.json
## Create a service account
eksctl create iamserviceaccount \
--cluster=$WOF_EKS_CLUSTER \
--region $WOF_AWS_REGION \
--namespace=kube-system \
--name=aws-load-balancer-controller \
--override-existing-serviceaccounts \
--attach-policy-arn=arn:aws:iam::$WOF_ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy \
--approve
AWS Load Balancer Controller は、cert-manager を使用して証明書設定を Webhook に挿入します。Kubernetes が Fargate で証明書マネージャーポッドをスケジュールできるように、cert-manager
名前空間の Fargate プロファイルを作成します。
eksctl create fargateprofile \
--cluster $WOF_EKS_CLUSTER \
--name cert-manager \
--namespace cert-manager \
--region $WOF_REGION
Helm を使用して AWS Load Balancer Controller をインストールします。
helm repo add eks https://aws.github.io/eks-charts
kubectl apply -k "github.com/aws/eks-charts/stable/aws-load-balancer-controller//crds?ref=master"
helm install aws-load-balancer-controller \
eks/aws-load-balancer-controller \
--namespace kube-system \
--set clusterName=$WOF_EKS_CLUSTER \
--set serviceAccount.create=false \
--set serviceAccount.name=aws-load-balancer-controller \
--set vpcId=$WOF_VPC_ID \
--set region=$WOF_AWS_REGION
MySQL インスタンスの作成
WordPress は、MySQL バージョン 5.0.15 以降 (または MariaDB の任意のバージョン) を使用して、投稿、コメント、設定、およびユーザー情報を保存します。WordPress データベーススキーマの概要については、WordPress のドキュメントを参照してください。
Amazon RDS を使用して WordPress 用の MySQL インスタンスを作成しましょう。
## Get VPC's private subnets
WOF_PRIVATE_SUBNETS=$(aws eks describe-fargate-profile \
--fargate-profile-name fp-default \
--cluster-name $WOF_EKS_CLUSTER\
--region $WOF_AWS_REGION \
--query "fargateProfile.[subnets]" --output text | awk -v OFS="," '{for(i=1;i<=NF;i++)if($i~/subnet/)$i="\"" $i "\"";$1=$1}1')
## Create a DB subnet group
aws rds create-db-subnet-group \
--db-subnet-group-name wp-mysql-subnet \
--subnet-ids "[$WOF_PRIVATE_SUBNETS]" \
--db-subnet-group-description "Subnet group for MySQL RDS" \
--region $WOF_AWS_REGION
## Create database instance
aws rds create-db-instance \
--db-instance-identifier wp-db \
--db-instance-class db.t3.micro \
--db-name wordpress \
--db-subnet-group-name wp-mysql-subnet \
--engine mysql \
--master-username admin \
--master-user-password supersecretpassword \
--allocated-storage 20 \
--no-publicly-accessible \
--region $WOF_AWS_REGION
データベースの作成には最大 5 分程度かかる場合があります。watch コマンドを使用してデータベースのステータスを確認することができます。
watch aws rds describe-db-instances \
--db-instance-identifier wp-db \
--region $WOF_AWS_REGION \
--query "DBInstances[].DBInstanceStatus"
出力に Available
と表示されたら、次の手順に進むことができます。データベースに接続できない場合、WordPress アプリケーションは初期化に失敗します。
データベースインスタンスが利用可能になったら、RDS DB エンドポイントを保存します。
WOF_RDS_Endpoint=$(aws rds describe-db-instances \
--db-instance-identifier wp-db \
--region $WOF_AWS_REGION \
--query "DBInstances[].Endpoint.Address" \
--output text)
実稼働環境ではマルチ AZ RDS クラスターを作成することをお勧めします。手順については「Modifying a DB instance to be a Multi-AZ deployment (DB インスタンスをマルチ AZ デプロイメントに変更する)」を参照してください。また、Amazon Aurora Serverless を使用することもできます。Amazon Aurora Serverless はアプリケーションのニーズに基づいて自動的に起動、シャットダウン、およびデータベース容量のスケーリングを行います。これにより、Fargate や EFS のように、サーバーを管理せずにデータベースを実行することができます。
MySQL データベースインスタンスにアタッチされたセキュリティグループで、インバウンド MySQL トラフィック (ポート 3305) を承認します。
## Get the security group attached to the RDS instance
WOF_RDS_SG=$(aws rds describe-db-instances \
--db-instance-identifier wp-db \
--region $WOF_AWS_REGION \
--query "DBInstances[].VpcSecurityGroups[].VpcSecurityGroupId" \
--output text)
## Accept MySQL traffic
aws ec2 authorize-security-group-ingress \
--group-id $WOF_RDS_SG \
--cidr $WOF_CIDR_BLOCK \
--port 3306 \
--protocol tcp \
--region $WOF_AWS_REGION
WordPress のデプロイ
デフォルトでは、使用する Bitnami WordPressイメージは WordPress データと設定を、コンテナーの /bitnami
パスに保存します。共有 EFS ファイルシステムをポイントするように /bitnami
を構成すると、WordPress ポッドを複数のアベイラビリティーゾーンで同時に実行しながらスケーリングできます。
Helm を使用して WordPress をデプロイします。WordPress の設定を含む Helm 値ファイルを作成しましょう。
cat > values.yaml <<EOF
## Database Settings
externalDatabase:
host: $WOF_RDS_Endpoint
user: admin
password: supersecretpassword
database: wordpress
## Disable MariaDB
mariadb:
enabled: false
## run multiple WordPress pods
replicaCount: 3
## Use EFS pvc
persistence:
existingClaim: wordpress-efs-uploads-pvc
## Change from LoadBalancer to ClusterIP service type since ALB will expose
service:
type: ClusterIP
## Increase pod resources
resources:
requests:
cpu: 1000m
memory: 1024Mi
EOF
WordPress をインストールします。
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm install myblog -f values.yaml bitnami/wordpress
クラスタの外部のユーザーが WordPress にアクセスできるように Ingress を作成します。
echo "
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: wordpress-ingress
annotations:
kubernetes.io/ingress.class: "alb"
alb.ingress.kubernetes.io/scheme: "internet-facing"
alb.ingress.kubernetes.io/healthcheck-path: "/index.php"
alb.ingress.kubernetes.io/success-codes: "200,201,302"
alb.ingress.kubernetes.io/target-type: "ip"
labels:
app: wordpress-ingress
spec:
rules:
- http:
paths:
- path: /*
backend:
serviceName: myblog-wordpress
servicePort: 80
" | kubectl apply -f -
この WordPress のデプロイメントは、HTTP トラフィックのみを着信するように構成されています。ここで説明されているように、Amazon Certificate Manager を使用して証明書を作成し、Kubernetes 入力に証明書の ARN で注釈を付けることで、TLS 暗号化を実装することができます。
データ永続性のテスト
セットアップには、現在 WordPress を実行している 3 つのポッドがあります。WordPress にログインして、いくつか変更を加えましょう。初期値を変更した後、すべての WordPress ポッドを終了して再作成し、変更が永続化されていることを確認します。
WordPress サービスの DNS 名を取得し、Web ブラウザでアドレスを開きます。
echo $(kubectl get ingress wordpress-ingress \
-o jsonpath="{.status.loadBalancer.ingress[].hostname}")/wp-admin/
前のコマンドの出力によって表示されているアドレスに移動すると、WordPress の管理ポータルに移動します。Web サイトの手順に従って、サンプルの WordPress サイトのセットアップを完了します。
インストールが完了したら、WordPress サイトのテーマを変更できます。WordPress はテーマファイルを /bitnami/wp-content/themes/
フォルダーに保存します。テーマを設定したら、WordPress ポッドを削除して再作成します。新しいポッドは古いポッドのデータに引き続きアクセスすることができ、サイトのテーマが既定のテーマに戻るということはありません。
インストールプロセス中に使用した資格情報を使用して WordPress ダッシュボードにログインします。右上隅にあるサイトの名前をクリックします。
サイトに移動し、サイトメニューからテーマを選択します。
メニューのテーマ (Themes) の項目にて、新しいテーマを選択してアクティブにします。
サイトに戻り、選択したテーマがサイトで使用されていることを確認します。その後、WordPress デプロイメントを 0 にスケーリングして、WordPress ポッドを削除します。
kubectl scale deployment myblog-wordpress --replicas=0
WordPress サイトのページを更新すると、バックエンドポッドがないため ALB はエラーを返します。デプロイを 3 つのポッドにスケーリングします。
kubectl scale deployment myblog-wordpress --replicas=3
ポッドが実行された後、WordPress サイトのページを更新すると、適用したテーマの変更を含むサイトが表示されます。WordPress のデータと設定はポッドの終了後も存続したと結論付けることができます。
クリーンアップ
この記事中に作成されたリソースを削除するためには、次のコマンドを使用します。
helm delete myblog
kubectl delete ingress wordpress-ingress
helm delete aws-load-balancer-controller --namespace kube-system
eksctl delete iamserviceaccount --cluster $WOF_EKS_CLUSTER --name aws-load-balancer-controller --namespace kube-system --region $WOF_AWS_REGION
kubectl delete pvc wordpress-efs-uploads-pvc
kubectl delete pv wordpress-efs-pv
aws rds delete-db-instance --db-instance-identifier wp-db --skip-final-snapshot --region $WOF_AWS_REGION
## Wait until the database is deleted
aws rds delete-db-subnet-group --db-subnet-group-name wp-mysql-subnet
for mount_target in $(aws efs describe-mount-targets --file-system-id $WOF_EFS_FS_ID --region $WOF_AWS_REGION --query 'MountTargets[].MountTargetId' --output text); do aws efs delete-mount-target --mount-target-id $mount_target; done
## Wait for a few seconds
sleep 30
aws efs delete-file-system --file-system-id $WOF_EFS_FS_ID --region $WOF_AWS_REGION
aws ec2 delete-security-group --group-id $WOF_EFS_SG_ID --region $WOF_AWS_REGION
eksctl delete cluster $WOF_EKS_CLUSTER --region $WOF_AWS_REGION
まとめ
AWS Fargate および Amazon EFS ファイルシステムとの統合により、Amazon EKS および Amazon ECS を使用してステートフルなワークロードを実行することができます。さらに Amazon EFS を使用すると、数千のポッドまたは EC2 インスタンスが共有ボリュームに対して同時に読み書きできます。これにより Fargate を、Web ホスティング、コンテンツ管理、メディア処理ワークフローなどの多くのソリューションで利用することができます。
さらに読む
- Optimizing WordPress performance with Amazon EFS (Amazon EFS を使用した WordPress パフォーマンスの最適化)
- WordPress: Best Practices on AWS (WordPress: AWS におけるベストプラクティス)
- How to accelerate your WordPress site with Amazon CloudFront (Amazon CloudFront を使用して WordPress サイトを高速化する方法)
- Developers guide to using Amazon EFS with Amazon ECS and AWS Fargate (Amazon ECS および AWS Fargate で Amazon EFS を使用するための開発者ガイド)
翻訳はソリューションアーキテクト 杉本 晋吾 が担当しました。原文はこちらです。