#状況
- GoによるでAPI開発をMac上で行っていた。
- ローカルではdocker-composeでコンテナの中で
go run
を実行して開発を行っていた。 - そこで実環境では以下のような手法でデプロイしようと試みた
- ①Mac上で
go build
してバイナリ作成 - ②バイナリを実行する
docker image
を作成 - ③ECRにpush
- ④ECS(Fargate)上で動かす
- ①Mac上で
- そこで②の
docker image
の作成まで行い、先ずローカルで試しにdocker run
したところ以下のようなエラーが発生して起動に失敗した。
standard_init_linux.go:211: exec user process caused "exec format error"
#原因
-
ググりまくったところMacとLinuxでアーキテクチャが異なり、ビルド対象が違うことがわかった。
-
試しにEC2でAmazon linuxを立てて①~④を実行したところ問題なく動いた!
- 上記のアーキテクチャの違いが原因であると推定し、linux上でgoをビルドすれば動くことが分かった
-
当時の悲鳴
#対処①これにハマった。。。MacでビルドするとCentOS系のコンテナとかの中では使えないのか。
— うぃすきー(箱男)📦 (@Whisky_shusuky) January 23, 2020
実行ファイルを実行すると「cannot execute binary file: Exec format error」エラー - 日々精進 https://t.co/2AdlWp8cQN
- 原因のところにも書いたようにEC2でビルドしてpushすればとりあえず動く。
- しかしながら以下のような問題がある。
- ビルドのためだけにインスタンスを立てるのは微妙
- ECRにpushするための接続情報をインスタンス上に置いておきたくない
- したがって廃案!
#対処②
- Mac上にLinuxのコンテナを立ててビルドすればLinux向けにビルドしてくれるのではないかと考えた。
- 以下のような
docker-compose-build.yml
を作成した- ローカルの
$GOPATH/src/hoge
が作成していたapiのディレクトリだとする - golangの公式イメージを使用
- コンテナの中の
$GOPATH
が/go
だったのでその配下にローカルの$GOPATH
をマウントさせる。 - この場合
hoge
が作成していたapiのディレクトリなのでマウントした/go/src/hoge
をworking_dir
に指定してgo build -o bin/hoge
を実行して$GOPATH/src/hoge/bin/hoge
にバイナリを出力
- ローカルの
- 以下のような
version: '3'
services:
go:
image: golang
container_name: golang_build
volumes:
- $GOPATH:/go
working_dir: /go/src/hoge
command: bash -c "go build -o bin/hoge"
environment:
- TZ=Asia/Tokyo
- ENV_GO=development
- これを
docker-compose -f docker-compose-build.yml up
で実行したところデプロイまで成功! - この対処②を採用した!
その他や感想など
- 本題と逸れるので記載しないが実際には
docker-compose -f docker-compose-build.yml up
,docker-compose -f docker-compose-build.yml down
,docker build ~
をコマンド一発で行うMakefileを作成して対応した。 - 本当はこの手のビルド周りはCIに任せたいが稟議に出すのが面倒だったのでローカルで完結させた。
- 同じような悩みを抱えてCIを使えない方は参考になるのではないでしょうか!