Docker ComposeでRails+Vue3+Typescript+PostgreSQLの開発環境を構築
はじめに
RailsとVue3とTypescriptとPostgreSQLの開発環境をDocker Composeで設定と実行してみました。
Ruby: 3.2.1
Rails: 7.2.1
tl:dr;
- ディレクトリ構造
- バックエンドを構築する
・Dockerfileを作成する
・docker-compose.ymlを作成する - データベースの接続情報を設定する
- フロントエンドを構築する
・viteを使ってプロジェクトをセットアップ
・ESLintを導入する
・Prettierを導入する
・Dockerfileを作成する
・docker-compose.ymlを追記する - docker compose build
- docker compoup up
ディレクトリ構造
簡単ですが、現時点ではこのような構造になります。
.
├── api/
│ ├── Dockerfile
│ ├── Gemfile
│ ├── Gemfile.lock
│ ├── entrypoint.sh
├── front/
│ └── Dockerfile
└── docker-compose.yml
└── .gitignore
バックエンドを構築する
Rails APIモードで新規アプリを作成します。
rails new . --api --force --database=postgresql --skip-test --skip-system-test
ターミナルで上記コマンド実行後には、Railsアプリに関わるファイル一式が自動生成されます。
Dockerfileを作成する
Dockerfile を以下のようにします。
Ruby、Bundler などの依存パッケージすべてをコンテナー内部に含めてビルドされます。
rails new
で生成されたデフォルトのDockerfileを使うこともできます。
FROM ruby:3.2.1-alpine
ENV LANG="ja_JP.UTF-8"
ENV app="/app"
WORKDIR $app
# 環境変数の設定(ここでは本番環境)
ENV RAILS_LOG_TO_STDOUT="1" \
RAILS_SERVE_STATIC_FILES="true" \
RAILS_ENV="production" \
BUNDLE_WITHOUT="development"
RUN apk update \
&& apk upgrade \
&& apk --update add \
g++ \
make \
tzdata \
gcompat \
libpq-dev \
postgresql-client \
openssh \
git \
bash \
nodejs \
yarn \
&& cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
&& rm -rf /var/cache/apk/*
RUN gem update --system \
&& gem install bundler --no-document
COPY Gemfile Gemfile.lock ./
# パッケージをインストール
RUN bundle install --jobs 4 --retry 3
# アプリケーションファイルをコピー
COPY . .
# コンテナー起動時に毎回実行されるスクリプトを追加
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000
# イメージ実行時に起動させる主プロセスを設定
CMD ["rails", "server", "-b", "0.0.0.0"]
Dockerコンテナが起動された際に実行されるエントリーポイント(起動スクリプト)を設定します。
CMD
やRUN
コマンドを使用して、アプリケーションを起動するコマンドを指定しますが、ENTRYPOINT
を使用することで、Dockerコンテナが常に特定のスクリプトを実行するように設定することができます。
#!/bin/bash
# If running the rails server then create or migrate existing database
if [ "${*}" == "./bin/rails server" ]; then
./bin/rails db:prepare
fi
exec "${@}"
Railsアプリケーションのデータベースを作成またはマイグレーションを実行するためのdb:prepare
タスクを実行します。
このスクリプトの目的は、特定の条件でRailsアプリケーションのデータベースをセットアップすることです。通常、RailsアプリケーションのデータベースをDockerコンテナ内で適切に設定するためには、データベースの作成やマイグレーションが必要です。
このスクリプトはそれを自動化しており、RailsアプリケーションがDockerコンテナ内で起動される際にデータベースを準備するためのスクリプトです。
docker-compose.ymlを作成する
services:
db:
image: postgres
restart: always
volumes:
- ./tmp/db:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: password
TZ: "Asia/Tokyo"
ports:
- "5432:5432"
web:
build: ./api
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- ./api:/app
ports:
- "3000:3000"
depends_on:
- db
データベースとウェブという 2 つのアプリを含んだサービスが定義します。
そしてそれぞれの Docker イメージを定義します。
データベースは既存の PostgreSQL イメージにより動作します。ウェブアプリはカレントディレクトリ内に生成されます。
rm -f /myapp/tmp/pids/server.pid
: これはサーバー内にserver.pid
というファイルが先に存在していたときに、サーバーが再起動できなくなる問題を回避するものです。 このスクリプトは、コンテナーが起動されるたびに実行されることになります。
DBの接続情報を追加する
PostgreSQLの接続情報を追加します。
default: &default
++ host: db
++ username: postgres
++ password: password
# For details on connection pooling, see Rails configuration guide
# https://guides.rubyonrails.org/configuring.html#database-pooling
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
フロントエンドを構築する
viteを使ってVue+Typescriptでアプリを作成します。
➜ npm create vite@latest
Need to install the following packages:
create-vite@5.5.3
Ok to proceed? (y) y
> npx
> create-vite
✔ Project name: … vue-app
✔ Select a framework: › Vue
✔ Select a variant: › TypeScript
Scaffolding project in /Users/***/vue-app...
Done. Now run:
cd vue-app
npm install
npm run dev
サーバーを立ち上げて以下のような画面が表示されればOKです。
これでVue+Typescriptのアプリの雛形が作成されました。
ESLintを導入する
ESLintを導入するためにこちらのパッケージをインストールします。
ESLintはJavaScript/TypeScript のソースコードがコーディングルールに則っているかを検証するためのツールです。
ESLint と Prettier にはそれぞれコード整形のためのルールが存在するため、競合する可能性があります。
そのため、コード整形は Prettier に任せ、Prettierと競合するESLintのルールを無効化するために、eslint-config-prettierをインストールします。
npm install --save-dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-vue typescript-eslint eslint-config-prettier
ESLintの設定用eslint.config.js
を作成します。
公式にあるサンプルを使います。
import js from '@eslint/js'
import eslintPluginVue from 'eslint-plugin-vue'
import ts from 'typescript-eslint'
import prettierConfig from 'eslint-config-prettier'
export default ts.config(
js.configs.recommended,
...ts.configs.recommended,
...eslintPluginVue.configs['flat/recommended'],
prettierConfig,
{
files: ['*.vue', '**/*.vue'],
languageOptions: {
parserOptions: {
parser: '@typescript-eslint/parser'
}
}
}
)
ESLint用スクリプトを追加します。
"scripts": {
++ "lint": "eslint . -c .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --config eslint.config.js",
},
npm run lint
を使えるようになりました。
npm run lint
> vue-app@0.0.0 lint
> eslint . -c .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --config eslint.config.js
Prettierを導入する
Prettierはソースコードを整形するツールです。
1 行のあたりの最大文字数、 セミコロンの有無、 インデント幅などの整形ルールを設定すると、任意のタイミングでコードを自動整形してくれます。
npm install --save-dev prettier @types/eslint-config-prettiere eslint-plugin-prettier
Prettierの設定用.prettierrc
を作成します。
{
"printWidth": 120,
"semi": false,
"singleQuote": true,
"trailingComma": "none",
"tabWidth": 2
}
コード整形から排除したいファイルがあれば.prettierignore
ファイルを作成し、ファイルやディレクトリを指定することができます。
Prettier用スクリプトを追加します。
"scripts": {
++ "format": "prettier --write \"src/**/*.{js,ts,vue,json}\"",
},
npm run format
を使えるようになりました。
npm run format
> vue-app@0.0.0 format
> prettier --write "src/**/*.{js,ts,vue,json}"
src/App.vue 47ms (unchanged)
src/components/HelloWorld.vue 21ms
src/main.ts 2ms (unchanged)
src/vite-env.d.ts 2ms (unchanged)
/front
にDockerfileを作成する
# 公式のNodeランタイムをベースイメージとして使用する
FROM node:18-alpine
# 作業ディレクトリを設定する
WORKDIR /app
# package.jsonとpackage-lock.jsonを作業ディレクトリにコピーする
COPY package*.json ./
# パッケージをインストールする
RUN apk --no-cache update && npm install
# プロジェクトのファイルとフォルダを現在の作業ディレクトリ('app'フォルダ)にコピーする
COPY . .
EXPOSE 5173
CMD ["npm", "run", "dev"]
docker-compose.yml
に/front
用の記述を追加します。
services:
++ front:
++ build:
++ context: ./front
++ dockerfile: Dockerfile
++ volumes:
++ - ./front:/app
++ - /app/node_modules
++ ports:
++ - "5173:5173"
++ command: npm run dev
++
++volumes:
++ postgres_data:
vite.config.ts
を編集する
vite.config.ts
にこちらの記述を追加します。
host: Viteサーバーがリッスンすべき IP アドレスを指定します。 0.0.0.0
もしくは true
に設定します。
server: {
host: true,
watch: {
usePolling: true
}
}
セットアップが完了しました。
コンテナをビルドと起動します。
docker compose build
docker compose build
✗ docker compose build
docker compose build
[+] Building 32.9s (26/26) FINISHED docker:desktop-linux
=> [web internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 1.16kB 0.0s
=> [front internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 477B 0.0s
=> [web internal] load metadata for docker.io/library/ruby:3.2.1-alpine 2.1s
=> [front internal] load metadata for docker.io/library/node:18-alpine 1.2s
=> [front internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [front 1/5] FROM docker.io/library/node:18-alpine@sha256:02376a266c84acbf45bd19440e08e48b1 0.0s
=> [front internal] load build context 1.7s
=> => transferring context: 121.84MB 1.7s
=> [web internal] load .dockerignore 0.0s
=> => transferring context: 801B 0.0s
=> [web 1/9] FROM docker.io/library/ruby:3.2.1-alpine@sha256:04ad4930356641f944d81037b32b5a34 2.4s
=> => resolve docker.io/library/ruby:3.2.1-alpine@sha256:04ad4930356641f944d81037b32b5a345c3d 0.0s
=> => sha256:e449c52ab15a86b642acc1f3d08fcc3d495eba58eb4b7b67c5b97787ce7691a9 4.12MB / 4.12MB 0.6s
=> => sha256:9ba7ad0f163b30834342d9da89d2cc78f2da66af5c514c6f0f2294f505d9e707 219B / 219B 0.7s
=> => sha256:04ad4930356641f944d81037b32b5a345c3debfce017559d65131b5d11b9b4e1 1.65kB / 1.65kB 0.0s
=> => sha256:23c585ea5bd244e9815b8353669550ae3d4edd06c015abcda71366168193970e 1.36kB / 1.36kB 0.0s
=> => sha256:e3e366d951988e0ea0bc116b16410c4aaf790b22603afd99aec2cfe0d4579103 7.25kB / 7.25kB 0.0s
=> => sha256:c41833b44d910632b415cd89a9cdaa4d62c9725dc56c99a7ddadafd6719960f9 3.26MB / 3.26MB 0.4s
=> => extracting sha256:c41833b44d910632b415cd89a9cdaa4d62c9725dc56c99a7ddadafd6719960f9 0.1s
=> => sha256:c83cd891d23f0c16a723e092511e103981be1130bbbda7930cc82628ed9835 31.76MB / 31.76MB 1.8s
=> => extracting sha256:e449c52ab15a86b642acc1f3d08fcc3d495eba58eb4b7b67c5b97787ce7691a9 0.2s
=> => sha256:cbbeecc62e2e9cd8e49deb0430769514d740fbe77b56b16dc257439e50167660 172B / 172B 1.0s
=> => extracting sha256:9ba7ad0f163b30834342d9da89d2cc78f2da66af5c514c6f0f2294f505d9e707 0.0s
=> => extracting sha256:c83cd891d23f0c16a723e092511e103981be1130bbbda7930cc82628ed9835c6 0.5s
=> => extracting sha256:cbbeecc62e2e9cd8e49deb0430769514d740fbe77b56b16dc257439e50167660 0.0s
=> [web internal] load build context 0.5s
=> => transferring context: 50.14kB 0.5s
=> CACHED [front 2/5] WORKDIR /app 0.0s
=> CACHED [front 3/5] COPY package*.json ./ 0.0s
=> CACHED [front 4/5] RUN apk --no-cache update && npm install 0.0s
=> CACHED [front 5/5] COPY . . 0.0s
=> [front] exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:495e0f39fe342643caae18d8301744c8a2e6be2a8e0a188dc924150708f9911b 0.0s
=> => naming to docker.io/library/xxx-app-front 0.0s
=> [front] resolving provenance for metadata file 0.0s
=> [web 2/9] WORKDIR /app 0.2s
=> [web 3/9] RUN apk update && apk upgrade && apk --update add g++ make t 8.3s
=> [web 4/9] RUN gem update --system && gem install bundler --no-document 4.5s
=> [web 5/9] COPY Gemfile Gemfile.lock ./ 0.0s
=> [web 6/9] RUN bundle install --jobs 4 --retry 3 14.8s
=> [web 7/9] COPY . . 0.0s
=> [web 8/9] COPY entrypoint.sh /usr/bin/ 0.0s
=> [web 9/9] RUN chmod +x /usr/bin/entrypoint.sh 0.1s
=> [web] exporting to image 0.5s
=> => exporting layers 0.5s
=> => writing image sha256:3e61e1301805ac153b45e19b99a2693d7953adc6fd0982d6ce8549036b7b9d57 0.0s
=> => naming to docker.io/library/xxx-app-web 0.0s
=> [web] resolving provenance for metadata file
docker compose build
を実行しコンテナ環境を構築します。
docker compoup upによりアプリを起動
docker compose up
docker compose up
[+] Running 4/4
✔ Network rails-vue-app_default Created 0.0s
✔ Container rails-vue-app-front-1 Created 0.6s
✔ Container rails-vue-app-db-1 Created 0.1s
✔ Container rails-vue-app-web-1 Created 0.0s
Attaching to db-1, front-1, web-1
db-1 | The files belonging to this database system will be owned by user "postgres".
db-1 | This user must also own the server process.
db-1 |
db-1 | The database cluster will be initialized with locale "en_US.utf8".
db-1 | The default database encoding has accordingly been set to "UTF8".
db-1 | The default text search configuration will be set to "english".
db-1 |
db-1 | Data page checksums are disabled.
db-1 |
db-1 | fixing permissions on existing directory /var/lib/postgresql/data ... ok
db-1 | creating subdirectories ... ok
db-1 | selecting dynamic shared memory implementation ... posix
db-1 | selecting default "max_connections" ... 100
db-1 | selecting default "shared_buffers" ... 128MB
db-1 | selecting default time zone ... Asia/Tokyo
db-1 | creating configuration files ... ok
front-1 |
front-1 | > vue-app@0.0.0 dev
front-1 | > vite
front-1 |
front-1 | Re-optimizing dependencies because lockfile has changed
front-1 |
front-1 | VITE v5.4.9 ready in 246 ms
front-1 |
front-1 | ➜ Local: http://localhost:5173/
front-1 | ➜ Network: use --host to expose
web-1 | Bundle complete! 8 Gemfile dependencies, 81 gems now installed.
web-1 | Gems in the group 'development' were not installed.
web-1 | Bundled gems are installed into `/usr/local/bundle`
db-1 | running bootstrap script ... ok
db-1 | performing post-bootstrap initialization ... ok
db-1 | syncing data to disk ... ok
db-1 |
db-1 |
db-1 | Success. You can now start the database server using:
db-1 |
db-1 | pg_ctl -D /var/lib/postgresql/data -l logfile start
db-1 |
db-1 | initdb: warning: enabling "trust" authentication for local connections
db-1 | initdb: hint: You can change this by editing pg_hba.conf or using the option -A, or --auth-local and --auth-host, the next time you run initdb.
db-1 | waiting for server to start....2024-10-19 21:09:06.564 JST [48] LOG: starting PostgreSQL 17.0 (Debian 17.0-1.pgdg120+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit
db-1 | 2024-10-19 21:09:06.566 JST [48] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
db-1 | 2024-10-19 21:09:06.574 JST [51] LOG: database system was shut down at 2024-10-19 21:09:06 JST
db-1 | 2024-10-19 21:09:06.581 JST [48] LOG: database system is ready to accept connections
db-1 | done
db-1 | server started
db-1 |
db-1 | /usr/local/bin/docker-entrypoint.sh: ignoring /docker-entrypoint-initdb.d/*
db-1 |
db-1 | waiting for server to shut down...2024-10-19 21:09:06.768 JST [48] LOG: received fast shutdown request
db-1 | .2024-10-19 21:09:06.770 JST [48] LOG: aborting any active transactions
db-1 | 2024-10-19 21:09:06.772 JST [48] LOG: background worker "logical replication launcher" (PID 54) exited with exit code 1
db-1 | 2024-10-19 21:09:06.774 JST [49] LOG: shutting down
db-1 | 2024-10-19 21:09:06.775 JST [49] LOG: checkpoint starting: shutdown immediate
db-1 | 2024-10-19 21:09:06.790 JST [49] LOG: checkpoint complete: wrote 3 buffers (0.0%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.004 s, sync=0.001 s, total=0.016 s; sync files=2, longest=0.001 s, average=0.001 s; distance=0 kB, estimate=0 kB; lsn=0/14E4F98, redo lsn=0/14E4F98
db-1 | 2024-10-19 21:09:06.802 JST [48] LOG: database system is shut down
db-1 | done
db-1 | server stopped
db-1 |
db-1 | PostgreSQL init process complete; ready for start up.
db-1 |
db-1 | 2024-10-19 21:09:06.883 JST [1] LOG: starting PostgreSQL 17.0 (Debian 17.0-1.pgdg120+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit
db-1 | 2024-10-19 21:09:06.884 JST [1] LOG: listening on IPv4 address "0.0.0.0", port 5432
db-1 | 2024-10-19 21:09:06.884 JST [1] LOG: listening on IPv6 address "::", port 5432
db-1 | 2024-10-19 21:09:06.885 JST [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
db-1 | 2024-10-19 21:09:06.892 JST [62] LOG: database system was shut down at 2024-10-19 21:09:06 JST
db-1 | 2024-10-19 21:09:06.900 JST [1] LOG: database system is ready to accept connections
web-1 | => Booting Puma
web-1 | => Rails 7.2.1.1 application starting in production
web-1 | => Run `bin/rails server --help` for more startup options
web-1 | Puma starting in single mode...
web-1 | * Puma version: 6.4.3 (ruby 3.2.1-p31) ("The Eagle of Durango")
web-1 | * Min threads: 3
web-1 | * Max threads: 3
web-1 | * Environment: production
web-1 | * PID: 1
web-1 | * Listening on http://0.0.0.0:3000
web-1 | Use Ctrl-C to stop
RailsとViteサーバーがそれぞれを立ち上げましたらOKです。
終わりに
RailsとVueとTypescriptとPostgreSQLの開発環境をDocker Composeで構築してみました。
誰かの参考になれば嬉しいです。
Discussion