いますぐ実践! Linuxシステム管理

いますぐ実践! Linux システム管理 / Vol.244 / 読者数:2434名

こんばんは、うすだです。

やること FIFO (ときにはスタックかも)が一向に減らない日々を過ごしておりますが、 先日、とあるメルマガに書いてあった文に、びびびっと来てしまいました。

外資系コンサルの仕事を「絞り込む」技術 (ビジネスブックマラソン)
http://newsbiz.yahoo.co.jp/detail?a=20130627-00010006-bizbookm-nb

とある、ではないです、有名な、ビジネスブックマラソンでした。
ちなみに、びびびっと来た文は、以下の通りです。

  1. 仕事を切りの良い単位で小分けにする
  2. 小分けにした後は、やるべきことに注力して効率的に行う

…そうですね、わかっているひとが見れば、当たり前じゃないか! と思うかもしれません。
ですが、凡人のわたしが読みますと、 もやもやしたものがぱーっと開けるようなすっきり感を得ることができました。

あとは、上記と、

脳の気持ちになって考えてみてください。
http://www.1101.com/ikegaya2010/2010-10-01.html

にある、

「やりはじめないと、やる気は出ません。
 脳の側坐核が活動すると
 やる気が出るのですが、側坐核は、
 何かをやりはじめないと活動しないので。」

を組み合わせれば、やる気とか関係なく、自動的に体が動いて、 やるべきことをぱっぱとこなせるようになるんじゃないか、と思います。

で、結局これしかできていませんが、今回もはりきってまいりましょう。

今回のお題 - Puppet でシステムを集中管理する 帝国の逆襲

前回は、Puppet がなんぞやというのと、簡単な使用例を、 さらさらっとご紹介しました。

Vol.243 - Puppet でシステムを集中管理する
http://www.usupi.org/sysad/243.html

あまりにさらさらしすぎでしたので、今回は、 もう少し踏み込んだ内容をお届けしたいと思います。 ラインナップは以下の通りでございます。

  • リソース
  • マニフェスト (もう少しちゃんと)
  • リソースの順序
  • 変数 (fact もありますよ)
  • 制御構造 (というほどでもありませんが)

基本はリソースです

まずは、基本の「リソース」について説明します。

リソースとは、Puppet の管理対象となる単位のことです。
具体的には、ユーザアカウント、ファイル、サービス、パッケージ、 などなどなどなどです。(たくさんあります。)

Puppetでは、前回さらっとご紹介しすぎた「マニフェスト」に、 一元管理したい内容をリソースで記述します。そして、 リソース単位でシステムを設定します。

たとえば、以下のようなリソースの場合、

file { '/tmp/test1' :
    mode => 444,
    content => "test1",
}

パスが /tmp/test1、モードが 444、中身が test1 というファイルが存在してほしい、 というリソースです。ですので、これを site.pp に書いておくと、 各クライアントに同条件の /tmp/test1 がそのうち作られます。

リソースにはタイプ(型)というものがあり、リソースはいずれかのタイプに属します。 前述の /tmp/test1 は「file」というタイプに属します。

タイプを確認するには、「puppet」コマンドを使用します。 「describe」というサブコマンドと、 「-l」もしくは「--list」オプションを指定して実行すると、 リソースタイプの一覧が出力されます。

  $ puppet describe -l
  augeas      -  Apply a change or an array of changes to the ...
  computer    - Computer object management using DirectorySer ...
  cron        -  Installs and manages cron jobs
  exec        - Executes external commands
  file        - Manages files, including their content, owner ...
  ...後略...

個々のリソースタイプの詳細を知るには、 describeの後にタイプ名を指定して実行します。以下では、 「user」の詳細を確認しています。

  $ puppet describe user
  user
  ====
  Manage users.  This type is mostly built to manage system
  users, so it is lacking some features useful for managing normal
  users.
  ...すごく長いので後略...

 

ちなみに、puppet コマンドには「help」というサブコマンドがあり、 各サブコマンドの使い方を確認できます。

  $ puppet help
  Usage: puppet  [options]  [options]

  Available subcommands, from Puppet Faces:
    ca             Local Puppet Certificate Authority management.
    catalog        Compile, save, view, and convert catalogs.
  ...後略...

  $ puppet help describe

  puppet-describe(8) -- Display help about resource types
  ========

  SYNOPSIS
  --------
  Prints help about Puppet resource types, providers, and metaparameters.

  USAGE
  -----
  puppet describe [-h|--help] [-s|--short] [-p|--providers] \
  [-l|--list] [-m|--meta]
  ...後略...

…ですが、CentOS にはなかったりしました。

  $ puppet help
  Error: Unknown command help.
  Usage: puppet command 
  Available commands are: agent, apply, cert, describe, doc, \
  filebucket, inspect, kick, master, queue, resource

まあ、あったらラッキーと思っていただけますと幸いです。(適当…)

マニフェストをもうちょっと詳しく

マニフェストは、Puppet で動かすプログラムのことです。
各リソースの状態をずらずらっと指定します。
個々のリソースは、以下のように記述します。

  リソースタイプ { タイトル:
      属性 => 値,
      ...中略...
  }

各リソースタイプで指定できる属性は、前述の puppet describe を実行すると確認できます。
たとえば、file には、owner, group, mode, type, content, source などの属性があります。user には、uid, gid, home, shell, groups などの属性があります。

マニフェストに記述があるかどうかはともかく、リソースのいまの状態を確認するには、 puppetコマンドの「resource」サブコマンドを使います。
リソースタイプとタイトルを指定して実行します。

  $ puppet resource user root
  user { 'root':
    ensure  => 'present',
    comment => 'root',
    gid     => '0',
    home    => '/root',
    shell   => '/bin/bash',
    uid     => '0',
  }

 

ちなみに、マニフェストはそのまま使われるわけではありません。
コンパイルして「カタログ」というものに変換されてから、 クライアントに配られるようです。

/var/lib/puppet/client_yaml/catalog/ホスト名.yaml がそれです。

名前からわかるように、 「YAML(YAML Ain't a Markup Language)」 というフォーマットで記述されています。
YAML は、テキストで、インデントにより階層構造を表現するものです。
(コ、コンパイル…? …ま、まあ、気にしないでおきましょう。)

リソースは書いた順に解釈されません

マニフェストに書かれたリソースは、その順番に処理されるわけではありません。 そのため、別のリソースを前提とする場合、順序を明示しておく必要があります。

そのための属性が「before」「require」「notify」「subscribe」です。
どちらも、以下の形式で、依存するリソースを指定します。

  リソースタイプ[タイトル]

上記のリソースタイプでは、最初の文字を大文字にします。

before は、 指定したリソースより自分の方が先に必要であることを示すための属性です。 たとえば、前述の /tmp/test1 を作成してから、 test1 という nofity を実行したい場合は、以下のように記述します。
(notify は、メッセージ出力のためのリソースタイプです。)

file { '/tmp/test1' :
    mode => 444,
    content => "test1\n",
    before => Notify['test1'],
}

notify { 'test1' :
    message => 'I created test1.',
}

require は、beforeの逆で、自分に必要なリソースを指定するための属性です。 上記と同じ指定をrequireで記述すると、以下のようになります。
(あ、いまさらですが、「#」以降はコメントと解釈されます。)

file { '/tmp/test1' :
    mode => 444,
    content => "test1\n",
    # before => Notify['test1'],
}

notify { 'test1' :
    message => 'I created test1.',
    require => File['/tmp/test1'],
}

また、順番だけでなく、 必要なリソースが変更されたときにも反映されるようにするには、 notify や subscribe を使います。
たとえば、/etc/ssh/sshd_configを更新したら、 クライアントの sshd を再起動するには、以下のように記述します。

file { '/etc/ssh/sshd_config' :
    mode => 600,
    source => 'puppet://master/files/sshd_config',
    notify => Service['sshd'],
}

service { 'sshd' :
    ensure => 'running',
    enable => 'true',
}

同じ設定を subscribe で書くとこうなります。

file { '/etc/ssh/sshd_config' :
    mode => 600,
    source => 'puppet://master/files/sshd_config',
}

service { 'sshd' :
    ensure => 'running',
    enable => 'true',
    subscribe => File['/etc/ssh/sshd_config'],
}

あるいは、before や notify などを使わない方法もあります。
リソースの外側で、「->」や「~>」を使って記述します。
before や require と同じように順序だけを指定する場合は -> を、 更新時に反映もしたい場合は ~> を使います。

# File['/tmp/test1'] の後に Notify['test1']
File['/tmp/test1'] -> Notify['test1']

# File['/etc/ssh/sshd_config'] が更新されたら Service['sshd']
File['/etc/ssh/sshd_config'] ~> Service['sshd']

変数も使えます

言語には変数がつきもの、ということで、Puppet にも変数があります。
変数名の頭に「$」をつければ、変数になります。

  $変数名 = 値

扱える種類は、文字、数値、真偽値(true か false)、配列、連想配列、 undef などがあります。

配列の場合は、要素を「,」でつなぎ、全体を「[」と「]」で囲みます。

  $privusers = [ 'root', 'daemon', 'bin', 'sys' ]

要素を参照するには、変数名の後ろに「[添字]」をつけます。
たとえば、上記の0番目を指定するには $privusers[0] と記述します。

連想配列の場合は、まずキーと値を「=>」でつないで、それらを「,」でつなぎ、 最終的に全体を「{」と「}」で囲みます。

  $rsync = { user => 'root', server =< '/usr/bin/rsync' }

連想配列を参照するには、変数名の後ろに「[キー]」をつけます。
たとえば、上記のuserを指定するには $rsync[user] と記述します。

undef は、定義されていないことを示す特別な値です。

  $hoge = undef

とすると、変数 hoge が未定義になります。

 

Puppet には、定義済の変数(fact)もあります。
定義済みの変数を確認するには、「facter」コマンドを実行します。
「-p」もしくは「--puppet」オプションをつけて実行すると、一覧を出力してくれます。

  $ facter -p
  architecture => amd64
  augeasversion => 1.0.0
  facterversion => 1.6.9
  hardwareisa => x86_64
  hardwaremodel => x86_64
  hostname => master
  id => usu
  ...後略...

制御構造もあります

Puppet には、「if」文や「case」文もあります。

まずはif文ですが、書式は以下の通りです。

  if 条件1 {
      条件1にマッチしたとき
  } elsif 条件2 {
      条件2にマッチしたとき
  } else {
      マッチしなかったとき
  }

たとえば、前述の sshd サービスの名前は、RedHat系では sshd ですが、 Debian系では ssh です。
そんなときは、定義済の変数「osfamily」で区別できます。

if $osfamily == 'Debian' {
    $sshd_service = 'ssh'
} else {
    $sshd_service = 'sshd'
}

service { $sshd_service :
    ensure => 'running',
    enable => 'true',
}

 

case文の書式は、以下の通りです。

  case $変数 {
      値1: { 変数が値1のとき }
      値2: { 変数が値2のとき }
      ...中略...
      default: { どれにもあてはまらなかったとき }
  }

たとえば、先ほどの sshd のif文を case文に変換すると、以下のようになります。

case $osfamily {
    'Debian': { $sshd_service = 'ssh' }
    default:  { $sshd_service = 'sshd' }
}

 

他に、「セレクタ」というものもあります。
変数に代入する値を、別の変数の値で分けることができます。

  $変数 = $条件の変数 ? {
      条件値1 => 設定値1,
      条件値2 => 設定値2,
      ...中略...
      default => あてはまらなかったときの設定値,
  }

先ほどの sshd のやつは、セレクタを使えば、以下のように書けます。

$sshd_service = $osfamily ? {
    'Debian' => 'ssh',
    default  => 'sshd',
}

おわりに

以上、Puppet について、リソースを中心にいくつかご紹介しました。

あんまり実践という感じではなく、淡々と説明してしまいました。
…が、最低限な情報は必要だと思いますので、ゆるしてください。

ちなみに、今回は、以下をおおいに参考にしております。
もちろん英語で書かれていますが、英語能力が著しく乏しい私でも読めていますので、 奥せずご覧ください。

Learning Puppet
http://docs.puppetlabs.com/learning/

他にも、様々なドキュメントが用意されています。
もっと詳しく知りたいという貴兄は、ぜひご覧くださいませ。

Puppet Documentation Index
http://docs.puppetlabs.com/puppet/

ちなみに、次回も Puppet で引っ張ってしまおうかなという思惑があるかどうかは、 タイトルからご想像ください。

宿題の答え

前回の宿題は、

  マニフェストがどういう条件で実行されるのか、調べてみましょう。

でした。

前回使用した安直マニフェストで試してみました。

file { '/etc/this_is_a_test_for_puppet' :
    owner => 'root',
    group => 'root',
    mode => 644,
    source => 'puppet://master/files/this_is_a_test_for_puppet',
}

まずは、mode を 600 に変更してみました。
そして、クライアント側で puppet を再起動してみましょう。

  agent# service puppet restart
  (ちょっと間をおく)
  agent# ls -l /etc/this_is_a_test_for_puppet
  -rw------- 1 root root 5 Jul  7 09:50 /etc/this_is_a_test_for_puppet

大方の予想通り、600 に変更されました。
次に、site.pp はそのままで、ファイルの中身を変えてみました。

  master# echo test >> /etc/puppet/files/this_is_a_test_for_puppet

先ほどと同じく、クライアント側で puppet を再起動します。

  agent# service puppet restart
  (ちょっと間をおく)
  agent# ls -l /etc/this_is_a_test_for_puppet
  -rw------- 1 root root 10 Jul  7 09:55 /etc/this_is_a_test_for_puppet

こちらも、なんとなく予想していた通り、更新されました。
それでは、サーバ側のファイルのタイムスタンプだけ更新するとどうなるのでしょうか。

  master# touch /etc/puppet/files/this_is_a_test_for_puppet

クライアントのファイルのタイムスタンプに変化はありませんでした。

  agent# service puppet restart
  (ちょっと間をおく)
  agent# ls -l /etc/this_is_a_test_for_puppet
  -rw------- 1 root root 10 Jul  7 09:55 /etc/this_is_a_test_for_puppet

マニフェストから生成されるカタログの該当部分を見てみますと、 タイムスタンプに該当する情報は、特に見当たりませんでした。
ですので、純粋に中身を確認しているのではないか、と推測します。

  agent# less /var/lib/puppet/client_yaml/catalog/ホスト名.yaml
  ...中略...
  target: &id005 !ruby/object:Puppet::Resource
    catalog: *id001
    exported: false
    file: /etc/puppet/manifests/site.pp
    line: 6
    parameters: 
      !ruby/sym source: puppet://master/files/this_is_a_test_for_puppet
      !ruby/sym group: root
      !ruby/sym owner: root
      !ruby/sym mode: "600"
    reference: "File[/etc/this_is_a_test_for_puppet]"
    tags: 
      - file
      - class
    title: /etc/this_is_a_test_for_puppet
    type: File
  ...後略...

ついでに、クライアント側のファイルを中身を変えてみました。

  agent# echo usouso > /etc/this_is_a_test_for_puppet
  agent# ls -l /etc/this_is_a_test_for_puppet
  -rw------- 1 root root 7 Jul  7 10:00 /etc/this_is_a_test_for_puppet
  agent# service puppet restart
  (ちょっと間をおく)
  agent# ls -l /etc/this_is_a_test_for_puppet
  -rw------- 1 root root 10 Jul  7 10:05 /etc/this_is_a_test_for_puppet

当然といえば当然ですが、サーバ側の状態に戻されました。

というわけで、サーバ側の状態(設定)がなにかしら変われば、 反映されるということがわかりました。

今回の宿題

今回の宿題は、

  複数の設定ファイルのいずれかが更新されたら、サービスを再起動する
  よう設定してみましょう。

です。

Apache も Postfix も BIND も RSyslog も Puppet もあれもこれもそれもなんでもかんでも、 複数の設定ファイルで運用することが前提となっているように思います。

ですので、複数の設定ファイルのどれかが更新されたら再起動せねば、 ということの方が多いのではないかと思います。

というわけで、そのようなマニフェストをお書きくださいませ。

あとがき

タブレットやスマートフォンが普及し、 どのブラウザを使ってもほぼ問題なくアクセスできて、 非常に便利な世の中になったなあと思います。

わたしの場合、Firefox の重さに耐えかねて Chrome に乗り換えて以来、 最近の Firefox は軽くなったなぁ〜と感じつつも、 メインは Chrome を使い続けております。

さて、あるとき、Chrome が起動しなくなってしまいました。

Chromeを起動すると、一旦画面が表示された後、以前の状態に復元しようとして、 100%間違いなく確実に落ちます。
ですので、復元の処理のどこか(おそらく復元のためのデータのどこか)に問題があって、 とち狂ってしまわれているように見えます。

結局、「~/.config/google-chrome/Default」以下をごっそり消したら、 立ち上がるようにはなりました。

ありがたいことに、 拡張機能や設定のほとんどが Google のアカウントに保存されているため、 上記を消しても、ほぼもとの状態に戻せました。

というわけで、設定がネットにあると、 うっかり消してしまうこともないし同期もできるし、 いいことづくめであることを実感しました。

 

…ということを言いたいのではございません。

今回のように、なにが原因かわからないまま突然落ちてしまうと、 対処のしようがないですし、数少ない現象から調べるしかありません。
せめて、ここがおかしいみたいよとメッセージを吐いて死んでくれれば、 そのメッセージを手がかりに調べることもできます。

というわけで、問題に対処したり、 対処できなくてもその旨をメッセージに残して正しく(?) 異常終了したりすることの大切さの方を、しみじみと実感しました。

バグのないプログラムを作ることができないのと同様に、 あらゆることを想定したプログラムを記述するのは、 限りなく難しいのかもしれません。

ですが、漏れのないようリスクを洗い出して、 それぞれに対処する努力は極力行うべきです。また、そのための手法を勉強したり、 ルールを明確にするなどの努力も、プロアマ問わず、行っていくべきだと思います。

そして、そのことは、プログラム開発に限らず、 システム管理にも言えることなのかもしれません。安直に書いたスクリプトが、 二次災害を起こすことのないよう、気を引き締めていかねばと、 思いをあらたにしました。

 

…ほ、ほんとに思っていますよ。
本業が組み込み系ですので、対岸の火事ではございません。(-ε-;;;

 

今回も、ここまで読んでいただき、誠にありがとうございました。
次回は、7月21日(日) の未明にお会いしましょう!

 

「いますぐ実践! Linux システム管理」の解除は、以下からできます。
http://www.usupi.org/sysad/ (まぐまぐ ID:149633)

バックナンバーは、こちらにほぼ全部そろっています。
http://www.usupi.org/sysad/backno.html

「栗日記」- 気合入れて描くと、すっきりします。栗でも。
http://www.usupi.org/kuri/ (まぐまぐ ID:126454)
http://usupi.seesaa.net/ (栗日記ブログ)
http://usupi.org/k/ (モバイル栗日記)
http://twitter.com/kuriking/ (栗つぶやき)
http://facebook.com/kuriking3 (栗顔本)


[バックナンバーのトップへ] [Linux システム管理のトップへ]

トップ

バックナンバー
    [日付順] [目的別]

プロフィール

▼ リンク

独学Linux
Linuxデスクトップ環境に関する情報が満載です。 メルマガもありますよ。
Server World
CentOS 6をサーバとしたときの設定例が、これでもかというくらいたくさん載っています。 CentOS以外のディストリビューション(Fedora, Ubuntu)も充実しています。
LINUXで自宅サーバーを構築・導入(Fedora9)
Fedora9のインストールの仕方から管理方法まで、詳しく載っています。 SearchManには情報がもりだくさんです。
マロンくん.NET
〜サーバ管理者への道〜
Linuxをサーバとして使用するための、いろいろな設定方法が載っています。 マロンくんもかわいいです。 なんといっても、マロンくんという名前がいいですね!!
日経Linux
今や数少なくなってしまったLinuxの雑誌。ニュースやガイドもあります。
Linux Square − @IT
@ITが提供する、Linux の情報が満載。 載っていない設定方法はないんじゃないでしょうか。
gihyo.jp…技術評論社
Linuxに限らず様々な技術情報が満載のサイト。 SoftwareDesign誌も、 ソフトウェア技術者は必見です。
SourceForge.JP Magazine
Linux に限らず、オープンソース関連の記事が網羅されています。
ITmediaエンタープライズ:Linux Tips 一覧
Tips というより FAQ 集でしょうか。わからないことがあれば覗きましょう。
IBM developerWorks : Linux
開発者向けですが、勉強になりますよ。
Yahoo!ニュース - Linux
Yahoo!のLinuxに関するニュース一覧です。
栗日記
システム管理とかと全然関係ありませんが、毎日栗の絵を描いています。
システム管理につかれちゃったとき、癒されたいときに、ご覧ください。:-)
WEB RANKING - PC関連
ランキングに参加してみました。押してやってください。

▼ 作ってみました

Add to Google

▼ せんでん




▼ 最近読んだ本

▼ 気に入ってる本