dip Engineer Blog

Engineer Blog
ディップ株式会社のエンジニアによる技術ブログです。
弊社はバイトル・はたらこねっとなど様々なサービスを運営しています。

ガタつきのない高さ可変のカルーセルスライダーを作る方法

初めまして。20新卒で自社サービスのフロントエンドやUX周りの業務を行っている須田(@tato_lol)です。
今回は高さ可変のカルーセルスライダーの実装についてお話したいと思います。

カルーセルスライダーはWebのUIの中でも有名な部類に入るもので、自前で実装せずとも世の中にはカルーセルスライダーのプラグインや、実装方法を教えるサイトが数多く存在します。
しかし、高さ可変のカルーセルスライダーとなると、実装例がなかなか見つかりにくく、かつ、プラグインなどで実現できたとしてもロード時のガタつきが起きやすいという難点があります。

(以下は有名プラグインslickの高さ可変スライドのロード時のガタつき)
参考:slick
f:id:tato_lol:20210210111147g:plain

上記の通り実装に難のある、高さ可変のカルーセルスライダーですが、弊社サービスの一つであるはたらこねっと(スマホ版)ではお仕事一覧の広告欄で、実際にガタつきのない高さ可変のカルーセルスライダーを実装することができました。
参考:はたらこねっと f:id:tato_lol:20210210110744p:plain

今回は、このカルーセルスライダーを「どのようにして高さ可変かつ、ロード時のガタつきのない実装ができたのか?」について説明したいと思います。

注意

本記事は「高さ可変」のカルーセルスライダーの実装方法にフォーカスした物になるため、基本となるカルーセルスライダーの実装方法についての説明は省略します。

カルーセルスライダーの構造

今回のスライダーの構造は以下のような形になっています。 f:id:tato_lol:20210210110722j:plain

一般的なスライダーはposition: absoluteのスライドをJavaScriptで位置を補正して作成することが多いですが、 今回はdisplay: flexで初期状態から横並びにすることで、ロード時のガタつきが起きないようにしました。
高さが全て同じ要素のスライドであれば、これだけで問題なく実装できるはずです。 しかし、今回は高さが可変であるため、最も高さが大きいスライドに全体の高さが調整されてしまいます。

f:id:tato_lol:20210210110728j:plain

この状態では相対的に小さめのスライドで不要な余白が生まれてしまい、あまり良い見た目とは言えません。
なおかつ、これは広告欄であるため、どんな高さのコマが初期表示されるか分からず、決め打ちで高さを指定することも難しいです。
上記の問題に自分も悩まされましたが、解決することができました。
その方法が以下のようなプロセスになります。

スライドの高さ問題の解決〜高さを持つコマを一つだけにする〜

まず、理想とするカルーセルスライダーの条件を洗い出してみると、以下の二つになります。

  1. ロード時にがたつかない
  2. 初期表示スライドの高さに合わせた表示がされる

この2つのうち、1の条件は既にdisplay: flexで解決できていますが、 同時にdisplay: flexによって最も高さが大きいスライドに合わせて表示が行われてしまいます。
そのため、2の条件と上記のデメリットを組み合わせてシンプルな解決方法を考えてみました。

「初期表示スライドの高さに合わせた表示がされる」と「最も高さが大きいスライドに合わせた表示がされる」を同時に達成するためには、 「初期表示スライドの高さが最も大きければ良い」 ということです。
これを達成するためには初期表示スライドが必ず最も高さの大きくなる状況、つまり、初期表示スライドのみしか高さが認識されなければ良いということになります。

「高さが認識されない」をどう作れば良いのか?という点ですが、position: absoluteを使うという方法が挙げられます。 初期表示以外の全てのコマにposition: absoluteを付与し、位置を画面外にすることでロード時から初期表示コマの高さでカルーセルスライダーを表示できます。 こうするとカルーセルスライダーは以下のような形になります。

f:id:tato_lol:20210210110734j:plain

もちろんこれだけではスライダーとしては動きませんが、とりあえず初期表示スライドの高さに合わせることはできました。
後は、JavaScriptで現在の高さを取得&付与し、position: relativeleft: autoで上書きすることで、スライドの位置が元に戻り、高さは初期表示スライドという状態にすることができます。

f:id:tato_lol:20210210110739j:plain

これでガタつきがない、高さ可変のカルーセルスライドが作成できました!
実際に動かす時は、横にスライドするアニメーションだけでなく高さ調整のアニメーションも挟む必要がありますがここでは割愛します。

最後に

私と同じように、高さ可変のカルーセルスライドの作成に悩む方にこの記事が届いたら嬉しいです。 お読みいただきありがとうございました。

著者

須田 耀平(画像は実家の犬) f:id:tato_lol:20210210110748j:plain

2020年dipアドベントカレンダーまとめ

f:id:naoya_prin:20210122150516p:plain dipのアドベントカレンダー

こんにちは、2020年新卒で入社し、求人系サービスの開発や社内向けツールの開発を行なっている @naoya_prin です。 今回は12/1~12/25に有志で行なったディップ Advent Calendar 2020について紹介します!

Advent Calendar って?

アドベントカレンダーとはクリスマスまでの期間に日数を数えるために使用されるカレンダーのことを指しますが、 エンジニア界隈では個人または複数人で記事を書いてクリスマス当日までバトンをつなげていく文化のことを指します! 弊社は2016年から毎年 Qiita Advent Calendar に参加しています。任意で参加者を募り、業務に関係するものから自分で興味を持った技術まで自由なテーマで記事を書いています。 今回はそのアドベントカレンダーの中から私が気になった記事を中心に振り返ります!

おすすめ記事一覧

AWS Lambda Runtime Interface EmulatorをDocker Desktop for M1で試してみる

AWS Lambda Runtime Interface EmulatorをDocker Desktop for M1で試してみる

こちらは、弊社CTOが昨年末に発売されたM1 Macを使ってDocker環境でRIEを試された記事です。 表題の手順だけでなく、M1 Macの使用感なども紹介されております。

PHPでアヤメの分類(機械学習)【PHP-ML】

PHPでアヤメの分類(機械学習)【PHP-ML】

機械学習をPHPで行う方法が紹介された記事です。機械学習といえばPythonのイメージが強いですが、 PHPで機械学習を試された手順を紹介してくれています。 PHPerで、機械学習に興味ある方はぜひ。

PostgreSQLをDockerで動かすときの初期設定

PostgreSQLをDockerで動かすときの初期設定

docker-compose.ymlで設定する項目をそれぞれの意味を含めて解説されています。 Dockerを学習中の方には、おすすめの記事です。

クリぼっちなので「何がクリスマスじゃあい!」をVRでやってみたかった【Unity+SteamVR】

クリぼっちなので「何がクリスマスじゃあい!」をVRでやってみたかった【Unity+SteamVR】

こちらは私の同期が12/25にあげた記事です! VRを使ってアニメ「巨○の星」のあのシーンを再現したそうです。 彼のクリスマスに対する思いがとても伝わります。 是非覗いてみてください!

おまけ

エンジニア以外にも、企画側から今回アドベントカレンダーに参加頂いた方もいらっしゃいました! ぜひこちらも。

ユーザーインタビューで聞こえた「チームの声」

ユーザーインタビューで聞こえた「チームの声」

エンジニアとして企画側がどんなことをしてユーザの課題を抽出しているのか、 サービスを違う視点から考えてみるのも面白いかもしれません。

また、過去実施したアドベントカレンダーはこちらから確認できます。

最後に

今回は12月に行なったアドベントカレンダーについて紹介しました。 弊社ではアドベントカレンダー以外にも様々な試み、イベントを行なっています。 ブログにて発信していくので楽しみにお待ちください。

また、弊社では一緒にサービスを開発している仲間を募集しています! とりあえず話だけ聞きたいでも構いません。興味がある方は下記よりご連絡ください! ディップ株式会社 採用サイト

著者

f:id:naoya_prin:20210122151428j:plain

中西直也

CloudWatchLogsからLambda経由でログメッセージを通知する

AWSを利用していると、アプリケーションのログをCloudWatch Logsに出力させることがあると思います。 本記事ではCloudWatch Logsに出力されたログの文字列を検知してAWS Lambda(以下、Lambda)を起動するシステムを構築していきます。

Lambdaの作成

CloudWatch Logsのサブスクリプションを作成する前に、起動先のLambdaを作成しておきます。 Lambda構築の説明は省略しますが、コードは以下のようにslack通知するようにしています。

require 'slack/incoming/webhooks'
require 'json'

def slack_notification(message)
  slack = Slack::Incoming::Webhooks.new ENV['SLACK_INCOMING_URL'], channel: '#general'
  slack.post message
end

def handler(event:, context:)
  slack_notification('エラーだよ')
  { event: JSON.generate(event), context: JSON.generate(context.inspect) }
end

CloudWatch Logs subscriptionsの設定

CloudWatch LogsからLambdaを起動させる方法の一つとして、サブスクリプションがあります。

サブスクリプションを使用して CloudWatch Logs からのログイベントのリアルタイムフィードにアクセスし、カスタム処理、分析、他のシステムへのロードを行うために、 Amazon Kinesis ストリーム、Amazon Kinesis Data Firehose ストリーム、AWS Lambda などの他のサービスに配信することができます。 ログイベントが宛先サービスに送信されると、Base64 でエンコードされ、gzip 形式で圧縮されます。

設定には、ロググループ設定のサブスクリプションフィルターのタブから作成できます。 また、サブスクリプションフィルターは1つのロググループにつき2つまでしか作成できません。 Lambdaサブスクリプションフィルターを選択する事でLambdaへの起動をするフィルターを作成できます。

実際に作成するにはまず起動先のLambda関数を選択します。 ログの形式は、今回はカスタムフィルターを利用したいのでその他にします。 サブスクリプションフィルターのパターンに、検知したい文字列を入力し、名前をつけます。

パターンをテストの項目で先ほど指定して文字列の検知が合っているかを確認できます。 すでにいくつかログが出力されている場合、そのログを利用してパターンのテストができます。

f:id:hayaosato:20201202153552p:plain

今回は ERROR という文字列を検知するようにしました。

ストリーミングを開始を設定する事でLambdaへのトリガが作成され、起動するようになります。

実際に飛ばしてみよう

作成したサブスクリプションが起動するか、実際にCloudWatch Logsで検知するであろう文字列(今回はERROR)を実際に出力させて Lambdaが起動するか確かめて見ます。

CloudWatch Logsのロググループにログを出力させるのは以下のコマンドで出来ます。

aws logs put-log-events --log-group-name ロググループ名 --log-stream-name ログストリーム名 --log-events timestamp=$(node -e 'console.log(Date.now())'),message='出力したいメッセージ'

今回は ロググループ: /sample-logs ログストリーム: stream01 出力するメッセージ: ERROR: hogehoge として実際に動かしてみます。

aws logs put-log-events --log-group-name /sample-logs --log-stream-name stream01  --log-events timestamp=$(node -e 'console.log(Date.now())'),message='ERROR: hogehoge'

ちなみに、成功すると

{
    "nextSequenceToken": "xxxxxxxxxxxxxxxx"
}

とトークンが発行されるので、2回目以降は

aws logs put-log-events --log-group-name /sample-logs --log-stream-name stream01  --log-events timestamp=$(node -e 'console.log(Date.now())'),message='ERROR: hogehoge'  --sequence-token='xxxxxxxxxxxxxx'

とトークンを指定する必要があります。

以上のように、ログを出力する事でLambdaが起動します。 今回はSlack通知を飛ばすLambdaなので、

f:id:hayaosato:20201202153513p:plain

出来ました。

CloudWatchからのログをデコード

しかし、実際の運用でこの仕組みを使おうとするとCloudWatchからのメッセージは

{
  "awslogs": {
    "data": "H4sIAAAAAAAAAHWPwQqCQBCGX0Xm7EFtK+smZBEUgXoLCdMhFtKV3akI8d0bLYmibvPPN3wz00CJxmQnTO41whwWQRIctmEcB6sQbFC3CjW3XW8kxpOpP+OC22d1Wml1qZkQGtoMsScxaczKN3plG8zlaHIta5KqWsozoTYw3/djzwhpLwivWFGHGpAFe7DL68JlBUk+l7KSN7tCOEJ4M3/qOI49vMHj+zCKdlFqLaU2ZHV2a4Ct/an0/ivdX8oYc1UVX860fQDQiMdxRQEAAA=="
  }
}

のようにエンコードされ、gzipで圧縮されています。 Lambdaをログをデコードおよび圧縮解除し、Slack通知するファンクションにしようと思います。 コードは以下のようになります。

require 'slack/incoming/webhooks'
require 'json'
require 'zlib'
require 'stringio'
require 'base64'


def slack_notification(message)
  slack = Slack::Incoming::Webhooks.new ENV['SLACK_INCOMING_URL'], channel: '#general'
  slack.post message
end

def parse_message(data)
  gzip_data = Base64.strict_decode64(data)
  gz = Zlib::GzipReader.new(StringIO.new(gzip_data))
  JSON.parse(gz.read).to_s
end

def main(event:, context:)
  slack_message = parse_message(event['awslogs']['data'])
  slack_notification(slack_message)
  { event: JSON.generate(event), context: JSON.generate(context.inspect) }
end

Base64デコードをしてGzipの圧縮解除で読み込んだデータをjsonにパースしています。 slackにメッセージを送信するために無理やり文字列に変換してますが、実際に運用する際には各自整形してあげてください。

このようにログの中身も確認できるようになりました。

f:id:hayaosato:20201202153640p:plain

Terraform化

最後に、この仕組みをTerraform化してみようと思います。

まずはLambdaのTerraformです。IAM Roleは適宜変更をお願いします。

resource "aws_lambda_function" "default" {
  filename      = "your_script.zip"
  function_name = "your_function_name"
  role          = aws_iam_role.default.arn
  handler       = "your.handler"
  timeout       = 900

  runtime = "ruby2.7"
}

resource "aws_iam_role" "default" {
  name               = "your_role_name"
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*",
      "Effect": "Allow"
    }
  ]
}
EOF
}

続いて、CloudWatch LogsとLambdaの連携をするTerraformです。

resource "aws_cloudwatch_log_group" "default" {
  name = "/your/log/group/name"
}

resource "aws_cloudwatch_log_subscription_filter" "default" {
  name            = "your subscription filter"
  log_group_name  = aws_cloudwatch_log_group.default.name
  filter_pattern  = "ERROR"
  destination_arn = aws_lambda_function.default.arn
}

resource "aws_lambda_permission" "from_cloudwatch_logs" {
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.default.function_name
  principal     = "logs.ap-northeast-1.amazonaws.com"
  source_arn    = aws_cloudwatch_log_group.default.arn
}

このように、ロググループのサブスクリプションフィルターはlambdaと連携させてあげる必要があります。

参考

著者

dippeople.dip-net.jp (写真左)

【小ネタ】XcodeのSchemeの並び順を変更する方法

はじめに

こんにちは。iOSエンジニアの@satoshi-babaです。 社内のあるアプリチームからXcodeのSchemeが見辛くなってしまったと相談を受けました。

f:id:satoshi-baba:20200929135440p:plain

うーん...確かにこれは見辛い...。 どうにかして変更ができないか調べてみました。

並び替えてみる

ここに表示されているものはManage Schemeで管理されているものです。 もしかしたらManage Schemeの画面をみてみたら何かヒントがあるかもしれません。

Product → Scheme → Edit Schemeで開いてみましょう。

f:id:satoshi-baba:20200929135504p:plain

先ほど見かけたSchemeの並び順と一致してますね。 この画面で並び替えができたので並び替えた結果がこちらです。

f:id:satoshi-baba:20200929135510p:plain

最初に相談されていた箇所も並び替えが完了しています。

f:id:satoshi-baba:20200929135515p:plain

感想

Schemeの並び替えなんて考えたこともありませんでした。

開発に直接関係はありませんでしたが、こういうところからプロジェクトを綺麗にしていけるといいですね!

著者

dippeople.dip-net.jp

バイトルアプリ開発にジョインしました!@林田守加

ご挨拶٩( ᐛ )و

みなさま、初めまして!
林田守加 @hayashidamoka と申します!
9月1日よりディップ株式会社に入社いたしました!
好きな仕事を”選んで”楽しく働ける人を増やし、
その人の人生も周りの人も全世界すらも楽しく変えちゃうようなそんなきっかけを作るため、
Androidエンジニアとしてバイトルアプリの開発をがんがんやって参ります!
どうぞ、よろしくお願い致します!

ディップの好きなところ

まだ入社から約1ヶ月しか経っていないのですが、好きポイントをたくさん見つけたのでお話しさせてください!

1. 先輩たちがとても優しい!

流行りの新型コロナウイルスの対策で、出社は週1日。
週4日はリモートでお仕事をしています。
入社早々のリモートワークだったので、1人でやっていけるかな...と不安もあったのですが、杞憂でした!
先輩方が常に気にかけてくださっていて、私が困る前にSlackで声をかけてくださいます。文章だけでなく、ビデオ通話で顔を見ながら優しく教えてくださることも!歓迎会もリモートで開催していただきました✨

2. 急速に成長できる環境

またまた先輩たちのお話になってしまうのですが、
私が将来どうしたいかをじっくりと聞いてくださって、そのためには何をしていくべきなのかを一緒になって本気で考えてくださいます。
どんな環境でも自分次第で成長することはできますが、周りの方々の支えもあると何倍にも早いスピードで進化していくことができます。
うまく言葉にするのは難しいのですが、面接中から大きな期待をひしひし感じていて、こんな環境で揉まれたい!と志望度がさらに跳ね上がりました。
プレッシャーはありますが、こんなに成長できる環境はありません!!期待を超えられるようにがんばります!!!
そして近い将来、後輩の人生に寄り添って育てていく側になりたいです💪

3.素敵な出会い

ディップは拠点が38箇所あり、2000名以上の社員が在籍しています!(契約社員、アルバイト、パートナーさんを含めるともっと多いです!)

TUNAGという社内SNSが活発に使われていて、社員全員のプロフィールを見て好きな物やどんな人かを知ったり、気軽に記事の投稿をして社員全員に共有することができます!
入社して半月経たないうちにびっくりするぐらい趣味が会うお友達と出会うことができました!部署もオフィスも全然違う方なので超奇跡的!!🥰
他にも、同好会があったり、共通の趣味を持った人たちが集まってざっくばらんなお話をする会(現在はリモートで開催)があったりするそうなので参加を企んでおります😎
会社全体で交流する文化があるのって素敵だなぁって思いました❣️

4. オフィスからの景色

私が通勤しているディップ本社は六本木グランドタワーの31Fにあります!
なのですっごく高いです。それに大きな窓がいっぱいあります。全面ガラス張りってやつだと思います。
なんと東京タワーが目の前!スカイツリーだって見えちゃうのです。
東京を一望できるこのビル...朝もお昼も夜も前も後ろも右も左も絶景ですが、今回はお昼のスカイツリー側の写真を載せます!

f:id:hayashidamoka:20201007110403j:plain
✨ザ・東京!って感じ✨

語り出すと長くなってしまうので割愛しますが
エンジニアになれるなんて夢にも思っていなかった上京したての頃に、同じビルのとある会社からこの景色を見させていただく機会がありました。
いつかこんなオフィスで働けるエンジニアになれたら...と憧れを抱いてこの景色を写真に収めたのを覚えています。
私にとってはただ綺麗な景色というだけでなく、初心を思い出させてくれる景色でもあるのです。
あの時憧れたかっこいいエンジニアを目指して精進していきます!

まとめ

エンジニアが欲しい制度が沢山あるところとか、社員に優しすぎるところとか 、社員総会が超豪華で楽しみとか、好きなところはまだまだありますが書ききれないのでそろそろ締めます!
気になったそこのあなたはぜひ入社してきてください!
一緒に働けるのを楽しみにしています!!🤗

余談

テックブログを書かせていただくにあたって、はてなブログのアカウントを作りました。メアドとかパスワードとか入力して利用規約とか読んで、順調にアカウント開設に向かっていたところ...
...!!!!!

こんな質問をされました。

f:id:hayashidamoka:20201007110637p:plain
「いぬどしであるか、」

....????
い ぬ ど し . . . ? ฅU•ﻌ•Uฅワン
なんで戌年???私丑年だし押せないなぁ...いやでもそもそもなんでこんなこと聞くんだろ???ってちょっと悩んで

コピペして調べてよく読んだら気がついたんですけど
「せいねんであるか、」
って問われてただけでした...

成年と戌年、似てますよね...????笑💧

著者

林田守加
f:id:hayashidamoka:20201007110900p:plain
(インタビュー記事はまだないです...お楽しみにっ!)

TerraformでFargateを構築する

はじめに

インフラエンジニアとしてTerraform運用を行っているのですが、 TerraformやFargateもだいぶ浸透してきて、導入している企業も増えてきているように感じます。 そのようなケースのサンプルとして公開したいと思います。

ファイル構成

ファイル構成は以下としています。

├── logs
│   ├── backend.tf
│   ├── main.tf
│   ├── outputs.tf
│   ├── provider.tf
│   └── variables.tf
├── buckets
│   ├── backend.tf
│   ├── main.tf
│   ├── outputs.tf
│   ├── provider.tf
│   └── variables.tf
├── ecr
│   ├── backend.tf
│   ├── main.tf
│   ├── outputs.tf
│   ├── provider.tf
│   └── variables.tf
└── fargate
    ├── backend.tf
    ├── files
    │   └── container_definition.json
    ├── main.tf
    ├── outputs.tf
    ├── provider.tf
    └── variables.tf

ポイントとしては、logとFargateのtfファイルの階層を分けている事です。 分ける理由としては、同階層にしてしまうとTerraform destoryした時にログまで消えてしまって後悔。。。というケースが起こるかなと思い階層を分けています。 同様の理由としてS3bucket、ECRも階層を分けています。

また、files以下にコンテナ定義のjsonファイル等を入れています。

Fargate

まずはクラスターから

resource "aws_ecs_cluster" "default" {
  name = local.service_name
}

タスク定義は以下のようになっています。 定義の内容をjsonファイルに記載しておいて、ECRのARNなどはdataソースを使って記入しています。

data "template_file" "default" {
  template = file("files/container_definition.json")
  vars = {
    ECR_ARN      = data.terraform_remote_state.ecr.outputs.default["repository_url"]
    SERVICE_NAME = local.service_name
  }
}

resource "aws_ecs_task_definition" "default" {
  family                   = local.service_name
  container_definitions    = data.template_file.default.rendered
  task_role_arn            = aws_iam_role.default.arn
  network_mode             = "awsvpc"
  execution_role_arn       = aws_iam_role.default.arn
  cpu                      = 512
  memory                   = 1024
  requires_compatibilities = ["FARGATE"]
}

タスク定義のjsonファイルは以下のようになっています。

[
  {
    "name": "${SERVICE_NAME}",
    "image": "${ECR_ARN}",
    "essential": true,
    "portMappings": [
      {
        "containerPort": 80,
        "hostPort": 80
      }
    ],
    "logConfiguration": {
      "logDriver": "awslogs",
      "options": {
        "awslogs-region": "ap-northeast-1",
        "awslogs-group": "/ecs/${SERVICE_NAME}",
        "awslogs-stream-prefix": "${SERVICE_NAME}"
      }
    }
  }
]

Ecsのサービスは以下のようになっています。

resource "aws_ecs_service" "default" {
  name            = local.service_name
  cluster         = aws_ecs_cluster.default.id
  task_definition = aws_ecs_task_definition.default.arn
  desired_count   = 2
  launch_type     = "FARGATE"

  load_balancer {
    target_group_arn = aws_lb_target_group.default.arn
    container_name   = local.service_name
    container_port   = 80
  }

  network_configuration {
    subnets = [
      data.terraform_remote_state.subnet.outputs.publib_a["id"],
      data.terraform_remote_state.subnet.outputs.publib_c["id"],
    ]
    security_groups = [
      aws_security_group.default.id
    ]
    assign_public_ip = true
  }
}

LB

resource "aws_lb" "default" {
  name = local.service_name
  internal           = false
  load_balancer_type = "application"
  subnets = [
    data.terraform_remote_state.subnet.outputs.publib_a["id"],
    data.terraform_remote_state.subnet.outputs.publib_c["id"],
  ]
  security_groups = [
    aws_security_group.default.id,
  ]

  enable_deletion_protection = true

  access_logs {
    bucket  = data.terraform_remote_state.buckets.outputs.default["id"]
    enabled = true
  }
}

resource "aws_lb_target_group" "default" {
  name        = local.service_name
  port        = 80
  protocol    = "HTTP"
  vpc_id      = data.terraform_remote_state.subnet.outputs.default["id"],
  target_type = "ip"
}

VPCとサブネットはバックエンドから参照しています。 また、security groupは別で作成しておいてください。 bucketについては、前述の通り階層を分けているためバックエンドから参照してください。 ターゲットグループのtarget_typeはFargateと連携するためにipに指定しておいてください。

LBへSSL証明書の適用 Certificate Managerに登録してあるSSL証明書を参照しています。

resource "aws_lb_listener" "default" {
  load_balancer_arn = aws_lb.default.arn
  protocol          = "HTTPS"
  port              = "443"
  ssl_policy        = "ELB_SecurityPolicy-TLS-1-2-2017-01"
  certificate_arn   = data.terraform_remote_state.certificate.outputs.default["arn"]
  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.default.arn
  }
}

80ポートへのアクセスはリダイレクトするようにします。

resource "aws_lb_listener" "redirect_https" {
  load_balancer_arn = aws_lb.default.arn
  port              = "80"
  protocol          = "HTTP"

  default_action  {
    type = "redirect"

    redirect {
      port        = "443"
      protocol    = "HTTPS"
      status_code = "HTTP_301"
    }
  }
}

variables

最後に、variablesは以下のようになっています。

variable "environment" {
  default = "development"
}

locals {
  service_name = "${var.environment}-service-name"
}

ここでlocalsを使っているのは、環境名などを変数に埋め込むためです。 特に必要ないかもしれないです。

最後に

これからTerraformを導入していきたい、Fargateを使ってみたいという方に少しでも参考になれば。。。

参考

筆者

dippeople.dip-net.jp (写真左)

BitriseのiOS Auto Provisionが超絶使いやすくなった件

はじめに

こんにちは。iOSエンジニアの@satoshi-babaです。 BitriseではiOS Auto Provisionの新しいステップが6月にリリースされました。 これは神対応だと思ったので早速使ってみました。

何が神対応なのか

BitriseはProvisioning ProfileをBitriseに登録する必要があり、Provisioning Profileが更新された場合に毎回アップロードし直してました。 ですが2年ほど前にリリースされたiOS Auto Provisionのステップを使用すると、BitriseにProvisioning Profileの登録が不要になり、自動で管理してくれるようになりました。

しかしこれは2FAを使用していたため、1ヶ月に1度の更新が必要だったのです。 それが2020年の6月にリリースされた、iOS Auto Provision with App Store Connect APIを使用すると解決するのです!

僕は弊社のBitriseの管理をしているのですが、毎月1度はBuildがうまくいかない問題の対応をしていました。(忘れる方が悪いのですが...) これは僕にとって救世主であって、即座に入れた方がいいと判断して導入しました!

導入の仕方

長い前置きでしたがここから導入していきます。 導入は簡単で認証情報の登録→ステップの差し替え→認証情報の設定をするだけです。

1. 認証情報の登録

まずはApp Store Connectにアクセスし、ユーザとアクセスのキーを開きます。 f:id:satoshi-baba:20200803101643p:plain

+ボタンを押すと登録するためのモーダルが表示されるので、適当な名称を入力します。 権限はDeveloper権限以上があれば動作します。 f:id:satoshi-baba:20200803101649p:plain

登録が完了すると一覧に表示されますので、APIキーのダウンロードをします。 また、キーIDとIssuer IDがこの後に必要になるのでコピーしておきましょう。 f:id:satoshi-baba:20200803101653p:plain

2. ステップの差し替え

次はWorkflowの修正をします。 ios-auto-provisionをios-auto-provision-appstoreconnectに変更するだけです。

- ios-auto-provision:
    inputs:
    - team_id: xxx
    - distribution_type: ad-hoc

- ios-auto-provision-appstoreconnect@0:
    inputs:
    - distribution_type: ad-hoc

3. 認証情報の設定

最後にBitriseに1で登録した認証情報を設定します。 Account Settings → Apple Developer Account → Add an Accountから登録します。 f:id:satoshi-baba:20200803101804p:plain

1で登録した際にメモした各種情報を入力します。 APIキーも忘れずにアップロードしましょう。 f:id:satoshi-baba:20200803101809p:plain

Workflowを変更したプロジェクトのTeamタブのApple Developer Portal APIに使用する認証情報を設定します。 f:id:satoshi-baba:20200803101813p:plain

以上で設定が完了しました。 Buildも通るようになっているはずです。

感想

これで月1の2FAの作業から解放されました...! このような神対応がされるのがBitriseのいいところですね! 皆さんもぜひ試してみてください!

著者

dippeople.dip-net.jp