前回はCFnを利用してEC2とDifyのコミュニティ版をデプロイしました。
ただ、正常に実行されたかどうかを毎回SSHでログインして確認していたので、ログをCloudWatch Logsに出力してSSHログインしなくても確認できるようにしてみます。
目次
実施作業
準備
今回は以下の手順で実行します。
- CFnテンプレートの修正
- CloudFormationサービスのコンソールからデプロイ
前提
手順を開始する時点の前提条件は以下です。
このあたりは前回と同じです。
- VPC/Subnetは構築済み
- EC2はPublic Subnet上に構築
- Difyはユーザーデータを利用してインストール・デプロイする
- Docker Composeのインストールもユーザーデータを利用する
- EC2に設定するSecurity Groupは作成済み(インバウンドは自宅IPからのHTTP接続のみ許可)
CFnテンプレートの修正
CFnテンプレートをAIに修正させ、細かいところを手修正したCFnテンプレートが以下になります。
以下の内容が記載された「dify_cfn_template_add_cwlogs.yaml」を作成します。
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Dify Application Deployment on EC2 Instance'
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:
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
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
# ファイルの所有権を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}'
CloudFormationサービスのコンソールからデプロイ
前回と同じ要領でCloudFormationのスタックを作成します。

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

前回と違う点として、今回はCloudWatch Logsに出力するためにEC2にIAMロールをアタッチする必要があるので、IAMリソースが作成されることを確認したチェックをする必要があります。

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

Difyアクセス
CFnスタックのOutputsタブから http://your_ip_address/install にアクセスしてDify画面が確認できました。


ログ出力確認
CloudWatchコンソールのLog groupsから「Dify-Server」で検索し、対象ロググループを開きます。

CFnテンプレートに指定した以下の完了メッセージがCloudWatch Logsに出力されていることが確認できました。
# ログファイルに完了メッセージを出力 echo "Dify installation completed at $(date)" >> /var/log/cloud-init-output.log

感想及び所感
Dockerログも出力しようか迷いましたが、ログ量がかなり増えそうだったので今回は止めておきました。
この記事がどなたかの参考になれば幸いです。