あきろぐ

いろいろめもするよ🐈🐈🐈

aws-vaultコマンドのエラー対応

こんにちは。 久しぶりにブログ書きます。

aws-vaultコマンド便利ですよね。 色々触っていたらエラー吐くようになったので調査したときのログです。

今回のエラー

雑な意訳:ネストに気をつけてね。$AWS_VAULTを強制的にアンセットして。 なにこれ?

aws-vault: error: aws-vault sessions should be nested with care, unset $AWS_VAULT to force

エラーに従って、アンセットしましたが、解決できず。

$ unset $AWS_VAULT
bash: unset: `xxx': not a valid identifier

有効な識別子じゃないといわれておる。

Issueを見ましたが、特に情報なかった。

github.com

解決策

ソースコードを見ました。 上記のエラーが出るのは環境変数AWS_VAULTに何かしら値が入っているときです。

# exec.goを一部抜粋
    if os.Getenv("AWS_VAULT") != "" {
        return fmt.Errorf("aws-vault sessions should be nested with care, unset $AWS_VAULT to force")
    }

github.com

つまり、AWS-VAULTの値をクリアしてあげればよさそうですね。

$ AWS_VAULT=""
$ echo $AWS_VAULT

これでエラーは解決しました。おわり。

ALBのヘルスチェックに失敗するときに確認すること

概要

ALBのヘルスチェックにハマったので、そのときに見直すところのメモ。

構成

  • ALB
  • ECS
    • Nignxコンテナ
    • Railsコンテナ

確認

ヘルスチェックのエンドポイントが間違っていないか

ALBのターゲットグループに設定するヘルスチェックのエンドポイントが間違っていないか確認する。単純にtypoなのか、ヘルスチェック用のエンドポイントを用意していないのか見直す。 自分がヘルスチェック用エンドポイントを作成している場合は気がつきやすいが、そうでない場合は開発者に確認しておく。/healthだと思っていたが実は/readme.txtだったなど。。。 ヘルスチェックのエンドポイントが間違っていないことが分かったら、curlコマンドでhttpレスポンスコードがちゃんと200を返しているか確認してみる。

# Railsコンテナ内で実行
$ curl localhost:3000/healthcheck -H 'Host:<your domain name>' -I

Railsコンテナからのレスポンスが問題なければ、Nginxコンテナ経由でエンドポイントにリクエスト送ってちゃんと正常なレスポンスを返すか確認する。ここで上手くいかないとNginxの設定がミスっている可能性があるので、設定ファイルを見直す。 Nginxコンテナの中にALBのヘルスチェック結果のログが吐かれているのでそれも確認しておく。(ヘルスチェックログ:/var/log/access.log

# Nginxコンテナ内で実行
$ curl localhost:80/healthcheck -H 'Host:<your domain name>' -I

続いてコンテナが乗っているEC2インスタンスからヘルスチェックのエンドポイントにリクエストを送ってみる。リクエストを送るポートはdocker psコマンドで確認する。

# EC2インスタンス内で実行
$ curl localhost:xxxx/healthcheck -H 'Host:<your domain name>' -I

ECSクラスタのセキュリィグループが間違っていないか

gateway timeout 504がヘルスチェックで返ってくる場合は、ECSコンテナのセキュリティグループにてALBに設定しているセキュリィグループを許可していない可能性がある。ここでALBからのリクエストが許可されていないとそもそもEC2インスタンスにリクエストが届かないので504エラーが返ってくる。

ヘルスチェックのタイムアウト時間が短すぎないか

コンテナが立ち上がるまでの処理に時間がかかっていると、コンテナが立ち上がる前にヘルスチェックが失敗と見なされてしまうので起動時に重い処理をentrypoint.shで実行している場合は、ALBのタイムアウト時間を長めにとっておく。

おしまい

aws firelensを使ってみる

Firelensとは

去年ECSのログ出力先をカスタマイズできる「Firelens」機能がリリースされました。 それまでは、ECSコンテナのログはCloudwatchLogsか自前でFluendコンテナを立ててログ取集する仕組みを作るみたいなやり方だったと思います。 CloudwatchLogsはログが見づらくてつらすぎるし、Fluentdコンテナ立てて自前でログ収集基盤を構築しメンテナンスするのもしんどい。ここら辺マネージドサービスでいい感じにしてくれる機能がFirelensです。

dev.classmethod.jp

どうやって使うかざっくり説明すると、1タスク定義の中にFirelens用コンテナを立ててアプリケーションコンテナのログ出力先をFirelensにするだけ。やってみたらサクッと設定できてしまいました。FluentBitのイメージはAWS側が提供しているのでそれを指定してあげればOK。

構成

構成は以下の通りで、Firelensコンテナをサイドカー構成にしています。 Kinesis Data Firehoseを経由してS3バケットにログをzip形式で出力するようにしました。

f:id:akngo22:20200426195221p:plain

Kinesis Data Firehoseは初めて使ったのですが、設定は本当に簡単。 ストリーミングデータをデータレイクや分析ツールに送ってくれる中継サービスなので、受けたストリーミングデータをどこにどんな形式でどれくらいの間隔で送ればいいか指定するだけでS3バケットによしなに格納してくれます。

タスク定義

タスクはいつものようにアプリケーションコンテナの設定を行い、ログ設定のところだけいじります。

    "logConfiguration": {
      "logDriver": "awsfirelens",
      "options": {
        "Name": "firehose",  <--- ルーティング先を"firehose"にする
        "region": "ap-northeast-1",
        "delivery_stream": "test" <--- ストリーム名
      }

そしてLog用コンテナを立ててマネージドイメージを指定し自身のコンテナログはCloudwatchLogsに出力されるようにします。

  {
    "name": "log_router",
    "image": "906394416424.dkr.ecr.ap-northeast-1.amazonaws.com/aws-for-fluent-bit:latest",
    "logConfiguration": {
      "logDriver": "awslogs",
      "options": {
        "awslogs-group": "firelens_test",
        "awslogs-region": "ap-northeast-1",
        "awslogs-stream-prefix": "aws-for-fluent-bit"
      }
    },
    "firelensConfiguration": {
      "type": "fluentbit"
    }
  }

タスク立ち上げてS3バケットに出力されているか確認。問題なさそう。 f:id:akngo22:20200426202805p:plain

気をつけること

タスクロールにログをKinesis Data Firehoseにルーティングするための権限を忘れずに付与してあげます。

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

Kinesis Data firehoseのロールには対象S3バケットの権限を付与します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": "[YOUR-S3-ARN]"
        }
    ]
}

参考文献

SansanさんのBuilders Book1を参考にさせていただきました わかりやすくてよかったです。

techbookfest.org

ECSコンテナインスタンスにSSMセッションマネージャを使えるようにする

概要

今までECSのコンテナインスタンスの中に入ってDockerコンテナのデバッグするためには、踏み台サーバー経由して対象のインスタンスsshする必要がありましたが、ECSエージェントのアップデートによりsshなし踏み台なしでコンテナインスタンスの中に入ることができるようになりました。

SSMセッションマネージャを使えば、わざわざセキュリティグループで22ポート開けなくていいし、踏み台サーバーも用意しなくていいし管理の手間が省けるのでとても素晴らしいアップデートです🙏🏻 やり方はクラスメソッドさんの記事に書かれているので、実際にやってみてつまずいたポイントがあるのでそれをまとめておきます。

aws.amazon.com

dev.classmethod.jp

何をしようとしたか

  • ECSエージェントのバージョンを1.36.2以上にあげる
  • SSMセッションマネージャを使うためのポリシーをコンテナインスタンスにアタッチする

何がうまくいかなかったか

コンテナインスタンスのAMIイメージがSSMセッションマネージャに対応していなかった

そもそも論なんですけど、今回のアップデートはAmazon ECS Optimized Linux 2」に対してなので、「Amazon ECS Optimized Linux 」は対応してないんですね。。。 自分のコンテナインスタンスAmazon Linux2だと思い込んでたので、気づくのが遅かったです。 コンテナインスタンスのOS情報は/etc/system-releaseの中に書かれています。

# /etc/system-release
Amazon Linux release 2 (Karoo)

事前に確認しておきましょう。

必要なポリシーを勘違いしていた

早とちりしていたのですが、必要なポリシーは以下のものを追加すれば良いと思っていました。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ssm:UpdateInstanceInformation",
                "ssmmessages:CreateControlChannel",
                "ssmmessages:CreateDataChannel",
                "ssmmessages:OpenControlChannel",
                "ssmmessages:OpenDataChannel"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetEncryptionConfiguration"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "kms:Decrypt"
            ],
            "Resource": "key-name"
        }
    ]
}

実際にはこれだけでは不十分でセッションマネージャーは使うことができません。下記のドキュメントにもこのように書かれています。

インスタンスのアクセス許可に対して AWS 提供のデフォルトポリシー [AmazonSSMManagedInstanceCore] に依存しない既存の IAM インスタンスプロファイルに Session Manager のアクセス許可を埋め込むには、以下の手順に従います。この手順では、アクセスを許可するアクションに対する他の Systems Manager の ssm アクセス権限が既存のプロファイルにすでに含まれていることを前提としています。このポリシーだけでは、Session Manager を使用するには十分ではありません。

この手順では、アクセスを許可するアクションに対する他の Systems Manager の ssm アクセス権限が既存のプロファイルにすでに含まれていることを前提としています。このポリシーだけでは、Session Manager を使用するには十分ではありません。

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/getting-started-add-permissions-to-existing-profile.html

このポリシーだけでは、SSMセッションマネージャを使うには不十分なのです。SSMアクセス権限がすでにコンテナインスタンスのロールにアタッチされている前提なのです。コンテナインスタンスのロールにSSMアクセス権限がついていないのであればAmazonSSMManagedInstanceCoreポリシーをアタッチする必要があります。(AmazonEC2RoleforSSMポリシーは権限が強すぎるので)

追記

最小権限を求めて、いろいろと検証したら最低限以下のアクションがあればセッションマネージャを使うことができました!

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ssmmessages:CreateControlChannel",
                "ssmmessages:CreateDataChannel",
                "ssmmessages:OpenControlChannel",
                "ssmmessages:OpenDataChannel",
                "ssm:UpdateInstanceInformation"
            ],
            "Resource": "*"
        }
    ]
}

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/setup-instance-profile.html

この2点を解消することで無事セッションマネージャをコンテナインスタンス対して使うことができました。 おわり