文系プログラマによるTIPSブログ

文系プログラマ脳の私が開発現場で学んだ事やプログラミングのTIPSをまとめています。

ansibleを学ぶ:vol06:mysql-serverのインストールからcreate databaseまでを自動化する

yum install mysql-xxx時のコンフリクト、yum install MySQL-python時のコンフリクトにも対応してますよ〜


f:id:treeapps:20160219001058p:plain

本記事で行う作業全てを自動化するplaybookも用意しています(記事末尾で紹介)

環境

OS RHE v5系
ansible v2系
MySQL 5.5系

最新ではない環境とします。オンプレ案件で実際ありそうな環境を意識しています。

MySQL-serverのプロビジョニングのつらみ

1)MySQLのrpm(client、server)をダウンロードする。
2)ダウンロードしたrpmをインストールする。
3)mysql_dbモジュールはMySQL-pythonに依存しているのでインストールする。
4)mysql_dbを使ってDB構築する。

というものです。

要は「MySQL-serverをインストールして create databaseまで自動化したい」というだけなのですが、これが色々と面倒な事を含んでいるため、ハマりやすいのです。

問題1、yum install mysql が面倒

CentOS7からは標準リポジトリからMySQLはインストールできなくなっています。その場合repoを追加してインストールできるようなのですが、CentOS6系と7系とインストール方法が異なる時点でもうゲンナリしますね。vagrant上だとプロビジョニング成功するのにawsだと失敗するとか起きると嫌ですね。それにyumだと目的のバージョン、特に最新版はそもそもyumリポジトリに無いし、かなり古いバージョンしか提供されていなかったりするので、そこも嫌な点です。

という事で、個人的にはrepoを追加してyumでインストールするのではなく、MySQL公式サイトからrpmをダウンロードし、yumでダウンロードしたrpmをインストールする形をオススメします。このやり方なら、yum repoの状態を気にせずvagrantでもdockerでもawsでも簡単に同じバージョンをインストールする事ができます。

具体的には、以下のようにインストールします。

- block:

  - get_url: url={{ item.url }} dest=/usr/local/src/{{ item.file }} checksum={{ item.checksum }}
    with_items:
      - { url: "http://dev.mysql.com/get/Downloads/MySQL-5.5/MySQL-client-5.5.49-1.rhel5.x86_64.rpm", file: 'MySQL-client-5.5.49-1.rhel5.x86_64.rpm', checksum: 'md5:543ef6a181e5d18eda5a175586fc4c82' }
      - { url: "http://dev.mysql.com/get/Downloads/MySQL-5.5/MySQL-devel-5.5.49-1.rhel5.x86_64.rpm", file: 'MySQL-devel-5.5.49-1.rhel5.x86_64.rpm', checksum: 'md5:6423f04a071bd8288895347d4217272f' }
      - { url: "http://dev.mysql.com/get/Downloads/MySQL-5.5/MySQL-server-5.5.49-1.rhel5.x86_64.rpm", file: 'MySQL-server-5.5.49-1.rhel5.x86_64.rpm', checksum: 'md5:d84f892cd8154cdc765bfd4fb68db01e' }
      - { url: "http://dev.mysql.com/get/Downloads/MySQL-5.5/MySQL-shared-5.5.49-1.rhel5.x86_64.rpm", file: 'MySQL-shared-5.5.49-1.rhel5.x86_64.rpm', checksum: 'md5:a7b9ff67782b57ebabe8a8ca6ddf6a17' }

  - yum: name="mysql-libs-5.1.73-5.el6_7.1.x86_64" state=absent

  - yum: name=/usr/local/src/{{ item }} state=present
    with_items:
      - "MySQL-client-5.5.49-1.rhel5.x86_64.rpm"
      - "MySQL-devel-5.5.49-1.rhel5.x86_64.rpm"
      - "MySQL-server-5.5.49-1.rhel5.x86_64.rpm"
      - "MySQL-shared-5.5.49-1.rhel5.x86_64.rpm"

  become: yes

checksumは以下のMySQL公式サイトの右端にMD5の値が書いてあるので、これをそのまま使います。
MySQL :: Download MySQL Community Server

途中で「mysql-libs」をアンインストールしていますが、既にmysql-libsがインストールされている場合、mysql-serverのrpmインストール時にconflictが起きてインストールできないため、事前に削除しています。削除しても、mysql-serverのインストール時に依存として再びインストールされます。処理効率は悪いですが、衝突を避けるため、仕方なく行っています。

問題2、yum install MySQL-pythonでconflict

MySQL-pythonインストール時にも、問題1で起きたようなコンフリクトが起きます。

例えば以下のようにMySQL-pythonをインストールしようとします。

- yum: name=MySQL-python state=present

すると、以下のエラーが起きます。

トランザクションの確認エラー
  file /usr/share/mysql/charsets/Index.xml from install of mysql-libs-5.1.73-5.el6_7.1.x86_64 conflicts with file from package MySQL-server-5.5.20-1.rhel5.x86_64
  file /usr/share/mysql/charsets/README from install of mysql-libs-5.1.73-5.el6_7.1.x86_64 conflicts with file from package MySQL-server-5.5.20-1.rhel5.x86_64
・・・・中略・・・・
  file /usr/share/mysql/swedish/errmsg.sys from install of mysql-libs-5.1.73-5.el6_7.1.x86_64 conflicts with file from package MySQL-server-5.5.20-1.rhel5.x86_64
  file /usr/share/mysql/ukrainian/errmsg.sys from install of mysql-libs-5.1.73-5.el6_7.1.x86_64 conflicts with file from package MySQL-server-5.5.20-1.rhel5.x86_64

エラーの要約
-------------

", "rc": 1, "results": ["読み込んだプラグイン:fastestmirror
インストール処理の設定をしています
Loading mirror speeds from cached hostfile
 * base: ftp.iij.ad.jp
 * epel: ftp.iij.ad.jp
 * extras: ftp.iij.ad.jp
 * updates: ftp.iij.ad.jp
依存性の解決をしています
--> トランザクションの確認を実行しています。
---> Package MySQL-python.x86_64 0:1.2.3-0.3.c1.1.el6 will be インストール
--> 依存性の処理をしています: libmysqlclient_r.so.16(libmysqlclient_16)(64bit) のパッケージ: MySQL-python-1.2.3-0.3.c1.1.el6.x86_64
--> 依存性の処理をしています: libmysqlclient_r.so.16()(64bit) のパッケージ: MySQL-python-1.2.3-0.3.c1.1.el6.x86_64
--> トランザクションの確認を実行しています。
---> Package mysql-libs.x86_64 0:5.1.73-5.el6_7.1 will be インストール
--> 依存性解決を終了しました。

依存性を解決しました

================================================================================
 パッケージ         アーキテクチャ
                                 バージョン                 リポジトリー   容量
================================================================================
インストールしています:
 MySQL-python       x86_64       1.2.3-0.3.c1.1.el6         base           86 k
依存性関連でのインストールをします。:
 mysql-libs         x86_64       5.1.73-5.el6_7.1           updates       1.2 M

トランザクションの要約
================================================================================
インストール         2 パッケージ

合計容量: 1.3 M
インストール済み容量: 4.3 M
パッケージをダウンロードしています:
rpm_check_debug を実行しています
トランザクションのテストを実行しています

どうやら既存の「mysql-libs」と「MySQL-python」がコンフリクトしてしまうようで、yumでインストールできないようなのです。Vagrant + CentOSでもAmazon EC2でも同様です。

この場合、MySQL-pythonをソースからコンパイルしてインストールする方法もありますが、個人的に最もいい解決方法は、MySQL-pythonをpipでインストールするという方法だと思います。無茶なインストールを強行するとyum update時にも衝突したりして面倒なので、ヘルパー的な扱いのMySQL-pythonだけ、yumではなくpipにお任せしてしまうのです。

手順としては以下のようになります。

  1. pyenvをインストールする。
  2. pyenvでpython v2.7系をインストールする。
  3. mysql-client・mysql-serverをrpmでインストールする。
  4. pip install MySQL-python する。

これでyum installの衝突をさせずにMySQL-pythonをインストールする事ができます。

問題3、インストールしたMySQL-pythonが見つからない?

pip install MySQL-python は確かに成功しました。

しかしplaybookを実行しても、そんなモジュールは無いと言われます。何故でしょう。

答えはansibleはデフォルトpython、つまりpyenvでインストールしたpythonではなく、デフォルトの/usr/bin/python を使ってしまうため、折角pipでインストールしたMySQL-pythonが見つからないと言っているのです。(pipでインストールすると、MySQL-pythonは~/.pyenv/ 配下にインストールされる)

ということで、ansibleにpyenvでインストールしたpythonを使わせれば解決なのです。

- set_fact: ansible_python_interpreter=/home/{{ work_user }}/.pyenv/shims/python

これでタスクと途中でansibleが使うpythonのパスを変更する事ができるので、pyenv配下に変更します。この変更は以降ずっと有効になってしまうので、不要になったら以下のように元に戻しましょう。

- set_fact: ansible_python_interpreter="/usr/bin/python"

問題4、rootパスワードを変更したいが・・・

↑のやり方でMySQLをインストールしていくと、rootユーザのパスワードは未設定、つまり「mysql -uroot」でログインできる状態になります。

しかしrootユーザにはパスワードを設定しておきたいものです。ここでうっかりrootのパスワード変更をしてしまうと、次のタスク実行時には既にrootパスワードが変わっているためログインエラーになります。以下の例では、MySQLのrootユーザのパスワードを設定 -> MySQLのrootユーザで新規MySQLユーザを作成、としているだけのものです。

現在のroot password ansible実行時root password タスク内容
無し 無し root passwordをhogeに変更。
hoge 無し rootユーザで新規ユーザ作成。が、既にrootパスはhogeなのでログインエラー

しかしansibleは既にこうなる事を見ぬいていた・・・・!!!

ΩΩΩ<な、なんだってー!!

mysql_user - Adds or removes a user from a MySQL database. — Ansible Documentation
この「check_implicit_admin」を使うと解決できてしまいます。

check_implicit_admin=yes とすると、「mysql -uroot」でログインを試みてログインできたらそのまま処理を続行し、ログインエラーになったら「login_user」「login_password」の情報で再施行する、というものです。つまり、↑の例では1つ目のタスクでは「mysql -uroot」でログインしてrootパス変更が成功し、2つ目のタスクでは「mysql -uroot」でログインに失敗したので「mysql -uroot -phoge」で再施行して成功、という事ができます。

- mysql_user:
  login_user=root
  login_password=hoge
  login_port=3306
  host=192.168.33.31
  name=root
  password=hoge
  check_implicit_admin=yes # これ!!!
  state=present

しかしこのcheck_implicit_admin、ドキュメント見ると (added in 1.3) とか書いてあって、v1.3までこの現象に気づいて無かったんかい!とツッコミたくなります。1.3以前はrootパス固定でやってたのかなあ。

全作業をplaybook化

github.com
例によってモノを作っておきました。

オンプレ環境を意識した作業なので、dockerではなくvagrantで、しかも最新ではない環境(CentOS v6.5、MySQL v5.5)向けに作りました。

雑感

今回は、大人の事情等によって全くクラウド化できないオンプレ環境を想定して、mysql-clientとmysql-server環境を自動化するためのplaybookを書いてみました。

yum install時にコンフリクトエラーが出まくるし、rootパス問題もあるし、恐らく躓いた方も結構いるのではないかと思うので、是非playbookを使ってみてください。
github.com

世間では「docker!docker!」ですが、こうした基礎となるサーバ構築知識を付けておいて損は無いと思っています。「dockerでmysql-serverコンテナ起動すりゃ終わりじゃんwww 無駄な努力ご苦労様ですwww」と言いたくなる気持ちも解りますが、世の中にはまだまだ大人の事情でdockerやRDSを使えない環境も多いし、何より環境構築の知識がある = Dockerfileを書く力も付くという事に繋がるので、こういった基礎知識を付ける努力を怠らず、頑張っていきたいですね。

・・・とか言ってみましたが、実はdockerで全MySQL・全mariadbのサーバの環境を一発で構築するdocker環境も用意しています(全と言ってもMySQL5.1等の古いのは除外)。
www.bunkei-programmer.net
記事中にも記載していますが、githubにもdocker-compose.ymlを用意していますので、そちらもどうぞ〜
github.com

Ansible実践ガイド 第2版 (impress top gear)

Ansible実践ガイド 第2版 (impress top gear)

ansibleを学ぶ:vol01:vagrantを使ってansibleを動かしてみる - 文系プログラマによるTIPSブログ
ansibleを学ぶ:vol02:Oracle JDK1.8のインストール、ユーザパスワード設定等 - 文系プログラマによるTIPSブログ
ansibleを学ぶ:vol03:実行中のホスト名を書き込む、変数の値に変数を使用する - 文系プログラマによるTIPSブログ
ansibleを学ぶ:vol04:よくハマる部分とその解決法 - 文系プログラマによるTIPSブログ
ansibleを学ぶ:vol05:対象サーバのid_rsa.pubを対象サーバのauthorized_keysに登録する - 文系プログラマによるTIPSブログ
ansibleを学ぶ:vol06:mysql-serverのインストールからcreate databaseまでを自動化する - 文系プログラマによるTIPSブログ
ansibleを学ぶ:vol07:figletで動的にホスト名をmotdに書き込んでニヤニヤする - 文系プログラマによるTIPSブログ