この記事は、MicroAd (マイクロアド) Advent Calendar 2020 - Qiitaの24日目の記事です。
はじめに
マイクロアドでは、MySQLの本番スキーマを入れたDockerコンテナを用意し、開発チームのテスト用に使っていただいています。これ自体は、日次実行で最新のスキーマと同期したものが用意できていたのですが、開発案件が複数並列で進む関係上「更新が入る前のスキーマでテストがしたい」という要望が生じてきました。これまでは、要望がある度にMySQL管理者側でコンテナのビルドとプッシュを手動実行していましたが、これを開発者側でも行えるよう、AnsibleとAWXを使ったビルド・プッシュの仕組みを構築してみました。
Playbook
---
- name: Dockerイメージのビルド、プッシュを実行
hosts: "{{ docker_operation_host }}"
gather_facts: no
vars:
github_repository_name: docker-images-mysqldb
tasks:
- name: GitHubのリポジトリを取得
git:
repo: git@{{ github_domain }}/{{ github_organization }}/{{ github_repository_name }}
dest: /opt/{{ github_repository_name }}
accept_hostkey: true
no_log: true
- name: Dockerレジストリにログイン
docker_login:
registry_url: "{{ docker_registry_domain }}"
username: "{{ docker_registry_user }}"
password: "{{ docker_registry_token }}"
no_log: true
- name: ビルド用キャッシュとしてlatestタグのイメージをプル
docker_image:
name: "{{ docker_registry_domain }}/{{ github_organization }}/{{ mysql_hostname }}"
tag: latest
source: pull
- name: イメージをビルドし、Dockerレジストリにプッシュ
docker_image:
build:
path: /opt/{{ github_repository_name }}/images/{{ mysql_hostname }}
cache_from:
- "{{ docker_registry_domain }}/{{ github_organization }}/{{ mysql_hostname }}:latest"
args:
MYSQL_HOSTNAME: "{{ mysql_hostname }}"
MYSQL_USER: "{{ mysql_docker_user }}"
MYSQL_PASSWORD: "{{ mysql_docker_password }}"
name: "{{ docker_registry_domain }}/{{ github_organization }}/{{ mysql_hostname }}"
tag: "{{ lookup('pipe','date +%Y%m%d') }}"
push: yes
source: build
no_log: true
- name: プッシュしたイメージをローカルから削除
docker_image:
state: absent
name: "{{ docker_registry_domain }}/{{ github_organization }}/{{ mysql_db_name }}"
tag: "{{ lookup('pipe','date +%Y%m%d') }}"
MySQLのDockerfileはGitHubリポジトリ上で管理しているため、まずDockerイメージをビルドするホストにリポジトリをクローンし、ホストでビルドした後、Dockerレジストリにプッシュしています。
docker_image
タスクで tag: "{{ lookup('pipe','date +%Y%m%d') }}"
とすることにより、YYYYMMDD形式での実行日がタグとなってビルド、プッシュされます。
変数について
github_domain
: リポジトリを取得するGitHubのドメイン名
github_organization
: リポジトリを取得するGitHubのオーガナイゼーション名
github_repository_name
: 取得するGitHubリポジトリ
docker_registry_domain
: プッシュするDockerレジストリのドメイン名
docker_registry_user
: Dockerレジストリにログインするユーザ名
docker_registry_token
: Dockerレジストリにログインするユーザのトークン
mysql_hostname
: イメージを作成するMySQLのホスト名
mysql_docker_user
: MySQLのスキーマを取得するためのユーザ(要、SELECT権限)
mysql_docker_password
: MySQLユーザのパスワード
これらの変数のうち、Playbook内で与えていないものについてはgroup_vars(秘匿情報はansible-vaultで暗号化)またはAnsible AWXの追加変数で値を付与しています。
Dockerfile
FROM mysql:8.0
ARG MYSQL_HOSTNAME=unknown
ARG MYSQL_USER=unknown
ARG MYSQL_PASSWORD=unknown
RUN apt-get update && apt-get install -y --no-install-recommends wget && rm -rf /var/lib/apt/lists/* && \
# MySQLのスキーマをインポート
mysqldump -h${MYSQL_HOSTNAME} -u${MYSQL_USER} -p${MYSQL_PASSWORD} -B xxxx_db --no-data --lock-tables=false --set-gtid-purged=OFF > /docker-entrypoint-initdb.d/dump.sql
# 外部から渡される引数 (docker build時に渡される)
ARG GIT_REVISION=unknown
ARG GIT_ORIGIN=unknown
ARG IMAGE_NAME=unknown
LABEL git-revision=$GIT_REVISION \
git-origin=$GIT_ORIGIN \
image-name=$IMAGE_NAME
Oracle公式で提供されているMySQLイメージには /docker-entrypoint-initdb.d/
配下にあるSQLファイルをビルド時に実行する機能があるため、 mysqldump の --no-data
オプションでスキーマ情報のみを取得したダンプファイルを作成し、取得した環境と同一のスキーマを持ったDockerイメージを生成します。
Dockerのビルドを行う環境に上記ファイルをクローンし、 docker_image
タスクで MYSQL_HOSTNAME
などの引数をAnsibleから渡すことでmysqldumpを実行できるようにしています。
Ansible AWXでのジョブテンプレート化
上記のPlaybookを使用したジョブテンプレートをAnsible AWX上で作成し、開発チームのユーザにジョブの実行権限を付与することで、ワンクリックのジョブ実行でDockerイメージのプッシュまでが完了するようになっています。