Slide 1

Slide 1 text

王岳宏 and 野澤聡史

Slide 2

Slide 2 text

2019年6月 入社 DeSC ヘルスケア システム部所属 SRE・インフラ サーバサイド 2018年12月 入社 DeSC ヘルスケア システム部所属 Tech Lead サーバサイド

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

● 保険契約者向けの健康増進サービス ● 楽しみながら、健康に。 ● 2019年6月に公開

Slide 5

Slide 5 text

● ハイブリッドアプリ ● フロントエンド・バックエンド分離 ● バックエンドはGo言語+マイクロサービス採用 ● 複数組織で複数マイクロサービスを運用ではなく ● 1つの組織で複数サービスをメンテナンス

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

● サーバー開発とインフラが別チーム ● インフラ作業は都度依頼 ● ● 開発とインフラ間の

Slide 9

Slide 9 text

● Polyrepoでサービス毎にリポジトリ作成 ● 一年間でリポジトリ数が20弱に到達 ● 担当者毎にアーキテクチャが異なる ● ( ) ● ● 言語とライブラリのバージョンアップ ● 新規作成時のCI/CDのセットアップ、etc...

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

● チームが推進した と ● Monorepoでマイクロサービス開発 ● 開発とインフラをOneTeamに ● 施策の背景や施策から得たもの

Slide 12

Slide 12 text

● 開発とインフラを に ● Polyrepoを に

Slide 13

Slide 13 text

● Monorepo ● Project Layout ● 起動とデプロイ ● 設計方針と開発ルール ● OneTeam ● チームのあるべき姿 ● 実現に向けた施策

Slide 14

Slide 14 text

Polyrepoで進むチームから生まれるレポジトリが増 大の一途を辿り、コードのメンテナンスには してい く状況の中で進めたMonorepoの経緯や施策の話。

Slide 15

Slide 15 text

● Monorepo = 1つのリポジトリ ● マイクロサービスを並行開発 ● 開発効率向上 ● 起動コマンド等の共通化 ● 統一性の担保 ● サービス作成方法を統一(自由度は許容)

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

alpide ├─ cmd/ ├─ eiger │ ├─ config/ │ ├─ e2e/ │ ├─ ... │ └─ internal/ ├─ manaslu │ ├─ e2e/ │ ├─ ... │ ├─ internal/ │ └─ pkg/ ├─ pkg │ ├─ log/ │ └─ ... ├─ .env.example ├─ ... ├─ Dockerfile ├─ Makefile ├─ go.mod ├─ go.sum └─ main.go alpide ├─ cmd/ ├─ config │ ├─ eiger/ │ └─ ... ├─ e2e │ ├─ eiger/ │ ├─ ... │ └─ manaslu/ ├─ internal │ ├─ eiger/ │ ├─ ... │ └─ manaslu/ ├─ pkg │ ├─ log/ │ └─ ... ├─ .env.example ├─ ... ├─ Dockerfile ├─ Makefile ├─ go.mod ├─ go.sum └─ main.go alpide ├─ cmd/ ├─ internal │ ├─ eiger │ │ ├─ config/ │ │ ├─ e2e/ │ │ └─ ... │ └─ manaslu │ ├─ e2e/ │ ├─ ... │ └─ pkg/ ├─ pkg │ ├─ log/ │ └─ ... ├─ .env.example ├─ ... ├─ Dockerfile ├─ Makefile ├─ go.mod ├─ go.sum └─ main.go

Slide 18

Slide 18 text

● 簡易に一括作業が可能 # Dockerfile COPY --from=builder /config /config alpide ├─ cmd/ ├─ config │ ├─ eiger/ │ └─ ... ├─ e2e │ ├─ eiger/ │ ├─ ... │ └─ manaslu/ ├─ internal │ ├─ eiger/ │ ├─ ... │ └─ manaslu/ ├─ pkg │ ├─ log/ │ └─ ... ├─ .env.example ├─ ... ├─ Dockerfile ├─ Makefile ├─ go.mod ├─ go.sum └─ main.go # Makefile unit-test: go test ./cmd/... ./internal/... ./pkg/... e2e-test: go test ./e2e/...

Slide 19

Slide 19 text

● cmd: 共通起動コマンド ● config: 設定ファイル ● e2e: E2Eテスト ● internal: 各マイクロサービス ● pkg: 共通ライブラリ alpide ├─ cmd/ ├─ config │ ├─ eiger/ │ └─ ... ├─ e2e │ ├─ eiger/ │ ├─ ... │ └─ manaslu/ ├─ internal │ ├─ eiger/ │ ├─ ... │ └─ manaslu/ ├─ pkg │ ├─ log/ │ └─ ... ├─ .env.example ├─ ... ├─ Dockerfile ├─ Makefile ├─ go.mod ├─ go.sum └─ main.go

Slide 20

Slide 20 text

● サービス開発しながら追加とリファクタを継続 ● internal/*/pkg -> pkg に移管 alpide ├─ internal │ └─ himalaya │ └─ pkg │ └─ lock/ └─ pkg ├─ cache/ ├─ crypto/ ├─ logger/ ├─ ... └─ validation/ alpide ├─ internal │ └─ himalaya └─ pkg ├─ cache/ ├─ crypto/ ├─ lock/ ├─ logger/ ├─ ... └─ validation/

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

● 共通コマンドでサービスを起動 ● 共通Docker Imageでサービスをデプロイ ● モノリシックとして起動する選択肢も可能

Slide 23

Slide 23 text

● 入り口は main.go ● サービス登録 ● main()で起動 // main.go package main import ( "***/alpide/cmd" // register services _ "***/alpide/internal/eiger/cmd" _ "***/alpide/internal/manaslu/cmd" _ ... ) func main() { cmd.Execute() }

Slide 24

Slide 24 text

● main.goで、1つの実行ファイルをビルド ● Dockerfileで、1つのDocker Imageをビルド # Dockerfile # ... RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \ -ldflags='-w -s -extldflags "-static"' -a \ -o /app ./main.go # ... COPY --from=builder /app /app # ... ENTRYPOINT ["/app"]

Slide 25

Slide 25 text

● サービス名でサービスを独自に起動 # start service manaslu $ /app manaslu

Slide 26

Slide 26 text

● サービス名+コンポーネント名でサービスの一部 を起動 # start only web server $ /app manaslu web-server

Slide 27

Slide 27 text

● 全サービスの起動が可能 # start all services as monolithic $ /app all

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

● サービス名 ● 起動時の初期化処理 ● 零 OR 複数のサーバー ● 零 OR 複数のバッチ ● サーバー数 + バッチ数 > 1 type Service struct { Name string InitFunc func(context.Context) error Servers []Server Batches []Batch }

Slide 30

Slide 30 text

● サービス名で全サーバーを起動 # start all servers of service himalaya $ /app himalaya # k8s manifest containers: - name: himalaya command: ["/app"] args: ["himalaya"]

Slide 31

Slide 31 text

● サーバー名 ● 起動時の初期化 ● 起動と停止が可能 type Server struct { Name string InitFunc func(context.Context) error IServer IServer } type IServer interface { Start(context.Context) error Shutdown(context.Context) error }

Slide 32

Slide 32 text

● サービス+サーバー名で起動 # start web server of service himalaya $ /app himalaya web-server # start worker of service himalaya $ /app himalaya worker # k8s manifest kind: Deployment spec: replicas: 5 template: spec: containers: - name: himalaya-web args: ["himalaya", "web-server"] --- kind: Deployment spec: replicas: 3 template: spec: containers: - name: himalaya-worker args: ["himalaya", "worker"]

Slide 33

Slide 33 text

● バッチ名 ● 起動時の初期化 ● 起動と中断が可能 ● CLIパラメーター対応 type Batch struct { Name string InitFunc func(context.Context) error IBatch IBatch } type IBatch interface { Start(context.Context, *cobra.Command) error Interrupt(context.Context) Customize(*cobra.Command) // cli args }

Slide 34

Slide 34 text

● サービス名+バッチ名+CLIパラメーターで起動 # start batch export of himalaya $ /app himalaya export --opt whatever # k8s manifest kind: CronJob # ... spec: jobTemplate: # ... spec: containers: - name: himalaya-batch-export args: ["himalaya", "export", "--opt whatever"]

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

● ドメイン駆動設計(DDD)のBounded Contextでマ イクロサービスの境界を決める ● 依存性逆転原則(DIP)でレイヤー化アーキテク チャを採用 ● アーキテクチャの多様性・実装の自由度を持たせ たい ● 厳格なルールは強制しない

Slide 37

Slide 37 text

● 四層Layer ● 依存逆転 ● 共通処理利用 の最大化

Slide 38

Slide 38 text

● コードレビュー必須 ● E2Eテスト必須 ● カバレージ原則70%以上 baker: 77.6% chiroro: 83.9% denali: 63.1% eiger: 55.5% hiyori: 79.5% ibuki: 81.3% kailas: 78.2% manaslu: 74.0% meru: 77.8% otake: 76.8% pumori: 79.0% rainier: 74.5%

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

● 初めからマイクロサービスの選択で疲弊 ● 初期はモノリシックのデプロイが望ましい ● 要件やドメイン理解の成熟に応じてマイクロ サービスの分割を検討

Slide 41

Slide 41 text

● 開発時には複数の開発メンバーが並行してマイク ロサービスを作成 ● デプロイ時に要件・状況に応じてモノリシックに デプロイするか選択が可能

Slide 42

Slide 42 text

No content

Slide 43

Slide 43 text

● ● マイクロサービスとして効率良く並行開発 ● メンテナンスコストが下がる ● モノリシックなデプロイの選択が可能 ● 共通認識と理解を得た ●

Slide 44

Slide 44 text

● デグレードの可能性 ● 自動化テストで保証 ● ブランチ・リリースバージョン管理の混乱 ● 複数ライン開発でバージョンがバッティング ● 稀に発生するが現状は運用でカバー

Slide 45

Slide 45 text

● monorepoでマイクロサービスの開発実践 ● 開発効率向上、統一性と多様性の両立 ● マイクロサービス ANDOR モノリシック

Slide 46

Slide 46 text

Monorepoに舵を切ったチームがマイクロサービス の課題解決を ために分断されていた チームを にするまでの経緯や施策の話。

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

● GKE ● Istio(OSS) ● CircleCI, Flux ● GitOps ● IAM Role for Service Accounts

Slide 50

Slide 50 text

No content

Slide 51

Slide 51 text

● サーバ開発とインフラ・SREのチームが分断 ● 分断により様々な弊害が生じていた

Slide 52

Slide 52 text

No content

Slide 53

Slide 53 text

● デプロイオペレーションに対する ● 過度な運用作業の分担による ● 互いの領域は ● や が頻出

Slide 54

Slide 54 text

● コミュニケーションの不足 ● オーナシップの欠如 ● 心理的障壁

Slide 55

Slide 55 text

● 、 されている ● サーバー開発とSRE・インフラが ● 互いの が自然発生している ● あるべき姿から

Slide 56

Slide 56 text

No content

Slide 57

Slide 57 text

● 掲げたVisionは ● 担当技術領域の分断を ● ○○担当や☓☓担当の廃止

Slide 58

Slide 58 text

● 主体的にサービスを開発できる ● 安全にインフラリソースをセットアップできる ● 特殊な操作を必要とせず本番デプロイできる ● これら ことが理想

Slide 59

Slide 59 text

● オーナーシップを持つ( ) ● を担保したコミュニケーション ● 技術領域を超えた成果( ) ● を体現 DeNA QualityはDeNAのミッション・ビジョンを参照 https://dena.com/jp/company/policy/

Slide 60

Slide 60 text

No content

Slide 61

Slide 61 text

● インフラ領域に苦手意識がある開発メンバーが技 術領域を広げられる環境を整える必要があり迎え 入れるオーナーとしての心構え ● 自身もサーバ開発に入り対面の課題を知る ● 技術領域を超える際の ● メンバーが領域を超える際のストレスを軽減し、

Slide 62

Slide 62 text

● ストレスの軽減 ● 反復なオペレーションの廃止 ● 自動化の仕組みの導入 ● 心理的障壁を下げる ● 苦手意識の排除 ● チームの開発状況の検知を容易にする

Slide 63

Slide 63 text

No content

Slide 64

Slide 64 text

● デプロイ手順の属人排除 ● リリースオペレーションの自動化 ● Pull Requestのストレス軽減と簡略化 ● ローカル開発環境の共有化 ● インフラリソース管理の品質担保

Slide 65

Slide 65 text

No content

Slide 66

Slide 66 text

● Slack BotでChatOps ● ● GitOpsのサポート ● コンテナイメージ差替のPullRequest作成 ● リリースとデプロイのオペレーションのサポート ● リリースバージョンの成果物作成 ● コンテナイメージとリポジトリのタグ切り

Slide 67

Slide 67 text

No content

Slide 68

Slide 68 text

● 運用オペレーションの効率改善に寄与 ● ● 履歴の蓄積 ● 開発状況が検知可能 ●

Slide 69

Slide 69 text

No content

Slide 70

Slide 70 text

● Monorepoの成長 ● Bounded Contextの増加 ● Contextのオーナーが不明瞭 ●

Slide 71

Slide 71 text

● CI/CDシステム ● KubernetesやIstioのレポジトリなどで導入 ● 主にPRにおいて自動化機能を提供 ● chat-opsを用いたオペレーション ● 自動マージ ● ○

Slide 72

Slide 72 text

● OWNERS filesを整理 ● ● PR作成時に自動でアサイン ● アサイン機能以外にも便利機能がある ● ex) ラベル付与、サイズ通知 ● カスタマイズ可能

Slide 73

Slide 73 text

No content

Slide 74

Slide 74 text

● MonorepoのPRストレス解消 ● OWNERS files定義による効果 ● ● Context理解が進むとReviewerにアサイン ● ●

Slide 75

Slide 75 text

No content

Slide 76

Slide 76 text

● ● 複数サービス起動のストレス ● サービス間通信を確保する難易度 ● サーバ開発メンバーの心理的障壁 ●

Slide 77

Slide 77 text

● Docker DesktopのKubernetes clusterを導入 ● Deploymentsフォルダにリソースを配置 ● デプロイスクリプトを整備 ● Skaffoldでローカルクラスターにデプロイ ● サンドボックスのGCP環境を配備

Slide 78

Slide 78 text

● ● 開発環境と差異のないサービス間通信を実現 ● Kubernetesリソースの ● ローカル開発からリソース整備を意識 ● ローカルからDev環境へのデプロイがスムーズ ● サンドボックスのGCP環境で知見を貯められる

Slide 79

Slide 79 text

No content

Slide 80

Slide 80 text

● 設定したリソースの過不足 ● ex) CPU/Memory limitの不足 ● レビュー時の確認漏れ ● ex) trueのクォーテーション付け漏れ ● デプロイ後にエラー発生 ● リソース不備が発覚 ●

Slide 81

Slide 81 text

● Kube-scoreとKubevalのlinterを導入 ● zegl/kube-score, instrumenta/kubeval ● CIのstepにlintを追加 ● デプロイ前にリソース不備が検知可能

Slide 82

Slide 82 text

● 品質担保に寄与 ● 運用の心理的障壁を下げる効果

Slide 83

Slide 83 text

No content

Slide 84

Slide 84 text

● OneTeam体制の過渡期 ● 人員とプロダクト規模から最適判断と評価 ● チームの指針が明確になり ● 人材の入れ替えに対応できる柔軟性を担保 ●

Slide 85

Slide 85 text

● がチームを成長させる ● 相互理解・信頼を得てアクションを実行 ● ● チーム力の底上げには不可欠 ● ことが大事 ● 下げる方法は ● 技術的アプローチ以外の施策も多かった

Slide 86

Slide 86 text

● OneTeamの実現には技術アプ ローチ以外の施策も多い ● コロナ禍も重なり が必要に ● チームビルドの詳細はメン バー執筆のブログを参照 https://engineer.dena.com/posts/2021.01/kencom-h oken-team-building/

Slide 87

Slide 87 text

No content

Slide 88

Slide 88 text

● 初期のPolyrepoやチーム分離は我々のサービスに は合わず課題に向き合うことでMonorepoと OneTeamの最適な選択ができた ● 課題解決から得たものは大きい ● 開発と運用効率 ● 品質とコストのバランス ● 継続すべきチームの指針

Slide 89

Slide 89 text

No content