iii ThreeTreesLight

about me / / /

kanegon-rock:

60s Japan!!
Nice hairstyle with DADA from Ultraman!!

(via meiro)

chefのssl verify warning

man in the middle atack対策として、chef 11.12系からssl verifyが出来るようになった様です。

SSL validation of HTTPS requests is disabled. HTTPS connections are still encrypted, but chef is not able to detect forged replies or man in the middle attacks.

To fix this issue add an entry like this to your configuration file:

“` # Verify all HTTPS connections (recommended) ssl_verify_mode :verify_peer

# OR, Verify only connections to chef-server verify_api_cert true “`

To check your SSL configuration, or troubleshoot errors, you can use the knife ssl check command like so:

knife ssl check -c /home/webadmin/chef-solo/solo.rb

ワーニングを放置するのもうざいので、言われた通り設定します。

対応

$ vim .chef/knife.rb

ssl_verify_mode :verify_peer

これでok

2 weeks ago  Notes (2)

#chef

nodejsのスクリプトをcapistranoでデプロイ

nodeのデプロイ洗ってみたけど、capistranoでやっていたり、shellでやっていたりベストプラクティスなんなんだろーと色々悩んでました。

必須の要件としてはシンプルに2つ。

  • rollbackできるようにデプロイのバージョニング
  • downtime無しで管理

Require

スクリプト本体+http server

  • nodejs
  • coffee-script

process管理

deploy

  • capistrano

下ごしらえ

packages

$ npm i pm2@latest -g

gems

$ bundle init
$ vim Gemfile
source 'https://rubygems.org'

gem 'capistrano', '~> 3.2.0'
gem 'capistrano-bundler', '~> 1.1.3'
gem 'capistrano-npm'

$ bundle

デプロイ設定

initialize

$ cap init

cap設定

$ vim Capfile
# Load DSL and Setup Up Stages
require 'capistrano/setup'

# Includes default deployment tasks
require 'capistrano/deploy'
require 'capistrano/bundler'
require 'capistrano/npm'
require 'capistrano/console'

# Loads custom tasks from `lib/capistrano/tasks' if you have any defined.
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }

pm2をキックするスクリプトを作る

$ vim lib/capistrano/tasks/pm2.rake
require 'json'
require 'pry'

namespace :pm2 do
  def start_app
    within current_path do
      execute :pm2, :start, fetch(:app_command)
    end
  end

  def restart_app
    within current_path do
      execute :pm2, :restart, fetch(:app_command)
    end
  end

  def stop_app
    within current_path do
      execute :pm2, :stop, fetch(:app_command)
    end
  end

  def force_stop_app
    within current_path do
      execute :pm2, :stop, fetch(:app_command), '--force'
    end
  end

  def graceful_reload_app
    within current_path do
      execute :pm2, :gracefulReload, fetch(:app_command)
    end
  end

  def delete_app
    within current_path do
      execute :pm2, :delete, fetch(:app_command)
    end
  end

  def app_status
    within current_path do
      ps = JSON.parse(capture :pm2, :jlist, fetch(:app_command))
      if ps.empty?
        return nil
      else
        # status: online, errored, stopped
        return ps[0]["pm2_env"]["status"]
      end
    end
  end

  desc 'Start app'
  task :start do
    on roles(:app) do
      start_app
    end
  end

  desc 'Stop app'
  task :stop do
    on roles(:app) do
      stop_app
    end
  end

  desc 'Restart app gracefully'
  task :restart do
    on roles(:app) do
      case app_status
      when nil
        info 'App is not registerd'
        start_app
      when 'stopped'
        info 'App is stopped'
        restart_app
      when 'errored'
        info 'App has errored'
        restart_app
      when 'online'
        info 'App is online'
        graceful_reload_app
      end
    end
  end

  desc 'Stop app immediately'
  task :force_stop do
    on roles(:app) do
      force_stop_app
    end
  end

  desc 'Delete app'
  task :delete do
    on roles(:app) do
      delete_app
    end
  end
end

デプロイ設定をごにょごにょ

$ vim config/deploy.rb
lock '3.2.1'

set :application, 'YOUR_APP_NAME'
set :app_command, 'egg.coffee'
set :repo_url,    'git@github.com:foo/foo.git'

set :deploy_to,   "/var/www/#{fetch(:application)}"
set :log_level, :debug

set :linked_dirs,  %w{ bin log node_modules }

set :default_env, { node_env: "local" }

namespace :deploy do

  desc 'Restart application'
  task :restart do
    invoke 'pm2:restart'
  end

  after :publishing, :restart   
end

targetにlocal作る(local VMを対象にしています)

$ vim config/deploy/local.rb
set :branch, ENV['BRANCH'] || 'master'
set :user,   'vagrant'

role :app, [ "#{fetch(:user)}@foo-server" ]

server 'foo-server', user: fetch(:user), roles: %w{ app }

localVMに流す

VMにPM2入れておいて

$ cap local deploy:check
$ cap local deploy

ok

pm2の操作はrakeの通り

P.S.

pm2でもgitによるバージョニングのdeployが可能なので、それでやるほうがnodeの哲学に合ってるかもしれません。

2 weeks ago  Notes (3)

#node #capistrano #deploy #nodejs

[chef] 複数環境を管理するcookbookをリファクタしてみた

Chefマスターから見たら「えっそんなこともちゃんとやってなかったの?情弱」的な感じかもしれませんが、とりあえず自分で気をつけたポイントをメモしてみました。

ほんとはこう分けた方が良いよ!とかありましたら教えてもらえると嬉しいです!

課題

やっとサービスが成長してきたので、ちゃんとChefで3環境(local, staging, production)を管理しているのですが、

「3rd partyのcookbookも使ってるし、attributeのoverrideをrunlistで行っていて、環境ごとのrunlistに差分が出る。ヤバい。目diff無理」

という素敵な課題が勃発

対策

このrunlist問題に対して、以下のような対策を打って、リファクタしました。

1. バージョンをattribute化してあるものは必ずserver specでテスト

これは当たり前ですね。なんでやってなかったんだって怒られそう。

2. site-cookbooks内のcookbookのまとまり感を揃える

リファクタ前は、あるpakcageのインストールをcookbook内のrecipeとして管理したり、独立したcookbookとして管理したり、粒度や方針がバラバラでした。

例えば以下のようなものがバラッバラでした。

そうなると当然、チーム内で新しいpackageを追加したいときに「これって切り出すべき?それともどっかのrecipeにするべき?」って話し合う事が多くなる感じです。

そこで、以下のような大きく4つのcookbookを作って整理した結果、runlistへの見通しも良くなりました。 (分け方は趣味です)

  • initialize
    • 最初にやっておくべき事(sudoとかuserの追加とか、iptablesとか)
  • languages
    • node, ruby, pythonとか
  • db
    • db接続とかdbそのものなど
  • sites
    • nginx周りの設定とかweb server絡み

ただ、recipeの内容が複雑になる場合やtemplateを多用する場合は、まとめてしまうとメンテし難くなるのでcookbookとして切り出し、include_recipeするwrap recipeを上記のcookbookに食わせるようにしました。

3. 3rd partyのcookbookを直接runlistから実行せず、包む。

runlistを長くなる原因の一つとして、3rd partyのcookbookをそのままrunlistから実行する事が挙げられると思います。

対策としては、ほぼ2のcookbook切り出した場合と同じで、3rd partyのcookbookをincludeするwarp recipeを作り、attributeもそのcookbook内でまず上書きする方針にしました。

例えばgitの3rdpartyを以下のようにrunlistで記載するのではなく、warpすると以下になるイメージです

リファクタ前

js // runlist { "environment": "production", "git": { "version: "1.9.0", "url": "https://git-core.googlecode.com/files/git-1.9.0.tar.gz" }, "run_list": [ "git::source" ] }

リファクタ後

wrapするrecipeを作って

“`ruby

initialize::git

include_recipe “git::source” “`

attributeで上書きして

“`ruby

attribute

git

default[‘git’][‘version’] = ‘1.9.0’ default[‘git’][‘url’] = ‘https://git-core.googlecode.com/files/git-1.9.0.tar.gz’ “`

runlistはこんな感じに

js // runlist { "environment": "production", "run_list": [ "initialize::git" ] }

このとき、attributeに記載するデフォルト値はstaging環境にしてみました。

理由としては以下2つです。

  • productionにすると、環境を増やしたときに繋がれてしまう恐れが有る
  • local(development)にすると、papertrailなど環境を増やしたときにattribute設定の漏れが出る恐れが有る

4. environmentを利用してrunlistからattributeを分離

環境ごとに異なるtokenやdbのつなぎ先などはenvironmentで管理します。

中を見ると以下のようになっているのですが、

js { "name": "production", "description":"This is it", "chef_type": "environment", "json_class": "Chef::Environment", "default_attributes": { }, "override_attributes": { } }

override attributeは、優先度の高い値として、attributeを強制的に上書きされるので、overrideを使います。

reference: http://docs.opscode.com/essentials_environments.html

で、そこで明示的に示しておくべきattributeは、defaultにあったとしてもそれぞれattributeで明示的に書いておくことにしました。

例えば、database.ymlの設定や.envファイルの設定です。これは、環境を別途切り出した場合の設定ミスを防ぐ目的で行いました。

5. runlist内の重複は、roleで回避する

ある程度整理できてくるとnodeの重複が出てきます。

リファクタ前

local

“`js { “environment”: “local”, “run_list”: [ “initialize::default”, “initialize::manage”, “initialize::users”, “initialize::sudo”, “initialize::ssh”, “initialize::hosts”, “initialize::iptables”, “initialize::git”, … // only staging, local “db::mysql_server”, “sites::memcached” … ] }

“`

production

js { "environment": "production", "run_list": [ "initialize::default", "initialize::manage", "initialize::users", "initialize::sudo", "initialize::ssh", "initialize::hosts", "initialize::iptables", "initialize::git", ... ] }

リファクタ後

common, db, web, dev(dbやらcacheやら、productionでは外に出すけど、stagingとかではお腹に置くもの)とか切り出します

js // roles/common.json { "name": "common", "chef_type": "role", "json_class":"Chef::Role", "default_attributes":{}, "override_attributes":{}, "description":"webserver’s role", "run_list": [ "initialize::default", "initialize::manage", "initialize::users", "initialize::sudo", "initialize::ssh", "initialize::hosts", "initialize::iptables", "initialize::git" ... ] }

runlist

“`js { “environment”: “local”, “run_list”: [ “role[common]”, … “role[dev]” ] }

“`

ただ、以下のサイトにもあるようにrunlistはバージョン管理できない事も有り、問題が有るかもしれません。

[和訳] 初心者Chefアンチパターン by Julian Dunn #opschef_ja

1 month ago  Notes (3)

#chef

pry 0.10.0にてundefined method `pager`が起きたときの暫定対処

事象

0.9.12.6 -> 0.10.0にあげたらエーって言うぐらい怒られた。

ruby pry> User.all undefined method `pager'

で、実際にissueもまだopen

pry/pry 0.10.0 - undefined method `pager’ for nil:NilClass #1265

環境

ruby 2.0.0p353 rails 4.1.1 pry-byebug 1.3.3 pry-rails 0.3.2 pry-remote 0.1.8

原因

詳しく調べてないおち

対応策

とりあえず、pagerが原因なら殺しておく。

“`bash $ vi .pryrc

Pry.config.pager = false

“`

https://github.com/pry/pry/wiki/Customization-and-configuration#pager

これで動作しました。

1 month ago  Notes (2)

#pry #ruby

"フルスタックエンジニアって、ようはRPGの「赤魔導士」とか一緒で、序盤は重宝するけど中盤以降に上級の専門職ユニットが使えるようになると、リストラされるアレ"

Twitter / fladdict (via igi)

(via kasei-san)

1 month ago  Notes (338)

(Source: sheepfilms, via kasei-san)