前回はCFnを利用してEC2とDifyのコミュニティ版をデプロイしましたが、デフォルトだとDify上でファイルをアップロードするとEBSに格納されてしまうため、利用を続けているとEBS容量が膨らんでしまいます。 そこで、DifyのストレージにAmazon S3を利用するように修正して、EBSにファイルが格納されないようにしてみます。
目次
実施作業
準備
今回は以下の手順で実行します。
- CFnテンプレートの修正
- CloudFormationサービスのコンソールからデプロイ
前提
手順を開始する時点の前提条件は以下です。
このあたりは前回と同じです。
- VPC/Subnetは構築済み
- EC2はPublic Subnet上に構築
- Difyはユーザーデータを利用してインストール・デプロイする
- Docker Composeのインストールもユーザーデータを利用する
- EC2に設定するSecurity Groupは作成済み(インバウンドは自宅IPからのHTTP接続のみ許可)
CFnテンプレートの修正
CFnテンプレートをAIに修正させ、細かいところを手修正したCFnテンプレートが以下になります。
以下の内容が記載された「dify_cfn_template_s3.yaml」を作成します。
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Dify Application Deployment on EC2 Instance with S3 Storage'
Parameters:
InstanceName:
Type: String
Default: 'Dify-Server'
Description: 'Name tag for the EC2 instance'
KeyPairName:
Type: AWS::EC2::KeyPair::KeyName
Description: 'EC2 Key Pair for SSH access'
ConstraintDescription: 'Must be the name of an existing EC2 KeyPair'
VPCId:
Type: AWS::EC2::VPC::Id
Description: 'VPC ID for the EC2 instance'
SubnetId:
Type: AWS::EC2::Subnet::Id
Description: 'Public subnet ID for the EC2 instance'
SecurityGroupId:
Type: AWS::EC2::SecurityGroup::Id
Description: 'Security Group ID for the EC2 instance'
Default: ''
AllowedPattern: '^(|sg-[0-9a-fA-F]{8,17})$'
ConstraintDescription: 'Must be a valid Security Group ID or left blank to create a new one'
Resources:
# S3 Bucket for Dify Storage
DifyS3Bucket:
Type: AWS::S3::Bucket
DeletionPolicy: Delete
Properties:
BucketName: !Sub 'dify-storage-${AWS::AccountId}-${AWS::Region}'
DifyEC2Role:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub '${AWS::StackName}-DifyEC2Role'
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: ec2.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy
Policies:
- PolicyName: DifyS3AccessPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- s3:ListBucket
Resource: !GetAtt DifyS3Bucket.Arn
- Effect: Allow
Action:
- s3:GetObject
- s3:PutObject
- s3:DeleteObject
Resource: !Sub '${DifyS3Bucket.Arn}/*'
DifyInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Roles:
- !Ref DifyEC2Role
DifyLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub '/dify/${InstanceName}'
RetentionInDays: 30
DifyEC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Sub '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64}}'
InstanceType: t3.medium
KeyName: !Ref KeyPairName
IamInstanceProfile: !Ref DifyInstanceProfile
SubnetId: !Ref SubnetId
SecurityGroupIds:
- !Ref SecurityGroupId
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeType: gp3
VolumeSize: 20
Iops: 3000
Encrypted: true
DeleteOnTermination: true
UserData:
Fn::Base64: !Sub |
#!/bin/bash
# システムアップデート
dnf update -y
# CloudWatch エージェントのインストール
dnf install -y amazon-cloudwatch-agent
# Dockerのインストール
dnf install -y docker
systemctl start docker
systemctl enable docker
# ec2-userをdockerグループに追加
usermod -a -G docker ec2-user
# Gitのインストール(Amazon Linux 2023には通常含まれているが念のため)
dnf install -y git
# Docker Compose(V2)のインストール
DOCKER_COMPOSE_VERSION="v2.39.2"
mkdir -p /usr/local/lib/docker/cli-plugins
curl -SL "https://github.com/docker/compose/releases/download/$DOCKER_COMPOSE_VERSION/docker-compose-linux-x86_64" -o /usr/local/lib/docker/cli-plugins/docker-compose
chmod +x /usr/local/lib/docker/cli-plugins/docker-compose
# Difyのクローンとセットアップ
cd /home/ec2-user
git clone https://github.com/langgenius/dify.git --branch 1.8.1
cd dify/docker
cp .env.example .env
# .envファイルのS3設定を更新
sed -i 's/^STORAGE_TYPE=.*/STORAGE_TYPE=s3/' .env
echo "" >> .env
echo "# S3 Configuration" >> .env
echo "S3_ENDPOINT=https://s3.ap-northeast-1.amazonaws.com" >> .env
echo "S3_REGION=ap-northeast-1" >> .env
echo "S3_BUCKET_NAME=${DifyS3Bucket}" >> .env
echo "S3_ACCESS_KEY=" >> .env
echo "S3_SECRET_KEY=" >> .env
echo "S3_USE_AWS_MANAGED_IAM=true" >> .env
# ファイルの所有権をec2-userに変更
chown -R ec2-user:ec2-user /home/ec2-user/dify
# CloudWatch エージェント設定ファイルの作成
cat > /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json << 'EOF'
{
"agent": {
"run_as_user": "root"
},
"logs": {
"logs_collected": {
"files": {
"collect_list": [
{
"file_path": "/var/log/cloud-init-output.log",
"log_group_name": "/dify/${InstanceName}",
"log_stream_name": "{instance_id}/cloud-init",
"timezone": "UTC"
}
]
}
}
}
}
EOF
# Docker Composeでサービス起動
sudo -u ec2-user docker compose up -d
# CloudWatch エージェント起動
/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \
-a fetch-config \
-m ec2 \
-c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json \
-s
# ログファイルに完了メッセージを出力
echo "Dify installation completed at $(date)" >> /var/log/cloud-init-output.log
Tags:
- Key: Name
Value: !Ref InstanceName
Outputs:
InstanceId:
Description: 'EC2 Instance ID'
Value: !Ref DifyEC2Instance
Export:
Name: !Sub '${AWS::StackName}-InstanceId'
PublicIP:
Description: 'Public IP address of the EC2 instance'
Value: !GetAtt DifyEC2Instance.PublicIp
Export:
Name: !Sub '${AWS::StackName}-PublicIP'
DifyURL:
Description: 'URL to access Dify application'
Value: !Sub 'http://${DifyEC2Instance.PublicIp}'
Export:
Name: !Sub '${AWS::StackName}-DifyURL'
SSHCommand:
Description: 'SSH command to connect to the instance'
Value: !Sub 'ssh -i <your-key.pem> ec2-user@${DifyEC2Instance.PublicIp}'
S3BucketName:
Description: 'S3 Bucket name for Dify storage'
Value: !Ref DifyS3Bucket
Export:
Name: !Sub '${AWS::StackName}-S3BucketName'
CloudFormationサービスのコンソールからデプロイ
前回と同じ要領でCloudFormationのスタックを作成します。

テンプレートに設定したEC2を構築するために必要なパラメータを指定して実行します。
- Stack name:Dify-stack
- InstanceName:Dify-Server
- KeyPairName:既存のキーペアを指定する
- SecurityGroupId:既存のSGを指定する
- SubnetId:既存のPublic Subnetを指定する
- VPCId:既存のVPCを指定する

数分経過後、CREATE_COMPLETE が表示されて正常終了しました。

Difyアクセス&ファイルアップロード
CFnスタックのOutputsタブから http://your_ip_address/install にアクセスしてDify画面が確認できました。


ログイン後、ナレッジ→ナレッジベースを作成を押下します。

適当なファイルをアップロードしてナレッジベースを作成します。


S3出力確認
CFnスタックのOutputsに表示されているS3バケット名をコピペして、S3コンソールから対象のバケットを表示します。

自動でパスが作成されており、upload_filsパスにはアップロードしたファイルが(名前は変わってますが)格納されていることが確認できました。


感想及び所感
ナレッジベースにアップロードするファイルはサイズが大きくなりがちだと思うので、S3を使えるとコストや容量の面で助かることは多そうです。
この記事がどなたかの参考になれば幸いです。