⚙️

Dev Containerで作る Sinatra 開発環境(MySQL対応)

2024/12/21に公開

はじめに

Dev Containerは、Dockerコンテナ上で開発環境を管理できる仕組みです。
VS CodeのDev Containersを使えば、簡単にセットアップできます。
通常、ローカル環境で開発する際には、ホストOSに必要なGemやライブラリをインストールして環境を構築します。

通常の開発

一方で、Dev Containerを使用した場合の構成は次のようになります。

DevContainerを用いた開発

Dev Containerを使用するメリット

  • Rubyのバージョンをプロジェクトごとに管理
    システムに影響を与えず、プロジェクトごとに必要なRubyのバージョンを切り替えられます。

  • VS Codeの設定や拡張機能を分離
    必要な設定や拡張機能をコンテナ内にまとめ、他のプロジェクトやローカル環境への影響を防ぎます。

これらの仕組みにより、開発環境の再現性が高まり、効率的かつ柔軟な開発が可能になります。

この記事では、Dev Containerを使って以下の環境を構築する手順を解説します。

  • Sinatra・MySQL開発環境
  • コード整形・品質チェック(Prettier、Rubocop、RubyLSP)環境

環境構築手順

準備

Ruby環境構築

  1. Dev Containerで作るRuby開発環境(Prettier & Rubocop & RubyLSP対応)を参考に、必要な設定を行います。
  2. Dev Containerを起動

Sinatraのセットアップ

  1. Gemfileに追記

    Gemfile
    ...
    gem 'sinatra'
    
  2. 依存関係をインストール

    bundle install
    
  3. index.rbを新規作成

    index.rb
    # frozen_string_literal: true
    
    require 'sinatra'
    
    get '/' do
      'Hello, world!'
    end
    
  4. アプリケーションを実行

    bundle exec ruby index.rb
    
  5. 動作確認

ブラウザでhttp://localhost:4567を開き、「Hello, world!」と表示されることを確認します。

MySQLのセットアップ

MySQLコンテナの追加

  1. docker-compose.ymlに設定追加

    docker-compose.yml
    services:
      ...
      db:
        image: mysql:8
        environment:
          MYSQL_ROOT_PASSWORD: password
        volumes:
          - db_data:/var/lib/mysql
    volumes:
      ...
      db_data:
    
  2. Dev Containerを再起動

  3. MySQLコンテナへの接続確認

    mysql -h db -u root -ppassword
    

アプリケーションからMySQLにアクセスできるようにする

  1. docker-compose.ymlに環境変数を追加

    docker-compose.yml
    services:
      ...
      web:
        image: mysql:8
        environment:
          DATABASE_HOST: db
          DATABASE_USER: root
          DATABASE_PASSWORD: password
          DATABASE_NAME: template-sinatra_development
    
  2. GemfileにMySQL関連のGemを追加

    Gemfile
    ...
    gem "mysql2", "~> 0.5.6"
    
  3. 接続確認用のルートを追加

    index.rb
    get '/health_check' do
      Mysql2::Client.new(
        host: ENV.fetch('DATABASE_HOST'),
        username: ENV.fetch('DATABASE_USER'),
        password: ENV.fetch('DATABASE_PASSWORD')
      )
      'OK'
    rescue StandardError => e
      status 500
      e.message
    end
    
  4. 動作確認
    ブラウザでhttp://localhost:4567/health_checkにアクセスし、"OK"と表示されることを確認。

DB作成タスク

  1. Rakefileを作成

    require 'rake'
    require 'mysql2'
    
    namespace :db do
      desc 'データベースを作成します'
      task :setup do
       begin
        # MySQLに接続
        client = Mysql2::Client.new(
          host: 'localhost',
          username: 'root',
          password: 'password'
        )
    
        db_name = 'template-sinatra_development'
        client.query("CREATE DATABASE IF NOT EXISTS #{db_name}")
        puts "データベースを作成しました: #{db_name}"
       rescue Mysql2::Error => e
        puts "エラーが発生しました: #{e.message}"
       ensure
        client&.close
       end
      end
    
      desc 'データを追加します'
      task :seed do
       begin
        db_name = 'template-sinatra_development'
        client = Mysql2::Client.new(
          host: 'localhost',
          username: 'root',
          password: 'password',
          database: db_name
        )
    
        client.query(<<~SQL)
          CREATE TABLE IF NOT EXISTS users (
           id INT AUTO_INCREMENT PRIMARY KEY,
           name VARCHAR(255),
           email VARCHAR(255)
          );
        SQL
    
        client.query("INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com')")
        client.query("INSERT INTO users (name, email) VALUES ('Bob', 'bob@example.com')")
        puts 'サンプルデータを追加しました'
       rescue Mysql2::Error => e
        puts "エラーが発生しました: #{e.message}"
       ensure
        client&.close
       end
      end
    end
    
  2. DB作成とデータの追加

    bundle exec rake db:setup
    bundle exec rake db:seed
    

データを表示する

  1. 以下のコードをindex.rbに記述

    index.rb
    # データベースクライアントを初期化
    DB_CLIENT = Mysql2::Client.new(
      host: ENV.fetch('DATABASE_HOST'),
      username: ENV.fetch('DATABASE_USER'),
      password: ENV.fetch('DATABASE_PASSWORD'),
      database: ENV.fetch('DATABASE_NAME')
    )
    
    # クエリ結果をシンボルで取得
    DB_CLIENT.query_options.merge!(symbolize_keys: true)
    
    # ユーザー一覧を表示するルート
    get '/users' do
      users = DB_CLIENT.query('SELECT * FROM users')
    
      # HTMLレスポンスを作成
      response = <<~HTML
        <h1>Users List</h1>
        <ul>
      HTML
    
      users.each do |user|
        response += "<li>#{user[:name]} (#{user[:email]})</li>"
      end
    
      response += '</ul>'
      response
    end
    
  2. 動作確認
    ブラウザでhttp://localhost:4567/usersにアクセスし、usersテーブルに登録されたユーザー一覧が表示されることを確認。

以上で、Dev Containerを使用したSinatra開発環境(MySQL対応)の構築が完了しました。

サンプルコード

これまでの内容に加え、以下を実装したテンプレートプロジェクトです。

  • Rspecを使ったテストの追加
  • dotenvを使用した環境変数の切り替え対応
  • Sequelを使用したマイグレーション機能の追加
  • GitHub Actionsを利用したCI/CDの設定

https://github.com/yuuu-takahashi/template-sinatra

参考資料

https://envader.plus/article/305
https://future-architect.github.io/articles/20231206a/
https://code.visualstudio.com/docs/devcontainers/containers

Discussion