LoginSignup
14
14

More than 5 years have passed since last update.

複数のDockerイメージを単一リポジトリで管理する

Posted at

この記事はDocker Advent Calendar 2018の10日目の記事です。

はじめに

インフラチームとして提供する共通利用のDockerfileはDockerfileごとにリポジトリを作ってると沢山リポジトリが増えて結構大変です。しかし単一のリポジトリに複数のDockerfileを纏めると今度はCI/CDでDockerイメージをビルドするのが難しくなります。

この記事では複数のDockerfileを単一のリポジトリにまとめた時に、差分のあったDockerfileだけをビルドする構成について紹介します。

ディレクトリ構成

今回のサンプルの構成はgithubに上げてます。
https://github.com/kanga333/dockerfiles-monolepo

プロジェクトのディレクトリ構成は以下のような感じです。

dockerfiles-monolepo
├── Makefile
├── README.md
├── dockerfiles
│   ├── proxy-nginx
│   │   ├── Dockerfile
│   │   ├── Makefile
│   │   └── files
│   │       ├── nginx.conf
│   │       └── service.conf
│   └── python-lambda-builder
│       ├── Dockerfile
│       ├── Makefile
│       └── README.md
└── scripts
    └── git-diff-make.sh

dockerfilesの下にDockerfileごとのディレクトリを切っていくような構造になります。

構成のポイント

DockerfileのビルドをMakefileによって抽象化する

Dockerfile用のディレクトリにMakefileを用意してmake releaseコマンドを実行すればdocker build & pushしてくれるようにします。これによってリリース操作を抽象化します。

Makefileサンプル
NAME         := python-lambda-builder
REVISION     := $(shell git rev-parse --short HEAD)
ORIGIN       := $(shell git remote get-url origin | sed -e 's/^.*@//g')
RELEASE_TAGS := 1.0.0 $(REVISION)
TAGS         := $(REVISION)
REGISTRY     := index.docker.io
USER         := kanga333

.PHONY: build
build:
    @docker build \
        --build-arg GIT_REVISION=$(REVISION) \
        --build-arg GIT_ORIGIN=$(ORIGIN) \
        --build-arg IMAGE_NAME=$(REGISTRY)/$(USER)/$(NAME) \
        $(addprefix -t $(REGISTRY)/$(USER)/$(NAME):,$(TAGS)) .

.PHONY: push
push:
    @for TAG in $(TAGS); do\
        docker push $(REGISTRY)/$(USER)/$(NAME):$$TAG; \
    done

.PHONY: release
release:
    @make build TAGS="$(RELEASE_TAGS)"
    @make push TAGS="$(RELEASE_TAGS)"

ちなみに以前dockerをビルドする際のMakefileについて記事を書いたのでこちらも合わせて参照いただければと思います。
https://qiita.com/kanga/items/aba6928996cb57daa460

差分のあったディレクトリを検知するShellスクリプト

このshellスクリプトは前回のコミットとの差分を比較して更新があったディレクトリでのみmakeを実行するshellスクリプトです。

#!/bin/bash

set -eu

if [ $# -ne 1 ]; then
    echo "Please specify the argument of make." 1>&2
    exit 1
fi

TARGETS=`find dockerfiles -maxdepth 1 -mindepth 1 -type d`
for TARGET in $TARGETS
do
    HAS_DIFF=`git diff --diff-filter=ACMR --name-only HEAD\^ HEAD --relative=$TARGET | head -1`
    if [ ! -z $HAS_DIFF ]; then
        ( cd ${TARGET} && make $1 )
    fi
done

git diff --diff-filter=ACMR --name-only HEAD\^ HEAD --relative=$TARGET | head -1によって対象ディレクトリで差分があるか無いかを判断するフィルターを実現しています。

あとはCIでマスターにマージされた際にこのshellスクリプトを呼ぶことで差分のあったディレクトリのみでビルドが走るようになります。

sh scripts/git-diff-make.sh release

注釈

ただしこの方法だと前回のコミットとの比較なのでマージが動いた事が差分検知の前提になります。
PRごとにビルドをしたい場合はMasterにマージした後にsh scripts/git-diff-make.shを動かすようにCIを工夫する必要があります。

14
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
14