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

# はじめに
以前「[無料！かつ最短？で Ruby on Rails on Docker on AWS のアプリを公開するぞ。 - Qiita](https://qiita.com/at-946/items/1e8acea19cc0b9f31b98)」でRuby on Rails on DockerのアプリをAWSで公開する手順を記事にまとめさせていただきました。

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

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

これではいけないということで、[GitLab Container Registry（GitLabレジストリ）](https://docs.gitlab.com/ce/user/project/container_registry.html)を活用させていただきbuildはEC2以外の場所で実行し、EC2はcontainer upを行うのみにしたいと思います。

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

# 事前準備
`docker-compose.yml`はこんなイメージです。

```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_web`、`myapp_nginx`のimageが作成されることと、`docker-compose up`すると`myapp_web_prod`、`myapp_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
説明は端折ります。

```bash
$ git push origin master
```

# 2. localhostで`docker-compose build`してdocker imageを作成
ここも説明端折ります。

```bash
$ 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
```bash
# 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](https://docs.gitlab.com/ce/user/project/container_registry.html)」を参考に。

# 4. EC2でGitLabリポジトリからアプリのソースコードをpull
こちらも端折ります。EC2にSSHしている前提で。

```bash
[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_web`と`myapp_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:migrate`や`assets: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に組み込めないか検討してみようと思います！