【Laravel & AWS】RDB(RDS)に接続する & cronを使える様にする【2日目】

AWSのサービス縛りでコスト最適で弾力性のあるLaravelアプリケーションのインフラを作ろうという企画の第2回です。
前回、アプリケーションサーバの構築とビルド・デプロイの自動化をしたので、今回は「RDBへの接続」と「cronを使える様にする」をやっていきます!🤟
ちなみにやりたい事の一覧は以下の通り。

  • アプリケーションサーバの構築
  • ビルド・デプロイの自動化
  • RDBに接続できる
  • テストの自動化
  • cronを使える様にする(Laravelのタスクスケジュールのトリガー)
  • HTTPS対応
  • アプリケーションサーバのオートスケール&ロードバランシング
  • Redisに接続できる
  • リソースをCDNから配信する

ElasticBeanstalkの課金を停止するには?

いきなり脱線しますが、作業しない間は課金を停止したいです。
そのためには環境を全て終了する必要があるようです。
以下の画像の様に、環境詳細画面で「アクション」→「環境の終了」をクリックする。
公式ドキュメントはこちら

Beanstalkの環境を終了している図

環境を再構築するにはアプリケーション一覧画面で「アクション」→「終了した環境の復元」をする。
なお、環境を終了してから6週間(42日)を超えると復元できなくなるとの事。(ドキュメントに記載が有る)

Beanstalkの環境を復元している図

RDBに接続する

さて本題に入っていきます。
まずはLaravelアプリケーションにDBに接続する処理を作成してリポジトリにPushします。
トップページにDBからテキストを表示する処理と、DBのテキストを更新する処理を追加した。
ローカル環境で表示するとこんな感じ。

いちおうスキーマ定義はこんな感じ。

        Schema::create('items', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->timestamps();
        });

Beanstalk環境で確認するとDBに接続できなくてエラーになりました。
まだRDBを用意していないので当然ですね!🧐

DBへの接続が失敗してエラーが表示されている図

RDSのインスタンスを作成します。

RDSのインスタンスを作成している図

出来ました!🤙

RDSのインスタンス一覧画面

Beanstalkの環境変数にRDSのホスト名やパスワードを設定する

Beanstalkの環境変数を設定している図

マイグレーションする必要があるので、eb sshで環境に接続してphp artisan migrateをします。
以下の様なエラーが発生しました。
データベースlaravel見つからないとの事🤔

Database name seems incorrect: You're using the default database name `laravel`. This database does not exist.

MySQL workbenchで接続して確認してみる。
一時的にRDSを外部から接続できる様に設定を変更する。

RDSを外部から接続できる様に設定を変更している図

あれ?laravelデータベースあるな??🤔🤔
ということは原因は別か・・・。

RDSのテーブルの一覧

RDSのログは見れないのか?

コンソールから閲覧できるっぽい。

RDSのログ一覧

ログファイルを選んでログの内容を閲覧してみる。
何も表示されねぇな・・・🤨

RDSのログを閲覧している図

ネットワークのログは見れないのか?

VPCフローログを有効化すれば見れるらしい。
さっそく有効化してみた。

VPCフローログを作成した図

CloudWatchにログが保存されて、こんな感じで確認できる。

CloudWatchでVPCフローログを確認している図

デフォルトのログの形式は以下の通り。

<version> <account-id> <interface-id> <srcaddr> <dstaddr> <srcport> <dstport> <protocol> <packets> <bytes> <start> <end> <action> <log-status>

ログを眺めてみたが、解決には至らず・・・💀
たぶんRDSへの接続がファイアウォールかなにかに拒否されている様な気がするのだが。

RDSのセキュリティグループを編集する

たまたま「VPCのDBインスタンスにアクセスするシナリオ」というドキュメントを見つけた。
ドンピシャこれだわ💡
RDSのセキュリティグループにBeanstalk環境からの接続を許可してやる必要があるみたい。
ちなみにセキュリティグループとはインスタンスに紐づくファイアウォールらしい。

RDSのセキュリティグループのインバウンドルール

インバウンドルールにBeanstalkのセキュリティグループからの接続を許可するルールを追加した。

RDSのセキュリティグループのインバウンドルールを追加した後の図

Beanstalk(EC2)からRDSに接続できる様になってDBのマイグレーションが通る様になった!💯

BeanstalkのインスタンスからDBのマイグレーションが成功している図

画面も開けた!(DBからデータが読み込めた)

アプリケーションのトップページが開けた図

cronを使える様にする(Laravelのタスクスケジュールのトリガー)

実験のために、タスクスケジュールで毎分カウントアップする項目を追加した。

タスクスケジュールによって更新される数値を表示している図

Beanstalkでcronのタスクを定義するには、ebextensionsとよばれる設定ファイルを記述する(ドキュメントはこちら
この設定ファイルはアプリケーションがデプロイされる際に実行されるとの事。
.ebextensions/cron-linux.configを作成し以下の様に記述してみた。
webappユーザとして毎分タスクスケジュールを起動している。

files:
    "/etc/cron.d/mycron":
        mode: "000644"
        owner: root
        group: root
        content: |
            * * * * * webapp cd /var/www/html && php artisan schedule:run >> /dev/null 2>&1

commands:
    remove_old_cron:
        command: "rm -f /etc/cron.d/mycron.bak"

何故かタスクがトリガーされない😒
/var/log/cronを確認すると以下のエラーが発生していた。
webappユーザのホームディレクトリが無いとユーザを切り替えられないらしい。

(CRON) ERROR chdir failed (/home/webapp): No such file or directory

また、もう1つ問題があって、環境変数が読み込まれていなくて、DB接続に失敗する😑
こちらによるとopt/elasticbeanstalk/support/envvarsを実行すれば環境変数が読み込めるとの事。
という訳で.ebextensions/cron-linux.configは最終的に以下の様になりました。
環境変数を読み込んでタスクをトリガーするスクリプト/opt/ebextensions/trigger-task.shを作成して、cronからはsudo -u webappでユーザを切り替えつつ前述のスクリプトを起動する様にしてます。

files:
    "/opt/ebextensions/trigger-task.sh":
        mode: "000744"
        owner: webapp
        group: webapp
        content: |
            source /opt/elasticbeanstalk/support/envvars
            cd /var/www/html
            php artisan schedule:run >> /dev/null 2>&1

    "/etc/cron.d/mycron":
        mode: "000644"
        owner: root
        group: root
        content: |
            * * * * * root sudo -u webapp /opt/ebextensions/trigger-task.sh

commands:
    remove_old_cron:
        command: "rm -f /etc/cron.d/mycron.bak"

cronによってトップページの数値がカウントアップされる様になった!😤

環境が消せないエラー

今日はこの辺で終わろうと思って、Beanstalk環境を停止したら正常に停止せず(ヘルスがSuspendedのまま)、以下の様なエラーが発生してました🆘
どうやら別のセキュリティグループから参照されているセキュリティグループは削除できないらしい。

Stack deletion failed: The following resource(s) failed to delete: [AWSEBSecurityGroup].
Deleting security group named: awseb-e-*-stack-AWSEBSecurityGroup-* failed Reason: resource sg-* has a dependent object (Service: AmazonEC2; Status Code: 400; Error Code: DependencyViolation; Request ID: *)

こちら対策が記載されている。

暫定対処

暫定対処として、セキュリティグループを参照しているルールを削除して、eb terminate [環境名]で環境を終了しました。

恒久対処

Beanstalkが自動的に作成したセキュリティグループawseb-e-XXXX-stack-AWSEBSecurityGroup-XXXの様な名前が付与されているやつ)は環境を削除するときに自動的に削除されるっぽい。
で、そのセキュリティグループを別のセキュリティグループから参照していると環境削除時にエラーが出てしまうと。
恒久対処としては、自分で作成して付与したセキュリティグループなら削除されない様なので、別途セキュリティグループを作成して付与した

所感

やってるうちに、他にもいろいろ試したい事が浮かんできたのでこの辺も少しずつ消化していきます!

  • storageフォルダの権限の付け方
  • RDSのバックアップ/リストア
  • RDSの容量のオートスケール
  • CodePipelineで、承認しないとデプロイされないようにする
  • ビルド完了時のslack通知
  • パブリックサブネット/プライベートサブネットの活用

「【Laravel & AWS】RDB(RDS)に接続する & cronを使える様にする【2日目】」への5件のフィードバック

コメントする