Knative Buildのbuild templateにBazelをつかいビルドする

KnativeはKubernetesを基盤としたプラットフォームをビルド、デプロイするためを管理するためフレームワークを提供する。Serving、Build、そしてEventingの3つのコンポーネントで構成されている。これら3つが疎結合に連携する。

cloud.google.com

Kubernetesを基盤にサービスをデプロイするにはDeploymentやService、Ingressなどの理解が必要であるがKnativeはそれらを抽象化してよりフレームワークに沿った扱い方を提供してくれている印象がある。

モチベーション

今回のエントリでは3つのコンポーネントのうち Buildに注目していきたい。これまでBazelをつかいGoプロジェクトをビルドする方法をまとめてきた。KnativeのBuildにはbuild templateという概念がありテンプレートの1つにBazelがサポートされている。KnativeのBuildのbuild templateにBazelをつかいGoプロジェクトをビルドする手順をまとめる。

インストール

Kubernetes環境が整っていれば次のリソースをapplyすればKnative Buildの環境がセットアップできる。

istioのインストール

# Install istio
$ kubectl apply --filename https://raw.githubusercontent.com/knative/serving/v0.2.2/third_party/istio-1.0.2/istio.yaml
# Label the default namespace with istio-injection=enabled:
$ kubectl label namespace default istio-injection=enabled

istio関連のPodがRunningかCompletedになれば完了

$ kubectl get pods --namespace istio-system --watch

NAME                                        READY     STATUS              RESTARTS   AGE
istio-citadel-84fb7985bf-shfdl              0/1       ContainerCreating   0          54s
istio-cleanup-secrets-zg9n6                 0/1       Completed           0          1m
istio-egressgateway-bd9fb967d-z7gfr         0/1       ContainerCreating   0          54s
istio-galley-655c4f9ccd-d9mgh               0/1       ContainerCreating   0          54s
istio-ingressgateway-688865c5f7-2p5gk       0/1       ContainerCreating   0          54s
istio-pilot-6cd69dc444-ts67c                0/2       ContainerCreating   0          54s
istio-policy-6b9f4697d-d4ndh                0/2       ContainerCreating   0          54s
istio-sidecar-injector-8975849b4-8x722      0/1       ContainerCreating   0          54s
istio-statsd-prom-bridge-7f44bb5ddb-qwdqv   1/1       Running             0          55s
istio-telemetry-6b5579595f-g2vm4            0/2       ContainerCreating   0          54s

参考: https://github.com/knative/docs/blob/master/install/Knative-with-any-k8s.md

Knative Buildのインストール

$ kubectl apply --filename https://raw.githubusercontent.com/knative/serving/v0.2.2/third_party/config/build/release.yaml

Build関連のPodがRunningになれば完了

kubectl get pods --namespace knative-build --watch
NAME                                READY     STATUS              RESTARTS   AGE
build-controller-747b8fd966-dwbdd   0/1       ContainerCreating   0          16s
build-webhook-6dc78d8f6d-vvkqm      0/1       ContainerCreating   0          16s

knative-buildのnamespaceが追加されている。以降に追加するリソースはknative-buildのnamespaceに追加していくのでcontextを切り替える。

Knative Buildを理解するために次の4つの要素

Knative Buildを理解するために次の4つの要素は抑えておきたい。

  • Build
  • BuildTemplate
  • Builder
  • ServiceAccount

Build

docs/builds.md at master · knative/docs · GitHub

BuildはBuildTemplate、Builder、ServiceAccountを集約した概念であり、それらをまとめたmanifestを作成する。

BuildTemplate

docs/build-templates.md at master · knative/docs · GitHub

BuildTemplateはparameterstepsを定義する。stepはビルド手順をまとめビルドに必要な変数をparameterで定義する。テンプレートはBazelがサポートされている。今後もその他のサポートが追加されることが期待される。

GitHub - knative/build-templates: A library of build templates.

Builder

docs/builder-contract.md at master · knative/docs · GitHub

BuilderはBuildTemplateでも触れたstepsの概念である。ビルドするために複数の手順があればstepsに追加していく。ビルドの完了までにBazelのtargerを複数実行したい場合はstepsにtargetを定義していく。

ServiceAccount

docs/auth.md at master · knative/docs · GitHub

ServiceAccountはKnative Buildにおける新概念ではなくビルドする過程で必要な認証をsecretリソースと一緒にセットアップすることでBuildリソースにアサインする。GitHubからソースのチェックアウトやリモートレジストリへのプッシュなどに必要な認証アカウントをServiceAccountリソースとして定義する。

Knative BuildでBazelをつかいビルドする

先述した4つの概念を頭に入れてBazelでビルドする方法をまとめていく。

ServiceAccountを作成する

BazelのtargetにはDocker hubにイメージをプッシュする工程が含まれているのでDocker hubに認証するSecretリソースを追加する。

# pkg/ops/k8s/knative-build/secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: docker-hub-account
  annotations:
    build.knative.dev/docker-0: https://index.docker.io/v1/
type: kubernetes.io/basic-auth
stringData:
  username: "<username>" # not base64 encoded
  password: "<password>" # not base64 encoded

リソースを追加する。

(bazel-multiprojects) $ kubectl apply -f pkg/ops/k8s/knative-build/secret.yaml
secret/docker-hub-account created

次にServiceAccountリソースを追加する。

# pkg/ops/k8s/knative-build/service-account.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: docker-hub-account
secrets:
  - name: docker-hub-account

リソースを追加する。

(bazel-multiprojects) $ kubectl apply -f service-account.yaml
serviceaccount/docker-hub-account created

これでDocker hubに認証するSecretリソースを参照しているdocker-hub-accountのServiceAccountが追加できた。

BuildTemplateリソースの追加

BuildTemplateリソースを追加する。

# pkg/ops/k8s/knative-build/build-template-bazel.yaml

apiVersion: build.knative.dev/v1alpha1
kind: BuildTemplate
metadata:
  name: bazel
spec:
  parameters:
  - name: TARGET
    description: The name of the Bazel "container_push" target to run
  - name: IMAGE_TAG
    description: The tag of image

  steps:
  - name: build-and-push
    image: gcr.io/cloud-builders/bazel
    args: ['run', '--platforms=@io_bazel_rules_go//go/toolchain:linux_amd64', '--define', 'IMAGE_TAG=${IMAGE_TAG}', '${TARGET}']

bazel runコマンドのオプションを変数化して必要な変数をparameterとして定義している。

リソースを追加する。

(bazel-multiprojects) $ kubectl apply -f pkg/ops/k8s/knative-build/build-template-bazel.yaml
buildtemplate.build.knative.dev/bazel created

これでBuildTemplateリソースのbazelが追加できた。

Buildリソースの追加

Buildリソースを定義する。

# pkg/ops/k8s/knative-build/bazel-build.yaml

apiVersion: build.knative.dev/v1alpha1
kind: Build
metadata:
  name: bazel-build
spec:
  serviceAccountName: docker-hub-account
  source:
    git:
      url: https://github.com/soushin/bazel-multiprojects
      revision: master
  template:
    name: bazel
    arguments:
    - name: TARGET
      value: //pkg/public_go:container_push
    - name: IMAGE_TAG
      value: latest

spec.serviceAccountNameに追加したServiceAccount docker-hub-accountを参照している。そしてspec.template.nameには追加したBuildTemplate bazelを参照している。また//pkg/public_go:container_pushのBazel targetを実行するためのソースをspec.sourceに定義している。

ビルドの実行

Buildリソースであるpkg/ops/k8s/knative-build/bazel-build.yamlをapplyしてビルドを実行する。

(bazel-multiprojects) $ kubectl apply -f pkg/ops/k8s/knative-build/bazel-build.yaml
build.build.knative.dev/bazel-build created

ポッドが起動しているのを確認する。

(bazel-multiprojects) $ kubectl get pods --namespace knative-build --watch
NAME                                READY     STATUS     RESTARTS   AGE
bazel-build-9jzhc                   0/1       Init:2/3   0          1m
build-controller-747b8fd966-dwbdd   1/1       Running    0          1h
build-webhook-6dc78d8f6d-vvkqm      1/1       Running    0          1h

Completedになればビルド完了。

(bazel-multiprojects) $ kubectl get pods --namespace knative-build --watch
NAME                                READY     STATUS      RESTARTS   AGE
dbuild-controller-747b8fd966-dwbdd   1/1       Running     0          3h
build-webhook-6dc78d8f6d-vvkqm      1/1       Running     0          3h
bazel-build-9jzhc   0/1       Pending   0         0s
bazel-build-9jzhc   0/1       Pending   0         0s
bazel-build-9jzhc   0/1       Init:0/3   0         0s
bazel-build-9jzhc   0/1       Init:1/3   0         1s
bazel-build-9jzhc   0/1       Init:1/3   0         3s
bazel-build-9jzhc   0/1       Init:2/3   0         4s
bazel-build-9jzhc   0/1       Init:2/3   0         6s
bazel-build-9jzhc   0/1       PodInitializing   0         5m
bazel-build-9jzhc   0/1       Completed   0         5m

まとめ

  • Knative Buildのbuild templateにBazelをつかいビルドする方法をまとめた
  • ビルドを実行するとPodが立ち上がりPod内でビルドが行われる。BazelやDockerといったビルドに必要なコンポーネントのセットアップをせずにビルドできるのは便利である。
  • ビルドが完了するとPodがCompletedになるが再度同じようにapplyを実行してもビルドが行われない。Podを削除した後にapplyを実行すると再度ビルドができた。
    • もしかすると定義したBuildはEventingと結合して進化を発揮するのかしれない。EventigはGitHubのイベントをソースに扱える。マージのイベントでKnative Buildを実行するイメージである。
    • Evenitngの理解がまだ浅いので引き続きEventingの理解も進めていく。

コード

紹介したyamlコードは次のレポジトリに置いてあります。

github.com