Skip to content

Instantly share code, notes, and snippets.

@joker1007
Created May 11, 2016 10:16
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joker1007/8f1ab3dce906296f6655d43e53834b00 to your computer and use it in GitHub Desktop.
Save joker1007/8f1ab3dce906296f6655d43e53834b00 to your computer and use it in GitHub Desktop.
capistranoでビルドサーバーにdocker buildを実行してもらう処理のサンプル
namespace :docker do
desc "build and push docker image on remote host"
task :build do
docker_registry_host = SSHKit::Host.new(fetch(:docker_registry_host))
docker_registry_host.ssh_options = {
user: "ec2-user",
keys: ENV['SSH_KEY'],
}
sha1 = `git rev-parse #{fetch(:branch)}`.chomp
staging_or_release = fetch(:rails_env).to_s == "staging" || fetch(:rails_env).to_s == "production"
precompile_target = staging_or_release ? "all" : fetch(:rails_env)
without_cache = ENV["WITHOUT_CACHE"].to_s != ""
on docker_registry_host do
old_verbosity = SSHKit.config.output_verbosity
begin
SSHKit.config.output_verbosity = :debug
within "/home/ec2-user" do
# githubのリポジトリと同期する
execute(:if, "[ -e repo ]; then cd repo && git remote update; else git clone --mirror git@github.com:<user>/<repo>.git repo; fi")
end
within "/home/ec2-user/repo" do
# ビルド時に利用するキャッシュを保持するディレクトリを用意する
execute(:if, %Q{[ -e tmp/docker_build_cache ]; then rm -rf tmp/docker_build_cache; fi}) if without_cache
execute(:mkdir, "-p tmp/docker_build_cache")
# 同時に複数人がビルドできるようにタイムスタンプとgit worktreeを利用して作業ディレクトリを分ける
timestamp = Time.now.strftime("%s%L")
execute(:git, :worktree, :add, "./worktree-#{timestamp}", sha1)
begin
within "worktree-#{timestamp}" do
execute(:mkdir, "-p tmp")
execute(:cp, "-r", "../tmp/docker_build_cache", "tmp/docker_build_cache")
# 必要ならプライベートレジストリにログインする
# execute(:sudo, "docker login <credential> <server>")
# execute(:sudo, "docker pull <baseimage>")
SSHKit.config.output_verbosity = :info
with yaml_vault_passphrase: ENV["YAML_VAULT_PASSPHRASE"], yaml_vault_sign_passphrase: ENV["YAML_VAULT_SIGN_PASSPHRASE"] do
# dockerコンテナをビルドする
# この時点でassets:precompile assets:sync等を実行する
execute(:sudo, "docker", "build", "--force-rm", "#{without_cache ? "--no-cache" : ""}", "-t",
"app:#{timestamp}",
"--build-arg=precompile=#{precompile_target}",
"--build-arg=git_commit=#{sha1}",
"--build-arg=yaml_vault_pass=${YAML_VAULT_PASSPHRASE}",
"--build-arg=yaml_vault_sign_pass=${YAML_VAULT_SIGN_PASSPHRASE}",
".")
end
SSHKit.config.output_verbosity = :debug
# 作成したイメージをプッシュする
execute(:sudo, "docker tag -f app:#{timestamp} #{fetch(:docker_registry_host_with_port)}/app:#{sha1}")
execute(:sudo, "docker push #{fetch(:docker_registry_host_with_port)}/app:#{sha1}")
# release対象には特別にタグを付ける
if staging_or_release
execute(:sudo, "docker tag -f app:#{timestamp} #{fetch(:docker_registry_host_with_port)}/app:#{fetch(:rails_env)}")
execute(:sudo, "docker push #{fetch(:docker_registry_host_with_port)}/app:#{fetch(:rails_env)}")
end
# dockerコンテナ内でassets:precompileした結果のキャッシュを抽出し保管しておく
# 次回ビルド時にコンテナ内にADDすることでassets:precompileの実行時間を短縮する
execute(:if, %Q{[ $(sudo docker ps -aq -f name=pickup_docker_cache | grep "\w") ]; then sudo docker rm -f $(sudo docker ps -aq -f name=pickup_docker_cache); fi})
execute(:sudo, "docker run -it -d --name pickup_docker_cache app:#{timestamp} shell")
execute(:sudo, "docker cp pickup_docker_cache:/app/tmp/cache - | gzip > ../tmp/docker_build_cache/tmp_cache.tar.gz")
execute(:sudo, "docker rm -f pickup_docker_cache")
# pushして不要になったタグを削除する
execute(:sudo, "docker rmi #{fetch(:docker_registry_host_with_port)}/app:#{sha1}")
if staging_or_release
execute(:sudo, "docker rmi #{fetch(:docker_registry_host_with_port)}/pp:#{fetch(:rails_env)}")
end
# ビルドサーバー上で保持しておく数の上限を越えた古いイメージを削除する
execute(:sudo, %Q{docker images | awk '/^app/ { print sprintf("%s:%s", $1, $2) }' | sort -r | awk 'NR > #{fetch(:keep_docker_image_count)} { print $0 }' > /tmp/app-old-images})
execute("while read image_id; do sudo docker rmi ${image_id}; done < /tmp/app-old-images")
end
ensure
# worktreeを削除する
execute(:rm, "-rf", "worktree-#{timestamp}")
execute(:git, :worktree, :prune)
end
end
ensure
SSHKit.config.output_verbosity = old_verbosity
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment