Sionの技術ブログ

SREとして日々の学習を書いて行きます。twitterは@sion_cojp

プロゲーマーのマネージメントとチームワーク

本記事は、FOLIOアドベントカレンダーの11日目の記事になります。

はじめに

ゲーマー時代に培ったマネージメントやチームワークは仕事にも当てはまることが多いと感じます。

私は様々なプレイヤーを指導したりリーダとして率いることが多かったので、ゲーマー時代に自分がどう行動してたか + それを仕事に照らし合わせて雑多に書いてみたいと思います。

自己紹介

私はCS1.6 (Counter Strike 1.6)の2012年アジアチャンピオンになった者です。

このゲームは私が高2のときくらいからやってました。

いろんなチームを渡り歩き、大半はリーダーとしてチームを指揮したりマネージメントする役目をやってました。

otya-milk.blog.jp

このCLARING STYLEが私本人です。

CS 1.6とは?

f:id:sion_cojp:20181210204710p:plain

現在だとCS:GO(Counter Strike Global Offensive)が後継のバージョンになります。

FPSというジャンルで、5 vs 5の銃で打ち合う戦い。

1:45sの間に、テロリストがC4(プラスチック爆弾)を所定の場所に爆破するか、どちらか壊滅させたら1round終了。

合計16ラウンド先に取ったら勝利です。

この1:45sという時間が恐ろしく短く、めまぐるしく考えを働かさないと一瞬で負けてしまうのがこのゲームの楽しさです。

本題

メンバーを適したポジションに配置する

f:id:sion_cojp:20181210215555p:plain:w220

スナイパー、仲間をフォローする、最後まで生き残るc4を運んで設置する....など様々なポジションがありました。

まずはチームメンバーにやりたいポジションを聞き、できる限り反映させます。

理由は、やりたいポジションを任せた方が責任感が生まれるからです。

その上で、個人の特徴を生かして「こういう役割、動き方をして欲しい」と伝えたり、ポジショニングの指導をします。

仕事に対してもやりたいことをさせたほうが責任感が生まれます。

その上で「こういうことをして欲しい」と伝えると本人もやる気になってくれるでしょう。

最高は「言わなくてもそのポジションを理解して勝手に行動してくれる」です。

報告はできる限りシンプルかつ明確に

f:id:sion_cojp:20181210220848p:plain:w220

よくある初心者の場合だと、「撃たれてる!いてて!なんか遠くで撃って来てる」とかですかね。

この報告を聞いて味方はどうすればいいか分からないですよね。

例えば、「階段に2人いた」という報告は重要なのか?という議論をよくしました。

結論は、「重要ではない、があると嬉しいかも」です。

敵がここから攻めてくるか引くのか分からない報告だからです。

ベストは「1人カバーに来て欲しい」。これなら敵がどうしようが、仲間がどうして欲しいかわかるので行動しやすいです。

このように指示と行動がシンプルかつ明確になってるほど、お互いが連携しやすいです。

これは仕事や特に障害対応、ドキュメント(手順書)で言えることですね。


ちなみに、最初の問いですが、さらにベストの「何も言わなくても100%伝わる」を私たちは目指してました。

報告に感情は不要

f:id:sion_cojp:20181210220210p:plain:w220

あるあるだと「くっそ!あいつむかつくわ!うぜー!」とかですかね。

この報告を聞いて味方は....ry

「報告に感情は不要だ」と私はよく指導してました。

怒らない

f:id:sion_cojp:20181210215839p:plain:w220

怒っても何も解決はしません。

私自身若い時はよく怒ってました。が、この結論に至りました。

(精神を保つために、「自分が5人倒さなかったから負けた」と言い聞かせたりしてました)

よくあるよねーってスルーしたり、「なぜそうなったのか?」「そういう行動をしてしまったか?」というのを議論しあい解決に導くのが最善です。

「なんで言ったのに理解できないの?」 -> 難しいよね〜、また教えるね

「なんで何回も同じ場所でミスるの?」 -> 何か原因ある?違う方法だとミスらない?

といった感じ。

あえて失敗させる

f:id:sion_cojp:20181210220017p:plain:w220

上の議論しあってるときに、意見がまとまらない場合があります。

例えばあるポイントに投げるグレネードが絶対必要だ、必要じゃないなど。

その場合は全部やるのが筋です。そこで失敗を経験してなぜ失敗したのかを理解します。

そうしないと実践で応用ができないからです。

またあえて失敗させる誘導をすることもあります。

そうしないと理解ができないからです。

(今の子たちはペヤングを一度もこぼすことはないでしょうし、その事実を知らないでしょう)

失敗は大事な糧なので、出来る限り失敗出来る時にいっぱい失敗させるチームにしてました。

讃え合う

f:id:sion_cojp:20181210215924p:plain:w220

先ほど報告に感情は...と言いましたが、1killとった時の「ナイス」などの賞賛は大事です。

理由はその場の雰囲気、士気がよくなるからですね。人間味ありますね。

slackやPRでいう :thumbsup: だと思ってます。

ルールはシンプルに最小に

f:id:sion_cojp:20181210223534p:plain:w220

日本人はガチガチの作戦で固めてくるチームが多かったのですが、それが4人以上限定とかグレネードの個数限定だったりしました。

敵の奇襲で3 vs 3とかになってしまうと、誰も次の行動を考えれなくなって時間切れになったりします。

私たちのチームは、作戦を設けず、自分たちで考えて行動させました。

その方が敵のアクションに柔軟に対応できます。

その場で、「こうしてここを攻めよう」と誰かが作戦を発言して行動を起こします。

またそこでのルールとして、「指揮官のいうことが絶対。それ以外は早めに言ったやつを優先」というルールでした。

「で、誰のを従うの?」っていうコミュニケーションコストの発生を避けたかったからです。


状況は一番メンバーがわかってます。仕事もそうですが、ルールを最小限にし、メンバーに権限を委ねた方が、スピーディーにスムーズに事が進みます。

自分たちで考えさせる

f:id:sion_cojp:20181210220059p:plain:w220

最高は「言わなくてもそのポジションを理解して勝手に行動してくれる」です。

少数精鋭の場合、マネージメントなんてない方が最高です。

彼ら自身が言葉を交わし合い、共通の目標に向かって行く方がベストです。


仕事でも少数精鋭の場合はマネージャーがいかにセルフマネージメント出来るようになるか、ポイントを指摘していくのが良いかと思います。

全体的に見渡すレベルを目指す

f:id:sion_cojp:20181210221044p:plain:w220

まずメンバーより下の実力だとダメです。「おれより弱いやつが」と言われたら終わりです。

(それ以上の何かしら尊敬の念があれば問題はない)

仕事でいうと、エンジニアなのに勉強することをやめたり、プログラム書く事を諦めてる人は部下に舐められる可能性が高いです。


次に、メンバーと同じ目線だと、いつまでも実力が水平です。

これではさらなる高みは目指せません。


私は全体を見回して、このチームがどうなったら強くなるかを考えてました。

例えばBサイドが抜かれやすかったらBサイドの研究をします。

それはBサイドのメンバーも研究してると思いますが、彼らは「連携や練習」という私より余分な時間が発生します。

その間に海外の動きをチェックし、良いものがあれば「このチームこういう動きをしてたから取り入れてもいいかもよ」と伝えることができます。

あとはプロフェッショナルな彼らに任せればいいです。そして存分に高みを目指してもらいましょう。

信頼する、言い過ぎない

f:id:sion_cojp:20181210221535p:plain:w220

例えば、「Flash Bomb欲しい」と言って、くれなかったとき。仲間は敵と交戦してるかもしれないです。

状況は仲間にしかわかりません。

Flash Bomb欲しい」を5回くらい連呼されたら相手も「わかってるようっせーな!交戦してんだよ!」ってなるでしょう。

フラストレーション貯めるのは色々と支障が出ます。

出来る限りフラストレーションためないよう言い過ぎないように、相手を信頼して待ちましょう。

待つのは不安になったり、精神辛かったりしますが、我慢ステータスを身につけましょう。

待った上でチームが議論し、それでもうまくいかない場合はリーダーが一言指摘しましょう。

時間を決めて練習する

f:id:sion_cojp:20181210231825p:plain:w220

時間を決めないとダラダラとやります。また長時間やらないように気をつけます。

事前に伸ばしたいポイントを決めておいて、短い時間で、サクッと練習する方が身になります。

仕事でいう、残業はもちろん、短時間で集中したほうがいいよね。というお話です。

最後に

リーダーはいいチームを作るための一つです。

もちろんメンバーもいてこそです。

お互いが尊敬しあい同じ目標に行くのはゲームの世界も仕事の世界も同じだなと思います。

FOLIOモバイルアプリのインフラ構成のお話

明日、弊社で SRE Lounge #6 - connpass というイベントがあるのですが、 残念ながら登壇する枠がないのでスライドだけ公開しました。

世間体ではGKEのお話が多い中、Fargateのお話です。

Fargateはクラスタの管理が不要な分、とても楽に運用出来て結構幸せだったりします。

当日興味がある方は是非お声がけください〜。

speakerdeck.com

clairでローカルのDockerイメージの脆弱性スキャン

clairとは?

github.com

CoreOSが作ってる、コンテナの脆弱性スキャンツールです。

CVEデータをpostgresに入れて(定期更新される)、それを元にスキャンします。

ローカルイメージをスキャン

github.com

CoreOSが提供してた、analyze-local-imagesはdeprecatedだったので、

https://github.com/arminc/clair-scanner を使って、ローカルのイメージをスキャンしてみました。

実行

# clair-scannerをインストール
$ make clair-scanner/install

# clairサーバとpostgresを起動
$ make clair/run

# 起動してから10 ~ 20分くらいでCVEデータが更新されます。それまで待機
# postgresに入ってるCVEデータの量を見たいときは
$ make check

# golang:1.10をスキャン
$ docker pull golang:1.10
$ make run IMAGE=golang:1.10
clair-scanner --ip=host.docker.internal golang:1.10
2018/10/04 14:53:39 [INFO] ▶ Start clair-scanner
2018/10/04 14:53:59 [INFO] ▶ Server listening on port 9279
2018/10/04 14:53:59 [INFO] ▶ Analyzing 4f68522e312f5f12340e4b9559e71bba43ef929a10efc9ea6b67b4ff33bfb82e
2018/10/04 14:54:02 [INFO] ▶ Analyzing f56aeae9371b6c04ca4cf57a326b42de8c0d08a5fdebb26ef6b8df324337ea72
2018/10/04 14:54:02 [INFO] ▶ Analyzing 66f389e10325cd0c5f124eba8c5e9b57a9d490a5ddfa02a38f92686d04bda898
2018/10/04 14:54:03 [INFO] ▶ Analyzing 070ca363ac71db895b70015f3c83a1b09a42e74a52b9afdddd15e8aab4dd4a4a
2018/10/04 14:54:06 [INFO] ▶ Analyzing 13d63372391595f4c4086f342f2d0205542ba4530ec95fb8bd069bc7a19dea5e
2018/10/04 14:54:10 [INFO] ▶ Analyzing bf50139cdff0a2429fdf26ed2464b30ec6c88adf24d973ac5a6ed046283ee397
2018/10/04 14:54:20 [INFO] ▶ Analyzing b16a12b1f36856e47d3cea6f2141b970f4b383c6b5302189b3dd452ce9389af9
2018/10/04 14:54:20 [WARN] ▶ Image [golang:1.10] contains 288 total vulnerabilities
2018/10/04 14:54:20 [ERRO] ▶ Image [golang:1.10] contains 288 unapproved vulnerabilities

+------------+-----------------------------+-----------------+-----------------------+--------------------------------------------------------------+
| STATUS     | CVE SEVERITY                | PACKAGE NAME    | PACKAGE VERSION       | CVE DESCRIPTION                                              |
+------------+-----------------------------+-----------------+-----------------------+--------------------------------------------------------------+
| Unapproved | High CVE-2018-6485          | glibc           | 2.24-11+deb9u3        | An integer overflow in the implementation of the             |
|            |                             |                 |                       | posix_memalign in memalign functions in the GNU C Library    |
|            |                             |                 |                       | (aka glibc or libc6) 2.26 and earlier could cause these      |
|            |                             |                 |                       | functions to return a pointer to a heap area that is         |
|            |                             |                 |                       | too small, potentially leading to heap corruption.           |
|            |                             |                 |                       | https://security-tracker.debian.org/tracker/CVE-2018-6485    |
+------------+-----------------------------+-----------------+-----------------------+--------------------------------------------------------------+
| Unapproved | High CVE-2018-1000001       | glibc           | 2.24-11+deb9u3        | In glibc 2.26 and earlier there is confusion in the          |
|            |                             |                 |                       | usage of getcwd() by realpath() which can be used            |
|            |                             |                 |                       | to write before the destination buffer leading to            |
|            |                             |                 |                       | a buffer underflow and potential code execution.             |
|            |                             |                 |                       | https://security-tracker.debian.org/tracker/CVE-2018-1000001 |
+------------+-----------------------------+-----------------+-----------------------+--------------------------------------------------------------+

まだまだCVEの詳細な情報が流れてくるが、量が多いため割愛します

# clairサーバのログが見たいときは
$ make tail

# clairサーバとpostgresのコンテナ削除
$ make clair/rm

所感

プロダクトに入れる前には脆弱性スキャンしたほうが良いですね。

High/Medium/Low/Negligible/Unknown で区別してくれるので、最低でもHighはチェックしましょう。

また、clair-scannerは -w でwhitelist指定出来るみたいなので、自前でwhitelistを持ってると良いかもですね。

ただこれらもイメージpush先のリポジトリ側でスキャンされるのが理想であり、デファクトスタンダードになるでしょう。

GCRはα版がすでに提供されており、ECRもいずれ自動でスキャンして通知してくれるでしょう。

ディレクトリ配下にある.tfファイル全てにterraform planをGoで並列実行する

FOLIO特有のロジックが入ってますが、参考になればと思います。

terraformのディレクトリ構成

FOLIOのterraformはこんなディレクトリ構成になってます。(一部抜粋)

── envs
   ├── mobile-prod
       ├── provider.tf       
       ├── ecs
       ├── iam
       ├── route53
       └── vpc
          ├── backend.tf
          ├── provider.tf
          ├── route_table.tf
          ├── variables.tf
          └── vpc.tf
   ├── mobile-stg
   ├── sandbox
   ├── web-prod
   └── web-stg
── global.tfvars
── backend_tf_template

global.tfvarsは全体の変数定義。(CIDRやIPリストなど)

provider.tfは各環境内の設定です。(subnet_idなど)

planの実行

terraformのオペレーションはMakefileで管理されてます。

下記のコマンドで特定のディレクトリに対してplanが実行できます。

$ make plan CONFIG=envs/mobile-prod/vpc
# initializeした後、terraform plan -var-file=global.tfvarsを打ってるだけです

今回作ったもの

  • ディレクトリを再帰的に検索して、xxx.tfがある場所でmake planを並列実行する
  • backend.tfとprovider.tf以外が対象
  • 差分がある or 問題が起こったら出力する
    • 具体的には、 No changes. Infrastructure is up-to-date というワードがなかったら出力
  • -n で並列数を選べる
  • -tディレクトリ指定も出来る
  • 常に差分が発生するものに対しては、ignorePlanで除外出来る
    • (そんなに変更するものじゃないので、ハードコーディング)
$ ./check-all-plan --help
Usage of ./check-all-plan:
  -n int
        並列数 (default 20)
  -t string
        ターゲット。ex: -t mobile-stg

$ ./check-all-plan
check-all-plan: 2018/09/21 13:49:47 [INFO] Check start......
check-all-plan: 2018/09/21 13:52:37 [INFO] Result: you need check below
make plan CONFIG=envs/mobile-stg/kinesis
make plan CONFIG=envs/web-prod/elasticache
make plan CONFIG=envs/web-prod/teleport
make plan CONFIG=envs/web-stg/iam
make plan CONFIG=envs/web-prod/instances
make plan CONFIG=envs/web-stg/network
make plan CONFIG=envs/web-stg/kinesis

ソースコード

package main

import (
    "flag"
    "fmt"
    "log"
    "os"
    "os/exec"
    "path/filepath"
    "strings"
    "sync"
)

const (
    APP = "check-all-plan"
)

var (
    // parallelNum ... 適当に20並列にしてる。
    parallelNum = 20

    // target ... envs/mobile-stgのように、ターゲット単位で指定出来るようにしてる
    target string
)

// init ... set flag
func init() {
    flag.IntVar(&parallelNum, "n", 20, "並列数")
    flag.StringVar(&target, "t", "", "ターゲット。ex: -t mobile-stg")
    flag.Parse()
}

func main() {
    log.SetOutput(os.Stderr)
    log.SetPrefix(APP + ": ")

    os.Exit(Run())
}

// Run ... 実行
func Run() int {
    // 結果を格納するslice
    var results []string

    // skipするディレクトリ。必要だったら修正してね!
    ignorePlan := []string{
        "sandbox",
        "web-prod/apps",
        "web-stg/apps",
    }

    // planを実行するdirの取得
    targetDirs := GetDir("envs", ignorePlan)

    // default: 20並列
    var m sync.Mutex
    wg := &sync.WaitGroup{}
    semaphore := make(chan struct{}, parallelNum)

    log.Println("[INFO] Check start......")

    for _, targetdir := range targetDirs {
        wg.Add(1)
        semaphore <- struct{}{}
        go func(d string, m *sync.Mutex) {
            defer func() {
                <-semaphore
                defer wg.Done()
            }()
            out := RunTerraformPlan(d)
            if !strings.Contains(out, "No changes. Infrastructure is up-to-date") {
                m.Lock()
                defer m.Unlock()
                results = append(results, d)
            }
        }(targetdir, &m)
    }
    wg.Wait()

    log.Println("[INFO] Result: you need check below")
    for _, result := range results {
        fmt.Printf("make plan CONFIG=%s\n", result)
    }

    return 0
}

// RunTerraformPlan ...make plan CONFIG=xxxxを実行する
func RunTerraformPlan(targetDir string) string {
    dir := fmt.Sprintf("CONFIG=%s", targetDir)

    // make plan打って差分 or 問題が起こったかを検知したいので、
    // ここではエラーハンドリングしない
    out, _ := exec.Command("make", "plan", dir).Output()
    return string(out)
}

// GetDir ...envs/配下の実行対象のディレクトリを取得する
func GetDir(parentDir string, ignorePlan []string) []string {
    var dirs []string
    err := filepath.Walk(parentDir, func(path string, info os.FileInfo, err error) error {
        if err != nil {
            return err
        }

        // 隠しディレクトリはskip
        if info.IsDir() && strings.HasPrefix(info.Name(), ".") {
            return filepath.SkipDir
        }

        // ignorePlanに書かれてるディレクトリ以下をskip
        for _, v := range ignorePlan {
            if info.IsDir() && path == fmt.Sprintf("envs/%s", v) {
                return filepath.SkipDir
            }
        }

        // backend.tfとprovider.tf以外のtfを持つディレクトリを抽出
        switch info.Name() {
        case "provider.tf":
            break
        case "backend.tf":
            break
        default:
            if strings.HasSuffix(info.Name(), ".tf") {
                dirs = append(dirs, filepath.Dir(path))
            }
        }

        return nil
    })

    if err != nil {
        log.Printf("[WARN] filepath.Walk: %s\n", err)
    }

    return getUniqueDirs(dirs)
}

// getUniqueDirs ...重複したデータを削除。targetが指定されてたら指定されたものだけをチョイス
func getUniqueDirs(src []string) []string {
    dst := make([]string, 0, len(src))
    m := make(map[string]bool)

    for _, s := range src {
        if _, ok := m[s]; !ok {
            m[s] = true
            // targetが指定されたら、指定されたものだけをappendする
            if target != "" {
                if strings.HasPrefix(s, fmt.Sprintf("envs/%s", target)) {
                    dst = append(dst, s)
                }
            } else {
                dst = append(dst, s)
            }
        }
    }
    return dst
}

terraform-provider-awsの開発からPRを出すまでの手順

github.com

些細ではありますが、出したPRがmergeされました。

開発方法よくわからないなぁ。と思う人が多いと思うので、私が実際に行ったことを書いて見ます。

開発方法

# go get。今回は本家で修正して試して、その差分をあとでfork先に適用する感じ。
# この二度手間めんどくさいときは、$GOPATH/src/github.com/terraform-providersにforkしたやつをgit cloneしたほうが良い
$ go get -u github.com/terraform-providers/terraform-provider-aws

# よしなに修正

# buildする
$ cd $GOPATH/src/github.com/terraform-providers/terraform-provider-aws
$ make build
# このときgofmtしろってエラーが出たらgoのバージョンが低い可能性があります
# 最新にしてまたやってみましょう

# buildしたものを利用する
# 既存のproviderを削除して自前のbuildをcopy。copyしたらinitを打つ
$ cd terraform-repository/xxxxx.tfファイルがあるところ
$ rm -f .terraform/plugins/darwin_amd64/*
$ cp $GOPATH/terraform-provider-aws .terraform/plugins/darwin_amd64
$ terraform init

# planとapply。global.tfvarsを設定してるバージョンです
$ terraform plan
$ terraform apply -var-file=global.tfvars

# debugログの出力。めっちゃ便利
# TF_LOGでloglevelが設定できます
# TF_LOG_PATHでファイルに出力できます(追加保存)
$ TF_LOG=1 TF_LOG_PATH='/tmp/terraform.log' terraform apply -var-file=global.tfvars

test

PR出す際に貼らないといけません。 結構な権限を持ったaccess_key, secret_keyが必要です。

# 移動してtest。TESTARGSに設定するのはmethod名。*で正規表現マッチが使えます
$ cd $GOPATH/src/github.com/terraform-providers/terraform-provider-aws
$ AWS_ACCESS_KEY_ID=xxxx AWS_SECRET_ACCESS_KEY=xxxx make testacc TEST=./aws TESTARGS='-run=TestFetchRootDevice*'
# このときgofmtしろってエラーが出たらgoのバージョンが低い可能性があります
# 最新にしてまたやってみましょう

FOLIOに入社して3ヶ月経ちました

SREとして担当してたモバイルアプリもリリース出来て落ち着いたので書いてみようと思います

FOLIO is 何?

f:id:sion_cojp:20180803152158p:plain

Fintech

[https://folio-sec.com/:title]

入社してやったこと

  • terraform操作周りのリファクタ

    • バージョンの統一
    • terraformを打つまでの認証周りや、providerの設定、ソフトウェアのアップデートなど自動化
    • makeで terraform xxxx を打てるようにした
    • applyログをs3に保存するようにした
  • terraform module作った

    • ECS ec2 type
    • fargate
    • ECS task scheduler
    • waf + cloudfront + s3のsorryサーバ
  • モバイルのインフラ構築、運用

    • サーバレス
    • infra: fargate, ALB, waf, cloudfront, ECR
    • logging: cloudwatch, lambda, kinesis stream/firehose, s3, elastic search(ロギングは同じチームの人が作ってくれました。最高)
    • monitoring: datadog(terraformで管理)
    • slack chatopsをGoで書いた(ossにしたい)
    • リリース前にSREと必要な関係者を読んで、SRE本のLaunchチェックリストをベースに構成やモニタリングなどの最終チェックを行なった
  • セキュリティ周り

    • SSMでの暗号化、復号化を積極的に使った
    • GoでtomlからSSMの復号化出来るようにした GitHub - sioncojp/tomlssm
  • fargateで色々サービス立てた

terraform周り

入社したとき、terraformを打つまでにいろんな障壁があることを経験したので、即座に自動化タスクに取り組みました。

前職の影響からか、makeで色々と出来るようにし、今ではその障壁がなくなりました。

make helpはこんな感じです。

f:id:sion_cojp:20180803142154p:plain

弊社で動かしてるansibleやpacker周りも自動化したいです。 が、ansibleに関してはそもそも無くす(減らす)動きをしていく気持ちです。

モバイルのインフラ構築にあたって

「まだsshしてるの?」「開発者が開発に集中」という気持ちで進めてました。

結果sshはしなくなったので、セキュアにもなりましたし、インフラ運用コストも下がって楽になりました。

chatopsや、エラーログやアラートなどもslackで対応出来るようになったのもgood。

今回初めてやったのですが、SRE本にも書かれてる Launchチェックリストを元に、構成や仕組みを一から全てチェックしました。

これで安全にリリース出来るよねという合意と、サービスにあまり携わらなかった人もシステム構成を把握出来た(非属人化への一歩)のは良かったです。

fargate

モバイルアプリ用APIは、EC2で行こうという話だったのですが、

それだと技術的進歩が望めないので、ECSを導入しました。

最初はEC2 typeで導入したのですが、途中でfargateが登場したので載せ換えました。

挙動、特にEC2 typeにはないオプション周りで悩まされた記憶があります。

運用と拡張しやすいようなterraform module構成を意識したので、すぐにfargate構成が出来るようになりました(今は4, 5サービスくらい動いてます)

ECS task scheduler

fargate対応してないので、やむなくEC2 typeでmodule化。

chatops

slack interactive componentsを使っており、Goで書かれてます。

auth周りも実装してるので、config.tomlのプロジェクト設定にある指定された人しかdeploy出来なくなってます。

モバイルアプリのメンテナンス画面切り替えもこちらでやってます。

f:id:sion_cojp:20180803140150p:plain

  • プロジェクトを選択
  • prod, stg...を選択
  • ブランチを選択
  • 最後にコミット番号などが出るので、OK or cancelを選択
  • deploy finish

最後に

Fintechなのに、スピード感もって新しいことが出来るいい会社だなぁと思いました。

個人としては運用しやすい、拡張しやすいコードを意識して出来たのとも良かったです。

(そのため、コメントを中心にドキュメント(README.md)や構成図(draw.io)を充実させた。)

インフラ周りが落ち着いたら、microserviceアーキテクチャの実装や、認証認可のサービス実装など色々やりたいですね。

tomlファイルをParameterStoreからdecodeするtomlssmを作った

github.com

GitHub - suzuken/yamlssm と同様にtomlでも出来るようにしました。

やってることは

  • AWS System Managerで、Parameter Storeでを設定する(例えばxxxという名前でsecure stringで設定します)
  • "ssm://xxxx" と書いてると、toml読み込み時にxxxの部分をdecodeする

使い方はREADMEにも書いてますが、下記のように使います

1. decode

package main

import (
    "fmt"
    toml "github.com/sioncojp/tomlssm"
)

type Config struct {
    User     string `toml:"username"`
    Password string `toml:"password"`
}

func LoadToml(c string) (*Config, error) {
    var config Config
    if _, err := toml.Decode(c, &config, "ap-northeast-1"); err != nil {
        return nil, err
    }
    return &config, nil
}

func main() {
    conf, err := LoadToml(`
username = "test"
password = "ssm://password"
`)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(conf)
}

2. tomlファイルを指定する

# config.toml
username = "test"
password = "ssm://password"
package main

import (
    "fmt"
    toml "github.com/sioncojp/tomlssm"
)

type Config struct {
    User     string `toml:"username"`
    Password string `toml:"password"`
}

func LoadToml(c string) (*Config, error) {
    var config Config
    if _, err := toml.DecodeFile(c, &config, "ap-northeast-1"); err != nil {
        return nil, err
    }
    return &config, nil
}

func main() {
    conf, err := LoadToml("config.toml")
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(conf)
}