Slide 1

Slide 1 text

[EC2からKubernetes] 楽天ラクマのコンテナ化の歩み Aug 22nd, 2023 Morix Rakuma Development Section Rakuten Group, Inc.

Slide 2

Slide 2 text

2 ⾃⼰紹介 • 名前 • ⻄野 翔太(Morix) • 所属 • 楽天グループ株式会社 • ラクマ開発課 SREチーム • X(Twitter) • @morix1500

Slide 3

Slide 3 text

3 話すこと • どのようにコンテナ化を進めたのか • どんな⽅針でKubernetesを使っているのか

Slide 4

Slide 4 text

4 コンテナ化プロジェクトの概略 このような順序でプロジェクトを進めた。約3年かかった。 • 現状の楽天ラクマの課題の洗い出し・コンテナ化プロジェクトの発⾜ • 移⾏のための⽅針作成 • Kubernetesクラスタ作成 • アプリケーションの改修 • 負荷試験 • コンテナ移⾏

Slide 5

Slide 5 text

5 現状のラクマの課題の洗い出し 楽天ラクマのSRE・基盤開発チームの中⻑期⽬標を考えたときに、コンテナ化しないと難しい課題 があった。 • 検証環境が⾜りない • ⾔語やパッケージなどのバージョンアップがSREしかできない

Slide 6

Slide 6 text

6 コンテナ化プロジェクトの発⾜ ⼤⽅針としてコンテナをどのように運⽤していくかを決める必要があった。 楽天ラクマでは移⾏のしやすさを重視する必要があったので AWS EKSを使⽤してKubernetesを運⽤していくことを決めた。 AWS EKS: AWSのKubernetesコントロールプレーンのマネージドサービス

Slide 7

Slide 7 text

7 楽天ラクマのざっくり規模感 あまり公にできる情報がないのでざっくりの規模感だけ・・・ • EC2のそれなりのスペックのものが⼤体数百台 • 1⽇のトラフィックのトレンドには波がある • 以下のような構成のアプリケーションが複数ある Application LoadBalancer EC2 EC2 EC2 DB

Slide 8

Slide 8 text

8 移⾏のための⽅針作成 • Network • Namespace • RBAC • DNS • Pod • Ingress/LoadBalancer • Secrets • AutoScale • Logging • Monitoring • マニフェストの管理 • Dockerfileの管理 • ContainerRepository • CI/CD • Batch • ServiceMesh • Security • ClusterUpgrade 期間: 約4ヶ⽉

Slide 9

Slide 9 text

9 Network Nodeを配置するサブネットが使えるIPをなるべく多くなるようにした。 AWS EKSを使う場合にNetworkで考えないといけないことはIPの数が⼗分かどうか。 これはAWS EKSのPodのIPはVPCサブネットのIPをそのまま使⽤するから。 楽天ラクマでは当初、諸事情でCIDRが/20(IPが4096個)のVPCで構築していたが、負荷試験中にIPが 枯渇してしまいネットワーク設計を1からやり直した。

Slide 10

Slide 10 text

10 IPの枯渇 EC2はインスタンスタイプによってアタッチできるENI数とENI1つにつきいくつIPを利⽤できるかと いう制限がある。 例えばc5.4xlargeであればENIは8、ENI1つにつきIPは30個。 つまり1つのEC2で240IP使える。またENIが1つ付与されると30IP確保する。 負荷試験当時、Nodeを70台起動していたのだが 70 * 30IP * 1ENI = 2,100IP使っていた。 また1Nodeに2〜3のENIが付与されているものが多数だったので、VPCサブネットのIPを使い切って しまった。

Slide 11

Slide 11 text

11 Namespace クラスタは環境ごとに分けている。 • Development • Staging • Production 楽天ラクマではStagingの環境がたくさんある。Staging環境のクラスタ内はnamespaceで環境を分 けるようにした。 • staging1 • staging2 • ・・・

Slide 12

Slide 12 text

12 RBAC EKSではAWS IAM RoleとGroupを紐付けることが可能。 ざっくり以下のような権限を付与するようにした。 本番は事故防⽌のため特定の環境からしか接続できないようにしてある。 種別 Dev Stg Prd SRE Admin Admin Admin Engineer Admin 検証環境⽤NSのみ Admin ReadOnly

Slide 13

Slide 13 text

13 DNS EC2はENI1つにつきDNSクエリーは1,024パケット/秒までしかリクエストできない。 EKSはデフォルトでCoreDNSのPodが2つ起動しているが、⾃動でスケールしない。 DNSクエリーを実⾏するPodが増えるとこの2つのPodにアクセスが集中してしまい、いずれこの制 限に達してエラーになる可能性があった。 そのため2つの施策を導⼊した。 • dns horizontal autoscaler • node local dns

Slide 14

Slide 14 text

14 dns horizontal autoscaler これはCoreDNSのPodをNodeの数(またはCPUの数)によって増減してくれるもの。 実態は kubernetes-sigs/cluster-proportional-autoscaler。 以下のような計算式で必要なレプリカ数を算出し、Pod数を調整できる。

Slide 15

Slide 15 text

15 node local dns CoreDNSのPodが増減するとPodを削除する際にそのPodが処理しているDNSクエリーが失敗してし まう問題があった。 これを解決するためにDNS結果をキャッシュするために node local dnsを導⼊した。 引⽤元: https://kubernetes.io/docs/tasks/administer-cluster/nodelocaldns/

Slide 16

Slide 16 text

16 Pod Podに対しても様々な⽅針を決めた。 • ラベル付与ルール • デプロイ戦略 • リソース要求・制限 • Probe • コンテナ終了順序 • 配置戦略

Slide 17

Slide 17 text

17 ラベル付与ルール 当初Podに対するラベルの付与ルールを作っておらず、PDBのLabelSelectorで複数Deploymentの Podがマッチしてしまい、PDBが正常に動作しないという事象が発⽣した。 そのためPodでラベルが⼀意になるようにルールを設定した。 種別 Label1 Label2 Webアプリケーション app: アプリ名 type: web ⾮同期アプリケーション app: アプリ名 type: event Batch app: アプリ名 type: batch

Slide 18

Slide 18 text

18 デプロイ戦略 Deploymentで使えるデプロイ戦略といえばRollingUpdateだが、いままでの運⽤上新旧Podが同時 にユーザーに公開されると不具合が発⽣する可能性があった。 そのためアプリケーションによってデプロイ戦略を変更するようにした。 • Webアプリケーション • BlueGreenDeploy(Argo Rolloutsを使⽤) • ⾮同期アプリケーション • Recreate

Slide 19

Slide 19 text

19 リソース要求・制限 楽天ラクマのKubernetesクラスタには⾃分たちのアプリケーションしか載らないことを前提に以下 の⽅針でリソース要求・制限をつけるようにした。 • requests • cpu: 必須。コンテナを動かすために必要なCPU量を指定する。低すぎてはダメ。 • memory: 必須。コンテナを動かすために必要なメモリ量を指定する。余裕を持った数値にする。 • limits • cpu: 不要。 • memory: requests.memoryと同じ値にする。 詳しくは記事にしてるので読んでほしい。 KubernetesのPodのResource設定の考え⽅ https://qiita.com/Morix1500/items/8e9e6f6a86ece5a1c98e

Slide 20

Slide 20 text

20 ディスクサイズ制限 Podのリソース要求・制限ではストレージに対してディスクサイズ制限を設けることができる。 楽天ラクマの⼀部コンテナはログをファイルで出⼒している。 放っておくとPodが持つログファイルが肥⼤化しNodeのディスク使⽤率増⼤に繋がってしまう。 ログローテートを実装するのではなく、このディスクサイズ制限を使うことでディスクを⼀定量 使ったらPodをEvictするようにした。

Slide 21

Slide 21 text

21 Probe 外部からトラフィックがあるようなPodはProbeの導⼊を必須にした。 • readinessProbe • Podがトラフィックを受けることが可能かどうか監視するもの • NginxとRailsコンテナがある場合、どちらも通るパスをこのProbeに設定する • そのためPod内のいずれか1つのコンテナにこのProbeがあればいい • livenessProbe • コンテナの死活監視を⾏うもの • すべてのコンテナに設定する • startupProbe • 起動が遅いコンテナで使⽤する

Slide 22

Slide 22 text

22 コンテナ終了順序 楽天ラクマのPodは複数のコンテナで構成されているので、コンテナの終了順序は重要になってい る。 これらをライフサイクルのpreStopを使⽤して終了順序を制御している。 またPodを安全に終了するためにpreStopでSleep処理を⼊れるのを必須にしている。

Slide 23

Slide 23 text

23 配置戦略 Podをどこにどのように配置するのかをそのPodの性質によって決めている。 たとえば通常のWebアプリケーションであれば • ZoneごとにPodを分散配置する • HPAで⾃動スケールさせる • PDBで最低台数を保証させる 簡単に終了してほしくないコントローラーPodであれば • オンデマンドインスタンスに配置する • 2PodをZone/Nodeごとに分散配置する • PDBで最低台数を保証させる

Slide 24

Slide 24 text

24 Ingress/LoadBalancer Ingressを扱うコントローラーはどうするのか、またNodeの前段に配置するLoadBalancerをどう⽤ 意するのか検討した。 Podのデプロイ戦略上、ArgoRolloutsを使うことになっていたのでそれと組み合わせて使えたり、今 後のServiceMesh導⼊も考え、Istio IngressGatewayを使うことにした。 またIngressリソースからAWS ALBを⽣成することも可能だったが次の利⽤でしなかった。 • ALBの機能でドメイン・パスごとに重み付けルーティングが可能なので、それを使いKubernetes バージョンアップの際に古いクラスターから新しいクラスターに移⾏する⽅針のため、クラス ターでロードバランサーリソースを作っては困る • 基本的にインフラリソースはTerraformで構築していたので統⼀したかった

Slide 25

Slide 25 text

25 AutoScale NodeのオートスケールはClusterAutoscalerを導⼊した。 PodはHPAでオートスケールさせる。 Podを増やす際にNodeが⾜りずNodeのスケールアウトとなった場合、スケールするまで時間がか かってしまう。 それを防⽌するためにオーバープロビジョニングの仕組みを導⼊している。 Kubernetesで常に余剰Nodeを確保しPodのスケールアウトの低速化を防ぐ「オーバープロビジョニ ング」について https://qiita.com/Morix1500/items/5ea47755bb04f6b08a2a

Slide 26

Slide 26 text

26 Logging ログはGoogleCloudのCloudLoggingに集約している。 楽天ラクマではログの出⼒⽅法は⼤きく2パターンあり、それによって収集⽅法を変えている。 • 標準出⼒・標準エラー出⼒ • このタイプのログはNode上にログがファイルとして出⼒されているので、それを読み込み CloudLoggingに送信するためのFluentd DaemonSetPodがいる • ファイル出⼒ • 楽天ラクマのアプリケーションはログをファイルに出⼒している。これは歴史的経緯でこう なってる。 • このログを収集するサイドカーのFluentdコンテナがいる

Slide 27

Slide 27 text

27 CloudLoggingにログを送信するときの⼯夫 ただログを送信しているだけはなく様々な情報を付与している。 Kubernetesで標準出⼒されるログのファイル名は以下のようになっている。 ここから情報をファイル名から抽出しログレコードに情報を付与している。 こうすることでログがどのPodで出⼒されたのか分析できるようになる。 Pod名 Namespace ContainerName sample-pod-694c957945- 9k7v5 _ default _ nginx -7582xxxxxx sample-pod-694c957945-9k7v5_default_nginx-7582d2414b0cc0bc402cdf27b354416dc849ff84935cd2c3508d8244e64fa2a7.log

Slide 28

Slide 28 text

28 Monitoring Datadogオンリー。とても便利。 Kubernetes向けの構成であるDatadog ClusterAgentを導⼊している。

Slide 29

Slide 29 text

29 マニフェストの管理 KustomizeでKubernetesマニフェストを管理することにした。 Kustomizeを使ってて困ったことで、修正のプルリクエストをレビューするときに • 実はkustomize buildコマンドでエラーが出る • パッチが正しく当たっていない ということが度々ありレビュワーが⾒るのが⼤変だった。 この問題を解決するために、修正前と後でkustomize build結果をdiffした結果をプルリクに⾃動でコ メントする仕組みを作った。

Slide 30

Slide 30 text

30 kustomize buildのdiff 変更内容: コメント内容:

Slide 31

Slide 31 text

31 Dockerfileの管理 コンテナイメージを作るときに迷わないようにいくつかのルールを作成した。 • どこでDockerfileを管理するのか • ベースイメージの利⽤⽅針 • ユーザID・グループIDをどうするか • 必ず⼊れるパッケージ

Slide 32

Slide 32 text

32 Container Repository AWS ECRを使⽤することにした。 なにも考えないとRepositoryサイズが肥⼤化してしまいお⾦がかかってしまう恐れがあった。 コンテナイメージのライフサイクルを設定できるので、イメージタグの命名規則を定め、環境ごと に世代数を定義した。 例) • 本番イメージ: 10世代まで • Stagingイメージ: 20世代まで • Devイメージ: 50世代まで

Slide 33

Slide 33 text

33 CI/CD(コンテナイメージ) コンテナイメージの作成のためのGitHub Actions Workflowを作成し、 Dockerfileが置かれているリポジトリからそのWorkflowを呼び出すようにした。

Slide 34

Slide 34 text

34 CI/CD(Kubernetes) マニフェストをKubernetesクラスタに適⽤するのはArgoCDを採⽤した。 App of Appsパターンを採⽤した。 楽天ラクマではKubernetesバージョンアップの際に新しいKubernetesクラスタを作成するので、1 つのApplicationをデプロイするだけでクラスタに必要なすべてのApplicationをデプロイできるので 便利。 引⽤元: https://argo-cd.readthedocs.io/en/stable/operator-manual/cluster-bootstrapping/#app-of-apps-pattern

Slide 35

Slide 35 text

35 Batch BatchはArgo Workflowで運⽤することにした。 Job/CronJobより多機能だしUIでスケジュールの確認や操作が可能なので採⽤した。 WorkflowTemplateを使⽤することで⽇々の業務を ちょっと楽にしてる。 これはHPAのminReplacesを簡単に変更できる WorkflowTemplateの例→

Slide 36

Slide 36 text

36 ClusterUpgrade Kubernetesクラスターのバージョンアップのやり⽅も決めた 新しいバージョンのクラスターを新規作成し、 ロードバランサーの機能で徐々にトラフィックを新しい⽅に向けるやり⽅。 この⽅法だとなにかあったときにすぐに元に戻せる。 Isitoなどのバージョンアップを合わせてやりやすい。

Slide 37

Slide 37 text

37 クラスタ構築・アプリケーションの改修 期間: 約1年半 これらの⽅針を実現するために様々なシステムコンポーネントを⼊れ、動作検証を⾏った。 またアプリケーションの改修も必要で、環境依存の設定がハードコーディングされていたのでそれ を環境変数などに外だしした。 環境依存の設定はさまざまな⽅法でされていたので、それをパターンごとにどのように外だしして いくかを考えたり、⼤量のソースコードの修正を⾏ったりして⼤幅に時間がかかった。

Slide 38

Slide 38 text

38 負荷試験 期間: 約4ヶ⽉ 楽天ラクマはRailsアプリケーションでUnicornをアプリケーションサーバーとして使っている。 UnicornはRailsをマルチプロセスで動かすもので、1Podでどのくらいのプロセス(UnicornWorker)を 動かすかがパフォーマンスの肝となる。 またコンテナ移⾏したことでパフォーマンス劣化しないかも確かめる必要があったので、負荷試験 を実施した。

Slide 39

Slide 39 text

39 負荷試験の観点 • 観点 • レイテンシが劣化しないか • スケールアウト速度が劣化しないか • その他⾒たところ • 1PodにどのくらいのUnicornWorkerを載せるか、また必要なリソースはどのくらいか • ClusterAutoscalerは意図通りスケールイン・アウトするか • IstioIngressGatewayおよびIstiodの負荷は問題ないか • ログ収集系コンポーネントの負荷は問題ないか • IPの消費量は問題ないか

Slide 40

Slide 40 text

40 コンテナ移⾏ 期間: 約1年 Dev・Staging・本番と段階を経てコンテナ化を⾏った。 さまざまなアプリケーションがあるのでそれら1つ1つコンテナ化をした。 Kubernetesの基盤はすでにある状態だったのであとはアプリケーションの設定をマニフェストに落 とし込んでいくだけだったが QAをアプリケーションごとに⾏ったため⼤幅に時間がかかった。

Slide 41

Slide 41 text

41 当初の課題を解決できたのか︖ • 検証環境が⾜りない • 増やしやすい環境が整った🎉 • 開発環境はGitHub Issueを作ると環境ができる仕組みを作れた︕ • ⾔語やパッケージなどのバージョンアップがSREしかできない • Dockerfileを編集することで可能になった🎉

Slide 42

Slide 42 text

42 コンテナ化後の課題 • Kubernetesの運⽤むずすぎる • アプリケーションのデプロイ時間が増えてしまった

Slide 43

Slide 43 text

43 課題1: Kubernetes運⽤むずかしすぎる問題 VM時代の構成はLB・EC2・DBとシンプルでトラブったときも原因調査しやすかった。 KubernetesはPodに到達するまでにいろんなものがあって原因調査が⼤変︕︕︕ Application LoadBalancer EC2 DB Application LoadBalancer Serivce Istio IngressGateway Serivce DB Istio- proxy App Pod VM時代︓ コンテナ時代︓

Slide 44

Slide 44 text

44 課題1: Kubernetes運⽤むずかしすぎる問題 • ⽅針を決め実装したはいいが、この仕組みを学習するのが⼤変・・・︕ • 利⽤しているコンポーネントが多すぎて、役割を理解するのが⼤変・・・︕ • ⽇々のメトリクス監視も対象が⼤幅に増えて⾒るのが⼤変・・・︕ • 年1くらいでKuberneteバージョンアップしないといけなくて⼤変・・・︕ • この基盤を利⽤するエンジニアにもある程度使い⽅を学んでもらう必要があって⾊々⼤ 変・・・︕

Slide 45

Slide 45 text

45 課題1: Kubernetes運⽤むずかしすぎる問題の対策 • 定期的にSREチーム向けに楽天ラクマKubernetesの勉強会を開催 • 不定期でエンジニア向けに楽天ラクマKubernetesの勉強会を開催 • Kubernetesトラブルシューティングガイドを作成 • エラーが起きたらこの順番でこのログを⾒ていけ など • Datadogメトリクスの⾒⽅や傾向をまとめた • この値がスパイクしてるときは◯◯が原因の可能性が⾼い など

Slide 46

Slide 46 text

46 課題2: アプリケーションのデプロイ時間が増えてしまった 今まではRailsアプリをEC2にデプロイするだけだったのでサクッと終わってたが コンテナではイメージのビルドがあったりPodの起動だったりあってデプロイ時間が増えてしまっ た。 これはいろんな要因があってひとつひとつ潰していくしかない • コンテナイメージビルドが遅い • ArgoCDが変更検知するのが遅い • 変更検知をポーリングからWebhookにすることで解決 • Podの起動処理が遅い

Slide 47

Slide 47 text

47 Kubernetesを採⽤してよかった︖ よかった︕ • ほとんどKubernetesだけで完結する世界を構築できたので、新しいアプリケーションやバッチを 動かすのをどこでやるのか悩まなくて良くなった。 • すべてマニフェストという形でコード化できて、アプリの運⽤に必要なものが⾃動化されている ので独⾃で実装していた⾃動化ツールが不要になった • ベンダーロックインをかなり少なくできた

Slide 48

Slide 48 text

No content