Next.js + Rails(API) + Mysql on Docker의 Hello World 할 바람!

Goal



안녕하세요. Nuxt.js와 Rails의 Docker 환경 구축 기사는 많이 있었지만 Next.js 기사가 없었기 때문에 시행 착오로 환경 구축한 기록입니다.
Qiita에 투고하는 것도 별로 없기 때문에 기사 타이틀·기사 구성 따위 @at-946 님을 참고로 하겠습니다.
  • 참고 기사
    Nuxt.js + Rails(API) on Docker의 Hello World 할!

  • 1.Docker 준비



    준비하는 파일 구성은 다음과 같이 했습니다.

    DirectoryStructure
    /
    |--front/
    |    |--Dockerfile
    |--back/
    |    |--Dockerfile
    |    |--Gemfile
    |    |--Gemfile.lock #空ファイル
    |--docker-compose.yml
    

    front/Dockerfile
    From node:14-alpine
    
    WORKDIR /usr/src/app
    

    back/Dockerfile
    FROM ruby:2.5
    
    ENV LANG=C.UTF-8 \
      TZ=Asia/Tokyo
    
    WORKDIR /app
    
    RUN apt-get update -qq && \
      apt-get install -y nodejs default-mysql-client
    
    COPY Gemfile /app/Gemfile
    COPY Gemfile.lock /app/Gemfile.lock
    RUN bundle install
    

    back/Gemfile
    source 'https://rubygems.org'
    gem 'rails', '~> 6.0.3', '>= 6.0.3.2'
    

    docker-compose.yml
    version: "3"
    
    services:
      db:
        container_name: database
        image: mysql:5.7
        command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
        environment:
          MYSQL_ROOT_PASSWORD: password
          MYSQL_DATABASE: sample
          MYSQL_USER: root
          MYSQL_PASSWORD: password
          TZ: Asia/Tokyo
        ports:
          - 3308:3306
        volumes:
          - ./database/my.cnf:/etc/mysql/conf.d/my.cnf
          - ./database/data:/var/lib/mysql
          - ./database/sql:/docker-entrypoint-initdb.d
    
      api:
        container_name: back
        tty: true
        depends_on:
          - db
        build:
          context: back/
          dockerfile: Dockerfile
        ports:
          - 3000:3000
        volumes:
          - ./back:/app
        command: rails server -b 0.0.0.0
    
      front:
        build:
          context: front/
          dockerfile: Dockerfile
        container_name: web
        volumes:
          - ./front/app:/usr/src/app
        command: 'yarn dev'
        ports:
          - "4001:3000"
    

    위의 파일을 준비했으면 빌드합니다.
    $ docker-compose build
    

    2.Next.js 앱을 만들어 봅시다.


    $ docker-compose run --rm front yarn create next-app .
    

    잠시 기다리면 Next.js 앱이 생성되었다고 생각합니다.
    바로 시작해 봅시다.
    $ docker-compose up
    
    localhost:4001로 이동하십시오. 잘되면 Welcome to Next.js!가 나올 것입니다.



    3.Rails 환경 구축



    계속해서 Rails의 환경 구축입니다. RDB는 MySQL를 채택합니다. Rails는 APIモード 합니다.
    $ docker-compose run --rm api bundle exec rails new . --api -d mysql
    

    도중에 Gemfile이 충돌하므로 덮어 쓰도록합시다.
    Overwrite /app/Gemfile? (enter "h" for help) [Ynaqdhm] Y
    

    Rails 앱을 만든 후에는 데이터베이스 설정을 docker-compose.yml로 만든 Mysql 설정에 맞추십시오.

    back/config/database.yml
    # MySQL. Versions 5.5.8 and up are supported.
    #
    # Install the MySQL driver
    #   gem install mysql2
    #
    # Ensure the MySQL gem is defined in your Gemfile
    #   gem 'mysql2'
    #
    # And be sure to use new-style password hashing:
    #   https://dev.mysql.com/doc/refman/5.7/en/password-hashing.html
    #
    default: &default
      adapter: mysql2
      encoding: utf8mb4
      pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
      username: root
      password: password
      host: database
    
    development:
      <<: *default
      database: sample
    
    # Warning: The database defined as "test" will be erased and
    # re-generated from your development database when you run "rake".
    # Do not set this db to the same as development or production.
    test:
      <<: *default
      database: app_test
    
    # As with config/credentials.yml, you never want to store sensitive information,
    # like your database password, in your source code. If your source code is
    # ever seen by anyone, they now have access to your database.
    #
    # Instead, provide the password as a unix environment variable when you boot
    # the app. Read https://guides.rubyonrails.org/configuring.html#configuring-a-database
    # for a full rundown on how to provide these environment variables in a
    # production deployment.
    #
    # On Heroku and other platform providers, you may have a full connection URL
    # available as an environment variable. For example:
    #
    #   DATABASE_URL="mysql2://myuser:mypass@localhost/somedatabase"
    #
    # You can use this database configuration with:
    #
    #   production:
    #     url: <%= ENV['DATABASE_URL'] %>
    #
    production:
      <<: *default
      database: app_production
      username: app
      password: <%= ENV['APP_DATABASE_PASSWORD'] %>
    

    그럼 시작하자.
    $ docker-compose up --build
    
    localhost:3000로 이동하십시오. 아래 화면이 표시되면 OK입니다.



    4.JSON을 반환하는 API를 만들어 보자.



    Next.js 측과 연동할 수 있도록 Rails 측에서 API를 만들어 봅시다.
    $ docker-compose run --rm api bundle exec rails g scaffold post title:string
    

    깨끗이 할 수 있었다고 생각합니다. 테이블을 만들기 때문에 migrate 합시다.
    $ docker-compose run --rm api bundle exec rake db:migrate
    

    테이블을 만든 곳에 데이터가 없으므로 JSON을 반환할 수 없습니다. 곤란했습니다・・・. 테스트 데이터를 만드세요.
    Rails에는 seed라는 초기 데이터를 캡처하는 편리한 기능이 있습니다.

    back/db/seeds.rb
    # This file should contain all the record creation needed to seed the database with its default values.
    # The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup).
    #
    # Examples:
    #
    #   movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }])
    #   Character.create(name: 'Luke', movie: movies.first)
    Post.create!(
      [
        {
          title: 'オフィスの近くの焼き芋を売ってる店がある'
        },
        {
          title: '焼き芋を配るフロントエンジニアがいるらしい'
        }
      ]
    )
    

    죄송합니다, 테스트 데이터에 평소 울분을 토해 버렸습니다. 어쩐지 보지 않아요-에.
    이제 테스트 데이터를 테이블로 가져옵니다.
    $ docker-compose run --rm api bundle exec rake db:seed
    

    그럼, 확인해 봅시다.
    $ docker-compose up
    
    localhost:3000/posts 를 방문해 봅시다. 그런 데이터를 볼 수 있네요. 성공입니다.



    5.Next.js에서 데이터 보기



    자, 드디어 API로 취득한 데이터를 Next.js측에서 표시시켜 봅시다.front/app/pages/index.js 를 다음과 같이 다시 작성해 보았습니다.
    단순히 API로 얻은 데이터를 표시하기 만하면됩니다.

    front/app/pages/index.js
    export default function Home(props) {
      return (
        <div>
          <h1>POSTの一覧</h1>
          {props.posts.map((post) =>
            <p>{ post.title }</p>
          )}
        </div>
      )
    }
    
    export async function getStaticProps() {
      const response = await fetch("http://localhost:3000/posts", {method: "GET"});
      const json = await response.json();
    
      return {
        props: {
          posts: json
        },
      };
    }
    
    http://localhost:4001 에 액세스 해 봅시다····어? ? ? 저희 프론트 엔지니어의 저주입니까? ?



    6.Rails측의 설정


    localhost:3000 그럼 Next.js 측에서 잘 작동하지 않는 것 같습니다.
    환경 설정에서 호스트를 지정합시다. (왜인지는 잘 모르겠습니다)docker-compose.yml 의 컨테이너 이름에 맞았습니다.

    back/config/environments/development.rb
    Rails.application.configure do
    ...
      config.hosts << "api"
    end
    

    7.Next.js에서 API URL 변경



    그런 다음 Next.js 측에서 API URL을 변경합니다.

    front/app/pages/index.js
    export async function getStaticProps() {
      const response = await fetch("http://api:3000/posts", {method: "GET"});
    ・・・
    }
    

    이제 다시 docker를 시작해 보겠습니다.
    $ docker-compose up
    

    오, 드디어 볼 수 있었던 것 같습니다.



    감상



    오랜만에 기사를 쓰고 지쳤습니다.

    좋은 웹페이지 즐겨찾기