kasei_sanのブログ

かせいさんのIT系のおぼえがきです。胡乱の方はnoteとtwitterへ

AWS Fargate のコスト削減アイデアいろいろ

AWS Fargate。便利だけど、EC2と比べるとコストも高いので、コスト削減の方法をいろいろまとめてみた

  • 上から順に効果が高くて、適用コストも低いので、上から実施を検討すると良いです

Compute Savings Plans

  • EC2やFargateやlambdaの利用について、1時間いくらで、1年 or 3年分契約することで割引が発生するプラン。前払いにすると更に割引
  • 前払いならば、東京リージョンのfargeteで、 1年なら22%OFF、3年なら47%OFF
  • インスタンスタイプなどに縛りはないので、一定額 EC2やFargateやlambda を使用するならば、入ったほうが得なことが多いハズ

構成変更も不要なので、まずはここから始めると良い

参考

dev.classmethod.jp

Fargate Spot

  • 不意に中断することがある代わりに、70%OFF で Fargate が利用できるサービス
    • Compute Savings Plans との併用はできない
    • ほとんど中断することはない様子

  • Capacity provider strategy で、task の起動時のFargate Spotの割合を設定可能

つかいどころ

  • 停止しても大きな問題が無い、QAやstaging環境
    • 自分の会社では、Spot にして、さらに土日深夜早朝停止することで、かなりの低コストでQA環境を運用できた

techblog.lclco.com

構成変更のコストも低く、停止することも今の所ほぼ無いので、stage環境があるならば、まずはSpotの利用をオススメ

あとは、失敗しても再実行すれば良いバッチ処理とか、Capacity provider strategyを使って本番の一部とか

参考

blog.kasei-san.com

メモリ、CPU、task数の調整

メトリクスを取っていることが前提

  • ピークタイムでもメモリ、CPUに余剰があるならば、task数の削減を検討
  • 最低維持task数 = AZの数 でもまだ余裕があるならば、メモリ、CPUの削減を検討
    • ただし、1個のAZが落ちても、余裕があるようにしておくこと
    • 2AZならば、maxでも50%にしておく
  • ピークタイムとそれ以外でメモリ、CPUの使用量に大きな差があるのであれば、オートスケーリングを検討

半年に1回くらい状況を見て、メモリ、CPU、task数を調整するとハッピーかもしれない

リクエスト数をへらす

キャッシュが最適化されていないのであれば要検討

必要なCPUやtask数が削減されるはず

まとめ

もし、Fargate Spot化や メモリ、CPU、task数の調整がすぐできるのならば、Compute Savings Plansの適用はその後にした方が良いかも

bash にて、とあるドメインが存在するなら、環境変数にそのドメインを格納する、なければデフォルト値という処理を書いたときのメモ

コード

API_URL=https://example.com
BRANCH_API_URL=https://hoge.com
host ${BRANCH_API_URL#https://} && API_URL=${BRANCH_API_URL} || :

ポイント

  • ${BRANCH_API_URL#https://} で、環境変数 BRANCH_API_URLの先頭の https:// を取り除いている
  • host は引数のドメインが無い場合、異常終了するコマンド
  • : は何もしないコマンド
  • これにより、 以下のような処理が実現できる
    • host が正常終了すれば、 API_URL には、BRANCH_API_URL が格納される
    • host が異常終了すればなにもしない(結果として、API_URL はデフォルトの https://example.com のまま

参考

qiita.com

AWS Codebuild で dig とか host コマンドを使う方法

先に方法

buildspec に以下を追加

phases:
  install:
    commands:
      - yum -y install bind-utils

解説

  • AWS Codebuild で動作させる、Amazon Linux 2 (centOSベース) には、host や dig コマンドがインストールされていない
  • host や dig コマンド は、bind-utils でまとめてインストールされる
  • buildspec にて、ビルド前になにかインストールしたい場合は、 install phase で実行する

Fargate Spot おぼえがき

先にまとめ

  • コンテナが不定期に停止する代わりに 通常価格の70%OFF になるサービス
    • Savings Plansとの併用はできない。らしい (伝聞のためソースなし
  • 雑に始めたければ、Capacity Provider を FARGATE SPOT のみにする
    • Fargete と Fargate Spot を併用したければ、Capacity provider strategy を設定する
  • 停止の120秒前に Amazon EventBridge で通知がくる
    • ただし、2019/12月時点の東京リージョンでは、80H稼働し続けても特に死ぬことはなかったらしい

想定される使いみち

  • 中断しても困らない並列処理や分散処理
  • QA環境などのテストサーバ
  • 本番サーバのバッファ

Fargate Spotの雑なはじめかた

ECS の Capacity Provider を FARGATE SPOT のみにする

f:id:kasei_san:20200311082737p:plain

Capacity Provider って何?

ECSのクラスターの実行環境。Fargete ならば FARGATEFARGATE SPOT がある

  • FARGATE を消してしまえば、 Capacity Provider は FARGATE SPOT のみなので、全ての task が Fargate Spot で実行される
  • 余談。ECS on EC2 ならば、ECS Cluster Auto Scaling も追加可能
    • これは、コンテナの増減に応じて、EC2のスケールイン/アウトを自動にしてくれるサービス
    • これまでは、個別に管理する必要があったので大変だった

Capacity provider strategy

もし、 FARGATEFARGATE SPOT を併用したい場合、Capacity provider strategy という設定で、task実行時の Capacity Provider の配分を決めることができる

コンテナの停止を検知する方法

Amazon EventBridge を使う

Amazon EventBridge とは

AWSとSaaSを統合するために、AWSで発生するイベントを他のAWSサービスやSaaSと紐付けるサービス

Amazon EventBridge は、独自のアプリケーション、統合 Software-as-a-Service (SaaS) アプリケーション、および AWS のサービスからのデータを使用して、アプリケーションを簡単に接続することを可能にするサーバーレスイベントバスです。

aws.amazon.com

Amazon EventBridge と SNS ってどう違うの?

大規模に素早く pub/sub したい場合は SNS。いろいろなサービスと手軽に繋がりたい場合は、EventBridge という感じらしい

lumigo.io

参考

aws.amazon.com

dev.classmethod.jp

dev.classmethod.jp

blog.astj.space

GitHub Actions で Action に失敗した時にslackに通知を投げる方法

先に方法

    - name: Slack Notification when build failed
      if: failure()
      uses: rtCamp/action-slack-notify@master
      env:
        SLACK_CHANNEL: channel-name
        SLACK_COLOR: '#ff0000'
        SLACK_TITLE: ':fire::fire::fire: Build error! :fire::fire::fire:'
        SLACK_MESSAGE: "Build error! Please check github!"
        SLACK_USERNAME: GitHub Actions
        SLACK_WEBHOOK: ${{secrets.SLACK_WEBHOOK}}

実行結果

f:id:kasei_san:20200310184843p:plain

解説

参考

tech.actindi.net

GitHub Actions で削除したブランチ名を取得する方法

課題

GitHub Actionsでは、ブランチ名は環境変数 GITHUB_REF から取ることができるが、ブランチ削除時には GITHUB_REFrefs/heads/master になってしまう

  • なお、GitHub Actions で使用できる環境変数については、こちらを参照

help.github.com

解決方法

${{ github.event.ref }} から取得する

github.event とは

webhook event のペイロードがすべて格納されているところ

ブランチ削除の場合のペイロードはこちらを参照

参考

検証コード

name: delete_branch

on: [delete]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Echo branch name
      run: echo ${GITHUB_REF}
    - name: Echo commit hash
      run: echo ${GITHUB_SHA}
    - name: Echo github.event.ref
      run: echo "${{ github.event.ref }}"

GitHub Actions から AWS lambda を実行してみる

こちらのつづき

blog.kasei-san.com

GitHub Actions から AWS lambda を実行するまでの流れ

  • lambdaを作成
  • lambdaの実行権限を持つIAMユーザを作成
  • AWS認証の action aws-actions/configure-aws-credentials を GitHub Actions に組み込む
  • 認証に使用する、lambdaの実行権限を持つIAMユーザの各キーを secrets に設定
  • 実行

lambdaを作成

"hello" を puts するだけのシンプルな lambda hellous-east-1 に作成

require 'json'

def lambda_handler(event:, context:)
    # TODO implement
    
    puts 'hello'
    
    { statusCode: 200, body: JSON.generate('Hello from Lambda!') }
end

lambdaの実行権限を持つIAMユーザを作成

IAMユーザ github-actions を作成

$ aws iam create-user --user-name github-actions
{
    "User": {
        "Path": "/",
        "UserName": "github-actions",
        "UserId": "********",
        "Arn": "arn:aws:iam::********:user/github-actions",
        "CreateDate": "2020-03-03T05:02:59Z"
    }
}

github-actions に lambda実行権限持つロールを付与

$ aws iam attach-user-policy \
  --user-name github-actions \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaRole

ローカルで動作確認

$ aws lambda invoke --function-name hello --region us-east-1 response.json
{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}

AWS認証の action aws-actions/configure-aws-credentials を GitHub Actions に組み込む

aws-actions/configure-aws-credentials は AWS 公式の github action

Configure AWS credential and region environment variables for use in other GitHub Actions.

github.com

こんなふうに、アクセスキーとシークレットキーとリージョンを設定してやれば、ユーザの権限に応じた、AWS CLI が使えるようになる

name: CI
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Configure AWS Credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: us-east-1
    - name: Run a one-line script
      run: echo Hello, world!
    - name: Run a multi-line script
      run: |
        echo Add other actions to build,
        echo test, and deploy your project.

認証に使用する、各キーを secrets に設定

GitHub Actionsで使用したい秘匿情報は、secrets に設定して、そこから取得する

アクセスキーを取得

$aws iam create-access-key --user-name github-actions


{
    "AccessKey": {
        "UserName": "github-actions",
        "AccessKeyId": "********",
        "Status": "Active",
        "SecretAccessKey": "********",
        "CreateDate": "2020-03-03T05:03:23Z"
    }
}

アクセスキーを github の secrets に設定

secrets に設定することで、GitHub Actions にて ${{ secrets.key_name }} で参照できるようになる

settings -> secrets で設定可能

f:id:kasei_san:20200304175044p:plain

ここに、AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY を設定する

f:id:kasei_san:20200304175206p:plain

実行

lambdaを実行する処理をstepに追加する

name: CI
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Configure AWS Credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: us-east-1
    - name: Run a hello lambda
      run: aws lambda invoke --function-name hello response.json

動作確認

コードをPUSHして、GitHub Actions から lambda が実行されて、正常終了の結果が返ってきたことを確認 👏

f:id:kasei_san:20200304175342p:plain