自己紹介

初めまして。入社4年目のエンジニアの荒井です。
大学から情報系の学部に入り、卒業時には学習工学分野の研究をしていました。
新卒で入社した会社では業務ツール系のWindowsデスクトップアプリケーション(WPF/.NET/C#)を開発していました。

普段はPMOおよび、アーキテクチャ設計から実装まで開発領域を幅広めに担当しています。
言語としてはPython >>> PHP, Vue.js > その他くらいの割合でコードと触れ合っており、本記事のテーマであるServerlessFramework歴は丸3年くらいです。
個人的なトピックとしてはガジェット系・車・クマなどが好きです。
よろしくお願いします。

はじめに

ServerlessFramework (公式: https://www.serverless.com/) を実務で使う中で「あれってできないのかな?」と思うと7割くらいは出来てしまう地味だけど便利なところを広めたい、という気持ちで記事を書きました。
ちなみに全く裏技的ではないのですが、裏技的ではなくこれができるのが良いなと思っています。
今回はserverless.ymlでの定義方法と使用例をご紹介します。

Tips3選

プロジェクト内のデフォルトtimeoutを作る

ServerlessFrameworkを使ってデプロイされたLambdaのデフォルトタイムアウト時間は6秒※と短めなので、カスタムのタイムアウト時間をセットすることはよくあると思います。
※2023年3月時点 (出典: https://www.serverless.com/framework/docs/providers/aws/guide/functions)
今回紹介するのは以下のような構成の時に全部のfunctionにtimeout設定を書くのをやめられる方法です。

  • functionsの8割がAPIで、API Gatewayに合わせたタイムアウト時間で一律60秒とする
  • 残り2割がバッチで、個別に考慮したタイムアウト時間とする

functionsでセットするとproviderでセットするtimeout値よりも強力なものとして反映されることを利用します。
まるでデフォルトのように扱えて、定義漏れの可能性&定義量が削減できてちょっと便利ではないでしょうか。
実際に書いてみるとこのようになります。

provider:
  timeout: 60

functions:
  hoge:
    handler: handler.hoge
  hello:
    handler: handler.hello
    timeout: 900

上の例ではhogeは60秒、helloは900秒のタイムアウトがセットされます。

ServerlessIfElseプラグイン

ある環境にはデプロイしないけど、ある環境にはデプロイしたい機能があることってありますよね。

  • 環境毎に複数のserverless.ymlを使い分けているが、更新を全環境分のymlに反映し忘れないか不安
  • 環境に合わせて都度serverless.ymlをコメントアウトしてデプロイしているが、うっかりミスをしないか不安

このようなヒヤヒヤを抱えているプロジェクトはないでしょうか。
このプラグインを使えば、名前の通り条件で定義を書き換えて1つのymlファイルを使うことが可能です。
実際に使う場合はこのようになります。

plugins:
  - serverless-plugin-ifelse

custom:
  serverlessIfElse:
  - If: '"${self:provider.stage}" == "prd"'
    Exclude:
      - functions.hogeBatchForDebug

functions:
  hogeBatchForDebug:
    handler: handler.hoge_batch_for_debug

これで、デバッグ用のhogeバッチはstageがprd(本番環境)の場合にはfunctionsに含まれなくなります。
例は単純にfunctionsを除外する定義ですが、その他にも様々な設定をIf-Else条件で変更できます。

詳しくは公式リファレンスを参照ください。
https://www.serverless.com/plugins/serverless-plugin-ifelse

VPCのSubnetIdをまとめて管理する

functionsをVPC内に入れる際に使う項目です。
サブネットIDは環境毎に書き換えたいことが多いと思うので、ここではenvを参照する前提とします。
以下の例のように紐付けたいサブネットが多く、サブネットIDの変数が増殖してしまうことってないでしょうか。

↓serverless.yml(before)

custom:
  vpc:
    subnetIds:
        - ${self:provider.environment.SUBNET_ID_A}
        - ${self:provider.environment.SUBNET_ID_B}
        - ${self:provider.environment.SUBNET_ID_C}

↓環境変数(before)

SUBNET_ID_A: "subnet-1234567"
SUBNET_ID_B: "subnet-abcdefg"
SUBNET_ID_C: ...

そんな時に、こんな書き方をすると環境変数1つでまとめて管理することができます。

↓serverless.yml(after)

custom:
  vpc:
    subnetIds:
      "Fn::Split":
        - ", "
        - ${self:provider.environment.SUBNET_IDS}

↓環境変数(after)

SUBNET_IDS: "subnet-1234567, subnet-abcdefg"

視覚的にも、管理的にもスッキリした感じがしませんか?
お気付きの方もいそうですが、Fn::SplitはCloudFormationの記法で、実はserverless定義でも使えます。
紐付けたいサブネットIDが増えた場合もSUBNET_IDSにカンマ区切りで追加するだけでOKです。
環境変数の数を増やしたくない時にこの書き方ができることを思い出すと便利かもしれません。

おわりに

ServerlessFrameworkがなんだか便利で可愛い子に見えてきましたでしょうか。
個人的には人間が理解しやすい方法でリソースが管理できる良いツールだなと思っています。
(思いがけずハマると抜けにくいという少し怖い面もありますが...)
今後も使っていく中でいいなと思った機能・書き方があったらまた紹介します。