go build で missing go.sum entry for module providing package ビルドが失敗したときの原因と対応

AWS CodeBuildはソースコードのコンパイルや、テストの実行できるマネージドのビルドサービスです。CodeBuildでdocker build実行したときに、CodeBuildの設定ミスによるエラーかと思ったら全然関係ない原因でした。エラー内容と対応方法を紹介します。
2021.08.20

FargateへCI/CDの設定をCodePipelineで行っていました。CodeBuildでgo build時に以下のエラーによりビルドが失敗しました。メッセージ内容からCodeBuildの設定を疑っていたのですがCodeBuildの問題ではなく知っていればミスしない箇所でした。そのエラーと対応内容を紹介します。

CodeBuildのビルドログより

0.371 main.go:5:2: missing go.sum entry for module providing package github.com/labstack/echo/v4/middleware (imported by sample2-webapp-service/webapp); to add:

12 ERROR: executor failed running [/bin/sh -c go build -o web-server .]: runc did not terminate sucessfully

failed to solve with frontend dockerfile.v0: failed to build LLB: executor failed running [/bin/sh -c go build -o web-server .]: runc did not terminate sucessfully

原因

  • 注目すべきメッセージは赤文字ではないところ missing go.sum entry for module providing package
    • 適切なgo.sumファイルがなかった
  • go build前にgo mod tidygo.sumファイルを作成・更新する必要があった
    • 実行環境はGo version 1.16

CodeBuildの設定

CodeBuildの設定は問題なかったのですが、ビルドステージが2個ある構成なので簡単に紹介します。

1つのレポジトリから2つビルドのステージを作成していました。1つはWebアプリコンテナ、もう1つはサイドカーとして起動するFireLens(Fluent Bit)です。

buildspec.ymlの内容はほぼ共通です。docker buildで指定するDockerfileが異なるパスにあるため差異があります。変数はCodePipelineから渡してアカウントIDや、ECRのリポジトリ名を設定しています。

buildspec.yml

version: 0.2
env:
  variables:
    DOCKER_BUILDKIT: "1"
phases:
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin ${ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com
      - REPOSITORY_URI=${ACCOUNT_ID}.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/${REPOSITORY_NAME}
      - IMAGE_TAG=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-8)

  build:
    commands:
      - echo Build started on `date`
      - docker build -t $REPOSITORY_NAME:$IMAGE_TAG ./webapp
      - docker tag $REPOSITORY_NAME:$IMAGE_TAG $REPOSITORY_URI:$IMAGE_TAG

  post_build:
    commands:
      - echo Build completed on `date`
      - echo Pushing the Docker image...
      - docker push $REPOSITORY_URI:$IMAGE_TAG
      - printf '{"ImageURI":"%s"}' $REPOSITORY_URI:$IMAGE_TAG > imageDetail.json

artifacts:
  files: imageDetail.json

レポジトリのディレクトリ構成は以下のとおりです。buildspec.ymlがディレクトリ違いで2個存在しています。

tree

.
├── README.md
├── appspec.yml
├── firelens
│   ├── Dockerfile
│   ├── buildspec.yml
│   └── extra.conf
├── taskdef.json
└── webapp
    ├── Dockerfile
    ├── buildspec.yml
    ├── go.mod
    ├── go.sum
    ├── handler
    │   └── handler.go
    └── main.go

ビルドプロジェクトも別れています。

以下のエラーメッセージが赤文字で表示されていたこともあり、当初はCodeBuildのビルドプロジェクトの設定を疑っていましたが関係ありませんでした。

ビルドログ

failed to solve with frontend dockerfile.v0: failed to build LLB: executor failed running [/bin/sh -c go build -o web-server .]: runc did not terminate sucessfully

Dockerfile

CodeBuildでエラーが発生したときのDockerfileです。 マルチステージビルドしているだけのシンプルな内容です。ローカルでは問題なくdocker buildできるのに、CodeBuildだとなぜ失敗するのか調べていました。

Dockerfile

FROM public.ecr.aws/bitnami/golang:1.16 as builder

WORKDIR /app

COPY . .
RUN go mod download
RUN go build -o web-server .

FROM gcr.io/distroless/base-debian10:latest

WORKDIR /app
COPY --from=builder /app/web-server /app/web-server

EXPOSE 80
ENTRYPOINT ["/app/web-server"]

ローカル実行環境

項目 バージョン
Go 1.16.6
Docker 20.10.7
macOS 10.15.7

CodeBuildのログから赤文字のエラーメッセージに気を取らていたのですが、よくみるとgo.sumがないというメッセージも出力されています。

エラーメッセージ

0.371 main.go:5:2: missing go.sum entry for module providing package ...

go.sum.gitignoreに追加しています。ローカルには存在していますが、CodeCommitには存在していません。さらに調べてみるとGoのバージョン1.15まではgo build時にgo.sumが自動更新されていたのが、1.16からは更新されなくなった。

go mod tidyコマンドがgo.modを確認し不足しているエントリをgo.sumに追加してくれることを知りました。つまり、go.sumの作成・更新をしてくれる。不要になった依存関係を削除してくれることしか把握しておらず、go.sumについては意識すらしていませんでした。

というわけでgo build前にgo mod tidyを追加した修正版です。

修正版Dockerfile

FROM public.ecr.aws/bitnami/golang:1.16 as builder

WORKDIR /app

COPY . .
RUN go mod download
RUN go mod tidy
RUN go build -o web-server .

FROM gcr.io/distroless/base-debian10:latest

WORKDIR /app
COPY --from=builder /app/web-server /app/web-server

EXPOSE 80
ENTRYPOINT ["/app/web-server"]

解決

修正版のDockerfileをCodeCommitへPushし、CodePipelineでCodeBuildが走りました。 go buildは正常に完了しました。

CodeBuildのログ

#11 [builder 4/6] RUN go mod download
#11 DONE 3.8s

#12 [builder 5/6] RUN go mod tidy
#12 DONE 0.6s

#13 [builder 6/6] RUN go build -o web-server .
#13 DONE 4.4s

その後、デプロイまで完了しました。

おわりに

以上、備忘録でした。たまに使ってみるとキャッチアップが全然できていないことに気付かされます。つい先日1.17がリリースされましたし、日々のキャッチアップが大切ですね。

Go 1.17 is released - go.dev

参考