LoginSignup
1
0

More than 1 year has passed since last update.

RailsアプリCICDパイプライン構築の手順(備忘録)(Docker+Rspec+GitHubActions+heroku)

Posted at

はじめに

つい最近DockerとCICD(Travis CI)を学んだので、実践がてらローカルのRailsアプリをDocker環境に移行し、CICDパイプラインを構築してみました。いろいろな方の知恵をお借りしてなんとか構築できたので、自分の備忘録として記録します。CICDツールには、最近登場したGitHubActionsを使用しています。
※まだまだ初学者ですので、間違い等あればご指導ご鞭撻のほどよろしくお願いいたします。

環境

Mac OS Monterey12.1
Ruby2.5.3
Rails5.2.5
MySQL(latest)

1.Dockerfileの作成

Dockerfile
Dockerfile
FROM ruby:2.5.3
RUN apt-get update && apt-get install -y \
    build-essential \
    libpq-dev \
    node.js \
    mysql-client \
    yarn
WORKDIR /workdir
COPY Gemfile Gemfile.lock /workdir/
RUN bundle install

docker-compose.yml
docker-compose.yml
version: '3'

volumes:
  mysqldb-data:

services:
  web:
    build: .
    ports:
      - '3000:3000'
    volumes:
      - '.:/workdir'
    environment:
      - 'DATABASE_PASSWORD=mysqlpass'
      - 'DB_HOST=db'
    tty: true
    stdin_open: true
    depends_on:
      - db
    links:
      - db
    networks:
      - app-net

  db:
    container_name: mysql
    image: mysql
    command: --default-authentication-plugin=mysql_native_password
    volumes:
      - 'mysqldb-data:/var/lib/mysql'
    environment:
      - 'MYSQL_ROOT_PASSWORD=mysqlpass'
      - 'MYSQL_DATABASE=collections_development'
      - 'MYSQL_PASSWORD=mysqlpass'
    ports:
      - '3306:3306'
    networks:
      - app-net

networks:
  app-net:
    driver: bridge

database.yml
database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  host: db  #⬅︎追加
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: <%= ENV.fetch("DATABASE_PASSWORD") %>  #⬅︎追加
  socket: /tmp/mysql.sock

docker-compose.ymlでDBはMySQLのlatest imageを使用するので、commandの部分を忘れないようにします。また、networksにてwebコンテナからdbコンテナにアクセスできるようにしています。
このままだと後からGitHubActionsでエラーが発生して修正しますが、とりあえず次に進みます。

2.Rspecの作成

Rspecの作成については、以下の記事を参考にさせていただきました。

試しにコンテナに入ってテストを実行してみます。

$ docker-compose up --build -d
$ docker-compose exec web bash
$ bundle exec rspec

テストが問題なく通りました。

次はCICDパイプラインを構築していきます。

3.GitHub Actionsの作成(test実行まで)

GitHubのActionsのタブで確認し、.github/workflows/ディレクトリを作成し、その中にymlファイルを作成します。

$ mkdir -p .github/workflows
$ touch .github/workflows/rails_ci.yml

続いて、ymlファイルを作成していきます。

.github/workflows/rails_ci.yml
.github/workflows/rails_ci.yml
name: Ruby

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  Rspec_test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2
      - name: Set up docker
        shell: bash
        env:
          RAILS_ENV: test
        run: |
          docker-compose up --build -d
          docker-compose exec -T web rails db:create
          docker-compose exec -T web rails db:migrate

      - name: RUN Rspec
        shell: bash
        env:
          RAILS_ENV: test
        run: |
          docker-compose exec -T web bundle exec rspec

docker-compose execの後に-Tオプションを付けないと以下のエラーが発生します。

GithubActions
the input device is not a TTY

ここから最初にハマった箇所です。CIの中で無事にコンテナをbuildできましたが、DBにつながりません。

GithubActions
Mysql2::Error::ConnectionError: Can't connect to MySQL server on 'db' (111 "Connection refused")

いろいろ調べて試しましたがうまくいかず、最終的にたどり着いた答えが、
「MySQLが起動していないのではないか?」

恐らくMySQLが起動する前にdb:createしてエラーが出ているのではないかと思い調べると、
「wait-for-it 」という起動を確認できるライブラリがあるようなので、それを利用してみる。

docker-compose.yml修正
docker-compose.yml
version: '3'

volumes:
  mysqldb-data:

services:
  web:
    build: .
    ports:
      - '3000:3000'
    volumes:
      - '.:/workdir'
    environment:
      - 'DATABASE_PASSWORD=mysqlpass'
      - 'DB_HOST=db'
    tty: true
    stdin_open: true
    depends_on:
      - db
    links:
      - db
    networks:
      - app-net


  wait:    #⬅︎追加
    image: willwill/wait-for-it:latest

  db:
    container_name: mysql
    image: mysql
    command: --default-authentication-plugin=mysql_native_password
    volumes:
      - 'mysqldb-data:/var/lib/mysql'
    environment:
      - 'MYSQL_ROOT_PASSWORD=mysqlpass'
      - 'MYSQL_DATABASE=collections_development'
      - 'MYSQL_PASSWORD=mysqlpass'
    ports:
      - '3306:3306'
    networks:
      - app-net

networks:
  app-net:
    driver: bridge

.github/workflows/rails_ci.yml修正
.github/workflows/rails_ci.yml
name: Ruby

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  Rspec_test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2
      - name: Set up docker
        shell: bash
        env:
          RAILS_ENV: test
        run: |
          docker-compose up --build -d
          docker-compose -f docker-compose.yml run wait db:3306 -- echo "Database is up"    #⬅︎追加
          docker-compose exec -T web rails db:create
          docker-compose exec -T web rails db:migrate

      - name: RUN Rspec
        shell: bash
        env:
          RAILS_ENV: test
        run: |
          docker-compose exec -T web bundle exec rspec

結果DBをcreateでき、テストが無事に実行されました。感激!
ローカル環境ではすぐにDBが立ち上がるのかdepends_onを記載するのみでうまくいきましたが、CI環境上ではうまくいかないみたいですね。

wait-for-it.sh: waiting 15 seconds for db:3306
wait-for-it.sh: timeout occurred after waiting 15 seconds for db:3306
Database is up
Database 'web_development' already exists
Created database 'web_test'

次はherokuへのデプロイです。

4.GitHub Actionsの作成(herokuへのデプロイ)

rails_ci.ymlにデプロイ部分を追記します。

.github/workflows/rails_ci.yml デプロイ
.github/workflows/rails_ci.yml
 #続き
  Deploy:
    needs: Rspec_test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: login to heroku
        run:
          docker login -u ${{secrets.HEROKU_USERNAME}} -p ${{secrets.HEROKU_API_KEY}} registry.heroku.com
      - name: deploy to heroku
        run: |
          docker build -t registry.heroku.com/${{secrets.HEROKU_APP}}/web -f Dockerfile.prod .
          docker push registry.heroku.com/${{secrets.HEROKU_APP}}/web
          heroku run -app ${{secrets.HEROKU_APP}} rails db:migrate

また、本番環境ではheroku側のDBを使用したいので、Dockerfile.prodを作成し、それをbuildすることにします。

Dockerfile.prod
Dockerfile.prod
FROM ruby:2.5.3
RUN apt-get update && apt-get install -y \
    build-essential \
    libpq-dev \
    node.js \
    mysql-client \
    yarn
WORKDIR /workdir
COPY Gemfile Gemfile.lock /workdir/
RUN bundle install
COPY . .          #⬅︎追加
CMD ["rails", "s"]     #⬅︎追加

続いて、各サービスの設定です。

●herokuの設定

新しくAPPをcreateします。

image.png

本番環境では、DBにheroku側のHeroku Postgresを使用します。
以下の通り準備します。

image.png

database.ymlproductionを以下の通りとします。
コメントアウトされているので外し、他のproductionをコメントアウトする。

database.yml
production:
  url: <%= ENV['DATABASE_URL'] %>

そうするとherokuのConfig Varsに記載されているDATABASE_URLの環境変数が使われ、herokuのPostgresが使用できます。
また、KEYのところにrailsのmaster.keyの値を設定します。

image.png

DeployでGitHubと連携します。

image.png

●GitHubの環境変数設定

GitHubのActions secretsに環境変数を設定していきます。
※余計な変数も設定されていますが気にしないでください。

image.png

herokuのAPI_KEYの取得の仕方は以下の通りです。

$ brew tap heroku/brew && brew install heroku
$ heroku authorizations:create

表示されるTokenのところです。

準備が整いましたので、リモートにpushしてCIを走らせます。

$ git add .
$ git commit -m '***'
$ git push origin main

image.png

やったー!!デプロイ成功!!herokuでアプリも起動できました!!!
長い道のりでしたが、やっと完成しました。
お知恵をお貸しいただいたみなさん、ありがとうございます!

記載していない途中出会ったエラーは別途まとめる予定です。

参考

Rails+RSpecで気軽に始めるテスト
GitHub ActionsでRails+Rspec+docker-compose環境のci構築
他のDockerコンテナからコンテナ内のMySQLに接続する
GitHub Actionsのワークフロー構文
Docker ComposeでDBコンテナが準備状態になるまで待つ
docker-composeで「the input device is not a TTY」
udemy 米国AI開発者がゼロから教えるDocker講座

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0