タイトルの通りCapistranoでJavaのWebアプリケーション(warファイルとかJettyを組み込んだjarファイルとか)をデプロイしてるのですが、みなさんどうやってるんでしょうか!?
会社ではJava以外のプロダクトも結構あって、それらをCapistranoでデプロイしているからJavaのプロダクトもCapistranoでデプロイしているのですが、Gradleとかでやるのが多いのかなぁー。。。
最近Capistranoのバージョンを2から3へ上げたときに、その辺の事情が気になったのでブログ記事に書くことにしました。
Capistranoのバージョンは、3.2.1です。
インストールやタスクのフローなどは以下のページが参考になると思います。
ビルド・デプロイの流れ
という流れは自動化されてます。
この後、Mavenリポジトリにpublishされたアーティファクトを自動でステージング環境へデプロイしたり、本番環境へデプロイを楽にするためにもデプロイを自動化したくなります。 これらのデプロイをCapistranoを使って自動化しています。
デプロイタスク
Capistranoでデプロイするとき、デフォルトだとGitからソースコードを取得するのですが、タスクをオーバーライドすることで社内のMavenリポジトリからアーティファクトをwgetで取得するように変更してます。
Capistrano3では以下のページにある通り、複数のタスクが順番に呼ばれます。
Capistrano3のデプロイフレームワークの使い方 - Qiita
呼び出されているタスクを見てみると、git関連のタスクがdeploy:check
タスクとdeploy:updating
タスクの中で呼び出されています。
まずは、deploy:check
タスクをオーバーライドしてgit:check
を呼ばないようにします。(参考:Overriding Capistrano tasks)
元々の処理からgit:check
の呼び出しだけ削除します。
# deply.rb namespace :deploy do Rake::Task["deploy:check"].clear_actions task :check do #invoke "#{scm}:check" gitを使わないので不要 invoke 'deploy:check:directories' invoke 'deploy:check:linked_dirs' invoke 'deploy:check:make_linked_dirs' invoke 'deploy:check:linked_files' end end
次に、deploy:updating
をオーバーライドします。
が、その前にアーティファクトのバージョン番号を入力するためのタスクを作ります。そして、before
を使って作成したタスクをdeploy:updating
タスクの実行前に呼ばれるようにします。
ask
を使うと対話的にパラメータを渡すことができます。
# deply.rb namespace :deploy do task :version do ask(:version, "nil") on roles(:all) do |h| if fetch(:version).nil? || fetch(:version) == "nil" error "version が指定されていません" exit 99 else execute "echo \"OK! version: #{fetch(:version)}\"" end end end before :updating, :version end
これでアーティファクトのバージョン番号を対話的に入力できるようになりました。環境変数で渡しても良いですね。
では、deploy:updating
をオーバーライドして、Mavenリポジトリからアーティファクトをダウンロードするようにします。
また、deploy:updating
タスクから呼び出しているdeploy:set_current_revision
タスクでRIVISIONというファイルを作っているのですが、このタスクの中でもgit関連のタスクを呼び出しているのでそこも書き換えます。
# deply.rb set :application, 'myapp' set :group_dir, 'com/exmaple' set :m2repo, 'http://m2repo.example.com' namespace :deploy do Rake::Task["deploy:updating"].clear_actions task :updating => :new_release_path do #invoke "#{scm}:create_release" gitを使わないので不要 # 代わりに、wgetでMavenリポジトリからjar/warファイルをダウンロードするようにする on release_roles :all do execute :mkdir, '-p', release_path execute :wget, "#{fetch(:m2repo)}/#{fetch(:group)}/#{fetch(:application)}/#{fetch(:version)}/#{fetch(:application)}-#{fetch(:version)}.war -P #{release_path}" end #invoke "deploy:set_current_revision" gitを使わないので不要 # 代わりに、入力させたバージョンをREVISIONファイルに書き込む on release_roles :all do within release_path do execute :echo, "\"#{fetch(:version)}\" >> REVISION" end end invoke 'deploy:symlink:shared' end end
あとは再起動タスクを作ります。after
を使ってpublishing
の後に実行されるようにします。
# deply.rb namespace :deploy do task :restart do on roles(:app), in: :sequence, wait: 5 do |host| info("restart on #{host}") # LBからサーバーを切り離して、アプリケーションサーバーを再起動したりする処理をここに書く end end after :publishing, :restart end
これで、Capistranoを使って自動デプロイできるようになりました。
ステージング環境へデプロイしたい場合はcap staging deploy
ですね!
おわりに
今のところ、このデプロイ方法で困ってないのですが、Java アプリケーションのデプロイについてのベストプラクティスが気になってるところです・・・。
最後にdeploy.rbの全体像を載せておきます。
# deply.rb set :application, 'myapp' set :group_dir, 'com/exmaple' set :m2repo, 'http://m2repo.example.com' namespace :deploy do Rake::Task["deploy:check"].clear_actions task :check do #invoke "#{scm}:check" gitを使わないので不要になる invoke 'deploy:check:directories' invoke 'deploy:check:linked_dirs' invoke 'deploy:check:make_linked_dirs' invoke 'deploy:check:linked_files' end task :version do ask(:version, "nil") on roles(:all) do |h| if fetch(:version).nil? || fetch(:version) == "nil" error "version が指定されていません" exit 99 else execute "echo \"OK! version: #{fetch(:version)}\"" end end end before :updating, :version Rake::Task["deploy:updating"].clear_actions task :updating => :new_release_path do #invoke "#{scm}:create_release" gitを使わないので不要になる # 代わりに、wgetでMavenリポジトリからjar/warファイルをダウンロードするようにする on release_roles :all do execute :mkdir, '-p', release_path execute :wget, "#{fetch(:m2repo)}/#{fetch(:group)}/#{fetch(:application)}/#{fetch(:version)}/#{fetch(:application)}-#{fetch(:version)}.war -P #{release_path}" end #invoke "deploy:set_current_revision" gitを使わないので不要になる # 代わりに、入力させたバージョンをREVISIONファイルに書き込む on release_roles :all do within release_path do execute :echo, "\"#{fetch(:version)}\" >> REVISION" end end invoke 'deploy:symlink:shared' end task :restart do on roles(:app), in: :sequence, wait: 5 do |host| info("restart on #{host}") # LBからサーバーを切り離して、アプリケーションサーバーを再起動したりする処理をここに書く end end after :publishing, :restart end