読者です 読者をやめる 読者になる 読者になる

めもめも

このブログに記載の内容は個人の見解であり、必ずしも所属組織の立場、戦略、意見を代表するものではありません。

アプリケーション環境構築の自動化をまじめに考えてみる(3)

復習

前回の記事では、アプリケーションの導入・設定の自動化をgithubと連携させるという試みを行いました。その際に発見された問題点は次のとおり。

・gitはファイルのオーナやパーミッションが扱えない
・アプリケーションの導入スクリプトはバージョン管理されず、職人技が入り込みやすい

ここでは、これらを改善する方法として、導入スクリプトの代わりにPuppetを利用する方法を試してみます。

通常、Puppetは、Puppetサーバから設定を一元管理しますが、実は、Puppetは、クライアントオンリーモード(?)でも使用することができます。次のように、クライアント上に用意したマニフェストファイルを指定して、puppetコマンドを実行すると、一回限りの設定作業が実行されます。

# puppet Manifest.pp

そこで、アプリケーションの導入・設定をすべてPuppetのマニフェストとして記述するというのはどうでしょうか? マニファスト、およびマニフェストから配布する設定ファイルをまとめてgithubにあげれば、アプリケーションに固有の導入手順もマニフェストとしてバージョン管理できるようになります。

これにより、KickStartから呼び出すインストールスクリプト自体は、「指定のリポジトリからマニフェストを取得して適用する」という形でアプリケーションに依存しない一般的なものになるので、前述の課題がクリアできる気がします。

というわけで、これに挑戦してみます。

前提条件として、自動インストールツールvirt-construct.pyは、タグ「article03」のバージョンを使用します。インストール対象のOSは、RHEL6.xで、puppetはEPEL経由で導入します。

Puppetマニフェストの準備

前回の記事と同様に、PostgreSQLを自動インストール/自動設定します。これをPuppetで実施するために、次のファイルを用意します。

$ tree pgsql_puppet/
pgsql_puppet/
|-- dist
|   |-- pg_hba.conf
|   `-- postgresql.conf
`-- main.pp

次のように、main.ppを指定してpuppetを実行すると、必要なインストール作業が行われるように構成します。

# puppet main.pp

ここでは、次のようなマニフェストを用意しました。(マニフェストの書き方は、一夜漬けなので、変な部分があってもご容赦ください。)

main.pp

import 'variables.pp'

class pgsql {
  service { 'postgresql':
    name      => 'postgresql',
###    ensure    => running,
    enable    => true,
    subscribe => Package['postgresql-server'],
  }

  package { 'postgresql-server':
    name   => 'postgresql-server',
    ensure => installed,
  }   

  file { '/var/lib/pgsql/data/postgresql.conf':
    owner   => 'postgres',
    group   => 'postgres',
    mode    => '0600',
    source  => "$manifest_dir/dist/postgresql.conf",
    notify  => Service['postgresql'],
    require => Exec['initdb'],
  }

  file { '/var/lib/pgsql/data/pg_hba.conf':
    owner   => 'postgres',
    group   => 'postgres',
    mode    => '0600',
    source  => "$manifest_dir/dist/pg_hba.conf",
    notify  => Service['postgresql'],
    require => Exec['initdb'],
  }

  exec {
    'initdb':
      path      => '/sbin',
      command   => 'service postgresql initdb',
      logoutput => true,
      creates   => '/var/lib/pgsql/data/PG_VERSION',
      before    => Service['postgresql'],
      require   => Package['postgresql-server'],
      notify    => Exec['init_pw'],
    ;

    'init_pw':
      path        => ['/sbin', '/bin'],
      command     => 'service postgresql start && \
                      su - postgres -c "psql -w -c \
               \"ALTER USER postgres encrypted password \'pas4pgsql\'\"" && \
                      service postgresql stop',
      logoutput   => true,
      refreshonly => true,
      before      => [Service['postgresql'],
                      File['/var/lib/pgsql/data/pg_hba.conf'],
                      File['/var/lib/pgsql/data/postgresql.conf']],
    ;
  }
}

include 'pgsql'

冒頭でimportしているvariables.ppは、配布する設定ファイルdist/*のベースディレクトリ名を$manifest_dirに設定するものです。この一連のファイル群がgithubからダウンロードされて、「/tmp/gittmp/<レポジトリ名>」以下に展開される前提となっており、このディレクトリを$manifest_dirにセットします。

variables.pp

$manifest_dir = '/tmp/gittmp/pgsql_puppet'

このファイル(variables.pp)自体は、KickStartから自動実行する際に動的に生成します。dist以下の設定ファイル(postgresql.conf、pg_hba.conf)は、好みの設定にしておきます。

そして、用意したマニフェストと設定ファイル一式をgitの管理下において、githubにアップロードしておきます。(githubでのリポジトリ作成、登録はできているという前提です。)これには、「v1_0」というタグを振っておきます。

# cd pgsql_puppet
# git commit -m "First release"
# git tag v1_0
# git push --tags

実際にアップロードしたものは、こちらにあります。

KickStartからの自動インストール

KickStartのpostセクションで次のスクリプトを実行すると、githubから必要なマニフェストを取得して、アプリケーション(PostgreSQL)の導入・設定が行われます。

## Application deployment template
yum -y install http://mirror.us.leaseweb.net/epel/6/i386/epel-release-6-7.noarch.rpm
yum -y install puppet

#---------------------------------#
# Specify your repository and tag #
#---------------------------------#
GitRepository=https://github.com/enakai00/pgsql_puppet.git
ConfigTag=v1_0

RepoName=${GitRepository##*/}
RepoName=${RepoName%.git}

rm -rf /tmp/gittmp
mkdir -p /tmp/gittmp
cd /tmp/gittmp
git clone $GitRepository
cd $RepoName
[[ ! -z $ConfigTag ]] && git checkout $ConfigTag
echo "\$manifest_dir = '/tmp/gittmp/$RepoName'" > variables.pp
puppet main.pp

冒頭の「GitRepository」「ConfigTag」で使用するリポジトリとタグを指定する以外は、完全に汎用的な作りになっています。アプリケーションの導入・設定手順は、リポジトリから取得するマニフェストに隠蔽されているわけです。

これを先の「virt-construct」ツールから一気通貫で実行できるようにvirt-constructの設定ファイルに埋め込んだものが、こちらになります。(設定ファイルの仕様上、一部、エスケープ用の\記号が追加されています。)

実際の実行結果(postセクションの実行ログ)はこちらになります。

# cat anaconda-post.log 
+ echo '192.168.122.99	pgsql01'
+ cat
+ yum -y install http://mirror.us.leaseweb.net/epel/6/i386/epel-release-6-7.noarch.rpm
Loaded plugins: product-id, security, subscription-manager
Updating certificate-based repositories.

(中略)

Installed:
  epel-release.noarch 0:6-7                                                     

Complete!
+ yum -y install puppet
Loaded plugins: product-id, security, subscription-manager
Updating certificate-based repositories.

(中略)

Installed:
  puppet.noarch 0:2.6.17-2.el6                                                  

Dependency Installed:
  augeas-libs.x86_64 0:0.9.0-4.el6      compat-readline5.x86_64 0:5.2-17.1.el6  
  facter.x86_64 0:1.6.6-1.el6           libselinux-ruby.x86_64 0:2.0.94-5.3.el6 
  ruby.x86_64 0:1.8.7.352-7.el6_2       ruby-augeas.x86_64 0:0.4.1-1.el6        
  ruby-libs.x86_64 0:1.8.7.352-7.el6_2  ruby-shadow.x86_64 0:1.4.1-13.el6       

Complete!
+ GitRepository=https://github.com/enakai00/pgsql_puppet.git
+ ConfigTag=v1_0
+ RepoName=pgsql_puppet.git
+ RepoName=pgsql_puppet
+ rm -rf /tmp/gittmp
+ mkdir -p /tmp/gittmp
+ cd /tmp/gittmp
+ git clone https://github.com/enakai00/pgsql_puppet.git
Initialized empty Git repository in /tmp/gittmp/pgsql_puppet/.git/
+ cd pgsql_puppet
+ [[ ! -z v1_0 ]]
+ git checkout v1_0
Note: checking out 'v1_0'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b new_branch_name

HEAD is now at 5ef8f88... fix manifest dependency
+ echo '$manifest_dir = '\''/tmp/gittmp/pgsql_puppet'\'''
+ puppet main.pp
warning: Could not retrieve fact fqdn
notice: /Stage[main]/Pgsql/Package[postgresql-server]/ensure: created
notice: /Stage[main]/Pgsql/Exec[initdb]/returns: データベースを初期化中: [  OK  ]
notice: /Stage[main]/Pgsql/Exec[initdb]/returns: executed successfully
notice: /Stage[main]/Pgsql/Exec[init_pw]/returns: postgresql サービスを開始中: [  OK  ]
notice: /Stage[main]/Pgsql/Exec[init_pw]/returns: ALTER ROLE
notice: /Stage[main]/Pgsql/Exec[init_pw]/returns: postgresql サービスを停止中: [  OK  ]
notice: /Stage[main]/Pgsql/Exec[init_pw]: Triggered 'refresh' from 1 events
notice: /File[/var/lib/pgsql/data/postgresql.conf]/content: content changed '{md5}04246025b15a71bec286a19abffdcb82' to '{md5}4b7b7481f9bf86fdc7f887f65944aef4'
notice: /File[/var/lib/pgsql/data/pg_hba.conf]/content: content changed '{md5}a21038ed8e80ad95d01da9cb6b0ae403' to '{md5}3d7342d0bc0c5e1700ccec5f2c5571fb'
notice: /Stage[main]/Pgsql/Service[postgresql]/enable: enable changed 'false' to 'true'
notice: /Stage[main]/Pgsql/Service[postgresql]: Triggered 'refresh' from 3 events
notice: Finished catalog run in 28.50 seconds