目次


アジャイル DevOps

動的な構成

ソフトウェア・デリバリー・ライフサイクルにおける静的構成を削減する

Comments

コンテンツシリーズ

このコンテンツは全#シリーズのパート#です: アジャイル DevOps

このシリーズの続きに乞うご期待。

このコンテンツはシリーズの一部分です:アジャイル DevOps

このシリーズの続きに乞うご期待。

複数の環境の構成を管理する作業は、多くのソフトウェア・デリバリー・システムの悩みの種となりがちです。ほとんどの組織は、静的プロパティー・ファイル (local.properties、dev.properties、test.properties、stage.properties、prod.properties など) を使用して、異なる環境のプロパティーを管理します。私自身、今までそうした方法で多くのソフトウェア・デリバリー・システムを設計してきており、「万人のためのオートメーション: オートメーションによるデプロイメントの円滑化」という記事では、その方法を説明しました。その方法は、私が見てきた中では最も単純な方法の 1 つでしたが、多数のアプリケーションや何百というインスタンスのための、何百、さらには何千というプロパティーを持つソフトウェア・デリバリー・システムを管理しなければならない場合には、この方法はスケーラブルでないため、最終的に管理不能になります。構成が失敗する場合というのは、1 つのソフトウェア・システムに対して何百種類もの異なるプロパティー・ファイルがあり、そのいずれかに誰かが誤った値を入力したことによって発生するケースがほとんどです。

しかし、そうした状況に望みがないわけではありません。異なる環境間でソフトウェアを移行する場合にも、自動化、動的構成、クラウド・インフラストラクチャーを効果的に使用することにより、ソフトウェア・デリバリー・システムに必要な静的プロパティーを大幅に減らすことができます。この記事では、その方法について説明します。

典型的なプロパティー

表 1 に、組織内のチームが管理する典型的なプロパティーの一部を示します。

表 1. ソフトウェア・デリバリー・システムにおける典型的なプロパティー
プロパティー説明
IP アドレス一意に指定できる、ノードのロケーション
エンドポイント任意のノード (ロード・バランサー、インスタンスなど) のドメイン名
ドメイン名ユーザーがアプリケーションにアクセスするために使用し、一意に指定できるドメインの名前。ドメイン登録機関やドメイン・サービスとの間で、ドメイン名に関するやりとりが行われます。
データベース名アプリケーションが使用するデータベースの名前
ポート内部および外部からノードにアクセスする場合に使用される 0 から 65535 の間の一意の数値
ユーザー名とパスワードリソースへのヘッドレス・アクセスで使用されるユーザー名とパスワード
ディレクトリーとファイルオペレーティング・システム内のディレクトリーとファイル
SSH 鍵セキュアなリソースにアクセスするための Secure Shell 鍵ファイル

この表はすべてを網羅したものではありませんが、典型的なソフトウェア・システムで最も一般的に使用されるプロパティーを表しています。

従来のプロパティー管理

ソフトウェアを扱う組織のほとんどは、開発チームと運用チームのサイロで構成されており、開発チーム (つまり、開発者、テスター、アナリストなど) は多くの場合、以下の作業を行います。

  • ワークステーション関連のプロパティーを管理するためのファイル (local.properties など) を作成する。
  • dev.properties ファイル内にある「開発」環境用のプロパティーを変更し、そのファイルをバージョン管理リポジトリーにコミットする。動的プロパティー (IP アドレスなど) は変更される可能性があるため、そのような変更が発生した場合、開発チームは必ずこのファイルを変更する必要があります。
  • テスターが使用する IP アドレス、ファイル、ディレクトリーは異なる可能性があるため、test.properties ファイルをテスター向けに、属性は同じで値が異なるプロパティーに変更する。

開発チームが行う構成は通常、これでは終わりません。組織の開発サイドは、「開発」環境と「テスト」環境に加え、他の環境も管理するのが一般的です。

従来の組織では、ソフトウェア・デリバリー・サイクルの一部として、開発チームから運用チーム (DBA、システム/運用担当、リリース・エンジニアリング担当など) にソフトウェア・パッケージが引き渡され、下流工程の環境にそのソフトウェアがデプロイされます。運用チームは以下の作業を行います。

  • stage.properties ファイル内にある「ステージング」環境用プロパティーを変更し、そのファイルをバージョン管理リポジトリーにコミットする。
  • prod.properties ファイル内にある「本番」環境用の同様のプロパティーを変更し、そのファイルをバージョン管理リポジトリーにコミットする。動的プロパティー (IP アドレスなど) は変更される可能性があるため、そのような変更が発生した場合、運用チームは必ずこのファイルを更新する必要があります。

私はかつて、プロパティーを階層構造にしているチームを見たことがあります。このチームでは、ローカル、環境 (通常少なくとも 4 つの環境プロパティー・ファイルがありますが、大抵はもっと多くあります)、アプリケーション、サブシステム、インスタンスのプロパティーを階層構造にしていました。インスタンスが何百もある場合には、何百もの異なるプロパティー・ファイルがあり、IP アドレス、ディレクトリー、その他のプロパティーが頻繁に変更されると、その変更を管理するのは事実上不可能でした。その結果、環境の問題やデプロイ時のエラーが頻繁に発生することとなり、多くの場合、そのトラブルシューティングは非常に困難でした。それは、変更管理の難題 (つまり誰が何をいつ変更したかの管理) がエラーの根本原因の特定を難しくしていたからです。

外部化されたプロパティー

従来の手法を使用する、適切に設計されたソフトウェア・システムでは、環境によって異なる可能性のあるプロパティーは、すべてプロパティー・ファイルに外部化されます。つまり、変更される可能性のある設定がアプリケーション・コード内にハードコーディングされることはありません。しかしプロパティーが増えれば増えるほど、デプロイ時にエラーが発生しやすくなります。こうしたエラーは、トラブルシューティングが難しく、それに伴う代償も大きいため、ユーザーにソフトウェアを提供するための「ビルド推進」プロセスの遅れにつながりがちです。

リスト 1 は簡単なプロパティー・ファイルの例です。

リスト 1. プロパティー・ファイル内で定義される構成
jboss.home=/usr/local/jboss
jboss.server.hostname=jenkins.example.com
jboss.server.port=8080
jboss.server.name=default

複雑なシステムでは、この例のようなプロパティー・ファイルに何百というプロパティーが含まれることは、ごく一般的です。またそうしたプロパティーは通常、開発環境、テスト環境、ステージング環境、本番環境で重複しており、本番用にソフトウェアを提供する際には何百、あるいは何千というプロパティーを管理することになります。

リスト 2 に、プロパティー・ファイルから値を取得する Java コード・スニペットを示します。

リスト 2. プロパティーを取得する Java コード・サンプル
public PropertyReader(final String name, final ClassLoader loader) {
  try {
    InputStream is = loader.getResourceAsStream(convertName(name));
    if (is != null) {
      properties.load(is);
      is.close();
    } else {
      throw new IOException("Couldn't find property file: "
        + convertName(name));
      }
    } catch (IOException problem) {
        System.out.println("Property Reader: problem initializing");
  }
}

このコードには、チームがプロパティーの管理で使用する最も一般的な手法が示されていますが、最近のソフトウェア・デリバリー・システムは、今までにないスケールで動作することができます。ハードウェアのコモディティー化が進み、仮想化やクラウド・コンピューティングが利用されるようになったことにより、ソフトウェア・システムを提供、管理する際には何百もの環境を起動 (または終了) する可能性があります。そうした状況に合わせて、構成管理手法もスケーラブルでなければなりません。そして (同じくハードウェアのコモディティー化、仮想化、クラウド・コンピューティングのおかげで)、それは可能なのです。

動的構成の仕組み

この記事で紹介する手法では、プロパティーを動的に設定、取得します。インフラストラクチャー自動化ツールを使用して環境を定義する場合 (「アジャイル DevOps: インフラストラクチャーの自動化」を参照) には、データベース名、ファイル名、ディレクトリー名などの構成項目を構成データベースに設定します。その設定はスクリプトによって行うことができます。なぜなら、インフラストラクチャー全体がゼロからスクリプトで作成され、そのスクリプトがバージョン管理リポジトリーにコミットされるからです。また、クラウド・インフラストラクチャーや仮想インフラストラクチャーでは、従来のインフラストラクチャーでは静的に設定されることが多い IP アドレスやドメイン名などの構成項目を動的に設定、取得することができます。

リスト 3 のコードは、SimpleDB (NoSQL) データベースに構成項目をロードする Ruby スクリプトです。

リスト 3. 構成項目を NoSQL データベースに動的に書き込むコード
AWS::SimpleDB.consistent_reads do
  domain = sdb.domains["stacks"]
  item = domain.items["#{opts[:itemname]}"]
  
  file.each_line do|line|
    key,value = line.split '='
    item.attributes.set(
      "#{key}" => "#{value}")
  end
end

ユーザー名とパスワード

Capistrano は、スクリプトによってデプロイメントを定義するための Ruby ベースのドメイン特化言語 (DSL) です。リスト 4 のコードは、ユーザーが一度定義したパラメーターに基づき、データベースのユーザー名とパスワードを定義する Capistrano スクリプトです。

リスト 4. ユーザー名とパスワードを設定する Capistrano のコード
set :dataSourceUsername do
  item = sdb.domains["stacks"].items["wildtracks-config"]
  item.attributes['dataSourceUsername'].values[0].to_s.chomp
end
set :dataSourcePassword do
  item = sdb.domains["stacks"].items["wildtracks-config"]
  item.attributes['dataSourcePassword'].values[0].to_s.chomp
end

スクリプトによってインフラストラクチャーを完全に制御できるため、データベースのユーザー名とパスワードを自動生成し、セキュアな構成データベースに格納することができます。

この構成は、ソフトウェア・デリバリー・システムの他の部分すべてに使用することができます。このデータベースにデータをプッシュすると、そのデータを上流環境で動的に取得したり、下流環境で使用したりすることができます。

IP アドレス

リスト 5 のコードは、外部 IP アドレスを動的に設定して関連付ける AWS CloudFormation の JSON スクリプトの一部です。

リスト 5. IP アドレスを動的に設定する CloudFormation のコード
"IPAddress" : {
  "Type" : "AWS::EC2::EIP"
},

"IPAssociation" : {
  "Type" : "AWS::EC2::EIPAssociation",
  "Properties" : {
    "InstanceId" : { "Ref" : "WebServer" },
    "EIP" : { "Ref" : "IPAddress" }
  }
},

このようなスクリプトは、関連する自動テストと共にバージョン管理リポジトリーにコミットすることができます。

ドメイン名

CloudFormation で記述したリスト 6 の JSON コードは、AWS の Route 53 サービスを使用してアプリケーションの A ドメイン・レコードを動的に設定します。

リスト 6. ドメインを設定する CloudFormation のコード
"JenkinsDNS" : {
  "Type" : "AWS::Route53::RecordSetGroup",
  "Properties" : {
    "HostedZoneName" : { "Fn::Join" : [ "", [ {"Ref" : "HostedZone"}, "." ]]},
    "RecordSets" : [
    {
      "Name" : { "Fn::Join" : ["", [ { "Ref" : "ApplicationName" }, ".", \
      { "Ref" : "HostedZone" }, "." ]]},
      "Type" : "A",
      "TTL"  : "900",
      "ResourceRecords" : [ { "Ref" : "IPAddress" } ]
    }]
  }
},

このスクリプトを使用すると、DNS (Domain Name Service) プロバイダーを使用してドメイン名を手動で構成するという、従来の方法を行う必要がなくなります。

データベース名

リスト 7 のコードは、DatabaseName というパラメーターを定義する CloudFormation スクリプトです。

リスト 7. データベース名を設定する CloudFormation のコード
"Parameters": {
  "DatabaseName": {
    "Description" : "The name of the database",
    "Type": "String"
  }
}

このスクリプトによって、アプリケーション用の新しいデータベースが作成されると、DatabaseName パラメーターはインフラストラクチャー・スクリプト (Puppet マニフェストなど) に渡されます。このスクリプト全体をバージョン管理リポジトリーにコミットし、自動テストを作成すれば、データベースにアクセス可能かどうかを検証することができます。

ポート

リスト 8 のコードは、環境 (およびアプリケーション) に対する外部ポートを設定します。

リスト 8. セキュリティー・グループ内のポートへのアクセスを設定する CloudFormation のコード
"FrontendGroup" : {
  "Type" : "AWS::EC2::SecurityGroup",
  "Properties" : {
    "GroupDescription" : "Enable SSH and access to Apache and Tomcat",
    "SecurityGroupIngress" : [
      {"IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : "0.0.0.0/0"},
      {"IpProtocol" : "tcp", "FromPort" : "8080", "ToPort" : "8080",\
       "CidrIp" : "0.0.0.0/0"},
	  {"IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", \
	    "CidrIp" : "0.0.0.0/0"}
    ]
  }      
},

この例で外部からアクセスできるポートは、ポート 22 (SSH アクセス用)、ポート 8080 (Apache Tomcat 用)、ポート 80 (Apache HTTP サーバー用) のみです。CIDR (Classless Inter-Domain Routing) 表記を使用することで、ネットワークへのアクセス、さらには個々のノードへのアクセスをさらに制限することもできます (「参考文献」を参照)。

動的構成にする

この記事では、ほとんどのソフトウェア・デリバリー・システムで静的に定義される構成は、動的に定義することが可能であること、またそうすべきであること、そしてそれにより、ターゲット環境ごとに構成を変更する必要がなくなり、環境を作成するために必要となる構成可能なプロパティーの数を大幅に減らせることを説明しました。

次回の記事では、クラウド内で継続的ソフトウェア・デリバリーを行うためのオープンソース・プラットフォームを紹介し、そのプラットフォームを実行するための基本的なステップ、デリバリー・パイプラインの使い方、そして環境をプロビジョニングするためのジョブの実行方法とデプロイメントの実行方法について説明します。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=DevOps, Open source
ArticleID=928950
ArticleTitle=アジャイル DevOps: 動的な構成
publish-date=05092013