Rails+SQL Server環境をDocker Composeで構築する

本番環境にMicrosoftのPaaSである[Azure SQL Database](https://azure.microsoft.com/ja-jp/services/sql-database/)を使っているサービスを想定し、その開発環境を[Docker版SQL Server](https://hub.docker.com/r/microsoft/mssql-server-linux/)を使って構築します。

Docker版SQL ServerもMicrosoftが公式に提供しています。良い時代になりました。

## 前提条件

<dl>
<dt>Docker Client</dt><dd>Windows Subsystem for Linux (Ubuntu 16.04.3) 17.12.0-ce</dd>
<dt>Docker Server</dt><dd>Docker for Windows 17.09.1-ce</dd>
</dl>

### RailsをDocker化

まず前提として [Docker公式のRails構築クイックスタート](https://docs.docker.com/compose/rails/)などを参考に、Railsのアプリケーション部分をDockerにしておきます。
(db部分は書き換えるのでSQLiteのままでも構いません)

参考としてDockerfileを掲載します。

```Dockerfile
FROM ruby:2.3.0

ENV APP_ROOT=/myapp \
    BUNDLE_PATH=/bundle

WORKDIR $APP_ROOT

RUN apt-get update && \
    apt-get install -y nodejs \
                       sqlite3 \
                       freetds-dev \
                       --no-install-recommends && \
    rm -rf /var/lib/apt/lists/*

COPY Gemfile $APP_ROOT
COPY Gemfile.lock $APP_ROOT

RUN \
  echo 'gem: --no-document' >> ~/.gemrc && \
  cp ~/.gemrc /etc/gemrc && \
  chmod uog+r /etc/gemrc && \
  bundle config --global build.nokogiri --use-system-libraries && \
  bundle config --global jobs 4 && \
  bundle install

COPY . $APP_ROOT

EXPOSE  3000
```
必ずしもこの通りである必要はありませんが、SQL Serverに接続するには`$ apt-get install freetds-dev`が必要になるので注意します。

## Docker版SQL Serverの導入

必要になるGemを導入します。

```ruby:Gemfile
# Azure SQL Server
gem 'tiny_tds', '~> 1.0'
gem 'activerecord-sqlserver-adapter'
```

次にdocker-compose.ymlを記述します。

このとき`volumes`を使ってデータを永続化しておきます。
なお同様の方法でbundleディレクトリも永続化することで、bundle installの度にbuildしなくても済むようにしています。
参考: [docker\-composeでRailsのGemを更新する時、docker buildするのを回避したい \- Qiita](https://qiita.com/neko-neko/items/abe912eba9c113fd527e)

```yaml:docker-compose.yml
version: '3'
services:
  db:
    image: microsoft/mssql-server-linux:2017-latest
    environment:
      ACCEPT_EULA: Y
      MSSQL_SA_PASSWORD: YourStrong!Passw0rd # ※のちに再設定するパスワード
    volumes:
      - db-volume:/var/opt/mssql/
    ports:
      - "1433:1433"
  app:
    build: .
    command: bundle exec rails server -p 3000 -b '0.0.0.0'
    volumes:
      - .:/myapp # ※Windows Subsystem for LinuxのDocker Clientは相対パスがうまく動かない事があるので、必要ならば絶対パスに書き換える
      - bundle-volume:/bundle
    ports:
      - "3000:3000"
    depends_on:
      - db
    tty: true
    stdin_open: true
    environment:
      RAILS_ENV: development
volumes:
  bundle-volume:
    driver: local
  db-volume:
    driver: local
```

database.ymlも、Dockerで構築したSQL Serverを見に行くよう書き換えます。

```yaml:database.yml
development:
  adapter: sqlserver
  host: db
  port: 1433
  dataserver: ""
  database: your_app_development
  username: SA
  password: "YourNewStrong!Passw0rd" # 再設定した後のパスワード
  timeout: 10
#  azure:    true # DockerではなくAzure SQL Databaseに接続する場合は必要
```

一度`$ docker-compose up`で起動した後、[Microsoft公式ドキュメント](https://docs.microsoft.com/ja-jp/sql/linux/quickstart-install-connect-docker)の手順に従ってコンテナの内部のSQL Serverに接続し、パスワードを変更しておきます。

```bash
$ docker-compose build
$ docker-compose up
$ docker-compose exec db /opt/mssql-tools/bin/sqlcmd \
   -S localhost -U SA -P '<YourStrong!Passw0rd>' \
   -Q 'ALTER LOGIN SA WITH PASSWORD="<YourNewStrong!Passw0rd>"'
```

あとは、この接続情報を使ってデータベーススキーマを適用し、アプリケーションを起動するだけです。

```
$ docker-compose run --rm app bundle install
$ docker-compose run --rm app bundle exec rake db:create
$ docker-compose run --rm app bundle exec rake db:migrate
```

## SQL Serverのデバッグ

SQL Serverへの接続のクライアントには[Visual Studio Codeのmssql拡張機能](https://marketplace.visualstudio.com/items?itemName=ms-mssql.mssql)を使うと便利です。

VSCodeを起動し、コマンドパレットで`>Install Extensions`から`mssql`拡張機能をインストールします。
再読み込みし、`>MS SQL: Connect`を実行するか、設定ファイルに下記を記述することで接続情報を設定します。

```json:settings.json
  "mssql.connections": [
    {
      "server": "localhost",
      "database": "your_app_development",
      "authenticationType": "SqlLogin",
      "user": "SA",
      "password": "",
      "emptyPasswordInput": false,
      "savePassword": true,
      "profileName": "localhost sql server"
    }
  ]
}
```

下記のようなファイルを作って`Ctrl+Shift+E`か`>MS SQL: Execute Query`すると、SQLが実行されます。

```sql:ms.sql
SELECT Name from sys.Databases
GO
```

詳細は[Microsoft公式ドキュメント](https://docs.microsoft.com/ja-jp/sql/linux/sql-server-linux-develop-use-vscode)を読んでください。

## 参考文献

- [microsoft/mssql\-server\-linux \- Docker Hub](https://hub.docker.com/r/microsoft/mssql-server-linux/)
- [rails\-sqlserver/tiny\_tds: TinyTDS \- Simple and fast FreeTDS bindings for Ruby using DB\-Library\.](https://github.com/rails-sqlserver/tiny_tds)
- [rails\-sqlserver/activerecord\-sqlserver\-adapter: SQL Server Adapter For Rails](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter)
- [SQL Server 2017 Docker を使ってみる \| Microsoft Docs](https://docs.microsoft.com/ja-jp/sql/linux/quickstart-install-connect-docker)
- [For SQL Server、Visual Studio Code mssql 拡張機能を使用して \| Microsoft Docs](https://docs.microsoft.com/ja-jp/sql/linux/sql-server-linux-develop-use-vscode)
- [DockerでRuby on Rails開発環境作ってみた \- Qiita](https://qiita.com/otama/items/9e7d00b4fdd8d647b688)