Memo

メモ > サーバ > サービス: AWS > ECR+ECS+Codeシリーズで自動デプロイ: RDSに接続する

■ECR+ECS+Codeシリーズで自動デプロイ: RDSに接続する
■Cloud9を作成 RDSにユーザやテーブルを作成するため、Cloud9を作成しておく (運用はコンテナなので、作業用にFargateやEC2を作成する…が、一時的に必要になるだけなのでCloud9を使う) Name: Test Description: (空欄のまま) Environment type: New EC2 instance Instance type: t2.micro (1 GiB RAM + 1 vCPU) Platform: Amazon Linux 2 (recommended) Cost-saving setting: After 30 minutes (default) ※再検証時は項目が無かったので未設定 IAM role: AWSServiceRoleForAWSCloud9 ※再検証時は項目が無かったので未設定 Network (VPC): Container ※コンテナ用のVPCを選択 Subnet: Container-Public-A ※外部からアクセスできる(Publicな)サブネットを選択 Cloud9のEC2には、以下のセキュリティグループが自動で割り当てられていた (EC2インスタンスの一覧から確認できる。このセキュリティグループは後から使用する) sg-04b8e304c2064b14d Environments一覧の「Cloud9 IDE」列の「Open」から接続できる 「Welcome」タブなどが開くが、「bash」タブからコマンドを入力できることを確認する ■パラメータグループの作成 パラメータグループファミリー: mariadb10.6 グループ名: container-test 説明: for Container-Test 以下のとおりパラメータを設定する character_set_client: utf8mb4 character_set_connection: utf8mb4 character_set_database: utf8mb4 character_set_results: utf8mb4 character_set_server: utf8mb4 init_connect: SET SESSION time_zone = CASE WHEN POSITION('rdsadmin@' IN CURRENT_USER()) = 1 THEN 'UTC' ELSE 'Asia/Tokyo' END; ■RDSの作成 データベース作成方法を選択: 標準作成 エンジンのオプション: MariaDB バージョン: MariaDB 10.6.10 テンプレート: 開発/テスト DBインスタンス識別子: container-test マスターユーザー名: admin マスターパスワード: qazwsxedc DBインスタンスクラス: バースト可能クラス(t クラスを含む) db.t3.micro ストレージタイプ: 汎用(SSD) ストレージ割り当て: 20GiB ストレージの自動スケーリング: (チェックを外す) マルチAZ配置: なし コンピューティングリソース: EC2コンピューティングリソースに接続 ※「EC2コンピューティングリソースに接続しない」だと、後からセキュリティグループを調整してもCloud9から接続できなかった。また検証したい EC2インスタンス: (上の手順で作成してCloud9のEC2インスタンスを選択する) Virtual Private Cloud: (初めから選択済みになっている)※「EC2コンピューティングリソースに接続」にすると、VPCを選択できない?選択したEC2に合わせて適切に設定される? DBサブネットグループ: 自動セットアップ(初めから選択済みになっている) 既存のVPCセキュリティグループ:(変更せずだが、「rds-ec2-1」が自動的に追加される) 最初のデータベース名: container DBパラメータグループ: container-test オプショングループ: default:mariadb-10-6 以下のセキュリティグループが作成&割り当てられていた ec2-rds-1 ... Cloud9に割り当てられていた rds-ec2-1 ... RDSに割り当てられていた ■RDSへの接続を許可 Cloud9からは、以下のようにして接続できる(mysqlはデフォルトでインストール済みだった) パスワードを入力しても、いつまで経っても結果が返ってこない場合、セキュリティグループの設定が正しいか確認する
$ mysql --version mysql Ver 15.1 Distrib 10.2.38-MariaDB, for Linux (x86_64) using EditLine wrapper $ mysql -h container-test.xxxxx.ap-northeast-1.rds.amazonaws.com -u admin -p Enter password: Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 8 Server version: 10.6.10-MariaDB managed by https://aws.amazon.com/rds/ Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [(none)]> SELECT VERSION(); +-----------------+ | VERSION() | +-----------------+ | 10.6.10-MariaDB | +-----------------+ 1 row in set (0.00 sec)
AWS Cloud9 環境を作成してAmazon Aurora Serverless MySQL データベースに接続する | DevelopersIO https://dev.classmethod.jp/articles/amazon-aurora-serverlessmysql-cloud9/ ■RDSに作業ユーザを作成
> CREATE USER webmaster IDENTIFIED BY 'qazwsxedc'; > GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, EVENT ON container.* TO webmaster; > FLUSH PRIVILEGES; > QUIT;
■RDSへの作業ユーザでの接続を確認&テーブルを作成
$ mysql -h container-test.xxxxx.ap-northeast-1.rds.amazonaws.com -u webmaster -p Enter password: > CREATE TABLE test_table( > id INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID', > text VARCHAR(255) NOT NULL COMMENT 'テキスト', > PRIMARY KEY(id) > ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT 'テスト'; > INSERT INTO test_table(text) VALUES('Test1'); > INSERT INTO test_table(text) VALUES('Test2'); > SELECT * FROM test_table; +----+-------+ | id | text | +----+-------+ | 1 | Test1 | | 2 | Test2 | +----+-------+ 2 rows in set (0.00 sec)
■Secrets ManagerにRDSへの接続情報を登録 ※環境変数や taskdef.json 内に、直接機密情報を記載しなくていいようにする Secrets Manager → 新しいシークレットを保存する シークレットのタイプを選択 シークレットのタイプ: Amazon RDS データベースの認証情報 ユーザー名: (RDS上に作成したユーザー) パスワード: (RDS上に作成したパスワード) 暗号化キー: aws/secretmanager (初回は「DefaultEncryptionKey」を選択するといい) データベース: (RDS上に作成したデータベース) 「次」ボタンをクリック シークレットを設定 シークレットの名前: dev/container-test/Mysql 「次」ボタンをクリック ローテーションを設定 - オプション 自動ローテーション: OFF 「次」ボタンをクリック レビュー 「保存」ボタンをクリック ■ポリシーの作成 ※ECSからSecrets Managerの情報を取得するためのポリシーを作成する セキュリティ認証情報 → ポリシー → ポリシーの作成 「JSON」タブに以下を入力する
{ "Version": "2012-10-17", "Statement": [ { "Sid": "GetSecretForECS", "Effect": "Allow", "Action": [ "secretsmanager:GetSecretValue" ], "Resource": [ "*" ] } ] }
「次のステップ:タグ」をクリック そのまま「次のステップ:確認」をクリック ポリシーの作成画面になるので以下を入力 名前: Container-Test-GettingSecretForECS 説明: Policy to get Secret for ECS 「ポリシーの作成」をクリック なお、上記のコードは書籍のサポートページ掲載されている sbcntr-resources/secrets_policy.json at main - uma-arai/sbcntr-resources - GitHub https://github.com/uma-arai/sbcntr-resources/blob/main/iam/secrets_policy.json ■タスク実行ロールの作成 ※ECSがタスクを実行するときのロールを作成する ※ロール ecsTaskExecutionRole を作成済みの場合、この手順は飛ばす セキュリティ認証情報 → ロール → ロールを作成 信頼されたエンティティを選択 信頼されたエンティティタイプ: AWSのサービス ユースケース 他のAWSのサービスのユースケース: Elastic Container Service → Elastic Container Service Task を選択 「次へ」ボタンをクリック 許可を追加 「AmazonECSTaskExecutionRolePolicy」を検索してチェックを入れる 「次へ」ボタンをクリック 名前、確認、および作成 ロール名: ecsTaskExecutionRole 「ロールを作成」ボタンをクリック Amazon ECS タスク実行IAM ロール - Amazon Elastic Container Service https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task_execution_IAM_role.html#creat... ECSのタスクロールとタスク実行ロールの違い - karakaram-blog https://www.karakaram.com/difference-between-ecs-task-role-and-task-execution-role/ ■タスク実行ロールにアクセス権限を付与 ※ECSがタスクを実行するとき、Secrets Managerの情報を取得できるように権限を付与する セキュリティ認証情報 → ロール 上の手順で作成した ecsTaskExecutionRole を選択 「許可を追加 → ポリシーをアタッチ」をクリック 上の手順中で作成した Container-Test-GettingSecretForECS にチェックを入れ、「ポリシーのアタッチ」ボタンをクリック ■Secrets Managerの情報を読み込ませるためにタスクを更新 Elastic Container Service → Amazon ECS → タスク定義 「Container-Test-Task」にチェックを入れて「新しいリビジョンの作成」をクリック (以下、前回タスクを作成した時の内容をベースに入力する) もともと追加されている「ecr_php81_apache」に対し、必要な箇所を調整 今回は「環境変数」にある「環境変数を追加」をクリックし、以下のように入力する キー 値のタイプ 値 RDS_HOST ValueFrom arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:dev/container-test/Mysql-bcmXxP:host:: RDS_DBNAME ValueFrom arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:dev/container-test/Mysql-bcmXxP:dbname:: RDS_USERNAME ValueFrom arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:dev/container-test/Mysql-bcmXxP:username:: RDS_PASSWORD ValueFrom arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:dev/container-test/Mysql-bcmXxP:password:: 上記で更新すると、各値がコンテナに渡されるようになる デプロイすると、phpinfo() の「Environment」に以下が現れた RDS_HOST: container-test.xxxxx.ap-northeast-1.rds.amazonaws.com RDS_DBNAME: container RDS_USERNAME: (RDS上に作成したユーザー) RDS_PASSWORD: (RDS上に作成したパスワード) 環境変数にはarnの値が表示されて、実際のパスワードを得るにはSDKなどで独自に処理が必要なのかと思いきや、普通に環境変数へ展開された これだと環境変数に普通に接続情報を書くのと変わらないような …と思ったが、taskdef.json に直接接続情報を書くと「リポジトリ内に機密情報を含めている」状態になるので、それを避けるための措置か phpinfo() の内容は絶対に流出させてはならない(もともと流出させるべきでは無い内容だが) 以下などを参考に、本番環境では phpinfo() を使用できないようにするなどしておくべきか php.iniで危険な関数を無効化する | 晴耕雨読 https://tex2e.github.io/blog/php/set-disable-functions ■PHPプログラムからの接続確認 Dockerfileを調整し、PHPからMySQLへ接続するための命令を追加インストールする 具体的には、ecr_php81_apache\docker\php\Dockerfile を以下のように修正する(「pdo_mysql」と「mysqli」を追加している)
RUN docker-php-ext-install gd mbstring intl zip ↓ RUN docker-php-ext-install gd pdo_mysql mysqli mbstring intl zip
デプロイして、PHPからMySQLへ接続する命令を書いたページへアクセスすると、データベースに接続できた 具体的なコードは以下のとおり
<?php try { $pdo = new PDO( 'mysql:dbname=' . $_ENV['RDS_DBNAME'] . ';host=' . $_ENV['RDS_HOST'], $_ENV['RDS_USERNAME'], $_ENV['RDS_PASSWORD'] ); $stmt = $pdo->query('SELECT NOW() AS now;'); $data = $stmt->fetch(PDO::FETCH_ASSOC); echo "<p>" . $data['now'] . "</p>\n"; $pdo = null; } catch (PDOException $e) { exit($e->getMessage()); }
■トラブル: PHPプログラムのページからRDSへアクセスしようとすると「504 Gateway Time-out」と表示された WebサーバのコンテナからRDSにアクセスできるように、 RDSに割り当てているセキュリティグループの設定を調整する

Advertisement