nazolabo

フリーランスのWebエンジニアが近況や思ったことを発信しています。

アタッチされたサービスとTerraformのModuleの分け方

何の話

TerraformのModuleの分け方はマイクロサービス的な単位で分けると良いという話です。TerraformだけではなくてIaC全般に言える話だと思います。

アタッチされたサービス

Twelve-Factor AppのIV. バックエンドサービスでは、バックエンドサービス(DBやキャッシュなど)はアタッチされたサービスとして扱う、としております。

f:id:nazone:20200502144124p:plain

設定は環境変数で接続先を具体的に記入し、アプリケーションコード(ビルド)の差し替えなしにバックエンドサービスを切り替えれるようにすべきとしております。

これにより様々なメリットが生まれますが、ここでは特に責任分界点がこの接続先によって明確になるということがあります。

f:id:nazone:20200502144709p:plain

マイクロサービスの設計では独立性が重要になりますので、責任分界点が明確になっているということは独立性が高いものを組み合わせて安全に利用できている状態と言えると思います。

TerraformによるModule化の境界

Terraformに限らずIaCではインフラの単位をコードとして再利用しようとすると失敗しやすく、例えば「フロントエンド用のnginx」と「画像変換サーバー用nginx」を「同じnginxだから」と言って「同じmodule化」すると確実に失敗します。

今の例は見ただけで失敗だとわかると思いますが、ようは複雑性の意味が全然違うものを共通にしようとすると、その複雑性を隠蔽するためにより複雑な汎用化をしないといけなくて本末転倒になるという話です。

TerraformにおけるModule化は、「共通のものを1つにまとめる」という用途より、「名前空間の分離」を目的として設計するほうが上手くいくと考えております。

例えばTerraformでAWSリソースをModule化する場合、以下のようにするのが良いです。

f:id:nazone:20200502150041p:plain

上記の「アタッチされたサービス」の図とほぼ同じなのがわかるかと思います。責任分界点が事前に明確になっているので、その単位でModule化することによって、Module内でお互いのことを意識することがほとんどなくなります。Module間で必要な情報(エンドポイントなど)はvariablesとoutputで明確に書く必要がありますので、どの情報が外で使われるかも明確になります。

IAM(Role)やSG(セキュリティグループ)もModule毎に個別で作ることで、変に再利用されることがなく、最小の権限を個別に与えることができます。別環境の同リソース(staging/productionなど)や似たような権限のModuleでも必ず個別に作りましょう。

Moduleは汎用的に使えないの?

もちろんそんなことはありません。責任分界点がしっかりしているModuleは汎用的になります。一般的なWebサービスの構成はそんなにどれも違いがないのでModule単位で別プロジェクトに持ち出しなども簡単にできるようになると思います。以前紹介した terraform-aws-modules などの設計も参考にしてください。

参考

memo.yuuk.io

Unity で gRPC を試す( HelloworldUnity )

概要

Unity で gRPC を試すには、以前はいろいろ準備する必要があったようですが、現在は https://github.com/grpc/grpc/tree/master/examples/csharp/HelloworldUnity にサンプルが丸ごと入っていますので、これを動かすところまで試します。

手順

上記を UnityEditor で開きます。

README.md に書いてある通り、別途 grpc_csharp_unity.zip が必要です。指定場所からダウンロードして展開して出てきた Plugins ディレクトリをプロジェクトに突っ込みます。

エラーが出る

Error: Could not load signature of Google.Protobuf.ByteString:get_Span due to: Could not load file or assembly 'System.Memory, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies. assembly:System.Memory, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51 type:<unknown type> member:(null) signature:<none>

こんな感じのエラーが出るのですが、grpc_unity_package.2.26.0-dev までは動作するが、それ以上のバージョンではエラーになるようです。いずれ解決する問題かどうかはよくわかりません。ちなみに grpc_unity_package.2.26.0-dev はここからダウンロードできます

動かす

f:id:nazone:20200505183848p:plain

動かすとこんな画面になります。

ちなみに Unity 側単体でサーバーとクライアントが両方起動しているので、通信はしているのですがよくわからないと思います。

ボタンを押すと表示が変わります。

f:id:nazone:20200505183906p:plain

サーバーを別で動かす

HelloWorldTest.cs に、Server server を new している一帯がありますので、そこを削除なりコメントアウトなりします。

同等のサーバーは https://github.com/grpc/grpc/tree/master/examples/csharp/Helloworld/GreeterServer にありますので、代わりにこちらをビルドして起動してから Unity 側を起動すると、いい感じで通信するようになります。

Webエンジニアとしてフリーランスしています

これまでのあらすじ(&お前誰よ)

UUUM株式会社を2019年10月に退職し、のんびりとした生活をしていましたが、本格的に働くことにしました。

能力や経歴などについてはポートフォリオを作りましたので、そちらをご覧頂ければと思います。

なぜフリーランス

働き方を自分で制御したいというのと、会社員という立場から一度離れていろいろな現場を見てみたい、そして私の力でそれを改善できるのか挑戦してみたい、という点から、しばらくフリーランスをすることを選びました。

特に最近は一人で全て解決することを求められることが多く、他の会社の視点ではどのようになっているのか、どのような他の良い方法があるのかというのをもっと知りたくなり、様々な現場を見てみたいという気持ちが強いです。

前にも少しやっていたのですが、当時の居住地や知名度では正直難しい(私の営業力不足も大きいですが…)状況で断念していました。

全く就職しないの?

そのうちすると思います。フリーランスという形態は自分には向いていないと思っておりますので、よほど軌道に乗って収入に困らない状態が続くとかでなければ就職するのではないかと思います。

その場合にしても、フリーランス中にお試しで仕事をしてマッチしたら入社という形態を取らせていただきたいと考えておりますので、興味がある会社様は先に声をかけていただいておくと良いと思います。

仕事募集してるの?

ありがたいことに今(2020年3月現在)は埋まっているので受けられないのですが、フリーランスなので状況はすぐ変わると思いますので、お仕事の相談をしたい方は先にご連絡頂ければと思います。本記事公開以降も状況が変わっているかもしれませんので、詳しくはお問い合わせ頂ければと思います。

原則としてリモートが可能な現場のみ受け付けております。たまには出社してほしいとかという場合でもお受けできますが、そのあたりは直接ご相談頂ければと思います。また最大でも週4まで、通常週2程度の稼働で受けております。

Terraform AWS modulesでざっくりAWSインフラを作る

https://github.com/terraform-aws-modules には、TerraformですぐにAWSリソースを立ち上げるためのModuleがいくつか存在します。

VPCの作成

terraform-aws-vpcでは、主に以下のリソースを作ってくれます。オプションでNATとかも用意してくれます。

module "vpc" {
  source = "terraform-aws-modules/vpc/aws"

  name = "test"
  cidr = "10.0.0.0/16"

  azs             = ["ap-northeast-1a", "ap-northeast-1c", "ap-northeast-1d"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]

  enable_nat_gateway = false
  enable_vpn_gateway = false
}

ALBの作成

terraform-aws-albでは、主に以下のリソースを作ってくれます。

Security Group は作ってくれないので、自前で用意しましょう。

resource "aws_security_group" "alb" {
  name        = "alb"
  description = "alb"
  vpc_id      = module.vpc.vpc_id
}

module "alb" {
  source  = "terraform-aws-modules/alb/aws"
  version = "~> 5.0"

  name = "test"

  load_balancer_type = "application"

  vpc_id          = module.vpc.vpc_id
  subnets         = module.vpc.public_subnets
  security_groups = [aws_security_group.alb.id]

  target_groups = [
    {
      name             = "test"
      backend_protocol = "HTTP"
      backend_port     = 80
      target_type      = "ip"
      deregistration_delay = 10
    }
  ]

  http_tcp_listeners = [
    {
      port               = 80
      protocol           = "HTTP"
      target_group_index = 0
    }
  ]
}

ACM

terraform-aws-acmでは、ACM証明書を一発で作ってくれます。これは定型フォーマットなので、そのまま利用して問題ないでしょう。(手元にRoute53管理のドメインがなかったので試してはいません)

module "acm" {
  source  = "terraform-aws-modules/acm/aws"
  version = "~> v2.0"

  domain_name  = "my-domain.com"
  zone_id      = "Z2ES7B9AZ6SHAE"

  subject_alternative_names = [
    "*.my-domain.com",
    "app.sub.my-domain.com",
  ]

  tags = {
    Name = "my-domain.com"
  }
}

SNSのSlack通知

terraform-aws-notify-slackを使うと、SNSトピックをSlackに通知させるやつも簡単にTerraformで管理することが可能です。おそらくこれが一番使うのではないでしょうか。

使い方も簡単で、よくあるCloudWatch AlarmをSlackに通知するのは以下の書き方で実装できます。(手元に通知するものがなかったので試していません)

  
provider "aws" {
  region = "eu-west-1"
}

resource "aws_kms_key" "this" {
  description = "KMS key for notify-slack test"
}

# Encrypt the URL, storing encryption here will show it in logs and in tfstate
# https://www.terraform.io/docs/state/sensitive-data.html
resource "aws_kms_ciphertext" "slack_url" {
  plaintext = "https://hooks.slack.com/services/AAA/BBB/CCC"
  key_id    = aws_kms_key.this.arn
}

module "notify_slack" {
  source = "../../"

  sns_topic_name = "slack-topic"

  slack_webhook_url = aws_kms_ciphertext.slack_url.ciphertext_blob
  slack_channel     = "aws-notification"
  slack_username    = "reporter"

  kms_key_arn = aws_kms_key.this.arn

  lambda_description = "Lambda function which sends notifications to Slack"
  log_events         = true

  tags = {
    Name = "cloudwatch-alerts-to-slack"
  }
}

resource "aws_cloudwatch_metric_alarm" "LambdaDuration" {
  alarm_name          = "NotifySlackDuration"
  comparison_operator = "GreaterThanOrEqualToThreshold"
  evaluation_periods  = "1"
  metric_name         = "Duration"
  namespace           = "AWS/Lambda"
  period              = "60"
  statistic           = "Average"
  threshold           = "5000"
  alarm_description   = "Duration of notifying slack exceeds threshold"

  alarm_actions = [module.notify_slack.this_slack_topic_arn]

  dimensions = {
    FunctionName = module.notify_slack.notify_slack_lambda_function_name
  }
}

https://github.com/terraform-aws-modules/terraform-aws-notify-slack/blob/master/examples/cloudwatch-alerts-to-slack/main.tf

まとめ

公式とはいえ外部にあるmoduleだと、例えば最新の機能を入れたい場合にmoduleの反映を待たないといけないですし、そういう理由以外でもカスタマイズすることが難しく、また、moduleが勝手にアップデートされることが嬉しくないことも多いため、実際に使うのであればローカルにmoduleまるごどcloneして利用するのがいいのではないでしょうか。

SNSのSlack通知やACMに関してはほぼそのまま使っても問題ないと思います。

今はVPC一通りとALBがあればECS on Fargateでクラスタを作ればサービスを上げられるので(DBとかは別にして)、Terraformで管理したいけど書き方が難しいという場合は使ってみるのもありなのではないでしょうか(そんなに難しくないですが…)。

SSH先のdockerをローカルからシームレスに使用する(SSHでDOCKER_HOSTを指定する)

何がしたいの?

例えば「MacBook Air で開発しているけどスペックが低いので Docker で動かすものはデスクトップPCで動かしたい」というようなケースに使います。

docker をリモートで動かす

まずリモートの Docker を用意します。私は Windows なので Hyper-V で作りました。Docker のバージョンはリモートもローカルも最新が良いです。最低でも 18.09 以上が必要かと思われます。

対象の環境に SSH で入れるようにしておいて、SSH で入るユーザーが sudo なしで docker コマンドを叩ける必要があります。 sudo usermod -aG docker myuser のようにして SSH 対象ユーザーを docker グループに所属させましょう。

docker コマンド内で SSH 鍵のプロンプトは出せないので、事前に ssh-add しておきましょう。

ここまでで、設定が問題なければ以下の方法で起動すると思います。

docker -H ssh://user@remote-host run -d -P nginx

-H の部分は、環境変数 DOCKER_HOST で指定が可能です。

docker-compose 対応

Docker for Mac 標準の docker-compose ではうまく動かなかったので(多分 このあたりの都合 )、docker-compose は pip で入れました。pip で入れただけでも動かない場合は pip install cryptography==2.4.2 が必要かもしれません。

また、 docker-compose は .ssh/config を読んでくれないっぽいので(1.25.0 時点)、DOCKER_HOST はそれを考慮して書いてください。

ボリュームマウントは SSH 先のホストに対して行われます。マウント先は SSH 先のホストのディレクトリ構成に合わせて記述してください。ローカルと同期したい場合は別途自前で同期する必要があると思います。

※ 2020-06-04 追記 : docker-py 4.2.0 で .ssh/config を読むようになったようなので、それが取り込まれている docker-compose 1.26.0 では読み込むことができるのではないかと思います。(未検証)

ユースケース

ローカルとボリュームマウントが基本的にできないので、アプリケーションコードを Docker コンテナ内で実行するようなケースには向いていません。特殊な構成のアプリケーションで実行に Docker がどうしても必要という場合は、この方法は避けたほうが良いです。

ローカルで編集しないもの、DB やキャッシュサーバーのようなものだけ Docker で起動し、アプリケーションはローカルで起動する、といったケースにはすぐに使用できると思います。この場合も設定ファイルを送り込むことができないので、設定ファイルが必要なもの(Elasticsearch など)は設定ファイルを入れるための Dockerfile を書いて、それ経由で起動するのが良いかと思われます。

現代の一般的な構成の Web アプリケーションでは、Docker でアプリケーションそのものを実行するメリットはあまりないので、この構成は十分実用的かと思われます。

そもそもSSH先で開発すればいいのでは?VSCodeのRemote-SSHもあるし…

あっはい…

一応ローカルに開発中のファイルを置いておけるので、外出先で開発したくなった場合にそれをそのまま使えるというメリットはありますが、まあ適当に作業中ブランチをpush/pullすればいいだけですね…

2019年トップツイート振り返り

Twitter Analyticsから各月のトップツイートについて振り返ってみます。

1月

ありません

2月

今でもこういう感想だし、下手に並列化するより直列でそのまま流したほうが(個別のジョブの時間が長すぎる場合以外は)速いという認識なのですが、皆様どうしてるのでしょうか。

3月

EntityやらValueObjectとかってのはDDDの表現手法の一つであって、本質としてDDDが目指してるものってそこじゃないでしょ?みたいな話でした。

4月

自分もそれなりにTerraform書いている量では多い自信があるのですが、こうやって具体例がまとめられている書籍は今までなかったのでとても良い内容でした。

現在はさらに内容を充実させた 実践Terraform AWSにおけるシステム設計とベストプラクティス が出ているようなので、そちらを読むのが良いのではないかと思われます。(私はまだ買ってないです…)

実践Terraform AWSにおけるシステム設計とベストプラクティス (技術の泉シリーズ(NextPublishing))

実践Terraform AWSにおけるシステム設計とベストプラクティス (技術の泉シリーズ(NextPublishing))

5月

通信レイヤーを使ってサービスを分離するのは規模が大きくないと難しいですが、モノリシックなプロダクトでも内部構造は分離できる構造になっていると変更に強いしテストも書きやすいしという話です。マイクロサービスが目指したいものが何なのかを考えて導入しましょう。

6月

リモートワーク論についてはいろいろあるのですが、自然にリモートワークをするにはオフィスを提供しても提供しなくても何も変わらないというような環境がベストではないかと思います。そのためにはオンラインにリソースを集中させる必要がありますし、顔を合わせないとできないことを最小限にする必要もあります。

7月

Terraform人気ですね。ACMDNS検証周りは内部でオーダーが勝手に変わるらしく突然差分が発生するというやつです。最近は諦めてここだけ手動でやっています。管理するメリットないし…。

8月

2019後半は本当に何もしていないので、2019年のアウトプットのほとんどはここに凝縮されています。12月の登壇内容と併せてご覧いただければと思います。

9月

リモートワーク大好きマンです。身も蓋もない話なのですが、できる人はできるしできない人はできないみたいな結論に行き着きます。そして多くの人はどちらかといえば「できない」ほうです。主語が大きいですが根拠はあるのでどこかで書けたらと思います。

10月

大きめの企業で「誰々さんを新たな役員に任命!」みたいなのって、大きく会社の方向性を変えたいという意思でもあると思うので、当然決断するのは大変だし、失敗することも多いと思うし、それでも決断するのはすごいなーという話です。私には無縁の内容ですが…。

なお、このツイートの次はこんな内容です。

11月

元ネタがあります

12月

これについては年が明けたら詳しく書きます。それではよいお年を。

OKRでありがちな間違い2点

ドキュメント(OKRはGoogleのものではありませんが…)ちゃんと読もうシリーズ第二弾です。(第三弾は多分ないです)

Google re:Workに書いてある内容のうち、間違った運用をされてそうな2点をピックアップしてみました。

一部に独自の解釈が含まれていますので、詳細は上記リンクなどを参照してください。またre:Workに書いてある内容ベースなので、OKRの正しい解釈としてはもう少し違う可能性があります。

1. 「OKR は、従業員を評価するためのツールではありません。」

評価するためのツールではないということは、OKRで評価しちゃ駄目なの?

普通に解釈したらそうなるのではないでしょうか。

なんで駄目なの?

OKRは、達成率が60%~70%が理想的とされています。簡単には達成できないような目標を設定して大きな成果を上げるのが目的だからです。しかしそれを個人の評価にしてしまうと、達成できなかった場合にマイナスにしてしまう可能性があります。達成できるかできないか微妙な目標で達成できなくてマイナスというのは理不尽なのではないでしょうか。

また、OKRでは、目標を達成できなくてもその過程で個人は大きな進化をするだろうとしています。「大きな目標に対して努力をする」ということが既に成果になっていて、それは評価されるべき内容となっているので、OKRの達成と個人の評価は関係がないということがわかります。

2. 「OKR は、社内共有のタスク管理ツールではありません。」

タスク管理ツールじゃないの?

そもそもOもKRもタスクではないのでタスク管理ツールではありません。

OにもKRにもタスクを入れないなら、OとKRの違いって何なの?

Oには数値ではない(定性的な)大きな目標を入れ、KRにはOを達成するための具体的な(定量的な)数値指標を入れる、とされています。

Oには会社規模であれば「世界一の〇〇を作る」みたいな感じの、とにかくすごそうな内容を入れておくのが良いでしょう。チームであればもう少しフォーカスを絞って「UIを改善する」とか「利益率を上げる」とかでもいいでしょう。

KRは、Oを達成するための具体的な数値を指定します。OKRの達成はKRの数値を0.0~1.0の範囲で評価できる状態にするというのがありますので、数値で評価できないものはKRにはなりません。

そうはいってもKRに具体的な話を書きたいんだけど…

「なお、OKR はチェックリストではありません。」ともあります。詳細はそこを読んでいただきたいのですが、あくまで「チームをどうしたか」を決める指針であり、具体的な内容を並べる場所ではありません。

まとめ

  • OKRで評価するのはやめましょう。
  • Oには大きな到達点、KRにはタスクではなく結果から見える数値指標を採用しましょう。
  • OKRのフォーマットが合わない場合はそこから外れても別にいいとは思いますが、その場合はOKRとは名乗らず「我々の手法」として利用しましょう。組織に合わせた適切なフォーマットを使用するのが一番です。