- 投稿日:2021-07-20T22:05:41+09:00
Github Actions で Laravel + MySQLのテスト
前回の環境を使用します。 ワークフローの作成 wsl mkdir -p .github/workflows touch laravel.yml laravel.yml name: Laravel on: push: branches: [ main ] paths: - 'src/**' pull_request: branches: [ main ] paths: - 'src/**' jobs: laravel-tests: runs-on: ubuntu-latest services: mysql: image: mysql:5.7 ports: - 3306:3306 env: MYSQL_DATABASE: laravel MYSQL_ROOT_PASSWORD: test options: --health-cmd "mysqladmin ping -h localhost" --health-interval 20s --health-timeout 10s --health-retries 10 env: DB_CONNECTION: mysql DB_HOST: 127.0.0.1 DB_PORT: 3306 DB_DATABASE: laravel DB_USER_NAME: root DB_PASSWORD: test steps: - uses: shivammathur/setup-php@15c43e89cdef867065b0213be354c2841860869e with: php-version: '7.4' - uses: actions/checkout@v2 - name: Initalize MySQL run: mysql -h 127.0.0.1 --port 3306 -uroot -ptest -e "$(cat docker/mysql/initdb.d/*.sql)" - name: Copy .env working-directory: ./src run: php -r "file_exists('.env') || copy('.env.example', '.env');" - name: Install Dependencies working-directory: ./src run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist - name: Generate key working-directory: ./src run: php artisan key:generate - name: Directory Permissions working-directory: ./src run: chmod -R 777 storage bootstrap/cache - name: Execute tests (Unit and Feature tests) via PHPUnit working-directory: ./src run: vendor/bin/phpunit 動作テスト 失敗するテストを試す テストファイルの作成 wsl docker-compose exec php php artisan make:test GithubActionsTest ./src/tests/Feature/GithubActionsTest <?php namespace Tests\Feature; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\WithFaker; use Tests\TestCase; class GithubActionsTest extends TestCase { /** * A basic feature test example. * * @return void */ public function test_example() { $this->assertTrue(false); } } ローカルで実行 wsl docker-compose exec php php artisan test Github上で実行 変更をプッシュ DBの初期化&接続テスト テストファイルの作成 先ほど作成したファイルを編集します。 ./src/tests/Feature/GithubActionsTest <?php namespace Tests\Feature; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\WithFaker; use Tests\TestCase; class GithubActionsTest extends TestCase { /** * A basic feature test example. * * @return void */ public function test_example() { $this->assertDatabaseHas('users', [ 'name' => 'Dog', ]); } } ローカルで実行 wsl docker-compose exec php php artisan test Github上で実行 変更をプッシュ
- 投稿日:2021-07-20T13:55:54+09:00
railsコンソール:実行環境の切替え
はじめに テストコードを書く際に、データベースに値を入れて検証したいと思ったが コンソールがデフォルトだとdevelopment(開発環境)だと気づく。 テスト環境や本番環境など、別環境への切替方法を調べたので 記録として残しておく。 ■使用データベース: MySQL 実行環境の種類 実行環境は3つ存在するので、状況に応じて切り替えする。 開発環境 (development) テスト環境 (test) 本番環境 (production) コンソール 記述したコードが正しく動作しているかを確認するもの。 rails cコマンドで起動できる。 ただし、デフォルトは開発環境。 % rails c Running via Spring preloader in process 25986 Loading development environment (Rails 6.1.4) irb(main):001:0> 現況確認 コンソール画面で、Rails.envコマンドで実行すると 現在の実行環境が返答される。 irb(main):001:0> Rails.env => "development" 環境を切替え コンソールから抜け出した後、linuxコマンドを打つ。 返答はないが、export RAILS_ENV=testコマンドで 実行環境がテスト環境に変わっている。 % export RAILS_ENV=test もし本番環境に変更したい場合は export RAILS_ENV=productionとする。 コンソールを起動 再びrails cコマンドを実行する。 % rails c Running via Spring preloader in process 26085 Loading test environment (Rails 6.1.4) irb(main):001:0> すると、表示されている環境が development → testに変更されているのが分かる。 データベースへ値の入力 Userモデルに、新規ユーザーを作成してみる。 ちゃんと、データが作成されている様子。 irb(main):001:0> User.create(name: "Test", email: "test@mail.com", password: "1122334455") TRANSACTION (0.3ms) BEGIN User Exists? (0.4ms) SELECT 1 AS one FROM `users` WHERE `users`.`email` = 'test@mail.com' LIMIT 1 User Create (0.4ms) INSERT INTO `users` (`name`, `email`, `created_at`, `updated_at`, `password_digest`, `activation_digest`) VALUES ('Test', 'test@mail.com', '2021-07-20 04:33:44.655390', '2021-07-20 04:33:44.655390', '$2a$04$ScRQSjFBEzENKlmFvdh7jug0nhwLmMtjFwH2GLdapCbiEab5pk24O', '$2a$04$PYLIqUcQuXZKmv2vcq71s.FzWgPmjTBk35.Rcf4HonQYYFm1qoBCC') TRANSACTION (0.6ms) COMMIT MySQLで確認 showコマンドで存在するテーブルを確認後、 select文で表示カラムをnameとemailに設定して表示させる。 mysql> show tables; +--------------------------------+ | Tables_in_<アプリ名>_test | +--------------------------------+ | articles | | relationships | | users | +--------------------------------+ mysql> select name, email from users; +------+-------------------+ | name | email | +------+-------------------+ | Test | test@mail.com | +------+-------------------+ ちゃんと、ユーザーが作成されているので上手くいっているはず。 番外:DBに保存せずに検証したい 下記コマンドなら、コンソール終了後にロールバックされるので DB上にデータが残らない。 検証はしたいが、データは残したくない場合に便利。 % rails c --sandbox Running via Spring preloader in process 26196 Loading development environment in sandbox (Rails 6.1.4) Any modifications you make will be rolled back on exit 終わりに 簡単な内容ではあるが、まとめてみた。 今後も学習記録を残す。 以上。
- 投稿日:2021-07-20T11:57:35+09:00
俺のSQL
よく書くけど毎回ググってる気がするMySQLのクエリーメモ 前日から直近1ヶ月のデータを抽出 カラムがdatetime(時分秒持ってる)のとき WHERE DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY) <= updated_at AND updated_at < CURRENT_DATE CURRENT_DATE は当日のdate(YYYY-MM-DD) を取得する関数 dateとdatetimeの比較メモ 2021-07-20 23:59:59 < 2021-07-21 2021-07-20 <= 2021-07-20 00:00:00
- 投稿日:2021-07-20T07:27:54+09:00
【MySQL】「SET sql_mode = ' '」は何をしているのか
結論 SQLモードを明示的にクリアすることで、デフォルトのSQLモード設定を利用することを指定しています。 SQLモードとは サーバー SQL モードは、MySQL でサポートされる SQL 構文、および実行されるデータ妥当性チェックの種類を定義します。これにより、MySQL をさまざまな環境で使用したり、MySQL をほかのデータベースサーバーと一緒に使用したりすることが、さらに容易になります。MySQL サーバーは、これらのモードを各クライアントに個別に適用します。 参考:5.1.7 サーバー SQL モード 現在のSQLモードの確認 SQLモードには複数の項目があり、個別にON/OFFを指定できます。 MySQL5.7のデフォルトのSQLモード設定では、以下に示す7つの項目がONになっています。 SELECT @@global.sql_mode; -- 出力(以下はデフォルトの設定) +-------------------------------------------------------------------------------------------------------------------------------------------+ | @@global.sql_mode | +-------------------------------------------------------------------------------------------------------------------------------------------+ | ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION | +-------------------------------------------------------------------------------------------------------------------------------------------+ それぞれのモードについては5.1.7 サーバー SQL モードを参照のこと。 SQLモードの設定 1.SETコマンドで設定する -- デフォルトの設定にする場合 SET GLOBAL sql_mode = ''; -- 特定の項目をオンにする場合 SET GLOBAL sql_mode = '<モード名>'; 2.my.cnfなどの設定ファイルにmodeを追記してMySQLを再起動する sql-mode='<モード名>'
- 投稿日:2021-07-20T03:28:18+09:00
Aurora MySQLでIAM認証する手順と検証メモ
Aurora MySQLでIAM認証を検証したので、備忘録を兼ねて諸々メモ。 AuroraのIAM認証とは? DBユーザーに、個別のパスワード入力の代わりにIAMクレデンシャルで認証する機能。 DBごと、ユーザーごとのパスワード管理が不要になる。 スロットルのリスクがあるためアプリケーションの認証には不向きだが、運用に伴う人による認証については一考の価値がある。 Aurora側での設定 クラスターでIAM認証を有効化しておく。マネジメントコンソールでいうと、インスタンス設定(≠クラスター設定)の以下が該当設定。 データベースで、IAM認証を有効にしたDBユーザーを作成する。IAM認証は、あくまでこのDBユーザーに対して、AWSプロファイルのIAMクレデンシャルでログインする行為であって、DBユーザーがないと機能しない点に注意。 DBユーザーの作成 CREATE USER ssotest IDENTIFIED WITH AWSAuthenticationPlugin AS 'RDS'; 踏み台インスタンスでの設定 DB接続用のmysqlクライアントを事前にインストールしておく。 実は微妙にハマリポイント。Amazon Linux 2で普通にsudo yum install mysqlとすると、MariaDB互換クライアントがインストールされる(Amazon Linux 1だとMySQL純正クライアントが入る)のだが、MariaDB互換クライアントを使う場合、公式ドキュメントに記載のオプションではログインできない(後述の通り、別のオプションを使えば行けるが、そこに辿り着くまで大分かかった)。 MySQL純正クライアントをインストールしてもよいが、アークテクチャーを選んでローカルインストールなど若干面倒くさい手順が必要になるので、ここでは一行で済むMariaDB互換をインストールする。 IAM認証時は、TLS接続設定に関わらずAuroraのCA証明書が必要になるので、ホームディレクトリあたりにwgetしておく。 少し前はrds-ca-2019-root.pemだったが、いつのまにか変わったらしい。リージョンごとの差異を吸収する CA証明書の保存 % wget https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem 権限付与の方針決定 DBへのアクセスは一般に、パブリックアクセスは勿論、任意の端末からの接続を禁止するために、VPC内の特定のEC2インスタンス(踏み台)からのアクセスにセキュリティグループで縛ることが多いと思う。そうでないパターンも当然あり得るが、ここでは一応、踏み台パターンを前提とする。 IAM認証には接続トークンの生成が必要になるが、踏み台からのIAM認証パターンは以下の二種類が考えられる。違いは、「誰の権限で・どこでトークンを生成するか」の観点。 踏み台のインスタンスプロファイル(ロール)にIAM認証を許可するポリシーを付与。接続トークンは踏み台内で生成して環境変数に格納。 踏み台には権限を付与せず、それ以外のIAMロールにIAM認証を許可するポリシーを付与。接続トークンは別端末で生成してコピペ。 具体的には、以下のようなポリシーをどこのロールに割り当てるかの話になる。 IAM認証ポリシー例 { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "rds-db:connect" ], "Resource": [ "arn:aws:rds-db:ap-northeast-1:123456789012:dbuser:test-cluster/ssotest" ], "Condition": { "ForAnyValue:StringLike": { "aws:PrincipalOrgPaths": "o-oXXXXXXXXX/r-YYYY/ou-ZZZZZZZZZZZZZ/*" } } } ] } プロコンはざっくり以下のようなイメージ。今回は踏み台の多系統化を避けて「別のIAMロール案」とする。具体的にはAWS SSOを使い、アクセス権限セットにrds-db:connectを付与する。 インスタンスプロファイル案 別のIAMロールに付与する案 利点 認証操作がシンプル 踏み台は一系統でよい 欠点 権限ごとに踏み台を分岐する必要がある トークンを持ち込む必要がありひと手間かかる 接続 まずは認証トークン取得。前述の方針に従い、今回はAWS SSOでログイン後、踏み台の外でトークンを取得する(踏み台でトークン生成コマンドを叩くと、踏み台のインスタンスプロファイルの権限内で生成され、今回だとどこにも接続できないことになるため)。 認証トークン取得 % aws sso login --profile ssotest-profile % aws rds generate-db-auth-token \ > --hostname hoge \ > --region ap-northeast-1 \ > --port 3306 \ > --username ssotest \ > --profile ssotest-profile トークンが生成されたら、クリップボードにコピーする。本来は環境変数に格納するのが楽なのだが、今回は踏み台に持ち込む必要上、コピペで対応する。 踏み台にSSM Sessions Manager等でログイン後、DB接続を実行する。ここではMariaDB互換クライアントのパターンを使用するが、参考までにMySQL純正クライアントのパターンも併記しておく。 DB接続(MariaDB互換クライアントのパターン) % TOKEN='(先程取得したトークンの文字列をそのままコピペ)' % mysql -h <Auroraエンドポイント>.ap-northeast-1.rds.amazonaws.com \ > --port=3306 \ > --user=ssotest \ > --password=$TOKEN \ > --ssl-ca=~/global-bundle.pem \ > --default-auth=mysql_clear_password DB接続(MySQL互換クライアントのパターン) % mysql -h <Auroraエンドポイント>.ap-northeast-1.rds.amazonaws.com \ > --port=3306 \ > --user=ssotest \ > --password=$TOKEN \ > --ssl-ca=~/global-bundle.pem \ > --enable-cleartext-plugin 無事繋がったら完了。 なかなかMySQLのプロンプトが出ないな?という場合は、セキュリティグループを見直してみることをお薦めする。ちゃんと3306が許可されてるかとか、Aurora側でEC2側セキュリティグループをIngressに含めているか、など。 Access Deniedの際は以下のようなエラーが即時返ってくるので、そうでない場合はまずネットワークを疑う。 AccessDeniedな場合の接続エラー ERROR 1045 (28000): Access denied for user 'ssotest'@'XXX.XXX.XXX.XXX' (using password: YES) 小ネタ トークンは15分だけ有効。 一度生成したらいつでもどこでも再利用できるわけではなく、一定期間で切れるようになっている。 別アカウントで取得したトークンは使えない。 IAMポリシーがどうあれ、アカウントをまたいでトークンを再利用することはできない。例えば、開発アカウントでたまたまrds-db:connect権限を持っていてトークンを生成できたとしても、それを使って本番アカウントのDBにログインすることができないようになっている。 「インスタンスプロファイル案」を選択して踏み台からトークンを生成する場合、当たり前だが、RDSのAPIエンドポイントへの経路が必要になる。 踏み台のEgressをガチガチに縛っている場合は、VPCエンドポイントが必要になるかも。 AdministratorAccessなど、iam:*を保持している権限だと、ポリシー内容に拘わらず全部接続できてしまう。 検証する際は注意しておかないと、想定した挙動にならなくて時間を無駄にする。 AWS SSOでも使える。 今は改修されているが、以前は公式ドキュメントに「DBユーザー名はロール名と同じにせよ」という誤記があり、ロール名にアカウントごとのランダム文字列が付記されるAWS SSOでは運用上成立しないように見えていたが、原文は"Make sure the specified database user name is the same as a resource in the IAM policy for IAM database access."なので単なる誤訳だったらしい。 Resourceの部分はワイルドカードを使える。つまり、 Resource句(個別指定) "Resource": [ "arn:aws:rds-db:ap-northeast-1:123456789012:dbuser:test-cluster/ssotest" ], は、要件に応じて、以下のようにも書き変えることができる。 Resource句(ワイルドカード) "Resource": [ "arn:aws:rds-db:*:*:dbuser:*/ssotest" ], ただし、このままだといささか範囲が広すぎるので、せめてOrganizationsで縛るくらいはしておくこと。要件によっては、対象アカウントを本番とそれ以外に分けたり、対象クラスターを分けたりとかもあるかも知れない。 Condition句(OU縛り) "Condition": { "ForAnyValue:StringLike": { "aws:PrincipalOrgPaths": "o-oXXXXXXXXX/r-YYYY/ou-ZZZZZZZZZZZZZ/*" } }