カピバラ好きなエンジニアブログ

興味ある技術とか検証した内容を赴くままに書いていきます。カピバラの可愛さこそ至高。

EC2上でDifyを動かしてみる(CFn利用)

前回はAWSマネジメントコンソールとユーザーデータを利用して手動でEC2とDifyを構築しましたが、手動で構築するのは手間なのでAWS公式のIaCツールであるCloudFormation(以下CFn)を利用してテンプレート化し、構築をもう少し楽にしてみます。

目次

実施作業

準備

Difyのインストールと実行方法については前回同様にDocker Composeを利用したデプロイを実施します。

docs.dify.ai

今回は以下の手順で実行します。

  • CFnテンプレートの作成
  • CloudFormationサービスコンソールからデプロイ

前提

手順を開始する時点の前提条件は以下です。
このあたりは前回と同じです。

  • VPC/Subnetは構築済み
  • EC2はPublic Subnet上に構築
  • Difyはユーザーデータを利用してインストール・デプロイする
  • Docker Composeのインストールもユーザーデータを利用する
  • EC2に設定するSecurity Groupは作成済み(インバウンドは自宅IPからのHTTP接続のみ許可)


CFnテンプレートの作成

ベースとなるCFnテンプレートをAIに作成させ、細かいところを修正したCFnテンプレートが以下になります。
以下の内容が記載された「dify_cfn_template.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:  
  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
      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

          # 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

          # Docker Composeでサービス起動
          sudo -u ec2-user docker compose up -d

          # ログファイルに完了メッセージを出力
          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のコンソールの「Crate stack」ボタンを押下して新しいリソースを作成します。

テンプレートをアップロードする項目を選択肢、「Choose file」から先ほど作成した「dify_cfn_template.yaml」ファイルをアップロードして次へを押下します。

テンプレートに設定したEC2を構築するために必要なパラメータを指定します。

  • Stack name:Dify-stack
  • InstanceName:Dify-Server
  • KeyPairName:既存のキーペアを指定する
  • SecurityGroupId:既存のSGを指定する
  • SubnetId:既存のPublic Subnetを指定する
  • VPCId:既存のVPCを指定する

尚、一部のパラメータはクリックすると同アカウント内の対象リソースをリストで表示してくれるので、この中から対象のリソースを指定すればOKです。

次のページでは特に変更せずに次へを押下します。

最後のページは確認画面なので問題なければ送信を押下します。
構築には少し時間がかかるので待ちます。

正常終了したら以下のように CREATE_COMPLETE が表示されます。


Difyアクセス

今回のテンプレートではOutputsにDifyURLを出力するようにしていたので、その値をコピペしてアクセスしてみます。

Dify管理者アカウント設定画面にアクセスする場合は以下のURLになるように修正してください。

[http://your_server_ip/install]

無事にアクセスできました。

セットアップが完了するとDifyのTop画面に遷移しました。

お片付け

CloudFormationで作成したAWSリソースは対象のCFnスタックを削除すればまとめて削除されます。
スタックの「Delete」を押下します。

確認画面が出てくるので再度「Delete」を押下します。

正常に削除が完了すると DELETE_COMPLETE と表示されます。


感想及び所感

Difyを何回も構築するケースは多くはないかと思いますが、ちょっと検証したいケースなどでは使うかもしれないのでCloudFormationを利用して構築してみました。

この記事がどなたかの参考になれば幸いです。