さゆフィクション | aws wordpress などなどゆるーく書いてます http://it.kensan.net/it aws wordpress などなどゆるーく書いてます Fri, 05 Jul 2024 11:21:42 +0000 ja hourly 1 https://wordpress.org/?v=6.5.2 https://it.kensan.net/wp-content/uploads/2023/03/cropped-icon-32x32.png さゆフィクション | aws wordpress などなどゆるーく書いてます http://it.kensan.net/it 32 32 LaravelでSendGrid-smtp送信のメール送信をテスト・デバッグする最短の方法ーSendGridの設定方法 https://it.kensan.net/laravel-sendgrid-smtp-mail-send.html Fri, 05 Jul 2024 10:54:47 +0000 https://it.kensan.net/?p=2113 LaravelでSendGrid-smtp送信のメール送信をテスト・デバッグする最短の方法について記載します。

こうすれば、SendGridのメール設定ができて、簡単に設定後の動作確認ができるよ、ということを記載していきます。

SendGridのテスト・デバッグ時のメール送信確認の設定周りを中心に記載します。

メール送信のLaravelプログラムの書き方については記載していません。

Laravelのローカル開発環境構築

ローカル開発環境構築は以下の記事をご参照ください。本記事ではローカル開発環境構築が済んでいることを前提に記載します。

DockerでLaravel 11のローカル開発環境を構築する。ついでにphpmyadminも入れてみる。
DockerでLaravel 11のローカル開発環境を構築していきます。 DB確認用に、phpmyadminもインストールします。 コンテナは以下のような構成です。本番環境に応用できるように、あえてSailは使いません。 アプリコンテナ P...

SendGrid側の設定

本記事ではSendGrid側の設定ができていることを前提に記載します。

SendGrid側の設定がまだの場合は以下のステップで設定できます。

  1. 以下の記事を参考に申し込みをする
  2. 申し込みが終わったら、以下の記事を参考に、差出人情報を設定する

LaravelにSendGrid-smtp送信の設定をして動作確認

メールをSendGridで送信するように設定変更

.envファイルでメールをSendGridで送信するように設定します。

以下のコマンドでプロジェクト直下の「.env」ファイルを開きます

vi .env

以下のとおり、「.env」ファイルを編集します。

MAIL_MAILER=smtp 
MAIL_HOST=smtp.sendgrid.net
MAIL_PORT=587
MAIL_USERNAME=apikey
MAIL_PASSWORD=<SendGridで払い出されたAPIキーを設定>
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS="<送信元メールアドレスを設定>"
MAIL_FROM_NAME="${APP_NAME}"

MAIL_PASSWORDには「SendGridで払い出されたAPIキー」を設定し、MAIL_FROM_ADDRESSには「送信元メールアドレス」を設定します。

メールを送って受信確認してみる

以下のコマンドでメールを送信可能です。

// コンテナの中に入る
docker compose exec app php artisan tinker
// メール送信
Mail::raw('test mail',function($message){$message->to('<実際に送信する送信先アドレス>')->subject('test');});

送付先のメールアドレスに実際にメールが届いていれば、SendGridの設定完了です。

まとめ

SendGridのメール設定ができて、簡単に設定後の動作確認ができたと思います。

]]>
Laravelのローカル開発環境でメール送信をテスト・デバッグする最短の方法(メール送信のための設定確認方法) https://it.kensan.net/laravel-mail-send-test.html Fri, 05 Jul 2024 10:17:45 +0000 https://it.kensan.net/?p=2106 Laravelのローカル開発環境でメール送信をテスト・デバッグする最短の方法について記載します。

以下の2つの方法を記載します。

  • ログで確認する方法
  • mailhog(コンテナ)で確認する方法

こうすれば、テスト時のメール設定ができて、簡単に設定後の動作確認ができるよ、ということを記載していきます。

テスト・デバッグ時のメール送信確認の設定周りを中心に記載します。

メール送信のLaravelプログラムの書き方については記載していません。

Laravelのローカル開発環境構築

ローカル開発環境構築は以下の記事をご参照ください。本記事ではローカル開発環境構築が済んでいることを前提に記載します。

DockerでLaravel 11のローカル開発環境を構築する。ついでにphpmyadminも入れてみる。
DockerでLaravel 11のローカル開発環境を構築していきます。 DB確認用に、phpmyadminもインストールします。 コンテナは以下のような構成です。本番環境に応用できるように、あえてSailは使いません。 アプリコンテナ P...

メール送信をログで確認する方法

メールの内容をログ出力するように設定変更

.envファイルでメールをログに吐き出すように設定します。

以下のコマンドでプロジェクト直下の「.env」ファイルを開きます

vi .env

以下のとおり、「.env」ファイル内のMAIL_MAILERにlogを設定します。

MAIL_MAILER=log

メールを送ってログを確認してみる

以下のコマンドでメールを送信可能です。

// コンテナの中に入る
docker compose exec app php artisan tinker
// メール送信
Mail::raw('test mail',function($message){$message->to('test@example.com')->subject('test');});

以下のようにcatコマンドなどを使ってログを確認します。

cat storage/logs/laravel.log 

以下のようにメールのログが確認できれば成功です。

From: Laravel <hello@example.com>
To: test@example.com
Subject: test
MIME-Version: 1.0
Date: Fri, 05 Jul 2024 09:41:54 +0000
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

test mail  

メール送信をmailhog(コンテナ)で確認する方法

メールをmailhog(コンテナ)に送信する設定変更

.envファイルでメールをmailhogに吐き出すように設定します。

以下のコマンドでプロジェクト直下の「.env」ファイルを開きます

vi .env

以下のとおり、「.env」ファイル内のMAIL_HOSTmailhogを設定します。

ポートは1025を指定します。

MAIL_MAILER=smtp
MAIL_HOST=mailhog
MAIL_PORT=1025

次にdocker-compose.ymlを編集します。

vi docker-compose.yml

ファイルの中身は以下のように記載します。

services:
  mailhog:
    image: mailhog/mailhog
    ports:
      - target: 8025
        published: ${MAILHOG_PUBLISHED_PORT:-8025}
        protocol: tcp
        mode: host

dockerを立ち上げます

// コンテナを立ち上げている場合は一度落とす
docker compose down
// コンテナを立ち上げる
docker compose up

メールを送ってをmailhogで送信内容を確認してみる

以下のコマンドでメールを送信可能です。

// コンテナの中に入る
docker compose exec app php artisan tinker
// メール送信
Mail::raw('test mail',function($message){$message->to('test@example.com')->subject('test');});

http://127.0.0.1:8025/にアクセスして、以下のようにメール受信を確認できればOKです。

まとめ

以下の2通りでのメールの確認方法を記載しました。

  • ログで確認する方法
  • mailhog(コンテナ)で確認する方法

これでメール実装の設定準備はできたと思いますー

]]>
ALB(ロードバランサー)でCloudFront経由のアクセスに絞るときは、カスタム HTTP ヘッダーとマネージドプレフィックスリストを併用する https://it.kensan.net/alb-cloudfront-accesss.html Sun, 30 Jun 2024 07:40:39 +0000 http://35.77.216.202/it/?p=2095 ALB(ロードバランサー)でCloudFront経由のアクセスに絞る方法として、以下の方法があると思います。

  • マネージドプレフィックスリスト(managed prefix list)によりアクセスを絞る
  • カスタム HTTP ヘッダーによりアクセスを絞る

    上記はよく知られた方法かと思いますので、詳細は割愛します。

    本記事で記載したいことは、上記2つを併用した方が安心だよということです。

    まずは、用語の説明からです。

    用語の説明

    マネージドプレフィックスリスト(managed prefix list)とは

    AWS Managed Prefix Listは、AWSによって管理されるIPアドレスのプレフィックスリストです。特定のAWSサービス(例えばCloudFrontやAmazon S3など)のIPアドレス範囲を含んでおり、ネットワーク設定やセキュリティ設定を簡素化するために使用されます。

    本記事では、「マネージドプレフィックスリスト=CloudFrontのIP」として記載します。

    カスタム HTTP ヘッダー

    カスタム HTTP ヘッダーは、HTTP リクエストやレスポンスに含まれるユーザー定義のヘッダーであり、標準の HTTP ヘッダーではカバーされない追加の情報を送信するために使用されるものです。

    なぜ併用した方がいいのか

    ALB(ロードバランサー)でCloudFront経由のアクセスに絞る際に、マネージドプレフィックスリストとカスタム HTTP ヘッダーを併用する場合、以下のようになります。

    • マネージドプレフィックスリスト(managed prefix list)によるアクセス制限
      • IP制限により、CloudFront経由のアクセスを絞る
        • CloudFront経由であれば、別アカウントのものでも許可してしまう
    • カスタム HTTP ヘッダーによるアクセス制限
      • カスタムHTTPヘッダーにより、CloudFront経由にアクセスを絞る
        • 自分が作成したCloudFrontのみにアクセスを絞ることができる
    • →マネージドプレフィックスリストとカスタム HTTP ヘッダーを併用することで、自分が作成したCloudFrontのみにアクセスを絞ることができる

    マネージドプレフィックスリスト(managed prefix list)だけでは、CloudFrontのIP制限のため、CloudFrontからの接続であれば、別アカウントのものでも許可してしまいます。

    そのため、カスタム HTTP ヘッダーも併用が必要となります。カスタム HTTP ヘッダーにより、自分が作成したCloudFrontのみにアクセスを絞ることができます。

    2段階で網をかけておいた方が安心ですね。

    カスタム HTTP ヘッダーとマネージドプレフィックスリストの設定方法

    公式記事に詳しく書いてあるので、以下の公式の記事をご参照ください。

    Application Load Balancer へのアクセスを制限する - Amazon CloudFront
    Amazon CloudFront でカスタムオリジンヘッダーを使用して、ユーザー(閲覧者)が Application Load Balancer に直接アクセスできないようにします。

    まとめ

    ALB(ロードバランサー)でCloudFront経由のアクセスに絞るときは、カスタム HTTP ヘッダーとマネージドプレフィックスリストを併用するのが良いです。

    マネージドプレフィックスリスト単体でも、https(443)の通信にしているから問題とならないケースもあると思いますが、基本的にはカスタム HTTP ヘッダーとマネージドプレフィックスリストを併用した方が安心かと思います。

    ]]>
    Laravel Adminのgridでの細かい検索とformでの1対多のデータ登録のやり方~todoリストを作成しつつ解説~ https://it.kensan.net/laravel-admin-grid-form.html Sat, 08 Jun 2024 03:22:02 +0000 http://35.78.204.110/it/?p=2052 Laravel Adminのgridとformの使い方について記載していきます。

    Laravel Adminって何者?という方は以下の記事をご参照ください。

    Laravel Adminで効率的に管理画面を作成する。Dockerを使用した環境構築と使い方について記載。
    Laravel Adminは、ウェブアプリケーションの管理画面を効率的かつ簡単に作成できるツールです。 この記事では、Laravel Adminの利点と使い方について詳しく記載します。 Laravel Adminを利用すると、データベースの...

    gridとformについて簡単に書くと、以下のようになります。gridとformを理解することでLaravel Adminの大部分を使いこなせると思います。

    • grid:一覧表示
    • form:新規登録・編集機能

    本記事でやること

    • 登録・編集(formメソッド)
      • セレクトボックスの設置
        • 選択肢はDBから取得
      • 入力ボックスを使わないデフォルト値設定
      • 1対多のテーブルでのデータ登録
    • フィルター・一覧(gridメソッド)
      • デフォルトでの検索条件の指定
      • チェックボックスでor検索の実装
      • 一覧の文字色変更

     

    では、todoリストを作成しつつ、説明していきます

    Laravel Adminを動作させる環境構築

    環境構築は以下の記事をご参照ください。Dockerで簡単に構築できます。

    Laravel Adminで効率的に管理画面を作成する。Dockerを使用した環境構築と使い方について記載。
    Laravel Adminは、ウェブアプリケーションの管理画面を効率的かつ簡単に作成できるツールです。 この記事では、Laravel Adminの利点と使い方について詳しく記載します。 Laravel Adminを利用すると、データベースの...

    テーブルとModelとControllerの準備

    テーブルの作成

    テーブル構成は以下のようになります。

    • todo情報を格納するtodosテーブル
    • todo情報に対するコメントを格納するcommentsテーブル

    では、以下のコマンドでマイグレートファイルを作成します。

    php artisan make:migration create_todos_table --create=todos
    
    php artisan make:migration create_comments_table --create=comments

    マイグレーションファイルは以下のように修正します。

    <todosテーブル>

    
    <?php
    
    use Illuminate\Database\Migrations\Migration;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Support\Facades\Schema;
    
    return new class extends Migration
    {
        /**
         * Run the migrations.
         */
        public function up(): void
        {
            Schema::create('todos', function (Blueprint $table) {
                $table->increments('id');
                $table->string('todo_name')->nullable(false)->index();    # todoの名前
                $table->string('target_user_id')->nullable(false);    # todoの担当者
                $table->string('regist_user_id')->nullable(true);    # todoの登録者
                $table->integer('status')->nullable(true)->default(0);    # 完了ステータス 0:未完了、1:完了
                $table->timestamps();
            });
        }
    
        /**
         * Reverse the migrations.
         */
        public function down(): void
        {
            Schema::dropIfExists('todos');
        }
    };

    <commentsテーブル>

    
    <?php
    
    use Illuminate\Database\Migrations\Migration;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Support\Facades\Schema;
    
    return new class extends Migration
    {
        /**
         * Run the migrations.
         */
        public function up(): void
        {
            Schema::create('comments', function (Blueprint $table) {
                $table->increments('id');
                $table->integer('todo_id');
                $table->text('comment');
                $table->string('regist_user_id')->nullable(true);
                $table->timestamps();
            });
        }
    
        /**
         * Reverse the migrations.
         */
        public function down(): void
        {
            Schema::dropIfExists('comments');
        }
    };
    

    Modelの準備

    以下のコマンドでModelを作成します。

    php artisan make:model Todo
    php artisan make:model Comment

    Modelは以下のように修正します。

    <Todo.php>

    
    <?php
    
    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Factories\HasFactory;
    use Illuminate\Database\Eloquent\Model;
    
    class Todo extends Model
    {
        use HasFactory;
        public function comments()
        {
            return $this->hasMany(comment::class);
        }
    }
    

    <Comment.php>

    
    <?php
    
    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Factories\HasFactory;
    use Illuminate\Database\Eloquent\Model;
    
    class Comment extends Model
    {
        protected $fillable = [
            'todo_id',
            'comment',
            'regist_user_id',
        ];
        use HasFactory;
        
        public function todo()
        {
            return $this->belongsTo(Todo::class);
        }
    }
    

    動作確認

    http://localhost:8000/admin/todos にアクセスして、以下のようにカラのリスト画面が表示されればOKです。

    準備ができましたので、formメソッドを編集しつつ、説明していきます。

    Laravel adminのformメソッドの使い方

    まずformメソッドについて記載します。

    formメソッドとは

    以下のような機能を持っています。新規登録・編集用のメソッドですね。

    • 入力フィールド:テキスト、数値、パスワード、セレクトボックス、ラジオボタン、チェックボックスなど。
    • バリデーション:入力データの検証機能。
    • リレーション管理:関連するデータモデルの管理。
    • イベントフック:フォームの保存前後に処理を追加。

    それではformメソッドを編集していきます。

    formメソッドの編集内容

    編集前(コマンドでコントローラ作成直後)は、以下の登録画面になっています。

    直したいポイントは以下です。

    1. Target user id(todoの担当者) を選択形式にしたい
    2. Regist user id(todoの作成者)はセッション情報から自動的に登録したい
    3. Statusは「0:未完了」で自動的に登録したい
    4. コメントを登録できるようにしたい(1対多のデータ登録)

    完成系の画面イメージは以下のような感じです。

    では順番に修正していきます。

    Target user id(todoの担当者) を選択形式にしたい

    ファイル上部でLaravel-adminのAdminクラスの名前空間を宣言します。

    use Encore\Admin\Facades\Admin;

    次に以下のように「target_user_id」をテキストからセレクトボックスに変更し、セレクトボックスの選択肢に、Adminユーザを指定します。

    // $form->text('target_user_id', __('Target user id'));  //コメントアウト
    $form->select('target_user_id', __('Target user id'))->options(Admin::user()->pluck('username', 'id')); //追加

    完了です。次にいきます。

    Regist user id(todoの作成者)はセッション情報から自動的に登録したい

    regist_user_idの入力ボックスをコメントアウトします。

    //$form->text('regist_user_id', __('Regist user id'));

    次に$form->savingを使ってregist_user_idにログイン中ユーザのIDを登録します。

            $form->saving(function (Form $form) {
                // regist_user_idは「Admin::user()->id」を設定する
                $form->model()->regist_user_id = Admin::user()->id;
            });

    完了です。次にいきます。

    Statusは「0:未完了」で自動的に登録したい

    statusの入力ボックスをコメントアウトします。

    //$form->number('status', __('Status'));

    次に$form->savingを使ってstatusに「0」を登録します。

            $form->saving(function (Form $form) {
                // regist_user_idは「Admin::user()->id」を設定する
                $form->model()->regist_user_id = Admin::user()->id;
                // statusは「0」を設定する
                $form->model()->status = 0;   //ここを追加
            });

    完了です。次はコメントです。

    コメントを登録できるようにしたい(1対多のデータ登録)

    以下のように記載することで、コメントを登録できるようになります。

            # コメント
            $form->hasMany('comments', 'コメント欄', function (Form\NestedForm $form) {
                $form->hidden('regist_user_id', __('regist_user_id'))->default(Admin::user()->id);
                $form->textarea('comment','コメント');
            });

    hasManyメソッドを使い、複数のコメントをフォームに追加できるようにしています。

    完成した画面

    以下の通り、実現したかった画面が出来上がりましたー

     

    編集画面でステータスを完了できるようにする

    このままだと、ステータスを完了にできないので、編集画面でステータスを完了できるようにします。

    以下のコードを書いてあげれば、ステータス更新可能になります。

            // ステータス更新(編集時のみ更新可能)
            if ($form->isEditing()) {
                $form->switch('status', '完了')->states([
                    'on' => ['value' => 1, 'text' => '完了', 'color' => 'success'],
                    'off' => ['value' => 0, 'text' => '未完了', 'color' => 'danger'],
                ]);
            }

    $form->isEditing()で登録か更新かの判定をしています。

    更新の場合、入力パーツswitchを表示するコードになっています。

    編集画面の完成系は以下のようになります!

     

    Laravel adminのgridメソッドの使い方

    まずgridメソッドについて記載します。

    gridメソッドとは

    以下のような機能を持っています。一覧ページ表示用のメソッドですね。

    • データ表示:データベースのレコードをテーブル形式で表示。
    • フィルタリング:条件に基づいてデータを絞り込む。
    • ソート:特定のカラムでデータを昇順または降順に並べ替え。

    一覧画面の直したいポイント

    直したいポイントは以下です。

    1. 自分が登録したtodoまたは自分が担当のtodoで検索したい
    2. 一覧で自分が担当のtodoは赤文字表示したい

    自分が登録したtodoまたは自分が担当のtodoで検索したい

    以下のコードを書いてあげれば、検索可能になります。

    作成者(regist_user_id)と担当者(target_user_id)のor検索になります。

            $grid->filter(function ($filter) {
                $filter->where(function ($query) {
                    if(array_search('1', $this->input) !== false) {
                        $query->orWhere('regist_user_id', Admin::user()->id);
                    }
                    if(array_search('2', $this->input) !== false) {
                        $query->orWhere('target_user_id', Admin::user()->id);
                    }
                }, '自分のtodoを表示', 'search_tantou')->checkbox([
                    '1' => '作成したtodoを表示',
                    '2' => '担当のtodoを表示',
                ]);
            });

    デフォルトで(画面アクセス時に)「作成者(regist_user_id)と担当者(target_user_id)のor検索」で絞り込みをしたい場合は、メニュー編集で対応できます。http://localhost:8000/admin/auth/menu にアクセスし、メニューを編集します。編集時に、URIを以下の通り設定します。

    todos?&search_tantou%5B%5D=1&search_tantou%5B%5D=2

    画面で説明すると、以下の画面のURIに上記の値を入力して保存です。

    一覧で自分が担当のtodoは赤文字表示したい

    以下のコードで、自分が担当のtodoを赤字で表示できます。

            // 文字色設定
            $grid->rows(function ($row) {
                # 自分が担当のtodoは、赤字にする
                if ($row->target_user_id == Admin::user()->id ) {
                    $row->style('color: red');
                }
            });

    完成した画面

    完成した一覧画面は以下の通りです。

    URIを「todos?&search_tantou%5B%5D=1&search_tantou%5B%5D=2」に変更した場合、画面表示直後は、「自分のtodoの表示」のチェックボックスはONになっているはずです。

    以下が実現できましたー

    • デフォルトでの検索条件の指定
    • チェックボックスでor検索の実装
    • 一覧の文字色変更

    修正後のコントローラの全体ソース

    修正後のコントローラの全体ソースは以下の通りです。

    
    <?php
    
    namespace App\Admin\Controllers;
    
    use App\Models\Todo;
    use Encore\Admin\Controllers\AdminController;
    use Encore\Admin\Form;
    use Encore\Admin\Grid;
    use Encore\Admin\Show;
    use Encore\Admin\Facades\Admin;
    
    class TodoController extends AdminController
    {
        /**
         * Title for current resource.
         *
         * @var string
         */
        protected $title = 'Todo';
    
        /**
         * Make a grid builder.
         *
         * @return Grid
         */
        protected function grid()
        {
            $grid = new Grid(new Todo());
    
    
            $grid->filter(function ($filter) {
                $filter->where(function ($query) {
                    if(array_search('1', $this->input) !== false) {
                        $query->orWhere('regist_user_id', Admin::user()->id);
                    }
                    if(array_search('2', $this->input) !== false) {
                        $query->orWhere('target_user_id', Admin::user()->id);
                    }
                }, '自分のtodoを表示', 'search_tantou')->checkbox([
                    '1' => '作成したtodoを表示',
                    '2' => '担当のtodoを表示',
                ]);
            });
    
            $grid->column('id', __('Id'));
            $grid->column('todo_name', __('Todo name'));
            $grid->column('target_user_id', __('Target user id'));
            $grid->column('regist_user_id', __('Regist user id'));
            $grid->column('status', __('Status'));
            $grid->column('created_at', __('Created at'));
            $grid->column('updated_at', __('Updated at'));
    
            // 表示色
            $grid->rows(function ($row) {
                # 自分が担当のtodoは、赤字にする
                if ($row->target_user_id == Admin::user()->id ) {
                    $row->style('color: red');
                }
            });
    
            return $grid;
        }
    
        /**
         * Make a show builder.
         *
         * @param mixed $id
         * @return Show
         */
        protected function detail($id)
        {
            $show = new Show(Todo::findOrFail($id));
    
            $show->field('id', __('Id'));
            $show->field('todo_name', __('Todo name'));
            $show->field('target_user_id', __('Target user id'));
            $show->field('regist_user_id', __('Regist user id'));
            $show->field('status', __('Status'));
            $show->field('created_at', __('Created at'));
            $show->field('updated_at', __('Updated at'));
    
            return $show;
        }
    
        /**
         * Make a form builder.
         *
         * @return Form
         */
        protected function form()
        {
            $form = new Form(new Todo());
    
            $form->text('todo_name', __('Todo name'));
    //        $form->text('target_user_id', __('Target user id'));
            $form->select('target_user_id', __('Target user id'))->options(Admin::user()->pluck('username', 'id'));
    //        $form->text('regist_user_id', __('Regist user id'));
    //        $form->number('status', __('Status'));
    
            # コメント
            $form->hasMany('comments', 'コメント欄', function (Form\NestedForm $form) {
                $form->hidden('regist_user_id', __('regist_user_id'))->default(Admin::user()->id);
                $form->textarea('comment','コメント');
            });
    
            // ステータス更新(編集時のみ更新可能)
            if ($form->isEditing()) {
                $form->switch('status', '完了')->states([
                    'on' => ['value' => 1, 'text' => '完了', 'color' => 'success'],
                    'off' => ['value' => 0, 'text' => '未完了', 'color' => 'danger'],
                ]);
            }
    
            $form->saving(function (Form $form) {
                // regist_user_idは「Admin::user()->id」を設定する
                $form->model()->regist_user_id = Admin::user()->id;
                // statusは「0」を設定する
                $form->model()->status = 0;
            });
    
            return $form;
        }
    }
    

     

    まとめ

    Laravel adminで以下の修正をしてみました。結構短時間でできたと思います。Laravel admin素晴らし〜

    • 登録・編集(formメソッド)
      • セレクトボックスの設置
        • 選択肢はDBから取得
      • 入力ボックスを使わないデフォルト値設定
      • 1対多のテーブルでのデータ登録
    • フィルター・一覧(gridメソッド)
      • デフォルトでの検索条件の指定
      • チェックボックスでor検索の実装
      • 一覧の文字色変更
    ]]>
    【初心者向け】意外と知らない便利なLinuxコマンド(「cd+スペース+ハイフン」とcalとtouchコマンドのご紹介) https://it.kensan.net/linux_command.html Fri, 07 Jun 2024 23:34:46 +0000 http://35.78.204.110/it/?p=2046 意外と知らない便利なLinuxコマンド集です。

    以下のコマンドを紹介します。

    • cd -(cd+スペース+ハイフン)コマンド
      • 前に居たフォルダと今居るフォルダを行き来できる
    • calコマンド
      • カレンダーを確認できます。
    • touch
      • ファイルのタイムスタンプを更新できる

    「cd -」で前に居たフォルダと今居るフォルダを行き来する

    以下のコマンドで、前に居たフォルダと今居るフォルダを行き来できます。

    cd -

    ぜひ使ってみてください。

    「cal」コマンドでカレンダーを確認する

    以下のコマンドで、カレンダーを確認できます。

    cal

    以下のようにカレンダーが表示されます。

    「touch」でファイルのタイムスタンプを更新する

    以下のコマンドで、ファイルのタイムスタンプを更新できます。

    touch {ファイル名}

    ファイルが存在しない場合、空ファイルを作成する挙動となります。

    まとめ

    意外と知らない便利なLinuxコマンドを紹介させていただきました。

    サーバ監視で使える便利なコマンドの記事もありますので、よろしければ以下をご参照ください!

    【初心者向け】サーバー監視で使える便利なLinuxコマンド(topとdfとlessとtailコマンドのご紹介)
    サーバー監視で使える便利なLinuxコマンド集です。 以下のコマンドを紹介します。 topコマンド CPU・メモリ・プロセスが確認できる dfコマンド ディスク空き容量が確認できる ログ確認コマンド lessコマンド 安全にファイルを開ける...
    ]]>
    AWS API Gatewayの統合タイムアウト制限の29秒が、30秒以上に引き上げ可能になった https://it.kensan.net/amazon-api-gateway-limit-29.html Wed, 05 Jun 2024 04:44:34 +0000 http://35.78.77.41/it/?p=2023 AWS API Gatewayの統合タイムアウト制限の29秒が、30秒以上に引き上げ可能になったようです。

    以下の記事に詳細記載されています。

    Amazon API Gateway integration timeout limit increase beyond 29 seconds - AWS
    Discover more about what's new at AWS with Amazon API Gateway integration timeout limit increase beyond 29 seconds

    以下要約です。

    • タイムアウト延長: 以前の29秒からそれ以上に設定可能。
    • 対象API: リージョナルREST APIおよびプライベートREST API。
    • 使用例: Generative AIなど、長時間処理を必要とするワークロードに対応。
    • 追加費用: 追加費用なしで利用可能。
    • 制限: アカウントレベルでクォータ制限の調整が必要。

    要するに、統合タイムアウトは29秒のままだけど、30秒以上に引き上げは可能になったよということです。

    Service Quotasを確認すると以下の通り、統合タイムアウトが、アカウントレベルでの引き上げリクエスト可能になっています。

     

    ]]>
    EC2のcronバッチを「EventBridgeをトリガーにStep Functionsを起動」に置き換えると、エラーハンドリングが快適になる https://it.kensan.net/eventbridge-stepfunctions-ec2-batch.html Mon, 03 Jun 2024 04:08:30 +0000 http://35.79.221.73/it/?p=2013 AWSのEC2で定期的なタスクを自動化するために、cronを使用しているケースも多いと思います。

    しかし、Amazon Linux 2023ではcronがデフォルトで無効になっています。これはcron以外に、cronのようなバッチ実行・定期実行する仕組みがあるということなのかと思い、cronを使わずにE2上でバッチ実行・定期実行する仕組みを考えてみました。

    そして、Amazon EventBridge、AWS Step Functions、およびAWS Systems Manager startAutomationExecutionを組み合わせて、EC2インスタンス上でバッチ・定期実行を試してみましたので、紹介します。

    特に、Step Functionsを使用することで、エラーハンドリングや通知が容易になり、安全にバッチ実行できるようになります。

    エラーハンドリングは以下の状態を把握したいという意味合いです。

    • 成功
    • 失敗
    • タイムアウト(バッチ実行に想定以上に時間がかかっている状態)

    使用するAWSサービスの概要

    Amazon EventBridge

    EventBridgeは、さまざまなAWSサービスやアプリケーションからのイベントをルーティングするサービスです。特定のイベントに基づいてStep Functionsをトリガーするのに適しています。

    AWS Step Functions

    Step Functionsは、複数のAWSサービスを連携させるワークフローを構築するためのサービスです。ワークフロー内でのエラーハンドリングやリトライ処理が容易であり、信頼性の高いタスク管理が可能です。

    AWS Systems Manager startAutomationExecution

    SSM オートメーション ドキュメントに則った処理をしてくれます。

    実際に試してみる

    EC2の準備

    EC2の起動

    バッチ実行環境のEC2を起動します。

    • Amazon Linux 2023 AMIを指定
    • インスタンスタイプは、t4g.nanoなど安いやつを選びます
    • ネットワーク設定で「からの SSH トラフィックを許可」を指定する
      • セキュリティを考慮して、アクセス元は絞った方がいい
    • EC2へはEC2 Instance Connectで接続するため、キーペアはなしでOK

    EC2の中に入る

    • 諸々設定するため、以下の流れで起動したEC2の中に入ります
      • AWSコンソールのEC2の一覧で、該当のEC2を選択して、接続を押下
        • EC2 Instance Connectタブの接続を押下

    EC2上でテスト用のスクリプトを作成

    vi test.sh

    <スクリプトの中身>

    exit 0;

    スクリプトに実行権限をつける

    chmod u+x test.sh

    Step Functionsの準備

    まず、Step Functionsでワークフローを作成します。このワークフローでは、Systems Manager startAutomationExecutionを使用してEC2インスタンス上でバッチジョブを実行します。

    Step Functionsのステートマシンを用意

    以下は、EC2インスタンス上でバッチジョブを実行するようになっています。

    プログラムが異常終了・時間以内(60秒)に終わらない場合、異常終了となります。

    
    {
      "Comment": "A description of my state machine",
      "StartAt": "StartAutomationWaitForCallBack",
      "States": {
        "StartAutomationWaitForCallBack": {
          "Type": "Task",
          "Resource": "arn:aws:states:::aws-sdk:ssm:startAutomationExecution.waitForTaskToken",
          "Parameters": {
            "DocumentName": "SfnRunCommandByInstanceIds",
            "Parameters": {
              "InstanceIds": [
                "{インスタンスID}"
              ],
              "taskToken.$": "States.Array($$.Task.Token)",
              "workingDirectory": [
                "/"
              ],
              "Commands": [
                "/test.sh"
              ],
              "executionTimeout": [
                "60"
              ],
              "deliveryTimeout": [
                "60"
              ],
              "shell": [
                "Shell"
              ]
            }
          },
          "End": true
        }
      }
    }

    以下のポリシーをアタッチします。

    
    {
    	"Version": "2012-10-17",
    	"Statement": [
    		{
    			"Effect": "Allow",
    			"Action": "ssm:StartAutomationExecution",
    			"Resource": "*"
    		}
    	]
    }

    SSM オートメーション ドキュメントの作成

    以下の「SfnRunCommandByInstanceIds」を使用させていただきます。

    GitHub - aws-samples/amazon-stepfunctions-ssm-waitfortasktoken: This pattern implements an automation document wrapper around AWS-RunShellScript execution for a AWS Step Functions waitForTaskToken integration.
    This pattern implements an automation document wrapper around AWS-RunShellScript execution for a AWS Step Functions waitForTaskToken integration. - GitHub - aws...

    SfnRunCommandByInstanceIds」はCloudFormationで作成できます。

    このファイルをダウンロードして、CloudFormationで実行すれば作成できます。

    EventBridgeの設定

    次に、EventBridgeを設定して、Step Functionsの実行をトリガーします。

    1. EventBridgeのルール作成: EventBridgeのダッシュボードに移動し、「ルールを作成」をクリックします。
    2. ルールの設定:
      • イベントソース: スケジュール(例えば、毎日午前2時に実行)を選択し、cron式を設定します。例えば、cron(0 2 * * ? *)
      • ターゲット: ターゲットとして、Step Functionsのステートマシンを選択します。
    3. ターゲットの設定: Step FunctionsのステートマシンのARNを指定します。

    動作確認

    • EC2のtest.shに「exit 0」を記載した状態で実行
      • StepFunctionsが成功していればOK
    • EC2のtest.shに「exit 1」を記載した状態で実行
      • StepFunctionsが失敗していればOK
    • EC2のtest.shに「sleep 61」と「exit 0」を記載した状態で実行
      • タイムアウトするので、StepFunctionsが失敗していればOK

    上記記載の方法のメリットとデメリット

    メリット

    • 柔軟なスケジューリング: EventBridgeを使用することで、定期的なスケジュール設定が容易になります。
    • 詳細なエラーハンドリング: Step Functionsを使用することで、ジョブの成功、失敗、遅延に対する詳細なエラーハンドリングと通知が可能です。

    デメリット

    • 設定の複雑さ: EventBridge、Step Functions、Systems Manager の設定が必要なため、設定手順が複雑になる可能性があります。
    • コスト: 複数のAWSサービスを使用するため、コストが増加する可能性があります。

    まとめ

    Amazon Linux 2023ではcronがデフォルトで無効になっているため、AWSのサービスを組み合わせて定期的なタスクを実行する方法を検討してみました。

    EventBridge、Step Functions、Systems Manager startAutomationExecutionを使用することで、EC2インスタンス上で定期的なバッチジョブを実行し、エラーハンドリングを実現できました。

    エラーの場合、通知するようにしておけばEC2でのバッチ実行も安心かなと思います!

    バッチの実行は他にもいろいろな方法がありますので、気になる方は以下のリンクをクリックくださーい

    AWS でバッチ処理・定期実行する4つの方法(EC2,EventBridge,SQS,ECS,Lambda)
    AWS上でバッチ処理を行う場合に、 「どのサービスが選択肢として考えられるか」 「どのサービスを選択すればいいのか」 についてです。 バッチの起動方式として「Cron」 「ECS Task Scheduler」 「キュー」 「Web API」をあげて、特徴等を踏まえて、どのような場合にどのような選択をすればいいか記載。
    ]]>
    Laravelをコンテナで運用する際のログ出力は、JSON形式で標準出力した方が良い https://it.kensan.net/laravel11-log.html Sun, 02 Jun 2024 00:51:23 +0000 http://18.181.252.126/it/?p=2004 Laravelをコンテナで運用する際のログ出力は、JSON形式で標準出力した方が良いということを書いていきます。

    Laravelに限らず、コンテナでは、JSON形式で標準出力が良いと思いますが、Laravelでは簡単にログをJSON形式で標準出力可能ですので、設定しておいた方が良いと思います!

    なぜ、ログをJSON形式で標準出力するのか

    なぜJSON形式か

    JSON形式はデータを構造化し、分析や監視ツールで扱いやすい形式です。

    また、新しい情報を追加するのも容易なため、ログ出力はJSON形式が良いと考えています。

    JSON化しておけば、たとえば、AWSのCloudWatchでログ検索する際などで便利です。

    なぜ標準出力か

    多くのクラウドプロバイダーは、コンテナの標準出力からログを収集し、そのログを分析や可視化するためのツールやサービスを提供しているためです。

    AWSで言うと、Fargateでのコンテナでログを標準出力すると、CloudWatchログの1つのロググループにまとまってくれて、簡単にログ検索できます。

    これにより、運用やデバッグがスムーズに行えます。

    以下の記事のようなメトリクスフィルターも簡単に作れたりします。

    CloudWatchLogsのメトリクスフィルターの使い方ーログデータをメトリクス化して監視する
    メトリクスフィルターを使いCloudWatchLogsのログデータを 「CloudWatchのメトリクスで見える化する」「メトリクスを監視してアラートをあげる」ということをやってみます。JSONログデータのメトリクス化も可能です。メトリクス化ができれば監視は通常のアラーム設定と同様となります

    では、Laravel11を例にログをJSON形式で標準出力する方法を記載します。

    Laravel11でログをJSON形式で標準出力する

    config/logging.phpの修正

    • config/logging.phpの2箇所修正します
      •  「use Monolog\Formatter\JsonFormatter;」を追加
      • channelsの中に以下のようにstdoutを追加
    
    
    use Monolog\Formatter\JsonFormatter;   // これを追加
    :
    :
    :
    
    
    
        'channels' => [
            // 以下を追加
            'stdout' => [
                'driver' => 'monolog',
                'level' => env('LOG_LEVEL', 'debug'),
                'handler' => StreamHandler::class,
                'with' => [
                    'stream' => 'php://stdout',
                ],
                'formatter' => JsonFormatter::class,
            ],

    .envの修正

    .envを修正します。

    以下のように、LOG_CHANNEL=stackをコメントアウトして、LOG_CHANNEL=stdoutを追加します。

    
    #LOG_CHANNEL=stack  // コメントアウト
    LOG_CHANNEL=stdout  // 追加

     

    動作確認

    routes/web.phpでログ出力するようにして動作確認します。

    •  routes/web.phpの2箇所を修正します
      • 「use Illuminate\Support\Facades\Log;」を追加する
      • 「Log::debug(‘test’);」を追加する
    use Illuminate\Support\Facades\Route;
    use Illuminate\Support\Facades\Log;   // 追加
    
    Route::get('/', function () {
        Log::debug('json_log_test');   // 追加
        return view('welcome');
    });

    Laravelアプリにアクセスし、以下のようにターミナル上に出力されれば、JSON形式でログを標準出力できています。

    
    {"message":"json_log_test","context":{},"level":100,"level_name":"DEBUG","channel":"local","datetime":"2024-06-02T00:27:24.540572+00:00","extra":{}}
    

    まとめ

    Laravelをコンテナで運用する際には、ログをJSON形式で標準出力することで、運用やデバッグを効率化できます。設定方法も簡単です!

    ]]>
    【SQL】SELECT文でスロークエリを発生させる方法〜SELECT SLEEPを使ってスロークエリーを発生させる〜 https://it.kensan.net/select-slow-query.html Sat, 01 Jun 2024 01:57:13 +0000 http://52.192.132.163/it/?p=1990 スロークエリを意図的に発生させる方法について記載します。

    なぜスロークエリを発生させるのか

    スロークエリをわざと発生させることで、以下のようなことに役立ちます。

    • パフォーマンステスト: システムがスロークエリに対してどのように反応するかを評価
    • 監視システムのテスト: スロークエリが発生した場合、監視ツールが適切にアラートを出すか確認
    • トラブルシューティング: スロークエリが原因でシステムがどのように挙動するかを再現し、問題解決

    SELECT SLEEP(5); とは?

    「SELECT SLEEP(5);」はSQLコマンドで、指定した時間(この場合は5秒)だけ待機します。このコマンドを利用することで、意図的にスロークエリを発生させることができます。

    実際に使ってみる

    以下はMySQLでの使用例です。

    
    mysql> SELECT SLEEP(5);
    +----------+
    | SLEEP(5) |
    +----------+
    |        0 |
    +----------+
    1 row in set (5.00 sec)

    このように、クエリが5秒間実行されます。

    スロークエリログに記録されるか確認する

    次に、このクエリがスロークエリログに記録されるかを確認します。MySQLでは、スロークエリの閾値を設定することができます。例えば、2秒以上のクエリをスロークエリとして記録するには、以下のように設定します。

    SET GLOBAL long_query_time = 2;

    この設定を行った後に「SELECT SLEEP(5);」を実行すると、このクエリはスロークエリログに記録されます。

    まとめ

    「SELECT SLEEP(5);」を使用してスロークエリを発生させる方法について記載しました。このSQLを使用することで、パフォーマンステストや監視システムのチェックが容易になり、トラブルシューティングにも役立つかと思います!

    ]]>
    Rails 7.2をインストールして起動してみる https://it.kensan.net/rails7-2-install.html Sat, 01 Jun 2024 01:32:38 +0000 http://52.192.132.163/it/?p=1983 この記事では、Rails 7.2をインストールし、起動するまでの手順を説明します。

    具体的には以下のブランチのRails7.2を起動する方法を記載していきます。

    GitHub - rails/rails at 7-2-stable
    Ruby on Rails. Contribute to rails/rails development by creating an account on GitHub.

    Railsプロジェクト作成

    まず、以下のコマンドで新しいRailsプロジェクトを作成し、そのプロジェクトディレクトリに移動します。

    rails new test_app
    
    cd test_app/

    次に、Railsのバージョンを確認します。

    rails -v
    
    Rails 7.1.3.3

    この時点では、Rails 7.1系がインストールされているはずです。

    Rails7.2へアップデート

    Rails 7.2にアップデートするために、Gemファイルを修正します。

    vi Gemfile

    以下の内容でGemfileを修正します。

    #gem "rails", "~> 7.1.3", ">= 7.1.3.3"     #コメントアウト
    
    gem "rails", github: "rails/rails", branch: "7-2-stable"     #これを追加

    次に、以下のコマンドでRails 7.2にアップデートします。

    bundle install

    動作確認

    最後に、以下のコマンドでサーバを立ち上げます。

    rails server

    ブラウザでhttp://localhost:3000/にアクセスし、「Rails version: 7.2.0」と表示されていれば成功です。

    以上で、Rails 7.2のインストールと起動が完了です。

    まとめ

    以下のブランチを指定して、Rails7.2を起動する方法を記載しました!

    GitHub - rails/rails at 7-2-stable
    Ruby on Rails. Contribute to rails/rails development by creating an account on GitHub.

     

    ]]>