オープンソースのSNSをDockerで動かしてみたら懐かしすぎた

こんにちは、たかぴーです。

このエントリは、GMOペパボエンジニア Advent Calendar 2020 - Adventarの8日目の記事です。7日目はしばっちさんの「AWSでDNSをRoute53を使わずに構築する」でした。

社内のPHPアプリケーションをDocker化するにあたりどういった流れで構築していくのか、自分はこうやっているよ!というのを書いていこうと思ったのですが、社内のアプリケーションの設定やソースコードは表に出す訳にはいかないので、今回は代わりにOpenPNEという、PHP製のオープンソースSNSをDocker化し構築の流れを書いていきます。

今回は最低限動かすことが目的なので、ローカルで動くところまでをゴールとします。

1. まずは、ざっくり動かしてみる

まずは細かいことは気にせず、ざっくり動かしていきます。

情報を集める

最新版(12/8時点)のOpenPNEセットアップ手順をの通りにやれば良さそうです。

推奨構成はこんな感じ

OS: Debian jessie
Apache 2.4.10 以降
PHP: PHP 7 以降
DB MySQL 5.5.53以降

いわゆるLAMP環境ってやつですね。 Docker Hubの公式イメージを使って作れそうです。

docker-composeを使って大枠を作る

最終的には、docker-composeがなくてもイメージ単体で動作させる予定ですが、 イメージ構築時は、設定をyamlに追加しながら作業できるので、個人的にはdocker-composeを使いながら構築するのがやりやすいです。

こんな感じで大枠を作成

version: '3'

services:
  app:
    build: ./
  db:
    image: mysql:5.7.32
FROM php:7.4.10-apache-buster

php:7.4.10-apacheで、jessieのイメージはなかったので、busterを使いました。(多分動くはず)

基本的に野良イメージは使わず、Officialなイメージを使うようにしています。

ライブラリを追加

引き続き、セットアップ手順を参考に必要なライブラリを追加していきます。

Dockerfileは後ほどきれいにするので、まずは雑にライブラリをインストールしていきます。

Dockerfileは上から各命令ごと順番にキャッシュされます。 そのため、構築時に上の方に記述されている命令を変更すると、それ以下はキャッシュが効かなくなるため、一気にインストールせずキャッシュを効かせながらインストールしています。

FROM php:7.4.10-apache-buster

RUN apt update && apt -y upgrade
RUN apt install -y libonig-dev
RUN docker-php-ext-install mbstring
RUN apt install -y libxml2-dev
RUN docker-php-ext-install xml
RUN docker-php-ext-install pdo_mysql
RUN docker-php-ext-install json
RUN apt -y install zlib1g-dev
RUN apt -y install libpng-dev
RUN apt -y install exif
RUN apt -y install mcrypt
RUN pecl install apcu
RUN docker-php-ext-enable apcu

RUN pecl install xdebug
RUN docker-php-ext-enable xdebug

RUN a2enmod rewrite
RUN docker-php-ext-install exif

ソースコード・設定ファイルをマウント

docker-compose側で、ソースコードOpenPNEの設定ファイルをマウントするようにします。 また、ここには出していないですがphp.ini, apache2.confの内容もいい感じに設定しています。

volumes:
  - ./src:/var/www/html
  - ./config/OpenPNE.yml:/var/www/html/config/OpenPNE.yml
  - ./config/ProjectConfiguration.class.php:/var/www/html/config/ProjectConfiguration.class.php
  - ./config/apache2.conf:/etc/apache2/apache2.conf
  - ./config/php.ini:/usr/local/etc/php/php.ini

個人的に、設定ファイルはconf.dなどメインのファイルにインクルードするような場所に置くと使用するイメージの設定によって設定内容が変わってくるため、conf.dなどのメインに設定にインクルードするような箇所にはマウントせず、メインのファイルのみ書き換えインクルードさせないようにするのが好みです。(が、みなさんどうやっているのだろう??)

初期化する

初期設定では、コマンドを叩きテーブルを初期化する必要があるようなので、mysqlのDBにユーザ・パスワード等の設定を追加し、実行します。

DBの設定を追加

  db:
    image: mysql:5.7.32
    volumes:
      - data_volume:/var/lib/mysql
    environment:
      TZ: Asia/Tokyo
      LANG: ja_JP.UTF-8
      MYSQL_DATABASE: openpne
      MYSQL_USER: openpne_user
      MYSQL_PASSWORD: openpne_password
      MYSQL_RANDOM_ROOT_PASSWORD: "yes"
volumes:
  data_volume:

初期化コマンドを実行!

docker-compose run --rm app bash -c "./symfony openpne:fast-install --dbms=mysql --dbuser=openpne_user --dbpassword=openpne_password --dbhost=db --dbport=3306 --dbname=openpne"

>> installer installation is completed! と出力されたので上手くいったっぽい。

動かす!

docker-compose up して動かします!

おお、なんかすごくm○xiっぽい。構築がおわったらゆっくり見ていきます。

f:id:takapi86:20201207031017p:plain

とりあえず、それっぽいコミュニティを設定しときました。

動かない箇所の修正

ポチポチ動かしてみると画像のアップロードが上手く行きませんでした。 エラーログやXdebugなどでデバッグで確認していきます。

ちなみに、DockerへのXdebug導入はこんな感じ

takapi86.hatenablog.com

今回は、拡張モジュールであるGDが漏れていたようなので追加しました。

RUN apt-get install -y libfreetype6-dev libjpeg-dev
RUN docker-php-ext-configure gd --with-jpeg=/usr/include/ --with-freetype=/usr/include/
RUN docker-php-ext-install -j$(nproc) gd

これで一通り動きました!

2. 設定を見直す

Dockerfileを整理する

キャッシュが効くようにババっと書いていってしまいましたが、 見た目も悪いですし、イメージのサイズも大きくなってしまうので整理していきます。

FROM php:7.4.10-apache-buster

RUN apt update && apt -y upgrade && apt install -y --no-install-recommends \
    exif \
    libfreetype6-dev \
    libjpeg-dev \
    libonig-dev \
    libpng-dev \
    libxml2-dev \
    mcrypt \
    zlib1g-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

RUN pecl install apcu && docker-php-ext-enable apcu
RUN docker-php-ext-install -j$(nproc) \
    exif \
    json \
    mbstring \
    pdo_mysql \
    xml

RUN docker-php-ext-configure gd --with-jpeg=/usr/include/ --with-freetype=/usr/include/ \
    && docker-php-ext-install -j$(nproc) gd
RUN a2enmod rewrite

こんな感じで整理しましたが、整理した以外にも上記の設定はこんなことを意識しています。

apt updateと一緒にapt installする

apt installをする際に古いパッケージ情報をキャッシュしたままだと、更新できないケースがありますので、それを避けるために、apt update apt installまとめています。 これにより、パッケージを追加したときにすべて新しいパッケージ情報で、更新されるようになります。

--no-install-recommendsを追加する

必須ではないパッケージが入ってくることを防いでいます。 https://manpages.debian.org/unstable/apt/apt-get.8.ja.html#%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3

キャッシュを削除する

&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

aptキャッシュをクリーンにし、/var/lib/apt/lits を削除することで、イメージのサイズを減らしています。

Dockerfile のベストプラクティス — Docker-docs-ja 1.9.0b ドキュメント

docker-composeに設定した値をDockerfileに寄せる

今回はDockerイメージ単体でも動作するようにしたいので、ソースコード・設定ファイルをDockerfileに移動させます。

COPY ./src /var/www/html
COPY ./config/OpenPNE.yml ./config/ProjectConfiguration.class.php /var/www/html/config/
COPY ./config/apache2.conf /etc/apache2/apache2.conf
COPY ./config/php.ini /usr/local/etc/php/php.ini

コピーする命令はCOPYの他にADDがありますが、ADDはローカル上でのtar展開や、リモートURLのサポートなど多くの機能を持っていて混乱の元なので、明確にCOPY以外の機能を使いたいとき以外は使わないようにしています。

こちらでもそう言っていますね。

Dockerfile のベストプラクティス — Docker-docs-ja 1.9.0b ドキュメント

その他、細かな設定を追加

WORKDIR,、EXPOSE、タイムゾーン、言語設定を追加します。

ENV TZ=Asia/Tokyo
ENV LANG=ja_JP.UTF-8
WORKDIR /var/www/html
EXPOSE 80

また、先に、DBが起動して欲しいので、depends_on を追加します。

depends_on:
  - db

3.ちょっとだけ、セキュアにする

今回はローカル環境でしか動かさないのですが、もし今後公開した環境で稼働させたくなったときにスムーズに移行できるよう、今回少しだけセキュリティ設定はしておきます。

アプリケーションのパーミッションに設定する

ソースコードを置いているディレクトリは最低限必要な権限のみを付与するようにします。

RUN chown -R www-data:www-data /var/www/html \
    && chmod -R 400 /var/www/html \
    && find /var/www/html -type d | xargs -I{} chmod 500 {} \
    && chmod 700 /var/www/html/log /var/www/html/cache

ReadOnlyで起動する

docker-compose.ymlに read_only: true を追加します。

書き込みが必要なディレクトリは次のように匿名ボリュームをマウントすることで書き込めるようにします。

read_only: true
volumes:
  - /var/www/html/log
  - /var/run/apache2/
  - /tmp

こちらに関しては先日記事を書きましたので良かったらご覧ください

takapi86.hatenablog.com

dockerignoreを設定する

イメージに含める必要のないファイルは.dockerignoreで除外しました。

4. 最終チェック

--no-cache オプションを利用して念の為キャッシュを使わず最初からビルドをし直して問題ないか確認します。

COMPOSE_DOCKER_CLI_BUILD=1 docker-compose build --no-cache

※COMPOSE_DOCKER_CLI_BUILD=1を設定することで、BuildKitを使って高速にビルドする様にしています。BuildKitについてはこちら

いろいろイジってみる

どうやら、インストール直後はプロフィールとコミュニティ機能くらいしか無いようなのですが、プラグインを追加することで、タイムラインや日記、あしあと機能などを追加ができるようです。

プラグインはこのページの各プラグインをクリックしたあとに表示されるコマンドを入力することで追加できるようです。

OpenPNE プラグイン|OpenPNE

プラグインを追加していった結果こんな見た目になりました!! なんかすごく大学生の頃を思い出すような懐かしい見た目になった!!!

f:id:takapi86:20201207025834p:plain

本家(UIの参考になったであろうサービス)の方もたまにはログインしてみようと思います。

まとめ

今回は、OpenPNEを使ったローカル環境を構築してみましたが、業務で使用している開発環境も大体同じような流れで構築をしています。もしこうすると良いよ!などアドバイスなどがあればコメントいただけると嬉しいです。

Twitterやっているので、良かったらマイミク申請フォローお願いします。

https://twitter.com/takapi86

明日9日目は、mochikoさんです〜