はじめに
DockerでGoのAPIサーバーを立てるDockerFileを作成しました。
調べたこと、DockerFileについて調べたことをまとめます。
入門Docker 学習メモ
後の実践
基礎知識の補足
ビルドコンテキスト(build context)
docker buildコマンドを実行したときの、カレントなワーキングディレクトリのこと
Dockerデーモン
Docker Engineの一部。
Docker EngineはDocker CLI、Docker Engine API、 Dockerデーモンで構成されている。
イメージのビルドやコンテナの起動を行ってくれるもの。
Docker Engineとは、コンテナ化及びコンテナを動作させるためのアプリケーションで、Dockerの核となる部分です。
【触って理解!】Docker入門 - 初心者に向けて使い方や基本コマンドを解説
そもそもデーモンって何、
→UNIX系OSにおけるメモリ上で命令を待機している常駐プログラムのこと
Docker Engine はクライアント・サーバーモデルのアプリケーション
[さわって理解する Docker 入門 第6回]
(https://www.ogis-ri.co.jp/otc/hiroba/technical/docker/part6.html)
.dockerignore を使ったファイル除外の指定
ビルドに関係ないファイルを除外する
アプリケーションの分割
1 つのコンテナーが取り扱う内容は 1 つにしぼる。
例えば、Go APIサーバーとmysqlサーバーを作成したいときは、
Goのコンテナ、mysqlコンテナをそれぞれ作成する。
Dockerfileを書くときのポイント
・イメージのビルドに必要がないファイルは含まないこと
・レイヤー数は最小に
Docker イメージは読み取り専用のレイヤーにより構成されます。 個々のレイヤーは Dockerfile の各命令を表現しています。 レイヤーは順に積み上げられ、それぞれは直前のレイヤーからの差分を表わします。
Dockerfile 記述のベストプラクティス
COPYなどの命令一行でレイヤーが一枚作成される。レイヤーが一行ごとに積みあがってimageが作成される。
同じDockerfileからimageを作成するとき、更新がなければ前回のimageのキャッシュが利用できる。imageを作成する時間が少なくて済むため、更新が少ないファイルに対する命令を前半に、更新が多いファイルに対する処理は後半に書くこと。
初回 Dockerfileとdocker-composeの設定
FROM golang:1.18-alpine as builder
ENV ROOT=/cafekatu/goapi
RUN mkdir -p ${ROOT}
WORKDIR ${ROOT}
COPY goapi/go.mod ./
COPY goapi/go.sum ./
RUN go mod download
COPY goapi/main.go ./
COPY goapi/controller ./
COPY goapi/model ./
RUN go get
RUN CGO_ENABLED=0 GOOS=linux go build -o $ROOT/binary
EXPOSE 8080
CMD ["/cafeKatu/goapi/binary"]
1行目:Goの元ファイルをダウンロード
2~4行目:linuxに/cafeKatu/goapiフォルダを作成、ワーキングディレクトリを設定。
ワーキングディレクトリとは、Dockerイメージの中のどのディレクトリで動作するかを設定する。
今回だと、Dockerイメージの/root/cafeKatu/goapiということ。
5~11行目
カレントディレクトリ(ビルドコンテキスト)からDockerの/cafeKatu/goapiにgo.mod go.sumをコピー
カレントディレクトリ(ビルドコンテキスト)からDockerの/cafeKatu/goapiにgoのソースをコピー
go.modに必要なライブラリを追加、不要なライブラリを削除
疑問 外部のリポジトリを利用してないからgogetするひつようあるのか???
12行目 クロスコンパイルで実行ファイルを作成する。Goはクロスコンパイルが便利なところが特徴の一つ。
クロスコンパイルとは、ソースコードを元に、開発に使用している機種やOSとは異なる環境向けに実行可能なコードを生成すること。
クロスコンパイル 【cross compile】
「 GOOS=linux」でDockerがLinuxの環境だからLinuxOS 向けのバイナリを生成してる?
Go のクロスコンパイル環境構築
「CGO_ENABLED=0」CGO_ENABLEDはコンパイル時にシステム native な C ライブラリの使用を指定するもの、0で無効になる。これよくわからない。
golang でクロスコンパイルする話
14行目 バイナリファイルを実行
Docker CMDとENTRYPOINTの使い方
○Dockerfile参考
[Goで作成したAPIをDockerで動かす]
(https://zenn.dev/kenny/articles/b9dd668bf09efe)
Golang - Dockerfileの最小構成
docker-compose
version: '3'
go-api-server:
image: go-api-server
container_name: go-api-server
build:
context: ./goapi
dockerfile: ../dockerfile/goapi/Dockerfile
env_file: ./goapi/env/dev.env
ports:
- "127.0.0.1:8080:8080"
depends_on:
- cafekatu_db
docker-composeを実施
以下のエラーが発生
cafekatu % docker-compose build --no-cache
[+] Building 3.1s (14/15)
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 32B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/golang:1.18-alpine 1.0s
=> CACHED [ 1/11] FROM docker.io/library/golang:1.18-alpine@sha256:7dc3de187ac994ac6d95a2e55fe87e962db391dddb4e28a0fdf0be4cd5962bbe 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 640B 0.0s
=> [ 2/11] RUN mkdir -p /cafekatu/goapi 0.2s
=> [ 3/11] WORKDIR /cafekatu/goapi 0.0s
=> [ 4/11] COPY goapi/go.mod ./ 0.0s
=> [ 5/11] COPY goapi/go.sum ./ 0.0s
=> [ 6/11] RUN go mod download 0.6s
=> [ 7/11] COPY goapi/main.go ./ 0.0s
=> [ 8/11] COPY goapi/controller ./ 0.0s
=> [ 9/11] COPY goapi/model ./ 0.0s
=> ERROR [10/11] RUN go get 1.1s
------
> [10/11] RUN go get:
#0 0.986 go: downloading github.com/akane-05/cafekatu v0.0.0-20220706064737-fe3f9a36b152
#0 1.044 github.com/akane-05/cafekatu/goapi imports
#0 1.044 github.com/akane-05/cafekatu/goapi/controller: cannot find module providing package github.com/akane-05/cafekatu/goapi/controller
#0 1.044 github.com/akane-05/cafekatu/goapi imports
#0 1.044 github.com/akane-05/cafekatu/goapi/controller/dto: cannot find module providing package github.com/akane-05/cafekatu/goapi/controller/dto
#0 1.045 github.com/akane-05/cafekatu/goapi imports
#0 1.045 github.com/akane-05/cafekatu/goapi/model/entity: cannot find module providing package github.com/akane-05/cafekatu/goapi/model/entity
#0 1.045 github.com/akane-05/cafekatu/goapi imports
#0 1.045 github.com/akane-05/cafekatu/goapi/model/repository: cannot find module providing package github.com/akane-05/cafekatu/goapi/model/repository
# 改善 Dockerfileとdocker-composeの設定
dockerfile
FROM golang:1.18-alpine3.15 as builder
ARG ROOT=/go/src/github.com/akane-05/cafekatu/goapi
WORKDIR ${ROOT}
COPY go.mod ./
COPY go.sum ./
COPY main.go ./
COPY controller/ ./controller/
COPY model/ ./model/
RUN go mod download
RUN CGO_ENABLED=0 GOOS=linux go install -v \
-ldflags="-w -s" \
${ROOT}
FROM alpine:3.15
COPY --from=builder /go/bin/goapi /goapi
RUN chmod a+x /goapi
RUN env
EXPOSE 8080
CMD ["/goapi"]
改善点
1.ディレクトリごとコピーしたい場合は
COPY controller/ ./controller/
と書く
DockerfileのCOPYでファイルやディレクトリごとコンテナにコピーする
2.envをARGに変更
ARGはbuild以降に有効、ENVはコンテナ(docker up)以降に有効。
テスト環境と本番環境でファイルを切り替えたりするときに便利。
ENVでは、コンテナ内で環境変数として変数が定義されます。 ARG は、 Dockerfileのbuild時に一時的に変数が定義され、コマンドの実行時に展開されます。ENVを使用する場合は、CMDやENTRYPOINTによって実行されたコマンドに適しており、ARGは、変数を展開した状態でコンテナ内にファイルを配置したい場合に有効です。
ARGは変数を展開した状態でコンテナに状態を設定するという特性から、コンテナが管理するファイルには有効ですが、 VOLUMEによって管理されているディレクトリに配置されているファイルに対してはENVを使ったほうが便利な場面が多いです。
Dockerfile ARG入門
3.go install だと不要にgo.modを変更することがなくなる。
Go1.16からは go get は使わず go install を使おう
4.コンパイルするとき-ldflags '-w -s'をするとサイズが小さくなって良い
Goプログラムのサイズを小さくする
Go のバイナリには -ldflags '-w -s' でコンパイルしてもたくさんパスが埋め込まれていた
5.go install -v
-v 現在コンパイル中のパッケージ名を出力します。
go install
このコマンドは実際には内部で2ステップの操作に分かれます。第1ステップはリザルトファイルの生成(実行可能ファイルまたはaパッケージ)、第2ステップはコンパイルし終わった結果を$GOPATH/pkgまたは$GOPATH/binに移動する操作です。引数はgo buildのコンパイルオプションをサポートしています。みなさんは-vオプションだけ覚えていただければ結構です。これにより低レイヤーの実行状況をいつでも確認することができます。
1.3 Goのコマンド
6.4と5のまとめ
RUN CGO_ENABLED=0 GOOS=linux go install -v \
-ldflags="-w -s" \
${ROOT}
上記では${ROOT}を小さいサイズgo install(リザルトファイルの生成)して現在コンパイル中のパッケージ名を出力してる
7.RUN chmod a+x
すべてのユーザーに全ての権限と実行権限を与える
chmod コマンド
8.ROOT=/go/src/github.com/akane-05/cafekatu/goapi
ベースイメージの「golang:1.18-alpine3.15」の中で、環境変数の「$GOPATH」に「/go」が設定されている
Goの各コードの中でのimport文の中で、モジュールを参照する際に「github.com/akane-05/cafekatu/goapi/controller」とが使用されていたため、
「$GOPATH/src」の下にソースコードを配置しないとモジュールのパスの解決ができないのでは?と考えられるため変更。
おそらく今はモジュールモードのため他パスでも大丈夫
9./go/bin/goapi
Executables are installed in the directory named by the GOBIN environment
variable, which defaults to $GOPATH/bin or $HOME/go/bin if the GOPATH
environment variable is not set. Executables in $GOROOT
are installed in $GOROOT/bin or $GOTOOLDIR instead of $GOBIN.
https://zenn.dev/asataka/scraps/71cbd9c6706474
10.Dockerfile内に「RUN env」という一文を追加
ベースとなるDockerイメージの環境変数の一覧を確認したい場合は、Dockerfile内に「RUN env」を追加
「docker-compose build --progress=plain --no-cache」というコマンドを実行😄
docker-compose
version: '3'
go-api-server:
image: go-api-server
container_name: go-api-server
build:
context: ./goapi
dockerfile: ../dockerfile/goapi/Dockerfile
env_file: ./goapi/env/dev.env
ports:
- "127.0.0.1:8080:8080"
depends_on:
- cafekatu_db
改善点
1.環境変数を定義するenvファイルを作成、追加
【Go】.envを使って環境変数を読み込む(godotenv) +osパッケージでenvを触ってみる。
.envで定義した環境変数をDocker,docker-compseで使用する例