Docker初心者です。
GoでHTTPサーバーを建てようとしたときのこと
下のDockfileをもとにGo言語製のHTTPサーバーをDockerコンテナ上で実行しようとしたところエラーが発生した。
参考記事
golangでdockerをはじめる ~ goのwebサーバーをdockerでたててみた ~
FROM golang
MAINTAINER tositeru
ADD ./main.go /go/src/server/main.go
RUN go install server
FROM alpine
COPY --from=0 /go/bin/server .
EXPOSE 8080
CMD ["./server"]
エラー内容はこちら
docker logs test
> standard_init_linux.go:207: exec user process caused "no such file or directory"
見た感じコンパイルしたバイナリがうまくコンテナ内にコピーできていない感じなので、とりあえず確認をしてみる。
なんだろビルド中のエラーかなと思いRUN
コマンドでファイルを確認、ついでにカレントディレクトリも。
FROM golang
MAINTAINER tositeru
ADD ./main.go /go/src/server/main.go
RUN go install server
FROM alpine
COPY --from=0 /go/bin/server .
EXPOSE 8080
RUN ls
RUN pwd
CMD ["./server"]
結果は省略するけど、ファイルは無事コピーされており、カレントディレクトリも正しい位置にあった。
何度か確認のためイメージを作っては消してを繰り返していくうちに、いやいやbash
を起動するほうが簡単に確認できるでしょ、と気づきCMD
を["bash"]
に変えた所、なんとエラーが発生。
ここであれ、Ubunutuとは環境が違うの?と気がつく。
Linuxディストリビューションって微妙に違うところがあるから困るよね
と言う訳で調べた所、alpineではash
を代わりに使うようでそれを使うようにしたら問題なくコンテナ内に入れた。
ファイルもコピーされており、何が原因なのかわからないとので検索してみたら、どうやらコンパイルしたバイナリが依存しているライブラリにアクセスできていないのが原因とのことで、次のコマンドをash
上で実行してみたら問題なくバイナリを実行できるようになった。
OSが違う環境でバイナリ化しているからそりゃそうだ
mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2
上でも解決できるそうだが異なるOSでコンパイルしていてなんか怖い感じがあるので、ビルドする環境もalipneに変えて最終的には下のようなDockfileに。
FROM golang:1.12.4-alpine3.9
MAINTAINER tositeru
ADD ./main.go /go/src/server/main.go
COM ["go", "install", "server"]
FROM alpine
COPY --from=0 /go/bin/server .
EXPOSE 8080
RUN mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2
ENTRYPOINY ["./server"]
これで問題なし!
終わりに
ちなみに今回のエラーには関係ないがDockerfileはUse multi-stage buildsという機能を使っていて、サーバーとして機能するコンテナにはGoのソースコードを含まないようにしている。
ローカルでビルドしたものを取り込むという形でもいいかもしれないけど、試し試しでやっていって作業がしやすい方にしていこうかなと。
検証中のイメージの作成/削除が地味に面倒だったのでスクリプト化していったほうがいいのかもしれないとか、
デプロイするときフロントエンド側のリソースも含めるようにしないといけないとかあるので、
作業を進めていく内に解決していこうと思う。