GitHub Actions の run ではパイプの終端の結果がジョブのステータスになる

GitHub Actions でテスト実行を tee で標準出力しつつファイルに出力するようにしました。

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - name: Test & report
        run: |
          go test . -v 2>&1 | tee result.txt
           :

出力されたファイルをレポーティング用のツールで加工してテスト結果レポートなどの成果物を作成したいためです。

しかし、テストが失敗してもワークフローが success() になってしまいます。

        run: |
          go test . -v 2>&1; test $? -ne 0 && exit 1 | tee result.txt

とかやるとテスト失敗したらfailure() にはなりますが、意図した内容がファイルに出力されません。

次のようにリダイレクトではちゃんとエラーになってくれます。

        run: |
          go test . -v 2>&1 > result.txt
           :

GitHub Actions の run ではコマンドパイプの途中の処理でエラーになっても終端の処理が成功しているとジョブステータスも success() になってしまうようです。ワンライナーで色々やりたい場合、ちょっと不便ですね。

テストの失敗はジョブのステータスとして検出したいのでテスト実行のみの step とテスト&レポート作成の step に分割しました。

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - name: Test
        run: |
          go test . -v

      - name: Test & report
        run: |
          go test . -v 2>&1 | tee result.txt
          :

この場合 test が失敗するとワークフロー自体は終了するので後続のテスト&レポート作成 step は実行されません。失敗成功にかかわらず後続の step を実行したい場合は、実行条件に always() を指定することで実行を強制可能です。

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - name: Test
        run: |
          go test . -v

      - name: Test & report
        if: always()
        run: |
          go test | tee result.txt
          :

後続の step が成功しても、それ以前の step がエラーになっていればジョブ自体は failure() になります。

help.github.com

テストを2回実行するコストが許容できない場合、テスト結果をファイルにリダイレクトして後続の step でログ出力するというやり方も考えられます。

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - name: Test & report
        run: |
          go test . -v 2>&1 > result.txt
          :

      - name: Print test result
        if: always()
        run: cat result.txt

この方法だとエラーが発生してもログ出力の step は成功するためログがどこに出ているのかわかりづらいという問題はあります。

f:id:kondoumh:20200119163222p:plain

GitHub Actions & kind (Kubernetes IN Docker) で Matrix build の CI を構築

CI で Kubernetes を使いたい場合、自前の Kubernetes 環境か GKE や EKS を利用して常時クラスターを使えるようにしておく方法があります。

しかし、ワーカーのノード数を色々変えてテストしたい、Kubernetes のバージョンを色々変えてテストしたい、常設のクラスターを準備するのがコスト的に厳しい・・などの場合、Docker 環境さえあれば揮発的に素早くクラスターを構築して終了後に破棄できる kind (Kubernetes in Docker) が有効です。

blog.kondoumh.com

GitHub Actions の Marketplace でも kind を使う Actions が公開されていました。

github.com

workflow の steps で以下のように指定するだけで kind でクラスターを構築できます。

    steps:
    :
    - uses: engineerd/setup-kind@v0.2.0
    :

kind の Config ファイルも width: に指定できます。

    - uses: engineerd/setup-kind@v0.2.0
      with:
        config: "k8s/kind.yml"

Kubernetes のバージョンを指定したいときは、kindest/node イメージのバージョンを指定すれば OK です。

    - uses: engineerd/setup-kind@v0.2.0
      with:
        image: kindest/node:v1.14.9

kind を手動起動する場合 Config ファイル内で kubeadmConfigPatches を使って kubeadm のオプションを与えるのですが、この Action では workflow 内で指定可能です。

複数バージョンの Kubernetes を使う Matrix build のサンプルを作ってみました。kindest/node のタグを matrix にしています。

name: "Create cluster using KinD"
on:
 push:
  paths:
  - k8s/**
  - .github/workflows/it_k8s.yml

jobs:
  kind:
    strategy:
      matrix:
        k8s: [1.14.9, 1.15.7]
  
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@master
    - uses: engineerd/setup-kind@v0.2.0
      with:
        config: "k8s/kind.yml"
        image: kindest/node:v${{ matrix.k8s }}
    - name: Testing
      run: |
        kubectl version
        kubectl cluster-info
        kubectl get node -o wide
        kubectl get pods -n kube-system
        kubectl apply -f k8s/nginx_deploy.yml
        kubectl describe deployment nginx-deployment

テストでは kubectl で nginx のマニフェストを apply して deployment を describe する処理を書いています (本来はデプロイしたアプリケーションのエンドポイントに対して E2E のテストを実行します)。

クラスターはデフォルトでシングルノード構成で起動されるので、複数ワーカー構成にしたい場合 Config ファイルで指定します。今回は、master (1) / worker (2) で構築しました。

# three node (two workers) cluster config
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4

nodes:
- role: control-plane
- role: worker
- role: worker

実行すると Kubernetes バージョン毎の結果が表示されます。

f:id:kondoumh:20200114231329p:plain

kind と Matrix build は相性がいいですね。

2019 ふりかえり

Job

引き続きプロダクト開発プロジェクト。1年以上在任してます。Kubernetes を中心とした開発環境・実行環境・CI/CD パイプラインの構築をやって IaC の良さも難しさも実感しています。

別のサービス開発プロジェクトにも少し入りました。こちらはコテコテの Java アプリでコード改善が主体です。

共に来年も続いていきそうです。

Private Project

GitHub の草は生やし続けてます。

野良 Scrapbox アプリは自分が一番のユーザということもあり、かなり更新して Electron にも馴染みました。

Vue は最近触ってませんが、v3 が出たら見ようかなと。

CI/CD ツールも色々と試しました。

11月にリリースされた GitHub Actions を public beta から使って気に入っています。野良 Scrapbox アプリの Windows / macOS のインストーラ配布もできました。

ホームページを Hugo に移行し GitHub Actions でジェネレートから公開まで自動化しました。

Hugo もですが Cloud Native なソフトウェアの多くが Go で書かれており、仕事で Go の開発環境・CI 整備をやっているので、個人的にもツール作成に使い始めました。久々に触るとかなり進化してました。Go Modules はかなりイケてる気がします。

今後 Go や d3.js などで可視化ツールを開発しようと思ってます。

Writing

ブログは週1以上ぐらいのペースで更新してました。

Scrapbox はすっかり会社のインフラになりました。僕もよく書いてます。個人プロジェクトも集約しました。

Software / Services

Netlify

PWA の配布やちょっとしたバッチ処理に使っています。

GCP

VM インスタンスをよく使ってます。GKE も使うようになりました。

AWS

仕事で EKS 中心に使ってます。個人アカウントはあまり使ってませんが、会社でアカウントもらったので来年から色々使うと思います。

DigitalOcean

Droplets をスポット利用してます。Kubernetes もローンチしたので使うかも。

VS Code

あらゆる開発環境が VS Code で構築できるようになってます。

Gitpod

iPad でも使える VS Code ベースの Web IDE。VS Code Online も出たし Eclipse Che や CodeSandbox も VS Code ベースだし・・と、Web IDE 界も VS Code が席巻してます。

Emacs

ターミナル作業も多いので設定や利用パッケージを見直しています。

Kibela

ドキュメント下書き・ToDo 管理・コードスニペット管理に使っています。PWA であらゆる場所で閲覧・編集できて便利。ただ、カーソルの挙動がおかしかったり投稿がうまくできなかったりする時があり、改善が望まれます。

Kibela (キベラ) - 個人の発信を組織の力にする情報共有ツール

draw.io

AWS アイコンも充実してシステム構成描くのに重宝します。Electron アプリになりました。

Flowchart Maker & Online Diagram Software

Ingress

Resurgence メダルもらいました。

Gadgets

中華ワイヤレスイヤホンとか Qi 充電器を買ったぐらい。

scrapbox.io

scrapbox.io

奥さん用に iPad Pro 書いました。

scrapbox.io

自分はまだ iPad Air 2 です。iPadOS でかなり使い勝手がよくなり、出先での作業はだいたい賄えてます。もう1世代ぐらい様子見かな。

MacBook Pro 13 Early 2015 も使い続けてます。そろそろ 6コアぐらいのマシンが欲しいところ。持ち歩かないので Mac mini とかでもいいかも。

まとめ

仕事も個人プロジェクトも1年前よりさらに Cloud Native 化が進んでいる気がします。コンピューティングもそれに合わせて変わっていくのでしょう。

Go Modules の hosting と import の関係

とあるプロジェクトでセルフホストしている GitLab で Go Modules を利用しようしてハマったのでメモ。

foo モジュールを private.host/account1/foo に公開したとします。

go.mod

module private.host/account1/foo

go 1.12

利用側では、

import "private.host/account1/foo"

のように指定します。go get / run / build する際、go コマンドは https://private.host/account1/foo?go-get=1 のようにリクエストを投げるようです。GitLab などの VCS hosting サイトはこのリクエストに対して

<meta name="go-import" content="private.host/account1/foo git https://private.host/account1/foo.git">

のように、VCS の種類とリポジトリの URL を含むメタタグを HTML として返すことを期待されます。

go コマンドはこの HTML をパースして VCS の種類、リポジトリのロケーションを特定し、VCS の CLI コマンドにモジュールの取得を委譲します。

godoc.org

gitlab.com では go-get=1 のクエリパラメータ付きリクエストに以下のような HTML を返却しています。

<html>
<head>
  <meta name="go-import" content="gitlab.com/kondoumh/go-samplemodlue git https://gitlab.com/kondoumh/go-samplemodule.git" />
  :
</head>
<body>
  go get https://gitlab.com/kondoumh/go-samplemodule
</body>
</html>

GitHub の場合はこんな感じ

<html lang="en">
  <head>
    <meta charset="utf-8">
      :
    <meta name="go-import" content="github.com/kondoumh/gogreeting git https://github.com/kondoumh/gogreeting.git">
      :
</head>
<body>
  :

Go Modules はソースコードであり、Git 以外の VCS (Mercurial, Bazzar etc.) でもホストされる可能性があります。Java や Node.js などのようにビルド・パッケージングしてホストするわけではないので、このように VCS によらない方法を取っているのでしょう。

件の GitLab は HTTPS ポートが規定の 443 以外で公開されていました。しかし go コマンドは既定のポートにリクエストを投げるので Connection refused でエラーになっていました。443 ポートを受け付けるように設定したら無事に使えるようになりました。

GitLab CI で kaniko を使ってコンテナイメージを build / push

CI パイプラインは Docker コンテナ Runner で実行することが一般的なので、パイプラインの中で docker build するには privileged モードで Runner のコンテナを実行する必要があります。いわゆる DinD (Docker in Docker) です。

build:
  image: docker:latest
  script:
    - docker build -t registry.gitlab.com/kondoumh/sandbox -f Dockerfile .
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD registry.gitlab.com
    - docker push registry.gitlab.com/kondoumh/sandbox
  services:
    - docker:dind

kaniko は Google 謹製のコンテナイメージビルドツールです*1

github.com

Docker daemon に依存せず、コンテナ内、もしくは Kubernetes cluster の Pod 内で Dockerfile からイメージをビルドできるため、DinD を回避しセキュアに運用できます。

GitLab CI でも kaniko の利用ガイドがありました。

https://docs.gitlab.com/ee/ci/docker/using_kaniko.html

/kaniko/.docker/config.json に Container Registry とそのユーザー名、パスワードを設定し、kaniko executer に Dockerfile や push 先などのコンテキストを渡して実行します。kaniko のイメージは debug タグを指定する必要があります。

build:
  stage: build
  image:
    name: gcr.io/kaniko-project/executor:debug
    entrypoint: [""]
  script:
    - echo "{\"auths\":{\"registry.gitlab.com\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
    - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG

docker:dind を services に指定する必要はありません。実行するとちゃんとイメージが push されました。

f:id:kondoumh:20191228145020p:plain

gitlab.com もいつの間にか Container Registry 提供していたんですね。

*1:蟹工船に由来するネーミング?

Electron アプリの通知 on Windows

Electron は Notification をサポートしていて、Renderer プロセスでも Main プロセスでも表示できます。

野良 Scrapbox アプリで GitHub API 使って latest release を取得し現在のバージョンと違っていたら通知を出し、クリックしたらダウンロードページを開くようコードを追加しました。

f:id:kondoumh:20191221123026p:plain

macOS では普通に動きました。Windows では「しかし何も起こらなかった。」

公式ドキュメントを見ると Application User Model IDs をスタートメニューにインストールしなくてはいけないとか、 Squirrel という更新フレームワークに依存してればちょっとワークアラウンドが省略できるとか書いてあり、要するに Windows のサポートは面倒ということがわかりました。更新フレームワークの導入はオーバーな気がしたので、通知だけ使いたかったのです。

https://electronjs.org/docs/tutorial/notifications#windows

NPM にも通知関連のパッケージがたくさんあり、いろんな人が苦労してそうな感じがしました。

macOS の方はアプリケーション起動時に一度許可すれば、以降は通知してくれます。

ということで、Electron 側の対応を待つことにして Windows 対応は諦めました。

Kubeflow が MicroK8s の Addon になってた

以前 Kubeflow を MiniKF (Minikube ベースの VirtualBox イメージ) で導入しました。

blog.kondoumh.com

その後 Ubuntu 19.10 のリリース時、Kubeflow が MicroK8s の Addon として導入できるようになるというアナウンスがありました。

ubuntu.com

MicroK8s は Snap で簡単にインストールできる Kubernetes 環境です。Addon として Dashboard、CoreDNS、Istio などを microk8s.enable コマンドで簡単に導入できます。

blog.kondoumh.com

そして、つい先日の MicroK8s 1.17 - 11 December 2019 で Addon として追加された模様です。

New addon: kubeflow. Give it a try with microk8s.enable kubeflow.

Release notes | MicroK8s

MicroK8s なので Ubuntu 19.10 が必須というわけでもなさそうですが、環境を用意して導入してみました。

まず Snap で MicroK8s をインストール

$ sudo snap install microk8s --classic
microk8s v1.17.0 from Canonical✓ installed

ユーザーを microk8s グループに追加してログインしなおし。

$ sudo usermod -a -G microk8s hoge

ステータスを確認。kubeflow は disable になっています。

$ microk8s.status --wait-ready
microk8s is running
addons:
cilium: disabled
dashboard: disabled
dns: disabled
fluentd: disabled
gpu: disabled
helm: disabled
ingress: disabled
istio: disabled
jaeger: disabled
juju: disabled
knative: disabled
kubeflow: disabled
linkerd: disabled
metallb: disabled
metrics-server: disabled
prometheus: disabled
rbac: disabled
registry: disabled
storage: disabled

microk8s.kubectl を kubectl として実行できるよう alias を設定

$ sudo snap alias microk8s.kubectl kubectl
Added:
  - microk8s.kubectl as kubectl

kubeflow を enable します。dns , storage など依存するアドオンも enable され最後に kubeflow のデプロイが開始されます。

Pod が大量に起動され、Service が Ready になるまでに 30分ほどかかりました。

$ microk8s.enable kubeflow
Enabling dns...
Enabling storage...
Enabling dashboard...
Enabling ingress...
Enabling rbac...
Enabling juju...
Deploying Kubeflow...
Kubeflow deployed.
Waiting for operator pods to become ready.
Waited 0s for operator pods to come up, 28 remaining.
Waited 15s for operator pods to come up, 27 remaining.
Waited 30s for operator pods to come up, 27 remaining.
Waited 45s for operator pods to come up, 27 remaining.
Waited 60s for operator pods to come up, 25 remaining.
Waited 75s for operator pods to come up, 21 remaining.
Waited 90s for operator pods to come up, 19 remaining.
Waited 105s for operator pods to come up, 18 remaining.
Waited 120s for operator pods to come up, 17 remaining.
Waited 135s for operator pods to come up, 15 remaining.
Waited 150s for operator pods to come up, 13 remaining.
Waited 165s for operator pods to come up, 13 remaining.
Waited 180s for operator pods to come up, 11 remaining.
Waited 195s for operator pods to come up, 10 remaining.
Waited 210s for operator pods to come up, 8 remaining.
Waited 225s for operator pods to come up, 4 remaining.
Waited 240s for operator pods to come up, 3 remaining.
Operator pods ready.
Waiting for service pods to become ready.

Congratulations, Kubeflow is now available.
The dashboard is available at https://localhost/

    Username: admin
    Password: XXXXXXXXXXXXXXXXXXXXXXX

To see these values again, run:
    microk8s.juju config kubeflow-gatekeeper username
    microk8s.juju config kubeflow-gatekeeper password


To tear down Kubeflow and associated infrastructure, run:
   microk8s.disable kubeflow

kubeflow というnamespace が作られ、多くの deployment や service が作られています。0.5 の時よりかなり増えてる感じです。

$ kubectl get deploy,svc -n kubeflow
NAME                                          READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/ambassador                    1/1     1            1           19m
deployment.apps/argo-controller               1/1     1            1           16m
deployment.apps/argo-ui                       1/1     1            1           19m
deployment.apps/jupyter-controller            1/1     1            1           19m
deployment.apps/jupyter-web                   1/1     1            1           18m
deployment.apps/katib-controller              1/1     1            1           18m
deployment.apps/katib-manager                 1/1     1            1           17m
deployment.apps/katib-ui                      1/1     1            1           17m
deployment.apps/kubeflow-dashboard            1/1     1            1           17m
deployment.apps/kubeflow-gatekeeper           1/1     1            1           17m
deployment.apps/kubeflow-login                1/1     1            1           17m
deployment.apps/kubeflow-profiles             1/1     1            1           17m
deployment.apps/metacontroller                1/1     1            1           17m
deployment.apps/metadata                      1/1     1            1           15m
deployment.apps/metadata-ui                   1/1     1            1           14m
deployment.apps/modeldb-backend               1/1     1            1           15m
deployment.apps/modeldb-store                 1/1     1            1           16m
deployment.apps/modeldb-ui                    1/1     1            1           15m
deployment.apps/pipelines-api                 1/1     1            1           15m
deployment.apps/pipelines-persistence         1/1     1            1           15m
deployment.apps/pipelines-scheduledworkflow   1/1     1            1           15m
deployment.apps/pipelines-ui                  1/1     1            1           14m
deployment.apps/pipelines-viewer              1/1     1            1           14m
deployment.apps/pytorch-operator              1/1     1            1           14m
deployment.apps/tf-job-dashboard              1/1     1            1           15m
deployment.apps/tf-job-operator               1/1     1            1           15m

NAME                                           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE
service/ambassador                             ClusterIP   10.152.183.73    <none>        80/TCP              19m
service/ambassador-operator                    ClusterIP   10.152.183.100   <none>        30666/TCP           19m
service/argo-controller-operator               ClusterIP   10.152.183.215   <none>        30666/TCP           19m
service/argo-ui                                ClusterIP   10.152.183.55    <none>        8001/TCP            19m
service/argo-ui-operator                       ClusterIP   10.152.183.134   <none>        30666/TCP           19m
service/jupyter-controller-operator            ClusterIP   10.152.183.104   <none>        30666/TCP           19m
service/jupyter-web                            ClusterIP   10.152.183.191   <none>        5000/TCP            18m
service/jupyter-web-operator                   ClusterIP   10.152.183.205   <none>        30666/TCP           19m
service/katib-controller                       ClusterIP   10.152.183.200   <none>        443/TCP             18m
service/katib-controller-operator              ClusterIP   10.152.183.189   <none>        30666/TCP           18m
service/katib-db                               ClusterIP   10.152.183.45    <none>        3306/TCP            18m
service/katib-db-endpoints                     ClusterIP   None             <none>        <none>              18m
service/katib-db-operator                      ClusterIP   10.152.183.48    <none>        30666/TCP           18m
service/katib-manager                          ClusterIP   10.152.183.222   <none>        6789/TCP            17m
service/katib-manager-operator                 ClusterIP   10.152.183.167   <none>        30666/TCP           18m
service/katib-ui                               ClusterIP   10.152.183.22    <none>        80/TCP              17m
service/katib-ui-operator                      ClusterIP   10.152.183.199   <none>        30666/TCP           18m
service/kubeflow-dashboard                     ClusterIP   10.152.183.237   <none>        8082/TCP            17m
service/kubeflow-dashboard-operator            ClusterIP   10.152.183.66    <none>        30666/TCP           18m
service/kubeflow-gatekeeper                    ClusterIP   10.152.183.240   <none>        8085/TCP            17m
service/kubeflow-gatekeeper-operator           ClusterIP   10.152.183.2     <none>        30666/TCP           17m
service/kubeflow-login                         ClusterIP   10.152.183.31    <none>        5000/TCP            17m
service/kubeflow-login-operator                ClusterIP   10.152.183.252   <none>        30666/TCP           17m
service/kubeflow-profiles                      ClusterIP   10.152.183.239   <none>        8081/TCP            17m
service/kubeflow-profiles-operator             ClusterIP   10.152.183.23    <none>        30666/TCP           18m
service/metacontroller                         ClusterIP   10.152.183.112   <none>        9999/TCP            17m
service/metacontroller-operator                ClusterIP   10.152.183.13    <none>        30666/TCP           18m
service/metadata                               ClusterIP   10.152.183.164   <none>        8080/TCP            15m
service/metadata-db                            ClusterIP   10.152.183.209   <none>        3306/TCP            16m
service/metadata-db-endpoints                  ClusterIP   None             <none>        <none>              16m
service/metadata-db-operator                   ClusterIP   10.152.183.67    <none>        30666/TCP           16m
service/metadata-operator                      ClusterIP   10.152.183.121   <none>        30666/TCP           15m
service/metadata-ui                            ClusterIP   10.152.183.182   <none>        3000/TCP            14m
service/metadata-ui-operator                   ClusterIP   10.152.183.6     <none>        30666/TCP           16m
service/minio                                  ClusterIP   10.152.183.213   <none>        9000/TCP            16m
service/minio-endpoints                        ClusterIP   None             <none>        <none>              16m
service/minio-operator                         ClusterIP   10.152.183.136   <none>        30666/TCP           17m
service/modeldb-backend                        ClusterIP   10.152.183.69    <none>        8085/TCP,8080/TCP   15m
service/modeldb-backend-operator               ClusterIP   10.152.183.94    <none>        30666/TCP           16m
service/modeldb-db                             ClusterIP   10.152.183.155   <none>        3306/TCP            15m
service/modeldb-db-endpoints                   ClusterIP   None             <none>        <none>              15m
service/modeldb-db-operator                    ClusterIP   10.152.183.56    <none>        30666/TCP           16m
service/modeldb-store                          ClusterIP   10.152.183.20    <none>        8086/TCP            16m
service/modeldb-store-operator                 ClusterIP   10.152.183.224   <none>        30666/TCP           17m
service/modeldb-ui                             ClusterIP   10.152.183.7     <none>        3000/TCP            15m
service/modeldb-ui-operator                    ClusterIP   10.152.183.130   <none>        30666/TCP           16m
service/pipelines-api                          ClusterIP   10.152.183.43    <none>        8887/TCP,8888/TCP   15m
service/pipelines-api-operator                 ClusterIP   10.152.183.34    <none>        30666/TCP           16m
service/pipelines-db                           ClusterIP   10.152.183.53    <none>        3306/TCP            16m
service/pipelines-db-endpoints                 ClusterIP   None             <none>        <none>              16m
service/pipelines-db-operator                  ClusterIP   10.152.183.32    <none>        30666/TCP           16m
service/pipelines-persistence-operator         ClusterIP   10.152.183.161   <none>        30666/TCP           15m
service/pipelines-scheduledworkflow-operator   ClusterIP   10.152.183.74    <none>        30666/TCP           15m
service/pipelines-ui                           ClusterIP   10.152.183.68    <none>        3000/TCP,3001/TCP   14m
service/pipelines-ui-operator                  ClusterIP   10.152.183.135   <none>        30666/TCP           15m
service/pipelines-viewer                       ClusterIP   10.152.183.61    <none>        8001/TCP            14m
service/pipelines-viewer-operator              ClusterIP   10.152.183.25    <none>        30666/TCP           15m
service/pytorch-operator-operator              ClusterIP   10.152.183.208   <none>        30666/TCP           14m
service/tf-job-dashboard                       ClusterIP   10.152.183.179   <none>        8080/TCP            15m
service/tf-job-dashboard-operator              ClusterIP   10.152.183.49    <none>        30666/TCP           15m
service/tf-job-operator-operator               ClusterIP   10.152.183.241   <none>        30666/TCP           15m

ブラウザで localhost に接続するとログイン画面が出るのでインストール完了時に表示された admin ユーザとパスワードでログインします。パスワードは microk8s.juju コマンドで再表示可能です。

$ microk8s.juju config kubeflow-gatekeeper password

おなじみの kubeflow の dashboard が表示されました。

f:id:kondoumh:20191215111758p:plain

v0.6.0-rc.0 が入ったようです。現在最新版は 0.7 で次は 1.0 になるみたいです。

kubeflow/ROADMAP.md at master · kubeflow/kubeflow · GitHub

ということで、MicroK8s の近い将来のリリースで Kubeflow 1.0 が入るようになるでしょう。

Kubeflow は導入障壁がまだ高いのですが、MicroK8s の Addon になるとかなり手軽になりますね。Kubeflow を利用する開発環境の構築にも良さそうです。今回は、GCP に 8 vCPU 30GB メモリという強めな VM を用意し GNOME と xrdp でリモートデスクトップ接続しました。Core i7 で 32GB メモリ程度の LInux マシンが用意できればけっこう使える環境が作れそうです。