• DevOps時代のアジャイルでスケーラブルな開発環境をVagrant, GitHub, Travis, Chef, OpsWorksで構築する

    どうも。久しぶりです。 デベロッパーの平形です。 このブログに訪れたすべてのエンジニアの方々。 そして、エンジニア以外の方々。 とても感謝致します。 初めに言っておきますが、この記事ではコード、コマンドラインの一切は登場しません。 はじめに 私が今回お送りする内容は本当にスケーラブルな環境の構築、運用を手助けする事ができます。 連載記事で複数回に渡ってお届けしますが、この連載を読み終えそして実践していただければ、あなたは既にスケーラブルな環境で作業を行っている事でしょう。 この連載記事では、順番に必要なツールのインストール、使い方をハンズオン形式でお送りします。 実際に手を動かして実感していただく事がとても意味がある事だと思っています。 この回では、コード、コマンドラインは一切登場しません。次回以降にどんどん出てきます。 その前に**「伝えたい事があるんだ。君の事が好きだから」by小田和正**と叫ばせてください。 この記事は以下の方には不向きです。 俺は一生一人で生きていくんだ!と1日1回はトイレで意気込んでいる人。 後先の事なんか考えたくない。俺は今を生きているんだ!と週に3回は言っている人。 これらに該当する方。お疲れ様でした。出口はこちらです。 この記事は以下に該当する方に是非読んでいただきたいです。 開発者、インフラ担当者の方。 これから新しいプロジェクトを立ち上げるんだけど、構成どうしようか悩んでる方。 サーバーの台数が多くなったらどうしよう。と悩んでいる方。 開発要員が急に増えたらどうしよう。と悩んでる方。 DevOpsとかスケーラブルな環境とかに興味があって、でも今ひとつ踏み出せない方。 上記を実践してみようとしたけど、挫折してしまった方。 開発環境で動いているコードがなぜか公開環境で動かなくて家に帰れない方。 本番反映が怖くて会社に行きたくない方。 サーバーが落ちる事が不安で夜も眠れない方。 将来の事を考えると不安で不安で仕方なく、「とにかくもう、学校や家には帰りたくない〜。」by尾崎豊と口ずさんでしまう方。 それでは、夢の扉を開きましょう。 レガシーな開発と運用 開発環境、公開環境の構築は、構築手順書を元に手動でインストールしている。 公開環境のサーバー増設は1台ずつ手動でキッティングしている。 パッチの適用、バージョンアップは手動で1台ずつ手順書を元に実行している。 バージョン管理はしないで各自、修正ファイルをFTPでファイルをアップロードしている。 これらをヒューマンエラーなく、ストレスなく運用できるのはスーパーマンです。 そして、開発、運用メンバー全員が自分と同じスーパーマンでなければいけません。 凡人の僕には無理です。 現代の開発と運用 現代のもの凄い勢いで変化するサービス要求に耐えるには、様々なものを効率化しなければいけません。 素早くリリースしてユーザの反応を見ては仕様を変更してすぐに反映しまたリリースする。といった事も必要です。 近頃、開発運用の自動化は様々なメディアの記事で取り上げられ、賑わっています。 しかし、実際にどこまで自動化ができているのでしょうか? バージョン管理 環境構築 セキュリティパッチの適用 バージョンアップ オートスケール 自動テスト 自動デプロイ 開発環境の配布 なかなか全部はできないですよね? でもやったほうが絶対に幸せになれます。
    ...
  • Capistrano3のタスク内でトップレベルのタスク名を取得する

    Capistrano3でタスク書いていて、タスク内でcapコマンドとして実行されたトップレベルのタスク名を引いて、処理を分岐させる必要が生じて、そのトップレベルのタスク名取得に苦労したので、ここに備忘録化しておく。 基本的にCapistrano3でタスク内で自分のタスク名を取得したい場合、次のようにブロックの引数として引ける。 desc "main task" task :main_task => :sub_task do |task| run_locally do info ": This task name: #{task}" info ": Running main deploy task!" end end desc "sub task" task :sub_task do |task| run_locally do current_task = task.name_with_args.split(':').last info ": This task name: #{current_task}" end end 上記タスクを実行してみると、こうなる。 $ cap test deploy:main_task INFO: This task name: sub_task INFO: This task name: deploy:main_task INFO: Running main deploy task!
    ...
  • Capistrano3でタスクが二重起動してしまう時の対処法

    Capistrano3でステージ環境を変えてタスクを実行した時に、タスクが二重起動するという症状に陥った。二重でタスクが実行されるので、ラウンチするAWSインスタンスを“2つ”と設定していても“4つ”起つし、MySQLに発行するクエリも2倍になって、INSERTするレコードが重複して挿入される。一時的にファイルに書き出していた設定なども二重起動している後続タスクによって上書きされてしまい、もうデプロイはしっちゃかめっちゃかな状態だった。 解決できたので、その時の対処法を備忘録として残しておく。 原因はinvoke設定でデフォルトのデプロイ環境を指定していたためだった。 はじめ、試験環境でデプロイタスクの開発を行っていた時、Capfileに下記のような設定を書いていた。 Rake::Task[:develop].invoke invoke :develop これを書いておくと、デフォルトデプロイ環境がdevelopに固定化されるので、デプロイコマンドを実行するときに本来ならデプロイ環境(ステージ名)を指定して、 $ cap develop deploy:task_name のようにするところを、 $ cap deploy:task_name と、デプロイ環境を省略できてちょっとだけ楽だったのだが、これがデフォルトデプロイ環境以外にデプロイを行う時に悪影響を及ぼしたのだ。 今回、試験環境でデプロイが上手くいったので、次に本番環境でデプロイを行うことになり、デプロイ環境(ステージ名)をproductionで実行することになった。デプロイ内容は試験環境とまったく同一だったため、デプロイタスク設定の差分はなく、ロール設定やSSH接続設定も同じだったため、config/deploy/develop.rbをコピーしてconfig/deploy/production.rbを作成していた。 この状態で、下記のようにデプロイ環境を指定してデプロイを実行した次第。 $ cap production deploy:task_name これだと、省略されているデフォルトデプロイ環境へのデプロイも同時に起動してしまうわけです。実際には、 $ cap develop production deploy:task_name と環境を二つ指定してデプロイを実行しているのと同じことになっているわけです。 この状態を解消するには、前述のinvoke設定を削除するだけです。 というか、複数環境に対してデプロイが発生する時は混乱の元になるんで、invoke設定とかはしない方がいいですね。 いやはや、何気に解決するまで数時間ハマってました。今後は注意しないと。
    ...
  • Capistrano3でEC2インスタンス新規作成から初期設定までのデプロイ(まとめ)

    ここまでAWSのEC2インスタンスを新規作成して、そのインスタンスに対しての初期設定までを、Capistrano3でタスク化することをやって来ました。難儀したものの、ようやくEC2インスタンスの準備が出来て、あとはミドルウェアやアプリケーションをインストールするだけ──というところまでたどり着きました。そこで今回は、これまでのデプロイの流れを一度総括してまとめてみようかと思います。 まず、Capistrano3を稼動させるデプロイサーバの準備から。公式のAmazon Linux環境などのEC2インスタンスをAWSマネージメントコンソール等からラウンチして、ログインしたら、Capistrano3をインストールします1。 # yum update -y # yum groupinstall -y "Development Tools" # openssl version OpenSSL 1.0.1h-fips 5 Jun 2014 # openssl version -d OPENSSLDIR: "/etc/pki/tls" # curl -L https://get.rvm.io | bash -s stable # source /etc/profile.d/rvm.sh # rvm list (※ rvm rubies と表示されればインストール完了) # ruby -v ruby 2.0.0p451 (2014-02-24 revision 45167) [x86_64-linux] # rvm install 2.
    ...
  • Capistranoのタスクを新EC2インスタンスが完全起動するまでsleepさせる

    Capistranoで新規作成したEC2インスタンスが完全に起動し切っていない状態で、そのインスタンスに対してSSHアクセスするタスクを実行すると、どこかしらでエラーになってタスクが完了しません。そこで、デプロイ対象となるEC2インスタンスの起動状態をチェックして、完全に起動していない状態の場合sleepして起動を待つようなタスクを作りました。 AWSのEC2インスタンスには3つのステータス情報があり、この全てのステータスを確認しないと、インスタンスの完全起動状態とは言えないので、注意が必要でした(下図参照)。 インスタンスが起動しているかどうかの確認は、AWSマネージメントコンソールでいうところの「Instance State」がrunningであるかを判定すればOKなのですが、実際にインスタンスにSSH接続ができるかどうかの確認は「Status Checks」欄に「2/2 checks」とあるように2つのステータス(INSTANCESTATUSとSYSTEMSTATUSのreachability)が共にpassedであるかまでを確認する必要があるのです。通常、インスタンスが起動すると「Instance State」は数秒から十数秒程度でrunningになるのですが、「Status Checks」は数分程度initializingで初期化処理を行っています。このステータスが共にpassedにならないとSSHアクセスでコケます。 今まで私が使っていたcheckタスクだと、「Instance State」のステータス1つしか確認していなかったので、後続タスクがSSHアクセスで中断したりしていました。それを回避するためのタスクが今回のcheckタスクになります。 task :check do run_locally do created_instances_list = 'CREATED_INSTANCES' def check_instance_status(instance_ids=[]) ec2 = AWS::EC2.new AWS.memoize do ec2info = ec2.client.describe_instance_status({'instance_ids' => instance_ids}) sys_status = ec2info.instance_status_set.map { |i| i.system_status.details[0].status } ins_status = ec2info.instance_status_set.map { |i| i.instance_status.details[0].status } status = sys_status + ins_status return status.
    ...
  • Capistranoで新規作成したEC2インスタンスの初期設定

    本項では、Capistranoで新規作成したEC2インスタンスへSSHで初回ログインした際の、保守用ユーザの作成、初期ユーザに対してのパスワード設定、サーバのホスト名設定など、いわゆるサーバ環境の初期設定を行うタスクを作ってみます。 その前に、ホスト名のつけ方としての色々と試してみての所感なのですが、初回SSHログイン後にそれぞれのインスタンスに対してHOSTS設定する際にEC2側にタグ付けてしていってもできるのですが、まずインスタンス作成する時にあらかじめホスト名の元となるタグを付けておいて、各インスタンスログイン後はそのタグを参照してHOST名を設定する方がスマートだと思いました。特に複数インスタンスを同時に立てる時などにホスト名に連番を振りたいとかいう時は、カウンター変数を使って回しているec2.instances.create()時にそのカウンターの数値を転用できるので簡単でした。ということで、インスタンス作成時にタグを追加する方法ですが、 # タグ情報 set :host_name, 'deploy-client' ~(中略)~ created_instances = [] cnt = 0 while cnt < fetch(:instance_count) do i = ec2.instances.create( ~(中略)~ ) sleep 10 while i.status == :panding i.tags['Name'] = [ fetch(:host_name), format("%02d", cnt+1) ].join('-') created_instances << i.id cnt += 1 end ~(省略)~ ── と、ec2.instances.create()の後でタグを付けてやればOKです1。 今回はこのNameタグの値をその後のタスクでインスタンスのホスト名として利用します。 いきなり横道に逸れましたが、本題に戻ります。 初回SSH時のタスクとして、前回作成したinitタスクを使います。流れとしては、デプロイサーバ側で新たに作成するユーザ用のキーペアを作成しておいて、デフォルトユーザにてSSHログイン後、まず保守用の新規ユーザアカウントを作成ます。その後、そのユーザに公開鍵認証によるSSH設定を行い、デフォルトユーザにはパスワードを設定してsudo権限を剥奪、ホスト名を設定して一旦ログアウトしています。 まず、タスク設定前に各種パラメータを定義します。
    ...
  • Capistranoで新規作成したEC2インスタンスにSSH接続する

    前回に引き続き、Capistranoで新たに作成したEC2インスタンスにSSHでログインしてみます。 まず、事前準備として、AWS側で新規インスタンス用のキーペアを作成しておきます。AWSマネージメントコンソールの「EC2」メニューから「NETWORK & SECURITY」カテゴリの「Key Pairs」メニューで、キーペアを作成できるので、必要に応じて作成してください。本項の例では、「deploy-test」というCapistranoが稼動しているデプロイ環境用インスタンスで使用しているキーペアを使います。 そして、利用するキーペアのプライベートキーファイル(本項例ではdeploy-test.pemファイル)をCapistranoを実行するデプロイ環境のデプロイを実行するユーザのホームディレクトリ(本項例では/home/deploy-user/)にアップロードしておきます1。 アップロードしたプライベートキーには適切な読み込み権限を付与しておく必要があるので、ファイルのパーミッションを変更します。 $ cd ~ $ chmod 600 deploy-test.pem $ ls -l *.pem -rw------- 1 deploy-user deploy-user 1692 Jul 2 10:18 deploy-test.pem デプロイ設定ファイルconfig/deploy.rbは下記のように修正。 # config valid only for Capistrano 3.1 lock '3.2.1' # AWS SDK for Ruby を読み込む require 'aws-sdk' # AWS SDK用の設定 AWS.config({ :access_key_id => '<AWS ACCESS KEY ID>', :secret_access_key => '<AWS SECRET ACCESS KEY>', :region => 'ap-northeast-1', }) # AMIのimage_id # Amazon Linux AMI 2014.
    ...
  • CapistranoでAWS EC2インスタンスをデプロイする時の注意点

    前回のデプロイ設定ファイルで新たに作成されたEC2インスタンスには、キーペアやセキュリティグループなどが設定されていなかったため、そのままでは作成したインスタンスにSSHでアクセスできませんでした…1orz その後、色々とデプロイ設定を修正して、作成したEC2インスタンスにSSHでログインするところまで出来たので、その経緯を備忘録として書いてみた次第。 まぁ、CapistranoでAWSのEC2インスタンスを作成する際…というより、「AWS SDK for Ruby」でEC2インスタンスを作成する時の注意点…に近いのかもしれない。 まず、前回のconfig/deploy.rbからインスタンスラウンチのタスク部分を見てみる。 desc 'Launch an EC2 instance to each availability zone different' task :launch do run_locally do ec2 = AWS::EC2.new created_instances = [] cnt = 0 while cnt < fetch(:instance_count) do if cnt.even? then current_az = fetch(:availability_zones)[0] current_sn = fetch(:subnet_ids)[0] else current_az = fetch(:availability_zones)[1] current_sn = fetch(:subnet_ids)[1] end i = ec2.
    ...
  • Capistranoで異なるAvilabilityZoneにEC2インスタンスをラウンチする

    前回、 次回はデータベースの作成や初期設定を直前タスクとして挿入して、さらにWordPressの設定ファイルの書き換え、GitHubからWordPressテーマをダウンロードするところまでやってみようと思います。 とか云っていたのですが、都合によりCapistrano3を使ってAWSのEC2インスタンス作成を行ったので、そのTIPSを残しておこうかと思います。 今回は、デプロイ用のEC2インスタンスから公式のAMIを利用してAvailabilityZonesが異なるエリアにそれぞれEC2インスタンスを立ててみました。試験的に、AMIは最新のインスタンスタイプ「t2.micro」に対応した「Amazon Linux AMI 2014.03.2 (HVM)」を利用して、Tokyoリージョンの1aと1cのAvailabilityZoneにそれぞれ2台ずつ、合計4インスタンスを同時に立ててみます。 ※ 事前準備として、インスタンスを立てるAWSアカウントにてVPCやSubnet等EC2インスタンスを作成する上で必要最小限の設定をしておく必要があります。特に今回は異なるAvailabilityZoneへのインスタンスを立てるのでそれぞれのゾーンにSubnetを設定しておく必要があります。 さて、早速デプロイの手順です。 はじめに、デプロイ環境(サーバ)の設定を行うため、config/deploy/test.rbを編集します。 今回は動的に作成したEC2インスタンスをデプロイ環境とするため、事前のサーバ設定ができません。というのも、AWSで立ち上がる新規インスタンスにはElasticIPを付与しないので、毎回PublicIPが異なり、エンドポイントURLも動的に変わってしまうためです。なので、今回はインスタンスが起動した後にCapistoranoのタスクにて対象サーバを設定するようにします。 初期のサーバ設定は不要となるので、記述をコメントアウトしておきます。なお、SSHのオプションだけは最終的に共通で利用する予定なので残しておきます(今回のデプロイタスクでは使いませんが…)。 $ vim config/deploy/test.rb #role :app, %w{deploy@localhost} #role :web, %w{deploy@localhost} #role :db, %w{deploy@localhost} set :ssh_options, { keys: %w(/home/deploy/.ssh/id_rsa), forward_agent: true, } 今回のデプロイでは、「AWS SDK for Ruby」を利用するので、あらかじめSDKをインストールしておきます。 $ sudo gem install aws-sdk 次に、config/deploy.rbにデプロイ内容を設定します。 $ vim config/deploy.rb # config valid only for Capistrano 3.
    ...
  • Capistrano3でWordPressのデプロイをしてみる

    Capistrano3を使って、自ホストに最新版のWordPressをデプロイしてみたのでその手順をログとして残しつつ、デプロイツール「Capistrano」の理解を進めていこうと思います。 事前準備として、デプロイ用の環境をAmazonEC2にt2.microインスタンスとしてラウンチして、WordPressが動作する環境(Apache+MySQL+PHP)、Rubygem(とRVM)、そしてCapistrano3のインストールまで出来ている状態で記載しています(この辺の事前準備の手順も後日TIPSとしてまとめたいと思っていますが、今回は省略します)。 さて、早速手順に入ります。 はじめに、デプロイプロジェクト用のディレクトリを作成して、Capistranoをインストールします。 $ cd ~ $ mkdir test-project $ cd test-project $ cap install STAGES=test mkdir -p config/deploy create config/deploy.rb create config/deploy/test.rb mkdir -p lib/capistrano/tasks Capified Capistrano3ではマルチステージデプロイ機能がデフォルトでONになっているので、単にcap installを行っただけだと、productionステージとstagingステージが作成されてしまいます。 今回はテスト用に自分のローカルホストのみを対象にデプロイを試すので、testステージのみのプロジェクトを環境変数STAGESの引数に指定します1。 次にCapistranoの初期設定を行います。必要ならば、プロジェクトディレクトリ直下に作成されたCapfileを編集します。 $ vim Capfile 今回はrvmやrbenvをデプロイに使わないので、編集項目はありません2。 続いて、デプロイ環境(サーバ)の設定を行うため、config/deploy/test.rbを編集します。 $ vim config/deploy/test.rb ---- role :app, %w{deploy@localhost} role :web, %w{deploy@localhost} role :db, %w{deploy@localhost} set :ssh_options, { keys: %w(/home/deploy/.
    ...