Posted at

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している前提で。

[myuser@xxx.xxx.xxx.xxx myapp]$ git pull origin master


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

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

[myuser@xxx.xxx.xxx.xxx ~]$ docker pull registry.gitlab.com/mygroup/myapp/myapp_web

[myuser@xxx.xxx.xxx.xxx ~]$ docker pull registry.gitlab.com/mygroup/myapp/myapp_nginx

[myuser@xxx.xxx.xxx.xxx ~]$ 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コマンドで変更していきます。

[myuser@xxx.xxx.xxx.xxx ~]$ docker tag registry.gitlab.com/mygroup/myapp/myapp_web myapp_web

[myuser@xxx.xxx.xxx.xxx ~]$ docker tag registry.gitlab.com/mygroup/myapp/myapp_nginx myapp_nginx

[myuser@xxx.xxx.xxx.xxx ~]$ 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はいらないので管理しやすくするために消してしまってもいいです。

[myuser@xxx.xxx.xxx.xxx ~]$ docker rmi registry.gitlab.com/mygroup/myapp/myapp_web

[myuser@xxx.xxx.xxx.xxx ~]$ docker rmi registry.gitlab.com/mygroup/myapp/myapp_nginx

[myuser@xxx.xxx.xxx.xxx ~]$ 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コマンドを使って実行することができます。

[myuser@xxx.xxx.xxx.xxx ~]$ docker-compose run web rails db:migrate

[myuser@xxx.xxx.xxx.xxx ~]$ docker-compose run web rails assets:clobber
[myuser@xxx.xxx.xxx.xxx ~]$ docker-compose run web rails assets:precompile
# ここまでは必要であれば。

[myuser@xxx.xxx.xxx.xxx ~]$ docker-compose up -d

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


終わりに

これを毎回毎回やるのは面倒ですので、とりあえずシェルスクリプトを組んでみてます。

GitLabではCI/CDツールも提供してくれているので、次はここに記載した手順をCI/CDに組み込めないか検討してみようと思います!