ホスティング事業部の業務信頼性向上チームでエンジニアをしているはらちゃんです。 先日STREET FIGHTER 6のオープンベータに参加し、友人にボコボコに負けました。 製品版買っていい勝負ができるように特訓を重ねたいと思います。
今回、ホスティング事業部のサービスであるロリポップ、ムームードメイン、ヘテムル、おさいぽのDBリストアテストを自動化したので紹介します。
まず業務信頼性向上チームとは?
最初に、自分の所属している業務信頼性向上チームの紹介です。 ホスティング事業部内では、Internal System Reliability(業務信頼性向上)の頭文字をとってISRチームと呼ばれています(以下ISRチーム)。 ISRチームは社内で使用する顧客管理システムや業務ツールなどの信頼性を高めるチームです。 加えて、内部統制を含む業務プロセス改善を行うことやDX推進を支援することで、事業部全体の生産性向上をミッションとしています。 ざっくり言うと、一緒に働く仲間が働きやすい環境を整えるチームです。 現在2名(2023/06/01時点)のメンバーで、さまざまな業務改善やホスティング事業部で使用している社内システムの運用を行っています。
売上集計システムのマイグレーションを行った際の記事も投稿しているのでぜひ見てみてください!
リストアテストを継続的にやっている理由
データベースのリストアテストを継続的にやっているのは、有事の際にしっかりとデータベースを復旧するためです。 リストアテストを行うことで、リストアに使用したバックアップファイルの完全性をある程度担保できます。 これで、何かあった際に「このバックアップファイル、リストアできない!」ということを未然に防ぐことができます。
なぜ自動化したのか
今回DBのリストアテストを自動化したのには下記の理由があります。
- リストアテスト実施の責務がインフラエンジニアからアプリケーションエンジニア側に変わった
- 月初作業として手動でシェルスクリプトを使ったリストアテストを実施していた
- 検証のたびVMを立てて手動でシェルスクリプトを実行したくなかった
このように、テスト実施者が変わったこのタイミングでもっと楽に運用できるように自動化を行いました。
全体像
全体の構成は下記のようになっています。
DBからdumpをしたファイル自体は、各DBサーバーで定期実行され所定のディレクトリに保管されています。
今回の自動化では下記一連の流れを自動化しました。
- 各DBサーバーよりdumpファイルの取得
- 一時的なDBインスタンスへリストア
- リストアしたDBへ対しSQLクエリを発行し動作のテスト
- サマリーの出力
今回の自動化では、この1~3の処理をtakutakahashi/database-restore-actionに任せています。
このアクションは、設定ファイルを記載しておくだけで、scpを用いてDBサーバーからdumpファイルを取得して指定DBにリストア、クエリのテストまで行ってくれる便利Actionです。
また、scpだけではなくAmazon S3からファイルを取得してきたり、ローカルのファイルを直接指定したりもできます。とても便利〜
具体的な実装
今回はscpを用いた場合で自動化したので、その方法で実装を紹介します。
まず、GitHub Actionsのworkflowの内容です。
今回は、さっと動かしたいのでトリガーをworkflow_dispatch
としています。
name: restore_test
on:
workflow_dispatch:
jobs:
service1: # service1のリストアテストを行うjob
runs-on: hoge
services:
db: # リストア先のDBを設定
image: mysql
ports:
- 3307:3306
env:
MYSQL_ROOT_PASSWORD: hogefuga
options: --health-cmd "mysqladmin ping -h localhost" --health-interval 20s --health-timeout 10s --health-retries 10
steps:
- uses: actions/checkout@v3
- name: setup mysql-cli # リストアに必要なmysql-clientをインストール
run: |
apt update && apt install -y mysql-client
- name: set credentials # scpの際に必要となる秘密鍵をrunnerにセット
run: |
mkdir -p /root/.ssh/
echo "${{secrets.[sshに使用する秘密鍵]}}" > /root/.ssh/id_rsa
chmod 600 /root/.ssh/id_rsa
- name: backup test # リストアテスト実施
uses: takutakahashi/database-restore-action@main
env:
SSH_KEY: "/root/.ssh/id_rsa"
with:
config-path: .database/service1.yaml
service2: # service2のリストアテストを行うjob
runs-on: hoge
services:
db: # リストア先のDBを設定
image: mysql
ports:
- 3307:3306
env:
MYSQL_ROOT_PASSWORD: hogefuga
options: --health-cmd "mysqladmin ping -h localhost" --health-interval 20s --health-timeout 10s --health-retries 10
steps:
- uses: actions/checkout@v3
- name: setup mysql-cli # リストアに必要なmysql-clientをインストール
run: |
apt update && apt install -y mysql-client
- name: set credentials # scpの際に必要となる秘密鍵をrunnerにセット
run: |
mkdir -p /root/.ssh/
echo "${{secrets.[sshに使用する秘密鍵]}}" > /root/.ssh/id_rsa
chmod 600 /root/.ssh/id_rsa
- name: backup test # リストアテスト実施
uses: takutakahashi/database-restore-action@main
env:
SSH_KEY: "/root/.ssh/id_rsa"
with:
config-path: .database/service2.yaml
summary: # リストア結果のサマリーをissueに作成するjob
runs-on: hoge
needs: [service1, service2]
if: ${{ always() }}
steps:
- name: Create Title # issueのタイトルを変数にセット
id: create-title
run: echo "title=$(date '+%Y' --date '1 month ago')年$(date '+%m' --date '1 month ago')月レポート" >> "$GITHUB_OUTPUT"
- name: Create report # issueを作成
uses: imjohnbo/issue-bot@v3
with:
labels: "report"
title: ${{ steps.create-title.outputs.title }}
body: |
# report
| service | host | result |
| --- | --- | --- |
| service1 | [service1のhost] | ${{ needs.service1.result }} |
| service2 | [service2のhost] | ${{ needs.service2.result }} |
このworkflowは、service1
とservice2
のリストアテストを並列に行い、両方の完了を待ってからリストア結果のサマリーをissueに作成するjobであるsummary
が動きissueを作成します。
続いて、database-restore-actionの設定ファイルです。
database: # リストア先のDB情報(今回はActionで立てているDBの情報)
type: mysql # sqlドライバー
name: service1 # DB名
user: root # DBユーザー
password: hogefuga # DBパスワード
host: 127.0.0.1 # DBホスト
port: 3307 # DBポート
check:
- query: "select * from users" # テストクエリ
operator: exists # operator(今回は結果がある場合はテストPASSするように指定)
backup:
scp: # dumpファイルがあるサーバーの情報
host: 127.0.0.1 # ホスト
port: 22 # scpに使用するポート
user: user # scpをするユーザー
key: "path_to_backup_file/service1_{{ .Yesterday.Format \"20060102\" }}.gz" #dumpファイルがあるパス
設定のkey
にある、{{ .Yesterday.Format \"20060102\" }}
は、Action実行時に昨日の日時を20060102
のフォーマットで置き換えてくれます。
なので、毎日バックアップして世代管理している場合でもファイル名の指定がしやすくなります。
上記のような設定ファイルをservice2
も作成し、Actionsを実行してみると下記のようにservice1
とservice2
のリストアテストを並列に実行され両方の完了を待ってからsummary
が動きissueを作成していることがわかります。
この結果、issueに作成されるサマリーは下記のようになります。
これで、リストアテストの一連の流れが自動化できました。
実際に運用されているコードはもう少しそれぞれの環境に合ったものにカスタマイズされていますが、おおむね上記のようなコードとなっています。
実装時に困ったこと
今回の実装にあたり、困ったことが3点あったのでご紹介します。
dumpのサイズが大きすぎて通常のrunnerではリストアテストができない場合
今回ロリポップのDBのdumpはとても大きく、通常のrunnerだとストレージ容量が足りずリストアテストができませんでした。
セルフホストランナーを使用していたためストレージを多く持つインスタンスを生成し、runnerとして使用することで解決しました。
scpをするアカウントにdumpファイルを操作する権限がない場合
この場合、取れる方法は3つほどあると思います。
- 操作権限を持ったアカウントを使う
- dumpファイルを該当アカウントでも操作できる権限で生成するように変更する
- 権限昇格できるならば、sshで権限昇格しdumpファイルをhomeディレクトリなどにコピーして権限を変更する
- appleboy/ssh-actionなどを使うと便利だと思います。
今回の実装時には、実際に権限が足りない場合があり、database-restore-action
を実行する前に3の方法で解決しました。
その時に書いたstepのコードは下記になります。
- name: cp backup file
uses: pepactions/ssh-action@v0.1.10
with:
host: [dumpファイルがあるホスト]
username: hoge
key: ${{secrets.[sshに使用する秘密鍵]}}
port: 22
envs: FILE
script: |
sudo cp path_to_backup_file/[dumpファイル名] /home/hoge/.
sudo chmod 755 /home/hoge/[dumpファイル名]
dumpファイルのファイル名が微妙に違ってうまく指定できない場合
dumpのファイル名にダンプ完了時の時刻を使っている場合、微妙に分秒が違う場合があると思います。 その場合、database-restore-actionの設定ファイルでファイル名の指定ができないと思います。 下記のようなコードを使ってファイル名をサーバーから取得してきて設定ファイルにkeyを動的に挿入するstepを入れば解決しそうです。(keyが2つ設定されていると、うまく処理ができないので、あらかじめkeyは設定しないで動的に挿入されるものだけになるようにしてください。)
- name: set-file-name
id: set-file-name
run: |
name=`ssh hoge@[dumpファイルがあるホスト] "ls path_to_backup_file/" | grep "[dumpファイルの固定されている部分].*.gz"` # ファイル名をサーバーから取得
echo "file=$name" >> "$GITHUB_OUTPUT" # 後続でも使えるようにoutputしておく
echo " key: '/home/hoge/$name'" >> .database/service1.yaml # database-restore-actionのkey設定を追記する
終わりに
今回、リストアテストの自動化を行いました。
DBリストアテストのレポートが1つのリポジトリにまとまっているので内部統制の観点からも便利になったかと思います。
今後、リストアに問題ないということが確認されたファイルをS3にアップロードするなどカスタマイズもできそうです。
自分の所属しているISRチームは、こういった業務改善を技術力をもって行っているチームです。
一緒に働く仲間の環境やリソース状況を改善することに興味がある方は、お気軽にカジュアル面談の申し込みお待ちしています!!