20200919のAWSに関する記事は16件です。

Amazon SQSの遅延キュー(delay queues)を理解しながら使ってみる

はじめに

サーバレスでイベント駆動なアーキテクチャを検討している中でどうしても「ちょっとSleepしてからのリトライ処理」を実装しなければいけない箇所が出てきて、実行中の処理でsleepするのはあまりにイケていないのでマネージドにやる方法として遅延キューがどれくらい使い物になるかを検討してみた。

遅延キューとは

その名の通り、キューイングされてからイベントトリガが引かれるまでの間にタイムラグがあるSQSのことだ。
正に「ちょっとSleepしてからのリトライ処理」をやるには良いのではないだろうか!
詳しくはAWS公式の開発者ガイド参照。

設定方法

マネージメントコンソール画面では以下の黄色蛍光ペンの設定部分にあたる。
キャプチャ1.png

Terraformで実装する場合は、以下のようなイメージになる。delay_seconds が該当の設定項目だ。

resource "aws_sqs_queue" "delay" {
  name                       = "r-kubota-delay-queue"
  delay_seconds              = 30
  visibility_timeout_seconds = 30
}

なお、マネージメントコンソール画面でピンク蛍光ペンを塗ったデフォルトの可視性タイムアウトが、Terraformの visibility_timeout_seconds にあたり、これも重要なので後程説明をする。

実際の動作を確認する

トリガ起動するLambdaの設定

さて、今回は、SQSのキューにPUTされたら、30秒後にLambdaが起動するということを実現しよう。
これにより、30秒後にリトライ処理を行ってあげれば、当初の目的が達成できる。

Lambda関数自体はテキトーに用意しよう。
reserved_concurrent_executions も重要なチューニング要素になるため、後程説明する。

data "archive_file" "scripts" {
  type        = "zip"
  source_dir  = "../scripts"
  output_path = "../outputs/lambda_function.zip"
}

resource "aws_lambda_function" "delay_queue" {
  depends_on = [
    aws_cloudwatch_log_group.lambda,
  ]

  function_name    = "delay-queue-function"
  filename         = data.archive_file.scripts.output_path
  role             = aws_iam_role.lambda.arn
  handler          = "lambda_function.lambda_handler"
  source_code_hash = data.archive_file.scripts.output_base64sha256
  runtime          = "python3.6"

  memory_size = 128
  timeout     = 30

  reserved_concurrent_executions = 1
}

SQSをイベントトリガとしてLambdaを起動する場合は、以下のように

      "sqs:DeleteMessage",
      "sqs:GetQueueAttributes",
      "sqs:ReceiveMessage",

のIAMポリシーの設定が必要なので注意。

resource "aws_iam_role" "lambda" {
  name               = "delay-queue-function-role"
  assume_role_policy = data.aws_iam_policy_document.lambda_assume.json
}

data "aws_iam_policy_document" "lambda_assume" {
  statement {
    effect = "Allow"

    actions = [
      "sts:AssumeRole",
    ]

    principals {
      type = "Service"
      identifiers = [
        "lambda.amazonaws.com",
      ]
    }
  }
}

resource "aws_iam_role_policy_attachment" "lambda" {
  role       = aws_iam_role.lambda.name
  policy_arn = aws_iam_policy.lambda_custom.arn
}

resource "aws_iam_policy" "lambda_custom" {
  name   = "delay-queue-function-policy"
  policy = data.aws_iam_policy_document.lambda_custom.json
}

data "aws_iam_policy_document" "lambda_custom" {
  statement {
    effect = "Allow"

    actions = [
      "sqs:DeleteMessage",
      "sqs:GetQueueAttributes",
      "sqs:ReceiveMessage",
      "logs:CreateLogGroup",
      "logs:CreateLogStream",
      "logs:PutLogEvents",
    ]

    resources = [
      "*",
    ]
  }
}

さて、Lambda関数が作れたら、SQSと接続をしよう。

resource "aws_lambda_event_source_mapping" "delay_queue" {
  event_source_arn = aws_sqs_queue.delay.arn
  function_name    = aws_lambda_function.delay_queue.arn
}

これで、準備は整った。

SQSにPUTしてみる

単発の実行

今回、Lambda側でCloudWatch Logsに、キューにPUTされた日時(sendDatetime)と、実際に処理を行った日時(receiveDateTime)、および試行回数(ApproximateReceiveCount)を出力するようにした。

単発で実行した場合の出力は以下のようになった。

{
    "messageId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "sendDatetime": "2020/09/19 12:01:30.712000",
    "approxSqsFirstReceiveTime": "2020/09/19 12:02:00.914000",
    "ApproximateReceiveCount": "1",
    "receiveDateTime": "2020/09/19 12:02:00.962043"
}

sendDatetimeとreceiveDateTimeがしっかり30秒離れているので、想定通りの動作をしてくれているようだ。

では、複数同時実行してみたらどうなるだろうか?

30連発の実行

SQSに10tps程度で30連発で書き込んでみる。
ここでのポイントは、Lambdaの reserved_concurrent_executions を 1 にしていることだ。

すると、

"messageId",                          ,"sendDatetime"              ,"receiveDateTime"          ","ApproximateReceiveCount"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:09.989000","2020/09/19 12:23:40.049147","1"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.001000","2020/09/19 12:23:40.070388","1"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.034000","2020/09/19 12:23:40.115585","1"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.038000","2020/09/19 12:23:40.115585","1"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.039000","2020/09/19 12:23:40.115585","1"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.023000","2020/09/19 12:23:40.315442","1"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.052000","2020/09/19 12:23:40.315442","1"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.065000","2020/09/19 12:23:40.315442","1"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.067000","2020/09/19 12:23:40.315442","1"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.047000","2020/09/19 12:23:40.315442","1"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.321000","2020/09/19 12:23:40.361676","1"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.301000","2020/09/19 12:23:40.361676","1"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.208000","2020/09/19 12:23:40.361676","1"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.511000","2020/09/19 12:23:43.794862","1"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.468000","2020/09/19 12:23:44.170619","1"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.089000","2020/09/19 12:24:10.155469","2"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.072000","2020/09/19 12:24:10.155469","2"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.147000","2020/09/19 12:24:10.293371","2"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.205000","2020/09/19 12:24:10.334936","2"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.145000","2020/09/19 12:24:10.425845","2"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.164000","2020/09/19 12:24:10.425845","2"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.164000","2020/09/19 12:24:13.925537","2"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.090000","2020/09/19 12:24:40.152953","3"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.085000","2020/09/19 12:24:40.200360","3"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.100000","2020/09/19 12:24:40.200360","3"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.103000","2020/09/19 12:24:43.237281","3"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.114000","2020/09/19 12:24:43.237281","3"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.110000","2020/09/19 12:24:43.237281","3"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.107000","2020/09/19 12:24:43.237281","3"
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","2020/09/19 12:23:10.061000","2020/09/19 12:24:43.237281","3"

といった感じで、3ターンに分かれて実行された。
また、2ターン目、3ターン目に起動したトランザクションは、試行回数が増えている。
これは何を意味しているかと言うと、同時実行数が1であるがためにエラーとなり、visibility_timeout_secondsで設定している30秒後に起動してきて再実行されていると考えられる(試しにこの値を45秒にしたら2回目の施行は30+45秒後になった)。

また、Lambdaの最大再実行回数は2より大きくすることができないため、これ以上の負荷をかけてしまうと、最大再実行回数を超過してデッドレターキューに入ってしまう(設定していない場合はロスト)。

つまり、「起動されてくるLambdaが処理できる十分な同時実行数」を確保しておかないと、想定したリトライ処理が行えない可能性が高くなる。この方法を採用する場合は、充分にチューニングして reserved_concurrent_executions を必要数分用意しておくか、この値を設定しないか、もしくは諦めてデッドレターキューに格納された場合のワークアラウンドを用意しておくかということを考える必要がある。
※10tpsの30連発程度であれば、reserved_concurrent_executionsを少し増やせば余裕でリトライは行われなくなった。

また、標準タイプのキューについては、イベントが2回トリガされる可能性があるため、そうなっても問題ないようにLambdaを実装する必要があるのに注意をしなければいけない。

便利な機能ではあるが、チューニング要素をしっかり理解しながら使っていこう。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Tips】CloudWatch Logsのロググループを日本時間で範囲指定して絞り込む方法

はじめに

CloudWatch Logsのログをコンソールで見ていると、キーワードの検索はできるものの、JSONの中身を絞って並べたりできないので、結局CLI経由でjqを使って確認がしたくなる。

というわけで、CLIでサクッと検索する方法を書き残しておこう。

絞り込み

方法①:時間帯

さて、だいたいAWSでCLIを使うとなるとEC2を使うことになると思うが、EC2のデフォルトのタイムゾーンはUTCに合わせられているため、日本時間で範囲指定しようとするとひと手間加えてあげる必要がある。

CloudWatch Logsの検索は

$ aws logs filter-log-events --log-group-name [ロググループ]

でグループ指定し、そこから --filter-pattern--start-time で絞り込みを行っていくことになる。

そこで、開始日時を指定する場合は

--start-time `TZ=Asia/Tokyo date --date='2020-09-19 19:30:00.000' +%s%3N`

とすることで、日本時間からUTCのエポック秒に変換できる。
%3Nは、CloudWatch Logsの精度に合わせてミリ秒にしている。

方法②:「~~分前」

こちらはもっと単純。以下のように指定すれば良い。

--start-time `date -d '60 minutes ago' +%s%3N`

jqでの編集

CLIではJSON出力の場合以下のように出力される。

{
    "searchedLogStreams": [
        {
            "searchedCompletely": true, 
            "logStreamName": "ログストリーム名"
        },
         
    ], 
    "events": [
        {
            "ingestionTime": 1600511663343, 
            "timestamp": 1600511656660, 
            "message": "ログ出力内容", 
            "eventId": "イベントID", 
            "logStreamName": "ログストリーム名"
        },
         
    ]
}

なので、jqコマンドで

jq -r '.events[].message'

な感じでパイプしてあげる。

さらに、Pythonなんかで json.dumps() でdict型をログ出力していると、

{
  "ingestionTime": 1600515840844,
  "timestamp": 1600515834171,
  "message": "{\"messageId\": \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\", \"sendDatetime\": \"2020/09/19 11:42:21.746000\", \"receiveDateTime\": \"2020/09/19 11:43:54.171187\"}\n",
  "eventId": "イベントID",
  "logStreamName": "ログストリーム名"
}

な感じでエスケープされてしまってキレイにパースできないことがある。
こういう時は

jq -r '.events[].message | fromjson'

とすることで、キレイなJSONにすることができる。

定型のmessageの中身をさらに好きなようにjqで編集しよう!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VPC+EC2+Apache+MariaDBでWordPressを構築し、独自ドメイン+https化

本記事を作成することになったきっかけ

自分のポートフォリオを公開するには何がいいだろうか?と考えた時にWordPressがふと思い浮かびました。
なので、AWSにWordPressが動くサーバーを構築しようと思い、その手順を残そうと思いました。
あとWordPressを使えばアフィリエイトでお金稼ぎできるようになるので、やり方を知ってて損は無いなということで記事にしようと思いました。まあ僕がアフィリエイトやっても絶対稼げないんですけどね。アフィリエイトやりたいと思った人の助けにもなればいいなと思いました。

対象の読者

WordPressを使いたい人
オリジナリティのあるブログを始めたい人
アフィリエイトをやりたい人
インフラ構築を勉強したい人
mac利用者
AWSアカウント作成済
クレジットカードをAWSに登録済

バージョン情報

あらかじめどのバージョンを使用しているか記載しておきます。
バージョンによってやり方全然違ったりするので・・・。

ソフト バージョン
Linux Amazon Linux 2 AMI (HVM), SSD Volume Type ami-0053d11f74e9e7f52 (64 ビット x86)
Apache 2.4.46
PHP 7.3.21
MariaDB 15.1
WordPress 5.5.1

最初RDSを組み合わせてやろうと思ったのですが値段が高いのでやめました。
個人利用であればわざわざ追加するほどのものでも無いですし。
技術的にもさほど難しくないのであまり勉強にならなさそうですし。
需要あれば解説します。簡単に変えられるので。

VPCの作成

以下のネットワーク構成にします。

スクリーンショット 2020-09-19 11.52.14.jpg

難しいと思った方はすみません。1つ1つの作り方をきちんと解説します。
簡単な構成だと思った方もすみません。ぶっちゃけWordPress作るくらいならこれくらいの構成で十分だなって。

下準備として、ネットワーク構築のために、VPCの設定を行います。

AWSでVPCを開きます。
スクリーンショット 2020-09-18 23.06.55.jpg

左のメニューからVPCをクリックします。
スクリーンショット 2020-09-18 23.07.57.jpg

VPCの作成をクリックします。
スクリーンショット 2020-09-18 23.08.25.jpg

VPCの設定をします。
名前タグをWordPress、IPv4 CIDRブロックを172.168.0.0/16としました。
スクリーンショット 2020-09-18 23.09.52.jpg

VPCの作成をクリックします。
スクリーンショット 2020-09-18 23.10.55.jpg

ここまでできました。
スクリーンショット 2020-09-19 12.05.42.jpg

EC2を配置するためのサブネットが必要なので、左のメニューからサブネットを選択し、サブネットの作成をクリックします。
スクリーンショット 2020-09-19 12.00.05.jpg

スクリーンショット 2020-09-19 12.00.23.jpg

名前タグをWordPressサブネットにして、VPCを先ほど作成したVPC(WordPress)にします。
アベイラビリティーゾーンをap-northeast-1aにします。
IPv4 CIDRブロックを172.168.0.0/20にします。
入力が終わったら作成をクリックします。
スクリーンショット 2020-09-18 23.28.04.jpg

サブネットが作成されたことを確認して閉じるをクリックします。
スクリーンショット 2020-09-18 23.28.28.jpg

ここまでできました。
スクリーンショット 2020-09-19 12.01.47.jpg

VPCがインターネットに繋がってないので、繋げる必要があります。
左のメニューからインターネットゲートウェイを選択します。
スクリーンショット 2020-09-18 23.54.03.jpg

インターネットゲートウェイの作成をクリックします。

スクリーンショット 2020-09-18 23.54.14.jpg

名前タグをWordPressゲートウェイにしてインターネットゲートウェイの作成をクリックします。

スクリーンショット 2020-09-18 23.54.42.jpg

インターネットゲートウェイをVPCにくっつける必要があるのでVPCへアタッチをクリックします。

スクリーンショット 2020-09-18 23.55.40.jpg

WordPressのVPCを選択してインターネットゲートウェイのアタッチをクリックします。

スクリーンショット 2020-09-18 23.56.00.jpg

アタッチされたらOKです。
スクリーンショット 2020-09-18 23.56.47.jpg

ここまでできました。
スクリーンショット 2020-09-19 12.03.03.jpg

インターネットとインターネットゲートウェイは自動的に繋がりますし、ルートテーブルはインターネットゲートウェイ作成時に自動的に作成されます。

しかし、不親切なことにサブネットからルートテーブルへのルーティングと、インターネットゲートウェイからルートテーブルへのルーティングが無いんですよね・・・

スクリーンショット 2020-09-19 12.09.27.jpg

仕方ないので、作成する必要があります。

まずはサブネットからルートテーブルへのルーティングを作成します。
左のメニューからVPCをクリックします。
スクリーンショット 2020-09-19 0.43.44.jpg

WordPressのVPC IDをクリックします。

スクリーンショット 2020-09-19 0.43.58.jpg

ルートテーブルのところにリンクがあるのでクリックします。

スクリーンショット 2020-09-19 0.44.37.jpg

サブネットの関連付けをクリックしてサブネットの関連付けの編集をクリックします。

スクリーンショット 2020-09-19 0.45.21.jpg

WordPressサブネットを選択して保存をクリックします。
スクリーンショット 2020-09-19 0.45.51.jpg

続けて、インターネットゲートウェイからルートテーブルへのルーティングを作成します。

ルートタブでルートの編集をクリックします。

スクリーンショット 2020-09-19 0.57.09.jpg

送信先を0.0.0.0/0にして、ターゲットをInternet GatewayのWordpressゲートウェイにします。(画像では表示されていませんが選択時にWordPressゲートウェイと表示されます)
終わったらルートの保存をクリックします。
スクリーンショット 2020-09-19 0.58.56.jpg

ルートが正常に編集されたことを確認します。

スクリーンショット 2020-09-19 0.59.34.jpg

これで、無事インターネットゲートウェイとサブネットが繋がるようになりました。

スクリーンショット 2020-09-19 12.10.18.jpg

ネットワーク構築はこれで完成!

ただ、ネットワークを構築してもサーバーをどこかに配置してあげないと意味がないのでサーバーを作成します。

EC2の作成

サーバー本体を作成するために、EC2インスタンスを作成します。

スクリーンショット 2020-09-19 12.15.12.jpg

EC2を開きます。

スクリーンショット 2020-09-18 23.16.01.jpg

リージョンが東京となっていることを確認します。

スクリーンショット 2020-09-18 23.16.28.jpg

左のメニューからインスタンスをクリックします。
スクリーンショット 2020-09-18 23.17.00.jpg

インスタンスを起動をクリックします。
スクリーンショット 2020-09-18 23.17.33.jpg

Amazon Linux 2 AMI (HVM), SSD Volume Type - ami-0053d11f74e9e7f52 (64 ビット x86)を選択します。

スクリーンショット 2020-09-18 23.21.28.jpg

インスタンスタイプはt2.microにして次のステップ:インスタンスの詳細の設定をクリックします。
スクリーンショット 2020-09-18 23.23.12.jpg

ネットワークをWordPressに設定し、サブネットをWordPressサブネットに変更します。
自動割り当てパブリックIPを有効にします。
入力が終わったら次のステップ:ストレージの追加をクリックします。
スクリーンショット 2020-09-18 23.33.00.jpg

ストレージはデフォルトで問題ありません。
次のステップ:タグの追加をクリックします。
スクリーンショット 2020-09-18 23.34.08.jpg

タグの追加をクリックして、
キーをName、値をWordPressインスタンスにします。
終わったら次のステップ:セキュリティグループの設定をクリックします。
スクリーンショット 2020-09-18 23.35.25.jpg

新しいセキュリティグループを作成します。
セキュリティグループ名をWordPress-sgにします。
SSH接続するための設定はデフォルトで設定されているのでそのままにします。
SSH接続はあとで嫌というほどやります。
HTTP(セキュリティ対策してないやつ)とHTTPS(セキュリティ対策してるやつ)のルールを追加します。HTTPS化するのはひと手間加える必要があるので現時点では使えないですが、HTTPS化する方法もあとで解説します。
警告は出てても問題ありません。
終わったら確認と作成をクリックします。

スクリーンショット 2020-09-18 23.38.50.jpg

今まで行った設定が一覧で表示されます。
問題なければ起動をクリックします。
スクリーンショット 2020-09-18 23.39.38.jpg

ローカルPCからAWS上のEC2(Linux)にssh接続するために必要な鍵を貰うために、新しいキーペアを作成します。
キーペア名はwordpressにします。
キーペアのダウンロードをクリックします。
スクリーンショット 2020-09-18 23.41.51.jpg

キーペアのダウンロードが終わったらインスタンスの作成をクリックします。

スクリーンショット 2020-09-18 23.42.49.jpg

AWSのEC2上でLinuxのインスタンスが作成されるまで数分かかるのでライバルズでもやりながら待ちます。

スクリーンショット 2020-09-18 23.44.20.jpg

ライバルズをやりつつ、IPアドレスの固定化を行います。
これをしないと、IPアドレスがコロコロ変わってssh接続する時などに煩わしくなります。
インスタンスの表示をクリックしたあと、左のメニューからElasticIPをクリックします。

スクリーンショット 2020-09-18 23.46.34.jpg

Elastic IPアドレスの割り当てをクリックします。
スクリーンショット 2020-09-18 23.47.07.jpg

割り当てをクリックします。
スクリーンショット 2020-09-18 23.47.23.jpg

ElasticIPアドレスが正常に割り当てられたのでこのElasticIPアドレスを関連付けるをクリックします。

スクリーンショット 2020-09-18 23.48.25.jpg

インスタンスはWordPressインスタンスを選択(画像だとインスタンス名消えてるけど選択する時は表示される)します。
プライベートIPアドレスは仕組み上1つしかないのでそれを選択します。
終わったら関連付けるをクリックします。
スクリーンショット 2020-09-18 23.50.15.jpg

これでWordPressインスタンスにElasticIPアドレスが割当たりました。

スクリーンショット 2020-09-18 23.57.40.jpg

ElasticIPは人によって異なるので読み替えてください。

ここでElasticIPアドレスの関連付けに失敗するようなら、VPCがインターネットと通信できるようにするためのインターネットゲートウェイがくっついていない可能性があります。つまりVPCの作成でミスってます。

あと、ElasticIPがどのインスタンスに割り当てられているのかあとで辿れるようにElasticIPに名前をつけておきます。

EC2の左のメニューからElasticIPを開きます。
スクリーンショット 2020-09-19 14.08.13.jpg

Nameのところにカーソルを合わせると編集ボタンが表示されるので、WordPressIPに変更しておきます。これをやっておかないと独自ドメイン作成する時にどのElasticIPを使うべきか判別がつかず困る可能性があります。僕は困りました。入力が終わったら保存をクリックします。

スクリーンショット 2020-09-19 14.10.02.jpg

これで、EC2にWordPressインスタンスを作成することができました。

スクリーンショット 2020-09-19 12.26.39.jpg
※ElasticIPは人によって異なります。

WordPressインスタンスにssh接続

WordPressインスタンスにソフトウェアをインストールするには、ssh接続が必要不可欠です。

ssh接続は相手の家にお邪魔する行為みたいなものです。
鍵なしでお邪魔することができるものもありますが、もし鍵がついてたら鍵を使って入ります。ちなみにWordPressインスタンスは鍵をつけた(というか絶対つけられちゃう)ので鍵が必要です。

WordPressインスタンスにssh接続します。
command+spaceでspotlight検索を呼び出し、terminal.appと入力してターミナルを起動します。

スクリーンショット 2020-09-19 0.02.05.jpg
スクリーンショット 2020-09-19 0.02.14.jpg

余談だけどspotlight検索作った人本当に天才
windows使いたくないまである

さっきssh鍵をダウンロードしたのでDownloadsディレクトリに移動し、.sshディレクトリに移動させましょう。良かれと思ってssh鍵を別のところに移動してしまった方はパスを読み替えましょう。

cd
cd Downloads
mv wordpress.pem ../.ssh

このコマンドで.sshディレクトリにwordpress.pemが見当たらないようであれば、Finderを使ってwordpress.pemを.sshディレクトリ(隠しディレクトリなので注意)に移動させます。

ssh鍵のある.sshディレクトリに移動します

cd
cd .ssh

ssh鍵のパーミッションを変更しておきます。
元は644(rw- r-- r--)になっています。
ぶっちゃけ変更しなくても繋がっちゃいますが、セキュリティの観点から管理者の読み取りのみ許可する形(400=r-- --- ---)にします。
AWSも400にすることを推奨しています。
EC2インスタンス→インスタンス→接続→SSHクライアントの画面でそのことが確認できます。

証拠↓

スクリーンショット 2020-09-19 1.03.39.jpg

下記コマンドでssh鍵のパーミッションを変更しちゃいましょう。

chmod 400 wordpress.pem

続いて、ssh接続します。
接続するのにElasticIPアドレスが必要なので、EC2のインスタンス画面でElasticIPを確認します。
IPアドレスは人によって異なるので読み替えます。

ssh -i wordpress.pem ec2-user@18.181.12.140

これで繋がらない場合、VPCでインターネットゲートウェイとルートテーブルが繋がってない、もしくはサブネットとルートテーブルが繋がってない、もしくはその両方だと思います。

接続できたら初回は下記表示になります。

The authenticity of host '18.181.12.140 (18.181.12.140)' can't be established.
ECDSA key fingerprint is SHA256:hogehogehogehogehogehogehogehoge.
Are you sure you want to continue connecting (yes/no)? 

yesを入力します。

yes

そしたら下記表示になり、無事ssh接続できたことが確認できます。


       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-2/

ssh接続するとき、わざわざコピペで入力したりとか手打ちで入力したりとか馬鹿馬鹿しくて時間の無駄なので、clipyというソフトウェアをすぐさまダウンロードして下記スニペットを登録しておいて、どのディレクトリにいてもすぐさまssh接続できるようにしておきます。

cd
cd .ssh
ssh -i wordpress.pem ec2-user@18.181.12.140

WordPressインスタンスにApacheをインストール

WebサーバーにはNginxとかありますが、WordPressにはApacheが相性良さそうっぽいのでApacheをインストールします。

ソフトウェアのインストールする時にいちいちコマンドの先頭にsudoつけたくないので、あらかじめ管理者のrootに変更しておきます。

sudo su

そうするとデフォルトのユーザー名を表すec2-userからrootに表示が変わったことが確認できます。

続いて、Apacheをインストールするためにyumという便利ソフトウェアインストールツールのコマンドを使ってApacheをインストールします。

下記コマンド、httpdとなっていますが、これがApacheです。
実行します。

yum install -y httpd

インストールが終わったら、Apacheのバージョンを確認しておきます。

httpd -v

Server version: Apache/2.4.46 ()
Server built: Aug 24 2020 18:54:20

と表示されました。
この記事では、Apacheのバージョンは2.4.46のようです。

これで、WordPressインスタンスにApacheをインストールできました。

WordPressインスタンスでApache起動

おっと、Apacheを起動する前にGoogleChromeでIPアドレスをURL欄に直打ちしてみましょう。

18.181.12.140(ElasticIPは人によって異なるので読み替えてね)

スクリーンショット 2020-09-19 1.36.53.jpg

アクセスできませんね。そのことを確認したら、下記コマンドでWebサーバーApacheを起動します。

systemctl start httpd

これでWordPressインスタンス上でWebサーバーであるApacheが起動しました。
GoogleChromeで更新ボタンを押します。

スクリーンショット 2020-09-19 1.37.52.jpg

Apacheのデフォルトページが表示されるようになりました。

また、EC2インスタンスが再起動すると停止してしまうので、自動起動設定にします。

systemctl enable httpd

WordPressインスタンスにPHPをインストール

WordPressはPHPで作られています。
プラグインもPHPで作成することができます。

なので、PHPのインストールと、あとライブラリが必要です。
下記コマンドを実行します。

amazon-linux-extras install -y php7.3
yum install -y php-mbstring php-gd

amazon-linux-extrasはyumコマンドのAWS版と思って貰えればいいかと思います。WordPressのバージョンが上がって、普通のphpのインストールコマンドだと駄目なようです。

ライブラリは、1行目のコマンドでphp-mysql(DB用)、2行目のコマンドでphp-mbstring(文字化け防止用)とphp-gd(画像取り扱い用)が入りました。

php -v

PHP 7.3.21 (cli) (built: Aug 21 2020 21:12:16) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.21, Copyright (c) 1998-2018 Zend Technologies

と表示されました。
この記事では、PHPのバージョンは7.3.21のようです。

このままだとphpがインストールされたことがApacheに伝わっていないので、伝えるためにApacheを再起動します。

systemctl restart httpd

これで、WordPressインスタンスにPHPをインストールできました。

WordPressインスタンスにMariaDBをインストール

WordPressを使う場合、データを保存するための場所が必要です。それがDBですね。
DBにもMySQLとかPostgreSQLとかありますが、MySQLの派生型であるMariaDBを使用します。

MariaDBのインストールコマンドを実行します。

yum install -y mariadb mariadb-server

MariaDBを起動します。

systemctl start mariadb

EC2インスタンスが再起動すると停止してしまうので、自動起動設定にします。

systemctl enable mariadb

起動したらMariaDBのバージョンを確認してみます。

mysql -u root -e 'status ' | grep Ver

mysql Ver 15.1 Distrib 5.5.64-MariaDB, for Linux (x86_64) using readline 5.1

と表示されました。
この記事では、MariaDBのバージョンは15.1のようです。

これで、WordPressインスタンスにMariaDBをインストールできました。

WordPressインスタンスのMariaDBのパスワードを変更

MariaDBにパスワードを設定しておかないと危ないので設定しておきます。

まずはMariaDBのプロンプトを開きます。

mysql -u root -p
(passwordの入力を求められたら空でEnter)

続いて、下記コマンドでパスワードを設定します。
'新しいパスワード'となっている部分は自分で設定します。

update mysql.user set password=password('新しいパスワード') where user = 'root'; flush privileges;

WordPressインスタンスに必要なデータベースの作成

以下の設定でデータベースを作成します。

設定値
ユーザー名 wordpress
パスワード (好きなパスワード)
データベース名 wordpressdb

※MariaDBのプロンプト上で操作。

確認のためにデータベースを表示します。

show databases;

下記の表示になっていたらOKです。

+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
+--------------------+

まずはユーザーとパスワードを作成します。

create user 'wordpress'@'localhost' IDENTIFIED BY '(好きなパスワード)';

続いて、WordPress用のデータベースを作成します。

create database wordpressdb;

続いて、作成したユーザーに対して作成したデータベースの全権限を与えます。

grant all privileges on wordpressdb.* to 'wordpress'@'localhost';
FLUSH PRIVILEGES;

再度確認のためにデータベースを表示します。

show databases;

下記の表示になっていたらOKです。

+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
| wordpressdb        |←NEW!!
+--------------------+

これで、WordPressインスタンスに必要なデータベースが作成できました。

下記コマンドでMariaDBのプロンプトを終了しておきます。

exit

WordPressインスタンスにWordPressをインストール

WordPress用の作業ディレクトリを作成します。
作業が終わると不要なディレクトリになることを念頭に置いておくといいと思います。
※ssh接続時の入力になっていることを確認

mkdir /home/wordpress
cd /home/wordpress

WordPressはyumではインストールできないので、wgetを用いてWordPressの圧縮ファイルを取得します。
※latest(最新)を取得しているので、このあとの手順は時代によって異なるかも。すまん。

wget https://wordpress.org/latest.tar.gz

.tar.gzのままになっているので解凍します。

tar xzvf latest.tar.gz

Apacheから見える場所にWordPressのデータを切り取って/var/www/html配下に全てペーストします。

mv wordpress/* /var/www/html/

Apacheユーザーに、先ほどWordPressのデータを置いた/var/www/htmlの書き込み権限を与えます。

chown apache.apache -R /var/www/html
chmod +w -R /var/www/html

終わったら、GoogleChromeでWordPressの設定ができるようになります。

GoogleChromeで18.181.12.140(ElasticIPは人それぞれ異なるので読み替えてね)とURL欄に入力するとWordPressの初期設定画面が開きます。

パスは勝手にhttp://18.181.12.140/wp-admin/setup-config.php になります。

Let's go!をクリックします。
スクリーンショット 2020-09-19 3.30.26.jpg

下記の設定にしてSubmitをクリックします。
パスワードはMariaDBで設定したパスワードにします。
下記画像だと好きなパスワードとなっていますが、MariaDBで設定したパスワードの間違いです

スクリーンショット 2020-09-19 3.33.06.jpg

wp-config.phpファイルが/var/www/htmlの中に無いから作成して下記を貼り付けてねと怒られます。

スクリーンショット 2020-09-19 3.35.12.jpg

下記コマンドでwp-config.phpを作成し、権限をapache.apacheに変更し、viエディタで開きます。
※sudo suで管理者であるrootユーザーになっていることを確認。

cd /var/www/html/
touch wp-config.php
chown apache.apache wp-config.php  
vi wp-config.php

viエディタが開いたら、先ほどのWordPressのテキストをCommand+Vで貼り付け、「:wq」を入力して保存し閉じます。

Run the installationをクリックします。

スクリーンショット 2020-09-19 3.41.51.jpg

下記の画面になるので、必要事項を入力します。

Site Title:ブログ名を入力

Username:英文字と記号で

Password:パスワード

Your Email: メールアドレス

終わったらInstall WordPressをクリックします。
スクリーンショット 2020-09-19 3.46.16.jpg

これでインストール完了です。
ログインをクリックします。

スクリーンショット 2020-09-19 3.52.42.jpg

先ほど設定したユーザー名とパスワードを入力してログインできることを確認します。

スクリーンショット 2020-09-19 3.53.20.jpg

管理画面を開くことができました。

スクリーンショット 2020-09-19 3.54.20.jpg

以上で、WordPressインスタンスにWordPressをインストールできました。

英語だと分かりづらいので日本語化します。
左のSettingsから、SiteLanguageを日本語にしてSaveChangesをクリックします。

スクリーンショット 2020-09-19 4.17.41.jpg

無事日本語化できました。

スクリーンショット 2020-09-19 4.18.25.jpg

これは管理画面なので、一般ユーザーから見た時にどう見えるかをチェックしてみます。
18.181.12.140(人によって異なるので読み替えてね)にアクセスしてみます。

スクリーンショット 2020-09-19 4.19.23.jpg

ログイン中なのでいくつか管理者用のリンク表示されていますが、一般ユーザーからどう見えるかを確認することができました。

バージョンを確認します。
http://ElasticIPアドレス/wp-admin/index.php を開き、概要をチェックします。
Qiitaの仕様でリンクになってしまったけど開かないので注意

スクリーンショット 2020-09-19 13.04.02.jpg

この記事では、WordPressのバージョンは5.5.1のようです。

独自ドメイン化

お金かかります。また、手続き上の問題で最大3日かかります。

IPアドレスでアクセスするのも不格好なので、独自ドメインを作成しちゃいましょう。
独自ドメイン化をするにはAWSのRoute53を利用します。

Route53を開きます。

スクリーンショット 2020-09-19 13.46.50.jpg

独自ドメインを持っているかどうかで多分表示が変わるのですが、僕は既に持っているので初めて独自ドメインを作成する方とは表示が異なるかと思います。多分。

パンくずりすと(Route53 > ダッシュボード)のところにあるRoute53をクリックします。

スクリーンショット 2020-09-19 13.49.51.jpg

ここから多分一緒かな?

Route53の使用開始のところにある開始するをクリックします。
スクリーンショット 2020-09-19 13.50.39.jpg

ドメインを登録を選択して開始するをクリックします。

スクリーンショット 2020-09-19 13.51.33.jpg

好きなドメイン名を入力してチェックします。
世界で同じものは2つ作成できないのでチェックをクリックして、重複がなければカートに入れます。
12ドルかかりますが、下手なもの作ると100ドルとかかかっちゃうので超注意!こだわらずに.comにしておけばいいです。

スクリーンショット 2020-09-19 13.54.42.jpg

一番下までスクロールして続行をクリックします。

スクリーンショット 2020-09-19 13.55.06.jpg

個人情報を入力していきます。少し長め。
スクリーンショット 2020-09-19 13.56.03.jpg
※バキバキ個人情報丸出しになっちゃうのでここまでしか見せられないよ!

完了したら一番下までスクロールして続行をクリックします。
スクリーンショット 2020-09-19 13.59.12.jpg

ドメインは自動更新有効化にしておくと自動で課金は継続しますが便利です。
規約のところにチェックを打って注文を完了をクリックします。

スクリーンショット 2020-09-19 13.59.47.jpg

チャリーン(12$飛ぶ音)
スクリーンショット 2020-09-19 14.01.25.jpg

もしかしたら人によってはここでメールを送ったので確認してくださいみたいな画面に飛ぶかも。
僕は2つ目の独自ドメイン購入なので出ませんでした。

閉じるをクリックしたあと以下の画面が表示されると思いますが、記載の通り最大で3日かかります。また、登録完了するとEメールが届きます。できなくてもEメールが届きます。
スクリーンショット 2020-09-19 14.03.30.jpg

ちなみに僕は数分ほどでドメインの登録完了のメールが届きました。
人によって登録完了までの時間はまちまちです。本当に。

Route53のホストゾーンから先ほど作成したドメインが確認できるので、クリックして開きます。

スクリーンショット 2020-09-19 14.17.02.jpg

レコードを作成をクリックします。

スクリーンショット 2020-09-19 14.18.19.jpg

シンプルルーティングを選択して次へをクリックします。

スクリーンショット 2020-09-19 14.18.57.jpg

シンプルなレコードを定義をクリックします。
スクリーンショット 2020-09-19 14.20.57.jpg

レコード名をblogs、
ルーティング先の種類をIPアドレス、
ルーティング先の値をElastic IPアドレス、
レコードタイプをAのIPv4アドレス、
TTLはそのままにしておきます。

入力が終わったらシンプルなレコードを定義をクリックします。

スクリーンショット 2020-09-19 14.24.55.jpg

忘れがちですが右下のレコードを作成をクリックします。
スクリーンショット 2020-09-19 14.27.06.jpg

一番下にレコードが作成できました。

スクリーンショット 2020-09-19 14.28.08.jpg

これで、独自ドメイン化は完了です。

以下のリンクから僕のWordPressが開けます。
https化したのでもう開けません。

http://blogs.jinsei-kouten.com/

Route53の画面は日々変わるのでノウハウが蓄積しづらいのが難点です。
僕が結構昔にやった独自ドメインの作成方法のノウハウはあまり役に立ちませんでした。はぁ・・・。

https化

「http://〜」になってるものにアクセスすると保護されてない通信とかアピールされてめっちゃ鬱陶しいです。
その鬱陶しい表示を消すために(それ目的でやる訳ではないですがw)https化します。

やることは以下の通りです。

①AWS Certificate managerで証明書の作成
②ロードバランサーの構成

やりたいことはめちゃくちゃ単純なのにやることは結構難しいです。
気合が必要です。
1回やれば十分なのでレッドブル飲んで臨みます。

Certificate Managerを開きます
スクリーンショット 2020-09-19 14.55.43.jpg

これまた今まで証明書を作成したことがあるかどうかで表示異なるかと思いますが、証明書のリクエストをクリックします。

スクリーンショット 2020-09-19 14.58.01.jpg

パブリック証明書のリクエストをクリックして証明書のリクエストをクリックします。

スクリーンショット 2020-09-19 14.58.37.jpg

先ほど作成したドメイン名を入力して次へをクリックします。
僕の場合はblogs.jinsei-kouten.comです。
自動入力機能がないので不便。

スクリーンショット 2020-09-19 14.59.26.jpg

DNSの検証にして次へをクリックします。

スクリーンショット 2020-09-19 15.01.04.jpg

管理しやすいように証明書に名前をつけておきます。
タグ名をName、値をWordPressCertificateにします。
確認をクリックします。

スクリーンショット 2020-09-19 15.01.54.jpg

作成をクリックします。

スクリーンショット 2020-09-19 15.05.32.jpg

確認画面が表示されます。
確定とリクエストをクリックします。

スクリーンショット 2020-09-19 15.02.46.jpg

下記の画面が表示されますが続行はまだクリックしません。

スクリーンショット 2020-09-19 15.03.29.jpg

blogs.jinsei-kouten.comをクリックして詳細を開き、Route53でのレコードの作成をクリックします。

スクリーンショット 2020-09-19 15.04.57.jpg

Route53でCNAMEレコードを追加してくれるので作成をクリックします。
最大で30分かかりますが、30分以内にこの証明書が使えるようになります。

スクリーンショット 2020-09-19 15.06.23.jpg

続いて、ALBを追加します。
Application Load Balancerの略です。

今こんな感じになっていると思います。

スクリーンショット 2020-09-19 15.10.23.jpg

証明書はALBにしかくっつけれません。
そのため、ALBの追加が必要不可欠です。
しかも、ALBを作成する場合は2つ以上のサブネットを指定する必要があります。
サブネットは1つしか作ってなかったからもう一つ作るのめんどくさいなって
なので、以下の形に変化します。

スクリーンショット 2020-09-19 15.36.27.jpg

まずは、サブネットを作成しに行きます。

VPCを開き、サブネットの作成をクリックし、以下のように入力して作成をクリックします。
名前タグはWordPressサブネット2にしました。
VPCはWordPressにします
アベイラビリティーゾーンはWordPressサブネットとは異なるものにします。
IPv4 CIDRブロックは172.168.32.0/20にします。

スクリーンショット 2020-09-19 15.37.58.jpg

サブネットを作成したので、ルートテーブルに関連付けなければなりません。でないと、二分の1の確率でアクセスに失敗します。

VPCのルートテーブルのサブネットの関連付けからWordPressルートテーブルを選択してサブネットの関連付けの編集をクリックします。

スクリーンショット 2020-09-19 19.36.09.jpg

WordPressサブネット2が未選択状態かと思いますので選択して保存をクリックします。

スクリーンショット 2020-09-19 19.37.15.jpg

これでルートテーブルにWordPressサブネット2が関連付けられました。

続いて、ALBを作成しに行きましょう。
ALBはEC2から作成できます。

左のメニューからロードバランサーをクリックします。
スクリーンショット 2020-09-19 15.19.41.jpg

ロードバランサーの作成をクリックします。

スクリーンショット 2020-09-19 15.20.22.jpg

一番左のApplication Load Balancerの作成をクリックします。

スクリーンショット 2020-09-19 15.20.45.jpg

名前は分かりやすいようにWordPressALB
スキームはインターネット向け
IPアドレスタイプはipv4
リスナーはHTTPS接続するのでHTTPS
ポートはHTTPSの標準が443なのでそのまま
VPCはWordPress
アベイラビリティーゾーンは2つとも選択し、WordPressサブネットとWordPressサブネット2を選択します。

入力が終わったら次の手順:セキュリティ設定の構成をクリックします。

スクリーンショット 2020-09-19 15.22.25.jpg

ACMから証明書を選択する(推奨)を選択し、証明書の名前を先ほど作成した証明書を選択し、セキュリティポリシーはデフォルトのままにします。
次の手順:セキュリティグループの設定をクリックします。

スクリーンショット 2020-09-19 15.44.58.jpg

既存のセキュリティグループは選ばずに、新しいセキュリティグループを作成します。

セキュリティグループ名は分かりやすい名前にするためにWordPressALB-sgにします。説明はWordPress HTTPSにしておきます。

あとは自動でHTTPS用のセキュリティグループが作成できるため、下の設定は弄らずに次の手順:ルーティングの設定をクリックします。

スクリーンショット 2020-09-19 15.48.06.jpg

続いてルーティングの設定をします。
ターゲットグループを新しいターゲットグループにします。
名前はWordPressTargetにします。
ターゲットの種類はインスタンスにします。

プロトコルはHTTP、ポートは80のままにします。
なぜならインターネットからALBへはHTTPS接続するのですが、ここで設定しているのはALBからEC2への接続だからです。それはHTTP接続で問題ありません。

ヘルスチェックはそのままにします。
入力が終わったら次の手順:ターゲットの登録をクリックします。

スクリーンショット 2020-09-19 15.50.27.jpg

下記画面、あまり操作性が好きでないのですが、WordPressインスタンスを選択したあと、登録済みに追加という青いボタンをクリックしてから次の手順:確認をクリックします。

スクリーンショット 2020-09-19 15.55.03.jpg

確認画面が出るので作成をクリックします。

スクリーンショット 2020-09-19 15.56.04.jpg

ロードバランサーの作成が完了しました。

スクリーンショット 2020-09-19 15.57.13.jpg

まだやることあるんですねぇ〜・・・。
次はRoute53での設定が必要です。
なぜなら、Route53はEC2インスタンスを指しているのですが、これをALBを指すように変更しなければなりません。

Route53を開いてホストゾーンを開いてblogs.jinsei-kouten.com開いてblogs.jinse-kouten.comのAレコードとなっているもの(つまりさっき独自ドメイン化の時に作ったレコード)を選択して編集をクリックします。

スクリーンショット 2020-09-19 15.59.21.jpg

元々IPアドレスを設定していたと思いますが、ALBに変更します。
値/トラフィックのルーティング先をApplication Load BalancerとClassic Load Balancerへのエイリアスに変更します。
リージョンは東京
ALBは〜.WordPressALB-〜となっているものを選択します。

スクリーンショット 2020-09-19 16.02.11.jpg

完了したら変更を保存をクリックします。

これで一度アクセスします。

https://blogs.jinsei-kouten.com/

この時点では、下記画像の表示のように崩れます。(このQiitaが公開されている頃には治っていると思いますが)

スクリーンショット 2020-09-19 16.07.30.jpg

そういうものです。
崩れる理由は、WordPress上の設定URLと実際にアクセスできるURLに相違があるためです。

これを直すためには以下の2通りのやり方があります。
①GUIでの操作。現時点でまだできるhttp接続でWordPressの設定画面(まだ表示が崩れてない)に行き、設定からWordPressアドレス(URL)とサイトアドレス(URL)を書き換える 駄目でした
②CUIでの操作。ssh接続でEC2にアクセスし、cdとかviとか駆使して/var/www/html配下にあるwp-config.phpを書き換える

②でやるほうがエンジニアっぽいですが僕はそこにこだわりが無いので簡単な①で変更します。

http接続で下記にアクセスします。ElasticIPアドレスは人によって異なるので読み替えます。
http://ElasticIPアドレス/wp-admin
僕の場合は
http://18.181.12.140/wp-admin
です。
読んでる方は違います。
ログインできなかったらログインして、左のメニューから設定をクリックします。

スクリーンショット 2020-09-19 16.18.51.jpg

WordPress アドレス (URL)とサイトアドレス (URL)を書き換えます。
僕の場合は https://blogs.jinsei-kouten.com/ です。

スクリーンショット 2020-09-19 16.21.26.jpg

一番下までスクロールして変更を保存をクリックします。

スクリーンショット 2020-09-19 16.22.04.jpg

GAME OVER

①の方法だと失敗したので仕方なく②の方法に切り替えます。

ターミナルでssh接続

cd
cd .ssh
ssh -i wordpress.pem ec2-user@18.181.12.140

管理者権限でwp-config.phpを開きます。

sudo su
cd /var/www/html
vi wp-config.php

iを押して入力モードにし、下記3行を追記します。

<?php
define('WP_HOME','https://blogs.jinsei-kouten.com/');
define('WP_SITEURL','https://blogs.jinsei-kouten.com/');
$_SERVER['HTTPS'] = 'on';

/**
 * The base configuration for WordPress


escで入力モード解除して:wqで保存して閉じます。

これやってしまうとWordPressのGUIの設定画面からはもう設定できなくなるのでやりたくなかったんだよなぁ・・・。
$_SERVER['HTTPS'] = 'on';に当たる部分の設定が見当たらなかったので致し方なし。

それでは下記にアクセスしてみます。

https://blogs.jinsei-kouten.com/

スクリーンショット 2020-09-19 16.55.27.jpg

表示崩れが解消されました。

現時点だとまだhttp接続できてしまうので、セキュリティグループからhttp接続をなくしちゃいましょう!

EC2のセキュリティグループからWordPress-sgを選択してアクションをクリックし、インバウンドルールを編集をクリックします。WordPressALB-sgはALBとEC2間の接続の設定なので関係がありません。インターネットとEC2の接続を管理しているWordPress-sgのみ修正の必要があります。

スクリーンショット 2020-09-19 16.58.07.jpg

HTTPのインバウンドルールを2つとも削除します。

スクリーンショット 2020-09-19 17.01.13.jpg

でも、ALBからはHTTP接続されるのでHTTPのインバウンドルールは必須です。でもソースを0.0.0.0/0にしてしまうといたちごっこになってしまいますね・・・。

では、こちらの図を思い出しましょう。

スクリーンショット 2020-09-19 17.10.23.jpg

ALBはどこにいますか?172.168.0.0/16の中にいますよね?

なので、172.168.0.0/16からのHTTP接続を許可しましょう。
最終的には以下の形になります。ルールを保存をクリックします。

スクリーンショット 2020-09-19 18.13.42.jpg

最終確認です。下記3パターンで①②が繋がらず、③④が接続できれば成功です。
[繋がらないパターン]
①18.181.12.140に接続する
http://blogs.jinsei-kouten.com/ に接続する
[繋がるパターン]
https://blogs.jinsei-kouten.com/ に接続する
https://blogs.jinsei-kouten.com/wp-login.php に接続する

①②が繋がらず、③④が繋がりました。

つまり、成功です!

以上が、VPC+EC2+Apache+MariaDBでWordPressを構築し、独自ドメイン+https化するやり方でした。

あとは好きなようにWordPressを弄り倒してしまいましょう!

お疲れ様でした!

なんか繋がりにくい?

GoogleChromeだと問題なく繋がるけど他のブラウザだと結構な頻度で繋がらない現象が発生。

嬉しすぎてレバテックフリーランスのエージェントさんにLINEでWordPressのURL送ったら繋がりにくくてそこで発覚。
70%くらいの確率で接続に失敗。

Safariでも同様の現象発生するっぽいので試してみたらこれも接続失敗の嵐。たまに繋がる。

訳わからなさすぎたので調べたら参考になりそうな記事がありました。
https://qiita.com/t-kigi/items/0723cd7c26472746d389
https://dev.classmethod.jp/articles/resolve-safari-and-alb-https-connection-errors/

インターネットからALBへはhttp/2.0を使うけどALBからEC2インスタンスへはhttp1.1が使われるのでたまに接続に失敗するとのこと。

とりあえず僕は以下の手順を踏みました。

WordPressインスタンスにSSH接続

cd
cd .ssh
ssh -i wordpress.pem ec2-user@18.181.12.140

下記コマンドを実施

yumdownloader --source mod_http2
sed -i -e "s/^LoadModule/#LoadModule/g" /etc/httpd/conf.modules.d/10-h2.conf
cat /etc/httpd/conf.modules.d/10-h2.conf
sudo systemctl restart httpd

3行目のcatで# LoadModule http2_module modules/mod_http2.soと出ます。

これでやってみたところ、今の所100回中100回接続に成功するようになりました。

終わりに

用語の解説とかほぼ省いているので、詳しく知りたい方はコメントくだされば解説します。(例:ElasticIPってなに? sudoってどんな意味?なんの略? パーミッションって?などなど)
必要な部分であれば全て解説できます。(AレコードとかCNAMEはうまく説明できるか怪しいかも・・・すみません・・・)
また、つまずいた部分は質問いただければ答えます。ただし、そちらは条件があります。最初から手順書を残して、その手順書も合わせて送っていただいた方限定でお答えします。最初から手順書を作っているだけで9割は解決しますので。

最後まで読んでくださり、ありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

実務経験約6ヶ月のペーペーが実務で使ってない技術だらけでWebアプリを0から開発してみた話

0.はじめに

実務経験だいたい6ヶ月の僕がスキルアップのために現時点では実務で使っていない技術を使ってWebアプリを0から開発してみた話。

未経験からエンジニア転職を目指す方々のWebアプリ(いわゆるポートフォリオ)作成にも結構参考になることはあると思いますのでぜひ。

作成したのは面接情報共有アプリです。

1.使用技術

  • フロント:HTML/MDBootstrap4/Vue.js(2.6.11)
  • バックエンド:Laravel(6.8)
  • DB:開発環境はDockerのMySQLコンテナ、本番環境はRDS(MySQL)
  • 開発環境:Docker(LEMP環境)
  • インフラ:AWS(EC2/S3/Route53/ELB/RDS)
  • CI/CD:CircleCI
  • ソース管理:Git/GitHub

赤太字が2020/9/19時点で実務で使ってない技術

2.簡単に自己紹介

  • 関西のWeb系企業でPHPを使ったWebアプリ開発を行う新米パパエンジニア
  • 2019年10月からプログラミング学習を開始→2020年4月からエンジニアのキャリアスタート
  • Twitterで情報発信
  • 好きな食べ物はホットケーキ

Twitterはこちら↓
https://twitter.com/shimotaroo

3.開発背景

面接情報共有アプリを開発した理由は大きく分けて2つ。

  • Laravel、Docker、AWS、CircleCIの勉強のため(アウトプットしながらが効率的)
  • エンジニアへの転職活動中の方の面接の内容(特に質問)がTwitterで伸びやすいく、需要のある情報だと思ったため
  • 1つのサービスの開発、運用を経験してみたかったら(特に運用)
    ↑開発前はリリース→機能追加→リリースをしてサービスをグロースできたらいいなと思っていました、他にやりたいこと・やるべきことがたくさんあり、今はそこまで考えてない

4.(ひとまず)完成したWebアプリをご紹介

トップページ↓
スクリーンショット 2020-09-13 23.59.34.png

URL↓
https://mensetsu-app.work/

GitHub↓
https://github.com/shimotaroo/laravel-app

README.mdはこちらの記事を見ながら書きました。
【GitHub】シンプルなREADME.mdの書き方 -コピペで使えるテンプレート付き-

トップページに画像だったりとアプリの説明をいれるケースもありますが、Twitter、note、Instagramをイメージしてこんな感じのトップページのUIアプリの説明とか画像が入ってない)にしました。

自分がテスト投稿したデータが本番環境に残ってますが悪しからずww

5.完成までにかかった日数

スクリーンショット 2020-09-14 0.06.34.png

毎日このアプリ開発に時間を費やしていたわけではないので明確にわかりませんが草は上の画像の感じです。
(育児と本業、その他諸々の傍らコツコツやってました)

まあフルコミットすれば1ヶ月くらいでできたのかな、って感じです。(多分)

6.実装した機能

  • CRUD機能
  • ユーザー登録
  • ログイン/ログアウト
  • Googleアカウントでユーザー登録/ログイン
  • Twitterアカウントでユーザー登録/ログイン
  • プロフィール編集
  • パスワード変更(現在のパスワードをチェックする仕様)
  • プロフィール画像のデフォルト設定/変更
  • いいね(お気に入り)
  • ページネーション
  • 並び替え+ページネーション保持
  • 絞り込み検索+ページネーション保持

特別難しい機能はないかと思います。レベルの高い初学者の方ならポートフォリオとして盛り込んでいたりするかもです。
(と言っても僕はいくつかは手こずりました)

7.その他にやったこと

  • ER図書いてDB設計
  • 開発環境DockerでLEMP環境構築(もちろんLaradockじゃないです)
  • PHPPUnitで単体テスト
  • AWSにデプロイ
  • Circle CIで自動テスト/自動デプロイ

1つ前に書いた機能実装よりこっちの方が未知の分野だったので大変でした。そして頑張った。
(上手くいかず何度PCをぶん投げようと思ったか...)

8.DB設計

DB設計というかER図作成はDraw.ioというツールを使いました。
VSCode用のプラグインがありエディター上ででER図を作成できるスグレもの。

作成したER図はこちら↓
スクリーンショット 2020-09-14 0.49.36.png

作成したテーブルはこちら↓

テーブル名 説明
users 登録ユーザーの管理
articles 投稿された面接情報の管理
prefectures articlesに紐づける都道府県
company_types articlesに紐づける企業の事業形態
phases articlesに紐づける選考フェーズ
likes いいねの管理

ポイントとしてはarticlesテーブルにprefecturesやcompany_types、phaseの情報をベタでINSERTせずにそれぞれのテーブルで値を保持しておき、articlesテーブルではそのidを参照するように外部キー制約を設定しました。(正規化っていうらしい)

詳しいことは上のER図をみていただければわかるかなと思います。

僕はこれまでER図を書いたことがなかったので1から勉強しました。
初めはリレーションあたりが「?」でしたが、めっちゃググって理解できました。ググった中でも特にわかりやすかった記事を下にピックアップします↓

9.ソース管理

ソース管理は皆さんお馴染みのGit/GitHubです。

個人開発なのでGitHub Flowでソース管理しました。(masterとfeatureブランチ)

GitHub Flowがよくわからない人はこちらから↓
GitHub Flow 図解

※Gitに関して、僕の記事にもまとめていますので特に初学者の方はこちらも併せて読んでいただくとお役に立てると思います↓

Gitでやりたいこと、ここで見つかる

※僕のQiitaの記事は約800LGTMなので結構オススメです(笑)

10.環境構築

環境構築はDockerでLEMP環境を構築しました。

LEMP環境は以下の通りです。

  • L:Linux(OS)
  • E:Nginx(Webサーバー)
  • M:MySQL(DBサーバー)
  • P:PHP(アプリケーション)

Dockerを使ったLaravel+Vue.jsの実行環境の構築方法については以下にまとめております。今回作成したアプリもこの記事通りに環境構築しました。

絶対失敗しないのでDockerでLaravelの実行環境を構築をしたい方はぜひ併せて読んでいただければと思います。

11.インフラ

インフラはAWSを使いました。
僕は独学期間にAWSはノータッチ&実務でもまだAWSを使ったことがないので、この開発を通して初めて触りました。最初は意味不明ながらもUdemyの動画教材(後ほどご紹介します)を見ながら必死でインフラ構築しました。

構築したインフラはこちらです。

image.png

上図の通りですが簡単に。

  • Webサーバー:EC2
  • DB:RDS
  • DNS:Route53
  • 画像用ストレージ:S3
  • ロードバランサー:ALB

せっかくローカルの環境をDockerで構築したのでECSを使ってデプロイできればよかったのですが、いかんせんAWSを初めて触ったレベルだったので諦めました...(一応チャレンジはしました)
なお、"EC2内でDockerコンテナを立ち上げる"方法も検討しましたが、こちらも全然上手くいかず諦めました...
良い勉強になりましたが、今後は↑このあたりも勉強&挑戦していきたい。

あと、先ほど掲載したインフラの図を見て、「あれ...」って思われた方がいらっしゃると思うのでここで簡単に反省点をあげます(笑)

  • ロードバランサー使っているのにアクセスを振り分けるEC2が1つしかない
  • てかそもそもEC2もRDSも1つしかなくて全然冗長化できてない
  • 画像を扱うのにCloudFront使ってない

わかっています。わかってるんです...
お、お金の面を考慮してリーズナブルにしました...(お許しを...)

12.使った教材

僕がこのWebアプリを作成するために活用した教材をご紹介します。

Laravel、Vue.js:【Techpit】Laravel(+Vue.js)でSNS風Webサービスを作ろう!

PHPUnit、Circle CI、AWS:【 Techpit】Laravel × CircleCI × AWSで学ぶCI/CD

AWS:【Udemy】AWS:ゼロから実践するAmazon Web Services。手を動かしながらインフラの基礎を習得

Docker:【Udemy】米国AI開発者がゼロから教えるDocker講座

ここで紹介している教材は本当にわかりやすかったです。もちろん上記プラスで公式ドキュメントQiitaを見ながらしました。

当たり前と思いますがLaravelならこちらは必ず見た方が良いですね。
ReadDouble

13.大変だったこと

大変だったこと、苦労したことはやはり初めて触る技術・実務で使っていないですね。
具体的にはこちら↓

  • Laravel
  • PHPUnit
  • Circle CI
  • AWS

Laravelで大変だったこと

Laravelに関しては現職に入社する前に基礎は学習していたのでそこまで躓かなかったのですが、

  • 並び替え・絞り込み検索時のページネーション保持
  • プロフィール画像のデフォルト設定/変更

は結構手こずりました。

画像の取り扱いに関しては

  • 開発環境ではローカルに保存
  • 本番環境ではS3に保存

にするように変更したので、初めからS3に保存していてもよかったですね。

PHPUnitで大変だったこと

  • テストコードの書き方全般
  • DBを使ったユニットテスト(単体テスト)

結合テストだったり統合テストは今後勉強していきたいです。

Circle CIで大変だったこと

  • config.yml(設定ファイル)の書き方全般

だいぶ苦労しました。4日くらいひたすら自動テストの段階で格闘してましたw
めっちゃググって実際に書いて大まかな書き方は理解できたのでこれは今後別の記事にできたら良いなと。

※ちなみに、自動テストと自動デプロイが無事に通った瞬間は最高の気分で昇天するかと思いました。

AWSで大変だったこと

  • AWSの概念の理解
  • ALB(ELB)を使ってクライアントとの通信をHTTPS化

HTTPS化に関しては結局Laravel側にも設定が必要ということに気づいて解決したんですが、ここも結構時間を使いました。

14.実装したかったけどできなかったこと・まだしていないこと

思いつくだけでもこちらです↓

  • 要件定義
  • 基本設計
  • 詳細設計
  • ユーザー登録時のバリデーション強化
  • セキュリティ面の確認
  • コメント機能
  • DM機能
  • フォロー機能
  • Vue.jsの活用
  • ファビコン設定
  • Twitterへのシェア機能
  • Webサーバー、DBサーバーの冗長化
  • ECS(Elastic Container Service)でデプロイ
  • Cloud Frontでの画像のキャッシュ配信
  • Docker環境の最適化
  • 結合テスト/統合テスト

見てもらうとわかると思いますが、できてないこと・してないことはたっぷりです(笑)
少しずつできたらいいなと思います。

15.開発してみた感想

プライベートでWebアプリを開発したのは転職活動前ぶりでしたが、当時は

  • フレームワークなしでネイティブPHPのみ
  • ローカルはMAMP
  • Xserverに手動デプロイ
  • テストコード0

というなかなか笑えない感じだったので、今回色々な技術を使って開発した感想としては

  • アウトプットしながらのインプットがまじで最強
  • FW超便利
  • Docker超便利
  • AWSはむずい
  • CI/CDパイプラインは構築はむずいけどできたら超便利
  • 公式ドキュメントをちゃんと読むようになった
  • ググればある程度の問題は解決できた

とかですかね。

赤字で強調しましたが、アウトプットありきのインプットはまじで効率がオバケです。
どういうことかと言うと、勉強(インプット)してから「どんな機能を実装しようかな」(アウトプット)じゃなくて、まず実装する機能をまず決めて(アウトプット)それに必要な知識を勉強(インプット)するということです。

アウトプット駆動開発とでも言いいますか。

超オススメです。

(あとは実務未経験でポートフォリオにDocker、Circle CI、AWSを盛り込んでいる方がいますがマジですげえなと思いましたね)

16.さいごに

かなり長くなってしまいましたが、最後までご覧いただき本当にありがとうございますm(__)m

今後はもっと上流工程(要件定義、基本設計、詳細設計)にチャレンジしたいなと思っています。

初学者の方々も僕と同じくエンジニア1年生の方もアウトプット駆動開発でゴリゴリスキルアップしていきましょう(^^)

(あ...最後に...LGTMをポチッと押していただけると...昇天しま...あ、嬉しいです)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

実務経験約6ヶ月の僕が実務で使ってない技術だらけでWebアプリを0から開発してみた話

0.はじめに

実務経験だいたい6ヶ月の僕がスキルアップのために現時点では実務で使っていない技術を使ってWebアプリを0から開発してみた話。

未経験からエンジニア転職を目指す方々のWebアプリ(いわゆるポートフォリオ)作成にも結構参考になることはあると思いますのでぜひ。

作成したのは面接情報共有アプリです。

1.使用技術

  • フロント:HTML/MDBootstrap4/Vue.js(2.6.11)
  • バックエンド:Laravel(6.8)
  • DB:開発環境はDockerのMySQLコンテナ、本番環境はRDS(MySQL)
  • 開発環境:Docker(LEMP環境)
  • インフラ:AWS(EC2/S3/Route53/ELB/RDS)
  • CI/CD:CircleCI
  • ソース管理:Git/GitHub

赤太字が2020/9/19時点で実務で使ってない技術

2.簡単に自己紹介

  • 関西のWeb系企業でPHPを使ったWebアプリ開発を行う新米パパエンジニア
  • 2019年10月からプログラミング学習を開始→2020年4月からエンジニアのキャリアスタート
  • Twitterで情報発信
  • 好きな食べ物はホットケーキ

Twitterはこちら↓
https://twitter.com/shimotaroo

3.開発背景

面接情報共有アプリを開発した理由は大きく分けて2つ。

  • Laravel、Docker、AWS、CircleCIの勉強のため(アウトプットしながらが効率的)
  • エンジニアへの転職活動中の方の面接の内容(特に質問)がTwitterで伸びやすいく、需要のある情報だと思ったため
  • 1つのサービスの開発、運用を経験してみたかったら(特に運用)
    ↑開発前はリリース→機能追加→リリースをしてサービスをグロースできたらいいなと思っていました、他にやりたいこと・やるべきことがたくさんあり、今はそこまで考えてない

4.(ひとまず)完成したWebアプリをご紹介

トップページ↓
スクリーンショット 2020-09-13 23.59.34.png

URL↓
https://mensetsu-app.work/

GitHub↓
https://github.com/shimotaroo/laravel-app

README.mdはこちらの記事を見ながら書きました。
【GitHub】シンプルなREADME.mdの書き方 -コピペで使えるテンプレート付き-

トップページに画像だったりとアプリの説明をいれるケースもありますが、Twitter、note、Instagramをイメージしてこんな感じのトップページのUIアプリの説明とか画像が入ってない)にしました。

自分がテスト投稿したデータが本番環境に残ってますが悪しからずww

5.完成までにかかった日数

スクリーンショット 2020-09-14 0.06.34.png

毎日このアプリ開発に時間を費やしていたわけではないので明確にわかりませんが草は上の画像の感じです。
(育児と本業、その他諸々の傍らコツコツやってました)

まあフルコミットすれば1ヶ月くらいでできたのかな、って感じです。(多分)

6.実装した機能

  • CRUD機能
  • ユーザー登録
  • ログイン/ログアウト
  • Googleアカウントでユーザー登録/ログイン
  • Twitterアカウントでユーザー登録/ログイン
  • プロフィール編集
  • パスワード変更(現在のパスワードをチェックする仕様)
  • プロフィール画像のデフォルト設定/変更
  • いいね(お気に入り)
  • ページネーション
  • 並び替え+ページネーション保持
  • 絞り込み検索+ページネーション保持

特別難しい機能はないかと思います。レベルの高い初学者の方ならポートフォリオとして盛り込んでいたりするかもです。
(と言っても僕はいくつかは手こずりました)

7.その他にやったこと

  • ER図書いてDB設計
  • 開発環境DockerでLEMP環境構築(もちろんLaradockじゃないです)
  • PHPUnitで単体テスト
  • AWSにデプロイ
  • Circle CIで自動テスト/自動デプロイ

1つ前に書いた機能実装よりこっちの方が未知の分野だったので大変でした。そして頑張った。
(上手くいかず何度PCをぶん投げようと思ったか...)

8.DB設計

DB設計というかER図作成はDraw.ioというツールを使いました。
VSCode用のプラグインがありエディター上ででER図を作成できるスグレもの。

作成したER図はこちら↓
スクリーンショット 2020-09-14 0.49.36.png

作成したテーブルはこちら↓

テーブル名 説明
users 登録ユーザーの管理
articles 投稿された面接情報の管理
prefectures articlesに紐づける都道府県
company_types articlesに紐づける企業の事業形態
phases articlesに紐づける選考フェーズ
likes いいねの管理

ポイントとしてはarticlesテーブルにprefecturesやcompany_types、phaseの情報をベタでINSERTせずにそれぞれのテーブルで値を保持しておき、articlesテーブルではそのidを参照するように外部キー制約を設定しました。(正規化っていうらしい)

詳しいことは上のER図をみていただければわかるかなと思います。

僕はこれまでER図を書いたことがなかったので1から勉強しました。
初めはリレーションあたりが「?」でしたが、めっちゃググって理解できました。ググった中でも特にわかりやすかった記事を下にピックアップします↓

9.ソース管理

ソース管理は皆さんお馴染みのGit/GitHubです。

個人開発なのでGitHub Flowでソース管理しました。(masterとfeatureブランチ)

GitHub Flowがよくわからない人はこちらから↓
GitHub Flow 図解

※Gitに関して、僕の記事にもまとめていますので特に初学者の方はこちらも併せて読んでいただくとお役に立てると思います↓

Gitでやりたいこと、ここで見つかる

※僕のQiitaの記事は約800LGTMなので結構オススメです(笑)

10.環境構築

環境構築はDockerでLEMP環境を構築しました。

LEMP環境は以下の通りです。

  • L:Linux(OS)
  • E:Nginx(Webサーバー)
  • M:MySQL(DBサーバー)
  • P:PHP(アプリケーション)

Dockerを使ったLaravel+Vue.jsの実行環境の構築方法については以下にまとめております。今回作成したアプリもこの記事通りに環境構築しました。

絶対失敗しないのでDockerでLaravelの実行環境を構築をしたい方はぜひ併せて読んでいただければと思います。

11.インフラ

インフラはAWSを使いました。
僕は独学期間にAWSはノータッチ&実務でもまだAWSを使ったことがないので、この開発を通して初めて触りました。最初は意味不明ながらもUdemyの動画教材(後ほどご紹介します)を見ながら必死でインフラ構築しました。

構築したインフラはこちらです。

image.png

上図の通りですが簡単に。

  • Webサーバー:EC2
  • DB:RDS
  • DNS:Route53
  • 画像用ストレージ:S3
  • ロードバランサー:ALB

せっかくローカルの環境をDockerで構築したのでECSを使ってデプロイできればよかったのですが、いかんせんAWSを初めて触ったレベルだったので諦めました...(一応チャレンジはしました)
なお、"EC2内でDockerコンテナを立ち上げる"方法も検討しましたが、こちらも全然上手くいかず諦めました...
良い勉強になりましたが、今後は↑このあたりも勉強&挑戦していきたい。

あと、先ほど掲載したインフラの図を見て、「あれ...」って思われた方がいらっしゃると思うのでここで簡単に反省点をあげます(笑)

  • ロードバランサー使っているのにアクセスを振り分けるEC2が1つしかない
  • てかそもそもEC2もRDSも1つしかなくて全然冗長化できてない
  • 画像を扱うのにCloudFront使ってない

わかっています。わかってるんです...
お、お金の面を考慮してリーズナブルにしました...(お許しを...)

12.使った教材

僕がこのWebアプリを作成するために活用した教材をご紹介します。

Laravel、Vue.js:【Techpit】Laravel(+Vue.js)でSNS風Webサービスを作ろう!

PHPUnit、Circle CI、AWS:【 Techpit】Laravel × CircleCI × AWSで学ぶCI/CD

AWS:【Udemy】AWS:ゼロから実践するAmazon Web Services。手を動かしながらインフラの基礎を習得

Docker:【Udemy】米国AI開発者がゼロから教えるDocker講座

ここで紹介している教材は本当にわかりやすかったです。もちろん上記プラスで公式ドキュメントQiitaを見ながらしました。

当たり前と思いますがLaravelならこちらは必ず見た方が良いですね。
ReadDouble

13.大変だったこと

大変だったこと、苦労したことはやはり初めて触る技術・実務で使っていないですね。
具体的にはこちら↓

  • Laravel
  • PHPUnit
  • Circle CI
  • AWS

Laravelで大変だったこと

Laravelに関しては現職に入社する前に基礎は学習していたのでそこまで躓かなかったのですが、

  • 並び替え・絞り込み検索時のページネーション保持
  • プロフィール画像のデフォルト設定/変更

は結構手こずりました。

画像の取り扱いに関しては

  • 開発環境ではローカルに保存
  • 本番環境ではS3に保存

にするように変更したので、初めからS3に保存していてもよかったですね。

PHPUnitで大変だったこと

  • テストコードの書き方全般
  • DBを使ったユニットテスト(単体テスト)

結合テストだったり統合テストは今後勉強していきたいです。

Circle CIで大変だったこと

  • config.yml(設定ファイル)の書き方全般

だいぶ苦労しました。4日くらいひたすら自動テストの段階で格闘してましたw
めっちゃググって実際に書いて大まかな書き方は理解できたのでこれは今後別の記事にできたら良いなと。

※ちなみに、自動テストと自動デプロイが無事に通った瞬間は最高の気分で昇天するかと思いました。

AWSで大変だったこと

  • AWSの概念の理解
  • ALB(ELB)を使ってクライアントとの通信をHTTPS化

HTTPS化に関しては結局Laravel側にも設定が必要ということに気づいて解決したんですが、ここも結構時間を使いました。

14.実装したかったけどできなかったこと・まだしていないこと

思いつくだけでもこちらです↓

  • 要件定義
  • 基本設計
  • 詳細設計
  • ユーザー登録時のバリデーション強化
  • セキュリティ面の確認
  • コメント機能
  • DM機能
  • フォロー機能
  • Vue.jsの活用
  • ファビコン設定
  • Twitterへのシェア機能
  • Webサーバー、DBサーバーの冗長化
  • ECS(Elastic Container Service)でデプロイ
  • Cloud Frontでの画像のキャッシュ配信
  • Docker環境の最適化
  • 結合テスト/統合テスト

見てもらうとわかると思いますが、できてないこと・してないことはたっぷりです(笑)
少しずつできたらいいなと思います。

15.開発してみた感想

プライベートでWebアプリを開発したのは転職活動前ぶりでしたが、当時は

  • フレームワークなしでネイティブPHPのみ
  • ローカルはMAMP
  • Xserverに手動デプロイ
  • テストコード0

というなかなか笑えない感じだったので、今回色々な技術を使って開発した感想としては

  • アウトプットしながらのインプットがまじで最強
  • FW超便利
  • Docker超便利
  • AWSはむずい
  • CI/CDパイプラインは構築はむずいけどできたら超便利
  • 公式ドキュメントをちゃんと読むようになった
  • ググればある程度の問題は解決できた

とかですかね。

赤字で強調しましたが、アウトプットありきのインプットはまじで効率がオバケです。
どういうことかと言うと、勉強(インプット)してから「どんな機能を実装しようかな」(アウトプット)じゃなくて、まず実装する機能をまず決めて(アウトプット)それに必要な知識を勉強(インプット)するということです。

アウトプット駆動開発とでも言いいますか。

超オススメです。

(あとは実務未経験でポートフォリオにDocker、Circle CI、AWSを盛り込んでいる方がいますがマジですげえなと思いましたね)

16.さいごに

かなり長くなってしまいましたが、最後までご覧いただき本当にありがとうございますm(__)m

今後はもっと上流工程(要件定義、基本設計、詳細設計)にチャレンジしたいなと思っています。

初学者の方々も僕と同じくエンジニア1年生の方もアウトプット駆動開発でゴリゴリスキルアップしていきましょう(^^)

(あ...最後に...LGTMをポチッと押していただけると...昇天しま...あ、嬉しいです)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

インフラ未経験の学生がAWS認定ソリューションアーキテクトプロフェッショナルを取得するまで

はじめに

AWSを触り始めて5ヶ月でAWSソリューションアーキテクトプロフェッショナルを取得しましたので、その経緯と勉強法をまとめたいと思います。

EhyPmxAUcAAfy2Y.jpg

自己紹介

情報系の学部に所属している大学3年生のみなみ(@mkoki0822)です。
趣味は空を飛ぶ事で、スカイダイビングやウイングスーツというスポーツをやってます。

今年の4月まではプログラミング経験は殆どなく、授業で触った程度でした。
「Web系のインターン参加したいな〜」って思いまして、今年の4月からKoilinでアプリ作ったり、PHP(Laravel)で簡単なCRUDアプリを作成しておりました。
5月からは趣味の繋がりでインフラエンジニアとして長期インターンのような形で勉強させて頂いております!

受験時点でのインフラの知識

5月〜6月にサーバーやネットワークの基礎、AWSの基礎を学習しまして、AWSソリューションアーキテクトアソシエイトを取得しております。
主要なサービスについては触ったことがあります。

受験しようと思ったきっかけ

純粋にAWSが面白くて、もっと知識を増やしたい!という思いで挑戦しました。

学習時間

約100時間
8月18日から9月12日の26日間を使いました。
夏休み期間中でしたので、一日5時間以上は学習していたかと思います。
(ダラけてた時間も多いと思いますので実際に集中して取り組んだ時間は60時間くらいかと思います笑)

やったこと・教材

AWS認定ソリューションアーキテクト -プロフェッショナル 試験特性から導き出した演習問題と詳細解説

今年の6月に出版されたばっかりのプロフェッショナルの対策本です。
日本語で書かれたプロフェッショナル試験の為の対策本はこれまで出版されていませんでした。実務経験も無く、英語も苦手な自分にとってはありがたかったです。

本書籍は1〜9章で構成されています。

  • 第1章 AWS認定ソリューションアーキテクト -プロフェッショナル試験の概要と特徴
  • 第2章 各種サービスの概要
  • 第3章 試験で問われるシナリオの特性
  • 第4章 「組織の複雑さに対応する設計」分野におけるケース問題
  • 第5章 「新しいソリューションの設計」分野におけるケース問題
  • 第6章 「移行の計画」分野におけるケース問題
  • 第7章 「コスト管理」分野におけるケース問題
  • 第8章 「既存のソリューションの継続的な改善」分野におけるケース問題
  • 第9章 模擬問題

1章〜3章が講義形式で
4章〜9章が問題形式となっております。
問題は全部で150問程度で、解説も詳しく記載されていますのでぜひやるべきです!

公式模擬試験

クラウドプラクティショナーとアソシエイトで2回分の無料バウチャーを貰いましたので、使わせていただきました。
なかなかの難易度の問題が出題されますが、気を落とさないように

自分の場合は対策本が終わった時点で45%
試験の3日前に75%でした。

また、問題の答えを教えてくれないので、自分で調べる必要があります。

AWS WEB問題集で学習しよう koiwaclub

https://aws.koiwaclub.com/
有料となりますが、かなり本試験に近い問題が350問ほどあります。
自分はこちらの問題集を重点的に学習しましたが、一番役に立った教材でした。

最低でも2〜3周、7割以上は正解できるまで繰り返すべきです。
また、しっかり解説も読み込み、それでも理解出来ない点に関してはAWS公式ドキュメントを確認しましょう。

Exam Readiness: AWS Certified Solutions Architect – Professional (Japanese)

https://www.aws.training/Details/eLearning?id=42403
AWSが公式に出しているプロフェッショナル試験対策のE-ラーニングです。(もちろん無料!)
約4時間程度で終わる分量ですが、絶対やっておくべきです!

Jayendra's Blog

https://jayendrapatil.com/
英語の教材となりますが、かなり評判がよかったので少し使ってみました。
こちらの教材は半分が講義形式、半分が問題形式の教材となります。
体感ですが、問題に関しては対策本やKoiwaClubと被っている所も結構ありますので、無理にしなくてもいいかもしれません。

対策本の代わりにこちらの教材をやるのであればオススメします!(無料ですので)

Blackbelt AWS クラウドサービス活用資料集

みんな大好きBlackBelt
サービスの概要を掴めます。

しかし今回のプロフェッショナル試験では、サービス一つ一つの知識よりもサービスを組み合わせてどのように課題解決を行うかが出題されますので、最初に確認する程度で大丈夫かと思います。

AWS 認定ソリューションアーキテクト プロフェッショナル模擬試験問題集(全5回分375問)

https://www.udemy.com/course/aws-53225/
こちらの問題集ではかなりマニアックな問題まで出題されます。
900点以上を目指したいのであればやるべきなのかも知れませんが、やりすぎな所もあります。

自分には難しすぎて、途中で投げ出しました....笑

公式のドキュメント、Q&A、WhitePaper

こちらは他の教材と組み合わせて使用するのがオススメです!
中にはこちらの教材のみを用いて合格する猛者もいらっしゃるようですが、結構な分量があります。

ちなみに、もし今回落ちた場合は、こちらを徹底的に読み込もうかと考えていました。

試験当日

試験当日は緊張しすぎて40分前に到着してしまいました...
今回は特別にテストセンターに空きがあった為30分前から受験させていただきました。
→基本的には15分前くらいに行きましょう笑

試験時間は180分ですが、わからない所を飛ばしつつ80分で一周しました。(一周終了時点でフラグを立てていた問題は25問程度です。)
KoiwaClubの類題が全体の2〜3割近くあったので、その問題に関しては即答できましたが、フラグを付けた問題はどれもビミョーな問題ばかり...
2周目は一旦フラグ以外の問題の見直して、ケアレスミスの確認を行います。(20分程度)

残りの80分で25問のフラグを付けた問題に取り掛かります。
どれも二択までは絞り込めるものの、どっちもありそうで困る、、
最終的には消去法でなんとか絞り込みました。

結果

無事合格出来ました!
最終的に自信のなかった問題は17問ほどありましたが、スコアは840 「ギリギリで合格かな〜」って思っておりましたが、二択が結構当たったのかもしれません。

全てのセクションも「十分な知識を有する」でしたので満足!
スクリーンショット 2020-09-19 18.17.49.png

感想

プロフェッショナル試験を合格しましたが、だからといって自分が「プロフェッショナルになった!」とは思えません。(AWSナニモワカンナイ)

ですが今回の試験勉強を通じて、AWSの基礎的知識であったりAWSはこんな風なユースケースを想定しているんだーってのをなんとなく感じることが出来ました!

PS.就活頑張ります......

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS-Athenaでファイル名をカラムに追加する方法

この記事の内容

AWS-Athenaで、ファイル名をカラムに追加するやり方をご紹介します。

もう少し具体的に述べると、
以下のファイル名のデータがS3の同じ場所に格納されていて、
YYYYMMの部分をクエリで利用したいケースを想定しました。
・「test_file_202001.csv」
・「test_file_202002.csv」
・「test_file_202003.csv」

クエリ例

Athenaでファイル名をカラムとして取得するには、「"$path"」を利用します。

SELECT "$path" FROM テーブル名

やってみた(環境構築)

バケット名「test-bucket」の配下に、以下3つのデータが格納されています。

・「test_file_202001.csv」

name
satoshi
kasumi

・「test_file_202002.csv」

name
takeshi

・「test_file_202003.csv」

name
musashi
kojiro
sakaki

やってみた(クエリ実行)

クエリを早速実行してみます。

SELECT
  *
  , "$path" 
FROM 
  バケット名

S3のバケット名とファイル名の両方が取得できました。

name $path
satoshi s3://test-bucket/test_file_202001.csv
kasumi s3://test-bucket/test_file_202001.csv
takeshi s3://test-bucket/test_file_202002.csv
musashi s3://test-bucket/test_file_202003.csv
kojiro s3://test-bucket/test_file_202003.csv
sakaki s3://test-bucket/test_file_202003.csv

応用例

今回のように「YYYYMM」部分のみを取得したい場合は、正規表現を用いて置換して取得しました。

SELECT
  *
  , REGEXP_REPLACE(REGEXP_REPLACE("$path", '^s3://test-bucket/test_file_', ''), '.csv$', '') AS yyyymm
FROM 
  バケット名

意図した通りの結果が取得できました!

name yyyymm
satoshi 202001
kasumi 202001
takeshi 202002
musashi 202003
kojiro 202003
sakaki 202003

最後に

簡単にカラムを追加できるので非常に便利ですね!

参考文献

Amazon Athena ユーザーガイド

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CloudFormationでEC2にIAMロールを付与する

CloudFormationで作成したEC2から「S3の特定バケットに対してアクセス可能にする」方法の紹介です。
テンプレートファイルに「S3の特定バケットに対してアクセスを許可する」IAMロールを作成しEC2に付与しました。

4 Step

テンプレートファイルに以下の4項目を追記します。

  1. IAMロールの記述
  2. IAMポリシーの記述
  3. IAMインスタンスロールの記述
  4. EC2インスタンスにIAMインスタンスロールを付与

1. IAMロールの記述

IAMユーザーと似ていますが異なる点があります。

  • IAMユーザーはにアクセス権限を付与
  • IAMロールはAWSリソースにアクセス権限を付与

今回アクセス権限を付与したいのはEC2ですので、IAMロールを使用します。

  S3AccessRole:
    Type: "AWS::IAM::Role"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement: 
          - 
            Effect: "Allow"
            Principal: 
              Service: 
                - "ec2.amazonaws.com"
            Action: 
              - "sts:AssumeRole"
      Path: "/"

2. IAMポリシーの記述

アクセス権限の具体的な内容は、IAMポリシーに記述します。
Roleに先程記述したIAMロールを指定します。

<bucketname>は実際のバケット名に置き換えます。

  S3AccessPolicies:
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: s3access
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Action:
            - "s3:ListAllMyBuckets"
            - "s3:GetBucketLocation"
          Resource: "arn:aws:s3:::*"
        - Effect: Allow
          Action: "*"
          Resource:
            - "arn:aws:s3:::<bucketname>"
            - "arn:aws:s3:::<bucketname>/*"
      Roles:
      - !Ref S3AccessRole

3. IAMインスタンスプロファイルの記述

EC2インスタンスとロールを紐づけるのに、IAMインスタンスプロファイルを記述します。

  S3AccessInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: "/"
      Roles:
      - !Ref S3AccessRole

4. EC2インスタンスにIAMインスタンスロールを付与

EC2インスタンスにIAMインスタンスプロファイルを付与します。

  Instance:
    Type: 'AWS::EC2::Instance'
    Properties:
      IamInstanceProfile:
        !Ref S3AccessInstanceProfile

参考

AWS::IAM::Role - AWS CloudFormation
やーまんぶろぐ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Amazon API GatewayでmTLSを試してみた。(1/2)

はじめに

特に金融系のAPI等、より強固な認証を求められるIoTデバイス等からの認証を行う際にはクライアント証明書による認証を求められることがあるかと思います。当記事では、Amazon API Gateway(執筆時点ではRegionalおよび、HTTP API限定)によるmTLS(Mutual TLS authentication)について構成を試したので記載したいと思います。
当機能に関するドキュメントとしてこちらを参考にして構築しました。

なお、当記事は2020年3月にGAしたHTTP APIをベースに記載しており、従来からあるREST APIについては検証・記載しておりません。

(この記事30分くらいの検証と2時間くらいの執筆かな~と持っていたら、苦労したことに書きましたが、自分の構成管理ミスで思ったより手間取りました。そして証明書のチェーン(中間CA)も作ろうと思ってまだ作れてなかったり・・・。)

追記:後続の記事はこちら

サマリ

  • 認証で使用された証明書情報はEvent内で連携される。
  • Lambda AuthorizerにもEventとして証明書情報が連携される。
  • PEMそのものや、解析済みのデータ(例:SubjectDN,Serial Number)を利用することで追加の処理が可能(この部分は別記事で書くことにしました。長くなったので。)

mTLS(Mutual TLS authentication)とは

mTLSはAPIのセキュリティを強化し、クライアントのなりすましや中間者攻撃などの攻撃からデータを保護するのに役立ちます。

mTLSを利用しない通常のTLS

mTLSを利用しない通常のTLSの通信(WebにおいてはHTTPS通信)は、クライアントがサーバに対してX.509証明書を要求し、サーバが自身の証明書をクライアントに提供します。サーバから提供された証明書は代表的な認証局(またはその中間認証局)によって認証(署名)されているケースが一般的なWebでは利用され、それをもって偽物ではないことを確認します。ここで、一般的とつけたのは、企業内でPrivateに利用する証明書については、自社内の認証局で署名された証明書を利用しているケースもあるためです。証明書の発行手順や認証(署名)、中間証明書の概念については世の中にわかりやすく解説されている記事がありますのでそちらをご参照ください。

mTLSを利用する通信

さて、一般的なTLS通信はサーバサイドの証明書を利用した片方の認証のみをする仕組みでした。
mTLSは?というと、クライアントサイドの証明書をサーバサイドに提供し、サーバサイド”も”クライアントを証明書の検証を通じて認証する仕組みとなります。Open Bankingなどの標準で使用されており、金融機関向けに安全なオープンAPI統合が可能になったり、IoT領域では、各デバイスにクライアント証明書を導入していることが多く、証明書を使用してデバイスを認証するのが一般的になっています。
 個々クライアントやデバイスごとに秘密鍵とクライアント証明書(CA証明書で署名)を用意して接続時に利用することで認証を強化します。AWS IoTでもクライアント証明書を利用した認証が採用されていますね。

mTLSを考える上での登場人物

アクター 説明 当記事の場合
クライアント HTTP リクエストを行う人。クライアント証明書と秘密鍵を保持しそれを利用してサーバと通信 cloud9のTerminal/Curlコマンド
サーバ HTTPのサーバ。サーバ証明書を持ち、クライアントと通信。なおmTLSの検証用にクライアント証明書の署名で利用したCA証明書を保持。 Amazon API Gateway + Amazon S3+ Amazon Certificate Manager(ACM)
CA局(ルート/中間) サーバ証明書の作成・署名や、クライアント証明書の署名を行う サーバ証明書はACM/クライアント署名に利用するCA証明書はOpenSSLを利用

Amazon API Gateway におけるmTLS対応

2020年9月18日より、Amazon API Gatewayは、追加費用なしでmTLS認証をサポートするようになりました。
今までは、
1. JWTによる認可
2. Lambda Authorizerによる認可
3. IAMベースの認可

がサポートされていましたが、新たにmTLSを有効化することができるようになりました。既存の認可と組み合わせ利用できるようで今回はLambda Authorizerと組み合わせて試してみました。(IAM/JWTは試してないです。また、構成や内容は別の記事に書きました。)

Amazon API Gatewayの構成

必要ななもの

<<直接的に必要なもの>>とそれを作るために<<間接的に必要なもの>>があります。例えば、クライアントが接続したときに提示する「クライアント証明書」や接続に利用するクライアントの秘密鍵は直接必要なものです。ちなみに、このクライアント証明書はCA証明書で署名されている必要があります。また、サーバサイドではクライアント証明書を検証するためには先ほど言及した「クライアント証明書作成時に署名したCAの証明書」を保持する必要があり、これもまた、直接必要なものとなります。一方、間接的にと表現したのは、例えば、CA証明書の秘密鍵はCA証明書を作るために必要ですが今回の構成で直接利用するものではありません。また、mTLSはカスタムドメインを有効化する必要が前提としてあり、カスタムドメインを有効化するためには、ご自身で管理可能なドメイン(DNS)やそのドメインでHTTP通信するためのサーバ証明書も必要となります。ということで必要なものを列挙しておきました。

API Gateway側

以下、1~8まで挙げましたが1~5はmTLSの設定というよりは、HTTP APIの基本構成(1,2)に加えてカスタムドメインで呼びさせるようにするための構成(3,4)となります。まずは、この1~4が終わっていることがAPI GatewayのmTLS有効化の第一歩です。また5については、今回は入れましたが必須ではありません。6~8がmTLS構成をするために必要な固有の要素で、既にCA証明書をお持ちの場合は、6,7は作る必要はなく、8を作るって構成するのみとなります。
1. APIそのもの
2.呼び出されたときのバックエンドのアプリケーション(今回はLambda)
3.API Gatewayのカスタムドメインで利用するドメイン名
4.API Gatewayのカスタムドメインに対応するサーバ証明書
5.呼び出されたときのLambda Authorizer
6.CA証明書を作るための秘密鍵
7.CA証明書
8.CA証明書を格納するS3バケット

クライアント側

クライアント側は通信時に以下があればmTLSで通信ができます。
1.秘密鍵
2.クライアント証明書(PEM)

構築開始

今回はAWS マネジメントコンソールやCloud9のターミナルを利用して構成しました。
Cloud9 のターミナルはopensslで鍵や証明書の作成、そして、動作確認としてcurlでアクセスするために利用しました。

下準備

まずはサーバサイドを構築しようと、上記のAPI Gateway側の中の1,2を構築し、その後3,4を実施する流れでご説明します。

A.APIの初期設定

A.1.APIやLambdaをSAMで構築(手動でもO.Kです)

手動で構築する手順の参考: HTTP APIの作成チュートリアル

今回は、面倒だったので実は以下のようなSAMのテンプレートで1,2,5,8を作りました。以下は例ですが、SAMのテンプレートを置いたディレクトリ内にhello_worldとauthの二つのフォルダを作ってそれぞれソースを配置しています。sam initで初期化してテンプレートを少しかえて微調整すればOK。

image.png

SAMをまだご経験がない方はAWS マネジメントコンソールでHTTP APIの作成、Lambda の作成(2個)、S3バケットの作成をしてみてください。

Globals:
  Function:
    Timeout: 3
Resources:
  mTLSTrustStoreS3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub 'mtls-truststore'
      VersioningConfiguration:
        Status: Enabled 
  TrustStoreS3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      VersioningConfiguration:
        Status: Enabled 
  mTLSAuthorizerFunction:
    Type: AWS::Serverless::Function 
    Properties:
      CodeUri: auth/
      Handler: app.lambda_handler
      Runtime: python3.7
  HelloWorldFunction:
    Type: AWS::Serverless::Function 
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.7
      Events:
        HttpApiEvent:
          Type: HttpApi
          Properties:
            Path: /hoge/auth
            Method: GET
Outputs:
  HelloWorldApi:
    Description: "API Gateway endpoint URL for Prod stage for Hello World function"
    Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/hoge/auth"
  BucketName:
    Value: !Ref 'TrustStoreS3Bucket'
    Description: Name of the TrustStore S3 Bucket.

SAMでbuild とdeployが成功すると以下のように中身が何もない空のS3バケットが出来上がります。

image.png

また、API GatewayのHTTP APIとして以下のようなルートの構成を持ったAPIができます。
なお、この時点ではLambda Authorizerによる認可設定はしていません。

image.png

一方で統合ではバックエンドのリソースとしてLambdaと統合しています。

image.png

Lambdaのコンソールを確認すると、Lambda関数が2個追加されています。1つはLambda Authorizer用,もう一つは前述の統合で指定されたHello Worldの関数です。両方とも処理結果の応答形式が決まっています。Lambda Authorizerはこちらを参考に以下の形式で固定値で応答しています

app.py
#Lambda Authorizer
def lambda_handler(event, context):
    return {
        "isAuthorized": True
    }
app.py
#Hello World
import json
def lambda_handler(event, context):
    return {
        "statusCode": 200,
        "body": json.dumps({
            "message": "hello world"
        }),
    }

さて、ここまでで、API Gatewayが提供するエンドポイントにアクセスするとLambda Authorizerは通らず(まだ未構成)、HelloWorldのLambdaが呼び出され、応答を受け取ることが可能です。Lambda Authorizerの構成は別の記事で記載します。

A.2 動作確認

CurlやブラウザでAPIにアクセスしてみてください。URLが分からない方は、画面で確認できますので確認してみてください。

image.png

B.カスタムドメイン設定

B.1 カスタムドメイン構成のために証明書を作成

さて、ここからは、カスタムドメインでアクセスできるようにするための設定です。
必要なことは、ドメインを手に入れ、証明書を作ることです。
今回は、ドメインはRoute 53を利用して登録することも可能ですし、ご自身、または会社がAWS外,または別のAWSアカウント内部で管理されているドメイン、オンプレで管理されているドメインを利用することも可能です。今回は私は、外部で販売されている1円のドメインを購入しました。そのドメインのネームサーバをRoute 53のネームサーバに登録したうえで、証明書の作成を実施しました。以下は証明書を作った状態です。こちらの証明書はAWSコンソール上で、私の場合は5分程度で作成できました。手順はこちらを参考にしてみてください。

image.png

ちなみに今作成した証明書はサーバ証明書と一般的に呼ばれるもので、Amazon Certificate Manager(ACM)をご利用いただくことで無料で発行ができ、API Gatewayだけでなく、Application Load BalancerやCDN(Contents Delivery Network)の役割を果たすCloudFront等のサービスとシームレスに連携でき便利です。発行される証明書の要件をご確認の上、ご活用ください。(注意;発行自体は容易ですが、発行するためにはそのドメインの管理者であること、つまり、DNS管理者ならできるであろう操作や、管理者へのメールによる確認が行われます)

B.2 カスタムドメイン構成

証明書を作成したのでACMの証明書を利用してAPI Gatewayにカスタムドメイン登録を行います。HTTP APIのカスタムドメインは1つのドメイン内に複数のドメインをルーティングでき、統合が可能になっています(私は実は、昨日社内の同僚たちのチャットで知り、試したところです)。以下の画面が構成したときの例です。ACM証明書は作成済みなため、選択できます。画面上にはMutual TLS authenticationというタブがありますが、この時点では有効化していません。もちろん有効化していただいてもよいですが、カスタムドメイン構成が失敗したまま、mTLS構成したときデバッグがしにくいかなと考え段階を踏んでいます。
image.png

さてドメイン名を構成すると裏では、Route 53にレコードが追加されています
image.png

1つのドメインに複数のAPIを統合することができると先ほど記載しましたが、以下が2つのAPIを統合する構成例です。ということで、今回構築しているAPIは
https://カスタムドメイン/qiita/hoge/auth
で動くように設定しました。

B.3 動作確認

ということで、動作確認をブラウザ、またはcurlで実施します。

image.png

mTLS構成開始

API Gatewayの構成

C.CA証明書の準備とS3への格納

ここからが本格的にmTLSの構成作業となっていきます。まずは、CA証明書ですね。こちらは、Public/PriateなCAでも自己署名で作成したCAの証明書でも問題とドキュメント上記載があります。
私は今回用に自己署名によるCA証明書を作成することにしました。
以下、コマンドで実施しました。

C.1 CA証明書用の秘密鍵の生成

openssl genrsa -out rootCA.key 2048

C.2 CA証明書の作成

openssl req -x509 -new -nodes \
    -key rootCA.key \
    -sha256 -days 1024 \
    -out rootCA.pem

C.3 CA証明書をS3バケットに保管

以下のコマンドでS3に保存可能です。こ

aws s3api put-object --bucket XXX --key rootCA.pem --body rootCA.pem

image.png

今回作成したこのバケットはバケット作成時にバージョニングを有効化したため、戻り値にVersionIdが返ってきました。
例えば、間違って上書きや削除されたときにバージョニングを指定しておくことでそのバージョンのオブジェクトが参照できるため有効化しています。ただ、バージョン自体の削除も権限があれば可能になるため、それを防ぎたい場合はS3 のObject Lockをご利用いただくと一段階、強固な設定となります。
なお、バージョニングを有効化するとその分のオブジェクトの料金が加算されますのでご注意ください(参考)
バージョニングは適宜S3のライフサイクルポリシー等を活用しながら有効活用してください。

D.API Gateway のmTLS構成

D.1 mTLS 有効化設定

S3 Bucketおよび格納したファイル名(オブジェクト名)、必要に応じてオブジェクトのバージョンを指定しmTLSを有効化します。
image.png

さあ、これでサーバサイドはmTLS対応しました。念のため接続確認をしてみましょう。

ステータスが以下の通りUpdatingではなく、Availableになってからお試しください。
image.png

D.2 mTLS 有効化設定後の動作確認

Curlコマンドで-vをつけてログを出力いながら確認しましたが、接続できなくなりました。サーバサイドはたぶんOK。エラーの理由は接続時にクライアント証明書を送付していないからです。(構成が正しければ)

image.png

クライアント証明書の準備と接続

ここまでくると後は証明書を作って接続するだけです。

E. クライアント証明書の作成

E.1 クライアントの秘密鍵の作成

openssl genrsa -out device.key 2048

E.2 CA証明書で証明したクライアント証明書の生成のための要求(CSR)の作成

openssl req -new \
    -key device.key \
    -out deviceCA.csr

E.3 CSR からクライアント証明書を作成

今回は有効期限が1日のものと有効期限が切れたものの二種類を用意しました。

openssl x509 -req \
-in deviceCA.csr \
-CA rootCA.pem \
-CAkey rootCA.key \
-CAcreateserial \
-out deviceCert.pem \
-days 1 -sha256

openssl x509 -req \
    -in deviceCA.csr \
    -CA rootCA.pem \
    -CAkey rootCA.key \
    -CAcreateserial \
    -out deviceCertExpire.pem \
    -days 0 -sha256

E.3 クライアント証明書を利用した接続確認

有効期限内

 curl -v --key device.key --cert deviceCert.pem  https://api.mtls.XXXXXX/qiita/hoge/auth

image.png

有効期限切れ

有効期限切れの証明書では以下の通りHTTP403 が応答されました。

curl -v --key device.key --cert deviceCertExpire.pem https://api.mtls.XXXXXX/qiita/hoge/auth

image.png

また、CloudWatch Logsにログを出力するように構成した結果、以下の通りログでも接続できていないことが確認できました。
image.png

苦労した点

構成を一通りまとめましたが、私がハマったのは、
1. CA証明書を複数作っていて、クライアント証明書との組み合わせが間違ったままテストしていた。
2. クライアント証明書の有効期限を逆に設定していてつながらない!って苦労した
3. 20分くらいでできるかな~とおもって梅酒を飲みながら挑戦したら、証明書をACMで発行するところで寝落ちしてどこまで何をしたか忘れてしまった。

ということで、構成自体は横道にずれずに構成していればすんなりいけました。ちなみに、CLIで操作する方やSAMをご利用になる方は最新バージョンにUpdateしてご利用ください。

まとめ

手順は色々ありますが、mTLSの構成だけであれば、簡単に実装できます。mTLS機能がリリースされる前は、例えば、自身でNLBを構築し、さらには、Farate or EC2を運用する形で利用されていたのではないでしょうか?そのアンマネージドな部分をサーバレスアーキテクチャに置き換えることも可能です。置き換えることでInternet Facingな自身のリソースを減らすことができたり、運用コストを減らすことが可能になるかと思います。ぜひご検討ください。

本当はLambda Authorizerや後続のLambdaの処理について記載しようと思いましが、長くなったのでいったん区切ります。別記事で記載します。

続きも書く予定です。 書きました。後続の記事はこちら

次に書きたいこと

・Lambda内で実施できること、すること
・セキュアなバケット
・運用回り
・ログ

参考

こちらのブログ、英文ですが丁寧に手順が書かれてました。書いてから気づいた・・・。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

EC2作成直後の状態から最速でVue.js(Vue CLI版)のWebサイトを立ち上げて簡易的にCI/CDする

はじめに

初心者向けシリーズ。
前回の記事で「Vue.js、チョットワカッテキタ」な感じになってきたら。

以下の通りに実行していけば、S3の静的Webサイトホスティング上でVue CLIでビルドしたVue.jsのHello Worldが動くようになる。

Vue CLIはけっこうすごくて、これを使いこなせるとJavaScriptの静的コンテンツのCI/CDを回せるようになる。楽しい。

手順

1. yumのアップデート

$ sudo yum update

2. Node.jsのインストール(npmがNode.jsに含まれる)

Vue.jsの静的解析はESLintという強力なlinterがあるので、それを動かすためにnpmを入れておく。

Node.jsについては、予め、rpm.nodesource.com でサポートバージョンを確認しておく。今回は、記事を書いたタイミングでサポートされている14をインストールする。

$ curl -sL https://rpm.nodesource.com/setup_14.x | sudo bash -
$ sudo yum install -y nodejs

3. Vue CLIのインストール

npmを -g でインストールするときは /usr/lib を触ったりすることもあるので、sudo で実行。

$ sudo npm install -g @vue/cli @vue/cli-init

4. プロジェクトの作成

$ vue init webpack test

質問に答えていくとプロジェクトが作られる。

キャプチャ1.png

プロジェクト名とか説明とかAuthorは適当に設定して、ビルドはランタイムを入れよう。

キャプチャ2.png

今回はVue-Routerは使わないのでNo、ESLintはStandardなチェックをするように入れておく。

キャプチャ3.png

単体テストはしておけるように、テストランナーでJestを入れておく。

キャプチャ4.png

NPMかYarnか選択できるが、今回はNPMを使う。

これでしばらく待つと、コマンドが終了し、以下のディレクトリ構造のプロジェクトが作成される。

test
├── .babelrc
├── build
│   ├── build.js
│   ├── check-versions.js
│   ├── logo.png
│   ├── utils.js
│   ├── vue-loader.conf.js
│   ├── webpack.base.conf.js
│   ├── webpack.dev.conf.js
│   └── webpack.prod.conf.js
├── config
│   ├── dev.env.js
│   ├── index.js
│   ├── prod.env.js
│   └── test.env.js
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── index.html
├── package.json
├── package-lock.json
├── .postcssrc.js
├── README.md
├── src
│   ├── App.vue
│   ├── assets
│   │   └── logo.png
│   ├── components
│   │   └── HelloWorld.vue
│   └── main.js
├── static
│   └── .gitkeep
└── test
    └── unit
        ├── .eslintrc
        ├── jest.conf.js
        ├── setup.js
        └── specs
            └── HelloWorld.spec.js

5. おためしコンテンツの作成

ディレクトリ構造の内、src部分が実際にコンテンツを作っていく部分になる。
今回は、以下のようにsrcを修正してみよう。

  • assets/logo.png を削除(使わない)
  • App.vueを修正
  • HelloWorld.vueを修正
App.vue
<template>
  <div id="app">
    <HelloWorld/>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld'

export default {
  name: 'App',
  components: {
    HelloWorld
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
HelloWorld.vue
<template>
  <div class="hello">
    <h1>{{ message }}</h1>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      message: "Hello World!!"
    }
  }
}
</script>

<style scoped>
h1 {
  font-weight: normal;
}
</style>

6. 構文チェック

スクリプトを書いたら構文チェックをしておこう。

$ npm run lint

↑の例ではあえてESLintに引っかかるエラーを入れてある。
実行すると、

キャプチャ5.png

というエラーが出るはずなので、

HelloWorld.vue
(前略)
<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      message: 'Hello World!!'  // ★ダブルクォートをシングルクォートに修正
    }
  }
}
</script>
(以下略)

と修正すればエラーが解消するはずだ。

7. テストコードの作成

ディレクトリ構造の内、test部分がテストコードを記述する部分だ。
Vue.jsのテスト自体は色々やり方があるので、以下のコンテンツを見てもらうと分かりやすい。

以下で、Vue Test Utilsのモジュールをインストールする

$ npm install --save-dev @vue/test-utils

今回のテストだと、使用しない機能の部分でエラーが出てしまうので、それを修正しておく。
詳細な説明はこちらを参照。

jest.config.js
module.exports = {
  (中略)
  testURL: 'http://localhost/',
  (中略)
}

さて、これができたらテストコードを書く。
といっても、今回はおためし程度なので、デフォルトをちょっといじる程度にしておこう。

HelloWorld.spec.js
import { shallowMount } from '@vue/test-utils'
import HelloWorld from '@/components/HelloWorld.vue'

describe('HelloWorld.vue', () => {
  it('should render correct contents', () => {
    const wrapper = shallowMount(HelloWorld)
    expect(wrapper.vm.$el.querySelector('.hello h1').textContent).toEqual('Hello World!!')
  })
})

これで、テストを実行する。

$ npm run unit

↓こんな感じで、テストの成否とカバレッジを表示してくれる。
今回の例では、App.vueのテストを作っていないのでカバレッジが0%になっている。

キャプチャ6.png

8. ビルド

コンテンツをビルドする。

$ npm run build

すると、distディレクトリが作られ、アップロード用のファイルが以下のように出力される。

dist
├── index.html
└── static
    ├── css
    │   ├── app.3e445f0fd3565060e18da48a5a8354c0.css
    │   └── app.3e445f0fd3565060e18da48a5a8354c0.css.map
    └── js
        ├── app.19b1235d26d10f952294.js
        ├── app.19b1235d26d10f952294.js.map
        ├── manifest.2ae2e69a05c33dfc65f8.js
        ├── manifest.2ae2e69a05c33dfc65f8.js.map
        ├── vendor.3bf08807642cffd4f854.js
        └── vendor.3bf08807642cffd4f854.js.map

9. S3バケットを作成

…の前にコンフィグ設定

$ aws configure
AWS Access Key ID [None]: xxxxxxxxxxxxxxxxxxxx
AWS Secret Access Key [None]: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Default region name [None]: ap-northeast-1
Default output format [None]: json

今度こそバケットを作成

$ aws s3 mb s3://neruneruo-vuejs-test-bucket
$ aws s3 ls

静的Webサイトホスティングの設定

$ aws s3 website s3://neruneruo-vuejs-test-bucket --index-document index.html

ファイルをアップロード

$ aws s3 cp dist s3://neruneruo-vuejs-test-bucket --acl public-read --recursive

これで、静的WebサイトホスティングのURLにアクセスしたら「Hello World!!」が表示されたはずだ。

あとは、package.json に

package.json
  "scripts": {
    (中略)
    "deploy": "npm run lint && npm run test && aws s3 cp dist s3://neruneruo-vuejs-test-bucket --acl public-read --recursive",
    (中略)
  }

を書いておけば、

$ npm run deploy

で良い感じに構文解析しつつテストコードを走らせてからデプロイができる!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS CloudFormation】EC2とRDSの自動構築

目標

CloudFormationを利用してEC2とRDSを自動構築するテンプレートを作成する。

前提

・VPC、及びサブネット(パブリック1つ、複数AZにプライベート2つ)が構築済みであること。
・サブネットグループ(RDSを配置する、複数AZにまたがるサブネット集合体)が構築済みであること

CloudFormationとは

AWSインフラの構成要素一式をテンプレートコードによって自動構築するサービスです。
一度テンプレートを作成すれば、同一構成のAWSインフラを簡易的に作成することが可能です。
テンプレート実行により作成されるAWSリソースの集合体をスタックといいます。

作成するスタックの仕様

・パブリックサブネットにEC2インスタンスを1台、プライベートサブネットにRDSインスタンス(MySQL、シングルAZ)を1台作成

EC2、RDS用のセキュリティグループを2つ新規作成し、上記EC2及びRDSインスタンスにアタッチする。

RDSインスタンスへの通信は、テンプレートによって作成されたEC2のセキュリティグループがアタッチされたEC2インスタンスからの通信のみを許可

・以下の値はテンプレート実行毎のユーザ入力による可変値とする。
 -EC2インスタンスタイプ
 -EC2に接続可能な送信元IPアドレス
 -EC2接続キーペア
 -RDSインスタンス識別子
 -RDSサブネットグループ
 -RDSで利用するDBポート
 -RDSで利用する管理者パスワード

参考サイト

・AWSドキュメント
CloudFormationでのパラメータと、EC2及びRDSリソース作成コードのリファレンスです
CloudFormationユーザガイド①(パラメータ)
CloudFormationユーザガイド②(AWS::EC2::Instance)
CloudFormationユーザガイド③(AWS::RDS::DBInstance)

・Qiita記事
初学者のためのAWS入門(2) CloudFormation入門-1

作業の流れ

項番 タイトル
1 テンプレートの作成
2 テンプレート実行
3 簡単な動作確認

手順

1.テンプレートの作成

テンプレートファイルの作成を行います。
本記事ではjsonファイルを利用しています。

<デフォルトのサブネットグループ名><VPC ID><AZ名><サブネットID>の部分は環境に応じて詰め替えを行ってください。

EC2_RDS_Create.json
{
  "AWSTemplateFormatVersion" : "2010-09-09",
  "Description" : "Simple Setup for EC2 and RDS. ",

  "Parameters" : {
    "EC2InstanceType" : {
      "Type" : "String",
      "Default" : "t2.micro",
      "AllowedValues" : ["t2.micro", "m1.small", "m1.large"],
      "Description" : "Enter EC2 InstanceType."
    },

    "EC2SSHLocation" : {
      "Type": "String",
      "MinLength": "9",
      "MaxLength": "18",
      "Default": "0.0.0.0/0",
      "AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
      "ConstraintDescription": "must be a valid IP CIDR range of the form x.x.x.x/x.",
      "Description" : " Enter the IP address range that is allowed to connect to EC2"
    },

    "EC2KeyName": {
      "Type": "AWS::EC2::KeyPair::KeyName",
      "ConstraintDescription" : "must be the name of an existing EC2 KeyPair.",
      "Description" : "Enter the name of an existing EC2 KeyPair to enable SSH access to the instance"
    },

    "RDSInstanceIdentifier" : {
      "Type" : "String",
      "Default" : "database-1",
      "Description" : "Enter RDS InstanceIdentifier to identify RDS."
    }, 

    "RDSSubnetGroupName": {
      "Type": "String",
      "Default": "<デフォルトのサブネットグループ名>",
      "Description" : "Enter the subnet group where you want to place the RDS."
    },

    "RDSInstanceType" : {
      "Type" : "String",
      "Default" : "db.t2.small",
      "AllowedValues" : ["db.t2.small", "db.t2.medium", "db.t3.small", "db.t3.medium"],
      "Description" : "Enter RDS InstanceType"
    },

    "RDSDBPort" : {
      "Default" : "3306",
      "Type" : "Number",
      "MinValue" : "1150",
      "MaxValue" : "65535",
      "Description" : "Enter TCP/IP port used to connect DB in RDS."
    },

    "RDSDBPwd" : {
      "NoEcho" : "true",
      "Type" : "String",
      "MinLength" : "1",
      "MaxLength" : "41",
      "AllowedPattern" : "^[a-zA-Z0-9]*$",
      "Description" : "Enter the database admin account password in RDS"
    }
  },

  "Resources" : {
    "EC2SecurityGroup" : {
      "Type" : "AWS::EC2::SecurityGroup",
      "Properties" : {
        "VpcId" : "<VPC ID>",
        "GroupDescription" : "Enable SSH access via port 22",
        "SecurityGroupIngress" : [
          {"IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : { "Ref" : "EC2SSHLocation"}}
         ]
      }
    },

    "RDSSecurityGroup" : {
      "Type" : "AWS::EC2::SecurityGroup",
      "Properties" : {
        "GroupDescription" : "SecurityGroup rds-grp",
        "VpcId" : "<VPC ID>",
        "SecurityGroupIngress" : [
          { "IpProtocol" : "tcp",
            "FromPort" : { "Ref" : "RDSDBPort" },
            "ToPort" : { "Ref" : "RDSDBPort" },
            "SourceSecurityGroupId" : { "Ref" : "EC2SecurityGroup" } }
        ]
      }
    },

    "RDSInstance": {
      "Type": "AWS::RDS::DBInstance",
      "Properties": {
          "Engine": "mysql",
          "DBInstanceClass": { "Ref" : "RDSInstanceType" },
          "AllocatedStorage": "20",
          "StorageType": "gp2",
          "DBInstanceIdentifier": { "Ref" : "RDSInstanceIdentifier" },
          "MasterUsername": "admin",
          "MasterUserPassword": {"Ref": "RDSDBPwd"},
          "DBSubnetGroupName": { "Ref": "RDSSubnetGroupName" },
          "PubliclyAccessible": false,
          "AvailabilityZone": "<AZ名>",
          "VPCSecurityGroups": [
              {
                  "Ref": "RDSSecurityGroup"
              }
          ],
          "CopyTagsToSnapshot": true,
          "BackupRetentionPeriod": 7,
          "Tags" : [ { "Key" : "Application", "Value" : "string" } ]
      },
      "DeletionPolicy": "Snapshot"
    },

    "EC2Instance" : {
      "Type" : "AWS::EC2::Instance",
      "Properties" : {
        "ImageId" : "<AMI ID>",
        "SubnetId" : "<サブネットID>",
        "InstanceType" : { "Ref" : "EC2InstanceType" },
        "KeyName" : { "Ref" : "EC2KeyName" },
        "SecurityGroupIds": [{"Ref": "EC2SecurityGroup"}],
        "Tags" : [ { "Key" : "Application", "Value" : "string" } ]
         }
      }
   }
}

テンプレートの書式内容説明です。

{
  # テンプレートのバージョンと説明文
  "AWSTemplateFormatVersion" : "2010-09-09",
  "Description" : "Simple Setup for EC2 and RDS.",

  "Parameters" : {
      # テンプレート実行時にユーザ入力を求めるパラメータ定義
      # パラメータ名は自由だが、パラメータの属性名(Type、Default等)は書式に沿う必要がある。
      # これを利用することでDBユーザ名やパスワードをテンプレート実行毎の可変値とすることが可能
  },

  "Resources" : {
      # 必須定義。テンプレートによって実際に構築されるAWSリソース群(スタック)を記載する。
      # リソース名は自由だが、リソースの属性名(Type、Propertiesの中身等)は書式に沿う必要がある。
      #  { "Ref" : <パラメータ名やリソース名> }を利用することで、テンプレート内で事前に定義したパラメータやリソース内容を値として利用することが可能
      # 上から順に構築が実施され、途中テンプレートの実行に失敗した場合、途中まで作成済みのAWSリソースもロールバックされ全て削除される。

      # ※なお、RDSSecurityGroupリソース内プロパティである「"SourceSecurityGroupId" : { "Ref" : "EC2SecurityGroup" }」という定義を利用して、
      #   本テンプレートで作成したEC2セキュリティグループがアタッチされたEC2インスタンスのみRDSへの通信を許可するよう設定している。
  }
}

2.テンプレート実行

CloudFormationコンソールからスタックの作成を開始
tempsnip.png

②作成したテンプレートファイルをアップロード
tempsnip.png

③スタック名と各種パラメータを入力
任意のスタック名とパラメータ(テンプレート内でParametersによって定義された項目)値を入力していきます。
tempsnip.png

④スタックオプションの設定
作成するリソースに共通のタグだけ付与し、その他はデフォルト値とします。入力が終わったら次へ。
tempsnip.png

次画面でスタック作成開始を実行
tempsnip.png

⑤スタック作成状態確認
スタックが作成されるまでしばらく待機し、状態がCREATE_COMPLETEになるまで待ちます。
tempsnip.png

⑥スタック内リソース確認
EC2コンソール及び、RDSコンソールから正常にAWSリソースが作成されていることを確認します。
image.png
image.png

3.簡単な動作確認

作成したスタック内EC2インスタンスにOSログインし、MySQLクライアントをインストールします。

sudo yum install mysql

その後、スタック内RDSインスタンスへのログインを検証しログイン出来ればOKです。

# RDSエンドポイントは作成したスタック内のRDSエンドポイントに詰め替える
mysql -h <RDSエンドポイント> -P 3306 -u admin -p

# 以下、正常出力例
[ec2-user@ip-172-31-34-74 ~]$ mysql -h database-4.cgfjapta11py.ap-northeast-1.rds.amazonaws.com -P 3306 -u admin -p
Enter password:
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 11
Server version: 8.0.20 Source distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [(none)]>

※念のため、他インスタンスからのRDSインスタンス接続が拒否されることも確認しました。

# スタック内EC2インスタンス以外からの接続は拒否される
[ec2-user@ip-172-31-40-97 ~]$ mysql -h database-4.cgfjapta11py.ap-northeast-1                                                                                .rds.amazonaws.com -P 3306 -u admin -p
Enter password:

ERROR 2003 (HY000): Can't connect to MySQL server on 'database-4.cgfjapta11py.ap-northeast-1.rds.amazonaws.com' (110)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS EC2(Amazon Linux 2 × nginx) に SSL を設定する

やりたいこと

ドメイン設定した、EC2にSSLを設定したい
Let's Encrypt で行います

前提

前回→(ドメインを設定してhttpアクセスはできる状態)
AWS Route53 親ドメインを移行しないでEC2にサブドメイン設定
前々回
Laravel 環境構築 AWS EC2(nginx + PHP) + RDS

インスタンスが以下の TCP ポートで接続を受け付けるようにセキュリティグループを設定済み。
HTTPS (ポート 443)

インストールの準備

EPEL 7 パッケージをダウンロードします。
これは、Certbot(Let's Encryptを自動的に使用してHTTPSを有効にするツール) が必要とする依存関係を提供するために必要です。

  • ホームディレクトリに移動
cd ~
  • EPEL をダウンロード
sudo wget -r --no-parent -A 'epel-release-*.rpm' http://dl.fedoraproject.org/pub/epel/7/x86_64/Packages/e/
  • EPEL インストール
sudo rpm -Uvh dl.fedoraproject.org/pub/epel/7/x86_64/Packages/e/epel-release-*.rpm
  • EPEL を有効化
sudo yum-config-manager --enable epel*
  • EPEL 有効化確認
sudo yum repolist all

# 出力 
...
epel/x86_64                          Extra Packages for Enterprise Linux 7 - x86_64                               enabled: 12949+175
epel-debuginfo/x86_64                Extra Packages for Enterprise Linux 7 - x86_64 - Debug                       enabled:      2890
epel-source/x86_64                   Extra Packages for Enterprise Linux 7 - x86_64 - Source                      enabled:         0
epel-testing/x86_64                  Extra Packages for Enterprise Linux 7 - Testing - x86_64                     enabled:    778+12
epel-testing-debuginfo/x86_64        Extra Packages for Enterprise Linux 7 - Testing - x86_64 - Debug             enabled:       107
epel-testing-source/x86_64           Extra Packages for Enterprise Linux 7 - Testing - x86_64 - Source            enabled:         0
...

Certbot のインストールと実行

Certbot(Let's Encryptを自動的に使用してHTTPSを有効にするツール) のインストール

sudo yum install certbot-nginx

Certbotの実行

sudo certbot --nginx

質問に選択で答えていく

1つ目
メアドの入力
セキュリティになんか問題あったときとか通知いく

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Enter email address (used for urgent renewal and security notices)
 (Enter 'c' to cancel): メアド

2つ目
利用規約同意するか聞かれるので
a入力

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server at
https://acme-v02.api.letsencrypt.org/directory
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(A)gree/(C)ancel: a

メアドの共有をしてよいかの確認

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: N

どのドメインをhttpsするかの選択
nginxのconfにserver_name指定してるので、自動でやってくれます

Which names would you like to activate HTTPS for?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: yourdomain.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel): 1

Obtaining a new certificate
Performing the following challenges:
http-01 challenge for twitter-admin.collapse-natsu.com
Waiting for verification...
Cleaning up challenges
Deploying Certificate to VirtualHost /etc/nginx/nginx.conf
Redirecting all traffic on port 80 to ssl in /etc/nginx/nginx.conf

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations! You have successfully enabled
https://yourdomain.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

httpsでサイトにアクセスしてできたらok

自動更新設定

cronに書き込み

sudo crontab -e

以下を追記

39      1,13    *       *       *       root    certbot renew --no-self-upgrade

毎日、01:39 と 13:39 にコマンドが実行されるようにスケジュールします。ここで選択した値は任意ですが、Certbot 開発者は、コマンドを少なくとも毎日 2 回実行することを推奨しています。これにより、侵害されていることがわかった証明書は必ずすぐに取り消されて置き換えられます。

再起動して反映

sudo systemctl restart crond
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS CLIを使ってECRに自前Dockerイメージを登録する

やりたいこと

ローカルで作成したDockerイメージをAWS CLIを使ってECRにプッシュする

前提

・AWS CLI バージョン2
・Dockerイメージ作成済

登録手順

ここに記載したのはイメージを Amazon Elastic Container Registry にプッシュするを自分なりにまとめなおしたものです。コマンド通らないってことがあったので、そこらへんも書いてます。

前準備

  • aws configure
    aws cliを利用するときにconfigureを実施しておく必要があります。すでに設定済の場合はスキップしてOKです。
    これはAWS CLIをセットアップする方法で、下記4つの情報の入力を求められます。

    • アクセスキーID
    • シークレットアクセスキー
    • AWSリージョン
    • 出力形式

configureするときは下記のように--profileを指定しておくことをお勧めします。
ここでは、prf-nameという名前にしました。

aws configure --profile prf-name

これを設定しておくとawsコマンドを使用するときに下記のような感じで--profileで作成した設定情報を指定してやれば、自分がどこにアクセスしたいのか簡単にコマンドに教えることができるわけです。

aws s3 ls --profile prf-name

--profileの指定がないと下記のように認証情報を特定することができないのでまずはaws configureしてね、と注意されます

Unable to locate credentials. You can configure credentials by running "aws configure"

作成したprofileのリストを確認したい場合は下記を実行します。設定した名前を忘れてしまったときに便利です。

aws configure list-profiles

Amazon ECRリポジトリを作成する

aws ecr create-repository --repository-name your-repository-name --region region --profile prf-name

your-repository-name: 好きなリポジトリ名
region: リージョン(例:ap-northeast-1)

公式サイトには記載がないですが、--profileを記載していないと、さきほどの認証エラーメッセージが表示されてしまいます。

イメージにタグをつけ、Amazon ECRにプッシュする

1. Amazon ECRリポジトリを作成する

aws ecr create-repository --repository-name hello-repository --region region

hello-repository: リポジトリ名
region: リージョン(例:ap-northeast-1)
出力:

{
    "repository": {
        "registryId": "aws_account_id",
        "repositoryName": "hello-repository",
        "repositoryArn": "arn:aws:ecr:region:aws_account_id:repository/hello-repository",
        "createdAt": 1505337806.0,
        "repositoryUri": "aws_account_id.dkr.ecr.region.amazonaws.com/hello-repository"
    }
}

2.前のステップの repositoryUri の値で hello-world イメージにタグを付けます。

docker tag hello-world aws_account_id.dkr.ecr.region.amazonaws.com/hello-repository

3.aws ecr get-login-password コマンドを実行します

aws ecr get-login-password --profile prf-name | docker login --username AWS --password-stdin aws_account_id.dkr.ecr.region.amazonaws.com

出力:

Login Succeeded

4.前のステップの値 repositoryUri を使用して、Amazon ECR にイメージをプッシュします。

docker push aws_account_id.dkr.ecr.region.amazonaws.com/hello-repository

5.プッシュしたイメージの確認
list-imagesを使って、プッシュしたイメージを確認

aws ecr list-images --repository-name hello-repository --region region --profile prf-name
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS-Athena エラーメッセージ「no viable alternative at input 'create external'」の原因・対処法

この記事の内容

AthenaでCreate Tableした時に「no viable alternative at input 'create external'」エラーメッセージが出たので原因と対処法をご紹介します。

エラー背景

S3にcsvのデータを設置して、Athenaで以下のCreate Tableクエリを実行しました。

CREATE EXTERNAL TABLE test_table (
 col1, 
 col2
) 
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde' 
LOCATION 's3://test-bucket/';

すると、エラーメッセージ(構文エラー)が出ました。

no viable alternative at input 'create external'

原因

Amazon Athena ユーザーガイドを見てみると、
・テーブル名、カラム名にアンダースコア(_)以外の特殊文字を使用している。
・カンマ(,)が抜けている。
などがエラー原因として考えられるようです。

今回の場合は、カラムの文字形式を指定しないのが原因でした。
カラム名の後ろに「string」を追加して、クエリを修正して実行してみると成功しました。

CREATE EXTERNAL TABLE test_table (
 col1 string, 
 col2 string
) 
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde' 
LOCATION 's3://test-bucket/';

最後に

細かいとこですが、AthenaのCreate-Tableの形式を守らないとエラーになりますね。

参考文献

Amazon Athena ユーザーガイド

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS-Athena エラーメッセージ「no viable alternative at input 'create external'」の原因・対処法

この記事の内容

AthenaでCreate Tableした時に「no viable alternative at input 'create external'」エラーメッセージが出たので原因と対処法をご紹介します。

エラー背景

S3にcsvのデータを設置して、Athenaで以下のCreate Tableクエリを実行しました。

CREATE EXTERNAL TABLE test_table (
 col1, 
 col2
) 
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde' 
LOCATION 's3://test-bucket/';

すると、エラーメッセージが出ました。

no viable alternative at input 'create external'

原因

どうやらカラムの文字形式を指定しないとエラーになるようです。
クエリを修正して実行してみると成功しました。

CREATE EXTERNAL TABLE test_table (
 col1 string, 
 col2 string
) 
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde' 
LOCATION 's3://test-bucket/';

最後に

細かいとこですが、AthenaのCreate-Tableの形式を守らないとエラーになりますね。

参考文献

Amazon Athena ユーザーガイド

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

amplifyのIAMユーザに適切なポリシーを設定したい

amplify configureを実行するとIAMユーザが作られます。

Specify the username of the new IAM user:
? user name:  amplify-AAAAA

amplifyチュートリアル的な記事などでは、このIAMユーザに管理者権限を振っていることが多い気がします。でも、なんかちょっと気持ち悪いですよね。適当に権限を制限しておきたいと思って調べたところ、以下を見つけました。

ADVANCED WORKFLOWS IAM Policy
https://docs.amplify.aws/cli/usage/iam

The Amplify CLI requires the below IAM policies for performing actions across all categories. You can grant or restrict category permissions by including or removing items from the Action section as appropriate. For example, if you wish to restrict operations on the Auth category you can remove any of the lines starting with cognito.

このページに書かれているJSONで権限を制限してみたところ、amplify pushで以下のエラーが発生。

Following resources failed

Resource Name: GraphQLAPI (AWS::AppSync::GraphQLApi)
Event Type: create
Reason: User: arn:aws:iam::xxx:user/amplify-AAAAA is not authorized to perform: appsync:TagResource on resource: arn:aws:appsync:ap-northeast-1:xxx:* (Service: AWSAppSync; Status Code: 403; Error Code: AccessDeniedException; Request ID: xxx; Proxy: null)

確かにJSONにはappsync:TagResourceが記載されていなかったので追加したところ、無事にpushも成功しました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む