はじめに
GolangでCloud pubsubのsubscriberを実装した時のことです。
ローカルでgo runコマンドで実行すると正常にsubするのですが、docker container上だとどうやってもsubしてくれない現象が発生しました。
なお、subscriberはstreaming pull方式です。
(詳細は サブスクリプション タイプを選択する を参照)
Googleで調べてもジャストな記事がヒットしなかったのでここにメモしておきます。
結論
docker containerで ca-certificates をちゃんとアップデートしましょう。
発生した現象
サンプルコードをそのまま動かすようなコードをdocker container上で起動しました。
以下は記事執筆時点の こちら のドキュメントのコードそのままです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
import (
"context"
"fmt"
"io"
"sync/atomic"
"time"
"cloud.google.com/go/pubsub"
)
func pullMsgs(w io.Writer, projectID, subID string) error {
// projectID := "my-project-id"
// subID := "my-sub"
ctx := context.Background()
client, err := pubsub.NewClient(ctx, projectID)
if err != nil {
return fmt.Errorf("pubsub.NewClient: %v", err)
}
defer client.Close()
sub := client.Subscription(subID)
// Receive messages for 10 seconds, which simplifies testing.
// Comment this out in production, since `Receive` should
// be used as a long running operation.
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
var received int32
err = sub.Receive(ctx, func(_ context.Context, msg *pubsub.Message) {
fmt.Fprintf(w, "Got message: %q\n", string(msg.Data))
atomic.AddInt32(&received, 1)
msg.Ack()
})
if err != nil {
return fmt.Errorf("sub.Receive: %v", err)
}
fmt.Fprintf(w, "Received %d messages\n", received)
return nil
}
|
これを以下のようなDockerfileでビルドしてdocker runしてもpullされませんでした。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
FROM golang:1.20 AS build
WORKDIR /go/src/github.com/ken-aio/pubsub-subscriber
COPY go.mod go.sum /go/src/github.com/ken-aio/pubsub-subscriber/
RUN go mod download
ADD . /go/src/github.com/ken-aio/lcms-pubsub-subscriber
RUN go build
FROM debian:bullseye
RUN cp /usr/share/zoneinfo/Japan /etc/localtime
COPY --from=build /go/src/github.com/ken-aio/pubsub-subscriber/dist/pubsub-subscriber /pubsub-subscriber
CMD /pubsub-subscriber
|
解決
golangのcloud pubsubのstreaming pullにはgRPCのstreamingが使われています。
調査したところ、以下の環境変数を設定してから起動するとgRPCのログが出力されることがわかりました。
1
|
export GRPC_GO_LOG_SEVERITY_LEVEL="INFO"
|
この設定をしてからsubscriberを起動すると、以下のエラーが確認できました。
1
2
3
4
5
6
7
8
|
2023/03/03 12:30:26 WARNING: [core] [Channel #11 SubChannel #12] grpc: addrConn.createTransport failed to connect to {
"Addr": "pubsub.googleapis.com:443",
"ServerName": "pubsub.googleapis.com:443",
"Attributes": null,
"BalancerAttributes": null,
"Type": 0,
"Metadata": null
}. Err: connection error: desc = "transport: authentication handshake failed: tls: failed to verify certificate: x509: certificate signed by unknown authority"
|
ということで、TLSの接続でエラーが出ていました。
debian:bullseye
のCA証明書が足りなかったのが原因でした。
1
|
RUN apt update && apt -y upgrade && apt install -y ca-certificates
|
こちらをDockerfileに追記してビルドし直したところ、無事にsubscribeできるようになりました。