Docker概要とDockerマルチステージビルドについて(Makefileでコマンドを作集約する)
まずdockerの基本概要の整理
DeamonとClientの関係
-
Docker Deamon
コマンドの受付場所。命令をAPIで受け取り, Dockerの機能に命令を出す部分
imageなどの情報を読み取り,コンテナを立ち上げる -
Docker Client
コマンドの受付場所でDocker Deamonとやりとりする
Docker Clientは複数PCに配置することも可能なので、Docker Deamonは複数箇所からAPIを受け付けることも可能。複数箇所からAPIを受け付けるには下記のコマンドでデーモンを起動する必要がある。
Docker Deamon側のコマンド
sudo dockerd -H tcp://0.0.0.0:2375
Docker Clentが遠隔地のDocker デーモンにコマンドを発行するには下記コマンドが必要
Docker Clinet
sudo docker -H tcp://<遠隔地のipアドレス>:2375 サブコマンド
例
sudo docker -H tcp://196.192.33.11:2375 images
マルチステージでDockerfileを作成してみる
今回はtestステージとリリースステージで作成してみます!
- testステージ作成
Dockerfile
FROM alpine AS test
LABEL application=todobackend
RUN apk add --no-cache bash git
RUN apk add --no-cache gcc python3-dev py3-pip libffi-dev musl-dev linux-headers mariadb-dev
RUN pip3 install wheel -U
COPY /src/requirements* /build/
WORKDIR /build
RUN pip3 wheel -r requirements_test.txt --no-cache-dir --no-input
RUN pip3 install -r requirements_test.txt -f /build --no-index --no-cache-dir
FROMの部分でAS testとすることでtestステージを明示することができる
上記のDockerfileを参照し、imageを作成する
docker build -t test-image .
docker historyコマンドで作成されたレイアーを確認してみる
docker history test-image
そうすると下記のように記載される
MAGE CREATED CREATED BY SIZE COMMENT
b1129dc9cf9d 5 minutes ago RUN /bin/sh -c apk add --no-cache bash git #… 15.2MB buildkit.dockerfile.v0
b1cdaccrra 5 minutes ago LABEL application=backend 0B buildkit.dockerfile.v0
b1cdsfewacd 5 months ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
b1cdsfewacd 5 months ago /bin/sh -c #(nop) ADD file:7fd90c097e2c4587d… 5.62MB
- 余談
このコマンドでimageのレイアーが下から順番に作成されていき、レイアーを積んで行っていることがわかる
もう一度dockerをbuildする際にこのレイアーがあれば使用する(キャッシュともいいう)のでdockerは高速でビルドが可能になる
また、RUNを実行した後のコンテナなどに接続することもでき、コンテナのレイアーごとにアクセすできるのでトラブルシューティングに役に立ちます!
アクセス方法
docker run -if iamgeID /bin/bash
RUNとCMDの違い
RUNはimage作成前に実行されimageレイヤーに積まれていくが
CMDはimageが作成された後にそのimageに対してコマンドを実行する際に使用します!
CMDとENTORYPIONTの違い
CMDに定義したコマンドはdocker run -it image /bin/bashを実行するとCMDが上書きされてしまうので、上書きして欲しくなければENTORYPIONTに定義するとよい
image削除したい場合は書きを実行すると削除される
docker rmi -f `docker image -q`
- 本番ステージの追加
FROM alpine AS test
LABEL application=todobackend
RUN apk add --no-cache bash git
RUN apk add --no-cache gcc python3-dev py3-pip libffi-dev musl-dev linux-headers mariadb-dev
RUN pip3 install wheel -U
COPY /src/requirements* /build/
WORKDIR /build
RUN pip3 wheel -r requirements_test.txt --no-cache-dir --no-input
RUN pip3 install -r requirements_test.txt -f /build --no-index --no-cache-dir
# ここから本番ステージ
FROM alpine
LABEL application=todobackend
RUN apk add --no-cache python3 py3-pip mariadb-client bash curl bats jq
# 本番用のユーザーは権限を絞るためにappグループを作成しappユーザーをそのグループに所属させている
RUN addgroup -g 1000 app && \
adduser -u 1000 -G app -D app
# ここが特殊で--from=test --chown=app:app /build /buildを行うことで
# testステージのbuildを本番ステージのbuildにコピーを行い, そのファイルの権限をappユーザーのappグループに所属させるようにしている
COPY --from=test --chown=app:app /build /build
COPY --from=test --chown=app:app /app /app
RUN pip3 install -r /build/requirements.txt -f /build --no-index --no-cache-dir
RUN rm -rf /build
WORKDIR /app
USER app
buildを行う
docker build -t reletese .
ここでtestステージのみbuildを行いたい場合は下記のように指定する
docker build -t test --target test .
docker-compose ファイルを作成してみる
- 雛形作成
version "2.4"
services:
test:
build:
context: .
dockerfile: Dockerfile
target: test
release:
build:
context: .
dockerfile: Dockerfile
depend_on:
db:
condition: service_healthy
db:
image: mysql:5.7
healthcheck:
test: mysqlshow -u $$MYSQL_USER -p $$MYSQL_PASSWORD
interval: 3s
retries: 10
environment:
MYSQL_DATABASE: test
MYSQL_USER: test_user
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: root_password
target: testをdcoker-compose ファイルの中に記載することでtestステージのDockerfileのみ起動可能となる
余談
depend_on:
db:
condition: service_healthy
上記でdbが正常に起動したらappを起動するようにしています。
service_healthy(サービス起動後health_checkが通れば)の他にもservice_stared(サービスが起動後に起動)
service completed_successfully(依存先のサービスが正常終了したら起動)
などがある
testステージのみコンテナを起動したい際は
dcoker-compose run test
extendsを使ってマイグレーションを行うサービスを作成する
version "2.4"
services:
test:
build:
context: .
dockerfile: Dockerfile
target: test
release:
build:
context: .
dockerfile: Dockerfile
depend_on:
db:
condition: service_healthy
app:
extend:
service: release
depend_on:
condition: service_healthy
port:
- 8000:8000
command:
サーバー起動コマンド
migrate:
extend:
service: release
depend_on:
condition: service_healthy
command:
マイグレーションコマンド
db:
image: mysql:5.7
healthcheck:
test: mysqlshow -u $$MYSQL_USER -p $$MYSQL_PASSWORD
interval: 3s
retries: 10
environment:
MYSQL_DATABASE: test
MYSQL_USER: test_user
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: root_password
上記のようにextendでreleaseコンテナを継承してサービスを作成することでアプリケーションを起動したい際はappサービスを起動, migrationを行いたい際はmigrateサービスを起動すればよくなる
docker-compose up migrate
docker-compose up app
今回extendsは同じファイルより読み込みを行ったが下記のようにすると、別ファイルから呼び出すことができる
app:
extends:
file: hogehoge.yml
service: fuefue
Makefileを作成していく
一旦簡単なMakefileを作成してみます
.PHONY: test clean
test:
@ echo "Hello world!"
touch test.txt
clean:
rm test.txt
下記で実行
make test
make clean
補足: @ echo "Hello world!"
@を使うとecho "Hello world!"の実行結果を表示するようになる
.PHONY: test cleanでmake testなどをしたときにtestファイルがあってもエラーが出ないようにしている
※スペースではなくタブなので注意
それでは今回のMakefileを作成してみる
.PHONY: test release clean
export APP_VERSION ?= $(shell git rev-parse --short HEAD)
test:
docker-compose build --pull release
docker-compose build
docker-compose run test
release:
docker-compose up --abort-on-container-exit migrate
clean:
docker-compose down -v
docker image -q -f dangling=true -f label=application=backend | xargs -I ARGS docker rmi -f --no-pruse ARGS
--pullをつけることで常に最新のimageを取得するようにしていいる
--abort-on-container-exitでエラーが発生した場合そこでコンテナ起動を終了するオプション
docker image -q -f dangling=trueの -f dangling=trueでタグのついていないimageをfilterし、 -f label=application=backendでlabelにapplication=backendがついているもののみをfilterしている
Discussion