事象
下記のDockerfileおよびdocker-compose.yamlで作成したRailsのコンテナをHerokuにpushした際に
unknown blob
▸ Error: docker push exited with Error: 1
とエラーが発生しました。
FROM ruby:2.6.3-stretch
RUN apt-get update &&\
apt-get install -y nodejs build-essential libpq-dev postgresql-client
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp
version: "3"
services:
db:
image: postgres:11.4-alpine
ports:
- "5432:5432"
volumes:
- "./postgres-data:/var/lib/postgresql/data"
web:
build:
context: .
dockerfile: Dockerfile
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- ".:/myapp"
ports:
- "3000:3000"
tty: true
stdin_open: true
depends_on:
- db
working_dir: "/myapp"
ちなみに、Herokuへのpushはローカルでコンテナの起動を停止後に下記の手順で行いました。
$ heroku create
$ heroku container:login
$ heroku container:push "コンテナ名"
↑このコマンドで上述のエラーが発生
原因と対策
エラーメッセージの「unknown blob Error: docker push exited with Error: 1」
を丸ごとコピペして検索すると、こちらのGitHubのissueを発見しました。
どうやら、コメントを読む限りでは、Herokuでコンテナを用いる際はCMD
を用いる必要があるようです。
ただ、issueのコメントにあったこちらのリンクがCMD
を用いる必要がある根拠なのかもしれませんが、私にはイマイチ読み取れませんでした。
あえて挙げるとすると
CMD will always be executed by a shell so that config vars are made available to your process; to execute single binaries or use images without a shell please use ENTRYPOINT`
がCMD
に関する記載なのですが、CMD
が常にシェルによって実行されるからCMD
を用いる必要があるということなんでしょうか...
いずれにせよ、一旦試しにDockerの公式サンプルを参考に下記のようにDockerfileを修正しました。
FROM ruby:2.6.3-stretch
RUN apt-get update &&\
apt-get install -y nodejs build-essential libpq-dev postgresql-client
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp
# ↓を追加
CMD ["rails", "server", "-b", "0.0.0.0"]
Dockerfileを修正後に、再度pushしてみると、
・・・(省略)・・・
Your image has been successfully pushed.
You can now release it with the 'container:release' command.
とエラーメッセージが消え、pushに成功することができました。
CMDとは
ここで改めてCMD
とはなんぞやということを調べてみましたら、非常に良い記事を発見したので、共有します。
@uehaj さんのDockerfileのCMDとENTRYPOINTを改めて解説するという記事です。
この記事によるとCMD指定には下記の2つの意味があるようです。
- docker runでコマンドを指定する方法において、「docker run」で実際のコマンドを何も指定しなかったときに実行するコマンド(と引数)のデフォルト値
- DockerfileのENTRYPOINT項目でコマンドを指定する方法において、ENTRYPOINTに指定したコマンドの追加的引数の、コマンドラインから指定しなかった場合のデフォルト値
結局CMD
には2つ意味がありますが、
いずれの場合でも、CMDはrunの後に続ける引数のデフォルト値指定であると言える。
とのことです。
まとめ
コンテナをHerokuにpushした際に
unknown blob
▸ Error: docker push exited with Error: 1
とエラーが発生したら、DockerfileにCMD
コマンドが書かれているかをチェックしてみると良いでしょう。
また、今回の調査の過程で、CMD
は「docker run
の後に続ける引数のデフォルト値を指定している」ということを学ぶことができました。改めてDockerの公式ドキュメントにも目を通しておこうと思います。
最後までお読みいただきありがとうございました。
参考文献
解決のきっかけ
https://github.com/heroku/cli/issues/1081
CMD
を用いる必要がある根拠と思われるページ
https://devcenter.heroku.com/articles/container-registry-and-runtime#dockerfile-commands-and-runtime
DockerfileのCMDとENTRYPOINTを改めて解説する
https://qiita.com/uehaj/items/e6dd013e28593c26372d