Strapi を開発環境と本番環境のDockerで動かしたい【その1】

今回より、Next.js で作ったサイトに、Strapi からコンテンツの配信を行っていくことを目指していきます。

Strapiとは

Strapiは Node.js ベースのヘッドレスCMSです。無料のオープンソースで、自分で用意したサーバー上に環境を構築して利用することができます。

ヘッドレスCMSにも色々ありますが、自分で用意したサーバ上にコンテンツを置くことができることと、自分で機能を拡張することができるという点で利用することにしました。

Strapi を Docker で導入するには

Strapi の Docker での導入方法は、現在v3でしか対応しておらず、v4を利用するにはDocker with Strapi V4を参考にすると良いようです。

また、Strapi 公式の Docker イメージもありますが、こちらもv3までの対応となっています。

目指すところ

Next.js のプロジェクトを Docker + VPS で動かすことができたので、それと同様に Docker + VPS で Strapi を動かすことを目標とします。

要件は以下の通りです。

  • GitHub Actions を用いて自動デプロイ
  • データベースのバックアップを取りたい
  • Strapi のプラグインを使いたい
  • ステージング環境で試せるようにしたい

タスク

タスクの洗い出しをします。開発や運用フローはNext.js の記事と同様にします。

Strapi での開発自体はほとんどない予定ですが、Strapi のバージョンのアップデートやプラグイン等の拡張機能を追加した時にローカル環境とステージング環境にて確認できるようにしておこうと思います。

  • 開発環境の Docker で Strapi を動かすために Dockerfile を用意する
  • GitHub のリポジトリを作成する
  • 本番環境用の Dockerfile を用意する
  • GitHub Actions を利用してワークフローを作成する
  • 本番環境のVPS上で Nginx の設定をする

開発環境の Docker で Strapi を動かす(方法1)

まずは、開発環境の Docker 上で Strapi を動かしてみようと思います。

Docker with Strapi V4」の記事通りにDockerfileを用意します。

STEP.1
Strapi をインストールする
まずは、ローカル環境にそのまま Strapi をインストールします。
前回の Next.js プロジェクトのCMS用にしたいので、donuts_strapiというプロジェクト名にしました。

# 作業ディレクトリを作成して移動する
$ mkdir StrapiProjects
$ cd ~/StrapiProjects
# Strapi をインストールする(TypeScript を利用したいので--ts オプションをつける。
$ yarn create strapi-app donuts-strapi --ts

# データベースをデフォルトのSQLiteからMySQLに変更したいのでCustomを選択
? Choose your installation type 
  Quickstart (recommended) 
❯ Custom (manual settings) 

? Choose your default database client 
  sqlite 
  postgres 
❯ mysql 

? Database name: donuts-strapi
? Host: 127.0.0.1
? Port: 3306
? Username: donuts-strapi
? Password: **********
? Enable SSL connection: Yes
プロジェクト構成

~/StrapiProjects/donuts-strapiの中身は以下の通りです。

.
├── .editorconfig
├── .env
├── .env.example
├── .gitignore
├── README.md
├── config
├── database
├── favicon.ico
├── node_modules
├── package.json
├── public
├── src
├── tsconfig.json
└── yarn.lock

より詳細はProject Structure – Strapi Developer Docsにて確認できます。

Strapi を利用するにはデータベースが必須になります。どのデータベースで構築されているかは、./config/database.tsで確認することができます。

デフォルトではSQLiteが使用されていますが、今回はMySQLに変更してインストールしました。

STEP.2
Dockefile を用意する
# 作業ディレクトリに移動する
$ cd ~/StrapiProjects/donuts-strapi

# Dockerfile を作成する
$ touch dev.Dockerfile
dev.Dockerfile
FROM node:16
# Installing libvips-dev for sharp Compatability
RUN apt-get update && apt-get install libvips-dev -y
ARG NODE_ENV=development
ENV NODE_ENV=${NODE_ENV}
WORKDIR /opt/
COPY ./package.json ./yarn.lock ./
ENV PATH /opt/node_modules/.bin:$PATH
RUN yarn config set network-timeout 600000 -g && yarn install
WORKDIR /opt/app
COPY ./ .
RUN yarn build
EXPOSE 1337
CMD ["yarn", "develop"]
STEP.3
.dockerignore ファイルを作成する

上記のDockerfileCOPY ./ .を行う時に無視したいファイルを.dockerignoreにて指定します。

# 作業ディレクトリに移動する
$ cd ~/StrapiProjects/donuts-strapi

# .dockerignore を作成する
$ touch .dockerignore
.dockerignore
.tmp/
.cache/
.git/
build/
node_modules/
data/
STEP.4
Docker イメージを作成する

作成したDockerfileを元に Docker イメージを作成します。

# 作業ディレクトリに移動する
$ cd ~/StrapiProjects/donuts-strapi

# Dockerイメージを作成
# docker build -f Dockerfile のファイル名 -t 作成するするイメージ名 もとになるDockerfileの場所
$ docker build -f dev.Dockerfile -t donuts-strapi-image .

# イメージができたことを確認
$ docker image ls

REPOSITORY                 TAG       IMAGE ID       CREATED          SIZE
donuts-strapi-image        latest    cb3567cb4c33   12 minutes ago   2.61GB
STEP.5
Docker コンテナを起動する

STEP.4 で作成したイメージからコンテナを起動します。

# 作業ディレクトリに移動する
$ cd ~/StrapiProjects/donuts-strapi

# コンテナの起動
# docker run  -d(バックグラウンドで起動) -p ポート --name コンテナの名前 元になるイメージ
$ docker run -d -p 1337:1337 --name donuts-strapi donuts-strapi-image

コンテナの起動を試みましたが、エラーが出ました。

$ docker run -p 1337:1337 --name donuts-strapi donuts-strapi-image

yarn run v1.22.19
$ strapi develop
Starting the compilation for TypeScript files in /opt/app
[2022-09-20 19:22:52.262] debug: ⛔️ Server wasn't able to start properly.
[2022-09-20 19:22:52.265] error: connect ECONNREFUSED 127.0.0.1:3306
Error: connect ECONNREFUSED 127.0.0.1:3306
    at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1247:16)
    --------------------
    at Protocol._enqueue (/opt/node_modules/mysql/lib/protocol/Protocol.js:144:48)
    at Protocol.handshake (/opt/node_modules/mysql/lib/protocol/Protocol.js:51:23)
    at Connection.connect (/opt/node_modules/mysql/lib/Connection.js:116:18)
    at /opt/node_modules/knex/lib/dialects/mysql/index.js:66:18
    at new Promise (<anonymous>)
    at Client_MySQL.acquireRawConnection (/opt/node_modules/knex/lib/dialects/mysql/index.js:61:12)
    at create (/opt/node_modules/knex/lib/client.js:252:39)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

デフォルトではSQLiteを使用しており、「Docker with Strapi V4」の記事にも書かれているように、SQLiteはコンテナの内部に存在するデータベースであり、上記のイメージのみでコンテナを起動することができますが、同時にコンテナを停止するとデータベースの中身も消えてしまいます。

今回 MySQLを利用しているため、MySQLのコンテナを起動する必要があります

STEP.6
MySQLのコンテナを起動する

上記エラーを解決するために、MySQLのコンテナを作成します。
MySQLコンテナとStrapiコンテナをつなぐためのnetworkも作成します。

# 作業ディレクトリに移動する
$ cd ~/StrapiProjects/donuts-strapi

# ネットワークを作成する
$ docker network create donuts-strapi-network

24a135ec61e96e1affc289964d92f74e5a0ab877a90726779fdb359500f6cab9

# ネットワークが作成されたことを確認する
$ docker network ls

24a135ec61e9   donuts-strapi-network      bridge    local

# MySQLのコンテナを作成する
# docker run --name コンテナ名 -dit --net=ネットワーク名 -p ポートの指定 環境の設定
$ docker run --name donuts-strapi-mysql -dit --net=donuts-strapi-network -p 3306:3306 -e MYSQL_ROOT_PASSWORD=donuts-strapi -e MYSQL_DATABASE=donuts-strapi -e MYSQL_USER=donuts-strapi -e MYSQL_PASSWORD=donuts-strapi mysql --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --default-authentication-plugin=mysql_native_password

# コンテナの確認をする
$ docker container ls

CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS                               NAMES
a89fc261fe45   mysql     "docker-entrypoint.s…"   4 seconds ago   Up 3 seconds   0.0.0.0:3306->3306/tcp, 33060/tcp   donuts-strapi-mysql

MySQLのパスワード等は./config/database.tsの内容を書きます。

改めてSTEP.5のコンテナを起動してみます。

# 作業ディレクトリに移動する
$ cd ~/StrapiProjects/donuts-strapi

# コンテナの起動
# docker run  -d(バックグラウンドで起動) -p ポート --net=ネットワーク名 --name コンテナの名前 元になるイメージ
$ docker run -d -p 1337:1337 --net=donuts-strapi-network --name donuts-strapi donuts-strapi-image

同様のエラーで起動できず。。。。😢

あとしまつ

うまくいかないので、手順を変更してやってみます。
その前に全て後片付けをしておきます。

# MySQL のコンテナを止める
$ docker container stop donuts-strapi-mysql

# 停止しているコンテナを確認
$ docker container ls -a

CONTAINER ID   IMAGE                      COMMAND                  CREATED         STATUS                           PORTS                               NAMES
949058f9a2d7   donuts-strapi-image        "docker-entrypoint.s…"   2 minutes ago   Exited (1) 2 minutes ago                                             donuts-strapi
a89fc261fe45   mysql                      "docker-entrypoint.s…"   6 minutes ago   Up 6 minutes                     0.0.0.0:3306->3306/tcp, 33060/tcp   donuts-strapi-mysql

# 作成したコンテナを削除する
$ docker container rm donuts-strapi donuts-strapi-mysql

# 作成したネットワークを削除する
$ docker network rm donuts-strapi-network

# 作成したイメージを削除する
$ docker image rm donuts-strapi-image

STEP.7
.env にデータベース情報を追記する

後述するやり方でなくても、こちらの方法でも無事に起動することができたので追記します。

STEP.6 のあとに.envファイルに以下を追記します。先ほどMySQLのコンテナに設定した情報を入力します。

.env
DATABASE_HOST=donuts-strapi-mysql
DATABASE_PORT=3306
DATABASE_NAME=donuts-strapi
DATABASE_USERNAME=donuts-strapi
DATABASE_PASSWORD=donuts-strapi
MYSQL_ROOT_PASSWORD=donuts-strapi

DATABASE_HOSTSTEP.6で作成したMySQLのコンテナ名を指定します。

.envを更新したので再度イメージのビルドからやり直し、コンテナを起動します。

# 作業ディレクトリに移動する
$ cd ~/StrapiProjects/donuts-strapi

# Dockerイメージを作成
# docker build -f Dockerfile のファイル名 -t 作成するするイメージ名 もとになるDockerfileの場所
$ docker build -f dev.Dockerfile -t donuts-strapi-image .


# docker run -p ポート --net=ネットワーク名 --name コンテナの名前 元になるイメージ
$ docker run -p 1337:1337 --net=donuts-strapi-network --name donuts-strapi donuts-strapi-image

これで http://localhost:1337/ にアクセスして Strapi の画面を表示することができました。

また今回のように最初にMySQLの設定を行う方法+後述のDockerComposeを利用した形でも無事に起動することができました。

開発環境の Docker で Strapi を動かす(方法2)

上記やり方では MySQL のところでハマってしまい、うまく起動することができませんでした。(後で成功したやり方も追記しました!)

以前うまく行った時のメモを見ながら再度やり直してみます。

STEP.1
Strapi をインストールする

先ほどは最初からMySQLを利用する形で設定していましたが、今回はSQLiteのままインストールしていきます。

# 作業ディレクトリを作成して移動する
$ mkdir StrapiProjects
$ cd ~/StrapiProjects
# Strapi をインストールする(TypeScript を利用したいので--ts オプションをつける。
$ npx create-strapi-app@latest donuts-strapi --quickstart --ts

http://localhost:1337/admin/auth/register-admin が自動で起動するのでcontrol+cで止めておきます。

STEP.2
Dockefile を用意する

STEP.2, 3, 4は先ほどと全く同じです。

# 作業ディレクトリに移動する
$ cd ~/StrapiProjects/donuts-strapi

# Dockerfile を作成する
$ touch dev.Dockerfile
dev.Dockerfile
FROM node:16
# Installing libvips-dev for sharp Compatability
RUN apt-get update && apt-get install libvips-dev -y
ARG NODE_ENV=development
ENV NODE_ENV=${NODE_ENV}
WORKDIR /opt/
COPY ./package.json ./yarn.lock ./
ENV PATH /opt/node_modules/.bin:$PATH
RUN yarn config set network-timeout 600000 -g && yarn install
WORKDIR /opt/app
COPY ./ .
RUN yarn build
EXPOSE 1337
CMD ["yarn", "develop"]
STEP.3
.dockerignore ファイルを作成する

上記のDockerfileCOPY ./ .を行う時に無視したいファイルを.dockerignoreにて指定します。

# 作業ディレクトリに移動する
$ cd ~/StrapiProjects/donuts-strapi

# .dockerignore を作成する
$ touch .dockerignore
.dockerignore
.tmp/
.cache/
.git/
build/
node_modules/
data/
STEP.4
Docker イメージを作成する

作成したDockerfileを元に Docker イメージを作成します。

# 作業ディレクトリに移動する
$ cd ~/StrapiProjects/donuts-strapi

# Dockerイメージを作成
# docker build -f Dockerfile のファイル名 -t 作成するするイメージ名 もとになるDockerfileの場所
$ docker build -f dev.Dockerfile -t donuts-strapi-image .

# イメージができたことを確認
$ docker image ls

REPOSITORY                 TAG       IMAGE ID       CREATED              SIZE
donuts-strapi-image        latest    8f728c883637   About a minute ago   2.95GB
STEP.5
Docker コンテナを起動する

先ほどとは異なり、まだSQLiteで設定されているため、コンテナを起動することができるはず。

# 作業ディレクトリに移動する
$ cd ~/StrapiProjects/donuts-strapi

# コンテナの起動
# docker run -p ポート --name コンテナの名前 元になるイメージ
$ docker run -p 1337:1337 --name donuts-strapi donuts-strapi-image

http://localhost:1337/ にアクセスして無事に表示されました。

確認できたらコンテナは削除しておきます。

# コンテナを止めて削除する
$ docker container stop donuts-strapi
$ docker container rm donuts-strapi
STEP.6
データベースをMySQLに変更する
改めて、SQLiteからMySQLにデータベースを変更していきます。

# 作業ディレクトリに移動する
$ cd ~/StrapiProjects/donuts-strapi

# MySQLを追加する
$ yarn add mysql

Docker Compose を利用して、MySQLのコンテナを作成とネットワークの作成等の定義を行います。

# 作業ディレクトリに移動する
$ cd ~/StrapiProjects/donuts-strapi

# Docker Compose の定義ファイルを作成
$ touch docker-compose.dev.yml

Docker Compose の定義は「HeadlessCMSの「Strapi」をDockerで爆速で立ち上げる」の記事を参考にしています。

docker-compose.dev.yml
version: '3'
services:
  strapi:
    container_name: donuts-strapi
    build:
      context: .
      dockerfile: dev.Dockerfile
    restart: always
    env_file: .env
    environment:
      DATABASE_CLIENT: ${DATABASE_CLIENT}
      DATABASE_HOST: mysql
      DATABASE_NAME: ${DATABASE_NAME}
      DATABASE_USERNAME: ${DATABASE_USERNAME}
      DATABASE_PORT: ${DATABASE_PORT}
      JWT_SECRET: ${JWT_SECRET}
      DATABASE_PASSWORD: ${DATABASE_PASSWORD}
      NODE_ENV: ${NODE_ENV}
    links:
      - mysql:mysql
    volumes:
      - ./config:/opt/app/config
      - ./src:/opt/app/src
      - ./package.json:/opt/package.json
      - ./yarn.lock:/opt/yarn.lock
      - ./.env:/opt/app/.env
    ports:
      - "1337:1337"
    networks:
      - strapi
    depends_on:
      - mysql
  mysql:
    image: mysql
    command: mysqld --default-authentication-plugin=mysql_native_password
    volumes:
      - ./data:/var/lib/mysql
    ports:
      - '3306:3306'
    restart: always
    env_file: .env
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${DATABASE_NAME}
      MYSQL_USER: ${DATABASE_USERNAME}
      MYSQL_PASSWORD: ${DATABASE_PASSWORD}
    cap_add:
      - SYS_NICE
    networks:
      - strapi
networks:
  strapi:
    name: Strapi
    driver: bridge

./config/database.tsをMySQL用に書き換えます。

database.ts
export default ({ env }) => ({
  connection: {
    client: 'mysql',
    connection: {
      host: env('DATABASE_HOST', '127.0.0.1'),
      port: env.int('DATABASE_PORT', 3306),
      database: env('DATABASE_NAME', 'strapi'),
      user: env('DATABASE_USERNAME', 'strapi'),
      password: env('DATABASE_PASSWORD', 'strapi'),
      ssl: {
        rejectUnauthorized: env.bool('DATABASE_SSL_SELF', false), // For self-signed certificates
      },
    },
    debug: false,
  },
});

.envで環境設定を行います。

# 作業ディレクトリに移動する
$ cd ~/StrapiProjects/donuts-strapi

# 開発環境用の環境変数設定ファイルを用意
$ touch .env.development
.env.development
HOST=0.0.0.0
PORT=1337
APP_KEYS="toBeModified1,toBeModified2"
API_TOKEN_SALT=tobemodified
ADMIN_JWT_SECRET=tobemodified
JWT_SECRET=tobemodified
DATABASE_HOST=localhost
DATABASE_PORT=3306
DATABASE_NAME=strapi
DATABASE_USERNAME=strapi
DATABASE_PASSWORD=strapi
NODE_ENV=development
DATABASE_CLIENT=mysql
MYSQL_ROOT_PASSWORD=pass
STEP.7
Docker Compose でイメージの作成とコンテナの起動を行う

STEP.6で作成した定義を元に、イメージの作成とコンテナの起動を行います。

# 作業ディレクトリに移動する
$ cd ~/StrapiProjects/donuts-strapi

# イメージの作成
$ docker compose -f docker-compose.dev.yml build

# コンテナの起動
$ docker compose -f docker-compose.dev.yml up -d

http://localhost:1337/ にアクセスしてもみれません😢

ログを見るためにバックグラウンドオプションを外してみました。

# コンテナの起動
$ docker compose -f docker-compose.dev.yml up

http://localhost:1337/ にアクセスしてみれるようになりました。どうして😢

おわりに

とりあえず開発環境のDocker上で動くようにはなりました。
まだわかってない部分が多いので、もう少し色々勉強して試してから本番環境へ臨みたいと思います。

続きます。