前々から自分でブログシステムを構築したいと思っていた。
はてなブログを始めたのはブログというアウトプットが自分に向いているのかどうかを確かめるためだ。そして一年以上はてなブログを続けてある程度ブログを書くという習慣はついたように思える。
そろそろ最初の夢を追いかけても良いだろう。あと、もっとtechカテゴリーを増やしたい。
最初はちゃんと全体の構成を考えて、開発環境と本番環境も事前にきっちり準備して、CI/CDももちろん用意するつもりだったけど、それすると一生設計する気がした、というか実際ずっと頭の中で考えてなかなか手を動かせなかったので、もうとりあえずデプロイするかってなった。
CMSの方をどうするか色々考えたがStrapiを利用することにした。
プロジェクト作成
さて、Strapiプロジェクトを作成する。Quick Start GuideによるとNode20をサポートしているようだ。Node20のDockerイメージをpullしてコンテナ上でcreate-strapi-app
コマンドを実行する。
% docker container run --rm -it -v $PWD:/tmp/strapi -w /tmp/strapi/ node:20.10.0 npx create-strapi-app@4.16.2 <application name> --typescript
Need to install the following packages:
create-strapi-app@4.16.2
Ok to proceed? (y) y
? Choose your installation type Custom (manual settings)
? Choose your default database client postgres
? Database name: strapi
? Host: 127.0.0.1
? Port: 5432
? Username: admin
? Password: ********
? Enable SSL connection: No
Creating a project with custom database options.
Creating a new Strapi application at /tmp/strapi/<application name>.
Creating files.
Dependencies installed successfully.
Your application was created at /tmp/strapi/<application name>.
Available commands in your project:
yarn develop
Start Strapi in watch mode. (Changes in Strapi project files will trigger a server restart)
yarn start
Start Strapi without watch mode.
yarn build
Build Strapi admin panel.
yarn strapi
Display all available commands.
You can start by doing:
cd /tmp/strapi/<application name>
yarn develop
npm notice
npm notice New patch version of npm available! 10.2.3 -> 10.2.5
npm notice Changelog: https://github.com/npm/cli/releases/tag/v10.2.5
npm notice Run npm install -g npm@10.2.5 to update!
npm notice
最終的にHerokuにデプロイしようと考えていたので、データベースにはPostgresを選択した。
まずローカル環境(PC)においてDockerで動作確認する。
docker-compose.yaml
を用意。DB用のコンテナとAPI用のコンテナを起動する。
% cat docker-compose.yaml
version: '3'
services:
postgres:
image: postgres:15.5
container_name: 'db'
ports:
- 5432:5432
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: password
POSTGRES_DB: strapi
volumes:
- ./db/data:/var/lib/postgresql/data
app:
image: node:20.10.0
container_name: 'app'
ports:
- 1337:1337
volumes:
- ./:/tmp/strapi/
working_dir: /tmp/strapi
tty: true
depends_on:
- postgres
DB用ディレクトリも作成する。
% mkdir -p db/data
.env
ファイルを修正。DATABASE_HOST
をpostgres
に修正してAPI用コンテナからDB用コンテナに接続できるようにする。
...
# Database
DATABASE_CLIENT=postgres
# DATABASE_HOST=127.0.0.1
DATABASE_HOST=postgres
...
コンテナを起動。
% docker-compose up -d
[+] Running 3/3
✔ Network xxx_default Created 0.1s
✔ Container xxx-postgres-db Started 0.5s
✔ Container xxx-app Started 5.2s
API用コンテナにログインし、npm run develop
を実行する。
% docker-compose exec app /bin/bash
root@67d28cb267ce:/tmp/strapi# npm run develop
> xxx-strapi@0.1.0 develop
> strapi develop
✔ Cleaning dist dir (19ms)
⠋ Building build context
[INFO] Including the following ENV variables as part of the JS bundle:
- ADMIN_PATH
- STRAPI_ADMIN_BACKEND_URL
- STRAPI_TELEMETRY_DISABLED
✔ Building build context (323ms)
✔ Creating admin (15750ms)
⠦ Loading Strapi[2024-01-07 03:00:05.219] info: The Users & Permissions plugin automatically generated a jwt secret and stored it in .env under the name JWT_SECRET.
✔ Loading Strapi (5234ms)
✔ Generating types (510ms)
✔ Cleaning dist dir (14ms)
✔ Compiling TS (4581ms)
Project information
┌────────────────────┬──────────────────────────────────────────────────┐
│ Time │ Sun Jan 07 2024 03:00:10 GMT+0000 (Coordinated … │
│ Launched in │ 10332 ms │
│ Environment │ development │
│ Process PID │ 341 │
│ Version │ 4.16.2 (node v20.10.0) │
│ Edition │ Community │
│ Database │ postgres │
└────────────────────┴──────────────────────────────────────────────────┘
Actions available
One more thing...
Create your first administrator 💻 by going to the administration panel at:
┌─────────────────────────────┐
│ http://localhost:1337/admin │
└─────────────────────────────┘
ブラウザからhttp://localhost:1337/admin
にリクエストする。
上記のようにユーザ作成画面が表示されるので適当なユーザを作成しログインする。
ブログ用のCMSを想定しているのでとりあえずArticleモデル(Collection Type)を作成してみる。
Collection Typeについては下記を参照。
記事の内容用のcontent
フィールドも追加した。
適当な記事を一つ作ってみる。
データベース確認
データベースの方はどうなっているのか確認してみる。
テーブル一覧は下記
strapi=# \dt
List of relations
Schema | Name | Type | Owner
--------+-----------------------------------------------+-------+-------
public | admin_permissions | table | admin
public | admin_permissions_role_links | table | admin
public | admin_roles | table | admin
public | admin_users | table | admin
public | admin_users_roles_links | table | admin
public | articles | table | admin
public | files | table | admin
public | files_folder_links | table | admin
public | files_related_morphs | table | admin
public | i18n_locale | table | admin
public | strapi_api_token_permissions | table | admin
public | strapi_api_token_permissions_token_links | table | admin
public | strapi_api_tokens | table | admin
public | strapi_core_store_settings | table | admin
public | strapi_database_schema | table | admin
public | strapi_migrations | table | admin
public | strapi_release_actions | table | admin
public | strapi_release_actions_release_links | table | admin
public | strapi_releases | table | admin
public | strapi_transfer_token_permissions | table | admin
public | strapi_transfer_token_permissions_token_links | table | admin
public | strapi_transfer_tokens | table | admin
public | strapi_webhooks | table | admin
public | up_permissions | table | admin
public | up_permissions_role_links | table | admin
public | up_roles | table | admin
public | up_users | table | admin
public | up_users_role_links | table | admin
public | upload_folders | table | admin
public | upload_folders_parent_links | table | admin
(30 rows)
色々あるけどarticles
テーブルが先ほど作ったContent Type
だろう。
テーブル定義はこちら
strapi=# \d articles
Table "public.articles"
Column | Type | Collation | Nullable | Default
---------------+--------------------------------+-----------+----------+--------------------------------------
id | integer | | not null | nextval('articles_id_seq'::regclass)
title | character varying(255) | | |
created_at | timestamp(6) without time zone | | |
updated_at | timestamp(6) without time zone | | |
published_at | timestamp(6) without time zone | | |
created_by_id | integer | | |
updated_by_id | integer | | |
content | text | | |
Indexes:
"articles_pkey" PRIMARY KEY, btree (id)
"articles_created_by_id_fk" btree (created_by_id)
"articles_updated_by_id_fk" btree (updated_by_id)
Foreign-key constraints:
"articles_created_by_id_fk" FOREIGN KEY (created_by_id) REFERENCES admin_users(id) ON DELETE SET NULL
"articles_updated_by_id_fk" FOREIGN KEY (updated_by_id) REFERENCES admin_users(id) ON DELETE SET NULL
created_at
とかupdated_at
はデフォルトで作成されるようだ。
先ほど作成した記事も見てみる。
strapi=# select id, created_at, updated_at, published_at, title, content from articles;
id | created_at | updated_at | published_at | title | content
----+-------------------------+-------------------------+--------------+------------+----------
1 | 2024-01-20 05:52:39.336 | 2024-01-20 05:52:39.336 | | test title | # hoge +
| | | | | hogehoge
(1 row)
まだ下書きのままだからpublished_at
は空だ。記事内容がそのままcontent
カラムに格納されていることがわかる。
Herokuにデプロイ
上記ページに従い作業すればデプロイできる。特に詰まるところはなかったかな。
前はHeroku無料枠があったけど無くなっちゃったみたいだね。まあ、他のクラウドサービス使ってもどのみちお金はかかるし、Herokuへのデプロイドキュメントがしっかりと用意されているからデプロイ先の見直しはしなかった。ただ一番安いプランにした。
PostgresプラグインはMiniプラン。
https://devcenter.heroku.com/articles/heroku-postgres-plans#essential-tier
dynoはEcoプラン。
https://devcenter.heroku.com/articles/eco-dyno-hours
Ecoプランはしばらくアクセスがなかったらスリープしちゃうみたいだね。スリープした状態でアプリケーションにアクセスすると表示されるまでに少し時間かかる。
このように本番環境ではContent Type
を更新することはできない。更新したいときは開発環境で起動したUIから操作し、本番環境に反映する必要がある。
とりあえず今回はここまで。次何するかは決まっていない。タイトルはナンバリングしているけど(2)が本当に作成されるかも怪しい。まあ、ここで終わるとただHerokuにスパチャしているだけになるので何かしら使えるものを作っていきたいと思う。
【次回】 【自作ブログ】(2) - Strapi Rich text (Markdown)の改行の扱いがちょっと気になった - のうらリリースノート