拾い物のコンパス

まともに書いたメモ

Linux環境でのインストールスクリプト確認用にdocker-composeを整備する

開発したプログラムが複数の環境上で動くかどうかの確認をしたいときがある.
例えばUbuntu, CentOSはバージョン・ディストリの特徴によって環境が僅かに違うが,新しいOSをインストールした際の設定自動化スクリプトはどんな場所でも動いてほしい.
例えば自分が作成したプログラムのコンパイル・インストールをどんな環境でも動くスクリプト1つ実行する形にまで仕上げたいとき
しかしこれを全環境の仮想マシンを用意してチェックしていくのは面倒だ.
というわけでdocker-composeを使って一斉に各ディストリで動くかどうかをチェックする環境を作った話.

やりたかったこと

最初に書いた理由も再掲.

  1. 作ったプログラムが各ディストリ・バージョン上で動くかどうか簡単に確かめたい
  2. 開発環境で動くようになったがまっさらな環境で動くのか確認したい
  3. 上記を一斉に行いたい

とうわけでコンパイル・インストールを確認する環境を作り,自分の環境構築用スクリプトが動くかどうかを確かめた.

何を使って実現するか

他の人がどうやっているのか知らないがいくつか案を練った.

  1. Virtualboxを複数立てて(vagrantを使う?)SSHで同時接続
  2. コンテナ(docker-compose, Kubernetes)を使う
  3. ラズパイをたくさん買ってPCを複数接続できるキーボードを用意して頑張る(ド鬼畜)

3.は財布的・手間的にない.1.は理想的だが手間がかかる.
2.が現実的かな.
docker-composeKubernetesを比較すると後者のほうが大規模の構成ができそうだ.
が,今回の用途だとそこまで複雑な実装は不要そう.
zozoのブログが非常に刺激になり,現実的な実装を思いつけた.

考えたアーキテクチャ

考慮した結果こうなった.

f:id:poppycompass:20200205213220p:plain
イメージ
開発者は端末から最初コマンドを実行すればあとはコンテナを立ち上げ,各コンテナ内での標準入出力をログとしてホスト上に保存する.
ファイル構成はこんな感じ.

|--dists # 各ディストリ設定を置く
|  |--ubuntu
|  |  |--Dockerfile
|  |  |--personal-settings.yml
|--docker-compose.yml # 共通設定
|--.env # 環境変数
|--logs # 各コンテナからのログの保存先
|  |--ubuntu.log # ubuntuコンテナからのログ(dists/???は???.logというファイルを作る)
|--run_env_test.sh # テスト実行

コンテナの追加はシンプルにしたかった.
考えた結果,追加はdists以下にコンテナ用の設定ディレクトリを追加するだけで良いようにした.
$ cp dists/ubuntu dists/centosとかして,中のファイルをいじれば良い.

各ファイルの中身

dists/<ディストリ>/Dockerfile

例はubuntuの場合で説明.

FROM ubuntu # 好きなコンテナを指定.他の設定もお好みで追加.

dists/<ディストリ>/personal-settings.yml

ubuntuの場合.
各コンテナ固有の設定を書く. ホスト上のディレクトリをマウントして共有している.
commandのところに実行したいコマンドを入力する.
今入力されているのは環境構築用のスクリプト
最後のsleepコマンドはエラーが合った時にデバッグするためにbashを継続させる.

version: "3.7"
services:
  ubuntu:
    image: ubuntu
    tty: true
    container_name: 'ubuntu'
    environment:
      APP_ENV: ubuntu
    volumes:
      - ./dists/ubuntu/Dockerfile:/mnt/host/Dockerfile:ro
      - ./dists/ubuntu/personal-settings.yml:/mnt/host/personal-settings.yml:ro
      - ./logs:/mnt/host/logs
    command: bash -c 'apt -y update > /mnt/host/logs/ubuntu.log &&
                      apt -y install git >> /mnt/host/logs/ubuntu.log &&
                      git clone https://github.com/poppycompass/dotfiles >> /mnt/host/logs/ubuntu.log &&
                      cd dotfiles >> /mnt/host/logs/ubuntu.log &&
                      ./start.sh >> /mnt/host/logs/ubuntu.log &&
                      sleep 600'

volumes:
  ubuntu:
    driver_opts:
      type: none
      # 絶対パスで指定する
      device: /home/user/logs
      o: bind

.env

環境設定用ファイル.

UBUNTU=ubuntu

run_env_test.sh

テストを実行するために使うスクリプト
コンテナの完全初期化と実行というシンプルな内容.

#!/bin/sh
# installation test for each Linux distributions
TOPDIR="dists"
COMMON="docker-compose.yml"

readonly DEBUG=false
if "${DEBUG}"; then
  DISTS="ubuntu" # 1つずつの環境で実行したいとき
else
  DISTS=`ls ${TOPDIR}`
fi

# Run your installation process
function run () {
  for dist in ${DISTS}
  do
    # sudo docker ps
    # sudo docker exec -it <hash> bash
    sudo docker-compose -f ${COMMON} -f ${TOPDIR}/${dist}/personal-settings.yml -p ${dist} up -d
  done;
}

# Initialize all docker containers
function initialize () {
  sudo docker stop $(sudo docker ps -aq)
  sudo docker rm $(sudo docker ps -aq)
  sudo docker network prune -f
  sudo docker rmi -f $(sudo docker images --filter dangling=true -qa)
  sudo docker volume rm $(sudo docker volume ls --filter dangling=true -q)
  sudo docker rmi -f $(sudo docker images -qa)
}

# Show help
function show_help () {
  echo "Usage: ./run_env_test.sh [options]"
  echo "[options]: "
  echo "  run : run your installation process"
  echo "  init: initialize all container"
}

# Main routines
if [ "$1" == "run" ]; then
  run
elif [ "$1" == "init" ]; then
  initialize
else
  show_help
fi

実行

$ ./run_env_test.sh run
これで各コンテナが実行される.
$ tail -f logs/ubuntu.log
とかすればコンテナ内で何が行われているか把握できる.

初期化

コンテナをまっさらな状態にしたいときは
$ ./run_env_test.sh init

評価

やりたかったこと(再掲)

  1. 作ったプログラムが各ディストリ・バージョン上で動くかどうか簡単に確かめたい
    → 各ディストリ・バージョン環境の簡単な追加,コマンド実行ができるようになった!
  2. 開発環境で動くようになったがまっさらな環境で動くのか確認したい
    → コンテナを初期化することで毎回まっさらな環境で試せるようになった!
  3. 上記を一斉に行いたい
    → 一斉に起動可能!

最初に設定した要件は満たした.

改善が必要なところ

  • dockerは基本的にrootのため,user環境での実験作成
    add userからやるのであれば問題ないか?
  • プログラムを修正してからの再度実行に手間がかかる(Dockerの初期化・再起動させる必要がある.デバッグ時の細かい試し実行がしにくい)
    → 対策考え中

所感

しばらくはこれで運用しようと思う.
Kubernetesは勉強中のためこっちのほうが良さそうならまた同じような環境を作ろうと思う. もっと冴えたやり方を知っている方は是非教えてください.

参考

自動テストの実行環境をDockerでお気軽引っ越し - ZOZO Technologies TECH BLOG

Docker入門(第六回)〜Docker Compose〜 | さくらのナレッジ

複数のDockerコンテナを自動で立ち上げる構成管理ツール「Docker Compose」(Dockerの最新機能を使ってみよう:第7回) | さくらのナレッジ

Dockerfileでうまくマウントできないのでdocker-compose.yml使ってマウントする(o*。_。)o - Qiita

Docker Composeのトップレベルvolumesでホストのディレクトリをマウントする - ニューなんとなく書くブログ

docker-compose volumeマウント - Qiita