Ruby on Rails on Docker on AWSのbuildでCPUが高騰するもんだからbuild済みのimageをpullすることにしました。


はじめに

以前「無料!かつ最短?で Ruby on Rails on Docker on AWS のアプリを公開するぞ。 - Qiita」でRuby on Rails on DockerのアプリをAWSで公開する手順を記事にまとめさせていただきました。

何回かアプリの更新を行なっているうちに気づいたことがあります。t2.microさん、bundle installに耐えられてない...

Gemfileに手を加えてない時はいいのですが、そうでない時は決まってEC2のCPU使用率がCloudWatch上100%になってしまい...最悪SSHがフリーズしてしまいインスタンス再起動なんてことも...

これではいけないということで、GitLab Container Registry(GitLabレジストリ)を活用させていただきbuildはEC2以外の場所で実行し、EC2はcontainer upを行うのみにしたいと思います。

インフラ構成は基本的に以前の記事と同じです。

事前準備

docker-compose.ymlはこんなイメージです。

docker-compose.yml
version: '3'

services:
  web:
    container_name: myapp_web_prod
    build: .
    environment:
      RAILS_ENV: production
    command: bundle exec puma -C config/puma.rb
    volumes:
      - .:/myapp
      - ./public:/myapp/public
      - ./tmp:/myapp/tmp
      - ./log:/myapp/log
    ports:
      - 3000:3000

  nginx:
    container_name: myapp_nginx_prod
    build: containers/nginx
    volumes:
      - ./public:/myapp/public
      - ./tmp:/myapp/tmp
    ports:
      - 80:80
    depends_on:
      - web

docker-compose buildすると、myapp_webmyapp_nginxのimageが作成されることと、docker-compose upするとmyapp_web_prodmyapp_nginx_prodのcontainerが起動することがわかればよしです。

今までの手順

  1. localhostからGitLabレポジトリにアプリのソースコードをpush
  2. EC2でGitLabリポジトリからアプリのソースコードをpull
  3. EC2でdocker-compose buildしてdocker imageを作成 #ここでとまる。
  4. EC2でdocker-compose upしてdocker imageからdocker containerを起動

改善版の手順

  1. localhostからGitLabレポジトリにアプリのソースコードをpush
  2. localhostでdocker-compose buildしてdocker imageを作成
  3. localhostからGitLabレジストリにdocker imageをpush
  4. EC2でGitLabリポジトリからアプリのソースコードをpull
  5. EC2でGitLabレジストリからdocker imageをpull
  6. EC2でdocker-compose upしてdocker imageからdocker containerを起動

それでは早速改善版の手順を進めていきましょう!

1. localhostからGitLabレポジトリにアプリのソースコードをpush

説明は端折ります。

$ git push origin master

2. localhostでdocker-compose buildしてdocker imageを作成

ここも説明端折ります。

$ docker-compose build
$ docker images #"myapp_web"と"myapp_nginx"のimageが作成されていることを確認
REPOSITORY     TAG     IMAGE ID     CREATED     SIZE
myapp_web      latest  xxxxxxxx     xxxxxxx     xxxxx
myapp_nginx    latest  xxxxxxxx     xxxxxxx     xxxxx

3. localhostからGitLabレジストリにdocker imageをpush

# Gitlabのレジストリにログインする。UsernameとPasswordを聞かれるので入力する。この手順は初めの1回だけです。
$ docker login registry.gitlab.com

# pushするimageのrepositoryをGitLabに向ける
$ docker tag myapp_web registry.gitlab.com/mygroup/myapp/myapp_web
$ docker tag myapp_nginx registry.gitlab.com/mygroup/myapp/myapp_nginx

# docker imagesを確認すると以下のようになる
$ docker images
REPOSITORY                                     TAG     IMAGE ID  CREATED  SIZE
myapp_web                                      latest  xxxxxxxx  xxxxxxx  xxxxx
myapp_nginx                                    latest  xxxxxxxx  xxxxxxx  xxxxx
registry.gitlab.com/mygroup/myapp/myapp_web    latest  xxxxxxxx  xxxxxxx  xxxxx
registry.gitlab.com/mygroup/myapp/myapp_nginx  latest  xxxxxxxx  xxxxxxx  xxxxx

# GitLabにimage pushする
$ docker push registry.gitlab.com/mygroup/myapp/myapp_web
$ docker push registry.gitlab.com/mygroup/myapp/myapp_nginx

GitLabへのpushは<registry URL>/<namespace>/<project>/<image>とするとのこと。
詳しくは「GitLab Container Registry | GitLab」を参考に。

4. EC2でGitLabリポジトリからアプリのソースコードをpull

こちらも端折ります。EC2にSSHしている前提で。

[[email protected] myapp]$ git pull origin master

5. EC2でGitLabレジストリからdocker imageをpull

GitLabのレジストリを指定してpullするだけです。

[[email protected] ~]$ docker pull registry.gitlab.com/mygroup/myapp/myapp_web
[[email protected] ~]$ docker pull registry.gitlab.com/mygroup/myapp/myapp_nginx

[[email protected] ~]$ docker images
REPOSITORY                                     TAG     IMAGE ID  CREATED  SIZE
registry.gitlab.com/mygroup/myapp/myapp_web    latest  xxxxxxxx  xxxxxxx  xxxxx
registry.gitlab.com/mygroup/myapp/myapp_nginx  latest  xxxxxxxx  xxxxxxx  xxxxx

6. EC2でdocker-compose upしてdocker imageからdocker containerを起動

docker-compose upではmyapp_webmyapp_nginxのimageからコンテナを起動することになっていますが、レポジトリがregistry.gitlab.com/mygroup/myapp/myapp_xxxxxになってしまっているのでこのままでは起動できません。localhostでGitLabにpushする前にやったようにレポジトリの名前をdocker tagコマンドで変更していきます。

[[email protected] ~]$ docker tag registry.gitlab.com/mygroup/myapp/myapp_web myapp_web
[[email protected] ~]$ docker tag registry.gitlab.com/mygroup/myapp/myapp_nginx myapp_nginx

[[email protected] ~]$ docker images
REPOSITORY                                     TAG     IMAGE ID  CREATED  SIZE
registry.gitlab.com/mygroup/myapp/myapp_web    latest  xxxxxxxx  xxxxxxx  xxxxx
registry.gitlab.com/mygroup/myapp/myapp_nginx  latest  xxxxxxxx  xxxxxxx  xxxxx
myapp_web                                      latest  xxxxxxxx  xxxxxxx  xxxxx
myapp_nginx                                    latest  xxxxxxxx  xxxxxxx  xxxxx

ここまできたらGitLabからpullしてきたレポジトリ名の方のimageはいらないので管理しやすくするために消してしまってもいいです。

[[email protected] ~]$ docker rmi registry.gitlab.com/mygroup/myapp/myapp_web
[[email protected] ~]$ docker rmi registry.gitlab.com/mygroup/myapp/myapp_nginx

[[email protected] ~]$ docker images
REPOSITORY                                     TAG     IMAGE ID  CREATED  SIZE
myapp_web                                      latest  xxxxxxxx  xxxxxxx  xxxxx
myapp_nginx                                    latest  xxxxxxxx  xxxxxxx  xxxxx

ここまでできたらコンテナを起動するのみです。
ソースコードの改修次第ではdb:migrateassets:precompileが必要かもしれませんが、それらもdocker-compose run webコマンドを使って実行することができます。

[[email protected] ~]$ docker-compose run web rails db:migrate
[[email protected] ~]$ docker-compose run web rails assets:clobber
[[email protected] ~]$ docker-compose run web rails assets:precompile
# ここまでは必要であれば。

[[email protected] ~]$ docker-compose up -d

これでEC2上でのbuildを回避することができました!

終わりに

これを毎回毎回やるのは面倒ですので、とりあえずシェルスクリプトを組んでみてます。
GitLabではCI/CDツールも提供してくれているので、次はここに記載した手順をCI/CDに組み込めないか検討してみようと思います!