本日も乙

ただの自己満足な備忘録。

go buildしたときに「unknown revision v0.0.0」でコケたときの回避方法

Golang で NVML(NVIDIA Management Library)を使いたかったので、NVIDIA/gpu-monitoring-tools のライブラリを使わせてもらおうと思ったら、躓いてしまったのでメモ。

環境

$ go version
go version go1.15 darwin/amd64

サンプルコード

NVIDIA/gpu-monitoring-tools リポジトリにあるサンプルコードを参考にしています。

package main

import (
    "fmt"

    "github.com/NVIDIA/gpu-monitoring-tools/bindings/go/nvml"
)

func getGpuUsage() error {
    if err := nvml.Init(); err != nil {
        return err
    }
    defer nvml.Shutdown()

    count, err := nvml.GetDeviceCount()
    if err != nil {
        return fmt.Errorf("error getting device count: %v", err)
    }

    for i := uint(0); i < count; i++ {
        device, err := nvml.NewDevice(i)
        if err != nil {
            return fmt.Errorf("error getting device %d: %v\n", i, err)
        }
        st, err := device.Status()
        if err != nil {
            return fmt.Errorf("error getting device %d status: %v\n", i, err)
        }
        fmt.Println(st.Utilization)
    }
    return nil
}

go build をすると unknown revision v0.0.0 でコケます。

$ go mod init
$ go build
go: finding module for package k8s.io/api
go: finding module for package github.com/NVIDIA/gpu-monitoring-tools/bindings/go/nvml
go: found github.com/NVIDIA/gpu-monitoring-tools/bindings/go/nvml in github.com/NVIDIA/gpu-monitoring-tools v0.0.0-20201006233419-a544dbcaacb0
go: found k8s.io/api in k8s.io/api v0.19.2
go: github.com/NVIDIA/gpu-monitoring-tools@v0.0.0-20201006233419-a544dbcaacb0 requires
        k8s.io/kubernetes@v1.18.2 requires
        k8s.io/api@v0.0.0: reading k8s.io/api/go.mod at revision v0.0.0: unknown revision v0.0.0

原因

Go Modules で依存パッケージを取得する際に kubernetes が必要で、kubernetes が依存している kubernetes/api のバージョン v0.0.0 というのが無いためエラーになっていました。順に追って説明します。

NVIDIA/gpu-monitoring-toolsgo.modrequirek8s.io/kubernetes v1.18.2 があるため、kubernetes v1.18.2 を取得しようとします。

# https://github.com/NVIDIA/gpu-monitoring-tools/blob/master/go.mod#L12

require (
    ...
    k8s.io/kubernetes v1.18.2
)

kubernetes v1.18.2 の go.mod を見ると、k8s.io/api v0.0.0 があるため、kubernetes/api v0.0.0 を取得しようとします。

# https://github.com/kubernetes/kubernetes/blob/v1.18.2/go.mod#L141

require (
    ...
    k8s.io/api v0.0.0
    ...
)

しかし、kubernetes/api を見ると、v0.0.0 がないためここでコケてしまうというわけです。

Tags · kubernetes/api

回避策

Issue を見ると replace を使うのが良さそうです。実は kubernetes/api 以外も多くのパッケージが同じエラーになったので次のようになりました。

module hogehoge_module

go 1.15

replace (
    k8s.io/api => k8s.io/api v0.0.0-20190620084959-7cf5895f2711
    k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.0.0-20190620085554-14e95df34f1f
    k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20190612205821-1799e75a0719
    k8s.io/apiserver => k8s.io/apiserver v0.0.0-20190620085212-47dc9a115b18
    k8s.io/cli-runtime => k8s.io/cli-runtime v0.0.0-20190620085706-2090e6d8f84c
    k8s.io/client-go => k8s.io/client-go v0.0.0-20190620085101-78d2af792bab
    k8s.io/cloud-provider => k8s.io/cloud-provider v0.0.0-20190620090043-8301c0bda1f0
    k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.0.0-20190620090013-c9a0fc045dc1
    k8s.io/code-generator => k8s.io/code-generator v0.0.0-20190612205613-18da4a14b22b
    k8s.io/component-base => k8s.io/component-base v0.0.0-20190620085130-185d68e6e6ea
    k8s.io/cri-api => k8s.io/cri-api v0.0.0-20190531030430-6117653b35f1
    k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.0.0-20190620090116-299a7b270edc
    k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.0.0-20190620085325-f29e2b4a4f84
    k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.0.0-20190620085942-b7f18460b210
    k8s.io/kube-proxy => k8s.io/kube-proxy v0.0.0-20190620085809-589f994ddf7f
    k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.0.0-20190620085912-4acac5405ec6
    k8s.io/kubectl => k8s.io/kubectl v0.0.0-20201008135616-e95e378e5972
    k8s.io/kubelet => k8s.io/kubelet v0.0.0-20190620085838-f1cb295a73c9
    k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.0.0-20190620090156-2138f2c9de18
    k8s.io/metrics => k8s.io/metrics v0.0.0-20190620085625-3b22d835f165
    k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.0.0-20190620085408-1aef9010884e
)

今回使いたい NVML ライブラリ自体は kubernetes が必要でないため、バージョンは古くてもOKなので Issue に載っていたものをパクリました。Issue にかかれていないパッケージ(kubectl など)は自分で追記しなければなりません。

Go Modules の仕様としてバージョンの後ろは「リビジョンのタイムスタンプ」と「リビジョン」を入れなければなりません。

replace (
    k8s.io/api => k8s.io/api v0.0.0-<リビジョンのタイムスタンプ>-<リビジョン>
)

リジョンは Git コミット ID の先頭12文字となります。リビジョンのタイムスタンプは committer date となるので git log --pretty=fuller で取得できます。UTC なのでタイムゾーンがずれていたら直します。

go.mod に replace を追記して go build をすると正常に依存パッケージを取得できてビルドできるようになりました。

参考文献