eityansメモ

eityansメモ

ゆるくやっていきます

記事一覧

素のRails + PostgreSQL構成をdockerで管理するようにしたメモ

個人開発の素のRails + PostgreSQLアプリがある。Redisを導入したくて、ついでにDocker管理するようにした。職場でDockerが使われているが、既に構築されたものをたまにメンテするぐらいで、一から作るのは初めてだったので新鮮だったメモ。


Dockerfileの作成

1FROM ruby:3.2.2-slim-bookworm
2
3## 必要なパッケージをインストール
4RUN apt update -qq && apt install -y --no-install-recommends \
5    build-essential \
6    libpq-dev
7
8# 作業ディレクトリを設定
9WORKDIR /app
10
11# GemfileとGemfile.lockをコピー
12COPY Gemfile Gemfile.lock ./
13
14# Bundlerをインストールし、依存関係をインストール
15RUN gem install bundler:2.6.8
16RUN bundle install --jobs=$(nproc) --retry=3
17
18# アプリケーションコードをコピー
19COPY . .
20
21# エントリーポイント
22CMD ["rails", "server", "-b", "0.0.0.0", "-p", "3000"]
23
24# ポートを公開
25EXPOSE 3000

いろいろなものを参考にしながら作成。古いアプリなのでRubyも古い。今度上げる。

  • aptとapt-getの違いを知ったり。機能面で優れているのでaptを使うで良さそう。
  • apt update -qq

    • qqオプションは、エラー以外の出力を無くすやつ

  • apt install -y --no-install-recommends

    • yオプションはインストール周りの承諾を自動的に「はい」にする

    • no-install-recommendsオプションは推奨パッケージをインストールしない。Debian系のパッケージシステムは、必須ではないがあると便利なパッケージをデフォルトでインストールさせるらしい。必要最低限にするために必要

  • build-essential

    • ビルドツールパッケージ

  • libpq-dev

    • PostgreSQLに必要

  • RUN bundle install --jobs=$(nproc) --retry=3

    • jobはインストール処理の並列実行

    • nprocコマンドでCPUコアの数が返る。いけるところまで並列化している

docker-composeの作成

1version: '3.9'
2services:
3  db:
4    image: postgres:16
5    environment:
6      POSTGRES_USER: XXX
7      POSTGRES_PASSWORD: XXX
8      POSTGRES_DB: XXX
9      DATABASE_HOST: db
10    volumes:
11      - db_data:/var/lib/postgresql/data
12    ports:
13      - "5432:5432"
14
15  web:
16    build: .
17    volumes:
18      - .:/app
19    ports:
20      - "3000:3000"
21    depends_on:
22      - db
23    environment:
24      RAILS_ENV: development
25      DATABASE_HOST: db
26      DATABASE_USERNAME: XXX
27      DATABASE_PASSWORD: XXX
28      DATABASE_NAME: XXX
29      REDIS_URL: redis://redis:6379/1
30
31  redis:
32    image: redis:8
33    ports:
34      - "6379:6379"
35    volumes:
36      - redis_data:/data
37
38volumes:
39  db_data:
40  redis_data:

DBに接続ができずにハマる。何度かPostgreSQLのユーザー名を変更したのと、その変更のキャッシュが残っていた関係で接続ができなくなった。イメージのビルドを明示的に指定することで解決。

1docker-compose up --build

マイグレーションの実行

1docker compose exec web rails db:migrate 

データの移行

環境を作っただけでデータがない。これまでローカルのPostgreSQLに保持していたデータをコンテナで呼び出しているDocker Volumeに移行する
1pg_dump database_name > local_backup.sql
2docker cp local_backup.sql db-container-name:/tmp/local_backup.sql
3docker compose exec db psql -U postgres -d database_name -f /tmp/local_backup.sql

ぼんやり知っているつもりだったけど、実際に手を動かしてみると色々時間取られた

33歳になった

昨日33歳になった。1年後の自分がゲラゲラ笑うかも知れないので、ぼんやり考えていることを雑に残す。


「年を取ると一年が早くなる」とよく言われるが、個人的にはそんなことはない気がする。一年が早くなるのは、おそらく年齢を重ねるごとにイベントごとが少なくなりがちだからだろう。ここ一年はいろいろなところに出かけたり、美味しいものを食べたりといった思い出がたくさんあるので、密度の濃い充実した一年を過ごせた気がする。これからもそういう思い出をたくさん作っていきたい。このあたりの考え方はDIE WITH ZEROの影響を強く受けている。

プライベートは充実しているが、仕事はどうだろうか。社会人になって8年ちょっと、Webエンジニアになってもうすぐ6年になる。エンジニアとしてできることはたくさん増えてきたが、ここ最近はできることを淡々とやっている感覚があり成長実感が薄くなっている。いわゆるキャリアを考えるというやつか。

それでいうと、個人の能力を高めることはもちろん大切だけれど、チームとしてより高みを目指すことも大事だなとここ一年で強く思うようになった。一人で出来ることは限界があるが、チーム、組織ならもっといろいろなことが出来る。これを表現するのはマネジメントといった世界になるのだろうか。

image

そんなことを考えながら、お祝いですき焼きを食べた。めちゃくちゃ旨い。

group_by を group + array_agg で高速化する(PostgreSQL)

こういうパフォーマンス改善もあるよメモ


ユーザーと記事があり、ユーザーは記事をお気に入りできる。お気に入りには種類がある。お気に入りの種類ごとに記事のidの配列を取得するような処理を考える。

1{
2  "like_name_1" => [1,2,3,4],
3  "like_name_2" => [5,6,7,8],
4}

最終的にはこんな感じのデータを取りたい

group_by を使う

1Like
2  .where(user_id: user.id)
3  .select(:name, :post_id)
4  .group_by(&:name)
5  .transform_values { |v| v.pluck(:post_id) }

group_byでDBの結果を取得しtransform_values以降をRailsで処理することになる。数が多い場合はパフォーマンスが気になる

group + array_aggを使う

集約関数のarray_aggを使う

NULLも含めてすべての入力値を収集して配列に格納します。

1Like
2  .where(user_id: user.id)
3  .group(:name)
4  .select(:name, "array_agg(post_id) as post_ids")
5  .to_h{ |g| [g.name, g.post_ids] }

こうすることでgroupの処理をDB側に寄せることができる。ただし、可読性の低下や、PostgreSQLに依存した実装になってしまうためそのあたりのデメリットは考慮すること。


ちなみにMySQLの場合はGROUP_CONCATが使えそう

RenderのServicesをStarterプランからFreeプランに移して節約する

Render上で動いている個人開発アプリがある。地味に利用されているが、そこまでバズっているわけでもない。

ServicesをStarterプランで毎月$7払っていたが、少しもったいない気がしたので、思い切ってStarterからFreeプランにダウングレードした。

Render側ではプランを変更するだけでできる。

問題はFreeプランの制約である。15分アクセスがないと落とされてしまうため、その後の起動が遅くなってしまう。

Spinning down after 15 minutes of inactivity

監視ツールであるUptimeRobotを使い、死活管理をしつつ定期的なリクエストを実現した。これで少しお金が浮いた✌('ω')

Cline使ってみたメモ

深夜に「AIエージェントをちゃんと使ったことがないな」とふと思ったので試してみたメモ。


Clineとは

  • Cline Bot Inc.社が開発

  • CLIとエディターを使用できるAIアシスタント

  • なんかもういろいろやってくれる

  • AIプロバイダーと共に使う

導入

Clineの導入

  1. 拡張機能を入れる

  2. AIプロバイダーを選択する(色々あるけど今回は安いDeepseekを選択)
    1. (データの扱いはどうなんだという話がありますが、今回は個人開発のレベルなのであまり気にしないことにしました。)

  3. プロバイダーのAPIキーを設定する

トークンの購入

DeepseekでAPIを呼び出すのにお金がかかるので、トークンを買った。お試しで$2。

購入した以上のコストが掛からないのは安心。

使ってみる

シンプルなhtml + cssのページの改修を依頼。身内の思い出を時系列で並べている単純なhtmlがあり、基本的に同じようなタグ構造が並んでいるもの。

対話型で作業が進む。小さく作業の方針を確認して、それに同意したら作業を進めるようなプロセスを繰り返す。作業中、エディタでコードが生成されていくところが未来感あってテンション上がる。

まずはAIくんに、良い感じにしたいんだけどどうすればいい?と聞いてみた。「中身をjsonに切り出し、ビルドスクリプトを作って静的ファイルを生成する仕組みを作る」のはどうでしょう?と提案、試しにお願いしてみると少し大げさすぎるものが出来上がった。

何回か対話を行い、最終的に「中身だけをjsonに切り出して、JavaScriptでjsonを読み込んでそこからDOMを生成する」方式に決定。

なんだかんだ対話を1時間ぐらいしていたが、最終的にやりたいことができて大満足。コストは$0.17

感想

  • シンプルに便利

  • やりたいけどめんどくさいみたいな作業をとりあえずお願いするのに向いているかも

  • 一部指示から外れたhtmlがあり、それをjsonに落としこめなかった(無視した)ところがあったので、出てきたものをチェックするのは人間の仕事だなと

  • トークンの関係なのか、60個ぐらいの置き換えをするのに複数回に分けて作業をしていた。もしかしたらもっとうまいテクニックがあるのかも知れない?

  • 個人開発だからのびのびとトライできたけど、これらを業務で使うとなると慎重になる気持ちもわかる。積極的に使いますと意思決定ができる組織って改めてすごいなと思う。

  • AIプロバイダーやモデルの選択がたくさんありすぎて、逆に困ってしまう。高いモデルも今度ためしてみるか..?

深夜テンションで始めたことだけど学びが多かった。今後も使っていきたい。