Ruby
Heroku
buildpack
herokuDay 20

【Heroku検討者向け】デプロイ方法5選!

皆さんはHerokuへのデプロイ方法どうしてますか。
スタンダードだとgitでpushとか、今回のheroku Advent Calendar 2018 1日目でも@sho7650さんが、Githubとの連携方法を分かりやすく解説してくれていますね。

さて、今回は「Heroku、使ってみようかな〜」という方向けに、こんなデプロイ方法あるよ!っていうのを5つ、ご紹介していこうと思います。

検証環境

OS
macOS High Sierra 10.13.6
git
git version 2.17.2 (Apple Git-113)
heroku cli
heroku/7.19.3 darwin-x64 node-v11.3.0
docker
docker for mac Version 2.0.0.0-mac81 (29211)

はじめに

サンプルアプリはこちらを採用しました。
https://github.com/heroku/ruby-getting-started
本記事の内容で遊んでみたい方はアプリのダウンロードを最初にお願いします。

$ git clone https://github.com/heroku/ruby-getting-started.git
Cloning into 'ruby-getting-started'...
remote: Enumerating objects: 363, done.
remote: Total 363 (delta 0), reused 0 (delta 0), pack-reused 363
Receiving objects: 100% (363/363), 72.09 KiB | 403.00 KiB/s, done.
Resolving deltas: 100% (136/136), done.

これから実行するコマンドは特別な指定がない限り、全てアプリケーションのルート直下で実行します。

また、料金にはお気をつけ下さい。
本記事の内容は全て無料枠内で再現可能ですが、万が一オペレーションミス等で料金請求が発生しても一切の責任を負いかねます。

(1)git(https)

参考ドキュメント:
https://devcenter.heroku.com/articles/getting-started-with-ruby

一番スタンダードなやつです。

まずはherokuアプリを作成します。

$ heroku create
Creating app... done, ⬢ still-mesa-87412
https://still-mesa-87412.herokuapp.com/ | https://git.heroku.com/still-mesa-87412.git

続いてbuildpackの指定。

$ heroku buildpacks:set heroku/ruby -a still-mesa-87412
Buildpack set. Next release on still-mesa-87412 will use heroku/ruby.
Run git push heroku master to create a new release using this buildpack.

ちなみにbuildpackの指定というのはgithubのURLを直接指定してもできるのですが、
オフィシャルなbuildpackの指定をURLで行うのは、開発中のbuildpackを取り込んでしまう恐れがあるので非推奨です。
ちゃんとheroku/xxxで指定しましょう。

https://devcenter.heroku.com/articles/buildpacks#using-a-third-party-buildpack

You can also specify the full Git URL of an official buildpack. This causes the master Git branch of the buildpack to be used, instead of the last released version. Because the latest Git version might contain unexpected changes, it is highly recommended to use the heroku/… syntax for official buildpacks.

デプロイはgit pushで行います。

$ git push heroku master

(2)git(ssh)

参考ドキュメント:
https://devcenter.heroku.com/articles/git#ssh-git-transport

(1)でご紹介した方法だと、デフォルトでgitの通信プロトコルにhttpsが指定されてしまっています。
ちゃんとsshキーでデプロイする方法もございます。

まずはアプリの作成をします。

$ heroku create
Creating app... done, ⬢ tranquil-badlands-65917
https://tranquil-badlands-65917.herokuapp.com/ | https://git.heroku.com/tranquil-badlands-65917.git

ここでgitの接続先を確認するとhttpsになっているのが分かります。

$ git remote -v
heroku    https://git.heroku.com/tranquil-badlands-65917.git (fetch)
heroku    https://git.heroku.com/tranquil-badlands-65917.git (push)

以下のコマンドを実行すると接続先が切り替わります。

$ heroku git:remote --ssh-git --app tranquil-badlands-65917
set git remote heroku to git@heroku.com:tranquil-badlands-65917.git

切り替わったことの確認。

$ git remote -v
heroku    git@heroku.com:tranquil-badlands-65917.git (fetch)
heroku    git@heroku.com:tranquil-badlands-65917.git (push)

キーの登録をします。
PATHは良しなにお願いします。

$ heroku keys:add ~/.ssh/public_key

あとは(1)と同じようにbuildpackを設定してデプロイするだけです。

$ heroku buildpacks:set heroku/ruby --app tranquil-badlands-65917
$ git push heroku master

(3)buildpackをtarballにする

参考ドキュメント:
https://devcenter.heroku.com/articles/buildpacks

buildpackは公式のものやpublic githubにあるものを用いる方法がありますが、
httpsアクセス可能かつPublicな場所にbuildpackをアーカイブ(tarball)にして配置してアプリをデプロイするという方法もあります。

buildpackを自作した際に有用かもしれませんね。

公式ドキュメントで推奨されているAWS S3を用いて検証してみます。
https://devcenter.heroku.com/articles/buildpacks#buildpack-references

Your buildpack value can point to either git repositories or a tarball URL. Hosting a buildpack on S3 can be a good way to ensure it’s highly available.

まずはpublicなs3バケットを作りましょう。
S3バケットをAWSのマネジメントコンソールから作成し、
作成した対象のバケット→アクセス権限→バケットポリシー
と進んで、バケットポリシーエディタに以下の権限を書いて保存します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::test-ruby-heroku-buildpack/*"
        }
    ]
}

ResourceのARNは良しなにお願いします(バケットポリシーエディターの横に書いてあります)。

続いてbuildpackのtarballを作ります。
いきなりカスタムビルドパックを作れというのも敷居が高いので、
今回はオフィシャルなBuildpackを使いましょう。

$ git clone https://github.com/heroku/heroku-buildpack-ruby.git
$ cd heroku-buildpack-ruby/
$ tar cfvz heroku-buildpack-ruby.tar.gz ./

作成したbuildpackは先ほど作ったPublicなS3バケットに配置します。

続いてアプリを作ります。

$ heroku create
Creating app... done, ⬢ secret-wave-57965
https://secret-wave-57965.herokuapp.com/ | https://git.heroku.com/secret-wave-57965.git

先ほど作成したS3バケットに保存したbuildpackのエンドポイントを指定します。

$ heroku buildpacks:set https://s3-ap-northeast-1.amazonaws.com/test-ruby-heroku-buildpack/heroku-buildpack-ruby.tar.gz
Buildpack set. Next release on secret-wave-57965 will use https://s3-ap-northeast-1.amazonaws.com/test-ruby-heroku-buildpack/heroku-buildpack-ruby.tar.gz.
Run git push heroku master to create a new release using this buildpack.

最後は(1)と(2)と同様にgit pushして下さい。

$ git push heroku master

(4)マニフェスト

参考ドキュメント:
https://devcenter.heroku.com/articles/buildpack-builds-heroku-yml

なんだか1年くらいdeveloper preview状態な気がします。
多分、きっと、恐らく、そろそろ大丈夫な気がしますので取り上げます。

このデプロイ方法は、マニフェスト(heroku.yml)というファイルにアプリ周りのいろんな情報を記載してデプロイすることができます。

例えば、(1)(2)ではデプロイするためのアプリがrubyであることを以下のコマンドで明示的に示したりしていました。

$ heroku buildpacks:set heroku/ruby -a still-mesa-87412
Buildpack set. Next release on still-mesa-87412 will use heroku/ruby.
Run git push heroku master to create a new release using this buildpack.

これをデプロイの際に行うのは煩雑です。
こういった情報をマニフェストに記載できます。

この他にもherokuにはアプリにDBやcacheを提供するアドオンという機能もあるのですが、
マニフェストを使わない場合は、都度コマンドやコンソール画面からアドオンと対象のアプリを紐付けるか、app.jsonという別ファイルに記載する必要があります。
また、Procfileというアプリコンテナ(Dyno)で立ち上がるプロセスを管理する設定ファイルがあるのですが、これもマニフェストにまとめることができます。

つまり多岐に渡るアプリ周りの設定を1つのマニフェスト(heroku.yml)というファイルで一元管理できるのです。

では、触ってみましょう。

開発中の機能のため、heroku cliをbeta版に引き上げます。

$ heroku update beta
heroku: Updating CLI from 7.19.3 to 7.19.3-beta.1039421 (beta)... done
heroku: Updating CLI... done

続いて、manifestプラグインを導入します。

$ heroku plugins:install @heroku-cli/plugin-manifest
Installing plugin manifest... installed v0.0.5

サンプルアプリのルートディレクトリにマニフェストファイル(heroku.yml)を作成します。

heroku.yml
setup:
  addons:
    - plan: heroku-postgresql
      as: DATABASE
build:
  languages:
    - ruby
run:
  web: bundle exec puma -C config/puma.rb

Procfileで実行予定だったものはマニフェストに記載したので、Procfileは削除しちゃいましょう。

$ rm Procfile

デプロイするため、ここまでの変更をコミットします。

$ git rm Procfile
$ git add heroku.yml
$ git commit -m "Added heroku.yml and removed Procfile"

続いてアプリを作成します。

$ heroku create --manifest
Reading heroku.yml manifest... done
Creating app... done, ⬢ evening-falls-33930, stack is container
Adding heroku-postgresql... done
https://evening-falls-33930.herokuapp.com/ | https://git.heroku.com/evening-falls-33930.git

--manifestオプションを付ける事によって、スタックにコンテナが使われたことがわかります。
スタックとはアプリケーションが動くオペレーティングシステムイメージのことです。
ubuntuをベースとしてherokuが手を加えたものになります。

デフォルトだとheroku-18が採用されますが、このマニフェストの場合はコンテナとなるのもマニフェストデプロイの特徴です。

コードをデプロイします。

$ git push heroku master

無事にstackにはコンテナが設定されています。

$ heroku stack --app evening-falls-33930
=== ⬢ evening-falls-33930 Available Stacks
  cedar-14
* container
  heroku-16
  heroku-18

まぁ、でもとはいえ、ベースはubuntuなんですけどね。

$ heroku run bash
Running bash on ⬢ evening-falls-33930... up, run.8448 (Free)
~ $ uname -a
Linux 21f3c783-4450-4493-b01f-17c5371fd07f 4.4.0-1031-aws #34-Ubuntu SMP Tue Sep 25 09:08:48 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

さあ、遊び終わったらHeroku CLIを安定版に戻して、manifestプラグインをremoveしましょう。

$ heroku update stable
$ heroku plugins:remove manifest

(5)Docker

参考ドキュメント:
https://devcenter.heroku.com/articles/build-docker-images-heroku-yml
https://devcenter.heroku.com/articles/container-registry-and-runtime

最近何かと話題のDockerですが、Herokuでも利用可能です。
HerokuにDockerをデプロイするには以下の2つのやり方があります。

  • マニフェストを利用し、Dockerfileをheroku上でbuildする
  • Dockerコンテナをherokuのレポジトリに保存し、それをリリースする

まず、マニフェストを利用し、Dockerfileをheroku上でbuildする方法ですが、
(4)で使用したマニフェストファイル(heroku.yml)を以下のように変更します。

heroku.yml
build:
  docker:
    web: Dockerfile
run:
  web: bundle exec puma -C config/puma.rb

こうすることで、webプロセスのビルドをDockerfileにすることができます。
このDockerfileのPATHはheroku.ymlからみた相対PATHとなります。

buildの下にあるrunですが、これはDockerfileが存在しなかった場合にはrunを実行するということになります。

この時、stackをcontainerにすることを忘れないようにしましょう。

$ heroku stack:set container
Stack set. Next release on ⬢ nameless-lowlands-11461 will use container.
Run git push heroku master to create a new release on ⬢ nameless-lowlands-11461.

あとはgit pushすれば先ほどheroku.ymlで指定した箇所はDockerfileの内容でbuildされて立ち上がる・・・はず。
※すみません、ここだけサンプルアプリでの検証が間に合いませんでした。。。

$ git push heroku master

続いて、Dockerコンテナをherokuのレポジトリに保存し、それをリリースする方法です。
これにはこちらのサンプルアプリを使いましょう。
https://github.com/heroku/alpinehelloworld/

まずはサンプルアプリをダウンロードします。

$ git clone https://github.com/heroku/alpinehelloworld.git
Cloning into 'alpinehelloworld'...
remote: Enumerating objects: 59, done.
remote: Total 59 (delta 0), reused 0 (delta 0), pack-reused 59
Unpacking objects: 100% (59/59), done.

続いてアプリを作ります。

$ heroku create
Creating app... done, ⬢ pacific-island-27732
https://pacific-island-27732.herokuapp.com/ | https://git.heroku.com/pacific-island-27732.git

Heroku Container Registryにログインします。

$ heroku container:login
Login Succeeded

サンプルアプリのルートディレクトリに移動し、以下のコマンドを叩きます。

$ heroku container:push web

サンプルアプリのルートディレクトリにはDockerfileが置かれているため、
Heroku Container Registry上でDockerのbuildが行われます。

ちなみにpushの後ろにあるwebはプロセスタイプのことです。
https://devcenter.heroku.com/articles/procfile#the-web-process-type

pushしたコンテナはビルド済みなので、以下のコマンドですぐにリリースできます。

$ heroku container:release web

最後に

いかがでしたでしょうか。
普段業務だとあまりHerokuに触る機会がなく、久しぶりに調べてみたら色々と発見があり楽しかったです。

少しでも皆さんの知見に貢献できたなら幸いです。
最後までお読み頂き有難うございました。