ProwではじめるChatOps on GitHub。

Kubernetesのtest-infraレポジトリにあるProwを試す。ProwはKubernates環境を基盤としたCIとCDのシステムである。

モチベーション

Kubernatesを追っている人であれば次のようなコメントのやり取りをGitHub上で見かけたことがあるだろう。

f:id:n_soushi:20190108105515p:plain

Enable kustomize in kubectl by Liujingfang1 · Pull Request #70875 · kubernetes/kubernetes · GitHub

/hold/testなどのキーワードをコメント欄に入力してオペレーションを実行している。/hold cancelでラベルを取り除いたり/testでテストを実行している。入力したキーワードはWebhookで稼働しているProwのエンドポイントに送信されてGitHubイベントと合わせてProwのプラグインが実行される仕組みである。

このProwの導入手順をまとめていきプロジェクトにフィットするか検討したいというのがエントリのモチベーションである。ProwはKubernetesをはじめIstio、Knative、Prometheusなどのオーガナイゼーションにも利用されている。

Prowをデプロイする

Prowが含まれるレポジトリはkubernetes/test-infraである。

github.com

デプロイ手順はgetting_started_deploy.mdを参考に進めている。

test-infra/getting_started_deploy.md at master · kubernetes/test-infra · GitHub

gcpを利用している人であればTackleというユーティリティが用意されているので対話式にProwをセットアップできるが私はローカル(Docker For Desktop)でKubernatesを起動させているためManual deploymentを参考にすすめた。

またClusterとNamespaceはdocker-for-desktopdefaultとしている。実際の運用ではプロジェクトに合わせた選択が求められる。

事前に準備するものを一覧にする。

  • Prowを試すレポジトリ
  • Botアカウント(GitHubのBot専用アカウント)
  • BotアカウントのAccessToken
  • ご自身のアカウントのAccessToken

Kubernatesはk8s-ci-robotというBotアカウントを使用している。

k8s-ci-robot (Kubernetes Prow Robot) · GitHub

kubernetes/test-infra をチェックアウト

$ git clone git@github.com:kubernetes/test-infra.git
$ cd test-infra

以降の手順はすべてtest-infraのディレクトリで行う。

GitHubとProwを連携するための準備

GitHubとProwを連携するための準備としてWebhookで送信するSecretキーを生成しSecretリソースに追加する。

(test-infra) $ openssl rand -hex 20 > hook_secret
(test-infra) $ kubectl create secret generic hmac-token --from-file=hmac=hook_secret

BotアカウントのGitHubアクセストークンをSecretリソースに追加する。

# BotアカウントのGitHubアクセストークンを`bot_oauth_secret`に保存している
(test-infra) $ kubectl create secret generic oauth-token --from-file=oauth=bog_oauth_secret

Prowのコンポーネントをデプロイする

(test-infra) $ kubectl apply -f prow/cluster/starter.yaml

Deploymentは次のようになっている。

(test-infra) $ kubectl get deployments 
NAME         DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deck         2         2         2            0           3m
hook         2         2         2            2           3m
horologium   1         1         1            1           3m
plank        1         1         1            1           3m
sinker       1         1         1            1           3m
tide         1         1         1            1           3m

deckがエラーになっているがOAuth Appを利用するケースのため割愛する。

test-infra/pr_status_setup.md at master · kubernetes/test-infra · GitHub

WebhookをGitHubに追加する

私の環境はローカルのためIngressにIPアドレスが割り振られないがGitHubのWebhookから叩かれるエンドポイントのhookPodはNodePortで開かれているのでngrockをつかってプロキシしている。

NodePortを確認する。

(test-infra) $ kubectl describe service hook
Name:                     hook
Namespace:                default
Labels:                   <none>
Annotations:              kubectl.kubernetes.io/last-applied-configuration:
                            {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"hook","namespace":"default"},"spec":{"ports":[{"port":8888}],"sel...
Selector:                 app=hook
Type:                     NodePort
IP:                       10.98.120.195
LoadBalancer Ingress:     localhost
Port:                     <unset>  8888/TCP
TargetPort:               8888/TCP
NodePort:                 <unset>  31797/TCP
Endpoints:                10.1.7.24:8888,10.1.7.25:8888
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

確認したNodePort 31797をngrockでプロキシする。

(test-infra) $ ngrok http 31797

Forwardingに表示されているhttps://xxxxxx.ap.ngrok.ioのURLをWebhookに利用する。

Webhookを追加するユーティリティをつかってみる

ProwにはWebhookを追加するユーティリティが用意されている。ユーティリティを使わなければ手動でGitHubからWebhookを追加すれば良い。

(test-infra) $ bazel run //experiment/add-hook -- \
  --hmac-path=/path/to/hook_secret \
  --github-token-path=/path/to/own_oauth_secret \
  --hook-url https://xxxxxx.ap.ngrok.io/hook \
  --repo soushin/bazel-multiprojects \
  --confirm=true
  • hmac-pathには生成したhook_secretを指定(注:絶対パス)
  • github-token-pathにはご自身のGitHubアクセストークンを保存したown_oauth_secretを指定(注:絶対パス)
  • hook-urlにはngrockでプロキシしたhttps://xxxxxx.ap.ngrok.io/hookのエンドポイントを追加して指定
  • repoにはProwを試すレポジトリを指定

実行後にINFOが次のように出力されていれば完了。

INFO[0000] ListRepoHooks(soushin, bazel-multiprojects)   client=github
INFO[0000] CreateRepoHook(soushin, bazel-multiprojects)  client=github

GitHubのSettings -> WebhooksのページにWebhookが追加されていてグリーンのチェックマークが点いていれば正常に完了。

これでKubernatesにデプロイしたProwのコンポーネントとGitHubがWebhookで連携できた。次にプラグインを追加してProwのChatOpsを体験していく。

Prowプラグインを追加する

プラグインを追加する前にProwのhookPodのログにno pluginsのエラーが確認できる。

hook-64448bb489-42v8b hook {"component":"hook","level":"warning","msg":"no plugins specified-- check syntax?","time":"2019-01-08T03:07:15Z"}
hook-64448bb489-42v8b hook {"component":"hook","level":"warning","msg":"no plugins specified-- check syntax?","time":"2019-01-08T03:08:15Z"}

つまり何かしらプラグインを追加して初めてProwのChatOpsが体験できるわけだ。

Prowのプラグインはこちらにまとまっている。

Prow Plugin Catalog

Sizeプラグインを試す

SizeプラグインはPushしたコード量に応じてBotアカウントがsize/SSize/XLなどのラベルをプルリクエストに付与してくれるプラグインである。

plugins.yamlを次のように作成する。

(test-infra) $ echo 'plugins:
  soushin/bazel-multiprojects:
  - size' > ./plugins.yaml

soushinbazel-multiprojectsレポジトリにsizeプラグインを有効にしている。soushinのみを指定してオーガナイゼーション全体にプラグインを有効にすることも可能である。

plugin.yamlをConfigMapに追加する。

(test-infra) $ kubectl create configmap plugins \
  --from-file=plugins.yaml=plugins.yaml --dry-run -o yaml  \
  | kubectl replace configmap plugins -f -

追加したConfigMapはhookPodにマウントされてプラグインが有効になる。

適当なプルリクエストを追加するとBotアカウントがSizeラベルを付与してくれる。

f:id:n_soushi:20190108122855p:plain

まとめ

  • Prowの導入手順をまとめた。
  • Kubernatesは1日にテストを1,000回以上実行するそうでスケーラビリティが求められる。ProwはKubernates環境で稼働するためニーズとマッチした仕組みである。
  • Jenkins XはKnativeとProwを基盤に実現したサーバレスJenkinsで、Knativeというサーバレスの仕組みにProwプラグインの拡張性が組み合わさった感じなのかな、という印象を持った。
  • 今回は既存のプラグインを試したがtriggerというプラグインはtestに関連していそうで非常に気になる。
  • プロジェクトにマッチするか引き続きProwを触っていきたい。