DockerHubが無課金で自動ビルド出来なくなった
公式ブログの記事によるとDockerHubの自動ビルドが暗号通貨マイニングに悪用されているため、2021年6月18日から無料利用枠でのAutobuildを廃止したとのこと。
CircleCIでDockerイメージビルドしてDockerHubにプッシュする
DockerHubには課金せず、CircleCIでDockerイメージをビルドしてDockerHubにプッシュする方法を考える。
CircleCIで使用する自前executorが必要なので、本末転倒だがCirleCIでビルドしてDockerHubに置くことにする。
手順は以下の通り
- GitHubにレポジトリを作って
.circleci/config.yml
とDockerfile
を置く - DockerHubにレポジトリを用意
- CirleCIに環境変数と登録しビルド〜プッシュを実行
.circleci/config.ymlの構成
GitHubのレポジトリにアップしたconfig.yml
はこちら。
再利用性を高めるため以下の3つのブロックで構成している。
commands
commands
は5つ用意した。
-
command-docker_checksum
はコンテキストディレクトリからキャッシュ用のチェックサムを生成する -
command-docker_build
はビルドを実行する -
command-docker_load
はキャッシュをロードする -
command-docker_save
はキャッシュを保存する -
command-docker_push
はプッシュを実行する
commands:
command-docker_checksum:
parameters:
context:
type: string
steps:
- run:
name: generate checksum.txt
command: |
rm -f /tmp/checksum.txt
cat $(find << parameters.context >> -type f | sort) >> /tmp/checksum.txt
command-docker_build:
parameters:
context:
type: string
dockerfile:
type: string
default: Dockerfile
target:
type: string
default: ""
image:
type: string
tag:
type: string
default: build
steps:
- run:
name: docker login
command: |
docker login -u $DOCKER_LOGIN -p $DOCKER_PASSWORD
- run:
name: docker build
command: |
if [ -z "<< parameters.target >>" ]; then
docker build --tag=<< parameters.image >>:<< parameters.tag >> --file=<< parameters.context >>/<< parameters.dockerfile >> << parameters.context >>
else
docker build --tag=<< parameters.image >>:<< parameters.tag >> --file=<< parameters.context >>/<< parameters.dockerfile >> --target << parameters.target >> << parameters.context >>
fi
command-docker_load:
parameters:
workdir:
type: string
default: /tmp/docker
image:
type: string
tag:
type: string
default: build
steps:
- run:
name: docker load
command: |
if [ -f "<< parameters.workdir >>/$(basename '<< parameters.image >>')_<< parameters.tag >>.tgz" ]; then
gunzip -c << parameters.workdir >>/$(basename '<< parameters.image >>')_<< parameters.tag >>.tgz | docker load
docker images << parameters.image >>:<< parameters.tag >>
else
echo "no cache"
fi
command-docker_save:
parameters:
workdir:
type: string
default: /tmp/docker
image:
type: string
tag:
type: string
default: build
steps:
- run:
name: docker save
command: |
if [ -n "$(docker images -q << parameters.image >>:<< parameters.tag >>)" ]; then
mkdir -p << parameters.workdir >>
docker save << parameters.image >>:<< parameters.tag >> $(docker history -q << parameters.image >>:<< parameters.tag >> | tail -n +2 | grep -v \<missing\> | tr '\n' ' ') | gzip > << parameters.workdir >>/$(basename '<< parameters.image >>')_<< parameters.tag >>.tgz
else
exit 1
fi
command-docker_push:
parameters:
image:
type: string
tag:
type: string
default: build
repo:
type: string
steps:
- run:
name: docker login
command: |
docker login -u $DOCKER_LOGIN -p $DOCKER_PASSWORD
- run:
name: docker push
command: |
if [ -n "$(docker images -q << parameters.image >>:<< parameters.tag >>)" ]; then
if [ -n "${CIRCLE_TAG}" ]; then
docker tag << parameters.image >>:<< parameters.tag >> ${DOCKER_LOGIN}/<< parameters.repo >>:${CIRCLE_TAG}
docker images ${DOCKER_LOGIN}/<< parameters.repo >>:${CIRCLE_TAG}
docker push ${DOCKER_LOGIN}/<< parameters.repo >>:${CIRCLE_TAG}
else
docker tag << parameters.image >>:<< parameters.tag >> ${DOCKER_LOGIN}/<< parameters.repo >>:latest
docker images ${DOCKER_LOGIN}/<< parameters.repo >>:latest
docker push ${DOCKER_LOGIN}/<< parameters.repo >>:latest
fi
else
exit 1
fi
executors
docker build
とdocker push
を使いたいのでDocker公式イメージをexecutors
として利用する。
executors:
docker:
docker:
- image: library/docker:latest
auth:
username: $DOCKER_LOGIN
password: $DOCKER_PASSWORD
jobsとworkflows
commands
に渡すcontext
とimage
はGitHubレポジトリと同じ。キャッシュ名も同様。
jobs:
docker_build:
executor:
name: docker
steps:
- setup_remote_docker
- checkout
- command-docker_checksum:
context: awscli-executor
- restore_cache:
keys:
- awscli-executor-v1-{{ checksum "/tmp/checksum.txt" }}
- awscli-executor-v1
- command-docker_load:
image: awscli-executor
- command-docker_build:
context: awscli-executor
image: awscli-executor
- command-docker_save:
image: awscli-executor
- save_cache:
key: awscli-executor-v1-{{ checksum "/tmp/checksum.txt" }}
paths:
- /tmp/docker
- persist_to_workspace:
root: /tmp
paths:
- docker
docker_push:
executor:
name: docker
steps:
- setup_remote_docker
- checkout
- command-docker_checksum:
context: awscli-executor
- restore_cache:
keys:
- awscli-executor-v1-{{ checksum "/tmp/checksum.txt" }}
- awscli-executor-v1
- command-docker_load:
image: awscli-executor
- command-docker_push:
image: awscli-executor
repo: awscli-executor
workflows
はmain
ブランチはlatest
としてタグはタグ名でDockerHubにDockerイメージがプッシュされる。
workflows:
version: 2
default:
jobs:
- docker_build:
filters:
tags:
only: /.*/
- docker_push:
requires:
- docker_build
filters:
tags:
only: /.*/
branches:
only: main
Dockerfile
AWS CLIのexecutorのDockerfile
をconfig.yml
に書いたcontext
と同じ名前のディレクトリに配置する。
FROM library/docker:19.03.15
ENV AWS_CLI_VERSION 2.0.63
ENV GLIBC_VER 2.31-r0
RUN apk update \
&& apk add --no-cache \
bash \
curl \
&& curl -sL https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub -o /etc/apk/keys/sgerrand.rsa.pub \
&& curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VER}/glibc-${GLIBC_VER}.apk \
&& curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VER}/glibc-bin-${GLIBC_VER}.apk \
&& apk add --no-cache \
glibc-${GLIBC_VER}.apk \
glibc-bin-${GLIBC_VER}.apk \
&& apk add --virtual .build-deps \
binutils \
unzip \
zip \
&& curl -sL https://awscli.amazonaws.com/awscli-exe-linux-x86_64-${AWS_CLI_VERSION}.zip -o awscliv2.zip \
&& unzip -q awscliv2.zip \
&& ./aws/install \
&& rm -f awscliv2.zip \
&& apk del .build-deps \
&& rm -rf /var/cache/apk/*
DockerHubにレポジトリを用意
config.yml
に書いたimage
名と同じ名前の空のレポジトリを作成するだけ。
CirleCIの設定
作成したGitHubレポジトリを取り込んでDockerHubログインの情報を環境変数(DOCKER_LOGIN
とDOCKER_PASSWORD
)として登録する。
DockerHubにプッシュしたイメージの確認
これでGitHubへのプッシュすれば今までと同じようにDockerHubにビルドイメージが自動でアップされる。