外部サービスとの連携でしくじった話

お疲れ様です。まっちゃんです。

みなさま体調の方は大丈夫でしょうか?
自分は年末から年始に崩してしまいあまり休めませんでした。
社内でもインフルエンザ感染者が出てきましたのでお気をつけください。

それでは最近開発して、アプリケーションとAmazon S3の連携しくじったなーという話を簡単に書きたいと思います。

要件

営業さんがアップロードしたファイルをメールに添付してほしい。

仕様

フロントエンドでAmazon S3へのアップロード処理が完了した後、バックエンドのAPIにファイル名を渡す。
そのファイル名をもとにAmazon S3からダウンロードし、メール添付処理を行う。

f:id:AdwaysEngineerBlog:20190118174840p:plain

実現方法

Amazon S3への通信のため、 application.conf に設定を記述しました。

s3 {
  accessKey = "access"
  secretKey = "secret"
  regionName = "region"
  bucketName = "bucket"
}

コード上にKEYを残すのはあまりよろしくないという指摘もレビュー時に頂いたので環境変数化しました。

s3 {
  accessKey = ${S3_ACCESS_KEY_ID}
  secretKey = ${S3_SECRET_ACCESS_KEY}
  regionName = "region"
  bucketName = "bucket"
}

ローカルで実施するときは環境変数を付与して動作確認をします。

$ S3_ACCESS_KEY_ID=*** S3_SECRET_ACCESS_KEY=*** ./sbt.sh "~web/run"

CI上でのテストは GitLab CI/CD Variablesにアクセスキーを登録し、テストができるようにしました。

...
web_test_job:
  ...
  variables:
    ...
    S3_ACCESS_KEY_ID: $S3_ACCESS_KEY_ID
    S3_SECRET_ACCESS_KEY: $S3_SECRET_ACCESS_KEY
...

テスト環境 | 本番環境では .systemd-environment に記述してsystemdで読み込むようにしました。

...
[Service]
...
EnvironmentFile=/home/user/.systemd-environment
...
S3_ACCESS_KEY_ID=***
S3_SECRET_ACCESS_KEY=***

要件の内容で実現はしたものの......

動作は問題なかったのですが、この実装をしたことで問題がないか、もっと良い方法はないか考えました。
自分や同期だけでは解決できそうになかったのでベテランの先輩方に相談してみることにしました。

相談事項

S3のアクセスキーを環境変数化したい。
application.confの設定は問題ないと思うが、テストで使用するためにはどうすれば良いのでしょうか?
対応方法について問題がないか、もっと良い実装方法があったら教えてください。

私「今はそのままローカルもCIもAmazon S3に対してテストが実行されます。」
ベテランAさん「外部サービスに接続しにいく方式は採用しないほうが良い。リスクが大きい。」
ベテランBさん「s3serverなどのs3に準じたオブジェクトストレージを導入するのを検討すべき、外部サービスから切り出すと開発しやすくなる」

私「今から着手するとスプリント終わらなそうですね......。チケットを切って相談してみます。」

その後出た問題点

若手Cさん「実行しようとするとアクセスキーが毎回求められる」
若手Dさん「アクセスキーで時間取られる」
私「ごめんなさいorz」

READMEには書いたものの、共有不足や並行開発等で周りの時間がプラスで取られてしまう結果になりました。

対応

まだ対応はできていません......
暫定対応として

  • 引数が必須じゃなくても良さそうな箇所がありそうだからリファクタリングしてみる
// Controller
...
- "s3_file_name" -> text
+ "s3_file_name" -> optional(text)
...
...
- def hoge(s3FileName: String = "") {}
+ def hoge(s3FileName: Option[String] = None) {}
...
  • 環境変数無しでも立ち上げても良さそう
- accessKey = ${S3_ACCESS_KEY_ID}
- secretKey = ${S3_SECRET_ACCESS_KEY}
+ accessKey = ${?S3_ACCESS_KEY_ID}
+ secretKey = ${?S3_SECRET_ACCESS_KEY}

恒久対応として
- 開発、CI、テスト環境、本番環境のS3環境を切り分けるため、オブジェクトストレージを入れる

が必要そうだねという話をチームメンバーとしました。

バックログには入れてあるので引き続き対応をしていきたいと思います。