Travis CIの設定用のTerraform providerを作った話
この記事はTerraform Advent Calendar 2019 の9日目の記事です。
私の所属しているSEQSENSEではTravis CIを主に利用しています。 CIサービスを使うにあたって、ビルドで使う環境変数やSSH鍵などの管理は課題の一つです。
一つ一つ手動で設定していってもいいのですが、リポジトリ数が多くなると
などの問題が発生したりします。 それを解決するためにTravis CIの設定をコードナイズして一括管理するためのTerraform providerを作成しました。
よかったら、使ってみてください! *1
使い方
これはオレオレprovider (正式名称はThird-party plugin) のため、バイナリをGitHubのReleasesから落として来る必要があります。
curlなんかを使ってCLIでインストールする場合はこんな感じでしょうか。
$ latest=$(curl -s https://api.github.com/repos/kamatama41/terraform-provider-unofficial-travis/releases/latest | jq -r ".name") $ os=$(uname | tr '[:upper:]' '[:lower:]') $ curl -LO https://github.com/kamatama41/terraform-provider-unofficial-travis/releases/download/${latest}/terraform-provider-utravis_${latest}_${os}_amd64.zip $ unzip terraform-provider-utravis_${latest}_${os}_amd64.zip && rm terraform-provider-utravis_${latest}_${os}_amd64.zip
インストール後、実際のTFファイルの書き方はこんな感じになっています。
# Configure the unofficial Travis Provider (utravis) provider "utravis" { base_url = "https://api.travis-ci.com/" token = "${var.travis_api_token}" } # Add an environment variable to the repository resource "utravis_env_var" "my-repo" { slug = "myuser/my-repository" name = "FOO" value = "bar" public = true } # Add a private key to the repository resource "utravis_key_pair" "my-repo" { slug = "myuser/my-repository" value = "${file("~/.ssh/id_travis_rsa")}" }
- プロバイダ名は
utravis
utravis_env_var
は環境変数を設定するためのリソースですpublic
フラグでTravisのコンソール上で表示するかどうかを指定できます (デフォルトはfalse)
utravis_key_pair
はSSH Keyを登録するためのリソースです。value
に秘密鍵の中身を指定します
注意
AWS Savings Plans メモ
AWSのSavings Plansのセミナーに参加してきたのでそのメモ。
Fargateに対しても割引が効いたりするし、インスタンスタイプの垣根が無いので*1、そろそろM6が出そうなので、M5のRI買うのやめとこうみたいなのが発生しないのがイイですね。
Savings Plansとは?
- AWSの計算リソース割引プラン、リザーブドインスタンス(RI)より柔軟性が高い
1時間あたりのコミットメント金額
に対して適用される- Compute Savings Plans と EC2 Instance Savings Plansがある
- 割引率は、インスタンスファミリー、Fargateによって違う(https://aws.amazon.com/jp/savingsplans/pricing/) ので、自分で計算するのは面倒。
- Recommendationsで直近 7 or 30 or 60 日の使用量をベースに推奨値を出してくれるので、それに従うのが良い
- 割引は一番安くなるように (割引率が高いものから順番に) 適用される
- RDSは対象外
*1:Compute Savings Plansの場合
Datadog LogsをCLIでtailするツールを作った
モチベーションとしては、Datadog LogsのWebコンソールはメッセージの全文が長いと全部表示されなかったり普通のtailと違って時間の降順に並んだりで微妙に見づらかったりするので、CLIでtail -f
コマンド感覚で見れて雑にgrepとかしたいと思って作りました。
インストール
Releases からバイナリをダウンロードしてパスを通してください。
あと多分 go get -u github.com/kamatama41/taildog
でもインストールできると思います。
使い方
まず、DD_API_KEY
と DD_APP_KEY
(application key) の2つの環境変数を設定する必要があります。DatadogのWebコンソールから取得してきてください。
全ログを追跡する
$ taildog
クエリで絞り込む
$ taildog -q "service:my-app"
一定期間のログを表示する (追跡はしない、 max 1000行)
$ taildog -q "service:my-app" --from 2019-07-10T11:00:00Z --to 2019-07-10T11:00:05Z
出力のフォーマットを変える
Goのtemplateのスタイルで記述します。使用できる項目はDatadogのLog Query APIのレスポンスのcontent
の内容に準拠します。 デフォルトは "{{.Timestamp}} {{.Host}} {{.Service}} {{.Message}}"
です。
$ taildog -q "service:my-app" -f "{{.Timestamp}} {{.Message}}"
注意
- 実際にログがインジェストされてからAPIで見れるようになるまで、微妙にタイムラグ (5~30秒くらい) があります。
- Log Query APIは300回/時間/組織のレートリミットがあるので*1、複数人で長時間使うとエラーになる可能性があります。
- 上記の理由からデフォルトで15秒おきにポーリングするようにしていて、そこまでリアルタイム性は高くないです。
よかったら使ってみてください〜!
*1:必要に応じで拡張はできるそうです
Mercari meetup for SRE Vol. 2 に参加してきた
データセンタープロジェクトの進捗って言うのが面白そうで抽選通ったので参加してきました。基本的には今自分が所属している小さいスタートアップでは直接的に参考になることはあまり無かったですが、こういうスケールの大きな話を聞くのは刺激になりました。その後の懇親会では負荷試験をどうやってするかと言うのをメインで話して、みんな「やりたいけど環境作るのが難しいよね」という感じで意見が一致しました。
Percona XtraDB Clusterに寄り添う @ichirin2501
Percona XtraDB Cluster を使ってMySQLのクラスタリングを一つのサービスに適用してみた話。
- ロードバランシングにProxySQLを使おうと思ったけどはまりポイントが多くてHAProxyに落ち着いた
- PXC5.7.16から5.7.17で10倍ぐらいの性能の差がある
- 移行後, DBのCPU使用率は2倍になったが、もともとのデッドロックを解消したら半分になった
- 将来的には社内RDSとして提供していく予定
Progress of Data Center Project @kazeburo
去年発表した自社DC (TC) のその後のお話
DockerのUbuntuコンテナでsystemdを動かす
TL; DR
- とりあえず
--privileged
をつける。つけないでいい感じで動かすのは大変そう。 - CentOSは公式でsystemd用のベースイメージを用意してくれているので、Ubuntuを使いたい人以外はそちらを使うのが良さそう
STOPSIGNAL SIGRTMIN+3
をつける
例
FROM ubuntu:18.04 RUN apt-get update \ && apt-get install -y \ openssh-server \ && rm -rf /var/lib/apt/lists/* RUN mkdir -p /var/run/sshd && chmod 755 /var/run/sshd ARG GITHUB_USER # ADD ubuntu user, and set password and public key ADD https://github.com/${GITHUB_USER}.keys /home/ubuntu/.ssh/authorized_keys RUN useradd -u 1000 ubuntu \ && usermod -s /bin/bash -G adm,sudo ubuntu \ && echo "ubuntu ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers \ && mkdir -p /home/ubuntu && chown -R ubuntu.ubuntu /home/ubuntu STOPSIGNAL SIGRTMIN+3 CMD [ "/sbin/init" ]
例えばこんな感じのDockerfileでSSHサーバをsystemd経由で起動しようとすると、想定どおりに動作していません。
(ubuntu
ユーザでコンテナにSSH出来ない)
$ docker build --build-arg GITHUB_USER=${GITHUB_USER} -t kamatama41-ubuntu-systemd-test . $ docker run -p 2222:22 -d --rm kamatama41-ubuntu-systemd-test 1faf7f57aabba3ccb935cbc3de84224f304021c87a31a7487164a2ac157e33b1 $ ssh ubuntu@localhost -p 2222 ssh_exchange_identification: Connection closed by remote host
docker runのときに --privileged
オプションを付けると想定通りの動きになります。
$ docker run -p 2222:22 -d --privileged --rm kamatama41-ubuntu-systemd-test f4adaea692edd55bdc059536cebe3b5aac03d842af33c0b902bb79ccb1251e3a $ ssh ubuntu@localhost -p 2222 Welcome to Ubuntu 18.04.2 LTS (GNU/Linux 4.9.125-linuxkit x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage This system has been minimized by removing packages and content that are not required on a system that users do not log into. To restore this content, you can run the 'unminimize' command. The programs included with the Ubuntu system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. ubuntu@f4adaea692ed:~$
とりあえず、テスト用途で動かす場合はこれで大丈夫そうですが、本番では使わない方が良いでしょう。ググった感じsystemdをnon-privilegedなUbuntuのコンテナで動かすのは結構大変そうです。
CentOSは公式でsystemd用のベースイメージを提供してくれているので、本番で使いたい場合はこちらを使うのが良いでしょう。
あと1点注意点として、systemdのコンテナを止めるときは SIGRTMIN+3 を使わないといけないようなので、 STOPSIGNAL
を変えてあげておきましょう。
GolangでForループの中でdeferしない
defer
はそれが定義された関数が終わったタイミングで実行されるので、forループでdeferを定義してしまうと、forループが終わって所属する関数が終わったタイミングで一斉に実行される。
package main import "fmt" func main() { for i := 1; i <= 5; i++ { println(fmt.Sprintf("Main %d", i)) defer closeResource(i) } } func closeResource(i int) { println(fmt.Sprintf("Close %d", i)) }
例えばこれを実行すると
Main 1 Main 2 Main 3 Main 4 Main 5 Close 5 Close 4 Close 3 Close 2 Close 1
こういう出力になる。これはDBコネクションなどの場合、リソースリークにつながるのであまりよろしくない。こういう場合はforのブロックを別関数に移すか、無名関数でラップするのが好ましい。
package main import "fmt" func main() { for i := 1; i <= 5; i++ { func() { println(fmt.Sprintf("Main %d", i)) defer closeResource(i) }() } } func closeResource(i int) { println(fmt.Sprintf("Close %d", i)) }
こうすれば、期待通りの結果になる
Main 1 Close 1 Main 2 Close 2 Main 3 Close 3 Main 4 Close 4 Main 5 Close 5
参考 go - `defer` in the loop - what will be better? - Stack Overflow