Serverless Framework の Deprecation warning: * is not accessible エラー対処法


問題

Serverless Framework 2.x 系を使用しており, serverless.yml の記述は以下のようになっています。 ググるとよく出てくるありがちな設定。

provider:
  stage: ${opt:stage, self:custom.default.stage}
  profile: ${opt:profile, self:custom.defaultProfile}

custom:
  defaultStage: production
  defaultProfile: ap-northeast-1

本日 serverless print を実行するとき,このようなエラーを踏みました。

Serverless: Deprecation warning: "provider.profile" is not accessible (configured behind variables which cannot be resolved at this stage).
            Starting with next major release, this will be communicated with a thrown error.
            Set "variablesResolutionMode: 20210326" in your service config, to adapt to this behavior now
            More Info: https://www.serverless.com/framework/docs/deprecations/#NEW_VARIABLES_RESOLVER

また, serlverless print --profile=xxx と指定すると,以下のようなエラーが出るようになりました。

Serverless: Deprecation warning: Detected unrecognized CLI options: "--profile".
            Starting with the next major, Serverless Framework will report them with a thrown error
            More Info: https://www.serverless.com/framework/docs/deprecations/#UNSUPPORTED_CLI_OPTIONS

どうすればよいのでしょうか?

解決策

--profile は非標準オプションです。非標準オプションのみ環境変数で代用します。

provider:
  stage: ${opt:stage, self:custom.default.stage}
  profile: ${env:AWS_PROFILE, self:custom.defaultProfile}

custom:
  defaultStage: production
  defaultProfile: ap-northeast-1

この部分に関しては custom: 自体を剥ぎ取って直接インラインで書いてしまったほうがいいと思います。クォーテーションで括れば Variable Syntax 中でも文字列リテラルを直接書くことができます。

provider:
  stage: ${opt:stage, 'production'}
  profile: ${env:AWS_PROFILE, 'ap-northeast-1'}

解説

エラーメッセージを良く読めば答えが書いてあるのですが,順を追って説明します。観点は2つあります。

変数解決の方法が変わった❓

"provider.profile" is not accessible (configured behind variables which cannot be resolved at this stage)

だけだとちょっと分かりにくいのですが, エラーメッセージを読む限りでは,新しいリゾルバでは provider は他の項目よりも早く解決される仕様になっているようです。ではどこまでなら許されるのでしょうか?

以下のようにしたところ, どちらのパターンもエラー無しに動作しました。

provider:
  stage: ${opt:stage, self:custom.default.stage}
  # 環境変数あり・なし両方 OK
  profile: ${env:AWS_PROFILE}

custom:
  defaultStage: production
  defaultProfile: ap-northeast-1
provider:
  stage: ${opt:stage, self:custom.default.stage}
  profile: ${self:custom.defaultProfile}

custom:
  defaultStage: production
  defaultProfile: ap-northeast-1

${env:*}${self:custom} の参照は全く問題ないようです。というか, ${opt:*} でも ${opt:stage} はちゃんと参照できていますね。では何が問題…?

serverless コマンドが標準オプション以外を受け取らなくなった❗

2つ目のエラーである

Detected unrecognized CLI options: "--profile".

がこの問題の本質です。従来は独自定義したオプションを CLI から受け取ることが出来ていたんですが, バージョン 3.x からは標準定義されたオプション以外は受け取れなくなるようです。

sls print --help の実行結果は以下のようになりました。

print ......................... Print your compiled and resolved config file
    --format ...........................Print configuration in given format ("yaml", "json", "text"). Default: yaml
    --path .............................Optional period-separated path to print a sub-value (eg: "provider.name")
    --transform ........................Optional transform-function to apply to the value ("keys")
    --region / -r ......................Region of the service
    --app ..............................Dashboard app
    --org ..............................Dashboard org
    --use-local-credentials ............Rely on locally resolved AWS credentials instead of loading them from Dashboard provider settings (applies only to services integrated with Dashboard)
    --config / -c ......................Path to serverless config file
    --stage / -s .......................Stage of the service
    --help / -h ........................Show this message
    --version ..........................Show version info

--stage が含まれているので問題なし, --profile は独自定義なのでダメ!そういうことでした。最初の「変数解決の方法が変わった」に関しては,標準定義されているオプションについては正しく参照できたので,結局まだ深くは分かっていないところです。現時点では,非標準オプションを非推奨化した影響で副次的にこのエラーも踏んでいるという形になっていると言えます。

またリンク先を読むと,以下のような記述がありました。

Note: If you've used such options to aid dynamic resolution of service configuration (passing custom values to ${opt:..} resolvers). We suggest to rely on environment variables instead. Setup of environment variables is also way more convenient since we've added support for .env files.

結果的には以下のように,非標準オプションのみ環境変数で代用する形に落ち着きそうですね。

provider:
  stage: ${opt:stage, self:custom.default.stage}
  profile: ${env:AWS_PROFILE, self:custom.defaultProfile}

custom:
  defaultStage: production
  defaultProfile: ap-northeast-1
provider:
  stage: ${opt:stage, 'production'}
  profile: ${env:AWS_PROFILE, 'ap-northeast-1'}