DamienKarrus’s blog

プログラミングとクライミングの足跡

既存webシステムのコンテナ化(1) Docker実践-2

WSL2(debian latest)を使って既存のシステムのコンテナ化をしてみようと思う。 開発環境の構成は次の通り。

Windows10 professional
WSL2 (debian latest) 
Docker (20.10.17)

開発環境の構築手順はこちら damienkarrus.hatenablog.com

コンテナ化する対象のシステムは、CentOS7+Apache2+PHP7+PostgreSQL14で動作し、顧客用webページと、コンテンツ管理用の管理者ページがあり、それぞれURIを持っているが同一サーバで稼動している。DBは双方のwebページからアクセスされている。永続的に保存しなければいけないデータは、データベース、ユーザアップロードファイルである。 デバッグの効率性を考えて、PHPのソースはWindows上のフォルダに置き、それをdebianが勝手にマウントしてくれるので、そのdebianディレクトリをコンテナがbindして使う。デバッグ完了後は、bindせずに、コンテナ内にソースファイルを保持するようyamlに定義することにする。

Windowsフォルダのマウント状況は当環境では次のようになった。

Windows:
X:\oto\public_html ←管理者向けwebページ
X:/rega/public_html ←顧客向けwebページ
X:\oto\files ←アップロードされたファイル
 ↓
WSL(
WSL2(debian):
/mnt/x/oto/public_html
/mnt/x/rega/public_html
/mnt/x/oto/files

フォルダ構成

作業フォルダ(oto)を作成し、配下にDBとウェブアプリ(apache+php)のサブフォルダを作って、イメージはそれぞれの中でDockerfileで定義しておき、全体をdocker-composeでコントロールする。また、webサーバは一般公開用(web)とコンテンツ管理用(web2)があるので、2つのコンテナを用意し、それぞれがDBコンテナ、外部ボリュームコンテナを参照するように構築する。 oto下のファイル、ディレクトリ構成は以下の通り

docker-compose.yaml
postgres/
web/
web2/

postgres

postgresフォルダ内は

Dockerfile
docker-entrypoint-initdb.d/

Dockerfileは

FROM postgres:14-alpine
ENV LANG ja_JP.utf8
ENV TZ=Asia/Tokyo

docker-entrypoint-initdb.d には、データベースの初期データを data.out というファイル名でおいておくことにする(後ほどリストアして使用する)。
Postgresのデータはボリュームを作成しておきvolumeマウントして使う。

$ docker volume create --name oto-db

web , web2

webフォルダ / web2フォルダは

Dockerfile
php.ini
apache2.conf

phpの設定ファイルはbindして使用する(デバッグ・調整のため)。apacheはlatest、phpは7.4を指定した。 アップロードされたデータの保存先はボリュームを作成しておきvolumeマウントして使う。

$ docker volume create --name oto-files

Dockerfileは

FROM debian
ENV TZ=Asia/Tokyo
EXPOSE 80
RUN apt-get update
RUN apt-get install -y sudo
RUN apt-get install -y curl ca-certificates gnupg \
&& sudo apt-get install -y build-essential apt-transport-https \
&& sudo apt-get install -y php7.4 php7.4-intl php7.4-mbstring php7.4-pgsql php7.4-fpm php7.4-cli php7.4-zip \
&& sudo apt-get install -y apache2 libapache2-mod-php \
&& sudo apt-get install -y iputils-ping net-tools dnsutils \ ←疎通確認などに使用するツール
&& sudo apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
&& rm /var/www/html/index.html
COPY apache2.conf /etc/apache2/
CMD /usr/sbin/apachectl -DFOREGROUND
STOPSIGNAL SIGWINCH

php.iniは

[PHP]
post_max_size = 1024M
upload_max_filesize = 1024M
max_file_uploads = 20
[Date]
date.timezone = "Asia/Tokyo"
[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"

↑色々足りていないが、動作確認にはこれでOK

docker-compose

docker-compose.yaml

version: '3'
services:
  web:
    build: ./web
    ports:
      - 8080:80
    volumes:
      - ./web/php.ini:/usr/local/etc/php/php.ini
      - /mnt/x/oto/public_html:/var/www/html
      - oto-files:/var/www/html/files
  web2:
    build: ./web2
    ports:
      - 8081:80
    volumes:
      - ./web2/php.ini:/usr/local/etc/php/php.ini
      - /mnt/x/rega/public_html:/var/www/html
      - oto-files:/var/www/html/files
  db:
    build: ./postgres
    ports:
      - 5432:5432
    environment:
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: admin
    volumes:
      - ./postgres/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
      - oto-db:/var/lib/postgresql/data
volumes:
  oto-db:
    external: true
  oto-files:
    external: true

build前に既存システムのdbのバックアップを取り、postgres/docker-entrypoint-initdb.dに保存しておく

(既存システムで)
pg_dump cpan69 > data.out 

このファイルをpostgres/docker-entrypoint-initdb.d内にコピーしておく。
buildしてみる

$ docker-compose up --build -d
Building web
[+] Building 7.2s (11/11) FINISHED
...(snip)...
Creating oto_db_1   ... done
Creating oto_web2_1 ... done
Creating oto_web_1  ... done

稼働状況を確認する

$ docker-compose ps
   Name                  Command               State            Ports
------------------------------------------------------------------------------
oto_db_1     docker-entrypoint.sh postgres    Up      0.0.0.0:5432->5432/tcp
oto_web2_1   /bin/sh -c /usr/sbin/apach ...   Up      0.0.0.0:8081->80/tcp
oto_web_1    /bin/sh -c /usr/sbin/apach ...   Up      0.0.0.0:8080->80/tcp

コンテナ構築後の諸作業

疎通確認をする。まずはwebサーバにログインする。

$ docker container exec -it oto_web_1 /bin/bash

dbサーバにpingしてみる

# ping db
PING db (192.168.160.2) 56(84) bytes of data.
64 bytes from oto_db_1.oto_default (172.18.0.2): icmp_seq=1 ttl=64 time=0.081 ms
...(snip)...

DBのリストア

バックアップファイルをリストアする。dbサーバにログインする。

$ docker container exec -it oto_db_1 /bin/bash

DBに移植元のユーザとapache2のユーザを登録して、リストアし、apache2に対してgrant allをかける

# cd /docker-entrypoint-initdb.d
# createuser cpan69 ※現行システムがユーザcpan69で運用されているため、リストア時のエラー回避の為作成
# createuser www-data ※apache2のデフォルトユーザ名
# createdb cpan69
# psql -U admin cpan69 < data.out
# psql -U admin cpan69 < grantall.sql ※grant all on テーブル名 to www-data を記述したファイル

ソースファイルの修正

PostgreSQLのopenパラメータの調整 コンテナ化前はlocalhostを参照していたためhost指定を追加し、アクセスユーザも指定する。

$handler=pg_pconnect("dbname=$db_name");//コンテナ化前の記述
↓
$handler=pg_pconnect("host=db dbname=$db_name user=admin password=admin");

アップロード済みファイルを外部ボリュームへ展開する
元データのtarボールをソースファイルと同じところにおいておき、外部コンテナがマウントされている場所にて展開する まずはwebサーバにログインする。

$ docker container exec -it oto_web_1 /bin/bash

tarボールを展開する

# cd /var/www/html/files
# tar xf /var/www/html/msheet.tar .
# cd msheet
# cdmod 757 . ※apacheから書き込みが出来るよう許可
# chown www-data:www-data *.pdf ※apacheが書き込んだデータなのでオーナーをwww-dataに変更

ブラウザでlocalhostの8080と8081にアクセスし動作を確認する。

cronの設定

次にcrontabにスケジュールを登録する。実はここではまった。いつもはredhat系でcrontabにスケジュールを登録していたのだが、これでは時刻になっても発火しない。debian系だから?コンテナだから?ネットで検索するとbusyboxのcrondが良いとある。動作しない原因が不明なのは気持ち悪いが原因究明は別の機会にするとして、ここでは動作するものをインストールして使用することにする。 まずはモジュールをインストールするため、Dockerfileの記述を書き足す。

FROM debian
ENV TZ=Asia/Tokyo
EXPOSE 80
RUN apt-get update
RUN apt-get install -y sudo
RUN apt-get install -y curl ca-certificates gnupg \
&& sudo apt-get install -y build-essential apt-transport-https \
&& sudo apt-get install -y php7.4 php7.4-intl php7.4-mbstring php7.4-pgsql php7.4-fpm php7.4-cli php7.4-zip \
&& sudo apt-get install -y apache2 libapache2-mod-php \
&& sudo apt-get install -y iputils-ping net-tools dnsutils \
&& sudo apt-get install -y busybox-static \ ←これでcrondがインストールされる
&& sudo apt-get install -y vim \ ←viもインストールしておく
&& sudo apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
&& rm -rf /var/www/html/* \
&& rm -rf /var/www/html/files
COPY apache2.conf /etc/apache2/
COPY crontab /var/spool/cron/crontabs/www-data ←crontabのコピー
CMD busybox crond -l 2 -L /dev/stderr -f & ←crondの起動 ※起動しない
CMD /usr/sbin/apachectl -DFOREGROUND
STOPSIGNAL SIGWINCH

crontabの内容は次の通り

00 11 * * * /bin/bash /var/www/html/cron.sh
00 07 * * 1 php /var/www/html/cli_shift_request_clear.php

※crondが起動しない。&を付けてもつけなくても起動しない。仕方ないので手動で起動した。

$ docker container exec -it otona_web_1 /bin/bash
root@d984e2b3e681:/# busybox crond -l 2 -L /dev/stderr -f &

※なお、EWSのEC2でdocker-composeすると、Dockerfile内にEXPOSE 80の記述があると、pullするときに404エラーになり落ちる

ここまでで、辛うじてコンテンツ自体はコンテナ化ができた。 次に定期的なバックアップをやってみる。 「既存webシステムのコンテナ化(2)」(現在作成中)に続く。