今回のk8sを利用したインフラの取りまとめを担当した@takemioIOです。

みなさん1年間コンテストに参加してくださってありがとうございました。
今回のコンテストも楽しんでいただけたでしょうか。

今回も引き続き機材提供してくださいました企業様、新規で機材提供して頂いた企業様、誠にありがとうございました。お陰様で無事開催ができ、運営学生もインフラ技術を学ぶことができました。特にk8sの担当者としてはさくらインターネット様のクラウドリソースを十二分に使わせていただきましたことを感謝いたします。

今年一年を通じて我々は k8s を利用し、スコアサーバー、監視基盤、問題用VMプロビジョニングツールの運用などを行ってきました。
この記事は我々が行ったk8sに関する利活用を解説する記事となっており、各担当者の寄稿文形式で行います。
まず前編ではネットワークやストレージなどのk8s自体に関する構築と構成について、後編では構築したk8sの利活用についてスポットを当てCDや監視などの運用についてを述べたいと思います。

全体像

このセクションでは今回の全体像について述べます。
我々のk8sはさくらのクラウド上に構築されています。
単一のk8sクラスタの構成と乗っかるコンテンツとしては以下の通りです。

画像に示している様にネットワーク周りではL4LBにMetalLB, L7LBにNginx Ingress Controllerを利用し、ストレージには Rook + Ceph、監視には Prometheus, Grafana, ELK, Elastiflow…etcと言った形で利用していました。

これらは予選と本戦通じて利活用されました。
我々の運用しているk8sクラスタは以下に示す合計3つとなります。

  • prd: 参加者がアクセスするためのスコアサーバーなど絶対に落とせないものを載せるクラスタ
  • dev: 実験のための利用がメインで、カナリアとして利用するためのクラスタ
  • wsp: 監視やツールなどを展開できる実験に巻き込まれるわけにはいかないが prd と共存させたくない時に使うクラスタ

また本戦においては問題が展開されているコアネットワークとVPNを貼る必要があり、以下の様な構成になっていました。この様にすることで本戦においての監視などは全てk8s上に載せることが可能になりました。

以降のセクションではマネージなk8sを運用していれば 全く ハマることがなく関わること少ないような部分だと思いますが、どのように転びながら構築をしたのかという話をします。

ストレージ

このセクションではk8sで利用してるストレージ周りについてを説明します。
今回の問題:Nginxが展開できない でも題材になっていましたが Rook + Ceph を我々は採用をしました。(実はこの問題は我々の構築においてもうっかり消し忘れていたことから起きたものでもありました)

Rookとは OSSのクラウドネイティブなストレージオーケストレーターと言うモノで、ストレージのソフトウェアをスケーリングや監視、スケーリングなどの機能ををk8sのエコシステムに載せることで高い可用性を実現したツールです。

今まで StateFulSet を利用する際に hostPath/data などを書いて適当にマウントする運用をしており、データの管理が大変辛かったと言うのがありました。

例えばStateFulSetを複数利用したいと考えると hostPath を複数書くことになります。その際に新しく追加したいと考えた際には /data/1, /data/2,/data/3…etc とどれがどこで何を使ってるのかわからない悲しいことが起きます。また雑にデータを処分することも叶わず rmコマンドを叩いて苦痛を伴った運用でカバーを行う羽目になっていました。

そこで、Rookを導入することで分散ストレージに加えてk8sでPV/PVCを使える様に我々クラスタにおいても可能になりました!
Cephの採用理由はCephであれば充分に枯れているので信頼性があると言う点やVeleroなどを併用することでDisasterRecoveryやDataMigrationが可能になると言うところや耐障害性を求めることができるのが嬉しい点としてあります。

また単純にRookの現在の安定バージョンのストレージプロバイダーは Cephのみであることからこれを選択することなりました。

Rook + Cephを利用した構築については本家ドキュメントが参考になるので今回は言及しませんのでそちらをご覧ください。

ネットワーク

k8sの運用構築担当の東畑@siberiy4です。 以降の解説記事は私が担当します
ここではk8sがおいてあるVPCの構成や、Metal LBの利用法についてを説明します。
まず、今年度のVM構成としては、

  • KubernetesのAPI用LB 2台
  • Kubernetesのマスター 3台
  • VyOS 1台
  • Kubernetesのノード 3台

となっていました。
API用LBと、Kubernetesのマスター、VyOSは対外疎通できるスイッチに接続しています。
プライベートなスイッチを作成し、KubernetesのノードとVyOSを接続しています。
この状態ではKubernetesのノードが対外疎通できないため、Kubernetesのノードがインターネット通信を行うためにVyOSにはProxy ARPの設定を入れています。

kube-apiserver の冗長

Kubernetesの冗長化のため、Kubernetesのマスターを複数台立てています。
複数のマスターを利用するためには、各マスターに対ししてロードバランスしてあげる必要があります。
そのためにLBとして HAProxyが稼働しているVMを2台用意しています。
2台利用している理由としては、単純にHAPorxyを1台稼働させた場合はSPOFとなってしまいます。
この対策として、2台用意しKeepalivedによってアクティブ・スタンバイ構成にしています。

アプリの外部公開

K8s上のアプリケーションを外部に公開するためのLoadBalancer Serviceを作成するため、MetalLBを利用しています。
昨年度のコンテストではMetalLB をLayer2モードで稼働させていました。
Layer2モードの場合、選出された単一のノードがすべてのトラフィックを受け取ります。
このため、ノードごとに処理負荷の偏りが発生してしまいます。

これを解決するために、MetalLBをBGPモードで利用することにしました。
BGPモードで利用するにはクラスタ外に用意したルーターが必要です。
用意したルーターとk8sの各ノードにあるMetalLBのSpeakerがBGPのピアを張ることで ECMPによるロードバランスができます。
そのため、VyOSを追加しそのVyOSに全てのKubernetesのノードを接続するように変更しました。
以下に 今年のクラウド上のトポロジー図を示します。

image.png

この追加したVyOSを利用して、コンテスト会場と各クラスタでVPN接続を行いました。 VPNソフトとして、Wireguardを利用しています。
これによって、WSPクラスタからすべてのリソースの監視が可能になります。

また、MetalLBでは複数のアドレスプールを用意することができます。
プライベートアドレスのプールを用意することで、コンテスト会場などの運営のみにアプリケーションを公開もできます。
使用するアドレスプールはServiceで指定します。

apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    peers:# BGPのピアの設定
    - peer-address: K8S_BGP_ROUTER_IPADDRESS 
      peer-asn: 65020
      my-asn: 65021
    address-pools:
    - name: globalIP
      protocol: bgp
      addresses:# e.g.- 192.0.2.1-192.0.2.254 or 192.0.2.0/24
      - METALLB_ADDRESS_RANGE 
      - METALLB_ADDRESS_RANGE 
    - name: privateIP
      avoid-buggy-ips: true
      protocol: bgp
      addresses:
        - PRIVATE_ADDRESS_RANGE
apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx
  namespace: scoreserver
  annotations:
    metallb.universe.tf/address-pool: globalIP
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
spec:
  type: LoadBalancer
  ports:
  - name: http
    port: 80
    targetPort: 80
    protocol: TCP
  - name: https
    port: 443
    targetPort: 443
    protocol: TCP
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

Ingress

SSLの終端やパスベースのルーティングを行うために、Ingressを利用しています。
昨年と同様に、Ingress ControllerとしてNginx Ingress Controllerを 使用しています。

クラスターのプロビジョニング

引き続き東畑が解説をします。

さくらのクラウドにKubernetesのマネージドサービスがないため、VMを作成しKubeadmによってKubernetes クラスタを構築しています。
手順としては、

  1. Terraform でVM作成
    Terraform for さくらのクラウド(v2)を利用してTerraform で各VMを作成しています。
    クラスタ作成時、さくらのクラウドでオブジェクトストレージのサービスが存在しなかったため、minioを稼働させたVMを作成しtfstateを保存しています。
  2. AnsibleでKubeadmのインストール/VyOSのBGPのコンフィグ投入
    Ansible のDynamic Inventory として、minioに保存されたtfstateを解釈しJSONとして出力してくれるPythonスクリプトを利用しています。
    Ansibleのplaybook は二つあり、一つ目はVyOS用です。
    Terraform for さくらのクラウド では複数インターフェースのIP設定はできないため、VyOSのKubernetesのノード側インターフェースにIPを割り当てをしていません。 そのための措置として、Terraform outputにあらかじめ出力してあるVyOS用のIPをインターフェースに設定します。
    また、VyOSにBGPのConfig、MetalLBから広報されたアドレスとKubernetesのノードを対外疎通させるためのProxy ARPなどのネットワーク設定をします。
    二つ目はサーバーのパッケージインストール用です。
    Keepalived、HAProxy、Kubeadmのインストールや、管理用ユーザーの追加を行います。
  3. 手動でKeepalived、HAProxy,kubeadmによるクラスタ構築。
    以降手作業。 Keepalived、HAProxy、kubeadmは設定ファイルのひな型が用意してあり、それらを各VMに適用します。
    あとは、MetalLB, Cert Manager, Nginx Ingress Controller, Argo CDなどをApplyすればKubernetesクラスタの土台が出来上がります。  
    課題としては、terraformの実行からKubernetesクラスタの構築まで2,3時間かかるのを眺める必要がありますのでpackerなどを利用しvmを事前にイメージ化するなどをしておくことを検討すべきだったなと思いました。

終わりに

今回は k8sの全体像と構築にあたっての詳細なエッセンスについて説明しました。

昨年私が一番最初に立てたk8sのクラスタはLBがそもそもL7のみでその単一のhostpathで上手いこと一つのアドレスを利用し複数のアプリケーションを公開していました。そこから振り返ると今年はようやく人が触れても問題なさそうなものになってきたなと思いました。

次回はk8sの利活用についてスポットを当て紹介します。